2022-03-31 11:46:25 +00:00
|
|
|
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 "../stores"
|
|
|
|
|
2022-07-20 14:54:30 +00:00
|
|
|
StatusGridView {
|
2022-03-31 11:46:25 +00:00
|
|
|
id: grid
|
|
|
|
|
|
|
|
property bool isValid: false
|
|
|
|
property string mnemonicString: ""
|
|
|
|
property int preferredHeight: (cellHeight * model/2) + footerItem.height
|
2022-05-05 18:54:45 +00:00
|
|
|
signal enterPressed()
|
2022-03-31 11:46:25 +00:00
|
|
|
|
|
|
|
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()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function validate() {
|
|
|
|
_internal.errorString = ""
|
|
|
|
if (!Utils.isMnemonic(mnemonicString)) {
|
2022-04-04 11:26:30 +00:00
|
|
|
_internal.errorString = qsTr("Invalid seed phrase")
|
2022-03-31 11:46:25 +00:00
|
|
|
} else {
|
|
|
|
_internal.errorString = RootStore.vaildateMnemonic(mnemonicString)
|
|
|
|
const regex = new RegExp('word [a-z]+ not found in the dictionary', 'i');
|
|
|
|
if (regex.test(_internal.errorString)) {
|
2022-04-04 11:26:30 +00:00
|
|
|
_internal.errorString = qsTr("Invalid seed phrase") + '. ' +
|
|
|
|
qsTr("This seed phrase doesn't match our supported dictionary. Check for misspelled words.")
|
2022-03-31 11:46:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return _internal.errorString === ""
|
|
|
|
}
|
|
|
|
|
|
|
|
QtObject {
|
|
|
|
id: _internal
|
2022-07-07 15:35:23 +00:00
|
|
|
property int seedPhraseInputWidth: (parent.width/2)
|
|
|
|
property int seedPhraseInputHeight: 48
|
2022-03-31 11:46:25 +00:00
|
|
|
property var mnemonicInput: []
|
|
|
|
property string errorString: ""
|
2022-06-03 08:32:55 +00:00
|
|
|
readonly property var seedPhraseWordsOptions: ([12, 18, 24])
|
2022-03-31 11:46:25 +00:00
|
|
|
|
|
|
|
function getSeedPhraseString() {
|
|
|
|
var seedPhrase = ""
|
|
|
|
for(var i = 0; i < grid.model; i++) {
|
|
|
|
if(!!grid.itemAtIndex(i)) {
|
|
|
|
seedPhrase += grid.itemAtIndex(i).text + " "
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return seedPhrase
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-07 15:35:23 +00:00
|
|
|
cellWidth: _internal.seedPhraseInputWidth
|
|
|
|
cellHeight: _internal.seedPhraseInputHeight
|
2022-03-31 11:46:25 +00:00
|
|
|
interactive: false
|
|
|
|
z: 100000
|
|
|
|
|
|
|
|
onModelChanged: {
|
|
|
|
mnemonicString = "";
|
2022-05-25 13:36:42 +00:00
|
|
|
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)
|
|
|
|
}
|
2022-03-31 11:46:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
onIsValidChanged: {
|
|
|
|
if(isValid) {
|
|
|
|
mnemonicString = _internal.getSeedPhraseString()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
onVisibleChanged: {
|
|
|
|
if(visible) {
|
|
|
|
grid.itemAtIndex(0).textEdit.input.edit.forceActiveFocus()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-05 18:54:45 +00:00
|
|
|
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
|
2022-06-03 08:32:55 +00:00
|
|
|
let indexOfWordsOption = _internal.seedPhraseWordsOptions.indexOf(words.length)
|
|
|
|
if(indexOfWordsOption == -1) {
|
2022-05-05 18:54:45 +00:00
|
|
|
return false
|
|
|
|
}
|
2022-06-03 08:32:55 +00:00
|
|
|
footerItem.switchToIndex(indexOfWordsOption)
|
|
|
|
timeout = 100
|
2022-05-05 18:54:45 +00:00
|
|
|
|
|
|
|
timer.setTimeout(function(){
|
|
|
|
_internal.mnemonicInput = []
|
|
|
|
for (let i = 0; i < words.length; i++) {
|
|
|
|
try {
|
|
|
|
grid.itemAtIndex(i).setWord(words[i])
|
|
|
|
} catch (e) {
|
|
|
|
// Getting items outside of the current view might not work
|
|
|
|
}
|
|
|
|
grid.addWord(i, words[i], true)
|
|
|
|
}
|
|
|
|
}, timeout);
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
function addWord(pos, word, ignoreGoingNext) {
|
|
|
|
_internal.mnemonicInput.push({"pos": pos, "seed": word.replace(/\s/g, '')});
|
2022-03-31 11:46:25 +00:00
|
|
|
for (var j = 0; j < _internal.mnemonicInput.length; j++) {
|
2022-05-05 18:54:45 +00:00
|
|
|
if (_internal.mnemonicInput[j].pos === pos && _internal.mnemonicInput[j].seed !== word) {
|
2022-03-31 11:46:25 +00:00
|
|
|
_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
|
|
|
|
});
|
2022-05-05 18:54:45 +00:00
|
|
|
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;
|
|
|
|
}
|
2022-03-31 11:46:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
grid.isValid = (_internal.mnemonicInput.length === grid.model);
|
2022-05-05 18:54:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
delegate: StatusSeedPhraseInput {
|
|
|
|
id: statusSeedInput
|
2022-07-07 15:35:23 +00:00
|
|
|
width: grid.cellWidth - (Style.current.halfPadding/2)
|
|
|
|
height: (grid.cellHeight - Style.current.halfPadding)
|
2022-05-05 18:54:45 +00:00
|
|
|
textEdit.errorMessageCmp.visible: false
|
2022-07-18 08:37:37 +00:00
|
|
|
textEdit.input.placeholder.objectName: "seedPhraseInputPlaceholder" + index
|
2022-05-05 18:54:45 +00:00
|
|
|
leftComponentText: index + 1
|
|
|
|
inputList: BIP39_en { }
|
|
|
|
property int itemIndex: index
|
|
|
|
z: (grid.currentIndex === index) ? 150000000 : 0
|
|
|
|
onDoneInsertingWord: {
|
|
|
|
grid.addWord(leftComponentText, word)
|
2022-03-31 11:46:25 +00:00
|
|
|
}
|
|
|
|
onEditClicked: {
|
|
|
|
grid.currentIndex = index;
|
|
|
|
grid.itemAtIndex(index).textEdit.input.edit.forceActiveFocus();
|
|
|
|
}
|
|
|
|
onKeyPressed: {
|
2022-05-05 18:54:45 +00:00
|
|
|
if (event.key === Qt.Key_Backtab) {
|
2022-03-31 11:46:25 +00:00
|
|
|
for (var i = !grid.atXBeginning ? 12 : 0; i < grid.count; i++) {
|
2022-05-05 18:54:45 +00:00
|
|
|
if (parseInt(grid.itemAtIndex(i).leftComponentText) === ((parseInt(leftComponentText)-1) >= 0 ? (parseInt(leftComponentText)-1) : 0)) {
|
|
|
|
grid.itemAtIndex(i).textEdit.input.edit.forceActiveFocus(Qt.TabFocusReason);
|
2022-03-31 11:46:25 +00:00
|
|
|
textEdit.input.tabNavItem = grid.itemAtIndex(i).textEdit.input.edit;
|
2022-05-05 18:54:45 +00:00
|
|
|
event.accepted = true
|
|
|
|
break
|
2022-03-31 11:46:25 +00:00
|
|
|
}
|
|
|
|
}
|
2022-05-05 18:54:45 +00:00
|
|
|
} else if (event.key === Qt.Key_Tab) {
|
2022-03-31 11:46:25 +00:00
|
|
|
for (var i = !grid.atXBeginning ? 12 : 0; i < grid.count; i++) {
|
2022-05-05 18:54:45 +00:00
|
|
|
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
|
2022-03-31 11:46:25 +00:00
|
|
|
}
|
|
|
|
}
|
2022-05-05 18:54:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2022-03-31 11:46:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
2022-05-05 18:54:45 +00:00
|
|
|
id: footerC
|
2022-06-03 08:32:55 +00:00
|
|
|
function switchToIndex(index) {
|
|
|
|
changeSeedNbWordsTabBar.currentIndex = index
|
2022-05-05 18:54:45 +00:00
|
|
|
}
|
2022-07-07 15:35:23 +00:00
|
|
|
width: grid.width - (Style.current.halfPadding/2)
|
2022-06-03 08:32:55 +00:00
|
|
|
height: changeSeedNbWordsTabBar.height + errorMessage.height + Style.current.padding*2
|
2022-03-31 11:46:25 +00:00
|
|
|
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
|
|
|
|
}
|
2022-06-03 08:32:55 +00:00
|
|
|
StatusSwitchTabBar {
|
|
|
|
id: changeSeedNbWordsTabBar
|
2022-07-07 15:35:23 +00:00
|
|
|
width: parent.width
|
2022-03-31 11:46:25 +00:00
|
|
|
anchors.top: errorMessage.bottom
|
|
|
|
anchors.topMargin: Style.current.padding
|
2022-06-03 08:32:55 +00:00
|
|
|
Repeater {
|
|
|
|
model: _internal.seedPhraseWordsOptions
|
|
|
|
StatusSwitchTabButton {
|
|
|
|
text: qsTr("%1 words").arg(modelData)
|
2022-03-31 11:46:25 +00:00
|
|
|
}
|
|
|
|
}
|
2022-06-03 08:32:55 +00:00
|
|
|
onCurrentIndexChanged: {
|
|
|
|
grid.model = _internal.seedPhraseWordsOptions[changeSeedNbWordsTabBar.currentIndex]
|
|
|
|
}
|
2022-03-31 11:46:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|