feat: collectibles details loading (#20400)

This commit is contained in:
BalogunofAfrica 2024-07-03 15:49:12 +01:00 committed by GitHub
parent b28a8e153e
commit b17f2892c7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 152 additions and 57 deletions

View File

@ -34,6 +34,12 @@
(set-state (fn [prev-state] (set-state (fn [prev-state]
(assoc prev-state :image-loaded? true))))) (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 (defn on-load-error
[set-state] [set-state]
(js/setTimeout (fn [] (js/setTimeout (fn []
@ -147,6 +153,7 @@
[reanimated/view {:style (style/supported-file image-opacity)} [reanimated/view {:style (style/supported-file image-opacity)}
[rn/image [rn/image
{:style style/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-start #(set-load-time (fn [start-time] (- (datetime/now) start-time)))
:on-load-end #(on-load-end {:load-time load-time :on-load-end #(on-load-end {:load-time load-time
:set-state set-state :set-state set-state
@ -197,6 +204,7 @@
[reanimated/view {:style (style/supported-file image-opacity)} [reanimated/view {:style (style/supported-file image-opacity)}
[rn/image [rn/image
{:style style/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-start #(set-load-time (fn [start-time] (- (datetime/now) start-time)))
:on-load-end #(on-load-end {:load-time load-time :on-load-end #(on-load-end {:load-time load-time
:set-state set-state :set-state set-state
@ -219,12 +227,13 @@
(defn- view-internal (defn- view-internal
[{:keys [container-style type on-press on-long-press supported-file?] [{:keys [container-style type on-press on-long-press supported-file?]
:as props}] :as props}]
(let [[state set-state] (rn/use-state {:image-loaded? false (let [[state set-state] (rn/use-state {:image-loaded? false
:image-error? false :image-aspect-ratio nil
:avatar-loaded? false}) :image-error? false
:avatar-loaded? false})
collectible-ready? (or (:image-loaded? state) (not supported-file?))] collectible-ready? (or (:image-loaded? state) (not supported-file?))]
[rn/pressable [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) :on-long-press (when collectible-ready? on-long-press)
:accessibility-label :collectible-list-item :accessibility-label :collectible-list-item
:style container-style} :style container-style}

View File

@ -1,10 +1,13 @@
(ns quo.components.profile.expanded-collectible.style (ns quo.components.profile.expanded-collectible.style
(:require [quo.foundations.colors :as colors])) (:require [quo.foundations.colors :as colors]))
(def container (defn container
{:align-items :center [aspect-ratio]
:justify-content :center (cond-> {:align-items :center
:border-radius 16}) :justify-content :center
:border-radius 16}
aspect-ratio (assoc :width "100%"
:aspect-ratio aspect-ratio)))
(defn image (defn image
[square? aspect-ratio theme] [square? aspect-ratio theme]
@ -25,18 +28,43 @@
:border-color (colors/theme-colors colors/neutral-80-opa-5 colors/white-opa-5 theme)}) :border-color (colors/theme-colors colors/neutral-80-opa-5 colors/white-opa-5 theme)})
(defn fallback (defn fallback
[{:keys [theme]}] ([theme]
{:background-color (colors/theme-colors colors/neutral-2_5 colors/neutral-90 theme) (fallback theme 1))
:border-style :dashed ([theme aspect-ratio]
: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 16 :border-color (colors/theme-colors colors/neutral-20 colors/neutral-80 theme)
:width "100%" :border-width 1
:aspect-ratio 1 :border-radius 16
:align-items :center :width "100%"
:justify-content :center}) :aspect-ratio aspect-ratio
:align-items :center
:justify-content :center}))
(def counter (def counter
{:position :absolute {:position :absolute
:top 12 :top 12
:right 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})

View File

@ -1,17 +1,53 @@
(ns quo.components.profile.expanded-collectible.view (ns quo.components.profile.expanded-collectible.view
(:require (:require
[clojure.string :as string] [clojure.string :as string]
[promesa.core :as promesa]
[quo.components.counter.collectible-counter.view :as collectible-counter] [quo.components.counter.collectible-counter.view :as collectible-counter]
[quo.components.icon :as icon] [quo.components.icon :as icon]
[quo.components.markdown.text :as text] [quo.components.markdown.text :as text]
[quo.components.profile.expanded-collectible.style :as style] [quo.components.profile.expanded-collectible.style :as style]
[quo.foundations.colors :as colors] [quo.foundations.colors :as colors]
[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- 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 (defn- counter-view
[counter] [counter]
[collectible-counter/view [collectible-counter/view
@ -21,7 +57,7 @@
(defn- fallback-view (defn- fallback-view
[{:keys [label theme counter on-mount]}] [{:keys [label theme counter on-mount]}]
(rn/use-mount on-mount) (rn/use-mount on-mount)
[rn/view {:style (style/fallback {:theme theme})} [rn/view {:style (style/fallback theme)}
[counter-view counter] [counter-view counter]
[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)}]]
@ -33,45 +69,57 @@
(defn view-internal (defn view-internal
[{:keys [container-style square? on-press counter image-src native-ID supported-file? [{:keys [container-style square? on-press counter image-src native-ID supported-file?
on-collectible-load]}] on-collectible-load aspect-ratio]}]
(let [theme (quo.theme/use-theme) (let [theme (quo.theme/use-theme)
[image-size set-image-size] (rn/use-state {}) loader-opacity (reanimated/use-shared-value
[image-error? set-image-error] (rn/use-state (or (nil? image-src) (if supported-file? 1 0))
(string/blank? image-src)))] image-opacity (reanimated/use-shared-value
(rn/use-effect (if supported-file? 0 1))
(fn [] [load-time set-load-time] (rn/use-state (datetime/now))
(promesa/let [[image-width image-height] (rn/image-get-size image-src)] [state set-state] (rn/use-state {:image-loaded? false
(set-image-size {:width image-width :image-error? (or (nil? image-src)
:height image-height (string/blank?
:aspect-ratio (/ image-width image-height)}))) image-src))})]
[image-src])
[rn/pressable [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 :accessibility-label :expanded-collectible
:style (merge container-style style/container)} :style (merge container-style
(style/container aspect-ratio))}
(cond (cond
(not supported-file?) (not supported-file?)
[fallback-view [fallback-view
{:label (i18n/label :t/unsupported-file) {:aspect-ratio aspect-ratio
:counter counter :label (i18n/label :t/unsupported-file)
:theme theme :counter counter
:on-mount on-collectible-load}] :theme theme
:on-mount on-collectible-load}]
image-error? (:image-error? state)
[fallback-view [fallback-view
{:label (i18n/label :t/cant-fetch-info) {:label (i18n/label :t/cant-fetch-info)
:counter counter :counter counter
:theme theme :theme theme
:on-mount on-collectible-load}] :on-mount on-collectible-load}]
:else (not (:image-loaded? state))
[rn/view [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 [rn/image
{:style (style/image square? (:aspect-ratio image-size) theme) {:style (style/image square? aspect-ratio theme)
:source image-src :source image-src
:native-ID native-ID :native-ID native-ID
:on-error #(set-image-error true) :on-load-start #(set-load-time (fn [start-time] (- (datetime/now) start-time)))
:on-load on-collectible-load}] :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 (when counter
[counter-view counter]) [counter-view counter])
[rn/view {:style (style/collectible-border theme)}]])])) [rn/view {:style (style/collectible-border theme)}]])]))
@ -81,6 +129,7 @@
[:catn [:catn
[:props [:props
[:map {:closed true} [:map {:closed true}
[:aspect-ratio {:optional true} [:maybe number?]]
[:image-src {:optional true} [:maybe string?]] [:image-src {:optional true} [:maybe string?]]
[:supported-file? {:optional true} [:maybe boolean?]] [:supported-file? {:optional true} [:maybe boolean?]]
[:container-style {:optional true} [:maybe :map]] [:container-style {:optional true} [:maybe :map]]

View File

@ -12,8 +12,8 @@
[utils.re-frame :as rf])) [utils.re-frame :as rf]))
(defn- on-collectible-press (defn- on-collectible-press
[{:keys [id]}] [{:keys [id]} aspect-ratio]
(rf/dispatch [:wallet/get-collectible-details id])) (rf/dispatch [:wallet/get-collectible-details id aspect-ratio]))
(defn- on-collectible-long-press (defn- on-collectible-long-press
[{:keys [preview-url collectible-details id]}] [{:keys [preview-url collectible-details id]}]

View File

@ -167,12 +167,13 @@
(rf/reg-event-fx (rf/reg-event-fx
:wallet/get-collectible-details :wallet/get-collectible-details
(fn [_ [collectible-id]] (fn [{:keys [db]} [collectible-id aspect-ratio]]
(let [request-id 0 (let [request-id 0
collectible-id-converted (cske/transform-keys transforms/->PascalCaseKeyword collectible-id) collectible-id-converted (cske/transform-keys transforms/->PascalCaseKeyword collectible-id)
data-type (collectible-data-types :details) data-type (collectible-data-types :details)
request-params [request-id [collectible-id-converted] data-type]] 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" [{:method "wallet_getCollectiblesByUniqueIDAsync"
:params request-params :params request-params
:on-error (fn [error] :on-error (fn [error]
@ -197,7 +198,7 @@
(rf/reg-event-fx (rf/reg-event-fx
:wallet/clear-last-collectible-details :wallet/clear-last-collectible-details
(fn [{:keys [db]}] (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 (rf/reg-event-fx :wallet/trigger-share-collectible
(fn [_ [{:keys [title uri]}]] (fn [_ [{:keys [title uri]}]]

View File

@ -12,8 +12,8 @@
(defn preview-container (defn preview-container
[] []
{:margin-horizontal 8 {:padding-horizontal 8
:margin-top (+ (header-height) 12)}) :margin-top (+ (header-height) 12)})
(def header (def header
{:margin-horizontal 20 {:margin-horizontal 20

View File

@ -150,6 +150,7 @@
set-title-ref (rn/use-callback #(reset! title-ref %)) set-title-ref (rn/use-callback #(reset! title-ref %))
animation-shared-element-id (rf/sub [:animation-shared-element-id]) animation-shared-element-id (rf/sub [:animation-shared-element-id])
collectible-owner (rf/sub [:wallet/last-collectible-details-owner]) collectible-owner (rf/sub [:wallet/last-collectible-details-owner])
aspect-ratio (rf/sub [:wallet/last-collectible-aspect-ratio])
{:keys [id {:keys [id
preview-url preview-url
collection-data collection-data
@ -180,7 +181,8 @@
[rn/view [rn/view
[gradient-layer preview-uri] [gradient-layer preview-uri]
[quo/expanded-collectible [quo/expanded-collectible
{:image-src preview-uri {:aspect-ratio aspect-ratio
:image-src preview-uri
:container-style (style/preview-container) :container-style (style/preview-container)
:counter (utils/collectible-owned-counter total-owned) :counter (utils/collectible-owned-counter total-owned)
:native-ID (when (= animation-shared-element-id token-id) :shared-element) :native-ID (when (= animation-shared-element-id token-id) :shared-element)

View File

@ -14,7 +14,7 @@
:as collectible} :as collectible}
index] index]
(let [on-press-fn (rn/use-callback #(when on-press (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-fn (rn/use-callback #(when on-long-press
(on-long-press collectible)))] (on-long-press collectible)))]
[quo/collectible-list-item [quo/collectible-list-item

View File

@ -18,8 +18,8 @@
:image (:uri preview-url)}])}])) :image (:uri preview-url)}])}]))
(defn- on-collectible-press (defn- on-collectible-press
[{:keys [id]}] [{:keys [id]} aspect-ratio]
(rf/dispatch [:wallet/get-collectible-details id])) (rf/dispatch [:wallet/get-collectible-details id aspect-ratio]))
(defn view (defn view
[{:keys [selected-tab]}] [{:keys [selected-tab]}]

View File

@ -97,6 +97,12 @@
(let [last-collectible (:last-collectible-details wallet)] (let [last-collectible (:last-collectible-details wallet)]
(assoc last-collectible :preview-url (preview-url last-collectible))))) (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 (re-frame/reg-sub
:wallet/last-collectible-details-chain-id :wallet/last-collectible-details-chain-id
:<- [:wallet/last-collectible-details] :<- [:wallet/last-collectible-details]