diff --git a/.clj-kondo/rewrite-clj/rewrite-clj/config.edn b/.clj-kondo/rewrite-clj/rewrite-clj/config.edn deleted file mode 100644 index 19ecae96a0f..00000000000 --- a/.clj-kondo/rewrite-clj/rewrite-clj/config.edn +++ /dev/null @@ -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/->>}} diff --git a/.clj-kondo/taoensso/encore/config.edn b/.clj-kondo/taoensso/encore/config.edn deleted file mode 100644 index 7b0ff3c2b7b..00000000000 --- a/.clj-kondo/taoensso/encore/config.edn +++ /dev/null @@ -1 +0,0 @@ -{:hooks {:analyze-call {taoensso.encore/defalias taoensso.encore/defalias}}} diff --git a/.clj-kondo/taoensso/encore/taoensso/encore.clj b/.clj-kondo/taoensso/encore/taoensso/encore.clj deleted file mode 100644 index 7f6d30ac94e..00000000000 --- a/.clj-kondo/taoensso/encore/taoensso/encore.clj +++ /dev/null @@ -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))})) diff --git a/src/status_im/contexts/shell/share/profile/view.cljs b/src/status_im/contexts/shell/share/profile/view.cljs new file mode 100644 index 00000000000..7b4b3c79acc --- /dev/null +++ b/src/status_im/contexts/shell/share/profile/view.cljs @@ -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]]]])) diff --git a/src/status_im/contexts/shell/share/view.cljs b/src/status_im/contexts/shell/share/view.cljs index 09128cc2853..ecb708998a5 100644 --- a/src/status_im/contexts/shell/share/view.cljs +++ b/src/status_im/contexts/shell/share/view.cljs @@ -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 [] diff --git a/src/status_im/contexts/shell/share/wallet/component_spec.cljs b/src/status_im/contexts/shell/share/wallet/component_spec.cljs new file mode 100644 index 00000000000..b0e00244523 --- /dev/null +++ b/src/status_im/contexts/shell/share/wallet/component_spec.cljs @@ -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:"))))))))) + diff --git a/src/status_im/contexts/shell/share/wallet/view.cljs b/src/status_im/contexts/shell/share/wallet/view.cljs new file mode 100644 index 00000000000..43856d031dd --- /dev/null +++ b/src/status_im/contexts/shell/share/wallet/view.cljs @@ -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))}])) diff --git a/src/status_im/contexts/wallet/receive/view.cljs b/src/status_im/contexts/wallet/receive/view.cljs index 8f983971877..e256f0dde35 100644 --- a/src/status_im/contexts/wallet/receive/view.cljs +++ b/src/status_im/contexts/wallet/receive/view.cljs @@ -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] diff --git a/src/status_im/core_spec.cljs b/src/status_im/core_spec.cljs index cda0e3d1e30..673095197dd 100644 --- a/src/status_im/core_spec.cljs +++ b/src/status_im/core_spec.cljs @@ -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] diff --git a/test/jest/jestSetup.js b/test/jest/jestSetup.js index 217b79d4815..58d8d77da3f 100644 --- a/test/jest/jestSetup.js +++ b/test/jest/jestSetup.js @@ -11,6 +11,10 @@ jest.mock('react-native-fs', () => ({ default: {}, })); +jest.mock('react-native-share', () => ({ + default: {}, +})); + jest.mock('react-native-navigation', () => ({ getNavigationConstants: () => ({ constants: [] }), Navigation: {