Skip to content

Commit

Permalink
Use Reanimated V2 for Switcher Animations
Browse files Browse the repository at this point in the history
  • Loading branch information
Parveshdhull committed Jun 19, 2022
1 parent fbf43a4 commit 21246dc
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 126 deletions.
1 change: 0 additions & 1 deletion src/mocks/js_dependencies.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@
:ValueXY (fn [])
:View {}
:FlatList {}
:Image {}
:ScrollView {}
:Text {}}
:Easing {:bezier (fn [])
Expand Down
3 changes: 0 additions & 3 deletions src/quo/react_native.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,6 @@
(def animated-view
(reagent/adapt-react-class (.-View ^js animated)))

(def animated-image-view
(reagent/adapt-react-class (.-Image ^js animated)))

(def ui-manager (.-UIManager ^js rn))

(def layout-animation (.-LayoutAnimation ^js rn))
Expand Down
114 changes: 71 additions & 43 deletions src/status_im/switcher/animation.cljs
Original file line number Diff line number Diff line change
@@ -1,47 +1,75 @@
(ns status-im.switcher.animation
(:require [quo.react-native :as rn]
[reagent.core :as reagent]
[status-im.switcher.constants :as constants]
[status-im.ui.components.animation :as anim]))
(:require [quo2.reanimated :as reanimated]
[status-im.switcher.constants :as constants]))

(def bottom-tabs-opacity (anim/create-value 1))
(def bottom-tabs-position (anim/create-value 0))
;; Component Animations
(defn switcher-touchable-on-press-in
[touchable-scale]
(reanimated/animate-shared-value-with-timing touchable-scale 0.9 300 :easing1))

;; TODO(parvesh): Use 300, after using dispatch-later for opening card(otherwise pending animation issue)
;; or OnAnimationEnd
(def layout-animation #js {:duration 250
:create #js {:type (:ease-in-ease-out rn/layout-animation-types)
:property (:scale-xy rn/layout-animation-properties)}
:update #js {:type (:ease-in-ease-out rn/layout-animation-types)
:property (:scale-xy rn/layout-animation-properties)}
:delete #js {:type (:ease-in-ease-out rn/layout-animation-types)
:property (:scale-xy rn/layout-animation-properties)}})
(defn switcher-touchable-on-press-out
[switcher-opened? close-button-opacity switcher-button-opacity button-touchable-scale]
(reanimated/animate-shared-value-with-timing button-touchable-scale 1 300 :easing2)
(if @switcher-opened?
(do
(reanimated/animate-shared-value-with-timing close-button-opacity 0 300 :easing2)
(reanimated/animate-shared-value-with-timing switcher-button-opacity 1 300 :easing1))
(do
(reanimated/animate-shared-value-with-timing close-button-opacity 1 300 :easing1)
(reanimated/animate-shared-value-with-timing switcher-button-opacity 0 300 :easing2)))
(swap! switcher-opened? not))

(defn animate-layout [show? anim-values]
(let [{:keys [width height]} (constants/dimensions)
target-radius (- (max width height)
constants/switcher-button-radius)]
(rn/configure-next layout-animation)
(reset! (:switcher-screen-radius anim-values) (if show? target-radius 1))
(reagent/flush)))

(defn timing-animation [property toValue]
(anim/timing property {:toValue toValue
:duration 300
:useNativeDriver true}))

(defn animate-components [show? view-id anim-values]
(anim/start
(anim/parallel
(into
[(timing-animation (:switcher-button-opacity anim-values) (if show? 0 1))
(timing-animation (:switcher-close-button-icon-opacity anim-values) (if show? 1 0))
(timing-animation (:switcher-close-button-background-opacity anim-values) (if show? 0.2 0))]
(when (= view-id :home-stack)
[(timing-animation bottom-tabs-opacity (if show? 0 1))
(timing-animation bottom-tabs-position (if show? (constants/bottom-tabs-height) 0))])))))

