Skip to content

Commit

Permalink
Switcher and Bottom Tabs Animations and UI Performance Improvements
Browse files Browse the repository at this point in the history
- Migrated Switcher animations to Reanimated V2
- Added bottom tabs & Stacks Animations
- Improved bottom tabs, tab changing performance
- Polished android & IOS UI
  • Loading branch information
Parveshdhull committed Jun 27, 2022
1 parent 042ce72 commit daddb3e
Show file tree
Hide file tree
Showing 24 changed files with 337 additions and 202 deletions.
2 changes: 1 addition & 1 deletion .clj-kondo/config.edn
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{:lint-as {status-im.utils.views/defview clojure.core/defn
status-im.utils.views/letsubs clojure.core/let
reagent.core/with-let clojkure.core/let
reagent.core/with-let clojure.core/let
status-im.utils.fx/defn clj-kondo.lint-as/def-catch-all
quo.react/with-deps-check clojure.core/fn
quo.previews.preview/list-comp clojure.core/for
Expand Down
Binary file added resources/images/icons/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added resources/images/icons/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added resources/images/icons/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added resources/images/icons/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified resources/images/icons/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified resources/images/icons/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added resources/images/ui/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added resources/images/ui/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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
1 change: 1 addition & 0 deletions src/status_im/multiaccounts/logout/core.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
(fx/merge cofx
{:init-root-fx :progress
:chat.ui/clear-inputs nil
:new-ui/reset-bottom-tabs nil
:hide-popover nil
::logout nil
::multiaccounts/webview-debug-changed false
Expand Down
5 changes: 3 additions & 2 deletions src/status_im/navigation2.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@
[_]
(swap! config/new-ui-enabled? not)
(reloader/reload)
{:dispatch [:init-root (if @config/new-ui-enabled? :home-stack :chat-stack)]
::async-storage/set! {:new-ui-enabled? @config/new-ui-enabled?}})
{:new-ui/reset-bottom-tabs nil
:dispatch [:init-root (if @config/new-ui-enabled? :home-stack :chat-stack)]
::async-storage/set! {:new-ui-enabled? @config/new-ui-enabled?}})

(fx/defn init-root-nav2
{:events [:init-root-nav2]}
Expand Down
29 changes: 0 additions & 29 deletions src/status_im/navigation2/home_stack.cljs

This file was deleted.

2 changes: 1 addition & 1 deletion src/status_im/navigation2/screens.cljs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
(ns status-im.navigation2.screens
(:require [status-im.ui.screens.chat.views :as chat]
[status-im.navigation2.home-stack :as home-stack]
[status-im.switcher.home-stack :as home-stack]
[status-im.navigation2.stack-with-switcher :as stack-with-switcher]))

;; We have to use the home screen name :chat-stack for now, for compatibility with navigation.cljs
Expand Down
7 changes: 5 additions & 2 deletions src/status_im/navigation2/stack_with_switcher.cljs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
(ns status-im.navigation2.stack-with-switcher
(:require [status-im.switcher.switcher :as switcher]))
(:require [quo.react-native :as rn]
[status-im.utils.platform :as platform]
[status-im.switcher.switcher :as switcher]))

(defn overlap-stack [comp view-id]
[:<>
[rn/view {:style {:flex 1
:margin-bottom (if platform/ios? 30 0)}}
[comp]
[switcher/switcher view-id]])
3 changes: 2 additions & 1 deletion src/status_im/react_native/resources.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@
:collectible (js/require "../resources/images/ui/collectible.png")
:collectible-dark (js/require "../resources/images/ui/collectible-dark.png")
:hand-wave (js/require "../resources/images/ui/hand-wave.png")
:graph (js/require "../resources/images/ui/graph.png")})
:graph (js/require "../resources/images/ui/graph.png")
:switcher (js/require "../resources/images/ui/switcher.png")})

(defn get-theme-image [k]
(get ui (when (colors/dark?) (keyword (str (name k) "-dark"))) (get ui k)))
Expand Down
112 changes: 66 additions & 46 deletions src/status_im/switcher/animation.cljs
Original file line number Diff line number Diff line change
@@ -1,47 +1,67 @@
(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]))

(def bottom-tabs-opacity (anim/create-value 1))
(def bottom-tabs-position (anim/create-value 0))

;; 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 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))
(:require [clojure.string :as string]
[quo2.reanimated :as reanimated]
[status-im.switcher.constants :as constants]))

;;;; Switcher Animations

;; Component Animations
(defn switcher-touchable-on-press-in
[touchable-scale]
(reanimated/animate-shared-value-with-timing touchable-scale constants/switcher-pressed-scale 300 :easing1))

