Implement network settings for wallet settings (#19995)

* fix: resolve warning about using subscription inside a lazy seq

* fix: avoid schema error when we do not have a port for the media server

* chore: add feature-flag for network-settings inside wallet-settings

* chore: add testnet mode label

* chore: add testnet labels for bottom-sheets

* chore: add label for changing testnet mode

* feature: add initial network-settings screen to wallet-settings

* test: add test for sub

* tidy: rename function to hide-bottom-sheet

* tweak: add info-box for testnet mode

* tidy: testnet-mode bottom-sheet

* tidy: use reduce-kv instead of map & into

* tidy: use noun naming convention for function creating options for settings

* tweak: add support for displaying testnet-mode status on each wallet network

* chore: add translation for labels referencing testnet-mode and sepolia
This commit is contained in:
Sean Hagstrom 2024-05-15 10:28:25 +01:00 committed by GitHub
parent 91c347f6f5
commit f7505db6fd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 307 additions and 5 deletions

View File

@ -26,7 +26,7 @@
{:list-type :settings {:list-type :settings
:container-style {:padding-bottom 12} :container-style {:padding-bottom 12}
:blur? true :blur? true
:data (filter show-settings-item? data)}])) :data (doall (filter show-settings-item? data))}]))
(defn scroll-handler (defn scroll-handler
[event scroll-y] [event scroll-y]

View File

@ -0,0 +1,25 @@
(ns status-im.contexts.settings.wallet.network-settings.style
(:require [quo.foundations.colors :as colors]))
(def title-container
{:padding-horizontal 20
:margin-vertical 12})
(defn page-wrapper
[inset-top]
{:padding-top inset-top
:flex 1})
(defn settings-container
[inset-bottom]
{:flex 1
:padding-bottom inset-bottom})
(def networks-container
{:flex 1})
(def advanced-settings-container
{:flex-shrink 0})
(def testnet-not-available
{:color colors/danger-60})

View File

@ -0,0 +1,17 @@
(ns status-im.contexts.settings.wallet.network-settings.testnet-mode.style)
(def description
{:padding-top 4
:padding-bottom 8
:padding-horizontal 20})
(def info-box-container
{:padding-top 4
:padding-bottom 12
:padding-horizontal 20})
(def drawer-top
{:padding-bottom 4})
(def bottom-actions-container
{:flex 1})

View File

@ -0,0 +1,62 @@
(ns status-im.contexts.settings.wallet.network-settings.testnet-mode.view
(:require [quo.core :as quo]
[react-native.core :as rn]
[status-im.contexts.settings.wallet.network-settings.testnet-mode.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn hide-bottom-sheet
[]
(rf/dispatch [:hide-bottom-sheet]))
(defn logout
[]
(rf/dispatch [:logout]))
(defn on-confirm-change
[enable?]
(hide-bottom-sheet)
(rf/dispatch [:profile.settings/profile-update :test-networks-enabled? enable? {:on-success logout}]))
(defn testnet-mode-confirm-change-sheet
[{:keys [title description on-confirm on-cancel]}]
(let [customization-color (rf/sub [:profile/customization-color])]
[:<>
[quo/drawer-top
{:title title
:container-style style/drawer-top}]
[quo/text {:style style/description} description]
[rn/view {:style style/info-box-container}
[quo/information-box
{:type :default
:icon :i/info}
(i18n/label :t/change-testnet-mode-logout-info)]]
[quo/bottom-actions
{:container-style {:style style/bottom-actions-container}
:actions :two-actions
:button-one-label (i18n/label :t/confirm)
:button-one-props {:accessibility-label :confirm-testnet-mode-change
:on-press on-confirm
:type :primary
:customization-color customization-color}
:button-two-label (i18n/label :t/cancel)
:button-two-props {:accessibility-label :cancel-testnet-mode-change
:type :dark-grey
:on-press on-cancel}}]]))
(defn view
[{:keys [enable?]}]
(let [on-confirm (rn/use-callback
#(on-confirm-change enable?)
[enable?])]
(if enable?
[testnet-mode-confirm-change-sheet
{:title (i18n/label :t/turn-on-testnet-mode)
:description (i18n/label :t/testnet-mode-enable-description)
:on-confirm on-confirm
:on-cancel hide-bottom-sheet}]
[testnet-mode-confirm-change-sheet
{:title (i18n/label :t/turn-off-testnet-mode)
:description (i18n/label :t/testnet-mode-disable-description)
:on-confirm on-confirm
:on-cancel hide-bottom-sheet}])))

View File

@ -0,0 +1,128 @@
(ns status-im.contexts.settings.wallet.network-settings.view
(:require [quo.core :as quo]
[quo.foundations.resources :as resources]
[quo.theme]
[react-native.core :as rn]
[react-native.safe-area :as safe-area]
[status-im.contexts.settings.wallet.network-settings.style :as style]
[status-im.contexts.settings.wallet.network-settings.testnet-mode.view :as testnet]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn navigate-back
[]
(rf/dispatch [:navigate-back]))
(defn make-network-settings-item
[{:keys [details testnet-label testnet-mode?]}]
(let [{:keys [network-name]} details]
(cond-> {:blur? true
:title (i18n/label network-name)
:image :icon-avatar
:image-props {:icon (resources/get-network network-name)
:size :size-20}}
testnet-mode? (assoc
:label :text
:label-props testnet-label))))
(defn mainnet-settings
[{:keys [networks testnet-mode?]}]
[quo/category
{:key :mainnet-settings
:data [(make-network-settings-item
{:details (:mainnet networks)
:testnet-mode? testnet-mode?
:testnet-label (i18n/label :t/sepolia-active)})]
:blur? true
:list-type :settings}])
(defn layer-2-settings
[{:keys [networks testnet-mode?]}]
[quo/category
{:key :layer-2-settings
:label (i18n/label :t/layer-2)
:data (map make-network-settings-item
[{:details (:optimism networks)
:testnet-mode? testnet-mode?
:testnet-label [quo/text
{:style style/testnet-not-available}
(i18n/label :t/testnet-not-available)]}
{:details (:arbitrum networks)
:testnet-mode? testnet-mode?
:testnet-label (i18n/label :t/sepolia-active)}])
:blur? true
:list-type :settings}])
(defn testnet-mode-setting
[{:keys [testnet-mode? on-enable on-disable]}]
(let [on-change-testnet (rn/use-callback
(fn [active?]
(if active? (on-enable) (on-disable)))
[on-enable on-disable])]
{:blur? true
:title (i18n/label :t/testnet-mode)
:action :selector
:image :icon
:image-props :i/settings
:action-props {:on-change on-change-testnet
:checked? (boolean testnet-mode?)}}))
(defn advanced-settings
[{:keys [testnet-mode? enable-testnet disable-testnet]}]
[quo/category
{:key :advanced-settings
:label (i18n/label :t/advanced)
:data [(testnet-mode-setting {:testnet-mode? testnet-mode?
:on-enable enable-testnet
:on-disable disable-testnet})]
:blur? true
:list-type :settings}])
(defn on-change-testnet
[{:keys [enable? theme]}]
(rf/dispatch [:show-bottom-sheet
{:content (fn [] [testnet/view {:enable? enable?}])
:theme theme}]))
(defn view
[]
(let [insets (safe-area/get-insets)
theme (quo.theme/use-theme)
networks-by-name (rf/sub [:wallet/network-details-by-network-name])
testnet-mode? (rf/sub [:profile/test-networks-enabled?])
enable-testnet (rn/use-callback
(fn []
(on-change-testnet {:theme theme
:enable? true}))
[theme])
disable-testnet (rn/use-callback
(fn []
(on-change-testnet {:theme theme
:enable? false}))
[theme])]
[quo/overlay
{:type :shell
:container-style (style/page-wrapper (:top insets))}
[quo/page-nav
{:key :header
:background :blur
:icon-name :i/arrow-left
:on-press navigate-back}]
[rn/view {:style style/title-container}
[quo/standard-title
{:title (i18n/label :t/network-settings)
:accessibility-label :network-settings-header}]]
[rn/view {:style (style/settings-container (:bottom insets))}
(when networks-by-name
[rn/view {:style style/networks-container}
[mainnet-settings
{:networks networks-by-name
:testnet-mode? testnet-mode?}]
[layer-2-settings
{:networks networks-by-name
:testnet-mode? testnet-mode?}]])
[rn/view {:style style/advanced-settings-container}
[advanced-settings
{:testnet-mode? testnet-mode?
:enable-testnet enable-testnet
:disable-testnet disable-testnet}]]]]))

View File

@ -14,7 +14,7 @@
[] []
(rf/dispatch [:open-modal :screen/settings.keypairs-and-accounts])) (rf/dispatch [:open-modal :screen/settings.keypairs-and-accounts]))
(defn gen-basic-settings-options (defn basic-settings-options
[] []
[(when (ff/enabled? ::ff/settings.keypairs-and-accounts) [(when (ff/enabled? ::ff/settings.keypairs-and-accounts)
{:title (i18n/label :t/keypairs-and-accounts) {:title (i18n/label :t/keypairs-and-accounts)
@ -31,10 +31,31 @@
[quo/category [quo/category
{:key :basic-wallet-settings {:key :basic-wallet-settings
:label (i18n/label :t/keypairs-accounts-and-addresses) :label (i18n/label :t/keypairs-accounts-and-addresses)
:data (gen-basic-settings-options) :data (basic-settings-options)
:blur? true :blur? true
:list-type :settings}]) :list-type :settings}])
(defn open-network-settings-modal
[]
(rf/dispatch [:open-modal :screen/settings.network-settings]))
(defn advanced-settings-options
[]
[{:title (i18n/label :t/network-settings)
:blur? true
:on-press open-network-settings-modal
:action :arrow}])
(defn advanced-settings
[]
(when (ff/enabled? ::ff/settings.network-settings)
[quo/category
{:key :advanced-wallet-settings
:label (i18n/label :t/advanced)
:data (advanced-settings-options)
:blur? true
:list-type :settings}]))
(defn navigate-back (defn navigate-back
[] []
(rf/dispatch [:navigate-back])) (rf/dispatch [:navigate-back]))
@ -53,4 +74,5 @@
[quo/page-top [quo/page-top
{:title (i18n/label :t/wallet) {:title (i18n/label :t/wallet)
:title-accessibility-label :wallet-settings-header}] :title-accessibility-label :wallet-settings-header}]
[basic-settings]])) [basic-settings]
[advanced-settings]]))

View File

@ -14,6 +14,7 @@
::settings.wallet-settings (enabled-in-env? :FLAG_WALLET_SETTINGS_ENABLED) ::settings.wallet-settings (enabled-in-env? :FLAG_WALLET_SETTINGS_ENABLED)
::settings.keypairs-and-accounts (enabled-in-env? ::settings.keypairs-and-accounts (enabled-in-env?
:FLAG_WALLET_SETTINGS_KEYPAIRS_AND_ACCOUNTS_ENABLED) :FLAG_WALLET_SETTINGS_KEYPAIRS_AND_ACCOUNTS_ENABLED)
::wallet.activities (enabled-in-env? :FLAG_WALLET_ACTIVITY_ENABLED)
::wallet.assets-modal-hide (enabled-in-env? :FLAG_ASSETS_MODAL_HIDE) ::wallet.assets-modal-hide (enabled-in-env? :FLAG_ASSETS_MODAL_HIDE)
::wallet.assets-modal-manage-tokens (enabled-in-env? :FLAG_ASSETS_MODAL_MANAGE_TOKENS) ::wallet.assets-modal-manage-tokens (enabled-in-env? :FLAG_ASSETS_MODAL_MANAGE_TOKENS)
::wallet.bridge-token (enabled-in-env? :FLAG_BRIDGE_TOKEN_ENABLED) ::wallet.bridge-token (enabled-in-env? :FLAG_BRIDGE_TOKEN_ENABLED)

View File

@ -59,6 +59,7 @@
[status-im.contexts.profile.settings.view :as settings] [status-im.contexts.profile.settings.view :as settings]
[status-im.contexts.settings.wallet.keypairs-and-accounts.rename.view :as keypair-rename] [status-im.contexts.settings.wallet.keypairs-and-accounts.rename.view :as keypair-rename]
[status-im.contexts.settings.wallet.keypairs-and-accounts.view :as keypairs-and-accounts] [status-im.contexts.settings.wallet.keypairs-and-accounts.view :as keypairs-and-accounts]
[status-im.contexts.settings.wallet.network-settings.view :as network-settings]
[status-im.contexts.settings.wallet.saved-addresses.view :as saved-addresses-settings] [status-im.contexts.settings.wallet.saved-addresses.view :as saved-addresses-settings]
[status-im.contexts.settings.wallet.wallet-options.view :as wallet-options] [status-im.contexts.settings.wallet.wallet-options.view :as wallet-options]
[status-im.contexts.shell.activity-center.view :as activity-center] [status-im.contexts.shell.activity-center.view :as activity-center]
@ -518,6 +519,10 @@
options/dark-screen) options/dark-screen)
:component keypairs-and-accounts/view} :component keypairs-and-accounts/view}
{:name :screen/settings.network-settings
:options options/transparent-modal-screen-options
:component network-settings/view}
{:name :screen/settings-messages {:name :screen/settings-messages
:options options/transparent-modal-screen-options :options options/transparent-modal-screen-options
:component settings.messages/view} :component settings.messages/view}

