feat(wallet): resize saved address popup to remove network selection

when ENS name is resolved. Resolve ENS name before used in SendModal.
UI tweaks:
  - red stroke on address input in case of error
  - smaller tick for validation address input
  - added validation spinner to address input, removed from the button
  - handled tab key to move focus between inputs
This commit is contained in:
Ivan Belyakov 2024-03-02 11:48:11 +01:00 committed by IvanBelyakoff
parent 5b8f37cba2
commit da226b75aa
3 changed files with 135 additions and 11 deletions

View File

@ -0,0 +1,67 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import Storybook 1.0
import Models 1.0
import AppLayouts.Wallet.popups 1.0
import utils 1.0
SplitView {
orientation: Qt.Horizontal
PopupBackground {
id: popupBg
property var popupIntance: null
SplitView.fillWidth: true
SplitView.fillHeight: true
Button {
id: reopenButton
anchors.centerIn: parent
text: "Reopen"
enabled: !dialog.visible
onClicked: dialog.open()
}
AddEditSavedAddressPopup {
id: dialog
visible: true
store: QtObject {
property var savedAddressNameExists: function() { return false }
}
// Emulate resoling ENS by simple validation
QtObject {
id: mainModule
function resolveENS(name, uuid) {
if (Utils.isValidEns(name)) {
resolvedENS("", "0x1234567890123456789012345678901234567890", uuid)
}
else {
resolvedENS("", "", uuid)
}
}
signal resolvedENS(string pubkey, string address, string uuid)
}
Component.onCompleted: initWithParams()
}
}
Pane {
SplitView.minimumWidth: 300
SplitView.preferredWidth: 300
}
}
// category: Popups
// https://www.figma.com/file/idUoxN7OIW2Jpp3PMJ1Rl8/%E2%9A%99%EF%B8%8F-Settings-%7C-Desktop?type=design&node-id=23256-263282&mode=design&t=0DRwQJKDGYJPHkq1-4

View File

