From 509ffc2a0126241b9aa1c654c9da864ed69cad9d Mon Sep 17 00:00:00 2001 From: Mohamed Javid <19339952+smohamedjavid@users.noreply.github.com> Date: Wed, 16 Nov 2022 22:13:58 +0530 Subject: [PATCH] [Feature] Added messages skeleton (#14072) * [Feature][#14025] Added Messages Skeleton while loading messages * [Improvements][#14025] Added animation to message skeleton * [Improvements][#14025] Changed to Reanimated2 for message skeleton animation * [Chores][#14025] Removed unused code * [Improvements][#14025] Added preview screen for messages skeleton * [Improvements][#14025] Style update for messages skeleton * [Chore][#14025] Indentation for message skeleton * [Improvements][#14025] On Layout calculation cleanup * [Fix][#14025] Added Skeleton on New UI only * [Chore] Moved Message Skeleton to new UI * [Feature][#14025] Added Message Skeleton on message gap * [TEMP][#14025] Added delay of preloading messages for testing * [Lint][#14025] Lint fixes for Message Gap component * [Chore][#14025] Reanimated namespace update * [Chore][#14025] React native namespace update * [Chore][#14025] Rollback preload messages --- src/react_native/reanimated.cljs | 10 ++- .../chat/components/messages_skeleton.cljs | 77 +++++++++++++++++++ .../ui/screens/chat/message/gap.cljs | 10 ++- .../ui2/screens/chat/messages/view.cljs | 12 ++- .../ui2/screens/quo2_preview/main.cljs | 4 + .../messages_skeleton.cljs | 11 +++ 6 files changed, 116 insertions(+), 8 deletions(-) create mode 100644 src/status_im/ui/screens/chat/components/messages_skeleton.cljs create mode 100644 src/status_im/ui2/screens/quo2_preview/posts_and_attachments/messages_skeleton.cljs diff --git a/src/react_native/reanimated.cljs b/src/react_native/reanimated.cljs index 93c3c79aeb..7e53182e0d 100644 --- a/src/react_native/reanimated.cljs +++ b/src/react_native/reanimated.cljs @@ -2,8 +2,9 @@ (:require ["react-native" :as rn] [reagent.core :as reagent] [clojure.string :as string] + ["react-native-linear-gradient" :default LinearGradient] ["react-native-reanimated" :default reanimated - :refer (useSharedValue useAnimatedStyle withTiming withDelay withSpring Easing Keyframe)])) + :refer (useSharedValue useAnimatedStyle withTiming withDelay withSpring withRepeat Easing Keyframe)])) ;; Animated Components (def create-animated-component (comp reagent/adapt-react-class (.-createAnimatedComponent reanimated))) @@ -12,6 +13,8 @@ (def image (reagent/adapt-react-class (.-Image reanimated))) (def touchable-opacity (create-animated-component (.-TouchableOpacity ^js rn))) +(def linear-gradient (create-animated-component LinearGradient)) + ;; Hooks (def use-shared-value useSharedValue) (def use-animated-style useAnimatedStyle) @@ -21,6 +24,7 @@ (def with-delay withDelay) (def with-spring withSpring) (def key-frame Keyframe) +(def with-repeat withRepeat) ;; Easings (def bezier (.-bezier ^js Easing)) @@ -68,3 +72,7 @@ (defn animate-shared-value-with-delay [anim val duration easing delay] (set-shared-value anim (with-delay delay (with-timing val (js-obj "duration" duration "easing" (get easings easing)))))) + +(defn animate-shared-value-with-repeat [anim val duration easing number-of-repetitions reverse?] + (set-shared-value anim (with-repeat (with-timing val (js-obj "duration" duration + "easing" (get easings easing))) number-of-repetitions reverse?))) \ No newline at end of file diff --git a/src/status_im/ui/screens/chat/components/messages_skeleton.cljs b/src/status_im/ui/screens/chat/components/messages_skeleton.cljs new file mode 100644 index 0000000000..ba7fdc450e --- /dev/null +++ b/src/status_im/ui/screens/chat/components/messages_skeleton.cljs @@ -0,0 +1,77 @@ +(ns status-im.ui.screens.chat.components.messages-skeleton + (:require [status-im.ui.components.react :as react] + [react-native.core :as rn] + [reagent.core :as reagent] + [react-native.reanimated :as reanimated] + [quo2.foundations.colors :as colors])) + +(def message-skeleton-height 54) + +(def avatar-skeleton-size 32) + +(def message-content-width [{:author 80 + :message 249} + {:author 124 + :message 156} + {:author 96 + :message 212} + {:author 112 + :message 144}]) + +;; Standlone message skeleton +(defn message-skeleton [] + [:f> + (fn [] + (let [color (colors/theme-colors colors/neutral-5 colors/neutral-70) + loading-color (colors/theme-colors colors/neutral-10 colors/neutral-60) + content-width (rand-nth message-content-width) + author-width (content-width :author) + message-width (content-width :message) + {window-width :width} (rn/use-window-dimensions) + translate-x (reanimated/use-shared-value (- window-width)) + animated-gradient-style (reanimated/apply-animations-to-style + {:transform [{:translateX translate-x}]} + {:width window-width + :height "100%"})] + (reanimated/animate-shared-value-with-repeat translate-x window-width 1000 :linear (- 1) false) + [react/masked-view + {:style {:height message-skeleton-height} + :maskElement (reagent/as-element + [rn/view {:style {:height message-skeleton-height + :flex-direction :row + :padding-vertical 11 + :background-color :transparent + :padding-left 21}} + [rn/view {:style {:height avatar-skeleton-size + :width avatar-skeleton-size + :border-radius (/ avatar-skeleton-size 2) + :background-color color + :overflow :hidden}}] + [rn/view {:style {:padding-left 8 + :background-color :transparent}} + [rn/view {:style {:height 8 + :width author-width + :border-radius 6 + :background-color color + :margin-bottom 8 + :overflow :hidden}}] + [rn/view {:style {:height 16 + :width message-width + :border-radius 6 + :overflow :hidden + :background-color color}}]]])} + [rn/view {:style {:flex 1 + :background-color color}} + [reanimated/linear-gradient {:colors [color color loading-color color color] + :start {:x 0 :y 0} + :end {:x 1 :y 0} + :style animated-gradient-style}]]]))]) + +(defn messages-skeleton [parent-height] + (let [number-of-skeletons (int (Math/floor (/ parent-height message-skeleton-height)))] + [rn/view {:style {:background-color (colors/theme-colors + colors/white + colors/neutral-90) + :flex 1}} + (for [n (range number-of-skeletons)] + [message-skeleton {:key n}])])) \ No newline at end of file diff --git a/src/status_im/ui/screens/chat/message/gap.cljs b/src/status_im/ui/screens/chat/message/gap.cljs index 8efaa16a70..50c4b811b6 100644 --- a/src/status_im/ui/screens/chat/message/gap.cljs +++ b/src/status_im/ui/screens/chat/message/gap.cljs @@ -4,6 +4,7 @@ [re-frame.core :as re-frame] [status-im.i18n.i18n :as i18n] [status-im.utils.datetime :as datetime] + [status-im.ui.screens.chat.components.messages-skeleton :as messages-skeleton] [status-im.ui.screens.chat.styles.input.gap :as style])) (defn on-press @@ -18,16 +19,17 @@ chat-id] connected? [:mailserver/connected?] use-status-nodes? [:mailserver/use-status-nodes?] - first-gap? (= gap-ids #{:first-gap})] + first-gap? (= gap-ids #{:first-gap}) + window-height [:dimensions/window-height]] (when (or (not first-gap?) public? community?) - [react/view {:style (style/gap-container)} + [react/view {:style (when-not in-progress? style/gap-container)} [react/touchable-highlight {:on-press (when (and (not in-progress?) use-status-nodes? connected?) (on-press chat-id gap-ids)) - :style style/touchable} + :style {:height (if in-progress? window-height 48)}} [react/view {:style style/label-container} (if in-progress? - [react/activity-indicator] + [messages-skeleton/messages-skeleton window-height] [react/nested-text {:style (style/gap-text (and connected? use-status-nodes?))} (i18n/label (if first-gap? :t/load-more-messages :t/fetch-messages)) diff --git a/src/status_im/ui2/screens/chat/messages/view.cljs b/src/status_im/ui2/screens/chat/messages/view.cljs index c019669c88..4eef9758be 100644 --- a/src/status_im/ui2/screens/chat/messages/view.cljs +++ b/src/status_im/ui2/screens/chat/messages/view.cljs @@ -9,6 +9,7 @@ [status-im.ui.screens.chat.group :as chat.group] [status-im.ui.screens.chat.message.datemark :as message-datemark] [status-im.ui.screens.chat.message.gap :as gap] + [status-im.ui.screens.chat.components.messages-skeleton :as messages-skeleton] [status-im.utils.utils :as utils] [status-im.utils.platform :as platform] [status-im.ui.screens.chat.state :as state] @@ -19,6 +20,11 @@ (defonce show-floating-scroll-down-button (reagent/atom false)) (defonce messages-list-ref (atom nil)) +(def messages-view-height (reagent/atom 0)) + +(defn on-messages-view-layout [^js ev] + (reset! messages-view-height (-> ev .-nativeEvent .-layout .-height))) + (def list-key-fn #(or (:message-id %) (:value %))) (def list-ref #(reset! messages-list-ref %)) @@ -63,8 +69,7 @@ all-loaded? (<sub [:chats/all-loaded? chat-id])] [rn/view {:style (when platform/android? {:scaleY -1})} (if (or loading-messages? (not chat-id) (not all-loaded?)) - [rn/view {:height 324 :align-items :center :justify-content :center} - [rn/activity-indicator {:animating true}]] + [messages-skeleton/messages-skeleton @messages-view-height] [chat-intro-header-container chat no-messages?])])) (defn list-header [{:keys [chat-id chat-type invitation-admin]}] @@ -186,6 +191,7 @@ :on-scroll on-scroll ;;TODO https://github.com/facebook/react-native/issues/30034 :inverted (when platform/ios? true) - :style (when platform/android? {:scaleY -1})})] + :style (when platform/android? {:scaleY -1}) + :on-layout on-messages-view-layout})] (when @show-floating-scroll-down-button [floating-scroll-down-button show-input?])])) diff --git a/src/status_im/ui2/screens/quo2_preview/main.cljs b/src/status_im/ui2/screens/quo2_preview/main.cljs index a4433b019d..d4e738de79 100644 --- a/src/status_im/ui2/screens/quo2_preview/main.cljs +++ b/src/status_im/ui2/screens/quo2_preview/main.cljs @@ -31,6 +31,7 @@ [status-im.ui2.screens.quo2-preview.messages.gap :as messages-gap] [status-im.ui2.screens.quo2-preview.messages.system-message :as system-message] [status-im.ui2.screens.quo2-preview.notifications.activity-logs :as activity-logs] + [status-im.ui2.screens.quo2-preview.posts-and-attachments.messages-skeleton :as messages-skeleton] [status-im.ui2.screens.quo2-preview.reactions.react :as react] [status-im.ui2.screens.quo2-preview.selectors.disclaimer :as disclaimer] [status-im.ui2.screens.quo2-preview.selectors.selectors :as selectors] @@ -144,6 +145,9 @@ :notifications [{:name :activity-logs :insets {:top false} :component activity-logs/preview-activity-logs}] + :posts-and-attachments [{:name :messages-skeleton + :insets {:top false} + :component messages-skeleton/preview-messages-skeleton}] :reactions [{:name :react :insets {:top false} :component react/preview-react}] diff --git a/src/status_im/ui2/screens/quo2_preview/posts_and_attachments/messages_skeleton.cljs b/src/status_im/ui2/screens/quo2_preview/posts_and_attachments/messages_skeleton.cljs new file mode 100644 index 0000000000..3e3cef509b --- /dev/null +++ b/src/status_im/ui2/screens/quo2_preview/posts_and_attachments/messages_skeleton.cljs @@ -0,0 +1,11 @@ +(ns status-im.ui2.screens.quo2-preview.posts-and-attachments.messages-skeleton + (:require [quo.react-native :as rn] + [quo2.foundations.colors :as colors] + [status-im.ui.screens.chat.components.messages-skeleton :as messages-skeleton])) + +(defn preview-messages-skeleton [] + [rn/view {:background-color (colors/theme-colors + colors/white + colors/neutral-90) + :flex 1} + [messages-skeleton/messages-skeleton]]) \ No newline at end of file