parent
e8b956d4f4
commit
2b701f9af0
|
@ -4,10 +4,8 @@
|
||||||
[quo2.foundations.colors :as colors]
|
[quo2.foundations.colors :as colors]
|
||||||
[react-native.core :as rn]
|
[react-native.core :as rn]
|
||||||
[react-native.gesture :as gesture]
|
[react-native.gesture :as gesture]
|
||||||
[react-native.navigation :as navigation]
|
|
||||||
[react-native.orientation :as orientation]
|
[react-native.orientation :as orientation]
|
||||||
[react-native.platform :as platform]
|
[react-native.platform :as platform]
|
||||||
[react-native.reanimated :as reanimated]
|
|
||||||
[react-native.safe-area :as safe-area]
|
[react-native.safe-area :as safe-area]
|
||||||
[reagent.core :as reagent]
|
[reagent.core :as reagent]
|
||||||
[status-im2.contexts.chat.lightbox.animations :as anim]
|
[status-im2.contexts.chat.lightbox.animations :as anim]
|
||||||
|
@ -83,27 +81,6 @@
|
||||||
(when (and enabled? (not= result orientation/landscape-right))
|
(when (and enabled? (not= result orientation/landscape-right))
|
||||||
(handle-orientation result props state animations))))))))
|
(handle-orientation result props state animations))))))))
|
||||||
|
|
||||||
(defn toggle-opacity
|
|
||||||
[index {:keys [opacity-value border-value transparent? props]} portrait?]
|
|
||||||
(let [{:keys [small-list-ref]} props
|
|
||||||
opacity (reanimated/get-shared-value opacity-value)]
|
|
||||||
(if (= opacity 1)
|
|
||||||
(do
|
|
||||||
(when platform/ios?
|
|
||||||
;; status-bar issue: https://github.com/status-im/status-mobile/issues/15343
|
|
||||||
(js/setTimeout #(navigation/merge-options "lightbox" {:statusBar {:visible false}}) 75))
|
|
||||||
(anim/animate opacity-value 0)
|
|
||||||
(js/setTimeout #(reset! transparent? (not @transparent?)) 400))
|
|
||||||
(do
|
|
||||||
(reset! transparent? (not @transparent?))
|
|
||||||
(js/setTimeout #(anim/animate opacity-value 1) 50)
|
|
||||||
(js/setTimeout #(when @small-list-ref
|
|
||||||
(.scrollToIndex ^js @small-list-ref #js {:animated false :index index}))
|
|
||||||
100)
|
|
||||||
(when (and platform/ios? portrait?)
|
|
||||||
(js/setTimeout #(navigation/merge-options "lightbox" {:statusBar {:visible true}}) 150))))
|
|
||||||
(anim/animate border-value (if (= opacity 1) 0 12))))
|
|
||||||
|
|
||||||
(defn drag-gesture
|
(defn drag-gesture
|
||||||
[{:keys [pan-x pan-y background-color opacity layout]} x? set-full-height?]
|
[{:keys [pan-x pan-y background-color opacity layout]} x? set-full-height?]
|
||||||
(->
|
(->
|
||||||
|
|
|
@ -38,8 +38,7 @@
|
||||||
[message index _ {:keys [screen-width screen-height] :as args}]
|
[message index _ {:keys [screen-width screen-height] :as args}]
|
||||||
[rn/view
|
[rn/view
|
||||||
{:style (style/image (+ screen-width constants/separator-width) screen-height)}
|
{:style (style/image (+ screen-width constants/separator-width) screen-height)}
|
||||||
[zoomable-image/zoomable-image message index args
|
[:f> zoomable-image/zoomable-image message index args]
|
||||||
#(utils/toggle-opacity index args %)]
|
|
||||||
[rn/view {:style {:width constants/separator-width}}]])
|
[rn/view {:style {:width constants/separator-width}}]])
|
||||||
|
|
||||||
(defn lightbox-content
|
(defn lightbox-content
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
(ns status-im2.contexts.chat.lightbox.zoomable-image.utils
|
(ns status-im2.contexts.chat.lightbox.zoomable-image.utils
|
||||||
(:require
|
(:require
|
||||||
[clojure.string :as string]
|
[clojure.string :as string]
|
||||||
|
[react-native.navigation :as navigation]
|
||||||
[react-native.orientation :as orientation]
|
[react-native.orientation :as orientation]
|
||||||
[react-native.platform :as platform]
|
[react-native.platform :as platform]
|
||||||
|
[react-native.reanimated :as reanimated]
|
||||||
|
[reagent.core :as reagent]
|
||||||
[status-im2.contexts.chat.lightbox.zoomable-image.constants :as c]
|
[status-im2.contexts.chat.lightbox.zoomable-image.constants :as c]
|
||||||
[status-im2.contexts.chat.lightbox.animations :as anim]
|
[status-im2.contexts.chat.lightbox.animations :as anim]
|
||||||
[utils.re-frame :as rf]))
|
[utils.re-frame :as rf]))
|
||||||
|
@ -36,9 +39,9 @@
|
||||||
exit?
|
exit?
|
||||||
{:keys [x-threshold-scale y-threshold-scale]}
|
{:keys [x-threshold-scale y-threshold-scale]}
|
||||||
{:keys [scale saved-scale] :as animations}
|
{:keys [scale saved-scale] :as animations}
|
||||||
{:keys [pan-x-enabled? pan-y-enabled?] :as props}]
|
{:keys [pan-x-enabled? pan-y-enabled?] :as state}]
|
||||||
(when (= value c/min-scale)
|
(when (= value c/min-scale)
|
||||||
(reset-values exit? animations props))
|
(reset-values exit? animations state))
|
||||||
(anim/animate scale value (if exit? 100 c/default-duration))
|
(anim/animate scale value (if exit? 100 c/default-duration))
|
||||||
(anim/set-val saved-scale value)
|
(anim/set-val saved-scale value)
|
||||||
(reset! pan-x-enabled? (> value x-threshold-scale))
|
(reset! pan-x-enabled? (> value x-threshold-scale))
|
||||||
|
@ -102,6 +105,27 @@
|
||||||
(when (and (= zoom-out-signal index) (> scale c/min-scale))
|
(when (and (= zoom-out-signal index) (> scale c/min-scale))
|
||||||
(rescale c/min-scale true)))
|
(rescale c/min-scale true)))
|
||||||
|
|
||||||
|
(defn toggle-opacity
|
||||||
|
[index {:keys [opacity-value border-value transparent? props]} portrait?]
|
||||||
|
(let [{:keys [small-list-ref]} props
|
||||||
|
opacity (reanimated/get-shared-value opacity-value)]
|
||||||
|
(if (= opacity 1)
|
||||||
|
(do
|
||||||
|
(when platform/ios?
|
||||||
|
;; status-bar issue: https://github.com/status-im/status-mobile/issues/15343
|
||||||
|
(js/setTimeout #(navigation/merge-options "lightbox" {:statusBar {:visible false}}) 75))
|
||||||
|
(anim/animate opacity-value 0)
|
||||||
|
(js/setTimeout #(reset! transparent? (not @transparent?)) 400))
|
||||||
|
(do
|
||||||
|
(reset! transparent? (not @transparent?))
|
||||||
|
(js/setTimeout #(anim/animate opacity-value 1) 50)
|
||||||
|
(js/setTimeout #(when @small-list-ref
|
||||||
|
(.scrollToIndex ^js @small-list-ref #js {:animated false :index index}))
|
||||||
|
100)
|
||||||
|
(when (and platform/ios? portrait?)
|
||||||
|
(js/setTimeout #(navigation/merge-options "lightbox" {:statusBar {:visible true}}) 150))))
|
||||||
|
(anim/animate border-value (if (= opacity 1) 0 12))))
|
||||||
|
|
||||||
;;; Dimensions
|
;;; Dimensions
|
||||||
(defn get-dimensions
|
(defn get-dimensions
|
||||||
"Calculates all required dimensions. Dimensions calculations are different on iOS and Android because landscape
|
"Calculates all required dimensions. Dimensions calculations are different on iOS and Android because landscape
|
||||||
|
@ -162,3 +186,28 @@
|
||||||
(if (or (> focal max) (< focal min))
|
(if (or (> focal max) (< focal min))
|
||||||
(/ screen-size 2)
|
(/ screen-size 2)
|
||||||
focal)))
|
focal)))
|
||||||
|
|
||||||
|
;;; INITIALIZATIONS
|
||||||
|
(defn init-animations
|
||||||
|
[]
|
||||||
|
{:scale (anim/use-val c/min-scale)
|
||||||
|
:saved-scale (anim/use-val c/min-scale)
|
||||||
|
:pan-x-start (anim/use-val c/init-offset)
|
||||||
|
:pan-x (anim/use-val c/init-offset)
|
||||||
|
:pan-y-start (anim/use-val c/init-offset)
|
||||||
|
:pan-y (anim/use-val c/init-offset)
|
||||||
|
:pinch-x-start (anim/use-val c/init-offset)
|
||||||
|
:pinch-x (anim/use-val c/init-offset)
|
||||||
|
:pinch-y-start (anim/use-val c/init-offset)
|
||||||
|
:pinch-y (anim/use-val c/init-offset)
|
||||||
|
:pinch-x-max (anim/use-val js/Infinity)
|
||||||
|
:pinch-y-max (anim/use-val js/Infinity)
|
||||||
|
:rotate (anim/use-val c/init-rotation)
|
||||||
|
:rotate-scale (anim/use-val c/min-scale)})
|
||||||
|
|
||||||
|
(defn init-state
|
||||||
|
[]
|
||||||
|
{:pan-x-enabled? (reagent/atom false)
|
||||||
|
:pan-y-enabled? (reagent/atom false)
|
||||||
|
:focal-x (reagent/atom nil)
|
||||||
|
:focal-y (reagent/atom nil)})
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
[react-native.gesture :as gesture]
|
[react-native.gesture :as gesture]
|
||||||
[react-native.platform :as platform]
|
[react-native.platform :as platform]
|
||||||
[react-native.reanimated :as reanimated]
|
[react-native.reanimated :as reanimated]
|
||||||
[reagent.core :as reagent]
|
|
||||||
[utils.re-frame :as rf]
|
[utils.re-frame :as rf]
|
||||||
[oops.core :refer [oget]]
|
[oops.core :refer [oget]]
|
||||||
[react-native.orientation :as orientation]
|
[react-native.orientation :as orientation]
|
||||||
|
@ -80,7 +79,7 @@
|
||||||
[{:keys [width height screen-height screen-width x-threshold-scale y-threshold-scale] :as dimensions}
|
[{:keys [width height screen-height screen-width x-threshold-scale y-threshold-scale] :as dimensions}
|
||||||
{:keys [saved-scale scale pinch-x pinch-y pinch-x-start pinch-y-start pinch-x-max pinch-y-max]
|
{:keys [saved-scale scale pinch-x pinch-y pinch-x-start pinch-y-start pinch-x-max pinch-y-max]
|
||||||
:as animations}
|
:as animations}
|
||||||
{:keys [focal-x focal-y] :as props}
|
{:keys [focal-x focal-y] :as state}
|
||||||
rescale
|
rescale
|
||||||
transparent?
|
transparent?
|
||||||
toggle-opacity]
|
toggle-opacity]
|
||||||
|
@ -135,7 +134,7 @@
|
||||||
(utils/center-x animations false))
|
(utils/center-x animations false))
|
||||||
(when (< (anim/get-val scale) y-threshold-scale)
|
(when (< (anim/get-val scale) y-threshold-scale)
|
||||||
(utils/center-y animations false))))
|
(utils/center-y animations false))))
|
||||||
(finalize-pinch dimensions animations props)))))
|
(finalize-pinch dimensions animations state)))))
|
||||||
|
|
||||||
(defn pan-x-gesture
|
(defn pan-x-gesture
|
||||||
[{:keys [width screen-width x-threshold-scale]}
|
[{:keys [width screen-width x-threshold-scale]}
|
||||||
|
@ -204,76 +203,61 @@
|
||||||
(anim/animate-decay pan-y velocity [lower-bound upper-bound])
|
(anim/animate-decay pan-y velocity [lower-bound upper-bound])
|
||||||
(anim/animate-decay pan-y-start velocity [lower-bound upper-bound]))))))))
|
(anim/animate-decay pan-y-start velocity [lower-bound upper-bound]))))))))
|
||||||
|
|
||||||
|
(defn- f-zoomable-image
|
||||||
|
[dimensions animations state rescale curr-orientation content focused? index render-data]
|
||||||
|
(let [{:keys [transparent? set-full-height?]} render-data
|
||||||
|
portrait? (= curr-orientation orientation/portrait)
|
||||||
|
on-tap #(utils/toggle-opacity index render-data portrait?)
|
||||||
|
tap (tap-gesture on-tap)
|
||||||
|
double-tap (double-tap-gesture dimensions animations rescale transparent? on-tap)
|
||||||
|
pinch (pinch-gesture dimensions animations state rescale transparent? on-tap)
|
||||||
|
pan-x (pan-x-gesture dimensions animations state rescale)
|
||||||
|
pan-y (pan-y-gesture dimensions animations state rescale)
|
||||||
|
composed-gestures (gesture/exclusive
|
||||||
|
(gesture/simultaneous pinch pan-x pan-y)
|
||||||
|
(gesture/exclusive double-tap tap))]
|
||||||
|
[gesture/gesture-detector {:gesture composed-gestures}
|
||||||
|
[reanimated/view
|
||||||
|
{:style (style/container dimensions
|
||||||
|
animations
|
||||||
|
@set-full-height?
|
||||||
|
(= curr-orientation orientation/portrait))}
|
||||||
|
[reanimated/fast-image
|
||||||
|
{:source {:uri (:image content)}
|
||||||
|
:native-ID (when focused? :shared-element)
|
||||||
|
:style (style/image dimensions animations (:border-value render-data))}]]]))
|
||||||
|
|
||||||
(defn zoomable-image
|
(defn zoomable-image
|
||||||
[{:keys [image-width image-height content message-id]} index args on-tap]
|
[{:keys [image-width image-height content message-id]} index render-data]
|
||||||
[:f>
|
(let [state (utils/init-state)
|
||||||
(fn []
|
shared-element-id (rf/sub [:shared-element-id])
|
||||||
(let [{:keys [transparent? set-full-height?]} args
|
exit-lightbox-signal (rf/sub [:lightbox/exit-signal])
|
||||||
shared-element-id (rf/sub [:shared-element-id])
|
zoom-out-signal (rf/sub [:lightbox/zoom-out-signal])
|
||||||
exit-lightbox-signal (rf/sub [:lightbox/exit-signal])
|
curr-orientation (or (rf/sub [:lightbox/orientation])
|
||||||
zoom-out-signal (rf/sub [:lightbox/zoom-out-signal])
|
orientation/portrait)
|
||||||
focused? (= shared-element-id message-id)
|
{:keys [set-full-height?]} render-data
|
||||||
curr-orientation (or (rf/sub [:lightbox/orientation])
|
focused? (= shared-element-id message-id)
|
||||||
orientation/portrait)
|
dimensions (utils/get-dimensions
|
||||||
portrait? (= curr-orientation orientation/portrait)
|
(or image-width c/default-dimension)
|
||||||
dimensions (utils/get-dimensions
|
(or image-height c/default-duration)
|
||||||
(or image-width c/default-dimension)
|
curr-orientation
|
||||||
(or image-height c/default-duration)
|
render-data)
|
||||||
curr-orientation
|
animations (utils/init-animations)
|
||||||
args)
|
rescale (fn [value exit?]
|
||||||
animations {:scale (anim/use-val c/min-scale)
|
(utils/rescale-image value
|
||||||
:saved-scale (anim/use-val c/min-scale)
|
exit?
|
||||||
:pan-x-start (anim/use-val c/init-offset)
|
dimensions
|
||||||
:pan-x (anim/use-val c/init-offset)
|
animations
|
||||||
:pan-y-start (anim/use-val c/init-offset)
|
state))]
|
||||||
:pan-y (anim/use-val c/init-offset)
|
(rn/use-effect (fn []
|
||||||
:pinch-x-start (anim/use-val c/init-offset)
|
(js/setTimeout #(reset! set-full-height? true) 500)))
|
||||||
:pinch-x (anim/use-val c/init-offset)
|
(when platform/ios?
|
||||||
:pinch-y-start (anim/use-val c/init-offset)
|
(utils/handle-orientation-change curr-orientation focused? dimensions animations state)
|
||||||
:pinch-y (anim/use-val c/init-offset)
|
(utils/handle-exit-lightbox-signal exit-lightbox-signal
|
||||||
:pinch-x-max (anim/use-val js/Infinity)
|
index
|
||||||
:pinch-y-max (anim/use-val js/Infinity)
|
(anim/get-val (:scale animations))
|
||||||
:rotate (anim/use-val c/init-rotation)
|
rescale
|
||||||
:rotate-scale (anim/use-val c/min-scale)}
|
set-full-height?))
|
||||||
props {:pan-x-enabled? (reagent/atom false)
|
(utils/handle-zoom-out-signal zoom-out-signal index (anim/get-val (:scale animations)) rescale)
|
||||||
:pan-y-enabled? (reagent/atom false)
|
[:f> f-zoomable-image dimensions animations state rescale curr-orientation content focused?
|
||||||
:focal-x (reagent/atom nil)
|
index render-data]))
|
||||||
:focal-y (reagent/atom nil)}
|
|
||||||
rescale (fn [value exit?]
|
|
||||||
(utils/rescale-image value
|
|
||||||
exit?
|
|
||||||
dimensions
|
|
||||||
animations
|
|
||||||
props))]
|
|
||||||
(rn/use-effect (fn []
|
|
||||||
(js/setTimeout #(reset! set-full-height? true) 500)))
|
|
||||||
(when platform/ios?
|
|
||||||
(utils/handle-orientation-change curr-orientation focused? dimensions animations props)
|
|
||||||
(utils/handle-exit-lightbox-signal exit-lightbox-signal
|
|
||||||
index
|
|
||||||
(anim/get-val (:scale animations))
|
|
||||||
rescale
|
|
||||||
set-full-height?))
|
|
||||||
(utils/handle-zoom-out-signal zoom-out-signal index (anim/get-val (:scale animations)) rescale)
|
|
||||||
[:f>
|
|
||||||
(fn []
|
|
||||||
(let [tap (tap-gesture #(on-tap portrait?))
|
|
||||||
double-tap
|
|
||||||
(double-tap-gesture dimensions animations rescale transparent? #(on-tap portrait?))
|
|
||||||
pinch
|
|
||||||
(pinch-gesture dimensions animations props rescale transparent? #(on-tap portrait?))
|
|
||||||
pan-x (pan-x-gesture dimensions animations props rescale)
|
|
||||||
pan-y (pan-y-gesture dimensions animations props rescale)
|
|
||||||
composed-gestures (gesture/exclusive
|
|
||||||
(gesture/simultaneous pinch pan-x pan-y)
|
|
||||||
(gesture/exclusive double-tap tap))]
|
|
||||||
[gesture/gesture-detector {:gesture composed-gestures}
|
|
||||||
[reanimated/view
|
|
||||||
{:style (style/container dimensions
|
|
||||||
animations
|
|
||||||
@set-full-height?
|
|
||||||
(= curr-orientation orientation/portrait))}
|
|
||||||
[reanimated/fast-image
|
|
||||||
{:source {:uri (:image content)}
|
|
||||||
:native-ID (when focused? :shared-element)
|
|
||||||
:style (style/image dimensions animations (:border-value args))}]]]))]))])
|
|
||||||
|
|
Loading…
Reference in New Issue