feat(shell): add share qr wallet accounts feature(#18511)
Co-authored-by: Paul Fitzgerald <paulfitz99@gmail.com>
This commit is contained in:
parent
92dcd1140b
commit
3e787ff112
|
@ -1,5 +0,0 @@
|
|||
{:lint-as
|
||||
{rewrite-clj.zip/subedit-> clojure.core/->
|
||||
rewrite-clj.zip/subedit->> clojure.core/->>
|
||||
rewrite-clj.zip/edit-> clojure.core/->
|
||||
rewrite-clj.zip/edit->> clojure.core/->>}}
|
|
@ -1 +0,0 @@
|
|||
{:hooks {:analyze-call {taoensso.encore/defalias taoensso.encore/defalias}}}
|
|
@ -1,16 +0,0 @@
|
|||
(ns taoensso.encore
|
||||
(:require
|
||||
[clj-kondo.hooks-api :as hooks]))
|
||||
|
||||
(defn defalias [{:keys [node]}]
|
||||
(let [[sym-raw src-raw] (rest (:children node))
|
||||
src (if src-raw src-raw sym-raw)
|
||||
sym (if src-raw
|
||||
sym-raw
|
||||
(symbol (name (hooks/sexpr src))))]
|
||||
{:node (with-meta
|
||||
(hooks/list-node
|
||||
[(hooks/token-node 'def)
|
||||
(hooks/token-node (hooks/sexpr sym))
|
||||
(hooks/token-node (hooks/sexpr src))])
|
||||
(meta src))}))
|
|
@ -0,0 +1,75 @@
|
|||
(ns status-im.contexts.shell.share.profile.view
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.ui.components.list-selection :as list-selection]
|
||||
[quo.core :as quo]
|
||||
[quo.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.qr-codes.view :as qr-codes]
|
||||
[status-im.contexts.profile.utils :as profile.utils]
|
||||
[status-im.contexts.shell.share.style :as style]
|
||||
[utils.address :as address]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn profile-tab
|
||||
[]
|
||||
(let [{:keys [emoji-hash
|
||||
customization-color
|
||||
universal-profile-url]
|
||||
:as profile} (rf/sub [:profile/profile])
|
||||
abbreviated-url (address/get-abbreviated-profile-url
|
||||
universal-profile-url)
|
||||
emoji-hash-string (string/join emoji-hash)]
|
||||
[:<>
|
||||
[rn/view {:style style/qr-code-container}
|
||||
[qr-codes/share-qr-code
|
||||
{:type :profile
|
||||
:unblur-on-android? true
|
||||
:qr-data universal-profile-url
|
||||
:qr-data-label-shown abbreviated-url
|
||||
:on-share-press #(list-selection/open-share {:message universal-profile-url})
|
||||
:on-text-press #(rf/dispatch [:share/copy-text-and-show-toast
|
||||
{:text-to-copy universal-profile-url
|
||||
:post-copy-message (i18n/label :t/link-to-profile-copied)}])
|
||||
:on-text-long-press #(rf/dispatch [:share/copy-text-and-show-toast
|
||||
{:text-to-copy universal-profile-url
|
||||
:post-copy-message (i18n/label :t/link-to-profile-copied)}])
|
||||
:profile-picture (:uri (profile.utils/photo profile))
|
||||
:full-name (profile.utils/displayed-name profile)
|
||||
:customization-color customization-color}]]
|
||||
|
||||
[rn/view {:style style/emoji-hash-container}
|
||||
[rn/view {:style style/emoji-address-container}
|
||||
[rn/view {:style style/emoji-address-column}
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:weight :medium
|
||||
:style style/emoji-hash-label}
|
||||
(i18n/label :t/emoji-hash)]
|
||||
[rn/touchable-highlight
|
||||
{:active-opacity 1
|
||||
:underlay-color colors/neutral-80-opa-1-blur
|
||||
:background-color :transparent
|
||||
:on-press #(rf/dispatch [:share/copy-text-and-show-toast
|
||||
{:text-to-copy emoji-hash-string
|
||||
:post-copy-message (i18n/label :t/emoji-hash-copied)}])
|
||||
:on-long-press #(rf/dispatch [:share/copy-text-and-show-toast
|
||||
{:text-to-copy emoji-hash-string
|
||||
:post-copy-message (i18n/label :t/emoji-hash-copied)}])}
|
||||
[rn/text {:style style/emoji-hash-content} emoji-hash-string]]]]
|
||||
[rn/view {:style style/emoji-share-button-container}
|
||||
[quo/button
|
||||
{:icon-only? true
|
||||
:type :grey
|
||||
:background :blur
|
||||
:size 32
|
||||
:accessibility-label :link-to-profile
|
||||
:container-style {:margin-right 12}
|
||||
:on-press #(rf/dispatch [:share/copy-text-and-show-toast
|
||||
{:text-to-copy emoji-hash-string
|
||||
:post-copy-message (i18n/label :t/emoji-hash-copied)}])
|
||||
:on-long-press #(rf/dispatch [:share/copy-text-and-show-toast
|
||||
{:text-to-copy emoji-hash-string
|
||||
:post-copy-message (i18n/label :t/emoji-hash-copied)}])}
|
||||
:i/copy]]]]))
|
|
@ -1,18 +1,14 @@
|
|||
(ns status-im.contexts.shell.share.view
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.ui.components.list-selection :as list-selection]
|
||||
[quo.core :as quo]
|
||||
[quo.foundations.colors :as colors]
|
||||
[react-native.blur :as blur]
|
||||
[react-native.core :as rn]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.common.qr-codes.view :as qr-codes]
|
||||
[status-im.contexts.profile.utils :as profile.utils]
|
||||
[status-im.contexts.shell.share.profile.view :as profile-view]
|
||||
[status-im.contexts.shell.share.style :as style]
|
||||
[utils.address :as address]
|
||||
[status-im.contexts.shell.share.wallet.view :as wallet-view]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
|
@ -43,72 +39,6 @@
|
|||
:style style/header-heading}
|
||||
(i18n/label :t/share)]])
|
||||
|
||||
(defn profile-tab
|
||||
[]
|
||||
(let [{:keys [emoji-hash
|
||||
customization-color
|
||||
universal-profile-url]
|
||||
:as profile} (rf/sub [:profile/profile])
|
||||
abbreviated-url (address/get-abbreviated-profile-url
|
||||
universal-profile-url)
|
||||
emoji-hash-string (string/join emoji-hash)]
|
||||
[:<>
|
||||
[rn/view {:style style/qr-code-container}
|
||||
[qr-codes/share-qr-code
|
||||
{:type :profile
|
||||
:unblur-on-android? true
|
||||
:qr-data universal-profile-url
|
||||
:qr-data-label-shown abbreviated-url
|
||||
:on-share-press #(list-selection/open-share {:message universal-profile-url})
|
||||
:on-text-press #(rf/dispatch [:share/copy-text-and-show-toast
|
||||
{:text-to-copy universal-profile-url
|
||||
:post-copy-message (i18n/label :t/link-to-profile-copied)}])
|
||||
:on-text-long-press #(rf/dispatch [:share/copy-text-and-show-toast
|
||||
{:text-to-copy universal-profile-url
|
||||
:post-copy-message (i18n/label :t/link-to-profile-copied)}])
|
||||
:profile-picture (:uri (profile.utils/photo profile))
|
||||
:full-name (profile.utils/displayed-name profile)
|
||||
:customization-color customization-color}]]
|
||||
|
||||
[rn/view {:style style/emoji-hash-container}
|
||||
[rn/view {:style style/emoji-address-container}
|
||||
[rn/view {:style style/emoji-address-column}
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:weight :medium
|
||||
:style style/emoji-hash-label}
|
||||
(i18n/label :t/emoji-hash)]
|
||||
[rn/touchable-highlight
|
||||
{:active-opacity 1
|
||||
:underlay-color colors/neutral-80-opa-1-blur
|
||||
:background-color :transparent
|
||||
:on-press #(rf/dispatch [:share/copy-text-and-show-toast
|
||||
{:text-to-copy emoji-hash-string
|
||||
:post-copy-message (i18n/label :t/emoji-hash-copied)}])
|
||||
:on-long-press #(rf/dispatch [:share/copy-text-and-show-toast
|
||||
{:text-to-copy emoji-hash-string
|
||||
:post-copy-message (i18n/label :t/emoji-hash-copied)}])}
|
||||
[rn/text {:style style/emoji-hash-content} emoji-hash-string]]]]
|
||||
[rn/view {:style style/emoji-share-button-container}
|
||||
[quo/button
|
||||
{:icon-only? true
|
||||
:type :grey
|
||||
:background :blur
|
||||
:size 32
|
||||
:accessibility-label :link-to-profile
|
||||
:container-style {:margin-right 12}
|
||||
:on-press #(rf/dispatch [:share/copy-text-and-show-toast
|
||||
{:text-to-copy emoji-hash-string
|
||||
:post-copy-message (i18n/label :t/emoji-hash-copied)}])
|
||||
:on-long-press #(rf/dispatch [:share/copy-text-and-show-toast
|
||||
{:text-to-copy emoji-hash-string
|
||||
:post-copy-message (i18n/label :t/emoji-hash-copied)}])}
|
||||
:i/copy]]]]))
|
||||
|
||||
(defn wallet-tab
|
||||
[]
|
||||
[rn/text {:style style/wip-style} "not implemented"])
|
||||
|
||||
(defn tab-content
|
||||
[]
|
||||
(let [selected-tab (reagent/atom :profile)]
|
||||
|
@ -126,8 +56,8 @@
|
|||
{:id :wallet
|
||||
:label (i18n/label :t/wallet)}]}]]
|
||||
(if (= @selected-tab :profile)
|
||||
[profile-tab]
|
||||
[wallet-tab])])))
|
||||
[profile-view/profile-tab]
|
||||
[wallet-view/wallet-tab])])))
|
||||
|
||||
(defn view
|
||||
[]
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
(ns status-im.contexts.shell.share.wallet.component-spec
|
||||
(:require
|
||||
[status-im.contexts.shell.share.wallet.view :as wallet-view]
|
||||
status-im.contexts.wallet.events
|
||||
[test-helpers.component :as h]))
|
||||
|
||||
(defn render-wallet-view
|
||||
[]
|
||||
(let [component-rendered (h/render [wallet-view/wallet-tab])
|
||||
rerender-fn (h/get-rerender-fn component-rendered)
|
||||
share-qr-code (h/get-by-label-text :share-qr-code)]
|
||||
;; Fires on-layout since it's needed to render the content
|
||||
(h/fire-event :layout share-qr-code #js {:nativeEvent #js {:layout #js {:width 500}}})
|
||||
(rerender-fn [wallet-view/wallet-tab])))
|
||||
|
||||
(h/describe "share wallet addresses"
|
||||
(h/setup-restorable-re-frame)
|
||||
(h/before-each
|
||||
(fn []
|
||||
(h/setup-subs {:dimensions/window-width 500
|
||||
:mediaserver/port 200
|
||||
:wallet/accounts [{:address "0x707f635951193ddafbb40971a0fcaab8a6415160"
|
||||
:name "Wallet One"
|
||||
:emoji "😆"
|
||||
:color :blue}]})))
|
||||
|
||||
(h/test "should display the the wallet tab"
|
||||
(render-wallet-view)
|
||||
(h/wait-for #(h/is-truthy (h/get-by-text "Wallet One"))))
|
||||
|
||||
(h/test "should display the the legacy account"
|
||||
(render-wallet-view)
|
||||
(-> (h/wait-for #(h/get-by-label-text :share-qr-code-legacy-tab))
|
||||
(.then (fn []
|
||||
(h/fire-event :press (h/get-by-label-text :share-qr-code-legacy-tab))
|
||||
(-> (h/wait-for #(h/is-falsy (h/query-by-text "eth:"))))))))
|
||||
|
||||
(h/test "should display the the multichain account"
|
||||
(render-wallet-view)
|
||||
(-> (h/wait-for #(h/get-by-label-text :share-qr-code-multichain-tab))
|
||||
(.then (fn []
|
||||
(h/fire-event :press (h/get-by-label-text :share-qr-code-multichain-tab))
|
||||
(-> (h/wait-for #(h/is-truthy (h/query-by-text "eth:")))))))))
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
(ns status-im.contexts.shell.share.wallet.view
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.share :as share]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.contexts.shell.share.style :as style]
|
||||
[status-im.contexts.wallet.common.sheets.network-preferences.view :as network-preferences]
|
||||
[status-im.contexts.wallet.common.utils :as utils]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.image-server :as image-server]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(def qr-size 500)
|
||||
|
||||
(defn- share-action
|
||||
[address share-title]
|
||||
(share/open
|
||||
(if platform/ios?
|
||||
{:activityItemSources [{:placeholderItem {:type "text"
|
||||
:content address}
|
||||
:item {:default {:type "text"
|
||||
:content
|
||||
address}}
|
||||
:linkMetadata {:title share-title}}]}
|
||||
{:title share-title
|
||||
:subject share-title
|
||||
:message address
|
||||
:isNewTask true})))
|
||||
|
||||
(defn- open-preferences
|
||||
[selected-networks]
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:theme :dark
|
||||
:shell? true
|
||||
:content
|
||||
(fn []
|
||||
[network-preferences/view
|
||||
{:blur? true
|
||||
:selected-networks (set selected-networks)
|
||||
:on-save (fn [chain-ids]
|
||||
(rf/dispatch [:hide-bottom-sheet])
|
||||
(reset! selected-networks (map #(get utils/id->network %)
|
||||
chain-ids)))}])}]))
|
||||
(defn wallet-qr-code-item
|
||||
[account width index]
|
||||
(let [selected-networks (reagent/atom [:ethereum :optimism :arbitrum])
|
||||
wallet-type (reagent/atom :wallet-legacy)]
|
||||
(fn []
|
||||
(let [share-title (str (:name account) " " (i18n/label :t/address))
|
||||
qr-url (utils/get-wallet-qr {:wallet-type @wallet-type
|
||||
:selected-networks @selected-networks
|
||||
:address (:address account)})
|
||||
qr-media-server-uri (image-server/get-qr-image-uri-for-any-url
|
||||
{:url qr-url
|
||||
:port (rf/sub [:mediaserver/port])
|
||||
:qr-size qr-size
|
||||
:error-level :highest})]
|
||||
[rn/view {:style {:width width :margin-left (if (zero? index) 0 -30)}}
|
||||
[rn/view {:style style/qr-code-container}
|
||||
[quo/share-qr-code
|
||||
{:type @wallet-type
|
||||
:qr-image-uri qr-media-server-uri
|
||||
:qr-data qr-url
|
||||
:networks @selected-networks
|
||||
:on-share-press #(share-action qr-url share-title)
|
||||
:profile-picture nil
|
||||
:unblur-on-android? true
|
||||
:full-name (:name account)
|
||||
:customization-color (:color account)
|
||||
:emoji (:emoji account)
|
||||
:on-multichain-press #(reset! wallet-type :wallet-multichain)
|
||||
:on-legacy-press #(reset! wallet-type :wallet-legacy)
|
||||
:on-settings-press #(open-preferences @selected-networks)}]]]))))
|
||||
|
||||
(defn wallet-tab
|
||||
[]
|
||||
(let [accounts (rf/sub [:wallet/accounts])
|
||||
width (rf/sub [:dimensions/window-width])]
|
||||
[rn/flat-list
|
||||
{:horizontal true
|
||||
:deceleration-rate 0.9
|
||||
:snap-to-alignment "start"
|
||||
:snap-to-interval (- width 30)
|
||||
:disable-interval-momentum true
|
||||
:scroll-event-throttle 64
|
||||
:data accounts
|
||||
:directional-lock-enabled true
|
||||
:render-fn (fn [account index]
|
||||
(wallet-qr-code-item account width index))}]))
|
|
@ -19,15 +19,16 @@
|
|||
[address share-title]
|
||||
(share/open
|
||||
(if platform/ios?
|
||||
{:activity-item-sources [{:placeholder-item {:type "text"
|
||||
:content address}
|
||||
:item {:default {:type "text"
|
||||
:content
|
||||
address}}
|
||||
:link-metadata {:title share-title}}]}
|
||||
{:title share-title
|
||||
:subject share-title
|
||||
:message address})))
|
||||
{:activityItemSources [{:placeholderItem {:type "text"
|
||||
:content address}
|
||||
:item {:default {:type "text"
|
||||
:content
|
||||
address}}
|
||||
:linkMetadata {:title share-title}}]}
|
||||
{:title share-title
|
||||
:subject share-title
|
||||
:message address
|
||||
:isNewTask true})))
|
||||
|
||||
(defn- open-preferences
|
||||
[selected-networks]
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
[status-im.common.floating-button-page.component-spec]
|
||||
[status-im.contexts.chat.messenger.messages.content.audio.component-spec]
|
||||
[status-im.contexts.communities.actions.community-options.component-spec]
|
||||
[status-im.contexts.shell.share.wallet.component-spec]
|
||||
[status-im.contexts.wallet.add-address-to-watch.component-spec]
|
||||
[status-im.contexts.wallet.add-address-to-watch.confirm-address.component-spec]
|
||||
[status-im.contexts.wallet.create-account.edit-derivation-path.component-spec]
|
||||
|
|
|
@ -11,6 +11,10 @@ jest.mock('react-native-fs', () => ({
|
|||
default: {},
|
||||
}));
|
||||
|
||||
jest.mock('react-native-share', () => ({
|
||||
default: {},
|
||||
}));
|
||||
|
||||
jest.mock('react-native-navigation', () => ({
|
||||
getNavigationConstants: () => ({ constants: [] }),
|
||||
Navigation: {
|
||||
|
|
Loading…
Reference in New Issue