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:
parent
5b8f37cba2
commit
da226b75aa
|
@ -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
|
|
@ -1,7 +1,8 @@
|
||||||
import QtQuick 2.13
|
import QtQuick 2.15
|
||||||
import QtQuick.Controls 2.13
|
import QtQml 2.15
|
||||||
import QtQml.Models 2.14
|
import QtQuick.Controls 2.15
|
||||||
import QtQuick.Layouts 1.14
|
import QtQml.Models 2.15
|
||||||
|
import QtQuick.Layouts 1.15
|
||||||
|
|
||||||
import utils 1.0
|
import utils 1.0
|
||||||
import shared.controls 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.title: d.editMode? qsTr("Edit saved address") : qsTr("Add new saved address")
|
||||||
headerSettings.subTitle: d.editMode? d.name : ""
|
headerSettings.subTitle: d.editMode? d.name : ""
|
||||||
|
|
||||||
|
property var store: RootStore
|
||||||
|
|
||||||
onClosed: {
|
onClosed: {
|
||||||
root.close()
|
root.close()
|
||||||
}
|
}
|
||||||
|
@ -115,6 +118,9 @@ StatusModal {
|
||||||
readonly property bool addressInputIsAddress: !!d.address &&
|
readonly property bool addressInputIsAddress: !!d.address &&
|
||||||
d.address != Constants.zeroAddress &&
|
d.address != Constants.zeroAddress &&
|
||||||
(Utils.isAddress(d.address) || Utils.isValidAddressWithChainPrefix(d.address))
|
(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 {}
|
property ListModel cardsModel: ListModel {}
|
||||||
|
|
||||||
|
@ -127,7 +133,7 @@ StatusModal {
|
||||||
property int contactsWithSameAddress: 0
|
property int contactsWithSameAddress: 0
|
||||||
|
|
||||||
function checkIfAddressIsAlreadyAdddedToWallet(address) {
|
function checkIfAddressIsAlreadyAdddedToWallet(address) {
|
||||||
let account = RootStore.getWalletAccount(address)
|
let account = root.store.getWalletAccount(address)
|
||||||
d.cardsModel.clear()
|
d.cardsModel.clear()
|
||||||
d.addressAlreadyAddedToWalletError = !!account.name
|
d.addressAlreadyAddedToWalletError = !!account.name
|
||||||
if (!d.addressAlreadyAddedToWalletError) {
|
if (!d.addressAlreadyAddedToWalletError) {
|
||||||
|
@ -144,7 +150,7 @@ StatusModal {
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkIfAddressIsAlreadyAdddedToSavedAddresses(address) {
|
function checkIfAddressIsAlreadyAdddedToSavedAddresses(address) {
|
||||||
let savedAddress = RootStore.getSavedAddress(address)
|
let savedAddress = root.store.getSavedAddress(address)
|
||||||
d.cardsModel.clear()
|
d.cardsModel.clear()
|
||||||
d.addressAlreadyAddedToSavedAddressesError = !!savedAddress.address
|
d.addressAlreadyAddedToSavedAddressesError = !!savedAddress.address
|
||||||
if (!d.addressAlreadyAddedToSavedAddressesError) {
|
if (!d.addressAlreadyAddedToSavedAddressesError) {
|
||||||
|
@ -244,6 +250,7 @@ StatusModal {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
networkSelector.state = ""
|
||||||
if (d.addressInputIsAddress) {
|
if (d.addressInputIsAddress) {
|
||||||
d.checkForAddressInputOwningErrorsWarnings()
|
d.checkForAddressInputOwningErrorsWarnings()
|
||||||
return
|
return
|
||||||
|
@ -259,7 +266,7 @@ StatusModal {
|
||||||
|| event !== undefined && event.key !== Qt.Key_Return && event.key !== Qt.Key_Enter)
|
|| event !== undefined && event.key !== Qt.Key_Return && event.key !== Qt.Key_Enter)
|
||||||
return
|
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()
|
root.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -273,7 +280,16 @@ StatusModal {
|
||||||
|
|
||||||
d.resolvingEnsNameInProgress = false
|
d.resolvingEnsNameInProgress = false
|
||||||
d.address = resolvedAddress
|
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
|
contentWidth: availableWidth
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
|
id: column
|
||||||
|
|
||||||
width: scrollView.availableWidth
|
width: scrollView.availableWidth
|
||||||
height: childrenRect.height
|
height: childrenRect.height
|
||||||
|
|
||||||
topPadding: 24 // (16 + 8 for Name, until we add it to the StatusInput component)
|
topPadding: 24 // (16 + 8 for Name, until we add it to the StatusInput component)
|
||||||
bottomPadding: 28
|
bottomPadding: 28
|
||||||
|
|
||||||
|
@ -365,7 +384,7 @@ StatusModal {
|
||||||
StatusValidator {
|
StatusValidator {
|
||||||
name: "check-saved-address-existence"
|
name: "check-saved-address-existence"
|
||||||
validate: (value) => {
|
validate: (value) => {
|
||||||
return !RootStore.savedAddressNameExists(value)
|
return !root.store.savedAddressNameExists(value)
|
||||||
|| d.editMode && d.storedName == value
|
|| d.editMode && d.storedName == value
|
||||||
}
|
}
|
||||||
errorMessage: qsTr("Name already in use")
|
errorMessage: qsTr("Name already in use")
|
||||||
|
@ -373,6 +392,7 @@ StatusModal {
|
||||||
]
|
]
|
||||||
input.clearable: true
|
input.clearable: true
|
||||||
input.rightPadding: 16
|
input.rightPadding: 16
|
||||||
|
input.tabNavItem: addressInput
|
||||||
|
|
||||||
onKeyPressed: {
|
onKeyPressed: {
|
||||||
d.submit(event)
|
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
|
input.implicitHeight: Math.min(Math.max(input.edit.contentHeight + topPadding + bottomPadding, minimumHeight), maximumHeight) // setting height instead does not work
|
||||||
enabled: !(d.editMode || d.addAddress)
|
enabled: !(d.editMode || d.addAddress)
|
||||||
input.edit.textFormat: TextEdit.RichText
|
input.edit.textFormat: TextEdit.RichText
|
||||||
|
input.rightComponent: (d.resolvingEnsNameInProgress || d.checkingContactsAddressInProgress) ?
|
||||||
|
loadingIndicator : null
|
||||||
input.asset.name: d.addressInputValid && !d.editMode ? "checkbox" : ""
|
input.asset.name: d.addressInputValid && !d.editMode ? "checkbox" : ""
|
||||||
input.asset.color: enabled ? Theme.palette.primaryColor1 : Theme.palette.baseColor1
|
input.asset.color: enabled ? Theme.palette.primaryColor1 : Theme.palette.baseColor1
|
||||||
|
input.asset.width: 17
|
||||||
|
input.asset.height: 17
|
||||||
input.rightPadding: 16
|
input.rightPadding: 16
|
||||||
input.leftIcon: false
|
input.leftIcon: false
|
||||||
|
input.tabNavItem: nameInput
|
||||||
|
|
||||||
multiline: true
|
multiline: true
|
||||||
|
|
||||||
property string plainText: input.edit.getText(0, text.length).trim()
|
property string plainText: input.edit.getText(0, text.length).trim()
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: loadingIndicator
|
||||||
|
|
||||||
|
StatusLoadingIndicator {}
|
||||||
|
}
|
||||||
|
|
||||||
onTextChanged: {
|
onTextChanged: {
|
||||||
if (skipTextUpdate || !d.initialized)
|
if (skipTextUpdate || !d.initialized)
|
||||||
return
|
return
|
||||||
|
@ -424,6 +455,7 @@ StatusModal {
|
||||||
// Update root values
|
// Update root values
|
||||||
if (Utils.isLikelyEnsName(plainText)) {
|
if (Utils.isLikelyEnsName(plainText)) {
|
||||||
d.ens = plainText
|
d.ens = plainText
|
||||||
|
d.address = ""
|
||||||
d.chainShortNames = ""
|
d.chainShortNames = ""
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -560,6 +592,7 @@ StatusModal {
|
||||||
|
|
||||||
StatusNetworkSelector {
|
StatusNetworkSelector {
|
||||||
id: networkSelector
|
id: networkSelector
|
||||||
|
|
||||||
objectName: "addSavedAddressNetworkSelector"
|
objectName: "addSavedAddressNetworkSelector"
|
||||||
title: "Network preference"
|
title: "Network preference"
|
||||||
implicitWidth: d.componentWidth
|
implicitWidth: d.componentWidth
|
||||||
|
@ -612,6 +645,28 @@ StatusModal {
|
||||||
item.modelRef.isEnabled = !item.modelRef.isEnabled
|
item.modelRef.isEnabled = !item.modelRef.isEnabled
|
||||||
d.chainShortNamesDirty = true
|
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 {
|
StatusButton {
|
||||||
text: d.editMode? qsTr("Save") : qsTr("Add address")
|
text: d.editMode? qsTr("Save") : qsTr("Add address")
|
||||||
enabled: d.valid && d.dirty
|
enabled: d.valid && d.dirty
|
||||||
loading: d.resolvingEnsNameInProgress || d.checkingContactsAddressInProgress
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
d.submit()
|
d.submit()
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,8 +44,11 @@ Loader {
|
||||||
}
|
}
|
||||||
case TabAddressSelectorView.Type.SavedAddress: {
|
case TabAddressSelectorView.Type.SavedAddress: {
|
||||||
root.addressText = root.selectedRecipient.address
|
root.addressText = root.selectedRecipient.address
|
||||||
|
|
||||||
|
// Resolve before using
|
||||||
if (!!root.selectedRecipient.ens && root.selectedRecipient.ens.length > 0) {
|
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)
|
preferredChainIds = store.getShortChainIds(root.selectedRecipient.chainShortNames)
|
||||||
break
|
break
|
||||||
|
|
Loading…
Reference in New Issue