Add pick multiple images
Add inner border to image message Add max batch size of 5 Disable camera roll more images Use interop instead of aget Add border as a separate layer Signed-off-by: Gheorghe Pinzaru <feross95@gmail.com>
This commit is contained in:
parent
fe5b5ab4bc
commit
cf4bef8268
|
@ -259,8 +259,8 @@ PODS:
|
|||
- React
|
||||
- react-native-splash-screen (3.2.0):
|
||||
- React
|
||||
- react-native-webview (10.3.1):
|
||||
- React
|
||||
- react-native-webview (10.9.2):
|
||||
- React-Core
|
||||
- React-RCTActionSheet (0.62.2):
|
||||
- React-Core/RCTActionSheetHeaders (= 0.62.2)
|
||||
- React-RCTAnimation (0.62.2):
|
||||
|
@ -630,7 +630,7 @@ SPEC CHECKSUMS:
|
|||
react-native-shake: de052eaa3eadc4a326b8ddd7ac80c06e8d84528c
|
||||
react-native-slider: 12bd76d3d568c9c5500825db54123d44b48e4ad4
|
||||
react-native-splash-screen: 200d11d188e2e78cea3ad319964f6142b6384865
|
||||
react-native-webview: 40bbeb6d011226f34cb83f845aeb0fdf515cfc5f
|
||||
react-native-webview: 4e96d493f9f90ba4f03b28933f30b2964df07e39
|
||||
React-RCTActionSheet: f41ea8a811aac770e0cc6e0ad6b270c644ea8b7c
|
||||
React-RCTAnimation: 49ab98b1c1ff4445148b72a3d61554138565bad0
|
||||
React-RCTBlob: a332773f0ebc413a0ce85942a55b064471587a71
|
||||
|
|
|
@ -46,7 +46,8 @@
|
|||
:shadow-01 "rgba(0,9,26,0.12)" ; Main shadow color
|
||||
:backdrop "rgba(0,0,0,0.4)" ; Backdrop for modals and bottom sheet
|
||||
:border-01 "rgba(238,242,245,1)"
|
||||
:border-02 "rgba(67, 96, 223, 0.1)"})
|
||||
:border-02 "rgba(67, 96, 223, 0.1)"
|
||||
:highlight "rgba(67,96,223,0.4)"})
|
||||
|
||||
(def dark-theme
|
||||
{:positive-01 "rgba(68,208,88,1)"
|
||||
|
@ -75,7 +76,8 @@
|
|||
:shadow-01 "rgba(0,0,0,0.75)"
|
||||
:backdrop "rgba(0,0,0,0.4)"
|
||||
:border-01 "rgba(37,37,40,1)"
|
||||
:border-02 "rgba(97,119,229,0.1)"})
|
||||
:border-02 "rgba(97,119,229,0.1)"
|
||||
:highlight "rgba(67,96,223,0.4)"})
|
||||
|
||||
(def theme (reagent/atom light-theme))
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
[status-im.utils.platform :as platform]))
|
||||
|
||||
(def maximum-image-size-px 2000)
|
||||
(def max-images-batch 5)
|
||||
|
||||
(defn- resize-and-call [uri cb]
|
||||
(react/image-get-size
|
||||
|
@ -22,12 +23,17 @@
|
|||
(if resize? maximum-image-size-px width)
|
||||
(if resize? maximum-image-size-px height)
|
||||
60
|
||||
(fn [resized-image]
|
||||
(let [path (aget resized-image "path")
|
||||
(fn [^js resized-image]
|
||||
(let [path (.-path resized-image)
|
||||
path (if (string/starts-with? path "file") path (str "file://" path))]
|
||||
(cb path)))
|
||||
#(log/error "could not resize image" %))))))
|
||||
|
||||
(defn result->id [^js result]
|
||||
(if platform/ios?
|
||||
(.-localIdentifier result)
|
||||
(.-path result)))
|
||||
|
||||
(re-frame/reg-fx
|
||||
::save-image-to-gallery
|
||||
(fn [base64-uri]
|
||||
|
@ -41,8 +47,8 @@
|
|||
width
|
||||
height
|
||||
100
|
||||
(fn [resized-image]
|
||||
(let [path (aget resized-image "path")
|
||||
(fn [^js resized-image]
|
||||
(let [path (.-path resized-image)
|
||||
path (if (string/starts-with? path "file") path (str "file://" path))]
|
||||
(.saveToCameraRoll CameraRoll path)))
|
||||
#(log/error "could not resize image" %)))))))
|
||||
|
@ -51,18 +57,27 @@
|
|||
::chat-open-image-picker
|
||||
(fn []
|
||||
(react/show-image-picker
|
||||
(fn [result]
|
||||
(resize-and-call
|
||||
(aget result "path")
|
||||
#(re-frame/dispatch [:chat.ui/image-selected %])))
|
||||
"photo")))
|
||||
(fn [^js images]
|
||||
;; NOTE(Ferossgp): Because we can't highlight the already selected images inside
|
||||
;; gallery, we just clean previous state and set all newly picked images
|
||||
(when (and platform/ios? (pos? (count images)))
|
||||
(re-frame/dispatch [:chat.ui/clear-sending-images]))
|
||||
(doseq [^js result (if platform/ios?
|
||||
(take max-images-batch images)
|
||||
[images])]
|
||||
(resize-and-call (.-path result)
|
||||
#(re-frame/dispatch [:chat.ui/image-selected (result->id result) %]))))
|
||||
;; NOTE(Ferossgp): On android you cannot set max limit on images, when a user
|
||||
;; selects too many images the app crashes.
|
||||
{:media-type "photo"
|
||||
:multiple platform/ios?})))
|
||||
|
||||
(re-frame/reg-fx
|
||||
::image-selected
|
||||
(fn [uri]
|
||||
(resize-and-call
|
||||
uri
|
||||
#(re-frame/dispatch [:chat.ui/image-selected %]))))
|
||||
#(re-frame/dispatch [:chat.ui/image-selected uri %]))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
::camera-roll-get-photos
|
||||
|
@ -72,7 +87,7 @@
|
|||
:on-allowed (fn []
|
||||
(-> (.getPhotos CameraRoll #js {:first num :assetType "Photos" :groupTypes "All"})
|
||||
(.then #(re-frame/dispatch [:on-camera-roll-get-photos (:edges (types/js->clj %))]))
|
||||
(.catch #(log/error "could not get cameraroll photos"))))})))
|
||||
(.catch #(log/warn "could not get cameraroll photos"))))})))
|
||||
|
||||
(fx/defn image-captured
|
||||
{:events [:chat.ui/image-captured]}
|
||||
|
@ -89,27 +104,46 @@
|
|||
[{db :db} photos]
|
||||
{:db (assoc db :camera-roll-photos (mapv #(get-in % [:node :image :uri]) photos))})
|
||||
|
||||
(fx/defn cancel-sending-image
|
||||
{:events [:chat.ui/cancel-sending-image]}
|
||||
(fx/defn clear-sending-images
|
||||
{:events [:chat.ui/clear-sending-images]}
|
||||
[{:keys [db]}]
|
||||
(let [current-chat-id (:current-chat-id db)]
|
||||
{:db (update-in db [:chats current-chat-id :metadata] dissoc :sending-image)}))
|
||||
{:db (update-in db [:chats current-chat-id :metadata] assoc :sending-image {})}))
|
||||
|
||||
(fx/defn cancel-sending-image
|
||||
{:events [:chat.ui/cancel-sending-image]}
|
||||
[cofx]
|
||||
(clear-sending-images cofx))
|
||||
|
||||
(fx/defn image-selected
|
||||
{:events [:chat.ui/image-selected]}
|
||||
[{:keys [db]} uri]
|
||||
[{:keys [db]} original uri]
|
||||
(let [current-chat-id (:current-chat-id db)]
|
||||
{:db (assoc-in db [:chats current-chat-id :metadata :sending-image :uri] uri)}))
|
||||
{:db (update-in db [:chats current-chat-id :metadata :sending-image original] merge {:uri uri})}))
|
||||
|
||||
(fx/defn image-unselected
|
||||
{:events [:chat.ui/image-unselected]}
|
||||
[{:keys [db]} original]
|
||||
(let [current-chat-id (:current-chat-id db)]
|
||||
{:db (update-in db [:chats current-chat-id :metadata :sending-image] dissoc original)}))
|
||||
|
||||
(fx/defn chat-open-image-picker
|
||||
{:events [:chat.ui/open-image-picker]}
|
||||
[_]
|
||||
{::chat-open-image-picker nil})
|
||||
[{:keys [db]}]
|
||||
(let [current-chat-id (:current-chat-id db)
|
||||
images (get-in db [:chats current-chat-id :metadata :sending-image])]
|
||||
(when (< (count images) max-images-batch)
|
||||
{::chat-open-image-picker nil})))
|
||||
|
||||
(fx/defn camera-roll-pick
|
||||
{:events [:chat.ui/camera-roll-pick]}
|
||||
[_ uri]
|
||||
{::image-selected uri})
|
||||
[{:keys [db]} uri]
|
||||
(let [current-chat-id (:current-chat-id db)
|
||||
images (get-in db [:chats current-chat-id :metadata :sending-image])]
|
||||
(when (and (< (count images) max-images-batch)
|
||||
(not (get images uri)))
|
||||
{:db (update-in db [:chats current-chat-id :metadata :sending-image] assoc uri {:uri uri})
|
||||
::image-selected uri})))
|
||||
|
||||
(fx/defn save-image-to-gallery
|
||||
{:events [:chat.ui/save-image-to-gallery]}
|
||||
|
|
|
@ -133,14 +133,17 @@
|
|||
|
||||
(fx/defn send-image
|
||||
[{{:keys [current-chat-id] :as db} :db :as cofx}]
|
||||
(let [image-path (get-in db [:chats current-chat-id :metadata :sending-image :uri])]
|
||||
(let [images (get-in db [:chats current-chat-id :metadata :sending-image])]
|
||||
(fx/merge cofx
|
||||
;; NOTE(Ferossgp): Ideally here and for all other types of message we should dissoc on success only
|
||||
{:db (update-in db [:chats current-chat-id :metadata] dissoc :sending-image)}
|
||||
(when-not (string/blank? image-path)
|
||||
(chat.message/send-message {:chat-id current-chat-id
|
||||
:content-type constants/content-type-image
|
||||
:image-path (utils/safe-replace image-path #"file://" "")
|
||||
:text (i18n/label :t/update-to-see-image)})))))
|
||||
(chat.message/send-messages
|
||||
(map (fn [[_ {:keys [uri]}]]
|
||||
{:chat-id current-chat-id
|
||||
:content-type constants/content-type-image
|
||||
:image-path (utils/safe-replace uri #"file://" "")
|
||||
:text (i18n/label :t/update-to-see-image)})
|
||||
images)))))
|
||||
|
||||
(fx/defn send-my-status-message
|
||||
"when not empty, proceed by sending text message with public key topic"
|
||||
|
|
|
@ -233,8 +233,12 @@
|
|||
(rebuild-message-list chat-id)))
|
||||
|
||||
(fx/defn send-message
|
||||
[{:keys [db now] :as cofx} {:keys [chat-id] :as message}]
|
||||
(protocol/send-chat-message cofx message))
|
||||
[{:keys [db now] :as cofx} message]
|
||||
(protocol/send-chat-messages cofx [message]))
|
||||
|
||||
(fx/defn send-messages
|
||||
[{:keys [db now] :as cofx} messages]
|
||||
(protocol/send-chat-messages cofx messages))
|
||||
|
||||
(fx/defn toggle-expand-message
|
||||
[{:keys [db]} chat-id message-id]
|
||||
|
|
|
@ -5,31 +5,31 @@
|
|||
[status-im.utils.fx :as fx]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
(fx/defn send-chat-message [cofx {:keys [chat-id
|
||||
text
|
||||
response-to
|
||||
ens-name
|
||||
image-path
|
||||
audio-path
|
||||
audio-duration-ms
|
||||
message-type
|
||||
sticker
|
||||
content-type]
|
||||
:as message}]
|
||||
{::json-rpc/call [{:method (json-rpc/call-ext-method
|
||||
"sendChatMessage")
|
||||
:params [{:chatId chat-id
|
||||
:text text
|
||||
:responseTo response-to
|
||||
:ensName ens-name
|
||||
:imagePath image-path
|
||||
:audioPath audio-path
|
||||
:audioDurationMs audio-duration-ms
|
||||
:sticker sticker
|
||||
:contentType content-type}]
|
||||
:on-success
|
||||
#(re-frame/dispatch [:transport/message-sent % 1])
|
||||
:on-failure #(log/error "failed to send a message" %)}]})
|
||||
(defn build-message [{:keys [chat-id
|
||||
text
|
||||
response-to
|
||||
ens-name
|
||||
image-path
|
||||
audio-path
|
||||
audio-duration-ms
|
||||
sticker
|
||||
content-type]}]
|
||||
{:method (json-rpc/call-ext-method "sendChatMessage")
|
||||
:params [{:chatId chat-id
|
||||
:text text
|
||||
:responseTo response-to
|
||||
:ensName ens-name
|
||||
:imagePath image-path
|
||||
:audioPath audio-path
|
||||
:audioDurationMs audio-duration-ms
|
||||
:sticker sticker
|
||||
:contentType content-type}]
|
||||
:on-success
|
||||
#(re-frame/dispatch [:transport/message-sent % 1])
|
||||
:on-failure #(log/error "failed to send a message" %)})
|
||||
|
||||
(fx/defn send-chat-messages [cofx messages]
|
||||
{::json-rpc/call (mapv build-message messages)})
|
||||
|
||||
(fx/defn send-reaction [cofx {:keys [message-id chat-id emoji-id]}]
|
||||
{::json-rpc/call [{:method (json-rpc/call-ext-method
|
||||
|
|
|
@ -6,13 +6,14 @@
|
|||
{:read-external-storage (cond
|
||||
platform/android? (.-READ_EXTERNAL_STORAGE (.-ANDROID PERMISSIONS)))
|
||||
:write-external-storage (cond
|
||||
platform/android? (.-WRITE_EXTERNAL_STORAGE (.-ANDROID PERMISSIONS)))
|
||||
platform/android? (.-WRITE_EXTERNAL_STORAGE (.-ANDROID PERMISSIONS))
|
||||
platform/ios? (.-PHOTO_LIBRARY (.-IOS PERMISSIONS)))
|
||||
:camera (cond
|
||||
platform/android? (.-CAMERA (.-ANDROID PERMISSIONS))
|
||||
platform/ios? (.-CAMERA (.-IOS PERMISSIONS)))
|
||||
platform/ios? (.-CAMERA (.-IOS PERMISSIONS)))
|
||||
:record-audio (cond
|
||||
platform/android? (.-RECORD_AUDIO (.-ANDROID PERMISSIONS))
|
||||
platform/ios? (.-MICROPHONE (.-IOS PERMISSIONS)))})
|
||||
platform/ios? (.-MICROPHONE (.-IOS PERMISSIONS)))})
|
||||
|
||||
(defn all-granted? [permissions]
|
||||
(let [permission-vals (distinct (vals permissions))]
|
||||
|
|
|
@ -192,9 +192,9 @@
|
|||
(defn show-image-picker
|
||||
([images-fn]
|
||||
(show-image-picker images-fn nil))
|
||||
([images-fn media-type]
|
||||
([images-fn {:keys [multiple media-type]}]
|
||||
(-> ^js image-picker
|
||||
(.openPicker (clj->js {:multiple false :mediaType (or media-type "any")}))
|
||||
(.openPicker (clj->js {:multiple multiple :mediaType (or media-type "any")}))
|
||||
(.then images-fn)
|
||||
(.catch show-access-error))))
|
||||
|
||||
|
|
|
@ -287,7 +287,7 @@
|
|||
{:style (styles/input-container)}
|
||||
(when reply
|
||||
[reply/reply-message reply])
|
||||
(when sending-image
|
||||
(when (seq sending-image)
|
||||
[reply/send-image sending-image])
|
||||
[rn/view {:style (styles/input-row)}
|
||||
[text-input props]
|
||||
|
|
|
@ -71,13 +71,17 @@
|
|||
[icons/icon :main-icons/close-circle {:container-style (styles/close-button)
|
||||
:color (:icon-01 @colors/theme)}]]]]))
|
||||
|
||||
(defn send-image [{:keys [uri]}]
|
||||
(defn send-image [images]
|
||||
[rn/view {:style (styles/reply-container true)}
|
||||
[rn/view {:style (styles/reply-content)}
|
||||
[rn/image {:source {:uri uri}
|
||||
:style {:width 56
|
||||
:height 56
|
||||
:border-radius 4}}]]
|
||||
[rn/scroll-view {:horizontal true
|
||||
:style (styles/reply-content)}
|
||||
(for [{:keys [uri]} (vals images)]
|
||||
^{:key uri}
|
||||
[rn/image {:source {:uri uri}
|
||||
:style {:width 56
|
||||
:height 56
|
||||
:border-radius 4
|
||||
:margin-right 4}}])]
|
||||
[rn/view
|
||||
[pressable/pressable {:on-press #(re-frame/dispatch [:chat.ui/cancel-sending-image])
|
||||
:accessibility-label :cancel-send-image}
|
||||
|
|
|
@ -2,13 +2,24 @@
|
|||
(:require-macros [status-im.utils.views :refer [defview letsubs]])
|
||||
(:require [status-im.ui.components.react :as react]
|
||||
[status-im.ui.components.icons.vector-icons :as icons]
|
||||
[status-im.ui.components.permissions :as permissions]
|
||||
[reagent.core :as reagent]
|
||||
[quo.components.animated.pressable :as pressable]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.ui.components.colors :as colors]))
|
||||
[quo.design-system.colors :as colors]
|
||||
[status-im.chat.models.images :as images]
|
||||
[quo.core :as quo]))
|
||||
|
||||
(defn take-picture []
|
||||
(react/show-image-picker-camera #(re-frame/dispatch [:chat.ui/image-captured (.-path %)]) {}))
|
||||
(permissions/request-permissions
|
||||
{:permissions [:camera]
|
||||
:on-allowed (fn []
|
||||
(react/show-image-picker-camera #(re-frame/dispatch [:chat.ui/image-captured (.-path %)]) {}))}))
|
||||
|
||||
(defn show-image-picker []
|
||||
(permissions/request-permissions
|
||||
{:permissions [:read-external-storage :write-external-storage]
|
||||
:on-allowed #(re-frame/dispatch [:chat.ui/open-image-picker])}))
|
||||
|
||||
(defn buttons []
|
||||
[react/view
|
||||
|
@ -18,26 +29,48 @@
|
|||
[react/view {:style {:padding 10}}
|
||||
[icons/icon :main-icons/camera]]]
|
||||
[react/view {:style {:padding-top 8}}
|
||||
[pressable/pressable {:on-press #(re-frame/dispatch [:chat.ui/open-image-picker])
|
||||
[pressable/pressable {:on-press show-image-picker
|
||||
:accessibility-label :open-gallery
|
||||
:type :scale}
|
||||
[react/view {:style {:padding 10}}
|
||||
[icons/icon :main-icons/gallery]]]]])
|
||||
|
||||
(defn image-preview [uri first? panel-height]
|
||||
(let [wh (/ (- panel-height 8) 2)]
|
||||
[react/touchable-highlight {:on-press #(re-frame/dispatch [:chat.ui/camera-roll-pick uri])}
|
||||
[react/image {:style (merge {:width wh
|
||||
:height wh
|
||||
:background-color :black
|
||||
:resize-mode :cover
|
||||
:border-radius 4}
|
||||
(when first?
|
||||
{:margin-bottom 8}))
|
||||
:source {:uri uri}}]]))
|
||||
(defn image-preview [uri all-selected first? panel-height]
|
||||
(let [wh (/ (- panel-height 8) 2)
|
||||
selected (get all-selected uri)
|
||||
max-selected (>= (count all-selected) images/max-images-batch)]
|
||||
[react/touchable-highlight {:on-press #(if selected
|
||||
(re-frame/dispatch [:chat.ui/image-unselected uri])
|
||||
(re-frame/dispatch [:chat.ui/camera-roll-pick uri]))
|
||||
:disabled (and max-selected (not selected))}
|
||||
[react/view {:style (merge {:width wh
|
||||
:height wh
|
||||
:border-radius 4
|
||||
:overflow :hidden}
|
||||
(when (and (not selected) max-selected)
|
||||
{:opacity 0.5})
|
||||
(when first?
|
||||
{:margin-bottom 4}))}
|
||||
[react/image {:style (merge {:width wh
|
||||
:height wh
|
||||
:background-color :black
|
||||
:resize-mode :cover
|
||||
:border-radius 4})
|
||||
:source {:uri uri}}]
|
||||
(when selected
|
||||
[react/view {:style {:position :absolute
|
||||
:top 0
|
||||
:bottom 0
|
||||
:left 0
|
||||
:right 0
|
||||
:padding 10
|
||||
:background-color (:highlight @colors/theme)
|
||||
:align-items :flex-end}}
|
||||
[quo/radio {:value true}]])]]))
|
||||
|
||||
(defview photos []
|
||||
(letsubs [camera-roll-photos [:camera-roll-photos]
|
||||
selected [:chats/sending-image]
|
||||
panel-height (reagent/atom nil)]
|
||||
[react/view {:style {:flex 1
|
||||
:flex-direction :row}
|
||||
|
@ -45,16 +78,18 @@
|
|||
(let [height @panel-height]
|
||||
(for [[first-img second-img] (partition 2 camera-roll-photos)]
|
||||
^{:key (str "image" first-img)}
|
||||
[react/view {:margin-left 8}
|
||||
[react/view {:margin-left 4}
|
||||
(when first-img
|
||||
[image-preview first-img true height])
|
||||
[image-preview first-img selected true height])
|
||||
(when second-img
|
||||
[image-preview second-img false height])]))]))
|
||||
[image-preview second-img selected false height])]))]))
|
||||
|
||||
(defview image-view []
|
||||
{:component-did-mount (fn []
|
||||
(re-frame/dispatch [:chat.ui/camera-roll-get-photos 20]))}
|
||||
[react/animated-view {:style {:background-color colors/white
|
||||
(permissions/request-permissions
|
||||
{:permissions [:read-external-storage :write-external-storage]
|
||||
:on-allowed #(re-frame/dispatch [:chat.ui/camera-roll-get-photos 20])}))}
|
||||
[react/animated-view {:style {:background-color (:ui-background @colors/theme)
|
||||
:flex 1}}
|
||||
[react/scroll-view {:horizontal true :style {:flex 1}}
|
||||
[react/view {:flex 1 :flex-direction :row :margin-horizontal 4}
|
||||
|
|
|
@ -218,19 +218,29 @@
|
|||
[react/view (style/delivery-status outgoing)
|
||||
[message-delivery-status message]]])
|
||||
|
||||
(defn message-content-image [{:keys [content outgoing]}]
|
||||
(defn message-content-image [{:keys [content outgoing] :as message} {:keys [on-long-press]}]
|
||||
(let [dimensions (reagent/atom [260 260])
|
||||
uri (:image content)]
|
||||
uri (:image content)]
|
||||
(react/image-get-size
|
||||
uri
|
||||
(fn [width height]
|
||||
(let [k (/ (max width height) 260)]
|
||||
(reset! dimensions [(/ width k) (/ height k)]))))
|
||||
(reset! dimensions [width height])))
|
||||
(fn []
|
||||
[react/view {:style (style/image-content outgoing)}
|
||||
[react/image {:style {:width (first @dimensions) :height (last @dimensions)}
|
||||
:resize-mode :contain
|
||||
:source {:uri uri}}]])))
|
||||
(let [k (/ (max (first @dimensions) (second @dimensions)) 260)
|
||||
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)}]]]))))
|
||||
|
||||
(defmulti ->message :content-type)
|
||||
|
||||
|
@ -372,18 +382,13 @@
|
|||
(defmethod ->message constants/content-type-image [{:keys [content] :as message} {:keys [on-long-press modal]
|
||||
:as reaction-picker}]
|
||||
[message-content-wrapper message
|
||||
[react/touchable-highlight (when-not modal
|
||||
{:on-press (fn [_]
|
||||
(when (:image content)
|
||||
(re-frame/dispatch [:navigate-to :image-preview message]))
|
||||
(react/dismiss-keyboard!))
|
||||
:on-long-press (fn []
|
||||
(on-long-press
|
||||
[{:on-press #(re-frame/dispatch [:chat.ui/reply-to-message message])
|
||||
:label (i18n/label :t/message-reply)}
|
||||
{:on-press #(re-frame/dispatch [:chat.ui/save-image-to-gallery (:image content)])
|
||||
:label (i18n/label :t/save)}]))})
|
||||
[message-content-image message]]
|
||||
[message-content-image message {:modal modal
|
||||
:on-long-press (fn []
|
||||
(on-long-press
|
||||
[{:on-press #(re-frame/dispatch [:chat.ui/reply-to-message message])
|
||||
:label (i18n/label :t/message-reply)}
|
||||
{:on-press #(re-frame/dispatch [:chat.ui/save-image-to-gallery (:image content)])
|
||||
:label (i18n/label :t/save)}]))}]
|
||||
reaction-picker])
|
||||
|
||||
(defmethod ->message constants/content-type-audio [message {:keys [on-long-press modal]
|
||||
|
|
|
@ -301,9 +301,21 @@
|
|||
(outgoing-blockquote-text-style)
|
||||
(default-blockquote-text-style)))
|
||||
|
||||
(defn image-content [outgoing]
|
||||
{:overflow :hidden
|
||||
(defn image-message
|
||||
[{:keys [outgoing width height]}]
|
||||
{:overflow "hidden"
|
||||
:border-top-left-radius 16
|
||||
:border-top-right-radius 16
|
||||
:border-bottom-left-radius (if outgoing 16 4)
|
||||
:border-bottom-right-radius (if outgoing 4 16)})
|
||||
:border-bottom-right-radius (if outgoing 4 16)
|
||||
:width width
|
||||
:height height})
|
||||
|
||||
(defn image-message-border [opts]
|
||||
(merge (image-message opts)
|
||||
{:position :absolute
|
||||
:top 0
|
||||
:left 0
|
||||
:background-color "transparent"
|
||||
:border-width 1
|
||||
:border-color colors/black-transparent}))
|
||||
|
|
Loading…
Reference in New Issue