From a468635ddc51cec353e5c0c4cc100b5a71fd3079 Mon Sep 17 00:00:00 2001 From: Khushboo Mehta Date: Tue, 27 Jun 2023 21:56:44 +0200 Subject: [PATCH] feat(@desktop/wallet): Networks - New List UX with link mainnet/testnet + testnet mode enable/disable fixes #11252 --- src/app_service/common/network_constants.nim | 68 +++++++++++-------- src/app_service/service/network/dto.nim | 8 ++- src/app_service/service/network/service.nim | 32 +++++---- .../service/network_connection/service.nim | 12 ++-- src/backend/backend.nim | 3 +- storybook/pages/AlertPopupPage.qml | 2 +- storybook/pages/StatusButtonPage.qml | 2 +- .../global_shared/scripts/wallet_names.py | 4 +- .../src/StatusQ/Controls/StatusBaseButton.qml | 3 +- .../src/StatusQ/Controls/StatusButton.qml | 16 +++-- .../panels/MintTokensSettingsPanel.qml | 1 + .../controls/WalletNetworkDelegate.qml | 7 ++ .../AppLayouts/Profile/views/WalletView.qml | 12 ---- .../Profile/views/wallet/NetworksView.qml | 50 +++++++++++++- ui/app/mainui/AppMain.qml | 41 ++--------- ui/app/mainui/Popups.qml | 29 ++++++++ ui/imports/shared/panels/ModuleWarning.qml | 12 ++++ .../shared}/popups/AlertPopup.qml | 30 +++++++- ui/imports/shared/popups/qmldir | 1 + ui/imports/utils/Global.qml | 2 + vendor/status-go | 2 +- 21 files changed, 221 insertions(+), 116 deletions(-) rename ui/{app/AppLayouts/Communities => imports/shared}/popups/AlertPopup.qml (59%) diff --git a/src/app_service/common/network_constants.nim b/src/app_service/common/network_constants.nim index f9668cded1..b0f73606f1 100644 --- a/src/app_service/common/network_constants.nim +++ b/src/app_service/common/network_constants.nim @@ -97,7 +97,7 @@ let DEFAULT_TORRENT_CONFIG_TORRENTDIR* = joinPath(main_constants.defaultDataDir( var NETWORKS* = %* [ { "chainId": 1, - "chainName": "Ethereum Mainnet", + "chainName": "Mainnet", "rpcUrl": "https://eth-archival.gateway.pokt.network/v1/lb/" & POKT_TOKEN_RESOLVED, "fallbackUrl": "https://mainnet.infura.io/v3/" & INFURA_TOKEN_RESOLVED, "blockExplorerUrl": "https://etherscan.io/", @@ -110,22 +110,24 @@ var NETWORKS* = %* [ "isTest": false, "layer": 1, "enabled": true, + "relatedChainId": 5, }, { "chainId": 5, - "chainName": "Goerli", + "chainName": "Mainnet", "rpcUrl": "https://goerli-archival.gateway.pokt.network/v1/lb/" & POKT_TOKEN_RESOLVED, "fallbackUrl": "https://goerli.infura.io/v3/" & INFURA_TOKEN_RESOLVED, "blockExplorerUrl": "https://goerli.etherscan.io/", - "iconUrl": "network/Network=Testnet", - "chainColor": "#939BA1", - "shortName": "goEth", + "iconUrl": "network/Network=Ethereum", + "chainColor": "#627EEA", + "shortName": "eth", "nativeCurrencyName": "Ether", "nativeCurrencySymbol": "ETH", "nativeCurrencyDecimals": 18, "isTest": true, "layer": 1, "enabled": true, + "relatedChainId": 1, }, { "chainId": 10, @@ -142,22 +144,24 @@ var NETWORKS* = %* [ "isTest": false, "layer": 2, "enabled": true, + "relatedChainId": 420, }, { "chainId": 420, - "chainName": "Optimism Goerli Testnet", + "chainName": "Optimism", "rpcUrl": "https://optimism-goerli.infura.io/v3/" & INFURA_TOKEN_RESOLVED, "fallbackUrl": "", "blockExplorerUrl": "https://goerli-optimism.etherscan.io/", - "iconUrl": "network/Network=Testnet", - "chainColor": "#939BA1", - "shortName": "goOpt", + "iconUrl": "network/Network=Optimism", + "chainColor": "#E90101", + "shortName": "opt", "nativeCurrencyName": "Ether", "nativeCurrencySymbol": "ETH", "nativeCurrencyDecimals": 18, "isTest": true, "layer": 2, "enabled": false, + "relatedChainId": 10, }, { "chainId": 42161, @@ -174,22 +178,24 @@ var NETWORKS* = %* [ "isTest": false, "layer": 2, "enabled": true, + "relatedChainId": 421613, }, { "chainId": 421613, - "chainName": "Arbitrum Goerli", + "chainName": "Arbitrum", "rpcUrl": "https://arbitrum-goerli.infura.io/v3/" & INFURA_TOKEN_RESOLVED, "fallbackUrl": "", "blockExplorerUrl": "https://goerli.arbiscan.io/", - "iconUrl": "network/Network=Testnet", - "chainColor": "#939BA1", - "shortName": "goArb", + "iconUrl": "network/Network=Arbitrum", + "chainColor": "#51D0F0", + "shortName": "arb", "nativeCurrencyName": "Ether", "nativeCurrencySymbol": "ETH", "nativeCurrencyDecimals": 18, "isTest": true, "layer": 2, "enabled": false, + "relatedChainId": 42161, } ] @@ -197,7 +203,7 @@ if GANACHE_NETWORK_RPC_URL != "": NETWORKS = %* [ { "chainId": 1, - "chainName": "Ethereum Mainnet", + "chainName": "Mainnet", "rpcUrl": GANACHE_NETWORK_RPC_URL, "fallbackUrl": GANACHE_NETWORK_RPC_URL, "blockExplorerUrl": "https://etherscan.io/", @@ -215,17 +221,18 @@ if GANACHE_NETWORK_RPC_URL != "": "symbol": "SNT", "address": "0x8571Ddc46b10d31EF963aF49b6C7799Ea7eff818" } - ] + ], + "relatedChainId": 5, }, { "chainId": 5, - "chainName": "Goerli", + "chainName": "Mainnet", "rpcUrl": GANACHE_NETWORK_RPC_URL, "fallbackUrl": GANACHE_NETWORK_RPC_URL, "blockExplorerUrl": "https://goerli.etherscan.io/", - "iconUrl": "network/Network=Testnet", - "chainColor": "#939BA1", - "shortName": "goEth", + "iconUrl": "network/Network=Ethereum", + "chainColor": "#627EEA", + "shortName": "eth", "nativeCurrencyName": "Ether", "nativeCurrencySymbol": "ETH", "nativeCurrencyDecimals": 18, @@ -237,7 +244,8 @@ if GANACHE_NETWORK_RPC_URL != "": "symbol": "STT", "address": "0x8571Ddc46b10d31EF963aF49b6C7799Ea7eff818" } - ] + ], + "relatedChainId": 1, }, { "chainId": 10, @@ -254,22 +262,24 @@ if GANACHE_NETWORK_RPC_URL != "": "isTest": false, "layer": 2, "enabled": true, + "relatedChainId": 420, }, { "chainId": 420, - "chainName": "Optimism Goerli Testnet", + "chainName": "Optimism", "rpcUrl": GANACHE_NETWORK_RPC_URL, "fallbackUrl": GANACHE_NETWORK_RPC_URL, "blockExplorerUrl": "https://goerli-optimism.etherscan.io/", - "iconUrl": "network/Network=Testnet", - "chainColor": "#939BA1", - "shortName": "goOpt", + "iconUrl": "network/Network=Optimism", + "chainColor": "#E90101", + "shortName": "opt", "nativeCurrencyName": "Ether", "nativeCurrencySymbol": "ETH", "nativeCurrencyDecimals": 18, "isTest": true, "layer": 2, "enabled": false, + "relatedChainId": 10, }, { "chainId": 42161, @@ -286,22 +296,24 @@ if GANACHE_NETWORK_RPC_URL != "": "isTest": false, "layer": 2, "enabled": true, + "relatedChainId": 421613, }, { "chainId": 421613, - "chainName": "Arbitrum Goerli", + "chainName": "Arbitrum", "rpcUrl": GANACHE_NETWORK_RPC_URL, "fallbackUrl": GANACHE_NETWORK_RPC_URL, "blockExplorerUrl": "https://goerli.arbiscan.io/", - "iconUrl": "network/Network=Testnet", - "chainColor": "#939BA1", - "shortName": "goArb", + "iconUrl": "network/Network=Arbitrum", + "chainColor": "#51D0F0", + "shortName": "arb", "nativeCurrencyName": "Ether", "nativeCurrencySymbol": "ETH", "nativeCurrencyDecimals": 18, "isTest": true, "layer": 2, "enabled": false, + "relatedChainId": 42161, } ] diff --git a/src/app_service/service/network/dto.nim b/src/app_service/service/network/dto.nim index 0f2748baaf..8f460f91c6 100644 --- a/src/app_service/service/network/dto.nim +++ b/src/app_service/service/network/dto.nim @@ -18,6 +18,11 @@ type NetworkDto* = ref object enabled* {.serializedFieldName("enabled").}: bool chainColor* {.serializedFieldName("chainColor").}: string shortName* {.serializedFieldName("shortName").}: string + relatedChainId* {.serializedFieldName("relatedChainId").}: int + +type CombinedNetworkDto* = ref object + prod* {.serializedFieldName("Prod").}: NetworkDto + test* {.serializedFieldName("Test").}: NetworkDto proc `$`*(self: NetworkDto): string = return fmt"""Network( @@ -34,7 +39,8 @@ proc `$`*(self: NetworkDto): string = nativeCurrencySymbol:{self.nativeCurrencySymbol}, isTest:{self.isTest}, enabled:{self.enabled}, chainColor:{self.chainColor}, - shortName:{self.shortName} + shortName:{self.shortName}, + relatedChainId:{self.relatedChainId} )""" proc hash*(self: NetworkDto): Hash = diff --git a/src/app_service/service/network/service.nim b/src/app_service/service/network/service.nim index b72e42725a..da1f98304f 100644 --- a/src/app_service/service/network/service.nim +++ b/src/app_service/service/network/service.nim @@ -14,7 +14,7 @@ logScope: type Service* = ref object of RootObj events: EventEmitter - networks: seq[NetworkDto] + networks: seq[CombinedNetworkDto] networksInited: bool dirty: Atomic[bool] settingsService: settings_service.Service @@ -31,16 +31,16 @@ proc newService*(events: EventEmitter, settingsService: settings_service.Service proc init*(self: Service) = discard -proc fetchNetworks*(self: Service, useCached: bool = true): seq[NetworkDto] = +proc fetchNetworks*(self: Service, useCached: bool = true): seq[CombinedNetworkDto] = let cacheIsDirty = not self.networksInited or self.dirty.load if useCached and not cacheIsDirty: result = self.networks else: - let response = backend.getEthereumChains(false) + let response = backend.getEthereumChains() if not response.error.isNil: raise newException(Exception, "Error getting networks: " & response.error.message) result = if response.result.isNil or response.result.kind == JNull: @[] - else: Json.decode($response.result, seq[NetworkDto], allowUnknownFields = true) + else: Json.decode($response.result, seq[CombinedNetworkDto], allowUnknownFields = true) self.dirty.store(false) self.networks = result self.networksInited = true @@ -49,11 +49,10 @@ proc getNetworks*(self: Service): seq[NetworkDto] = let testNetworksEnabled = self.settingsService.areTestNetworksEnabled() for network in self.fetchNetworks(): - if testNetworksEnabled and network.isTest: - result.add(network) - - if not testNetworksEnabled and not network.isTest: - result.add(network) + if testNetworksEnabled: + result.add(network.test) + else: + result.add(network.prod) proc upsertNetwork*(self: Service, network: NetworkDto) = discard backend.addEthereumChain(backend.Network( @@ -71,6 +70,7 @@ proc upsertNetwork*(self: Service, network: NetworkDto) = enabled: network.enabled, chainColor: network.chainColor, shortName: network.shortName, + relatedChainID: network.relatedChainID, )) self.dirty.store(true) @@ -79,14 +79,20 @@ proc deleteNetwork*(self: Service, network: NetworkDto) = self.dirty.store(true) proc getNetwork*(self: Service, chainId: int): NetworkDto = + let testNetworksEnabled = self.settingsService.areTestNetworksEnabled() for network in self.fetchNetworks(): - if chainId == network.chainId: - return network + let net = if testNetworksEnabled: network.test + else: network.prod + if chainId == net.chainId: + return net proc getNetwork*(self: Service, networkType: NetworkType): NetworkDto = + let testNetworksEnabled = self.settingsService.areTestNetworksEnabled() for network in self.fetchNetworks(): - if networkType.toChainId() == network.chainId: - return network + let net = if testNetworksEnabled: network.test + else: network.prod + if networkType.toChainId() == net.chainId: + return net # Will be removed, this is used in case of legacy chain Id return NetworkDto(chainId: networkType.toChainId()) diff --git a/src/app_service/service/network_connection/service.nim b/src/app_service/service/network_connection/service.nim index 38442209ac..9696b401c6 100644 --- a/src/app_service/service/network_connection/service.nim +++ b/src/app_service/service/network_connection/service.nim @@ -120,19 +120,15 @@ QtObject: var allDown: bool = true var chaindIdsDown: seq[int] = @[] - # checking all down we check all networks and for chainIds to be displayed as down - # we only check for networks currently active (for test net only testnet networks etc...) - let currentChainIds = self.networkService.getNetworks().map(a => a.chainId) - let allChainIds = self.networkService.fetchNetworks().map(a => a.chainId) + let allChainIds = self.networkService.getNetworks().map(a => a.chainId) if chainStatusTable.kind != JNull: for id in allChainIds: if chainStatusTable[$id].kind != JNull: let isDown = self.getIsDown(chainStatusTable[$id].getStr) - if not isDown: + if isDown: + chaindIdsDown.add(id) + else: allDown = false - if currentChainIds.contains(id): - if isDown: - chaindIdsDown.add(id) return (allDown, chaindIdsDown) proc getFormattedStringForChainIds(self: Service, chainIds: seq[int]): string = diff --git a/src/backend/backend.nim b/src/backend/backend.nim index fc0c6cacb3..f14ceb95bb 100644 --- a/src/backend/backend.nim +++ b/src/backend/backend.nim @@ -49,6 +49,7 @@ type enabled* {.serializedFieldName("enabled").}: bool chainColor* {.serializedFieldName("chainColor").}: string shortName* {.serializedFieldName("shortName").}: string + relatedChainID* {.serializedFieldName("relatedChainID").}: int ActivityCenterNotificationsRequest* = ref object of RootObj cursor* {.serializedFieldName("cursor").}: string @@ -64,7 +65,7 @@ rpc(clientVersion, "web3"): discard rpc(getEthereumChains, "wallet"): - onlyEnabled: bool + discard rpc(addEthereumChain, "wallet"): network: Network diff --git a/storybook/pages/AlertPopupPage.qml b/storybook/pages/AlertPopupPage.qml index 53cc9807d5..abf7de9b76 100644 --- a/storybook/pages/AlertPopupPage.qml +++ b/storybook/pages/AlertPopupPage.qml @@ -5,7 +5,7 @@ import QtQuick.Layouts 1.14 import Storybook 1.0 import Models 1.0 -import AppLayouts.Communities.popups 1.0 +import shared.popups 1.0 SplitView { Logs { id: logs } diff --git a/storybook/pages/StatusButtonPage.qml b/storybook/pages/StatusButtonPage.qml index 50e3df1d6f..f9a8eeb702 100644 --- a/storybook/pages/StatusButtonPage.qml +++ b/storybook/pages/StatusButtonPage.qml @@ -238,7 +238,7 @@ SplitView { Label { text: "Type:" } ComboBox { id: ctrlType - model: ["Normal", "Danger", "Primary"] // enum StatusBaseButton.Type.xxx + model: ["Normal", "Danger", "Primary", "Warning"] // enum StatusBaseButton.Type.xxx } } RowLayout { diff --git a/test/ui-test/testSuites/global_shared/scripts/wallet_names.py b/test/ui-test/testSuites/global_shared/scripts/wallet_names.py index 2d4fdfa2e6..f3f8a06621 100644 --- a/test/ui-test/testSuites/global_shared/scripts/wallet_names.py +++ b/test/ui-test/testSuites/global_shared/scripts/wallet_names.py @@ -168,10 +168,10 @@ mainWallet_Saved_Addreses_Popup_Address_Add_Button = {"container": statusDesktop mainWallet_Saved_Addreses_Popup_Add_Network_Selector = {"container": statusDesktop_mainWindow, "objectName": "addSavedAddressNetworkSelector", "type": "StatusNetworkSelector", "visible": True} mainWallet_Saved_Addreses_Popup_Add_Network_Button = {"container": statusDesktop_mainWindow_overlay, "objectName": "addNetworkTagItemButton", "type": "StatusRoundButton", "visible": True} mainWallet_Saved_Addreses_Popup_Add_Network_Selector_Tag = {"container": statusDesktop_mainWindow_overlay, "objectName": "networkSelectorTag", "type": "StatusNetworkListItemTag"} -mainWallet_Saved_Addresses_Popup_Add_Network_Selector_Mainnet_checkbox = {"container": statusDesktop_mainWindow_overlay, "objectName": "networkSelectionCheckbox_Ethereum Mainnet", "type": "StatusCheckBox", "visible": True} +mainWallet_Saved_Addresses_Popup_Add_Network_Selector_Mainnet_checkbox = {"container": statusDesktop_mainWindow_overlay, "objectName": "networkSelectionCheckbox_Mainnet", "type": "StatusCheckBox", "visible": True} mainWallet_Saved_Addresses_Popup_Add_Network_Selector_Optimism_checkbox = {"container": statusDesktop_mainWindow_overlay, "objectName": "networkSelectionCheckbox_Optimism", "type": "StatusCheckBox", "visible": True} mainWallet_Saved_Addresses_Popup_Add_Network_Selector_Arbitrum_checkbox = {"container": statusDesktop_mainWindow_overlay, "objectName": "networkSelectionCheckbox_Arbitrum", "type": "StatusCheckBox", "visible": True} -mainWallet_Saved_Addresses_Popup_Network_Selector_Mainnet_network_tag = {"container": statusDesktop_mainWindow_overlay, "objectName": "networkTagRectangle_Ethereum Mainnet", "type": "Rectangle", "visible": True} +mainWallet_Saved_Addresses_Popup_Network_Selector_Mainnet_network_tag = {"container": statusDesktop_mainWindow_overlay, "objectName": "networkTagRectangle_Mainnet", "type": "Rectangle", "visible": True} mainWallet_Saved_Addresses_Popup_Network_Selector_Optimism_network_tag = {"container": statusDesktop_mainWindow_overlay, "objectName": "networkTagRectangle_Optimism", "type": "Rectangle", "visible": True} mainWallet_Saved_Addresses_Popup_Network_Selector_Arbitrum_network_tag = {"container": statusDesktop_mainWindow_overlay, "objectName": "networkTagRectangle_Arbitrum", "type": "Rectangle", "visible": True} # Collectibles view diff --git a/ui/StatusQ/src/StatusQ/Controls/StatusBaseButton.qml b/ui/StatusQ/src/StatusQ/Controls/StatusBaseButton.qml index f92da20e37..ee3d449bbf 100644 --- a/ui/StatusQ/src/StatusQ/Controls/StatusBaseButton.qml +++ b/ui/StatusQ/src/StatusQ/Controls/StatusBaseButton.qml @@ -19,7 +19,8 @@ Button { enum Type { Normal, Danger, - Primary + Primary, + Warning } enum TextPosition { diff --git a/ui/StatusQ/src/StatusQ/Controls/StatusButton.qml b/ui/StatusQ/src/StatusQ/Controls/StatusButton.qml index 95c08ef0cb..80b84b1b94 100644 --- a/ui/StatusQ/src/StatusQ/Controls/StatusButton.qml +++ b/ui/StatusQ/src/StatusQ/Controls/StatusButton.qml @@ -6,15 +6,19 @@ StatusBaseButton { id: statusButton normalColor: type === StatusBaseButton.Type.Primary ? Theme.palette.primaryColor1 : - type === StatusBaseButton.Type.Normal ? Theme.palette.primaryColor3 - : Theme.palette.dangerColor3 + type === StatusBaseButton.Type.Normal ? Theme.palette.primaryColor3 : + type === StatusBaseButton.Type.Warning ? Theme.palette.warningColor3 + : Theme.palette.dangerColor3 hoverColor: type === StatusBaseButton.Type.Primary ? Theme.palette.hoverColor(normalColor) : - type === StatusBaseButton.Type.Normal ? Theme.palette.primaryColor2 - : Theme.palette.dangerColor2 + type === StatusBaseButton.Type.Normal ? Theme.palette.primaryColor2 : + type === StatusBaseButton.Type.Warning ? Theme.palette.warningColor2 + : Theme.palette.dangerColor2 + disabledColor: Theme.palette.baseColor2 textColor: type === StatusBaseButton.Type.Primary ? Theme.palette.white : - type === StatusBaseButton.Type.Normal ? Theme.palette.primaryColor1 - : Theme.palette.dangerColor1 + type === StatusBaseButton.Type.Normal ? Theme.palette.primaryColor1 : + type === StatusBaseButton.Type.Warning ? Theme.palette.warningColor1 + : Theme.palette.dangerColor1 disabledTextColor: Theme.palette.baseColor1 } diff --git a/ui/app/AppLayouts/Communities/panels/MintTokensSettingsPanel.qml b/ui/app/AppLayouts/Communities/panels/MintTokensSettingsPanel.qml index 5ddd037267..e9839c3044 100644 --- a/ui/app/AppLayouts/Communities/panels/MintTokensSettingsPanel.qml +++ b/ui/app/AppLayouts/Communities/panels/MintTokensSettingsPanel.qml @@ -15,6 +15,7 @@ import AppLayouts.Communities.views 1.0 import shared.controls 1.0 import utils 1.0 +import shared.popups 1.0 import SortFilterProxyModel 0.2 StackView { diff --git a/ui/app/AppLayouts/Profile/controls/WalletNetworkDelegate.qml b/ui/app/AppLayouts/Profile/controls/WalletNetworkDelegate.qml index a08f3f44ec..e2ce9e4195 100644 --- a/ui/app/AppLayouts/Profile/controls/WalletNetworkDelegate.qml +++ b/ui/app/AppLayouts/Profile/controls/WalletNetworkDelegate.qml @@ -6,6 +6,7 @@ import StatusQ.Core.Theme 0.1 StatusListItem { property var network + property bool areTestNetworksEnabled title: network.chainName asset.name: Style.svg(network.iconUrl) asset.isImage: true @@ -13,6 +14,12 @@ StatusListItem { leftPadding: Style.current.padding rightPadding: Style.current.padding components: [ + StatusBaseText { + text: qsTr("Goerli testnet active") + font.pixelSize: 15 + color: Theme.palette.baseColor1 + visible: areTestNetworksEnabled + }, StatusIcon { icon: "next" color: Theme.palette.baseColor1 diff --git a/ui/app/AppLayouts/Profile/views/WalletView.qml b/ui/app/AppLayouts/Profile/views/WalletView.qml index 6bb89eeecf..29dd1ffebf 100644 --- a/ui/app/AppLayouts/Profile/views/WalletView.qml +++ b/ui/app/AppLayouts/Profile/views/WalletView.qml @@ -54,8 +54,6 @@ SettingsContentBase { if(currentIndex == root.networksViewIndex) { root.rootStore.backButtonName = qsTr("Wallet") root.sectionTitle = qsTr("Networks") - - root.titleRowComponentLoader.sourceComponent = testnetModeSwitchComponent } else if(currentIndex == root.accountViewIndex) { root.rootStore.backButtonName = qsTr("Wallet") @@ -118,16 +116,6 @@ SettingsContentBase { walletStore: root.walletStore } - Component { - id: testnetModeSwitchComponent - StatusSwitch { - objectName: "testnetModeSwitch" - text: qsTr("Testnet Mode") - checked: walletStore.areTestNetworksEnabled - onClicked: walletStore.toggleTestNetworksEnabled() - } - } - Component { id: addNewAccountButtonComponent StatusButton { diff --git a/ui/app/AppLayouts/Profile/views/wallet/NetworksView.qml b/ui/app/AppLayouts/Profile/views/wallet/NetworksView.qml index 53e2da6a49..cf21ddc233 100644 --- a/ui/app/AppLayouts/Profile/views/wallet/NetworksView.qml +++ b/ui/app/AppLayouts/Profile/views/wallet/NetworksView.qml @@ -2,9 +2,14 @@ import QtQuick 2.13 import SortFilterProxyModel 0.2 import shared.status 1.0 +import shared.popups 1.0 +import shared.panels 1.0 + import StatusQ.Controls 0.1 import StatusQ.Core 0.1 import StatusQ.Core.Theme 0.1 +import StatusQ.Components 0.1 +import StatusQ.Popups.Dialog 0.1 import utils 1.0 import "../../stores" @@ -21,6 +26,7 @@ Item { anchors.top: parent.top anchors.left: parent.left width: parent.width + spacing: 0 Repeater { id: layer1List @@ -33,15 +39,20 @@ Item { } delegate: WalletNetworkDelegate { network: model + areTestNetworksEnabled: walletStore.areTestNetworksEnabled } } + Separator { + height: Style.current.padding + } + StatusSectionHeadline { leftPadding: Style.current.padding rightPadding: Style.current.padding text: qsTr("Layer 2") - topPadding: Style.current.bigPadding - bottomPadding: Style.current.padding + topPadding: Style.current.smallPadding + bottomPadding: Style.current.smallPadding } Repeater { @@ -55,7 +66,42 @@ Item { } delegate: WalletNetworkDelegate { network: model + areTestNetworksEnabled: walletStore.areTestNetworksEnabled } } + + Separator { + height: Style.current.padding + } + + StatusSectionHeadline { + leftPadding: Style.current.padding + rightPadding: Style.current.padding + text: qsTr("Advanced") + topPadding: Style.current.smallPadding + bottomPadding: Style.current.smallPadding + } + + StatusListItem { + width: parent.width + asset.name: "settings" + asset.color: Theme.palette.warningColor1 + asset.bgColor: Theme.palette.warningColor3 + title: qsTr("Testnet mode") + subTitle: qsTr("Switch entire Status app to testnet only mode") + onClicked: testnetSwitch.clicked() + components: [ + StatusSwitch { + id: testnetSwitch + objectName: "testnetModeSwitch" + checked: walletStore.areTestNetworksEnabled + checkable: false + onClicked: { + checkable = false + Global.openTestnetPopup() + } + } + ] + } } } diff --git a/ui/app/mainui/AppMain.qml b/ui/app/mainui/AppMain.qml index 0326c3ed89..84bedbc776 100644 --- a/ui/app/mainui/AppMain.qml +++ b/ui/app/mainui/AppMain.qml @@ -535,45 +535,14 @@ Item { id: testnetBanner objectName: "testnetBanner" Layout.fillWidth: true - text: qsTr("Testnet mode is enabled. All balances, transactions and dApp interactions will be on testnets.") + text: qsTr("Testnet mode enabled. All balances, transactions and dApp interactions will be on testnets.") buttonText: qsTr("Turn off") - type: ModuleWarning.Danger + type: ModuleWarning.Warning + iconName: "warning" active: appMain.rootStore.profileSectionStore.walletStore.areTestNetworksEnabled - onClicked: { - testnetBannerDialog.open() - } - - onCloseClicked: { - testnetBannerDialog.open() - } - - StatusDialog { - id: testnetBannerDialog - - width: 400 - title: qsTr("Turn off Testnet mode") - - StatusBaseText { - anchors.fill: parent - text: qsTr("Closing this banner will turn off Testnet mode.\nAll future transactions will be on mainnet or other active networks.") - font.pixelSize: 15 - wrapMode: Text.WordWrap - } - - footer: StatusDialogFooter { - rightButtons: ObjectModel { - StatusButton { - type: StatusButton.Danger - text: qsTr("Turn off Testnet") - onClicked: { - appMain.rootStore.profileSectionStore.walletStore.toggleTestNetworksEnabled() - testnetBannerDialog.close() - } - } - } - } - } + onClicked: Global.openTestnetPopup() + onCloseClicked: Global.openTestnetPopup() } ModuleWarning { diff --git a/ui/app/mainui/Popups.qml b/ui/app/mainui/Popups.qml index 1611fe86a5..6fd2012d07 100644 --- a/ui/app/mainui/Popups.qml +++ b/ui/app/mainui/Popups.qml @@ -8,6 +8,7 @@ import StatusQ.Core 0.1 import StatusQ.Controls 0.1 import StatusQ.Components 0.1 import StatusQ.Popups 0.1 +import StatusQ.Core.Theme 0.1 import AppLayouts.Chat.popups 1.0 import AppLayouts.Profile.popups 1.0 @@ -54,6 +55,7 @@ QtObject { Global.openDeleteMessagePopup.connect(openDeleteMessagePopup) Global.openDownloadImageDialog.connect(openDownloadImageDialog) Global.leaveCommunityRequested.connect(openLeaveCommunityPopup) + Global.openTestnetPopup.connect(openTestnetPopup) } property var currentPopup @@ -242,6 +244,10 @@ QtObject { openPopup(leaveCommunityPopupComponent, {community, communityId, outroMessage}) } + function openTestnetPopup() { + openPopup(testnetModal) + } + readonly property list _components: [ Component { id: removeContactConfirmationDialog @@ -559,6 +565,29 @@ QtObject { onClosed: destroy() } + }, + + Component { + id: testnetModal + AlertPopup { + width: 521 + readonly property string mainTitle: root.rootStore.profileSectionStore.walletStore.areTestNetworksEnabled ? qsTr("Turn off testnet mode") : qsTr("Turn on testnet mode") + title: mainTitle + alertLabel.textFormat: Text.RichText + alertText: root.rootStore.profileSectionStore.walletStore.areTestNetworksEnabled ? + qsTr("Are you sure you want to turn off %1? All future transactions will be performed on live networks with real funds").arg("testnet mode") : + qsTr("Are you sure you want to turn on %1? In this mode, all blockchain data displayed will come from testnets and all blockchain interactions will be with testnets. Testnet mode switches the entire app to using testnets only. Please switch this mode on only if you know exactly why you need to use it.").arg("testnet mode") + acceptBtnText: mainTitle + acceptBtnType: root.rootStore.profileSectionStore.walletStore.areTestNetworksEnabled ? StatusBaseButton.Type.Normal : StatusBaseButton.Type.Warning + asset.name: "settings" + asset.color: Theme.palette.warningColor1 + asset.bgColor: Theme.palette.warningColor3 + onAcceptClicked: { + root.rootStore.profileSectionStore.walletStore.toggleTestNetworksEnabled() + Global.displayToastMessage(root.rootStore.profileSectionStore.walletStore.areTestNetworksEnabled ? qsTr("Testnet mode turned on") : qsTr("Testnet mode turned off") , "", "checkmark-circle", false, Constants.ephemeralNotificationType.success, "") + } + onCancelClicked: close() + } } ] } diff --git a/ui/imports/shared/panels/ModuleWarning.qml b/ui/imports/shared/panels/ModuleWarning.qml index 0697012a05..3a3fe261a1 100644 --- a/ui/imports/shared/panels/ModuleWarning.qml +++ b/ui/imports/shared/panels/ModuleWarning.qml @@ -5,6 +5,7 @@ import QtGraphicalEffects 1.13 import StatusQ.Core 0.1 import StatusQ.Core.Theme 0.1 +import StatusQ.Components 0.1 import utils 1.0 @@ -23,6 +24,7 @@ Item { property string text: "" property alias buttonText: button.text property alias closeBtnVisible: closeImg.visible + property string iconName signal clicked() signal closeClicked() @@ -129,6 +131,16 @@ Item { spacing: 12 anchors.centerIn: parent + StatusRoundIcon { + Layout.preferredHeight: 16 + Layout.preferredWidth: 16 + Layout.rightMargin: -8 + visible: !!root.iconName + asset.name: root.iconName + asset.bgColor: Theme.palette.indirectColor1 + asset.color: content.baseColor + } + StatusBaseText { text: root.text font.pixelSize: 13 diff --git a/ui/app/AppLayouts/Communities/popups/AlertPopup.qml b/ui/imports/shared/popups/AlertPopup.qml similarity index 59% rename from ui/app/AppLayouts/Communities/popups/AlertPopup.qml rename to ui/imports/shared/popups/AlertPopup.qml index 21cc2b588c..f7211170eb 100644 --- a/ui/app/AppLayouts/Communities/popups/AlertPopup.qml +++ b/ui/imports/shared/popups/AlertPopup.qml @@ -7,8 +7,7 @@ import StatusQ.Core 0.1 import StatusQ.Controls 0.1 import StatusQ.Popups.Dialog 0.1 import StatusQ.Core.Theme 0.1 - -import AppLayouts.Communities.panels 1.0 +import StatusQ.Components 0.1 import utils 1.0 @@ -17,6 +16,19 @@ StatusDialog { property alias acceptBtnText: acceptBtn.text property alias alertText: contentTextItem.text + property alias alertLabel: contentTextItem + property int acceptBtnType: StatusBaseButton.Type.Danger + + property StatusAssetSettings asset: StatusAssetSettings { + width: 24 + height: 24 + rotation: 0 + color: Theme.palette.primaryColor1 + bgWidth: 40 + bgHeight: 40 + bgColor: Theme.palette.primaryColor3 + bgRadius: bgWidth / 2 + } signal acceptClicked signal cancelClicked @@ -32,6 +44,18 @@ StatusDialog { lineHeight: 1.2 } + header: StatusDialogHeader { + visible: root.title || root.subtitle + headline.title: root.title + headline.subtitle: root.subtitle + actions.closeButton.onClicked: root.close() + leftComponent: StatusRoundIcon { + width: visible? implicitWidth: 0 + visible: !!root.asset.name + asset: root.asset + } + } + footer: StatusDialogFooter { spacing: Style.current.padding rightButtons: ObjectModel { @@ -49,7 +73,7 @@ StatusDialog { StatusButton { id: acceptBtn - type: StatusBaseButton.Type.Danger + type: root.acceptBtnType onClicked: { root.acceptClicked() diff --git a/ui/imports/shared/popups/qmldir b/ui/imports/shared/popups/qmldir index da48356261..35238b096a 100644 --- a/ui/imports/shared/popups/qmldir +++ b/ui/imports/shared/popups/qmldir @@ -29,3 +29,4 @@ RemoveAccountConfirmationPopup 1.0 RemoveAccountConfirmationPopup.qml RenameGroupPopup 1.0 RenameGroupPopup.qml DeleteMessageConfirmationPopup 1.0 DeleteMessageConfirmationPopup.qml UserAgreementPopup 1.0 UserAgreementPopup.qml +AlertPopup 1.0 AlertPopup.qml diff --git a/ui/imports/utils/Global.qml b/ui/imports/utils/Global.qml index 77a79bf011..d9248ead85 100644 --- a/ui/imports/utils/Global.qml +++ b/ui/imports/utils/Global.qml @@ -64,6 +64,8 @@ QtObject { signal playNotificationSound() signal playErrorSound() + signal openTestnetPopup() + function openProfilePopup(publicKey, parentPopup, cb) { root.openProfilePopupRequested(publicKey, parentPopup, cb) } diff --git a/vendor/status-go b/vendor/status-go index 9ee523be99..104d9c8ff6 160000 --- a/vendor/status-go +++ b/vendor/status-go @@ -1 +1 @@ -Subproject commit 9ee523be99483a14f83c3e7a74220d5695ee755a +Subproject commit 104d9c8ff6b4f7f02bfd04d053a948b84f230fda