This commit is contained in:
Omar Basem
2023-04-12 23:07:18 +04:00
parent a446eca14d
commit c19f425cb3
2 changed files with 130 additions and 120 deletions
@@ -20,13 +20,15 @@
:bottom 0
:left 0
:right 0
:background-color (colors/theme-colors colors/white colors/neutral-90)
;:background-color (colors/theme-colors colors/white colors/neutral-90)
;:background-color (colors/theme-colors colors/white colors/neutral-90)
:background-color "rgba(255,255,255,1)"
;:background-color "rgba(255,255,255,1)"
;:background-color :black
:opacity (if (or focused? has-text?) 1 (if platform/ios? 0.7 0.5))
:z-index 3
:padding-bottom (:bottom insets)}
:padding-bottom (:bottom insets)
;:padding-bottom 0
}
(if platform/ios?
{:shadow-radius 20
:shadow-opacity 0.1
@@ -54,7 +56,7 @@
:background-color (colors/theme-colors colors/neutral-100-opa-5 colors/white-opa-10)})
(defn input
[focused? expanded?]
[focused? expanded? saved-keyboard-height]
(merge typography/paragraph-1
{:min-height (if platform/ios? 32 44)
:text-align-vertical :top
@@ -62,11 +64,11 @@
;:position (if (and platform/android? (or (<= (reanimated/get-shared-value value) input-height) animating)) :absolute :relative)
;:position (if platform/android? :absolute :relative)
:position :absolute
:position (if saved-keyboard-height :relative :absolute)
:top 0
:left 0
:right (when (or (not focused?) expanded? platform/ios?) 0) ; to inc gesture detection area on Android
;:right 0 ; to inc gesture detection area on Android
;:overflow :hidden
;:padding-vertical 10
;:min-height input-height
@@ -21,7 +21,7 @@
[status-im2.contexts.chat.messages.composer-new.style :as style]
[utils.re-frame :as rf]))
(def ^:const drag-threshold 80)
(def ^:const drag-threshold 30)
(def input-height (if platform/ios? 32 44))
@@ -50,36 +50,38 @@
:i/image])
(defn drag-gesture
[height saved-height opacity bg-bottom window-height keyboard-shown max-height input-ref lines add-keyboard-height emojis-open]
[height saved-height opacity bg-bottom window-height keyboard-shown max-height input-ref lines add-keyboard-height saved-keyboard-height emojis-open]
(let [expanding? (atom true)]
(->
(gesture/gesture-pan)
(gesture/on-start (fn [e] (reanimated/set-shared-value bg-bottom 0)
(reset! expanding? (neg? (oops/oget e "velocityY")))))
(gesture/on-update (fn [e]
(let [translation (oops/oget e "translationY")
new-height (Math/max input-height (Math/min (+ (- (/ translation 1)) (reanimated/get-shared-value saved-height)) max-height))
remaining-height (if @expanding? (- max-height (reanimated/get-shared-value saved-height)) (reanimated/get-shared-value saved-height))
progress (/ translation remaining-height)
progress (if (= new-height input-height) 1 progress)]
(let [translation (oops/oget e "translationY")
new-height (Math/max input-height (Math/min (+ (- (/ translation 1)) (reanimated/get-shared-value saved-height)) max-height))
remaining-height (if @expanding? (- max-height (reanimated/get-shared-value saved-height)) (reanimated/get-shared-value saved-height))
progress (/ translation remaining-height)
progress (if (= new-height input-height) 1 progress)
currently-expanding? (neg? (oops/oget e "velocityY"))
maximum-opacity? (and currently-expanding? (= (reanimated/get-shared-value opacity) 1))]
(if keyboard-shown
(do
(if (>= translation 0)
(do
(reanimated/set-shared-value height new-height)
(when (and (pos? progress) (not= (reanimated/get-shared-value opacity) 0))
(reanimated/set-shared-value opacity (- 1 progress))))
(do
(reanimated/set-shared-value height new-height)
(when @expanding?
(reanimated/set-shared-value opacity (Math/abs progress))))))
(do
(.focus ^js @input-ref))))))
(if (>= translation 0)
(do
(reanimated/set-shared-value height new-height)
(when (and (pos? progress) (not= (reanimated/get-shared-value opacity) 0))
(reanimated/set-shared-value opacity (- 1 progress))))
(do
(reanimated/set-shared-value height new-height)
(when (and @expanding? (not maximum-opacity?))
(reanimated/set-shared-value opacity (Math/abs progress)))))
(.focus ^js @input-ref)))))
(gesture/on-end (fn [e]
(let [diff (- (reanimated/get-shared-value height) (reanimated/get-shared-value saved-height))
collapsing? (pos? (oops/oget e "velocityY"))]
(let [collapsing? (pos? (oops/oget e "velocityY"))
diff (- (reanimated/get-shared-value height) (reanimated/get-shared-value saved-height))
remaining (if (not collapsing?) (- max-height (reanimated/get-shared-value height)) (reanimated/get-shared-value height))
threshold (if (> remaining drag-threshold) drag-threshold 10)]
(if (>= diff 0)
(if (> diff drag-threshold)
(if (and (> diff threshold) (not collapsing?))
(do
(reanimated/animate height max-height)
(reanimated/set-shared-value saved-height max-height)
@@ -90,7 +92,7 @@
(when (or (and collapsing? (not= (reanimated/get-shared-value saved-height) max-height)) (= (reanimated/get-shared-value saved-height) input-height))
(reanimated/animate opacity 0)
(reanimated/animate-delay bg-bottom (- window-height) 300))))
(if (and (> diff (- drag-threshold)) (not collapsing?))
(if (or (< (Math/abs diff) threshold) (and (not collapsing?) (> (Math/abs diff) threshold)))
(do
(reanimated/animate height max-height)
(reanimated/set-shared-value saved-height max-height)
@@ -99,9 +101,8 @@
(let [target-height (if (> lines 1) (+ input-height 18) input-height)]
(when @add-keyboard-height
(reanimated/set-shared-value height (+ (reanimated/get-shared-value height) @add-keyboard-height))
(reanimated/set-shared-value saved-height (+ (reanimated/get-shared-value saved-height) @add-keyboard-height))
(reset! emojis-open false)
(reset! saved-keyboard-height @add-keyboard-height)
(reset! add-keyboard-height nil))
(.blur ^js @input-ref)
@@ -156,6 +157,7 @@
lock-layout? (reagent/atom false)
keyboard-show-listener (reagent/atom nil)
add-keyboard-height (atom nil)
saved-keyboard-height (atom nil)
margin-top (if platform/ios? (:top insets) (+ (:top insets) 10))
emojis-open (reagent/atom false)]
(rn/use-effect
@@ -178,7 +180,8 @@
(reanimated/set-shared-value height (+ (reanimated/get-shared-value height) @add-keyboard-height))
(reanimated/set-shared-value saved-height (+ (reanimated/get-shared-value saved-height) @add-keyboard-height))
(reset! emojis-open false)
(reset! add-keyboard-height nil)))))))
(reset! add-keyboard-height nil)))
))))
(fn [] (.remove ^js @keyboard-show-listener))))
[:f>
(fn []
@@ -191,94 +194,98 @@
expanded? (= (reanimated/get-shared-value height) max-height)]
[:<>
[reanimated/view {:style (style/background opacity bg-bottom window-height height)}]
[gesture/gesture-detector {:gesture (drag-gesture height saved-height opacity bg-bottom window-height keyboard-shown max-height input-ref lines add-keyboard-height emojis-open)}
[rn/keyboard-avoiding-view {:style (style/container insets @focused? (not-empty @text-value))
:behavior (if platform/ios? "padding" nil)
:keyboard-vertical-offset ios-extra-offset
:on-layout (fn [e]
(when-not @lock-layout?
(reanimated/set-shared-value layout-height (oops/oget e "nativeEvent.layout.height"))))}
[rn/view {:style {:padding-bottom (:bottom insets)
:z-index 2}}
[handle]
[reanimated/view {:style (style/input-container height max-height @emojis-open)}
[reanimated/linear-gradient
{:colors ["rgba(255,255,255,0)" "rgba(255,255,255,1)"]
:start {:x 0 :y 1}
:end {:x 0 :y 0}
:style (style/text-top-overlay overlay-opacity @overlay-z-index)}]
[rn/text-input
{:ref #(reset! input-ref %)
:default-value @text-value
:on-change-text (fn [text]
(reset! text-value text)
(js/setTimeout #(.setNativeProps ^js @input-ref (clj->js {:selection (clj->js @cursor-position)})) 20)
(rf/dispatch [:chat.ui/set-chat-input-text text]))
:on-selection-change (fn [e]
(when-not @lock-selection
(reset! cursor-position {:start (oops/oget e "nativeEvent.selection.end") :end (oops/oget e "nativeEvent.selection.end")})))
:on-focus (fn []
(reset! focused? true)
(reset! lock-layout? true)
(js/setTimeout #(reset! lock-selection false) 300)
(when (not-empty @text-value)
(.setNativeProps ^js @input-ref (clj->js {:selection @saved-cursor-position})))
(reanimated/animate height (reanimated/get-shared-value last-height))
(reanimated/set-shared-value saved-height (reanimated/get-shared-value last-height))
(when (> (reanimated/get-shared-value last-height) (* 0.75 max-height))
(reanimated/animate opacity 1)
(reanimated/set-shared-value bg-bottom 0))
(reanimated/set-shared-value blur-opacity 0))
:on-blur (fn []
(let [target-height (if (> lines 1) (+ input-height 18) input-height)]
(reset! saved-cursor-position @cursor-position)
(reanimated/set-shared-value last-height (if (empty? @text-value) target-height (Math/min (+ @content-height (if platform/ios? 5 0))
(reanimated/get-shared-value saved-height))))
(reanimated/set-shared-value blur-opacity 1)
(reanimated/animate height target-height)
(reanimated/set-shared-value saved-height target-height)
(reset! focused? false)
(reset! lock-selection true)
(js/setTimeout #(reset! lock-layout? false) 500)
(reanimated/animate overlay-opacity 0)
(reset! overlay-z-index 0)))
:style (style/input @focused? expanded?)
:on-scroll (fn [e] (let [y (oops/oget e "nativeEvent.contentOffset.y")]
(when (and (> y line-height) (>= lines max-lines) (= @overlay-z-index 0) @focused?)
(reset! overlay-z-index 1)
(js/setTimeout #(reanimated/animate overlay-opacity 1) 0))
(when (and (<= y line-height) (= @overlay-z-index 1))
(reanimated/animate overlay-opacity 0)
(js/setTimeout #(reset! overlay-z-index 0) 300))))
:on-content-size-change (fn [e]
(when @focused?
(let [extra-offset (if platform/ios? (if @emojis-open ios-extra-offset 5) 0)
x (+ (oops/oget e "nativeEvent.contentSize.height") extra-offset)
diff (Math/abs (- x (reanimated/get-shared-value height)))]
(reset! content-height (oops/oget e "nativeEvent.contentSize.height"))
(when (and (> diff 10) (not-empty @text-value) (<= x (+ max-height line-height)) (not= (reanimated/get-shared-value height) max-height))
(reanimated/animate height (Math/min x max-height))
(reanimated/set-shared-value saved-height (Math/min x max-height)))
(if (> (reanimated/get-shared-value saved-height) (* 0.75 max-height))
(do
(reanimated/set-shared-value bg-bottom 0)
(reanimated/animate opacity 1))
(do
(reanimated/animate opacity 0)
(reanimated/animate-delay bg-bottom (- window-height) 300))))))
:max-height max-height
:multiline true
:placeholder-text-color (colors/theme-colors colors/neutral-40 colors/neutral-60)
:placeholder (i18n/label :t/type-something)}]
(when (and (not-empty @text-value) (not @focused?) (> lines 1))
[rn/touchable-without-feedback
{:on-press #(.focus ^js @input-ref)}
[linear-gradient/linear-gradient
{:colors ["rgba(255,255,255,1)" "rgba(255,255,255,0)"]
:start {:x 0 :y 1}
:end {:x 0 :y 0}
:style (style/text-overlay)}]])]
[actions input-ref text-value]]]]]))]))])
[gesture/gesture-detector {:gesture (drag-gesture height saved-height opacity bg-bottom window-height keyboard-shown max-height input-ref lines add-keyboard-height saved-keyboard-height emojis-open)}
[rn/view {:style (style/container insets @focused? (not-empty @text-value))
:on-layout (fn [e]
(when-not @lock-layout?
(reanimated/set-shared-value layout-height (oops/oget e "nativeEvent.layout.height"))))}
[handle]
[reanimated/view {:style (style/input-container height max-height @emojis-open)}
[reanimated/linear-gradient
{:colors ["rgba(255,255,255,0)" "rgba(255,255,255,1)"]
:start {:x 0 :y 1}
:end {:x 0 :y 0}
:style (style/text-top-overlay overlay-opacity @overlay-z-index)}]
[rn/text-input
{:ref #(reset! input-ref %)
:default-value @text-value
:on-change-text (fn [text]
(reset! text-value text)
(js/setTimeout #(.setNativeProps ^js @input-ref (clj->js {:selection (clj->js @cursor-position)})) 20)
(rf/dispatch [:chat.ui/set-chat-input-text text]))
:on-selection-change (fn [e]
(when-not @lock-selection
(reset! cursor-position {:start (oops/oget e "nativeEvent.selection.end") :end (oops/oget e "nativeEvent.selection.end")})))
:on-focus (fn []
(reset! focused? true)
(reset! lock-layout? true)
(js/setTimeout #(reset! lock-selection false) 300)
(when (not-empty @text-value)
(.setNativeProps ^js @input-ref (clj->js {:selection @saved-cursor-position})))
(reanimated/animate height (reanimated/get-shared-value last-height))
(reanimated/set-shared-value saved-height (reanimated/get-shared-value last-height))
(when @saved-keyboard-height
(js/setTimeout (fn []
(when (> lines max-lines)
(reanimated/animate height (+ (reanimated/get-shared-value last-height) @saved-keyboard-height))
(reanimated/set-shared-value saved-height (+ (reanimated/get-shared-value last-height) @saved-keyboard-height)))
(reset! saved-keyboard-height nil)) 600))
(when (> (reanimated/get-shared-value last-height) (* 0.75 max-height))
(reanimated/animate opacity 1)
(reanimated/set-shared-value bg-bottom 0))
(reanimated/set-shared-value blur-opacity 0))
:on-blur (fn []
(let [target-height (if (> lines 1) (+ input-height 18) input-height)]
(reset! saved-cursor-position @cursor-position)
(reanimated/set-shared-value last-height (if (empty? @text-value) target-height (Math/min (+ @content-height (if platform/ios? 5 0))
(reanimated/get-shared-value saved-height))))
(reanimated/set-shared-value blur-opacity 1)
(reanimated/animate height target-height)
(reanimated/set-shared-value saved-height target-height)
(reset! focused? false)
(reset! lock-selection true)
(js/setTimeout #(reset! lock-layout? false) 500)
(reanimated/animate overlay-opacity 0)
(reset! overlay-z-index 0)))
:style (style/input @focused? expanded? @saved-keyboard-height)
:on-scroll (fn [e] (let [y (oops/oget e "nativeEvent.contentOffset.y")]
(when (and (> y line-height) (>= lines max-lines) (= @overlay-z-index 0) @focused?)
(reset! overlay-z-index 1)
(js/setTimeout #(reanimated/animate overlay-opacity 1) 0))
(when (and (<= y line-height) (= @overlay-z-index 1))
(reanimated/animate overlay-opacity 0)
(js/setTimeout #(reset! overlay-z-index 0) 300))))
:on-content-size-change (fn [e]
;(when @focused?
(let [extra-offset (if platform/ios? (if @emojis-open ios-extra-offset 5) 0)
x (+ (oops/oget e "nativeEvent.contentSize.height") extra-offset)
diff (Math/abs (- x (reanimated/get-shared-value height)))]
(reset! content-height (oops/oget e "nativeEvent.contentSize.height"))
(when (and (> diff 10) (not-empty @text-value) (<= x (+ max-height line-height)) (not= (reanimated/get-shared-value height) max-height))
(reanimated/animate height (Math/min x max-height))
(reanimated/set-shared-value saved-height (Math/min x max-height)))
(if (> (reanimated/get-shared-value saved-height) (* 0.75 max-height))
(do
(reanimated/set-shared-value bg-bottom 0)
(reanimated/animate opacity 1))
(do
(reanimated/animate opacity 0)
(reanimated/animate-delay bg-bottom (- window-height) 300))))
;)
)
:max-height max-height
:multiline true
:placeholder-text-color (colors/theme-colors colors/neutral-40 colors/neutral-60)
:placeholder (i18n/label :t/type-something)}]
(when (and (not-empty @text-value) (not @focused?) (> lines 1))
[rn/touchable-without-feedback
{:on-press #(.focus ^js @input-ref)}
[linear-gradient/linear-gradient
{:colors ["rgba(255,255,255,1)" "rgba(255,255,255,0)"]
:start {:x 0 :y 1}
:end {:x 0 :y 0}
:style (style/text-overlay)}]])]
[actions input-ref text-value]]]]))]))])
(defn blur-view [insets blur-opacity layout-height]
@@ -301,3 +308,4 @@
[rn/view
[blur-view insets blur-opacity layout-height]
[sheet insets blur-opacity layout-height]]))])