[18942] Slideshow: slider-bar component (#20615)
This commit is contained in:
parent
940edc2e53
commit
bd9e440839
|
@ -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)))))
|
|
@ -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])
|
|
@ -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))})
|
|
@ -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))
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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]]))
|
|
@ -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})
|
|
|
@ -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}]])]))))
|
||||||
|
|
Loading…
Reference in New Issue