Skip to content

Commit

Permalink
New TopBar animation (#17582)
Browse files Browse the repository at this point in the history
  • Loading branch information
ibrkhalil authored Nov 3, 2023
1 parent 8d3558f commit 132e538
Show file tree
Hide file tree
Showing 10 changed files with 250 additions and 109 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"react-native-image-crop-picker": "git+https://github.com/status-im/react-native-image-crop-picker.git#refs/tags/v0.36.2-status.0",
"react-native-image-resizer": "^1.2.3",
"react-native-image-viewing": "git+https://github.com/status-im/react-native-image-viewing.git#refs/tags/v0.2.1.status",
"react-native-intersection-observer": "^0.2.0",
"react-native-keychain": "git+https://github.com/status-im/react-native-keychain.git#refs/tags/v.3.0.0-5-status",
"react-native-languages": "^3.0.2",
"react-native-linear-gradient": "^2.8.0",
Expand Down
6 changes: 6 additions & 0 deletions src/mocks/js_dependencies.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,11 @@
{:clamp nil
:withPause (fn [])})

(def react-native-intersection-observer
#js
{:InView #js {}
:IOFlatList #js {}})

(def react-native-languages
(clj->js {:default {:language "en"
:addEventListener (fn [])
Expand Down Expand Up @@ -426,6 +431,7 @@
"react-native-transparent-video" react-native-transparent-video
"react-native-orientation-locker" react-native-orientation-locker
"react-native-gifted-charts" react-native-gifted-charts
"react-native-intersection-observer" react-native-intersection-observer
"../resources/data/emojis/en.json" (js/JSON.parse (slurp
"./resources/data/emojis/en.json"))
"../src/js/worklets/core.js" worklet-factory
Expand Down
12 changes: 12 additions & 0 deletions src/react_native/react_native_intersection_observer.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
(ns react-native.react-native-intersection-observer
(:require
["react-native-intersection-observer" :refer [InView IOFlatList]]
[react-native.flat-list :refer [base-list-props]]
[reagent.core :as reagent]))

(def view (reagent/adapt-react-class InView))
(def flat-list-comp (reagent/adapt-react-class IOFlatList))

(defn flat-list
[props]
[flat-list-comp (base-list-props props)])
15 changes: 12 additions & 3 deletions src/status_im2/contexts/chat/composer/actions/view.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,10 @@
[opacity]
[reanimated/view {:style (reanimated/apply-animations-to-style {:opacity opacity} {})}
[quo/composer-button
{:on-press #(js/alert "to be implemented")
{:on-press (fn []
(rf/dispatch [:chat.ui/set-input-focused false])
(rn/dismiss-keyboard!)
(js/alert "to be implemented"))
:icon :i/audio}]])

(defn audio-button
Expand Down Expand Up @@ -213,13 +216,19 @@
[]
[quo/composer-button
{:icon :i/reaction
:on-press #(js/alert "to be implemented")
:on-press (fn []
(rf/dispatch [:chat.ui/set-input-focused false])
(rn/dismiss-keyboard!)
(js/alert "to be implemented"))
:container-style {:margin-right 12}}])

(defn format-button
[]
[quo/composer-button
{:on-press #(js/alert "to be implemented")
{:on-press (fn []
(rf/dispatch [:chat.ui/set-input-focused false])
(rn/dismiss-keyboard!)
(js/alert "to be implemented"))
:icon :i/format}])

(defn view
Expand Down
4 changes: 3 additions & 1 deletion src/status_im2/contexts/chat/events.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,9 @@
(chat.state/reset-visible-item)
(rf/merge cofx
(merge
{:db (dissoc db :current-chat-id)
{:db (-> db
(dissoc :current-chat-id)
(assoc-in [:chat/inputs chat-id :focused?] false))
:async-storage-set {:chat-id nil
:key-uid nil}}
(let [community-id (get-in db [:chats chat-id :community-id])]
Expand Down
4 changes: 3 additions & 1 deletion src/status_im2/contexts/chat/messages/content/view.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,9 @@
:outgoing-status outgoing-status})
:on-press (fn []
(if (and platform/ios? keyboard-shown?)
(rn/dismiss-keyboard!)
(do
(rf/dispatch [:chat.ui/set-input-focused false])
(rn/dismiss-keyboard!))
(when (and outgoing
(not= outgoing-status :sending)
(not @show-delivery-state?))
Expand Down
92 changes: 68 additions & 24 deletions src/status_im2/contexts/chat/messages/list/view.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
[react-native.core :as rn]
[react-native.hooks :as hooks]
[react-native.platform :as platform]
[react-native.react-native-intersection-observer :as rnio]
[react-native.reanimated :as reanimated]
[status-im.ui.screens.chat.group :as chat.group]
[status-im.ui.screens.chat.message.gap :as message.gap]
Expand All @@ -24,9 +25,12 @@
(defonce ^:const threshold-percentage-to-show-floating-scroll-down-button 75)
(defonce ^:const loading-indicator-extra-spacing 250)
(defonce ^:const loading-indicator-page-loading-height 100)
(defonce ^:const scroll-animation-input-range [50 125])
(defonce ^:const scroll-animation-input-range [0 50])
(defonce ^:const min-message-height 32)

(defonce ^:const topbar-visible-scroll-y-value 85)
(defonce ^:const topbar-invisible-scroll-y-value 135)
(defonce ^:const minimum-scroll-y-topbar-overlaying-avatar 400)
(def root-margin-for-big-name-visibility-detector {:bottom -35})
(defonce messages-list-ref (atom nil))

(defn list-key-fn [{:keys [message-id value]}] (or message-id value))
Expand Down Expand Up @@ -64,15 +68,15 @@
(= :message (:type first-not-visible)))
first-not-visible))))))


(defn list-on-end-reached
[scroll-y]
[scroll-y on-end-reached?]
;; FIXME: that's a bit of a hack but we need to update `scroll-y` once the new messages
;; are fetched in order for the header to work properly
(let [on-loaded (fn [n]
(reanimated/set-shared-value scroll-y
(+ (reanimated/get-shared-value scroll-y)
(* n 200))))]
(reset! on-end-reached? true)
(if @state/scrolling
(rf/dispatch [:chat.ui/load-more-messages-for-current-chat on-loaded])
(background-timer/set-timeout #(rf/dispatch [:chat.ui/load-more-messages-for-current-chat
Expand Down Expand Up @@ -194,7 +198,7 @@

(defn f-list-footer
[{:keys [chat scroll-y cover-bg-color on-layout theme messages-view-height
messages-view-header-height]}]
messages-view-header-height big-name-visible?]}]
(let [{:keys [chat-id chat-name emoji chat-type
group-chat]} chat
all-loaded? (rf/sub [:chats/all-loaded? chat-id])
Expand Down Expand Up @@ -227,9 +231,11 @@
:display-name display-name
:online? online?
:profile-picture photo-path}])]
[rn/view
{:style {:flex-direction :row
:margin-top (if group-chat 54 12)}}
[rnio/view
{:on-change (fn [view-visible?]
(reset! big-name-visible? view-visible?))
:style {:flex-direction :row
:margin-top (if group-chat 54 12)}}
[quo/text
{:weight :semi-bold
:size :heading-1
Expand Down Expand Up @@ -275,14 +281,31 @@
[message/message message-data context keyboard-shown?])]))

(defn scroll-handler
[event scroll-y]
(let [content-size-y (- (oops/oget event "nativeEvent.contentSize.height")
(oops/oget event "nativeEvent.layoutMeasurement.height"))
current-y (oops/oget event "nativeEvent.contentOffset.y")]
(reanimated/set-shared-value scroll-y (- content-size-y current-y))))
[event scroll-y animate-topbar-opacity? on-end-reached? animate-topbar-name?]
(let [content-size-y (- (oops/oget event "nativeEvent.contentSize.height")
(oops/oget event "nativeEvent.layoutMeasurement.height"))
current-y (oops/oget event "nativeEvent.contentOffset.y")
scroll-distance (- content-size-y current-y)]
(when (and @on-end-reached? (pos? scroll-distance))
(reset! on-end-reached? false))
(if (< topbar-visible-scroll-y-value scroll-distance)
(reset! animate-topbar-opacity? true)
(reset! animate-topbar-opacity? false))
(if (< topbar-invisible-scroll-y-value scroll-distance)
(reset! animate-topbar-name? true)
(reset! animate-topbar-name? false))
(reanimated/set-shared-value scroll-y scroll-distance)))

(defn f-messages-list-content
[{:keys [chat insets scroll-y content-height cover-bg-color keyboard-shown? inner-state-atoms]}]
[{:keys [chat insets scroll-y content-height cover-bg-color keyboard-shown? inner-state-atoms
big-name-visible? animate-topbar-opacity? composer-active?
on-end-reached? animate-topbar-name?]}]
(rn/use-effect (fn []
(if (and (not @on-end-reached?)
(< topbar-visible-scroll-y-value (reanimated/get-shared-value scroll-y)))
(reset! animate-topbar-opacity? true)
(reset! animate-topbar-opacity? false)))
[composer-active? @on-end-reached? @animate-topbar-opacity?])
(let [theme (quo.theme/use-theme-value)
{window-height :height} (rn/get-window)
{:keys [keyboard-height]} (hooks/use-keyboard)
Expand All @@ -294,8 +317,9 @@
messages-view-height
messages-view-header-height]} inner-state-atoms]
[rn/view {:style {:flex 1}}
[rn/flat-list
{:key-fn list-key-fn
[rnio/flat-list
{:root-margin root-margin-for-big-name-visibility-detector
:key-fn list-key-fn
:ref list-ref
:bounces false
:header [:<>
Expand All @@ -311,7 +335,8 @@
%
messages-view-header-height)
:messages-view-header-height messages-view-header-height
:messages-view-height messages-view-height}]
:messages-view-height messages-view-height
:big-name-visible? big-name-visible?}]
:data messages
:render-data {:theme theme
:context context
Expand All @@ -320,10 +345,23 @@
:render-fn render-fn
:on-viewable-items-changed on-viewable-items-changed
:on-content-size-change (fn [_ y]
;; NOTE(alwx): here we set the initial value of `scroll-y`
;; which is needed because by default the chat is
;; scrolled to the bottom and no initial `on-scroll`
;; event is getting triggered
(if (or
(< minimum-scroll-y-topbar-overlaying-avatar
(reanimated/get-shared-value scroll-y))
(< topbar-visible-scroll-y-value
(reanimated/get-shared-value scroll-y)))
(reset! animate-topbar-opacity? true)
(reset! animate-topbar-opacity? false))
(when-not (or
(not @big-name-visible?)
(= :initial-render @big-name-visible?)
(pos? (reanimated/get-shared-value
scroll-y)))
(reset! on-end-reached? false))
;; NOTE(alwx): here we set the initial value of
;; `scroll-y` which is needed because by default the
;; chat is scrolled to the bottom and no initial
;; `on-scroll` event is getting triggered
(let [scroll-y-shared (reanimated/get-shared-value
scroll-y)
content-height-shared (reanimated/get-shared-value
Expand All @@ -337,19 +375,25 @@
(- (when keyboard-shown?
keyboard-height))))
(reanimated/set-shared-value content-height y))))
:on-end-reached #(list-on-end-reached scroll-y)
:on-end-reached #(list-on-end-reached scroll-y on-end-reached?)
:on-scroll-to-index-failed identity
:scroll-indicator-insets {:top (if (:able-to-send-message? context)
(- composer.constants/composer-default-height 16)
0)}
:keyboard-dismiss-mode :interactive
:keyboard-should-persist-taps :always
:on-scroll-begin-drag rn/dismiss-keyboard!
:on-scroll-begin-drag #(do
(rf/dispatch [:chat.ui/set-input-focused false])
(rn/dismiss-keyboard!))
:on-momentum-scroll-begin state/start-scrolling
:on-momentum-scroll-end state/stop-scrolling
:scroll-event-throttle 16
:on-scroll (fn [event]
(scroll-handler event scroll-y)
(scroll-handler event
scroll-y
animate-topbar-opacity?
on-end-reached?
animate-topbar-name?)
(on-scroll event show-floating-scroll-down-button?))
:style (add-inverted-y-android
{:background-color (if all-loaded?
Expand Down
Loading

0 comments on commit 132e538

Please sign in to comment.