diff --git a/package.json b/package.json index 64f86d40f8..c5e1de6fcb 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "react-native-haptic-feedback": "^1.9.0", "react-native-image-crop-picker": "^0.31.1", "react-native-image-resizer": "^1.2.3", + "react-native-image-viewing": "git+https://github.com/Ferossgp/react-native-image-viewing.git#v0.2.1", "react-native-keychain": "git+https://github.com/status-im/react-native-keychain.git#v.3.0.0-5-status", "react-native-languages": "^3.0.2", "react-native-linear-gradient": "^2.5.6", diff --git a/src/quo/react_native.cljs b/src/quo/react_native.cljs index 585c3880a7..72732e6cae 100644 --- a/src/quo/react_native.cljs +++ b/src/quo/react_native.cljs @@ -121,7 +121,7 @@ {:font-scale (.-fontScale window) :height (.-height ^js window) :scale (.-scale ^js window) - :width (.-window ^js window)})) + :width (.-width ^js window)})) (def use-back-handler (.-useBackHandler hooks)) diff --git a/src/status_im/ui/screens/chat/image/preview/views.cljs b/src/status_im/ui/screens/chat/image/preview/views.cljs index 14b8d86cb5..e30761506f 100644 --- a/src/status_im/ui/screens/chat/image/preview/views.cljs +++ b/src/status_im/ui/screens/chat/image/preview/views.cljs @@ -1,39 +1,79 @@ (ns status-im.ui.screens.chat.image.preview.views - (:require-macros [status-im.utils.views :refer [defview letsubs]]) (:require [status-im.ui.components.colors :as colors] [status-im.ui.components.react :as react] + [reagent.core :as reagent] [re-frame.core :as re-frame] [quo.core :as quo] + [quo.platform :as platform] [status-im.i18n :as i18n] [status-im.ui.components.icons.vector-icons :as icons] [status-im.ui.screens.chat.sheets :as sheets] - [quo.components.safe-area :as safe-area])) + [quo.components.safe-area :as safe-area] + ["react-native-image-viewing" :default image-viewing])) -(defview preview-image [] - (letsubs [{:keys [content] :as message} [:get-screen-params] - {:keys [width height]} [:dimensions/window]] - [safe-area/consumer - (fn [insets] - [react/view {:style {:flex 1 :justify-content :flex-end - :padding-top (:top insets) :padding-bottom (:bottom insets) - :background-color colors/black-persist}} - [react/view {:flex 1 :align-items :center :justify-content :center} - [react/image {:style (merge {:width width - :height (- height 200) - :background-color :black}) - :resize-mode :contain - :source {:uri (:image content)}}]] - [react/view {:flex-direction :row :padding-horizontal 8 - :justify-content :space-between :align-items :center} - [react/view {:width 64}] - [quo/button {:on-press #(re-frame/dispatch [:navigate-back]) - :type :secondary - :text-style {:color colors/white-persist}} - (i18n/label :t/close)] - [react/touchable-highlight - {:on-press #(re-frame/dispatch [:bottom-sheet/show-sheet - {:content (sheets/image-long-press message true) - :height 64}])} - [icons/icon :main-icons/more {:container-style {:width 24 :height 24 - :margin 20} - :color colors/white-persist}]]]])])) +(defn footer-options [] + (let [show-sheet (reagent/atom false)] + (fn [{:keys [message on-close]}] + ;; FIXME(Ferossgp): Bottom sheet doesn't work on Android because of https://github.com/software-mansion/react-native-gesture-handler/issues/139 + (if platform/android? + [:<> + [react/touchable-opacity + {:on-press (fn [] + (on-close) + (re-frame/dispatch [:chat.ui/save-image-to-gallery (get-in message [:content :image])])) + :style {:background-color colors/black-transparent-86 + :border-radius 44 + :padding 8 + :position :absolute + :bottom 0 + :right 0}} + [icons/icon :main-icons/download {:container-style {:width 24 + :height 24} + :color colors/white-persist}]]] + [:<> + [react/touchable-opacity + {:on-press #(reset! show-sheet true) + :style {:background-color colors/black-transparent-86 + :border-radius 44 + :padding 8 + :position :absolute + :bottom 0 + :right 0}} + [icons/icon :main-icons/more {:container-style {:width 24 + :height 24} + :color colors/white-persist}]] + ;; NOTE(Ferossgp): If we use global bottom sheet, then it is rendered under the preview + [quo/bottom-sheet {:visible? @show-sheet + :on-cancel #(reset! show-sheet false)} + [sheets/image-long-press message #(do (reset! show-sheet false) + (on-close))]]])))) + +(defn footer [{:keys [on-close] :as props}] + [safe-area/consumer + (fn [insets] + [react/view {:style {:padding-horizontal 24 + :padding-bottom (+ (:bottom insets) 8)}} + [react/view {:style {:justify-content :center + :align-items :center}} + [react/touchable-opacity {:on-press on-close + :style {:background-color colors/black-transparent-86 + :padding-horizontal 24 + :padding-vertical 11 + :border-radius 44}} + [quo/text {:style {:color colors/white-persist}} + (i18n/label :t/close)]] + [footer-options props]]])]) + +(defn preview-image [{{:keys [content] :as message} :message + visible :visible + on-close :on-close}] + [:> image-viewing {:images #js [#js {:uri (:image content)}] + :on-request-close on-close + :hide-header-on-zoom false + :hide-footer-on-zoom false + :swipe-to-close-enabled platform/ios? + :presentation-style "overFullScreen" + :HeaderComponent #(reagent/as-element [:<>]) ; NOTE: Keep it to remove default header + :FooterComponent #(reagent/as-element [footer {:on-close on-close + :message message}]) + :visible visible}]) diff --git a/src/status_im/ui/screens/chat/message/message.cljs b/src/status_im/ui/screens/chat/message/message.cljs index b4b582796c..01ee4059db 100644 --- a/src/status_im/ui/screens/chat/message/message.cljs +++ b/src/status_im/ui/screens/chat/message/message.cljs @@ -15,6 +15,7 @@ [status-im.utils.contenthash :as contenthash] [status-im.utils.security :as security] [status-im.ui.screens.chat.message.reactions :as reactions] + [status-im.ui.screens.chat.image.preview.views :as preview] [quo.core :as quo] [reagent.core :as reagent] [status-im.ui.screens.chat.components.reply :as components.reply] @@ -226,6 +227,7 @@ (defn message-content-image [{:keys [content outgoing] :as message} {:keys [on-long-press]}] (let [dimensions (reagent/atom [260 260]) + visible (reagent/atom false) uri (:image content)] (react/image-get-size uri @@ -236,17 +238,21 @@ style-opts {:outgoing outgoing :width (/ (first @dimensions) k) :height (/ (second @dimensions) k)}] - [react/touchable-highlight {:on-press (fn [] - (when (:image content) - (re-frame/dispatch [:navigate-to :image-preview message])) - (react/dismiss-keyboard!)) - :on-long-press on-long-press} - [react/view {:style (style/image-message style-opts)} - [react/image {:style {:width (/ (first @dimensions) k) - :height (/ (second @dimensions) k)} - :resize-mode :contain - :source {:uri uri}}] - [react/view {:style (style/image-message-border style-opts)}]]])))) + [:<> + [preview/preview-image {:message message + :visible @visible + :on-close #(do (reset! visible false) + (reagent/flush))}] + [react/touchable-highlight {:on-press (fn [] + (reset! visible true) + (react/dismiss-keyboard!)) + :on-long-press on-long-press} + [react/view {:style (style/image-message style-opts)} + [react/image {:style {:width (/ (first @dimensions) k) + :height (/ (second @dimensions) k)} + :resize-mode :contain + :source {:uri uri}}] + [react/view {:style (style/image-message-border style-opts)}]]]])))) (defmulti ->message :content-type) diff --git a/src/status_im/ui/screens/chat/sheets.cljs b/src/status_im/ui/screens/chat/sheets.cljs index 55719cdc45..e3121c830f 100644 --- a/src/status_im/ui/screens/chat/sheets.cljs +++ b/src/status_im/ui/screens/chat/sheets.cljs @@ -141,52 +141,50 @@ :accessibility-label :delete-transaccent-button :on-press #(hide-sheet-and-dispatch [:chat.ui/delete-message chat-id message-id])}]])) -(defn image-long-press [{:keys [content identicon from outgoing cant-be-replied] :as message} from-preview?] - (fn [] - (let [contact-name @(re-frame/subscribe [:contacts/contact-name-by-identity from])] - [react/view - (when-not outgoing - [quo/list-item - {:theme :accent - :icon [chat-icon/contact-icon-contacts-tab - (multiaccounts/displayed-photo {:identicon identicon - :public-key from})] - :title contact-name - :subtitle (i18n/label :t/view-profile) - :accessibility-label :view-chat-details-button - :chevron true - :on-press #(do - (when from-preview? - (re-frame/dispatch [:navigate-back])) - (hide-sheet-and-dispatch [:chat.ui/show-profile from]))}]) - (when-not cant-be-replied - [quo/list-item - {:theme :accent - :title (i18n/label :t/message-reply) - :icon :main-icons/reply - :on-press #(do - (when from-preview? - (re-frame/dispatch [:navigate-back])) - (hide-sheet-and-dispatch [:chat.ui/reply-to-message message]))}]) - ;; we have only base64 string for image, so we need to find a way how to copy it - #_[quo/list-item - {:theme :accent - :title :t/sharing-copy-to-clipboard - :icon :main-icons/copy - :on-press (fn [] - (re-frame/dispatch [:bottom-sheet/hide]) - (react/copy-to-clipboard (:image content)))}] +(defn image-long-press [{:keys [content identicon from outgoing cant-be-replied] :as message} hide] + (let [contact-name @(re-frame/subscribe [:contacts/contact-name-by-identity from])] + [react/view + (when-not outgoing + [quo/list-item + {:theme :accent + :icon [chat-icon/contact-icon-contacts-tab + (multiaccounts/displayed-photo {:identicon identicon + :public-key from})] + :title contact-name + :subtitle (i18n/label :t/view-profile) + :accessibility-label :view-chat-details-button + :chevron true + :on-press #(do + (hide) + (re-frame/dispatch [:chat.ui/show-profile from]))}]) + (when-not cant-be-replied [quo/list-item {:theme :accent - :title (i18n/label :t/save) - :icon :main-icons/download + :title (i18n/label :t/message-reply) + :icon :main-icons/reply + :on-press #(do + (hide) + (re-frame/dispatch [:chat.ui/reply-to-message message]))}]) + ;; we have only base64 string for image, so we need to find a way how to copy it + #_[quo/list-item + {:theme :accent + :title :t/sharing-copy-to-clipboard + :icon :main-icons/copy :on-press (fn [] - (hide-sheet-and-dispatch [:chat.ui/save-image-to-gallery (:image content)]))}] - ;; we have only base64 string for image, so we need to find a way how to share it - #_[quo/list-item - {:theme :accent - :title :t/sharing-share - :icon :main-icons/share - :on-press (fn [] - (re-frame/dispatch [:bottom-sheet/hide]) - (list-selection/open-share {:message (:image content)}))}]]))) + (re-frame/dispatch [:bottom-sheet/hide]) + (react/copy-to-clipboard (:image content)))}] + [quo/list-item + {:theme :accent + :title (i18n/label :t/save) + :icon :main-icons/download + :on-press (fn [] + (hide) + (re-frame/dispatch [:chat.ui/save-image-to-gallery (:image content)]))}] + ;; we have only base64 string for image, so we need to find a way how to share it + #_[quo/list-item + {:theme :accent + :title :t/sharing-share + :icon :main-icons/share + :on-press (fn [] + (re-frame/dispatch [:bottom-sheet/hide]) + (list-selection/open-share {:message (:image content)}))}]])) diff --git a/src/status_im/ui/screens/routing/main.cljs b/src/status_im/ui/screens/routing/main.cljs index ac8989db04..a6fc721d22 100644 --- a/src/status_im/ui/screens/routing/main.cljs +++ b/src/status_im/ui/screens/routing/main.cljs @@ -21,7 +21,6 @@ [status-im.utils.platform :as platform] [quo.previews.main :as quo.preview] [status-im.utils.config :as config] - [status-im.ui.screens.chat.image.preview.views :as image-preview] [status-im.ui.screens.profile.contact.views :as contact] [status-im.ui.screens.notifications-settings.views :as notifications-settings] [status-im.ui.screens.wallet.send.views :as wallet] @@ -122,9 +121,6 @@ {:name :qr-scanner :insets {:top false :bottom false} :component qr-scanner/qr-scanner} - {:name :image-preview - :insets {:top false :bottom false} - :component image-preview/preview-image} {:name :notifications-settings :back-handler :noop :insets {:bottom true} diff --git a/src/status_im/ui/screens/status/views.cljs b/src/status_im/ui/screens/status/views.cljs index 8aefcf94c4..af29dcf21c 100644 --- a/src/status_im/ui/screens/status/views.cljs +++ b/src/status_im/ui/screens/status/views.cljs @@ -13,6 +13,7 @@ [status-im.ui.screens.status.styles :as styles] [status-im.ui.screens.chat.views :as chat.views] [status-im.ui.components.plus-button :as components.plus-button] + [status-im.ui.screens.chat.image.preview.views :as preview] [status-im.ui.screens.chat.photos :as photos] [status-im.ui.components.tabs :as tabs] [status-im.utils.contenthash :as contenthash] @@ -53,13 +54,19 @@ :justify-content :center} [icons/icon :main-icons/close-circle {:color colors/white-persist}]]])]))) -(defn image-message [{:keys [content] :as message}] - [react/touchable-highlight {:on-press (fn [_] - (when (:image content) - (re-frame/dispatch [:navigate-to :image-preview - (assoc message :cant-be-replied true)])) - (react/dismiss-keyboard!))} - [message-content-image (:image content) false]]) +(defn image-message [] + (let [visible (reagent/atom false)] + (fn [{:keys [content] :as message}] + [:<> + [preview/preview-image {:message (assoc message :cant-be-replied true) + :visible @visible + :can-reply false + :on-close #(do (reset! visible false) + (reagent/flush))}] + [react/touchable-highlight {:on-press (fn [_] + (reset! visible true) + (react/dismiss-keyboard!))} + [message-content-image (:image content) false]]]))) (defn message-item [{:keys [content-type content from last-in-group? timestamp identicon outgoing] :as message} timeline? account] [react/view (when last-in-group? @@ -147,4 +154,4 @@ :header [react/view {:height 8}] :footer [react/view {:height 68}]}]) [components.plus-button/plus-button - {:on-press #(re-frame/dispatch [:navigate-to :my-status])}]])) \ No newline at end of file + {:on-press #(re-frame/dispatch [:navigate-to :my-status])}]])) diff --git a/yarn.lock b/yarn.lock index 2375ba0ffe..a3cf43fa42 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6613,6 +6613,10 @@ react-native-image-resizer@^1.2.3: resolved "https://registry.yarnpkg.com/react-native-image-resizer/-/react-native-image-resizer-1.2.3.tgz#21cb2b158ff950e55a0fc01c2cb61375bd5a03ba" integrity sha512-RDPNJglRmWDZ/7hvu+CbpsKYl6AQmseL8cWX4UkLAHxQWNc5ZdYhP/9avC5xCfyiwkRw+Zmkmv78HO0kt0ewhQ== +"react-native-image-viewing@git+https://github.com/Ferossgp/react-native-image-viewing.git#v0.2.1": + version "0.2.1" + resolved "git+https://github.com/Ferossgp/react-native-image-viewing.git#8ef67cdce7b7c66065a939847e45db71347c678e" + react-native-iphone-x-helper@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/react-native-iphone-x-helper/-/react-native-iphone-x-helper-1.2.1.tgz#645e2ffbbb49e80844bb4cbbe34a126fda1e6772"