View File

@ -41,7 +41,7 @@
(let [{:keys [images ens-name? customization-color] :as profile} (get profiles target-key-uid) (let [{:keys [images ens-name? customization-color] :as profile} (get profiles target-key-uid)
image-name (-> images first :type) image-name (-> images first :type)
override-ring? (when ens-name? false)] override-ring? (when ens-name? false)]
(when profile (when (and profile port)
{:config {:config
(if image-name (if image-name
{:type :account {:type :account

View File

@ -63,6 +63,17 @@
:layer layer))) :layer layer)))
(sort-by (juxt :layer :short-name))))) (sort-by (juxt :layer :short-name)))))
(re-frame/reg-sub
:wallet/network-details-by-network-name
:<- [:wallet/network-details]
(fn [network-details]
(when (seq network-details)
(->> network-details
(group-by :network-name)
(reduce-kv (fn [acc network-key network-group]
(assoc acc network-key (first network-group)))
{})))))
(re-frame/reg-sub (re-frame/reg-sub
:wallet/network-details-by-chain-id :wallet/network-details-by-chain-id
:<- [:wallet/network-details] :<- [:wallet/network-details]

View File

@ -59,3 +59,26 @@
:chain-id 10 :chain-id 10
:layer 2}] :layer 2}]
(map #(dissoc % :source :related-chain-id) (rf/sub [sub-name])))))) (map #(dissoc % :source :related-chain-id) (rf/sub [sub-name]))))))
(h/deftest-sub :wallet/network-details-by-network-name
[sub-name]
(testing "returns the prod network data that is accessible by the network name"
(swap! rf-db/app-db assoc-in [:wallet :networks] network-data)
(is
(match?
{:mainnet {:network-name :mainnet
:short-name "eth"
:chain-id 1
:abbreviated-name "Eth."
:layer 1}
:arbitrum {:network-name :arbitrum
:short-name "arb1"
:abbreviated-name "Arb1."
:chain-id 42161
:layer 2}
:optimism {:network-name :optimism
:short-name "opt"
:abbreviated-name "Opt."
:chain-id 10
:layer 2}}
(rf/sub [sub-name])))))

View File

@ -2307,6 +2307,7 @@
"sync-devices-complete-sub-title": "Your devices are now in sync", "sync-devices-complete-sub-title": "Your devices are now in sync",
"synced-with": "Synced with", "synced-with": "Synced with",
"confirm-and-leave": "Confirm and leave", "confirm-and-leave": "Confirm and leave",
"change-testnet-mode-logout-info": "Youll be logged out of the app",
"membership-requirements-not-met": "Membership requirements not met", "membership-requirements-not-met": "Membership requirements not met",
"edit-shared-addresses": "Edit shared addresses", "edit-shared-addresses": "Edit shared addresses",
"leave-community-farewell": "Well be sad to see you go but remember, you can come back at any time! All shared addresses will be unshared.", "leave-community-farewell": "Well be sad to see you go but remember, you can come back at any time! All shared addresses will be unshared.",
@ -2573,6 +2574,8 @@
"keypair-name-input-placeholder": "Collectibles account, Old vault....", "keypair-name-input-placeholder": "Collectibles account, Old vault....",
"key-pair-name-updated": "Key pair name updated", "key-pair-name-updated": "Key pair name updated",
"goerli-testnet-toggle-confirmation": "Are you sure you want to toggle Goerli? This will log you out and you will have to login again.", "goerli-testnet-toggle-confirmation": "Are you sure you want to toggle Goerli? This will log you out and you will have to login again.",
"sepolia-active": "Sepolia active",
"testnet-not-available": "Testnet not available",
"bridged-to": "Bridged to {{network}}", "bridged-to": "Bridged to {{network}}",
"slide-to-bridge": "Slide to bridge", "slide-to-bridge": "Slide to bridge",
"provider-is-down": "The provider for the following chain(s) is down: {{chains}}", "provider-is-down": "The provider for the following chain(s) is down: {{chains}}",
@ -2599,6 +2602,11 @@
"key-name-error-special-char": "Special characters are not allowed", "key-name-error-special-char": "Special characters are not allowed",
"key-name-error-too-short": "Key pair name must be at least {{count}} characters", "key-name-error-too-short": "Key pair name must be at least {{count}} characters",
"display": "Display", "display": "Display",
"testnet-mode": "Testnet mode",
"turn-on-testnet-mode": "Turn on testnet mode",
"turn-off-testnet-mode": "Turn off testnet mode",
"testnet-mode-enable-description": "In this mode, all blockchain data displayed will come from testnets and all blockchain interactions will be with testnets.\nTestnet 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.",
"testnet-mode-disable-description": "Are you sure you want to turn off Testnet mode? All future transactions will be performed on live networks with real funds.",
"testnet-mode-enabled": "Testnet mode enabled", "testnet-mode-enabled": "Testnet mode enabled",
"online-community-member": "Online", "online-community-member": "Online",
"offline-community-member": "Offline", "offline-community-member": "Offline",