From add759711ad5805adfe03a718c80ccfd0e6ed426 Mon Sep 17 00:00:00 2001 From: Volodymyr Kozieiev Date: Mon, 20 May 2019 18:15:17 +0300 Subject: [PATCH] Optimized ScrollView instead of FlatList for desktop chat Signed-off-by: Andrey Shovkoplyas --- .../ui/screens/chat/input/input.cljs | 18 ++++-- .../ui/screens/chat/input/send_button.cljs | 4 +- .../ui/screens/chat/message/gap.cljs | 5 +- .../ui/screens/chat/styles/main.cljs | 2 + src/status_im/ui/screens/chat/views.cljs | 57 ++++++++++++++++++- 5 files changed, 77 insertions(+), 9 deletions(-) diff --git a/src/status_im/ui/screens/chat/input/input.cljs b/src/status_im/ui/screens/chat/input/input.cljs index 1e7051373d..3608befad0 100644 --- a/src/status_im/ui/screens/chat/input/input.cljs +++ b/src/status_im/ui/screens/chat/input/input.cljs @@ -53,10 +53,13 @@ {:placeholder (i18n/label :cooldown/text-input-disabled)}))])) (defview basic-text-input-desktop [{:keys [set-container-width-fn height single-line-input? set-text state-text]}] - (letsubs [cooldown-enabled? [:chats/cooldown-enabled?]] + (letsubs [inp-ref (atom nil) + cooldown-enabled? [:chats/cooldown-enabled?]] [react/text-input (merge - {:ref #(when % (re-frame/dispatch [:chat.ui/set-chat-ui-props {:input-ref %}])) + {:ref #(when % (do + (reset! inp-ref %) + (re-frame/dispatch [:chat.ui/set-chat-ui-props {:input-ref %}]))) :accessibility-label :chat-message-input :multiline (not single-line-input?) :default-value @state-text @@ -68,6 +71,8 @@ :on-blur #(re-frame/dispatch [:chat.ui/set-chat-ui-props {:input-focused? false}]) :submit-shortcut {:key "Enter"} :on-submit-editing #(do + (.clear @inp-ref) + (.focus @inp-ref) (re-frame/dispatch [:chat.ui/set-chat-input-text @state-text]) (re-frame/dispatch [:chat.ui/send-current-message]) (set-text "")) @@ -200,8 +205,13 @@ (if input-text-empty? [commands-button] (if platform/desktop? - [send-button/send-button-view {:input-text @state-text}] - [send-button/send-button-view {:input-text input-text}]))]]))) + [send-button/send-button-view {:input-text @state-text} + #(do + (re-frame/dispatch [:chat.ui/set-chat-input-text @state-text]) + (re-frame/dispatch [:chat.ui/send-current-message]) + (set-text ""))] + [send-button/send-button-view {:input-text input-text} + #(re-frame/dispatch [:chat.ui/send-current-message])]))]]))) (defn container [] [react/view diff --git a/src/status_im/ui/screens/chat/input/send_button.cljs b/src/status_im/ui/screens/chat/input/send_button.cljs index e4167d51fb..162f98a0d8 100644 --- a/src/status_im/ui/screens/chat/input/send_button.cljs +++ b/src/status_im/ui/screens/chat/input/send_button.cljs @@ -13,7 +13,7 @@ login-processing? disconnected?)))) -(defview send-button-view [{:keys [input-text]}] +(defview send-button-view [{:keys [input-text]} on-send-press] (letsubs [{:keys [command-completion]} [:chats/selected-chat-command] disconnected? [:disconnected?] {:keys [processing]} [:accounts/login]] @@ -21,7 +21,7 @@ (or (not command-completion) (#{:complete :less-than-needed} command-completion))) [react/touchable-highlight - {:on-press #(re-frame/dispatch [:chat.ui/send-current-message])} + {:on-press on-send-press} [vector-icons/icon :main-icons/arrow-up {:container-style style/send-message-container :accessibility-label :send-message-button diff --git a/src/status_im/ui/screens/chat/message/gap.cljs b/src/status_im/ui/screens/chat/message/gap.cljs index 7f4d529b29..fa938179fe 100644 --- a/src/status_im/ui/screens/chat/message/gap.cljs +++ b/src/status_im/ui/screens/chat/message/gap.cljs @@ -4,12 +4,13 @@ [re-frame.core :as re-frame] [status-im.i18n :as i18n] [status-im.utils.datetime :as datetime] - [status-im.ui.screens.chat.styles.input.gap :as style])) + [status-im.ui.screens.chat.styles.input.gap :as style] + [status-im.utils.platform :as platform])) (defn on-press [ids first-gap? idx list-ref] (fn [] - (when (and list-ref @list-ref) + (when (and list-ref @list-ref (not platform/desktop?)) (.scrollToIndex @list-ref #js {:index (max 0 (dec idx)) :viewOffset 20 diff --git a/src/status_im/ui/screens/chat/styles/main.cljs b/src/status_im/ui/screens/chat/styles/main.cljs index ee90165ad6..0052d67600 100644 --- a/src/status_im/ui/screens/chat/styles/main.cljs +++ b/src/status_im/ui/screens/chat/styles/main.cljs @@ -271,3 +271,5 @@ (def decline-chat {:color colors/blue :margin-bottom 40}) + +(def messages-list-vertical-padding 46) \ No newline at end of file diff --git a/src/status_im/ui/screens/chat/views.cljs b/src/status_im/ui/screens/chat/views.cljs index 0f22a0d5d9..6b649c31b8 100644 --- a/src/status_im/ui/screens/chat/views.cljs +++ b/src/status_im/ui/screens/chat/views.cljs @@ -1,5 +1,6 @@ (ns status-im.ui.screens.chat.views (:require [re-frame.core :as re-frame] + [reagent.core :as reagent] [status-im.chat.models :as models.chat] [status-im.contact.db :as contact.db] [status-im.group-chats.db :as group-chats.db] @@ -272,6 +273,57 @@ [list/flat-list (merge flat-list-conf group-header)] [list/flat-list flat-list-conf])))) +(def load-step 5) + +(defn load-more [all-messages-count messages-to-load] + (let [next-count (min all-messages-count (+ @messages-to-load load-step))] + (reset! messages-to-load next-count))) + +(defview messages-view-desktop [{:keys [chat-id group-chat]} + modal?] + (letsubs [messages [:chats/current-chat-messages-stream] + current-public-key [:account/public-key] + messages-to-load (reagent/atom load-step) + chat-id* (reagent/atom nil)] + {:component-did-update #(if (:messages-initialized? (second (.-argv (.-props %1)))) + (load-more (count messages) messages-to-load) + (re-frame/dispatch [:chat.ui/load-more-messages])) + :component-did-mount #(if (:messages-initialized? (second (.-argv (.-props %1)))) + (load-more (count messages) messages-to-load) + (re-frame/dispatch [:chat.ui/load-more-messages]))} + (let [messages-list-ref (atom nil) + scroll-timer (atom nil) + scroll-height (atom nil) + _ (when (or (not @chat-id*) (not= @chat-id* chat-id)) + (do + (reset! messages-to-load load-step) + (reset! chat-id* chat-id)))] + [react/view {:style style/chat-view} + [react/scroll-view {:scrollEventThrottle 16 + :headerHeight style/messages-list-vertical-padding + :footerWidth style/messages-list-vertical-padding + :enableArrayScrollingOptimization true + :inverted true + :ref #(reset! messages-list-ref %) + :on-scroll (fn [e] + (let [ne (.-nativeEvent e) + y (.-y (.-contentOffset ne))] + (when (<= y 0) + (when @scroll-timer (js/clearTimeout @scroll-timer)) + (reset! scroll-timer (js/setTimeout #(re-frame/dispatch [:chat.ui/load-more-messages]) 300))) + (reset! scroll-height (+ y (.-height (.-layoutMeasurement ne))))))} + [react/view + (doall + (for [{:keys [from content] :as message-obj} (take @messages-to-load messages)] + ^{:key message-obj} + [message-row + {:group-chat group-chat + :modal? modal? + :current-public-key current-public-key + :row message-obj + :idx #(or (:message-id message-obj) (:value message-obj)) + :list-ref messages-list-ref}]))]]]))) + (defn show-input-container? [my-public-key current-chat] (or (not (models.chat/group-chat? current-chat)) (group-chats.db/joined? my-public-key current-chat))) @@ -300,7 +352,10 @@ (re-frame/dispatch [:set :layout-height (-> e .-nativeEvent .-layout .-height)]))} [chat-toolbar current-chat public? modal?] [messages-view-animation - [messages-view current-chat modal?]] + ;;TODO(kozieiev) : When FlatList in react-native-desktop become viable it should be used instead of optimized ScrollView for chat + (if platform/desktop? + [messages-view-desktop current-chat modal?] + [messages-view current-chat modal?])] (when (show-input-container? my-public-key current-chat) [input/container]) (when show-stickers?