353 lines
14 KiB
QML
353 lines
14 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
|
|
|
|
readonly property int marginBetweenInputs: 38
|
|
property var emojiPopup: null
|
|
|
|
header.title: qsTr("Generate an account")
|
|
closePolicy: nextButton.loading? Popup.NoAutoClose : Popup.CloseOnEscape
|
|
hasCloseButton: !nextButton.loading
|
|
|
|
signal afterAddAccount()
|
|
|
|
Connections {
|
|
target: emojiPopup
|
|
enabled: root.opened
|
|
|
|
function onEmojiSelected (emojiText, atCursor) {
|
|
accountNameInput.input.asset.emoji = emojiText
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: walletSectionAccounts
|
|
function onUserAuthenticationSuccess(password: string) {
|
|
validationError.text = ""
|
|
d.password = password
|
|
RootStore.loggedInUserAuthenticated = true
|
|
if (d.selectedAccountType === Constants.AddAccountType.ImportPrivateKey) {
|
|
d.generateNewAccount()
|
|
}
|
|
else {
|
|
if (!d.selectedKeyUidMigratedToKeycard) {
|
|
d.getDerivedAddressList()
|
|
}
|
|
}
|
|
}
|
|
function onUserAuthentiactionFail() {
|
|
d.password = ""
|
|
RootStore.loggedInUserAuthenticated = false
|
|
validationError.text = qsTr("An authentication failed")
|
|
nextButton.loading = false
|
|
}
|
|
}
|
|
|
|
QtObject {
|
|
id: d
|
|
|
|
readonly property int numOfItems: 100
|
|
readonly property int pageNumber: 1
|
|
|
|
property string password: ""
|
|
property int selectedAccountType: Constants.AddAccountType.GenerateNew
|
|
property string selectedAccountDerivedFromAddress: ""
|
|
property string selectedKeyUid: RootStore.defaultSelectedKeyUid
|
|
property bool selectedKeyUidMigratedToKeycard: RootStore.defaultSelectedKeyUidMigratedToKeycard
|
|
property string selectedPath: ""
|
|
property string selectedAddress: ""
|
|
property bool selectedAddressAvailable: false
|
|
property bool useFullyCustomPath: false
|
|
|
|
readonly property bool authenticationNeeded: d.selectedAccountType !== Constants.AddAccountType.WatchOnly &&
|
|
d.password === ""
|
|
property string addAccountIcon: ""
|
|
|
|
property bool isLoading: RootStore.derivedAddressesLoading
|
|
onIsLoadingChanged: {
|
|
if(!isLoading && nextButton.loading) {
|
|
d.generateNewAccount()
|
|
}
|
|
}
|
|
|
|
function getDerivedAddressList() {
|
|
if (d.useFullyCustomPath) {
|
|
if(!!d.selectedPath && !!d.selectedAccountDerivedFromAddress
|
|
&& (d.password.length > 0)) {
|
|
RootStore.getDerivedAddressList(d.password, d.selectedAccountDerivedFromAddress,
|
|
d.selectedPath, numOfItems, pageNumber,
|
|
!(d.selectedKeyUidMigratedToKeycard || userProfile.isKeycardUser))
|
|
}
|
|
} else if(d.selectedAccountType === Constants.AddAccountType.ImportSeedPhrase
|
|
&& !!advancedSelection.expandableItem.path
|
|
&& !!advancedSelection.expandableItem.mnemonicText) {
|
|
RootStore.getDerivedAddressListForMnemonic(advancedSelection.expandableItem.mnemonicText,
|
|
advancedSelection.expandableItem.path, numOfItems, pageNumber)
|
|
} else if(!!d.selectedPath && !!d.selectedAccountDerivedFromAddress
|
|
&& (d.password.length > 0)) {
|
|
RootStore.getDerivedAddress(d.password, d.selectedAccountDerivedFromAddress, d.selectedPath,
|
|
!(d.selectedKeyUidMigratedToKeycard || userProfile.isKeycardUser))
|
|
}
|
|
}
|
|
|
|
function generateNewAccount() {
|
|
// TODO the loading doesn't work because the function freezes the view. Might need to use threads
|
|
if (!advancedSelection.validate()) {
|
|
Global.playErrorSound()
|
|
return nextButton.loading = false
|
|
}
|
|
|
|
let errMessage = ""
|
|
|
|
switch(d.selectedAccountType) {
|
|
case Constants.AddAccountType.GenerateNew:
|
|
if (d.selectedKeyUidMigratedToKeycard) {
|
|
errMessage = RootStore.addNewWalletAccountGeneratedFromKeycard(Constants.generatedWalletType,
|
|
accountNameInput.text,
|
|
colorSelectionGrid.selectedColor,
|
|
accountNameInput.input.asset.emoji)
|
|
}
|
|
else {
|
|
let finalFullPath = advancedSelection.expandableItem.completePath
|
|
if (!d.useFullyCustomPath) {
|
|
finalFullPath = d.selectedPath
|
|
}
|
|
errMessage = RootStore.generateNewAccount(d.password, accountNameInput.text, colorSelectionGrid.selectedColor,
|
|
accountNameInput.input.asset.emoji, finalFullPath,
|
|
advancedSelection.expandableItem.derivedFromAddress)
|
|
}
|
|
break
|
|
case Constants.AddAccountType.ImportSeedPhrase:
|
|
errMessage = RootStore.addAccountsFromSeed(advancedSelection.expandableItem.mnemonicText, d.password,
|
|
accountNameInput.text, colorSelectionGrid.selectedColor, accountNameInput.input.asset.emoji,
|
|
advancedSelection.expandableItem.completePath)
|
|
break
|
|
case Constants.AddAccountType.ImportPrivateKey:
|
|
errMessage = RootStore.addAccountsFromPrivateKey(advancedSelection.expandableItem.privateKey, d.password,
|
|
accountNameInput.text, colorSelectionGrid.selectedColor, accountNameInput.input.asset.emoji)
|
|
break
|
|
case Constants.AddAccountType.WatchOnly:
|
|
errMessage = RootStore.addWatchOnlyAccount(advancedSelection.expandableItem.watchAddress, accountNameInput.text,
|
|
colorSelectionGrid.selectedColor, accountNameInput.input.asset.emoji)
|
|
break
|
|
}
|
|
|
|
nextButton.loading = false
|
|
|
|
if (errMessage) {
|
|
console.warn(`Unhandled error case. Status-go message: ${errMessage}`)
|
|
} else {
|
|
root.afterAddAccount()
|
|
root.close()
|
|
}
|
|
}
|
|
|
|
function nextButtonClicked() {
|
|
nextButton.loading = true
|
|
if (d.authenticationNeeded) {
|
|
d.password = ""
|
|
if (d.selectedKeyUidMigratedToKeycard &&
|
|
d.selectedAccountType === Constants.AddAccountType.GenerateNew) {
|
|
RootStore.authenticateUserAndDeriveAddressOnKeycardForPath(d.selectedKeyUid, d.selectedPath, true)
|
|
}
|
|
else {
|
|
RootStore.authenticateUser()
|
|
}
|
|
}
|
|
else {
|
|
d.generateNewAccount()
|
|
}
|
|
}
|
|
}
|
|
|
|
onOpened: {
|
|
RootStore.loggedInUserAuthenticated = false
|
|
d.addAccountIcon = "password"
|
|
if (RootStore.loggedInUserUsesBiometricLogin()) {
|
|
d.addAccountIcon = "touch-id"
|
|
}
|
|
else if (RootStore.loggedInUserIsKeycardUser()) {
|
|
d.addAccountIcon = "keycard"
|
|
}
|
|
|
|
accountNameInput.input.asset.emoji = StatusQUtils.Emoji.getRandomEmoji(StatusQUtils.Emoji.size.verySmall)
|
|
colorSelectionGrid.selectedColorIndex = Math.floor(Math.random() * colorSelectionGrid.model.length)
|
|
accountNameInput.input.edit.forceActiveFocus()
|
|
}
|
|
|
|
onClosed: {
|
|
RootStore.loggedInUserAuthenticated = false
|
|
d.password = ""
|
|
validationError.text = ""
|
|
accountNameInput.reset()
|
|
advancedSelection.expanded = false
|
|
advancedSelection.reset()
|
|
}
|
|
|
|
contentItem: StatusScrollView {
|
|
id: scroll
|
|
implicitWidth: root.width
|
|
implicitHeight: 400
|
|
topPadding: Style.current.halfPadding
|
|
bottomPadding: Style.current.halfPadding
|
|
leftPadding: Style.current.padding
|
|
rightPadding: Style.current.padding
|
|
objectName: "AddAccountModalContent"
|
|
|
|
Column {
|
|
property alias accountNameInput: accountNameInput
|
|
width: scroll.availableWidth
|
|
spacing: Style.current.halfPadding
|
|
topPadding: 20
|
|
|
|
StatusBaseText {
|
|
id: validationError
|
|
visible: text !== ""
|
|
width: parent.width
|
|
height: 16
|
|
horizontalAlignment: Text.AlignHCenter
|
|
font.pixelSize: 12
|
|
color: Style.current.danger
|
|
wrapMode: TextEdit.Wrap
|
|
}
|
|
|
|
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
|
|
enabled: accountNameInput.valid
|
|
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.selectedAccountDerivedFromAddress = derivedFromAddress
|
|
d.selectedPath = path
|
|
if (d.selectedKeyUidMigratedToKeycard) {
|
|
d.password = ""
|
|
validationError.text = ""
|
|
RootStore.loggedInUserAuthenticated = false
|
|
}
|
|
else{
|
|
d.getDerivedAddressList()
|
|
}
|
|
}
|
|
onEnterPressed: {
|
|
if (nextButton.enabled) {
|
|
nextButton.clicked(null)
|
|
return
|
|
}
|
|
}
|
|
|
|
Component.onCompleted: {
|
|
d.selectedAccountType = Qt.binding(() => addAccountType)
|
|
d.selectedAccountDerivedFromAddress = Qt.binding(() => derivedFromAddress)
|
|
d.selectedKeyUid = Qt.binding(() => selectedKeyUid)
|
|
d.selectedKeyUidMigratedToKeycard = Qt.binding(() => selectedKeyUidMigratedToKeycard)
|
|
d.selectedPath = Qt.binding(() => path)
|
|
d.selectedAddress = Qt.binding(() => selectedAddress)
|
|
d.selectedAddressAvailable = Qt.binding(() => selectedAddressAvailable)
|
|
d.useFullyCustomPath = Qt.binding(() => useFullyCustomPath)
|
|
advancedSelection.isValid = Qt.binding(() => isValid)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
rightButtons: [
|
|
StatusButton {
|
|
id: nextButton
|
|
|
|
text: {
|
|
if (loading) {
|
|
return qsTr("Loading...")
|
|
}
|
|
return qsTr("Add account")
|
|
}
|
|
|
|
enabled: {
|
|
if (!accountNameInput.valid ||
|
|
loading ||
|
|
((root.authenticationNeeded && !d.useFullyCustomPath) && !d.selectedAddressAvailable)) {
|
|
return false
|
|
}
|
|
return advancedSelection.isValid
|
|
}
|
|
|
|
icon.name: d.authenticationNeeded? d.addAccountIcon : ""
|
|
highlighted: focus
|
|
|
|
onClicked : d.nextButtonClicked()
|
|
}
|
|
]
|
|
}
|