Add support for custom network upstreams

Signed-off-by: Andrey Shovkoplyas <motor4ik@gmail.com>
This commit is contained in:
Connor Christie 2018-05-17 16:21:01 +12:00 committed by Andrey Shovkoplyas
parent 41900da38c
commit 24d5fabe2e
No known key found for this signature in database
GPG Key ID: EAAB7C8622D860A4
30 changed files with 407 additions and 114 deletions

View File

@ -37,7 +37,7 @@
[{:keys [db get-local-storage-data]} commands-resource whisper-identity] [{:keys [db get-local-storage-data]} commands-resource whisper-identity]
(let [data (get-local-storage-data whisper-identity) (let [data (get-local-storage-data whisper-identity)
local-storage-snippet (js-resources/local-storage-data data) 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) ethereum-id-snippet (js-resources/network-id network-id)
commands-snippet (str local-storage-snippet ethereum-id-snippet commands-resource)] commands-snippet (str local-storage-snippet ethereum-id-snippet commands-resource)]
{::evaluate-jail-n [{:jail-id whisper-identity {::evaluate-jail-n [{:jail-id whisper-identity

View File

@ -80,8 +80,8 @@
(handlers/register-handler-fx (handlers/register-handler-fx
:initialize-sync-listener :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) (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) {:db (assoc db :sync-listening-started true)
:dispatch [:check-sync]}))) :dispatch [:check-sync]})))

View File

@ -331,6 +331,7 @@
:add-new-contact "Add new contact" :add-new-contact "Add new contact"
:scan-qr "Scan QR code" :scan-qr "Scan QR code"
:name "Name" :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" :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" :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" :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-new-network "Add new network"
:add-wnode "Add mailserver" :add-wnode "Add mailserver"
:existing-networks "Existing networks" :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 ;; TODO(dmitryn): come up with better description/naming. Suggested namings: Mailbox and Master Node
:existing-wnodes "Existing mailservers" :existing-wnodes "Existing mailservers"
:add-json-file "Add a JSON file" :add-json-file "Add a JSON file"
@ -591,12 +594,15 @@
:process-json "Process JSON" :process-json "Process JSON"
:error-processing-json "Error processing JSON" :error-processing-json "Error processing JSON"
:rpc-url "RPC URL" :rpc-url "RPC URL"
:network-chain "Network chain"
:network "Network" :network "Network"
:network-details "Network details"
:remove-network "Remove network" :remove-network "Remove network"
:network-settings "Network settings" :network-settings "Network settings"
:offline-messaging "Offline messages" :offline-messaging "Offline messages"
:offline-messaging-settings "Offline messages settings" :offline-messaging-settings "Offline messages settings"
:edit-network-warning "Be careful, editing the network data may disable this network for you" :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" :connecting-requires-login "Connecting to another network requires login"
:close-app-title "Warning!" :close-app-title "Warning!"
:close-app-content "The app will stop and close. When you reopen it, the selected network will be used" :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, wed like to point out the dangers. Youre 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-text "While we highly appreciate your contribution as a tester of Status, wed like to point out the dangers. Youre 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" :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 "Browser" :browser "Browser"
:enter-dapp-url "Enter a ÐApp URL" :enter-dapp-url "Enter a ÐApp URL"

View File

@ -42,9 +42,10 @@
(success-fn result))))) (success-fn result)))))
(defn get-current-wnode-address [db] (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])] 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 [] (defn initialize-offline-inbox-flow []
{:first-dispatch [:inbox/get-sym-key] {:first-dispatch [:inbox/get-sym-key]

View File

@ -8,10 +8,20 @@
{:background-color (if checked? colors/blue colors/gray-lighter) {:background-color (if checked? colors/blue colors/gray-lighter)
:align-items :center :align-items :center
:justify-content :center :justify-content :center
:border-radius 2 :border-radius 2
:width 24 :width 24
:height 24}) :height 24})
(defn icon-radio-container [checked?]
(merge (icon-check-container checked?)
{:border-radius 100
:width 26
:height 26}))
(def check-icon (def check-icon
{:width 12 {:width 12
:height 12}) :height 12})
(def plain-check-icon
(merge check-icon
{:tint-color colors/blue}))

View File

@ -1,17 +1,26 @@
(ns status-im.ui.components.checkbox.view (ns status-im.ui.components.checkbox.view
(:require [status-im.ui.components.checkbox.styles :as styles] (:require [status-im.ui.components.checkbox.styles :as styles]
[status-im.ui.components.react :as react] [status-im.ui.components.react :as react]
[status-im.ui.components.icons.vector-icons :as vector-icons]
[status-im.utils.platform :as platform])) [status-im.utils.platform :as platform]))
(defn checkbox [{:keys [on-value-change checked? accessibility-label] :or {accessibility-label :checkbox}}] (defn- checkbox-generic [{:keys [on-value-change checked? accessibility-label] :or {accessibility-label :checkbox}} plain?]
(if platform/android? (let [icon-check-container (if plain? #() styles/icon-check-container)
[react/view {:style styles/wrapper} check-icon (if plain? styles/plain-check-icon styles/check-icon)]
[react/check-box {:on-value-change on-value-change (if platform/android?
:value checked? [react/view styles/wrapper
:accessibility-label accessibility-label}]] [react/check-box {:on-value-change on-value-change
[react/touchable-highlight (merge {:style styles/wrapper :value checked?
:accessibility-label accessibility-label} :accessibility-label accessibility-label}]]
(when on-value-change {:on-press #(on-value-change (not checked?))})) [react/touchable-highlight (merge {:style styles/wrapper
[react/view (styles/icon-check-container checked?) :accessibility-label accessibility-label}
(when checked? (when on-value-change {:on-press #(on-value-change (not checked?))}))
[react/icon :check_on styles/check-icon])]])) [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])

View File

@ -53,7 +53,7 @@
{:width icon-size {:width icon-size
:height icon-size}) :height icon-size})
(def horizontal-margin 16) (def horizontal-margin 12)
(def vertical-margin 12) (def vertical-margin 12)
(def left-item-wrapper (def left-item-wrapper
@ -83,11 +83,6 @@
{:android {:background-color colors/white {:android {:background-color colors/white
:height 8}}) :height 8}})
(defstyle section-separator
(merge base-separator
{:android {:margin-top 12}
:ios {:margin-top 16}}))
(defstyle section-header (defstyle section-header
{:font-size 14 {:font-size 14
:color colors/gray :color colors/gray
@ -95,7 +90,10 @@
:android {:margin-top 11 :android {:margin-top 11
:margin-bottom 3} :margin-bottom 3}
:ios {:margin-top 10 :ios {:margin-top 10
:margin-bottom 2}}) :margin-bottom 10}})
(defstyle section-header-container
{:background-color colors/white})
(def action-list (def action-list
{:background-color colors/blue}) {:background-color colors/blue})

View File

@ -34,8 +34,9 @@
([left content] (item left content nil)) ([left content] (item left content nil))
([left content right] ([left content right]
[react/view {:style styles/item} [react/view {:style styles/item}
[react/view {:style styles/left-item-wrapper} (when left
left] [react/view {:style styles/left-item-wrapper}
left])
[react/view {:style styles/content-item-wrapper} [react/view {:style styles/content-item-wrapper}
content] content]
(when right (when right
@ -88,7 +89,7 @@
(defn list-item-with-checkbox [{:keys [on-value-change checked? plain-checkbox?] :as props} item] (defn list-item-with-checkbox [{:keys [on-value-change checked? plain-checkbox?] :as props} item]
(let [handler #(on-value-change (not checked?)) (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)] item (conj item checkbox)]
[touchable-item handler item])) [touchable-item handler item]))
@ -105,14 +106,14 @@
{:post [(some? %)]} {:post [(some? %)]}
(f data index))) (f data index)))
(def base-separator [react/view styles/base-separator])
(def default-separator [react/view styles/separator]) (def default-separator [react/view styles/separator])
(def default-header [react/view styles/list-header-footer-spacing]) (def default-header [react/view styles/list-header-footer-spacing])
(def default-footer [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 (defn- base-list-props
[{:keys [key-fn render-fn empty-component header separator default-separator?]}] [{:keys [key-fn render-fn empty-component header separator default-separator?]}]
(let [separator (or separator (when (and platform/ios? default-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]}] (defn- default-render-section-header [{:keys [title data]}]
(when (seq data) (when (seq data)
[react/text {:style styles/section-header} [react/view styles/section-header-container
title])) [react/text {:style styles/section-header}
title]]))
(defn- wrap-per-section-render-fn [props] (defn- wrap-per-section-render-fn [props]
(update (update
@ -182,8 +184,7 @@
(merge (base-list-props props) (merge (base-list-props props)
props props
{:sections (clj->js (map wrap-per-section-render-fn sections)) {:sections (clj->js (map wrap-per-section-render-fn sections))
:renderSectionHeader (wrap-render-section-header-fn render-section-header-fn)} :renderSectionHeader (wrap-render-section-header-fn render-section-header-fn)})])
(when platform/ios? {:SectionSeparatorComponent (fn [] (reagent/as-element section-separator))}))])
(defn- render-action [{:keys [label accessibility-label icon action disabled?]} (defn- render-action [{:keys [label accessibility-label icon action disabled?]}
{:keys [action-style action-label-style icon-opts]}] {:keys [action-style action-label-style icon-opts]}]

View File

@ -72,6 +72,11 @@
:height 24}) :height 24})
(def icon-add (def icon-add
{:width 24
:height 24
:color colors/blue})
(def icon-add-illuminated
{:width 24 {:width 24
:height 24 :height 24
:color colors/blue :color colors/blue

View File

@ -2,9 +2,9 @@
(:require [re-frame.core :as re-frame] (:require [re-frame.core :as re-frame]
[status-im.ui.components.styles :as styles])) [status-im.ui.components.styles :as styles]))
(defn add [handler] (defn add [illuminated? handler]
{:icon :icons/add {:icon :icons/add
:icon-opts styles/icon-add :icon-opts (if illuminated? styles/icon-add-illuminated styles/icon-add)
:handler handler}) :handler handler})
(defn opts [options] (defn opts [options]

View File

@ -167,6 +167,7 @@
:group-chat-profile/editing? :group-chat-profile/editing?
:networks/selected-network :networks/selected-network
:networks/networks :networks/networks
:networks/manage
:node/after-start :node/after-start
:node/after-stop :node/after-stop
:inbox/wnodes :inbox/wnodes

View File

@ -26,7 +26,7 @@
[components.common/logo styles/toolbar-logo]]) [components.common/logo styles/toolbar-logo]])
[toolbar/actions [toolbar/actions
(when platform/ios? (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))])]]) (assoc-in [:icon-opts :accessibility-label] :new-chat-button))])]])
(defn- home-action-button [] (defn- home-action-button []

View File

@ -12,3 +12,5 @@
(spec/def :networks/selected-network :networks/network) (spec/def :networks/selected-network :networks/network)
(spec/def :networks/networks (spec/nilable (spec/map-of :networks/id :networks/network))) (spec/def :networks/networks (spec/nilable (spec/map-of :networks/id :networks/network)))
(spec/def :networks/manage (spec/nilable map?))

View File

@ -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]}))