@ -1,7 +1,8 @@
import QtQuick 2.13
import QtQuick.Controls 2.13
import QtQml.Models 2.14
import QtQuick.Layouts 1.14
import QtQuick 2.15
import QtQml 2.15
import QtQuick.Controls 2.15
import QtQml.Models 2.15
import QtQuick.Layouts 1.15
import utils 1.0
import shared.controls 1.0
@ -35,6 +36,8 @@ StatusModal {
headerSettings.title: d.editMode? qsTr("Edit saved address") : qsTr("Add new saved address")
headerSettings.subTitle: d.editMode? d.name : ""
property var store: RootStore
onClosed: {
root.close()
}
@ -115,6 +118,9 @@ StatusModal {
readonly property bool addressInputIsAddress: !!d.address &&
d.address != Constants.zeroAddress &&
(Utils.isAddress(d.address) || Utils.isValidAddressWithChainPrefix(d.address))
readonly property bool addressInputHasError: !!addressInput.errorMessageCmp.text
onAddressInputHasErrorChanged: addressInput.input.valid = !addressInputHasError // can't use binding because valid is overwritten in StatusInput
readonly property string networksHiddenState: "networksHidden"
property ListModel cardsModel: ListModel {}
@ -127,7 +133,7 @@ StatusModal {
property int contactsWithSameAddress: 0
function checkIfAddressIsAlreadyAdddedToWallet(address) {
let account = RootStore.getWalletAccount(address)
let account = root.store.getWalletAccount(address)
d.cardsModel.clear()
d.addressAlreadyAddedToWalletError = !!account.name
if (!d.addressAlreadyAddedToWalletError) {
@ -144,7 +150,7 @@ StatusModal {
}
function checkIfAddressIsAlreadyAdddedToSavedAddresses(address) {
let savedAddress = RootStore.getSavedAddress(address)
let savedAddress = root.store.getSavedAddress(address)
d.cardsModel.clear()
d.addressAlreadyAddedToSavedAddressesError = !!savedAddress.address
if (!d.addressAlreadyAddedToSavedAddressesError) {
@ -244,6 +250,7 @@ StatusModal {
return
}
networkSelector.state = ""
if (d.addressInputIsAddress) {
d.checkForAddressInputOwningErrorsWarnings()
return
@ -259,7 +266,7 @@ StatusModal {
|| event !== undefined && event.key !== Qt.Key_Return && event.key !== Qt.Key_Enter)
return
RootStore.createOrUpdateSavedAddress(d.name, d.address, d.ens, d.colorId, d.chainShortNames)
root.store.createOrUpdateSavedAddress(d.name, d.address, d.ens, d.colorId, d.chainShortNames)
root.close()
}
}
@ -273,7 +280,16 @@ StatusModal {
d.resolvingEnsNameInProgress = false
d.address = resolvedAddress
d.checkForAddressInputOwningErrorsWarnings()
try { // allows to avoid issues in storybook without much refactoring
d.checkForAddressInputOwningErrorsWarnings()
}
catch (e) {
}
if (!d.addressInputHasError)
networkSelector.state = d.networksHiddenState
else
networkSelector.state = ""
}
}
@ -322,8 +338,11 @@ StatusModal {
contentWidth: availableWidth
Column {
id: column
width: scrollView.availableWidth
height: childrenRect.height
topPadding: 24 // (16 + 8 for Name, until we add it to the StatusInput component)
bottomPadding: 28
@ -365,7 +384,7 @@ StatusModal {
StatusValidator {
name: "check-saved-address-existence"
validate: (value) => {
return !RootStore.savedAddressNameExists(value)
return !root.store.savedAddressNameExists(value)
|| d.editMode && d.storedName == value
}
errorMessage: qsTr("Name already in use")
@ -373,6 +392,7 @@ StatusModal {
]
input.clearable: true
input.rightPadding: 16
input.tabNavItem: addressInput
onKeyPressed: {
d.submit(event)
@ -391,15 +411,26 @@ StatusModal {
input.implicitHeight: Math.min(Math.max(input.edit.contentHeight + topPadding + bottomPadding, minimumHeight), maximumHeight) // setting height instead does not work
enabled: !(d.editMode || d.addAddress)
input.edit.textFormat: TextEdit.RichText
input.rightComponent: (d.resolvingEnsNameInProgress || d.checkingContactsAddressInProgress) ?
loadingIndicator : null
input.asset.name: d.addressInputValid && !d.editMode ? "checkbox" : ""
input.asset.color: enabled ? Theme.palette.primaryColor1 : Theme.palette.baseColor1
input.asset.width: 17
input.asset.height: 17
input.rightPadding: 16
input.leftIcon: false
input.tabNavItem: nameInput
multiline: true
property string plainText: input.edit.getText(0, text.length).trim()
Component {
id: loadingIndicator
StatusLoadingIndicator {}
}
onTextChanged: {
if (skipTextUpdate || !d.initialized)
return
@ -424,6 +455,7 @@ StatusModal {
// Update root values
if (Utils.isLikelyEnsName(plainText)) {
d.ens = plainText
d.address = ""
d.chainShortNames = ""
}
else {
@ -560,6 +592,7 @@ StatusModal {
StatusNetworkSelector {
id: networkSelector
objectName: "addSavedAddressNetworkSelector"
title: "Network preference"
implicitWidth: d.componentWidth
@ -612,6 +645,28 @@ StatusModal {
item.modelRef.isEnabled = !item.modelRef.isEnabled
d.chainShortNamesDirty = true
}
readonly property int animationDuration: 350
states: [
// As when networks seclector becomes invisible, spacing before it disappears as well, we see jumping height
// To overcome this, we animate bottom padding to 0 and when spacing disappears, reset bottom padding to spacing to compensate it
State {
name: d.networksHiddenState
PropertyChanges { target: networkSelector; height: 0 }
PropertyChanges { target: networkSelector; opacity: 0 }
PropertyChanges { target: column; bottomPadding: 0 }
}
]
transitions: [
Transition {
NumberAnimation { property: "height"; duration: networkSelector.animationDuration; easing.type: Easing.OutCirc }
NumberAnimation { property: "opacity"; duration: networkSelector.animationDuration; easing.type: Easing.OutCirc}
SequentialAnimation {
NumberAnimation { property: "bottomPadding"; duration: networkSelector.animationDuration; easing.type: Easing.OutCirc }
PropertyAction { target: column; property: "bottomPadding"; value: column.spacing }
}
}
]
}
}
}
@ -655,7 +710,6 @@ StatusModal {
StatusButton {
text: d.editMode? qsTr("Save") : qsTr("Add address")
enabled: d.valid && d.dirty
loading: d.resolvingEnsNameInProgress || d.checkingContactsAddressInProgress
onClicked: {
d.submit()
}

View File

@ -44,8 +44,11 @@ Loader {
}
case TabAddressSelectorView.Type.SavedAddress: {
root.addressText = root.selectedRecipient.address
// Resolve before using
if (!!root.selectedRecipient.ens && root.selectedRecipient.ens.length > 0) {
root.resolvedENSAddress = root.selectedRecipient.ens
d.isPending = true
d.resolveENS(root.selectedRecipient.ens)
}
preferredChainIds = store.getShortChainIds(root.selectedRecipient.chainShortNames)
break