chore(wallet): smooth collectible list loading transition
This commit is contained in:
parent
f17484f61b
commit
777b2bb8da
|
@ -10,12 +10,13 @@
|
||||||
|
|
||||||
:image - collection image
|
:image - collection image
|
||||||
:theme - keyword -> :light/:dark"
|
:theme - keyword -> :light/:dark"
|
||||||
[{:keys [image size on-load-end on-error] :or {size :size-24}}]
|
[{:keys [image size on-load-start on-load-end on-error] :or {size :size-24}}]
|
||||||
(let [theme (quo.theme/use-theme)]
|
(let [theme (quo.theme/use-theme)]
|
||||||
[rn/view {:style (style/collection-avatar-container theme size)}
|
[rn/view {:style (style/collection-avatar-container theme size)}
|
||||||
[fast-image/fast-image
|
[fast-image/fast-image
|
||||||
{:accessibility-label :collection-avatar
|
{:accessibility-label :collection-avatar
|
||||||
:source image
|
:source image
|
||||||
|
:on-load-start on-load-start
|
||||||
:on-load-end on-load-end
|
:on-load-end on-load-end
|
||||||
:on-error on-error
|
:on-error on-error
|
||||||
:style (style/collection-avatar size)}]]))
|
:style (style/collection-avatar size)}]]))
|
||||||
|
|
|
@ -5,18 +5,22 @@
|
||||||
(def container-border-radius 12)
|
(def container-border-radius 12)
|
||||||
(def card-image-padding-vertical 3)
|
(def card-image-padding-vertical 3)
|
||||||
(def card-image-padding-horizontal 3)
|
(def card-image-padding-horizontal 3)
|
||||||
|
(def default-opacity-for-loader 1)
|
||||||
|
(def default-opacity-for-image 0)
|
||||||
|
|
||||||
(defn fallback
|
(defn fallback
|
||||||
[{:keys [theme]}]
|
[{:keys [theme opacity]}]
|
||||||
{:background-color (colors/theme-colors colors/neutral-2_5 colors/neutral-90 theme)
|
[{:opacity opacity}
|
||||||
:border-style :dashed
|
{:opacity default-opacity-for-image
|
||||||
:border-color (colors/theme-colors colors/neutral-20 colors/neutral-80 theme)
|
:background-color (colors/theme-colors colors/neutral-2_5 colors/neutral-90 theme)
|
||||||
:border-width 1
|
:border-style :dashed
|
||||||
:border-radius container-border-radius
|
:border-color (colors/theme-colors colors/neutral-20 colors/neutral-80 theme)
|
||||||
:width "100%"
|
:border-width 1
|
||||||
:aspect-ratio 1
|
:border-radius container-border-radius
|
||||||
:align-items :center
|
:width "100%"
|
||||||
:justify-content :center})
|
:aspect-ratio 1
|
||||||
|
:align-items :center
|
||||||
|
:justify-content :center}])
|
||||||
|
|
||||||
(def collectible-counter
|
(def collectible-counter
|
||||||
{:position :absolute
|
{:position :absolute
|
||||||
|
@ -59,6 +63,15 @@
|
||||||
(def card-detail-text
|
(def card-detail-text
|
||||||
{:flex 1})
|
{:flex 1})
|
||||||
|
|
||||||
|
(defn card-loader
|
||||||
|
[opacity]
|
||||||
|
[{:opacity opacity}
|
||||||
|
{:position :absolute
|
||||||
|
:opacity default-opacity-for-loader
|
||||||
|
:left 8
|
||||||
|
:align-items :center
|
||||||
|
:flex-direction :row}])
|
||||||
|
|
||||||
(def image-view-container
|
(def image-view-container
|
||||||
{:aspect-ratio 1
|
{:aspect-ratio 1
|
||||||
:border-radius container-border-radius})
|
:border-radius container-border-radius})
|
||||||
|
@ -83,6 +96,7 @@
|
||||||
(defn loading-image
|
(defn loading-image
|
||||||
[theme]
|
[theme]
|
||||||
{:position :absolute
|
{:position :absolute
|
||||||
|
:opacity default-opacity-for-loader
|
||||||
:top 0
|
:top 0
|
||||||
:bottom 0
|
:bottom 0
|
||||||
:left 0
|
:left 0
|
||||||
|
@ -91,8 +105,20 @@
|
||||||
:background-color (colors/theme-colors colors/white-70-blur colors/neutral-95-opa-70-blur theme)
|
:background-color (colors/theme-colors colors/white-70-blur colors/neutral-95-opa-70-blur theme)
|
||||||
:z-index 2})
|
:z-index 2})
|
||||||
|
|
||||||
|
(defn loading-image-with-opacity
|
||||||
|
[theme opacity]
|
||||||
|
[{:opacity opacity}
|
||||||
|
(loading-image theme)])
|
||||||
|
|
||||||
(defn avatar-container
|
(defn avatar-container
|
||||||
[loaded?]
|
[opacity]
|
||||||
{:flex 1
|
[{:opacity opacity}
|
||||||
:flex-direction :row
|
{:flex 1
|
||||||
:opacity (when-not loaded? 0)})
|
:flex-direction :row
|
||||||
|
:opacity default-opacity-for-image}])
|
||||||
|
|
||||||
|
(defn supported-file
|
||||||
|
[opacity]
|
||||||
|
[{:opacity opacity}
|
||||||
|
{:aspect-ratio 1
|
||||||
|
:opacity default-opacity-for-image}])
|
||||||
|
|
|
@ -10,13 +10,54 @@
|
||||||
[quo.foundations.gradients :as gradients]
|
[quo.foundations.gradients :as gradients]
|
||||||
[quo.theme]
|
[quo.theme]
|
||||||
[react-native.core :as rn]
|
[react-native.core :as rn]
|
||||||
|
[react-native.reanimated :as reanimated]
|
||||||
[schema.core :as schema]
|
[schema.core :as schema]
|
||||||
|
[utils.datetime :as datetime]
|
||||||
[utils.i18n :as i18n]))
|
[utils.i18n :as i18n]))
|
||||||
|
|
||||||
|
(def timing-options-out 650)
|
||||||
|
(def timing-options-in 1000)
|
||||||
|
(def first-load-time 500)
|
||||||
|
(def cached-load-time 200)
|
||||||
|
(def error-wait-time 800)
|
||||||
|
|
||||||
|
(defn on-load-end
|
||||||
|
[{:keys [load-time set-state loader-opacity image-opacity]}]
|
||||||
|
(reanimated/animate loader-opacity 0 timing-options-out)
|
||||||
|
(reanimated/animate image-opacity 1 timing-options-in)
|
||||||
|
(if (> load-time cached-load-time)
|
||||||
|
(js/setTimeout
|
||||||
|
(fn []
|
||||||
|
(set-state (fn [prev-state]
|
||||||
|
(assoc prev-state :image-loaded? true))))
|
||||||
|
first-load-time)
|
||||||
|
(set-state (fn [prev-state]
|
||||||
|
(assoc prev-state :image-loaded? true)))))
|
||||||
|
|
||||||
|
(defn on-load-error
|
||||||
|
[set-state]
|
||||||
|
(js/setTimeout (fn []
|
||||||
|
(set-state (fn [prev-state] (assoc prev-state :image-error? true))))
|
||||||
|
error-wait-time))
|
||||||
|
|
||||||
|
(defn on-load-avatar
|
||||||
|
[{:keys [load-time set-state loader-opacity avatar-opacity]}]
|
||||||
|
(reanimated/animate loader-opacity 0 timing-options-out)
|
||||||
|
(reanimated/animate avatar-opacity 1 timing-options-in)
|
||||||
|
(if (> load-time cached-load-time)
|
||||||
|
(js/setTimeout
|
||||||
|
(fn []
|
||||||
|
(set-state (fn [prev-state]
|
||||||
|
(assoc prev-state :avatar-loaded? true))))
|
||||||
|
first-load-time)
|
||||||
|
(set-state (fn [prev-state]
|
||||||
|
(assoc prev-state :avatar-loaded? true)))))
|
||||||
|
|
||||||
(defn- fallback-view
|
(defn- fallback-view
|
||||||
[{:keys [label theme]}]
|
[{:keys [label theme image-opacity]}]
|
||||||
[rn/view
|
[reanimated/view
|
||||||
{:style (style/fallback {:theme theme})}
|
{:style (style/fallback {:opacity image-opacity
|
||||||
|
:theme theme})}
|
||||||
[rn/view
|
[rn/view
|
||||||
[icon/icon :i/sad {:color (colors/theme-colors colors/neutral-40 colors/neutral-50 theme)}]]
|
[icon/icon :i/sad {:color (colors/theme-colors colors/neutral-40 colors/neutral-50 theme)}]]
|
||||||
[rn/view {:style {:height 4}}]
|
[rn/view {:style {:height 4}}]
|
||||||
|
@ -34,77 +75,85 @@
|
||||||
[rn/view {:style (style/loading-message theme)}])
|
[rn/view {:style (style/loading-message theme)}])
|
||||||
|
|
||||||
(defn- loading-image
|
(defn- loading-image
|
||||||
[{:keys [theme gradient-color-index]}]
|
[{:keys [theme gradient-color-index loader-opacity]}]
|
||||||
[gradients/view
|
[reanimated/view
|
||||||
{:theme theme
|
{:style (style/loading-image-with-opacity theme loader-opacity)}
|
||||||
:container-style (style/loading-image theme)
|
[gradients/view
|
||||||
:color-index gradient-color-index}])
|
{:theme theme
|
||||||
|
:container-style (style/loading-image theme)
|
||||||
|
:color-index gradient-color-index}]])
|
||||||
|
|
||||||
(defn- card-details
|
(defn- card-details
|
||||||
[{:keys [community? avatar-image-src collectible-name theme state set-state]}]
|
[{:keys [community? avatar-image-src collectible-name theme state set-state]}]
|
||||||
[rn/view {:style style/card-details-container}
|
(let [loader-opacity (reanimated/use-shared-value 1)
|
||||||
(cond (not (:avatar-loaded? state))
|
avatar-opacity (reanimated/use-shared-value 0)
|
||||||
[rn/view {:style {:flex-direction :row}}
|
[load-time set-load-time] (rn/use-state (datetime/now))]
|
||||||
[loading-square theme]
|
[rn/view {:style style/card-details-container}
|
||||||
[loading-message theme]]
|
[reanimated/view {:style (style/avatar-container avatar-opacity)}
|
||||||
|
(if community?
|
||||||
community?
|
[preview-list/view
|
||||||
[:<>
|
{:type :communities
|
||||||
[preview-list/view
|
:size :size-20}
|
||||||
{:type :communities
|
[avatar-image-src]]
|
||||||
:size :size-20}
|
[collection-avatar/view
|
||||||
[avatar-image-src]]
|
{:size :size-20
|
||||||
[rn/view {:style {:width 8}}]
|
:on-start #(set-load-time (fn [start-time] (- (datetime/now) start-time)))
|
||||||
[text/text
|
:on-load-end #(on-load-avatar {:set-state set-state
|
||||||
{:size :paragraph-1
|
:load-time load-time
|
||||||
:weight :semi-bold
|
:loader-opacity loader-opacity
|
||||||
:style style/card-detail-text}
|
:avatar-opacity avatar-opacity})
|
||||||
collectible-name]])
|
:image avatar-image-src}])
|
||||||
|
[rn/view {:style {:width 8}}]
|
||||||
[rn/view
|
[text/text
|
||||||
{:style (style/avatar-container (:avatar-loaded? state))}
|
{:size :paragraph-1
|
||||||
[:<>
|
:weight :semi-bold
|
||||||
[collection-avatar/view
|
:ellipsize-mode :tail
|
||||||
{:size :size-20
|
:number-of-lines 1
|
||||||
:on-load-end #(set-state (fn [prev-state] (assoc prev-state :avatar-loaded? true)))
|
:style style/card-detail-text}
|
||||||
:image avatar-image-src}]
|
collectible-name]]
|
||||||
[rn/view {:style {:width 8}}]]
|
(when (not (:avatar-loaded? state))
|
||||||
[text/text
|
[reanimated/view {:style (style/card-loader loader-opacity)}
|
||||||
{:size :paragraph-1
|
[loading-square theme]
|
||||||
:weight :semi-bold
|
[loading-message theme]])]))
|
||||||
:ellipsize-mode :tail
|
|
||||||
:number-of-lines 1
|
|
||||||
:style style/card-detail-text}
|
|
||||||
collectible-name]]])
|
|
||||||
|
|
||||||
(defn- card-view
|
(defn- card-view
|
||||||
[{:keys [avatar-image-src collectible-name community? counter state set-state
|
[{:keys [avatar-image-src collectible-name community? counter state set-state
|
||||||
gradient-color-index image-src supported-file?]}]
|
gradient-color-index image-src supported-file?]}]
|
||||||
(let [theme (quo.theme/use-theme)]
|
(let [theme (quo.theme/use-theme)
|
||||||
|
loader-opacity (reanimated/use-shared-value (if supported-file? 1 0))
|
||||||
|
image-opacity (reanimated/use-shared-value (if supported-file? 0 1))
|
||||||
|
[load-time set-load-time] (rn/use-state (datetime/now))]
|
||||||
[rn/view {:style (style/card-view-container theme)}
|
[rn/view {:style (style/card-view-container theme)}
|
||||||
[rn/view {:style {:aspect-ratio 1}}
|
[rn/view {:style {:aspect-ratio 1}}
|
||||||
(cond
|
(cond
|
||||||
(:image-error? state)
|
(:image-error? state)
|
||||||
[fallback-view
|
[fallback-view
|
||||||
{:theme theme
|
{:image-opacity image-opacity
|
||||||
:label (i18n/label :t/cant-fetch-info)}]
|
:theme theme
|
||||||
|
:label (i18n/label :t/cant-fetch-info)}]
|
||||||
|
|
||||||
(not supported-file?)
|
(not supported-file?)
|
||||||
[fallback-view
|
[fallback-view
|
||||||
{:theme theme
|
{:image-opacity image-opacity
|
||||||
:label (i18n/label :t/unsupported-file)}]
|
:theme theme
|
||||||
|
:label (i18n/label :t/unsupported-file)}]
|
||||||
|
|
||||||
(not (:image-loaded? state))
|
(not (:image-loaded? state))
|
||||||
[loading-image
|
[loading-image
|
||||||
{:theme theme
|
{:loader-opacity loader-opacity
|
||||||
|
:theme theme
|
||||||
:gradient-color-index gradient-color-index}])
|
:gradient-color-index gradient-color-index}])
|
||||||
(when supported-file?
|
(when supported-file?
|
||||||
[rn/view {:style {:aspect-ratio 1}}
|
[reanimated/view {:style (style/supported-file image-opacity)}
|
||||||
[rn/image
|
[rn/image
|
||||||
{:style style/image
|
{:style style/image
|
||||||
:on-load-end #(set-state (fn [prev-state] (assoc prev-state :image-loaded? true)))
|
:on-load-start #(set-load-time (fn [start-time] (- (datetime/now) start-time)))
|
||||||
:on-error #(set-state (fn [prev-state] (assoc prev-state :image-error? true)))
|
:on-load-end #(on-load-end {:load-time load-time
|
||||||
:source image-src}]])]
|
:set-state set-state
|
||||||
|
:loader-opacity loader-opacity
|
||||||
|
:image-opacity image-opacity})
|
||||||
|
:on-error #(on-load-error set-state)
|
||||||
|
:source image-src}]])]
|
||||||
(when (and (:image-loaded? state) (not (:image-error? state)) counter)
|
(when (and (:image-loaded? state) (not (:image-error? state)) counter)
|
||||||
[collectible-counter/view
|
[collectible-counter/view
|
||||||
{:container-style style/collectible-counter
|
{:container-style style/collectible-counter
|
||||||
|
@ -121,30 +170,40 @@
|
||||||
(defn- image-view
|
(defn- image-view
|
||||||
[{:keys [avatar-image-src community? counter state set-state
|
[{:keys [avatar-image-src community? counter state set-state
|
||||||
gradient-color-index image-src supported-file?]}]
|
gradient-color-index image-src supported-file?]}]
|
||||||
(let [theme (quo.theme/use-theme)]
|
(let [theme (quo.theme/use-theme)
|
||||||
|
loader-opacity (reanimated/use-shared-value (if supported-file? 1 0))
|
||||||
|
image-opacity (reanimated/use-shared-value (if supported-file? 0 1))
|
||||||
|
[load-time set-load-time] (rn/use-state (datetime/now))]
|
||||||
[rn/view {:style style/image-view-container}
|
[rn/view {:style style/image-view-container}
|
||||||
(cond
|
(cond
|
||||||
(:image-error? state)
|
(:image-error? state)
|
||||||
[fallback-view
|
[fallback-view
|
||||||
{:theme theme
|
{:image-opacity image-opacity
|
||||||
:label (i18n/label :t/cant-fetch-info)}]
|
:theme theme
|
||||||
|
:label (i18n/label :t/cant-fetch-info)}]
|
||||||
|
|
||||||
(not supported-file?)
|
(not supported-file?)
|
||||||
[fallback-view
|
[fallback-view
|
||||||
{:theme theme
|
{:image-opacity image-opacity
|
||||||
:label (i18n/label :t/unsupported-file)}]
|
:theme theme
|
||||||
|
:label (i18n/label :t/unsupported-file)}]
|
||||||
|
|
||||||
(not (:image-loaded? state))
|
(not (:image-loaded? state))
|
||||||
[loading-image
|
[loading-image
|
||||||
{:theme theme
|
{:loader-opacity loader-opacity
|
||||||
|
:theme theme
|
||||||
:gradient-color-index gradient-color-index}])
|
:gradient-color-index gradient-color-index}])
|
||||||
(when supported-file?
|
(when supported-file?
|
||||||
[rn/view {:style {:aspect-ratio 1}}
|
[reanimated/view {:style (style/supported-file image-opacity)}
|
||||||
[rn/image
|
[rn/image
|
||||||
{:style style/image
|
{:style style/image
|
||||||
:on-load-end #(set-state (fn [prev-state] (assoc prev-state :image-loaded? true)))
|
:on-load-start #(set-load-time (fn [start-time] (- (datetime/now) start-time)))
|
||||||
:on-error #(set-state (fn [prev-state] (assoc prev-state :image-error? true)))
|
:on-load-end #(on-load-end {:load-time load-time
|
||||||
:source image-src}]])
|
:set-state set-state
|
||||||
|
:loader-opacity loader-opacity
|
||||||
|
:image-opacity image-opacity})
|
||||||
|
:on-error #(on-load-error set-state)
|
||||||
|
:source image-src}]])
|
||||||
(when (and (:image-loaded? state) (not (:image-error? state)) counter)
|
(when (and (:image-loaded? state) (not (:image-error? state)) counter)
|
||||||
[collectible-counter/view
|
[collectible-counter/view
|
||||||
{:container-style style/collectible-counter
|
{:container-style style/collectible-counter
|
||||||
|
|
|
@ -105,23 +105,6 @@
|
||||||
(def fast-create-community-enabled?
|
(def fast-create-community-enabled?
|
||||||
(enabled? (get-config :FAST_CREATE_COMMUNITY_ENABLED "0")))
|
(enabled? (get-config :FAST_CREATE_COMMUNITY_ENABLED "0")))
|
||||||
|
|
||||||
(def default-multiaccount
|
|
||||||
{:preview-privacy? blank-preview?
|
|
||||||
:wallet-legacy/visible-tokens {:mainnet #{:SNT}}
|
|
||||||
:currency :usd
|
|
||||||
:appearance 0
|
|
||||||
:profile-pictures-show-to 2
|
|
||||||
:profile-pictures-visibility 2
|
|
||||||
:log-level log-level
|
|
||||||
:webview-allow-permission-requests? false
|
|
||||||
:opensea-enabled? false
|
|
||||||
:link-previews-enabled-sites #{}
|
|
||||||
:link-preview-request-enabled true})
|
|
||||||
|
|
||||||
(defn default-visible-tokens
|
|
||||||
[chain]
|
|
||||||
(get-in default-multiaccount [:wallet-legacy/visible-tokens chain]))
|
|
||||||
|
|
||||||
(def waku-nodes-config
|
(def waku-nodes-config
|
||||||
{:status.prod
|
{:status.prod
|
||||||
["enrtree://AL65EKLJAUXKKPG43HVTML5EFFWEZ7L4LOKTLZCLJASG4DSESQZEC@prod.status.nodes.status.im"]
|
["enrtree://AL65EKLJAUXKKPG43HVTML5EFFWEZ7L4LOKTLZCLJASG4DSESQZEC@prod.status.nodes.status.im"]
|
||||||
|
|
|
@ -11,6 +11,22 @@
|
||||||
[utils.i18n :as i18n]
|
[utils.i18n :as i18n]
|
||||||
[utils.re-frame :as rf]))
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
|
(defn- on-collectible-press
|
||||||
|
[{:keys [id]}]
|
||||||
|
(rf/dispatch [:wallet/get-collectible-details id]))
|
||||||
|
|
||||||
|
(defn- on-collectible-long-press
|
||||||
|
[{:keys [preview-url collectible-details]}]
|
||||||
|
(rf/dispatch [:show-bottom-sheet
|
||||||
|
{:content (fn []
|
||||||
|
[options-drawer/view
|
||||||
|
{:name (:name collectible-details)
|
||||||
|
:image (:uri preview-url)}])}]))
|
||||||
|
|
||||||
|
(defn- on-end-reached
|
||||||
|
[]
|
||||||
|
(rf/dispatch [:wallet/request-collectibles-for-current-viewing-account]))
|
||||||
|
|
||||||
(defn view
|
(defn view
|
||||||
[{:keys [selected-tab]}]
|
[{:keys [selected-tab]}]
|
||||||
(let [collectible-list (rf/sub
|
(let [collectible-list (rf/sub
|
||||||
|
@ -20,19 +36,11 @@
|
||||||
(case selected-tab
|
(case selected-tab
|
||||||
:assets [assets/view]
|
:assets [assets/view]
|
||||||
:collectibles [collectibles/view
|
:collectibles [collectibles/view
|
||||||
{:collectibles collectible-list
|
{:collectibles collectible-list
|
||||||
:current-account-address current-account-address
|
:current-account-address current-account-address
|
||||||
:on-end-reached #(rf/dispatch
|
:on-end-reached on-end-reached
|
||||||
[:wallet/request-collectibles-for-current-viewing-account])
|
:on-collectible-press on-collectible-press
|
||||||
:on-collectible-press (fn [{:keys [id]}]
|
:on-collectible-long-press on-collectible-long-press}]
|
||||||
(rf/dispatch [:wallet/get-collectible-details id]))
|
|
||||||
:on-collectible-long-press (fn [{:keys [preview-url collectible-details]}]
|
|
||||||
(rf/dispatch
|
|
||||||
[:show-bottom-sheet
|
|
||||||
{:content (fn []
|
|
||||||
[options-drawer/view
|
|
||||||
{:name (:name collectible-details)
|
|
||||||
:image (:uri preview-url)}])}]))}]
|
|
||||||
:activity [activity/view]
|
:activity [activity/view]
|
||||||
:permissions [empty-tab/view
|
:permissions [empty-tab/view
|
||||||
{:title (i18n/label :t/no-permissions)
|
{:title (i18n/label :t/no-permissions)
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
(ns status-im.contexts.wallet.collectible.utils
|
(ns status-im.contexts.wallet.collectible.utils
|
||||||
(:require [status-im.config :as config]
|
(:require [status-im.config :as config]
|
||||||
[status-im.constants :as constants]
|
[status-im.constants :as constants]
|
||||||
[status-im.contexts.wallet.common.utils.networks :as network-utils]))
|
[status-im.contexts.wallet.common.utils.networks :as network-utils]
|
||||||
|
[taoensso.timbre :as log]))
|
||||||
|
|
||||||
(defn collectible-balance
|
(defn collectible-balance
|
||||||
[collectible]
|
[collectible]
|
||||||
|
@ -23,7 +24,7 @@
|
||||||
(if (supported-collectible-types collectible-type)
|
(if (supported-collectible-types collectible-type)
|
||||||
true
|
true
|
||||||
(do
|
(do
|
||||||
(println "unsupoorted collectible file type" collectible-type)
|
(log/debug "unsupported collectible file type:" (or collectible-type "Unknown type"))
|
||||||
false)))
|
false)))
|
||||||
|
|
||||||
(defn total-owned-collectible
|
(defn total-owned-collectible
|
||||||
|
|
|
@ -4,3 +4,7 @@
|
||||||
(def list-container-style
|
(def list-container-style
|
||||||
{:margin-horizontal 12
|
{:margin-horizontal 12
|
||||||
:padding-bottom constants/floating-shell-button-height})
|
:padding-bottom constants/floating-shell-button-height})
|
||||||
|
|
||||||
|
(def collectible-container
|
||||||
|
{:padding 8
|
||||||
|
:flex 0.5})
|
||||||
|
|
|
@ -9,10 +9,14 @@
|
||||||
[status-im.contexts.wallet.common.empty-tab.view :as empty-tab]
|
[status-im.contexts.wallet.common.empty-tab.view :as empty-tab]
|
||||||
[utils.i18n :as i18n]))
|
[utils.i18n :as i18n]))
|
||||||
|
|
||||||
(defn- render-fn
|
(defn- collectible-item
|
||||||
[{:keys [preview-url collection-data ownership collectible-data] :as collectible} index address
|
[{:keys [preview-url collection-data collectible-data total-owned on-press on-long-press]
|
||||||
on-press on-long-press]
|
:as collectible}
|
||||||
(let [total-owned (utils/total-owned-collectible ownership address)]
|
index]
|
||||||
|
(let [on-press-fn (rn/use-callback #(when on-press
|
||||||
|
(on-press collectible)))
|
||||||
|
on-long-press-fn (rn/use-callback #(when on-long-press
|
||||||
|
(on-long-press collectible)))]
|
||||||
[quo/collectible-list-item
|
[quo/collectible-list-item
|
||||||
{:type :card
|
{:type :card
|
||||||
:image-src (:uri preview-url)
|
:image-src (:uri preview-url)
|
||||||
|
@ -21,18 +25,15 @@
|
||||||
:supported-file? (utils/supported-file? (:animation-media-type collectible-data))
|
:supported-file? (utils/supported-file? (:animation-media-type collectible-data))
|
||||||
:gradient-color-index (keyword (str "gradient-" (inc (mod index 5))))
|
:gradient-color-index (keyword (str "gradient-" (inc (mod index 5))))
|
||||||
:counter (utils/collectible-owned-counter total-owned)
|
:counter (utils/collectible-owned-counter total-owned)
|
||||||
:container-style {:padding 8
|
:container-style style/collectible-container
|
||||||
:width "50%"}
|
:on-press on-press-fn
|
||||||
:on-press #(when on-press
|
:on-long-press on-long-press-fn}]))
|
||||||
(on-press collectible))
|
|
||||||
:on-long-press #(when on-long-press
|
|
||||||
(on-long-press collectible))}]))
|
|
||||||
|
|
||||||
(defn view
|
(defn view
|
||||||
[{:keys [collectibles filtered? on-collectible-press on-end-reached current-account-address
|
[{:keys [collectibles filtered? on-end-reached
|
||||||
on-collectible-long-press]}]
|
on-collectible-press current-account-address on-collectible-long-press]}]
|
||||||
(let [no-results-match-query? (and filtered? (empty? collectibles))
|
(let [theme (quo.theme/use-theme)
|
||||||
theme (quo.theme/use-theme)]
|
no-results-match-query? (and filtered? (empty? collectibles))]
|
||||||
(cond
|
(cond
|
||||||
no-results-match-query?
|
no-results-match-query?
|
||||||
[rn/view {:style {:flex 1 :justify-content :center}}
|
[rn/view {:style {:flex 1 :justify-content :center}}
|
||||||
|
@ -48,17 +49,25 @@
|
||||||
:image (resources/get-themed-image :no-collectibles theme)}]
|
:image (resources/get-themed-image :no-collectibles theme)}]
|
||||||
|
|
||||||
:else
|
:else
|
||||||
[rn/flat-list
|
;; TODO: https://github.com/status-im/status-mobile/issues/20137
|
||||||
{:data collectibles
|
;; 1. If possible, move `collectibles-data` calculation to a subscription
|
||||||
:style {:flex 1}
|
;; 2. Optimization: do not recalculate all the collectibles, process only the new ones
|
||||||
:content-container-style style/list-container-style
|
(let [collectibles-data (map-indexed (fn [index {:keys [ownership] :as collectible}]
|
||||||
:window-size 11
|
(assoc collectible
|
||||||
:num-columns 2
|
:total-owned (utils/total-owned-collectible
|
||||||
:render-fn (fn [item index]
|
ownership
|
||||||
(render-fn item
|
current-account-address)
|
||||||
index
|
:on-long-press on-collectible-long-press
|
||||||
current-account-address
|
:on-press on-collectible-press
|
||||||
on-collectible-press
|
:collectible-index index))
|
||||||
on-collectible-long-press))
|
collectibles)]
|
||||||
:on-end-reached on-end-reached
|
[rn/flat-list
|
||||||
:on-end-reached-threshold 4}])))
|
{:data collectibles-data
|
||||||
|
:style {:flex 1}
|
||||||
|
:content-container-style style/list-container-style
|
||||||
|
:window-size 11
|
||||||
|
:num-columns 2
|
||||||
|
:render-fn collectible-item
|
||||||
|
:on-end-reached on-end-reached
|
||||||
|
:key-fn :collectible-index
|
||||||
|
:on-end-reached-threshold 4}]))))
|
||||||
|
|
|
@ -8,6 +8,22 @@
|
||||||
[status-im.contexts.wallet.home.tabs.style :as style]
|
[status-im.contexts.wallet.home.tabs.style :as style]
|
||||||
[utils.re-frame :as rf]))
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
|
(defn- on-collectible-long-press
|
||||||
|
[{:keys [preview-url collectible-details id]}]
|
||||||
|
(let [chain-id (get-in id [:contract-id :chain-id])
|
||||||
|
address (get-in id [:contract-id :address])]
|
||||||
|
(rf/dispatch [:show-bottom-sheet
|
||||||
|
{:content (fn []
|
||||||
|
[options-drawer/view
|
||||||
|
{:chain-id chain-id
|
||||||
|
:address address
|
||||||
|
:name (:name collectible-details)
|
||||||
|
:image (:uri preview-url)}])}])))
|
||||||
|
|
||||||
|
(defn- on-collectible-press
|
||||||
|
[{:keys [id]}]
|
||||||
|
(rf/dispatch [:wallet/get-collectible-details id]))
|
||||||
|
|
||||||
(defn view
|
(defn view
|
||||||
[{:keys [selected-tab]}]
|
[{:keys [selected-tab]}]
|
||||||
(let [collectible-list (rf/sub [:wallet/all-collectibles-list-in-selected-networks])
|
(let [collectible-list (rf/sub [:wallet/all-collectibles-list-in-selected-networks])
|
||||||
|
@ -18,20 +34,7 @@
|
||||||
:assets [assets/view]
|
:assets [assets/view]
|
||||||
:collectibles [collectibles/view
|
:collectibles [collectibles/view
|
||||||
{:collectibles collectible-list
|
{:collectibles collectible-list
|
||||||
:on-collectible-long-press (fn [{:keys [preview-url collectible-details id]}]
|
:on-collectible-long-press on-collectible-long-press
|
||||||
(let [chain-id (get-in id [:contract-id :chain-id])
|
|
||||||
address (get-in id [:contract-id :address])]
|
|
||||||
(rf/dispatch
|
|
||||||
[:show-bottom-sheet
|
|
||||||
{:content (fn []
|
|
||||||
[options-drawer/view
|
|
||||||
{:chain-id chain-id
|
|
||||||
:address address
|
|
||||||
:name (:name
|
|
||||||
collectible-details)
|
|
||||||
:image (:uri
|
|
||||||
preview-url)}])}])))
|
|
||||||
:on-end-reached request-collectibles
|
:on-end-reached request-collectibles
|
||||||
:on-collectible-press (fn [{:keys [id]}]
|
:on-collectible-press on-collectible-press}]
|
||||||
(rf/dispatch [:wallet/get-collectible-details id]))}]
|
|
||||||
[activity/view {:activities []}])]))
|
[activity/view {:activities []}])]))
|
||||||
|
|
Loading…
Reference in New Issue