Add QR scanner to connect Dapps through Connected Dapps screen (#20647)

* Add QR scanner to connect Dapps through Connected Dapps screen

* Style fix

* use-mount
This commit is contained in:
Alexander 2024-07-08 13:55:32 +02:00 committed by GitHub
parent de6d9a6c3b
commit 4c4a8b65d4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 179 additions and 109 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -6,7 +6,7 @@
[:type {:optional true} [:type {:optional true}
[:maybe [:maybe
[:enum :default :multiuser :group :channel :community :token :network :multinetwork :account [:enum :default :multiuser :group :channel :community :token :network :multinetwork :account
:collectible :address :icon :audio :wallet-user]]] :collectible :address :icon :audio :wallet-user :dapp]]]
[:customization-color {:optional true} [:maybe :schema.common/customization-color]] [:customization-color {:optional true} [:maybe :schema.common/customization-color]]
[:container-style {:optional true} [:maybe :map]] [:container-style {:optional true} [:maybe :map]]
[:blur? {:optional true} [:maybe :boolean]] [:blur? {:optional true} [:maybe :boolean]]

View File

@ -17,16 +17,18 @@
[schema.core :as schema])) [schema.core :as schema]))
(defn- tag-skeleton (defn- tag-skeleton
[{:keys [size text] :or {size 24}} logo-component] [{:keys [size text theme]
(let [theme (quo.theme/use-theme)] :or {size 24
[rn/view {:style (style/tag-container size)} theme (quo.theme/use-theme)}}
logo-component logo-component]
[rn/view {:style (style/tag-spacing size)} [rn/view {:style (style/tag-container size)}
[text/text logo-component
{:style (style/text theme) [rn/view {:style (style/tag-spacing size)}
:weight :medium [text/text
:size (if (= size 24) :paragraph-2 :paragraph-1)} {:style (style/text theme)
text]]])) :weight :medium
:size (if (= size 24) :paragraph-2 :paragraph-1)}
text]]])
(defn- communities-tag (defn- communities-tag
[{:keys [size community-logo community-name blur? channel? channel-name]}] [{:keys [size community-logo community-name blur? channel? channel-name]}]
@ -81,95 +83,100 @@
context]]])) context]]]))
(defn- view-internal (defn- view-internal
[{:keys [type size state blur? customization-color profile-picture full-name users [{:keys [type theme size state blur? customization-color profile-picture full-name users
group-name amount token network-logo network-name networks group-name amount token network-logo network-name networks
account-name emoji collectible collectible-name collectible-number duration container-style] account-name emoji collectible collectible-name collectible-number
dapp-name dapp-logo duration container-style]
:or {customization-color :blue :or {customization-color :blue
type :default type :default
state :default} state :default
theme (quo.theme/use-theme)}
:as props}] :as props}]
(let [theme (quo.theme/use-theme)] [rn/view {:style (merge {:align-items :flex-start} container-style)}
[rn/view {:style (merge {:align-items :flex-start} container-style)} [rn/view
[rn/view {:style (style/container {:theme theme
{:style (style/container {:theme theme :type type
:type type :size size
:size size :state state
:state state :blur? blur?
:blur? blur? :customization-color customization-color})
:customization-color customization-color}) :accessibility-label :context-tag}
:accessibility-label :context-tag} (case type
(case type :default
:default [tag-skeleton {:theme theme :size size :text full-name}
[tag-skeleton {:theme theme :size size :text full-name} [user-avatar/user-avatar
[user-avatar/user-avatar {:full-name full-name
{:full-name full-name :profile-picture profile-picture
:profile-picture profile-picture :size (if (= size 24) :xxs 28)
:size (if (= size 24) :xxs 28) :status-indicator? false
:status-indicator? false :ring? false
:ring? false :customization-color customization-color}]]
:customization-color customization-color}]]
:multiuser :multiuser
[preview-list/view {:type :user :size :size-20} [preview-list/view {:type :user :size :size-20}
users] users]
:multinetwork :multinetwork
[preview-list/view {:type :network :size :size-20} [preview-list/view {:type :network :size :size-20}
networks] networks]
:audio :audio
[tag-skeleton {:theme theme :text (str duration)} [tag-skeleton {:theme theme :text (str duration)}
[rn/view {:style (style/audio-tag-icon-container customization-color theme)} [rn/view {:style (style/audio-tag-icon-container customization-color theme)}
[icons/icon :i/play {:color style/audio-tag-icon-color :size 12}]]] [icons/icon :i/play {:color style/audio-tag-icon-color :size 12}]]]
:group :group
[tag-skeleton {:theme theme :size size :text group-name} [tag-skeleton {:theme theme :size size :text group-name}
[group-avatar/view [group-avatar/view
{:icon-name :i/members {:icon-name :i/members
:size (if (= size 24) :size-20 :size-28) :size (if (= size 24) :size-20 :size-28)
:customization-color (colors/custom-color customization-color 50)}]] :customization-color (colors/custom-color customization-color 50)}]]
(:channel :community) (:channel :community)
[communities-tag (assoc props :channel? (= type :channel))] [communities-tag (assoc props :channel? (= type :channel))]
:token :token
[tag-skeleton {:theme theme :size size :text (str amount " " token)} [tag-skeleton {:theme theme :size size :text (str amount " " token)}
[token/view [token/view
{:style (style/token-logo size) {:style (style/token-logo size)
:token token :token token
:size (if (= size 24) :size-20 :size-28)}]] :size (if (= size 24) :size-20 :size-28)}]]
:network :network
[tag-skeleton {:theme theme :size size :text network-name} [tag-skeleton {:theme theme :size size :text network-name}
[rn/image {:style (style/circle-logo size) :source network-logo}]] [rn/image {:style (style/circle-logo size) :source network-logo}]]
:collectible :collectible
[tag-skeleton [tag-skeleton
{:theme theme {:theme theme
:size size :size size
:text (str collectible-name " #" collectible-number)} :text (str collectible-name " #" collectible-number)}
[rn/image {:style (style/rounded-logo size) :source collectible}]] [rn/image {:style (style/rounded-logo size) :source collectible}]]
:account :account
[tag-skeleton {:theme theme :size size :text account-name} [tag-skeleton {:theme theme :size size :text account-name}
[account-avatar/view [account-avatar/view
{:customization-color customization-color {:customization-color customization-color
:emoji emoji :emoji emoji
:size (if (= size 24) 20 28)}]] :size (if (= size 24) 20 28)}]]
:address :address
[address-tag props] [address-tag props]
:icon :icon
[icon-tag props] [icon-tag props]
:wallet-user :wallet-user
[tag-skeleton {:theme theme :size size :text full-name} [tag-skeleton {:theme theme :size size :text full-name}
[wallet-user-avatar/wallet-user-avatar [wallet-user-avatar/wallet-user-avatar
{:full-name full-name {:full-name full-name
:size (if (= size 24) :size-20 :size-24) :size (if (= size 24) :size-20 :size-24)
:customization-color customization-color}]] :customization-color customization-color}]]
nil)]])) :dapp
[tag-skeleton {:theme theme :size size :text dapp-name}
[rn/image {:style (style/circle-logo size) :source dapp-logo}]]
nil)]])
(def view (schema/instrument #'view-internal component-schema/?schema)) (def view (schema/instrument #'view-internal component-schema/?schema))

View File

@ -24,12 +24,13 @@
(get ui k)) (get ui k))
(def dapps (def dapps
{:coingecko (js/require "../resources/images/dapps/CoinGecko.png") {:coingecko (js/require "../resources/images/dapps/CoinGecko.png")
:1inch (js/require "../resources/images/dapps/1inch.png") :1inch (js/require "../resources/images/dapps/1inch.png")
:aave (js/require "../resources/images/dapps/Aave.png") :aave (js/require "../resources/images/dapps/Aave.png")
:uniswap (js/require "../resources/images/dapps/Uniswap.png") :uniswap (js/require "../resources/images/dapps/Uniswap.png")
:zapper (js/require "../resources/images/dapps/Zapper.png") :zapper (js/require "../resources/images/dapps/Zapper.png")
:zerion (js/require "../resources/images/dapps/Zerion.png")}) :zerion (js/require "../resources/images/dapps/Zerion.png")
:wallet-connect (js/require "../resources/images/dapps/WalletConnect.png")})
(defn get-dapp (defn get-dapp
[k] [k]

View File

@ -37,7 +37,7 @@
:networks networks :networks networks
:align-center? true :align-center? true
:networks-on-press #(rf/dispatch [:show-bottom-sheet {:content network-filter/view}]) :networks-on-press #(rf/dispatch [:show-bottom-sheet {:content network-filter/view}])
:right-side [(when (and (ff/enabled? ::wallet.wallet-connect) :right-side [(when (and (ff/enabled? ::ff/wallet.wallet-connect)
(not watch-only?)) (not watch-only?))
{:icon-name :i/dapps {:icon-name :i/dapps
:on-press #(rf/dispatch [:navigate-to :screen/wallet.connected-dapps])}) :on-press #(rf/dispatch [:navigate-to :screen/wallet.connected-dapps])})

View File

@ -0,0 +1,11 @@
(ns status-im.contexts.wallet.connected-dapps.scan-dapp.style
(:require [quo.foundations.colors :as colors]))
(def subtitle-container
{:flex-direction :row
:align-items :center
:padding-horizontal 20
:gap 4})
(def subtitle-text
{:color colors/white})

View File

@ -0,0 +1,44 @@
(ns status-im.contexts.wallet.connected-dapps.scan-dapp.view
(:require [quo.core :as quo]
[quo.foundations.resources :as quo.resources]
[quo.theme]
[react-native.core :as rn]
[react-native.hooks :as hooks]
[status-im.common.scan-qr-code.view :as scan-qr-code]
[status-im.contexts.wallet.connected-dapps.scan-dapp.style :as style]
[utils.debounce :as debounce]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn view
[]
(let [{:keys [keyboard-shown]} (hooks/use-keyboard)
{:keys [name emoji color]} (rf/sub [:wallet/current-viewing-account])]
(rn/use-mount
(fn []
(when keyboard-shown
(rn/dismiss-keyboard!))))
[scan-qr-code/view
{:title (i18n/label :t/scan-qr)
:subtitle [rn/view style/subtitle-container
[quo/context-tag
{:theme :dark
:type :account
:size 24
:account-name name
:emoji emoji
:customization-color color}]
[quo/text
{:style style/subtitle-text
:size :paragraph-1}
(i18n/label :t/wallet-connect-via)]
[quo/context-tag
{:theme :dark
:type :dapp
:size 24
:dapp-name (i18n/label :t/wallet-connect-label)
:dapp-logo (quo.resources/get-dapp :wallet-connect)}]]
:on-success-scan (fn [scanned-text]
(debounce/debounce-and-dispatch
[:wallet-connect/on-scan-connection scanned-text]
300))}]))

View File

@ -90,7 +90,7 @@
{:title (i18n/label :t/connected-dapps) {:title (i18n/label :t/connected-dapps)
:wallet-account wallet-account :wallet-account wallet-account
:on-close #(rf/dispatch [:navigate-back]) :on-close #(rf/dispatch [:navigate-back])
:on-add #(js/alert "Feature not implemented")}] :on-add #(rf/dispatch [:navigate-to :screen/wallet.scan-dapp])}]
(if (empty? pairings) (if (empty? pairings)
[quo/empty-state [quo/empty-state
{:title (i18n/label :t/no-dapps) {:title (i18n/label :t/no-dapps)

View File

@ -67,8 +67,7 @@
:session-networks session-networks :session-networks session-networks
:address (-> without-watched :address (-> without-watched
first first
:address) :address))
)
:fx [[:dispatch :fx [[:dispatch
[:open-modal :screen/wallet.wallet-connect-session-proposal]]]} [:open-modal :screen/wallet.wallet-connect-session-proposal]]]}
{:fx [[:dispatch {:fx [[:dispatch
@ -190,27 +189,25 @@
(fn [_ [scanned-text]] (fn [_ [scanned-text]]
(let [parsed-uri (wallet-connect/parse-uri scanned-text) (let [parsed-uri (wallet-connect/parse-uri scanned-text)
version (:version parsed-uri) version (:version parsed-uri)
valid-wc-uri? (wc-utils/valid-uri? parsed-uri)
expired? (-> parsed-uri expired? (-> parsed-uri
:expiryTimestamp :expiryTimestamp
wc-utils/timestamp-expired?) wc-utils/timestamp-expired?)
version-supported? (wc-utils/version-supported? version)] version-supported? (wc-utils/version-supported? version)]
(cond (if (or (not valid-wc-uri?) expired? (not version-supported?))
expired?
{:fx [[:dispatch {:fx [[:dispatch
[:toasts/upsert [:toasts/upsert
{:type :negative {:type :negative
:theme :dark :theme :dark
:text (i18n/label :t/wallet-connect-qr-expired)}]]]} :text (cond (not valid-wc-uri?)
(i18n/label :t/wallet-connect-wrong-qr)
(not version-supported?) expired?
{:fx [[:dispatch (i18n/label :t/wallet-connect-qr-expired)
[:toasts/upsert
{:type :negative
:theme :dark
:text (i18n/label :t/wallet-connect-version-not-supported
{:version version})}]]]}
:else (not version-supported?)
(i18n/label :t/wallet-connect-version-not-supported
{:version version}))}]]]}
{:fx [[:dispatch [:wallet-connect/pair scanned-text]]]})))) {:fx [[:dispatch [:wallet-connect/pair scanned-text]]]}))))
(rf/reg-event-fx (rf/reg-event-fx

View File

@ -108,6 +108,7 @@
[status-im.contexts.wallet.bridge.select-asset.view :as wallet-bridge-select-asset] [status-im.contexts.wallet.bridge.select-asset.view :as wallet-bridge-select-asset]
[status-im.contexts.wallet.collectible.view :as wallet-collectible] [status-im.contexts.wallet.collectible.view :as wallet-collectible]
[status-im.contexts.wallet.common.scan-account.view :as wallet-scan-address] [status-im.contexts.wallet.common.scan-account.view :as wallet-scan-address]
[status-im.contexts.wallet.connected-dapps.scan-dapp.view :as wallet-scan-dapp]
[status-im.contexts.wallet.connected-dapps.view :as wallet-connected-dapps] [status-im.contexts.wallet.connected-dapps.view :as wallet-connected-dapps]
[status-im.contexts.wallet.send.from.view :as wallet-select-from] [status-im.contexts.wallet.send.from.view :as wallet-select-from]
[status-im.contexts.wallet.send.select-address.view :as wallet-select-address] [status-im.contexts.wallet.send.select-address.view :as wallet-select-address]
@ -411,10 +412,6 @@
:options {:insets {:top? true}} :options {:insets {:top? true}}
:component wallet-accounts/view} :component wallet-accounts/view}
{:name :screen/wallet.connected-dapps
:options {:insets {:top? true}}
:component wallet-connected-dapps/view}
{:name :screen/wallet.wallet-connect-session-proposal {:name :screen/wallet.wallet-connect-session-proposal
:options {:sheet? true} :options {:sheet? true}
:component wallet-connect-session-proposal/view} :component wallet-connect-session-proposal/view}
@ -549,6 +546,16 @@
:options {:sheet? true} :options {:sheet? true}
:component wallet-connect-send-transaction/view} :component wallet-connect-send-transaction/view}
{:name :screen/wallet.connected-dapps
:options {:insets {:top? true}}
:component wallet-connected-dapps/view}
{:name :screen/wallet.scan-dapp
:options (merge
options/dark-screen
{:modalPresentationStyle :overCurrentContext})
:component wallet-scan-dapp/view}
;; Settings ;; Settings
{:name :screen/settings-password {:name :screen/settings-password

View File

@ -2733,8 +2733,11 @@
"dapp-will-be-able-to": "{{dapp-name}} will be able to:", "dapp-will-be-able-to": "{{dapp-name}} will be able to:",
"check-your-account-balance-and-activity": "Check your account balance and activity", "check-your-account-balance-and-activity": "Check your account balance and activity",
"request-txns-and-message-signing": "Request transactions and message signing", "request-txns-and-message-signing": "Request transactions and message signing",
"wallet-connect-label": "WalletConnect",
"wallet-connect-via": "via",
"wallet-connect-qr-expired": "WalletConnect QR has expired", "wallet-connect-qr-expired": "WalletConnect QR has expired",
"wallet-connect-version-not-supported": "WalletConnect version {{version}} is not supported", "wallet-connect-version-not-supported": "WalletConnect version {{version}} is not supported",
"wallet-connect-wrong-qr": "Its not a WalletConnect QR",
"add-network-preferences": "Add network preferences", "add-network-preferences": "Add network preferences",
"saved-address-network-preference-selection-description": "Only change if you know which networks the address owner is happy to to receive funds on", "saved-address-network-preference-selection-description": "Only change if you know which networks the address owner is happy to to receive funds on",
"add-preferences": "Add preferences", "add-preferences": "Add preferences",