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:
parent
eeff44eea7
commit
7bb7b48db7
|
@ -11,8 +11,10 @@
|
||||||
[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]
|
||||||
|
(when-not platform/android?
|
||||||
(js->clj (.-panHandlers
|
(js->clj (.-panHandlers
|
||||||
^js (.create
|
^js (.create
|
||||||
^js rn/pan-responder
|
^js rn/pan-responder
|
||||||
|
@ -21,13 +23,17 @@
|
||||||
:onPanResponderMove (fn [_ ^js state]
|
:onPanResponderMove (fn [_ ^js state]
|
||||||
(animated/set-value y (.-moveY state)))
|
(animated/set-value y (.-moveY state)))
|
||||||
:onPanResponderRelease (fn []
|
:onPanResponderRelease (fn []
|
||||||
|
(animated/set-value pan-active 0)
|
||||||
(js/setTimeout
|
(js/setTimeout
|
||||||
#(animated/set-value y 0)
|
#(animated/set-value y 0)
|
||||||
100))
|
100))
|
||||||
:onPanResponderEnd (fn []
|
:onPanResponderTerminate (fn []
|
||||||
(animated/set-value pan-active 0))}))))
|
(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))
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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})]))
|
||||||
|
|
||||||
|
@ -191,19 +193,33 @@
|
||||||
|
|
||||||
(defn chat []
|
(defn chat []
|
||||||
(let [bottom-space (reagent/atom 0)
|
(let [bottom-space (reagent/atom 0)
|
||||||
|
panel-space (reagent/atom 0)
|
||||||
active-panel (reagent/atom nil)
|
active-panel (reagent/atom nil)
|
||||||
position-y (animated/value 0)
|
position-y (animated/value 0)
|
||||||
pan-state (animated/value 0)
|
pan-state (animated/value 0)
|
||||||
text-input-ref (quo.react/create-ref)
|
text-input-ref (quo.react/create-ref)
|
||||||
on-update (partial reset! bottom-space)
|
on-update (partial reset! panel-space)
|
||||||
pan-responder (accessory/create-pan-responder position-y pan-state)
|
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
|
||||||
|
|
Loading…
Reference in New Issue