diff --git a/resources/images/ui/collectible-dark@2x.png b/resources/images/ui/collectible-dark@2x.png new file mode 100644 index 0000000000..fc0c066e5b Binary files /dev/null and b/resources/images/ui/collectible-dark@2x.png differ diff --git a/resources/images/ui/collectible-dark@3x.png b/resources/images/ui/collectible-dark@3x.png new file mode 100644 index 0000000000..4bc40bf7fa Binary files /dev/null and b/resources/images/ui/collectible-dark@3x.png differ diff --git a/resources/images/ui/collectible@2x.png b/resources/images/ui/collectible@2x.png new file mode 100644 index 0000000000..07141bb38b Binary files /dev/null and b/resources/images/ui/collectible@2x.png differ diff --git a/resources/images/ui/collectible@3x.png b/resources/images/ui/collectible@3x.png new file mode 100644 index 0000000000..daf70ecfce Binary files /dev/null and b/resources/images/ui/collectible@3x.png differ diff --git a/src/status_im/ethereum/json_rpc.cljs b/src/status_im/ethereum/json_rpc.cljs index e61a0e2a3d..929bb74c0c 100644 --- a/src/status_im/ethereum/json_rpc.cljs +++ b/src/status_im/ethereum/json_rpc.cljs @@ -134,6 +134,7 @@ "multiaccounts_getIdentityImages" {} "multiaccounts_getIdentityImage" {} "multiaccounts_storeIdentityImage" {} + "multiaccounts_storeIdentityImageFromURL" {} "multiaccounts_deleteIdentityImage" {} "wakuext_changeIdentityImageShowTo" {} "wakuext_createCommunity" {} diff --git a/src/status_im/multiaccounts/core.cljs b/src/status_im/multiaccounts/core.cljs index 68fa28a927..16b0f1d923 100644 --- a/src/status_im/multiaccounts/core.cljs +++ b/src/status_im/multiaccounts/core.cljs @@ -202,6 +202,20 @@ :type (name photo-quality-large)}]) (bottom-sheet/hide-bottom-sheet)))) +(fx/defn save-profile-picture-from-url + {:events [::save-profile-picture-from-url]} + [cofx url] + (let [key-uid (get-in cofx [:db :multiaccount :key-uid])] + (fx/merge cofx + {::json-rpc/call [{:method "multiaccounts_storeIdentityImageFromURL" + :params [key-uid url] + :on-error log/warn + :on-success #(re-frame/dispatch [::update-local-picture %])}]} + (bottom-sheet/hide-bottom-sheet)))) + +(comment + (re-frame/dispatch [::save-profile-picture-from-url "https://lh3.googleusercontent.com/XuKjNm3HydsaxbPkbpGs9YyCKhn5QQk5oDC8XF2jzmPyYXeZofxFtfUDZuQ3EVmacS_BlBKzbX2ypm37YNX3n1fDJA3WndeFcPsp7Z0=w600"])) + (fx/defn delete-profile-picture {:events [::delete-profile-picture]} [cofx name] diff --git a/src/status_im/react_native/resources.cljs b/src/status_im/react_native/resources.cljs index 36fe2b66ce..2ff16e14b1 100644 --- a/src/status_im/react_native/resources.cljs +++ b/src/status_im/react_native/resources.cljs @@ -6,9 +6,9 @@ :welcome (js/require "../resources/images/ui/welcome.jpg") :welcome-dark (js/require "../resources/images/ui/welcome-dark.jpg") :chat (js/require "../resources/images/ui/chat.jpg") + :chat-dark (js/require "../resources/images/ui/chat-dark.jpg") :wallet (js/require "../resources/images/ui/wallet.jpg") :browser (js/require "../resources/images/ui/browser.jpg") - :chat-dark (js/require "../resources/images/ui/chat-dark.jpg") :wallet-dark (js/require "../resources/images/ui/wallet-dark.jpg") :browser-dark (js/require "../resources/images/ui/browser-dark.jpg") :keys (js/require "../resources/images/ui/keys.jpg") @@ -43,6 +43,8 @@ :theme-light (js/require "../resources/images/ui/theme-light.png") :theme-system (js/require "../resources/images/ui/theme-system.png") :notifications (js/require "../resources/images/ui/notifications.png") + :collectible (js/require "../resources/images/ui/collectible.png") + :collectible-dark (js/require "../resources/images/ui/collectible-dark.png") :graph (js/require "../resources/images/ui/graph.png")}) (defn get-theme-image [k] diff --git a/src/status_im/subs.cljs b/src/status_im/subs.cljs index 1abdd4b897..fa4a4621c6 100644 --- a/src/status_im/subs.cljs +++ b/src/status_im/subs.cljs @@ -176,8 +176,10 @@ (reg-root-key-sub :wallet/transactions-management-enabled? :wallet/transactions-management-enabled?) (reg-root-key-sub :wallet/all-tokens :wallet/all-tokens) (reg-root-key-sub :wallet/collectible-collections :wallet/collectible-collections) +(reg-root-key-sub :wallet/fetching-collection-assets :wallet/fetching-collection-assets) (reg-root-key-sub :wallet/collectible-assets :wallet/collectible-assets) -(reg-root-key-sub :wallet/current-collectible-asset :wallet/current-collectible-asset) +(reg-root-key-sub :wallet/selected-collectible :wallet/selected-collectible) + ;;commands (reg-root-key-sub :commands/select-account :commands/select-account) @@ -1831,7 +1833,8 @@ :<- [:wallet/collectible-collections] (fn [all-collections [_ address]] (when address - (get all-collections (string/lower-case address) [])))) + (let [all-collections (get all-collections (string/lower-case address) [])] + (sort-by :name all-collections))))) (re-frame/reg-sub :wallet/collectible-assets-by-collection-and-address @@ -1839,6 +1842,12 @@ (fn [all-assets [_ address collectible-slug]] (get-in all-assets [address collectible-slug] []))) +(re-frame/reg-sub + :wallet/fetching-assets-by-collectible-slug + :<- [:wallet/fetching-collection-assets] + (fn [fetching-collection-assets [_ collectible-slug]] + (get fetching-collection-assets collectible-slug false))) + ;;ACTIVITY CENTER NOTIFICATIONS ======================================================================================== (defn- group-notifications-by-date diff --git a/src/status_im/ui/components/accordion.cljs b/src/status_im/ui/components/accordion.cljs index 8f0d7f33f7..fd00dddd4e 100644 --- a/src/status_im/ui/components/accordion.cljs +++ b/src/status_im/ui/components/accordion.cljs @@ -20,15 +20,18 @@ (let [opened? (reagent/atom false)] (fn [{:keys [title content icon opened disabled padding-vertical dropdown-margin-left + open-container-style on-open on-close] :or {padding-vertical 8 dropdown-margin-left 8 + open-container-style {} on-open #() on-close #()}}] (let [on-press #(do (apply (if @opened? on-close on-open) []) (swap! opened? not))] - [react/view {:padding-vertical padding-vertical} + [react/view (merge {:padding-vertical padding-vertical} + (when @opened? open-container-style)) (if (string? title) [quo/list-item {:title title @@ -40,7 +43,7 @@ :margin-right 14 :justify-content :space-between} title - [drop-down-icon {:opened? (or @opened? opened) + [drop-down-icon {:opened? (or @opened? opened) :dropdown-margin-left dropdown-margin-left}]]]) (when (or @opened? opened) content)])))) diff --git a/src/status_im/ui/components/toastable_highlight.cljs b/src/status_im/ui/components/toastable_highlight.cljs new file mode 100644 index 0000000000..a164e35e71 --- /dev/null +++ b/src/status_im/ui/components/toastable_highlight.cljs @@ -0,0 +1,117 @@ +(ns status-im.ui.components.toastable-highlight + "A wrapped touchable highlight that presents a toast when clicked" + (:require [reagent.core :as reagent] + [status-im.ui.components.animation :as animation] + [quo.design-system.colors :as colors] + [status-im.ui.components.react :as react])) + +(defn hide-cue-atom [anim-opacity anim-y cue-atom] + (animation/start + (animation/parallel + [(animation/timing + anim-opacity + {:toValue 0 + :duration 140 + :delay 1000 + :easing (.-ease ^js animation/easing) + :useNativeDriver true}) + (animation/timing + anim-y + {:toValue 0 + :duration 140 + :delay 1000 + :easing (.-ease ^js animation/easing) + :useNativeDriver true})]) + #(reset! cue-atom false))) + +(defn show-cue-atom [anim-opacity anim-y cue-atom y] + (when @cue-atom + (animation/start + (animation/parallel + [(animation/timing + anim-opacity + {:toValue 1 + :duration 140 + :easing (.-ease ^js animation/easing) + :useNativeDriver true}) + (animation/timing + anim-y + {:toValue y + :duration 140 + :easing (.-ease ^js animation/easing) + :useNativeDriver true})]) + #(hide-cue-atom anim-opacity anim-y cue-atom)))) + +(defn toast [anim-opacity anim-y width cue-atom label] + [react/animated-view + {:style + {:opacity anim-opacity + :transform [{:translateY anim-y}] + :max-width @width + :z-index (if @cue-atom 1 -1) + :height 34 + :position :absolute + :border-radius 8 + :align-self :center + :align-items :center + :justify-content :center + :shadow-offset {:width 0 :height 4} + :shadow-radius 12 + :elevation 8 + :shadow-opacity 1 + :shadow-color "rgba(0, 34, 51, 0.08)" + :background-color colors/white}} + [react/view + {:padding-horizontal 16 + :padding-vertical 7 + :border-radius 8 + :background-color colors/white + :shadow-offset {:width 0 :height 2} + :shadow-radius 4 + :shadow-opacity 1 + :shadow-color "rgba(0, 34, 51, 0.16)"} + [react/text + {:style + {:typography :main-medium + ;; line height specified here because of figma spec + :line-height 20 + :font-size 14}} + label]]]) + +(defn toastable-highlight-view + [{:keys [toast-label on-press + container-style]} + content] + (let [cue-atom (reagent/atom false) + width (reagent/atom 0) + height (reagent/atom 0) + anim-y (animation/create-value 0) + anim-opacity (animation/create-value 0)] + (reagent/create-class + {:reagent-render + (fn [{:keys []} _] + (let [press-fn #(when (not @cue-atom) + (reset! cue-atom true) + (show-cue-atom + anim-opacity + anim-y + cue-atom + (if (> @height 34) + (- (/ @height 2)) + (- (+ 17 @height)))) + (when on-press + (on-press)))] + [react/view + {:style (if container-style container-style {}) + :on-layout + #(do + (reset! width (-> ^js % .-nativeEvent .-layout .-width)) + (reset! height (-> ^js % .-nativeEvent .-layout .-height)))} + [toast anim-opacity anim-y width cue-atom toast-label] + [react/touchable-highlight + {:active-opacity (if @cue-atom 1 0.85) + :underlay-color colors/black + :on-press press-fn + :on-long-press press-fn} + [react/view {:background-color colors/white} + content]]]))}))) diff --git a/src/status_im/ui/screens/privacy_and_security_settings/views.cljs b/src/status_im/ui/screens/privacy_and_security_settings/views.cljs index b476864385..4595cfca4c 100644 --- a/src/status_im/ui/screens/privacy_and_security_settings/views.cljs +++ b/src/status_im/ui/screens/privacy_and_security_settings/views.cljs @@ -71,7 +71,7 @@ ((complement boolean) preview-privacy?)])}] (when config/collectibles-enabled? [quo/list-item {:size :small - :title (i18n/label :t/enable-opensea-nfts) + :title (i18n/label :t/display-collectibles) :container-margin-bottom 8 :active opensea-enabled? :accessory :switch diff --git a/src/status_im/ui/screens/screens.cljs b/src/status_im/ui/screens/screens.cljs index 5bfb1fec94..d5df196d21 100644 --- a/src/status_im/ui/screens/screens.cljs +++ b/src/status_im/ui/screens/screens.cljs @@ -55,6 +55,7 @@ [status-im.ui.screens.wallet.transactions.views :as wallet-transactions] [status-im.ui.screens.wallet.custom-tokens.views :as custom-tokens] [status-im.ui.screens.wallet.accounts.views :as wallet.accounts] + [status-im.ui.screens.wallet.collectibles.views :as wallet.collectibles] [status-im.ui.screens.wallet.account.views :as wallet.account] [status-im.ui.screens.wallet.add-new.views :as add-account] [status-im.ui.screens.wallet.account-settings.views :as account-settings] @@ -700,7 +701,7 @@ :insets {:bottom true} ;;TODO dynamic title :options {:topBar {:visible false}} - :component wallet.account/nft-details} + :component wallet.collectibles/nft-details-modal} ;My Status {:name :my-status diff --git a/src/status_im/ui/screens/wallet/account/views.cljs b/src/status_im/ui/screens/wallet/account/views.cljs index 396d0cd260..2068769a4d 100644 --- a/src/status_im/ui/screens/wallet/account/views.cljs +++ b/src/status_im/ui/screens/wallet/account/views.cljs @@ -6,8 +6,6 @@ [status-im.ui.components.animation :as animation] [quo.design-system.colors :as colors] [status-im.ui.components.icons.icons :as icons] - [status-im.ui.components.accordion :as accordion] - [status-im.react-native.resources :as resources] [quo.core :as quo] [status-im.ui.components.react :as react] [status-im.ui.components.topbar :as topbar] @@ -17,11 +15,8 @@ [status-im.ui.screens.wallet.accounts.views :as accounts] [status-im.ui.screens.wallet.buy-crypto.views :as buy-crypto] [status-im.ui.screens.wallet.transactions.views :as history] - [status-im.wallet.core :as wallet] [status-im.ui.components.tabs :as tabs] - [status-im.multiaccounts.update.core :as multiaccounts.update] - [status-im.ui.screens.wallet.components.views :as wallet.components] - [status-im.utils.handlers :refer [ - (for [i (range num-assets)] - ^{:key i} - [react/view {:style {:width "48%" - :margin-bottom 16}} - [react/view {:style {:flex 1 - :aspect-ratio 1 - :border-width 1 - :background-color colors/gray-transparent-10 - :border-color colors/gray-lighter - :border-radius 16}}]])]) - -(defn nft-assets [{:keys [num-assets address collectible-slug]}] - (let [assets ( - (for [collectible collection] - ^{:key (:slug collectible)} - [accordion/section - {:title - [react/view {:flex 1} - [quo/list-item - {:title (:name collectible) - :text-size :large - :icon - [wallet.components/token-icon {:style {:border-radius 40 - :overflow :hidden - :border-width 1 - :border-color "#EEF2F5"} - :source {:uri (:image_url collectible)}}] - :accessory :text - :accessory-text (:owned_asset_count collectible)}]] - :padding-vertical 0 - :dropdown-margin-left -12 - :on-open #(re-frame/dispatch [::wallet/fetch-collectible-assets-by-owner-and-collection - address - (:slug collectible) - (:owned_asset_count collectible)]) - :content [nft-assets {:address address - :num-assets (:owned_asset_count collectible) - :collectible-slug (:slug collectible)}]}])])) - -(defn nft-traits [traits] - [react/view {:flex 1 - :margin-bottom 24 - :flex-direction :row - :flex-wrap :wrap} - (for [trait traits] - ^{:key (:trait_type trait)} - [react/view {:style {:border-width 1 - :border-radius 12 - :padding-horizontal 8 - :padding-vertical 4 - :margin-right 8 - :margin-bottom 8 - :border-color colors/gray-lighter}} - [quo/text {:size :small - :color :secondary} - (:trait_type trait)] - [quo/text {} - (:value trait)]])]) - -(defn nft-details [] - (let [nft ( - [topbar/topbar - {:title (:name nft) - :subtitle (-> nft :collection :name) - :border-bottom false - :right-accessories - [{:icon :main-icons/browser - :on-press #(re-frame/dispatch [:browser.ui/open-url (:permalink nft)])}]}] - [react/scroll-view {:padding 16} - [react/image {:source {:uri (:image_url nft)} - :style {:width "100%" - :aspect-ratio 1 - :border-radius 4 - :border-width 1 - :border-color "#EEF2F5"}}] - [react/text {:style {:margin-top 24 - :margin-bottom 16}} - (:description nft)] - [nft-traits (:traits nft)]]])) - -(defn enable-opensea-view [] - [react/view {:style {:border-width 1 - :border-color colors/gray-lighter - :border-radius 8 - :margin 16}} - [react/view {:style {:padding 16}} - [react/image {:source (resources/get-theme-image :unfurl) - :style {:align-self :center - :width 132 - :height 94}}] - [quo/text {:size :small - :align :center - :style {:margin-top 6}} - (i18n/label :t/enable-opensea-nfts)] - [quo/text {:size :small - :color :secondary - :align :center - :style {:margin-top 2}} - (i18n/label :t/opensea-nfts-leak-metadata)]] - [quo/separator] - [quo/button {:on-press #(re-frame/dispatch [::multiaccounts.update/toggle-opensea-nfts-visiblity true]) - :type :secondary} - (i18n/label :enable)]]) - (views/defview assets-and-collections [address] (views/letsubs [{:keys [tokens]} [:wallet/visible-assets-with-values address] currency [:wallet/currency] @@ -257,10 +122,10 @@ (when config/collectibles-enabled? (cond (not opensea-enabled?) - [enable-opensea-view] + [collectibles.views/enable-opensea-view] (and opensea-enabled? (seq collectible-collection)) - [nft-collections address] + [collectibles.views/nft-collections address] :else [react/view {:align-items :center :margin-top 32} diff --git a/src/status_im/ui/screens/wallet/collectibles/views.cljs b/src/status_im/ui/screens/wallet/collectibles/views.cljs new file mode 100644 index 0000000000..d223e24ae4 --- /dev/null +++ b/src/status_im/ui/screens/wallet/collectibles/views.cljs @@ -0,0 +1,256 @@ +(ns status-im.ui.screens.wallet.collectibles.views + (:require [re-frame.core :as re-frame] + [clojure.string :as str] + [status-im.ui.components.react :as react] + [quo.core :as quo] + [status-im.utils.handlers :refer [ + (for [i (range num-assets)] + ^{:key i} + [react/view {:style {:width "48%" + :margin-bottom 16}} + [react/view {:style {:flex 1 + :aspect-ratio 1 + :border-width 1 + :background-color colors/gray-transparent-10 + :border-color colors/gray-lighter + :border-radius 16}}]])]) + +(defn nft-trait-card [trait] + [react/view {:style {:border-width 1 + :border-radius 12 + :margin-right 8 + :padding-vertical 4 + :padding-horizontal 8 + :border-color colors/gray-lighter}} + [quo/text {:size :small + :color :secondary} + (:trait_type trait)] + [quo/text {} + (:value trait)]]) + +(defn nft-traits-scroller [traits] + [react/scroll-view {:horizontal true + :deceleration-rate "fast" + :snap-to-alignment "left" + :shows-horizontal-scroll-indicator + false + :scroll-event-throttle 64 + :style {:padding-left 16 + :margin-vertical 16 + :padding-bottom 8}} + (for [trait traits] + ^{:key (:trait_type trait)} + [nft-trait-card trait]) + + ;; spacer + [react/view {:style {:height 40 + :width 40}}]]) + +(defn nft-details-modal [] + (let [nft ( nft :collection :name)] + + (if (is-image? nft) + [react/image {:source {:uri (:image_url nft)} + :style {:width "100%" + :margin-bottom 16 + :aspect-ratio 1 + :border-radius 4 + :border-width 1 + :border-color colors/gray-lighter}}] + [missing-image-placeholder]) + + [quo/text {:style {:margin-top 12}} + (:description nft)]] + + (when (seq (:traits nft)) + [nft-traits-scroller (:traits nft)]) + + ;; seperator + [react/view {:style {:border-bottom-width 1 + :padding-top 8 + :border-color colors/gray-lighter}}] + + ;; TODO : Enable txns + ;; [quo/list-item {:title (i18n/label :t/wallet-send) + ;; :icon :main-icons/send + ;; :accessibility-label + ;; :nft-send + ;; :theme :accent + ;; :on-press #()}] + + ;; TODO : What to do with share? + ;; Share links or share image? + ;; [quo/list-item {:title (i18n/label :t/share) + ;; :theme :accent + ;; :accessibility-label + ;; :nft-share + ;; :on-press #() + ;; :icon :main-icons/share}] + [quo/list-item {:title (i18n/label :t/view-on-opensea) + :theme :accent + :icon :main-icons/browser + :on-press #(re-frame/dispatch [:browser.ui/open-url (:permalink nft)])}] + (when (is-image? nft) + [toastable-highlight-view + ;; the last string is an emoji. It might not show up in all editors but its there + {:toast-label (str (i18n/label :profile-picture-updated)) " " "😎"} + [quo/list-item {:title (i18n/label :t/use-as-profile-picture) + :theme :accent + :on-press #(re-frame/dispatch + [::multiaccounts/save-profile-picture-from-url (:image_url nft)]) + :icon :main-icons/profile + :accessibility-label + :set-nft-as-pfp}]])])) + +(defn no-assets-error [] + [react/view {:style {:flex 1 + :justify-content :center + :padding 16 + :margin-vertical 16 + :align-items :center + :border-radius 16}} + [icons/icon :photo {:color colors/red}] + [quo/text {:color :secondary + :style {:magin-top 8}} + (i18n/label :t/no-collectibles)]]) + +(defn nft-assets [{:keys [num-assets address collectible-slug]}] + (let [assets ( OpenSea sometimes doesn't return an asset + ;; This condition handles it + (and (not fetching?) + (not (seq assets))) + [no-assets-error] + + (seq assets) + (for [asset assets] + ^{:key (:id asset)} + [react/touchable-opacity + {:style + {:width "48%" + :border-radius 16 + :margin-bottom 16} + :on-press #(re-frame/dispatch [::wallet/show-nft-details asset]) + :accessibility-label + :nft-asset} + (if (is-image? asset) + [react/image {:style {:flex 1 + :aspect-ratio 1 + :border-width 1 + :border-color colors/gray-lighter + :border-radius 16} + :source {:uri (:image_url asset)}}] + [missing-image-placeholder])]))])) + +(defn nft-collections [address] + (let [collection ( + (for [[index collectible] (map-indexed vector collection)] + ^{:key (:slug collectible)} + [accordion/section + {:title + [react/view {:flex 1} + [quo/list-item + {:title (:name collectible) + :text-size :large + :accessibility-label + (keyword (str "collection-" index)) + :icon (if (seq (:image_url collectible)) + [wallet.components/token-icon + {:style {:border-radius 40 + :overflow :hidden + :border-width 1 + :border-color colors/gray-lighter} + :source {:uri (:image_url collectible)}}] + :main-icons/photo) + :accessory :text + :accessory-text (:owned_asset_count collectible)}]] + :padding-vertical 0 + :dropdown-margin-left -12 + :open-container-style {:border-top-width 8 + :border-bottom-width 8 + :border-color colors/gray-lighter} + :on-open #(re-frame/dispatch [::wallet/fetch-collectible-assets-by-owner-and-collection + address + (:slug collectible) + (:owned_asset_count collectible)]) + :content [nft-assets {:address address + :num-assets (:owned_asset_count collectible) + :collectible-slug (:slug collectible)}]}])])) + +(defn enable-opensea-view [] + [react/view {:style {:padding 16}} + [react/view {:style {:border-color colors/gray-lighter + :border-width 1 + :align-self :center + :padding 4 + :border-radius 12}} + [react/image {:source (resources/get-theme-image :collectible) + :style {:align-self :center + :resize-mode :contain}}]] + [quo/text {:align :center + :style {:margin-vertical 16}} + (i18n/label :t/collectibles-leak-metadata)] + [react/view {:align-items :center} + [quo/button {:accessibility-label :enable-opensea-nft-visibility + :on-press + #(re-frame/dispatch + [::multiaccounts.update/toggle-opensea-nfts-visiblity true]) + :theme :main + :type :primary} + (i18n/label :display-collectibles)]] + [quo/text {:size :small + :color :secondary + :align :center + :style {:margin-top 10}} + (i18n/label :t/disable-later-in-settings)]]) diff --git a/src/status_im/wallet/accounts/core.cljs b/src/status_im/wallet/accounts/core.cljs index a915393329..6089cb130c 100644 --- a/src/status_im/wallet/accounts/core.cljs +++ b/src/status_im/wallet/accounts/core.cljs @@ -343,3 +343,4 @@ {:events [:wallet.accounts/share]} [_ address] {:list.selection/open-share {:message (eip55/address->checksum address)}}) + diff --git a/src/status_im/wallet/core.cljs b/src/status_im/wallet/core.cljs index 2473ec0ee6..ae1dec1b84 100644 --- a/src/status_im/wallet/core.cljs +++ b/src/status_im/wallet/core.cljs @@ -220,36 +220,49 @@ {:events [::fetch-collectibles-collection]} [{:keys [db]}] (let [addresses (map (comp string/lower-case :address) - (get db :multiaccount/accounts))] + (get db :multiaccount/accounts)) + chain-id (-> db + ethereum/current-network + ethereum/network->chain-id)] (when (get-in db [:multiaccount :opensea-enabled?]) {::json-rpc/call (map (fn [address] - {:method "wallet_getOpenseaCollectionsByOwner" - :params [address] - :on-error (fn [error] - (log/error "Unable to get Opensea collections" address error)) + {:method "wallet_getOpenseaCollectionsByOwner" + :params [chain-id address] + :on-error (fn [error] + (log/error "Unable to get Opensea collections" address error)) :on-success #(re-frame/dispatch [::collectibles-collection-fetch-success address %])}) addresses)}))) (fx/defn collectible-assets-fetch-success {:events [::collectible-assets-fetch-success]} [{:keys [db]} address collectible-slug assets] - {:db (assoc-in db [:wallet/collectible-assets address collectible-slug] assets)}) + {:db (-> db + (assoc-in [:wallet/fetching-collection-assets collectible-slug] false) + (assoc-in [:wallet/collectible-assets address collectible-slug] assets))}) + +(fx/defn collectibles-assets-fetch-error + {:events [::collectibles-assets-fetch-error]} + [{:keys [db]} collectible-slug] + {:db (assoc-in db [:wallet/fetching-collection-assets collectible-slug] false)}) (fx/defn fetch-collectible-assets-by-owner-and-collection {:events [::fetch-collectible-assets-by-owner-and-collection]} - [_ address collectible-slug limit] - {::json-rpc/call [{:method "wallet_getOpenseaAssetsByOwnerAndCollection" - :params [address collectible-slug limit] - :on-error (fn [error] - (log/error "Unable to get collectible assets" address error)) - :on-success #(re-frame/dispatch [::collectible-assets-fetch-success address collectible-slug %])}]}) + [{:keys [db]} address collectible-slug limit] + (let [chain-id (ethereum/network->chain-id (ethereum/current-network db))] + {:db (assoc-in db [:wallet/fetching-collection-assets collectible-slug] true) + ::json-rpc/call [{:method "wallet_getOpenseaAssetsByOwnerAndCollection" + :params [chain-id address collectible-slug limit] + :on-error (fn [error] + (log/error "Unable to get collectible assets" address error) + (re-frame/dispatch [::collectibles-assets-fetch-error collectible-slug])) + :on-success #(re-frame/dispatch [::collectible-assets-fetch-success address collectible-slug %])}]})) (fx/defn show-nft-details {:events [::show-nft-details]} [cofx asset] (fx/merge cofx - {:db (assoc (:db cofx) :wallet/current-collectible-asset asset)} - (navigation/navigate-to :nft-details {}))) + {:db (assoc (:db cofx) :wallet/selected-collectible asset)} + (navigation/open-modal :nft-details {}))) (defn rpc->token [tokens] (reduce (fn [acc {:keys [address] :as token}] diff --git a/translations/en.json b/translations/en.json index 6e9020a24e..c185989262 100644 --- a/translations/en.json +++ b/translations/en.json @@ -1669,6 +1669,10 @@ "fee-options": "Suggested fee options", "fee-cap": "Fee cap", "tip-cap": "Tip cap", - "enable-opensea-nfts": "Enable loading NFTs from OpenSea ?", - "opensea-nfts-leak-metadata": "Loading NFTs from OpenSea shares metadata with third party services" + "collectibles-leak-metadata": "You can display your NFTs here. If you do, you will share your wallet and IP address", + "display-collectibles": "Display collectibles", + "disable-later-in-settings": "You can disable this later in Settings", + "use-as-profile-picture": "Use as profile picture", + "view-on-opensea": "View on OpenSea", + "profile-picture-updated": "Profile picture updated" }