mirror of
https://github.com/status-im/status-react.git
synced 2025-02-24 08:38:28 +00:00
feat: collectibles details loading (#20400)
This commit is contained in:
parent
b28a8e153e
commit
b17f2892c7
@ -34,6 +34,12 @@
|
||||
(set-state (fn [prev-state]
|
||||
(assoc prev-state :image-loaded? true)))))
|
||||
|
||||
(defn on-load
|
||||
[evt set-state]
|
||||
(let [source (.. evt -nativeEvent -source)
|
||||
aspect-ratio (/ (.-width source) (.-height source))]
|
||||
(set-state (fn [prev-state] (assoc prev-state :image-aspect-ratio aspect-ratio)))))
|
||||
|
||||
(defn on-load-error
|
||||
[set-state]
|
||||
(js/setTimeout (fn []
|
||||
@ -147,6 +153,7 @@
|
||||
[reanimated/view {:style (style/supported-file image-opacity)}
|
||||
[rn/image
|
||||
{:style style/image
|
||||
:on-load #(on-load % set-state)
|
||||
:on-load-start #(set-load-time (fn [start-time] (- (datetime/now) start-time)))
|
||||
:on-load-end #(on-load-end {:load-time load-time
|
||||
:set-state set-state
|
||||
@ -197,6 +204,7 @@
|
||||
[reanimated/view {:style (style/supported-file image-opacity)}
|
||||
[rn/image
|
||||
{:style style/image
|
||||
:on-load #(on-load % set-state)
|
||||
:on-load-start #(set-load-time (fn [start-time] (- (datetime/now) start-time)))
|
||||
:on-load-end #(on-load-end {:load-time load-time
|
||||
:set-state set-state
|
||||
@ -219,12 +227,13 @@
|
||||
(defn- view-internal
|
||||
[{:keys [container-style type on-press on-long-press supported-file?]
|
||||
:as props}]
|
||||
(let [[state set-state] (rn/use-state {:image-loaded? false
|
||||
:image-error? false
|
||||
:avatar-loaded? false})
|
||||
(let [[state set-state] (rn/use-state {:image-loaded? false
|
||||
:image-aspect-ratio nil
|
||||
:image-error? false
|
||||
:avatar-loaded? false})
|
||||
collectible-ready? (or (:image-loaded? state) (not supported-file?))]
|
||||
[rn/pressable
|
||||
{:on-press (when collectible-ready? on-press)
|
||||
{:on-press (when collectible-ready? #(on-press (:image-aspect-ratio state)))
|
||||
:on-long-press (when collectible-ready? on-long-press)
|
||||
:accessibility-label :collectible-list-item
|
||||
:style container-style}
|
||||
|
@ -1,10 +1,13 @@
|
||||
(ns quo.components.profile.expanded-collectible.style
|
||||
(:require [quo.foundations.colors :as colors]))
|
||||
|
||||
(def container
|
||||
{:align-items :center
|
||||
:justify-content :center
|
||||
:border-radius 16})
|
||||
(defn container
|
||||
[aspect-ratio]
|
||||
(cond-> {:align-items :center
|
||||
:justify-content :center
|
||||
:border-radius 16}
|
||||
aspect-ratio (assoc :width "100%"
|
||||
:aspect-ratio aspect-ratio)))
|
||||
|
||||
(defn image
|
||||
[square? aspect-ratio theme]
|
||||
@ -25,18 +28,43 @@
|
||||
:border-color (colors/theme-colors colors/neutral-80-opa-5 colors/white-opa-5 theme)})
|
||||
|
||||
(defn fallback
|
||||
[{:keys [theme]}]
|
||||
{:background-color (colors/theme-colors colors/neutral-2_5 colors/neutral-90 theme)
|
||||
:border-style :dashed
|
||||
:border-color (colors/theme-colors colors/neutral-20 colors/neutral-80 theme)
|
||||
:border-width 1
|
||||
:border-radius 16
|
||||
:width "100%"
|
||||
:aspect-ratio 1
|
||||
:align-items :center
|
||||
:justify-content :center})
|
||||
([theme]
|
||||
(fallback theme 1))
|
||||
([theme aspect-ratio]
|
||||
{:background-color (colors/theme-colors colors/neutral-2_5 colors/neutral-90 theme)
|
||||
:border-style :dashed
|
||||
:border-color (colors/theme-colors colors/neutral-20 colors/neutral-80 theme)
|
||||
:border-width 1
|
||||
:border-radius 16
|
||||
:width "100%"
|
||||
:aspect-ratio aspect-ratio
|
||||
:align-items :center
|
||||
:justify-content :center}))
|
||||
|
||||
(def counter
|
||||
{:position :absolute
|
||||
:top 12
|
||||
:right 12})
|
||||
|
||||
(defn loading-image-with-opacity
|
||||
[opacity]
|
||||
[{:align-items :center
|
||||
:aspect-ratio 1
|
||||
:border-radius 16
|
||||
:justify-content :center
|
||||
:opacity opacity
|
||||
:position :absolute
|
||||
:width "100%"
|
||||
:z-index 1}])
|
||||
|
||||
(defn gradient-view
|
||||
[aspect-ratio]
|
||||
{:border-radius 16
|
||||
:width "100%"
|
||||
:aspect-ratio aspect-ratio
|
||||
:align-items :center
|
||||
:justify-content :center})
|
||||
|
||||
(defn supported-file
|
||||
[opacity]
|
||||
{:opacity opacity})
|
||||
|
@ -1,17 +1,53 @@
|
||||
(ns quo.components.profile.expanded-collectible.view
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[promesa.core :as promesa]
|
||||
[quo.components.counter.collectible-counter.view :as collectible-counter]
|
||||
[quo.components.icon :as icon]
|
||||
[quo.components.markdown.text :as text]
|
||||
[quo.components.profile.expanded-collectible.style :as style]
|
||||
[quo.foundations.colors :as colors]
|
||||
[quo.foundations.gradients :as gradients]
|
||||
[quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[schema.core :as schema]
|
||||
[utils.datetime :as datetime]
|
||||
[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- loading-image
|
||||
[{:keys [theme gradient-color-index loader-opacity aspect-ratio]}]
|
||||
[reanimated/view
|
||||
{:style (style/loading-image-with-opacity loader-opacity)}
|
||||
[gradients/view
|
||||
{:theme theme
|
||||
:container-style (style/gradient-view aspect-ratio)
|
||||
:color-index gradient-color-index}]])
|
||||
|
||||
(defn- counter-view
|
||||
[counter]
|
||||
[collectible-counter/view
|
||||
@ -21,7 +57,7 @@
|
||||
(defn- fallback-view
|
||||
[{:keys [label theme counter on-mount]}]
|
||||
(rn/use-mount on-mount)
|
||||
[rn/view {:style (style/fallback {:theme theme})}
|
||||
[rn/view {:style (style/fallback theme)}
|
||||
[counter-view counter]
|
||||
[rn/view
|
||||
[icon/icon :i/sad {:color (colors/theme-colors colors/neutral-40 colors/neutral-50 theme)}]]
|
||||
@ -33,45 +69,57 @@
|
||||
|
||||
(defn view-internal
|
||||
[{:keys [container-style square? on-press counter image-src native-ID supported-file?
|
||||
on-collectible-load]}]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
[image-size set-image-size] (rn/use-state {})
|
||||
[image-error? set-image-error] (rn/use-state (or (nil? image-src)
|
||||
(string/blank? image-src)))]
|
||||
(rn/use-effect
|
||||
(fn []
|
||||
(promesa/let [[image-width image-height] (rn/image-get-size image-src)]
|
||||
(set-image-size {:width image-width
|
||||
:height image-height
|
||||
:aspect-ratio (/ image-width image-height)})))
|
||||
[image-src])
|
||||
on-collectible-load aspect-ratio]}]
|
||||
(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))
|
||||
[state set-state] (rn/use-state {:image-loaded? false
|
||||
:image-error? (or (nil? image-src)
|
||||
(string/blank?
|
||||
image-src))})]
|
||||
[rn/pressable
|
||||
{:on-press (when (and (not image-error?) supported-file?) on-press)
|
||||
{:on-press (when (and (not (:image-error? state)) supported-file?) on-press)
|
||||
:accessibility-label :expanded-collectible
|
||||
:style (merge container-style style/container)}
|
||||
:style (merge container-style
|
||||
(style/container aspect-ratio))}
|
||||
(cond
|
||||
(not supported-file?)
|
||||
[fallback-view
|
||||
{:label (i18n/label :t/unsupported-file)
|
||||
:counter counter
|
||||
:theme theme
|
||||
:on-mount on-collectible-load}]
|
||||
{:aspect-ratio aspect-ratio
|
||||
:label (i18n/label :t/unsupported-file)
|
||||
:counter counter
|
||||
:theme theme
|
||||
:on-mount on-collectible-load}]
|
||||
|
||||
image-error?
|
||||
(:image-error? state)
|
||||
[fallback-view
|
||||
{:label (i18n/label :t/cant-fetch-info)
|
||||
:counter counter
|
||||
:theme theme
|
||||
:on-mount on-collectible-load}]
|
||||
|
||||
:else
|
||||
[rn/view
|
||||
(not (:image-loaded? state))
|
||||
[loading-image
|
||||
{:aspect-ratio aspect-ratio
|
||||
:loader-opacity loader-opacity
|
||||
:theme theme
|
||||
:gradient-color-index :gradient-5}])
|
||||
(when supported-file?
|
||||
[reanimated/view {:style (style/supported-file image-opacity)}
|
||||
[rn/image
|
||||
{:style (style/image square? (:aspect-ratio image-size) theme)
|
||||
:source image-src
|
||||
:native-ID native-ID
|
||||
:on-error #(set-image-error true)
|
||||
:on-load on-collectible-load}]
|
||||
{:style (style/image square? aspect-ratio theme)
|
||||
:source image-src
|
||||
:native-ID native-ID
|
||||
:on-load-start #(set-load-time (fn [start-time] (- (datetime/now) start-time)))
|
||||
:on-load-end #(on-load-end {:load-time load-time
|
||||
:set-state set-state
|
||||
:loader-opacity loader-opacity
|
||||
:image-opacity image-opacity})
|
||||
:on-error #(on-load-error set-state)
|
||||
:on-load on-collectible-load}]
|
||||
(when counter
|
||||
[counter-view counter])
|
||||
[rn/view {:style (style/collectible-border theme)}]])]))
|
||||
@ -81,6 +129,7 @@
|
||||
[:catn
|
||||
[:props
|
||||
[:map {:closed true}
|
||||
[:aspect-ratio {:optional true} [:maybe number?]]
|
||||
[:image-src {:optional true} [:maybe string?]]
|
||||
[:supported-file? {:optional true} [:maybe boolean?]]
|
||||
[:container-style {:optional true} [:maybe :map]]
|
||||
|
@ -12,8 +12,8 @@
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- on-collectible-press
|
||||
[{:keys [id]}]
|
||||
(rf/dispatch [:wallet/get-collectible-details id]))
|
||||
[{:keys [id]} aspect-ratio]
|
||||
(rf/dispatch [:wallet/get-collectible-details id aspect-ratio]))
|
||||
|
||||
(defn- on-collectible-long-press
|
||||
[{:keys [preview-url collectible-details id]}]
|
||||
|
@ -167,12 +167,13 @@
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet/get-collectible-details
|
||||
(fn [_ [collectible-id]]
|
||||
(fn [{:keys [db]} [collectible-id aspect-ratio]]
|
||||
(let [request-id 0
|
||||
collectible-id-converted (cske/transform-keys transforms/->PascalCaseKeyword collectible-id)
|
||||
data-type (collectible-data-types :details)
|
||||
request-params [request-id [collectible-id-converted] data-type]]
|
||||
{:fx [[:json-rpc/call
|
||||
{:db (assoc-in db [:wallet :last-collectible-aspect-ratio] aspect-ratio)
|
||||
:fx [[:json-rpc/call
|
||||
[{:method "wallet_getCollectiblesByUniqueIDAsync"
|
||||
:params request-params
|
||||
:on-error (fn [error]
|
||||
@ -197,7 +198,7 @@
|
||||
(rf/reg-event-fx
|
||||
:wallet/clear-last-collectible-details
|
||||
(fn [{:keys [db]}]
|
||||
{:db (update-in db [:wallet] dissoc :last-collectible-details)}))
|
||||
{:db (update-in db [:wallet] dissoc :last-collectible-details :last-collectible-aspect-ratio)}))
|
||||
|
||||
(rf/reg-event-fx :wallet/trigger-share-collectible
|
||||
(fn [_ [{:keys [title uri]}]]
|
||||
|
@ -12,8 +12,8 @@
|
||||
|
||||
(defn preview-container
|
||||
[]
|
||||
{:margin-horizontal 8
|
||||
:margin-top (+ (header-height) 12)})
|
||||
{:padding-horizontal 8
|
||||
:margin-top (+ (header-height) 12)})
|
||||
|
||||
(def header
|
||||
{:margin-horizontal 20
|
||||
|
@ -150,6 +150,7 @@
|
||||
set-title-ref (rn/use-callback #(reset! title-ref %))
|
||||
animation-shared-element-id (rf/sub [:animation-shared-element-id])
|
||||
collectible-owner (rf/sub [:wallet/last-collectible-details-owner])
|
||||
aspect-ratio (rf/sub [:wallet/last-collectible-aspect-ratio])
|
||||
{:keys [id
|
||||
preview-url
|
||||
collection-data
|
||||
@ -180,7 +181,8 @@
|
||||
[rn/view
|
||||
[gradient-layer preview-uri]
|
||||
[quo/expanded-collectible
|
||||
{:image-src preview-uri
|
||||
{:aspect-ratio aspect-ratio
|
||||
:image-src preview-uri
|
||||
:container-style (style/preview-container)
|
||||
:counter (utils/collectible-owned-counter total-owned)
|
||||
:native-ID (when (= animation-shared-element-id token-id) :shared-element)
|
||||
|
@ -14,7 +14,7 @@
|
||||
:as collectible}
|
||||
index]
|
||||
(let [on-press-fn (rn/use-callback #(when on-press
|
||||
(on-press collectible)))
|
||||
(on-press collectible %)))
|
||||
on-long-press-fn (rn/use-callback #(when on-long-press
|
||||
(on-long-press collectible)))]
|
||||
[quo/collectible-list-item
|
||||
|
@ -18,8 +18,8 @@
|
||||
:image (:uri preview-url)}])}]))
|
||||
|
||||
(defn- on-collectible-press
|
||||
[{:keys [id]}]
|
||||
(rf/dispatch [:wallet/get-collectible-details id]))
|
||||
[{:keys [id]} aspect-ratio]
|
||||
(rf/dispatch [:wallet/get-collectible-details id aspect-ratio]))
|
||||
|
||||
(defn view
|
||||
[{:keys [selected-tab]}]
|
||||
|
@ -97,6 +97,12 @@
|
||||
(let [last-collectible (:last-collectible-details wallet)]
|
||||
(assoc last-collectible :preview-url (preview-url last-collectible)))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet/last-collectible-aspect-ratio
|
||||
:<- [:wallet]
|
||||
(fn [wallet]
|
||||
(:last-collectible-aspect-ratio wallet)))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:wallet/last-collectible-details-chain-id
|
||||
:<- [:wallet/last-collectible-details]
|
||||
|
Loading…
x
Reference in New Issue
Block a user