NFT UI 🖼

New UI and re-frame handlers for setting pfp from url
Add fake chain-id, connect the pfp upload backend to UI
Add toast on setting pfp, new-new-new UI
Show assets based on selected network
Add horzontal padding to traits card
a11y ids and pr review changes
Added emoji in toast, fix chain id nill issue
Restore Podfile
Fix fix podfile
Add placeholder images for collections, hide option to set pfp when image url is empty or ends in mp4 or svg
Improvise missing designs
Fix paddings
New nu placeholders
Sort collections by name
Kinda fix issue 4
Fix lint

Signed-off-by: Shivek Khurana <shivek@status.im>
This commit is contained in:
Shivek Khurana 2021-09-22 05:45:21 +05:30
parent 84d3b562a4
commit 389ce6695a
No known key found for this signature in database
GPG Key ID: 9BEB56E6E62968C7
17 changed files with 447 additions and 161 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -134,6 +134,7 @@
"multiaccounts_getIdentityImages" {}
"multiaccounts_getIdentityImage" {}
"multiaccounts_storeIdentityImage" {}
"multiaccounts_storeIdentityImageFromURL" {}
"multiaccounts_deleteIdentityImage" {}
"wakuext_changeIdentityImageShowTo" {}
"wakuext_createCommunity" {}

View File

@ -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]

View File

@ -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]

View File

@ -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

View File

@ -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)]))))

View File

@ -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]]]))})))

View File

@ -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

View File

@ -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

View File

@ -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 [<sub]])
[status-im.ui.screens.wallet.collectibles.views :as collectibles.views])
(:require-macros [status-im.utils.views :as views]))
(def state (reagent/atom {:tab :assets}))
@ -102,136 +97,6 @@
{:style {:color colors/blue}}
(i18n/label :t/check-on-opensea)]]])
(defn nft-assets-skeleton [num-assets]
[:<>
(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 (<sub [:wallet/collectible-assets-by-collection-and-address address collectible-slug])]
[react/view {:flex 1
:flex-wrap :wrap
:justify-content :space-between
:flex-direction :row
:style {:padding-horizontal 16}}
(if (seq assets)
(for [asset assets]
^{:key (:id asset)}
[react/touchable-opacity
{:style {:width "48%"
:margin-bottom 16}
:on-press #(re-frame/dispatch [::wallet/show-nft-details 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)}}]])
[nft-assets-skeleton num-assets])]))
(defn nft-collections [address]
(let [collection (<sub [:wallet/collectible-collection address])]
[:<>
(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 (<sub [:wallet/current-collectible-asset])]
[:<>
[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}

View File

@ -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 [<sub]]
[status-im.ui.components.topbar :as topbar]
[status-im.ui.components.toastable-highlight :refer [toastable-highlight-view]]
[status-im.ui.screens.wallet.components.views :as wallet.components]
[status-im.react-native.resources :as resources]
[status-im.multiaccounts.core :as multiaccounts]
[status-im.wallet.core :as wallet]
[status-im.multiaccounts.update.core :as multiaccounts.update]
[quo.design-system.colors :as colors]
[status-im.ui.components.icons.icons :as icons]
[status-im.i18n.i18n :as i18n]
[status-im.ui.components.accordion :as accordion]))
(defn is-image? [nft]
(and (seq (:image_url nft))
(not (str/ends-with? (:image_url nft) ".svg"))
(not (str/ends-with? (:image_url nft) ".mp4"))))
(defn missing-image-placeholder []
[react/view {:style {:width "100%"
:flex 1
:align-items :center
:border-radius 16
:background-color colors/gray-lighter
:justify-content :center
:aspect-ratio 1}}
[icons/icon :photo {:color colors/gray}]])
(defn nft-assets-skeleton [num-assets]
[:<>
(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 (<sub [:wallet/selected-collectible])]
[react/scroll-view
[topbar/topbar
{:navigation {:icon :main-icons/close}
:border-bottom false}]
[react/view {:padding-horizontal 16}
[quo/text {:size :large
:weight :bold}
(:name nft)]
[quo/text {:size :small
:color :secondary
:style {:margin-top 4}}
(-> 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 <shivekkhurana>: Enable txns
;; [quo/list-item {:title (i18n/label :t/wallet-send)
;; :icon :main-icons/send
;; :accessibility-label
;; :nft-send
;; :theme :accent
;; :on-press #()}]
;; TODO <shivekkhurana>: 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 (<sub [:wallet/collectible-assets-by-collection-and-address address collectible-slug])
fetching? (<sub [:wallet/fetching-assets-by-collectible-slug collectible-slug])]
[react/view {:flex 1
:flex-wrap :wrap
:justify-content :space-between
:flex-direction :row
:style {:padding-horizontal 16}}
(cond
fetching? [nft-assets-skeleton num-assets]
;; <shivekkhurana> 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 (<sub [:wallet/collectible-collection address])]
[:<>
(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)]])

View File

@ -343,3 +343,4 @@
{:events [:wallet.accounts/share]}
[_ address]
{:list.selection/open-share {:message (eip55/address->checksum address)}})

View File

@ -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}]

View File

@ -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"
}