View File

@ -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})

View File

@ -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))))

View File

@ -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])}]]]]))

View File

@ -1,11 +1,15 @@
(ns status-im.ui.screens.network-settings.events (ns status-im.ui.screens.network-settings.events
(:require [re-frame.core :refer [dispatch dispatch-sync after] :as re-frame] (:require [re-frame.core :refer [dispatch dispatch-sync after] :as re-frame]
[status-im.utils.handlers :refer [register-handler] :as handlers] [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.utils.handlers-macro :as handlers-macro]
[status-im.ui.screens.accounts.utils :as accounts.utils] [status-im.ui.screens.accounts.utils :as accounts.utils]
[status-im.i18n :as i18n] [status-im.i18n :as i18n]
[status-im.utils.ethereum.core :as utils] [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 ;; handlers
@ -35,13 +39,21 @@
:last-updated now} :last-updated now}
[::close-application])))) [::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 (handlers/register-handler-fx
:connect-network :connect-network
(fn [{:keys [db now] :as cofx} [_ network]] (fn [{:keys [db now] :as cofx} [_ network]]
(let [current-network (:network db) (let [current-network (get-in db [:account/account :networks (:network db)])
networks (:networks/networks db)
chats (:transport/chats 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 (handlers-macro/merge-fx cofx
{:dispatch-n [[:load-accounts] {:dispatch-n [[:load-accounts]
[:navigate-to-clean :accounts]]} [:navigate-to-clean :accounts]]}
@ -53,3 +65,15 @@
:confirm-button-text (i18n/label :t/close-app-button) :confirm-button-text (i18n/label :t/close-app-button)
:on-accept #(dispatch [::save-network network]) :on-accept #(dispatch [::save-network network])
:on-cancel nil}})))) :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}}))))

