refactor: lightbox screen (#15996)

* refactor: lightbox screen
This commit is contained in:
Omar Basem 2023-05-24 22:32:31 +04:00 committed by GitHub
parent 24eaec80bd
commit 0cc631ce2e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 360 additions and 318 deletions

View File

@ -130,6 +130,7 @@
;;Solid ;;Solid
(def black "#000000") (def black "#000000")
(def black-opa-0 (alpha black 0))
(def onboarding-header-black "#000716") (def onboarding-header-black "#000716")
;;;;Primary ;;;;Primary

View File

@ -15,60 +15,59 @@
:offset (* (+ c/small-image-size 8) index) :offset (* (+ c/small-image-size 8) index)
:index index}) :index index})
(defn- f-small-image
[item index _ {:keys [scroll-index props]}]
(let [size (if (= @scroll-index index) c/focused-image-size c/small-image-size)
size-value (anim/use-val size)
{:keys [scroll-index-lock? small-list-ref flat-list-ref]}
props]
(anim/animate size-value size)
[rn/touchable-opacity
{:active-opacity 1
:on-press (fn []
(rf/dispatch [:chat.ui/zoom-out-signal @scroll-index])
(reset! scroll-index-lock? true)
(js/setTimeout #(reset! scroll-index-lock? false) 500)
(js/setTimeout
(fn []
(reset! scroll-index index)
(.scrollToIndex ^js @small-list-ref
#js {:animated true :index index})
(.scrollToIndex ^js @flat-list-ref
#js {:animated true :index index}))
(if platform/ios? 50 150))
(rf/dispatch [:chat.ui/update-shared-element-id (:message-id item)]))}
[reanimated/fast-image
{:source {:uri (:image (:content item))}
:style (reanimated/apply-animations-to-style {:width size-value
:height size-value}
{:border-radius 10})}]]))
(defn small-image (defn small-image
[item index _ {:keys [scroll-index atoms]}] [item index _ render-data]
[:f> [:f> f-small-image item index _ render-data])
(fn []
(let [size (if (= @scroll-index index) c/focused-image-size c/small-image-size)
size-value (anim/use-val size)
{:keys [scroll-index-lock? small-list-ref
flat-list-ref]} atoms]
(anim/animate size-value size)
[rn/touchable-opacity
{:active-opacity 1
:on-press (fn []
(rf/dispatch [:chat.ui/zoom-out-signal @scroll-index])
(reset! scroll-index-lock? true)
(js/setTimeout #(reset! scroll-index-lock? false) 500)
(js/setTimeout
(fn []
(reset! scroll-index index)
(.scrollToIndex ^js @small-list-ref
#js {:animated true :index index})
(.scrollToIndex ^js @flat-list-ref
#js {:animated true :index index}))
(if platform/ios? 50 150))
(rf/dispatch [:chat.ui/update-shared-element-id (:message-id item)]))}
[reanimated/fast-image
{:source {:uri (:image (:content item))}
:style (reanimated/apply-animations-to-style {:width size-value
:height size-value}
{:border-radius 10})}]]))])
(defn bottom-view (defn bottom-view
[messages index scroll-index insets animations derived item-width atoms] [messages index scroll-index insets animations derived item-width props]
[:f> (let [text (get-in (first messages) [:content :text])
(fn [] padding-horizontal (- (/ item-width 2) (/ c/focused-image-size 2))]
(let [text (get-in (first messages) [:content :text]) [reanimated/linear-gradient
padding-horizontal (- (/ item-width 2) (/ c/focused-image-size 2))] {:colors [:black :transparent]
[reanimated/linear-gradient :start {:x 0 :y 1}
{:colors [:black :transparent] :end {:x 0 :y 0}
:start {:x 0 :y 1} :style (style/gradient-container insets animations derived)}
:end {:x 0 :y 0} [rn/text {:style style/text-style} text]
:style (style/gradient-container insets animations derived)} [rn/flat-list
[rn/text {:style style/text-style} text] {:ref #(reset! (:small-list-ref props) %)
[rn/flat-list :key-fn :message-id
{:ref #(reset! (:small-list-ref atoms) %) :style {:height c/small-list-height}
:key-fn :message-id :data messages
:style {:height c/small-list-height} :render-fn small-image
:data messages :render-data {:scroll-index scroll-index
:render-fn small-image :props props}
:render-data {:scroll-index scroll-index :horizontal true
:atoms atoms} :shows-horizontal-scroll-indicator false
:horizontal true :get-item-layout get-small-item-layout
:shows-horizontal-scroll-indicator false :separator [rn/view {:style {:width 8}}]
:get-item-layout get-small-item-layout :initial-scroll-index index
:separator [rn/view {:style {:width 8}}] :content-container-style (style/content-container padding-horizontal)}]]))
:initial-scroll-index index
:content-container-style (style/content-container padding-horizontal)}]]))])

View File

@ -11,3 +11,7 @@
(def ^:const small-list-padding-vertical 12) (def ^:const small-list-padding-vertical 12)
(def ^:const top-view-height 56) (def ^:const top-view-height 56)
(def ^:const separator-width 16)
(def ^:const drag-threshold 100)

View File

@ -67,9 +67,7 @@
:opacity opacity} :opacity opacity}
{:position :absolute {:position :absolute
:bottom 0 :bottom 0
:padding-bottom (if platform/ios? :padding-bottom (:bottom insets)
(:bottom insets)
(+ (:bottom insets) c/small-list-padding-vertical c/focused-extra-size))
:z-index 3})) :z-index 3}))
(defn content-container (defn content-container

View File

@ -41,49 +41,47 @@
(defn top-view (defn top-view
[{:keys [from timestamp]} insets index animations derived landscape? screen-width] [{:keys [from timestamp]} insets index animations derived landscape? screen-width]
[:f> (let [display-name (first (rf/sub [:contacts/contact-two-names-by-identity
(fn [] from]))
(let [display-name (first (rf/sub [:contacts/contact-two-names-by-identity bg-color (if landscape?
from])) colors/neutral-100-opa-70
bg-color (if landscape? colors/neutral-100-opa-0)
colors/neutral-100-opa-70 {:keys [background-color opacity]} animations]
colors/neutral-100-opa-0) [reanimated/view
{:keys [background-color opacity]} animations] {:style
[reanimated/view (style/top-view-container (:top insets) screen-width bg-color landscape? animations derived)}
{:style [reanimated/linear-gradient
(style/top-view-container (:top insets) screen-width bg-color landscape? animations derived)} {:colors [(colors/alpha "#000000" 0.8) :transparent]
[reanimated/linear-gradient :start {:x 0 :y 0}
{:colors [(colors/alpha "#000000" 0.8) :transparent] :end {:x 0 :y 1}
:start {:x 0 :y 0} :style (style/top-gradient insets)}]
:end {:x 0 :y 1} [rn/view
:style (style/top-gradient insets)}] {:style {:flex-direction :row
[rn/view :align-items :center}}
{:style {:flex-direction :row [rn/touchable-opacity
:align-items :center}} {:on-press (fn []
[rn/touchable-opacity (anim/animate background-color :transparent)
{:on-press (fn [] (anim/animate opacity 0)
(anim/animate background-color :transparent) (rf/dispatch (if platform/ios?
(anim/animate opacity 0) [:chat.ui/exit-lightbox-signal @index]
(rf/dispatch (if platform/ios? [:navigate-back])))
[:chat.ui/exit-lightbox-signal @index] :style style/close-container}
[:navigate-back]))) [quo/icon :close {:size 20 :color colors/white}]]
:style style/close-container} [rn/view {:style {:margin-left 12}}
[quo/icon :close {:size 20 :color colors/white}]] [quo/text
[rn/view {:style {:margin-left 12}} {:weight :semi-bold
[quo/text :size :paragraph-1
{:weight :semi-bold :style {:color colors/white}} display-name]
:size :paragraph-1 [quo/text
:style {:color colors/white}} display-name] {:weight :medium
[quo/text :size :paragraph-2
{:weight :medium :style {:color colors/neutral-40}} (datetime/to-short-str timestamp)]]]
:size :paragraph-2 [rn/view {:style style/top-right-buttons}
:style {:color colors/neutral-40}} (datetime/to-short-str timestamp)]]] [rn/touchable-opacity
[rn/view {:style style/top-right-buttons} {:active-opacity 1
[rn/touchable-opacity :style (merge style/close-container {:margin-right 12})}
{:active-opacity 1 [quo/icon :share {:size 20 :color colors/white}]]
:style (merge style/close-container {:margin-right 12})} [rn/touchable-opacity
[quo/icon :share {:size 20 :color colors/white}]] {:active-opacity 1
[rn/touchable-opacity :style style/close-container}
{:active-opacity 1 [quo/icon :options {:size 20 :color colors/white}]]]]))
:style style/close-container}
[quo/icon :options {:size 20 :color colors/white}]]]]))])

View File

@ -0,0 +1,166 @@
(ns status-im2.contexts.chat.lightbox.utils
(:require
[clojure.string :as string]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
[react-native.gesture :as gesture]
[react-native.navigation :as navigation]
[react-native.orientation :as orientation]
[react-native.platform :as platform]
[react-native.reanimated :as reanimated]
[react-native.safe-area :as safe-area]
[reagent.core :as reagent]
[status-im2.contexts.chat.lightbox.animations :as anim]
[status-im2.contexts.chat.lightbox.top-view :as top-view]
[utils.re-frame :as rf]
[oops.core :refer [oget]]
[status-im2.contexts.chat.lightbox.constants :as constants]
[utils.worklets.lightbox :as worklet]))
(defn effect
[{:keys [flat-list-ref scroll-index-lock?]} {:keys [opacity layout border]} index]
(rn/use-effect (fn []
(reagent/next-tick (fn []
(when @flat-list-ref
(.scrollToIndex ^js @flat-list-ref
#js {:animated false :index index}))))
(js/setTimeout (fn []
(anim/animate opacity 1)
(anim/animate layout 0)
(anim/animate border 12))
(if platform/ios? 250 100))
(js/setTimeout #(reset! scroll-index-lock? false) 300)
(fn []
(rf/dispatch [:chat.ui/zoom-out-signal nil])
(when platform/android?
(rf/dispatch [:chat.ui/lightbox-scale 1]))))))
(defn handle-orientation
[result {:keys [flat-list-ref]} {:keys [scroll-index]} animations]
(let [insets (safe-area/get-insets)
window (rn/get-window)
window-width (:width window)
window-height (:height window)
window-height (if platform/android?
(+ window-height (:top insets))
window-height)
screen-width (if (or platform/ios? (= result orientation/portrait))
window-width
window-height)
screen-height (if (or platform/ios? (= result orientation/portrait))
window-height
window-width)
landscape? (string/includes? result orientation/landscape)
item-width (if (and landscape? platform/ios?) screen-height screen-width)]
(when (or landscape? (= result orientation/portrait))
(rf/dispatch [:chat.ui/orientation-change result]))
(cond
landscape?
(orientation/lock-to-landscape "lightbox")
(= result orientation/portrait)
(orientation/lock-to-portrait "lightbox"))
(js/setTimeout
(fn []
(when @flat-list-ref
(.scrollToOffset
^js @flat-list-ref
#js {:animated false :offset (* (+ item-width constants/separator-width) @scroll-index)})))
100)
(when platform/ios?
(top-view/animate-rotation result screen-width screen-height insets animations))))
(defn orientation-change
[props state animations]
(orientation/use-device-orientation-change
(fn [result]
(if platform/ios?
(handle-orientation result props state animations)
;; `use-device-orientation-change` will always be called on Android, so need to check
(orientation/get-auto-rotate-state
(fn [enabled?]
;; RNN does not support landscape-right
(when (and enabled? (not= result orientation/landscape-right))
(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
[{:keys [pan-x pan-y background-color opacity layout]} x? set-full-height?]
(->
(gesture/gesture-pan)
(gesture/enabled true)
(gesture/max-pointers 1)
(gesture/on-start #(reset! set-full-height? false))
(gesture/on-update (fn [e]
(let [translation (if x? (oget e "translationX") (oget e "translationY"))
progress (Math/abs (/ translation constants/drag-threshold))]
(anim/set-val (if x? pan-x pan-y) translation)
(anim/set-val opacity (- 1 progress))
(anim/set-val layout (* progress -20)))))
(gesture/on-end (fn [e]
(if (> (Math/abs (if x? (oget e "translationX") (oget e "translationY")))
constants/drag-threshold)
(do
(anim/animate background-color "rgba(0,0,0,0)")
(anim/animate opacity 0)
(rf/dispatch [:navigate-back]))
(do
#(reset! set-full-height? true)
(anim/animate (if x? pan-x pan-y) 0)
(anim/animate opacity 1)
(anim/animate layout 0)))))))
(defn init-props
[]
{:flat-list-ref (atom nil)
:small-list-ref (atom nil)
:scroll-index-lock? (atom true)})
(defn init-state
[messages index]
;; The initial value of data is the image that was pressed (and not the whole album) in order
;; for the transition animation to execute properly, otherwise it would animate towards
;; outside the screen (even if we have `initialScrollIndex` set).
{:data (reagent/atom (if (number? index) [(nth messages index)] []))
:scroll-index (reagent/atom index)
:transparent? (reagent/atom false)
:set-full-height? (reagent/atom false)})
(defn init-animations
[]
{:background-color (anim/use-val colors/black-opa-0)
:border (anim/use-val (if platform/ios? 0 12))
:opacity (anim/use-val 0)
:rotate (anim/use-val "0deg")
:layout (anim/use-val -10)
:top-view-y (anim/use-val 0)
:top-view-x (anim/use-val 0)
:top-view-width (anim/use-val (:width (rn/get-window)))
:top-view-bg (anim/use-val colors/neutral-100-opa-0)
:pan-y (anim/use-val 0)
:pan-x (anim/use-val 0)})
(defn init-derived-animations
[{:keys [layout]}]
{:top-layout (worklet/info-layout layout true)
:bottom-layout (worklet/info-layout layout false)})

View File

@ -1,80 +1,31 @@
(ns status-im2.contexts.chat.lightbox.view (ns status-im2.contexts.chat.lightbox.view
(:require (:require
[clojure.string :as string] [clojure.string :as string]
[quo2.foundations.colors :as colors]
[react-native.core :as rn] [react-native.core :as rn]
[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.reanimated :as reanimated]
[react-native.safe-area :as safe-area]
[status-im2.contexts.chat.lightbox.animations :as anim] [status-im2.contexts.chat.lightbox.animations :as anim]
[status-im2.contexts.chat.lightbox.style :as style] [status-im2.contexts.chat.lightbox.style :as style]
[utils.re-frame :as rf] [utils.re-frame :as rf]
[reagent.core :as reagent]
[react-native.gesture :as gesture] [react-native.gesture :as gesture]
[status-im2.contexts.chat.lightbox.zoomable-image.view :as zoomable-image] [status-im2.contexts.chat.lightbox.zoomable-image.view :as zoomable-image]
[status-im2.contexts.chat.lightbox.top-view :as top-view] [status-im2.contexts.chat.lightbox.top-view :as top-view]
[status-im2.contexts.chat.lightbox.bottom-view :as bottom-view] [status-im2.contexts.chat.lightbox.bottom-view :as bottom-view]
[utils.worklets.lightbox :as worklet] [oops.core :refer [oget]]
[oops.core :refer [oget]])) [status-im2.contexts.chat.lightbox.utils :as utils]
[status-im2.contexts.chat.lightbox.constants :as constants]))
(def ^:const seperator-width 16)
(def ^:const drag-threshold 100)
(defn toggle-opacity
[index {:keys [opacity-value border-value transparent? atoms]} portrait?]
(let [{:keys [small-list-ref]} atoms
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 handle-orientation
[result index window-width window-height animations insets {:keys [flat-list-ref]}]
(let [screen-width (if (or platform/ios? (= result orientation/portrait))
window-width
window-height)
screen-height (if (or platform/ios? (= result orientation/portrait))
window-height
window-width)
landscape? (string/includes? result orientation/landscape)
item-width (if (and landscape? platform/ios?) screen-height screen-width)
timeout (if platform/ios? 50 100)]
(when (or landscape? (= result orientation/portrait))
(rf/dispatch [:chat.ui/orientation-change result]))
(cond
landscape?
(orientation/lock-to-landscape "lightbox")
(= result orientation/portrait)
(orientation/lock-to-portrait "lightbox"))
(js/setTimeout #(when @flat-list-ref
(.scrollToOffset
^js @flat-list-ref
#js {:animated false :offset (* (+ item-width seperator-width) @index)}))
timeout)
(when platform/ios?
(top-view/animate-rotation result screen-width screen-height insets animations))))
(defn get-item-layout (defn get-item-layout
[_ index item-width] [_ index item-width]
#js {:length item-width :offset (* (+ item-width seperator-width) index) :index index}) #js
{:length item-width
:offset (* (+ item-width constants/separator-width) index)
:index index})
(defn on-viewable-items-changed (defn on-viewable-items-changed
[e scroll-index {:keys [scroll-index-lock? small-list-ref]}] [e {:keys [scroll-index-lock? small-list-ref]} {:keys [scroll-index]}]
(when-not @scroll-index-lock? (when-not @scroll-index-lock?
(let [changed (-> e (oget :changed) first) (let [changed (-> e (oget :changed) first)
index (oget changed :index)] index (oget changed :index)]
@ -86,160 +37,88 @@
(defn image (defn image
[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 seperator-width) screen-height)} {:style (style/image (+ screen-width constants/separator-width) screen-height)}
[zoomable-image/zoomable-image message index args [zoomable-image/zoomable-image message index args
#(toggle-opacity index args %)] #(utils/toggle-opacity index args %)]
[rn/view {:style {:width seperator-width}}]]) [rn/view {:style {:width constants/separator-width}}]])
(defn drag-gesture (defn lightbox-content
[{:keys [pan-x pan-y background-color opacity layout]} x? set-full-height?] [props {:keys [data transparent? scroll-index set-full-height?]} animations derived messages index
(-> callback]
(gesture/gesture-pan) (let [insets (safe-area/get-insets)
(gesture/enabled true) window (rn/get-window)
(gesture/max-pointers 1) window-width (:width window)
(gesture/on-start #(reset! set-full-height? false)) window-height (if platform/android?
(gesture/on-update (fn [e] (+ (:height window) (:top insets))
(let [translation (if x? (oget e "translationX") (oget e "translationY")) (:height window))
progress (Math/abs (/ translation drag-threshold))] curr-orientation (or (rf/sub [:lightbox/orientation]) orientation/portrait)
(anim/set-val (if x? pan-x pan-y) translation) landscape? (string/includes? curr-orientation orientation/landscape)
(anim/set-val opacity (- 1 progress)) horizontal? (or platform/android? (not landscape?))
(anim/set-val layout (* progress -20))))) inverted? (and platform/ios? (= curr-orientation orientation/landscape-right))
(gesture/on-end (fn [e] screen-width (if (or platform/ios? (= curr-orientation orientation/portrait))
(if (> (Math/abs (if x? (oget e "translationX") (oget e "translationY"))) window-width
drag-threshold) window-height)
(do screen-height (if (or platform/ios? (= curr-orientation orientation/portrait))
(anim/animate background-color "rgba(0,0,0,0)") window-height
(anim/animate opacity 0) window-width)
(rf/dispatch [:navigate-back])) item-width (if (and landscape? platform/ios?) screen-height screen-width)]
(do [reanimated/view
#(reset! set-full-height? true) {:style (reanimated/apply-animations-to-style {:background-color (:background-color animations)}
(anim/animate (if x? pan-x pan-y) 0) {:height screen-height})}
(anim/animate opacity 1) (when-not @transparent?
(anim/animate layout 0))))))) [:f> top-view/top-view (first messages) insets scroll-index animations derived landscape?
screen-width])
[gesture/gesture-detector
{:gesture (utils/drag-gesture animations (and landscape? platform/ios?) set-full-height?)}
[reanimated/view
{:style (reanimated/apply-animations-to-style
{:transform [{:translateY (:pan-y animations)}
{:translateX (:pan-x animations)}]}
{})}
[gesture/flat-list
{:ref #(reset! (:flat-list-ref props) %)
:key-fn :message-id
:style {:width (+ screen-width constants/separator-width)}
:data @data
:render-fn image
:render-data {:opacity-value (:opacity animations)
:border-value (:border animations)
:transparent? transparent?
:set-full-height? set-full-height?
:screen-height screen-height
:screen-width screen-width
:window-height window-height
:window-width window-width
:props props}
:horizontal horizontal?
:inverted inverted?
:paging-enabled true
:get-item-layout (fn [_ index] (get-item-layout _ index item-width))
:viewability-config {:view-area-coverage-percent-threshold 50
:wait-for-interaction true}
:shows-vertical-scroll-indicator false
:shows-horizontal-scroll-indicator false
:on-viewable-items-changed callback}]]]
(when (and (not @transparent?) (not landscape?))
[:f> bottom-view/bottom-view messages index scroll-index insets animations derived
item-width props])]))
(defn- f-lightbox
[{:keys [messages index]}]
(let [props (utils/init-props)
state (utils/init-state messages index)]
(fn [{:keys [messages index]}]
(let [animations (utils/init-animations)
derived (utils/init-derived-animations animations)
callback (fn [e]
(on-viewable-items-changed e props state))]
(anim/animate (:background-color animations) "rgba(0,0,0,1)")
(reset! (:data state) messages)
(utils/orientation-change props state animations)
(utils/effect props animations index)
[:f> lightbox-content props state animations derived messages index callback]))))
(defn lightbox (defn lightbox
[] []
[:f> (let [screen-params (rf/sub [:get-screen-params])]
(fn [] [:f> f-lightbox screen-params]))
;; we get `insets` from `screen-params` because trying to consume it from
;; lightbox screen causes lots of problems
(let [{:keys [messages index insets]} (rf/sub [:get-screen-params])
atoms {:flat-list-ref (atom nil)
:small-list-ref (atom nil)
:scroll-index-lock? (atom true)}
;; The initial value of data is the image that was pressed (and not the whole album) in order
;; for the transition animation to execute properly, otherwise it would animate towards
;; outside the screen (even if we have `initialScrollIndex` set).
data (reagent/atom (if (number? index) [(nth messages index)] []))
scroll-index (reagent/atom index)
transparent? (reagent/atom false)
set-full-height? (reagent/atom false)
window (rf/sub [:dimensions/window])
window-width (:width window)
window-height (:height window)
window-height (if platform/android?
(+ window-height (:top insets))
window-height)
animations {:background-color (anim/use-val "rgba(0,0,0,0)")
:border (anim/use-val (if platform/ios? 0 12))
:opacity (anim/use-val 0)
:rotate (anim/use-val "0deg")
:layout (anim/use-val -10)
:top-view-y (anim/use-val 0)
:top-view-x (anim/use-val 0)
:top-view-width (anim/use-val window-width)
:top-view-bg (anim/use-val colors/neutral-100-opa-0)
:pan-y (anim/use-val 0)
:pan-x (anim/use-val 0)}
derived {:top-layout (worklet/info-layout (:layout animations)
true)
:bottom-layout (worklet/info-layout (:layout animations)
false)}
callback (fn [e]
(on-viewable-items-changed e scroll-index atoms))]
(anim/animate (:background-color animations) "rgba(0,0,0,1)")
(reset! data messages)
(orientation/use-device-orientation-change
(fn [result]
(if platform/ios?
(handle-orientation result scroll-index window-width window-height animations insets atoms)
;; `use-device-orientation-change` will always be called on Android, so need to check
(orientation/get-auto-rotate-state
(fn [enabled?]
;; RNN does not support landscape-right
(when (and enabled? (not= result orientation/landscape-right))
(handle-orientation result
scroll-index
window-width
window-height
animations
insets
atoms)))))))
(rn/use-effect (fn []
(when @(:flat-list-ref atoms)
(.scrollToIndex ^js @(:flat-list-ref atoms)
#js {:animated false :index index}))
(js/setTimeout (fn []
(anim/animate (:opacity animations) 1)
(anim/animate (:layout animations) 0)
(anim/animate (:border animations) 12))
(if platform/ios? 250 100))
(js/setTimeout #(reset! (:scroll-index-lock? atoms) false) 300)
(fn []
(rf/dispatch [:chat.ui/zoom-out-signal nil])
(when platform/android?
(rf/dispatch [:chat.ui/lightbox-scale 1])))))
[:f>
(fn []
(let [curr-orientation (or (rf/sub [:lightbox/orientation]) orientation/portrait)
landscape? (string/includes? curr-orientation orientation/landscape)
horizontal? (or platform/android? (not landscape?))
inverted? (and platform/ios? (= curr-orientation orientation/landscape-right))
screen-width (if (or platform/ios? (= curr-orientation orientation/portrait))
window-width
window-height)
screen-height (if (or platform/ios? (= curr-orientation orientation/portrait))
window-height
window-width)
item-width (if (and landscape? platform/ios?) screen-height screen-width)]
[reanimated/view
{:style (reanimated/apply-animations-to-style {:background-color (:background-color
animations)}
{:height screen-height})}
(when-not @transparent?
[top-view/top-view (first messages) insets scroll-index animations derived landscape?
screen-width])
[gesture/gesture-detector
{:gesture (drag-gesture animations (and landscape? platform/ios?) set-full-height?)}
[reanimated/view
{:style (reanimated/apply-animations-to-style
{:transform [{:translateY (:pan-y animations)}
{:translateX (:pan-x animations)}]}
{})}
[gesture/flat-list
{:ref #(reset! (:flat-list-ref atoms) %)
:key-fn :message-id
:style {:width (+ screen-width seperator-width)}
:data @data
:render-fn image
:render-data {:opacity-value (:opacity animations)
:border-value (:border animations)
:transparent? transparent?
:set-full-height? set-full-height?
:screen-height screen-height
:screen-width screen-width
:window-height window-height
:window-width window-width
:atoms atoms}
:horizontal horizontal?
:inverted inverted?
:paging-enabled true
:get-item-layout (fn [_ index] (get-item-layout _ index item-width))
:viewability-config {:view-area-coverage-percent-threshold 50
:wait-for-interaction true}
:shows-vertical-scroll-indicator false
:shows-horizontal-scroll-indicator false
:on-viewable-items-changed callback}]]]
(when (and (not @transparent?) (not landscape?))
[bottom-view/bottom-view messages index scroll-index insets animations derived
item-width atoms])]))]))])

View File

@ -3,7 +3,6 @@
[quo2.foundations.colors :as colors] [quo2.foundations.colors :as colors]
[react-native.core :as rn] [react-native.core :as rn]
[react-native.fast-image :as fast-image] [react-native.fast-image :as fast-image]
[react-native.safe-area :as safe-area]
[status-im2.contexts.chat.messages.content.album.style :as style] [status-im2.contexts.chat.messages.content.album.style :as style]
[status-im2.constants :as constants] [status-im2.constants :as constants]
[status-im2.contexts.chat.messages.content.image.view :as image] [status-im2.contexts.chat.messages.content.image.view :as image]
@ -20,8 +19,7 @@
(defn album-message (defn album-message
[{:keys [albumize?] :as message} context on-long-press] [{:keys [albumize?] :as message} context on-long-press]
(let [insets (safe-area/get-insets) (let [shared-element-id (rf/sub [:shared-element-id])
shared-element-id (rf/sub [:shared-element-id])
first-image (first (:album message)) first-image (first (:album message))
album-style (if (> (:image-width first-image) (:image-height first-image)) album-style (if (> (:image-width first-image) (:image-height first-image))
:landscape :landscape
@ -53,8 +51,7 @@
:on-press #(rf/dispatch [:chat.ui/navigate-to-lightbox :on-press #(rf/dispatch [:chat.ui/navigate-to-lightbox
(:message-id item) (:message-id item)
{:messages (:album message) {:messages (:album message)
:index index :index index}])}
:insets insets}])}
[fast-image/fast-image [fast-image/fast-image
{:style (style/image dimensions index portrait? images-count) {:style (style/image dimensions index portrait? images-count)
:source {:uri (:image (:content item))} :source {:uri (:image (:content item))}