mirror of
https://github.com/status-im/status-react.git
synced 2025-01-11 03:26:31 +00:00
[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
This commit is contained in:
parent
e44d4c83c0
commit
509ffc2a01
@ -2,8 +2,9 @@
|
|||||||
(:require ["react-native" :as rn]
|
(:require ["react-native" :as rn]
|
||||||
[reagent.core :as reagent]
|
[reagent.core :as reagent]
|
||||||
[clojure.string :as string]
|
[clojure.string :as string]
|
||||||
|
["react-native-linear-gradient" :default LinearGradient]
|
||||||
["react-native-reanimated" :default reanimated
|
["react-native-reanimated" :default reanimated
|
||||||
:refer (useSharedValue useAnimatedStyle withTiming withDelay withSpring Easing Keyframe)]))
|
:refer (useSharedValue useAnimatedStyle withTiming withDelay withSpring withRepeat Easing Keyframe)]))
|
||||||
|
|
||||||
;; Animated Components
|
;; Animated Components
|
||||||
(def create-animated-component (comp reagent/adapt-react-class (.-createAnimatedComponent reanimated)))
|
(def create-animated-component (comp reagent/adapt-react-class (.-createAnimatedComponent reanimated)))
|
||||||
@ -12,6 +13,8 @@
|
|||||||
(def image (reagent/adapt-react-class (.-Image reanimated)))
|
(def image (reagent/adapt-react-class (.-Image reanimated)))
|
||||||
(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))
|
||||||
|
|
||||||
;; Hooks
|
;; Hooks
|
||||||
(def use-shared-value useSharedValue)
|
(def use-shared-value useSharedValue)
|
||||||
(def use-animated-style useAnimatedStyle)
|
(def use-animated-style useAnimatedStyle)
|
||||||
@ -21,6 +24,7 @@
|
|||||||
(def with-delay withDelay)
|
(def with-delay withDelay)
|
||||||
(def with-spring withSpring)
|
(def with-spring withSpring)
|
||||||
(def key-frame Keyframe)
|
(def key-frame Keyframe)
|
||||||
|
(def with-repeat withRepeat)
|
||||||
|
|
||||||
;; Easings
|
;; Easings
|
||||||
(def bezier (.-bezier ^js Easing))
|
(def bezier (.-bezier ^js Easing))
|
||||||
@ -68,3 +72,7 @@
|
|||||||
(defn animate-shared-value-with-delay [anim val duration easing delay]
|
(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
|
(set-shared-value anim (with-delay delay (with-timing val (js-obj "duration" duration
|
||||||
"easing" (get easings easing))))))
|
"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?)))
|
@ -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}])]))
|
@ -4,6 +4,7 @@
|
|||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
[status-im.i18n.i18n :as i18n]
|
[status-im.i18n.i18n :as i18n]
|
||||||
[status-im.utils.datetime :as datetime]
|
[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]))
|
[status-im.ui.screens.chat.styles.input.gap :as style]))
|
||||||
|
|
||||||
(defn on-press
|
(defn on-press
|
||||||
@ -18,16 +19,17 @@
|
|||||||
chat-id]
|
chat-id]
|
||||||
connected? [:mailserver/connected?]
|
connected? [:mailserver/connected?]
|
||||||
use-status-nodes? [:mailserver/use-status-nodes?]
|
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?)
|
(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
|
[react/touchable-highlight
|
||||||
{:on-press (when (and (not in-progress?) use-status-nodes? connected?)
|
{:on-press (when (and (not in-progress?) use-status-nodes? connected?)
|
||||||
(on-press chat-id gap-ids))
|
(on-press chat-id gap-ids))
|
||||||
:style style/touchable}
|
:style {:height (if in-progress? window-height 48)}}
|
||||||
[react/view {:style style/label-container}
|
[react/view {:style style/label-container}
|
||||||
(if in-progress?
|
(if in-progress?
|
||||||
[react/activity-indicator]
|
[messages-skeleton/messages-skeleton window-height]
|
||||||
[react/nested-text
|
[react/nested-text
|
||||||
{:style (style/gap-text (and connected? use-status-nodes?))}
|
{:style (style/gap-text (and connected? use-status-nodes?))}
|
||||||
(i18n/label (if first-gap? :t/load-more-messages :t/fetch-messages))
|
(i18n/label (if first-gap? :t/load-more-messages :t/fetch-messages))
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
[status-im.ui.screens.chat.group :as chat.group]
|
[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.datemark :as message-datemark]
|
||||||
[status-im.ui.screens.chat.message.gap :as gap]
|
[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.utils :as utils]
|
||||||
[status-im.utils.platform :as platform]
|
[status-im.utils.platform :as platform]
|
||||||
[status-im.ui.screens.chat.state :as state]
|
[status-im.ui.screens.chat.state :as state]
|
||||||
@ -19,6 +20,11 @@
|
|||||||
(defonce show-floating-scroll-down-button (reagent/atom false))
|
(defonce show-floating-scroll-down-button (reagent/atom false))
|
||||||
(defonce messages-list-ref (atom nil))
|
(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-key-fn #(or (:message-id %) (:value %)))
|
||||||
(def list-ref #(reset! messages-list-ref %))
|
(def list-ref #(reset! messages-list-ref %))
|
||||||
|
|
||||||
@ -63,8 +69,7 @@
|
|||||||
all-loaded? (<sub [:chats/all-loaded? chat-id])]
|
all-loaded? (<sub [:chats/all-loaded? chat-id])]
|
||||||
[rn/view {:style (when platform/android? {:scaleY -1})}
|
[rn/view {:style (when platform/android? {:scaleY -1})}
|
||||||
(if (or loading-messages? (not chat-id) (not all-loaded?))
|
(if (or loading-messages? (not chat-id) (not all-loaded?))
|
||||||
[rn/view {:height 324 :align-items :center :justify-content :center}
|
[messages-skeleton/messages-skeleton @messages-view-height]
|
||||||
[rn/activity-indicator {:animating true}]]
|
|
||||||
[chat-intro-header-container chat no-messages?])]))
|
[chat-intro-header-container chat no-messages?])]))
|
||||||
|
|
||||||
(defn list-header [{:keys [chat-id chat-type invitation-admin]}]
|
(defn list-header [{:keys [chat-id chat-type invitation-admin]}]
|
||||||
@ -186,6 +191,7 @@
|
|||||||
:on-scroll on-scroll
|
:on-scroll on-scroll
|
||||||
;;TODO https://github.com/facebook/react-native/issues/30034
|
;;TODO https://github.com/facebook/react-native/issues/30034
|
||||||
:inverted (when platform/ios? true)
|
: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
|
(when @show-floating-scroll-down-button
|
||||||
[floating-scroll-down-button show-input?])]))
|
[floating-scroll-down-button show-input?])]))
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
[status-im.ui2.screens.quo2-preview.messages.gap :as messages-gap]
|
[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.messages.system-message :as system-message]
|
||||||
[status-im.ui2.screens.quo2-preview.notifications.activity-logs :as activity-logs]
|
[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.reactions.react :as react]
|
||||||
[status-im.ui2.screens.quo2-preview.selectors.disclaimer :as disclaimer]
|
[status-im.ui2.screens.quo2-preview.selectors.disclaimer :as disclaimer]
|
||||||
[status-im.ui2.screens.quo2-preview.selectors.selectors :as selectors]
|
[status-im.ui2.screens.quo2-preview.selectors.selectors :as selectors]
|
||||||
@ -144,6 +145,9 @@
|
|||||||
:notifications [{:name :activity-logs
|
:notifications [{:name :activity-logs
|
||||||
:insets {:top false}
|
:insets {:top false}
|
||||||
:component activity-logs/preview-activity-logs}]
|
:component activity-logs/preview-activity-logs}]
|
||||||
|
:posts-and-attachments [{:name :messages-skeleton
|
||||||
|
:insets {:top false}
|
||||||
|
:component messages-skeleton/preview-messages-skeleton}]
|
||||||
:reactions [{:name :react
|
:reactions [{:name :react
|
||||||
:insets {:top false}
|
:insets {:top false}
|
||||||
:component react/preview-react}]
|
:component react/preview-react}]
|
||||||
|
@ -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]])
|
Loading…
x
Reference in New Issue
Block a user