View File

@ -6,31 +6,45 @@
[status-im.ui.components.toolbar.view :as toolbar] [status-im.ui.components.toolbar.view :as toolbar]
[status-im.ui.components.react :as react] [status-im.ui.components.react :as react]
[status-im.i18n :as i18n] [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.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/defview network-details []
(views/letsubs [{:keys [networks/selected-network]} [:get-screen-params] (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 (let [{:keys [id name config]} selected-network
connected? (= id network)] connected? (= id network)
[react/view {:flex 1} custom? (seq (filter #(= (:id %) id) (:custom networks)))]
[react/view components.styles/flex
[status-bar/status-bar] [status-bar/status-bar]
[toolbar/simple-toolbar] [react/view components.styles/flex
[network-settings/network-badge [toolbar/simple-toolbar (i18n/label :t/network-details)]
{:name name [react/view components.styles/flex
:connected? connected?}] [network-settings/network-badge
(when-not connected? {:name name
[react/touchable-highlight {:on-press #(rf/dispatch [:connect-network id])} :connected? connected?}]
[react/view st/connect-button-container (when-not connected?
[react/view {:style st/connect-button [react/touchable-highlight {:on-press #(rf/dispatch [:connect-network id])}
:accessibility-label :network-connect-button} [react/view st/connect-button-container
[react/text {:style st/connect-button-label [react/view {:style st/connect-button
:uppercase? true} :accessibility-label :network-connect-button}
(i18n/label :t/connect)]] [react/text {:style st/connect-button-label
[react/text {:style st/connect-button-description} :uppercase? true}
(i18n/label :t/connecting-requires-login)]]]) (i18n/label :t/connect)]]
[react/view st/network-config-container [react/text {:style st/connect-button-description}
[react/text {:style st/network-config-text (i18n/label :t/connecting-requires-login)]]])
:accessibility-label :network-details-text} [react/view st/network-config-container
config]]]))) [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])}]]])]])))

View File

@ -139,3 +139,14 @@
:letter-spacing -0.2} :letter-spacing -0.2}
:android {:font-size 12 :android {:font-size 12
:margin-top 2}}) :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})

