mirror of
https://github.com/status-im/status-mobile.git
synced 2025-01-13 10:16:01 +00:00
parent
a38ef22ca7
commit
fb9309f700
74
src/quo2/components/animated_header_flatlist/style.cljs
Normal file
74
src/quo2/components/animated_header_flatlist/style.cljs
Normal file
@ -0,0 +1,74 @@
|
||||
(ns quo2.components.animated-header-flatlist.style
|
||||
(:require [quo2.foundations.colors :as colors]
|
||||
[react-native.reanimated :as reanimated]))
|
||||
|
||||
(defn container-view
|
||||
[view-height]
|
||||
{:position :absolute
|
||||
:top 0
|
||||
:left 0
|
||||
:right 0
|
||||
;; height must be set, otherwise list will not scroll
|
||||
:height view-height})
|
||||
|
||||
(defn button-container
|
||||
[position]
|
||||
(merge
|
||||
{:width 32
|
||||
:height 32
|
||||
:border-radius 10
|
||||
:justify-content :center
|
||||
:align-items :center
|
||||
:background-color (colors/theme-colors colors/white-opa-40 colors/neutral-80-opa-40)
|
||||
:position :absolute
|
||||
:top 56
|
||||
:z-index 3}
|
||||
position))
|
||||
|
||||
(defn blur-view
|
||||
[animation]
|
||||
(reanimated/apply-animations-to-style
|
||||
{:opacity animation}
|
||||
{:position :absolute
|
||||
:top 0
|
||||
:left 0
|
||||
:right 0
|
||||
:height 100
|
||||
:z-index 2
|
||||
:overflow :hidden}))
|
||||
|
||||
(defn entity-picture
|
||||
[animation]
|
||||
(reanimated/apply-animations-to-style
|
||||
{:width animation
|
||||
:height animation}
|
||||
{:transform [{:scale 1}]
|
||||
:border-radius 40
|
||||
:position :absolute
|
||||
:bottom 42
|
||||
:left 20
|
||||
:justify-content :center
|
||||
:align-items :center
|
||||
:background-color (colors/theme-colors colors/white colors/neutral-100)
|
||||
:overflow :hidden}))
|
||||
|
||||
(defn header-bottom-part
|
||||
[animation]
|
||||
(reanimated/apply-animations-to-style
|
||||
{:border-top-right-radius animation
|
||||
:border-top-left-radius animation}
|
||||
{:position :absolute
|
||||
:bottom 0
|
||||
:height 86
|
||||
:left 0
|
||||
:right 0
|
||||
:background-color (colors/theme-colors colors/white colors/neutral-100)}))
|
||||
|
||||
(defn header-comp
|
||||
[y-animation opacity-animation]
|
||||
(reanimated/apply-animations-to-style
|
||||
;; here using `left` won't work on Android, so we are using `translateX`
|
||||
{:transform [{:translateX (reanimated/use-shared-value 64)} {:translateY y-animation}]
|
||||
:opacity opacity-animation}
|
||||
{:position :absolute
|
||||
:z-index 3}))
|
100
src/quo2/components/animated_header_flatlist/view.cljs
Normal file
100
src/quo2/components/animated_header_flatlist/view.cljs
Normal file
@ -0,0 +1,100 @@
|
||||
(ns quo2.components.animated-header-flatlist.view
|
||||
(:require
|
||||
[quo2.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[reagent.core :as reagent]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[status-im.ui.components.fast-image :as fast-image]
|
||||
[quo2.components.animated-header-flatlist.style :as style]
|
||||
[oops.core :as oops]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(def header-height 234)
|
||||
(def cover-height 192)
|
||||
(def blur-view-height 100)
|
||||
(def threshold (- header-height blur-view-height))
|
||||
|
||||
(defn interpolate
|
||||
[value input-range output-range]
|
||||
(reanimated/interpolate value
|
||||
input-range
|
||||
output-range
|
||||
{:extrapolateLeft "clamp"
|
||||
:extrapolateRight "clamp"}))
|
||||
|
||||
(defn scroll-handler
|
||||
[event initial-y scroll-y]
|
||||
(let [current-y (- (oops/oget event "nativeEvent.contentOffset.y") initial-y)]
|
||||
(reanimated/set-shared-value scroll-y current-y)))
|
||||
|
||||
(defn header
|
||||
[{:keys [theme-color display-picture-comp cover-uri title-comp]} top-inset scroll-y]
|
||||
(let [input-range [0 (* threshold 0.33)]
|
||||
picture-scale-down 0.4
|
||||
size-animation (interpolate scroll-y input-range [80 (* 80 picture-scale-down)])
|
||||
image-animation (interpolate scroll-y input-range [72 (* 72 picture-scale-down)])
|
||||
border-animation (interpolate scroll-y input-range [12 0])]
|
||||
[rn/view
|
||||
{:style {:height header-height
|
||||
:background-color (or theme-color (colors/theme-colors colors/white colors/neutral-95))
|
||||
:margin-top (when platform/ios? (- top-inset))}}
|
||||
(when cover-uri
|
||||
[fast-image/fast-image
|
||||
{:style {:width "100%"
|
||||
:height cover-height}
|
||||
:source {:uri cover-uri}}])
|
||||
[reanimated/view {:style (style/header-bottom-part border-animation)}
|
||||
[title-comp]]
|
||||
[reanimated/view {:style (style/entity-picture size-animation)}
|
||||
[display-picture-comp image-animation]]]))
|
||||
|
||||
|
||||
|
||||
(defn animated-header-list
|
||||
[{:keys [header-comp main-comp] :as parameters}]
|
||||
[safe-area/consumer
|
||||
(fn [insets]
|
||||
(let [window-height (:height (rn/get-window))
|
||||
status-bar-height (rn/status-bar-height)
|
||||
bottom-inset (:bottom insets)
|
||||
;; view height calculation is different because window height is different on iOS and Android:
|
||||
view-height (if platform/ios?
|
||||
(- window-height bottom-inset)
|
||||
(+ window-height status-bar-height))
|
||||
initial-y (if platform/ios? (- (:top insets)) 0)]
|
||||
[:f>
|
||||
(fn []
|
||||
(let [scroll-y (reanimated/use-shared-value initial-y)
|
||||
opacity-animation (interpolate scroll-y
|
||||
[(* threshold 0.33) (* threshold 0.66)]
|
||||
[0 1])
|
||||
translate-animation (interpolate scroll-y [(* threshold 0.66) threshold] [100 56])
|
||||
title-opacity-animation (interpolate scroll-y [(* threshold 0.66) threshold] [0 1])]
|
||||
[rn/view {:style (style/container-view view-height)}
|
||||
[rn/touchable-opacity
|
||||
{:active-opacity 1
|
||||
:on-press #(rf/dispatch [:navigate-back])
|
||||
:style (style/button-container {:left 20})}
|
||||
[quo/icon :i/arrow-left {:size 20 :color (colors/theme-colors colors/black colors/white)}]]
|
||||
[rn/touchable-opacity
|
||||
{:active-opacity 1
|
||||
:style (style/button-container {:right 20})}
|
||||
[quo/icon :i/options {:size 20 :color (colors/theme-colors colors/black colors/white)}]]
|
||||
[reanimated/blur-view
|
||||
{:blurAmount 32
|
||||
:blurType :light
|
||||
:overlayColor (if platform/ios? colors/white-opa-70 :transparent)
|
||||
:style (style/blur-view opacity-animation)}
|
||||
[reanimated/view {:style (style/header-comp translate-animation title-opacity-animation)}
|
||||
[header-comp]]]
|
||||
[reanimated/flat-list
|
||||
{:data [nil]
|
||||
:render-fn main-comp
|
||||
:key-fn str
|
||||
:header (reagent/as-element (header parameters (:top insets) scroll-y))
|
||||
;; TODO: https://github.com/status-im/status-mobile/issues/14924
|
||||
:scroll-event-throttle 8
|
||||
:on-scroll (fn [event] (scroll-handler event initial-y scroll-y))}]]))]))])
|
@ -12,4 +12,4 @@
|
||||
quo2.colors/neutral-10
|
||||
quo2.colors/neutral-80)
|
||||
:align-self :stretch
|
||||
:height 1})}])
|
||||
:height 1})}])
|
||||
|
@ -1,6 +1,7 @@
|
||||
(ns react-native.reanimated
|
||||
(:require ["react-native" :as rn]
|
||||
["react-native-linear-gradient" :default LinearGradient]
|
||||
["react-native-fast-image" :as FastImage]
|
||||
["@react-native-community/blur" :as blur]
|
||||
["react-native-reanimated" :default reanimated :refer
|
||||
(useSharedValue useAnimatedStyle
|
||||
@ -15,6 +16,7 @@
|
||||
SlideOutUp
|
||||
LinearTransition)]
|
||||
[reagent.core :as reagent]
|
||||
[react-native.flat-list :as rn-flat-list]
|
||||
[utils.collection]))
|
||||
|
||||
;; Animations
|
||||
@ -27,9 +29,15 @@
|
||||
|
||||
(def view (reagent/adapt-react-class (.-View reanimated)))
|
||||
(def image (reagent/adapt-react-class (.-Image reanimated)))
|
||||
(def reanimated-flat-list (reagent/adapt-react-class (.-FlatList ^js rn)))
|
||||
(defn flat-list
|
||||
[props]
|
||||
[reanimated-flat-list (rn-flat-list/base-list-props props)])
|
||||
|
||||
(def touchable-opacity (create-animated-component (.-TouchableOpacity ^js rn)))
|
||||
|
||||
(def linear-gradient (create-animated-component LinearGradient))
|
||||
(def fast-image (create-animated-component FastImage))
|
||||
(def blur-view (create-animated-component (.-BlurView blur)))
|
||||
|
||||
;; Hooks
|
||||
|
@ -0,0 +1,88 @@
|
||||
(ns status-im2.contexts.quo-preview.animated-header-list.animated-header-list
|
||||
(:require
|
||||
[quo2.core :as quo]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[react-native.fast-image :as fast-image]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[quo2.components.animated-header-flatlist.view :as animated-header-list]))
|
||||
|
||||
(def data [0 1 2 3 4 5 6 7 8 9 10])
|
||||
|
||||
(defn child
|
||||
[]
|
||||
[rn/view
|
||||
{:style {:height 100
|
||||
:background-color colors/primary-50-opa-40
|
||||
:margin 10
|
||||
:justify-content :center
|
||||
:padding-left 10}}
|
||||
[quo/text "This is some message!!!!!"]])
|
||||
|
||||
|
||||
(defn main-comp
|
||||
[]
|
||||
[rn/flat-list
|
||||
{:data data
|
||||
:render-fn child
|
||||
:key-fn (fn [item] (str item))
|
||||
:header
|
||||
[rn/view
|
||||
{:style {:height 70
|
||||
:padding-top 8
|
||||
:padding-horizontal 20}}
|
||||
[quo/text {:size :paragraph-2}
|
||||
"Some random description • Developer • Designer • Olympic gold winner • President • Super Hero"]]}])
|
||||
|
||||
(defn display-picture-comp
|
||||
[animation]
|
||||
[:f>
|
||||
(fn []
|
||||
[reanimated/fast-image
|
||||
{:style (reanimated/apply-animations-to-style
|
||||
{:width animation
|
||||
:height animation}
|
||||
{:border-radius 72})
|
||||
:source
|
||||
{:uri
|
||||
"https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg"}}])])
|
||||
|
||||
|
||||
|
||||
(defn header-comp
|
||||
[]
|
||||
[rn/view
|
||||
{:style {:flex-direction :row
|
||||
:justify-content :center
|
||||
:align-items :center}}
|
||||
[fast-image/fast-image
|
||||
{:source {:uri
|
||||
"https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg"}
|
||||
:style {:width 32
|
||||
:height 32
|
||||
:border-radius 16
|
||||
:margin-right 8}}]
|
||||
[quo/text {:weight :semi-bold} "Alecia Keys"]])
|
||||
|
||||
(defn title-comp
|
||||
[]
|
||||
[quo/text
|
||||
{:weight :semi-bold
|
||||
:size :heading-1
|
||||
:style {:margin-top 56
|
||||
:margin-left 20}} "Alicia Keys"])
|
||||
|
||||
(def theme-color (colors/theme-alpha "#5BCC95" 0.2 0.2))
|
||||
|
||||
(def parameters
|
||||
{:theme-color theme-color
|
||||
:cover-uri
|
||||
"https://hips.hearstapps.com/hmg-prod.s3.amazonaws.com/images/kitten-playing-with-toy-mouse-royalty-free-image-590055188-1542816918.jpg?crop=1.00xw:0.758xh;0,0.132xh&resize=480:*"
|
||||
:display-picture-comp display-picture-comp
|
||||
:header-comp header-comp
|
||||
:title-comp title-comp
|
||||
:main-comp main-comp})
|
||||
|
||||
(defn mock-screen
|
||||
[]
|
||||
[animated-header-list/animated-header-list parameters])
|
@ -68,12 +68,16 @@
|
||||
[status-im2.contexts.quo-preview.wallet.lowest-price :as lowest-price]
|
||||
[status-im2.contexts.quo-preview.wallet.network-amount :as network-amount]
|
||||
[status-im2.contexts.quo-preview.wallet.network-breakdown :as network-breakdown]
|
||||
[status-im2.contexts.quo-preview.wallet.token-overview :as token-overview]))
|
||||
[status-im2.contexts.quo-preview.wallet.token-overview :as token-overview]
|
||||
[status-im2.contexts.quo-preview.animated-header-list.animated-header-list :as animated-header-list]))
|
||||
|
||||
(def screens-categories
|
||||
{:foundations [{:name :shadows
|
||||
:insets {:top false}
|
||||
:component shadows/preview-shadows}]
|
||||
:animated-list [{:name :animated-header-list
|
||||
:options {:topBar {:visible false}}
|
||||
:component animated-header-list/mock-screen}]
|
||||
:avatar [{:name :group-avatar
|
||||
:insets {:top false}
|
||||
:component group-avatar/preview-group-avatar}
|
||||
|
Loading…
x
Reference in New Issue
Block a user