Implement collectible image preview (#18449)

* Lightbox refactored and moved to common screens that can be reused
* Events renamed
* Unify constants namespace importing
This commit is contained in:
Volodymyr Kozieiev 2024-01-25 10:58:12 +00:00 committed by GitHub
parent ed7463132a
commit 8999b2b9e8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
26 changed files with 343 additions and 250 deletions

View File

@ -1,4 +1,4 @@
(ns status-im.contexts.chat.messenger.lightbox.animations (ns status-im.common.lightbox.animations
(:require (:require
[react-native.reanimated :as reanimated])) [react-native.reanimated :as reanimated]))

View File

@ -1,25 +1,25 @@
(ns status-im.contexts.chat.messenger.lightbox.bottom-view (ns status-im.common.lightbox.bottom-view
(:require (:require
[quo.foundations.colors :as colors] [quo.foundations.colors :as colors]
[react-native.core :as rn] [react-native.core :as rn]
[react-native.platform :as platform] [react-native.platform :as platform]
[react-native.reanimated :as reanimated] [react-native.reanimated :as reanimated]
[status-im.contexts.chat.messenger.lightbox.animations :as anim] [status-im.common.lightbox.animations :as anim]
[status-im.contexts.chat.messenger.lightbox.constants :as c] [status-im.common.lightbox.constants :as constants]
[status-im.contexts.chat.messenger.lightbox.style :as style] [status-im.common.lightbox.style :as style]
[status-im.contexts.chat.messenger.lightbox.text-sheet.view :as text-sheet] [status-im.common.lightbox.text-sheet.view :as text-sheet]
[utils.re-frame :as rf])) [utils.re-frame :as rf]))
(defn get-small-item-layout (defn get-small-item-layout
[_ index] [_ index]
#js #js
{:length c/small-image-size {:length constants/small-image-size
:offset (* (+ c/small-image-size 8) index) :offset (* (+ constants/small-image-size 8) index)
:index index}) :index index})
(defn- f-small-image (defn- f-small-image
[item index _ {:keys [scroll-index props]}] [item index _ {:keys [scroll-index props]}]
(let [size (if (= @scroll-index index) c/focused-image-size c/small-image-size) (let [size (if (= @scroll-index index) constants/focused-image-size constants/small-image-size)
size-value (anim/use-val size) size-value (anim/use-val size)
{:keys [scroll-index-lock? small-list-ref flat-list-ref]} {:keys [scroll-index-lock? small-list-ref flat-list-ref]}
props] props]
@ -27,7 +27,7 @@
[rn/touchable-opacity [rn/touchable-opacity
{:active-opacity 1 {:active-opacity 1
:on-press (fn [] :on-press (fn []
(rf/dispatch [:chat.ui/zoom-out-signal @scroll-index]) (rf/dispatch [:lightbox/zoom-out-signal @scroll-index])
(reset! scroll-index-lock? true) (reset! scroll-index-lock? true)
(js/setTimeout #(reset! scroll-index-lock? false) 500) (js/setTimeout #(reset! scroll-index-lock? false) 500)
(js/setTimeout (js/setTimeout
@ -38,9 +38,9 @@
(.scrollToIndex ^js @flat-list-ref (.scrollToIndex ^js @flat-list-ref
#js {:animated true :index index})) #js {:animated true :index index}))
(if platform/ios? 50 150)) (if platform/ios? 50 150))
(rf/dispatch [:chat.ui/update-shared-element-id (:message-id item)]))} (rf/dispatch [:lightbox/update-animation-shared-element-id (:id item)]))}
[reanimated/fast-image [reanimated/fast-image
{:source {:uri (:image (:content item))} {:source {:uri (:image item)}
:style (reanimated/apply-animations-to-style {:width size-value :style (reanimated/apply-animations-to-style {:width size-value
:height size-value} :height size-value}
{:border-radius 10})}]])) {:border-radius 10})}]]))
@ -50,20 +50,26 @@
[:f> f-small-image item index _ render-data]) [:f> f-small-image item index _ render-data])
(defn bottom-view (defn bottom-view
[messages index scroll-index insets animations derived item-width props state transparent?] [{:keys [images index scroll-index insets animations derived item-width props state transparent?
(let [padding-horizontal (- (/ item-width 2) (/ c/focused-image-size 2))] bottom-text-component]}]
(let [padding-horizontal (- (/ item-width 2) (/ constants/focused-image-size 2))]
[reanimated/linear-gradient [reanimated/linear-gradient
{:colors [colors/neutral-100-opa-100 colors/neutral-100-opa-80 colors/neutral-100-opa-0] {:colors [colors/neutral-100-opa-100 colors/neutral-100-opa-80 colors/neutral-100-opa-0]
:location [0.2 0.9] :location [0.2 0.9]
:start {:x 0 :y 1} :start {:x 0 :y 1}
:end {:x 0 :y 0} :end {:x 0 :y 0}
:style (style/gradient-container insets animations derived transparent?)} :style (style/gradient-container insets animations derived transparent?)}
[text-sheet/view messages animations state props] (when bottom-text-component
[text-sheet/view
{:overlay-opacity (:overlay-opacity animations)
:overlay-z-index (:overlay-z-index state)
:text-sheet-lock? (:text-sheet-lock? props)
:text-component bottom-text-component}])
[rn/flat-list [rn/flat-list
{:ref #(reset! (:small-list-ref props) %) {:ref #(reset! (:small-list-ref props) %)
:key-fn :message-id :key-fn :id
:style {:height c/small-list-height} :style {:height constants/small-list-height}
:data messages :data images
:render-fn small-image :render-fn small-image
:render-data {:scroll-index scroll-index :render-data {:scroll-index scroll-index
:props props} :props props}

View File

@ -1,4 +1,4 @@
(ns status-im.contexts.chat.messenger.lightbox.constants) (ns status-im.common.lightbox.constants)
(def ^:const small-image-size 40) (def ^:const small-image-size 40)
(def ^:const focused-extra-size 16) (def ^:const focused-extra-size 16)

View File

@ -1,4 +1,4 @@
(ns status-im.contexts.chat.messenger.lightbox.effects (ns status-im.common.lightbox.effects
(:require [react-native.blob :as blob] (:require [react-native.blob :as blob]
[react-native.cameraroll :as cameraroll] [react-native.cameraroll :as cameraroll]
[react-native.fs :as fs] [react-native.fs :as fs]
@ -10,7 +10,7 @@
{:trusty platform/ios? {:trusty platform/ios?
:path (str (fs/cache-dir) "/StatusIm_Image.jpeg")}) :path (str (fs/cache-dir) "/StatusIm_Image.jpeg")})
(rf/reg-fx :effects.chat/share-image (rf/reg-fx :effects.lightbox/share-image
(fn [uri] (fn [uri]
(blob/fetch uri (blob/fetch uri
config config
@ -20,7 +20,7 @@
#(fs/unlink downloaded-url) #(fs/unlink downloaded-url)
#(fs/unlink downloaded-url)))))) #(fs/unlink downloaded-url))))))
(rf/reg-fx :effects.chat/save-image-to-gallery (rf/reg-fx :effects.lightbox/save-image-to-gallery
(fn [[uri on-success]] (fn [[uri on-success]]
(blob/fetch uri (blob/fetch uri
config config

View File

@ -0,0 +1,37 @@
(ns status-im.common.lightbox.events
(:require [reagent.core :as reagent]
status-im.common.lightbox.effects
[utils.re-frame :as rf]))
(rf/reg-event-fx :lightbox/navigate-to-lightbox
(fn [{:keys [db]} [animation-shared-element-id screen-params]]
(reagent/next-tick #(rf/dispatch [:navigate-to :lightbox screen-params]))
{:db (assoc db :animation-shared-element-id animation-shared-element-id)}))
(rf/reg-event-fx :lightbox/update-animation-shared-element-id
(fn [{:keys [db]} [animation-shared-element-id]]
{:db (assoc db :animation-shared-element-id animation-shared-element-id)}))
(rf/reg-event-fx :lightbox/exit-lightbox-signal
(fn [{:keys [db]} [value]]
{:db (assoc db :lightbox/exit-signal value)}))
(rf/reg-event-fx :lightbox/zoom-out-signal
(fn [{:keys [db]} [value]]
{:db (assoc db :lightbox/zoom-out-signal value)}))
(rf/reg-event-fx :lightbox/orientation-change
(fn [{:keys [db]} [value]]
{:db (assoc db :lightbox/orientation value)}))
(rf/reg-event-fx :lightbox/lightbox-scale
(fn [{:keys [db]} [value]]
{:db (assoc db :lightbox/scale value)}))
(rf/reg-event-fx :lightbox/share-image
(fn [_ [uri]]
{:effects.lightbox/share-image uri}))
(rf/reg-event-fx :lightbox/save-image-to-gallery
(fn [_ [uri on-success]]
{:effects.lightbox/save-image-to-gallery [uri on-success]}))

View File

@ -1,9 +1,9 @@
(ns status-im.contexts.chat.messenger.lightbox.style (ns status-im.common.lightbox.style
(:require (:require
[quo.foundations.colors :as colors] [quo.foundations.colors :as colors]
[react-native.platform :as platform] [react-native.platform :as platform]
[react-native.reanimated :as reanimated] [react-native.reanimated :as reanimated]
[status-im.contexts.chat.messenger.lightbox.constants :as c])) [status-im.common.lightbox.constants :as constants]))
;;;; VIEW ;;;; VIEW
(defn image (defn image
@ -33,7 +33,7 @@
{:position :absolute {:position :absolute
:padding-horizontal 20 :padding-horizontal 20
:top (if (or platform/ios? (not landscape?)) top-inset 0) :top (if (or platform/ios? (not landscape?)) top-inset 0)
:height c/top-view-height :height constants/top-view-height
:z-index 4 :z-index 4
:flex-direction :row :flex-direction :row
:justify-content :space-between :justify-content :space-between
@ -44,7 +44,7 @@
(defn top-gradient (defn top-gradient
[insets] [insets]
{:position :absolute {:position :absolute
:height (+ c/top-view-height (:top insets) 0) :height (+ constants/top-view-height (:top insets) 0)
:top (- (:top insets)) :top (- (:top insets))
:left 0 :left 0
:right 0}) :right 0})
@ -71,12 +71,12 @@
:display (if @transparent? :none :flex) :display (if @transparent? :none :flex)
:bottom 0 :bottom 0
:padding-bottom (:bottom insets) :padding-bottom (:bottom insets)
:padding-top c/text-min-height :padding-top constants/text-min-height
:z-index 3})) :z-index 3}))
(defn content-container (defn content-container
[padding-horizontal] [padding-horizontal]
{:padding-vertical c/small-list-padding-vertical {:padding-vertical constants/small-list-padding-vertical
:padding-horizontal padding-horizontal :padding-horizontal padding-horizontal
:align-items :center :align-items :center
:justify-content :center}) :justify-content :center})

View File

@ -1,8 +1,8 @@
(ns status-im.contexts.chat.messenger.lightbox.text-sheet.style (ns status-im.common.lightbox.text-sheet.style
(:require (:require
[quo.foundations.colors :as colors] [quo.foundations.colors :as colors]
[react-native.reanimated :as reanimated] [react-native.reanimated :as reanimated]
[status-im.contexts.chat.messenger.lightbox.constants :as constants])) [status-im.common.lightbox.constants :as constants]))
(defn sheet-container (defn sheet-container
[{:keys [height top]}] [{:keys [height top]}]
@ -14,10 +14,10 @@
:right 0})) :right 0}))
(defn text-style (defn text-style
[expanding-message?] [expandable-text?]
{:color colors/white {:color colors/white
:margin-horizontal 20 :margin-horizontal 20
:align-items (when-not expanding-message? :center) :align-items (when-not expandable-text? :center)
:flex-grow 1}) :flex-grow 1})
(def bar-container (def bar-container

View File

@ -1,10 +1,10 @@
(ns status-im.contexts.chat.messenger.lightbox.text-sheet.utils (ns status-im.common.lightbox.text-sheet.utils
(:require (:require
[oops.core :as oops] [oops.core :as oops]
[react-native.gesture :as gesture] [react-native.gesture :as gesture]
[react-native.reanimated :as reanimated] [react-native.reanimated :as reanimated]
[reagent.core :as r] [reagent.core :as r]
[status-im.contexts.chat.messenger.lightbox.constants :as constants])) [status-im.common.lightbox.constants :as constants]))
(defn- collapse-sheet (defn- collapse-sheet
[{:keys [derived-value overlay-opacity saved-top expanded? overlay-z-index]}] [{:keys [derived-value overlay-opacity saved-top expanded? overlay-z-index]}]
@ -16,10 +16,10 @@
(defn sheet-gesture (defn sheet-gesture
[{:keys [derived-value saved-top overlay-opacity gradient-opacity]} [{:keys [derived-value saved-top overlay-opacity gradient-opacity]}
expanded-height max-height full-height overlay-z-index expanded? dragging? expanding-message?] expanded-height max-height full-height overlay-z-index expanded? dragging? expandable-text?]
(let [disable-gesture-update (r/atom false)] (let [disable-gesture-update (r/atom false)]
(-> (gesture/gesture-pan) (-> (gesture/gesture-pan)
(gesture/enabled expanding-message?) (gesture/enabled expandable-text?)
(gesture/on-start (fn [] (gesture/on-start (fn []
(reset! overlay-z-index 1) (reset! overlay-z-index 1)
(reset! dragging? true) (reset! dragging? true)

View File

@ -1,4 +1,4 @@
(ns status-im.contexts.chat.messenger.lightbox.text-sheet.view (ns status-im.common.lightbox.text-sheet.view
(:require (:require
[quo.foundations.colors :as colors] [quo.foundations.colors :as colors]
[react-native.core :as rn] [react-native.core :as rn]
@ -8,33 +8,31 @@
[react-native.reanimated :as reanimated] [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-im.contexts.chat.messenger.lightbox.constants :as constants] [status-im.common.lightbox.constants :as constants]
[status-im.contexts.chat.messenger.lightbox.text-sheet.style :as style] [status-im.common.lightbox.text-sheet.style :as style]
[status-im.contexts.chat.messenger.lightbox.text-sheet.utils :as utils] [status-im.common.lightbox.text-sheet.utils :as utils]))
[status-im.contexts.chat.messenger.messages.content.text.view :as message-view]))
(defn- text-sheet (defn- text-sheet
[messages overlay-opacity overlay-z-index text-sheet-lock?] [_]
(let [text-height (reagent/atom 0) (let [text-height (reagent/atom 0)
expanded? (reagent/atom false) expanded? (reagent/atom false)
dragging? (atom false)] dragging? (atom false)]
(fn [] (fn [{:keys [overlay-opacity overlay-z-index text-sheet-lock? text-component]}]
(let [{:keys [chat-id content]} (first messages) (let [insets (safe-area/get-insets)
insets (safe-area/get-insets) window-height (:height (rn/get-window))
window-height (:height (rn/get-window)) max-height (- window-height
max-height (- window-height constants/text-min-height
constants/text-min-height constants/top-view-height
constants/top-view-height (:bottom insets)
(:bottom insets) (when platform/ios? (:top insets)))
(when platform/ios? (:top insets))) full-height (+ constants/bar-container-height
full-height (+ constants/bar-container-height constants/text-margin
constants/text-margin constants/line-height
constants/line-height @text-height)
@text-height) expanded-height (min max-height full-height)
expanded-height (min max-height full-height) animations (utils/init-animations overlay-opacity)
animations (utils/init-animations overlay-opacity) derived (utils/init-derived-animations animations)
derived (utils/init-derived-animations animations) expandable-text? (> @text-height (* constants/line-height 2))]
expanding-message? (> @text-height (* constants/line-height 2))]
[rn/view [rn/view
[reanimated/linear-gradient [reanimated/linear-gradient
{:colors [colors/neutral-100-opa-0 colors/neutral-100] {:colors [colors/neutral-100-opa-0 colors/neutral-100]
@ -51,10 +49,10 @@
overlay-z-index overlay-z-index
expanded? expanded?
dragging? dragging?
expanding-message?)} expandable-text?)}
[gesture/gesture-detector [gesture/gesture-detector
{:gesture (-> (gesture/gesture-tap) {:gesture (-> (gesture/gesture-tap)
(gesture/enabled (and expanding-message? (not @expanded?))) (gesture/enabled (and expandable-text? (not @expanded?)))
(gesture/on-start (fn [] (gesture/on-start (fn []
(utils/expand-sheet animations (utils/expand-sheet animations
expanded-height expanded-height
@ -63,7 +61,7 @@
expanded? expanded?
text-sheet-lock?))))} text-sheet-lock?))))}
[reanimated/view {:style (style/sheet-container derived)} [reanimated/view {:style (style/sheet-container derived)}
(when expanding-message? (when expandable-text?
[rn/view {:style style/bar-container} [rn/view {:style style/bar-container}
[rn/view {:style style/bar}]]) [rn/view {:style style/bar}]])
[linear-gradient/linear-gradient [linear-gradient/linear-gradient
@ -72,19 +70,17 @@
:end {:x 0 :y 0} :end {:x 0 :y 0}
:locations [0.7 0.8 1] :locations [0.7 0.8 1]
:style (style/bottom-gradient (:bottom insets))}] :style (style/bottom-gradient (:bottom insets))}]
[gesture/scroll-view [gesture/scroll-view
{:scroll-enabled false {:scroll-enabled false
:scroll-event-throttle 16 :scroll-event-throttle 16
:bounces false :bounces false
:style {:height (- max-height constants/bar-container-height)} :style {:height (- max-height constants/bar-container-height)}
:content-container-style {:padding-top (when (not expanding-message?) :content-container-style {:padding-top (when (not expandable-text?)
constants/bar-container-height)}} constants/bar-container-height)}}
[message-view/render-parsed-text [rn/view {:on-layout #(utils/on-layout % text-height)}
{:content content text-component]]]]]]))))
:chat-id chat-id
:style-override (style/text-style expanding-message?)
:on-layout #(utils/on-layout % text-height)}]]]]]]))))
(defn view (defn view
[messages {:keys [overlay-opacity]} {:keys [overlay-z-index]} {:keys [text-sheet-lock?]}] [props]
[:f> text-sheet messages overlay-opacity overlay-z-index text-sheet-lock?]) [:f> text-sheet props])

View File

@ -1,4 +1,4 @@
(ns status-im.contexts.chat.messenger.lightbox.top-view (ns status-im.common.lightbox.top-view
(:require (:require
[quo.core :as quo] [quo.core :as quo]
[quo.foundations.colors :as colors] [quo.foundations.colors :as colors]
@ -6,10 +6,9 @@
[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]
[status-im.contexts.chat.messenger.lightbox.animations :as anim] [status-im.common.lightbox.animations :as anim]
[status-im.contexts.chat.messenger.lightbox.constants :as c] [status-im.common.lightbox.constants :as constants]
[status-im.contexts.chat.messenger.lightbox.style :as style] [status-im.common.lightbox.style :as style]
[utils.datetime :as datetime]
[utils.i18n :as i18n] [utils.i18n :as i18n]
[utils.re-frame :as rf] [utils.re-frame :as rf]
[utils.url :as url])) [utils.url :as url]))
@ -17,7 +16,7 @@
(defn animate-rotation (defn animate-rotation
[result screen-width screen-height insets [result screen-width screen-height insets
{:keys [rotate top-view-y top-view-x top-view-width top-view-bg]}] {:keys [rotate top-view-y top-view-x top-view-width top-view-bg]}]
(let [top-x (+ (/ c/top-view-height 2) (:top insets))] (let [top-x (+ (/ constants/top-view-height 2) (:top insets))]
(cond (cond
(= result orientation/landscape-left) (= result orientation/landscape-left)
(do (do
@ -42,9 +41,9 @@
(anim/animate top-view-bg colors/neutral-100-opa-0))))) (anim/animate top-view-bg colors/neutral-100-opa-0)))))
(defn drawer (defn drawer
[messages index] [images index]
(let [{:keys [content]} (nth messages index) (let [{:keys [image]} (nth images index)
uri (url/replace-port (:image content) (rf/sub [:mediaserver/port]))] uri (url/replace-port image (rf/sub [:mediaserver/port]))]
[quo/action-drawer [quo/action-drawer
[[{:icon :i/save [[{:icon :i/save
:accessibility-label :save-image :accessibility-label :save-image
@ -52,7 +51,7 @@
:on-press (fn [] :on-press (fn []
(rf/dispatch [:hide-bottom-sheet]) (rf/dispatch [:hide-bottom-sheet])
(rf/dispatch (rf/dispatch
[:chat.ui/save-image-to-gallery [:lightbox/save-image-to-gallery
uri uri
#(rf/dispatch [:toasts/upsert #(rf/dispatch [:toasts/upsert
{:id :random-id {:id :random-id
@ -61,20 +60,19 @@
:text (i18n/label :t/photo-saved)}])]))}]]])) :text (i18n/label :t/photo-saved)}])]))}]]]))
(defn share-image (defn share-image
[messages index] [images index]
(let [{:keys [content]} (nth messages index) (let [{:keys [image]} (nth images index)
uri (url/replace-port (:image content) (rf/sub [:mediaserver/port]))] uri (url/replace-port image (rf/sub [:mediaserver/port]))]
(rf/dispatch [:chat.ui/share-image uri]))) (rf/dispatch [:lightbox/share-image uri])))
(defn top-view (defn top-view
[messages insets index animations derived landscape? screen-width] [images insets index animations derived landscape? screen-width]
(let [{:keys [from timestamp]} (first messages) (let [{:keys [description header]} (nth images @index)
[primary-name _] (rf/sub [:contacts/contact-two-names-by-identity from]) bg-color (if landscape?
bg-color (if landscape? colors/neutral-100-opa-70
colors/neutral-100-opa-70 colors/neutral-100-opa-0)
colors/neutral-100-opa-0)
{:keys [background-color opacity {:keys [background-color opacity
overlay-opacity]} animations] overlay-opacity]} animations]
[reanimated/view [reanimated/view
{:style {:style
(style/top-view-container (:top insets) screen-width bg-color landscape? animations derived)} (style/top-view-container (:top insets) screen-width bg-color landscape? animations derived)}
@ -92,7 +90,7 @@
(anim/animate opacity 0) (anim/animate opacity 0)
(anim/animate overlay-opacity 0) (anim/animate overlay-opacity 0)
(rf/dispatch (if platform/ios? (rf/dispatch (if platform/ios?
[:chat.ui/exit-lightbox-signal @index] [:lightbox/exit-lightbox-signal @index]
[:navigate-back]))) [:navigate-back])))
:style style/close-container} :style style/close-container}
[quo/icon :close {:size 20 :color colors/white}]] [quo/icon :close {:size 20 :color colors/white}]]
@ -100,22 +98,22 @@
[quo/text [quo/text
{:weight :semi-bold {:weight :semi-bold
:size :paragraph-1 :size :paragraph-1
:style {:color colors/white}} primary-name] :style {:color colors/white}} header]
[quo/text [quo/text
{:weight :medium {:weight :medium
:size :paragraph-2 :size :paragraph-2
:style {:color colors/neutral-40}} (when timestamp (datetime/to-short-str timestamp))]]] :style {:color colors/neutral-40}} description]]]
[rn/view {:style style/top-right-buttons} [rn/view {:style style/top-right-buttons}
[rn/touchable-opacity [rn/touchable-opacity
{:active-opacity 1 {:active-opacity 1
:accessibility-label :share-image :accessibility-label :share-image
:on-press #(share-image messages @index) :on-press #(share-image images @index)
:style (merge style/close-container {:margin-right 12})} :style (merge style/close-container {:margin-right 12})}
[quo/icon :share {:size 20 :color colors/white}]] [quo/icon :share {:size 20 :color colors/white}]]
[rn/touchable-opacity [rn/touchable-opacity
{:active-opacity 1 {:active-opacity 1
:accessibility-label :image-options :accessibility-label :image-options
:on-press #(rf/dispatch [:show-bottom-sheet :on-press #(rf/dispatch [:show-bottom-sheet
{:content (fn [] [drawer messages @index])}]) {:content (fn [] [drawer images @index])}])
:style style/close-container} :style style/close-container}
[quo/icon :options {:size 20 :color colors/white}]]]])) [quo/icon :options {:size 20 :color colors/white}]]]]))

View File

@ -1,4 +1,4 @@
(ns status-im.contexts.chat.messenger.lightbox.utils (ns status-im.common.lightbox.utils
(:require (:require
[clojure.string :as string] [clojure.string :as string]
[oops.core :as oops] [oops.core :as oops]
@ -9,9 +9,9 @@
[react-native.platform :as platform] [react-native.platform :as platform]
[react-native.safe-area :as safe-area] [react-native.safe-area :as safe-area]
[reagent.core :as reagent] [reagent.core :as reagent]
[status-im.contexts.chat.messenger.lightbox.animations :as anim] [status-im.common.lightbox.animations :as anim]
[status-im.contexts.chat.messenger.lightbox.constants :as constants] [status-im.common.lightbox.constants :as constants]
[status-im.contexts.chat.messenger.lightbox.top-view :as top-view] [status-im.common.lightbox.top-view :as top-view]
[utils.re-frame :as rf] [utils.re-frame :as rf]
[utils.worklets.chat.messenger.lightbox :as worklet])) [utils.worklets.chat.messenger.lightbox :as worklet]))
@ -46,7 +46,7 @@
(if platform/ios? 250 100))) (if platform/ios? 250 100)))
(swap! timers assoc :mount-index-lock (js/setTimeout #(reset! scroll-index-lock? false) 300)) (swap! timers assoc :mount-index-lock (js/setTimeout #(reset! scroll-index-lock? false) 300))
(fn [] (fn []
(rf/dispatch [:chat.ui/zoom-out-signal nil]) (rf/dispatch [:lightbox/zoom-out-signal nil])
(when platform/android? (when platform/android?
(rf/dispatch [:chat.ui/lightbox-scale 1])) (rf/dispatch [:chat.ui/lightbox-scale 1]))
(clear-timers timers))))) (clear-timers timers)))))
@ -69,7 +69,7 @@
landscape? (string/includes? result orientation/landscape) landscape? (string/includes? result orientation/landscape)
item-width (if (and landscape? platform/ios?) screen-height screen-width)] item-width (if (and landscape? platform/ios?) screen-height screen-width)]
(when (or landscape? (= result orientation/portrait)) (when (or landscape? (= result orientation/portrait))
(rf/dispatch [:chat.ui/orientation-change result])) (rf/dispatch [:lightbox/orientation-change result]))
(cond (cond
landscape? landscape?
(orientation/lock-to-landscape "lightbox") (orientation/lock-to-landscape "lightbox")
@ -148,11 +148,11 @@
:timers (atom {})}) :timers (atom {})})
(defn init-state (defn init-state
[messages index] [images index]
;; The initial value of data is the image that was pressed (and not the whole album) in order ;; 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 ;; for the transition animation to execute properly, otherwise it would animate towards
;; outside the screen (even if we have `initialScrollIndex` set). ;; outside the screen (even if we have `initialScrollIndex` set).
{:data (reagent/atom (if (number? index) [(nth messages index)] [])) {:data (reagent/atom (if (number? index) [(nth images index)] []))
:scroll-index (reagent/atom index) :scroll-index (reagent/atom index)
:transparent? (reagent/atom false) :transparent? (reagent/atom false)
:set-full-height? (reagent/atom false) :set-full-height? (reagent/atom false)

View File

@ -1,4 +1,4 @@
(ns status-im.contexts.chat.messenger.lightbox.view (ns status-im.common.lightbox.view
(:require (:require
[clojure.string :as string] [clojure.string :as string]
[oops.core :as oops] [oops.core :as oops]
@ -9,13 +9,13 @@
[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] [react-native.safe-area :as safe-area]
[status-im.contexts.chat.messenger.lightbox.animations :as anim] [status-im.common.lightbox.animations :as anim]
[status-im.contexts.chat.messenger.lightbox.bottom-view :as bottom-view] [status-im.common.lightbox.bottom-view :as bottom-view]
[status-im.contexts.chat.messenger.lightbox.constants :as constants] [status-im.common.lightbox.constants :as constants]
[status-im.contexts.chat.messenger.lightbox.style :as style] [status-im.common.lightbox.style :as style]
[status-im.contexts.chat.messenger.lightbox.top-view :as top-view] [status-im.common.lightbox.top-view :as top-view]
[status-im.contexts.chat.messenger.lightbox.utils :as utils] [status-im.common.lightbox.utils :as utils]
[status-im.contexts.chat.messenger.lightbox.zoomable-image.view :as zoomable-image] [status-im.common.lightbox.zoomable-image.view :as zoomable-image]
[utils.re-frame :as rf])) [utils.re-frame :as rf]))
(defn get-item-layout (defn get-item-layout
@ -33,9 +33,10 @@
(reset! scroll-index index) (reset! scroll-index index)
(when @small-list-ref (when @small-list-ref
(.scrollToIndex ^js @small-list-ref #js {:animated true :index index})) (.scrollToIndex ^js @small-list-ref #js {:animated true :index index}))
(rf/dispatch [:chat.ui/update-shared-element-id (:message-id (oops/oget changed :item))])))) (rf/dispatch [:lightbox/update-animation-shared-element-id
(:id (oops/oget changed :item))]))))
(defn image (defn image-view
[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)}
@ -43,30 +44,31 @@
[rn/view {:style {:width constants/separator-width}}]]) [rn/view {:style {:width constants/separator-width}}]])
(defn lightbox-content (defn lightbox-content
[props {:keys [data transparent? scroll-index set-full-height?] :as state} [{:keys [props state animations derived images index handle-items-changed bottom-text-component]}]
animations derived messages index handle-items-changed] (let [{:keys [data transparent? scroll-index
(let [insets (safe-area/get-insets) set-full-height?]} state
window (rn/get-window) insets (safe-area/get-insets)
window-width (:width window) window (rn/get-window)
window-height (if platform/android? window-width (:width window)
(+ (:height window) (:top insets)) window-height (if platform/android?
(:height window)) (+ (:height window) (:top insets))
curr-orientation (or (rf/sub [:lightbox/orientation]) orientation/portrait) (:height window))
landscape? (string/includes? curr-orientation orientation/landscape) curr-orientation (or (rf/sub [:lightbox/orientation]) orientation/portrait)
horizontal? (or platform/android? (not landscape?)) landscape? (string/includes? curr-orientation orientation/landscape)
inverted? (and platform/ios? (= curr-orientation orientation/landscape-right)) horizontal? (or platform/android? (not landscape?))
screen-width (if (or platform/ios? (= curr-orientation orientation/portrait)) inverted? (and platform/ios? (= curr-orientation orientation/landscape-right))
window-width screen-width (if (or platform/ios? (= curr-orientation orientation/portrait))
window-height) window-width
screen-height (if (or platform/ios? (= curr-orientation orientation/portrait)) window-height)
window-height screen-height (if (or platform/ios? (= curr-orientation orientation/portrait))
window-width) window-height
item-width (if (and landscape? platform/ios?) screen-height screen-width)] window-width)
item-width (if (and landscape? platform/ios?) screen-height screen-width)]
[reanimated/view [reanimated/view
{:style (reanimated/apply-animations-to-style {:background-color (:background-color animations)} {:style (reanimated/apply-animations-to-style {:background-color (:background-color animations)}
{:height screen-height})} {:height screen-height})}
(when-not @transparent? (when-not @transparent?
[:f> top-view/top-view messages insets scroll-index animations derived landscape? [:f> top-view/top-view images insets scroll-index animations derived landscape?
screen-width]) screen-width])
[gesture/gesture-detector [gesture/gesture-detector
{:gesture (utils/drag-gesture animations (and landscape? platform/ios?) set-full-height?)} {:gesture (utils/drag-gesture animations (and landscape? platform/ios?) set-full-height?)}
@ -92,7 +94,7 @@
:scroll-event-throttle 8 :scroll-event-throttle 8
:style {:width (+ screen-width constants/separator-width)} :style {:width (+ screen-width constants/separator-width)}
:data @data :data @data
:render-fn image :render-fn image-view
:render-data {:opacity-value (:opacity animations) :render-data {:opacity-value (:opacity animations)
:overlay-opacity (:overlay-opacity animations) :overlay-opacity (:overlay-opacity animations)
:border-value (:border animations) :border-value (:border animations)
@ -118,26 +120,47 @@
;; NOTE: not un-mounting bottom-view based on `transparent?` (like we do with the top-view ;; NOTE: not un-mounting bottom-view based on `transparent?` (like we do with the top-view
;; above), since we need to save the state of the text-sheet position. Instead, we use ;; above), since we need to save the state of the text-sheet position. Instead, we use
;; the `:display` style property to hide the bottom-sheet. ;; the `:display` style property to hide the bottom-sheet.
(when (not landscape?) (when (and (not landscape?) (or bottom-text-component (> (count images) 1)))
[:f> bottom-view/bottom-view messages index scroll-index insets animations derived [:f> bottom-view/bottom-view
item-width props state transparent?])])) {:images images
:index index
:scroll-index scroll-index
:insets insets
:animations animations
:derived derived
:item-width item-width
:props props
:state state
:transparent? transparent?
:bottom-text-component bottom-text-component}])]))
(defn- f-lightbox (defn- f-lightbox
[] []
(let [{:keys [messages index]} (rf/sub [:get-screen-params]) (let [{:keys [images index bottom-text-component]} (rf/sub [:get-screen-params])
props (utils/init-props) props
state (utils/init-state messages index) (utils/init-props)
handle-items-changed (fn [e] state
(on-viewable-items-changed e props state))] (utils/init-state images index)
handle-items-changed
(fn [e]
(on-viewable-items-changed e props state))]
(fn [] (fn []
(let [animations (utils/init-animations (count messages) index) (let [animations (utils/init-animations (count images) index)
derived (utils/init-derived-animations animations)] derived (utils/init-derived-animations animations)]
(anim/animate (:background-color animations) colors/neutral-100) (anim/animate (:background-color animations) colors/neutral-100)
(reset! (:data state) messages) (reset! (:data state) images)
(when platform/ios? ; issue: https://github.com/wix/react-native-navigation/issues/7726 (when platform/ios? ; issue: https://github.com/wix/react-native-navigation/issues/7726
(utils/orientation-change props state animations)) (utils/orientation-change props state animations))
(utils/effect props animations index) (utils/effect props animations index)
[:f> lightbox-content props state animations derived messages index handle-items-changed])))) [:f> lightbox-content
{:props props
:state state
:animations animations
:derived derived
:images images
:index index
:handle-items-changed handle-items-changed
:bottom-text-component bottom-text-component}]))))
(defn lightbox (defn lightbox
[] []

View File

@ -1,4 +1,4 @@
(ns status-im.contexts.chat.messenger.lightbox.zoomable-image.constants) (ns status-im.common.lightbox.zoomable-image.constants)
(def ^:const min-scale 1) (def ^:const min-scale 1)

View File

@ -1,4 +1,4 @@
(ns status-im.contexts.chat.messenger.lightbox.zoomable-image.style (ns status-im.common.lightbox.zoomable-image.style
(:require (:require
[react-native.platform :as platform] [react-native.platform :as platform]
[react-native.reanimated :as reanimated])) [react-native.reanimated :as reanimated]))

View File

@ -1,4 +1,4 @@
(ns status-im.contexts.chat.messenger.lightbox.zoomable-image.utils (ns status-im.common.lightbox.zoomable-image.utils
(:require (:require
[clojure.string :as string] [clojure.string :as string]
[react-native.core :as rn] [react-native.core :as rn]
@ -6,8 +6,8 @@
[react-native.orientation :as orientation] [react-native.orientation :as orientation]
[react-native.platform :as platform] [react-native.platform :as platform]
[reagent.core :as reagent] [reagent.core :as reagent]
[status-im.contexts.chat.messenger.lightbox.animations :as anim] [status-im.common.lightbox.animations :as anim]
[status-im.contexts.chat.messenger.lightbox.zoomable-image.constants :as constants] [status-im.common.lightbox.zoomable-image.constants :as constants]
[utils.re-frame :as rf])) [utils.re-frame :as rf]))
;;; Helpers ;;; Helpers
@ -97,7 +97,7 @@
(rescale constants/min-scale true) (rescale constants/min-scale true)
(js/setTimeout #(rf/dispatch [:navigate-back]) 70)) (js/setTimeout #(rf/dispatch [:navigate-back]) 70))
(rf/dispatch [:navigate-back])) (rf/dispatch [:navigate-back]))
(js/setTimeout #(rf/dispatch [:chat.ui/exit-lightbox-signal nil]) 500))) (js/setTimeout #(rf/dispatch [:lightbox/exit-lightbox-signal nil]) 500)))
(defn handle-zoom-out-signal (defn handle-zoom-out-signal
"Zooms out when pressing on another photo from the small bottom list" "Zooms out when pressing on another photo from the small bottom list"

View File

@ -1,4 +1,4 @@
(ns status-im.contexts.chat.messenger.lightbox.zoomable-image.view (ns status-im.common.lightbox.zoomable-image.view
(:require (:require
[oops.core :refer [oget]] [oops.core :refer [oget]]
[react-native.core :as rn] [react-native.core :as rn]
@ -7,10 +7,10 @@
[react-native.platform :as platform] [react-native.platform :as platform]
[react-native.reanimated :as reanimated] [react-native.reanimated :as reanimated]
[reagent.core :as r] [reagent.core :as r]
[status-im.contexts.chat.messenger.lightbox.animations :as anim] [status-im.common.lightbox.animations :as anim]
[status-im.contexts.chat.messenger.lightbox.zoomable-image.constants :as c] [status-im.common.lightbox.zoomable-image.constants :as c]
[status-im.contexts.chat.messenger.lightbox.zoomable-image.style :as style] [status-im.common.lightbox.zoomable-image.style :as style]
[status-im.contexts.chat.messenger.lightbox.zoomable-image.utils :as utils] [status-im.common.lightbox.zoomable-image.utils :as utils]
[utils.re-frame :as rf] [utils.re-frame :as rf]
[utils.url :as url])) [utils.url :as url]))
@ -206,7 +206,7 @@
(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 (defn- f-zoomable-image
[dimensions animations state rescale curr-orientation content focused? index render-data [dimensions animations state rescale curr-orientation image focused? index render-data
image-dimensions-nil?] image-dimensions-nil?]
(let [{:keys [transparent? set-full-height?]} render-data (let [{:keys [transparent? set-full-height?]} render-data
portrait? (= curr-orientation orientation/portrait) portrait? (= curr-orientation orientation/portrait)
@ -229,7 +229,7 @@
(= curr-orientation orientation/portrait))} (= curr-orientation orientation/portrait))}
[reanimated/fast-image [reanimated/fast-image
(merge (merge
{:source {:uri (url/replace-port (:image content) (rf/sub [:mediaserver/port]))} {:source {:uri (url/replace-port image (rf/sub [:mediaserver/port]))}
:native-ID (when focused? :shared-element) :native-ID (when focused? :shared-element)
:style (style/image dimensions animations render-data index)} :style (style/image dimensions animations render-data index)}
(when image-dimensions-nil? (when image-dimensions-nil?
@ -238,12 +238,12 @@
(defn zoomable-image (defn zoomable-image
[] []
(let [state (utils/init-state)] (let [state (utils/init-state)]
(fn [{:keys [image-width image-height content message-id]} index render-data] (fn [{:keys [image-width image-height image id]} index render-data]
(let [shared-element-id (rf/sub [:shared-element-id]) (let [animation-shared-element-id (rf/sub [:animation-shared-element-id])
exit-lightbox-signal (rf/sub [:lightbox/exit-signal]) exit-lightbox-signal (rf/sub [:lightbox/exit-signal])
zoom-out-signal (rf/sub [:lightbox/zoom-out-signal]) zoom-out-signal (rf/sub [:lightbox/zoom-out-signal])
{:keys [set-full-height? curr-orientation]} render-data {:keys [set-full-height? curr-orientation]} render-data
focused? (= shared-element-id message-id) focused? (= animation-shared-element-id id)
;; TODO - remove `image-dimensions` check, once ;; TODO - remove `image-dimensions` check, once
;; https://github.com/status-im/status-desktop/issues/10944 is fixed ;; https://github.com/status-im/status-desktop/issues/10944 is fixed
image-dimensions-nil? (not (and image-width image-height)) image-dimensions-nil? (not (and image-width image-height))
@ -269,5 +269,5 @@
rescale rescale
set-full-height?)) set-full-height?))
(utils/handle-zoom-out-signal zoom-out-signal index (anim/get-val (:scale animations)) rescale) (utils/handle-zoom-out-signal zoom-out-signal index (anim/get-val (:scale animations)) rescale)
[:f> f-zoomable-image dimensions animations state rescale curr-orientation content focused? [:f> f-zoomable-image dimensions animations state rescale curr-orientation image focused?
index render-data image-dimensions-nil?])))) index render-data image-dimensions-nil?]))))

View File

@ -4,13 +4,12 @@
[legacy.status-im.chat.models.loading :as loading] [legacy.status-im.chat.models.loading :as loading]
[legacy.status-im.data-store.chats :as chats-store] [legacy.status-im.data-store.chats :as chats-store]
[re-frame.core :as re-frame] [re-frame.core :as re-frame]
[reagent.core :as reagent] status-im.common.lightbox.events
[status-im.common.muting.helpers :refer [format-mute-till]] [status-im.common.muting.helpers :refer [format-mute-till]]
[status-im.constants :as constants] [status-im.constants :as constants]
[status-im.contexts.chat.contacts.events :as contacts-store] [status-im.contexts.chat.contacts.events :as contacts-store]
status-im.contexts.chat.effects status-im.contexts.chat.effects
[status-im.contexts.chat.messenger.composer.link-preview.events :as link-preview] [status-im.contexts.chat.messenger.composer.link-preview.events :as link-preview]
status-im.contexts.chat.messenger.lightbox.events
status-im.contexts.chat.messenger.messages.content.reactions.events status-im.contexts.chat.messenger.messages.content.reactions.events
[status-im.contexts.chat.messenger.messages.delete-message-for-me.events :as delete-for-me] [status-im.contexts.chat.messenger.messages.delete-message-for-me.events :as delete-for-me]
[status-im.contexts.chat.messenger.messages.delete-message.events :as delete-message] [status-im.contexts.chat.messenger.messages.delete-message.events :as delete-message]
@ -394,38 +393,6 @@
[cofx chat-id] [cofx chat-id]
(navigation/navigate-to cofx :chat-pinned-messages {:chat-id chat-id})) (navigation/navigate-to cofx :chat-pinned-messages {:chat-id chat-id}))
(rf/defn update-shared-element-id
{:events [:chat.ui/update-shared-element-id]}
[{:keys [db]} shared-element-id]
{:db (assoc db :shared-element-id shared-element-id)})
(rf/defn navigate-to-lightbox
{:events [:chat.ui/navigate-to-lightbox]}
[{:keys [db]} shared-element-id screen-params]
(reagent/next-tick #(rf/dispatch [:navigate-to :lightbox screen-params]))
{:db (assoc db :shared-element-id shared-element-id)})
(rf/defn exit-lightbox-signal
{:events [:chat.ui/exit-lightbox-signal]}
[{:keys [db]} value]
{:db (assoc db :lightbox/exit-signal value)})
(rf/defn zoom-out-signal
{:events [:chat.ui/zoom-out-signal]}
[{:keys [db]} value]
{:db (assoc db :lightbox/zoom-out-signal value)})
(rf/defn orientation-change
{:events [:chat.ui/orientation-change]}
[{:keys [db]} value]
{:db (assoc db :lightbox/orientation value)})
(rf/defn lightbox-scale
{:events [:chat.ui/lightbox-scale]}
[{:keys [db]} value]
{:db (assoc db :lightbox/scale value)})
(rf/defn check-last-chat (rf/defn check-last-chat
{:events [:chat/check-last-chat]} {:events [:chat/check-last-chat]}
[{:keys [db]}] [{:keys [db]}]
@ -452,3 +419,15 @@
{:events [:chat.ui/scroll-to-bottom]} {:events [:chat.ui/scroll-to-bottom]}
[_] [_]
{:effects.chat/scroll-to-bottom nil}) {:effects.chat/scroll-to-bottom nil})
(rf/reg-event-fx :chat.ui/clear-sending-images
(fn [{:keys [db]}]
{:db (update-in db [:chat/inputs (:current-chat-id db) :metadata] assoc :sending-image {})}))
(rf/reg-event-fx :chat.ui/image-unselected
(fn [{:keys [db]} [original]]
(let [current-chat-id (:current-chat-id db)]
{:db (update-in db
[:chat/inputs current-chat-id :metadata :sending-image]
dissoc
(:uri original))})))

View File

@ -1,23 +0,0 @@
(ns status-im.contexts.chat.messenger.lightbox.events
(:require status-im.contexts.chat.messenger.lightbox.effects
[utils.re-frame :as rf]))
(rf/reg-event-fx :chat.ui/clear-sending-images
(fn [{:keys [db]}]
{:db (update-in db [:chat/inputs (:current-chat-id db) :metadata] assoc :sending-image {})}))
(rf/reg-event-fx :chat.ui/image-unselected
(fn [{:keys [db]} [original]]
(let [current-chat-id (:current-chat-id db)]
{:db (update-in db
[:chat/inputs current-chat-id :metadata :sending-image]
dissoc
(:uri original))})))
(rf/reg-event-fx :chat.ui/share-image
(fn [_ [uri]]
{:effects.chat/share-image uri}))
(rf/reg-event-fx :chat.ui/save-image-to-gallery
(fn [_ [uri on-success]]
{:effects.chat/save-image-to-gallery [uri on-success]}))

View File

@ -7,6 +7,8 @@
[status-im.constants :as constants] [status-im.constants :as constants]
[status-im.contexts.chat.messenger.messages.content.album.style :as style] [status-im.contexts.chat.messenger.messages.content.album.style :as style]
[status-im.contexts.chat.messenger.messages.content.image.view :as image] [status-im.contexts.chat.messenger.messages.content.image.view :as image]
[status-im.contexts.chat.messenger.messages.content.lightbox.utils :as lightbox-utils]
[status-im.contexts.chat.messenger.messages.content.lightbox.view :as lightbox]
[status-im.contexts.chat.messenger.messages.content.text.view :as text] [status-im.contexts.chat.messenger.messages.content.text.view :as text]
[utils.re-frame :as rf] [utils.re-frame :as rf]
[utils.url :as url])) [utils.url :as url]))
@ -21,17 +23,19 @@
(defn album-message (defn album-message
[{:keys [albumize?] :as message} context on-long-press message-container-data] [{:keys [albumize?] :as message} context on-long-press message-container-data]
(let [shared-element-id (rf/sub [:shared-element-id]) (let [animation-shared-element-id (rf/sub [:animation-shared-element-id])
media-server-port (rf/sub [:mediaserver/port]) media-server-port (rf/sub [:mediaserver/port])
first-image (first (:album message)) album-messages (:album message)
album-style (if (> (:image-width first-image) (:image-height first-image)) first-image (first album-messages)
:landscape album-style (if (> (:image-width first-image) (:image-height first-image))
:portrait) :landscape
images-count (count (:album message)) :portrait)
images-count (count album-messages)
;; album images are always square, except when we have 3 images, then they must be ;; album images are always square, except when we have 3 images, then they must be
;; rectangular ;; rectangular
;; (portrait or landscape) ;; (portrait or landscape)
portrait? (and (= images-count rectangular-style-count) (= album-style :portrait))] portrait? (and (= images-count rectangular-style-count)
(= album-style :portrait))]
(if (and albumize? (> images-count 1)) (if (and albumize? (> images-count 1))
[:<> [:<>
[rn/view {:style {:margin-bottom 4}} [text/text-content first-image]] [rn/view {:style {:margin-bottom 4}} [text/text-content first-image]]
@ -52,14 +56,21 @@
{:key (:message-id item) {:key (:message-id item)
:active-opacity 1 :active-opacity 1
:on-long-press #(on-long-press message context) :on-long-press #(on-long-press message context)
:on-press #(rf/dispatch [:chat.ui/navigate-to-lightbox :on-press #(rf/dispatch
(:message-id item) [:lightbox/navigate-to-lightbox
{:messages (:album message) (:message-id item)
:index index}])} {:index index
:images (into []
(map
lightbox-utils/convert-message-to-lightbox-image
album-messages))
:bottom-text-component
[lightbox/bottom-text-for-lightbox
first-image]}])}
[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 (url/replace-port (:image (:content item)) media-server-port)} :source {:uri (url/replace-port (:image (:content item)) media-server-port)}
:native-ID (when (and (= shared-element-id (:message-id item)) :native-ID (when (and (= animation-shared-element-id (:message-id item))
(< index constants/max-album-photos)) (< index constants/max-album-photos))
:shared-element)}] :shared-element)}]
(when (and (> images-count constants/max-album-photos) (when (and (> images-count constants/max-album-photos)
@ -71,11 +82,11 @@
:size :heading-2 :size :heading-2
:style {:color colors/white}} :style {:color colors/white}}
(str "+" (- images-count (dec constants/max-album-photos)))]])])) (str "+" (- images-count (dec constants/max-album-photos)))]])]))
(:album message))]] album-messages)]]
[:<> [:<>
(map-indexed (map-indexed
(fn [index item] (fn [index item]
[:<> {:key (:message-id item)} [:<> {:key (:message-id item)}
[image/image-message index item {:on-long-press #(on-long-press message context)} [image/image-message index item {:on-long-press #(on-long-press message context)}
message-container-data]]) message-container-data]])
(:album message))]))) album-messages)])))

