From ff9062a1b059c9b58770fd1e2eec19bc7c9a9078 Mon Sep 17 00:00:00 2001 From: Sale Djenic Date: Fri, 29 Dec 2023 14:10:55 +0100 Subject: [PATCH] feat(savedaddresses): update adding saved address popup to match new design Implemented: - adding selection color section - all input field validations - interactions within the popup - an ephemeral notification when adding an address Closes #13089 --- .../saved_addresses/controller.nim | 7 +- .../saved_addresses/io_interface.nim | 11 +- .../wallet_section/saved_addresses/item.nim | 11 +- .../wallet_section/saved_addresses/model.nim | 40 ++-- .../wallet_section/saved_addresses/module.nim | 34 +++- .../wallet_section/saved_addresses/view.nim | 29 +-- .../service/saved_address/async_tasks.nim | 5 +- src/app_service/service/saved_address/dto.nim | 22 +-- .../service/saved_address/service.nim | 9 +- src/backend/backend.nim | 11 +- .../Controls/StatusColorSelectorGrid.qml | 2 +- .../controls/SavedAddressesDelegate.qml | 7 +- .../Wallet/controls/StatusNetworkSelector.qml | 2 +- .../Wallet/panels/ActivityFilterPanel.qml | 10 +- .../popups/AddEditSavedAddressPopup.qml | 185 +++++++++++------- .../Wallet/popups/TransactionAddressMenu.qml | 14 +- .../Wallet/stores/ActivityFiltersStore.qml | 8 - ui/app/AppLayouts/Wallet/stores/RootStore.qml | 38 +++- .../Wallet/views/SavedAddresses.qml | 24 +-- ui/app/mainui/AppMain.qml | 24 ++- .../shared/controls/TransactionAddress.qml | 6 +- .../shared/popups/addaccount/states/Main.qml | 11 +- ui/imports/shared/stores/RootStore.qml | 12 -- .../views/profile/ProfileShowcaseView.qml | 27 ++- ui/imports/utils/Constants.qml | 6 +- ui/imports/utils/Utils.qml | 10 + vendor/status-go | 2 +- 27 files changed, 335 insertions(+), 232 deletions(-) diff --git a/src/app/modules/main/wallet_section/saved_addresses/controller.nim b/src/app/modules/main/wallet_section/saved_addresses/controller.nim index f21a42e103..c14a304d25 100644 --- a/src/app/modules/main/wallet_section/saved_addresses/controller.nim +++ b/src/app/modules/main/wallet_section/saved_addresses/controller.nim @@ -27,7 +27,7 @@ proc init*(self: Controller) = self.events.on(SIGNAL_SAVED_ADDRESS_UPDATED) do(e:Args): let args = SavedAddressArgs(e) - self.delegate.savedAddressUpdated(args.address, args.ens, args.errorMsg) + self.delegate.savedAddressUpdated(args.name, args.address, args.ens, args.errorMsg) self.events.on(SIGNAL_SAVED_ADDRESS_DELETED) do(e:Args): let args = SavedAddressArgs(e) @@ -36,8 +36,9 @@ proc init*(self: Controller) = proc getSavedAddresses*(self: Controller): seq[saved_address_service.SavedAddressDto] = return self.savedAddressService.getSavedAddresses() -proc createOrUpdateSavedAddress*(self: Controller, name: string, address: string, favourite: bool, chainShortNames: string, ens: string) = - self.savedAddressService.createOrUpdateSavedAddress(name, address, favourite, chainShortNames, ens) +proc createOrUpdateSavedAddress*(self: Controller, name: string, address: string, ens: string, colorId: string, + favourite: bool, chainShortNames: string) = + self.savedAddressService.createOrUpdateSavedAddress(name, address, ens, colorId, favourite, chainShortNames) proc deleteSavedAddress*(self: Controller, address: string, ens: string) = self.savedAddressService.deleteSavedAddress(address, ens) diff --git a/src/app/modules/main/wallet_section/saved_addresses/io_interface.nim b/src/app/modules/main/wallet_section/saved_addresses/io_interface.nim index 30fa7ad3ec..e16e8ae10f 100644 --- a/src/app/modules/main/wallet_section/saved_addresses/io_interface.nim +++ b/src/app/modules/main/wallet_section/saved_addresses/io_interface.nim @@ -17,18 +17,25 @@ method viewDidLoad*(self: AccessInterface) {.base.} = method loadSavedAddresses*(self: AccessInterface) {.base.} = raise newException(ValueError, "No implementation available") -method createOrUpdateSavedAddress*(self: AccessInterface, name: string, address: string, favourite: bool, chainShortNames: string, ens: string) {.base.} = +method createOrUpdateSavedAddress*(self: AccessInterface, name: string, address: string, ens: string, colorId: string, + favourite: bool, chainShortNames: string) {.base.} = raise newException(ValueError, "No implementation available") method deleteSavedAddress*(self: AccessInterface, address: string, ens: string) {.base.} = raise newException(ValueError, "No implementation available") -method savedAddressUpdated*(self: AccessInterface, address: string, ens: string, errorMsg: string) {.base.} = +method savedAddressUpdated*(self: AccessInterface, name: string, address: string, ens: string, errorMsg: string) {.base.} = raise newException(ValueError, "No implementation available") method savedAddressDeleted*(self: AccessInterface, address: string, ens: string, errorMsg: string) {.base.} = raise newException(ValueError, "No implementation available") +method savedAddressNameExists*(self: AccessInterface, name: string): bool {.base.} = + raise newException(ValueError, "No implementation available") + +method getSavedAddressAsJson*(self: AccessInterface, address: string): string {.base.} = + raise newException(ValueError, "No implementation available") + type ## Abstract class (concept) which must be implemented by object/s used in this ## module. diff --git a/src/app/modules/main/wallet_section/saved_addresses/item.nim b/src/app/modules/main/wallet_section/saved_addresses/item.nim index 13377ce4ca..6bb82bede4 100644 --- a/src/app/modules/main/wallet_section/saved_addresses/item.nim +++ b/src/app/modules/main/wallet_section/saved_addresses/item.nim @@ -5,6 +5,7 @@ type name: string address: string ens: string + colorId: string favourite: bool chainShortNames: string isTest: bool @@ -12,8 +13,9 @@ type proc initItem*( name: string, address: string, - favourite: bool, ens: string, + colorId: string, + favourite: bool, chainShortNames: string, isTest: bool ): Item = @@ -21,6 +23,7 @@ proc initItem*( result.address = address result.favourite = favourite result.ens = ens + result.colorId = colorId result.chainShortNames = chainShortNames result.isTest = isTest @@ -28,8 +31,9 @@ proc `$`*(self: Item): string = result = fmt"""SavedAddressItem( name: {self.name}, address: {self.address}, - favourite: {self.favourite}, ens: {self.ens}, + colorId: {self.colorId}, + favourite: {self.favourite}, chainShortNames: {self.chainShortNames}, isTest: {self.isTest}, ]""" @@ -43,6 +47,9 @@ proc getEns*(self: Item): string = proc getAddress*(self: Item): string = return self.address +proc getColorId*(self: Item): string = + return self.colorId + proc getFavourite*(self: Item): bool = return self.favourite diff --git a/src/app/modules/main/wallet_section/saved_addresses/model.nim b/src/app/modules/main/wallet_section/saved_addresses/model.nim index 888766c85f..4e983d4f96 100644 --- a/src/app/modules/main/wallet_section/saved_addresses/model.nim +++ b/src/app/modules/main/wallet_section/saved_addresses/model.nim @@ -1,13 +1,16 @@ import NimQml, Tables, strutils, strformat -import ./item +import item + +export item type ModelRole {.pure.} = enum Name = UserRole + 1, Address - Favourite Ens + ColorId + Favourite ChainShortNames IsTest @@ -48,8 +51,9 @@ QtObject: { ModelRole.Name.int:"name", ModelRole.Address.int:"address", - ModelRole.Favourite.int:"favourite", ModelRole.Ens.int:"ens", + ModelRole.ColorId.int:"colorId", + ModelRole.Favourite.int:"favourite", ModelRole.ChainShortNames.int:"chainShortNames", ModelRole.IsTest.int:"isTest", }.toTable @@ -69,10 +73,12 @@ QtObject: result = newQVariant(item.getName()) of ModelRole.Address: result = newQVariant(item.getAddress()) - of ModelRole.Favourite: - result = newQVariant(item.getFavourite()) of ModelRole.Ens: result = newQVariant(item.getEns()) + of ModelRole.ColorId: + result = newQVariant(item.getColorId()) + of ModelRole.Favourite: + result = newQVariant(item.getFavourite()) of ModelRole.ChainShortNames: result = newQVariant(item.getChainShortNames()) of ModelRole.IsTest: @@ -85,8 +91,9 @@ QtObject: case column: of "name": result = $item.getName() of "address": result = $item.getAddress() - of "favourite": result = $item.getFavourite() of "ens": result = $item.getEns() + of "colorId": result = $item.getColorId() + of "favourite": result = $item.getFavourite() of "chainShortNames": result = $item.getChainShortNames() of "isTest": result = $item.getIsTest() @@ -99,20 +106,13 @@ QtObject: for item in items: self.itemChanged(item.getAddress()) - proc getNameByAddress*(self: Model, address: string): string = + proc getItemByAddress*(self: Model, address: string): Item = for item in self.items: - if(cmpIgnoreCase(item.getAddress(), address) == 0): - return item.getName() - return "" + if cmpIgnoreCase(item.getAddress(), address) == 0: + return item - proc getChainShortNamesForAddress*(self: Model, address: string): string = + proc nameExists*(self: Model, name: string): bool = for item in self.items: - if(cmpIgnoreCase(item.getAddress(), address) == 0): - return item.getChainShortNames() - return "" - - proc getEnsForAddress*(self: Model, address: string): string = - for item in self.items: - if(cmpIgnoreCase(item.getAddress(), address) == 0): - return item.getEns() - return "" + if item.getName() == name: + return true + return false \ No newline at end of file diff --git a/src/app/modules/main/wallet_section/saved_addresses/module.nim b/src/app/modules/main/wallet_section/saved_addresses/module.nim index ed45e147c7..8fc0be32b9 100644 --- a/src/app/modules/main/wallet_section/saved_addresses/module.nim +++ b/src/app/modules/main/wallet_section/saved_addresses/module.nim @@ -1,11 +1,11 @@ -import NimQml, sugar, sequtils +import NimQml, json, sugar, sequtils import ../io_interface as delegate_interface import app/global/global_singleton import app/core/eventemitter import app_service/service/saved_address/service as saved_address_service -import ./io_interface, ./view, ./controller, ./item +import io_interface, view, controller, model export io_interface @@ -36,8 +36,9 @@ method loadSavedAddresses*(self: Module) = savedAddresses.map(s => initItem( s.name, s.address, - s.favourite, s.ens, + s.colorId, + s.favourite, s.chainShortNames, s.isTest, )) @@ -57,16 +58,33 @@ method viewDidLoad*(self: Module) = self.moduleLoaded = true self.delegate.savedAddressesModuleDidLoad() -method createOrUpdateSavedAddress*(self: Module, name: string, address: string, favourite: bool, chainShortNames: string, ens: string) = - self.controller.createOrUpdateSavedAddress(name, address, favourite, chainShortNames, ens) +method createOrUpdateSavedAddress*(self: Module, name: string, address: string, ens: string, colorId: string, + favourite: bool, chainShortNames: string) = + self.controller.createOrUpdateSavedAddress(name, address, ens, colorId, favourite, chainShortNames) method deleteSavedAddress*(self: Module, address: string, ens: string) = self.controller.deleteSavedAddress(address, ens) -method savedAddressUpdated*(self: Module, address: string, ens: string, errorMsg: string) = +method savedAddressUpdated*(self: Module, name: string, address: string, ens: string, errorMsg: string) = self.loadSavedAddresses() - self.view.savedAddressUpdated(address, ens, errorMsg) + self.view.savedAddressUpdated(name, address, ens, errorMsg) method savedAddressDeleted*(self: Module, address: string, ens: string, errorMsg: string) = self.loadSavedAddresses() - self.view.savedAddressDeleted(address, ens, errorMsg) \ No newline at end of file + self.view.savedAddressDeleted(address, ens, errorMsg) + +method savedAddressNameExists*(self: Module, name: string): bool = + return self.view.getModel().nameExists(name) + +method getSavedAddressAsJson*(self: Module, address: string): string = + let item = self.view.getModel().getItemByAddress(address) + let jsonObj = %* { + "name": item.getName(), + "address": item.getAddress(), + "ens": item.getEns(), + "colorId": item.getColorId(), + "favourite": item.getFavourite(), + "chainShortNames": item.getChainShortNames(), + "isTest": item.getIsTest(), + } + return $jsonObj \ No newline at end of file diff --git a/src/app/modules/main/wallet_section/saved_addresses/view.nim b/src/app/modules/main/wallet_section/saved_addresses/view.nim index e34472fe5e..aa0f0daaf1 100644 --- a/src/app/modules/main/wallet_section/saved_addresses/view.nim +++ b/src/app/modules/main/wallet_section/saved_addresses/view.nim @@ -1,7 +1,7 @@ import NimQml -import ./model, ./item -import ./io_interface +import model +import io_interface QtObject: type @@ -27,31 +27,32 @@ QtObject: proc modelChanged*(self: View) {.signal.} - proc getModel(self: View): QVariant {.slot.} = + proc getModel*(self: View): Model = + return self.model + + proc getModelVariant(self: View): QVariant {.slot.} = return self.modelVariant QtProperty[QVariant] model: - read = getModel + read = getModelVariant notify = modelChanged proc setItems*(self: View, items: seq[Item]) = self.model.setItems(items) - proc savedAddressUpdated*(self: View, address: string, ens: string, errorMsg: string) {.signal.} + proc savedAddressUpdated*(self: View, name: string, address: string, ens: string, errorMsg: string) {.signal.} - proc createOrUpdateSavedAddress*(self: View, name: string, address: string, favourite: bool, chainShortNames: string, ens: string) {.slot.} = - self.delegate.createOrUpdateSavedAddress(name, address, favourite, chainShortNames, ens) + proc createOrUpdateSavedAddress*(self: View, name: string, address: string, ens: string, colorId: string, + favourite: bool, chainShortNames: string) {.slot.} = + self.delegate.createOrUpdateSavedAddress(name, address, ens, colorId, favourite, chainShortNames) proc savedAddressDeleted*(self: View, address: string, ens: string, errorMsg: string) {.signal.} proc deleteSavedAddress*(self: View, address: string, ens: string) {.slot.} = self.delegate.deleteSavedAddress(address, ens) - proc getNameByAddress*(self: View, address: string): string {.slot.} = - return self.model.getNameByAddress(address) + proc savedAddressNameExists*(self: View, name: string): bool {.slot.} = + return self.delegate.savedAddressNameExists(name) - proc getChainShortNamesForAddress*(self: View, address: string): string {.slot.} = - return self.model.getChainShortNamesForAddress(address) - - proc getEnsForAddress*(self: View, address: string): string {.slot.} = - return self.model.getEnsForAddress(address) + proc getSavedAddressAsJson*(self: View, address: string): string {.slot.} = + return self.delegate.getSavedAddressAsJson(address) \ No newline at end of file diff --git a/src/app_service/service/saved_address/async_tasks.nim b/src/app_service/service/saved_address/async_tasks.nim index 804431dbf5..1f29cee236 100644 --- a/src/app_service/service/saved_address/async_tasks.nim +++ b/src/app_service/service/saved_address/async_tasks.nim @@ -7,6 +7,7 @@ type SavedAddressTaskArg = ref object of QObjectTaskArg name: string address: string + colorId: string favourite: bool chainShortNames: string ens: string @@ -16,14 +17,16 @@ const upsertSavedAddressTask: Task = proc(argEncoded: string) {.gcsafe, nimcall. let arg = decode[SavedAddressTaskArg](argEncoded) var response = %* { "response": "", + "name": %* arg.name, "address": %* arg.address, "ens": %* arg.ens, "error": "", } try: - let rpcResponse = backend.upsertSavedAddress(backend.SavedAddress( + let rpcResponse = backend.upsertSavedAddress(SavedAddressDto( name: arg.name, address: arg.address, + colorId: arg.colorId, favourite: arg.favourite, chainShortNames: arg.chainShortNames, ens: arg.ens, diff --git a/src/app_service/service/saved_address/dto.nim b/src/app_service/service/saved_address/dto.nim index cd8e21ffb3..4705bda60a 100644 --- a/src/app_service/service/saved_address/dto.nim +++ b/src/app_service/service/saved_address/dto.nim @@ -1,4 +1,4 @@ -import json +import json, strutils include ../../common/json_utils @@ -7,33 +7,19 @@ type name*: string address*: string ens*: string + colorId*: string favourite*: bool chainShortNames*: string isTest*: bool createdAt*: int64 -proc newSavedAddressDto*( - name: string, - address: string, - ens: string, - favourite: bool, - chainShortNames: string, - isTest: bool -): SavedAddressDto = - return SavedAddressDto( - name: name, - address: address, - ens: ens, - favourite: favourite, - chainShortNames: chainShortNames, - isTest: isTest - ) - proc toSavedAddressDto*(jsonObj: JsonNode): SavedAddressDto = result = SavedAddressDto() discard jsonObj.getProp("name", result.name) discard jsonObj.getProp("address", result.address) discard jsonObj.getProp("ens", result.ens) + discard jsonObj.getProp("colorId", result.colorId) + result.colorId = result.colorId.toUpper() # to match `preDefinedWalletAccountColors` on the qml side discard jsonObj.getProp("favourite", result.favourite) discard jsonObj.getProp("chainShortNames", result.chainShortNames) discard jsonObj.getProp("isTest", result.isTest) diff --git a/src/app_service/service/saved_address/service.nim b/src/app_service/service/saved_address/service.nim index 426977fcb6..cf14219de1 100644 --- a/src/app_service/service/saved_address/service.nim +++ b/src/app_service/service/saved_address/service.nim @@ -24,6 +24,7 @@ const SIGNAL_SAVED_ADDRESS_DELETED* = "savedAddressDeleted" type SavedAddressArgs* = ref object of Args + name*: string address*: string ens*: string errorMsg*: string @@ -83,14 +84,15 @@ QtObject: proc getSavedAddresses*(self: Service): seq[SavedAddressDto] = return self.savedAddresses - proc createOrUpdateSavedAddress*(self: Service, name: string, address: string, favourite: bool, chainShortNames: string, - ens: string) = + proc createOrUpdateSavedAddress*(self: Service, name: string, address: string, ens: string, colorId: string, + favourite: bool, chainShortNames: string) = let arg = SavedAddressTaskArg( name: name, address: address, + ens: ens, + colorId: colorId, favourite: favourite, chainShortNames: chainShortNames, - ens: ens, isTestAddress: self.settingsService.areTestNetworksEnabled(), tptr: cast[ByteAddress](upsertSavedAddressTask), vptr: cast[ByteAddress](self.vptr), @@ -107,6 +109,7 @@ QtObject: if rpcResponseObj{"response"}.kind != JNull and rpcResponseObj{"response"}.getStr != "ok": raise newException(CatchableError, "invalid response") + arg.name = rpcResponseObj{"name"}.getStr arg.address = rpcResponseObj{"address"}.getStr arg.ens = rpcResponseObj{"ens"}.getStr except Exception as e: diff --git a/src/backend/backend.nim b/src/backend/backend.nim index 86377ff9db..1cc06ccd9d 100644 --- a/src/backend/backend.nim +++ b/src/backend/backend.nim @@ -1,6 +1,7 @@ import json, json_serialization, strformat import hashes import ./core, ./response_type +import app_service/service/saved_address/dto as saved_address_dto from ./gen import rpc export response_type @@ -26,14 +27,6 @@ type address* {.serializedFieldName("address").}: string permissions* {.serializedFieldName("permissions").}: seq[string] - SavedAddress* = ref object of RootObj - name* {.serializedFieldName("name").}: string - address* {.serializedFieldName("address").}: string - favourite* {.serializedFieldName("favourite").}: bool - chainShortNames* {.serializedFieldName("chainShortNames").}: string - ens* {.serializedFieldName("ens").}: string - isTest* {.serializedFieldName("isTest").}: bool - Network* = ref object of RootObj chainId* {.serializedFieldName("chainId").}: int nativeCurrencyDecimals* {.serializedFieldName("nativeCurrencyDecimals").}: int @@ -94,7 +87,7 @@ rpc(fetchChainIDForURL, "wallet"): url: string rpc(upsertSavedAddress, "wakuext"): - savedAddress: SavedAddress + savedAddress: SavedAddressDto rpc(deleteSavedAddress, "wakuext"): address: string diff --git a/ui/StatusQ/src/StatusQ/Controls/StatusColorSelectorGrid.qml b/ui/StatusQ/src/StatusQ/Controls/StatusColorSelectorGrid.qml index bdb62c474e..57cde15e4c 100644 --- a/ui/StatusQ/src/StatusQ/Controls/StatusColorSelectorGrid.qml +++ b/ui/StatusQ/src/StatusQ/Controls/StatusColorSelectorGrid.qml @@ -27,7 +27,7 @@ Column { id: title width: parent.width verticalAlignment: Text.AlignVCenter - font.pixelSize: 13 + font.pixelSize: 15 color: Theme.palette.baseColor1 } diff --git a/ui/app/AppLayouts/Wallet/controls/SavedAddressesDelegate.qml b/ui/app/AppLayouts/Wallet/controls/SavedAddressesDelegate.qml index fcdcc24c27..41758153f8 100644 --- a/ui/app/AppLayouts/Wallet/controls/SavedAddressesDelegate.qml +++ b/ui/app/AppLayouts/Wallet/controls/SavedAddressesDelegate.qml @@ -22,6 +22,7 @@ StatusListItem { property string name property string address property string ens + property string colorId property string chainShortNames property bool favourite: false property bool areTestNetworksEnabled: false @@ -88,6 +89,7 @@ StatusListItem { favourite: root.favourite, chainShortNames: root.chainShortNames, ens: root.ens, + colorId: root.colorId, } ); } @@ -115,6 +117,7 @@ StatusListItem { property bool storeFavourite property string contactChainShortNames property string contactEns + property string colorId readonly property int maxHeight: 341 height: implicitHeight > maxHeight ? maxHeight : implicitHeight @@ -126,6 +129,7 @@ StatusListItem { storeFavourite = model.favourite; contactChainShortNames = model.chainShortNames; contactEns = model.ens; + colorId = model.colorId; popup(parent, x, y); } onClosed: { @@ -146,7 +150,8 @@ StatusListItem { name: editDeleteMenu.contactName, favourite: editDeleteMenu.storeFavourite, chainShortNames: editDeleteMenu.contactChainShortNames, - ens: editDeleteMenu.contactEns + ens: editDeleteMenu.contactEns, + colorId: editDeleteMenu.colorId }) } } diff --git a/ui/app/AppLayouts/Wallet/controls/StatusNetworkSelector.qml b/ui/app/AppLayouts/Wallet/controls/StatusNetworkSelector.qml index aec8c747d4..599951dbd9 100644 --- a/ui/app/AppLayouts/Wallet/controls/StatusNetworkSelector.qml +++ b/ui/app/AppLayouts/Wallet/controls/StatusNetworkSelector.qml @@ -189,7 +189,7 @@ Rectangle { StatusNetworkListItemTag { id: networkTag - title: model.chainName + title: model.shortName asset.height: root.asset.height asset.width: root.asset.width diff --git a/ui/app/AppLayouts/Wallet/panels/ActivityFilterPanel.qml b/ui/app/AppLayouts/Wallet/panels/ActivityFilterPanel.qml index 53b09ec82b..e97342ccad 100644 --- a/ui/app/AppLayouts/Wallet/panels/ActivityFilterPanel.qml +++ b/ui/app/AppLayouts/Wallet/panels/ActivityFilterPanel.qml @@ -201,8 +201,14 @@ Column { Repeater { model: activityFilterStore.savedAddressFilters delegate: ActivityFilterTagItem { - tagPrimaryLabel.text: activityFilterStore.getEnsForSavedWalletAddress(modelData) - || activityFilterStore.getChainShortNamesForSavedWalletAddress(modelData) + StatusQUtils.Utils.elideText(modelData,6,4) + tagPrimaryLabel.text: { + let savedAddress = root.store.getSavedAddress(modelData) + if (!!savedAddress.ens) { + return savedAddress.ens + } + + return savedAddress.chainShortNames + StatusQUtils.Utils.elideText(modelData,6,4) + } onClosed: activityFilterStore.toggleSavedAddress(modelData) } } diff --git a/ui/app/AppLayouts/Wallet/popups/AddEditSavedAddressPopup.qml b/ui/app/AppLayouts/Wallet/popups/AddEditSavedAddressPopup.qml index 5b529ef0f6..3427070f28 100644 --- a/ui/app/AppLayouts/Wallet/popups/AddEditSavedAddressPopup.qml +++ b/ui/app/AppLayouts/Wallet/popups/AddEditSavedAddressPopup.qml @@ -25,41 +25,80 @@ import ".." StatusDialog { id: root - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - - property bool edit: false - property bool addAddress: false - property string address: Constants.zeroAddress // Setting as zero address since we don't have the address yet - property string chainShortNames - property string ens - - property alias name: nameInput.text - property bool favourite: false - property var allNetworks - function applyParams(params = {}) { - root.addAddress = params.addAddress?? false - root.address = params.address?? Constants.zeroAddress - root.ens = params.ens?? "" - root.edit = params.edit?? false - root.name = params.name?? "" - root.favourite = params.favourite?? false - root.chainShortNames = params.chainShortNames?? "" + closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside + + width: 477 + topPadding: 24 // (16 + 8 for Name, until we add it to the StatusInput component) + bottomPadding: 28 + + header: StatusDialogHeader { + headline.title: d.editMode? qsTr("Edit saved address") : qsTr("Add new saved address") + headline.subtitle: d.editMode? d.name : "" + actions.closeButton.onClicked: root.close() + } + + function initWithParams(params = {}) { + d.storedName = params.name?? "" + d.storedColorId = params.colorId?? "" + d.storedChainShortNames = params.chainShortNames?? "" + + d.editMode = params.edit?? false + d.addAddress = params.addAddress?? false + d.name = d.storedName + nameInput.input.dirty = false + d.address = params.address?? Constants.zeroAddress + d.ens = params.ens?? "" + d.colorId = d.storedColorId + d.chainShortNames = d.storedChainShortNames + d.favourite = params.favourite?? false + + d.initialized = true + + if (d.colorId === "") { + colorSelection.selectedColorIndex = Math.floor(Math.random() * colorSelection.model.length) + } + else { + let ind = Utils.getColorIndexForId(d.colorId) + colorSelection.selectedColorIndex = ind + } + + if (!!d.ens) + addressInput.setPlainText(d.ens) + else + addressInput.setPlainText("%1%2" + .arg(d.chainShortNames) + .arg(d.address == Constants.zeroAddress? "" : d.address)) + + nameInput.input.edit.forceActiveFocus(Qt.MouseFocusReason) } QtObject { id: d - readonly property int validationMode: root.edit ? - StatusInput.ValidationMode.Always - : StatusInput.ValidationMode.OnlyWhenDirty - readonly property bool valid: addressInput.valid && nameInput.valid + + property bool editMode: false + property bool addAddress: false + property alias name: nameInput.text + property string address: Constants.zeroAddress // Setting as zero address since we don't have the address yet + property string ens: "" + property string colorId: "" + property string chainShortNames: "" + property bool favourite: false + + property string storedName: "" + property string storedColorId: "" + property string storedChainShortNames: "" + property bool chainShortNamesDirty: false - readonly property bool dirty: nameInput.input.dirty || chainShortNamesDirty + readonly property bool valid: addressInput.valid && nameInput.valid + readonly property bool dirty: nameInput.input.dirty && (!d.editMode || d.storedName !== d.name) + || chainShortNamesDirty && (!d.editMode || d.storedChainShortNames !== d.chainShortNames) + || d.colorId.toUpperCase() !== d.storedColorId.toUpperCase() + readonly property var chainPrefixRegexPattern: /[^:]+\:?|:/g - readonly property string visibleAddress: root.address == Constants.zeroAddress ? "" : root.address - readonly property bool addressInputIsENS: !!root.ens + readonly property bool addressInputIsENS: !!d.ens /// Ensures that the \c root.address and \c root.chainShortNames are not reset when the initial text is set property bool initialized: false @@ -69,60 +108,53 @@ StatusDialog { } function resetAddressValues() { - root.ens = "" - root.address = Constants.zeroAddress - root.chainShortNames = "" + d.ens = "" + d.address = Constants.zeroAddress + d.chainShortNames = "" allNetworksModelCopy.setEnabledNetworks([]) } } - width: 574 - height: 490 - - header: StatusDialogHeader { - headline.title: edit ? qsTr("Edit saved address") : qsTr("Add saved address") - headline.subtitle: edit ? name : "" - actions.closeButton.onClicked: root.close() - } - - onOpened: { - d.initialized = true - - if(edit || addAddress) { - if (root.ens) - addressInput.setPlainText(root.ens) - else - addressInput.setPlainText(root.chainShortNames + d.visibleAddress) - } - nameInput.input.edit.forceActiveFocus(Qt.MouseFocusReason) - } - Column { width: parent.width height: childrenRect.height - topPadding: Style.current.bigPadding - spacing: Style.current.bigPadding + spacing: Style.current.xlPadding StatusInput { id: nameInput implicitWidth: parent.width + charLimit: 24 input.edit.objectName: "savedAddressNameInput" placeholderText: qsTr("Address name") label: qsTr("Name") validators: [ StatusMinLengthValidator { minLength: 1 - errorMessage: qsTr("Name must not be blank") + errorMessage: qsTr("Please name your saved address") + }, + StatusValidator { + name: "check-for-no-emojis" + validate: (value) => { + return !Constants.regularExpressions.emoji.test(value) + } + errorMessage: Constants.errorMessages.emojRegExp }, StatusRegularExpressionValidator { - regularExpression: /^[^<>]+$/ - errorMessage: qsTr("This is not a valid account name") + regularExpression: Constants.regularExpressions.alphanumericalExpanded1 + errorMessage: Constants.errorMessages.alphanumericalExpanded1RegExp + }, + StatusValidator { + name: "check-saved-address-existence" + validate: (value) => { + return !RootStore.savedAddressNameExists(value) + || d.editMode && d.storedName == value + } + errorMessage: qsTr("Name already in use") } ] input.clearable: true input.rightPadding: 16 - validationMode: d.validationMode } StatusInput { @@ -134,7 +166,7 @@ StatusDialog { placeholderText: qsTr("Ethereum address") maximumHeight: 66 input.implicitHeight: Math.min(Math.max(input.edit.contentHeight + topPadding + bottomPadding, minimumHeight), maximumHeight) // setting height instead does not work - enabled: !(root.edit || root.addAddress) + enabled: !(d.editMode || d.addAddress) validators: [ StatusMinLengthValidator { minLength: 1 @@ -148,10 +180,9 @@ StatusDialog { } } ] - validationMode: d.validationMode input.edit.textFormat: TextEdit.RichText - input.asset.name: addressInput.valid && !root.edit ? "checkbox" : "" + input.asset.name: addressInput.valid && !d.editMode ? "checkbox" : "" input.asset.color: enabled ? Theme.palette.primaryColor1 : Theme.palette.baseColor1 input.rightPadding: 16 input.leftIcon: false @@ -185,14 +216,14 @@ StatusDialog { // Update root values if (Utils.isLikelyEnsName(plainText)) { - root.ens = plainText - root.address = Constants.zeroAddress - root.chainShortNames = "" + d.ens = plainText + d.address = Constants.zeroAddress + d.chainShortNames = "" } else { - root.ens = "" - root.address = prefixAndAddress.address - root.chainShortNames = prefixAndAddress.prefix + d.ens = "" + d.address = prefixAndAddress.address + d.chainShortNames = prefixAndAddress.prefix let prefixArrWithColumn = d.getPrefixArrayWithColumns(prefixAndAddress.prefix) if (!prefixArrWithColumn) @@ -253,10 +284,26 @@ StatusDialog { } } + StatusColorSelectorGrid { + id: colorSelection + objectName: "addSavedAddressColor" + width: parent.width + model: Theme.palette.customisationColorsArray + title.color: Theme.palette.directColor1 + title.font.pixelSize: Constants.addAccountPopup.labelFontSize1 + title.text: qsTr("Colour") + selectedColorIndex: -1 + + onSelectedColorChanged: { + d.colorId = Utils.getIdForColor(selectedColor) + } + } + StatusNetworkSelector { id: networkSelector objectName: "addSavedAddressNetworkSelector" title: "Network preference" + implicitWidth: parent.width enabled: addressInput.valid && !d.addressInputIsENS defaultItemText: "Add networks" defaultItemImageSource: "add" @@ -278,11 +325,11 @@ StatusDialog { onCountChanged: { if (!networkSelector.modelUpdateBlocked && d.initialized) { // Initially source model is empty, filter proxy is also empty, but does - // extra work and mistakenly overwrites root.chainShortNames property + // extra work and mistakenly overwrites d.chainShortNames property if (sourceModel.count != 0) { const prefixAndAddress = Utils.splitToChainPrefixAndAddress(addressInput.plainText) const syncedPrefix = addressInput.syncChainPrefixWithModel(prefixAndAddress.prefix, this) - root.chainShortNames = syncedPrefix + d.chainShortNames = syncedPrefix addressInput.setPlainText(syncedPrefix + prefixAndAddress.address) } } @@ -345,10 +392,10 @@ StatusDialog { footer: StatusDialogFooter { rightButtons: ObjectModel { StatusButton { - text: root.edit ? qsTr("Save") : qsTr("Add address") + text: d.editMode? qsTr("Save") : qsTr("Add address") enabled: d.valid && d.dirty onClicked: { - RootStore.createOrUpdateSavedAddress(name, address, root.favourite, chainShortNames, ens) + RootStore.createOrUpdateSavedAddress(d.name, d.address, d.ens, d.colorId, d.favourite, d.chainShortNames) root.close() } objectName: "addSavedAddress" diff --git a/ui/app/AppLayouts/Wallet/popups/TransactionAddressMenu.qml b/ui/app/AppLayouts/Wallet/popups/TransactionAddressMenu.qml index aae111a30f..d05f51690a 100644 --- a/ui/app/AppLayouts/Wallet/popups/TransactionAddressMenu.qml +++ b/ui/app/AppLayouts/Wallet/popups/TransactionAddressMenu.qml @@ -52,6 +52,7 @@ StatusMenu { property string addressName: "" property string addressEns: "" + property string colorId: "" property string addressChains: "" property string contractName: "" @@ -136,17 +137,19 @@ StatusMenu { if (isContact) { d.addressName = contactData.name } else { + // Revisit here after this issue (resolving source for preferred chains...): + // https://github.com/status-im/status-desktop/issues/13109 d.addressName = WalletStores.RootStore.getNameForWalletAddress(address) isWalletAccount = d.addressName.length > 0 if (!isWalletAccount) { - d.addressName = WalletStores.RootStore.getNameForSavedWalletAddress(address) + let savedAddress = WalletStores.RootStore.getSavedAddress(address) + d.addressName = savedAddress.name + d.addressEns = savedAddress.ens + d.colorId = savedAddress.colorId + d.addressChains = savedAddress.chainShortNames } } - d.addressName = contactData.isContact ? contactData.name : WalletStores.RootStore.getNameForAddress(address) - d.addressEns = RootStore.getEnsForSavedWalletAddress(address) - d.addressChains = RootStore.getChainShortNamesForSavedWalletAddress(address) - showOnEtherscanAction.enabled = true showOnArbiscanAction.enabled = address.includes(Constants.networkShortChainNames.arbiscan + ":") showOnOptimismAction.enabled = address.includes(Constants.networkShortChainNames.optimism + ":") @@ -329,6 +332,7 @@ StatusMenu { name: d.addressName, address: d.selectedAddress, ens: d.addressEns, + colorId: d.colorId, chainShortNames: d.addressChains }) } diff --git a/ui/app/AppLayouts/Wallet/stores/ActivityFiltersStore.qml b/ui/app/AppLayouts/Wallet/stores/ActivityFiltersStore.qml index dc82b2d9e9..edd4040aac 100644 --- a/ui/app/AppLayouts/Wallet/stores/ActivityFiltersStore.qml +++ b/ui/app/AppLayouts/Wallet/stores/ActivityFiltersStore.qml @@ -228,14 +228,6 @@ QtObject { activityController.updateFilter() } - function getChainShortNamesForSavedWalletAddress(address) { - return walletSectionSavedAddresses.getChainShortNamesForAddress(address) - } - - function getEnsForSavedWalletAddress(address) { - return walletSectionSavedAddresses.getEnsForAddress(address) - } - property var savedAddressesModel: walletSectionSavedAddresses.model property bool areTestNetworksEnabled: networksModule.areTestNetworksEnabled property var savedAddressList: SortFilterProxyModel { diff --git a/ui/app/AppLayouts/Wallet/stores/RootStore.qml b/ui/app/AppLayouts/Wallet/stores/RootStore.qml index 3b8358c8cc..29b922a633 100644 --- a/ui/app/AppLayouts/Wallet/stores/RootStore.qml +++ b/ui/app/AppLayouts/Wallet/stores/RootStore.qml @@ -18,6 +18,7 @@ QtObject { readonly property bool showAllAccounts: !root.showSavedAddresses && !root.selectedAddress property var lastCreatedSavedAddress + property var lastDeletedSavedAddress property bool addingSavedAddress: false property bool deletingSavedAddress: false @@ -249,18 +250,37 @@ QtObject { return globalUtils.hex2Dec(value) } - function getNameForSavedWalletAddress(address) { - return walletSectionSavedAddresses.getNameByAddress(address) - } - function getNameForWalletAddress(address) { return walletSectionAccounts.getNameByAddress(address) } + function getSavedAddress(address) { + const defaultValue = { + name: "", + address: "", + ens: "", + colorId: Constants.walletAccountColors.primary, + favourite: false, + chainShortNames: "", + isTest: false, + } + + const jsonObj = root.walletSectionSavedAddressesInst.getSavedAddressAsJson(address) + + try { + return JSON.parse(jsonObj) + } + catch (e) { + console.warn("error parsing saved address for address: ", address, " error: ", e.message) + return defaultValue + } + } + function getNameForAddress(address) { var name = getNameForWalletAddress(address) if (name.length === 0) { - name = getNameForSavedWalletAddress(address) + let savedAddress = getSavedAddress(address) + name = savedAddress.name } return name } @@ -330,9 +350,9 @@ QtObject { return walletSectionAccounts.getColorByAddress(address) } - function createOrUpdateSavedAddress(name, address, favourite, chainShortNames, ens) { + function createOrUpdateSavedAddress(name, address, ens, colorId, favourite, chainShortNames) { root.addingSavedAddress = true - walletSectionSavedAddresses.createOrUpdateSavedAddress(name, address, favourite, chainShortNames, ens) + walletSectionSavedAddresses.createOrUpdateSavedAddress(name, address, ens, colorId, favourite, chainShortNames) } function deleteSavedAddress(address, ens) { @@ -340,6 +360,10 @@ QtObject { walletSectionSavedAddresses.deleteSavedAddress(address, ens) } + function savedAddressNameExists(name) { + return walletSectionSavedAddresses.savedAddressNameExists(name) + } + function toggleNetwork(chainId) { networksModule.toggleNetwork(chainId) } diff --git a/ui/app/AppLayouts/Wallet/views/SavedAddresses.qml b/ui/app/AppLayouts/Wallet/views/SavedAddresses.qml index 91b34a68e0..02c7f75821 100644 --- a/ui/app/AppLayouts/Wallet/views/SavedAddresses.qml +++ b/ui/app/AppLayouts/Wallet/views/SavedAddresses.qml @@ -22,23 +22,11 @@ ColumnLayout { QtObject { id: d - function saveAddress(name, address, favourite, chainShortNames, ens) { - RootStore.createOrUpdateSavedAddress(name, address, favourite, chainShortNames, ens) - } - function reset() { RootStore.lastCreatedSavedAddress = undefined } } - SavedAddressesError { - id: error - Layout.alignment: Qt.AlignHCenter - text: RootStore.lastCreatedSavedAddress? RootStore.lastCreatedSavedAddress.error?? "" : "" - visible: !!text - height: visible ? 36 : 0 - } - ShapeRectangle { id: noSavedAddresses Layout.fillWidth: true @@ -54,7 +42,7 @@ ColumnLayout { } Item { - visible: error.visible || noSavedAddresses.visible || loadingIndicator.visible + visible: noSavedAddresses.visible || loadingIndicator.visible Layout.fillWidth: true Layout.fillHeight: true } @@ -77,6 +65,7 @@ ColumnLayout { address: model.address chainShortNames: model.chainShortNames ens: model.ens + colorId: model.colorId favourite: model.favourite store: RootStore contactsStore: root.contactsStore @@ -84,15 +73,12 @@ ColumnLayout { isSepoliaEnabled: RootStore.isSepoliaEnabled onOpenSendModal: root.sendModal.open(recipient); - saveAddress: function(name, address, favourite, chainShortNames, ens) { - d.saveAddress(name, address, favourite, chainShortNames, ens) - } - states: [ State { name: "highlighted" - when: RootStore.lastCreatedSavedAddress ? (RootStore.lastCreatedSavedAddress.address.toLowerCase() === address.toLowerCase() && - RootStore.lastCreatedSavedAddress.ens === ens) : false + when: RootStore.lastCreatedSavedAddress ? (!RootStore.lastCreatedSavedAddress.error && + RootStore.lastCreatedSavedAddress.address.toLowerCase() === address.toLowerCase() && + RootStore.lastCreatedSavedAddress.ens === ens) : false PropertyChanges { target: savedAddressDelegate; color: Theme.palette.baseColor2 } StateChangeScript { script: Qt.callLater(d.reset) diff --git a/ui/app/mainui/AppMain.qml b/ui/app/mainui/AppMain.qml index cea16afcf1..44c7774c1f 100644 --- a/ui/app/mainui/AppMain.qml +++ b/ui/app/mainui/AppMain.qml @@ -1700,7 +1700,7 @@ Item { } onLoaded: { - addEditSavedAddress.item.applyParams(addEditSavedAddress.params) + addEditSavedAddress.item.initWithParams(addEditSavedAddress.params) addEditSavedAddress.item.open() } @@ -1715,15 +1715,29 @@ Item { Connections { target: WalletStore.RootStore.walletSectionSavedAddressesInst - function onSavedAddressUpdated(address: string, ens: string, errorMsg: string) { + function onSavedAddressUpdated(name: string, address: string, ens: string, errorMsg: string) { WalletStore.RootStore.addingSavedAddress = false + WalletStore.RootStore.lastCreatedSavedAddress = { address: address, ens: ens, error: errorMsg } if (!!errorMsg) { - WalletStore.RootStore.lastCreatedSavedAddress = { error: errorMsg } + Global.displayToastMessage(qsTr("An error occurred while adding %1 addresses").arg(name), + "", + "warning", + false, + Constants.ephemeralNotificationType.danger, + "" + ) return } - WalletStore.RootStore.lastCreatedSavedAddress = { address: address, ens: ens } + Global.displayToastMessage(qsTr("%1 successfully added to your saved addresses").arg(name), + "", + "checkmark-circle", + false, + Constants.ephemeralNotificationType.success, + "" + ) + } } } @@ -1804,7 +1818,7 @@ Item { function onSavedAddressDeleted(address: string, ens: string, errorMsg: string) { WalletStore.RootStore.deletingSavedAddress = false - WalletStore.RootStore.lastCreatedSavedAddress = { error: errorMsg } + WalletStore.RootStore.lastDeletedSavedAddress = { address: address, ens: ens, error: errorMsg } } } } diff --git a/ui/imports/shared/controls/TransactionAddress.qml b/ui/imports/shared/controls/TransactionAddress.qml index 1dfc299be8..bf1336666b 100644 --- a/ui/imports/shared/controls/TransactionAddress.qml +++ b/ui/imports/shared/controls/TransactionAddress.qml @@ -90,7 +90,11 @@ Item { } function refreshSavedAddressName() { - d.savedAddressName = !!root.rootStore ? root.rootStore.getNameForSavedWalletAddress(root.address) : "" + if (!root.rootStore) { + return + } + let savedAddress = root.rootStore.getSavedAddress(root.address) + d.savedAddressName = savedAddress.name } function refreshWalletAddress() { diff --git a/ui/imports/shared/popups/addaccount/states/Main.qml b/ui/imports/shared/popups/addaccount/states/Main.qml index beba5217ab..d892b1ec8a 100644 --- a/ui/imports/shared/popups/addaccount/states/Main.qml +++ b/ui/imports/shared/popups/addaccount/states/Main.qml @@ -26,7 +26,7 @@ Item { colorSelection.selectedColorIndex = Math.floor(Math.random() * colorSelection.model.length) } else { - let ind = d.evaluateColorIndex(Utils.getColorForId(root.store.addAccountModule.selectedColorId)) + let ind = Utils.getColorIndexForId(root.store.addAccountModule.selectedColorId) colorSelection.selectedColorIndex = ind } @@ -48,15 +48,6 @@ Item { id: d readonly property bool isEdit: root.store.editMode - function evaluateColorIndex(color) { - for (let i = 0; i < Theme.palette.customisationColorsArray.length; i++) { - if(Theme.palette.customisationColorsArray[i] === color) { - return i - } - } - return 0 - } - function openEmojiPopup(showLeft) { if (!root.store.emojiPopup) { return diff --git a/ui/imports/shared/stores/RootStore.qml b/ui/imports/shared/stores/RootStore.qml index ebe4c4a3f8..9810919b23 100644 --- a/ui/imports/shared/stores/RootStore.qml +++ b/ui/imports/shared/stores/RootStore.qml @@ -179,18 +179,6 @@ QtObject { return "" } - function getNameForSavedWalletAddress(address) { - return walletSectionSavedAddresses.getNameByAddress(address) - } - - function getChainShortNamesForSavedWalletAddress(address) { - return walletSectionSavedAddresses.getChainShortNamesForAddress(address) - } - - function getEnsForSavedWalletAddress(address) { - return walletSectionSavedAddresses.getEnsForAddress(address) - } - function getCurrencyAmount(amount, symbol) { return currencyStore.getCurrencyAmount(amount, symbol) } diff --git a/ui/imports/shared/views/profile/ProfileShowcaseView.qml b/ui/imports/shared/views/profile/ProfileShowcaseView.qml index 9c435add93..f763752664 100644 --- a/ui/imports/shared/views/profile/ProfileShowcaseView.qml +++ b/ui/imports/shared/views/profile/ProfileShowcaseView.qml @@ -159,7 +159,19 @@ Control { } delegate: StatusListItem { id: accountDelegate - property bool saved: root.walletStore.getNameForSavedWalletAddress(model.address) !== "" + property bool saved: { + let savedAddress = root.walletStore.getSavedAddress(model.address) + if (savedAddress.name !== "") + return true + + if (!!root.walletStore.lastCreatedSavedAddress) { + if (root.walletStore.lastCreatedSavedAddress.address.toLowerCase() === model.address.toLowerCase()) { + return !!root.walletStore.lastCreatedSavedAddress.error + } + } + + return false + } border.width: 1 border.color: Theme.palette.baseColor2 width: ListView.view.width @@ -184,14 +196,11 @@ Control { enabled: !accountDelegate.saved text: accountDelegate.saved ? qsTr("Address saved") : qsTr("Save Address") onClicked: { - accountDelegate.saved = root.walletStore.createOrUpdateSavedAddress(model.name, model.address, false) === "" - Global.displayToastMessage(qsTr("%1 saved to your wallet").arg(accountDelegate.subTitle), - qsTr("Go to your wallet"), - "wallet", - false, - Constants.ephemeralNotificationType.normal, - `#${Constants.appSection.wallet}` // internal link to wallet section - ) + // From here, we should just run add saved address popup + Global.openAddEditSavedAddressesPopup({ + addAddress: true, + address: model.address + }) } }, StatusFlatRoundButton { diff --git a/ui/imports/utils/Constants.qml b/ui/imports/utils/Constants.qml index f8d020a81e..63042765cb 100644 --- a/ui/imports/utils/Constants.qml +++ b/ui/imports/utils/Constants.qml @@ -679,18 +679,22 @@ QtObject { readonly property QtObject regularExpressions: QtObject { readonly property var alphanumerical: /^$|^[a-zA-Z0-9]+$/ readonly property var alphanumericalExpanded: /^$|^[a-zA-Z0-9\-_.\u0020]+$/ + readonly property var alphanumericalExpanded1: /^[a-zA-Z0-9\-_]+(?: [a-zA-Z0-9\-_]+)*$/ readonly property var alphanumericalWithSpace: /^$|^[a-zA-Z0-9\s]+$/ readonly property var asciiPrintable: /^$|^[!-~]+$/ readonly property var ascii: /^$|^[\x00-\x7F]+$/ readonly property var capitalOnly: /^$|^[A-Z]+$/ readonly property var numerical: /^$|^[0-9]+$/ + readonly property var emoji: /\ud83c\udff4(\udb40[\udc61-\udc7a])+\udb40\udc7f|(\ud83c[\udde6-\uddff]){2}|([\#\*0-9]\ufe0f?\u20e3)|(\u00a9|\u00ae|[\u203c\u2049\u20e3\u2122\u2139\u2194-\u2199\u21a9\u21aa\u231a\u231b\u2328\u23cf\u23e9-\u23fa\u24c2\u25aa\u25ab\u25b6\u25c0\u25fb-\u25fe\u2600-\u2604\u260e\u2611\u2614\u2615\u2618\u261d\u2620\u2622\u2623\u2626\u262a\u262e\u262f\u2638-\u263a\u2640\u2642\u2648-\u2653\u265f\u2660\u2663\u2665\u2666\u2668\u267b\u267e\u267f\u2692-\u2697\u2699\u269b\u269c\u26a0\u26a1\u26a7\u26aa\u26ab\u26b0\u26b1\u26bd\u26be\u26c4\u26c5\u26c8\u26ce\u26cf\u26d1\u26d3\u26d4\u26e9\u26ea\u26f0-\u26f5\u26f7-\u26fa\u26fd\u2702\u2705\u2708-\u270d\u270f\u2712\u2714\u2716\u271d\u2721\u2728\u2733\u2734\u2744\u2747\u274c\u274e\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27a1\u27b0\u27bf\u2934\u2935\u2b05-\u2b07\u2b1b\u2b1c\u2b50\u2b55\u3030\u303d\u3297\u3299]|\ud83c[\udc04\udccf\udd70\udd71\udd7e\udd7f\udd8e\udd91-\udd9a\udde6-\uddff\ude01\ude02\ude1a\ude2f\ude32-\ude3a\ude50\ude51\udf00-\udf21\udf24-\udf93\udf96\udf97\udf99-\udf9b\udf9e-\udff0\udff3-\udff5\udff7-\udfff]|\ud83d[\udc00-\udcfd\udcff-\udd3d\udd49-\udd4e\udd50-\udd67\udd6f\udd70\udd73-\udd7a\udd87\udd8a-\udd8d\udd90\udd95\udd96\udda4\udda5\udda8\uddb1\uddb2\uddbc\uddc2-\uddc4\uddd1-\uddd3\udddc-\uddde\udde1\udde3\udde8\uddef\uddf3\uddfa-\ude4f\ude80-\udec5\udecb-\uded2\uded5-\uded7\udedc-\udee5\udee9\udeeb\udeec\udef0\udef3-\udefc\udfe0-\udfeb\udff0]|\ud83e[\udd0c-\udd3a\udd3c-\udd45\udd47-\ude7c\ude80-\ude88\ude90-\udebd\udebf-\udec5\udece-\udedb\udee0-\udee8\udef0-\udef8])((\ud83c[\udffb-\udfff])?(\ud83e[\uddb0-\uddb3])?(\ufe0f?\u200d([\u2000-\u3300]|[\ud83c-\ud83e][\ud000-\udfff])\ufe0f?)?)*/g; } readonly property QtObject errorMessages: QtObject { readonly property string alphanumericalRegExp: qsTr("Only letters and numbers allowed") - readonly property string alphanumericalExpandedRegExp: qsTr("Only letters, numbers, underscores, whitespaces and hyphens allowed") + readonly property string alphanumericalExpandedRegExp: qsTr("Only letters, numbers, underscores, periods, whitespaces and hyphens allowed") + readonly property string alphanumericalExpanded1RegExp: qsTr("Only letters, numbers, underscores, whitespaces and hyphens allowed") readonly property string alphanumericalWithSpaceRegExp: qsTr("Special characters are not allowed") readonly property string asciiRegExp: qsTr("Only letters, numbers and ASCII characters allowed") + readonly property string emojRegExp: qsTr("Name is too cool (use letters, numbers, underscores, whitespaces and hyphens only)") } readonly property QtObject socialLinkType: QtObject { diff --git a/ui/imports/utils/Utils.qml b/ui/imports/utils/Utils.qml index 39ec5c8fe7..06362ec134 100644 --- a/ui/imports/utils/Utils.qml +++ b/ui/imports/utils/Utils.qml @@ -836,6 +836,16 @@ QtObject { return Theme.palette.customisationColors.blue } + function getColorIndexForId(colorId) { + let color = getColorForId(colorId) + for (let i = 0; i < Theme.palette.customisationColorsArray.length; i++) { + if(Theme.palette.customisationColorsArray[i] === color) { + return i + } + } + return 0 + } + function getPathForDisplay(path) { return path.split("/").join(" / ") } diff --git a/vendor/status-go b/vendor/status-go index 843bae5659..a8357dceac 160000 --- a/vendor/status-go +++ b/vendor/status-go @@ -1 +1 @@ -Subproject commit 843bae56597ecf3811d724504bd0216b867979f7 +Subproject commit a8357dceacd1b737952660272bf80251df19b8f8