diff --git a/src/status_im2/constants.cljs b/src/status_im2/constants.cljs index a654f0a7c0..8a5c90a3ac 100644 --- a/src/status_im2/constants.cljs +++ b/src/status_im2/constants.cljs @@ -215,9 +215,9 @@ (def album-image-sizes ; sometimes we subtract 1 or 0.5 for padding {2 {0 image-size 1 image-size} - 3 {0 [(* image-size 2) (* image-size 1.5)] - 1 [(- image-size 0.5) (- (* image-size 0.67) 1)] - 2 [(- image-size 0.5) (- (* image-size 0.67) 1)]} + 3 {0 [(* image-size 2) (* image-size 1.25)] + 1 [(- image-size 0.5) (- (* image-size 0.75) 1)] + 2 [(- image-size 0.5) (- (* image-size 0.75) 1)]} 4 {0 image-size 1 image-size 2 image-size diff --git a/src/status_im2/contexts/chat/events.cljs b/src/status_im2/contexts/chat/events.cljs index ca0bab4a66..ce10de5a23 100644 --- a/src/status_im2/contexts/chat/events.cljs +++ b/src/status_im2/contexts/chat/events.cljs @@ -353,3 +353,8 @@ [{: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)}) + diff --git a/src/status_im2/contexts/chat/lightbox/bottom_view.cljs b/src/status_im2/contexts/chat/lightbox/bottom_view.cljs index f5f46d09c8..bad63521dd 100644 --- a/src/status_im2/contexts/chat/lightbox/bottom_view.cljs +++ b/src/status_im2/contexts/chat/lightbox/bottom_view.cljs @@ -61,18 +61,20 @@ :start {:x 0 :y 1} :end {:x 0 :y 0} :style (style/gradient-container insets animations)} - [rn/text - {:style style/text-style} text] + (when (not= text "placeholder") + [rn/text {:style style/text-style} text]) [rn/flat-list - {:ref #(reset! (:small-list-ref atoms) %) - :key-fn :message-id - :style {:height small-list-height} - :data messages - :render-fn small-image - :render-data {:scroll-index scroll-index - :atoms atoms} - :horizontal true - :get-item-layout get-small-item-layout - :separator [rn/view {:style {:width 8}}] - :initial-scroll-index index - :content-container-style (style/content-container padding-horizontal)}]]))]) + {:ref #(reset! (:small-list-ref atoms) %) + :key-fn :message-id + :style {:height small-list-height} + :data messages + :render-fn small-image + :render-data {:scroll-index scroll-index + :atoms atoms} + :horizontal true + :shows-horizontal-scroll-indicator false + :get-item-layout get-small-item-layout + :separator [rn/view {:style {:width 8}}] + :initial-scroll-index index + :content-container-style (style/content-container padding-horizontal)}]]))]) + diff --git a/src/status_im2/contexts/chat/lightbox/style.cljs b/src/status_im2/contexts/chat/lightbox/style.cljs index ddb92de6bc..99749793ec 100644 --- a/src/status_im2/contexts/chat/lightbox/style.cljs +++ b/src/status_im2/contexts/chat/lightbox/style.cljs @@ -10,19 +10,19 @@ ;;;; TOP-VIEW (defn top-view-container - [top-inset {:keys [opacity rotate top-view-y top-view-x top-view-width top-view-bg]} window-width + [top-inset {:keys [opacity rotate top-view-y top-view-x top-view-width top-view-bg top-layout]} + window-width bg-color] (reanimated/apply-animations-to-style (if platform/ios? - {:transform [{:rotate rotate} + {:transform [{:translateY top-layout} + {:rotate rotate} {:translateY top-view-y} {:translateX top-view-x}] :opacity opacity :width top-view-width :background-color top-view-bg} - {:transform [{:rotate rotate} - {:translateY top-view-y} - {:translateX top-view-x}] + {:transform [{:translateY top-layout}] :opacity opacity}) {:position :absolute :padding-horizontal 20 @@ -48,9 +48,10 @@ ;;;; BOTTOM-VIEW (defn gradient-container - [insets {:keys [opacity]}] + [insets {:keys [opacity bottom-layout]}] (reanimated/apply-animations-to-style - {:opacity opacity} + {:transform [{:translateY bottom-layout}] + :opacity opacity} {:position :absolute :bottom 0 :padding-bottom (:bottom insets) diff --git a/src/status_im2/contexts/chat/lightbox/top_view.cljs b/src/status_im2/contexts/chat/lightbox/top_view.cljs index 66988fedcc..25219f0354 100644 --- a/src/status_im2/contexts/chat/lightbox/top_view.cljs +++ b/src/status_im2/contexts/chat/lightbox/top_view.cljs @@ -50,9 +50,11 @@ {:style {:flex-direction :row :align-items :center}} [rn/touchable-opacity - {:on-press #(rf/dispatch (if platform/ios? - [:chat.ui/exit-lightbox-signal @index] - [:navigate-back])) + {:on-press (fn [] + (common/set-val-timing (:opacity animations) 0) + (rf/dispatch (if platform/ios? + [:chat.ui/exit-lightbox-signal @index] + [:navigate-back]))) :style style/close-container} [quo/icon :close {:size 20 :color colors/white}]] [rn/view {:style {:margin-left 12}} diff --git a/src/status_im2/contexts/chat/lightbox/view.cljs b/src/status_im2/contexts/chat/lightbox/view.cljs index 3a407bb562..7833233e3c 100644 --- a/src/status_im2/contexts/chat/lightbox/view.cljs +++ b/src/status_im2/contexts/chat/lightbox/view.cljs @@ -94,7 +94,7 @@ (let [{:keys [messages index]} (rf/sub [:get-screen-params]) atoms {:flat-list-ref (atom nil) :small-list-ref (atom nil) - :scroll-index-lock? (atom false) + :scroll-index-lock? (atom true) :insets-atom (atom nil)} ;; 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 @@ -103,9 +103,11 @@ scroll-index (reagent/atom index) transparent? (reagent/atom false) window (rf/sub [:dimensions/window]) - animations {:border (common/use-val 12) - :opacity (common/use-val 1) + animations {:border (common/use-val (if platform/ios? 0 12)) + :opacity (common/use-val 0) :rotate (common/use-val "0deg") + :top-layout (common/use-val -10) + :bottom-layout (common/use-val 10) :top-view-y (common/use-val 0) :top-view-x (common/use-val 0) :top-view-width (common/use-val (:width window)) @@ -124,11 +126,21 @@ ;; RNN does not support landscape-right (when (and enabled? (not= result orientation/landscape-right)) (handle-orientation result scroll-index window animations atoms))))))) - (rn/use-effect-once (fn [] - (when @(:flat-list-ref atoms) - (.scrollToIndex ^js @(:flat-list-ref atoms) - #js {:animated false :index index})) - js/undefined)) + (rn/use-effect (fn [] + (when @(:flat-list-ref atoms) + (.scrollToIndex ^js @(:flat-list-ref atoms) + #js {:animated false :index index})) + (js/setTimeout (fn [] + (common/set-val-timing (:opacity animations) 1) + (common/set-val-timing (:top-layout animations) 0) + (common/set-val-timing (:bottom-layout animations) 0) + (common/set-val-timing (: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]))))) [safe-area/consumer (fn [insets] (let [curr-orientation (or (rf/sub [:lightbox/orientation]) orientation/portrait) diff --git a/src/status_im2/contexts/chat/lightbox/zoomable_image/style.cljs b/src/status_im2/contexts/chat/lightbox/zoomable_image/style.cljs index 9206886a2c..dee2bf8411 100644 --- a/src/status_im2/contexts/chat/lightbox/zoomable_image/style.cljs +++ b/src/status_im2/contexts/chat/lightbox/zoomable_image/style.cljs @@ -1,9 +1,12 @@ (ns status-im2.contexts.chat.lightbox.zoomable-image.style - (:require [react-native.reanimated :as reanimated])) + (:require + [react-native.platform :as platform] + [react-native.reanimated :as reanimated])) (defn container [{:keys [width height]} - {:keys [pan-x pan-y pinch-x pinch-y scale]}] + {:keys [pan-x pan-y pinch-x pinch-y scale]} + set-full-height?] (reanimated/apply-animations-to-style {:transform [{:translateX pan-x} {:translateY pan-y} @@ -12,8 +15,8 @@ {:scale scale}]} {:justify-content :center :align-items :center - :width width - :height height})) + :width (if platform/ios? width "100%") + :height (if set-full-height? "100%" height)})) (defn image [{:keys [image-width image-height]} diff --git a/src/status_im2/contexts/chat/lightbox/zoomable_image/utils.cljs b/src/status_im2/contexts/chat/lightbox/zoomable_image/utils.cljs index 95b9020f52..e272b2995c 100644 --- a/src/status_im2/contexts/chat/lightbox/zoomable_image/utils.cljs +++ b/src/status_im2/contexts/chat/lightbox/zoomable_image/utils.cljs @@ -42,8 +42,9 @@ (defn handle-exit-lightbox-signal "On ios, when attempting to navigate back while zoomed in, the shared-element transition animation doesn't execute properly, so we need to zoom out first" - [exit-lightbox-signal index scale rescale] + [exit-lightbox-signal index scale rescale set-full-height?] (when (= exit-lightbox-signal index) + (reset! set-full-height? false) (if (> scale c/min-scale) (do (rescale c/min-scale true) @@ -81,3 +82,11 @@ (defn get-pinch-position [scale-diff size focal] (* (- (/ size 2) focal) scale-diff)) + +(defn get-focal + [focal size screen-size] + (let [min (/ (- screen-size size) 2) + max (+ min size)] + (if (or (> focal max) (< focal min)) + (/ screen-size 2) + focal))) diff --git a/src/status_im2/contexts/chat/lightbox/zoomable_image/view.cljs b/src/status_im2/contexts/chat/lightbox/zoomable_image/view.cljs index fa0ae2dcb6..8f570058b4 100644 --- a/src/status_im2/contexts/chat/lightbox/zoomable_image/view.cljs +++ b/src/status_im2/contexts/chat/lightbox/zoomable_image/view.cljs @@ -1,5 +1,6 @@ (ns status-im2.contexts.chat.lightbox.zoomable-image.view (:require + [react-native.core :as rn] [react-native.gesture :as gesture] [react-native.platform :as platform] [react-native.reanimated :as reanimated] @@ -73,7 +74,9 @@ (when (= value c/min-scale) (reset-values exit? animations props)) (reset! pan-x-enabled? (> value x-threshold-scale)) - (reset! pan-y-enabled? (> value y-threshold-scale))) + (reset! pan-y-enabled? (> value y-threshold-scale)) + (when platform/android? + (rf/dispatch [:chat.ui/lightbox-scale value]))) (defn handle-orientation-change [curr-orientation @@ -128,28 +131,58 @@ (rescale c/double-tap-scale)) (rescale c/min-scale)))))) -(defn pinch-gesture +;; not using on-finalize because on-finalize gets called always regardless the gesture executed or not +(defn finalize-pinch [{:keys [width height screen-height screen-width x-threshold-scale y-threshold-scale]} - {:keys [saved-scale scale pinch-x pinch-y pinch-x-start pinch-y-start pinch-x-max pinch-y-max pan-y - pan-y-start pan-x pan-x-start] + {:keys [saved-scale scale pinch-x pinch-y pinch-x-start pinch-y-start pan-y pan-y-start pan-x + pan-x-start]} + {:keys [pan-x-enabled? pan-y-enabled?]}] + (let [curr-offset-y (+ (get-val pan-y) (get-val pinch-y)) + max-offset-y (utils/get-max-offset height screen-height (get-val scale)) + max-offset-y (if (neg? curr-offset-y) (- max-offset-y) max-offset-y) + curr-offset-x (+ (get-val pan-x) (get-val pinch-x)) + max-offset-x (utils/get-max-offset width screen-width (get-val scale)) + max-offset-x (if (neg? curr-offset-x) (- max-offset-x) max-offset-x)] + (when (and (> (get-val scale) y-threshold-scale) + (< (get-val scale) c/max-scale) + (> (Math/abs curr-offset-y) (Math/abs max-offset-y))) + (set-val pinch-y (timing c/init-offset)) + (set-val pinch-y-start c/init-offset) + (set-val pan-y (timing max-offset-y)) + (set-val pan-y-start max-offset-y)) + (when (and (> (get-val scale) x-threshold-scale) + (< (get-val scale) c/max-scale) + (> (Math/abs curr-offset-x) (Math/abs max-offset-x))) + (set-val pinch-x (timing c/init-offset)) + (set-val pinch-x-start c/init-offset) + (set-val pan-x (timing max-offset-x)) + (set-val pan-x-start max-offset-x)) + (reset! pan-x-enabled? (> (get-val scale) x-threshold-scale)) + (reset! pan-y-enabled? (> (get-val scale) y-threshold-scale)) + (when platform/android? + (rf/dispatch [:chat.ui/lightbox-scale (get-val saved-scale)])))) + +(defn pinch-gesture + [{: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] :as animations} - {:keys [pan-x-enabled? pan-y-enabled? focal-x focal-y]} + {:keys [focal-x focal-y] :as props} rescale] (-> (gesture/gesture-pinch) (gesture/on-begin (fn [e] (when platform/ios? (reset! focal-x (oget e "focalX")) - (reset! focal-y (oget e "focalY"))))) + (reset! focal-y (utils/get-focal (oget e "focalY") height screen-height))))) (gesture/on-start (fn [e] (when platform/android? - (reset! focal-x (oget e "focalX")) - (reset! focal-y (oget e "focalY"))))) + (reset! focal-x (utils/get-focal (oget e "focalX") width screen-width)) + (reset! focal-y (utils/get-focal (oget e "focalY") height screen-height))))) (gesture/on-update (fn [e] (let [new-scale (* (oget e "scale") (get-val saved-scale)) scale-diff (utils/get-scale-diff new-scale (get-val saved-scale)) - new-pinch-x (utils/get-pinch-position scale-diff width @focal-x) - new-pinch-y (utils/get-pinch-position scale-diff height @focal-y)] + new-pinch-x (utils/get-pinch-position scale-diff screen-width @focal-x) + new-pinch-y (utils/get-pinch-position scale-diff screen-height @focal-y)] (when (and (>= new-scale c/max-scale) (= (get-val pinch-x-max) js/Infinity)) (set-val pinch-x-max (get-val pinch-x)) (set-val pinch-y-max (get-val pinch-y))) @@ -179,29 +212,8 @@ (when (< (get-val scale) x-threshold-scale) (center-x animations false)) (when (< (get-val scale) y-threshold-scale) - (center-y animations false)))))) - (gesture/on-finalize - (fn [] - (let [curr-offset-y (+ (get-val pan-y) (get-val pinch-y)) - max-offset-y (utils/get-max-offset height screen-height (get-val scale)) - max-offset-y (if (neg? curr-offset-y) (- max-offset-y) max-offset-y) - curr-offset-x (+ (get-val pan-x) (get-val pinch-x)) - max-offset-x (utils/get-max-offset width screen-width (get-val scale)) - max-offset-x (if (neg? curr-offset-x) (- max-offset-x) max-offset-x)] - (when (and (> (get-val scale) y-threshold-scale) - (> (Math/abs curr-offset-y) (Math/abs max-offset-y))) - (set-val pinch-y (timing c/init-offset)) - (set-val pinch-y-start c/init-offset) - (set-val pan-y (timing max-offset-y)) - (set-val pan-y-start max-offset-y)) - (when (and (> (get-val scale) x-threshold-scale) - (> (Math/abs curr-offset-x) (Math/abs max-offset-x))) - (set-val pinch-x (timing c/init-offset)) - (set-val pinch-x-start c/init-offset) - (set-val pan-x (timing max-offset-x)) - (set-val pan-x-start max-offset-x)) - (reset! pan-x-enabled? (> (get-val scale) x-threshold-scale)) - (reset! pan-y-enabled? (> (get-val scale) y-threshold-scale))))))) + (center-y animations false)))) + (finalize-pinch dimensions animations props))))) (defn pan-x-gesture [{:keys [width screen-width x-threshold-scale]} @@ -272,55 +284,62 @@ ;;;; Finally, the component (defn zoomable-image [{:keys [image-width image-height content message-id]} index border-radius on-tap] - [:f> - (fn [] - (let [shared-element-id (rf/sub [:shared-element-id]) - exit-lightbox-signal (rf/sub [:lightbox/exit-signal]) - zoom-out-signal (rf/sub [:lightbox/zoom-out-signal]) - curr-orientation (or (rf/sub [:lightbox/orientation]) orientation/portrait) - focused? (= shared-element-id message-id) - dimensions (utils/get-dimensions image-width image-height curr-orientation) - animations {:scale (use-val c/min-scale) - :saved-scale (use-val c/min-scale) - :pan-x-start (use-val c/init-offset) - :pan-x (use-val c/init-offset) - :pan-y-start (use-val c/init-offset) - :pan-y (use-val c/init-offset) - :pinch-x-start (use-val c/init-offset) - :pinch-x (use-val c/init-offset) - :pinch-y-start (use-val c/init-offset) - :pinch-y (use-val c/init-offset) - :pinch-x-max (use-val js/Infinity) - :pinch-y-max (use-val js/Infinity) - :rotate (use-val c/init-rotation) - :rotate-scale (use-val c/min-scale)} - props {:pan-x-enabled? (reagent/atom false) - :pan-y-enabled? (reagent/atom false) - :focal-x (reagent/atom nil) - :focal-y (reagent/atom nil)} - rescale (fn [value exit?] - (rescale-image value exit? dimensions animations props))] - (when platform/ios? - (handle-orientation-change curr-orientation focused? dimensions animations props) - (utils/handle-exit-lightbox-signal exit-lightbox-signal - index - (get-val (:scale animations)) - rescale)) - (utils/handle-zoom-out-signal zoom-out-signal index (get-val (:scale animations)) rescale) - [:f> - (fn [] - (let [tap (tap-gesture on-tap) - double-tap (double-tap-gesture dimensions animations rescale) - pinch (pinch-gesture dimensions animations props rescale) - 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)} - [reanimated/fast-image - {:source {:uri (:image content)} - :native-ID (when focused? :shared-element) - :style (style/image dimensions animations border-radius)}]]]))]))]) + (let [set-full-height? (reagent/atom false)] + [:f> + (fn [] + (let [shared-element-id (rf/sub [:shared-element-id]) + exit-lightbox-signal (rf/sub [:lightbox/exit-signal]) + zoom-out-signal (rf/sub [:lightbox/zoom-out-signal]) + initial-scale (if platform/ios? c/min-scale (rf/sub [:lightbox/scale])) + curr-orientation (or (rf/sub [:lightbox/orientation]) orientation/portrait) + focused? (= shared-element-id message-id) + dimensions (utils/get-dimensions image-width image-height curr-orientation) + animations {:scale (use-val initial-scale) + :saved-scale (use-val initial-scale) + :pan-x-start (use-val c/init-offset) + :pan-x (use-val c/init-offset) + :pan-y-start (use-val c/init-offset) + :pan-y (use-val c/init-offset) + :pinch-x-start (use-val c/init-offset) + :pinch-x (use-val c/init-offset) + :pinch-y-start (use-val c/init-offset) + :pinch-y (use-val c/init-offset) + :pinch-x-max (use-val js/Infinity) + :pinch-y-max (use-val js/Infinity) + :rotate (use-val c/init-rotation) + :rotate-scale (use-val c/min-scale)} + props {:pan-x-enabled? (reagent/atom false) + :pan-y-enabled? (reagent/atom false) + :focal-x (reagent/atom nil) + :focal-y (reagent/atom nil)} + rescale (fn [value exit?] + (rescale-image value exit? dimensions animations props))] + (rn/use-effect-once (fn [] + (js/setTimeout #(reset! set-full-height? true) 500) + js/undefined)) + (when platform/ios? + (handle-orientation-change curr-orientation focused? dimensions animations props) + (utils/handle-exit-lightbox-signal exit-lightbox-signal + index + (get-val (:scale animations)) + rescale + set-full-height?)) + (utils/handle-zoom-out-signal zoom-out-signal index (get-val (:scale animations)) rescale) + [:f> + (fn [] + (let [tap (tap-gesture on-tap) + double-tap (double-tap-gesture dimensions animations rescale) + pinch (pinch-gesture dimensions animations props rescale) + 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?)} + [reanimated/fast-image + {:source {:uri (:image content)} + :native-ID (when focused? :shared-element) + :style (style/image dimensions animations border-radius)}]]]))]))])) + diff --git a/src/status_im2/contexts/chat/messages/content/album/view.cljs b/src/status_im2/contexts/chat/messages/content/album/view.cljs index 56302b73a5..f9f149b59b 100644 --- a/src/status_im2/contexts/chat/messages/content/album/view.cljs +++ b/src/status_im2/contexts/chat/messages/content/album/view.cljs @@ -45,7 +45,6 @@ [rn/touchable-opacity {:key (:message-id item) :active-opacity 1 - ;; issue: https://github.com/status-im/status-mobile/issues/14995 :on-long-press #(on-long-press message context) :on-press (fn [] (rf/dispatch [:chat.ui/update-shared-element-id (:message-id item)]) diff --git a/src/status_im2/contexts/chat/messages/content/image/view.cljs b/src/status_im2/contexts/chat/messages/content/image/view.cljs index 2a27bb46b8..a4c5738ae5 100644 --- a/src/status_im2/contexts/chat/messages/content/image/view.cljs +++ b/src/status_im2/contexts/chat/messages/content/image/view.cljs @@ -21,7 +21,7 @@ [rn/touchable-opacity {:active-opacity 1 :key message-id - :style {:margin-top (when (> index 0) 20)} + :style {:margin-top (when (> index 0) 10)} :on-long-press on-long-press :on-press (fn [] (rf/dispatch [:chat.ui/update-shared-element-id message-id]) diff --git a/src/status_im2/navigation/screens.cljs b/src/status_im2/navigation/screens.cljs index 76c23c69cd..d1370f858e 100644 --- a/src/status_im2/navigation/screens.cljs +++ b/src/status_im2/navigation/screens.cljs @@ -44,11 +44,13 @@ :navigationBar {:backgroundColor colors/black-persist} :animations {:push {:sharedElementTransitions [{:fromId :shared-element :toId :shared-element - :interpolation {:type :decelerate}}]} + :interpolation {:type :decelerate + :factor 1.5}}]} :pop {:sharedElementTransitions [{:fromId :shared-element :toId :shared-element :interpolation {:type - :decelerate}}]}}} + :decelerate + :factor 1.5}}]}}} :component lightbox/lightbox} {:name :photo-selector :options {:topBar {:visible false}} diff --git a/src/status_im2/subs/root.cljs b/src/status_im2/subs/root.cljs index fba978fdcf..14482d2ba1 100644 --- a/src/status_im2/subs/root.cljs +++ b/src/status_im2/subs/root.cljs @@ -115,9 +115,12 @@ (reg-root-key-sub :chats/mention-suggestions :chats/mention-suggestions) (reg-root-key-sub :chat/inputs-with-mentions :chat/inputs-with-mentions) (reg-root-key-sub :chats-home-list :chats-home-list) + +;;lightbox (reg-root-key-sub :lightbox/exit-signal :lightbox/exit-signal) (reg-root-key-sub :lightbox/zoom-out-signal :lightbox/zoom-out-signal) (reg-root-key-sub :lightbox/orientation :lightbox/orientation) +(reg-root-key-sub :lightbox/scale :lightbox/scale) ;;messages (reg-root-key-sub :messages/messages :messages)