status-desktop/ui/app/AppLayouts/Wallet/popups/AddAccountModal.qml

293 lines
11 KiB
QML

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"
import "../panels"
StatusModal {
id: root
property int minPswLen: 10
readonly property int marginBetweenInputs: 38
readonly property alias passwordValidationError: d.passwordValidationError
property var emojiPopup: null
header.title: qsTr("Generate an account")
closePolicy: Popup.CloseOnEscape
signal afterAddAccount()
Timer {
id: waitTimer
interval: 1000
running: false
onTriggered: d.getDerivedAddressList()
}
Connections {
target: emojiPopup
enabled: root.opened
function onEmojiSelected (emojiText, atCursor) {
accountNameInput.input.asset.emoji = emojiText
}
}
Connections {
target: RootStore
enabled: root.opened
function onDerivedAddressesListChanged() {
d.isPasswordCorrect = RootStore.derivedAddressesError.length === 0
}
function onDerivedAddressesErrorChanged() {
if(Utils.isInvalidPasswordMessage(RootStore.derivedAddressesError))
d.passwordValidationError = qsTr("Password must be at least %n character(s) long", "", root.minPswLen);
}
}
QtObject {
id: d
readonly property int numOfItems: 100
readonly property int pageNumber: 1
property string passwordValidationError: ""
property bool isPasswordCorrect: false
function getDerivedAddressList() {
if(advancedSelection.expandableItem.addAccountType === SelectGeneratedAccount.AddAccountType.ImportSeedPhrase
&& !!advancedSelection.expandableItem.path
&& !!advancedSelection.expandableItem.mnemonicText) {
RootStore.getDerivedAddressListForMnemonic(advancedSelection.expandableItem.mnemonicText,
advancedSelection.expandableItem.path, numOfItems, pageNumber)
} else if(!!advancedSelection.expandableItem.path && !!advancedSelection.expandableItem.derivedFromAddress
&& (passwordInput.text.length > 0)) {
RootStore.getDerivedAddressList(passwordInput.text, advancedSelection.expandableItem.derivedFromAddress,
advancedSelection.expandableItem.path, numOfItems, pageNumber)
}
}
function showPasswordError(errMessage) {
if (errMessage) {
if (Utils.isInvalidPasswordMessage(errMessage)) {
d.passwordValidationError = qsTr("Wrong password")
scroll.contentY = -scroll.padding
} else {
console.warn(`Unhandled error case. Status-go message: ${errMessage}`)
}
}
}
function generateNewAccount() {
// TODO the loading doesn't work because the function freezes the view. Might need to use threads
nextButton.loading = true
if (!advancedSelection.validate()) {
Global.playErrorSound()
return nextButton.loading = false
}
let errMessage = ""
switch(advancedSelection.expandableItem.addAccountType) {
case SelectGeneratedAccount.AddAccountType.GenerateNew:
errMessage = RootStore.generateNewAccount(passwordInput.text, accountNameInput.text, colorSelectionGrid.selectedColor,
accountNameInput.input.asset.emoji, advancedSelection.expandableItem.completePath,
advancedSelection.expandableItem.derivedFromAddress)
break
case SelectGeneratedAccount.AddAccountType.ImportSeedPhrase:
errMessage = RootStore.addAccountsFromSeed(advancedSelection.expandableItem.mnemonicText, passwordInput.text,
accountNameInput.text, colorSelectionGrid.selectedColor, accountNameInput.input.asset.emoji,
advancedSelection.expandableItem.completePath)
break
case SelectGeneratedAccount.AddAccountType.ImportPrivateKey:
errMessage = RootStore.addAccountsFromPrivateKey(advancedSelection.expandableItem.privateKey, passwordInput.text,
accountNameInput.text, colorSelectionGrid.selectedColor, accountNameInput.input.asset.emoji)
break
case SelectGeneratedAccount.AddAccountType.WatchOnly:
errMessage = RootStore.addWatchOnlyAccount(advancedSelection.expandableItem.watchAddress, accountNameInput.text,
colorSelectionGrid.selectedColor, accountNameInput.input.asset.emoji)
break
}
nextButton.loading = false
if (errMessage) {
d.showPasswordError(errMessage)
} else {
root.afterAddAccount()
root.close()
}
}
}
onOpened: {
accountNameInput.input.asset.emoji = StatusQUtils.Emoji.getRandomEmoji(StatusQUtils.Emoji.size.verySmall)
colorSelectionGrid.selectedColorIndex = Math.floor(Math.random() * colorSelectionGrid.model.length)
passwordInput.forceActiveFocus(Qt.MouseFocusReason)
}
onClosed: {
d.passwordValidationError = ""
passwordInput.text = ""
accountNameInput.reset()
advancedSelection.expanded = false
advancedSelection.reset()
}
contentItem: StatusScrollView {
id: scroll
width: popup.width
topPadding: Style.current.halfPadding
bottomPadding: Style.current.halfPadding
leftPadding: Style.current.padding
rightPadding: Style.current.padding
height: 400
objectName: "AddAccountModalContent"
Column {
property alias accountNameInput: accountNameInput
width: scroll.availableWidth
spacing: Style.current.halfPadding
topPadding: 20
// To-Do Password hidden option not supported in StatusQ StatusInput
Item {
width: parent.width
height: passwordInput.height
visible: advancedSelection.expandableItem.addAccountType !== SelectGeneratedAccount.AddAccountType.WatchOnly
Input {
id: passwordInput
anchors.fill: parent
placeholderText: qsTr("Enter your password...")
label: qsTr("Password")
textField.echoMode: TextInput.Password
validationError: d.passwordValidationError
textField.objectName: "accountModalPassword"
inputLabel.font.pixelSize: 15
inputLabel.font.weight: Font.Normal
onTextChanged: {
d.isPasswordCorrect = false
d.passwordValidationError = ""
waitTimer.restart()
}
onKeyPressed: {
if(event.key === Qt.Key_Tab) {
accountNameInput.input.edit.forceActiveFocus(Qt.MouseFocusReason)
event.accepted = true
}
}
}
}
StatusInput {
id: accountNameInput
placeholderText: qsTr("Enter an account name...")
label: qsTr("Account name")
input.isIconSelectable: true
input.asset.color: colorSelectionGrid.selectedColor ? colorSelectionGrid.selectedColor : Theme.palette.directColor1
input.leftPadding: Style.current.padding
onIconClicked: {
root.emojiPopup.open()
root.emojiPopup.emojiSize = StatusQUtils.Emoji.size.verySmall
root.emojiPopup.x = root.x + accountNameInput.x + Style.current.padding
root.emojiPopup.y = root.y + contentItem.y + accountNameInput.y + accountNameInput.height + Style.current.halfPadding
}
validators: [
StatusMinLengthValidator {
errorMessage: qsTr("You need to enter an account name")
minLength: 1
}
]
onKeyPressed: {
if(event.key === Qt.Key_Tab) {
if (nextButton.enabled) {
nextButton.forceActiveFocus(Qt.MouseFocusReason)
event.accepted = true
}
}
}
}
StatusColorSelectorGrid {
id: colorSelectionGrid
anchors.horizontalCenter: parent.horizontalCenter
titleText: qsTr("color").toUpperCase()
}
StatusExpandableItem {
id: advancedSelection
property bool isValid: true
function validate() {
return !!expandableItem && expandableItem.validate()
}
function reset() {
return !!expandableItem && expandableItem.reset()
}
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width
primaryText: qsTr("Advanced")
type: StatusExpandableItem.Type.Tertiary
expandable: true
expandableComponent: AdvancedAddAccountView {
width: parent.width
onCalculateDerivedPath: d.getDerivedAddressList()
onEnterPressed: {
if (nextButton.enabled) {
nextButton.clicked(null)
return
}
}
Component.onCompleted: advancedSelection.isValid = Qt.binding(() => isValid)
}
}
}
}
rightButtons: [
StatusButton {
id: nextButton
text: loading ? qsTr("Loading...") : qsTr("Add account")
enabled: {
if (loading) {
return false
}
return (advancedSelection.expandableItem.addAccountType === SelectGeneratedAccount.AddAccountType.WatchOnly || d.isPasswordCorrect)
&& accountNameInput.text !== "" && advancedSelection.isValid
}
highlighted: focus
Keys.onReturnPressed: d.generateNewAccount()
onClicked : d.generateNewAccount()
}
]
}