(defn animate [show? view-id anim-values]
(reagent/flush)
(animate-layout show? anim-values)
(animate-components show? view-id anim-values))
;; Layout Animations
(defn switcher-layout-animations [view-id]
(let [{:keys [width height]} (constants/dimensions)
half-width (/ width 2)
switcher-bottom-position (constants/switcher-bottom-position view-id)
switcher-target-radius (Math/hypot
half-width
(- height constants/switcher-button-radius switcher-bottom-position))
switcher-size (* 2 switcher-target-radius)
switcher-from-x (- half-width constants/switcher-button-radius)
switcher-from-y (- height switcher-bottom-position constants/switcher-button-size constants/switcher-height-offset)
switcher-to-x (- half-width switcher-target-radius)
switcher-to-y (- height constants/switcher-button-size switcher-bottom-position switcher-target-radius)
switcher-entering-animation (.duration (new reanimated/key-frame
(clj->js
{:from {:width constants/switcher-button-size
:height constants/switcher-button-size
:originX switcher-from-x
:originY switcher-from-y}
:to {:width switcher-size
:height switcher-size
:originX switcher-to-x
:originY switcher-to-y}})) 300)
switcher-exiting-animation (.duration (new reanimated/key-frame
(clj->js {:from {:width switcher-size
:height switcher-size
:originX switcher-to-x
:originY switcher-to-y}
:to {:width constants/switcher-button-size
:height constants/switcher-button-size
:originX switcher-from-x
:originY switcher-from-y}})) 300)
container-from-x (- switcher-from-x)
container-from-y (- switcher-from-y)
container-to-x (- switcher-to-x)
container-to-y (- switcher-to-y)
container-entering-animation (.duration (new reanimated/key-frame
(clj->js {:from {:originX container-from-x
:originY container-from-y
:transform [{:scale 0.9}]}
:to {:originX container-to-x
:originY container-to-y
:transform [{:scale 1}]}})) 300)
container-exiting-animation (.duration (new reanimated/key-frame
(clj->js {:from {:originX container-to-x
:originY container-to-y
:transform [{:scale 1}]}
:to {:originX container-from-x
:originY container-from-y
:transform [{:scale 0.9}]}})) 300)]
{:switcher-entering-animation switcher-entering-animation
:switcher-exiting-animation switcher-exiting-animation
:container-entering-animation container-entering-animation
:container-exiting-animation container-exiting-animation}))
7 changes: 4 additions & 3 deletions src/status_im/switcher/constants.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
(:require [status-im.utils.handlers :refer [<sub]]
[status-im.utils.platform :as platform]))

;; For translucent status bar, dimensions/window also includes status bar's height,
;; this offset is used for correctly calculating switcher position
(def switcher-height-offset 24)

(def switcher-button-radius 24)

(def switcher-button-size
Expand All @@ -20,9 +24,6 @@
switcher-bottom-positions
[(keyword platform/os) view-id]))

(defn switcher-center-position [view-id]
(+ (switcher-bottom-position view-id) (/ switcher-button-size 2)))

;; TODO(parvesh) - use different height for android and ios(Confirm from Design)
(defn bottom-tabs-height []
(if platform/android? 55 80))
Expand Down
60 changes: 22 additions & 38 deletions src/status_im/switcher/styles.cljs
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
(ns status-im.switcher.styles
(:require [quo.theme :as theme]
[quo2.foundations.colors :as colors]
[status-im.switcher.constants :as constants]
[status-im.switcher.animation :as animation]))
[status-im.switcher.constants :as constants]))

(def themes
{:light {:bottom-tabs-bg-color colors/neutral-80
:bottom-tabs-on-scroll-bg-color colors/neutral-80-opa-80
:bottom-tabs-non-selected-tab colors/neutral-50
:bottom-tabs-selected-tab colors/white}
:bottom-tabs-selected-tab colors/white
:switcher-close-button-bg-color colors/white}
:dark {:bottom-tabs-bg-color colors/neutral-80
:bottom-tabs-on-scroll-bg-color colors/neutral-80-opa-60
:bottom-tabs-non-selected-tab colors/neutral-40
:bottom-tabs-selected-tab colors/white}})
:bottom-tabs-selected-tab colors/white
:switcher-close-button-bg-color colors/white}})