(defn switcher-touchable-on-press-out [switcher-opened? view-id shared-values]
(let [{:keys [width height]} (constants/dimensions)
switcher-bottom-position (constants/switcher-pressed-bottom-position view-id)
switcher-target-radius (Math/hypot
(/ width 2)
(- height constants/switcher-pressed-radius switcher-bottom-position))
switcher-size (* 2 switcher-target-radius)]
(reanimated/animate-shared-value-with-timing (:button-touchable-scale shared-values) 1 300 :easing1)
(if @switcher-opened?
(do
(reanimated/animate-shared-value-with-timing (:switcher-button-opacity shared-values) 1 300 :easing1)
(reanimated/animate-shared-value-with-timing (:switcher-screen-size shared-values) constants/switcher-pressed-size 300 :linear)
(reanimated/animate-shared-value-with-timing (:switcher-container-scale shared-values) 0.9 300 :linear))
(do
(reanimated/animate-shared-value-with-timing (:switcher-button-opacity shared-values) 0 300 :easing1)
(reanimated/animate-shared-value-with-timing (:switcher-screen-size shared-values) switcher-size 300 :linear)
(reanimated/animate-shared-value-with-timing (:switcher-container-scale shared-values) 1 300 :linear)))
(swap! switcher-opened? not)))

;; Derived Values

(defn switcher-close-button-opacity [switcher-button-opacity]
(.switcherCloseButtonOpacity ^js reanimated/worklet-factory switcher-button-opacity))

(defn switcher-screen-radius [switcher-screen-size]
(.switcherScreenRadius ^js reanimated/worklet-factory switcher-screen-size))

(defn switcher-screen-bottom-position [switcher-screen-radius view-id]
(.switcherScreenBottomPosition ^js reanimated/worklet-factory
switcher-screen-radius
constants/switcher-pressed-radius
(constants/switcher-pressed-bottom-position view-id)))

(defn switcher-container-bottom-position [switcher-screen-bottom]
(.switcherContainerBottomPosition ^js reanimated/worklet-factory
switcher-screen-bottom
(+ constants/switcher-container-height-padding
constants/switcher-height-offset)))


;;;; Bottom Tabs & Home Stack Animations


