status-desktop/ui/app/AppLayouts/Wallet/panels/ImportSeedPhrasePanel.qml

269 lines
9.5 KiB
QML
Raw Normal View History

import QtQuick 2.12
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import utils 1.0
import shared.stores 1.0
import shared.controls 1.0
import "../stores"
StatusGridView {
id: grid
property bool isValid: false
property string mnemonicString: ""
property int preferredHeight: (cellHeight * model/2) + footerItem.height
signal enterPressed()
function reset() {
_internal.errorString = ""
mnemonicString = ""
_internal.mnemonicInput = [];
if (!grid.atXBeginning) {
grid.positionViewAtBeginning();
}
for(var i = 0; i < grid.model; i++) {
if(grid.itemAtIndex(i)) {
grid.itemAtIndex(i).textEdit.text = ""
grid.itemAtIndex(i).textEdit.reset()
}
}
grid.isValid = false
}
function validate() {
_internal.errorString = ""
if (!Utils.isMnemonic(mnemonicString)) {
_internal.errorString = qsTr("Invalid seed phrase")
} else {
if (!RootStore.validSeedPhrase(mnemonicString)) {
_internal.errorString = qsTr("Invalid seed phrase") + '. ' +
2022-07-21 12:15:02 +00:00
qsTr("This seed phrase doesn't match our supported dictionary. Check for misspelled words.")
}
}
return _internal.errorString === ""
}
QtObject {
id: _internal
property int seedPhraseInputWidth: (parent.width/2)
property int seedPhraseInputHeight: 48
property var mnemonicInput: []
property string errorString: ""
readonly property var seedPhraseWordsOptions: [12, 18, 24]
function getSeedPhraseString() {
var seedPhrase = ""
for(var i = 0; i < grid.model; i++) {
if(!!grid.itemAtIndex(i)) {
seedPhrase += grid.itemAtIndex(i).text + " "
}
}
return seedPhrase
}
}
cellWidth: _internal.seedPhraseInputWidth
cellHeight: _internal.seedPhraseInputHeight
interactive: false
z: 100000
onModelChanged: {
mnemonicString = "";
let menmonicInputTemp = _internal.mnemonicInput.filter(function(value) {
return value.pos <= grid.count
})
_internal.mnemonicInput = []
for (let i = 0; i < menmonicInputTemp.length; i++) {
// .pos starts with 1
grid.itemAtIndex(menmonicInputTemp[i].pos - 1).setWord(menmonicInputTemp[i].seed)
grid.addWord(menmonicInputTemp[i].pos,
menmonicInputTemp[i].seed,
true)
}
}
Timer {
id: timer
}
onIsValidChanged: {
if(isValid) {
mnemonicString = _internal.getSeedPhraseString()
}
}
onVisibleChanged: {
if(visible) {
grid.itemAtIndex(0).textEdit.input.edit.forceActiveFocus()
}
}
function pasteWords () {
const clipboardText = globalUtils.getFromClipboard()
// Split words separated by commas and or blank spaces (spaces, enters, tabs)
let words = clipboardText.split(/[, \s]+/)
let timeout = 0
let indexOfWordsOption = _internal.seedPhraseWordsOptions.indexOf(words.length)
if(indexOfWordsOption == -1) {
return false
}
footerItem.switchToIndex(indexOfWordsOption)
timeout = 100
timer.setTimeout(function(){
_internal.mnemonicInput = []
for (let i = 0; i < words.length; i++) {
const item = grid.itemAtIndex(i)
if (item && item.leftComponentText)
item.setWord(words[i])
}
}, timeout);
return true
}
function addWord(pos, word, ignoreGoingNext) {
_internal.mnemonicInput.push({"pos": pos, "seed": word.replace(/\s/g, '')});
for (var j = 0; j < _internal.mnemonicInput.length; j++) {
if (_internal.mnemonicInput[j].pos === pos && _internal.mnemonicInput[j].seed !== word) {
_internal.mnemonicInput[j].seed = word;
}
}
//remove duplicates
var valueArr = _internal.mnemonicInput.map(function(item){ return item.pos });
var isDuplicate = valueArr.some(function(item, idx){
if (valueArr.indexOf(item) !== idx) {
_internal.mnemonicInput.splice(idx, 1);
}
return valueArr.indexOf(item) !== idx
});
if (!ignoreGoingNext) {
for (var i = !grid.atXBeginning ? 12 : 0; i < grid.count; i++) {
if (parseInt(grid.itemAtIndex(i).leftComponentText) === (parseInt(pos)+1)) {
grid.currentIndex = grid.itemAtIndex(i).itemIndex;
grid.itemAtIndex(i).textEdit.input.edit.forceActiveFocus();
if (grid.currentIndex === 11) {
grid.positionViewAtEnd();
if (grid.count === 20) {
grid.contentX = 1500;
}
}
}
}
}
grid.isValid = (_internal.mnemonicInput.length === grid.model);
}
delegate: StatusSeedPhraseInput {
id: statusSeedInput
width: grid.cellWidth - (Style.current.halfPadding/2)
height: (grid.cellHeight - Style.current.halfPadding)
textEdit.errorMessageCmp.visible: false
textEdit.input.placeholder.objectName: "seedPhraseInputPlaceholder" + index
leftComponentText: index + 1
inputList: BIP39_en { }
property int itemIndex: index
z: (grid.currentIndex === index) ? 150000000 : 0
onDoneInsertingWord: {
grid.addWord(leftComponentText, word)
}
onEditClicked: {
grid.currentIndex = index;
grid.itemAtIndex(index).textEdit.input.edit.forceActiveFocus();
}
onKeyPressed: {
if (event.key === Qt.Key_Backtab) {
for (var i = !grid.atXBeginning ? 12 : 0; i < grid.count; i++) {
if (parseInt(grid.itemAtIndex(i).leftComponentText) === ((parseInt(leftComponentText)-1) >= 0 ? (parseInt(leftComponentText)-1) : 0)) {
grid.itemAtIndex(i).textEdit.input.edit.forceActiveFocus(Qt.TabFocusReason);
textEdit.input.tabNavItem = grid.itemAtIndex(i).textEdit.input.edit;
event.accepted = true
break
}
}
} else if (event.key === Qt.Key_Tab) {
for (var i = !grid.atXBeginning ? 12 : 0; i < grid.count; i++) {
if (parseInt(grid.itemAtIndex(i).leftComponentText) === ((parseInt(leftComponentText)+1) <= grid.count ? (parseInt(leftComponentText)+1) : grid.count)) {
grid.itemAtIndex(i).textEdit.input.edit.forceActiveFocus(Qt.TabFocusReason);
textEdit.input.tabNavItem = grid.itemAtIndex(i).textEdit.input.edit;
event.accepted = true
break
}
}
}
if (event.matches(StandardKey.Paste)) {
if (grid.pasteWords()) {
// Paste was done by splitting the words
event.accepted = true
}
return
}
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
event.accepted = true
grid.enterPressed()
return
}
if (event.key === Qt.Key_Delete || event.key === Qt.Key_Backspace) {
var wordIndex = _internal.mnemonicInput.findIndex(x => x.pos === leftComponentText);
if (wordIndex > -1) {
_internal.mnemonicInput.splice(wordIndex , 1);
grid.isValid = _internal.mnemonicInput.length === grid.model
}
}
grid.currentIndex = index;
}
}
footer: Item {
id: footerC
function switchToIndex(index) {
changeSeedNbWordsTabBar.currentIndex = index
}
width: grid.width - (Style.current.halfPadding/2)
height: changeSeedNbWordsTabBar.height + errorMessage.height + Style.current.padding*2
StatusBaseText {
id: errorMessage
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.topMargin: Style.current.padding
height: visible ? implicitHeight : 0
visible: !!text
text: _internal.errorString
font.pixelSize: 12
color: Theme.palette.dangerColor1
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
}
StatusSwitchTabBar {
id: changeSeedNbWordsTabBar
width: parent.width
anchors.top: errorMessage.bottom
anchors.topMargin: Style.current.padding
Repeater {
model: _internal.seedPhraseWordsOptions
StatusSwitchTabButton {
text: qsTr("%n word(s)", "", modelData)
}
}
onCurrentIndexChanged: {
grid.model = _internal.seedPhraseWordsOptions[changeSeedNbWordsTabBar.currentIndex]
}
}
}
}