feat(chats): Implement a simpler chat screen (#21313)
* Change `defonce ^:const` -> `def ^:const` in `status-im.contexts.chat.messenger.messages.list.view` to be more REPL friendly * Remove animations from `status-im.contexts.chat.messenger.messages.pin.banner.style` * Simplify placeholder for messages * Replace shared-value with a ratom usage since no animations were performed. * Fix the style for the new designs and remove now unnecessary animations * Improve chat component implementation The previous implementation has two main problems: 1. It is creating atoms and ratoms in non-form-2-components. 2. Conditionally uses a hook: `rn/use-mount` in `lazy-chat-screen`. The new implementation fixes the previous problems, improves the readability and passes only the props needed to its children. * Remove action buttons from the chat screen * Remove now unused code * Replace reanimated/view -> rn/view where no animations are made
This commit is contained in:
parent
3a4b58f32f
commit
63d0aaca2a
|
@ -1,47 +0,0 @@
|
|||
import { useDerivedValue, withTiming, interpolate } from 'react-native-reanimated';
|
||||
|
||||
export function navigationHeaderOpacity(distanceFromListTop, isAllLoaded, isCalculationsComplete, startPosition) {
|
||||
return useDerivedValue(function () {
|
||||
'worklet';
|
||||
const isCalculationsCompleteValue = isCalculationsComplete.value;
|
||||
if (distanceFromListTop.value < startPosition && isAllLoaded.value) {
|
||||
return isCalculationsCompleteValue ? withTiming(0) : 0;
|
||||
} else {
|
||||
return isCalculationsCompleteValue ? withTiming(1) : 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function navigationHeaderPosition(distanceFromListTop, isAllLoaded, topBarHeight, startPosition) {
|
||||
return useDerivedValue(function () {
|
||||
'worklet';
|
||||
return distanceFromListTop.value < startPosition && isAllLoaded.value ? withTiming(topBarHeight) : withTiming(0);
|
||||
});
|
||||
}
|
||||
|
||||
export function navigationButtonsCompleteOpacity(isCalculationComplete) {
|
||||
return useDerivedValue(function () {
|
||||
'worklet';
|
||||
return isCalculationComplete.value ? withTiming(1) : 0;
|
||||
});
|
||||
}
|
||||
|
||||
export function interpolateNavigationViewOpacity(props) {
|
||||
return useDerivedValue(function () {
|
||||
'worklet';
|
||||
const {
|
||||
'all-loaded?': isAllLoaded,
|
||||
'end-position': endPosition,
|
||||
'start-position': startPosition,
|
||||
'distance-from-list-top': distanceFromListTop,
|
||||
} = props;
|
||||
if (isAllLoaded.value) {
|
||||
return interpolate(distanceFromListTop.value, [startPosition, endPosition], [0, 1], {
|
||||
extrapolateLeft: 'clamp',
|
||||
extrapolateRight: 'clamp',
|
||||
});
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
import { useDerivedValue } from 'react-native-reanimated';
|
||||
|
||||
export function placeholderOpacity(isCalculationsComplete) {
|
||||
return useDerivedValue(function () {
|
||||
'worklet';
|
||||
return isCalculationsComplete.value ? 0 : 1;
|
||||
});
|
||||
}
|
||||
|
||||
export function placeholderZIndex(isCalculationsComplete) {
|
||||
return useDerivedValue(function () {
|
||||
'worklet';
|
||||
return isCalculationsComplete.value ? 0 : 2;
|
||||
});
|
||||
}
|
|
@ -17,7 +17,7 @@
|
|||
user])
|
||||
|
||||
(defn view
|
||||
[{:keys [layout-height]}]
|
||||
[layout-height]
|
||||
(let [suggestions (rf/sub [:chat/mention-suggestions])
|
||||
suggestions? (seq suggestions)
|
||||
theme (quo.theme/use-theme)
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
:default-value default-value}])))
|
||||
|
||||
(defn view
|
||||
[props]
|
||||
[layout-height]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
bottom (safe-area/get-bottom)
|
||||
input-ref (rn/use-ref-atom nil)
|
||||
|
@ -43,7 +43,7 @@
|
|||
(rf/dispatch [:chat/set-input-ref value])
|
||||
(reset! input-ref value)))]
|
||||
[rn/view {:style {:margin-bottom bottom}}
|
||||
[mentions/view props]
|
||||
[mentions/view layout-height]
|
||||
[quo/separator]
|
||||
[rn/view {:style {:padding-horizontal 20 :padding-top 20}}
|
||||
[:<>
|
||||
|
|
|
@ -3,15 +3,4 @@
|
|||
;;;; Navigation
|
||||
(def ^:const top-bar-height 56)
|
||||
(def ^:const pinned-banner-height 40)
|
||||
(def ^:const header-container-top-margin 48)
|
||||
(def ^:const header-container-radius 20)
|
||||
(def ^:const header-animation-distance 20)
|
||||
(def ^:const content-animation-start-position-android 130)
|
||||
(def ^:const content-animation-start-position-ios 124)
|
||||
;; Note - We should also consider height of bio for banner animation starting position
|
||||
;; Todo - Should be updated once New-profile implemation is complete
|
||||
(def ^:const pinned-banner-animation-start-position 148)
|
||||
|
||||
(def ^:const default-extrapolation-option
|
||||
{:extrapolateLeft "clamp"
|
||||
:extrapolateRight "clamp"})
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
(ns status-im.contexts.chat.messenger.messages.list.view
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.ui.screens.chat.group :as chat.group]
|
||||
[oops.core :as oops]
|
||||
[quo.core :as quo]
|
||||
|
@ -25,8 +24,8 @@
|
|||
[utils.re-frame :as rf]
|
||||
[utils.worklets.chat.messenger.messages :as worklets]))
|
||||
|
||||
(defonce ^:const distance-from-last-message 4)
|
||||
(defonce ^:const loading-indicator-page-loading-height 100)
|
||||
(def ^:const distance-from-last-message 4)
|
||||
(def ^:const loading-indicator-page-loading-height 100)
|
||||
|
||||
(defn list-key-fn [{:keys [message-id value]}] (or message-id value))
|
||||
(defn list-ref [ref] (reset! state/messages-list-ref ref))
|
||||
|
@ -60,44 +59,17 @@
|
|||
on-loaded])
|
||||
(if platform/low-device? 700 100)))))
|
||||
|
||||
(defn- contact-icon
|
||||
[{:keys [ens-verified added?]} theme]
|
||||
(when (or ens-verified added?)
|
||||
[rn/view
|
||||
{:style {:margin-left 4}}
|
||||
(if ens-verified
|
||||
[quo/icon :i/verified
|
||||
{:no-color true
|
||||
:size 20
|
||||
:color (colors/theme-colors
|
||||
(colors/custom-color :success 50)
|
||||
(colors/custom-color :success 60)
|
||||
theme)}]
|
||||
(when added?
|
||||
[quo/icon :i/contact
|
||||
{:no-color true
|
||||
:size 20
|
||||
:color (colors/theme-colors colors/primary-50 colors/primary-60 theme)}]))]))
|
||||
|
||||
(defn- skeleton-list-props
|
||||
[content parent-height animated?]
|
||||
{:content content
|
||||
:parent-height parent-height
|
||||
:animated? animated?})
|
||||
|
||||
(defn loading-view
|
||||
[chat-id {:keys [window-height]}]
|
||||
[{:keys [chat-id window-height]}]
|
||||
(let [messages (rf/sub [:chats/raw-chat-messages-stream chat-id])
|
||||
loading-first-page? (= (count messages) 0)
|
||||
top-spacing (if loading-first-page?
|
||||
0
|
||||
(+ messages.constants/top-bar-height (safe-area/get-top)))
|
||||
parent-height (if loading-first-page?
|
||||
window-height
|
||||
loading-indicator-page-loading-height)]
|
||||
[rn/view {:padding-top top-spacing}
|
||||
;; Don't use animated loading skeleton https://github.com/status-im/status-mobile/issues/17426
|
||||
[quo/skeleton-list (skeleton-list-props :messages parent-height false)]]))
|
||||
[quo/skeleton-list
|
||||
{:content :messages
|
||||
:parent-height parent-height
|
||||
:animated? false}]))
|
||||
|
||||
(defn header-height
|
||||
[{:keys [insets able-to-send-message? images reply edit link-previews? input-content-height]}]
|
||||
|
@ -125,84 +97,6 @@
|
|||
(+ (:bottom insets)))
|
||||
(- 70 (:bottom insets))))
|
||||
|
||||
(defn list-header
|
||||
[insets able-to-send-message?]
|
||||
(let [header-data {:insets insets
|
||||
:able-to-send-message? able-to-send-message?
|
||||
:input-content-height (:input-content-height (rf/sub [:chats/current-chat-input]))
|
||||
:images (rf/sub [:chats/sending-image])
|
||||
:reply (rf/sub [:chats/reply-message])
|
||||
:edit (rf/sub [:chats/edit-message])
|
||||
:link-previews? (or (rf/sub [:chats/link-previews?])
|
||||
(rf/sub [:chats/status-link-previews?]))}]
|
||||
[rn/view {:style {:height (header-height header-data)}}]))
|
||||
|
||||
(defn list-footer-avatar
|
||||
[{:keys [distance-from-list-top display-name online? profile-picture theme group-chat color
|
||||
emoji chat-type chat-name empty-chat?]}]
|
||||
(let [scale (reanimated/interpolate
|
||||
distance-from-list-top
|
||||
[0 (if empty-chat? 0 messages.constants/header-container-top-margin)]
|
||||
[1 0.4]
|
||||
messages.constants/default-extrapolation-option)
|
||||
top (reanimated/interpolate
|
||||
distance-from-list-top
|
||||
[0 (if empty-chat? 0 messages.constants/header-container-top-margin)]
|
||||
[-44 -12]
|
||||
messages.constants/default-extrapolation-option)
|
||||
left (reanimated/interpolate
|
||||
distance-from-list-top
|
||||
[0 (if empty-chat? 0 messages.constants/header-container-top-margin)]
|
||||
[16 -8]
|
||||
messages.constants/default-extrapolation-option)
|
||||
community-channel? (= chat-type constants/community-chat-type)]
|
||||
[reanimated/view
|
||||
{:style (style/header-image scale top left theme)}
|
||||
(cond
|
||||
community-channel?
|
||||
[quo/channel-avatar
|
||||
{:size :size-80
|
||||
:full-name chat-name
|
||||
:customization-color color
|
||||
:emoji (when-not (string/blank? emoji)
|
||||
(string/trim emoji))}]
|
||||
group-chat
|
||||
[quo/group-avatar
|
||||
{:customization-color color
|
||||
:size :size-80
|
||||
:picture profile-picture
|
||||
:chat-name chat-name}]
|
||||
:else
|
||||
[quo/user-avatar
|
||||
{:full-name display-name
|
||||
:online? online?
|
||||
:profile-picture profile-picture
|
||||
:size :big}])]))
|
||||
|
||||
(defn chat-display-name
|
||||
[{:keys [distance-from-list-top display-name contact theme empty-chat?]}]
|
||||
(let [top (reanimated/interpolate
|
||||
distance-from-list-top
|
||||
[0 (if empty-chat? 0 messages.constants/header-container-top-margin)]
|
||||
[0 -35]
|
||||
messages.constants/default-extrapolation-option)
|
||||
left (reanimated/interpolate
|
||||
distance-from-list-top
|
||||
[0 (if empty-chat? 0 messages.constants/header-container-top-margin)]
|
||||
[0 40]
|
||||
messages.constants/default-extrapolation-option)]
|
||||
[reanimated/view
|
||||
{:style (style/user-name-container top left)}
|
||||
[rn/view
|
||||
{:style style/user-name}
|
||||
[quo/text
|
||||
{:weight :semi-bold
|
||||
:size :heading-1
|
||||
:style {:flex-shrink 1}
|
||||
:number-of-lines 1}
|
||||
display-name]
|
||||
[contact-icon contact theme]]]))
|
||||
|
||||
(defn actions
|
||||
[chat-id cover-bg-color]
|
||||
(let [latest-pin-text (rf/sub [:chats/last-pinned-message-text chat-id])
|
||||
|
@ -236,101 +130,12 @@
|
|||
chat-type
|
||||
muted?)))}]}]))
|
||||
|
||||
(defn bio-and-actions
|
||||
[{:keys [distance-from-list-top bio chat-id customization-color empty-chat? description]}]
|
||||
(let [has-bio (seq (or bio description))
|
||||
top (reanimated/interpolate
|
||||
distance-from-list-top
|
||||
[0 (if empty-chat? 0 messages.constants/header-container-top-margin)]
|
||||
[(if has-bio 8 16) (if has-bio -28 -20)]
|
||||
messages.constants/default-extrapolation-option)]
|
||||
[reanimated/view
|
||||
{:style (style/bio-and-actions top)}
|
||||
(when has-bio
|
||||
[quo/text (or bio description)])
|
||||
[actions chat-id customization-color]]))
|
||||
|
||||
(defn footer-component
|
||||
[{:keys [chat distance-from-list-top customization-color]}]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
{:keys [chat-id chat-name emoji chat-type
|
||||
group-chat color description
|
||||
empty-chat?]} chat
|
||||
display-name (cond
|
||||
(= chat-type constants/one-to-one-chat-type)
|
||||
(first (rf/sub [:contacts/contact-two-names-by-identity chat-id]))
|
||||
(= chat-type constants/community-chat-type)
|
||||
(str "# " chat-name)
|
||||
:else (str emoji chat-name))
|
||||
{:keys [bio]} (rf/sub [:contacts/contact-by-identity chat-id])
|
||||
online? (rf/sub [:visibility-status-updates/online? chat-id])
|
||||
contact (when-not group-chat
|
||||
(rf/sub [:contacts/contact-by-address chat-id]))
|
||||
photo-path (if group-chat
|
||||
(rf/sub [:chats/group-chat-image chat-id])
|
||||
(rf/sub [:chats/photo-path chat-id]))
|
||||
top-margin (+ (safe-area/get-top)
|
||||
messages.constants/top-bar-height
|
||||
messages.constants/header-container-top-margin
|
||||
32)
|
||||
background-color (colors/theme-colors
|
||||
(colors/resolve-color customization-color theme 20)
|
||||
(colors/resolve-color customization-color theme 40)
|
||||
theme)
|
||||
bottom (reanimated/interpolate
|
||||
distance-from-list-top
|
||||
[0 messages.constants/header-container-top-margin]
|
||||
[32 -4]
|
||||
messages.constants/default-extrapolation-option)
|
||||
background-opacity (reanimated/interpolate
|
||||
distance-from-list-top
|
||||
[messages.constants/header-container-top-margin
|
||||
(+ messages.constants/header-animation-distance
|
||||
messages.constants/header-container-top-margin)]
|
||||
[1 0]
|
||||
messages.constants/default-extrapolation-option)]
|
||||
[:<>
|
||||
[reanimated/view
|
||||
{:style (style/background-container background-color background-opacity top-margin)}]
|
||||
[reanimated/view {:style (style/header-bottom-container bottom top-margin)}
|
||||
[rn/view {:style (style/header-bottom-shadow theme)}]
|
||||
[rn/view {:style (style/header-bottom-part theme)}
|
||||
[list-footer-avatar
|
||||
{:distance-from-list-top distance-from-list-top
|
||||
:display-name display-name
|
||||
:online? online?
|
||||
:theme theme
|
||||
:profile-picture photo-path
|
||||
:group-chat group-chat
|
||||
:color color
|
||||
:emoji emoji
|
||||
:chat-type chat-type
|
||||
:chat-name chat-name
|
||||
:empty-chat? empty-chat?}]
|
||||
[chat-display-name
|
||||
{:distance-from-list-top distance-from-list-top
|
||||
:display-name display-name
|
||||
:theme theme
|
||||
:contact contact
|
||||
:group-chat group-chat
|
||||
:empty-chat? empty-chat?}]
|
||||
[bio-and-actions
|
||||
{:distance-from-list-top distance-from-list-top
|
||||
:bio bio
|
||||
:chat-id chat-id
|
||||
:customization-color customization-color
|
||||
:description description
|
||||
:empty-chat? empty-chat?}]]]]))
|
||||
|
||||
(defn list-footer
|
||||
[props]
|
||||
(let [chat-id (get-in props [:chat :chat-id])
|
||||
loading-messages? (rf/sub [:chats/loading-messages? chat-id])
|
||||
(defn more-messages-loader
|
||||
[{:keys [chat-id] :as props}]
|
||||
(let [loading-messages? (rf/sub [:chats/loading-messages? chat-id])
|
||||
all-loaded? (rf/sub [:chats/all-loaded? chat-id])]
|
||||
[:<>
|
||||
(if (or loading-messages? (not all-loaded?))
|
||||
[loading-view chat-id props]
|
||||
[footer-component props])]))
|
||||
(when (or loading-messages? (not all-loaded?))
|
||||
[loading-view props])))
|
||||
|
||||
(defn list-group-chat-header
|
||||
[{:keys [chat-id invitation-admin]}]
|
||||
|
@ -359,8 +164,7 @@
|
|||
(reset! content-height content-height-new)))))
|
||||
|
||||
(defn on-layout
|
||||
[{:keys [event layout-height distance-atom distance-from-list-top
|
||||
chat-screen-layout-calculations-complete?]}]
|
||||
[{:keys [event layout-height distance-atom distance-from-list-top on-layout-done?]}]
|
||||
(let [layout-height-new (oops/oget event "nativeEvent.layout.height")
|
||||
change (- layout-height-new @layout-height)
|
||||
new-distance (- @distance-atom change)]
|
||||
|
@ -368,8 +172,7 @@
|
|||
(reanimated/set-shared-value distance-from-list-top new-distance)
|
||||
(reset! distance-atom new-distance)
|
||||
(reset! layout-height layout-height-new))
|
||||
(when-not (reanimated/get-shared-value chat-screen-layout-calculations-complete?)
|
||||
(reanimated/set-shared-value chat-screen-layout-calculations-complete? true))))
|
||||
(reset! on-layout-done? true)))
|
||||
|
||||
(defn on-scroll-fn
|
||||
[distance-atom layout-height-atom]
|
||||
|
@ -379,28 +182,21 @@
|
|||
(reset! distance-atom new-distance)))
|
||||
|
||||
(defn messages-list-content
|
||||
[{:keys [insets distance-from-list-top content-height layout-height distance-atom
|
||||
chat-screen-layout-calculations-complete? chat-list-scroll-y]}]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
{:keys [chat-type chat-id] :as chat} (rf/sub [:chats/current-chat-chat-view])
|
||||
one-to-one-chat? (= chat-type constants/one-to-one-chat-type)
|
||||
community-channel? (= constants/community-chat-type chat-type)
|
||||
{contact-customization-color
|
||||
:customization-color} (when one-to-one-chat?
|
||||
(rf/sub [:contacts/contact-by-identity chat-id]))
|
||||
customization-color (cond community-channel?
|
||||
(or (:color chat)
|
||||
(rf/sub [:communities/community-color
|
||||
(:community-id chat)]))
|
||||
one-to-one-chat? contact-customization-color
|
||||
:else (or (:color chat) :turquoise))
|
||||
{:keys [keyboard-shown]} (hooks/use-keyboard)
|
||||
{window-height :height} (rn/get-window)
|
||||
context (rf/sub [:chats/current-chat-message-list-view-context])
|
||||
able-to-send-message? (:able-to-send-message? context)
|
||||
messages (rf/sub [:chats/raw-chat-messages-stream chat-id])
|
||||
margin-bottom? (and community-channel? (not able-to-send-message?))
|
||||
recording? (rf/sub [:chats/recording?])]
|
||||
[{:keys [insets distance-from-list-top layout-height chat-list-scroll-y on-layout-done?]}]
|
||||
(let [content-height (rn/use-ref-atom 0)
|
||||
distance-atom (rn/use-ref-atom 0)
|
||||
theme (quo.theme/use-theme)
|
||||
{:keys [keyboard-shown]} (hooks/use-keyboard)
|
||||
{:keys [chat-type chat-id]
|
||||
:as chat} (rf/sub [:chats/current-chat-chat-view])
|
||||
community-channel? (= constants/community-chat-type chat-type)
|
||||
{window-height :height} (rn/get-window)
|
||||
context (rf/sub [:chats/current-chat-message-list-view-context])
|
||||
able-to-send-message? (:able-to-send-message? context)
|
||||
messages (rf/sub [:chats/raw-chat-messages-stream chat-id])
|
||||
margin-bottom? (and community-channel? (not able-to-send-message?))
|
||||
recording? (rf/sub [:chats/recording?])
|
||||
top-margin (+ (safe-area/get-top) messages.constants/top-bar-height)]
|
||||
[rn/view {:style (style/permission-context-sheet margin-bottom?)}
|
||||
[rn/view {:style {:flex-shrink 1}} ;; Keeps flat list on top
|
||||
[reanimated/flat-list
|
||||
|
@ -409,12 +205,9 @@
|
|||
:bounces false
|
||||
:header (when (= (:chat-type chat) constants/private-group-chat-type)
|
||||
[list-group-chat-header chat])
|
||||
:footer [list-footer
|
||||
{:theme theme
|
||||
:chat chat
|
||||
:window-height window-height
|
||||
:distance-from-list-top distance-from-list-top
|
||||
:customization-color customization-color}]
|
||||
:footer [more-messages-loader
|
||||
{:chat-id chat-id
|
||||
:window-height window-height}]
|
||||
:data messages
|
||||
:render-data {:theme theme
|
||||
:context context
|
||||
|
@ -444,15 +237,15 @@
|
|||
:style {:background-color (colors/theme-colors colors/white
|
||||
colors/neutral-95
|
||||
theme)}
|
||||
:content-container-style {:padding-top distance-from-last-message}
|
||||
:content-container-style {:padding-top distance-from-last-message
|
||||
:padding-bottom top-margin}
|
||||
:inverted true
|
||||
:on-layout #(on-layout
|
||||
{:event %
|
||||
:layout-height layout-height
|
||||
:distance-atom distance-atom
|
||||
{:event %
|
||||
:layout-height layout-height
|
||||
:distance-atom distance-atom
|
||||
:distance-from-list-top distance-from-list-top
|
||||
:chat-screen-layout-calculations-complete?
|
||||
chat-screen-layout-calculations-complete?})
|
||||
:on-layout-done? on-layout-done?})
|
||||
:scroll-enabled (not recording?)
|
||||
:content-inset-adjustment-behavior :never
|
||||
:scroll-indicator-insets {:right 1}}]]]))
|
||||
|
|
|
@ -1,56 +1,43 @@
|
|||
(ns status-im.contexts.chat.messenger.messages.navigation.style
|
||||
(:require
|
||||
[quo.foundations.colors :as colors]
|
||||
[react-native.reanimated :as reanimated]))
|
||||
(:require [quo.foundations.colors :as colors]
|
||||
[status-im.contexts.chat.messenger.messages.constants :as messages.constants]))
|
||||
|
||||
(defn navigation-view
|
||||
[navigation-view-height pinned-banner-height]
|
||||
[navigation-view-height]
|
||||
{:top 0
|
||||
:left 0
|
||||
:right 0
|
||||
:position :absolute
|
||||
:pointer-events :box-none
|
||||
:height (+ navigation-view-height pinned-banner-height)
|
||||
:height (+ navigation-view-height messages.constants/pinned-banner-height)
|
||||
:z-index 1})
|
||||
|
||||
(defn animated-background-view
|
||||
[background-opacity navigation-view-height]
|
||||
(reanimated/apply-animations-to-style
|
||||
{:opacity background-opacity}
|
||||
{:height navigation-view-height
|
||||
:top 0
|
||||
:left 0
|
||||
:right 0
|
||||
:overflow :hidden
|
||||
:position :absolute}))
|
||||
(defn background
|
||||
[navigation-view-height]
|
||||
{:height navigation-view-height
|
||||
:top 0
|
||||
:left 0
|
||||
:right 0
|
||||
:overflow :hidden
|
||||
:position :absolute})
|
||||
|
||||
(defn header-container
|
||||
[top-insets top-bar-height]
|
||||
[top-insets]
|
||||
{:margin-top top-insets
|
||||
:flex-direction :row
|
||||
:padding-horizontal 20
|
||||
:overflow :hidden
|
||||
:height top-bar-height
|
||||
:height messages.constants/top-bar-height
|
||||
:align-items :center})
|
||||
|
||||
(defn button-animation-container
|
||||
[opacity-value]
|
||||
(reanimated/apply-animations-to-style
|
||||
{:opacity opacity-value}
|
||||
{}))
|
||||
|
||||
;;;; Content
|
||||
|
||||
(defn header-content-container
|
||||
[header-opacity header-position]
|
||||
(reanimated/apply-animations-to-style
|
||||
{:transform [{:translate-y header-position}]
|
||||
:opacity header-opacity}
|
||||
{:flex-direction :row
|
||||
:align-items :center
|
||||
:flex 1
|
||||
:margin-horizontal 12
|
||||
:height 40}))
|
||||
(def header-content-container
|
||||
{:flex-direction :row
|
||||
:align-items :center
|
||||
:flex 1
|
||||
:margin-horizontal 12
|
||||
:height 40})
|
||||
|
||||
(def header-text-container
|
||||
{:margin-left 8})
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
[re-frame.db]
|
||||
[react-native.core :as rn]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[status-im.common.home.actions.view :as actions]
|
||||
[status-im.constants :as constants]
|
||||
|
@ -15,44 +14,26 @@
|
|||
[status-im.contexts.chat.messenger.messages.navigation.style :as style]
|
||||
[status-im.contexts.chat.messenger.messages.pin.banner.view :as pin.banner]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.worklets.chat.messenger.messages :as messages.worklets]
|
||||
[utils.worklets.chat.messenger.navigation :as worklets]))
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn header-content-container
|
||||
[{:keys [chat distance-from-list-top all-loaded? chat-screen-layout-calculations-complete?]}]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
{:keys [chat-id group-chat chat-type chat-name
|
||||
emoji color]} chat
|
||||
display-name (cond
|
||||
(= chat-type constants/one-to-one-chat-type)
|
||||
(first (rf/sub
|
||||
[:contacts/contact-two-names-by-identity
|
||||
chat-id]))
|
||||
(= chat-type constants/community-chat-type)
|
||||
(str "# " chat-name)
|
||||
:else (str emoji chat-name))
|
||||
online? (when-not group-chat (rf/sub [:visibility-status-updates/online? chat-id]))
|
||||
photo-path (if group-chat
|
||||
(rf/sub [:chats/group-chat-image chat-id])
|
||||
(rf/sub [:chats/photo-path chat-id]))
|
||||
header-opacity (worklets/navigation-header-opacity
|
||||
distance-from-list-top
|
||||
all-loaded?
|
||||
chat-screen-layout-calculations-complete?
|
||||
(if platform/ios?
|
||||
messages.constants/content-animation-start-position-ios
|
||||
messages.constants/content-animation-start-position-android))
|
||||
header-position (worklets/navigation-header-position
|
||||
distance-from-list-top
|
||||
all-loaded?
|
||||
messages.constants/top-bar-height
|
||||
(if platform/ios?
|
||||
messages.constants/content-animation-start-position-ios
|
||||
messages.constants/content-animation-start-position-android))
|
||||
community-channel? (= chat-type constants/community-chat-type)]
|
||||
[reanimated/view
|
||||
{:style (style/header-content-container header-opacity header-position)}
|
||||
[{:keys [chat-id group-chat chat-type chat-name emoji color] :as _chat}]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
display-name (cond
|
||||
(= chat-type constants/one-to-one-chat-type)
|
||||
(first (rf/sub [:contacts/contact-two-names-by-identity chat-id]))
|
||||
|
||||
(= chat-type constants/community-chat-type)
|
||||
(str "# " chat-name)
|
||||
|
||||
:else
|
||||
(str emoji chat-name))
|
||||
online? (when-not group-chat (rf/sub [:visibility-status-updates/online? chat-id]))
|
||||
photo-path (if group-chat
|
||||
(rf/sub [:chats/group-chat-image chat-id])
|
||||
(rf/sub [:chats/photo-path chat-id]))
|
||||
community-channel? (= chat-type constants/community-chat-type)]
|
||||
[rn/view {:style style/header-content-container}
|
||||
(cond
|
||||
community-channel?
|
||||
[quo/channel-avatar
|
||||
|
@ -90,30 +71,11 @@
|
|||
(i18n/label
|
||||
(if online? :t/online :t/offline))])]]))
|
||||
|
||||
(defn animated-background-and-pinned-banner
|
||||
[{:keys [chat-id navigation-view-height distance-from-list-top all-loaded?]}]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
animation-distance messages.constants/header-animation-distance
|
||||
props {:distance-from-list-top distance-from-list-top
|
||||
:all-loaded? all-loaded?}
|
||||
background-opacity (worklets/interpolate-navigation-view-opacity
|
||||
(assoc props
|
||||
:start-position
|
||||
messages.constants/header-container-top-margin
|
||||
:end-position
|
||||
(+ animation-distance
|
||||
messages.constants/header-container-top-margin)))
|
||||
banner-opacity (worklets/interpolate-navigation-view-opacity
|
||||
(assoc props
|
||||
:start-position
|
||||
(+ navigation-view-height
|
||||
messages.constants/pinned-banner-animation-start-position)
|
||||
:end-position
|
||||
(+ animation-distance
|
||||
navigation-view-height
|
||||
messages.constants/pinned-banner-animation-start-position)))]
|
||||
(defn header-background
|
||||
[{:keys [chat-id navigation-view-height]}]
|
||||
(let [theme (quo.theme/use-theme)]
|
||||
[:<>
|
||||
[reanimated/view {:style (style/animated-background-view background-opacity navigation-view-height)}
|
||||
[rn/view {:style (style/background navigation-view-height)}
|
||||
[quo/blur
|
||||
{:style {:flex 1}
|
||||
:blur-amount 20
|
||||
|
@ -121,58 +83,37 @@
|
|||
:overlay-color (colors/theme-colors colors/white-70-blur colors/neutral-95-opa-70-blur theme)
|
||||
:blur-radius (if platform/ios? 20 10)}]]
|
||||
[pin.banner/banner
|
||||
{:chat-id chat-id
|
||||
:banner-opacity banner-opacity
|
||||
:top-offset navigation-view-height}]]))
|
||||
{:chat-id chat-id
|
||||
:top-offset navigation-view-height}]]))
|
||||
|
||||
(defn view
|
||||
[{:keys [distance-from-list-top chat-screen-layout-calculations-complete?]}]
|
||||
[]
|
||||
(let [{:keys [chat-id chat-type]
|
||||
:as chat} (rf/sub [:chats/current-chat-chat-view])
|
||||
all-loaded? (reanimated/use-shared-value false)
|
||||
all-loaded-sub (rf/sub [:chats/all-loaded? chat-id])
|
||||
top-insets (safe-area/get-top)
|
||||
top-bar-height messages.constants/top-bar-height
|
||||
navigation-view-height (+ top-bar-height top-insets)
|
||||
navigation-buttons-opacity (worklets/navigation-buttons-complete-opacity
|
||||
chat-screen-layout-calculations-complete?)
|
||||
reached-threshold? (messages.worklets/use-messages-scrolled-to-threshold
|
||||
distance-from-list-top
|
||||
top-bar-height)
|
||||
button-background (if reached-threshold? :photo :blur)]
|
||||
(rn/use-effect (fn [] (reanimated/set-shared-value all-loaded? all-loaded-sub))
|
||||
[all-loaded-sub])
|
||||
[rn/view
|
||||
{:style (style/navigation-view navigation-view-height messages.constants/pinned-banner-height)}
|
||||
[animated-background-and-pinned-banner
|
||||
:as chat} (rf/sub [:chats/current-chat-chat-view])
|
||||
top-insets (safe-area/get-top)
|
||||
navigation-view-height (+ top-insets messages.constants/top-bar-height)]
|
||||
[rn/view {:style (style/navigation-view navigation-view-height)}
|
||||
[header-background
|
||||
{:chat-id chat-id
|
||||
:navigation-view-height navigation-view-height
|
||||
:distance-from-list-top distance-from-list-top
|
||||
:all-loaded? all-loaded?}]
|
||||
[rn/view {:style (style/header-container top-insets top-bar-height)}
|
||||
[reanimated/view {:style (style/button-animation-container navigation-buttons-opacity)}
|
||||
[quo/button
|
||||
{:icon-only? true
|
||||
:type :grey
|
||||
:background button-background
|
||||
:size 32
|
||||
:accessibility-label :back-button
|
||||
:on-press #(rf/dispatch [:navigate-back])}
|
||||
(if (= chat-type constants/community-chat-type) :i/arrow-left :i/close)]]
|
||||
[header-content-container
|
||||
{:chat chat
|
||||
:distance-from-list-top distance-from-list-top
|
||||
:all-loaded? all-loaded?
|
||||
:chat-screen-layout-calculations-complete? chat-screen-layout-calculations-complete?}]
|
||||
[reanimated/view {:style (style/button-animation-container navigation-buttons-opacity)}
|
||||
[quo/button
|
||||
{:icon-only? true
|
||||
:type :grey
|
||||
:background button-background
|
||||
:size 32
|
||||
:accessibility-label :options-button
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:dismiss-keyboard])
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:content (fn [] [actions/chat-actions chat true])}]))}
|
||||
:i/options]]]]))
|
||||
:navigation-view-height navigation-view-height}]
|
||||
[rn/view {:style (style/header-container top-insets)}
|
||||
[quo/button
|
||||
{:icon-only? true
|
||||
:type :grey
|
||||
:background :blur
|
||||
:size 32
|
||||
:accessibility-label :back-button
|
||||
:on-press #(rf/dispatch [:navigate-back])}
|
||||
(if (= chat-type constants/community-chat-type) :i/arrow-left :i/close)]
|
||||
[header-content-container chat]
|
||||
[quo/button
|
||||
{:icon-only? true
|
||||
:type :grey
|
||||
:background :blur
|
||||
:size 32
|
||||
:accessibility-label :options-button
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:dismiss-keyboard])
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:content (fn [] [actions/chat-actions chat true])}]))}
|
||||
:i/options]]]))
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
(ns status-im.contexts.chat.messenger.messages.pin.banner.style
|
||||
(:require
|
||||
[react-native.reanimated :as reanimated]
|
||||
[status-im.contexts.chat.messenger.messages.constants :as messages.constants]))
|
||||
|
||||
(def container
|
||||
|
@ -10,8 +9,6 @@
|
|||
:right 0
|
||||
:height messages.constants/pinned-banner-height})
|
||||
|
||||
(defn container-animated-style
|
||||
[top-offset banner-opacity]
|
||||
(reanimated/apply-animations-to-style
|
||||
{:opacity banner-opacity}
|
||||
(assoc container :top top-offset)))
|
||||
(defn container-with-top-offset
|
||||
[top-offset]
|
||||
(assoc container :top top-offset))
|
||||
|
|
|
@ -2,30 +2,26 @@
|
|||
(:require
|
||||
[quo.core :as quo]
|
||||
[quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[status-im.contexts.chat.messenger.messages.pin.banner.style :as style]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn f-banner
|
||||
[{:keys [chat-id banner-opacity top-offset]} latest-pin-text pins-count]
|
||||
(let [theme (quo.theme/use-theme)]
|
||||
[reanimated/view {:style (style/container-animated-style top-offset banner-opacity)}
|
||||
[quo/blur
|
||||
{:style style/container
|
||||
:blur-radius (if platform/ios? 20 10)
|
||||
:blur-type theme
|
||||
:blur-amount 20}]
|
||||
[quo/banner
|
||||
{:latest-pin-text latest-pin-text
|
||||
:pins-count pins-count
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:dismiss-keyboard])
|
||||
(rf/dispatch [:pin-message/show-pins-bottom-sheet chat-id]))}]]))
|
||||
|
||||
(defn banner
|
||||
[{:keys [chat-id] :as props}]
|
||||
(let [latest-pin-text (rf/sub [:chats/last-pinned-message-text chat-id])
|
||||
[{:keys [chat-id top-offset]}]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
latest-pin-text (rf/sub [:chats/last-pinned-message-text chat-id])
|
||||
pins-count (rf/sub [:chats/pin-messages-count chat-id])]
|
||||
(when (> pins-count 0)
|
||||
[:f> f-banner props latest-pin-text pins-count])))
|
||||
[rn/view {:style (style/container-with-top-offset top-offset)}
|
||||
[quo/blur
|
||||
{:style style/container
|
||||
:blur-radius (if platform/ios? 20 10)
|
||||
:blur-type theme
|
||||
:blur-amount 20}]
|
||||
[quo/banner
|
||||
{:latest-pin-text latest-pin-text
|
||||
:pins-count pins-count
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:dismiss-keyboard])
|
||||
(rf/dispatch [:pin-message/show-pins-bottom-sheet chat-id]))}]])))
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
[utils.worklets.chat.messenger.composer :as worklets]))
|
||||
|
||||
(defn button
|
||||
[{:keys [chat-list-scroll-y]}]
|
||||
[chat-list-scroll-y]
|
||||
(let [{window-height :height} (rn/get-window)
|
||||
scroll-down-button-opacity (worklets/scroll-down-button-opacity
|
||||
chat-list-scroll-y
|
||||
|
|
|
@ -19,57 +19,50 @@
|
|||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- footer
|
||||
[props]
|
||||
[layout-height]
|
||||
(let [current-chat-id (rf/sub [:chats/current-chat-id])
|
||||
able-to-send-message? (rf/sub [:chats/able-to-send-message?])]
|
||||
(when-not (string/blank? current-chat-id)
|
||||
(if able-to-send-message?
|
||||
[composer/view props]
|
||||
[composer/view layout-height]
|
||||
[contact-requests.bottom-drawer/view {:contact-id current-chat-id}]))))
|
||||
|
||||
(defn- chat-screen
|
||||
[{:keys [insets] :as props}]
|
||||
[on-layout-done?]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
layout-height (rn/use-ref-atom 0)
|
||||
distance-from-list-top (reanimated/use-shared-value 0)
|
||||
chat-list-scroll-y (reanimated/use-shared-value 0)
|
||||
alert-banners-top-margin (rf/sub [:alert-banners/top-margin])
|
||||
chat-exist? (rf/sub [:chats/current-chat-exist?])]
|
||||
(when chat-exist?
|
||||
[rn/keyboard-avoiding-view
|
||||
{:style (style/keyboard-avoiding-container theme)
|
||||
:keyboard-vertical-offset (- (if platform/ios? alert-banners-top-margin 0) (:bottom insets))}
|
||||
[:<>
|
||||
[list.view/messages-list-content props]
|
||||
[scroll-to-bottom/button props]]
|
||||
[messages.navigation/view props]
|
||||
[footer props]])))
|
||||
|
||||
(defn lazy-chat-screen
|
||||
[chat-screen-layout-calculations-complete? *screen-loaded?*]
|
||||
(let [screen-loaded? (rf/sub [:shell/chat-screen-loaded?])
|
||||
distance-from-list-top (reanimated/use-shared-value 0)
|
||||
chat-list-scroll-y (reanimated/use-shared-value 0)
|
||||
props {:insets (safe-area/get-insets)
|
||||
:content-height (atom 0)
|
||||
:layout-height (atom 0)
|
||||
:distance-atom (atom 0)
|
||||
:distance-from-list-top distance-from-list-top
|
||||
:chat-list-scroll-y chat-list-scroll-y
|
||||
:chat-screen-layout-calculations-complete?
|
||||
chat-screen-layout-calculations-complete?}]
|
||||
(when *screen-loaded?*
|
||||
(rn/use-mount #(reset! *screen-loaded?* true)))
|
||||
(when-not (if *screen-loaded?* @*screen-loaded?* screen-loaded?)
|
||||
(reanimated/set-shared-value chat-screen-layout-calculations-complete? false)
|
||||
(reanimated/set-shared-value distance-from-list-top 0)
|
||||
(reanimated/set-shared-value chat-list-scroll-y 0))
|
||||
(when (if *screen-loaded?* @*screen-loaded?* screen-loaded?)
|
||||
[chat-screen props])))
|
||||
insets (safe-area/get-insets)]
|
||||
[rn/keyboard-avoiding-view
|
||||
{:style (style/keyboard-avoiding-container theme)
|
||||
:keyboard-vertical-offset (- (if platform/ios? alert-banners-top-margin 0)
|
||||
(:bottom insets))}
|
||||
[:<>
|
||||
[list.view/messages-list-content
|
||||
{:insets insets
|
||||
:distance-from-list-top distance-from-list-top
|
||||
:chat-list-scroll-y chat-list-scroll-y
|
||||
:layout-height layout-height
|
||||
:on-layout-done? on-layout-done?}]
|
||||
[scroll-to-bottom/button chat-list-scroll-y]]
|
||||
[messages.navigation/view]
|
||||
[footer layout-height]]))
|
||||
|
||||
(defn chat
|
||||
[]
|
||||
(let [chat-screen-layout-calculations-complete? (reanimated/use-shared-value false)
|
||||
jump-to-enabled? (ff/enabled? ::ff/shell.jump-to)
|
||||
*screen-loaded?* (when-not jump-to-enabled?
|
||||
(reagent/atom false))]
|
||||
[:<>
|
||||
[lazy-chat-screen chat-screen-layout-calculations-complete? *screen-loaded?*]
|
||||
[placeholder.view/view chat-screen-layout-calculations-complete?]]))
|
||||
(let [on-layout-done? (reagent/atom false)
|
||||
first-render-done? (reagent/atom false)]
|
||||
(fn []
|
||||
(let [chat-exists? (rf/sub [:chats/current-chat-exist?])
|
||||
jump-to-enabled? (ff/enabled? ::ff/shell.jump-to)
|
||||
screen-loaded-for-jump-to? (rf/sub [:shell/chat-screen-loaded?])
|
||||
screen-loaded? (if jump-to-enabled?
|
||||
screen-loaded-for-jump-to?
|
||||
@first-render-done?)]
|
||||
(rn/use-mount #(reset! first-render-done? true))
|
||||
[:<>
|
||||
(when (and chat-exists? screen-loaded?)
|
||||
[chat-screen on-layout-done?])
|
||||
[placeholder.view/view on-layout-done?]]))))
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
(ns status-im.contexts.chat.messenger.placeholder.style
|
||||
(:require [quo.foundations.colors :as colors]
|
||||
[react-native.reanimated :as reanimated]))
|
||||
[react-native.safe-area :as safe-area]))
|
||||
|
||||
(defn container
|
||||
[top opacity z-index theme]
|
||||
(reanimated/apply-animations-to-style
|
||||
{:opacity opacity
|
||||
:z-index z-index}
|
||||
{:position :absolute
|
||||
:padding-top top
|
||||
:top 0
|
||||
:left 0
|
||||
:right 0
|
||||
:bottom 0
|
||||
:background-color (colors/theme-colors colors/white colors/neutral-95 theme)}))
|
||||
[theme on-layout-done?]
|
||||
{:position :absolute
|
||||
:padding-top (safe-area/get-top)
|
||||
:top 0
|
||||
:left 0
|
||||
:right 0
|
||||
:bottom 0
|
||||
:background-color (colors/theme-colors colors/white colors/neutral-95 theme)
|
||||
:opacity (if on-layout-done? 0 1)
|
||||
:z-index (if on-layout-done? 0 2)})
|
||||
|
|
|
@ -3,11 +3,8 @@
|
|||
[quo.core :as quo]
|
||||
[quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[status-im.contexts.chat.messenger.placeholder.style :as style]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.worklets.chat.messenger.placeholder :as worklets]))
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- loading-skeleton
|
||||
[]
|
||||
|
@ -17,13 +14,10 @@
|
|||
:animated? false}])
|
||||
|
||||
(defn view
|
||||
[chat-screen-layout-calculations-complete?]
|
||||
[on-layout-done?]
|
||||
(let [theme (quo.theme/use-theme)
|
||||
top (safe-area/get-top)
|
||||
chat-exist? (rf/sub [:chats/current-chat-exist?])
|
||||
opacity (worklets/placeholder-opacity chat-screen-layout-calculations-complete?)
|
||||
z-index (worklets/placeholder-z-index chat-screen-layout-calculations-complete?)]
|
||||
[reanimated/view {:style (style/container top opacity z-index theme)}
|
||||
chat-exist? (rf/sub [:chats/current-chat-exist?])]
|
||||
[rn/view {:style (style/container theme @on-layout-done?)}
|
||||
(when-not chat-exist?
|
||||
[quo/page-nav
|
||||
{:icon-name :i/arrow-left
|
||||
|
|
|
@ -6,8 +6,3 @@
|
|||
[distance-from-list-top chat-list-scroll-y callback]
|
||||
(.messagesListOnScroll ^js worklets distance-from-list-top chat-list-scroll-y callback))
|
||||
|
||||
(defn use-messages-scrolled-to-threshold
|
||||
[distance-from-list-top threshold]
|
||||
(.useMessagesScrolledToThreshold ^js worklets
|
||||
distance-from-list-top
|
||||
threshold))
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
(ns utils.worklets.chat.messenger.navigation)
|
||||
|
||||
(def ^:private worklets (js/require "../src/js/worklets/chat/messenger/navigation.js"))
|
||||
|
||||
(defn navigation-header-opacity
|
||||
[distance-from-list-top all-loaded? chat-screen-layout-calculations-complete? start-position]
|
||||
(.navigationHeaderOpacity ^js worklets
|
||||
distance-from-list-top
|
||||
all-loaded?
|
||||
chat-screen-layout-calculations-complete?
|
||||
start-position))
|
||||
|
||||
(defn navigation-header-position
|
||||
[distance-from-list-top all-loaded? top-bar-height start-position]
|
||||
(.navigationHeaderPosition ^js worklets
|
||||
distance-from-list-top
|
||||
all-loaded?
|
||||
top-bar-height
|
||||
start-position))
|
||||
|
||||
(defn navigation-buttons-complete-opacity
|
||||
[chat-screen-layout-calculations-complete?]
|
||||
(.navigationButtonsCompleteOpacity ^js worklets chat-screen-layout-calculations-complete?))
|
||||
|
||||
(defn interpolate-navigation-view-opacity
|
||||
[props]
|
||||
(.interpolateNavigationViewOpacity ^js worklets (clj->js props)))
|
|
@ -1,11 +0,0 @@
|
|||
(ns utils.worklets.chat.messenger.placeholder)
|
||||
|
||||
(def ^:private worklets (js/require "../src/js/worklets/chat/messenger/placeholder.js"))
|
||||
|
||||
(defn placeholder-opacity
|
||||
[chat-screen-layout-calculations-complete?]
|
||||
(.placeholderOpacity ^js worklets chat-screen-layout-calculations-complete?))
|
||||
|
||||
(defn placeholder-z-index
|
||||
[chat-screen-layout-calculations-complete?]
|
||||
(.placeholderZIndex ^js worklets chat-screen-layout-calculations-complete?))
|
Loading…
Reference in New Issue