View File

@ -1,16 +1,36 @@
(ns status-im.ui.screens.network-settings.subs (ns status-im.ui.screens.network-settings.subs
(:require [re-frame.core :refer [reg-sub subscribe]])) (:require [re-frame.core :refer [reg-sub subscribe]]
[status-im.utils.ethereum.core :as ethereum]
(reg-sub status-im.ui.screens.network-settings.edit-network.subs))
:get-current-account-network
:<- [:get-current-account]
:<- [:get :networks/networks]
(fn [[current-account networks]]
(get networks (:network current-account))))
(reg-sub (reg-sub
:get-network-id :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 :networks/networks]
:<- [:get :network] (fn [[{:keys [networks] :as account} default-networks]]
(fn [[networks network]] (let [networks (map (label-networks default-networks) (sort-by :name (vals networks)))
(get-in networks [network :raw-config :NetworkId]))) types [:mainnet :testnet :custom]]
(zipmap
types
(map #(filter (filter-networks %) networks) types)))))

View File

@ -1,12 +1,16 @@
(ns status-im.ui.screens.network-settings.views (ns status-im.ui.screens.network-settings.views
(:require-macros [status-im.utils.views :as views]) (:require-macros [status-im.utils.views :as views])
(:require [re-frame.core :as re-frame] (:require [re-frame.core :as re-frame]
[reagent.core :as reagent]
[status-im.i18n :as i18n] [status-im.i18n :as i18n]
[status-im.ui.components.react :as react] [status-im.ui.components.react :as react]
[status-im.ui.components.icons.vector-icons :as vector-icons] [status-im.ui.components.icons.vector-icons :as vector-icons]
[status-im.ui.components.list.views :as list] [status-im.ui.components.list.views :as list]
[status-im.ui.components.status-bar.view :as status-bar] [status-im.ui.components.status-bar.view :as status-bar]
[status-im.ui.components.toolbar.view :as toolbar] [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.ui.screens.network-settings.styles :as styles]
[status-im.utils.utils :as utils] [status-im.utils.utils :as utils]
[status-im.utils.config :as config])) [status-im.utils.config :as config]))
@ -31,6 +35,9 @@
(defn navigate-to-network [network] (defn navigate-to-network [network]
(re-frame/dispatch [:navigate-to :network-details {:networks/selected-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] (defn wrap-mainnet-warning [network cb]
(fn [] (fn []
(if (and config/mainnet-warning-enabled? (if (and config/mainnet-warning-enabled?
@ -44,9 +51,7 @@
(defn render-network [current-network] (defn render-network [current-network]
(fn [{:keys [id name] :as network}] (fn [{:keys [id name] :as network}]
(let [connected? (= id current-network)] (let [connected? (= id current-network)]
[react/touchable-highlight [list/touchable-item (wrap-mainnet-warning network navigate-to-network)
{:on-press (wrap-mainnet-warning network navigate-to-network)
:accessibility-label :network-item}
[react/view styles/network-item [react/view styles/network-item
[network-icon connected? 40] [network-icon connected? 40]
[react/view {:padding-horizontal 16} [react/view {:padding-horizontal 16}
@ -58,13 +63,25 @@
(i18n/label :t/connected)])]]]))) (i18n/label :t/connected)])]]])))
(views/defview network-settings [] (views/defview network-settings []
(views/letsubs [{:keys [network networks]} [:get-current-account]] (views/letsubs [{:keys [network]} [:get-current-account]
[react/view {:flex 1} networks [:get-networks]]
[react/view components.styles/flex
[status-bar/status-bar] [status-bar/status-bar]
[toolbar/simple-toolbar [toolbar/toolbar {}
(i18n/label :t/network-settings)] 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 [react/view styles/wrapper
[list/flat-list {:data (vals networks) [list/section-list {:sections [{:title (i18n/label :t/main-networks)
:key-fn :id :key :mainnet
:default-separator? true :data (:mainnet networks)}
:render-fn (render-network network)}]]])) {: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)}]]]))

View File

@ -9,20 +9,20 @@
(handlers/register-handler-fx (handlers/register-handler-fx
::save-wnode ::save-wnode
(fn [{:keys [db now] :as cofx} [_ wnode]] (fn [{:keys [db now] :as cofx} [_ chain wnode]]
(let [network (ethereum/network->chain-keyword (:network db)) (let [settings (get-in db [:account/account :settings])]
settings (get-in db [:account/account :settings])]
(handlers-macro/merge-fx cofx (handlers-macro/merge-fx cofx
{:dispatch [:logout]} {: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 (handlers/register-handler-fx
:connect-wnode :connect-wnode
(fn [{:keys [db]} [_ 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) {:show-confirmation {:title (i18n/label :t/close-app-title)
:content (i18n/label :t/connect-wnode-content :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) :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}}))) :on-cancel nil}})))

View File

@ -32,7 +32,10 @@
(fn [current-account] (fn [current-account]
(:signed-up? 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 :sync-state :sync-state)
(reg-sub :network-status :network-status) (reg-sub :network-status :network-status)

View File

@ -41,6 +41,7 @@
[status-im.ui.screens.wallet.components.views :refer [contact-code recent-recipients recipient-qr-code]] [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.views :refer [network-settings]]
[status-im.ui.screens.network-settings.network-details.views :refer [network-details]] [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.offline-messaging-settings.views :refer [offline-messaging-settings]]
[status-im.ui.screens.currency-settings.views :refer [currency-settings]] [status-im.ui.screens.currency-settings.views :refer [currency-settings]]
[status-im.ui.screens.browser.views :refer [browser]] [status-im.ui.screens.browser.views :refer [browser]]
@ -151,6 +152,7 @@
:recover recover :recover recover
:network-settings network-settings :network-settings network-settings
:network-details network-details :network-details network-details
:edit-network edit-network
:offline-messaging-settings offline-messaging-settings :offline-messaging-settings offline-messaging-settings
:currency-settings currency-settings :currency-settings currency-settings
:recent-recipients recent-recipients :recent-recipients recent-recipients

View File

@ -102,7 +102,8 @@
(handlers/register-handler-fx (handlers/register-handler-fx
:update-wallet :update-wallet
(fn [{{:keys [web3 account/account network network-status] {:keys [address settings]} :account/account :as db} :db} _] (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) mainnet? (= :mainnet chain)
symbols (get-in settings [:wallet :visible-tokens chain]) symbols (get-in settings [:wallet :visible-tokens chain])
currency-id (or (get-in settings [:wallet :currency]) :usd) currency-id (or (get-in settings [:wallet :currency]) :usd)
@ -132,12 +133,13 @@
:update-transactions :update-transactions
(fn [{{:keys [network network-status web3] :as db} :db} _] (fn [{{:keys [network network-status web3] :as db} :db} _]
(when (not= network-status :offline) (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) all-tokens (tokens/tokens-for chain)
token-addresses (map :address all-tokens)] token-addresses (map :address all-tokens)]
{:get-transactions {:account-id (get-in db [:account/account :address]) {:get-transactions {:account-id (get-in db [:account/account :address])
:token-addresses token-addresses :token-addresses token-addresses
:network network :network chain
:web3 web3 :web3 web3
:success-event :update-transactions-success :success-event :update-transactions-success
:error-event :update-transactions-fail} :error-event :update-transactions-fail}

View File

@ -10,8 +10,9 @@
(handlers/register-handler-fx (handlers/register-handler-fx
:wallet.settings/toggle-visible-token :wallet.settings/toggle-visible-token
(fn [{{:keys [network account/account] :as db} :db :as cofx} [_ symbol checked?]] (fn [{{:keys [account/account] :as db} :db :as cofx} [_ symbol checked?]]
(let [chain (ethereum/network->chain-keyword network) (let [network (get (:networks account) (:network account))
chain (ethereum/network->chain-keyword network)
settings (get account :settings) settings (get account :settings)
new-settings (update-in settings [:wallet :visible-tokens chain] #(toggle-checked % symbol checked?))] new-settings (update-in settings [:wallet :visible-tokens chain] #(toggle-checked % symbol checked?))]
(accounts/update-settings new-settings cofx)))) (accounts/update-settings new-settings cofx))))

View File

@ -4,7 +4,8 @@
[status-im.utils.datetime :as datetime] [status-im.utils.datetime :as datetime]
[status-im.utils.hex :as utils.hex] [status-im.utils.hex :as utils.hex]
[status-im.utils.money :as money] [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? (reg-sub :wallet.transactions/transactions-loading?
:<- [:wallet] :<- [:wallet]
@ -125,7 +126,8 @@
:<- [:network] :<- [:network]
(fn [[unsigned-transactions transactions current-transaction network]] (fn [[unsigned-transactions transactions current-transaction network]]
(let [transactions (merge transactions unsigned-transactions) (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 (when transaction
(merge transaction (merge transaction
{:gas-price-eth (if gas-price (money/wei->str :eth gas-price) "-") {:gas-price-eth (if gas-price (money/wei->str :eth gas-price) "-")
@ -140,7 +142,7 @@
:hash (i18n/label :not-applicable)} :hash (i18n/label :not-applicable)}
{:cost (when gas-used {:cost (when gas-used
(money/wei->str :eth (money/fee-value gas-used gas-price))) (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 (reg-sub :wallet.transactions.details/confirmations
:<- [:wallet.transactions/transaction-details] :<- [:wallet.transactions/transaction-details]

View File

@ -3,7 +3,8 @@
[status-im.js-dependencies :as dependencies] [status-im.js-dependencies :as dependencies]
[status-im.utils.ethereum.tokens :as tokens] [status-im.utils.ethereum.tokens :as tokens]
[status-im.utils.money :as money] [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 ;; 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] (defn testnet? [id]
(contains? #{(chain-keyword->chain-id :testnet) (chain-keyword->chain-id :rinkeby)} id)) (contains? #{(chain-keyword->chain-id :testnet) (chain-keyword->chain-id :rinkeby)} id))
(defn network-with-upstream-rpc? [networks network] (defn network-config [network]
(get-in networks [network :raw-config :UpstreamConfig :Enabled])) (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") (def hex-prefix "0x")
@ -36,9 +40,11 @@
(when s (when s
(.isAddress dependencies/Web3.prototype s))) (.isAddress dependencies/Web3.prototype s)))
(defn network->chain-id [network]
(:NetworkId (network-config network)))
(defn network->chain-keyword [network] (defn network->chain-keyword [network]
(when network (chain-id->chain-keyword (network->chain-id network)))
(keyword (string/replace network "_rpc" ""))))
(defn sha3 [s] (defn sha3 [s]
(.sha3 dependencies/Web3.prototype (str s))) (.sha3 dependencies/Web3.prototype (str s)))

View File

@ -4,9 +4,9 @@
(defn- get-network-subdomain [network] (defn- get-network-subdomain [network]
(case network (case network
("testnet" "testnet_rpc") "ropsten" (:testnet) "ropsten"
("mainnet" "mainnet_rpc") nil (:mainnet) nil
("rinkeby" "rinkeby_rpc") "rinkeby")) (:rinkeby) "rinkeby"))
(defn get-transaction-details-url [network hash] (defn get-transaction-details-url [network hash]
(let [network-subdomain (get-network-subdomain network)] (let [network-subdomain (get-network-subdomain network)]
@ -16,9 +16,9 @@
(defn- get-api-network-subdomain [network] (defn- get-api-network-subdomain [network]
(case network (case network
("testnet" "testnet_rpc") "api-ropsten" (:testnet) "api-ropsten"
("mainnet" "mainnet_rpc") "api" (:mainnet) "api"
("rinkeby" "rinkeby_rpc") "api-rinkeby")) (:rinkeby) "api-rinkeby"))
(defn get-transaction-url [network account] (defn get-transaction-url [network account]
(let [network-subdomain (get-api-network-subdomain network)] (let [network-subdomain (get-api-network-subdomain network)]