Fix chat text input animation lags

Remove picker panel from input

Clean pan state

Fixes #11031

Do not use pan state on android

iOs panel switching do not change height

Revert "Remove picker panel from input"

This reverts commit 0ab2c1544b70f8c491424376268f572696bd284a.

Change reactions space keeper method

Audio

Do not use accessory view on Android

Signed-off-by: Gheorghe Pinzaru <feross95@gmail.com>
This commit is contained in:
Gheorghe Pinzaru 2020-08-04 12:16:20 +03:00
parent eeff44eea7
commit 7bb7b48db7
No known key found for this signature in database
GPG Key ID: C9A094959935A952
5 changed files with 119 additions and 63 deletions

View File

@ -11,23 +11,29 @@
[quo.components.safe-area :refer [use-safe-area]])) [quo.components.safe-area :refer [use-safe-area]]))
(def tabbar-height tabs.styles/minimized-tabs-height) (def tabbar-height tabs.styles/minimized-tabs-height)
(def duration 250)
(defn create-pan-responder [y pan-active] (defn create-pan-responder [y pan-active]
(js->clj (.-panHandlers (when-not platform/android?
^js (.create (js->clj (.-panHandlers
^js rn/pan-responder ^js (.create
#js {:onPanResponderGrant (fn [] ^js rn/pan-responder
(animated/set-value pan-active 1)) #js {:onPanResponderGrant (fn []
:onPanResponderMove (fn [_ ^js state] (animated/set-value pan-active 1))
(animated/set-value y (.-moveY state))) :onPanResponderMove (fn [_ ^js state]
:onPanResponderRelease (fn [] (animated/set-value y (.-moveY state)))
(js/setTimeout :onPanResponderRelease (fn []
#(animated/set-value y 0) (animated/set-value pan-active 0)
100)) (js/setTimeout
:onPanResponderEnd (fn [] #(animated/set-value y 0)
(animated/set-value pan-active 0))})))) 100))
:onPanResponderTerminate (fn []
(animated/set-value pan-active 0)
(js/setTimeout
#(animated/set-value y 0)
100))})))))
(def view (def ios-view
(reagent/adapt-react-class (reagent/adapt-react-class
(react/memo (react/memo
(fn [props] (fn [props]
@ -39,7 +45,6 @@
children :children} (bean/bean props) children :children} (bean/bean props)
{keyboard-height :height {keyboard-height :height
keyboard-max-height :max-height keyboard-max-height :max-height
duration :duration
keyboard-end-position :end-position} (use-keyboard-dimension) keyboard-end-position :end-position} (use-keyboard-dimension)
{:keys [bottom]} (use-safe-area) {:keys [bottom]} (use-safe-area)
{on-layout :on-layout {on-layout :on-layout
@ -64,15 +69,13 @@
:easing (:keyboard animated/easings)}) :easing (:keyboard animated/easings)})
0 0
panel-on-screen)) panel-on-screen))
[duration panel-on-screen]) [panel-on-screen])
delta-y (animated/clamp (animated/add drag-diff animated-y) max-delta 0) delta-y (animated/clamp (animated/add drag-diff animated-y) max-delta 0)
on-update (react/callback on-update (fn []
(fn [] (when on-update-inset
(when on-update-inset (on-update-inset (+ bar-height panel-height))))
(on-update-inset (+ bar-height panel-height))))
[panel-height bar-height])
children (react/get-children children)] children (react/get-children children)]
(react/effect! on-update) (react/effect! on-update [panel-height bar-height])
(animated/code! (animated/code!
(fn [] (fn []
(when has-panel (when has-panel
@ -86,12 +89,7 @@
(animated/delay (animated/delay
(animated/set anim-visible (if visible 1 0)) (animated/set anim-visible (if visible 1 0))
(if visible delay 0))) (if visible delay 0)))
[visible keyboard-max-height duration]) [visible keyboard-max-height delay])
(rn/use-back-handler
(fn []
(when visible
(on-close))
visible))
(reagent/as-element (reagent/as-element
[animated/view {:style {:position :absolute [animated/view {:style {:position :absolute
:left 0 :left 0
@ -104,3 +102,44 @@
[rn/view {:style {:flex 1 [rn/view {:style {:flex 1
:height (when (pos? panel-height) panel-height)}} :height (when (pos? panel-height) panel-height)}}
(second children)]])))))) (second children)]]))))))
(def android-view
(reagent/adapt-react-class
(react/memo
(fn [props]
(let [{on-update-inset :onUpdateInset
on-close :onClose
has-panel :hasPanel
children :children} (bean/bean props)
{keyboard-max-height :max-height} (use-keyboard-dimension)
{:keys [bottom]} (use-safe-area)
{on-layout :on-layout
bar-height :height} (rn/use-layout)
visible has-panel
panel-on-screen (* -1 (- keyboard-max-height bottom tabbar-height))
max-delta (min 0 (if has-panel panel-on-screen 0))
panel-height (* -1 max-delta)
on-update (fn []
(when on-update-inset
(on-update-inset (+ bar-height panel-height))))
children (react/get-children children)]
(react/effect! on-update [panel-height bar-height])
(rn/use-back-handler
(fn []
(when visible
(on-close))
visible))
(reagent/as-element
[animated/view {:style {:position :absolute
:left 0
:right 0
:bottom 0
:background-color (:ui-background @colors/theme)}}
[rn/view {:on-layout on-layout}
(first children)]
[rn/view {:style {:flex 1
:height (when (pos? panel-height) panel-height)}}
(second children)]]))))))
(def view (if platform/android? android-view ios-view))

