diff --git a/resources/images/icons2/16x16/connector@2x.png b/resources/images/icons2/16x16/connector@2x.png new file mode 100644 index 0000000000..58d7e3b1f4 Binary files /dev/null and b/resources/images/icons2/16x16/connector@2x.png differ diff --git a/resources/images/icons2/16x16/connector@3x.png b/resources/images/icons2/16x16/connector@3x.png new file mode 100644 index 0000000000..bb1ab6c365 Binary files /dev/null and b/resources/images/icons2/16x16/connector@3x.png differ diff --git a/src/status_im/chat/models/input.cljs b/src/status_im/chat/models/input.cljs index 63f2680ac2..453ab26951 100644 --- a/src/status_im/chat/models/input.cljs +++ b/src/status_im/chat/models/input.cljs @@ -126,6 +126,7 @@ text (get-in message [:content :text])] {:dispatch [:chat.ui.input/set-chat-input-text text current-chat-id] + :set-input-text [current-chat-id text] :db (-> db (assoc-in [:chat/inputs current-chat-id :metadata :editing-message] message) diff --git a/src/status_im/ui/screens/chat/components/input.cljs b/src/status_im/ui/screens/chat/components/input.cljs index 8942677a2c..83ba8c770f 100644 --- a/src/status_im/ui/screens/chat/components/input.cljs +++ b/src/status_im/ui/screens/chat/components/input.cljs @@ -187,16 +187,6 @@ (when platform/ios? (re-frame/dispatch [::mentions/calculate-suggestions mentionable-users])))) -(re-frame/reg-fx - :set-input-text - (fn [[chat-id text]] - ;; We enable mentions - (swap! mentions-enabled assoc chat-id true) - (on-text-change text chat-id) - ;; We update the key so that we force a refresh of the text input, as those - ;; are not ratoms - (force-text-input-update!))) - (fx/defn set-input-text "Set input text for current-chat. Takes db and input text and cofx as arguments and returns new fx. Always clear all validation messages." diff --git a/src/status_im/ui2/screens/chat/components/edit/style.cljs b/src/status_im/ui2/screens/chat/components/edit/style.cljs new file mode 100644 index 0000000000..f2bf804e5f --- /dev/null +++ b/src/status_im/ui2/screens/chat/components/edit/style.cljs @@ -0,0 +1,25 @@ +(ns status-im.ui2.screens.chat.components.edit.style) + +(def container + {:flex-direction :row + :height 24}) + +(def content-container + {:padding-horizontal 10 + :flex 1 + :flex-direction :row}) + +(def icon-container + {:position :absolute + :left 10 + :bottom -4 + :width 16 + :height 16}) + +(def text-container + {:position :absolute + :left 36 + :right 54 + :top 3 + :flex-direction :row + :align-items :center}) diff --git a/src/status_im/ui2/screens/chat/components/edit/view.cljs b/src/status_im/ui2/screens/chat/components/edit/view.cljs new file mode 100644 index 0000000000..4465d438af --- /dev/null +++ b/src/status_im/ui2/screens/chat/components/edit/view.cljs @@ -0,0 +1,28 @@ +(ns status-im.ui2.screens.chat.components.edit.view + (:require [re-frame.core :as rf] + [react-native.core :as rn] + [quo2.foundations.colors :as colors] + [i18n.i18n :as i18n] + [status-im.ui2.screens.chat.components.edit.style :as style] + [quo2.core :as quo] + [quo.gesture-handler :as gesture-handler])) + +(defn edit-message [] + [rn/view {:style style/container + :accessibility-label :edit-message} + [rn/view {:style style/content-container} + [quo/icon :i/connector {:size 16 + :color (colors/theme-colors colors/neutral-40 colors/neutral-60) + :container-style style/icon-container}] + [rn/view {:style style/text-container} + [quo/text {:weight :medium + :size :paragraph-2} + (i18n/label :t/editing-message)]]] + [gesture-handler/touchable-without-feedback + {:accessibility-label :reply-cancel-button + :on-press #(rf/dispatch [:chat.ui/cancel-message-edit])} + [quo/button {:width 24 + :size 24 + :type :outline} + [quo/icon :i/close {:size 16 + :color (colors/theme-colors colors/neutral-100 colors/neutral-40)}]]]]) diff --git a/src/status_im/ui2/screens/chat/composer/edit/style.cljs b/src/status_im/ui2/screens/chat/composer/edit/style.cljs new file mode 100644 index 0000000000..27d3282d8a --- /dev/null +++ b/src/status_im/ui2/screens/chat/composer/edit/style.cljs @@ -0,0 +1,5 @@ +(ns status-im.ui2.screens.chat.composer.edit.style) + +(def container + {:padding-horizontal 15 + :padding-vertical 8}) diff --git a/src/status_im/ui2/screens/chat/composer/edit/view.cljs b/src/status_im/ui2/screens/chat/composer/edit/view.cljs new file mode 100644 index 0000000000..8f918b7303 --- /dev/null +++ b/src/status_im/ui2/screens/chat/composer/edit/view.cljs @@ -0,0 +1,21 @@ +(ns status-im.ui2.screens.chat.composer.edit.view + (:require [react-native.core :as rn] + [status-im.ui2.screens.chat.composer.input :as input] + [status-im.ui2.screens.chat.components.edit.view :as edit] + [status-im.ui2.screens.chat.composer.edit.style :as style])) + +(defn- focus-input-on-edit [edit had-edit text-input-ref] + ;;when we show edit we focus input + (when-not (= edit @had-edit) + (reset! had-edit edit) + (when edit + ;; A setTimeout of 0 is necessary to ensure the statement is enqueued and will get executed ASAP. + (js/setTimeout #(input/input-focus text-input-ref) 0)))) + +(defn edit-message-auto-focus-wrapper [text-input-ref _] + (let [had-edit (atom nil)] + (fn [_ edit] + (focus-input-on-edit edit had-edit text-input-ref) + (when edit + [rn/view {:style style/container} + [edit/edit-message]])))) diff --git a/src/status_im/ui2/screens/chat/composer/input.cljs b/src/status_im/ui2/screens/chat/composer/input.cljs index d2abac8897..221b8870db 100644 --- a/src/status_im/ui2/screens/chat/composer/input.cljs +++ b/src/status_im/ui2/screens/chat/composer/input.cljs @@ -21,6 +21,7 @@ (defonce input-texts (atom {})) (defonce mentions-enabled (reagent/atom {})) (defonce chat-input-key (reagent/atom 1)) +(defonce text-input-ref (reagent/atom nil)) (declare selectable-text-input) @@ -182,6 +183,7 @@ [rn/text (when (= type :mention) {:style {:color colors/primary-50}}) text]) input-with-mentions) (get @input-texts chat-id)))] + (reset! text-input-ref (:text-input-ref refs)) ;when ios implementation for selectable-text-input is ready, we need remove this condition and use selectable-text-input directly. (if platform/android? [selectable-text-input chat-id props children] @@ -200,6 +202,17 @@ (on-text-change text chat-id) (.setNativeProps ^js text-input (clj->js {:text text}))) +(re-frame/reg-fx + :set-input-text + (fn [[chat-id text]] + (if platform/ios? + (.setNativeProps ^js (quo.react/current-ref @text-input-ref) (clj->js {:text text})) + (do + (on-text-change text chat-id) + (if (string/blank? text) + (.clear ^js (quo.react/current-ref @text-input-ref)) + (.setNativeProps ^js (quo.react/current-ref @text-input-ref) (clj->js {:text text}))))))) + (defn calculate-input-text [{:keys [full-text selection-start selection-end]} content] (let [head (subs full-text 0 selection-start) tail (subs full-text selection-end)] diff --git a/src/status_im/ui2/screens/chat/composer/view.cljs b/src/status_im/ui2/screens/chat/composer/view.cljs index 77e2098a49..17a66d43a9 100644 --- a/src/status_im/ui2/screens/chat/composer/view.cljs +++ b/src/status_im/ui2/screens/chat/composer/view.cljs @@ -3,7 +3,7 @@ [react-native.reanimated :as reanimated] [re-frame.core :as re-frame] [quo.components.safe-area :as safe-area] - [quo.react-native :as rn] + [quo.react-native :as rn :refer [navigation-const]] [status-im.ui2.screens.chat.composer.style :as styles] [status-im.ui2.screens.chat.composer.reply :as reply] [quo2.components.buttons.button :as quo2.button] @@ -16,7 +16,8 @@ [status-im.ui.components.permissions :as permissions] [status-im.ui2.screens.chat.photo-selector.view :as photo-selector] [status-im.utils.utils :as utils] - [i18n.i18n :as i18n])) + [i18n.i18n :as i18n] + [status-im.ui2.screens.chat.composer.edit.view :as edit])) (defn calculate-y [context keyboard-shown min-y max-y added-value] (if keyboard-shown @@ -135,13 +136,14 @@ [:f> (fn [] (let [reply ( keyboard-height 0) keyboard-height 360) (:top insets)) ; 360 - default height + max-y (- window-height (if (> keyboard-height 0) keyboard-height 360) (:top insets) (:status-bar-height @navigation-const)) ; 360 - default height max-height (Math/abs (- max-y 56 (:bottom insets))) ; 56 - top-bar height - added-value (if (and (not (seq suggestions)) reply) 38 0) ; increased height of input box needed when reply - min-y (+ min-y (when reply 38)) + added-value (if (and (not (seq suggestions)) (or edit reply)) 38 0) ; increased height of input box needed when reply + min-y (+ min-y (when (or edit reply) 38)) y (get-y-value context keyboard-shown min-y max-y added-value max-height chat-id suggestions reply) translate-y (reanimated/use-shared-value 0) shared-height (reanimated/use-shared-value min-y) @@ -160,6 +162,12 @@ (reanimated/set-shared-value bg-opacity (reanimated/with-timing 0))) (reanimated/set-shared-value translate-y (reanimated/with-timing (- y))) (reanimated/set-shared-value shared-height (reanimated/with-timing (min y max-height))))) + (quo.react/effect! #(when (and (not edit) (= (:state @context) :max)) + (swap! context assoc :state :min) + (reanimated/set-shared-value translate-y (reanimated/with-timing (- min-y))) + (reanimated/set-shared-value shared-height (reanimated/with-timing min-y)) + (reanimated/set-shared-value bg-opacity (reanimated/with-timing 0)) + (re-frame/dispatch [:dismiss-keyboard])) edit) [reanimated/view {:style (reanimated/apply-animations-to-style {:height shared-height} {})} @@ -170,6 +178,7 @@ (styles/input-bottom-sheet window-height))} ;handle [rn/view {:style (styles/bottom-sheet-handle)}] + [edit/edit-message-auto-focus-wrapper (:text-input-ref refs) edit] [reply/reply-message-auto-focus-wrapper (:text-input-ref refs) reply] [rn/view {:style {:height (- max-y 80 added-value)}} [input/text-input {:chat-id chat-id