From 24d5fabe2e9acd946914bfc1440aa0af4d15ef51 Mon Sep 17 00:00:00 2001 From: Connor Christie Date: Thu, 17 May 2018 16:21:01 +1200 Subject: [PATCH] Add support for custom network upstreams Signed-off-by: Andrey Shovkoplyas --- src/status_im/commands/events/loading.cljs | 2 +- src/status_im/protocol/handlers.cljs | 4 +- src/status_im/translations/en.cljs | 14 +++++ src/status_im/transport/inbox.cljs | 5 +- .../ui/components/checkbox/styles.cljs | 16 ++++- .../ui/components/checkbox/view.cljs | 33 ++++++---- src/status_im/ui/components/list/styles.cljs | 12 ++-- src/status_im/ui/components/list/views.cljs | 19 +++--- src/status_im/ui/components/styles.cljs | 5 ++ .../ui/components/toolbar/actions.cljs | 4 +- src/status_im/ui/screens/db.cljs | 1 + src/status_im/ui/screens/home/views.cljs | 2 +- .../ui/screens/network_settings/db.cljs | 2 + .../network_settings/edit_network/events.cljs | 47 ++++++++++++++ .../network_settings/edit_network/styles.cljs | 27 ++++++++ .../network_settings/edit_network/subs.cljs | 14 +++++ .../network_settings/edit_network/views.cljs | 62 +++++++++++++++++++ .../ui/screens/network_settings/events.cljs | 32 ++++++++-- .../network_details/views.cljs | 58 ++++++++++------- .../ui/screens/network_settings/styles.cljs | 11 ++++ .../ui/screens/network_settings/subs.cljs | 42 +++++++++---- .../ui/screens/network_settings/views.cljs | 39 ++++++++---- .../offline_messaging_settings/events.cljs | 14 ++--- src/status_im/ui/screens/subs.cljs | 5 +- src/status_im/ui/screens/views.cljs | 2 + src/status_im/ui/screens/wallet/events.cljs | 8 ++- .../ui/screens/wallet/settings/events.cljs | 5 +- .../ui/screens/wallet/transactions/subs.cljs | 8 ++- src/status_im/utils/ethereum/core.cljs | 16 +++-- src/status_im/utils/transactions.cljs | 12 ++-- 30 files changed, 407 insertions(+), 114 deletions(-) create mode 100644 src/status_im/ui/screens/network_settings/edit_network/events.cljs create mode 100644 src/status_im/ui/screens/network_settings/edit_network/styles.cljs create mode 100644 src/status_im/ui/screens/network_settings/edit_network/subs.cljs create mode 100644 src/status_im/ui/screens/network_settings/edit_network/views.cljs diff --git a/src/status_im/commands/events/loading.cljs b/src/status_im/commands/events/loading.cljs index 21d1e5b797..0e130f178a 100644 --- a/src/status_im/commands/events/loading.cljs +++ b/src/status_im/commands/events/loading.cljs @@ -37,7 +37,7 @@ [{:keys [db get-local-storage-data]} commands-resource whisper-identity] (let [data (get-local-storage-data whisper-identity) local-storage-snippet (js-resources/local-storage-data data) - network-id (get-in db [:networks/networks (:network db) :raw-config :NetworkId]) + network-id (get-in db [:account/account :networks (:network db) :raw-config :NetworkId]) ethereum-id-snippet (js-resources/network-id network-id) commands-snippet (str local-storage-snippet ethereum-id-snippet commands-resource)] {::evaluate-jail-n [{:jail-id whisper-identity diff --git a/src/status_im/protocol/handlers.cljs b/src/status_im/protocol/handlers.cljs index ebb0e7b525..1b31461371 100644 --- a/src/status_im/protocol/handlers.cljs +++ b/src/status_im/protocol/handlers.cljs @@ -80,8 +80,8 @@ (handlers/register-handler-fx :initialize-sync-listener - (fn [{{:keys [sync-listening-started network networks/networks] :as db} :db} _] + (fn [{{:keys [sync-listening-started network account/account] :as db} :db} _] (when (and (not sync-listening-started) - (not (utils/network-with-upstream-rpc? networks network))) + (not (utils/network-with-upstream-rpc? (get-in account [:networks network])))) {:db (assoc db :sync-listening-started true) :dispatch [:check-sync]}))) diff --git a/src/status_im/translations/en.cljs b/src/status_im/translations/en.cljs index fa2b64a4a6..c3c537b76c 100644 --- a/src/status_im/translations/en.cljs +++ b/src/status_im/translations/en.cljs @@ -331,6 +331,7 @@ :add-new-contact "Add new contact" :scan-qr "Scan QR code" :name "Name" + :specify-name "Specify a name" :address-explication "Your public key is used to generate your address on Ethereum and is a series of numbers and letters. You can find it easily in your profile" :use-valid-contact-code "Please enter a valid contact code" :enter-valid-public-key "Please enter a valid public key or scan a QR code" @@ -580,6 +581,8 @@ :add-new-network "Add new network" :add-wnode "Add mailserver" :existing-networks "Existing networks" + :delete-network-title "Delete network?" + :delete-network-confirmation "Are you sure you want to delete this network?" ;; TODO(dmitryn): come up with better description/naming. Suggested namings: Mailbox and Master Node :existing-wnodes "Existing mailservers" :add-json-file "Add a JSON file" @@ -591,12 +594,15 @@ :process-json "Process JSON" :error-processing-json "Error processing JSON" :rpc-url "RPC URL" + :network-chain "Network chain" :network "Network" + :network-details "Network details" :remove-network "Remove network" :network-settings "Network settings" :offline-messaging "Offline messages" :offline-messaging-settings "Offline messages settings" :edit-network-warning "Be careful, editing the network data may disable this network for you" + :delete-network-error "Please connect to a different network before deleting this one" :connecting-requires-login "Connecting to another network requires login" :close-app-title "Warning!" :close-app-content "The app will stop and close. When you reopen it, the selected network will be used" @@ -607,6 +613,14 @@ :mainnet-warning-text "While we highly appreciate your contribution as a tester of Status, we’d like to point out the dangers. You’re switching to Mainnet mode which is still in Alpha. This means it is still in development and has not been audited yet. Some of the risks you may be exposed to include:\n\n- Accounts may be unrecoverable due to breaking changes\n- Loss of ETH and tokens\n- Failure to send or receive messages\n\nSwitching to Mainnet should be done for testing purposes only. By tapping \"I understand\", you confirm that you assume the full responsibility for all risks concerning your data and funds. " :mainnet-warning-ok-text "I understand" + :main-networks "Main networks" + :test-networks "Test networks" + :custom-networks "Custom networks" + + :mainnet-network "Main network" + :ropsten-network "Ropsten test network" + :rinkeby-network "Rinkeby test network" + ;; browser :browser "Browser" :enter-dapp-url "Enter a ÐApp URL" diff --git a/src/status_im/transport/inbox.cljs b/src/status_im/transport/inbox.cljs index ebb5abcbf9..b66a49ad7c 100644 --- a/src/status_im/transport/inbox.cljs +++ b/src/status_im/transport/inbox.cljs @@ -42,9 +42,10 @@ (success-fn result))))) (defn get-current-wnode-address [db] - (let [network (ethereum/network->chain-keyword (get db :network)) + (let [network (get (:networks (:account/account db)) (:network db)) + chain (ethereum/network->chain-keyword network) wnode-id (get-in db [:account/account :settings :wnode network])] - (get-in db [:inbox/wnodes network wnode-id :address]))) + (get-in db [:inbox/wnodes chain wnode-id :address]))) (defn initialize-offline-inbox-flow [] {:first-dispatch [:inbox/get-sym-key] diff --git a/src/status_im/ui/components/checkbox/styles.cljs b/src/status_im/ui/components/checkbox/styles.cljs index 8c49063894..e2dbe427ee 100644 --- a/src/status_im/ui/components/checkbox/styles.cljs +++ b/src/status_im/ui/components/checkbox/styles.cljs @@ -8,10 +8,20 @@ {:background-color (if checked? colors/blue colors/gray-lighter) :align-items :center :justify-content :center - :border-radius 2 - :width 24 - :height 24}) + :border-radius 2 + :width 24 + :height 24}) + +(defn icon-radio-container [checked?] + (merge (icon-check-container checked?) + {:border-radius 100 + :width 26 + :height 26})) (def check-icon {:width 12 :height 12}) + +(def plain-check-icon + (merge check-icon + {:tint-color colors/blue})) diff --git a/src/status_im/ui/components/checkbox/view.cljs b/src/status_im/ui/components/checkbox/view.cljs index ad6edab9c4..1f3eafeb09 100644 --- a/src/status_im/ui/components/checkbox/view.cljs +++ b/src/status_im/ui/components/checkbox/view.cljs @@ -1,17 +1,26 @@ (ns status-im.ui.components.checkbox.view (:require [status-im.ui.components.checkbox.styles :as styles] [status-im.ui.components.react :as react] + [status-im.ui.components.icons.vector-icons :as vector-icons] [status-im.utils.platform :as platform])) -(defn checkbox [{:keys [on-value-change checked? accessibility-label] :or {accessibility-label :checkbox}}] - (if platform/android? - [react/view {:style styles/wrapper} - [react/check-box {:on-value-change on-value-change - :value checked? - :accessibility-label accessibility-label}]] - [react/touchable-highlight (merge {:style styles/wrapper - :accessibility-label accessibility-label} - (when on-value-change {:on-press #(on-value-change (not checked?))})) - [react/view (styles/icon-check-container checked?) - (when checked? - [react/icon :check_on styles/check-icon])]])) +(defn- checkbox-generic [{:keys [on-value-change checked? accessibility-label] :or {accessibility-label :checkbox}} plain?] + (let [icon-check-container (if plain? #() styles/icon-check-container) + check-icon (if plain? styles/plain-check-icon styles/check-icon)] + (if platform/android? + [react/view styles/wrapper + [react/check-box {:on-value-change on-value-change + :value checked? + :accessibility-label accessibility-label}]] + [react/touchable-highlight (merge {:style styles/wrapper + :accessibility-label accessibility-label} + (when on-value-change {:on-press #(on-value-change (not checked?))})) + [react/view (icon-check-container checked?) + (when checked? + [react/icon :check_on check-icon])]]))) + +(defn checkbox [props] + [checkbox-generic props false]) + +(defn plain-checkbox [props] + [checkbox-generic props true]) diff --git a/src/status_im/ui/components/list/styles.cljs b/src/status_im/ui/components/list/styles.cljs index 7fae1fba60..7b203a5e52 100644 --- a/src/status_im/ui/components/list/styles.cljs +++ b/src/status_im/ui/components/list/styles.cljs @@ -53,7 +53,7 @@ {:width icon-size :height icon-size}) -(def horizontal-margin 16) +(def horizontal-margin 12) (def vertical-margin 12) (def left-item-wrapper @@ -83,11 +83,6 @@ {:android {:background-color colors/white :height 8}}) -(defstyle section-separator - (merge base-separator - {:android {:margin-top 12} - :ios {:margin-top 16}})) - (defstyle section-header {:font-size 14 :color colors/gray @@ -95,7 +90,10 @@ :android {:margin-top 11 :margin-bottom 3} :ios {:margin-top 10 - :margin-bottom 2}}) + :margin-bottom 10}}) + +(defstyle section-header-container + {:background-color colors/white}) (def action-list {:background-color colors/blue}) diff --git a/src/status_im/ui/components/list/views.cljs b/src/status_im/ui/components/list/views.cljs index 295150770e..edfcb2649f 100644 --- a/src/status_im/ui/components/list/views.cljs +++ b/src/status_im/ui/components/list/views.cljs @@ -34,8 +34,9 @@ ([left content] (item left content nil)) ([left content right] [react/view {:style styles/item} - [react/view {:style styles/left-item-wrapper} - left] + (when left + [react/view {:style styles/left-item-wrapper} + left]) [react/view {:style styles/content-item-wrapper} content] (when right @@ -88,7 +89,7 @@ (defn list-item-with-checkbox [{:keys [on-value-change checked? plain-checkbox?] :as props} item] (let [handler #(on-value-change (not checked?)) - checkbox [(if plain-checkbox? checkbox/checkbox item-checkbox) props] + checkbox [(if plain-checkbox? checkbox/plain-checkbox item-checkbox) props] item (conj item checkbox)] [touchable-item handler item])) @@ -105,14 +106,14 @@ {:post [(some? %)]} (f data index))) +(def base-separator [react/view styles/base-separator]) + (def default-separator [react/view styles/separator]) (def default-header [react/view styles/list-header-footer-spacing]) (def default-footer [react/view styles/list-header-footer-spacing]) -(def section-separator [react/view styles/section-separator]) - (defn- base-list-props [{:keys [key-fn render-fn empty-component header separator default-separator?]}] (let [separator (or separator (when (and platform/ios? default-separator?) default-separator))] @@ -163,8 +164,9 @@ (defn- default-render-section-header [{:keys [title data]}] (when (seq data) - [react/text {:style styles/section-header} - title])) + [react/view styles/section-header-container + [react/text {:style styles/section-header} + title]])) (defn- wrap-per-section-render-fn [props] (update @@ -182,8 +184,7 @@ (merge (base-list-props props) props {:sections (clj->js (map wrap-per-section-render-fn sections)) - :renderSectionHeader (wrap-render-section-header-fn render-section-header-fn)} - (when platform/ios? {:SectionSeparatorComponent (fn [] (reagent/as-element section-separator))}))]) + :renderSectionHeader (wrap-render-section-header-fn render-section-header-fn)})]) (defn- render-action [{:keys [label accessibility-label icon action disabled?]} {:keys [action-style action-label-style icon-opts]}] diff --git a/src/status_im/ui/components/styles.cljs b/src/status_im/ui/components/styles.cljs index 6ace15535a..5a0dcbbdad 100644 --- a/src/status_im/ui/components/styles.cljs +++ b/src/status_im/ui/components/styles.cljs @@ -72,6 +72,11 @@ :height 24}) (def icon-add + {:width 24 + :height 24 + :color colors/blue}) + +(def icon-add-illuminated {:width 24 :height 24 :color colors/blue diff --git a/src/status_im/ui/components/toolbar/actions.cljs b/src/status_im/ui/components/toolbar/actions.cljs index 58688c77f5..3a2236679b 100644 --- a/src/status_im/ui/components/toolbar/actions.cljs +++ b/src/status_im/ui/components/toolbar/actions.cljs @@ -2,9 +2,9 @@ (:require [re-frame.core :as re-frame] [status-im.ui.components.styles :as styles])) -(defn add [handler] +(defn add [illuminated? handler] {:icon :icons/add - :icon-opts styles/icon-add + :icon-opts (if illuminated? styles/icon-add-illuminated styles/icon-add) :handler handler}) (defn opts [options] diff --git a/src/status_im/ui/screens/db.cljs b/src/status_im/ui/screens/db.cljs index 548617409b..2609795bed 100644 --- a/src/status_im/ui/screens/db.cljs +++ b/src/status_im/ui/screens/db.cljs @@ -167,6 +167,7 @@ :group-chat-profile/editing? :networks/selected-network :networks/networks + :networks/manage :node/after-start :node/after-stop :inbox/wnodes diff --git a/src/status_im/ui/screens/home/views.cljs b/src/status_im/ui/screens/home/views.cljs index 1ea0887d68..6b0f511f8f 100644 --- a/src/status_im/ui/screens/home/views.cljs +++ b/src/status_im/ui/screens/home/views.cljs @@ -26,7 +26,7 @@ [components.common/logo styles/toolbar-logo]]) [toolbar/actions (when platform/ios? - [(-> (toolbar.actions/add #(re-frame/dispatch [:navigate-to :new])) + [(-> (toolbar.actions/add true #(re-frame/dispatch [:navigate-to :new])) (assoc-in [:icon-opts :accessibility-label] :new-chat-button))])]]) (defn- home-action-button [] diff --git a/src/status_im/ui/screens/network_settings/db.cljs b/src/status_im/ui/screens/network_settings/db.cljs index db31d7ee49..f7d1ec31dc 100644 --- a/src/status_im/ui/screens/network_settings/db.cljs +++ b/src/status_im/ui/screens/network_settings/db.cljs @@ -12,3 +12,5 @@ (spec/def :networks/selected-network :networks/network) (spec/def :networks/networks (spec/nilable (spec/map-of :networks/id :networks/network))) + +(spec/def :networks/manage (spec/nilable map?)) diff --git a/src/status_im/ui/screens/network_settings/edit_network/events.cljs b/src/status_im/ui/screens/network_settings/edit_network/events.cljs new file mode 100644 index 0000000000..0681c03bb5 --- /dev/null +++ b/src/status_im/ui/screens/network_settings/edit_network/events.cljs @@ -0,0 +1,47 @@ +(ns status-im.ui.screens.network-settings.edit-network.events + (:require [re-frame.core :as re-frame] + [status-im.utils.handlers :refer [register-handler] :as handlers] + [status-im.utils.handlers-macro :as handlers-macro] + [status-im.ui.screens.accounts.utils :as accounts.utils] + [status-im.utils.ethereum.core :as ethereum] + [status-im.utils.types :as types] + [clojure.string :as string])) + +(defn- new-network [{:keys [random-id] :as cofx} network-name upstream-url type] + (let [data-dir (str "/ethereum/" (name type) "_rpc") + config {:NetworkId (ethereum/chain-keyword->chain-id type) + :DataDir data-dir + :UpstreamConfig {:Enabled true + :URL upstream-url}}] + {:id (string/replace random-id "-" "") + :name network-name + :config (types/clj->json config) + :raw-config config})) + +(handlers/register-handler-fx + :save-new-network + [(re-frame/inject-cofx :random-id)] + (fn [{{:networks/keys [manage] :account/keys [account] :as db} :db :as cofx} _] + (let [{:keys [name url chain]} manage + network (new-network cofx (:value name) (:value url) (:value chain)) + new-networks (merge {(:id network) network} (:networks account))] + (handlers-macro/merge-fx cofx + {:db (dissoc db :networks/manage) + :dispatch [:navigate-back]} + (accounts.utils/account-update {:networks new-networks}))))) + +(handlers/register-handler-fx + :network-set-input + (fn [{db :db} [_ input-key value]] + {:db (update db :networks/manage merge {input-key {:value value + :error (and (string? value) (empty? value))}})})) + +(handlers/register-handler-fx + :edit-network + (fn [{db :db} _] + {:db (update-in db [:networks/manage] assoc + :name {:error true} + :url {:error true} + :chain {:value :mainnet}) + :dispatch [:navigate-to :edit-network]})) + diff --git a/src/status_im/ui/screens/network_settings/edit_network/styles.cljs b/src/status_im/ui/screens/network_settings/edit_network/styles.cljs new file mode 100644 index 0000000000..3eea619bc8 --- /dev/null +++ b/src/status_im/ui/screens/network_settings/edit_network/styles.cljs @@ -0,0 +1,27 @@ +(ns status-im.ui.screens.network-settings.edit-network.styles + (:require-macros [status-im.utils.styles :refer [defstyle]]) + (:require [status-im.ui.components.colors :as colors] + [status-im.ui.components.styles :as styles])) + +(def edit-network-view + {:flex 1 + :margin-horizontal 16 + :margin-vertical 15}) + +(def input-container + {:margin-bottom 15}) + +(def network-type + {:flex-direction :row + :align-items :center}) + +(defstyle network-type-text + {:color colors/black + :ios {:font-size 17 + :letter-spacing -0.2} + :android {:font-size 16}}) + +(def bottom-container + {:flex-direction :row + :margin-horizontal 12 + :margin-vertical 15}) diff --git a/src/status_im/ui/screens/network_settings/edit_network/subs.cljs b/src/status_im/ui/screens/network_settings/edit_network/subs.cljs new file mode 100644 index 0000000000..00f88edf52 --- /dev/null +++ b/src/status_im/ui/screens/network_settings/edit_network/subs.cljs @@ -0,0 +1,14 @@ +(ns status-im.ui.screens.network-settings.edit-network.subs + (:require [re-frame.core :refer [reg-sub]])) + +(reg-sub + :get-manage-network + :<- [:get :networks/manage] + (fn [manage] + manage)) + +(reg-sub + :manage-network-valid? + :<- [:get-manage-network] + (fn [manage] + (not-any? :error (vals manage)))) diff --git a/src/status_im/ui/screens/network_settings/edit_network/views.cljs b/src/status_im/ui/screens/network_settings/edit_network/views.cljs new file mode 100644 index 0000000000..14523e3562 --- /dev/null +++ b/src/status_im/ui/screens/network_settings/edit_network/views.cljs @@ -0,0 +1,62 @@ +(ns status-im.ui.screens.network-settings.edit-network.views + (:require-macros [status-im.utils.views :as views]) + (:require + [re-frame.core :as re-frame] + [status-im.ui.components.react :as react] + [status-im.i18n :as i18n] + [status-im.ui.components.styles :as components.styles] + [status-im.ui.components.common.common :as components.common] + [status-im.ui.components.status-bar.view :as status-bar] + [status-im.ui.components.toolbar.view :as toolbar] + [status-im.ui.components.list.views :as list] + [status-im.ui.components.text-input.view :as text-input] + [status-im.ui.screens.network-settings.edit-network.styles :as styles] + [status-im.ui.components.checkbox.view :as checkbox])) + +(defn- render-network-type [manage-network type] + (let [name (case type + :mainnet (i18n/label :t/mainnet-network) + :testnet (i18n/label :t/ropsten-network) + :rinkeby (i18n/label :t/rinkeby-network))] + [list/list-item-with-checkbox + {:checked? (= (get-in manage-network [:chain :value]) type) + :on-value-change #(re-frame/dispatch [:network-set-input :chain type]) + :plain-checkbox? true} + [list/item + nil [list/item-primary-only name]]])) + +(views/defview edit-network [] + (views/letsubs [manage-network [:get-manage-network] + is-valid? [:manage-network-valid?]] + [react/view components.styles/flex + [status-bar/status-bar] + [react/keyboard-avoiding-view components.styles/flex + [toolbar/simple-toolbar (i18n/label :t/add-network)] + [react/scroll-view + [react/view styles/edit-network-view + [text-input/text-input-with-label + {:label (i18n/label :t/name) + :placeholder (i18n/label :t/specify-name) + :container styles/input-container + :default-value (get-in manage-network [:name :value]) + :on-change-text #(re-frame/dispatch [:network-set-input :name %]) + :auto-focus true}] + [text-input/text-input-with-label + {:label (i18n/label :t/rpc-url) + :placeholder (i18n/label :t/specify-rpc-url) + :container styles/input-container + :default-value (get-in manage-network [:url :value]) + :on-change-text #(re-frame/dispatch [:network-set-input :url %])}] + [react/text (i18n/label :t/network-chain)] + [react/view styles/network-type + [list/flat-list {:data [:mainnet :testnet :rinkeby] + :key-fn (fn [_ i] (str i)) + :separator list/base-separator + :render-fn #(render-network-type manage-network %)}]]]] + [react/view styles/bottom-container + [react/view components.styles/flex] + [components.common/bottom-button + {:forward? true + :label (i18n/label :t/save) + :disabled? (not is-valid?) + :on-press #(re-frame/dispatch [:save-new-network])}]]]])) diff --git a/src/status_im/ui/screens/network_settings/events.cljs b/src/status_im/ui/screens/network_settings/events.cljs index cd859cbbcf..7af6a38039 100644 --- a/src/status_im/ui/screens/network_settings/events.cljs +++ b/src/status_im/ui/screens/network_settings/events.cljs @@ -1,11 +1,15 @@ (ns status-im.ui.screens.network-settings.events (:require [re-frame.core :refer [dispatch dispatch-sync after] :as re-frame] [status-im.utils.handlers :refer [register-handler] :as handlers] + status-im.ui.screens.network-settings.edit-network.events [status-im.utils.handlers-macro :as handlers-macro] [status-im.ui.screens.accounts.utils :as accounts.utils] [status-im.i18n :as i18n] [status-im.utils.ethereum.core :as utils] - [status-im.transport.core :as transport])) + [status-im.transport.core :as transport] + [status-im.utils.ethereum.core :as ethereum] + [status-im.utils.types :as types] + [clojure.string :as string])) ;; handlers @@ -35,13 +39,21 @@ :last-updated now} [::close-application])))) +(handlers/register-handler-fx + ::remove-network + (fn [{:keys [db now] :as cofx} [_ network]] + (let [networks (dissoc (get-in db [:account/account :networks]) network)] + (handlers-macro/merge-fx cofx + {:dispatch [:navigate-back]} + (accounts.utils/account-update {:networks networks + :last-updated now}))))) + (handlers/register-handler-fx :connect-network (fn [{:keys [db now] :as cofx} [_ network]] - (let [current-network (:network db) - networks (:networks/networks db) + (let [current-network (get-in db [:account/account :networks (:network db)]) chats (:transport/chats db)] - (if (utils/network-with-upstream-rpc? networks current-network) + (if (utils/network-with-upstream-rpc? current-network) (handlers-macro/merge-fx cofx {:dispatch-n [[:load-accounts] [:navigate-to-clean :accounts]]} @@ -53,3 +65,15 @@ :confirm-button-text (i18n/label :t/close-app-button) :on-accept #(dispatch [::save-network network]) :on-cancel nil}})))) + +(handlers/register-handler-fx + :delete-network + (fn [{{:account/keys [account] :as db} :db :as cofx} [_ network]] + (let [current-network? (= (:network account) network)] + (if current-network? + {:show-error (i18n/label :t/delete-network-error)} + {:show-confirmation {:title (i18n/label :t/delete-network-title) + :content (i18n/label :t/delete-network-confirmation) + :confirm-button-text (i18n/label :t/delete) + :on-accept #(dispatch [::remove-network network]) + :on-cancel nil}})))) diff --git a/src/status_im/ui/screens/network_settings/network_details/views.cljs b/src/status_im/ui/screens/network_settings/network_details/views.cljs index 1facdfce46..ffcb9ec860 100644 --- a/src/status_im/ui/screens/network_settings/network_details/views.cljs +++ b/src/status_im/ui/screens/network_settings/network_details/views.cljs @@ -6,31 +6,45 @@ [status-im.ui.components.toolbar.view :as toolbar] [status-im.ui.components.react :as react] [status-im.i18n :as i18n] + [status-im.ui.components.styles :as components.styles] + [status-im.ui.components.common.common :as components.common] [status-im.ui.screens.network-settings.styles :as st] - [status-im.ui.screens.network-settings.views :as network-settings])) + [status-im.ui.screens.network-settings.views :as network-settings] + [status-im.ui.components.colors :as colors])) (views/defview network-details [] (views/letsubs [{:keys [networks/selected-network]} [:get-screen-params] - {:keys [network]} [:get-current-account]] + {:keys [network]} [:get-current-account] + networks [:get-networks]] (let [{:keys [id name config]} selected-network - connected? (= id network)] - [react/view {:flex 1} + connected? (= id network) + custom? (seq (filter #(= (:id %) id) (:custom networks)))] + [react/view components.styles/flex [status-bar/status-bar] - [toolbar/simple-toolbar] - [network-settings/network-badge - {:name name - :connected? connected?}] - (when-not connected? - [react/touchable-highlight {:on-press #(rf/dispatch [:connect-network id])} - [react/view st/connect-button-container - [react/view {:style st/connect-button - :accessibility-label :network-connect-button} - [react/text {:style st/connect-button-label - :uppercase? true} - (i18n/label :t/connect)]] - [react/text {:style st/connect-button-description} - (i18n/label :t/connecting-requires-login)]]]) - [react/view st/network-config-container - [react/text {:style st/network-config-text - :accessibility-label :network-details-text} - config]]]))) + [react/view components.styles/flex + [toolbar/simple-toolbar (i18n/label :t/network-details)] + [react/view components.styles/flex + [network-settings/network-badge + {:name name + :connected? connected?}] + (when-not connected? + [react/touchable-highlight {:on-press #(rf/dispatch [:connect-network id])} + [react/view st/connect-button-container + [react/view {:style st/connect-button + :accessibility-label :network-connect-button} + [react/text {:style st/connect-button-label + :uppercase? true} + (i18n/label :t/connect)]] + [react/text {:style st/connect-button-description} + (i18n/label :t/connecting-requires-login)]]]) + [react/view st/network-config-container + [react/text {:style st/network-config-text + :accessibility-label :network-details-text} + config]]] + (when custom? + [react/view st/bottom-container + [react/view components.styles/flex + [components.common/button {:label (i18n/label :t/delete) + :button-style st/delete-button + :label-style st/delete-button-text + :on-press #(rf/dispatch [:delete-network id])}]]])]]))) diff --git a/src/status_im/ui/screens/network_settings/styles.cljs b/src/status_im/ui/screens/network_settings/styles.cljs index 3b4f18e102..3fd1bfc3ab 100644 --- a/src/status_im/ui/screens/network_settings/styles.cljs +++ b/src/status_im/ui/screens/network_settings/styles.cljs @@ -139,3 +139,14 @@ :letter-spacing -0.2} :android {:font-size 12 :margin-top 2}}) + +(def bottom-container + {:flex-direction :row + :margin-horizontal 12 + :margin-vertical 15}) + +(def delete-button + {:background-color colors/white}) + +(def delete-button-text + {:color colors/red}) diff --git a/src/status_im/ui/screens/network_settings/subs.cljs b/src/status_im/ui/screens/network_settings/subs.cljs index da1f6e160c..f69ad4c2a6 100644 --- a/src/status_im/ui/screens/network_settings/subs.cljs +++ b/src/status_im/ui/screens/network_settings/subs.cljs @@ -1,16 +1,36 @@ (ns status-im.ui.screens.network-settings.subs - (:require [re-frame.core :refer [reg-sub subscribe]])) - -(reg-sub - :get-current-account-network - :<- [:get-current-account] - :<- [:get :networks/networks] - (fn [[current-account networks]] - (get networks (:network current-account)))) + (:require [re-frame.core :refer [reg-sub subscribe]] + [status-im.utils.ethereum.core :as ethereum] + status-im.ui.screens.network-settings.edit-network.subs)) (reg-sub :get-network-id + :<- [:network] + (fn [network] + (ethereum/network->chain-id network))) + +(defn- filter-networks [network-type] + (fn [network] + (let [chain-id (ethereum/network->chain-id network) + testnet? (ethereum/testnet? chain-id) + custom? (:custom? network)] + (case network-type + :custom custom? + :mainnet (and (not custom?) (not testnet?)) + :testnet (and (not custom?) testnet?))))) + +(defn- label-networks [default-networks] + (fn [network] + (let [custom? (not (contains? default-networks (:id network)))] + (assoc network :custom? custom?)))) + +(reg-sub + :get-networks + :<- [:get :account/account] :<- [:get :networks/networks] - :<- [:get :network] - (fn [[networks network]] - (get-in networks [network :raw-config :NetworkId]))) \ No newline at end of file + (fn [[{:keys [networks] :as account} default-networks]] + (let [networks (map (label-networks default-networks) (sort-by :name (vals networks))) + types [:mainnet :testnet :custom]] + (zipmap + types + (map #(filter (filter-networks %) networks) types))))) diff --git a/src/status_im/ui/screens/network_settings/views.cljs b/src/status_im/ui/screens/network_settings/views.cljs index bab968d58b..1278870db5 100644 --- a/src/status_im/ui/screens/network_settings/views.cljs +++ b/src/status_im/ui/screens/network_settings/views.cljs @@ -1,12 +1,16 @@ (ns status-im.ui.screens.network-settings.views (:require-macros [status-im.utils.views :as views]) (:require [re-frame.core :as re-frame] + [reagent.core :as reagent] [status-im.i18n :as i18n] [status-im.ui.components.react :as react] [status-im.ui.components.icons.vector-icons :as vector-icons] [status-im.ui.components.list.views :as list] [status-im.ui.components.status-bar.view :as status-bar] [status-im.ui.components.toolbar.view :as toolbar] + [status-im.ui.components.toolbar.actions :as toolbar.actions] + [status-im.ui.components.styles :as components.styles] + [status-im.ui.components.common.common :as components.common] [status-im.ui.screens.network-settings.styles :as styles] [status-im.utils.utils :as utils] [status-im.utils.config :as config])) @@ -31,6 +35,9 @@ (defn navigate-to-network [network] (re-frame/dispatch [:navigate-to :network-details {:networks/selected-network network}])) +(defn navigate-to-add-network [] + (re-frame/dispatch [:edit-network])) + (defn wrap-mainnet-warning [network cb] (fn [] (if (and config/mainnet-warning-enabled? @@ -44,9 +51,7 @@ (defn render-network [current-network] (fn [{:keys [id name] :as network}] (let [connected? (= id current-network)] - [react/touchable-highlight - {:on-press (wrap-mainnet-warning network navigate-to-network) - :accessibility-label :network-item} + [list/touchable-item (wrap-mainnet-warning network navigate-to-network) [react/view styles/network-item [network-icon connected? 40] [react/view {:padding-horizontal 16} @@ -58,13 +63,25 @@ (i18n/label :t/connected)])]]]))) (views/defview network-settings [] - (views/letsubs [{:keys [network networks]} [:get-current-account]] - [react/view {:flex 1} + (views/letsubs [{:keys [network]} [:get-current-account] + networks [:get-networks]] + [react/view components.styles/flex [status-bar/status-bar] - [toolbar/simple-toolbar - (i18n/label :t/network-settings)] + [toolbar/toolbar {} + toolbar/default-nav-back + [toolbar/content-title (i18n/label :t/network-settings)] + [toolbar/actions + [(toolbar.actions/add false navigate-to-add-network)]]] [react/view styles/wrapper - [list/flat-list {:data (vals networks) - :key-fn :id - :default-separator? true - :render-fn (render-network network)}]]])) + [list/section-list {:sections [{:title (i18n/label :t/main-networks) + :key :mainnet + :data (:mainnet networks)} + {:title (i18n/label :t/test-networks) + :key :testnet + :data (:testnet networks)} + {:title (i18n/label :t/custom-networks) + :key :custom + :data (:custom networks)}] + :key-fn :id + :default-separator? true + :render-fn (render-network network)}]]])) diff --git a/src/status_im/ui/screens/offline_messaging_settings/events.cljs b/src/status_im/ui/screens/offline_messaging_settings/events.cljs index 053c412523..d5cd33ef2f 100644 --- a/src/status_im/ui/screens/offline_messaging_settings/events.cljs +++ b/src/status_im/ui/screens/offline_messaging_settings/events.cljs @@ -9,20 +9,20 @@ (handlers/register-handler-fx ::save-wnode - (fn [{:keys [db now] :as cofx} [_ wnode]] - (let [network (ethereum/network->chain-keyword (:network db)) - settings (get-in db [:account/account :settings])] + (fn [{:keys [db now] :as cofx} [_ chain wnode]] + (let [settings (get-in db [:account/account :settings])] (handlers-macro/merge-fx cofx {:dispatch [:logout]} - (accounts-events/update-settings (assoc-in settings [:wnode network] wnode)))))) + (accounts-events/update-settings (assoc-in settings [:wnode chain] wnode)))))) (handlers/register-handler-fx :connect-wnode (fn [{:keys [db]} [_ wnode]] - (let [network (ethereum/network->chain-keyword (:network db))] + (let [network (get (:networks (:account/account db)) (:network db)) + chain (ethereum/network->chain-keyword network)] {:show-confirmation {:title (i18n/label :t/close-app-title) :content (i18n/label :t/connect-wnode-content - {:name (get-in db [:inbox/wnodes network wnode :name])}) + {:name (get-in db [:inbox/wnodes chain wnode :name])}) :confirm-button-text (i18n/label :t/close-app-button) - :on-accept #(dispatch [::save-wnode wnode]) + :on-accept #(dispatch [::save-wnode chain wnode]) :on-cancel nil}}))) diff --git a/src/status_im/ui/screens/subs.cljs b/src/status_im/ui/screens/subs.cljs index b06732fa97..8ef40b63a7 100644 --- a/src/status_im/ui/screens/subs.cljs +++ b/src/status_im/ui/screens/subs.cljs @@ -32,7 +32,10 @@ (fn [current-account] (:signed-up? current-account))) -(reg-sub :network :network) +(reg-sub :network + :<- [:get-current-account] + (fn [current-account] + (get (:networks current-account) (:network current-account)))) (reg-sub :sync-state :sync-state) (reg-sub :network-status :network-status) diff --git a/src/status_im/ui/screens/views.cljs b/src/status_im/ui/screens/views.cljs index 84eaa1f8e1..b4bca5fe7d 100644 --- a/src/status_im/ui/screens/views.cljs +++ b/src/status_im/ui/screens/views.cljs @@ -41,6 +41,7 @@ [status-im.ui.screens.wallet.components.views :refer [contact-code recent-recipients recipient-qr-code]] [status-im.ui.screens.network-settings.views :refer [network-settings]] [status-im.ui.screens.network-settings.network-details.views :refer [network-details]] + [status-im.ui.screens.network-settings.edit-network.views :refer [edit-network]] [status-im.ui.screens.offline-messaging-settings.views :refer [offline-messaging-settings]] [status-im.ui.screens.currency-settings.views :refer [currency-settings]] [status-im.ui.screens.browser.views :refer [browser]] @@ -151,6 +152,7 @@ :recover recover :network-settings network-settings :network-details network-details + :edit-network edit-network :offline-messaging-settings offline-messaging-settings :currency-settings currency-settings :recent-recipients recent-recipients diff --git a/src/status_im/ui/screens/wallet/events.cljs b/src/status_im/ui/screens/wallet/events.cljs index 931c8b2bb5..dc6a45fd89 100644 --- a/src/status_im/ui/screens/wallet/events.cljs +++ b/src/status_im/ui/screens/wallet/events.cljs @@ -102,7 +102,8 @@ (handlers/register-handler-fx :update-wallet (fn [{{:keys [web3 account/account network network-status] {:keys [address settings]} :account/account :as db} :db} _] - (let [chain (ethereum/network->chain-keyword network) + (let [network (get-in db [:account/account :networks network]) + chain (ethereum/network->chain-keyword network) mainnet? (= :mainnet chain) symbols (get-in settings [:wallet :visible-tokens chain]) currency-id (or (get-in settings [:wallet :currency]) :usd) @@ -132,12 +133,13 @@ :update-transactions (fn [{{:keys [network network-status web3] :as db} :db} _] (when (not= network-status :offline) - (let [chain (ethereum/network->chain-keyword network) + (let [network (get-in db [:account/account :networks network]) + chain (ethereum/network->chain-keyword network) all-tokens (tokens/tokens-for chain) token-addresses (map :address all-tokens)] {:get-transactions {:account-id (get-in db [:account/account :address]) :token-addresses token-addresses - :network network + :network chain :web3 web3 :success-event :update-transactions-success :error-event :update-transactions-fail} diff --git a/src/status_im/ui/screens/wallet/settings/events.cljs b/src/status_im/ui/screens/wallet/settings/events.cljs index aadb2fd8bb..a70400fb36 100644 --- a/src/status_im/ui/screens/wallet/settings/events.cljs +++ b/src/status_im/ui/screens/wallet/settings/events.cljs @@ -10,8 +10,9 @@ (handlers/register-handler-fx :wallet.settings/toggle-visible-token - (fn [{{:keys [network account/account] :as db} :db :as cofx} [_ symbol checked?]] - (let [chain (ethereum/network->chain-keyword network) + (fn [{{:keys [account/account] :as db} :db :as cofx} [_ symbol checked?]] + (let [network (get (:networks account) (:network account)) + chain (ethereum/network->chain-keyword network) settings (get account :settings) new-settings (update-in settings [:wallet :visible-tokens chain] #(toggle-checked % symbol checked?))] (accounts/update-settings new-settings cofx)))) diff --git a/src/status_im/ui/screens/wallet/transactions/subs.cljs b/src/status_im/ui/screens/wallet/transactions/subs.cljs index 42e81299fd..b641535448 100644 --- a/src/status_im/ui/screens/wallet/transactions/subs.cljs +++ b/src/status_im/ui/screens/wallet/transactions/subs.cljs @@ -4,7 +4,8 @@ [status-im.utils.datetime :as datetime] [status-im.utils.hex :as utils.hex] [status-im.utils.money :as money] - [status-im.utils.transactions :as transactions])) + [status-im.utils.transactions :as transactions] + [status-im.utils.ethereum.core :as ethereum])) (reg-sub :wallet.transactions/transactions-loading? :<- [:wallet] @@ -125,7 +126,8 @@ :<- [:network] (fn [[unsigned-transactions transactions current-transaction network]] (let [transactions (merge transactions unsigned-transactions) - {:keys [gas-used gas-price hash timestamp type] :as transaction} (get transactions current-transaction)] + {:keys [gas-used gas-price hash timestamp type] :as transaction} (get transactions current-transaction) + chain (ethereum/network->chain-keyword network)] (when transaction (merge transaction {:gas-price-eth (if gas-price (money/wei->str :eth gas-price) "-") @@ -140,7 +142,7 @@ :hash (i18n/label :not-applicable)} {:cost (when gas-used (money/wei->str :eth (money/fee-value gas-used gas-price))) - :url (transactions/get-transaction-details-url network hash)})))))) + :url (transactions/get-transaction-details-url chain hash)})))))) (reg-sub :wallet.transactions.details/confirmations :<- [:wallet.transactions/transaction-details] diff --git a/src/status_im/utils/ethereum/core.cljs b/src/status_im/utils/ethereum/core.cljs index d28bad61d4..b56cde0825 100644 --- a/src/status_im/utils/ethereum/core.cljs +++ b/src/status_im/utils/ethereum/core.cljs @@ -3,7 +3,8 @@ [status-im.js-dependencies :as dependencies] [status-im.utils.ethereum.tokens :as tokens] [status-im.utils.money :as money] - [taoensso.timbre :as log])) + [taoensso.timbre :as log] + [status-im.utils.types :as types])) ;; IDs standardized in https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md#list-of-chain-ids @@ -21,8 +22,11 @@ (defn testnet? [id] (contains? #{(chain-keyword->chain-id :testnet) (chain-keyword->chain-id :rinkeby)} id)) -(defn network-with-upstream-rpc? [networks network] - (get-in networks [network :raw-config :UpstreamConfig :Enabled])) +(defn network-config [network] + (or (:raw-config network) (types/json->clj (:config network)))) + +(defn network-with-upstream-rpc? [network] + (get-in (network-config network) [:UpstreamConfig :Enabled])) (def hex-prefix "0x") @@ -36,9 +40,11 @@ (when s (.isAddress dependencies/Web3.prototype s))) +(defn network->chain-id [network] + (:NetworkId (network-config network))) + (defn network->chain-keyword [network] - (when network - (keyword (string/replace network "_rpc" "")))) + (chain-id->chain-keyword (network->chain-id network))) (defn sha3 [s] (.sha3 dependencies/Web3.prototype (str s))) diff --git a/src/status_im/utils/transactions.cljs b/src/status_im/utils/transactions.cljs index 5be70c416b..8f269beb9b 100644 --- a/src/status_im/utils/transactions.cljs +++ b/src/status_im/utils/transactions.cljs @@ -4,9 +4,9 @@ (defn- get-network-subdomain [network] (case network - ("testnet" "testnet_rpc") "ropsten" - ("mainnet" "mainnet_rpc") nil - ("rinkeby" "rinkeby_rpc") "rinkeby")) + (:testnet) "ropsten" + (:mainnet) nil + (:rinkeby) "rinkeby")) (defn get-transaction-details-url [network hash] (let [network-subdomain (get-network-subdomain network)] @@ -16,9 +16,9 @@ (defn- get-api-network-subdomain [network] (case network - ("testnet" "testnet_rpc") "api-ropsten" - ("mainnet" "mainnet_rpc") "api" - ("rinkeby" "rinkeby_rpc") "api-rinkeby")) + (:testnet) "api-ropsten" + (:mainnet) "api" + (:rinkeby) "api-rinkeby")) (defn get-transaction-url [network account] (let [network-subdomain (get-api-network-subdomain network)]