diff --git a/src/status_im/ui/screens/chat/components/accessory.cljs b/src/status_im/ui/screens/chat/components/accessory.cljs index e09baf1701..a9f7f01a31 100644 --- a/src/status_im/ui/screens/chat/components/accessory.cljs +++ b/src/status_im/ui/screens/chat/components/accessory.cljs @@ -11,23 +11,29 @@ [quo.components.safe-area :refer [use-safe-area]])) (def tabbar-height tabs.styles/minimized-tabs-height) +(def duration 250) (defn create-pan-responder [y pan-active] - (js->clj (.-panHandlers - ^js (.create - ^js rn/pan-responder - #js {:onPanResponderGrant (fn [] - (animated/set-value pan-active 1)) - :onPanResponderMove (fn [_ ^js state] - (animated/set-value y (.-moveY state))) - :onPanResponderRelease (fn [] - (js/setTimeout - #(animated/set-value y 0) - 100)) - :onPanResponderEnd (fn [] - (animated/set-value pan-active 0))})))) + (when-not platform/android? + (js->clj (.-panHandlers + ^js (.create + ^js rn/pan-responder + #js {:onPanResponderGrant (fn [] + (animated/set-value pan-active 1)) + :onPanResponderMove (fn [_ ^js state] + (animated/set-value y (.-moveY state))) + :onPanResponderRelease (fn [] + (animated/set-value pan-active 0) + (js/setTimeout + #(animated/set-value y 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 (react/memo (fn [props] @@ -39,7 +45,6 @@ children :children} (bean/bean props) {keyboard-height :height keyboard-max-height :max-height - duration :duration keyboard-end-position :end-position} (use-keyboard-dimension) {:keys [bottom]} (use-safe-area) {on-layout :on-layout @@ -64,15 +69,13 @@ :easing (:keyboard animated/easings)}) 0 panel-on-screen)) - [duration panel-on-screen]) + [panel-on-screen]) delta-y (animated/clamp (animated/add drag-diff animated-y) max-delta 0) - on-update (react/callback - (fn [] - (when on-update-inset - (on-update-inset (+ bar-height panel-height)))) - [panel-height bar-height]) + on-update (fn [] + (when on-update-inset + (on-update-inset (+ bar-height panel-height)))) children (react/get-children children)] - (react/effect! on-update) + (react/effect! on-update [panel-height bar-height]) (animated/code! (fn [] (when has-panel @@ -86,12 +89,7 @@ (animated/delay (animated/set anim-visible (if visible 1 0)) (if visible delay 0))) - [visible keyboard-max-height duration]) - (rn/use-back-handler - (fn [] - (when visible - (on-close)) - visible)) + [visible keyboard-max-height delay]) (reagent/as-element [animated/view {:style {:position :absolute :left 0 @@ -104,3 +102,44 @@ [rn/view {:style {:flex 1 :height (when (pos? panel-height) panel-height)}} (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)) diff --git a/src/status_im/ui/screens/chat/components/input.cljs b/src/status_im/ui/screens/chat/components/input.cljs index 75e3b31237..40590ef08a 100644 --- a/src/status_im/ui/screens/chat/components/input.cljs +++ b/src/status_im/ui/screens/chat/components/input.cljs @@ -15,8 +15,7 @@ [clojure.string :as string])) (def panel->icons {:extensions :main-icons/commands - :images :main-icons/photo - :audio :main-icons/speech}) + :images :main-icons/photo}) (defn touchable-icon [{:keys [panel active set-active accessibility-label]}] [pressable/pressable {:type :scale @@ -38,6 +37,8 @@ [icons/icon :main-icons/keyboard (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] (re-frame/dispatch [:request-permissions @@ -58,9 +59,9 @@ (input-focus) (request-record-audio-permission set-active panel))} [rn/view {:style (styles/in-input-touchable-icon)} - [icons/icon - (panel->icons panel) - (styles/icon (= active panel))]]]) + (if (= active panel) + [icons/icon :main-icons/keyboard (styles/icon false)] + [icons/icon :main-icons/speech (styles/icon false)])]]) (defn send-button [{:keys [on-send-press]}] [pressable/pressable {:type :scale diff --git a/src/status_im/ui/screens/chat/components/style.cljs b/src/status_im/ui/screens/chat/components/style.cljs index 1cba33a325..88ec9edd02 100644 --- a/src/status_im/ui/screens/chat/components/style.cljs +++ b/src/status_im/ui/screens/chat/components/style.cljs @@ -104,7 +104,8 @@ (defn in-input-buttons [] {:flex-direction :row - :height 34}) + :height 34 + :overflow :hidden}) (defn send-icon-color [] colors/white) diff --git a/src/status_im/ui/screens/chat/message/message.cljs b/src/status_im/ui/screens/chat/message/message.cljs index 6e368c964b..096507a130 100644 --- a/src/status_im/ui/screens/chat/message/message.cljs +++ b/src/status_im/ui/screens/chat/message/message.cljs @@ -2,7 +2,6 @@ (:require [re-frame.core :as re-frame] [status-im.constants :as constants] [status-im.i18n :as i18n] - [quo.platform :as platform] [status-im.ui.components.colors :as colors] [status-im.ui.components.icons.vector-icons :as vector-icons] [status-im.ui.components.react :as react] @@ -341,17 +340,14 @@ [message-content-wrapper message [unknown-content-type message]]) -(defn chat-message [message set-active-panel] +(defn chat-message [message space-keeper] [reactions/with-reaction-picker {:message message :reactions @(re-frame/subscribe [:chats/message-reactions (:message-id message)]) :picker-on-open (fn [] - ;; NOTE(Ferossgp): Because of soft-input adjustResize there are some problems on android - (when (and platform/ios? (pos? @(re-frame/subscribe [:keyboard-height]))) - (set-active-panel :keep-space))) + (space-keeper true)) :picker-on-close (fn [] - (when platform/ios? - (set-active-panel nil))) + (space-keeper false)) :send-emoji (fn [{:keys [emoji-id]}] (re-frame/dispatch [::models.reactions/send-emoji-reaction {:message-id (:message-id message) diff --git a/src/status_im/ui/screens/chat/views.cljs b/src/status_im/ui/screens/chat/views.cljs index 64a0f5604a..96b90975a2 100644 --- a/src/status_im/ui/screens/chat/views.cljs +++ b/src/status_im/ui/screens/chat/views.cljs @@ -11,6 +11,7 @@ [status-im.ui.screens.chat.sheets :as sheets] [quo.animated :as animated] [quo.react-native :as rn] + [quo.platform :as platform] [status-im.ui.screens.chat.audio-message.views :as audio-message] [quo.react :as quo.react] [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.screens.chat.components.accessory :as accessory] [status-im.ui.screens.chat.components.input :as components] - [status-im.ui.screens.chat.message.datemark :as message-datemark]) - (:require-macros [status-im.utils.views :refer [defview letsubs]])) + [status-im.ui.screens.chat.message.datemark :as message-datemark])) (defn topbar [current-chat] [topbar/topbar @@ -137,14 +137,16 @@ first-not-visible))))) (debounce/debounce-and-dispatch [:chat.ui/message-visibility-changed e] 5000)) -(defview messages-view - [{:keys [group-chat chat-id public?] :as chat} bottom-space pan-handler set-active-panel] - (letsubs [messages [:chats/current-chat-messages-stream] - no-messages? [:chats/current-chat-no-messages?] - current-public-key [:multiaccount/public-key]] +(defn messages-view + [{:keys [chat bottom-space pan-responder space-keeper]}] + (let [{:keys [group-chat chat-id public?]} chat + + 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 (merge - pan-handler + pan-responder {:key-fn #(or (:message-id %) (:value %)) :ref #(reset! messages-list-ref %) :header (when (and group-chat (not public?)) @@ -167,13 +169,13 @@ :group-chat group-chat :public? public? :current-public-key current-public-key) - set-active-panel]))) + space-keeper]))) :on-viewable-items-changed on-viewable-items-changed :on-end-reached #(re-frame/dispatch [:chat.ui/load-more-messages]) :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} - :scrollIndicatorInsets {:top @bottom-space} + :scrollIndicatorInsets {:top bottom-space} :keyboardDismissMode "interactive" :keyboard-should-persist-taps :handled})])) @@ -190,20 +192,34 @@ nil)) (defn chat [] - (let [bottom-space (reagent/atom 0) - active-panel (reagent/atom nil) - position-y (animated/value 0) - pan-state (animated/value 0) - text-input-ref (quo.react/create-ref) - on-update (partial reset! bottom-space) - pan-responder (accessory/create-pan-responder position-y pan-state) + (let [bottom-space (reagent/atom 0) + panel-space (reagent/atom 0) + active-panel (reagent/atom nil) + position-y (animated/value 0) + pan-state (animated/value 0) + text-input-ref (quo.react/create-ref) + 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] (rn/configure-next (: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) + (reagent/flush) (when panel (js/setTimeout #(react/dismiss-keyboard!) 100)))] (fn [] @@ -215,7 +231,10 @@ [react/view {:style {:flex 1}} (when-not group-chat [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? [accessory/view {:y position-y :pan-state pan-state