(defn bottom-tab-on-press [shared-values selected-tab-id]
(let [selected-tab (get (string/split (name selected-tab-id) #"-") 0)]
(doseq [tab constants/tabs]
(let [selected-tab? (= tab selected-tab)
tab-opacity-shared-value (get shared-values (keyword (str tab "-tab-opacity")))
stack-opacity-shared-value (get shared-values (keyword (str tab "-stack-opacity")))
stack-pointer-shared-value (get shared-values (keyword (str tab "-stack-pointer")))]
(reanimated/animate-shared-value-with-timing tab-opacity-shared-value (if selected-tab? 1 0) 300 :easing3)
(reanimated/set-shared-value stack-pointer-shared-value (if selected-tab? "auto" "none"))
(if selected-tab?
(reanimated/animate-shared-value-with-delay stack-opacity-shared-value 1 300 :easing3 150)
(reanimated/animate-shared-value-with-timing stack-opacity-shared-value 0 300 :easing3))))))
76 changes: 57 additions & 19 deletions src/status_im/switcher/bottom_tabs.cljs
Original file line number Diff line number Diff line change
@@ -1,30 +1,68 @@
(ns status-im.switcher.bottom-tabs
(:require [quo.react-native :as rn]
[reagent.core :as reagent]
[re-frame.core :as re-frame]
[quo2.reanimated :as reanimated]
[status-im.switcher.styles :as styles]
[status-im.switcher.animation :as animation]
[status-im.ui.components.icons.icons :as icons]))

(def selected-tab-id (reagent/atom :chats-stack))
(def selected-tab-id (atom :communities-stack))

(defn bottom-tab-pressed [tab-id]
;; Reagent atoms used for lazily loading home screen tabs
(def load-communities-tab? (reagent/atom true))
(def load-chats-tab? (reagent/atom false))
(def load-wallet-tab? (reagent/atom false))
(def load-browser-tab? (reagent/atom false))

(re-frame/reg-fx
:new-ui/reset-bottom-tabs
(fn []
(reset! selected-tab-id :communities-stack)
(reset! load-communities-tab? true)
(reset! load-chats-tab? false)
(reset! load-wallet-tab? false)
(reset! load-browser-tab? false)))

(defn bottom-tab-on-press [shared-values tab-id]
(when-not (= tab-id @selected-tab-id)
(reset! selected-tab-id tab-id)))
(reset! selected-tab-id tab-id)
(animation/bottom-tab-on-press shared-values tab-id)
(case tab-id
:communities-stack (reset! load-communities-tab? true)
:chats-stack (reset! load-chats-tab? true)
:wallet-stack (reset! load-wallet-tab? true)
:browser-stack (reset! load-browser-tab? true))))

;; TODO(parvesh) - reimplement tab with counter, once design is complete
;; (implement natively, for performance improvement)
(defn bottom-tab [icon tab-id]
[rn/touchable-opacity {:style {:padding 15}
:active-opacity 1
:on-press #(bottom-tab-pressed tab-id)}
[icons/icon icon (styles/bottom-tab-icon
(if (= tab-id @selected-tab-id)
:bottom-tabs-selected-tab
:bottom-tabs-non-selected-tab))]])
(defn bottom-tab [icon tab icons-only? shared-values]
[:>
(fn []
(let [tab-id (keyword (str tab "-stack"))
bottom-tab-original-style {:padding 16}]
(reagent/as-element
(if icons-only?
[rn/touchable-opacity {:active-opacity 1
:style bottom-tab-original-style
:on-press #(bottom-tab-on-press shared-values tab-id)}
[reanimated/view {:style (reanimated/apply-animations-to-style
{:opacity (get
shared-values
(keyword (str tab "-tab-opacity")))}
{})}
[icons/icon icon (styles/bottom-tab-icon :bottom-tabs-selected-tab)]]]
[rn/view {:style bottom-tab-original-style}
[icons/icon icon (styles/bottom-tab-icon :bottom-tabs-non-selected-tab)]]))))])

(defn tabs [shared-values icons-only?]
[rn/view {:style (styles/bottom-tabs icons-only?)}
[bottom-tab :main-icons/redesign-communities "communities" icons-only? shared-values]
[bottom-tab :main-icons/redesign-messages "chats" icons-only? shared-values]
[rn/view {:width 50}]
[bottom-tab :main-icons/redesign-wallet "wallet" icons-only? shared-values]
[bottom-tab :main-icons/redesign-browser "browser" icons-only? shared-values]])

(defn bottom-tabs []
[rn/animated-view {:style (styles/bottom-tabs)}
[bottom-tab :main-icons/redesign-messages :chats-stack]
[bottom-tab :main-icons/communities :communities-stack]
[rn/view {:width 10}]
[bottom-tab :main-icons/redesign-wallet :wallet-stack]
[bottom-tab :main-icons/browser :browser-stack]])
(defn bottom-tabs [shared-values]
[:<>
[tabs shared-values false]
[tabs shared-values true]])
2 changes: 1 addition & 1 deletion src/status_im/switcher/cards/messaging_card.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
[status-im.switcher.cards.styles :as styles]))

(defn on-press [id toggle-switcher-screen]
(toggle-switcher-screen)
(js/setTimeout toggle-switcher-screen 100)
(>evt [:chat.ui/navigate-to-chat-nav2 id true]))

;; TODO - add last message for other content types
Expand Down
30 changes: 25 additions & 5 deletions src/status_im/switcher/constants.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,51 @@
(: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)

;; extra height of switcher container for show/peek hidden cards while opening animation
(def switcher-container-height-padding 100)

(def switcher-button-radius 24)

(def switcher-button-size
(* switcher-button-radius 2))

(def switcher-pressed-scale 0.9)

(def switcher-pressed-radius
(* switcher-pressed-scale switcher-button-radius))

(def switcher-pressed-size
(* 2 switcher-pressed-radius))

(def switcher-bottom-positions
{:android
{:home-stack 17
{:home-stack 15
:chat 57}
:ios
{:home-stack 35
{:home-stack 40
:chat 67}})

(defn switcher-bottom-position [view-id]
(get-in
switcher-bottom-positions
[(keyword platform/os) view-id]))

(defn switcher-center-position [view-id]
(+ (switcher-bottom-position view-id) (/ switcher-button-size 2)))
(defn switcher-pressed-bottom-position [view-id]
(+
(get-in
switcher-bottom-positions
[(keyword platform/os) view-id])
(- switcher-button-radius switcher-pressed-radius)))

;; TODO(parvesh) - use different height for android and ios(Confirm from Design)
(defn bottom-tabs-height []
(if platform/android? 55 80))

;; TODO - move to switcher/utils.cljs
(defn dimensions []
(<sub [:dimensions/window]))

(def tabs '("communities" "chats" "wallet" "browser"))
Loading

0 comments on commit daddb3e

Please sign in to comment.