parent
e8e8547879
commit
6c14fd1cb9
|
@ -30,11 +30,11 @@ export function applyAnimationsToStyle(animations, style) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function interpolateValue(sharedValue, inputRange, outputRange) {
|
export function interpolateValue(sharedValue, inputRange, outputRange, extrapolation) {
|
||||||
return useDerivedValue(
|
return useDerivedValue(
|
||||||
function () {
|
function () {
|
||||||
'worklet'
|
'worklet'
|
||||||
return interpolate(sharedValue.value, inputRange, outputRange);
|
return interpolate(sharedValue.value, inputRange, outputRange, extrapolation);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
(ns react-native.reanimated
|
(ns react-native.reanimated
|
||||||
(:require ["react-native" :as rn]
|
(:require ["react-native" :as rn]
|
||||||
["react-native-linear-gradient" :default LinearGradient]
|
["react-native-linear-gradient" :default LinearGradient]
|
||||||
|
["@react-native-community/blur" :as blur]
|
||||||
["react-native-reanimated" :default reanimated :refer
|
["react-native-reanimated" :default reanimated :refer
|
||||||
(useSharedValue useAnimatedStyle
|
(useSharedValue useAnimatedStyle
|
||||||
withTiming
|
withTiming
|
||||||
|
@ -30,6 +31,7 @@
|
||||||
(def touchable-opacity (create-animated-component (.-TouchableOpacity ^js rn)))
|
(def touchable-opacity (create-animated-component (.-TouchableOpacity ^js rn)))
|
||||||
|
|
||||||
(def linear-gradient (create-animated-component LinearGradient))
|
(def linear-gradient (create-animated-component LinearGradient))
|
||||||
|
(def blur-view (create-animated-component (.-BlurView blur)))
|
||||||
|
|
||||||
;; Hooks
|
;; Hooks
|
||||||
(def use-shared-value useSharedValue)
|
(def use-shared-value useSharedValue)
|
||||||
|
@ -67,11 +69,14 @@
|
||||||
(def worklet-factory (js/require "../src/js/worklet_factory.js"))
|
(def worklet-factory (js/require "../src/js/worklet_factory.js"))
|
||||||
|
|
||||||
(defn interpolate
|
(defn interpolate
|
||||||
[shared-value input-range output-range]
|
([shared-value input-range output-range]
|
||||||
|
(interpolate shared-value input-range output-range nil))
|
||||||
|
([shared-value input-range output-range extrapolation]
|
||||||
(.interpolateValue ^js worklet-factory
|
(.interpolateValue ^js worklet-factory
|
||||||
shared-value
|
shared-value
|
||||||
(clj->js input-range)
|
(clj->js input-range)
|
||||||
(clj->js output-range)))
|
(clj->js output-range)
|
||||||
|
(clj->js extrapolation))))
|
||||||
|
|
||||||
;;;; Component Animations
|
;;;; Component Animations
|
||||||
|
|
||||||
|
|
|
@ -1,29 +1,26 @@
|
||||||
(ns status-im2.common.scroll-page.style
|
(ns status-im2.common.scroll-page.style
|
||||||
(:require [quo2.foundations.colors :as colors]
|
(:require [quo2.foundations.colors :as colors]
|
||||||
[react-native.platform :as platform]))
|
[react-native.platform :as platform]
|
||||||
|
[react-native.reanimated :as reanimated]))
|
||||||
|
|
||||||
(defn image-slider
|
(defn image-slider
|
||||||
[height]
|
[size]
|
||||||
{:top (if platform/ios? 0 -64)
|
{:top (if platform/ios? 0 -64)
|
||||||
;; -64 is needed on android as the scroll doesn't
|
:height size
|
||||||
;; bounce so this slider won't disapear otherwise
|
:width size
|
||||||
:height height
|
|
||||||
:z-index 4
|
:z-index 4
|
||||||
:flex 1})
|
:flex 1})
|
||||||
|
|
||||||
(defn blur-slider
|
(defn blur-slider
|
||||||
[height]
|
[animation]
|
||||||
{:blur-amount 32
|
(reanimated/apply-animations-to-style
|
||||||
:blur-type :xlight
|
{:transform [{:translateY animation}]}
|
||||||
:overlay-color (if platform/ios? colors/white-opa-70 :transparent)
|
{:z-index 5
|
||||||
:style {:z-index 5
|
:top 0
|
||||||
:top (if platform/ios? 0 -64)
|
|
||||||
;; -64 is needed on android as the scroll doesn't
|
|
||||||
;; bounce so this slider won't disapear otherwise
|
|
||||||
:position :absolute
|
:position :absolute
|
||||||
:height height
|
:height (if platform/ios? 100 124)
|
||||||
:width "100%"
|
:width "100%"
|
||||||
:flex 1}})
|
:flex 1}))
|
||||||
|
|
||||||
(defn scroll-view-container
|
(defn scroll-view-container
|
||||||
[border-radius]
|
[border-radius]
|
||||||
|
@ -32,3 +29,42 @@
|
||||||
:overflow :scroll
|
:overflow :scroll
|
||||||
:border-radius border-radius
|
:border-radius border-radius
|
||||||
:height "100%"})
|
:height "100%"})
|
||||||
|
|
||||||
|
(defn sticky-header-title
|
||||||
|
[animation]
|
||||||
|
(reanimated/apply-animations-to-style
|
||||||
|
{:opacity animation}
|
||||||
|
{:position :absolute
|
||||||
|
:flex-direction :row
|
||||||
|
:left 64
|
||||||
|
:top 16}))
|
||||||
|
|
||||||
|
(def sticky-header-image
|
||||||
|
{:border-radius 12
|
||||||
|
:border-width 0
|
||||||
|
:border-color :transparent
|
||||||
|
:width 24
|
||||||
|
:height 24
|
||||||
|
:margin-right 8})
|
||||||
|
|
||||||
|
(defn display-picture-container
|
||||||
|
[animation]
|
||||||
|
(reanimated/apply-animations-to-style
|
||||||
|
{:transform [{:scale animation}]}
|
||||||
|
{:border-radius 40
|
||||||
|
:border-width 1
|
||||||
|
:border-color colors/white
|
||||||
|
:position :absolute
|
||||||
|
:top -40
|
||||||
|
:left 17
|
||||||
|
:padding 2
|
||||||
|
:background-color (colors/theme-colors
|
||||||
|
colors/white
|
||||||
|
colors/neutral-90)}))
|
||||||
|
|
||||||
|
(def display-picture
|
||||||
|
{:border-radius 50
|
||||||
|
:border-width 0
|
||||||
|
:border-color :transparent
|
||||||
|
:width 80
|
||||||
|
:height 80})
|
||||||
|
|
|
@ -3,11 +3,11 @@
|
||||||
[quo2.core :as quo]
|
[quo2.core :as quo]
|
||||||
[quo2.foundations.colors :as colors]
|
[quo2.foundations.colors :as colors]
|
||||||
[react-native.core :as rn]
|
[react-native.core :as rn]
|
||||||
[react-native.blur :as blur]
|
|
||||||
[react-native.platform :as platform]
|
[react-native.platform :as platform]
|
||||||
[reagent.core :as reagent]
|
[reagent.core :as reagent]
|
||||||
[status-im2.common.scroll-page.style :as style]
|
[status-im2.common.scroll-page.style :as style]
|
||||||
[utils.re-frame :as rf]))
|
[utils.re-frame :as rf]
|
||||||
|
[react-native.reanimated :as reanimated]))
|
||||||
|
|
||||||
(defn icon-color
|
(defn icon-color
|
||||||
[]
|
[]
|
||||||
|
@ -15,24 +15,8 @@
|
||||||
colors/white-opa-40
|
colors/white-opa-40
|
||||||
colors/neutral-80-opa-40))
|
colors/neutral-80-opa-40))
|
||||||
|
|
||||||
(defn get-platform-value [value] (if platform/ios? (+ value 44) value))
|
|
||||||
(def negative-scroll-position-0 (if platform/ios? -44 0))
|
(def negative-scroll-position-0 (if platform/ios? -44 0))
|
||||||
(def scroll-position-0 (if platform/ios? 44 0))
|
(def scroll-position-0 (if platform/ios? 44 0))
|
||||||
(def scroll-position-1 (if platform/ios? 86 134))
|
|
||||||
(def scroll-position-2 (if platform/ios? -26 18))
|
|
||||||
|
|
||||||
(defn get-header-size
|
|
||||||
[scroll-height]
|
|
||||||
(if (<= scroll-height scroll-position-2)
|
|
||||||
0
|
|
||||||
(->>
|
|
||||||
(+ (get-platform-value -17) scroll-height)
|
|
||||||
(* (if platform/ios? 3 1))
|
|
||||||
(max 0)
|
|
||||||
(min (if platform/ios? 100 124)))))
|
|
||||||
|
|
||||||
(def max-image-size 80)
|
|
||||||
(def min-image-size 32)
|
|
||||||
|
|
||||||
(defn diff-with-max-min
|
(defn diff-with-max-min
|
||||||
[value maximum minimum]
|
[value maximum minimum]
|
||||||
|
@ -42,54 +26,97 @@
|
||||||
(max minimum)
|
(max minimum)
|
||||||
(min maximum)))
|
(min maximum)))
|
||||||
|
|
||||||
(defn icon-top-fn
|
(defn scroll-page-header
|
||||||
[scroll-height]
|
[scroll-height name page-nav cover sticky-header]
|
||||||
(if (<= scroll-height negative-scroll-position-0)
|
[:f>
|
||||||
-40
|
(fn []
|
||||||
(->> (+ scroll-position-0 scroll-height)
|
(let [input-range (if platform/ios? [-47 10] [0 150])
|
||||||
(* (if platform/ios? 3 1))
|
output-range (if platform/ios? [-100 0] [-169 -45])
|
||||||
(+ -40)
|
y (reanimated/use-shared-value @scroll-height)
|
||||||
(min 8))))
|
translate-animation (reanimated/interpolate y
|
||||||
|
input-range
|
||||||
(defn icon-size-fn
|
output-range
|
||||||
[scroll-height]
|
{:extrapolateLeft "clamp"
|
||||||
(->> (+ scroll-position-0 scroll-height)
|
:extrapolateRight "clamp"})
|
||||||
(* (if platform/ios? 3 1))
|
opacity-animation (reanimated/use-shared-value 0)
|
||||||
(- max-image-size)
|
threshold (if platform/ios? 30 170)]
|
||||||
(max min-image-size)
|
(rn/use-effect
|
||||||
(min max-image-size)))
|
#(do
|
||||||
|
(reanimated/set-shared-value y @scroll-height)
|
||||||
(defn scroll-page
|
(reanimated/set-shared-value opacity-animation
|
||||||
[icon cover page-nav name]
|
(reanimated/with-timing (if (>= @scroll-height threshold) 1 0)
|
||||||
(let [scroll-height (reagent/atom negative-scroll-position-0)]
|
(clj->js {:duration 300}))))
|
||||||
(fn [sticky-header children]
|
[@scroll-height])
|
||||||
[:<>
|
|
||||||
[:<>
|
[:<>
|
||||||
|
[reanimated/blur-view
|
||||||
|
{:blur-amount 32
|
||||||
|
:blur-type :xlight
|
||||||
|
:overlay-color (if platform/ios? colors/white-opa-70 :transparent)
|
||||||
|
:style (style/blur-slider translate-animation)}]
|
||||||
|
[rn/view
|
||||||
|
{:style {:z-index 6
|
||||||
|
:margin-top (if platform/ios? 44 0)}}
|
||||||
|
[reanimated/view
|
||||||
|
{:style (style/sticky-header-title opacity-animation)}
|
||||||
[rn/image
|
[rn/image
|
||||||
{:source cover
|
{:source cover
|
||||||
:position :absolute
|
:style style/sticky-header-image}]
|
||||||
:style (style/image-slider (get-header-size @scroll-height))}]
|
[quo/text
|
||||||
[blur/view (style/blur-slider (get-header-size @scroll-height))]]
|
{:size :paragraph-1
|
||||||
[rn/view {:style {:z-index 6 :margin-top (if platform/ios? 44 0)}}
|
:weight :semi-bold
|
||||||
|
:style {:line-height 21}}
|
||||||
|
name]]
|
||||||
[quo/page-nav
|
[quo/page-nav
|
||||||
{:horizontal-description? true
|
{:horizontal-description? true
|
||||||
:one-icon-align-left? true
|
:one-icon-align-left? true
|
||||||
:align-mid? false
|
:align-mid? false
|
||||||
:page-nav-color :transparent
|
:page-nav-color :transparent
|
||||||
:page-nav-background-uri ""
|
|
||||||
:mid-section {:type :text-with-description
|
:mid-section {:type :text-with-description
|
||||||
:main-text (when (>= @scroll-height scroll-position-1) name)
|
:main-text nil
|
||||||
:description-img (when (>= @scroll-height scroll-position-1) icon)}
|
:description-img nil}
|
||||||
:right-section-buttons (:right-section-buttons page-nav)
|
:right-section-buttons (:right-section-buttons page-nav)
|
||||||
:left-section {:icon :i/close
|
:left-section {:icon :i/close
|
||||||
:icon-background-color (icon-color)
|
:icon-background-color (icon-color)
|
||||||
:on-press #(rf/dispatch [:navigate-back])}}]
|
:on-press #(rf/dispatch [:navigate-back])}}]
|
||||||
(when sticky-header [sticky-header @scroll-height])]
|
(when sticky-header [sticky-header @scroll-height])]]))])
|
||||||
|
|
||||||
|
(defn display-picture
|
||||||
|
[scroll-height cover]
|
||||||
|
[:f>
|
||||||
|
(fn []
|
||||||
|
(let [input-range (if platform/ios? [-67 10] [0 150])
|
||||||
|
y (reanimated/use-shared-value @scroll-height)
|
||||||
|
animation (reanimated/interpolate y
|
||||||
|
input-range
|
||||||
|
[1.2 0.5]
|
||||||
|
{:extrapolateLeft "clamp"
|
||||||
|
:extrapolateRight "clamp"})]
|
||||||
|
(rn/use-effect #(do
|
||||||
|
(reanimated/set-shared-value y @scroll-height)
|
||||||
|
js/undefined)
|
||||||
|
[@scroll-height])
|
||||||
|
[reanimated/view
|
||||||
|
{:style (style/display-picture-container animation)}
|
||||||
|
[rn/image
|
||||||
|
{:source cover
|
||||||
|
:style style/display-picture}]]))])
|
||||||
|
|
||||||
|
(defn scroll-page
|
||||||
|
[cover page-nav name]
|
||||||
|
(let [scroll-height (reagent/atom negative-scroll-position-0)]
|
||||||
|
(fn [sticky-header children]
|
||||||
|
[:<>
|
||||||
|
[scroll-page-header scroll-height name page-nav cover sticky-header]
|
||||||
[rn/scroll-view
|
[rn/scroll-view
|
||||||
{:style (style/scroll-view-container (diff-with-max-min @scroll-height 16 0))
|
{:style (style/scroll-view-container
|
||||||
|
(diff-with-max-min @scroll-height 16 0))
|
||||||
:shows-vertical-scroll-indicator false
|
:shows-vertical-scroll-indicator false
|
||||||
:scroll-event-throttle 4
|
:scroll-event-throttle 16
|
||||||
:on-scroll #(swap! scroll-height (fn [] (int (oops/oget % "nativeEvent.contentOffset.y"))))}
|
:on-scroll (fn [event]
|
||||||
|
(reset! scroll-height (int
|
||||||
|
(oops/oget
|
||||||
|
event
|
||||||
|
"nativeEvent.contentOffset.y"))))}
|
||||||
[rn/view {:style {:height 151}}
|
[rn/view {:style {:height 151}}
|
||||||
[rn/image
|
[rn/image
|
||||||
{:source cover
|
{:source cover
|
||||||
|
@ -102,5 +129,5 @@
|
||||||
:background-color (colors/theme-colors
|
:background-color (colors/theme-colors
|
||||||
colors/white
|
colors/white
|
||||||
colors/neutral-90)}
|
colors/neutral-90)}
|
||||||
[children @scroll-height icon-top-fn icon-size-fn]])]])))
|
[display-picture scroll-height cover]
|
||||||
|
[children]])]])))
|
||||||
|
|
|
@ -226,22 +226,9 @@
|
||||||
channel-heights first-channel-height]
|
channel-heights first-channel-height]
|
||||||
(let [pending? (pos? requested-to-join-at)
|
(let [pending? (pos? requested-to-join-at)
|
||||||
thumbnail-image (get-in images [:thumbnail])]
|
thumbnail-image (get-in images [:thumbnail])]
|
||||||
(fn [scroll-height icon-top icon-size]
|
(fn []
|
||||||
[rn/view
|
[rn/view
|
||||||
[rn/view {:padding-horizontal 20}
|
[rn/view {:padding-horizontal 20}
|
||||||
[rn/view
|
|
||||||
{:border-radius 40
|
|
||||||
:border-width 1
|
|
||||||
:border-color colors/white
|
|
||||||
:position :absolute
|
|
||||||
:top (icon-top scroll-height)
|
|
||||||
:left 17
|
|
||||||
:padding 2
|
|
||||||
:background-color (colors/theme-colors
|
|
||||||
colors/white
|
|
||||||
colors/neutral-90)}
|
|
||||||
[quo/community-icon community
|
|
||||||
(icon-size scroll-height)]]
|
|
||||||
(when (and (not joined)
|
(when (and (not joined)
|
||||||
(not pending?)
|
(not pending?)
|
||||||
(= status :gated))
|
(= status :gated))
|
||||||
|
@ -324,7 +311,6 @@
|
||||||
(let [channel-heights (reagent/atom [])
|
(let [channel-heights (reagent/atom [])
|
||||||
first-channel-height (reagent/atom 0)
|
first-channel-height (reagent/atom 0)
|
||||||
scroll-component (scroll-page/scroll-page
|
scroll-component (scroll-page/scroll-page
|
||||||
(fn [] [quo/community-icon community 24])
|
|
||||||
{:uri (get-in images [:large :uri])}
|
{:uri (get-in images [:large :uri])}
|
||||||
{:right-section-buttons [{:icon :i/search
|
{:right-section-buttons [{:icon :i/search
|
||||||
:background-color (scroll-page/icon-color)}
|
:background-color (scroll-page/icon-color)}
|
||||||
|
|
Loading…
Reference in New Issue