(defn get-color [key]
(get-in themes [(theme/get-theme) key]))
Expand All @@ -33,63 +34,46 @@
:position :absolute
:bottom -1
:right 0
:left 0
:opacity animation/bottom-tabs-opacity
:transform [{:translateY animation/bottom-tabs-position}]})
:left 0})

;; Switcher
(defn switcher-button [opacity]

(defn switcher-button []
{:width constants/switcher-button-size
:height constants/switcher-button-size
:opacity opacity})
:z-index 2})

(defn merge-switcher-button-common-styles [style]
(merge
{:width constants/switcher-button-size
:height constants/switcher-button-size
:border-radius constants/switcher-button-radius
:position :absolute
:bottom 0
:z-index 3
:z-index 2
:align-items :center
:align-self :center
:justify-content :center}
style))

(defn switcher-button-touchable [view-id]
(merge-switcher-button-common-styles
{:align-self :center
:bottom (constants/switcher-bottom-position view-id)}))
{:bottom (constants/switcher-bottom-position view-id)}))

(defn switcher-close-button-background [opacity]
(defn switcher-close-button []
(merge-switcher-button-common-styles
{:background-color colors/switcher-background
:opacity opacity}))
{:backgroundColor (get-color :switcher-close-button-bg-color)}))

(defn switcher-close-button-icon [opacity]
(defn switcher-screen []
(merge-switcher-button-common-styles
{:opacity opacity}))

(defn switcher-screen [view-id radius]
(let [bottom (- (constants/switcher-center-position view-id) radius)
size (* 2 radius)]
(merge-switcher-button-common-styles
{:background-color colors/switcher-background-opa-80
:bottom bottom
:border-radius 1000
:width size
:overflow :hidden
:height size})))
{:background-color colors/switcher-background-opa-80
:border-radius 1500
:z-index 1
:overflow :hidden}))

