feat(@desktop/Wallet): Add acccounts Modal as per new design
fixes #5073
This commit is contained in:
parent
b732ad6e5c
commit
2852d70731
|
@ -1 +1 @@
|
|||
Subproject commit b2ac2794bbee350539e20d95f1e3adf626e8feb7
|
||||
Subproject commit 46dfd594dfa889448fbeefc9a011bea38042f41e
|
|
@ -25,7 +25,7 @@ Rectangle {
|
|||
|
||||
RowLayout {
|
||||
anchors.centerIn: parent
|
||||
height: sendBtn.height
|
||||
height: parent.height
|
||||
spacing: Style.current.padding
|
||||
|
||||
StatusFlatButton {
|
||||
|
|
|
@ -0,0 +1,224 @@
|
|||
import QtQuick 2.13
|
||||
import QtQuick.Controls 2.13
|
||||
import QtQuick.Dialogs 1.3
|
||||
import QtQuick.Layouts 1.14
|
||||
|
||||
import utils 1.0
|
||||
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
import StatusQ.Core.Utils 0.1 as StatusQUtils
|
||||
import StatusQ.Controls 0.1
|
||||
import StatusQ.Controls.Validators 0.1
|
||||
import StatusQ.Popups 0.1
|
||||
import StatusQ.Components 0.1
|
||||
|
||||
import shared.controls 1.0
|
||||
|
||||
import "../stores"
|
||||
import "../views"
|
||||
|
||||
StatusModal {
|
||||
id: popup
|
||||
|
||||
property int marginBetweenInputs: 38
|
||||
property string passwordValidationError: ""
|
||||
property bool loading: false
|
||||
property var emojiPopup: null
|
||||
|
||||
signal afterAddAccount()
|
||||
|
||||
//% "Generate an account"
|
||||
header.title: qsTrId("generate-a-new-account")
|
||||
|
||||
function validate() {
|
||||
if (passwordInput.text === "") {
|
||||
//% "You need to enter a password"
|
||||
passwordValidationError = qsTrId("you-need-to-enter-a-password")
|
||||
} else if (passwordInput.text.length < 6) {
|
||||
//% "Password needs to be 6 characters or more"
|
||||
passwordValidationError = qsTrId("password-needs-to-be-6-characters-or-more")
|
||||
} else {
|
||||
passwordValidationError = ""
|
||||
}
|
||||
return passwordValidationError === "" && accountNameInput.valid
|
||||
}
|
||||
|
||||
onOpened: {
|
||||
passwordValidationError = "";
|
||||
passwordInput.text = "";
|
||||
accountNameInput.text = "";
|
||||
accountNameInput.reset()
|
||||
accountNameInput.input.icon.emoji = StatusQUtils.Emoji.getRandomEmoji()
|
||||
colorSelectionGrid.selectedColorIndex = Math.floor(Math.random() * colorSelectionGrid.model.length)
|
||||
advancedSelection.expanded = false
|
||||
advancedSelection.reset()
|
||||
passwordInput.forceActiveFocus(Qt.MouseFocusReason)
|
||||
}
|
||||
|
||||
Connections {
|
||||
enabled: popup.opened
|
||||
target: emojiPopup
|
||||
onEmojiSelected: function (emojiText, atCursor) {
|
||||
accountNameInput.input.icon.emoji = emojiText
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: ScrollView {
|
||||
width: popup.width
|
||||
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
|
||||
topPadding: Style.current.halfPadding
|
||||
bottomPadding: Style.current.halfPadding
|
||||
height: 400
|
||||
clip: true
|
||||
|
||||
Column {
|
||||
property alias accountNameInput: accountNameInput
|
||||
width: popup.width
|
||||
spacing: Style.current.halfPadding
|
||||
topPadding: 20
|
||||
|
||||
// To-Do Password hidden option not supported in StatusQ StatusBaseInput
|
||||
Item {
|
||||
width: parent.width
|
||||
height: passwordInput.height
|
||||
Input {
|
||||
id: passwordInput
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: Style.current.padding
|
||||
anchors.rightMargin: Style.current.padding
|
||||
|
||||
//% "Enter your password…"
|
||||
placeholderText: qsTrId("enter-your-password…")
|
||||
//% "Password"
|
||||
label: qsTrId("password")
|
||||
textField.echoMode: TextInput.Password
|
||||
validationError: popup.passwordValidationError
|
||||
inputLabel.font.pixelSize: 15
|
||||
inputLabel.font.weight: Font.Normal
|
||||
}
|
||||
}
|
||||
|
||||
StatusInput {
|
||||
id: accountNameInput
|
||||
//% "Enter an account name..."
|
||||
input.placeholderText: qsTrId("enter-an-account-name...")
|
||||
//% "Account name"
|
||||
label: qsTrId("account-name")
|
||||
input.isIconSelectable: true
|
||||
input.icon.color: colorSelectionGrid.selectedColor ? colorSelectionGrid.selectedColor : Theme.palette.directColor1
|
||||
onIconClicked: {
|
||||
popup.emojiPopup.open()
|
||||
popup.emojiPopup.x = popup.x + accountNameInput.x + Style.current.padding
|
||||
popup.emojiPopup.y = popup.y + contentItem.y + accountNameInput.y + accountNameInput.height + Style.current.halfPadding
|
||||
}
|
||||
validators: [
|
||||
StatusMinLengthValidator {
|
||||
//% "You need to enter an account name"
|
||||
errorMessage: qsTrId("you-need-to-enter-an-account-name")
|
||||
minLength: 1
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
StatusColorSelectorGrid {
|
||||
id: colorSelectionGrid
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
//% "color"
|
||||
titleText: qsTr("color").toUpperCase()
|
||||
}
|
||||
|
||||
StatusExpandableItem {
|
||||
id: advancedSelection
|
||||
|
||||
property bool isValid: true
|
||||
|
||||
function validate() {
|
||||
if(expandableItem) {
|
||||
return expandableItem.validate()
|
||||
}
|
||||
}
|
||||
|
||||
function reset() {
|
||||
if(expandableItem) {
|
||||
return expandableItem.reset()
|
||||
}
|
||||
}
|
||||
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: parent.width
|
||||
|
||||
//% "Advanced"
|
||||
primaryText: qsTr("Advanced")
|
||||
type: StatusExpandableItem.Type.Tertiary
|
||||
expandable: true
|
||||
expandableComponent: AdvancedAddAccountView {
|
||||
width: parent.width
|
||||
Layout.margins: Style.current.padding
|
||||
Component.onCompleted: advancedSelection.isValid = Qt.binding(function(){return isValid})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rightButtons: [
|
||||
StatusButton {
|
||||
id: nextButton
|
||||
text: loading ?
|
||||
//% "Loading..."
|
||||
qsTrId("loading") :
|
||||
//% "Add account"
|
||||
qsTrId("add-account")
|
||||
|
||||
enabled: !loading && passwordInput.text !== "" && accountNameInput.text !== "" && advancedSelection.isValid
|
||||
|
||||
MessageDialog {
|
||||
id: accountError
|
||||
title: "Adding the account failed"
|
||||
icon: StandardIcon.Critical
|
||||
standardButtons: StandardButton.Ok
|
||||
}
|
||||
|
||||
onClicked : {
|
||||
// TODO the loaidng doesn't work because the function freezes th eview. Might need to use threads
|
||||
loading = true
|
||||
if (!validate() || !advancedSelection.validate()) {
|
||||
Global.playErrorSound();
|
||||
return loading = false
|
||||
}
|
||||
|
||||
var errMessage = ""
|
||||
if(advancedSelection.expandableItem) {
|
||||
switch(advancedSelection.expandableItem.addAccountType) {
|
||||
case AdvancedAddAccountView.AddAccountType.GenerateNew:
|
||||
errMessage = RootStore.generateNewAccount(passwordInput.text, accountNameInput.text, colorSelectionGrid.selectedColor, accountNameInput.input.icon.emoji)
|
||||
break
|
||||
case AdvancedAddAccountView.AddAccountType.ImportSeedPhrase:
|
||||
errMessage = RootStore.addAccountsFromSeed(advancedSelection.expandableItem.mnemonicText, passwordInput.text, accountNameInput.text, colorSelectionGrid.selectedColor, accountNameInput.input.icon.emoji)
|
||||
break
|
||||
case AdvancedAddAccountView.AddAccountType.ImportPrivateKey:
|
||||
errMessage = RootStore.addAccountsFromPrivateKey(advancedSelection.expandableItem.privateKey, passwordInput.text, accountNameInput.text, colorSelectionGrid.selectedColor, accountNameInput.input.icon.emoji)
|
||||
break
|
||||
}
|
||||
} else {
|
||||
errMessage = RootStore.generateNewAccount(passwordInput.text, accountNameInput.text, colorSelectionGrid.selectedColor, accountNameInput.input.icon.emoji)
|
||||
}
|
||||
|
||||
loading = false
|
||||
if (errMessage) {
|
||||
Global.playErrorSound();
|
||||
if (Utils.isInvalidPasswordMessage(errMessage)) {
|
||||
//% "Wrong password"
|
||||
popup.passwordValidationError = qsTrId("wrong-password")
|
||||
} else {
|
||||
accountError.text = errMessage;
|
||||
accountError.open();
|
||||
}
|
||||
return
|
||||
}
|
||||
popup.afterAddAccount();
|
||||
popup.close();
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,211 +0,0 @@
|
|||
import QtQuick 2.13
|
||||
import QtQuick.Controls 2.13
|
||||
import QtQuick.Dialogs 1.3
|
||||
|
||||
import utils 1.0
|
||||
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
import StatusQ.Controls 0.1
|
||||
import StatusQ.Popups 0.1
|
||||
import StatusQ.Controls.Validators 0.1
|
||||
import StatusQ.Core.Utils 0.1 as StatusQUtils
|
||||
|
||||
import shared.panels 1.0
|
||||
import shared.controls 1.0
|
||||
|
||||
import "../stores"
|
||||
|
||||
StatusModal {
|
||||
id: popup
|
||||
|
||||
property int marginBetweenInputs: 38
|
||||
property string passwordValidationError: ""
|
||||
property string privateKeyValidationError: ""
|
||||
property bool loading: false
|
||||
property var emojiPopup: null
|
||||
|
||||
signal afterAddAccount()
|
||||
|
||||
function validate() {
|
||||
if (passwordInput.text === "") {
|
||||
//% "You need to enter a password"
|
||||
passwordValidationError = qsTrId("you-need-to-enter-a-password")
|
||||
} else if (passwordInput.text.length < 6) {
|
||||
//% "Password needs to be 6 characters or more"
|
||||
passwordValidationError = qsTrId("password-needs-to-be-6-characters-or-more")
|
||||
} else {
|
||||
passwordValidationError = ""
|
||||
}
|
||||
|
||||
if (accountPKeyInput.text === "") {
|
||||
//% "You need to enter a private key"
|
||||
privateKeyValidationError = qsTrId("you-need-to-enter-a-private-key")
|
||||
} else if (!Utils.isPrivateKey(accountPKeyInput.text)) {
|
||||
//% "Enter a valid private key (64 characters hexadecimal string)"
|
||||
privateKeyValidationError = qsTrId("enter-a-valid-private-key-(64-characters-hexadecimal-string)")
|
||||
} else {
|
||||
privateKeyValidationError = ""
|
||||
}
|
||||
|
||||
return passwordValidationError === "" && privateKeyValidationError === "" && accountNameInput.valid
|
||||
}
|
||||
|
||||
//% "Add account from private key"
|
||||
header.title: qsTrId("add-private-key-account")
|
||||
|
||||
onOpened: {
|
||||
passwordInput.text = ""
|
||||
accountPKeyInput.text = ""
|
||||
accountNameInput.reset()
|
||||
accountNameInput.text = ""
|
||||
accountNameInput.input.icon.emoji = StatusQUtils.Emoji.getRandomEmoji()
|
||||
passwordValidationError = ""
|
||||
privateKeyValidationError = ""
|
||||
accountColorInput.selectedColorIndex = Math.floor(Math.random() * accountColorInput.model.length)
|
||||
passwordInput.forceActiveFocus(Qt.MouseFocusReason)
|
||||
}
|
||||
|
||||
Connections {
|
||||
enabled: popup.opened
|
||||
target: emojiPopup
|
||||
onEmojiSelected: function (emojiText, atCursor) {
|
||||
popup.contentItem.accountNameInput.input.icon.emoji = emojiText
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: Column {
|
||||
property alias accountNameInput: accountNameInput
|
||||
|
||||
width: popup.width
|
||||
spacing: 8
|
||||
topPadding: 20
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Style.current.xlPadding
|
||||
// To-Do Password hidden option not supported in StatusQ StatusBaseInput
|
||||
Input {
|
||||
id: passwordInput
|
||||
anchors.leftMargin: Style.current.padding
|
||||
anchors.rightMargin: Style.current.padding
|
||||
width: parent.width
|
||||
|
||||
//% "Enter your password…"
|
||||
placeholderText: qsTrId("enter-your-password…")
|
||||
//% "Password"
|
||||
label: qsTrId("password")
|
||||
textField.echoMode: TextInput.Password
|
||||
validationError: popup.passwordValidationError
|
||||
inputLabel.font.pixelSize: 15
|
||||
inputLabel.font.weight: Font.Normal
|
||||
}
|
||||
// To-Do use StatusInput
|
||||
StyledTextArea {
|
||||
id: accountPKeyInput
|
||||
customHeight: 88
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.leftMargin: Style.current.padding
|
||||
anchors.rightMargin: Style.current.padding
|
||||
|
||||
validationError: popup.privateKeyValidationError
|
||||
//% "Private key"
|
||||
label: qsTrId("private-key")
|
||||
textField.wrapMode: Text.WordWrap
|
||||
textField.horizontalAlignment: TextEdit.AlignHCenter
|
||||
textField.verticalAlignment: TextEdit.AlignVCenter
|
||||
textField.font.weight: Font.DemiBold
|
||||
//% "Paste the contents of your private key"
|
||||
placeholderText: qsTrId("paste-the-contents-of-your-private-key")
|
||||
textField.placeholderTextColor: Style.current.secondaryText
|
||||
textField.selectByKeyboard: true
|
||||
textField.selectionColor: Style.current.secondaryBackground
|
||||
textField.selectedTextColor: Style.current.secondaryText
|
||||
}
|
||||
}
|
||||
|
||||
StatusInput {
|
||||
id: accountNameInput
|
||||
//% "Enter an account name..."
|
||||
input.placeholderText: qsTrId("enter-an-account-name...")
|
||||
//% "Account name"
|
||||
label: qsTrId("account-name")
|
||||
input.isIconSelectable: true
|
||||
input.icon.color: accountColorInput.selectedColor ? accountColorInput.selectedColor : Theme.palette.directColor1
|
||||
onIconClicked: {
|
||||
popup.emojiPopup.open()
|
||||
popup.emojiPopup.x = popup.x + Style.current.padding
|
||||
popup.emojiPopup.y = popup.y + contentItem.y + accountNameInput.y + accountNameInput.height + Style.current.halfPadding
|
||||
}
|
||||
validators: [
|
||||
StatusMinLengthValidator {
|
||||
//% "You need to enter an account name"
|
||||
errorMessage: qsTrId("you-need-to-enter-an-account-name")
|
||||
minLength: 1
|
||||
},
|
||||
StatusRegularExpressionValidator {
|
||||
regularExpression: /^[^<>]+$/
|
||||
errorMessage: qsTr("This is not a valid account name")
|
||||
}
|
||||
]
|
||||
charLimit: 40
|
||||
}
|
||||
|
||||
StatusColorSelectorGrid {
|
||||
id: accountColorInput
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
//% "color"
|
||||
titleText: qsTr("color").toUpperCase()
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width
|
||||
height: 8
|
||||
}
|
||||
}
|
||||
|
||||
rightButtons: [
|
||||
StatusButton {
|
||||
text: loading ?
|
||||
//% "Loading..."
|
||||
qsTrId("loading") :
|
||||
//% "Add account"
|
||||
qsTrId("add-account")
|
||||
|
||||
enabled: !loading && passwordInput.text !== "" && accountNameInput.text !== "" && accountNameInput.valid && accountPKeyInput.text !== ""
|
||||
|
||||
MessageDialog {
|
||||
id: accountError
|
||||
title: "Adding the account failed"
|
||||
icon: StandardIcon.Critical
|
||||
standardButtons: StandardButton.Ok
|
||||
}
|
||||
|
||||
onClicked : {
|
||||
// TODO the loaidng doesn't work because the function freezes th eview. Might need to use threads
|
||||
loading = true
|
||||
if (!validate()) {
|
||||
return loading = false
|
||||
}
|
||||
|
||||
const errMessage = RootStore.addAccountsFromPrivateKey(accountPKeyInput.text, passwordInput.text, accountNameInput.text, accountColorInput.selectedColor, accountNameInput.input.icon.emoji)
|
||||
|
||||
loading = false
|
||||
if (errMessage) {
|
||||
Global.playErrorSound();
|
||||
if (Utils.isInvalidPasswordMessage(errMessage)) {
|
||||
//% "Wrong password"
|
||||
popup.passwordValidationError = qsTrId("wrong-password")
|
||||
} else {
|
||||
accountError.text = errMessage
|
||||
accountError.open()
|
||||
}
|
||||
return
|
||||
}
|
||||
popup.afterAddAccount()
|
||||
popup.close();
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,200 +0,0 @@
|
|||
import QtQuick 2.13
|
||||
import QtQuick.Controls 2.13
|
||||
import QtQuick.Dialogs 1.3
|
||||
|
||||
import utils 1.0
|
||||
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
import StatusQ.Controls 0.1
|
||||
import StatusQ.Popups 0.1
|
||||
import StatusQ.Controls.Validators 0.1
|
||||
import StatusQ.Core.Utils 0.1 as StatusQUtils
|
||||
|
||||
import shared.controls 1.0
|
||||
|
||||
import "../stores"
|
||||
|
||||
StatusModal {
|
||||
id: popup
|
||||
|
||||
property string passwordValidationError: ""
|
||||
property string seedValidationError: ""
|
||||
property bool loading: false
|
||||
property var emojiPopup: null
|
||||
|
||||
signal afterAddAccount()
|
||||
|
||||
function reset() {
|
||||
passwordInput.text = ""
|
||||
accountNameInput.text = ""
|
||||
seedPhraseTextArea.textArea.text = ""
|
||||
}
|
||||
|
||||
function validate() {
|
||||
if (passwordInput.text === "") {
|
||||
//% "You need to enter a password"
|
||||
passwordValidationError = qsTrId("you-need-to-enter-a-password")
|
||||
} else if (passwordInput.text.length < 6) {
|
||||
//% "Password needs to be 6 characters or more"
|
||||
passwordValidationError = qsTrId("password-needs-to-be-6-characters-or-more")
|
||||
} else {
|
||||
passwordValidationError = ""
|
||||
}
|
||||
|
||||
if (seedPhraseTextArea.textArea.text === "") {
|
||||
//% "You need to enter a seed phrase"
|
||||
seedValidationError = qsTrId("you-need-to-enter-a-seed-phrase")
|
||||
} else if (!Utils.isMnemonic(seedPhraseTextArea.textArea.text)) {
|
||||
//% "Enter a valid mnemonic"
|
||||
seedValidationError = qsTrId("enter-a-valid-mnemonic")
|
||||
} else {
|
||||
seedValidationError = ""
|
||||
}
|
||||
|
||||
return passwordValidationError === "" && seedValidationError === "" && accountNameInput.valid
|
||||
}
|
||||
|
||||
//% "Add account with a seed phrase"
|
||||
header.title: qsTrId("add-seed-account")
|
||||
|
||||
onOpened: {
|
||||
seedPhraseTextArea.textArea.text = ""
|
||||
passwordInput.text = ""
|
||||
accountNameInput.text = ""
|
||||
accountNameInput.reset()
|
||||
accountNameInput.input.icon.emoji = StatusQUtils.Emoji.getRandomEmoji()
|
||||
passwordValidationError = ""
|
||||
seedValidationError = ""
|
||||
accountColorInput.selectedColorIndex = Math.floor(Math.random() * accountColorInput.model.length)
|
||||
passwordInput.forceActiveFocus(Qt.MouseFocusReason)
|
||||
}
|
||||
|
||||
Connections {
|
||||
enabled: popup.opened
|
||||
target: emojiPopup
|
||||
onEmojiSelected: function (emojiText, atCursor) {
|
||||
popup.contentItem.accountNameInput.input.icon.emoji = emojiText
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: Column {
|
||||
property alias accountNameInput: accountNameInput
|
||||
|
||||
width: popup.width
|
||||
spacing: 8
|
||||
topPadding: 20
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Style.current.xlPadding
|
||||
// To-Do Password hidden option not supported in StatusQ StatusBaseInput
|
||||
Input {
|
||||
id: passwordInput
|
||||
anchors.leftMargin: Style.current.padding
|
||||
anchors.rightMargin: Style.current.padding
|
||||
width: parent.width
|
||||
|
||||
//% "Enter your password…"
|
||||
placeholderText: qsTrId("enter-your-password…")
|
||||
//% "Password"
|
||||
label: qsTrId("password")
|
||||
textField.echoMode: TextInput.Password
|
||||
validationError: popup.passwordValidationError
|
||||
inputLabel.font.pixelSize: 15
|
||||
inputLabel.font.weight: Font.Normal
|
||||
}
|
||||
// To-Do use StatusInput
|
||||
SeedPhraseTextArea {
|
||||
id: seedPhraseTextArea
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Style.current.padding
|
||||
width: parent.width - 2*Style.current.padding
|
||||
}
|
||||
}
|
||||
|
||||
StatusInput {
|
||||
id: accountNameInput
|
||||
//% "Enter an account name..."
|
||||
input.placeholderText: qsTrId("enter-an-account-name...")
|
||||
//% "Account name"
|
||||
label: qsTrId("account-name")
|
||||
input.isIconSelectable: true
|
||||
input.icon.color: accountColorInput.selectedColor ? accountColorInput.selectedColor : Theme.palette.directColor1
|
||||
onIconClicked: {
|
||||
popup.emojiPopup.open()
|
||||
popup.emojiPopup.x = popup.x + Style.current.padding
|
||||
popup.emojiPopup.y = popup.y + contentItem.y + accountNameInput.y + accountNameInput.height + Style.current.halfPadding
|
||||
}
|
||||
validators: [
|
||||
StatusMinLengthValidator {
|
||||
//% "You need to enter an account name"
|
||||
errorMessage: qsTrId("you-need-to-enter-an-account-name")
|
||||
minLength: 1
|
||||
},
|
||||
StatusRegularExpressionValidator {
|
||||
regularExpression: /^[^<>]+$/
|
||||
errorMessage: qsTr("This is not a valid account name")
|
||||
}
|
||||
]
|
||||
charLimit: 40
|
||||
}
|
||||
|
||||
StatusColorSelectorGrid {
|
||||
id: accountColorInput
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
//% "color"
|
||||
titleText: qsTr("color").toUpperCase()
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width
|
||||
height: 8
|
||||
}
|
||||
}
|
||||
|
||||
rightButtons: [
|
||||
StatusButton {
|
||||
text: loading ?
|
||||
//% "Loading..."
|
||||
qsTrId("loading") :
|
||||
//% "Add account"
|
||||
qsTrId("add-account")
|
||||
|
||||
enabled: !loading && passwordInput.text !== "" && accountNameInput.text !== "" && accountNameInput.valid && seedPhraseTextArea.correctWordCount
|
||||
|
||||
MessageDialog {
|
||||
id: accountError
|
||||
title: "Adding the account failed"
|
||||
icon: StandardIcon.Critical
|
||||
standardButtons: StandardButton.Ok
|
||||
}
|
||||
|
||||
onClicked : {
|
||||
// TODO the loading doesn't work because the function freezes the view. Might need to use threads
|
||||
loading = true
|
||||
if (!validate() || !seedPhraseTextArea.validateSeed()) {
|
||||
Global.playErrorSound();
|
||||
return loading = false
|
||||
}
|
||||
|
||||
const errMessage = RootStore.addAccountsFromSeed(seedPhraseTextArea.textArea.text, passwordInput.text, accountNameInput.text, accountColorInput.selectedColor, accountNameInput.input.icon.emoji)
|
||||
loading = false
|
||||
if (errMessage) {
|
||||
Global.playErrorSound();
|
||||
if (Utils.isInvalidPasswordMessage(errMessage)) {
|
||||
//% "Wrong password"
|
||||
popup.passwordValidationError = qsTrId("wrong-password")
|
||||
} else {
|
||||
accountError.text = errMessage
|
||||
accountError.open()
|
||||
}
|
||||
return
|
||||
}
|
||||
popup.afterAddAccount()
|
||||
popup.reset()
|
||||
popup.close();
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
import QtQuick 2.13
|
||||
import QtQuick.Controls 2.13
|
||||
|
||||
import shared 1.0
|
||||
import shared.popups 1.0
|
||||
|
||||
import utils 1.0
|
||||
|
||||
// TODO: replace with StatusPopupMenu
|
||||
PopupMenu {
|
||||
id: newAccountMenu
|
||||
width: 260
|
||||
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
|
||||
|
||||
signal generateNewAccountTriggered();
|
||||
signal addWatchAccountTriggered();
|
||||
signal enterSeedPhraseTriggered();
|
||||
signal enterPrivateKeyTriggered();
|
||||
|
||||
Action {
|
||||
//% "Generate an account"
|
||||
text: qsTrId("generate-a-new-account")
|
||||
icon.source: Style.svg("generate_account")
|
||||
icon.width: 19
|
||||
icon.height: 19
|
||||
onTriggered: {
|
||||
newAccountMenu.generateNewAccountTriggered();
|
||||
}
|
||||
}
|
||||
Action {
|
||||
//% "Add a watch-only address"
|
||||
text: qsTrId("add-a-watch-account")
|
||||
icon.source: Style.svg("eye")
|
||||
icon.width: 19
|
||||
icon.height: 19
|
||||
onTriggered: {
|
||||
newAccountMenu.addWatchAccountTriggered();
|
||||
}
|
||||
}
|
||||
Action {
|
||||
//% "Enter a seed phrase"
|
||||
text: qsTrId("enter-a-seed-phrase")
|
||||
icon.source: Style.svg("enter_seed_phrase")
|
||||
icon.width: 19
|
||||
icon.height: 19
|
||||
onTriggered: {
|
||||
newAccountMenu.enterSeedPhraseTriggered();
|
||||
}
|
||||
}
|
||||
Action {
|
||||
//% "Enter a private key"
|
||||
text: qsTrId("enter-a-private-key")
|
||||
icon.source: Style.svg("enter_private_key")
|
||||
icon.width: 19
|
||||
icon.height: 19
|
||||
onTriggered: {
|
||||
newAccountMenu.enterPrivateKeyTriggered();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,150 +0,0 @@
|
|||
import QtQuick 2.13
|
||||
import QtQuick.Controls 2.13
|
||||
import QtQuick.Dialogs 1.3
|
||||
|
||||
import utils 1.0
|
||||
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
import StatusQ.Popups 0.1
|
||||
import StatusQ.Controls 0.1
|
||||
import StatusQ.Controls.Validators 0.1
|
||||
import StatusQ.Core.Utils 0.1 as StatusQUtils
|
||||
|
||||
import shared.controls 1.0
|
||||
|
||||
import "../stores"
|
||||
|
||||
StatusModal {
|
||||
id: popup
|
||||
|
||||
property bool loading: false
|
||||
property var emojiPopup: null
|
||||
|
||||
signal afterAddAccount()
|
||||
|
||||
//% "Add a watch-only account"
|
||||
header.title: qsTrId("add-watch-account")
|
||||
|
||||
onOpened: {
|
||||
addressInput.text = ""
|
||||
addressInput.reset()
|
||||
accountNameInput.text = ""
|
||||
accountNameInput.reset()
|
||||
accountNameInput.input.icon.emoji = StatusQUtils.Emoji.getRandomEmoji()
|
||||
accountColorInput.selectedColorIndex = Math.floor(Math.random() * accountColorInput.model.length)
|
||||
addressInput.forceActiveFocus(Qt.MouseFocusReason)
|
||||
}
|
||||
|
||||
Connections {
|
||||
enabled: popup.opened
|
||||
target: emojiPopup
|
||||
onEmojiSelected: function (emojiText, atCursor) {
|
||||
popup.contentItem.accountNameInput.input.icon.emoji = emojiText
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: Column {
|
||||
property alias accountNameInput: accountNameInput
|
||||
|
||||
width: popup.width
|
||||
spacing: 8
|
||||
topPadding: 20
|
||||
|
||||
StatusInput {
|
||||
id: addressInput
|
||||
// TODO add QR code reader for the address
|
||||
//% "Enter address..."
|
||||
input.placeholderText: qsTrId("enter-address...")
|
||||
//% "Account address"
|
||||
label: qsTrId("wallet-key-title")
|
||||
validators: [
|
||||
StatusAddressValidator {
|
||||
//% "This needs to be a valid address (starting with 0x)"
|
||||
errorMessage: qsTrId("this-needs-to-be-a-valid-address-(starting-with-0x)")
|
||||
},
|
||||
StatusMinLengthValidator {
|
||||
//% "You need to enter an address"
|
||||
errorMessage: qsTrId("you-need-to-enter-an-address")
|
||||
minLength: 1
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
StatusInput {
|
||||
id: accountNameInput
|
||||
//% "Enter an account name..."
|
||||
input.placeholderText: qsTrId("enter-an-account-name...")
|
||||
//% "Account name"
|
||||
label: qsTrId("account-name")
|
||||
input.isIconSelectable: true
|
||||
input.icon.color: accountColorInput.selectedColor ? accountColorInput.selectedColor : Theme.palette.directColor1
|
||||
onIconClicked: {
|
||||
popup.emojiPopup.open()
|
||||
popup.emojiPopup.x = popup.x + Style.current.padding
|
||||
popup.emojiPopup.y = popup.y + contentItem.y + accountNameInput.y + accountNameInput.height + Style.current.halfPadding
|
||||
}
|
||||
validators: [
|
||||
StatusMinLengthValidator {
|
||||
//% "You need to enter an account name"
|
||||
errorMessage: qsTrId("you-need-to-enter-an-account-name")
|
||||
minLength: 1
|
||||
},
|
||||
StatusRegularExpressionValidator {
|
||||
regularExpression: /^[^<>]+$/
|
||||
errorMessage: qsTr("This is not a valid account name")
|
||||
}
|
||||
]
|
||||
charLimit: 40
|
||||
}
|
||||
|
||||
StatusColorSelectorGrid {
|
||||
id: accountColorInput
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
//% "color"
|
||||
titleText: qsTr("color").toUpperCase()
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width
|
||||
height: 8
|
||||
}
|
||||
}
|
||||
|
||||
rightButtons: [
|
||||
StatusButton {
|
||||
text: loading ?
|
||||
//% "Loading..."
|
||||
qsTrId("loading") :
|
||||
//% "Add account"
|
||||
qsTrId("add-account")
|
||||
|
||||
enabled: !loading && addressInput.text !== "" && accountNameInput.text !== "" && accountNameInput.valid
|
||||
|
||||
MessageDialog {
|
||||
id: accountError
|
||||
title: "Adding the account failed"
|
||||
icon: StandardIcon.Critical
|
||||
standardButtons: StandardButton.Ok
|
||||
}
|
||||
|
||||
onClicked : {
|
||||
// TODO the loaidng doesn't work because the function freezes th eview. Might need to use threads
|
||||
loading = true
|
||||
if (!addressInput.valid || !accountNameInput.valid) {
|
||||
Global.playErrorSound();
|
||||
return loading = false
|
||||
}
|
||||
const error = RootStore.addWatchOnlyAccount(addressInput.text, accountNameInput.text, accountColorInput.selectedColor, accountNameInput.input.icon.emoji);
|
||||
loading = false
|
||||
if (error) {
|
||||
Global.playErrorSound();
|
||||
accountError.text = error
|
||||
return accountError.open()
|
||||
}
|
||||
popup.afterAddAccount()
|
||||
popup.close();
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,173 +0,0 @@
|
|||
import QtQuick 2.13
|
||||
import QtQuick.Controls 2.13
|
||||
import QtQuick.Dialogs 1.3
|
||||
|
||||
import utils 1.0
|
||||
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
import StatusQ.Core.Utils 0.1 as StatusQUtils
|
||||
import StatusQ.Controls 0.1
|
||||
import StatusQ.Controls.Validators 0.1
|
||||
import StatusQ.Popups 0.1
|
||||
|
||||
import shared.controls 1.0
|
||||
|
||||
import "../stores"
|
||||
|
||||
StatusModal {
|
||||
id: popup
|
||||
|
||||
property int marginBetweenInputs: 38
|
||||
property string passwordValidationError: ""
|
||||
property bool loading: false
|
||||
property var emojiPopup: null
|
||||
|
||||
signal afterAddAccount()
|
||||
|
||||
//% "Generate an account"
|
||||
header.title: qsTrId("generate-a-new-account")
|
||||
|
||||
function validate() {
|
||||
if (passwordInput.text === "") {
|
||||
//% "You need to enter a password"
|
||||
passwordValidationError = qsTrId("you-need-to-enter-a-password")
|
||||
} else if (passwordInput.text.length < 6) {
|
||||
//% "Password needs to be 6 characters or more"
|
||||
passwordValidationError = qsTrId("password-needs-to-be-6-characters-or-more")
|
||||
} else {
|
||||
passwordValidationError = ""
|
||||
}
|
||||
return passwordValidationError === "" && accountNameInput.valid
|
||||
}
|
||||
|
||||
onOpened: {
|
||||
passwordValidationError = "";
|
||||
passwordInput.text = "";
|
||||
accountNameInput.reset()
|
||||
accountNameInput.text = "";
|
||||
accountNameInput.input.icon.emoji = StatusQUtils.Emoji.getRandomEmoji()
|
||||
colorSelectionGrid.selectedColorIndex = Math.floor(Math.random() * colorSelectionGrid.model.length)
|
||||
passwordInput.forceActiveFocus(Qt.MouseFocusReason)
|
||||
}
|
||||
|
||||
Connections {
|
||||
enabled: popup.opened
|
||||
target: emojiPopup
|
||||
onEmojiSelected: function (emojiText, atCursor) {
|
||||
popup.contentItem.accountNameInput.input.icon.emoji = emojiText
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: Column {
|
||||
property alias accountNameInput: accountNameInput
|
||||
width: popup.width
|
||||
spacing: 8
|
||||
topPadding: 20
|
||||
|
||||
// To-Do Password hidden option not supported in StatusQ StatusBaseInput
|
||||
Item {
|
||||
width: parent.width
|
||||
height: passwordInput.height
|
||||
Input {
|
||||
id: passwordInput
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: Style.current.padding
|
||||
anchors.rightMargin: Style.current.padding
|
||||
|
||||
//% "Enter your password…"
|
||||
placeholderText: qsTrId("enter-your-password…")
|
||||
//% "Password"
|
||||
label: qsTrId("password")
|
||||
textField.echoMode: TextInput.Password
|
||||
validationError: popup.passwordValidationError
|
||||
inputLabel.font.pixelSize: 15
|
||||
inputLabel.font.weight: Font.Normal
|
||||
}
|
||||
}
|
||||
|
||||
StatusInput {
|
||||
id: accountNameInput
|
||||
//% "Enter an account name..."
|
||||
input.placeholderText: qsTrId("enter-an-account-name...")
|
||||
//% "Account name"
|
||||
label: qsTrId("account-name")
|
||||
input.isIconSelectable: true
|
||||
input.icon.color: colorSelectionGrid.selectedColor ? colorSelectionGrid.selectedColor : Theme.palette.directColor1
|
||||
onIconClicked: {
|
||||
popup.emojiPopup.open()
|
||||
popup.emojiPopup.x = popup.x + accountNameInput.x + Style.current.padding
|
||||
popup.emojiPopup.y = popup.y + contentItem.y + accountNameInput.y + accountNameInput.height + Style.current.halfPadding
|
||||
}
|
||||
validators: [
|
||||
StatusMinLengthValidator {
|
||||
//% "You need to enter an account name"
|
||||
errorMessage: qsTrId("you-need-to-enter-an-account-name")
|
||||
minLength: 1
|
||||
},
|
||||
StatusRegularExpressionValidator {
|
||||
regularExpression: /^[^<>]+$/
|
||||
errorMessage: qsTr("This is not a valid account name")
|
||||
}
|
||||
]
|
||||
charLimit: 40
|
||||
}
|
||||
|
||||
StatusColorSelectorGrid {
|
||||
id: colorSelectionGrid
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
//% "color"
|
||||
titleText: qsTr("color").toUpperCase()
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width
|
||||
height: 8
|
||||
}
|
||||
}
|
||||
|
||||
rightButtons: [
|
||||
StatusButton {
|
||||
text: loading ?
|
||||
//% "Loading..."
|
||||
qsTrId("loading") :
|
||||
//% "Add account"
|
||||
qsTrId("add-account")
|
||||
|
||||
enabled: !loading && passwordInput.text !== "" && accountNameInput.text !== "" && accountNameInput.valid
|
||||
|
||||
MessageDialog {
|
||||
id: accountError
|
||||
title: "Adding the account failed"
|
||||
icon: StandardIcon.Critical
|
||||
standardButtons: StandardButton.Ok
|
||||
}
|
||||
|
||||
onClicked : {
|
||||
// TODO the loaidng doesn't work because the function freezes th eview. Might need to use threads
|
||||
loading = true
|
||||
if (!validate()) {
|
||||
Global.playErrorSound();
|
||||
return loading = false
|
||||
}
|
||||
|
||||
const errMessage = RootStore.generateNewAccount(passwordInput.text, accountNameInput.text, colorSelectionGrid.selectedColor, accountNameInput.input.icon.emoji)
|
||||
console.log(errMessage)
|
||||
loading = false
|
||||
if (errMessage) {
|
||||
Global.playErrorSound();
|
||||
if (Utils.isInvalidPasswordMessage(errMessage)) {
|
||||
//% "Wrong password"
|
||||
popup.passwordValidationError = qsTrId("wrong-password")
|
||||
} else {
|
||||
accountError.text = errMessage;
|
||||
accountError.open();
|
||||
}
|
||||
return
|
||||
}
|
||||
popup.afterAddAccount();
|
||||
popup.close();
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -8,6 +8,7 @@ QtObject {
|
|||
id: root
|
||||
property var currentAccount: Constants.isCppApp ? walletSectionAccounts.currentAccount: walletSectionCurrent
|
||||
property var accounts: walletSectionAccounts.model
|
||||
property var generatedAccounts: walletSectionAccounts.generated
|
||||
property var appSettings: localAppSettings
|
||||
property var accountSensitiveSettings: localAccountSensitiveSettings
|
||||
property string locale: appSettings.locale
|
||||
|
|
|
@ -0,0 +1,354 @@
|
|||
import QtQuick 2.14
|
||||
import QtQuick.Controls 2.14
|
||||
import QtQuick.Layouts 1.14
|
||||
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
import StatusQ.Controls 0.1
|
||||
import StatusQ.Popups 0.1
|
||||
import StatusQ.Components 0.1
|
||||
import StatusQ.Core.Utils 0.1
|
||||
import StatusQ.Controls.Validators 0.1
|
||||
|
||||
import utils 1.0
|
||||
import "../stores"
|
||||
|
||||
ColumnLayout {
|
||||
id: advancedSection
|
||||
|
||||
property alias privateKey: privateKey.text
|
||||
property int addAccountType: AdvancedAddAccountView.AddAccountType.GenerateNew
|
||||
property string mnemonicText: getSeedPhraseString()
|
||||
property string errorString: ""
|
||||
property bool isValid: addAccountType === AdvancedAddAccountView.AddAccountType.ImportSeedPhrase ? grid.isValid :
|
||||
addAccountType === AdvancedAddAccountView.AddAccountType.ImportPrivateKey ? (privateKey.text !== "" && privateKey.valid) : true
|
||||
|
||||
enum AddAccountType {
|
||||
GenerateNew,
|
||||
ImportSeedPhrase,
|
||||
ImportPrivateKey
|
||||
}
|
||||
|
||||
function reset() {
|
||||
mnemonicText = ""
|
||||
errorString = ""
|
||||
select.currentIndex = 0
|
||||
addAccountType = AdvancedAddAccountView.AddAccountType.GenerateNew
|
||||
privateKey.text = ""
|
||||
privateKey.reset()
|
||||
for(var i = 0; i < grid.model; i++) {
|
||||
if(grid.itemAtIndex(i)) {
|
||||
grid.itemAtIndex(i).textEdit.text = ""
|
||||
grid.itemAtIndex(i).textEdit.reset()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function validate() {
|
||||
errorString = "";
|
||||
if(addAccountType == AdvancedAddAccountView.AddAccountType.ImportSeedPhrase) {
|
||||
mnemonicText = getSeedPhraseString()
|
||||
|
||||
if (!Utils.isMnemonic(mnemonicText)) {
|
||||
//% "Invalid seed phrase"
|
||||
errorString = qsTrId("custom-seed-phrase")
|
||||
} else {
|
||||
errorString = onboardingModule.validateMnemonic(mnemonicText)
|
||||
const regex = new RegExp('word [a-z]+ not found in the dictionary', 'i');
|
||||
if (regex.test(errorString)) {
|
||||
//% "Invalid seed phrase"
|
||||
errorString = qsTrId("custom-seed-phrase") + '. ' +
|
||||
//% "This seed phrase doesn't match our supported dictionary. Check for misspelled words."
|
||||
qsTrId("custom-seed-phrase-text-1")
|
||||
}
|
||||
}
|
||||
return errorString === ""
|
||||
}
|
||||
else if(addAccountType == AdvancedAddAccountView.AddAccountType.ImportPrivateKey) {
|
||||
if (privateKey.text === "") {
|
||||
//% "You need to enter a private key"
|
||||
errorString = qsTrId("you-need-to-enter-a-private-key")
|
||||
} else if (!Utils.isPrivateKey(privateKey.text)) {
|
||||
//% "Enter a valid private key (64 characters hexadecimal string)"
|
||||
errorString = qsTrId("enter-a-valid-private-key-(64-characters-hexadecimal-string)")
|
||||
} else {
|
||||
errorString = ""
|
||||
}
|
||||
return errorString === ""
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
function getSeedPhraseString() {
|
||||
var seedPhrase = ""
|
||||
for(var i = 0; i < grid.model; i++) {
|
||||
seedPhrase += grid.itemAtIndex(i).text + " "
|
||||
}
|
||||
return seedPhrase
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: _internal
|
||||
property int seedPhraseInputHeight: 44
|
||||
property int seedPhraseInputWidth: 220
|
||||
}
|
||||
|
||||
spacing: Style.current.padding
|
||||
|
||||
StatusSelect {
|
||||
id: select
|
||||
//% "Origin"
|
||||
label: qsTr("Origin")
|
||||
Layout.margins: Style.current.padding
|
||||
property int currentIndex: 0
|
||||
selectedItemComponent: StatusListItem {
|
||||
id: selectedItem
|
||||
icon.background.color: "transparent"
|
||||
border.width: 1
|
||||
border.color: Theme.palette.baseColor2
|
||||
tagsDelegate: StatusListItemTag {
|
||||
color: model.color
|
||||
height: Style.current.bigPadding
|
||||
radius: 6
|
||||
closeButtonVisible: false
|
||||
icon.emoji: model.emoji
|
||||
icon.emojiSize: Emoji.size.verySmall
|
||||
icon.isLetterIdenticon: true
|
||||
title: model.name
|
||||
titleText.font.pixelSize: 12
|
||||
titleText.color: Theme.palette.indirectColor1
|
||||
}
|
||||
}
|
||||
model: ListModel {
|
||||
Component.onCompleted: {
|
||||
//% "Default"
|
||||
append({"name": qsTr("Default"), "iconName": "status", "accountsModel": RootStore.generatedAccounts, "enabled": true})
|
||||
//% "Add new"
|
||||
append({"name": qsTr("Add new"), "iconName": "", "enabled": false})
|
||||
//% "Import new Seed Phrase"
|
||||
append({"name": qsTr("Import new Seed Phrase"), "iconName": "seed-phrase", "enabled": true})
|
||||
//% "Import new Private Key"
|
||||
append({"name": qsTr("Import new Private Key"), "iconName": "password", "enabled": true})
|
||||
selectedItem.title = Qt.binding(function() {return get(select.currentIndex).name})
|
||||
selectedItem.icon.name = Qt.binding(function() {return get(select.currentIndex).iconName})
|
||||
selectedItem.tagsModel = Qt.binding(function() {return get(select.currentIndex).accountsModel})
|
||||
}
|
||||
}
|
||||
selectMenu.delegate: StatusListItem {
|
||||
id: defaultListItem
|
||||
title: model.name
|
||||
icon.name: model.iconName
|
||||
tagsModel : model.accountsModel
|
||||
enabled: model.enabled
|
||||
icon.background.color: "transparent"
|
||||
icon.color: model.accountsModel ? Theme.palette.primaryColor1 : Theme.palette.directColor5
|
||||
tagsDelegate: StatusListItemTag {
|
||||
color: model.color
|
||||
height: 24
|
||||
radius: 6
|
||||
closeButtonVisible: false
|
||||
icon.emoji: model.emoji
|
||||
icon.emojiSize: Emoji.size.verySmall
|
||||
icon.isLetterIdenticon: true
|
||||
title: model.name
|
||||
titleText.font.pixelSize: 12
|
||||
titleText.color: Theme.palette.indirectColor1
|
||||
}
|
||||
onClicked: {
|
||||
advancedSection.addAccountType = (index === 2) ? AdvancedAddAccountView.AddAccountType.ImportSeedPhrase :
|
||||
(index === 3) ? AdvancedAddAccountView.AddAccountType.ImportPrivateKey :
|
||||
AdvancedAddAccountView.AddAccountType.GenerateNew
|
||||
select.currentIndex = index
|
||||
select.selectMenu.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StatusInput {
|
||||
id: privateKey
|
||||
//% "Private key"
|
||||
label: qsTrId("private-key")
|
||||
charLimit: 64
|
||||
input.multiline: true
|
||||
input.minimumHeight: 80
|
||||
input.maximumHeight: 108
|
||||
//% "Paste the contents of your private key"
|
||||
input.placeholderText: qsTrId("paste-the-contents-of-your-private-key")
|
||||
visible: advancedSection.addAccountType === AdvancedAddAccountView.AddAccountType.ImportPrivateKey && advancedSection.visible
|
||||
errorMessage: advancedSection.errorString
|
||||
validators: [
|
||||
StatusMinLengthValidator {
|
||||
minLength: 1
|
||||
//% "You need to enter a private key"
|
||||
errorMessage: qsTrId("you-need-to-enter-a-private-key")
|
||||
},
|
||||
StatusValidator {
|
||||
property var validate: function (value) {
|
||||
return Utils.isPrivateKey(value)
|
||||
}
|
||||
//% "Enter a valid private key (64 characters hexadecimal string)"
|
||||
errorMessage: qsTrId("enter-a-valid-private-key-(64-characters-hexadecimal-string)")
|
||||
}
|
||||
]
|
||||
onVisibleChanged: {
|
||||
if(visible)
|
||||
privateKey.input.edit.forceActiveFocus();
|
||||
}
|
||||
}
|
||||
|
||||
GridView {
|
||||
id: grid
|
||||
Layout.preferredWidth: parent.width
|
||||
Layout.preferredHeight: visible ? (cellHeight * model/2) + footerItem.height: 0
|
||||
Layout.leftMargin: Style.current.padding
|
||||
Layout.rightMargin: Style.current.padding
|
||||
visible: advancedSection.addAccountType === AdvancedAddAccountView.AddAccountType.ImportSeedPhrase && advancedSection.visible
|
||||
cellHeight: _internal.seedPhraseInputHeight + Style.current.halfPadding
|
||||
cellWidth: _internal.seedPhraseInputWidth + Style.current.halfPadding
|
||||
model: 12
|
||||
interactive: false
|
||||
property bool isValid: checkIsValid()
|
||||
function checkIsValid() {
|
||||
var valid = model > 0 ? true: false
|
||||
for(var i = 0; i < model; i++) {
|
||||
if(grid.itemAtIndex(i))
|
||||
valid &= grid.itemAtIndex(i).isValid
|
||||
}
|
||||
return valid
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
if(visible)
|
||||
grid.itemAtIndex(0).textEdit.input.edit.forceActiveFocus();
|
||||
}
|
||||
|
||||
// To-do Alex has introduced a model for bip39 dictonary, need to use it once its available
|
||||
// https://github.com/status-im/status-desktop/pull/5058
|
||||
delegate: StatusSeedPhraseInput {
|
||||
id: statusSeedInput
|
||||
width: _internal.seedPhraseInputWidth
|
||||
height: _internal.seedPhraseInputHeight
|
||||
textEdit.errorMessageCmp.visible: false
|
||||
textEdit.input.anchors.topMargin: 11
|
||||
leftComponentText: index + 1
|
||||
property bool isValid: !!text
|
||||
onIsValidChanged: {
|
||||
grid.isValid = grid.checkIsValid()
|
||||
}
|
||||
onTextChanged: {
|
||||
if (text !== "") {
|
||||
grid.currentIndex = index;
|
||||
}
|
||||
}
|
||||
// To-do Alex has introduced a model for bip39 dictonary, need to use it once its available
|
||||
// https://github.com/status-im/status-desktop/pull/5058
|
||||
// onDoneInsertingWord: {
|
||||
// advancedSection.mnemonicText += (index === 0) ? word : (" " + word);
|
||||
// for (var i = !grid.atXBeginning ? 12 : 0; i < grid.count; i++) {
|
||||
// if (parseInt(grid.itemAtIndex(i).leftComponentText) === (parseInt(leftComponentText)+1)) {
|
||||
// grid.itemAtIndex(i).textEdit.input.edit.forceActiveFocus();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
onEditClicked: {
|
||||
grid.currentIndex = index;
|
||||
grid.itemAtIndex(index).textEdit.input.edit.forceActiveFocus();
|
||||
}
|
||||
onKeyPressed: {
|
||||
if (event.key === Qt.Key_Tab || event.key === Qt.Key_Right) {
|
||||
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();
|
||||
textEdit.input.tabNavItem = grid.itemAtIndex(i).textEdit.input.edit;
|
||||
}
|
||||
}
|
||||
} else if (event.key === Qt.Key_Left) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
} else if (event.key === Qt.Key_Down) {
|
||||
grid.itemAtIndex((index+1 < grid.count) ? (index+1) : (grid.count-1)).textEdit.input.edit.forceActiveFocus();
|
||||
} else if (event.key === Qt.Key_Up) {
|
||||
grid.itemAtIndex((index-1 >= 0) ? (index-1) : 0).textEdit.input.edit.forceActiveFocus();
|
||||
}
|
||||
}
|
||||
textEdit.validators: [
|
||||
StatusMinLengthValidator {
|
||||
errorMessage: qsTr("Enter a valid word")
|
||||
minLength: 3
|
||||
}
|
||||
]
|
||||
}
|
||||
footer: Item {
|
||||
width: grid.width - Style.current.padding
|
||||
height: button.height + errorMessage.height + 16*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: errorString
|
||||
|
||||
font.pixelSize: 12
|
||||
color: Theme.palette.dangerColor1
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
StatusButton {
|
||||
id: button
|
||||
anchors.top: errorMessage.bottom
|
||||
anchors.topMargin: Style.current.padding
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
//% "Use 24 word seed phrase"
|
||||
text: grid.model === 12 ? qsTr("Use 24 word seed phrase"):
|
||||
qsTr("Use 12 word seed phrase")
|
||||
onClicked: grid.model = grid.model === 12 ? 24 : 12
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
RowLayout {
|
||||
Layout.margins: Style.current.padding
|
||||
Layout.preferredWidth: parent.width
|
||||
spacing: Style.current.bigPadding
|
||||
StatusSelect {
|
||||
Layout.preferredWidth: 213
|
||||
//% "Origin"
|
||||
label: qsTr("Derivation Path")
|
||||
selectedItemComponent: StatusListItem {
|
||||
width: parent.width
|
||||
icon.background.color: "transparent"
|
||||
border.width: 1
|
||||
border.color: Theme.palette.baseColor2
|
||||
title: "Default"
|
||||
subTitle: "m/44’/61’/0’/1"
|
||||
enabled: false
|
||||
}
|
||||
enabled: false
|
||||
}
|
||||
StatusSelect {
|
||||
Layout.preferredWidth: 213
|
||||
//% "Origin"
|
||||
label: qsTr("Account")
|
||||
width: parent.width
|
||||
enabled: false
|
||||
selectedItemComponent: StatusListItem {
|
||||
icon.background.color: "transparent"
|
||||
border.width: 1
|
||||
border.color: Theme.palette.baseColor2
|
||||
title: "0x1234...abcd"
|
||||
subTitle: "No activity"
|
||||
enabled: false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -10,6 +10,7 @@ import shared.controls 1.0
|
|||
|
||||
import StatusQ.Components 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
import StatusQ.Controls 0.1
|
||||
|
||||
import "../controls"
|
||||
import "../popups"
|
||||
|
@ -73,66 +74,10 @@ Rectangle {
|
|||
font.weight: Font.Medium
|
||||
font.pixelSize: 13
|
||||
}
|
||||
|
||||
AddAccountButton {
|
||||
id: addAccountButton
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
onClicked: {
|
||||
if (newAccountMenu.opened) {
|
||||
newAccountMenu.close()
|
||||
} else {
|
||||
newAccountMenu.popup(addAccountButton.x + addAccountButton.width/2 - newAccountMenu.width/2 ,
|
||||
addAccountButton.y + addAccountButton.height + 55)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AddNewAccountMenu {
|
||||
id: newAccountMenu
|
||||
onAboutToShow: addAccountButton.state = "pressed"
|
||||
onAboutToHide: {
|
||||
addAccountButton.state = "default";
|
||||
addAccountButton.checked = false;
|
||||
}
|
||||
onGenerateNewAccountTriggered: {
|
||||
generateAccountModal.open();
|
||||
}
|
||||
onAddWatchAccountTriggered: {
|
||||
addWatchOnlyAccountModal.open();
|
||||
}
|
||||
onEnterSeedPhraseTriggered: {
|
||||
addAccountWithSeedModal.open();
|
||||
}
|
||||
onEnterPrivateKeyTriggered: {
|
||||
addAccountWithPrivateKeydModal.open();
|
||||
}
|
||||
}
|
||||
|
||||
GenerateAccountModal {
|
||||
id: generateAccountModal
|
||||
anchors.centerIn: parent
|
||||
onAfterAddAccount: walletInfoContainer.onAfterAddAccount()
|
||||
emojiPopup: walletInfoContainer.emojiPopup
|
||||
}
|
||||
|
||||
AddAccountWithSeedModal {
|
||||
id: addAccountWithSeedModal
|
||||
anchors.centerIn: parent
|
||||
onAfterAddAccount: walletInfoContainer.onAfterAddAccount()
|
||||
emojiPopup: walletInfoContainer.emojiPopup
|
||||
}
|
||||
|
||||
AddAccountWithPrivateKeyModal {
|
||||
id: addAccountWithPrivateKeydModal
|
||||
anchors.centerIn: parent
|
||||
onAfterAddAccount: walletInfoContainer.onAfterAddAccount()
|
||||
emojiPopup: walletInfoContainer.emojiPopup
|
||||
}
|
||||
|
||||
AddWatchOnlyAccountModal {
|
||||
id: addWatchOnlyAccountModal
|
||||
AddAccountModal {
|
||||
id: addAccountModal
|
||||
anchors.centerIn: parent
|
||||
onAfterAddAccount: walletInfoContainer.onAfterAddAccount()
|
||||
emojiPopup: walletInfoContainer.emojiPopup
|
||||
|
@ -176,6 +121,20 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
|
||||
footer: Item {
|
||||
width: parent.width
|
||||
height: addAccountBtn.height + Style.current.xlPadding
|
||||
StatusButton {
|
||||
id: addAccountBtn
|
||||
anchors.top: parent.top
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.margins: Style.current.bigPadding
|
||||
//% "Add account"
|
||||
text: qsTrId("add-account")
|
||||
onClicked: addAccountModal.open()
|
||||
}
|
||||
}
|
||||
|
||||
model: RootStore.accounts
|
||||
// model: RootStore.exampleWalletModel
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue