[18942] Slideshow: slider-bar component (#20615)

This commit is contained in:
Nikolay 2024-07-16 13:42:38 +03:00 committed by GitHub
parent 940edc2e53
commit bd9e440839
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 281 additions and 30 deletions

View File

@ -0,0 +1,25 @@
(ns quo.components.slideshow.slider-bar.component-spec
(:require
[quo.components.slideshow.slider-bar.view :as slider-bar]
[test-helpers.component :as h]))
(h/describe "Slideshow: slider-bar"
(h/test "default render"
(h/render-with-theme-provider [slider-bar/view {:accessibility-label :slider-bar}])
(h/is-truthy (h/query-by-label-text :slider-bar)))
(h/test "render with total-amount and active-index"
(h/render-with-theme-provider [slider-bar/view
{:total-amount 4
:active-index 1
:accessibility-label :slider-bar}])
(h/is-truthy (h/query-by-label-text :slider-bar))
(h/is-equal 4 (count (h/query-all-by-label-text :slide-bar-item))))
(h/test "render with total-amount active-index and possible scroll"
(h/render-with-theme-provider [slider-bar/view
{:total-amount 10
:active-index 7
:accessibility-label :slider-bar}])
(h/is-truthy (h/query-by-label-text :slider-bar))
(h/is-equal 10 (count (h/query-all-by-label-text :slide-bar-item)))))

View File

@ -0,0 +1,14 @@
(ns quo.components.slideshow.slider-bar.schema)
(def ?schema
[:=>
[:cat
[:map {:closed true}
[:total-amount {:optional true} [:maybe :int]]
[:active-index {:optional true} :int]
[:customization-color {:optional true}
[:maybe :schema.common/customization-color]]
[:blur? {:optional true} [:maybe :boolean]]
[:accessibility-label {:optional true} [:maybe :keyword]]
[:container-style {:optional true} [:maybe :map]]]]
:any])

View File

@ -0,0 +1,31 @@
(ns quo.components.slideshow.slider-bar.style
(:require
[quo.foundations.colors :as colors]))
(def list-wrapper
{:align-items :center})
(defn list-bar
[bar-width]
{:width bar-width})
(defn item-wrapper
[{:keys [size spacing]}]
{:width size
:height size
:margin-left spacing
:flex 1
:align-items :center
:justify-content :center})
(defn item
[{:keys [size spacing active? customization-color theme blur?]}]
{:width size
:height size
:border-radius spacing
:background-color
(cond
(and blur? active?) colors/white
(and blur? (not active?)) colors/white-opa-10
(and (not blur?) active?) (colors/resolve-color customization-color theme)
:else (colors/theme-colors colors/neutral-20 colors/neutral-80 theme))})

View File

@ -0,0 +1,150 @@
(ns quo.components.slideshow.slider-bar.view
(:require
[quo.components.slideshow.slider-bar.schema :as component-schema]
[quo.components.slideshow.slider-bar.style :as style]
[quo.theme]
[react-native.core :as rn]
[react-native.reanimated :as reanimated]
[schema.core :as schema]))
(def item-size 8)
(def item-spacing item-size)
(def max-length 6)
(def bar-width (* (+ item-spacing item-size) max-length))
(def micro-scale 0.25)
(def small-scale 0.5)
(def medium-scale 0.75)
(def default-scale 1)
(def items-before-scroll
(/ max-length 2))
(defn- calc-relative-index
"Calculates item index in visible area"
[index active-index total-length]
(let [last-index (dec total-length)]
(cond
(< active-index items-before-scroll) index
(> active-index
(- last-index items-before-scroll)) (+ (- index total-length) max-length)
:else (+ (- index active-index) items-before-scroll))))
(defn- calc-first-item-scale
"Calculates scale for first item in visible area"
[active-index]
(cond
(= active-index items-before-scroll) medium-scale
(> active-index items-before-scroll) small-scale
:else default-scale))
(defn- calc-second-item-scale
"Calculates scale for second item in visible area"
[active-index]
(if (> active-index items-before-scroll)
medium-scale
default-scale))
(defn- calc-last-item-scale
"Calculates scale for last item in visible area"
[active-index total-length]
(let [last-index (dec total-length)]
(if (> active-index (- last-index items-before-scroll))
medium-scale
small-scale)))
(defn- calc-last-but-one-item-scale
"Calculates scale for before last item in visible area"
[active-index total-length]
(if (> active-index (- (dec total-length) items-before-scroll))
default-scale
medium-scale))
(defn- get-scale
[index active-index total-length]
(let [relative-index (calc-relative-index index active-index total-length)]
(if (or (= index active-index)
(< total-length max-length))
default-scale
(cond
(< relative-index 0) micro-scale
(= relative-index 0) (calc-first-item-scale active-index)
(= relative-index 1) (calc-second-item-scale active-index)
(= relative-index 4) (calc-last-but-one-item-scale active-index total-length)
(= relative-index 5) (calc-last-item-scale active-index total-length)
(> relative-index 5) micro-scale
:else
default-scale))))
(defn- bar-item
[index _ _ {:keys [active-index total-length customization-color theme blur?]}]
(let [active? (= index active-index)
shared-scale (reanimated/use-shared-value (get-scale index active-index total-length))]
(rn/use-effect (fn []
(let [new-scale-value (get-scale index active-index total-length)]
(reanimated/animate shared-scale new-scale-value)))
[index active-index total-length])
[rn/view
{:key index
:style (style/item-wrapper {:size item-size
:spacing item-spacing})}
[reanimated/view
{:accessibility-label :slide-bar-item
:style
(reanimated/apply-animations-to-style
{:transform [{:scale shared-scale}]}
(style/item {:size item-size
:spacing item-spacing
:active? active?
:customization-color customization-color
:theme theme
:blur? blur?}))}]]))
(defn- get-item-layout
[_ index]
(let [length (+ item-size item-spacing)]
#js {:length length
:index index
:offset (* index length)}))
(defn- view-internal
[{:keys [customization-color blur? accessibility-label container-style]
:as props}]
(let [active-index (or (:active-index props) 0)
total-amount (or (:total-amount props) 1)
theme (quo.theme/use-theme)
flat-list-ref (rn/use-ref-atom nil)
set-flat-list-ref (rn/use-callback #(reset! flat-list-ref %))
center-position 0.5
data (range total-amount)
scroll-to-index (rn/use-callback
(fn []
(some-> ^js @flat-list-ref
(.scrollToIndex #js {:animated true
:index active-index
:viewOffset item-spacing
:viewPosition center-position})))
[flat-list-ref active-index])]
(rn/use-effect scroll-to-index [active-index])
[rn/view
{:style (merge style/list-wrapper container-style)
:accessibility-label accessibility-label}
[reanimated/flat-list
{:style (style/list-bar bar-width)
:data data
:scroll-enabled false
:ref set-flat-list-ref
:shows-horizontal-scroll-indicator false
:bounces false
:horizontal true
:extra-data (str active-index)
:render-data {:active-index active-index
:total-length total-amount
:customization-color customization-color
:theme theme
:blur? blur?}
:get-item-layout get-item-layout
:render-fn bar-item
:key-fn identity}]]))
(def view (schema/instrument #'view-internal component-schema/?schema))

View File

@ -147,6 +147,7 @@
quo.components.settings.settings-item.view quo.components.settings.settings-item.view
quo.components.share.qr-code.view quo.components.share.qr-code.view
quo.components.share.share-qr-code.view quo.components.share.share-qr-code.view
quo.components.slideshow.slider-bar.view
quo.components.switchers.group-messaging-card.view quo.components.switchers.group-messaging-card.view
quo.components.tabs.account-selector quo.components.tabs.account-selector
quo.components.tabs.segmented-tab quo.components.tabs.segmented-tab
@ -418,6 +419,9 @@
(def qr-code quo.components.share.qr-code.view/view) (def qr-code quo.components.share.qr-code.view/view)
(def share-qr-code quo.components.share.share-qr-code.view/view) (def share-qr-code quo.components.share.share-qr-code.view/view)
;;;; Slideshow
(def slider-bar quo.components.slideshow.slider-bar.view/view)
;;;; SWITCHER ;;;; SWITCHER
(def group-messaging-card quo.components.switchers.group-messaging-card.view/view) (def group-messaging-card quo.components.switchers.group-messaging-card.view/view)

View File

@ -87,6 +87,7 @@
quo.components.settings.reorder-item.component-spec quo.components.settings.reorder-item.component-spec
quo.components.settings.settings-item.component-spec quo.components.settings.settings-item.component-spec
quo.components.share.share-qr-code.component-spec quo.components.share.share-qr-code.component-spec
quo.components.slideshow.slider-bar.component-spec
quo.components.switchers.base-card.component-spec quo.components.switchers.base-card.component-spec
quo.components.switchers.group-messaging-card.component-spec quo.components.switchers.group-messaging-card.component-spec
quo.components.tags.collectible-tag.component-spec quo.components.tags.collectible-tag.component-spec

View File

@ -170,6 +170,7 @@
[status-im.contexts.preview.quo.settings.settings-item :as settings-item] [status-im.contexts.preview.quo.settings.settings-item :as settings-item]
[status-im.contexts.preview.quo.share.qr-code :as qr-code] [status-im.contexts.preview.quo.share.qr-code :as qr-code]
[status-im.contexts.preview.quo.share.share-qr-code :as share-qr-code] [status-im.contexts.preview.quo.share.share-qr-code :as share-qr-code]
[status-im.contexts.preview.quo.slideshow.slider-bar :as slider-bar]
[status-im.contexts.preview.quo.style :as style] [status-im.contexts.preview.quo.style :as style]
[status-im.contexts.preview.quo.switcher.group-messaging-card :as [status-im.contexts.preview.quo.switcher.group-messaging-card :as
group-messaging-card] group-messaging-card]
@ -502,6 +503,8 @@
:component qr-code/view} :component qr-code/view}
{:name :share-qr-code {:name :share-qr-code
:component share-qr-code/view}] :component share-qr-code/view}]
:slideshow [{:name :slider-bar
:component slider-bar/view}]
:switchers [{:name :group-messaging-card :switchers [{:name :group-messaging-card
:component group-messaging-card/view} :component group-messaging-card/view}
{:name :switcher-cards {:name :switcher-cards

View File

@ -0,0 +1,49 @@
(ns status-im.contexts.preview.quo.slideshow.slider-bar
(:require
[quo.core :as quo]
[react-native.core :as rn]
[status-im.contexts.preview.quo.preview :as preview]))
(def descriptor
[{:key :total-amount
:type :number}
{:label "Blur (dark only)?"
:key :blur?
:type :boolean}
(preview/customization-color-option)])
(defn view
[]
(let [[state set-state] (rn/use-state {:total-amount 10
:active-index 0
:blur? false
:customization-color :blue})]
[preview/preview-container
{:state state
:set-state set-state
:descriptor descriptor
:blur? (:blur? state)
:show-blur-background? true
:blur-dark-only? true}
[rn/view
{:style {:flex-direction :row
:justify-content :center
:gap 10
:padding 10}}
[quo/button
{:type :outline
:style {:disabled true}
:disabled? (zero? (:active-index state))
:icon-only? true
:on-press (fn []
(set-state (update state :active-index dec)))}
:i/chevron-left]
[quo/button
{:type :outline
:disabled? (= (:active-index state)
(dec (:total-amount state)))
:icon-only? true
:on-press (fn []
(set-state (update state :active-index inc)))}
:i/chevron-right]]
[quo/slider-bar state]]))

View File

@ -1,18 +0,0 @@
(ns status-im.contexts.shell.share.wallet.style
(:require
[quo.foundations.colors :as colors]))
(defn indicator-wrapper-style
[active?]
{:width 8
:height 8
:border-radius 4
:background-color colors/white
:opacity (if active? 1.0 0.5)})
(def indicator-list-style
{:display :flex
:flex-direction :row
:align-items :center
:justify-content :center
:gap 8})

View File

@ -6,7 +6,6 @@
[react-native.platform :as platform] [react-native.platform :as platform]
[reagent.core :as reagent] [reagent.core :as reagent]
[status-im.contexts.shell.share.style :as style] [status-im.contexts.shell.share.style :as style]
[status-im.contexts.shell.share.wallet.style :as wallet-style]
[status-im.contexts.wallet.common.utils :as utils] [status-im.contexts.wallet.common.utils :as utils]
[status-im.contexts.wallet.common.utils.networks :as network-utils] [status-im.contexts.wallet.common.utils.networks :as network-utils]
[status-im.contexts.wallet.sheets.network-preferences.view :as network-preferences] [status-im.contexts.wallet.sheets.network-preferences.view :as network-preferences]
@ -85,16 +84,6 @@
:on-legacy-press on-legacy-press :on-legacy-press on-legacy-press
:on-settings-press on-settings-press}]]])))) :on-settings-press on-settings-press}]]]))))
(defn- indicator
[active?]
[rn/view {:style (wallet-style/indicator-wrapper-style active?)}])
(defn- indicator-list
[num-indicators current-index]
[rn/view {:style wallet-style/indicator-list-style}
(for [i (range num-indicators)]
^{:key i} [indicator (= current-index i)])])
(defn render-item (defn render-item
[{:keys [address] :as account}] [{:keys [address] :as account}]
[wallet-qr-code-item [wallet-qr-code-item
@ -136,4 +125,7 @@
:render-fn render-item}] :render-fn render-item}]
(when (> num-accounts 1) (when (> num-accounts 1)
[rn/view {:style {:margin-top 20}} [rn/view {:style {:margin-top 20}}
[indicator-list num-accounts @current-index]])])))) [quo/slider-bar
{:total-amount num-accounts
:active-index @current-index
:blur? true}]])]))))