feat: extract seed textArea to shared component and use it in wallet
This commit is contained in:
parent
757eb2bc9e
commit
dae0d60684
|
@ -7,7 +7,7 @@ import "../../../../shared/status"
|
||||||
|
|
||||||
ModalPopup {
|
ModalPopup {
|
||||||
id: popup
|
id: popup
|
||||||
height: 600
|
height: 615
|
||||||
|
|
||||||
property int marginBetweenInputs: 38
|
property int marginBetweenInputs: 38
|
||||||
property string passwordValidationError: ""
|
property string passwordValidationError: ""
|
||||||
|
@ -18,7 +18,7 @@ ModalPopup {
|
||||||
function reset() {
|
function reset() {
|
||||||
passwordInput.text = ""
|
passwordInput.text = ""
|
||||||
accountNameInput.text = ""
|
accountNameInput.text = ""
|
||||||
accountSeedInput.text = ""
|
seedPhraseTextArea.textArea.text = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
function validate() {
|
function validate() {
|
||||||
|
@ -39,10 +39,10 @@ ModalPopup {
|
||||||
accountNameValidationError = ""
|
accountNameValidationError = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
if (accountSeedInput.text === "") {
|
if (seedPhraseTextArea.textArea.text === "") {
|
||||||
//% "You need to enter a seed phrase"
|
//% "You need to enter a seed phrase"
|
||||||
seedValidationError = qsTrId("you-need-to-enter-a-seed-phrase")
|
seedValidationError = qsTrId("you-need-to-enter-a-seed-phrase")
|
||||||
} else if (!Utils.isMnemonic(accountSeedInput.text)) {
|
} else if (!Utils.isMnemonic(seedPhraseTextArea.textArea.text)) {
|
||||||
//% "Enter a valid mnemonic"
|
//% "Enter a valid mnemonic"
|
||||||
seedValidationError = qsTrId("enter-a-valid-mnemonic")
|
seedValidationError = qsTrId("enter-a-valid-mnemonic")
|
||||||
} else {
|
} else {
|
||||||
|
@ -53,7 +53,7 @@ ModalPopup {
|
||||||
}
|
}
|
||||||
|
|
||||||
onOpened: {
|
onOpened: {
|
||||||
accountSeedInput.text = "";
|
seedPhraseTextArea.textArea.text = "";
|
||||||
passwordInput.text = "";
|
passwordInput.text = "";
|
||||||
accountNameInput.text = "";
|
accountNameInput.text = "";
|
||||||
passwordValidationError = "";
|
passwordValidationError = "";
|
||||||
|
@ -76,28 +76,16 @@ ModalPopup {
|
||||||
validationError: popup.passwordValidationError
|
validationError: popup.passwordValidationError
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SeedPhraseTextArea {
|
||||||
StyledTextArea {
|
id: seedPhraseTextArea
|
||||||
id: accountSeedInput
|
|
||||||
anchors.top: passwordInput.bottom
|
anchors.top: passwordInput.bottom
|
||||||
anchors.topMargin: marginBetweenInputs
|
anchors.topMargin: marginBetweenInputs
|
||||||
//% "Enter your seed phrase, separate words with commas or spaces..."
|
width: parent.width
|
||||||
placeholderText: qsTrId("enter-your-seed-phrase,-separate-words-with-commas-or-spaces...")
|
|
||||||
//% "Seed phrase"
|
|
||||||
label: qsTrId("recovery-phrase")
|
|
||||||
customHeight: 88
|
|
||||||
validationError: popup.seedValidationError
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
text: Utils.seedPhraseWordCountText(accountSeedInput.text)
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.top: accountSeedInput.bottom
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Input {
|
Input {
|
||||||
id: accountNameInput
|
id: accountNameInput
|
||||||
anchors.top: accountSeedInput.bottom
|
anchors.top: seedPhraseTextArea.bottom
|
||||||
anchors.topMargin: marginBetweenInputs
|
anchors.topMargin: marginBetweenInputs
|
||||||
//% "Enter an account name..."
|
//% "Enter an account name..."
|
||||||
placeholderText: qsTrId("enter-an-account-name...")
|
placeholderText: qsTrId("enter-an-account-name...")
|
||||||
|
@ -123,7 +111,7 @@ ModalPopup {
|
||||||
//% "Add account"
|
//% "Add account"
|
||||||
qsTrId("add-account")
|
qsTrId("add-account")
|
||||||
|
|
||||||
enabled: !loading && passwordInput.text !== "" && accountNameInput.text !== "" && accountSeedInput.text !== ""
|
enabled: !loading && passwordInput.text !== "" && accountNameInput.text !== "" && seedPhraseTextArea.correctWordCount
|
||||||
|
|
||||||
MessageDialog {
|
MessageDialog {
|
||||||
id: accountError
|
id: accountError
|
||||||
|
@ -133,14 +121,14 @@ ModalPopup {
|
||||||
}
|
}
|
||||||
|
|
||||||
onClicked : {
|
onClicked : {
|
||||||
// TODO the loaidng doesn't work because the function freezes th eview. Might need to use threads
|
// TODO the loading doesn't work because the function freezes the view. Might need to use threads
|
||||||
loading = true
|
loading = true
|
||||||
if (!validate()) {
|
if (!validate() || !seedPhraseTextArea.validateSeed()) {
|
||||||
errorSound.play()
|
errorSound.play()
|
||||||
return loading = false
|
return loading = false
|
||||||
}
|
}
|
||||||
|
|
||||||
const error = walletModel.addAccountsFromSeed(accountSeedInput.text, passwordInput.text, accountNameInput.text, accountColorInput.selectedColor)
|
const error = walletModel.addAccountsFromSeed(seedPhraseTextArea.textArea.text, passwordInput.text, accountNameInput.text, accountColorInput.selectedColor)
|
||||||
loading = false
|
loading = false
|
||||||
if (error) {
|
if (error) {
|
||||||
errorSound.play()
|
errorSound.play()
|
||||||
|
|
|
@ -125,7 +125,6 @@ QtObject {
|
||||||
|
|
||||||
function isMnemonic(value) {
|
function isMnemonic(value) {
|
||||||
if(!value.match(/^([a-z\s]+)$/)){
|
if(!value.match(/^([a-z\s]+)$/)){
|
||||||
console.log('allo')
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return Utils.seedPhraseValidWordCount(value);
|
return Utils.seedPhraseValidWordCount(value);
|
||||||
|
|
|
@ -387,6 +387,7 @@ DISTFILES += \
|
||||||
shared/GasValidator.qml \
|
shared/GasValidator.qml \
|
||||||
shared/RoundedImage.qml \
|
shared/RoundedImage.qml \
|
||||||
shared/SearchBox.qml \
|
shared/SearchBox.qml \
|
||||||
|
shared/SeedPhraseTextArea.qml \
|
||||||
shared/Select.qml \
|
shared/Select.qml \
|
||||||
shared/SendToContractWarning.qml \
|
shared/SendToContractWarning.qml \
|
||||||
shared/Separator.qml \
|
shared/Separator.qml \
|
||||||
|
|
|
@ -7,69 +7,27 @@ import "../shared/status"
|
||||||
|
|
||||||
ModalPopup {
|
ModalPopup {
|
||||||
property var onConfirmSeedClick: function () {}
|
property var onConfirmSeedClick: function () {}
|
||||||
property alias error: errorText.text
|
|
||||||
property bool correctWordCount: Utils.seedPhraseValidWordCount(mnemonicTextField.text)
|
|
||||||
id: popup
|
id: popup
|
||||||
//% "Enter seed phrase"
|
//% "Enter seed phrase"
|
||||||
title: qsTrId("enter-seed-phrase")
|
title: qsTrId("enter-seed-phrase")
|
||||||
height: 400
|
height: 400
|
||||||
|
|
||||||
onOpened: {
|
onOpened: {
|
||||||
mnemonicTextField.text = "";
|
seedPhraseTextArea.textArea.text = "";
|
||||||
mnemonicTextField.forceActiveFocus(Qt.MouseFocusReason)
|
seedPhraseTextArea.textArea.forceActiveFocus(Qt.MouseFocusReason)
|
||||||
}
|
}
|
||||||
TextArea {
|
|
||||||
id: mnemonicTextField
|
SeedPhraseTextArea {
|
||||||
|
id: seedPhraseTextArea
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.topMargin: 40
|
anchors.topMargin: 40
|
||||||
height: 100
|
width: parent.width
|
||||||
anchors.left: parent.left
|
hideRectangle: true
|
||||||
anchors.leftMargin: 76
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.rightMargin: 76
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
horizontalAlignment: TextEdit.AlignHCenter
|
|
||||||
verticalAlignment: TextEdit.AlignVCenter
|
|
||||||
font.pixelSize: 15
|
|
||||||
font.weight: Font.DemiBold
|
|
||||||
//% "Start with the first word"
|
|
||||||
placeholderText: qsTrId("start-with-the-first-word")
|
|
||||||
placeholderTextColor: Style.current.secondaryText
|
|
||||||
selectByMouse: true
|
|
||||||
selectByKeyboard: true
|
|
||||||
selectionColor: Style.current.secondaryBackground
|
|
||||||
selectedTextColor: Style.current.secondaryText
|
|
||||||
|
|
||||||
Keys.onReleased: errorText.text = ""
|
textArea.anchors.leftMargin: 76
|
||||||
|
textArea.anchors.rightMargin: 76
|
||||||
|
|
||||||
color: Style.current.textColor
|
onEnterPressed: submitBtn.clicked()
|
||||||
|
|
||||||
Keys.onReturnPressed: {
|
|
||||||
submitBtn.clicked()
|
|
||||||
}
|
|
||||||
KeyNavigation.priority: KeyNavigation.BeforeItem
|
|
||||||
KeyNavigation.tab: submitBtn
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
visible: errorText.text === ""
|
|
||||||
text: Utils.seedPhraseWordCountText(mnemonicTextField.text)
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.top: mnemonicTextField.bottom
|
|
||||||
anchors.topMargin: Style.current.smallPadding
|
|
||||||
color: correctWordCount ? Style.current.textColor : Style.current.secondaryText
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
id: errorText
|
|
||||||
visible: !!text && text != ""
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
color: Style.current.danger
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.top: mnemonicTextField.bottom
|
|
||||||
anchors.topMargin: Style.current.smallPadding
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
|
@ -92,13 +50,15 @@ ModalPopup {
|
||||||
icon.name: "arrow-right"
|
icon.name: "arrow-right"
|
||||||
icon.width: 20
|
icon.width: 20
|
||||||
icon.height: 16
|
icon.height: 16
|
||||||
enabled: correctWordCount
|
enabled: seedPhraseTextArea.correctWordCount
|
||||||
|
|
||||||
onClicked : {
|
onClicked : {
|
||||||
if (mnemonicTextField.text === "") {
|
if (seedPhraseTextArea.textArea.text === "") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
onConfirmSeedClick(mnemonicTextField.text)
|
if (seedPhraseTextArea.validateSeed()) {
|
||||||
|
onConfirmSeedClick(seedPhraseTextArea.textArea.text)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,27 +15,11 @@ Item {
|
||||||
property bool wentNext: false
|
property bool wentNext: false
|
||||||
id: enterSeedPhraseModal
|
id: enterSeedPhraseModal
|
||||||
onConfirmSeedClick: function (mnemonic) {
|
onConfirmSeedClick: function (mnemonic) {
|
||||||
error = "";
|
wentNext = true
|
||||||
|
enterSeedPhraseModal.close()
|
||||||
if (!Utils.isMnemonic(mnemonic)) {
|
onboardingModel.importMnemonic(mnemonic)
|
||||||
//% "Invalid seed phrase"
|
removeMnemonicAfterLogin = true
|
||||||
error = qsTrId("custom-seed-phrase")
|
recoverySuccessModal.open()
|
||||||
} else {
|
|
||||||
error = onboardingModel.validateMnemonic(mnemonic)
|
|
||||||
const regex = new RegExp('word [a-z]+ not found in the dictionary', 'i');
|
|
||||||
if (regex.test(error)) {
|
|
||||||
error = qsTr('Invalid seed phrase') + '. ' +
|
|
||||||
qsTr("This seed phrase doesn't match our supported dictionary. Check for misspelled words.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error === "") {
|
|
||||||
wentNext = true
|
|
||||||
enterSeedPhraseModal.close()
|
|
||||||
onboardingModel.importMnemonic(mnemonic)
|
|
||||||
removeMnemonicAfterLogin = true
|
|
||||||
recoverySuccessModal.open()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
onClosed: function () {
|
onClosed: function () {
|
||||||
if (!wentNext) {
|
if (!wentNext) {
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
import QtQuick 2.13
|
||||||
|
import QtQuick.Controls 2.13
|
||||||
|
import "../imports"
|
||||||
|
import "../shared"
|
||||||
|
|
||||||
|
Item {
|
||||||
|
property bool correctWordCount: Utils.seedPhraseValidWordCount(mnemonicTextField.text)
|
||||||
|
property alias textArea: mnemonicTextField.textField
|
||||||
|
signal enterPressed()
|
||||||
|
property var nextComponentTab
|
||||||
|
property bool hideRectangle: false
|
||||||
|
|
||||||
|
id: root
|
||||||
|
// Width controlled by parent component
|
||||||
|
height: childrenRect.height
|
||||||
|
|
||||||
|
function validateSeed() {
|
||||||
|
errorText.text = "";
|
||||||
|
|
||||||
|
if (!Utils.isMnemonic(mnemonicTextField.textField.text)) {
|
||||||
|
//% "Invalid seed phrase"
|
||||||
|
errorText.text = qsTrId("custom-seed-phrase")
|
||||||
|
} else {
|
||||||
|
errorText.text = onboardingModel.validateMnemonic(mnemonicTextField.textField.text)
|
||||||
|
const regex = new RegExp('word [a-z]+ not found in the dictionary', 'i');
|
||||||
|
if (regex.test(errorText.text)) {
|
||||||
|
errorText.text = qsTr('Invalid seed phrase') + '. ' +
|
||||||
|
qsTr("This seed phrase doesn't match our supported dictionary. Check for misspelled words.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return errorText.text === ""
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledTextArea {
|
||||||
|
id: mnemonicTextField
|
||||||
|
customHeight: 100
|
||||||
|
hideRectangle: root.hideRectangle
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
textField.wrapMode: Text.WordWrap
|
||||||
|
textField.horizontalAlignment: TextEdit.AlignHCenter
|
||||||
|
textField.verticalAlignment: TextEdit.AlignVCenter
|
||||||
|
textField.font.pixelSize: 15
|
||||||
|
textField.font.weight: Font.DemiBold
|
||||||
|
//% "Start with the first word"
|
||||||
|
placeholderText: qsTrId("start-with-the-first-word")
|
||||||
|
textField.placeholderTextColor: Style.current.secondaryText
|
||||||
|
textField.selectByMouse: true
|
||||||
|
textField.selectByKeyboard: true
|
||||||
|
textField.selectionColor: Style.current.secondaryBackground
|
||||||
|
textField.selectedTextColor: Style.current.secondaryText
|
||||||
|
|
||||||
|
onKeyPressed: {
|
||||||
|
if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) {
|
||||||
|
event.accepted = true
|
||||||
|
root.enterPressed()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
errorText.text = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
textField.color: Style.current.textColor
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
visible: errorText.text === ""
|
||||||
|
text: Utils.seedPhraseWordCountText(mnemonicTextField.textField.text)
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: mnemonicTextField.bottom
|
||||||
|
anchors.topMargin: Style.current.smallPadding
|
||||||
|
color: correctWordCount ? Style.current.textColor : Style.current.secondaryText
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
id: errorText
|
||||||
|
visible: !!text && text !== ""
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
color: Style.current.danger
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: mnemonicTextField.bottom
|
||||||
|
anchors.topMargin: Style.current.smallPadding
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,8 @@ Item {
|
||||||
}
|
}
|
||||||
readonly property int labelMargin: 7
|
readonly property int labelMargin: 7
|
||||||
property int customHeight: 44
|
property int customHeight: 44
|
||||||
|
property bool hideRectangle: false
|
||||||
|
signal keyPressed(var event)
|
||||||
|
|
||||||
id: inputBox
|
id: inputBox
|
||||||
height: inputRectangle.height + (hasLabel ? inputLabel.height + labelMargin : 0) + (!!validationError ? validationErrorText.height : 0)
|
height: inputRectangle.height + (hasLabel ? inputLabel.height + labelMargin : 0) + (!!validationError ? validationErrorText.height : 0)
|
||||||
|
@ -37,13 +39,13 @@ Item {
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: inputRectangle
|
id: inputRectangle
|
||||||
height: customHeight
|
height: customHeight
|
||||||
color: bgColor
|
color: hideRectangle ? Style.current.transparent : bgColor
|
||||||
radius: Style.current.radius
|
radius: Style.current.radius
|
||||||
anchors.top: inputBox.hasLabel ? inputLabel.bottom : parent.top
|
anchors.top: inputBox.hasLabel ? inputLabel.bottom : parent.top
|
||||||
anchors.topMargin: inputBox.hasLabel ? inputBox.labelMargin : 0
|
anchors.topMargin: inputBox.hasLabel ? inputBox.labelMargin : 0
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
border.width: !!validationError ? 1 : 0
|
border.width: !!validationError && !hideRectangle ? 1 : 0
|
||||||
border.color: Style.current.red
|
border.color: Style.current.red
|
||||||
|
|
||||||
TextArea {
|
TextArea {
|
||||||
|
@ -61,6 +63,8 @@ Item {
|
||||||
color: Style.current.textColor
|
color: Style.current.textColor
|
||||||
placeholderTextColor: Style.current.darkGrey
|
placeholderTextColor: Style.current.darkGrey
|
||||||
selectionColor: Style.current.primarySelectionColor
|
selectionColor: Style.current.primarySelectionColor
|
||||||
|
|
||||||
|
Keys.onPressed: inputBox.keyPressed(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
|
|
Loading…
Reference in New Issue