From 14c243803f5b1b19e80bd1cc80278b37f0476a59 Mon Sep 17 00:00:00 2001 From: Omar Basem Date: Thu, 24 Nov 2022 15:29:54 +0400 Subject: [PATCH] Photo Selector (1) (#14426) * feat: photo-selector (1) --- .../components/notifications/info_count.cljs | 2 + .../ui/screens/chat/components/input.cljs | 8 +- src/status_im/ui/screens/screens.cljs | 7 +- .../ui2/screens/chat/composer/view.cljs | 71 +++++++----- .../screens/chat/photo_selector/style.cljs | 73 ++++++++++++ .../ui2/screens/chat/photo_selector/view.cljs | 108 ++++++++++++++++++ translations/en.json | 4 +- 7 files changed, 238 insertions(+), 35 deletions(-) create mode 100644 src/status_im/ui2/screens/chat/photo_selector/style.cljs create mode 100644 src/status_im/ui2/screens/chat/photo_selector/view.cljs diff --git a/src/quo2/components/notifications/info_count.cljs b/src/quo2/components/notifications/info_count.cljs index 02edd4a45d..e0a3a1ca43 100644 --- a/src/quo2/components/notifications/info_count.cljs +++ b/src/quo2/components/notifications/info_count.cljs @@ -10,6 +10,8 @@ :position :absolute :right 22 :border-radius 6 + :justify-content :center + :align-items :center :background-color (colors/theme-colors colors/primary-50 colors/primary-60)} style)} [rn/text {:style (merge typography/font-medium typography/label {:color colors/white :text-align :center})} count]])) diff --git a/src/status_im/ui/screens/chat/components/input.cljs b/src/status_im/ui/screens/chat/components/input.cljs index d8668432b0..8942677a2c 100644 --- a/src/status_im/ui/screens/chat/components/input.cljs +++ b/src/status_im/ui/screens/chat/components/input.cljs @@ -380,7 +380,7 @@ contact-request @(re-frame/subscribe [:chats/sending-contact-request])] [rn/view {:style (styles/toolbar) :on-layout on-chat-toolbar-layout} - ;;EXTENSIONS and IMAGE buttons + ;; EXTENSIONS and IMAGE buttons [actions extensions image show-send actions-ref active-panel set-active-panel contact-request] [rn/view {:style (styles/input-container contact-request)} [send-image] @@ -389,14 +389,14 @@ :sending-image sending-image :refs refs :set-active-panel set-active-panel}] - ;;SEND button + ;; SEND button [rn/view {:ref send-ref :style (when-not show-send {:width 0 :right -100})} (when send [send-button #(do (clear-input chat-id refs) (re-frame/dispatch [:chat.ui/send-current-message])) contact-request])] - ;;STICKERS and AUDIO buttons + ;; STICKERS and AUDIO buttons (when-not @(re-frame/subscribe [:chats/edit-message]) [rn/view {:style (merge {:flex-direction :row} (when show-send {:width 0 :right -100})) :ref sticker-ref} @@ -411,4 +411,4 @@ :accessibility-label :show-audio-message-icon :active active-panel :input-focus #(input-focus text-input-ref) - :set-active set-active-panel}])])]]])))) \ No newline at end of file + :set-active set-active-panel}])])]]])))) diff --git a/src/status_im/ui/screens/screens.cljs b/src/status_im/ui/screens/screens.cljs index 9252dd5034..dcb81a6f69 100644 --- a/src/status_im/ui/screens/screens.cljs +++ b/src/status_im/ui/screens/screens.cljs @@ -115,7 +115,8 @@ [status-im.ui.screens.wallet.recipient.views :as recipient] [status-im.ui.screens.wallet.send.views :as wallet.send] [status-im.ui.screens.wallet.manage-connections.views :as manage-all-connections] - [status-im.ui2.screens.chat.group-details.view :as group-details])) + [status-im.ui2.screens.chat.group-details.view :as group-details] + [status-im.ui2.screens.chat.photo-selector.view :as photo-selector])) (defn right-button-options [id icon] {:id id @@ -211,6 +212,10 @@ :options {:topBar {:visible false}} :component pin-messages/pinned-messages} + {:name :photo-selector + :options {:topBar {:visible false}} + :component photo-selector/photo-selector} + {:name :group-chat-profile ;;TODO animated-header :options {:topBar {:visible false}} diff --git a/src/status_im/ui2/screens/chat/composer/view.cljs b/src/status_im/ui2/screens/chat/composer/view.cljs index fbd1c35011..77e2098a49 100644 --- a/src/status_im/ui2/screens/chat/composer/view.cljs +++ b/src/status_im/ui2/screens/chat/composer/view.cljs @@ -12,7 +12,11 @@ [oops.core :refer [oget]] [quo.react] [clojure.string :as string] - [status-im.ui2.screens.chat.composer.mentions :as mentions])) + [status-im.ui2.screens.chat.composer.mentions :as mentions] + [status-im.ui.components.permissions :as permissions] + [status-im.ui2.screens.chat.photo-selector.view :as photo-selector] + [status-im.utils.utils :as utils] + [i18n.i18n :as i18n])) (defn calculate-y [context keyboard-shown min-y max-y added-value] (if keyboard-shown @@ -28,12 +32,12 @@ min-y))) (defn calculate-y-with-mentions [y max-y max-height chat-id suggestions reply] - (let [input-text (:input-text (get ( (fn [] - (let [reply ( keyboard-height 0) keyboard-height 360) (:top insets)) ; 360 - default height - max-height (Math/abs (- max-y 56 (:bottom insets))) ; 56 - top-bar height - added-value (if (and (not (seq suggestions)) reply) 38 0) ; increased height of input box needed when reply - min-y (+ min-y (when reply 38)) - y (get-y-value context keyboard-shown min-y max-y added-value max-height chat-id suggestions reply) - translate-y (reanimated/use-shared-value 0) - shared-height (reanimated/use-shared-value min-y) - bg-opacity (reanimated/use-shared-value 0) + max-y (- window-height (if (> keyboard-height 0) keyboard-height 360) (:top insets)) ; 360 - default height + max-height (Math/abs (- max-y 56 (:bottom insets))) ; 56 - top-bar height + added-value (if (and (not (seq suggestions)) reply) 38 0) ; increased height of input box needed when reply + min-y (+ min-y (when reply 38)) + y (get-y-value context keyboard-shown min-y max-y added-value max-height chat-id suggestions reply) + translate-y (reanimated/use-shared-value 0) + shared-height (reanimated/use-shared-value min-y) + bg-opacity (reanimated/use-shared-value 0) input-content-change (get-input-content-change context translate-y shared-height max-height bg-opacity keyboard-shown min-y max-y) @@ -176,7 +180,16 @@ ;CONTROLS (when-not (seq suggestions) [rn/view {:style (styles/bottom-sheet-controls insets)} - [quo2.button/button {:icon true :type :outline :size 32} :i/image] + [quo2.button/button {:on-press (fn [] + (permissions/request-permissions + {:permissions [:read-external-storage :write-external-storage] + :on-allowed #(re-frame/dispatch [:bottom-sheet/show-sheet + {:content [photo-selector/photo-selector]}]) + :on-denied (fn [] + (utils/set-timeout + #(utils/show-popup (i18n/label :t/error) + (i18n/label :t/external-storage-denied)) 50))})) + :icon true :type :outline :size 32} :i/image] [rn/view {:width 12}] [quo2.button/button {:icon true :type :outline :size 32} :i/reaction] [rn/view {:flex 1}] diff --git a/src/status_im/ui2/screens/chat/photo_selector/style.cljs b/src/status_im/ui2/screens/chat/photo_selector/style.cljs new file mode 100644 index 0000000000..d6d32d3a6e --- /dev/null +++ b/src/status_im/ui2/screens/chat/photo_selector/style.cljs @@ -0,0 +1,73 @@ +(ns status-im.ui2.screens.chat.photo-selector.style + (:require [quo2.foundations.colors :as colors])) + +(defn remove-photo-container [] + {:width 14 + :height 14 + :border-radius 7 + :background-color colors/neutral-50 + :position :absolute + :top -7 + :right -7 + :justify-content :center + :align-items :center}) + +(defn gradient-container [safe-area] + {:width "100%" + :height (+ (:bottom safe-area) 161) + :position :absolute + :bottom 0}) + +(defn buttons-container [safe-area] + {:flex-direction :row + :justify-content :space-between + :padding-horizontal 20 + :bottom (+ (:bottom safe-area) 33)}) + +(defn clear-container [] + {:background-color (colors/theme-colors colors/neutral-10 colors/neutral-80) + :position :absolute + :align-self :flex-end + :padding-horizontal 12 + :padding-vertical 5 + :right 20 + :border-radius 10}) + +(defn camera-button-container [] + {:background-color (colors/theme-colors colors/neutral-10 colors/neutral-80) + :width 32 + :height 32 + :border-radius 10 + :justify-content :center + :align-items :center + :margin-left 20 + :margin-bottom 24}) + +(defn chevron-container [] + {:background-color (colors/theme-colors colors/neutral-10 colors/neutral-80) + :width 14 + :height 14 + :border-radius 7 + :justify-content :center + :align-items :center + :margin-left 7 + :margin-top 4}) + +(defn image [window-width index] + {:width (- (/ window-width 3) 0.67) + :height (/ window-width 3) + :margin-left (when (not= (mod index 3) 0) 1) + :margin-bottom 1}) + +(defn overlay [window-width] + {:position :absolute + :width (- (/ window-width 3) 0.67) + :height (/ window-width 3) + :background-color (colors/theme-colors colors/white-opa-40 colors/neutral-80-opa-40)}) + +(defn image-count [] + {:width 24 + :height 24 + :border-radius 8 + :top 8 + :right 8}) diff --git a/src/status_im/ui2/screens/chat/photo_selector/view.cljs b/src/status_im/ui2/screens/chat/photo_selector/view.cljs new file mode 100644 index 0000000000..0c1b2a5ced --- /dev/null +++ b/src/status_im/ui2/screens/chat/photo_selector/view.cljs @@ -0,0 +1,108 @@ +(ns status-im.ui2.screens.chat.photo-selector.view + (:require [react-native.core :as rn] + [quo2.foundations.colors :as colors] + [quo.components.safe-area :as safe-area] + [quo2.core :as quo2] + [i18n.i18n :as i18n] + [utils.re-frame :as rf] + [reagent.core :as reagent] + [quo2.components.notifications.info-count :as info-count] + [react-native.linear-gradient :as linear-gradient] + [status-im.ui2.screens.chat.photo-selector.style :as style] + [status-im.utils.core :as utils])) + +(def selected (reagent/atom [])) + +(defn small-image [item] + [rn/view + [rn/image {:source {:uri item} + :style {:width 56 + :height 56 + :border-radius 8 + :margin-bottom 20}}] + [rn/touchable-opacity + {:on-press (fn [] (reset! selected (vec (remove #(= % item) @selected)))) + :style (style/remove-photo-container)} + [quo2/icon :i/close {:color colors/white :size 12}]]]) + +(defn bottom-gradient [] + [:f> + (fn [] + (let [safe-area (safe-area/use-safe-area)] + (when (pos? (count @selected)) + [linear-gradient/linear-gradient + {:colors [:black :transparent] + :start {:x 0 :y 1} + :end {:x 0 :y 0} + :style (style/gradient-container safe-area)} + [rn/flat-list {:key-fn (fn [item] item) + :render-fn small-image + :data @selected + :horizontal true + :content-container-style {:padding-horizontal 20 :margin-top 12} + :separator [rn/view {:style {:width 12}}]}] + [rn/view {:style (style/buttons-container safe-area)} + [quo2/button {:type :grey + :style {:flex 0.48} + :on-press #(js/alert "Add text: to be implemented")} + (i18n/label :t/add-text)] + [quo2/button {:style {:flex 0.48} + :before :send + :on-press #(do + (rf/dispatch [:chat.ui/send-current-message]) + (reset! selected []) + (rf/dispatch [:bottom-sheet/hide]))} + (str (i18n/label :t/send) " " (when (> (count @selected) 1) (count @selected)))]]])))]) + +(defn clear-button [] + (when (pos? (count @selected)) + [rn/touchable-opacity {:on-press #(reset! selected []) + :style (style/clear-container)} + [quo2/text {:weight :medium} (i18n/label :t/clear)]])) + +(defn image [item index window-width] + [rn/touchable-opacity + {:active-opacity 1 + :on-press (fn [] + (if (some #{item} @selected) + (do + (reset! selected (vec (remove #(= % item) @selected))) + (rf/dispatch [:chat.ui/image-unselected item])) + (do + (swap! selected conj item) + (rf/dispatch [:chat.ui/camera-roll-pick item]))))} + [rn/image {:source {:uri item} + :style (style/image window-width index)}] + (when (some #{item} @selected) + [rn/view {:style (style/overlay window-width)}]) + (when (some #{item} @selected) + [info-count/info-count (+ (utils/first-index #(= item %) @selected) 1) (style/image-count)])]) + +(defn photo-selector [] + (rf/dispatch [:chat.ui/camera-roll-get-photos 20]) + [:f> + (fn [] + (let [{window-height :height + window-width :width} (rn/use-window-dimensions) + safe-area (safe-area/use-safe-area) + camera-roll-photos (rf/sub [:camera-roll-photos])] + [rn/view {:style {:height (- window-height (:top safe-area))}} + [rn/touchable-opacity + {:on-press #(js/alert "Camera: not implemented") + :style (style/camera-button-container)} + [quo2/icon :i/camera {:color (colors/theme-colors colors/neutral-100 colors/white)}]] + [rn/view {:style {:flex-direction :row + :position :absolute + :align-self :center}} + [quo2/text {:weight :medium} (i18n/label :t/recent)] + [rn/view {:style (style/chevron-container)} + [quo2/icon :i/chevron-down {:color (colors/theme-colors colors/neutral-100 colors/white)}]]] + [clear-button] + [rn/flat-list {:key-fn (fn [item] item) + :render-fn (fn [item index] (image item index window-width)) + :data camera-roll-photos + :num-columns 3 + :content-container-style {:width "100%" + :padding-bottom (+ (:bottom safe-area) 100)} + :style {:border-radius 20}}] + [bottom-gradient]]))]) diff --git a/translations/en.json b/translations/en.json index 3886fc139a..1d73e25cbb 100644 --- a/translations/en.json +++ b/translations/en.json @@ -1868,5 +1868,7 @@ "biu": "BIU", "bold": "Bold", "italic": "Italic", - "strikethrough": "Strikethrough" + "strikethrough": "Strikethrough", + "add-text": "Add text", + "send": "Send" }