Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d433285acb | ||
|
|
eb16f4b6c4 | ||
|
|
9268060aa9 | ||
|
|
7ab9e7abd0 | ||
|
|
2430bde3d5 | ||
|
|
739556f2b4 | ||
|
|
f4ac7a4c51 | ||
|
|
36fac66eac |
@@ -3,6 +3,7 @@
|
|||||||
[quo.react :as react]
|
[quo.react :as react]
|
||||||
[quo.react-native :as rn]
|
[quo.react-native :as rn]
|
||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
|
[status-im2.config :as config]
|
||||||
[utils.re-frame :as rf]
|
[utils.re-frame :as rf]
|
||||||
[taoensso.timbre :as log]
|
[taoensso.timbre :as log]
|
||||||
[native-module.core :as native-module]))
|
[native-module.core :as native-module]))
|
||||||
@@ -167,17 +168,20 @@
|
|||||||
cursor (+ at-sign-idx (count primary-name) 2)]
|
cursor (+ at-sign-idx (count primary-name) 2)]
|
||||||
(rf/merge
|
(rf/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (-> db
|
(let [common {:db (-> db
|
||||||
(assoc-in [:chats/mention-suggestions chat-id] nil))
|
(assoc-in [:chats/mention-suggestions chat-id] nil))
|
||||||
:set-text-input-value [chat-id new-text text-input-ref]
|
:dispatch [:chat.ui/set-chat-input-text new-text chat-id]}
|
||||||
:dispatch [:chat.ui/set-chat-input-text new-text chat-id]}
|
extra (if (not config/new-composer-enabled?)
|
||||||
;; NOTE(rasom): Some keyboards do not react on selection property passed to
|
;; NOTE(rasom): Some keyboards do not react on selection property passed to
|
||||||
;; text input (specifically Samsung keyboard with predictive text set on).
|
;; text input (specifically Samsung keyboard with predictive text set on).
|
||||||
;; In this case, if the user continues typing after the programmatic change,
|
;; In this case, if the user continues typing after the programmatic change,
|
||||||
;; the new text is added to the last known cursor position before
|
;; the new text is added to the last known cursor position before
|
||||||
;; programmatic change. By calling `reset-text-input-cursor` we force the
|
;; programmatic change. By calling `reset-text-input-cursor` we force the
|
||||||
;; keyboard's cursor position to be changed before the next input.
|
;; keyboard's cursor position to be changed before the next input.
|
||||||
(reset-text-input-cursor text-input-ref cursor)
|
{:set-text-input-value [chat-id new-text text-input-ref]
|
||||||
|
:reset-text-input-cursor (reset-text-input-cursor text-input-ref cursor)}
|
||||||
|
{})]
|
||||||
|
(merge common extra))
|
||||||
(recheck-at-idxs public-key))))
|
(recheck-at-idxs public-key))))
|
||||||
|
|
||||||
(rf/defn clear-suggestions
|
(rf/defn clear-suggestions
|
||||||
|
|||||||
@@ -159,4 +159,4 @@
|
|||||||
|
|
||||||
(def default-kdf-iterations 3200)
|
(def default-kdf-iterations 3200)
|
||||||
|
|
||||||
(def ^:const new-composer-enabled? false)
|
(def ^:const new-composer-enabled? true)
|
||||||
|
|||||||
@@ -21,6 +21,8 @@
|
|||||||
|
|
||||||
(def ^:const edit-container-height 32)
|
(def ^:const edit-container-height 32)
|
||||||
|
|
||||||
|
(def ^:const mentions-max-height 240)
|
||||||
|
|
||||||
(def ^:const extra-content-offset (if platform/ios? 6 0))
|
(def ^:const extra-content-offset (if platform/ios? 6 0))
|
||||||
|
|
||||||
(def ^:const content-change-threshold 10)
|
(def ^:const content-change-threshold 10)
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
(ns status-im2.contexts.chat.bottom-sheet-composer.handlers
|
(ns status-im2.contexts.chat.bottom-sheet-composer.handlers
|
||||||
(:require [react-native.reanimated :as reanimated]
|
(:require
|
||||||
[reagent.core :as reagent]
|
[react-native.reanimated :as reanimated]
|
||||||
[oops.core :as oops]
|
[reagent.core :as reagent]
|
||||||
[status-im2.contexts.chat.bottom-sheet-composer.constants :as constants]
|
[oops.core :as oops]
|
||||||
[status-im2.contexts.chat.bottom-sheet-composer.keyboard :as kb]
|
[status-im2.contexts.chat.bottom-sheet-composer.constants :as constants]
|
||||||
[status-im2.contexts.chat.bottom-sheet-composer.utils :as utils]
|
[status-im2.contexts.chat.bottom-sheet-composer.keyboard :as kb]
|
||||||
[utils.re-frame :as rf]))
|
[status-im2.contexts.chat.bottom-sheet-composer.utils :as utils]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(defn focus
|
(defn focus
|
||||||
[{:keys [input-ref] :as props}
|
[{:keys [input-ref] :as props}
|
||||||
@@ -70,7 +71,8 @@
|
|||||||
(reanimated/animate height new-height)
|
(reanimated/animate height new-height)
|
||||||
(reanimated/set-shared-value saved-height new-height))
|
(reanimated/set-shared-value saved-height new-height))
|
||||||
(when (= new-height max-height)
|
(when (= new-height max-height)
|
||||||
(reset! maximized? true))
|
(reset! maximized? true)
|
||||||
|
(rf/dispatch [:chat.ui/set-input-maximized true]))
|
||||||
(if (utils/show-background? saved-height max-height new-height)
|
(if (utils/show-background? saved-height max-height new-height)
|
||||||
(do
|
(do
|
||||||
(reanimated/set-shared-value background-y 0)
|
(reanimated/set-shared-value background-y 0)
|
||||||
@@ -82,10 +84,12 @@
|
|||||||
|
|
||||||
(defn scroll
|
(defn scroll
|
||||||
[event
|
[event
|
||||||
|
{:keys [scroll-y]}
|
||||||
{:keys [gradient-z-index focused?]}
|
{:keys [gradient-z-index focused?]}
|
||||||
{:keys [gradient-opacity]}
|
{:keys [gradient-opacity]}
|
||||||
{:keys [lines max-lines]}]
|
{:keys [lines max-lines]}]
|
||||||
(let [y (oops/oget event "nativeEvent.contentOffset.y")]
|
(let [y (oops/oget event "nativeEvent.contentOffset.y")]
|
||||||
|
(reset! scroll-y y)
|
||||||
(when (utils/show-top-gradient? y lines max-lines gradient-opacity focused?)
|
(when (utils/show-top-gradient? y lines max-lines gradient-opacity focused?)
|
||||||
(reset! gradient-z-index 1)
|
(reset! gradient-z-index 1)
|
||||||
(js/setTimeout #(reanimated/animate gradient-opacity 1) 0))
|
(js/setTimeout #(reanimated/animate gradient-opacity 1) 0))
|
||||||
@@ -105,10 +109,12 @@
|
|||||||
(when @recording?
|
(when @recording?
|
||||||
(@record-reset-fn)
|
(@record-reset-fn)
|
||||||
(reset! recording? false))
|
(reset! recording? false))
|
||||||
(rf/dispatch [:chat.ui/set-chat-input-text text]))
|
(rf/dispatch [:chat.ui/set-chat-input-text text])
|
||||||
|
(rf/dispatch [:mention/on-change-text text]))
|
||||||
|
|
||||||
(defn selection-change
|
(defn selection-change
|
||||||
[event {:keys [lock-selection? cursor-position]}]
|
[event {:keys [lock-selection? cursor-position]}]
|
||||||
|
(println "selectionc ahnge")
|
||||||
(when-not @lock-selection?
|
(when-not @lock-selection?
|
||||||
(reset! cursor-position (oops/oget event "nativeEvent.selection.end"))))
|
(reset! cursor-position (oops/oget event "nativeEvent.selection.end"))))
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
(ns status-im2.contexts.chat.bottom-sheet-composer.mentions.style
|
||||||
|
(:require [quo2.foundations.colors :as colors]
|
||||||
|
[react-native.platform :as platform]
|
||||||
|
[react-native.reanimated :as reanimated]
|
||||||
|
[status-im2.contexts.chat.bottom-sheet-composer.constants :as constants]))
|
||||||
|
|
||||||
|
|
||||||
|
(defn shadow
|
||||||
|
[]
|
||||||
|
(if platform/ios?
|
||||||
|
{:shadow-radius (colors/theme-colors 30 50)
|
||||||
|
:shadow-opacity (colors/theme-colors 0.1 0.7)
|
||||||
|
:shadow-color colors/neutral-100
|
||||||
|
:shadow-offset {:width 0 :height (colors/theme-colors 8 12)}}
|
||||||
|
{:elevation 10}))
|
||||||
|
|
||||||
|
(defn container
|
||||||
|
[opacity bottom]
|
||||||
|
(reanimated/apply-animations-to-style
|
||||||
|
{:opacity opacity}
|
||||||
|
(merge
|
||||||
|
{:position :absolute
|
||||||
|
:bottom bottom
|
||||||
|
:left 8
|
||||||
|
:right 8
|
||||||
|
:border-radius 16
|
||||||
|
:z-index 4
|
||||||
|
:max-height constants/mentions-max-height
|
||||||
|
:background-color (colors/theme-colors colors/white colors/neutral-95)}
|
||||||
|
(shadow))))
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
(ns status-im2.contexts.chat.bottom-sheet-composer.mentions.view
|
||||||
|
(:require
|
||||||
|
[react-native.hooks :as hooks]
|
||||||
|
[react-native.platform :as platform]
|
||||||
|
[react-native.safe-area :as safe-area]
|
||||||
|
[reagent.core :as reagent]
|
||||||
|
[status-im2.contexts.chat.bottom-sheet-composer.utils :as utils]
|
||||||
|
[utils.re-frame :as rf]
|
||||||
|
[react-native.core :as rn]
|
||||||
|
[react-native.reanimated :as reanimated]
|
||||||
|
[status-im2.common.contact-list-item.view :as contact-list-item]
|
||||||
|
[status-im2.contexts.chat.bottom-sheet-composer.mentions.style :as style]))
|
||||||
|
|
||||||
|
(defn update-cursor
|
||||||
|
[user {:keys [cursor-position input-ref]}]
|
||||||
|
(when platform/android?
|
||||||
|
(let [new-cursor-pos (+ (count (:primary-name user)) @cursor-position)]
|
||||||
|
(reset! cursor-position new-cursor-pos)
|
||||||
|
(reagent/next-tick #(when @input-ref
|
||||||
|
(.setNativeProps ^js @input-ref
|
||||||
|
(clj->js {:selection {:start new-cursor-pos
|
||||||
|
:end
|
||||||
|
new-cursor-pos}})))))))
|
||||||
|
|
||||||
|
(defn mention-item
|
||||||
|
[user _ _ render-data]
|
||||||
|
[contact-list-item/contact-list-item
|
||||||
|
{:on-press (fn []
|
||||||
|
(rf/dispatch [:chat.ui/select-mention nil user])
|
||||||
|
(update-cursor user render-data))}
|
||||||
|
user])
|
||||||
|
|
||||||
|
(defn- f-view
|
||||||
|
[suggestions-atom props state animations max-height cursor-pos]
|
||||||
|
(let [{:keys [keyboard-height]} (hooks/use-keyboard)
|
||||||
|
suggestions (rf/sub [:chat/mention-suggestions])
|
||||||
|
opacity (reanimated/use-shared-value (if (seq suggestions) 1 0))
|
||||||
|
size (count suggestions)
|
||||||
|
data {:keyboard-height keyboard-height
|
||||||
|
:insets (safe-area/get-insets)
|
||||||
|
:curr-height (reanimated/get-shared-value (:height animations))
|
||||||
|
:window-height (rf/sub [:dimensions/window-height])
|
||||||
|
:reply (rf/sub [:chats/reply-message])
|
||||||
|
:edit (rf/sub [:chats/edit-message])}
|
||||||
|
mentions-pos (utils/calc-suggestions-position cursor-pos max-height size state data)]
|
||||||
|
(rn/use-effect
|
||||||
|
(fn []
|
||||||
|
(if (seq suggestions)
|
||||||
|
(reset! suggestions-atom suggestions)
|
||||||
|
(js/setTimeout #(reset! suggestions-atom suggestions) 300))
|
||||||
|
(reanimated/animate opacity (if (seq suggestions) 1 0)))
|
||||||
|
[(seq suggestions)])
|
||||||
|
[reanimated/view
|
||||||
|
{:style (style/container opacity mentions-pos)}
|
||||||
|
[rn/flat-list
|
||||||
|
{:keyboard-should-persist-taps :always
|
||||||
|
:data (vals @suggestions-atom)
|
||||||
|
:key-fn :key
|
||||||
|
:render-fn mention-item
|
||||||
|
:render-data {:cursor-position (:cursor-position state)
|
||||||
|
:input-ref (:input-ref props)}
|
||||||
|
:accessibility-label :mentions-list}]]))
|
||||||
|
|
||||||
|
(defn view
|
||||||
|
[props state animations max-height cursor-pos]
|
||||||
|
(let [suggestions-atom (reagent/atom {})]
|
||||||
|
[:f> f-view suggestions-atom props state animations max-height cursor-pos]))
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
(ns status-im2.contexts.chat.bottom-sheet-composer.selectable-input.view
|
||||||
|
(:require [utils.i18n :as i18n]))
|
||||||
|
|
||||||
|
(declare first-level-menu-items second-level-menu-items)
|
||||||
|
|
||||||
|
(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)]
|
||||||
|
(str head content tail)))
|
||||||
|
|
||||||
|
(defn reset-to-first-level-menu
|
||||||
|
[first-level menu-items]
|
||||||
|
(reset! first-level true)
|
||||||
|
(reset! menu-items first-level-menu-items))
|
||||||
|
|
||||||
|
(defn append-markdown-char
|
||||||
|
[{:keys [first-level menu-items content selection-start selection-end text-input-handle
|
||||||
|
selection-event]
|
||||||
|
:as params} wrap-chars]
|
||||||
|
(let [content (str wrap-chars content wrap-chars)
|
||||||
|
new-text (calculate-input-text params content)
|
||||||
|
len-wrap-chars (count wrap-chars)
|
||||||
|
selection-start (+ selection-start len-wrap-chars)
|
||||||
|
selection-end (+ selection-end len-wrap-chars)]
|
||||||
|
;don't update selection directly here, process it within on-selection-change instead
|
||||||
|
;so that we can avoid java.lang.IndexOutOfBoundsException: setSpan..
|
||||||
|
(reset! selection-event {:start selection-start
|
||||||
|
:end selection-end
|
||||||
|
:text-input-handle text-input-handle})
|
||||||
|
;(update-input-text params new-text)
|
||||||
|
(reset-to-first-level-menu first-level menu-items)))
|
||||||
|
|
||||||
|
|
||||||
|
(def second-level-menus
|
||||||
|
{:bold #(append-markdown-char % "**")
|
||||||
|
|
||||||
|
:italic #(append-markdown-char % "*")
|
||||||
|
|
||||||
|
:strikethrough #(append-markdown-char % "~~")})
|
||||||
|
|
||||||
|
(def second-level-menu-items (map i18n/label (keys second-level-menus)))
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
(ns status-im2.contexts.chat.bottom-sheet-composer.utils
|
(ns status-im2.contexts.chat.bottom-sheet-composer.utils
|
||||||
(:require
|
(:require
|
||||||
|
[clojure.string :as string]
|
||||||
[oops.core :as oops]
|
[oops.core :as oops]
|
||||||
[react-native.platform :as platform]
|
[react-native.platform :as platform]
|
||||||
[react-native.reanimated :as reanimated]
|
[react-native.reanimated :as reanimated]
|
||||||
@@ -90,3 +91,53 @@
|
|||||||
(reanimated/set-shared-value last-height constants/input-height))
|
(reanimated/set-shared-value last-height constants/input-height))
|
||||||
(reset! text-value "")
|
(reset! text-value "")
|
||||||
(rf/dispatch [:chat.ui/set-input-content-height constants/input-height]))
|
(rf/dispatch [:chat.ui/set-input-content-height constants/input-height]))
|
||||||
|
|
||||||
|
(defn update-input
|
||||||
|
[{:keys [input-ref]}
|
||||||
|
{:keys [text-value]}
|
||||||
|
input-text]
|
||||||
|
(when (and input-text (not= @text-value input-text))
|
||||||
|
(reset! text-value input-text)
|
||||||
|
(when @input-ref
|
||||||
|
(.setNativeProps ^js @input-ref (clj->js {:text input-text})))))
|
||||||
|
|
||||||
|
(defn count-lines
|
||||||
|
[s]
|
||||||
|
(-> s
|
||||||
|
(string/split #"\n" -1)
|
||||||
|
(butlast)
|
||||||
|
count))
|
||||||
|
|
||||||
|
(defn cursor-y-position-relative-to-container
|
||||||
|
[{:keys [scroll-y]}
|
||||||
|
{:keys [cursor-position text-value]}]
|
||||||
|
(let [sub-text (subs @text-value 0 @cursor-position)
|
||||||
|
sub-text-lines (count-lines sub-text)
|
||||||
|
scrolled-lines (Math/round (/ @scroll-y constants/line-height))
|
||||||
|
sub-text-lines-in-view (- sub-text-lines scrolled-lines)]
|
||||||
|
(* sub-text-lines-in-view constants/line-height)))
|
||||||
|
|
||||||
|
(defn calc-suggestions-position
|
||||||
|
[cursor-pos max-height size
|
||||||
|
{:keys [maximized?]}
|
||||||
|
{:keys [insets curr-height window-height keyboard-height edit reply]}]
|
||||||
|
(let [base (+ constants/composer-default-height (:bottom insets) 8)
|
||||||
|
base (+ base (- curr-height constants/input-height))
|
||||||
|
base (if edit
|
||||||
|
(+ base constants/edit-container-height)
|
||||||
|
base)
|
||||||
|
base (if reply
|
||||||
|
(+ base constants/reply-container-height)
|
||||||
|
base)
|
||||||
|
view-height (- window-height keyboard-height (:top insets))
|
||||||
|
container-height (bounded-val
|
||||||
|
(* (/ constants/mentions-max-height 4) size)
|
||||||
|
(/ constants/mentions-max-height 4)
|
||||||
|
constants/mentions-max-height)]
|
||||||
|
(if @maximized?
|
||||||
|
(if (< (+ cursor-pos container-height) max-height)
|
||||||
|
(+ constants/actions-container-height (:bottom insets))
|
||||||
|
(+ constants/actions-container-height (:bottom insets) (- max-height cursor-pos) 18))
|
||||||
|
(if (< (+ base container-height) view-height)
|
||||||
|
base
|
||||||
|
(+ constants/actions-container-height (:bottom insets) (- curr-height cursor-pos) 18)))))
|
||||||
|
|||||||
@@ -7,11 +7,13 @@
|
|||||||
[react-native.reanimated :as reanimated]
|
[react-native.reanimated :as reanimated]
|
||||||
[reagent.core :as reagent]
|
[reagent.core :as reagent]
|
||||||
[utils.i18n :as i18n]
|
[utils.i18n :as i18n]
|
||||||
|
[utils.re-frame :as rf]
|
||||||
|
[oops.core :as oops]
|
||||||
[status-im2.contexts.chat.bottom-sheet-composer.style :as style]
|
[status-im2.contexts.chat.bottom-sheet-composer.style :as style]
|
||||||
[status-im2.contexts.chat.bottom-sheet-composer.images.view :as images]
|
[status-im2.contexts.chat.bottom-sheet-composer.images.view :as images]
|
||||||
[status-im2.contexts.chat.bottom-sheet-composer.reply.view :as reply]
|
[status-im2.contexts.chat.bottom-sheet-composer.reply.view :as reply]
|
||||||
[utils.re-frame :as rf]
|
|
||||||
[status-im2.contexts.chat.bottom-sheet-composer.edit.view :as edit]
|
[status-im2.contexts.chat.bottom-sheet-composer.edit.view :as edit]
|
||||||
|
[status-im2.contexts.chat.bottom-sheet-composer.mentions.view :as mentions]
|
||||||
[status-im2.contexts.chat.bottom-sheet-composer.utils :as utils]
|
[status-im2.contexts.chat.bottom-sheet-composer.utils :as utils]
|
||||||
[status-im2.contexts.chat.bottom-sheet-composer.constants :as constants]
|
[status-im2.contexts.chat.bottom-sheet-composer.constants :as constants]
|
||||||
[status-im2.contexts.chat.bottom-sheet-composer.actions.view :as actions]
|
[status-im2.contexts.chat.bottom-sheet-composer.actions.view :as actions]
|
||||||
@@ -20,131 +22,150 @@
|
|||||||
[status-im2.contexts.chat.bottom-sheet-composer.effects :as effects]
|
[status-im2.contexts.chat.bottom-sheet-composer.effects :as effects]
|
||||||
[status-im2.contexts.chat.bottom-sheet-composer.gesture :as drag-gesture]
|
[status-im2.contexts.chat.bottom-sheet-composer.gesture :as drag-gesture]
|
||||||
[status-im2.contexts.chat.bottom-sheet-composer.handlers :as handler]
|
[status-im2.contexts.chat.bottom-sheet-composer.handlers :as handler]
|
||||||
[status-im2.contexts.chat.bottom-sheet-composer.gradients.view :as gradients]))
|
[status-im2.contexts.chat.bottom-sheet-composer.gradients.view :as gradients]
|
||||||
|
[status-im2.contexts.chat.bottom-sheet-composer.selectable-input.view :as selectable-input]))
|
||||||
|
|
||||||
(defn sheet
|
(defn sheet
|
||||||
[insets window-height blur-height opacity background-y]
|
[insets window-height blur-height opacity background-y]
|
||||||
[:f>
|
[:f>
|
||||||
(fn []
|
(fn []
|
||||||
(let [props {:input-ref (atom nil)
|
(let [props {:input-ref (atom nil)
|
||||||
:keyboard-show-listener (atom nil)
|
:keyboard-show-listener (atom nil)
|
||||||
:keyboard-frame-listener (atom nil)
|
:keyboard-frame-listener (atom nil)
|
||||||
:keyboard-hide-listener (atom nil)
|
:keyboard-hide-listener (atom nil)
|
||||||
:emoji-kb-extra-height (atom nil)
|
:emoji-kb-extra-height (atom nil)
|
||||||
:saved-emoji-kb-extra-height (atom nil)
|
:saved-emoji-kb-extra-height (atom nil)
|
||||||
:replying? (atom nil)
|
:replying? (atom nil)
|
||||||
:sending-images? (atom nil)
|
:sending-images? (atom nil)
|
||||||
:editing? (atom nil)
|
:editing? (atom nil)
|
||||||
:record-permission? (atom nil)
|
:record-permission? (atom nil)
|
||||||
:record-reset-fn (atom nil)}
|
:record-reset-fn (atom nil)
|
||||||
state {:text-value (reagent/atom "")
|
:scroll-y (atom 0)}
|
||||||
:cursor-position (reagent/atom 0)
|
state {:text-value (reagent/atom "")
|
||||||
:saved-cursor-position (reagent/atom 0)
|
:cursor-position (reagent/atom 0)
|
||||||
:gradient-z-index (reagent/atom 0)
|
:saved-cursor-position (reagent/atom 0)
|
||||||
:kb-default-height (reagent/atom nil)
|
:gradient-z-index (reagent/atom 0)
|
||||||
:gesture-enabled? (reagent/atom true)
|
:kb-default-height (reagent/atom nil)
|
||||||
:lock-selection? (reagent/atom true)
|
:gesture-enabled? (reagent/atom true)
|
||||||
:focused? (reagent/atom false)
|
:lock-selection? (reagent/atom true)
|
||||||
:lock-layout? (reagent/atom false)
|
:focused? (reagent/atom false)
|
||||||
:maximized? (reagent/atom false)
|
:lock-layout? (reagent/atom false)
|
||||||
:recording? (reagent/atom false)}]
|
:maximized? (reagent/atom false)
|
||||||
|
:recording? (reagent/atom false)}
|
||||||
|
selectable-input-ref (atom nil)
|
||||||
|
menu-items (reagent/atom selectable-input/first-level-menu-items)
|
||||||
|
manager (rn/selectable-text-input-manager)]
|
||||||
[:f>
|
[:f>
|
||||||
(fn []
|
(fn []
|
||||||
(let [images (rf/sub [:chats/sending-image])
|
(let [images (rf/sub [:chats/sending-image])
|
||||||
audio (rf/sub [:chats/sending-audio])
|
audio (rf/sub [:chats/sending-audio])
|
||||||
reply (rf/sub [:chats/reply-message])
|
reply (rf/sub [:chats/reply-message])
|
||||||
edit (rf/sub [:chats/edit-message])
|
edit (rf/sub [:chats/edit-message])
|
||||||
{:keys [input-text input-content-height]
|
{:keys [input-text input-content-height]
|
||||||
:as chat-input} (rf/sub [:chats/current-chat-input])
|
:as chat-input} (rf/sub [:chats/current-chat-input])
|
||||||
content-height (reagent/atom (or input-content-height
|
content-height (reagent/atom (or input-content-height
|
||||||
constants/input-height))
|
constants/input-height))
|
||||||
{:keys [keyboard-shown keyboard-height]} (hooks/use-keyboard)
|
{:keys [keyboard-shown keyboard-height]} (hooks/use-keyboard)
|
||||||
kb-height (kb/get-kb-height keyboard-height
|
kb-height (kb/get-kb-height keyboard-height
|
||||||
@(:kb-default-height state))
|
@(:kb-default-height state))
|
||||||
max-height (utils/calc-max-height window-height
|
max-height (utils/calc-max-height window-height
|
||||||
kb-height
|
kb-height
|
||||||
insets
|
insets
|
||||||
(seq images)
|
(boolean (seq images))
|
||||||
reply
|
reply
|
||||||
edit)
|
edit)
|
||||||
lines (utils/calc-lines @content-height)
|
lines (utils/calc-lines @content-height)
|
||||||
max-lines (utils/calc-lines max-height)
|
max-lines (utils/calc-lines max-height)
|
||||||
initial-height (if (> lines 1)
|
initial-height (if (> lines 1)
|
||||||
constants/multiline-minimized-height
|
constants/multiline-minimized-height
|
||||||
constants/input-height)
|
constants/input-height)
|
||||||
animations {:gradient-opacity (reanimated/use-shared-value
|
animations {:gradient-opacity (reanimated/use-shared-value
|
||||||
0)
|
0)
|
||||||
:container-opacity (reanimated/use-shared-value
|
:container-opacity (reanimated/use-shared-value
|
||||||
(if (utils/empty-input?
|
(if (utils/empty-input?
|
||||||
input-text
|
input-text
|
||||||
images
|
images
|
||||||
reply
|
reply
|
||||||
audio)
|
audio)
|
||||||
0.7
|
0.7
|
||||||
1))
|
1))
|
||||||
:height (reanimated/use-shared-value
|
:height (reanimated/use-shared-value
|
||||||
initial-height)
|
initial-height)
|
||||||
:saved-height (reanimated/use-shared-value
|
:saved-height (reanimated/use-shared-value
|
||||||
initial-height)
|
initial-height)
|
||||||
:last-height (reanimated/use-shared-value
|
:last-height (reanimated/use-shared-value
|
||||||
(utils/bounded-val
|
(utils/bounded-val
|
||||||
@content-height
|
@content-height
|
||||||
constants/input-height
|
constants/input-height
|
||||||
max-height))
|
max-height))
|
||||||
:opacity opacity
|
:opacity opacity
|
||||||
:background-y background-y}
|
:background-y background-y}
|
||||||
dimensions {:content-height content-height
|
dimensions {:content-height content-height
|
||||||
:max-height max-height
|
:max-height max-height
|
||||||
:window-height window-height
|
:window-height window-height
|
||||||
:lines lines
|
:lines lines
|
||||||
:max-lines max-lines}
|
:max-lines max-lines}
|
||||||
show-bottom-gradient? (utils/show-bottom-gradient? state dimensions)]
|
show-bottom-gradient? (utils/show-bottom-gradient? state dimensions)
|
||||||
|
cursor-pos (utils/cursor-y-position-relative-to-container
|
||||||
|
props
|
||||||
|
state)]
|
||||||
(effects/initialize props
|
(effects/initialize props
|
||||||
state
|
state
|
||||||
animations
|
animations
|
||||||
dimensions
|
dimensions
|
||||||
chat-input
|
chat-input
|
||||||
keyboard-height
|
keyboard-height
|
||||||
(seq images)
|
(boolean (seq images))
|
||||||
reply
|
reply
|
||||||
edit
|
edit
|
||||||
audio)
|
audio)
|
||||||
[gesture/gesture-detector
|
(rn/use-effect (fn []
|
||||||
{:gesture (drag-gesture/drag-gesture props state animations dimensions keyboard-shown)}
|
(let [selectable-text-input-handle (rn/find-node-handle @selectable-input-ref)
|
||||||
[reanimated/view
|
text-input-handle (rn/find-node-handle @(:input-ref props))]
|
||||||
{:style (style/sheet-container insets state animations)
|
(oops/ocall manager :setupMenuItems selectable-text-input-handle text-input-handle))))
|
||||||
:on-layout #(handler/layout % state blur-height)}
|
(utils/update-input props state input-text)
|
||||||
[sub-view/bar]
|
[:<>
|
||||||
[reply/view state]
|
[mentions/view props state animations max-height cursor-pos]
|
||||||
[edit/view edit #(utils/cancel-edit-message state animations)]
|
[gesture/gesture-detector
|
||||||
[reanimated/touchable-opacity
|
{:gesture (drag-gesture/drag-gesture props state animations dimensions keyboard-shown)}
|
||||||
{:active-opacity 1
|
[reanimated/view
|
||||||
:on-press (when @(:input-ref props) #(.focus ^js @(:input-ref props)))
|
{:style (style/sheet-container insets state animations)
|
||||||
:style (style/input-container (:height animations) max-height)
|
:on-layout #(handler/layout % state blur-height)}
|
||||||
:accessibility-label :message-input-container}
|
[sub-view/bar]
|
||||||
[rn/text-input
|
[reply/view state]
|
||||||
{:ref #(reset! (:input-ref props) %)
|
[edit/view edit #(utils/cancel-edit-message state animations)]
|
||||||
:default-value @(:text-value state)
|
[reanimated/touchable-opacity
|
||||||
:on-focus #(handler/focus props state animations dimensions)
|
{:active-opacity 1
|
||||||
:on-blur #(handler/blur state animations dimensions images reply)
|
:on-press (when @(:input-ref props) #(.focus ^js @(:input-ref props)))
|
||||||
:on-content-size-change #(handler/content-size-change %
|
:style (style/input-container (:height animations) max-height)
|
||||||
state
|
:accessibility-label :message-input-container}
|
||||||
animations
|
[rn/selectable-text-input {:ref #(reset! selectable-input-ref %)
|
||||||
dimensions
|
:menuItems @menu-items}
|
||||||
(or keyboard-shown edit))
|
[rn/text-input
|
||||||
:on-scroll #(handler/scroll % state animations dimensions)
|
{:ref #(reset! (:input-ref props) %)
|
||||||
:on-change-text #(handler/change-text % props state)
|
:default-value @(:text-value state)
|
||||||
:on-selection-change #(handler/selection-change % state)
|
:on-focus #(handler/focus props state animations dimensions)
|
||||||
:max-height max-height
|
:on-blur #(handler/blur state animations dimensions images reply)
|
||||||
:max-font-size-multiplier 1
|
:on-content-size-change #(handler/content-size-change %
|
||||||
:multiline true
|
state
|
||||||
:placeholder (i18n/label :t/type-something)
|
animations
|
||||||
:placeholder-text-color (colors/theme-colors colors/neutral-40 colors/neutral-50)
|
dimensions
|
||||||
:style (style/input props state)
|
(or keyboard-shown edit))
|
||||||
:accessibility-label :chat-message-input}]
|
:on-scroll #(handler/scroll % props state animations dimensions)
|
||||||
[gradients/view props state animations show-bottom-gradient?]]
|
:on-change-text #(handler/change-text % props state)
|
||||||
[images/images-list]
|
:on-selection-change #(handler/selection-change % state)
|
||||||
[actions/view props state animations window-height insets (seq images)]]]))]))])
|
:on-selection (fn [e] (println "onselection"))
|
||||||
|
:max-height max-height
|
||||||
|
:max-font-size-multiplier 1
|
||||||
|
:multiline true
|
||||||
|
:placeholder (i18n/label :t/type-something)
|
||||||
|
:placeholder-text-color (colors/theme-colors colors/neutral-40 colors/neutral-50)
|
||||||
|
:style (style/input props state)
|
||||||
|
:accessibility-label :chat-message-input}]]
|
||||||
|
[gradients/view props state animations show-bottom-gradient?]]
|
||||||
|
[images/images-list]
|
||||||
|
[actions/view props state animations window-height insets
|
||||||
|
(boolean (seq images))]]]]))]))])
|
||||||
|
|
||||||
(defn f-bottom-sheet-composer
|
(defn f-bottom-sheet-composer
|
||||||
[insets]
|
[insets]
|
||||||
|
|||||||
Reference in New Issue
Block a user