[#8977] [Multi-account] Allow user to choose wallet for DApp transactions
Signed-off-by: Andrey Shovkoplyas <motor4ik@gmail.com>
4
ICONS.md
|
@ -1,5 +1,9 @@
|
|||
# new icons
|
||||
|
||||
## Export icons
|
||||
|
||||
![](./export-icons.gif)
|
||||
|
||||
## android
|
||||
1. copy files to corresponding directories at `/Users/romanvolosovskyi/clj/status-react/android/app/src/main/res` (one of `drawable-hdpi`, `drawable-mdpi`, `drawable-xhdpi`, `drawable-xxhdpi`, `drawable-xxxhdpi` for corresponding resolution)
|
||||
If you only have 3 pngs 1x, 2x and 3x put them in mdpi, xhdpi and xxhdpi
|
||||
|
|
After Width: | Height: | Size: 279 B |
After Width: | Height: | Size: 426 B |
After Width: | Height: | Size: 636 B |
After Width: | Height: | Size: 231 KiB |
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "account.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "account@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "account@3x.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 279 B |
After Width: | Height: | Size: 426 B |
After Width: | Height: | Size: 636 B |
|
@ -21,7 +21,9 @@
|
|||
[status-im.utils.types :as types]
|
||||
[status-im.utils.universal-links.core :as universal-links]
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.signing.core :as signing]))
|
||||
[status-im.signing.core :as signing]
|
||||
[status-im.multiaccounts.update.core :as multiaccounts.update]
|
||||
[status-im.ui.components.bottom-sheet.core :as bottom-sheet]))
|
||||
|
||||
(fx/defn update-browser-option
|
||||
[{:keys [db]} option-key option-value]
|
||||
|
@ -311,29 +313,37 @@
|
|||
(ethereum/address? second-param)
|
||||
[second-param first-param]))))
|
||||
|
||||
(fx/defn send-to-bridge
|
||||
[cofx message]
|
||||
{:browser/send-to-bridge {:message message
|
||||
:webview (get-in cofx [:db :webview-bridge])}})
|
||||
|
||||
(fx/defn web3-send-async
|
||||
[cofx {:keys [method params id] :as payload} message-id]
|
||||
(let [message? (constants/web3-sign-message? method)]
|
||||
(let [message? (constants/web3-sign-message? method)
|
||||
dapps-address (get-in cofx [:db :multiaccount :dapps-address])]
|
||||
(if (or message? (= constants/web3-send-transaction method))
|
||||
(let [[address data] (when message? (normalize-sign-message-params params))]
|
||||
(when (or (not message?) (and address data))
|
||||
(signing/sign cofx (merge
|
||||
(if message?
|
||||
{:message {:address address :data data :typed? (not= constants/web3-personal-sign method)}}
|
||||
{:tx-obj (first params)})
|
||||
{:message {:address address :data data :typed? (not= constants/web3-personal-sign method)
|
||||
:from dapps-address}}
|
||||
{:tx-obj (update (first params) :from #(or % dapps-address))})
|
||||
{:on-result [:browser.dapp/transaction-on-result message-id id]
|
||||
:on-error [:browser.dapp/transaction-on-error message-id]}))))
|
||||
{:browser/call-rpc [payload
|
||||
#(re-frame/dispatch [:browser.callback/call-rpc
|
||||
{:type constants/web3-send-async-callback
|
||||
:messageId message-id
|
||||
:error %1
|
||||
:result %2}])]})))
|
||||
|
||||
(fx/defn send-to-bridge
|
||||
[cofx message]
|
||||
{:browser/send-to-bridge {:message message
|
||||
:webview (get-in cofx [:db :webview-bridge])}})
|
||||
(if (#{"eth_accounts" "eth_coinbase"} method)
|
||||
(send-to-bridge cofx {:type constants/web3-send-async-callback
|
||||
:messageId message-id
|
||||
:result {:jsonrpc "2.0"
|
||||
:id (int id)
|
||||
:result (if (= method "eth_coinbase") dapps-address [dapps-address])}})
|
||||
{:browser/call-rpc [payload
|
||||
#(re-frame/dispatch [:browser.callback/call-rpc
|
||||
{:type constants/web3-send-async-callback
|
||||
:messageId message-id
|
||||
:error %1
|
||||
:result %2}])]}))))
|
||||
|
||||
(fx/defn web3-send-async-read-only
|
||||
[{:keys [db] :as cofx} dapp-name {:keys [method] :as payload} message-id]
|
||||
|
@ -437,7 +447,24 @@
|
|||
(fn [link]
|
||||
(list-selection/browse-in-web-browser link)))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:browser/clear-web-data
|
||||
(fn []
|
||||
(status/clear-web-data)))
|
||||
|
||||
(defn share-link [url]
|
||||
(let [link (universal-links/generate-link :browse :external url)
|
||||
message (i18n/label :t/share-dapp-text {:link link})]
|
||||
(list-selection/open-share {:message message})))
|
||||
|
||||
(fx/defn dapps-account-selected
|
||||
{:events [:dapps-account-selected]}
|
||||
[{:keys [db] :as cofx} address]
|
||||
(fx/merge cofx
|
||||
{:browser/clear-web-data nil}
|
||||
(bottom-sheet/hide-bottom-sheet)
|
||||
(browser.permissions/clear-dapps-permissions)
|
||||
(multiaccounts.update/multiaccount-update {:dapps-address address} {})
|
||||
#(when (= (:view-id db) :browser)
|
||||
(merge (navigation/navigate-back %)
|
||||
{:dispatch [:browser.ui/browser-item-selected (get-in db [:browser/options :browser-id])]}))))
|
|
@ -1,12 +1,10 @@
|
|||
(ns status-im.browser.permissions
|
||||
(:require [status-im.constants :as constants]
|
||||
[status-im.ethereum.core :as ethereum]
|
||||
[status-im.ethereum.json-rpc :as json-rpc]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.qr-scanner.core :as qr-scanner]
|
||||
[status-im.ui.screens.navigation :as navigation]
|
||||
[status-im.utils.fx :as fx]
|
||||
[status-im.ethereum.core :as ethereum]))
|
||||
[status-im.utils.fx :as fx]))
|
||||
|
||||
(declare process-next-permission)
|
||||
(declare send-response-to-bridge)
|
||||
|
@ -14,10 +12,12 @@
|
|||
(def supported-permissions
|
||||
{constants/dapp-permission-qr-code {:yield-control? true
|
||||
:allowed? true}
|
||||
constants/dapp-permission-contact-code {:title (i18n/label :t/wants-to-access-profile)
|
||||
constants/dapp-permission-contact-code {:type :profile
|
||||
:title (i18n/label :t/wants-to-access-profile)
|
||||
:description (i18n/label :t/your-contact-code)
|
||||
:icon :main-icons/profile}
|
||||
constants/dapp-permission-web3 {:title (i18n/label :t/dapp-would-like-to-connect-wallet)
|
||||
constants/dapp-permission-web3 {:type :wallet
|
||||
:title (i18n/label :t/dapp-would-like-to-connect-wallet)
|
||||
:description (i18n/label :t/allowing-authorizes-this-dapp)
|
||||
:icon :main-icons/wallet}})
|
||||
|
||||
|
@ -44,7 +44,7 @@
|
|||
(defn get-permission-data [cofx allowed-permission]
|
||||
(let [multiaccount (get-in cofx [:db :multiaccount])]
|
||||
(get {constants/dapp-permission-contact-code (:public-key multiaccount)
|
||||
constants/dapp-permission-web3 [(:address (ethereum/get-default-account (:accounts multiaccount)))]}
|
||||
constants/dapp-permission-web3 [(:dapps-address multiaccount)]}
|
||||
allowed-permission)))
|
||||
|
||||
(fx/defn send-response-to-bridge
|
||||
|
@ -81,6 +81,15 @@
|
|||
:on-success #()}]}
|
||||
(navigation/navigate-back)))
|
||||
|
||||
(fx/defn clear-dapps-permissions
|
||||
[{:keys [db]}]
|
||||
(let [dapp-permissions (keys (:dapps/permissions db))]
|
||||
{:db (dissoc db :dapps/permissions)
|
||||
::json-rpc/call (for [dapp dapp-permissions]
|
||||
{:method "permissions_deleteDappPermissions"
|
||||
:params [dapp]
|
||||
:on-success #()})}))
|
||||
|
||||
(fx/defn process-next-permission
|
||||
"Process next permission by removing it from pending permissions and prompting user
|
||||
if there is no pending permissions left, save all granted permissions
|
||||
|
|
|
@ -228,6 +228,8 @@
|
|||
:photo-path photo-path
|
||||
; public key of the chat account
|
||||
:public-key publicKey
|
||||
; default address for Dapps
|
||||
:dapps-address (:address wallet-account)
|
||||
:latest-derived-path 0
|
||||
:accounts [wallet-account]
|
||||
:signing-phrase signing-phrase
|
||||
|
|
|
@ -60,9 +60,9 @@
|
|||
|
||||
(fx/defn sign-message
|
||||
[{{:signing/keys [sign tx] :as db} :db}]
|
||||
(let [{{:keys [data typed?]} :message} tx
|
||||
(let [{{:keys [data typed? from]} :message} tx
|
||||
{:keys [in-progress? password]} sign
|
||||
from (ethereum/default-address db)
|
||||
from (or from (ethereum/default-address db))
|
||||
hashed-password (ethereum/sha3 (security/safe-unmask-data password))]
|
||||
(when-not in-progress?
|
||||
(merge
|
||||
|
|
|
@ -457,6 +457,19 @@
|
|||
(or (get sett :log-level)
|
||||
config/log-level-status-go)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:dapps-address
|
||||
:<- [:multiaccount]
|
||||
(fn [acc]
|
||||
(get acc :dapps-address)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:dapps-account
|
||||
:<- [:multiaccount]
|
||||
:<- [:dapps-address]
|
||||
(fn [[acc address]]
|
||||
(some #(when (= (:address %) address) %) (:accounts acc))))
|
||||
|
||||
;;CHAT ==============================================================================================================
|
||||
|
||||
(re-frame/reg-sub
|
||||
|
|
|
@ -102,10 +102,7 @@
|
|||
height content on-cancel]
|
||||
:or {on-cancel #(re-frame/dispatch [:bottom-sheet/hide])}
|
||||
:as opts}]
|
||||
[react/keyboard-avoiding-view
|
||||
(merge
|
||||
(pan-handlers (swipe-pan-responder opts))
|
||||
{:style styles/container})
|
||||
[react/keyboard-avoiding-view {:style styles/container}
|
||||
[react/touchable-highlight
|
||||
{:on-press #(cancel opts on-cancel)
|
||||
:style styles/container}
|
||||
|
@ -113,7 +110,10 @@
|
|||
[react/animated-view (styles/shadow opacity-value)]]
|
||||
[react/animated-view
|
||||
{:style (styles/content-container height bottom-value)}
|
||||
[react/view styles/content-header
|
||||
[react/view
|
||||
(merge
|
||||
(pan-handlers (swipe-pan-responder opts))
|
||||
{:style styles/content-header})
|
||||
[react/view styles/handle]]
|
||||
[react/view {:style {:flex 1
|
||||
:height height}}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
[status-im.ui.components.icons.vector-icons :as vector-icons]
|
||||
[status-im.utils.label :as utils.label]))
|
||||
|
||||
(defn style-container [type disabled?]
|
||||
(defn style-container [type disabled? theme]
|
||||
(merge
|
||||
(when (= type :main)
|
||||
{:margin-vertical 8 :margin-horizontal 16})
|
||||
|
@ -24,7 +24,10 @@
|
|||
disabled?
|
||||
colors/gray-transparent-10
|
||||
(= type :main)
|
||||
colors/blue-transparent-10
|
||||
(case theme
|
||||
:red colors/red-transparent-10
|
||||
:green colors/green-transparent-10
|
||||
colors/blue-transparent-10)
|
||||
:else
|
||||
"")}))
|
||||
|
||||
|
@ -34,6 +37,9 @@
|
|||
'type'
|
||||
:main (default), :secondary, :next, :previous
|
||||
|
||||
`theme`
|
||||
:blue (default), :green, :red
|
||||
|
||||
`label`
|
||||
Any one of string, keyword representing translated string in the form of :t/{translation-key-in-translation-files}
|
||||
|
||||
|
@ -45,12 +51,12 @@
|
|||
|
||||
Spec: https://www.figma.com/file/cb4p8AxLtTF3q1L6JYDnKN15/Index?node-id=858%3A0"
|
||||
|
||||
[{:keys [label type disabled? on-press accessibility-label style] :or {type :main}}]
|
||||
[{:keys [label type theme disabled? on-press accessibility-label style] :or {type :main theme :blue}}]
|
||||
(let [label (utils.label/stringify label)]
|
||||
[react/touchable-opacity (merge {:on-press on-press :disabled disabled? :active-pacity 0.5 :style style}
|
||||
(when accessibility-label
|
||||
{:accessibility-label accessibility-label}))
|
||||
[react/view {:style (style-container type disabled?)}
|
||||
[react/view {:style (style-container type disabled? theme)}
|
||||
[react/view {:flex-direction :row :align-items :center}
|
||||
(when (= type :previous)
|
||||
[vector-icons/icon :main-icons/back {:container-style {:width 24 :height 24 :margin-right 4}
|
||||
|
@ -59,7 +65,10 @@
|
|||
disabled?
|
||||
colors/gray
|
||||
(#{:main :secondary :next :previous} type)
|
||||
colors/blue
|
||||
(case theme
|
||||
:green colors/green
|
||||
:red colors/red
|
||||
colors/blue)
|
||||
:else
|
||||
"")}}
|
||||
label]
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
:padding-bottom (if (= type :section-header) 4 10)
|
||||
:align-items :center}
|
||||
(when selected?
|
||||
{:background-color colors/gray-transparent-40})))
|
||||
{:background-color colors/blue-light})))
|
||||
|
||||
(def icon-column-container
|
||||
{:margin-right 14
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
[status-im.ui.components.tooltip.views :as tooltip]
|
||||
[status-im.ui.screens.chat.photos :as photos]
|
||||
[status-im.ui.screens.profile.db :as profile.db]
|
||||
[status-im.utils.label :as utils.label]))
|
||||
[status-im.utils.label :as utils.label]
|
||||
[status-im.ui.components.radio :as radio]))
|
||||
|
||||
(def divider
|
||||
[react/view {:height 1 :background-color colors/gray-lighter}])
|
||||
|
@ -350,13 +351,12 @@
|
|||
(reagent/create-class
|
||||
{:reagent-render
|
||||
(fn
|
||||
[{:keys
|
||||
[react-key type theme container-margin-top container-margin-bottom
|
||||
icon title-prefix title-prefix-width title-prefix-height
|
||||
title title-color-override title-row-accessory
|
||||
title-accessibility-label subtitle subtitle-max-lines
|
||||
subtitle-row-accessory content accessories on-press
|
||||
on-long-press error accessibility-label disabled? selected?]
|
||||
[{:keys [react-key type theme container-margin-top container-margin-bottom
|
||||
icon title-prefix title-prefix-width title-prefix-height
|
||||
title title-color-override title-row-accessory
|
||||
title-accessibility-label subtitle subtitle-max-lines
|
||||
subtitle-row-accessory content accessories on-press
|
||||
on-long-press error accessibility-label disabled? selected?]
|
||||
:or {react-key r-key
|
||||
type :default
|
||||
theme :default
|
||||
|
@ -364,19 +364,18 @@
|
|||
container-margin-top 0
|
||||
container-margin-bottom 0
|
||||
subtitle-max-lines 1}}]
|
||||
(let [title-row-elements
|
||||
{:title title
|
||||
:title-color-override title-color-override
|
||||
:title-accessibility-label title-accessibility-label
|
||||
:title-prefix title-prefix
|
||||
:title-prefix-width title-prefix-width
|
||||
:title-prefix-height title-prefix-height
|
||||
:title-row-accessory title-row-accessory}
|
||||
subtitle-row-elements
|
||||
{:subtitle subtitle
|
||||
:subtitle-max-lines subtitle-max-lines
|
||||
:subtitle-row-accessory subtitle-row-accessory}
|
||||
radio-selected? (and (= theme :selectable) selected?)]
|
||||
(let [title-row-elements {:title title
|
||||
:title-color-override title-color-override
|
||||
:title-accessibility-label title-accessibility-label
|
||||
:title-prefix title-prefix
|
||||
:title-prefix-width title-prefix-width
|
||||
:title-prefix-height title-prefix-height
|
||||
:title-row-accessory title-row-accessory}
|
||||
subtitle-row-elements {:subtitle subtitle
|
||||
:subtitle-max-lines subtitle-max-lines
|
||||
:subtitle-row-accessory subtitle-row-accessory}
|
||||
theme-select? (= theme :selectable)
|
||||
radio-selected? (and theme-select? selected?)]
|
||||
^{:key react-key}
|
||||
(if (= type :divider)
|
||||
divider
|
||||
|
@ -384,12 +383,12 @@
|
|||
:margin-bottom container-margin-bottom}
|
||||
:on-layout #(reset! width (-> % .-nativeEvent .-layout .-width))}
|
||||
[react/touchable-highlight
|
||||
(cond-> {:on-press (when (not= theme :selectable) on-press)
|
||||
:on-press-in (when (= theme :selectable) on-press)
|
||||
(cond-> {:on-press (when (not theme-select?) on-press)
|
||||
:on-press-in (when theme-select? on-press)
|
||||
:on-long-press on-long-press
|
||||
:underlay-color colors/gray-transparent-40
|
||||
:active-opacity (if (= theme :selectable) 1 0.85)
|
||||
:disabled (or (not on-press) selected? disabled?)}
|
||||
:active-opacity (if theme-select? 1 0.85)
|
||||
:disabled (or (not on-press) selected? disabled?)}
|
||||
accessibility-label
|
||||
(assoc :accessibility-label accessibility-label))
|
||||
[react/view {:style (styles/container type radio-selected?)}
|
||||
|
@ -401,7 +400,10 @@
|
|||
title-row-elements subtitle-row-elements
|
||||
type icon disabled? theme content accessories])
|
||||
|
||||
(when accessories
|
||||
[accessories-column accessories width])]]
|
||||
(if theme-select?
|
||||
[react/view styles/accessories-container
|
||||
[radio/radio radio-selected?]]
|
||||
(when accessories
|
||||
[accessories-column accessories width]))]]
|
||||
(when error
|
||||
[tooltip/tooltip error styles/error])])))})))
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
(ns status-im.ui.screens.browser.accounts
|
||||
(:require [status-im.ui.components.list.views :as list]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui.components.list-item.views :as list-item]
|
||||
[status-im.ui.components.chat-icon.screen :as chat-icon]
|
||||
[status-im.utils.utils :as utils]
|
||||
[re-frame.core :as re-frame]))
|
||||
|
||||
(defn render-account [dapps-account]
|
||||
(fn [account]
|
||||
[list-item/list-item
|
||||
{:theme :selectable
|
||||
:selected? (= (:address dapps-account) (:address account))
|
||||
:icon [chat-icon/custom-icon-view-list (:name account) (:color account)]
|
||||
:title (:name account)
|
||||
:subtitle (utils/get-shortened-checksum-address (:address account))
|
||||
:on-press #(re-frame/dispatch [:dapps-account-selected (:address account)])}]))
|
||||
|
||||
(defn accounts-list [accounts dapps-account]
|
||||
(fn []
|
||||
[react/view {:flex 1}
|
||||
[react/text {:style {:margin 16 :text-align :center}}
|
||||
(i18n/label :t/select-account-dapp)]
|
||||
[list/flat-list {:data accounts
|
||||
:key-fn :address
|
||||
:render-fn (render-account dapps-account)}]]))
|
|
@ -63,3 +63,18 @@
|
|||
:color colors/gray
|
||||
:line-height 18
|
||||
:margin-top 2})
|
||||
|
||||
(defn dapps-account [color]
|
||||
{:flex-direction :row
|
||||
:background-color color
|
||||
:border-radius 36
|
||||
:padding-horizontal 8
|
||||
:padding-vertical 6
|
||||
:flex 1
|
||||
:align-items :center
|
||||
:justify-content :center
|
||||
:shadow-offset {:width 0 :height 1}
|
||||
:shadow-radius 6
|
||||
:shadow-opacity 1
|
||||
:shadow-color "rgba(0, 12, 63, 0.2)"
|
||||
:elevation 2})
|
||||
|
|
|
@ -15,7 +15,8 @@
|
|||
[status-im.ui.components.icons.vector-icons :as vector-icons]
|
||||
[status-im.ui.components.radio :as radio]
|
||||
[status-im.ui.components.icons.vector-icons :as icons]
|
||||
[reagent.core :as reagent])
|
||||
[reagent.core :as reagent]
|
||||
[status-im.ui.screens.browser.accounts :as accounts])
|
||||
(:require-macros [status-im.utils.views :as views]))
|
||||
|
||||
(defn hide-sheet-and-dispatch [event]
|
||||
|
@ -96,6 +97,30 @@
|
|||
[react/text {:style {:line-height 22 :font-size 15 :color colors/gray}}
|
||||
(i18n/label :t/recent)]])])
|
||||
|
||||
(views/defview select-account []
|
||||
(views/letsubs [height [:dimensions/window-height]
|
||||
{:keys [accounts]} [:multiaccount]
|
||||
{:keys [name color] :as dapps-account} [:dapps-account]]
|
||||
[react/view {:position :absolute
|
||||
:z-index 2
|
||||
:align-items :center
|
||||
:bottom (+ 16 tabs.styles/tabs-diff)
|
||||
:left 0
|
||||
:right 0
|
||||
:padding-horizontal 32}
|
||||
[react/touchable-highlight
|
||||
{:accessibility-label :select-account
|
||||
:on-press #(re-frame/dispatch [:bottom-sheet/show-sheet
|
||||
{:content (accounts/accounts-list accounts dapps-account)
|
||||
:content-height (/ height 2)}])}
|
||||
[react/view (styles/dapps-account color)
|
||||
[icons/icon :main-icons/account {:color colors/white}]
|
||||
[react/view {:flex-shrink 1}
|
||||
[react/text {:numberOfLines 1
|
||||
:style {:margin-horizontal 6 :color :white :typography :main-medium}}
|
||||
name]]
|
||||
[icons/icon :main-icons/dropdown {:color colors/white-transparent}]]]]))
|
||||
|
||||
(views/defview open-dapp []
|
||||
(views/letsubs [browsers [:browser/browsers-vals]
|
||||
url-text (atom nil)]
|
||||
|
@ -116,8 +141,9 @@
|
|||
[list-header false]
|
||||
[list/flat-list {:data browsers
|
||||
:footer [react/view
|
||||
{:style {:height tabs.styles/tabs-diff
|
||||
{:style {:height (+ tabs.styles/tabs-diff 64)
|
||||
:align-self :stretch}}]
|
||||
:key-fn :browser-id
|
||||
:end-fill-color colors/white
|
||||
:render-fn list-item}]])]))
|
||||
:render-fn list-item}]])
|
||||
[select-account]]))
|
||||
|
|
|
@ -5,11 +5,11 @@
|
|||
[status-im.i18n :as i18n]
|
||||
[status-im.ui.components.animation :as anim]
|
||||
[status-im.ui.components.chat-icon.screen :as chat-icon.screen]
|
||||
[status-im.ui.components.common.common :as components.common]
|
||||
[status-im.ui.components.icons.vector-icons :as icons]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui.screens.browser.styles :as styles]
|
||||
[status-im.ui.components.colors :as colors])
|
||||
[status-im.ui.components.colors :as colors]
|
||||
[status-im.ui.components.button :as button])
|
||||
(:require-macros [status-im.utils.views :as views]))
|
||||
|
||||
(defn hide-panel-anim
|
||||
|
@ -26,7 +26,7 @@
|
|||
[bottom-anim-value alpha-value]
|
||||
(anim/start
|
||||
(anim/parallel
|
||||
[(anim/spring bottom-anim-value {:toValue 20
|
||||
[(anim/spring bottom-anim-value {:toValue 20
|
||||
:useNativeDriver true})
|
||||
(anim/timing alpha-value {:toValue 0.6
|
||||
:duration 500
|
||||
|
@ -35,7 +35,7 @@
|
|||
(defn permission-details [requested-permission]
|
||||
(get browser.permissions/supported-permissions requested-permission))
|
||||
|
||||
(views/defview permissions-panel [[dapp? dapp] {:keys [dapp-name]}]
|
||||
(views/defview permissions-panel [[dapp? dapp dapps-account] {:keys [dapp-name]}]
|
||||
(views/letsubs [bottom-anim-value (anim/create-value styles/panel-height)
|
||||
alpha-value (anim/create-value 0)
|
||||
current-permission (reagent/atom nil)
|
||||
|
@ -76,37 +76,54 @@
|
|||
(do (js/setTimeout #(reset! current-permission nil) 500)
|
||||
(hide-panel-anim bottom-anim-value alpha-value))))}
|
||||
(when @current-permission
|
||||
(let [{:keys [title description icon]} @current-permission]
|
||||
(let [{:keys [title description type icon]} @current-permission]
|
||||
[react/view styles/permissions-panel-container
|
||||
[react/animated-view {:style (styles/permissions-panel-background alpha-value)}]
|
||||
[react/animated-view {:style (styles/permissions-panel bottom-anim-value)}
|
||||
[react/view styles/permissions-panel-icons-container
|
||||
(if dapp?
|
||||
[chat-icon.screen/dapp-icon-permission dapp 48]
|
||||
[chat-icon.screen/dapp-icon-permission dapp 40]
|
||||
[react/view styles/permissions-panel-dapp-icon-container
|
||||
[icons/icon :main-icons/dapp {:color colors/gray}]])
|
||||
[react/view {:margin-left 3 :margin-right 3}
|
||||
[react/view {:margin-left 8 :margin-right 4}
|
||||
[react/view styles/dot]]
|
||||
[react/view {:margin-right 3}
|
||||
[react/view {:margin-right 4}
|
||||
[react/view styles/dot]]
|
||||
[react/view {:margin-right 8}
|
||||
[react/view styles/dot]]
|
||||
[react/view styles/permissions-panel-ok-icon-container
|
||||
[icons/icon :main-icons/check styles/permissions-panel-ok-ico]]
|
||||
[react/view {:margin-left 3 :margin-right 3}
|
||||
[icons/icon :tiny-icons/tiny-check styles/permissions-panel-ok-ico]]
|
||||
[react/view {:margin-left 8 :margin-right 4}
|
||||
[react/view styles/dot]]
|
||||
[react/view {:margin-right 3}
|
||||
[react/view {:margin-right 4}
|
||||
[react/view styles/dot]]
|
||||
[react/view styles/permissions-panel-wallet-icon-container
|
||||
(when icon
|
||||
[icons/icon icon {:color :white}])]]
|
||||
[react/view {:margin-right 8}
|
||||
[react/view styles/dot]]
|
||||
(if (= :wallet type)
|
||||
[chat-icon.screen/custom-icon-view-list (:name dapps-account) (:color dapps-account)]
|
||||
[react/view styles/permissions-panel-wallet-icon-container
|
||||
(when icon
|
||||
[icons/icon icon {:color :white}])])]
|
||||
[react/text {:style styles/permissions-panel-title-label}
|
||||
(str "\"" dapp-name "\" " title)]
|
||||
(when (= :wallet type)
|
||||
[react/view styles/permissions-account
|
||||
[icons/icon :main-icons/account {:color (:color dapps-account)}]
|
||||
[react/view {:flex-shrink 1}
|
||||
[react/text {:numberOfLines 1
|
||||
:style {:margin-horizontal 6 :color (:color dapps-account) :typography :main-medium
|
||||
:font-size 13}}
|
||||
(:name dapps-account)]]])
|
||||
[react/text {:style styles/permissions-panel-description-label}
|
||||
description]
|
||||
[react/view {:flex-direction :row :margin-top 14}
|
||||
[components.common/button
|
||||
{:on-press #(re-frame/dispatch [:browser.permissions.ui/dapp-permission-denied])
|
||||
[react/view {:flex-direction :row :margin-top 24}
|
||||
[button/button
|
||||
{:theme :red
|
||||
:style {:flex 1}
|
||||
:on-press #(re-frame/dispatch [:browser.permissions.ui/dapp-permission-denied])
|
||||
:label (i18n/label :t/deny)}]
|
||||
[react/view {:width 16}]
|
||||
[components.common/button
|
||||
{:on-press #(re-frame/dispatch [:browser.permissions.ui/dapp-permission-allowed])
|
||||
[button/button
|
||||
{:theme :green
|
||||
:style {:flex 1}
|
||||
:on-press #(re-frame/dispatch [:browser.permissions.ui/dapp-permission-allowed])
|
||||
:label (i18n/label :t/allow)}]]]]))))
|
||||
|
|
|
@ -20,10 +20,12 @@
|
|||
|
||||
(def navbar
|
||||
{:background-color :white
|
||||
:height 48
|
||||
:height 51
|
||||
:flex-direction :row
|
||||
:align-items :center
|
||||
:justify-content :space-between
|
||||
:border-top-color colors/gray-lighter
|
||||
:border-top-width 1
|
||||
:padding-horizontal 32})
|
||||
|
||||
(def disabled-button
|
||||
|
@ -56,8 +58,8 @@
|
|||
:border-radius 8
|
||||
:max-height 36
|
||||
:background-color colors/gray-lighter
|
||||
:padding-horizontal 12
|
||||
:margin-right 8
|
||||
:padding-horizontal 10
|
||||
:margin-right 16
|
||||
:align-items :center
|
||||
:align-self :center
|
||||
:margin-top 10
|
||||
|
@ -78,7 +80,7 @@
|
|||
(def dot
|
||||
{:height 4
|
||||
:width 4
|
||||
:background-color "#E4E6EB"
|
||||
:background-color colors/blue
|
||||
:border-radius 2})
|
||||
|
||||
(def permissions-panel-container
|
||||
|
@ -114,42 +116,53 @@
|
|||
:flex-direction :row})
|
||||
|
||||
(def permissions-panel-dapp-icon-container
|
||||
{:height 48
|
||||
:width 48
|
||||
:background-color "#E4E6EB"
|
||||
:border-radius 24
|
||||
{:height 40
|
||||
:width 40
|
||||
:background-color colors/gray-lighter
|
||||
:border-radius 20
|
||||
:align-items :center
|
||||
:justify-content :center})
|
||||
|
||||
(def permissions-panel-ok-icon-container
|
||||
{:height 24
|
||||
:width 24
|
||||
:background-color "#48EA77"
|
||||
:background-color colors/blue-light
|
||||
:border-radius 12
|
||||
:align-items :center
|
||||
:justify-content :center})
|
||||
|
||||
(def permissions-panel-ok-ico
|
||||
{:color :white
|
||||
:width 12
|
||||
:height 12})
|
||||
{:color colors/blue
|
||||
:width 16
|
||||
:height 16})
|
||||
|
||||
(def permissions-panel-wallet-icon-container
|
||||
{:height 48
|
||||
:width 48
|
||||
{:height 40
|
||||
:width 40
|
||||
:background-color colors/blue
|
||||
:border-radius 24
|
||||
:border-radius 20
|
||||
:align-items :center
|
||||
:justify-content :center})
|
||||
|
||||
(def permissions-panel-title-label
|
||||
{:typography :header
|
||||
{:typography :title-bold
|
||||
:margin-horizontal 20
|
||||
:text-align :center
|
||||
:margin-top 19})
|
||||
:margin-top 16})
|
||||
|
||||
(def permissions-panel-description-label
|
||||
{:margin-horizontal 20
|
||||
:color colors/gray
|
||||
:text-align :center
|
||||
:margin-top 9})
|
||||
:margin-top 16})
|
||||
|
||||
(def permissions-account
|
||||
{:flex-direction :row
|
||||
:border-radius 36
|
||||
:border-width 1
|
||||
:border-color colors/gray-lighter
|
||||
:padding-horizontal 8
|
||||
:padding-vertical 6
|
||||
:margin-top 16
|
||||
:align-items :center
|
||||
:justify-content :center})
|
||||
|
|
|
@ -19,7 +19,9 @@
|
|||
[status-im.ui.screens.browser.site-blocked.views :as site-blocked.views]
|
||||
[status-im.ui.screens.browser.styles :as styles]
|
||||
[status-im.utils.http :as http]
|
||||
[status-im.utils.js-resources :as js-res])
|
||||
[status-im.utils.js-resources :as js-res]
|
||||
[status-im.ui.components.chat-icon.screen :as chat-icon]
|
||||
[status-im.ui.screens.browser.accounts :as accounts])
|
||||
(:require-macros
|
||||
[status-im.utils.slurp :refer [slurp]]
|
||||
[status-im.utils.views :as views]))
|
||||
|
@ -38,7 +40,7 @@
|
|||
(fn []
|
||||
(edn/read-string (browser-config-edn)))))
|
||||
|
||||
(defn toolbar-content [url url-original {:keys [secure?]} url-editing?]
|
||||
(defn toolbar-content [url url-original {:keys [secure?]} url-editing? webview]
|
||||
(let [url-text (atom url)]
|
||||
[react/view styles/toolbar-content
|
||||
[react/touchable-highlight {:on-press #(re-frame/dispatch [:browser.ui/lock-pressed secure?])}
|
||||
|
@ -58,9 +60,12 @@
|
|||
:style styles/url-input}]
|
||||
[react/touchable-highlight {:style styles/url-text-container
|
||||
:on-press #(re-frame/dispatch [:browser.ui/url-input-pressed])}
|
||||
[react/text (http/url-host url-original)]])]))
|
||||
[react/text (http/url-host url-original)]])
|
||||
[react/touchable-highlight {:on-press #(.reload @webview)
|
||||
:accessibility-label :refresh-page-button}
|
||||
[icons/icon :main-icons/refresh]]]))
|
||||
|
||||
(defn toolbar [error? url url-original browser browser-id url-editing?]
|
||||
(defn toolbar [error? url url-original browser browser-id url-editing? webview]
|
||||
[toolbar.view/toolbar
|
||||
{:browser? true}
|
||||
[toolbar.view/nav-button
|
||||
|
@ -69,7 +74,7 @@
|
|||
(re-frame/dispatch [:navigate-back])
|
||||
(when error?
|
||||
(re-frame/dispatch [:browser.ui/remove-browser-pressed browser-id]))))]
|
||||
[toolbar-content url url-original browser url-editing?]])
|
||||
[toolbar-content url url-original browser url-editing? webview]])
|
||||
|
||||
(defn- web-view-error [_ code desc]
|
||||
(reagent/as-element
|
||||
|
@ -85,38 +90,43 @@
|
|||
(let [domain-name (nth (re-find #"^\w+://(www\.)?([^/:]+)" url) 2)]
|
||||
(get (:inject-js (browser-config)) domain-name))))
|
||||
|
||||
(defn navigation [browser-id url webview can-go-back? can-go-forward?]
|
||||
[react/view styles/navbar
|
||||
[react/touchable-highlight {:on-press #(re-frame/dispatch [:browser.ui/previous-page-button-pressed])
|
||||
:disabled (not can-go-back?)
|
||||
:style (when-not can-go-back? styles/disabled-button)
|
||||
:accessibility-label :previous-page-button}
|
||||
[react/view
|
||||
[icons/icon :main-icons/arrow-left]]]
|
||||
[react/touchable-highlight {:on-press #(re-frame/dispatch [:browser.ui/next-page-button-pressed])
|
||||
:disabled (not can-go-forward?)
|
||||
:style (when-not can-go-forward? styles/disabled-button)
|
||||
:accessibility-label :next-page-button}
|
||||
[react/view
|
||||
[icons/icon :main-icons/arrow-right]]]
|
||||
[react/touchable-highlight
|
||||
{:on-press #(re-frame/dispatch [:browser.ui/open-modal-chat-button-pressed (http/url-host url)])
|
||||
:accessibility-label :modal-chat-button}
|
||||
[icons/icon :main-icons/message]]
|
||||
[react/touchable-highlight
|
||||
{:on-press #(browser/share-link url)
|
||||
:accessibility-label :modal-share-link-button}
|
||||
[icons/icon :main-icons/share]]
|
||||
[react/touchable-highlight {:on-press #(.reload @webview)
|
||||
:accessibility-label :refresh-page-button}
|
||||
[icons/icon :main-icons/refresh]]])
|
||||
(views/defview navigation [url can-go-back? can-go-forward? dapps-account]
|
||||
(views/letsubs [height [:dimensions/window-height]
|
||||
{:keys [accounts]} [:multiaccount]]
|
||||
[react/view styles/navbar
|
||||
[react/touchable-highlight {:on-press #(re-frame/dispatch [:browser.ui/previous-page-button-pressed])
|
||||
:disabled (not can-go-back?)
|
||||
:style (when-not can-go-back? styles/disabled-button)
|
||||
:accessibility-label :previous-page-button}
|
||||
[react/view
|
||||
[icons/icon :main-icons/arrow-left]]]
|
||||
[react/touchable-highlight {:on-press #(re-frame/dispatch [:browser.ui/next-page-button-pressed])
|
||||
:disabled (not can-go-forward?)
|
||||
:style (when-not can-go-forward? styles/disabled-button)
|
||||
:accessibility-label :next-page-button}
|
||||
[react/view
|
||||
[icons/icon :main-icons/arrow-right]]]
|
||||
[react/touchable-highlight
|
||||
{:on-press #(browser/share-link url)
|
||||
:accessibility-label :modal-share-link-button}
|
||||
[icons/icon :main-icons/share]]
|
||||
[react/touchable-highlight
|
||||
{:accessibility-label :select-account
|
||||
:on-press #(re-frame/dispatch [:bottom-sheet/show-sheet
|
||||
{:content (accounts/accounts-list accounts dapps-account)
|
||||
:content-height (/ height 2)}])}
|
||||
[chat-icon/custom-icon-view-list (:name dapps-account) (:color dapps-account) 32]]
|
||||
[react/touchable-highlight
|
||||
{:on-press #(re-frame/dispatch [:browser.ui/open-modal-chat-button-pressed (http/url-host url)])
|
||||
:accessibility-label :modal-chat-button}
|
||||
[icons/icon :main-icons/message]]]))
|
||||
|
||||
;; should-component-update is called only when component's props are changed,
|
||||
;; that's why it can't be used in `browser`, because `url` comes from subs
|
||||
(views/defview browser-component
|
||||
[{:keys [webview error? url browser browser-id unsafe? can-go-back?
|
||||
can-go-forward? resolving? network-id address url-original
|
||||
show-permission show-tooltip opt-in? dapp? name]}]
|
||||
can-go-forward? resolving? network-id url-original
|
||||
show-permission show-tooltip opt-in? dapp? name dapps-account]}]
|
||||
{:should-component-update (fn [_ _ args]
|
||||
(let [[_ props] args]
|
||||
(not (nil? (:url props)))))}
|
||||
|
@ -144,11 +154,11 @@
|
|||
:injected-on-start-loading-java-script (str (when-not opt-in? (js-res/web3))
|
||||
(if opt-in?
|
||||
(js-res/web3-opt-in-init (str network-id))
|
||||
(js-res/web3-init address (str network-id)))
|
||||
(js-res/web3-init (:address dapps-account) (str network-id)))
|
||||
(get-inject-js url))
|
||||
:injected-java-script (js-res/webview-js)}])]
|
||||
[navigation browser-id url-original webview can-go-back? can-go-forward?]
|
||||
[permissions.views/permissions-panel [(:dapp? browser) (:dapp browser)] show-permission]
|
||||
[navigation url-original can-go-back? can-go-forward? dapps-account]
|
||||
[permissions.views/permissions-panel [(:dapp? browser) (:dapp browser) dapps-account] show-permission]
|
||||
(when show-tooltip
|
||||
[tooltip/bottom-tooltip-info
|
||||
(if (= show-tooltip :secure)
|
||||
|
@ -159,9 +169,10 @@
|
|||
(views/defview browser []
|
||||
(views/letsubs [webview (atom nil)
|
||||
window-width [:dimensions/window-width]
|
||||
{:keys [accounts settings]} [:multiaccount]
|
||||
{:keys [settings]} [:multiaccount]
|
||||
{:keys [browser-id dapp? name unsafe?] :as browser} [:get-current-browser]
|
||||
{:keys [url error? loading? url-editing? show-tooltip show-permission resolving?]} [:browser/options]
|
||||
dapps-account [:dapps-account]
|
||||
network-id [:chain-id]]
|
||||
(let [can-go-back? (browser/can-go-back? browser)
|
||||
can-go-forward? (browser/can-go-forward? browser)
|
||||
|
@ -169,7 +180,7 @@
|
|||
opt-in? (or (nil? (:web3-opt-in? settings)) (:web3-opt-in? settings))]
|
||||
[react/view {:style styles/browser}
|
||||
[status-bar/status-bar]
|
||||
[toolbar error? url url-original browser browser-id url-editing?]
|
||||
[toolbar error? url url-original browser browser-id url-editing? webview]
|
||||
[react/view
|
||||
(when loading?
|
||||
[connectivity/loading-indicator window-width])]
|
||||
|
@ -185,8 +196,8 @@
|
|||
:can-go-forward? can-go-forward?
|
||||
:resolving? resolving?
|
||||
:network-id network-id
|
||||
:address (:address (ethereum/get-default-account accounts))
|
||||
:show-permission show-permission
|
||||
:show-tooltip show-tooltip
|
||||
:opt-in? opt-in?
|
||||
:name name}]])))
|
||||
:name name
|
||||
:dapps-account dapps-account}]])))
|
||||
|
|
|
@ -22,12 +22,13 @@
|
|||
:on-press #(re-frame/dispatch [:navigate-to :manage-dapps-permissions {:dapp dapp :permissions permissions}])
|
||||
:icon d-icon})
|
||||
|
||||
(defn prepare-items-manage [permission]
|
||||
{:title (case permission
|
||||
constants/dapp-permission-web3 :t/wallet
|
||||
constants/dapp-permission-contact-code :t/contact-code)
|
||||
:type :small
|
||||
:accessories [:main-icons/check]})
|
||||
(defn prepare-items-manage [name]
|
||||
(fn [permission]
|
||||
{:title (case permission
|
||||
constants/dapp-permission-web3 name
|
||||
constants/dapp-permission-contact-code :t/contact-code)
|
||||
:type :small
|
||||
:accessories [:main-icons/check]}))
|
||||
|
||||
(views/defview dapps-permissions []
|
||||
(views/letsubs [permissions [:dapps/permissions]]
|
||||
|
@ -41,12 +42,13 @@
|
|||
:render-fn list/flat-list-generic-render-fn}]]))
|
||||
|
||||
(views/defview manage []
|
||||
(views/letsubs [{:keys [dapp permissions]} [:get-screen-params]]
|
||||
(views/letsubs [{:keys [dapp permissions]} [:get-screen-params]
|
||||
{:keys [name]} [:dapps-account]]
|
||||
[react/view {:flex 1 :background-color colors/white}
|
||||
[status-bar/status-bar]
|
||||
[toolbar/simple-toolbar dapp]
|
||||
[list/flat-list
|
||||
{:data (vec (map prepare-items-manage permissions))
|
||||
{:data (vec (map (prepare-items-manage name) permissions))
|
||||
:key-fn (fn [_ i] (str i))
|
||||
:render-fn list/flat-list-generic-render-fn}]
|
||||
[react/view {:padding-vertical 16}
|
||||
|
|
|
@ -95,7 +95,7 @@
|
|||
[list/flat-list {:data all-home-items
|
||||
:key-fn first
|
||||
:header [react/view {:height 4 :flex 1}]
|
||||
:footer [react/view {:height 4 :flex 1}]
|
||||
:footer [react/view {:height 68 :flex 1}]
|
||||
:on-scroll-begin-drag
|
||||
(fn [e]
|
||||
(reset! scrolling-from-top?
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
(:require [status-im.i18n :as i18n]
|
||||
[status-im.react-native.js-dependencies :as rn-dependencies]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.utils.platform :as platform]))
|
||||
[status-im.utils.platform :as platform]
|
||||
[status-im.ethereum.eip55 :as eip55]
|
||||
[status-im.ethereum.core :as ethereum]))
|
||||
|
||||
(defn show-popup
|
||||
([title content]
|
||||
|
@ -79,6 +81,10 @@
|
|||
(when address
|
||||
(str (subs address 0 6) "\u2026" (subs address (- (count address) 4) (count address)))))
|
||||
|
||||
(defn get-shortened-checksum-address [address]
|
||||
(when address
|
||||
(get-shortened-address (eip55/address->checksum (ethereum/normalized-address address)))))
|
||||
|
||||
;; background-timer
|
||||
|
||||
(defn set-timeout [cb ms]
|
||||
|
|
|
@ -268,7 +268,7 @@
|
|||
"custom": "Custom",
|
||||
"custom-networks": "Custom networks",
|
||||
"dapp": "ÐApp",
|
||||
"dapp-would-like-to-connect-wallet": "would like\n to connect to your wallet",
|
||||
"dapp-would-like-to-connect-wallet": "would like to connect to",
|
||||
"dapps": "ÐApps",
|
||||
"dapps-can-access": "ÐApps can access my wallet and chat key",
|
||||
"dapps-permissions": "DApp permissions",
|
||||
|
@ -1107,5 +1107,6 @@
|
|||
"ok-save-pass": "OK, save password",
|
||||
"lock-app-with": "Lock app with",
|
||||
"grant-face-id-permissions": "To grant the required Face ID permission, please go to your system settings and make sure that Status > Face ID is selected",
|
||||
"request-feature": "Request a feature"
|
||||
"request-feature": "Request a feature",
|
||||
"select-account-dapp": "Select the account you wish to use with Dapps"
|
||||
}
|
||||
|
|