diff --git a/ui/app/AppLayouts/WalletV2/LeftTab.qml b/ui/app/AppLayouts/WalletV2/LeftTab.qml index 692e54c476..d82f98022b 100644 --- a/ui/app/AppLayouts/WalletV2/LeftTab.qml +++ b/ui/app/AppLayouts/WalletV2/LeftTab.qml @@ -2,11 +2,15 @@ import QtQuick 2.13 import QtQuick.Controls 2.13 import QtQuick.Layouts 1.13 import QtGraphicalEffects 1.13 +import StatusQ.Core 0.1 +import StatusQ.Core.Theme 0.1 import "../../../imports" import "../../../shared" import "./components" Rectangle { + id: walletInfoContainer + color: Style.current.secondaryMenuBackground property int selectedAccount: 0 property var changeSelectedAccount: function(newIndex) { if (newIndex > walletV2Model.accountsView.accounts) { @@ -15,8 +19,6 @@ Rectangle { selectedAccount = newIndex walletV2Model.setCurrentAccountByIndex(newIndex) } - id: walletInfoContainer - color: Style.current.secondaryMenuBackground StyledText { id: title @@ -61,11 +63,6 @@ Rectangle { font.weight: Font.Medium font.pixelSize: 13 } - - AddAccount { - anchors.top: parent.top - anchors.right: parent.right - } } @@ -160,28 +157,26 @@ Rectangle { rectangle.hovered = false } onClicked: { - changeSelectedAccount(index) + walletInfoContainer.changeSelectedAccount(index) } } } } ScrollView { - anchors.bottom: parent.bottom - anchors.top: walletValueTextContainer.bottom - anchors.topMargin: Style.current.padding + id: accountsList anchors.right: parent.right anchors.left: parent.left - Layout.fillWidth: true - Layout.fillHeight: true + height: (listView.count <= 8) ? (listView.count * 64) : 530 + anchors.top: walletValueTextContainer.bottom + anchors.topMargin: Style.current.padding ScrollBar.horizontal.policy: ScrollBar.AlwaysOff ScrollBar.vertical.policy: listView.contentHeight > listView.height ? ScrollBar.AlwaysOn : ScrollBar.AlwaysOff ListView { id: listView - - spacing: 5 anchors.fill: parent + spacing: 5 boundsBehavior: Flickable.StopAtBounds delegate: walletDelegate @@ -212,6 +207,33 @@ Rectangle { model: walletV2Model.accountsView.accounts } } + + AddAccount { + id: addAccountButton + anchors.left: parent.left + anchors.leftMargin: Style.current.padding + anchors.top: accountsList.bottom + anchors.topMargin: 31 + } + + RowLayout { + id: savedAdressesLabel + height: 20 + anchors.left: parent.left + anchors.leftMargin: Style.current.padding + anchors.bottom: parent.bottom + anchors.bottomMargin: 22 + StatusIcon { + color: Theme.palette.baseColor1 + Layout.alignment: Qt.AlignVCenter + icon: "address" + } + StatusBaseText { + Layout.alignment: Qt.AlignVCenter + text: qsTr("Saved addresses") + color: Theme.palette.baseColor1 + } + } } /*##^## diff --git a/ui/app/AppLayouts/WalletV2/components/AddAccount.qml b/ui/app/AppLayouts/WalletV2/components/AddAccount.qml index 13b32901d3..fdb3ab737f 100644 --- a/ui/app/AppLayouts/WalletV2/components/AddAccount.qml +++ b/ui/app/AppLayouts/WalletV2/components/AddAccount.qml @@ -1,24 +1,28 @@ import QtQuick 2.13 import QtQuick.Controls 2.13 +import StatusQ.Controls 0.1 import "../../../../shared" import "../../../../shared/status" import "../../../../imports" -StatusRoundButton { +StatusFlatButton { id: btnAdd - icon.name: "plusSign" - pressedIconRotation: 45 - size: "medium" - type: "secondary" - width: 36 - height: 36 + width: 138 + height: 38 + size: StatusBaseButton.Size.Small + text: qsTr("Add account") + icon.name: "add" + icon.width: 14 + icon.height: 14 + readonly property var onAfterAddAccount: function() { + walletInfoContainer.changeSelectedAccount(walletModel.accountsView.accounts.rowCount() - 1); + } onClicked: { if (newAccountMenu.opened) { - newAccountMenu.close() + newAccountMenu.close(); } else { - let x = btnAdd.iconX + btnAdd.icon.width / 2 - newAccountMenu.width / 2 - newAccountMenu.popup(x, btnAdd.height + 4) + newAccountMenu.popup(0, btnAdd.height + 4); } } @@ -43,20 +47,13 @@ StatusRoundButton { onTriggered: console.log("TODO") } Action { - //% "Enter a seed phrase" - text: qsTrId("enter-a-seed-phrase") - icon.source: "../../../img/enter_seed_phrase.svg" - icon.width: 19 - icon.height: 19 - onTriggered: console.log("TODO") - } - Action { - //% "Enter a private key" - text: qsTrId("enter-a-private-key") + text: qsTr("Add with key or seed phrase") icon.source: "../../../img/enter_private_key.svg" icon.width: 19 icon.height: 19 - onTriggered: console.log("TODO") + onTriggered: { + addAccountPopupLoader.active = !addAccountPopupLoader.active; + } } onAboutToShow: { btnAdd.state = "pressed" @@ -66,10 +63,22 @@ StatusRoundButton { btnAdd.state = "default" } } -} -/*##^## -Designer { - D{i:0;height:36;width:36} + Loader { + id: addAccountPopupLoader + active: false + sourceComponent: AddAccountPopup { + id: addAccountPopup + anchors.centerIn: parent + onAddAccountClicked: { btnAdd.onAfterAddAccount(); } + onClosed: { + addAccountPopupLoader.active = false; + } + } + onLoaded: { + if (status === Loader.Ready) { + item.open(); + } + } + } } -##^##*/ diff --git a/ui/app/AppLayouts/WalletV2/components/AddAccountPopup.qml b/ui/app/AppLayouts/WalletV2/components/AddAccountPopup.qml new file mode 100644 index 0000000000..eed8b7dcb3 --- /dev/null +++ b/ui/app/AppLayouts/WalletV2/components/AddAccountPopup.qml @@ -0,0 +1,192 @@ +import QtQuick 2.13 +import QtQuick.Controls 2.13 +import QtQuick.Dialogs 1.3 + +import "../../../../imports" +import "../../../../shared" +import "../../../../shared/status" + +import StatusQ.Core 0.1 +import StatusQ.Core.Theme 0.1 +import StatusQ.Controls 0.1 +import StatusQ.Controls.Validators 0.1 +import StatusQ.Popups 0.1 + +StatusModal { + id: popup + width: 574 + height: (keyOrSeedPhraseInput.height > 100) ? 517 : 498 + header.title: qsTr("Add account") + onOpened: { + keyOrSeedPhraseInput.input.edit.forceActiveFocus(Qt.MouseFocusReason); + } + + property bool loading: false + property int marginBetweenInputs: 20 + property bool seedPhraseInserted: false + property bool isSeedCountValid: false + signal addAccountClicked() + + function seedPhraseNotFound() { + var seedValidationError = onboardingModel.validateMnemonic(keyOrSeedPhraseInput.text); + var regex = new RegExp('word [a-z]+ not found in the dictionary', 'i'); + return regex.test(seedValidationError); + } + + function validate() { + return (keyOrSeedPhraseInput.valid && accountNameInput.valid); + } + + contentItem: Item { + id: contentItem + anchors.left: parent.left + anchors.leftMargin: 8 + anchors.right: parent.right + anchors.rightMargin: 10 + height: parent.height + + Item { + id: seedOrPKInputContainer + width: parent.width + height: 120 + ((keyOrSeedPhraseInput.height > 100) ? 30 : 0) + + StatusInput { + id: keyOrSeedPhraseInput + width: parent.width + anchors.top: parent.top + anchors.topMargin: popup.marginBetweenInputs + input.multiline: true + input.icon.width: 15 + input.icon.height: 11 + input.icon.name: (popup.isSeedCountValid) || Utils.isPrivateKey(keyOrSeedPhraseInput.text) ? "checkmark" : "" + input.icon.color: Theme.palette.primaryColor1 + input.leftIcon: false + input.implicitHeight: 56 + input.placeholderText: qsTr("Enter private key or seed phrase") + label: qsTr("Private key or seed phrase") + validators: [ + StatusValidator { + validate: function () { + return popup.seedPhraseInserted ? (popup.isSeedCountValid && + !popup.seedPhraseNotFound()) : Utils.isPrivateKey(keyOrSeedPhraseInput.text); + } + } + ] + onTextChanged: { + popup.seedPhraseInserted = keyOrSeedPhraseInput.text.includes(" "); + popup.isSeedCountValid = (!!keyOrSeedPhraseInput.text && (keyOrSeedPhraseInput.text.match(/(\w+)/g).length === 12)); + if (text === "") { + errorMessage = qsTr("You need to enter a valid private key or seed phrase"); + } else { + if (!popup.seedPhraseInserted) { + errorMessage = !Utils.isPrivateKey(keyOrSeedPhraseInput.text) ? + qsTrId("enter-a-valid-private-key-(64-characters-hexadecimal-string)") : ""; + } else { + if (!popup.isSeedCountValid) { + errorMessage = qsTrId("enter-a-valid-mnemonic"); + } else if (popup.seedPhraseNotFound()) { + errorMessage = qsTrId("custom-seed-phrase") + '. ' + qsTrId("custom-seed-phrase-text-1"); + } else { + errorMessage = ""; + } + } + } + } + } + } + + Separator { + id: separator + anchors.left: parent.left + anchors.leftMargin: 16 + anchors.right: parent.right + anchors.rightMargin: 16 + anchors.top: seedOrPKInputContainer.bottom + anchors.topMargin: (2*popup.marginBetweenInputs) + } + + Row { + id: accountNameInputRow + anchors.left: parent.left + anchors.right: parent.right + anchors.rightMargin: 10 + anchors.top: separator.bottom + anchors.topMargin: popup.marginBetweenInputs + height: (parent.height/2) + StatusInput { + id: accountNameInput + implicitWidth: (parent.width - emojiDropDown.width) + input.implicitHeight: 56 + input.placeholderText: qsTrId("enter-an-account-name...") + label: qsTrId("account-name") + validators: [StatusMinLengthValidator { minLength: 1 }] + onTextChanged: { + errorMessage = (accountNameInput.text === "") ? + qsTrId("you-need-to-enter-an-account-name") : "" + } + } + Item { + id: emojiDropDown + //emoji placeholder + width: 80 + height: parent.height + anchors.top: parent.top + anchors.topMargin: 11 + StyledText { + id: inputLabel + text: "Emoji" + font.weight: Font.Medium + font.pixelSize: 13 + color: Style.current.textColor + } + Rectangle { + width: parent.width + height: 56 + anchors.top: inputLabel.bottom + anchors.topMargin: 7 + radius: 10 + color: "pink" + opacity: 0.6 + } + } + } + } + + rightButtons: [ + StatusButton { + text: popup.loading ? qsTrId("loading") : qsTrId("add-account") + enabled: !popup.loading && (accountNameInput.text !== "") + && (keyOrSeedPhraseInput.correctWordCount || (keyOrSeedPhraseInput.text !== "")) + + MessageDialog { + id: accountError + title: qsTr("Adding the account failed") + icon: StandardIcon.Critical + standardButtons: StandardButton.Ok + } + + onClicked : { + popup.loading = true; + if (!popup.validate()) { + errorSound.play(); + popup.loading = false; + } else { + //TODO account color to be verified with design + const result = popup.seedPhraseInserted ? + walletModel.accountsView.addAccountsFromSeed(keyOrSeedPhraseInput.text, "", accountNameInput.text, "") : + walletModel.accountsView.addAccountsFromPrivateKey(keyOrSeedPhraseInput.text, "", accountNameInput.text, ""); + popup.loading = false; + if (result) { + let resultJson = JSON.parse(result); + accountError.text = resultJson.error; + accountError.open(); + errorSound.play(); + return; + } + popup.addAccountClicked(); + popup.close(); + } + } + } + ] +} diff --git a/ui/app/AppLayouts/WalletV2/components/qmldir b/ui/app/AppLayouts/WalletV2/components/qmldir index 4b58b0fd88..e1cf6060eb 100644 --- a/ui/app/AppLayouts/WalletV2/components/qmldir +++ b/ui/app/AppLayouts/WalletV2/components/qmldir @@ -1,4 +1,5 @@ AddAccount 1.0 AddAccount.qml HeaderButton 1.0 HeaderButton.qml CollectibleCollection 1.0 CollectibleCollection.qml -CollectibleModal 1.0 CollectibleModal.qml \ No newline at end of file +CollectibleModal 1.0 CollectibleModal.qml +AddAccountPopup 1.0 AddAccountPopup.qml