View File

@ -15,8 +15,7 @@
[clojure.string :as string])) [clojure.string :as string]))
(def panel->icons {:extensions :main-icons/commands (def panel->icons {:extensions :main-icons/commands
:images :main-icons/photo :images :main-icons/photo})
:audio :main-icons/speech})
(defn touchable-icon [{:keys [panel active set-active accessibility-label]}] (defn touchable-icon [{:keys [panel active set-active accessibility-label]}]
[pressable/pressable {:type :scale [pressable/pressable {:type :scale
@ -38,6 +37,8 @@
[icons/icon :main-icons/keyboard (styles/icon false)] [icons/icon :main-icons/keyboard (styles/icon false)]
[icons/icon :main-icons/stickers (styles/icon false)])]]) [icons/icon :main-icons/stickers (styles/icon false)])]])
;; TODO(Ferossgp): Move this into audio panel.
;; Instead of not changing panel we can show a placeholder with no permission
(defn- request-record-audio-permission [set-active panel] (defn- request-record-audio-permission [set-active panel]
(re-frame/dispatch (re-frame/dispatch
[:request-permissions [:request-permissions
@ -58,9 +59,9 @@
(input-focus) (input-focus)
(request-record-audio-permission set-active panel))} (request-record-audio-permission set-active panel))}
[rn/view {:style (styles/in-input-touchable-icon)} [rn/view {:style (styles/in-input-touchable-icon)}
[icons/icon (if (= active panel)
(panel->icons panel) [icons/icon :main-icons/keyboard (styles/icon false)]
(styles/icon (= active panel))]]]) [icons/icon :main-icons/speech (styles/icon false)])]])
(defn send-button [{:keys [on-send-press]}] (defn send-button [{:keys [on-send-press]}]
[pressable/pressable {:type :scale [pressable/pressable {:type :scale

View File

@ -104,7 +104,8 @@
(defn in-input-buttons [] (defn in-input-buttons []
{:flex-direction :row {:flex-direction :row
:height 34}) :height 34
:overflow :hidden})
(defn send-icon-color [] (defn send-icon-color []
colors/white) colors/white)

View File

@ -2,7 +2,6 @@
(:require [re-frame.core :as re-frame] (:require [re-frame.core :as re-frame]
[status-im.constants :as constants] [status-im.constants :as constants]
[status-im.i18n :as i18n] [status-im.i18n :as i18n]
[quo.platform :as platform]
[status-im.ui.components.colors :as colors] [status-im.ui.components.colors :as colors]
[status-im.ui.components.icons.vector-icons :as vector-icons] [status-im.ui.components.icons.vector-icons :as vector-icons]
[status-im.ui.components.react :as react] [status-im.ui.components.react :as react]
@ -341,17 +340,14 @@
[message-content-wrapper message [message-content-wrapper message
[unknown-content-type message]]) [unknown-content-type message]])
(defn chat-message [message set-active-panel] (defn chat-message [message space-keeper]
[reactions/with-reaction-picker [reactions/with-reaction-picker
{:message message {:message message
:reactions @(re-frame/subscribe [:chats/message-reactions (:message-id message)]) :reactions @(re-frame/subscribe [:chats/message-reactions (:message-id message)])
:picker-on-open (fn [] :picker-on-open (fn []
;; NOTE(Ferossgp): Because of soft-input adjustResize there are some problems on android (space-keeper true))
(when (and platform/ios? (pos? @(re-frame/subscribe [:keyboard-height])))
(set-active-panel :keep-space)))
:picker-on-close (fn [] :picker-on-close (fn []
(when platform/ios? (space-keeper false))
(set-active-panel nil)))
:send-emoji (fn [{:keys [emoji-id]}] :send-emoji (fn [{:keys [emoji-id]}]
(re-frame/dispatch [::models.reactions/send-emoji-reaction (re-frame/dispatch [::models.reactions/send-emoji-reaction
{:message-id (:message-id message) {:message-id (:message-id message)

View File

@ -11,6 +11,7 @@
[status-im.ui.screens.chat.sheets :as sheets] [status-im.ui.screens.chat.sheets :as sheets]
[quo.animated :as animated] [quo.animated :as animated]
[quo.react-native :as rn] [quo.react-native :as rn]
[quo.platform :as platform]
[status-im.ui.screens.chat.audio-message.views :as audio-message] [status-im.ui.screens.chat.audio-message.views :as audio-message]
[quo.react :as quo.react] [quo.react :as quo.react]
[status-im.ui.screens.chat.message.message :as message] [status-im.ui.screens.chat.message.message :as message]
@ -27,8 +28,7 @@
[status-im.ui.components.invite.chat :as invite.chat] [status-im.ui.components.invite.chat :as invite.chat]
[status-im.ui.screens.chat.components.accessory :as accessory] [status-im.ui.screens.chat.components.accessory :as accessory]
[status-im.ui.screens.chat.components.input :as components] [status-im.ui.screens.chat.components.input :as components]
[status-im.ui.screens.chat.message.datemark :as message-datemark]) [status-im.ui.screens.chat.message.datemark :as message-datemark]))
(:require-macros [status-im.utils.views :refer [defview letsubs]]))
(defn topbar [current-chat] (defn topbar [current-chat]
[topbar/topbar [topbar/topbar
@ -137,14 +137,16 @@
first-not-visible))))) first-not-visible)))))
(debounce/debounce-and-dispatch [:chat.ui/message-visibility-changed e] 5000)) (debounce/debounce-and-dispatch [:chat.ui/message-visibility-changed e] 5000))
(defview messages-view (defn messages-view
[{:keys [group-chat chat-id public?] :as chat} bottom-space pan-handler set-active-panel] [{:keys [chat bottom-space pan-responder space-keeper]}]
(letsubs [messages [:chats/current-chat-messages-stream] (let [{:keys [group-chat chat-id public?]} chat
no-messages? [:chats/current-chat-no-messages?]
current-public-key [:multiaccount/public-key]] messages @(re-frame/subscribe [:chats/current-chat-messages-stream])
no-messages? @(re-frame/subscribe [:chats/current-chat-no-messages?])
current-public-key @(re-frame/subscribe [:multiaccount/public-key])]
[list/flat-list [list/flat-list
(merge (merge
pan-handler pan-responder
{:key-fn #(or (:message-id %) (:value %)) {:key-fn #(or (:message-id %) (:value %))
:ref #(reset! messages-list-ref %) :ref #(reset! messages-list-ref %)
:header (when (and group-chat (not public?)) :header (when (and group-chat (not public?))
@ -167,13 +169,13 @@
:group-chat group-chat :group-chat group-chat
:public? public? :public? public?
:current-public-key current-public-key) :current-public-key current-public-key)
set-active-panel]))) space-keeper])))
:on-viewable-items-changed on-viewable-items-changed :on-viewable-items-changed on-viewable-items-changed
:on-end-reached #(re-frame/dispatch [:chat.ui/load-more-messages]) :on-end-reached #(re-frame/dispatch [:chat.ui/load-more-messages])
:on-scroll-to-index-failed #() ;;don't remove this :on-scroll-to-index-failed #() ;;don't remove this
:content-container-style {:padding-top (+ @bottom-space 16) :content-container-style {:padding-top (+ bottom-space 16)
:padding-bottom 16} :padding-bottom 16}
:scrollIndicatorInsets {:top @bottom-space} :scrollIndicatorInsets {:top bottom-space}
:keyboardDismissMode "interactive" :keyboardDismissMode "interactive"
:keyboard-should-persist-taps :handled})])) :keyboard-should-persist-taps :handled})]))
@ -190,20 +192,34 @@
nil)) nil))
(defn chat [] (defn chat []
(let [bottom-space (reagent/atom 0) (let [bottom-space (reagent/atom 0)
active-panel (reagent/atom nil) panel-space (reagent/atom 0)
position-y (animated/value 0) active-panel (reagent/atom nil)
pan-state (animated/value 0) position-y (animated/value 0)
text-input-ref (quo.react/create-ref) pan-state (animated/value 0)
on-update (partial reset! bottom-space) text-input-ref (quo.react/create-ref)
pan-responder (accessory/create-pan-responder position-y pan-state) on-update (partial reset! panel-space)
pan-responder (accessory/create-pan-responder position-y pan-state)
space-keeper (fn [state]
;; NOTE: Only iOs now because we use soft input resize screen on android
(when platform/ios?
(cond
(and state
(< @bottom-space @panel-space)
(not @active-panel))
(reset! bottom-space @panel-space)
(and (not state)
(< @panel-space @bottom-space))
(do
(some-> ^js (quo.react/current-ref text-input-ref) .focus)
(reset! panel-space @bottom-space)
(reset! bottom-space 0)))))
set-active-panel (fn [panel] set-active-panel (fn [panel]
(rn/configure-next (rn/configure-next
(:ease-opacity-200 rn/custom-animations)) (:ease-opacity-200 rn/custom-animations))
(when (and (not panel)
(= :keep-space @active-panel))
(some-> ^js (quo.react/current-ref text-input-ref) .focus))
(reset! active-panel panel) (reset! active-panel panel)
(reagent/flush)
(when panel (when panel
(js/setTimeout #(react/dismiss-keyboard!) 100)))] (js/setTimeout #(react/dismiss-keyboard!) 100)))]
(fn [] (fn []
@ -215,7 +231,10 @@
[react/view {:style {:flex 1}} [react/view {:style {:flex 1}}
(when-not group-chat (when-not group-chat
[add-contact-bar chat-id]) [add-contact-bar chat-id])
[messages-view current-chat bottom-space pan-responder set-active-panel]]] [messages-view {:chat current-chat
:bottom-space (max @bottom-space @panel-space)
:pan-responder pan-responder
:space-keeper space-keeper}]]]
(when show-input? (when show-input?
[accessory/view {:y position-y [accessory/view {:y position-y
:pan-state pan-state :pan-state pan-state