(defn switcher-screen-container [view-id radius]
(let [radius radius
bottom (- radius (constants/switcher-center-position view-id))
{:keys [width height]} (constants/dimensions)]
{:position :absolute
:align-self :center
:bottom bottom
:width width
:height (- height 25)
(defn switcher-screen-container []
(let [{:keys [width height]} (constants/dimensions)]
{:width width
:height (+ height 100) ;; Extra Height is required to show hidden cards when zoom animation is running
:align-items :center}))

(defn switcher-switch-screen []
Expand Down
86 changes: 52 additions & 34 deletions src/status_im/switcher/switcher.cljs
Original file line number Diff line number Diff line change
@@ -1,44 +1,62 @@
(ns status-im.switcher.switcher
(:require [quo.react-native :as rn]
[reagent.core :as reagent]
(:require [reagent.core :as reagent]
[quo2.reanimated :as reanimated]
[status-im.switcher.styles :as styles]
[status-im.ui.components.animation :as anim]
[status-im.switcher.animation :as animation]
[status-im.ui.components.icons.icons :as icons]
[status-im.react-native.resources :as resources]
[status-im.switcher.switcher-container :as switcher-container]))

(defn toggle-switcher-screen [switcher-opened? view-id anim-values]
(swap! switcher-opened? not)
(animation/animate @switcher-opened? view-id anim-values))
(defn switcher-button
[view-id close-button-opacity switcher-button-opacity
button-touchable-scale toggle-switcher-screen-fn]
[:f>
(fn []
(let [touchable-original-style (styles/switcher-button-touchable view-id)
close-button-original-style (styles/switcher-close-button)
switcher-button-original-style (styles/switcher-button)
touchable-animated-style (reanimated/apply-animations-to-style
{:transform [{:scale button-touchable-scale}]}
touchable-original-style)
close-button-animated-style (reanimated/apply-animations-to-style
{:opacity close-button-opacity}
close-button-original-style)
switcher-button-animated-style (reanimated/apply-animations-to-style
{:opacity switcher-button-opacity}
switcher-button-original-style)]
[reanimated/touchable-opacity {:active-opacity 1
:on-press-in #(animation/switcher-touchable-on-press-in
button-touchable-scale)
:on-press-out toggle-switcher-screen-fn
:style touchable-animated-style}
[reanimated/view {:style close-button-animated-style}
[icons/icon :main-icons/close {:color :black}]]
[reanimated/image {:source (resources/get-image :status-logo)
:style switcher-button-animated-style}]]))])

(defn switcher-button [switcher-opened? view-id anim-values]
[rn/touchable-opacity {:active-opacity 1
:on-press #(toggle-switcher-screen switcher-opened? view-id anim-values)
:style (styles/switcher-button-touchable view-id)}
[rn/animated-view {:style (styles/switcher-close-button-background
(:switcher-close-button-background-opacity anim-values))}]
[rn/animated-view {:style (styles/switcher-close-button-icon
(:switcher-close-button-icon-opacity anim-values))}
[icons/icon :main-icons/close {:color :white}]]
[rn/animated-image-view {:source (resources/get-image :status-logo)
:style (styles/switcher-button
(:switcher-button-opacity anim-values))}]])

(defn switcher-screen [switcher-opened? view-id anim-values]
[rn/view {:style (styles/switcher-screen
view-id @(:switcher-screen-radius anim-values))
:pointer-events (if switcher-opened? :auto :none)}
[switcher-container/container
view-id @(:switcher-screen-radius anim-values)
#(toggle-switcher-screen switcher-opened? view-id anim-values)]])
(defn switcher-screen [switcher-opened? view-id toggle-switcher-screen-fn]
(let [{:keys [switcher-entering-animation switcher-exiting-animation
container-entering-animation container-exiting-animation]}
(animation/switcher-layout-animations view-id)]
(when @switcher-opened?
[reanimated/view {:entering switcher-entering-animation
:exiting switcher-exiting-animation
:style (styles/switcher-screen)}
[reanimated/view {:entering container-entering-animation
:exiting container-exiting-animation
:style (styles/switcher-screen-container)}
[switcher-container/tabs toggle-switcher-screen-fn]]])))

(defn switcher [view-id]
(let [switcher-opened? (reagent/atom false)
anim-values {:switcher-button-opacity (anim/create-value 1)
:switcher-close-button-icon-opacity (anim/create-value 0)
:switcher-close-button-background-opacity (anim/create-value 0)
:switcher-screen-radius (reagent/atom 1)}]
[:<>
[switcher-screen switcher-opened? view-id anim-values]
[switcher-button switcher-opened? view-id anim-values]]))
[:f>
(fn []
(let [switcher-opened? (reagent/atom false)
close-button-opacity (reanimated/use-shared-value 0)
switcher-button-opacity (reanimated/use-shared-value 1)
button-touchable-scale (reanimated/use-shared-value 1)
toggle-switcher-screen-fn #(animation/switcher-touchable-on-press-out
switcher-opened? close-button-opacity switcher-button-opacity button-touchable-scale)]
[:<>
[switcher-screen switcher-opened? view-id toggle-switcher-screen-fn]
[switcher-button view-id close-button-opacity switcher-button-opacity
button-touchable-scale toggle-switcher-screen-fn]]))])
6 changes: 2 additions & 4 deletions src/status_im/switcher/switcher_container.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,5 @@
:num-columns 2
:key-fn str}]]))

(defn container [view-id switcher-screen-radius toggle-switcher-screen]
[rn/view {:style (styles/switcher-screen-container
view-id switcher-screen-radius)}
[switch-screen toggle-switcher-screen]])
(defn tabs [toggle-switcher-screen]
[switch-screen toggle-switcher-screen])

0 comments on commit 21246dc

Please sign in to comment.