View File

@ -4,6 +4,8 @@
[react-native.fast-image :as fast-image] [react-native.fast-image :as fast-image]
[react-native.safe-area :as safe-area] [react-native.safe-area :as safe-area]
[status-im.constants :as constants] [status-im.constants :as constants]
[status-im.contexts.chat.messenger.messages.content.lightbox.utils :as lightbox-utils]
[status-im.contexts.chat.messenger.messages.content.lightbox.view :as lightbox]
[status-im.contexts.chat.messenger.messages.content.text.view :as text] [status-im.contexts.chat.messenger.messages.content.text.view :as text]
[utils.re-frame :as rf] [utils.re-frame :as rf]
[utils.url :as url])) [utils.url :as url]))
@ -39,7 +41,7 @@
image-height image-height
max-container-width max-container-width
max-container-height) max-container-height)
shared-element-id (rf/sub [:shared-element-id]) animation-shared-element-id (rf/sub [:animation-shared-element-id])
image-local-url (url/replace-port (:image content) (rf/sub [:mediaserver/port]))] image-local-url (url/replace-port (:image content) (rf/sub [:mediaserver/port]))]
[:<> [:<>
(when (= index 0) (when (= index 0)
@ -48,13 +50,16 @@
{:active-opacity 1 {:active-opacity 1
:style {:margin-top 4} :style {:margin-top 4}
:on-long-press on-long-press :on-long-press on-long-press
:on-press #(rf/dispatch [:chat.ui/navigate-to-lightbox :on-press #(rf/dispatch [:lightbox/navigate-to-lightbox
message-id message-id
{:messages [message] {:images [(lightbox-utils/convert-message-to-lightbox-image
:index 0 message)]
:insets insets}])} :index 0
:insets insets
:bottom-text-component
[lightbox/bottom-text-for-lightbox message]}])}
[fast-image/fast-image [fast-image/fast-image
{:source {:uri image-local-url} {:source {:uri image-local-url}
:style (merge dimensions {:border-radius 12}) :style (merge dimensions {:border-radius 12})
:native-ID (when (= shared-element-id message-id) :shared-element) :native-ID (when (= animation-shared-element-id message-id) :shared-element)
:accessibility-label :image-message}]]])) :accessibility-label :image-message}]]]))

View File

@ -0,0 +1,10 @@
(ns status-im.contexts.chat.messenger.messages.content.lightbox.style
(:require
[quo.foundations.colors :as colors]))
(defn bottom-text
[expandable-text?]
{:color colors/white
:margin-horizontal 20
:align-items (when-not expandable-text? :center)
:flex-grow 1})

View File

@ -0,0 +1,14 @@
(ns status-im.contexts.chat.messenger.messages.content.lightbox.utils
(:require
[utils.datetime :as datetime]
[utils.re-frame :as rf]))
(defn convert-message-to-lightbox-image
[{:keys [timestamp image-width image-height message-id from content]}]
(let [[primary-name _] (rf/sub [:contacts/contact-two-names-by-identity from])]
{:image (:image content)
:image-width image-width
:image-height image-height
:id message-id
:header primary-name
:description (when timestamp (datetime/to-short-str timestamp))}))

View File

@ -0,0 +1,18 @@
(ns status-im.contexts.chat.messenger.messages.content.lightbox.view
(:require
[oops.core :as oops]
[reagent.core :as reagent]
[status-im.common.lightbox.constants :as constants]
[status-im.contexts.chat.messenger.messages.content.lightbox.style :as style]
[status-im.contexts.chat.messenger.messages.content.text.view :as message-view]))
(defn bottom-text-for-lightbox
[_]
(let [text-height (reagent/atom 0)]
(fn [{:keys [content chat-id] :as _message}]
(let [expandable-text? (> @text-height (* constants/line-height 2))]
[message-view/render-parsed-text
{:content content
:chat-id chat-id
:style-override (style/bottom-text expandable-text?)
:on-layout #(reset! text-height (oops/oget % "nativeEvent.layout.height"))}]))))

View File

@ -75,12 +75,14 @@
(let [selected-tab (reagent/atom :overview) (let [selected-tab (reagent/atom :overview)
on-tab-change #(reset! selected-tab %)] on-tab-change #(reset! selected-tab %)]
(fn [] (fn []
(let [collectible (rf/sub [:wallet/last-collectible-details]) (let [collectible (rf/sub [:wallet/last-collectible-details])
animation-shared-element-id (rf/sub [:animation-shared-element-id])
{:keys [collectible-data preview-url {:keys [collectible-data preview-url
collection-data]} collectible collection-data id]} collectible
token-id (:token-id id)
{collection-image :image-url {collection-image :image-url
collection-name :name} collection-data collection-name :name} collection-data
{collectible-name :name} collectible-data] {collectible-name :name} collectible-data]
[scroll-page/scroll-page [scroll-page/scroll-page
{:navigate-back? true {:navigate-back? true
:height 148 :height 148
@ -95,9 +97,26 @@
:picture preview-url}} :picture preview-url}}
[rn/view {:style style/container} [rn/view {:style style/container}
[rn/view {:style style/preview-container} [rn/view {:style style/preview-container}
[rn/image [rn/touchable-opacity
{:source preview-url {:active-opacity 1
:style style/preview}]] :on-press #(rf/dispatch [:lightbox/navigate-to-lightbox
token-id
{:images [{:image preview-url
:image-width 300 ; collectibles don't have
; width/height but we need
; to pass something
:image-height 300 ; without it animation
; doesn't work smoothly and
; :border-radius not
; applied
:id token-id
:header collectible-name
:description collection-name}]
:index 0}])}
[rn/image
{:source preview-url
:style style/preview
:native-ID (when (= animation-shared-element-id token-id) :shared-element)}]]]
[header collectible-name collection-name collection-image] [header collectible-name collection-name collection-image]
[cta-buttons] [cta-buttons]
[quo/tabs [quo/tabs

View File

@ -2,13 +2,13 @@
(:require (:require
[legacy.status-im.ui.screens.screens :as old-screens] [legacy.status-im.ui.screens.screens :as old-screens]
[status-im.common.emoji-picker.view :as emoji-picker] [status-im.common.emoji-picker.view :as emoji-picker]
[status-im.common.lightbox.view :as lightbox]
[status-im.config :as config] [status-im.config :as config]
[status-im.contexts.chat.group-details.view :as group-details] [status-im.contexts.chat.group-details.view :as group-details]
[status-im.contexts.chat.home.add-new-contact.scan.scan-profile-qr-page :as scan-profile-qr-page] [status-im.contexts.chat.home.add-new-contact.scan.scan-profile-qr-page :as scan-profile-qr-page]
[status-im.contexts.chat.home.add-new-contact.views :as add-new-contact] [status-im.contexts.chat.home.add-new-contact.views :as add-new-contact]
[status-im.contexts.chat.home.new-chat.view :as new-chat] [status-im.contexts.chat.home.new-chat.view :as new-chat]
[status-im.contexts.chat.messenger.camera.view :as camera-screen] [status-im.contexts.chat.messenger.camera.view :as camera-screen]
[status-im.contexts.chat.messenger.lightbox.view :as lightbox]
[status-im.contexts.chat.messenger.messages.view :as chat] [status-im.contexts.chat.messenger.messages.view :as chat]
[status-im.contexts.chat.messenger.photo-selector.view :as photo-selector] [status-im.contexts.chat.messenger.photo-selector.view :as photo-selector]
[status-im.contexts.communities.actions.accounts-selection.view :as communities.accounts-selection] [status-im.contexts.communities.actions.accounts-selection.view :as communities.accounts-selection]

View File

@ -23,7 +23,7 @@
;;view ;;view
(reg-root-key-sub :view-id :view-id) (reg-root-key-sub :view-id :view-id)
(reg-root-key-sub :screen-params :navigation/screen-params) (reg-root-key-sub :screen-params :navigation/screen-params)
(reg-root-key-sub :shared-element-id :shared-element-id) (reg-root-key-sub :animation-shared-element-id :animation-shared-element-id)
;;bottom sheet ;;bottom sheet
(reg-root-key-sub :bottom-sheet :bottom-sheet) (reg-root-key-sub :bottom-sheet :bottom-sheet)