improve photo-selector and adjust according to the latest designs (#16053)
This commit is contained in:
parent
68e53e05bd
commit
a4bc18ee3f
|
@ -220,10 +220,10 @@
|
|||
only icon
|
||||
[button {:icon true} :i/close-circle]"
|
||||
[_ _]
|
||||
(let [pressed (reagent/atom false)]
|
||||
(let [pressed-in (reagent/atom false)]
|
||||
(fn
|
||||
[{:keys [on-press disabled type size before after above
|
||||
width customization-color override-theme override-background-color
|
||||
[{:keys [on-press disabled type size before after above icon-secondary-no-color
|
||||
width customization-color override-theme override-background-color pressed
|
||||
on-long-press accessibility-label icon icon-no-color style inner-style test-ID]
|
||||
:or {type :primary
|
||||
size 40
|
||||
|
@ -234,17 +234,17 @@
|
|||
[(or
|
||||
override-theme
|
||||
(theme/get-theme)) type])
|
||||
state (cond disabled :disabled
|
||||
@pressed :pressed
|
||||
:else :default)
|
||||
state (cond disabled :disabled
|
||||
(or @pressed-in pressed) :pressed
|
||||
:else :default)
|
||||
icon-size (when (= 24 size) 12)
|
||||
icon-secondary-color (or icon-secondary-color icon-color)]
|
||||
[rn/touchable-without-feedback
|
||||
(merge {:test-ID test-ID
|
||||
:disabled disabled
|
||||
:accessibility-label accessibility-label
|
||||
:on-press-in #(reset! pressed true)
|
||||
:on-press-out #(reset! pressed nil)}
|
||||
:on-press-in #(reset! pressed-in true)
|
||||
:on-press-out #(reset! pressed-in nil)}
|
||||
(when on-press
|
||||
{:on-press on-press})
|
||||
(when on-long-press
|
||||
|
@ -306,5 +306,6 @@
|
|||
[quo2.icons/icon after
|
||||
{:container-style {:margin-left 4
|
||||
:margin-right (if (= size 40) 12 8)}
|
||||
:no-color icon-secondary-no-color
|
||||
:color icon-secondary-color
|
||||
:size icon-size}]])]]]))))
|
||||
|
|
|
@ -1,165 +1,14 @@
|
|||
(ns quo2.components.dropdowns.dropdown
|
||||
(:require [quo2.components.icon :as icons]
|
||||
[quo2.components.markdown.text :as text]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[reagent.core :as reagent]))
|
||||
|
||||
(defn apply-anim
|
||||
[dd-height val]
|
||||
(reanimated/animate-shared-value-with-delay dd-height
|
||||
val
|
||||
300
|
||||
:easing1
|
||||
0))
|
||||
|
||||
(def sizes
|
||||
{:big {:icon-size 20
|
||||
:font {:font-size :paragraph-1}
|
||||
:height 40
|
||||
:padding {:padding-with-icon {:padding-vertical 9
|
||||
:padding-horizontal 12}
|
||||
:padding-with-no-icon {:padding-vertical 9
|
||||
:padding-left 12
|
||||
:padding-right 8}}}
|
||||
:medium {:icon-size 20
|
||||
:font {:font-size :paragraph-1}
|
||||
:height 32
|
||||
:padding {:padding-with-icon {:padding-vertical 5
|
||||
:padding-horizontal 8}
|
||||
:padding-with-no-icon {:padding-vertical 5
|
||||
:padding-left 12
|
||||
:padding-right 8}}}
|
||||
:small {:icon-size 15
|
||||
:font {:font-size :paragraph-2}
|
||||
:height 24
|
||||
:padding {:padding-with-icon {:padding-vertical 3
|
||||
:padding-horizontal 6}
|
||||
:padding-with-no-icon {:padding-vertical 3
|
||||
:padding-horizontal 6}}}})
|
||||
(defn color-by-10
|
||||
[color]
|
||||
(colors/alpha color 0.6))
|
||||
|
||||
(defn dropdown-comp
|
||||
[{:keys [icon dd-height size disabled? dd-color use-border? border-color]}]
|
||||
(let [dark? (colors/dark?)
|
||||
{:keys [width height width-with-icon padding font icon-size]} (size sizes)
|
||||
{:keys [padding-with-icon padding-with-no-icon]} padding
|
||||
font-size (:font-size font)
|
||||
spacing (case size
|
||||
:big 4
|
||||
:medium 2
|
||||
:small 2)
|
||||
open? (reagent/atom false)]
|
||||
(fn []
|
||||
[rn/touchable-opacity
|
||||
(cond->
|
||||
{:on-press (fn []
|
||||
(if (swap! open? not)
|
||||
(apply-anim dd-height 120)
|
||||
(apply-anim dd-height 0)))
|
||||
:style (cond->
|
||||
(merge
|
||||
(if icon
|
||||
padding-with-icon
|
||||
padding-with-no-icon)
|
||||
{:width (if icon
|
||||
width-with-icon
|
||||
width)
|
||||
:height height
|
||||
:border-radius (case size
|
||||
:big 12
|
||||
:medium 10
|
||||
:small 8)
|
||||
:flex-direction :row
|
||||
:align-items :center
|
||||
:background-color (if @open?
|
||||
dd-color
|
||||
(color-by-10 dd-color))})
|
||||
use-border? (assoc :border-width 1
|
||||
:border-color (if @open?
|
||||
border-color
|
||||
(color-by-10 border-color))))}
|
||||
disabled? (assoc-in [:style :opacity] 0.3)
|
||||
disabled? (assoc :disabled true))
|
||||
(when icon
|
||||
[icons/icon icon
|
||||
{:no-color true
|
||||
:size 20
|
||||
:container-style {:margin-right spacing
|
||||
:margin-top 1
|
||||
:width icon-size
|
||||
:height icon-size}}])
|
||||
[text/text
|
||||
{:size font-size
|
||||
:weight :medium
|
||||
:font :font-medium
|
||||
:color :main} "Dropdown"]
|
||||
[icons/icon
|
||||
(if @open?
|
||||
(if dark?
|
||||
:main-icons/pullup-dark
|
||||
:main-icons/pullup)
|
||||
(if dark?
|
||||
:main-icons/dropdown-dark
|
||||
:main-icons/dropdown))
|
||||
{:size 20
|
||||
:no-color true
|
||||
:container-style {:width (+ icon-size 3)
|
||||
:border-radius 20
|
||||
:margin-left (if (= :small size)
|
||||
2
|
||||
4)
|
||||
:margin-top 1
|
||||
:height (+ icon-size 4)}}]])))
|
||||
|
||||
(defn items-comp
|
||||
[{:keys [items on-select]}]
|
||||
(let [items-count (count items)]
|
||||
[rn/scroll-view
|
||||
{:horizontal false
|
||||
:nestedScrollEnabled true}
|
||||
(doall
|
||||
(map-indexed (fn [index item]
|
||||
[rn/touchable-opacity
|
||||
{:key (str item index)
|
||||
:style {:padding 4
|
||||
:border-bottom-width (if (= index (- items-count 1))
|
||||
0
|
||||
1)
|
||||
:border-color (colors/theme-colors
|
||||
colors/neutral-100
|
||||
colors/white)
|
||||
:text-align :center}
|
||||
:on-press #(on-select item)}
|
||||
[text/text {:style {:text-align :center}} item]])
|
||||
items))]))
|
||||
|
||||
(defn- f-dropdown
|
||||
[{:keys [items icon text default-item on-select size disabled? border-color use-border? dd-color]}]
|
||||
(let [dd-height (reanimated/use-shared-value 0)]
|
||||
[rn/view {:style {:flex-grow 1}}
|
||||
[dropdown-comp
|
||||
{:items items
|
||||
:icon icon
|
||||
:disabled? disabled?
|
||||
:size size
|
||||
:dd-color dd-color
|
||||
:text text
|
||||
:border-color (colors/custom-color-by-theme border-color 50 60)
|
||||
:use-border? use-border?
|
||||
:default-item default-item
|
||||
:dd-height dd-height}]
|
||||
[reanimated/view
|
||||
{:style (reanimated/apply-animations-to-style
|
||||
{:height dd-height}
|
||||
{})}
|
||||
[items-comp
|
||||
{:items items
|
||||
:on-select on-select}]]]))
|
||||
(:require [quo2.components.buttons.button :as button]))
|
||||
|
||||
(defn dropdown
|
||||
[params]
|
||||
[:f> f-dropdown params])
|
||||
[_ _]
|
||||
(fn [{:keys [on-change selected] :as opts} children]
|
||||
[button/button
|
||||
(merge
|
||||
opts
|
||||
{:after (if selected :i/pullup :i/dropdown)
|
||||
:icon-secondary-no-color true
|
||||
:pressed selected
|
||||
:on-press #(when on-change (on-change selected))})
|
||||
children]))
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
(ns react-native.cameraroll
|
||||
(:require ["@react-native-community/cameraroll" :as CameraRoll]
|
||||
[utils.transforms :as transforms]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
(defn get-photos
|
||||
[opts callback]
|
||||
(-> (.getPhotos CameraRoll (clj->js opts))
|
||||
(.then #(callback (transforms/js->clj %)))
|
||||
(.catch #(log/warn "could not get camera roll photos" %))))
|
||||
|
||||
(defn get-albums
|
||||
[opts callback]
|
||||
(-> (.getAlbums CameraRoll (clj->js opts))
|
||||
(.then #(callback (transforms/js->clj %)))
|
||||
(.catch #(log/warn "could not get camera roll albums" %))))
|
|
@ -17,6 +17,7 @@
|
|||
(def view (reagent/adapt-react-class (.-View ^js react-native)))
|
||||
(def scroll-view (reagent/adapt-react-class (.-ScrollView ^js react-native)))
|
||||
(def image (reagent/adapt-react-class (.-Image ^js react-native)))
|
||||
(defn image-get-size [uri callback] (.getSize ^js (.-Image ^js react-native) uri callback))
|
||||
(def text (reagent/adapt-react-class (.-Text ^js react-native)))
|
||||
(def text-input (reagent/adapt-react-class (.-TextInput ^js react-native)))
|
||||
|
||||
|
|
|
@ -91,7 +91,7 @@
|
|||
[flat-list
|
||||
(merge props
|
||||
{:data data
|
||||
:render-fn (fn [item]
|
||||
(if (:header? item)
|
||||
(render-section-header-fn item)
|
||||
(render-fn item)))})]))
|
||||
:render-fn (fn [p1 p2 p3 p4]
|
||||
(if (:header? p1)
|
||||
[render-section-header-fn p1 p2 p3 p4]
|
||||
[render-fn p1 p2 p3 p4]))})]))
|
||||
|
|
|
@ -1,47 +1,17 @@
|
|||
(ns status-im.chat.models.images
|
||||
(:require ["@react-native-community/cameraroll" :as CameraRoll]
|
||||
["react-native-blob-util" :default ReactNativeBlobUtil]
|
||||
[clojure.string :as string]
|
||||
[re-frame.core :as re-frame]
|
||||
[utils.i18n :as i18n]
|
||||
[status-im.ui.components.permissions :as permissions]
|
||||
[react-native.permissions :as permissions]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im2.config :as config]
|
||||
[status-im.utils.fs :as fs]
|
||||
[utils.re-frame :as rf]
|
||||
[status-im.utils.image-processing :as image-processing]
|
||||
[status-im.utils.platform :as platform]
|
||||
[status-im.utils.types :as types]
|
||||
[status-im.utils.utils :as utils]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
(def maximum-image-size-px 2000)
|
||||
|
||||
(defn- resize-and-call
|
||||
[uri cb]
|
||||
(react/image-get-size
|
||||
uri
|
||||
(fn [width height]
|
||||
(let [resize? (> (max width height) maximum-image-size-px)]
|
||||
(image-processing/resize
|
||||
uri
|
||||
(if resize? maximum-image-size-px width)
|
||||
(if resize? maximum-image-size-px height)
|
||||
60
|
||||
(fn [^js resized-image]
|
||||
(let [path (.-path resized-image)
|
||||
path (if (string/starts-with? path "file") path (str "file://" path))]
|
||||
(cb {:resized-uri path
|
||||
:width width
|
||||
:height height})))
|
||||
#(log/error "could not resize image" %))))))
|
||||
|
||||
(defn result->id
|
||||
[^js result]
|
||||
(if platform/ios?
|
||||
(.-localIdentifier result)
|
||||
(.-path result)))
|
||||
|
||||
(def temp-image-url (str (fs/cache-dir) "/StatusIm_Image.jpeg"))
|
||||
|
||||
(defn download-image-http
|
||||
|
@ -78,108 +48,6 @@
|
|||
#(re-frame/dispatch [:chat.ui/image-captured current-chat-id (.-path %)])
|
||||
{})))
|
||||
|
||||
(re-frame/reg-fx
|
||||
::chat-open-image-picker
|
||||
(fn [chat-id]
|
||||
(react/show-image-picker
|
||||
(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 chat-id]))
|
||||
(doseq [^js result (if platform/ios?
|
||||
(take config/max-images-batch images)
|
||||
[images])]
|
||||
(resize-and-call (.-path result)
|
||||
#(re-frame/dispatch [:chat.ui/image-selected chat-id (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 [[image chat-id]]
|
||||
(resize-and-call
|
||||
(:uri image)
|
||||
#(re-frame/dispatch [:chat.ui/image-selected chat-id image %]))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
::camera-roll-get-photos
|
||||
(fn [[num end-cursor album]]
|
||||
(permissions/request-permissions
|
||||
{:permissions [:read-external-storage]
|
||||
:on-allowed (fn []
|
||||
(-> (if end-cursor
|
||||
(.getPhotos
|
||||
CameraRoll
|
||||
#js
|
||||
{:first num
|
||||
:after end-cursor
|
||||
:assetType "Photos"
|
||||
:groupTypes (if (= album (i18n/label :t/recent)) "All" "Albums")
|
||||
:groupName (when (not= album (i18n/label :t/recent)) album)
|
||||
:include (clj->js ["imageSize"])})
|
||||
(.getPhotos
|
||||
CameraRoll
|
||||
#js
|
||||
{:first num
|
||||
:assetType "Photos"
|
||||
:groupTypes (if (= album (i18n/label :t/recent)) "All" "Albums")
|
||||
:groupName (when (not= album (i18n/label :t/recent)) album)
|
||||
:include (clj->js ["imageSize"])}))
|
||||
(.then #(let [response (types/js->clj %)]
|
||||
(re-frame/dispatch [:on-camera-roll-get-photos (:edges response)
|
||||
(:page_info response) end-cursor])))
|
||||
(.catch #(log/warn "could not get camera roll photos"))))})))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:chat.ui/camera-roll-get-albums
|
||||
(fn []
|
||||
(let [albums (atom [{:title :smart-albums :data []}
|
||||
{:title (i18n/label :t/my-albums) :data []}])]
|
||||
;; Get the "recent" album first
|
||||
(->
|
||||
(.getPhotos CameraRoll
|
||||
#js
|
||||
{:first 1
|
||||
:groupTypes "All"})
|
||||
(.then
|
||||
(fn [res]
|
||||
(let [recent-album {:title (i18n/label :t/recent)
|
||||
:count "--"
|
||||
:uri (get-in (first (:edges (types/js->clj res))) [:node :image :uri])}]
|
||||
(swap! albums update-in [0 :data] conj recent-album)
|
||||
;; Get albums, then loop over albums and get each one's cover (first photo)
|
||||
(->
|
||||
(.getAlbums CameraRoll #js {:assetType "All"})
|
||||
(.then
|
||||
(fn [response]
|
||||
(let [response (types/js->clj response)]
|
||||
(reduce
|
||||
(fn [_ album]
|
||||
(->
|
||||
(.getPhotos
|
||||
CameraRoll
|
||||
#js
|
||||
{:first 1
|
||||
:groupTypes "Albums"
|
||||
:groupName (:title album)})
|
||||
(.then (fn [res]
|
||||
(let [uri (get-in (first (:edges (types/js->clj res)))
|
||||
[:node :image :uri])]
|
||||
(swap! albums update-in [1 :data] conj (merge album {:uri uri}))
|
||||
(when (= (count (get-in @albums [1 :data])) (count response))
|
||||
(swap! albums update-in
|
||||
[1 :data]
|
||||
#(->> %
|
||||
(sort-by :title)))
|
||||
(re-frame/dispatch [:on-camera-roll-get-albums @albums])))))))
|
||||
nil
|
||||
response))))
|
||||
(.catch #(log/warn "could not get camera roll albums"))))))))))
|
||||
|
||||
|
||||
(rf/defn image-captured
|
||||
{:events [:chat.ui/image-captured]}
|
||||
[{:keys [db]} chat-id uri]
|
||||
|
@ -189,81 +57,17 @@
|
|||
(not (get images uri)))
|
||||
{::image-selected [uri current-chat-id]})))
|
||||
|
||||
(rf/defn on-end-reached
|
||||
{:events [:camera-roll/on-end-reached]}
|
||||
[_ end-cursor selected-album loading? has-next-page?]
|
||||
(when (and (not loading?) has-next-page?)
|
||||
(re-frame/dispatch [:chat.ui/camera-roll-loading-more true])
|
||||
(re-frame/dispatch [:chat.ui/camera-roll-get-photos 20 end-cursor selected-album])))
|
||||
|
||||
(rf/defn camera-roll-get-photos
|
||||
{:events [:chat.ui/camera-roll-get-photos]}
|
||||
[_ num end-cursor selected-album]
|
||||
{::camera-roll-get-photos [num end-cursor selected-album]})
|
||||
|
||||
(rf/defn camera-roll-get-albums
|
||||
{:events [:chat.ui/camera-roll-get-albums]}
|
||||
[_]
|
||||
{:chat.ui/camera-roll-get-albums []})
|
||||
|
||||
(rf/defn camera-roll-loading-more
|
||||
{:events [:chat.ui/camera-roll-loading-more]}
|
||||
[{:keys [db]} is-loading]
|
||||
{:db (assoc db :camera-roll/loading-more is-loading)})
|
||||
|
||||
(rf/defn on-camera-roll-get-photos
|
||||
{:events [:on-camera-roll-get-photos]}
|
||||
[{:keys [db] :as cofx} photos page-info end-cursor]
|
||||
(let [photos_x (when end-cursor (:camera-roll/photos db))]
|
||||
{:db (-> db
|
||||
(assoc :camera-roll/photos (concat photos_x (map #(get-in % [:node :image]) photos)))
|
||||
(assoc :camera-roll/end-cursor (:end_cursor page-info))
|
||||
(assoc :camera-roll/has-next-page (:has_next_page page-info))
|
||||
(assoc :camera-roll/loading-more false))}))
|
||||
|
||||
(rf/defn on-camera-roll-get-albums
|
||||
{:events [:on-camera-roll-get-albums]}
|
||||
[{:keys [db]} albums]
|
||||
{:db (-> db
|
||||
(assoc :camera-roll/albums albums)
|
||||
(assoc :camera-roll/loading-albums false))})
|
||||
|
||||
(rf/defn clear-sending-images
|
||||
{:events [:chat.ui/clear-sending-images]}
|
||||
[{:keys [db]}]
|
||||
{:db (update-in db [:chat/inputs (:current-chat-id db) :metadata] assoc :sending-image {})})
|
||||
|
||||
(rf/defn cancel-sending-image
|
||||
{:events [:chat.ui/cancel-sending-image]}
|
||||
[{:keys [db] :as cofx} chat-id]
|
||||
(clear-sending-images cofx))
|
||||
|
||||
(rf/defn image-selected
|
||||
{:events [:chat.ui/image-selected]}
|
||||
[{:keys [db]} current-chat-id original {:keys [resized-uri width height]}]
|
||||
{:db
|
||||
(update-in db
|
||||
[:chat/inputs current-chat-id :metadata :sending-image (:uri original)]
|
||||
merge
|
||||
original
|
||||
{:resized-uri resized-uri
|
||||
:width width
|
||||
:height height})})
|
||||
|
||||
(rf/defn image-unselected
|
||||
{:events [:chat.ui/image-unselected]}
|
||||
[{: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/defn chat-open-image-picker
|
||||
{:events [:chat.ui/open-image-picker]}
|
||||
[{:keys [db]} chat-id]
|
||||
(let [current-chat-id (or chat-id (:current-chat-id db))
|
||||
images (get-in db [:chat/inputs current-chat-id :metadata :sending-image])]
|
||||
(when (< (count images) config/max-images-batch)
|
||||
{::chat-open-image-picker current-chat-id})))
|
||||
|
||||
(rf/defn chat-show-image-picker-camera
|
||||
{:events [:chat.ui/show-image-picker-camera]}
|
||||
[{:keys [db]} chat-id]
|
||||
|
@ -271,25 +75,3 @@
|
|||
images (get-in db [:chat/inputs current-chat-id :metadata :sending-image])]
|
||||
(when (< (count images) config/max-images-batch)
|
||||
{::chat-open-image-picker-camera current-chat-id})))
|
||||
|
||||
(rf/defn camera-roll-pick
|
||||
{:events [:chat.ui/camera-roll-pick]}
|
||||
[{:keys [db]} image chat-id]
|
||||
(let [current-chat-id (or chat-id (:current-chat-id db))
|
||||
images (get-in db [:chat/inputs current-chat-id :metadata :sending-image])]
|
||||
(if (get-in db [:chats current-chat-id :timeline?])
|
||||
{:db (assoc-in db [:chat/inputs current-chat-id :metadata :sending-image] {})
|
||||
::image-selected [image current-chat-id]}
|
||||
(when (and (< (count images) config/max-images-batch)
|
||||
(not (some #(= (:uri image) (:uri %)) images)))
|
||||
{::image-selected [image current-chat-id]}))))
|
||||
|
||||
(rf/defn camera-roll-select-album
|
||||
{:events [:chat.ui/camera-roll-select-album]}
|
||||
[{:keys [db]} album]
|
||||
{:db (assoc db :camera-roll/selected-album album)})
|
||||
|
||||
(rf/defn save-image-to-gallery
|
||||
{:events [:chat.ui/save-image-to-gallery]}
|
||||
[_ base64-uri]
|
||||
{::save-image-to-gallery base64-uri})
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
status-im.signals.core
|
||||
status-im.stickers.core
|
||||
status-im.transport.core
|
||||
[status-im.ui.components.permissions :as permissions]
|
||||
[react-native.permissions :as permissions]
|
||||
[status-im.ui.components.react :as react]
|
||||
status-im.ui.screens.privacy-and-security-settings.events
|
||||
[status-im.utils.dimensions :as dimensions]
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
(ns status-im.ui.components.permissions
|
||||
(:require ["react-native-permissions" :refer (requestMultiple PERMISSIONS RESULTS)]
|
||||
[status-im.utils.platform :as platform]))
|
||||
|
||||
(def permissions-map
|
||||
{:read-external-storage (cond
|
||||
platform/android? (.-READ_EXTERNAL_STORAGE (.-ANDROID PERMISSIONS)))
|
||||
:write-external-storage (cond
|
||||
platform/low-device? (.-WRITE_EXTERNAL_STORAGE (.-ANDROID PERMISSIONS)))
|
||||
:camera (cond
|
||||
platform/android? (.-CAMERA (.-ANDROID PERMISSIONS))
|
||||
platform/ios? (.-CAMERA (.-IOS PERMISSIONS)))
|
||||
:record-audio (cond
|
||||
platform/android? (.-RECORD_AUDIO (.-ANDROID PERMISSIONS))
|
||||
platform/ios? (.-MICROPHONE (.-IOS PERMISSIONS)))})
|
||||
|
||||
(defn all-granted?
|
||||
[permissions]
|
||||
(let [permission-vals (distinct (vals permissions))]
|
||||
(and (= (count permission-vals) 1)
|
||||
(not (#{(.-BLOCKED RESULTS) (.-DENIED RESULTS)} (first permission-vals))))))
|
||||
|
||||
(defn request-permissions
|
||||
[{:keys [permissions on-allowed on-denied]
|
||||
:or {on-allowed #()
|
||||
on-denied #()}}]
|
||||
(let [permissions (remove nil? (mapv #(get permissions-map %) permissions))]
|
||||
(if (empty? permissions)
|
||||
(on-allowed)
|
||||
(-> (requestMultiple (clj->js permissions))
|
||||
(.then #(if (all-granted? (js->clj %))
|
||||
(on-allowed)
|
||||
(on-denied)))
|
||||
(.catch on-denied)))))
|
|
@ -11,7 +11,7 @@
|
|||
[status-im.ui.components.chat-icon.screen :as chat-icon]
|
||||
[status-im.ui.components.connectivity.view :as connectivity]
|
||||
[status-im.ui.components.icons.icons :as icons]
|
||||
[status-im.ui.components.permissions :as components.permissions]
|
||||
[react-native.permissions :as components.permissions]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui.components.tooltip.views :as tooltip]
|
||||
[status-im.ui.components.webview :as components.webview]
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
(ns status-im2.contexts.chat.events-test
|
||||
(:require [cljs.test :refer-macros [deftest is testing]]
|
||||
[status-im2.contexts.chat.events :as chat]
|
||||
[status-im.chat.models.images :as images]
|
||||
[status-im.utils.clocks :as utils.clocks]))
|
||||
|
||||
(deftest clear-history-test
|
||||
|
@ -90,8 +89,3 @@
|
|||
(testing "Pagination info should be reset on navigation"
|
||||
(let [res (chat/navigate-to-chat {:db db} chat-id)]
|
||||
(is (nil? (get-in res [:db :pagination-info chat-id :all-loaded?])))))))
|
||||
|
||||
(deftest camera-roll-loading-more-test
|
||||
(let [cofx {:db {:camera-roll/loading-more false}}]
|
||||
(is (= {:db {:camera-roll/loading-more true}}
|
||||
(images/camera-roll-loading-more cofx true)))))
|
||||
|
|
|
@ -6,16 +6,16 @@
|
|||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[status-im2.contexts.chat.photo-selector.view :refer [album-title]]
|
||||
[status-im2.contexts.chat.photo-selector.album-selector.style :as style]))
|
||||
|
||||
(defn album
|
||||
[{:keys [title count uri]} index _ selected-album]
|
||||
(defn render-album
|
||||
[{:keys [title count uri]} index _ {:keys [album? selected-album]}]
|
||||
(let [selected? (= selected-album title)]
|
||||
[rn/touchable-opacity
|
||||
{:on-press (fn []
|
||||
(rf/dispatch [:chat.ui/camera-roll-select-album title])
|
||||
(rf/dispatch [:navigate-back]))
|
||||
(rf/dispatch [:photo-selector/get-photos-for-selected-album])
|
||||
(reset! album? false))
|
||||
:style (style/album-container selected?)
|
||||
:accessibility-label (str "album-" index)}
|
||||
[rn/image
|
||||
|
@ -31,7 +31,7 @@
|
|||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40)}}
|
||||
(str count " " (i18n/label :t/images))]]
|
||||
(when count (str count " " (i18n/label :t/images)))]]
|
||||
(when selected?
|
||||
[rn/view
|
||||
{:style {:position :absolute
|
||||
|
@ -39,9 +39,11 @@
|
|||
[quo/icon :i/check
|
||||
{:size 20 :color (colors/theme-colors colors/primary-50 colors/primary-60)}]])]))
|
||||
|
||||
(def no-title "no-title")
|
||||
|
||||
(defn section-header
|
||||
[{:keys [title]}]
|
||||
(when (not= title "smart-albums")
|
||||
(when-not (= title no-title)
|
||||
[quo/divider-label
|
||||
{:label title
|
||||
:container-style style/divider}]))
|
||||
|
@ -51,22 +53,19 @@
|
|||
(str (:title item) index))
|
||||
|
||||
(defn album-selector
|
||||
[{:keys [on-scroll]}]
|
||||
(rf/dispatch [:chat.ui/camera-roll-get-albums])
|
||||
(fn [{:keys [scroll-enabled]}]
|
||||
(let [albums (rf/sub [:camera-roll/albums])
|
||||
selected-album (or (rf/sub [:camera-roll/selected-album]) (i18n/label :t/recent))]
|
||||
[rn/view {:style {:padding-top 20}}
|
||||
[album-title false]
|
||||
[gesture/section-list
|
||||
{:data albums
|
||||
:render-fn album
|
||||
:render-data selected-album
|
||||
:sections albums
|
||||
:sticky-section-headers-enabled false
|
||||
:render-section-header-fn section-header
|
||||
:style {:margin-top 12}
|
||||
:content-container-style {:padding-bottom 40}
|
||||
:key-fn key-fn
|
||||
:scroll-enabled @scroll-enabled
|
||||
:on-scroll on-scroll}]])))
|
||||
[{:keys [scroll-enabled on-scroll]} album? selected-album]
|
||||
(let [albums (rf/sub [:camera-roll/albums])
|
||||
albums-sections [{:title no-title :data (:smart-albums albums)}
|
||||
{:title (i18n/label :t/my-albums) :data (:my-albums albums)}]]
|
||||
[gesture/section-list
|
||||
{:data albums-sections
|
||||
:sections albums-sections
|
||||
:render-data {:album? album? :selected-album selected-album}
|
||||
:render-fn render-album
|
||||
:sticky-section-headers-enabled false
|
||||
:render-section-header-fn section-header
|
||||
:content-container-style {:padding-top 64
|
||||
:padding-bottom 40}
|
||||
:key-fn key-fn
|
||||
:scroll-enabled @scroll-enabled
|
||||
:on-scroll on-scroll}]))
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
(ns status-im2.contexts.chat.photo-selector.events
|
||||
(:require [react-native.cameraroll :as cameraroll]
|
||||
[clojure.string :as string]
|
||||
[re-frame.core :as re-frame]
|
||||
[utils.i18n :as i18n]
|
||||
[react-native.permissions :as permissions]
|
||||
[status-im2.config :as config]
|
||||
[utils.re-frame :as rf]
|
||||
[status-im.utils.image-processing :as image-processing]
|
||||
[taoensso.timbre :as log]
|
||||
[react-native.core :as rn]))
|
||||
|
||||
(def maximum-image-size-px 2000)
|
||||
|
||||
(defn- resize-photo
|
||||
[uri callback]
|
||||
(rn/image-get-size
|
||||
uri
|
||||
(fn [width height]
|
||||
(let [resize? (> (max width height) maximum-image-size-px)]
|
||||
(image-processing/resize
|
||||
uri
|
||||
(if resize? maximum-image-size-px width)
|
||||
(if resize? maximum-image-size-px height)
|
||||
60
|
||||
(fn [^js resized-image]
|
||||
(let [path (.-path resized-image)
|
||||
path (if (string/starts-with? path "file") path (str "file://" path))]
|
||||
(callback {:resized-uri path
|
||||
:width width
|
||||
:height height})))
|
||||
#(log/error "could not resize image" %))))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:camera-roll-request-permissions-and-get-photos
|
||||
(fn [[num end-cursor album]]
|
||||
(permissions/request-permissions
|
||||
{:permissions [:read-external-storage]
|
||||
:on-allowed
|
||||
(fn []
|
||||
(cameraroll/get-photos
|
||||
(merge {:first num
|
||||
:assetType "Photos"
|
||||
:groupTypes (if (= album (i18n/label :t/recent)) "All" "Albums")
|
||||
:groupName (when (not= album (i18n/label :t/recent)) album)
|
||||
:include ["imageSize"]}
|
||||
(when end-cursor
|
||||
{:after end-cursor}))
|
||||
#(re-frame/dispatch [:on-camera-roll-get-photos (:edges %) (:page_info %) end-cursor])))})))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:camera-roll-image-selected
|
||||
(fn [[image chat-id]]
|
||||
(resize-photo (:uri image) #(re-frame/dispatch [:photo-selector/image-selected chat-id image %]))))
|
||||
|
||||
(defn get-albums
|
||||
[callback]
|
||||
(let [albums (atom {:smart-albums []
|
||||
:my-albums []})]
|
||||
;; Get the "recent" album first
|
||||
(cameraroll/get-photos
|
||||
{:first 1 :groupTypes "All"}
|
||||
(fn [res-recent]
|
||||
(swap! albums assoc
|
||||
:smart-albums
|
||||
[{:title (i18n/label :t/recent)
|
||||
:uri (get-in (first (:edges res-recent)) [:node :image :uri])}])
|
||||
;; Get albums, then loop over albums and get each one's cover (first photo)
|
||||
(cameraroll/get-albums
|
||||
{:assetType "All"}
|
||||
(fn [res-albums]
|
||||
(let [response-count (count res-albums)]
|
||||
(if (pos? response-count)
|
||||
(doseq [album res-albums]
|
||||
(cameraroll/get-photos
|
||||
{:first 1 :groupTypes "Albums" :groupName (:title album)}
|
||||
(fn [res]
|
||||
(let [uri (get-in (first (:edges res)) [:node :image :uri])]
|
||||
(swap! albums update :my-albums conj (merge album {:uri uri}))
|
||||
(when (= (count (:my-albums @albums)) response-count)
|
||||
(swap! albums update :my-albums #(sort-by :title %))
|
||||
(callback @albums))))))
|
||||
(callback @albums)))))))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:camera-roll-get-albums
|
||||
(fn []
|
||||
(get-albums #(re-frame/dispatch [:on-camera-roll-get-albums %]))))
|
||||
|
||||
(rf/defn on-camera-roll-get-albums
|
||||
{:events [:on-camera-roll-get-albums]}
|
||||
[{:keys [db]} albums]
|
||||
{:db (assoc db :camera-roll/albums albums)})
|
||||
|
||||
(rf/defn camera-roll-get-albums
|
||||
{:events [:photo-selector/camera-roll-get-albums]}
|
||||
[_]
|
||||
{:camera-roll-get-albums nil})
|
||||
|
||||
(rf/defn camera-roll-select-album
|
||||
{:events [:chat.ui/camera-roll-select-album]}
|
||||
[{:keys [db]} album]
|
||||
{:db (assoc db :camera-roll/selected-album album)})
|
||||
|
||||
(rf/defn image-selected
|
||||
{:events [:photo-selector/image-selected]}
|
||||
[{:keys [db]} current-chat-id original {:keys [resized-uri width height]}]
|
||||
{:db
|
||||
(update-in db
|
||||
[:chat/inputs current-chat-id :metadata :sending-image (:uri original)]
|
||||
merge
|
||||
original
|
||||
{:resized-uri resized-uri
|
||||
:width width
|
||||
:height height})})
|
||||
|
||||
(rf/defn on-camera-roll-get-photos
|
||||
{:events [:on-camera-roll-get-photos]}
|
||||
[{:keys [db]} photos page-info end-cursor]
|
||||
(let [photos_x (when end-cursor (:camera-roll/photos db))]
|
||||
{:db (-> db
|
||||
(assoc :camera-roll/photos (concat photos_x (map #(get-in % [:node :image]) photos)))
|
||||
(assoc :camera-roll/end-cursor (:end_cursor page-info))
|
||||
(assoc :camera-roll/has-next-page (:has_next_page page-info))
|
||||
(assoc :camera-roll/loading-more false))}))
|
||||
|
||||
(rf/defn get-photos-for-selected-album
|
||||
{:events [:photo-selector/get-photos-for-selected-album]}
|
||||
[{:keys [db]} end-cursor]
|
||||
{:camera-roll-request-permissions-and-get-photos [21 end-cursor
|
||||
(or (:camera-roll/selected-album db)
|
||||
(i18n/label :t/recent))]})
|
||||
|
||||
(rf/defn camera-roll-loading-more
|
||||
{:events [:photo-selector/camera-roll-loading-more]}
|
||||
[{:keys [db]} is-loading]
|
||||
{:db (assoc db :camera-roll/loading-more is-loading)})
|
||||
|
||||
(rf/defn camera-roll-pick
|
||||
{:events [:photo-selector/camera-roll-pick]}
|
||||
[{:keys [db]} image chat-id]
|
||||
(let [current-chat-id (or chat-id (:current-chat-id db))
|
||||
images (get-in db [:chat/inputs current-chat-id :metadata :sending-image])]
|
||||
(when (and (< (count images) config/max-images-batch)
|
||||
(not (some #(= (:uri image) (:uri %)) images)))
|
||||
{:camera-roll-image-selected [image current-chat-id]})))
|
|
@ -15,18 +15,13 @@
|
|||
:flex-direction :row
|
||||
:left 0
|
||||
:right 0
|
||||
:top 0
|
||||
:top 20
|
||||
:justify-content :center
|
||||
:z-index 1})
|
||||
|
||||
(defn clear-container
|
||||
[]
|
||||
{:background-color (colors/theme-colors colors/neutral-10 colors/neutral-80)
|
||||
:padding-horizontal 12
|
||||
:padding-vertical 5
|
||||
:border-radius 10
|
||||
:position :absolute
|
||||
:right 20})
|
||||
(def clear-container
|
||||
{:position :absolute
|
||||
:right 20})
|
||||
|
||||
(defn close-button-container
|
||||
[]
|
||||
|
|
|
@ -1,150 +1,126 @@
|
|||
(ns status-im2.contexts.chat.photo-selector.view
|
||||
(:require
|
||||
[react-native.gesture :as gesture]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[react-native.platform :as platform]
|
||||
[status-im2.constants :as constants]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[quo2.components.notifications.info-count :as info-count]
|
||||
[quo2.core :as quo]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[react-native.linear-gradient :as linear-gradient]
|
||||
[reagent.core :as reagent]
|
||||
[status-im2.constants :as constants]
|
||||
[status-im2.contexts.chat.photo-selector.style :as style]
|
||||
[status-im.utils.core :as utils]
|
||||
[quo.react]
|
||||
[utils.re-frame :as rf]))
|
||||
[status-im2.contexts.chat.photo-selector.album-selector.view :as album-selector]
|
||||
utils.collection))
|
||||
|
||||
(defn show-toast
|
||||
[]
|
||||
(rf/dispatch [:toasts/upsert
|
||||
{:id :random-id
|
||||
:icon :info
|
||||
:icon-color colors/danger-50-opa-40
|
||||
:container-style {:top (when platform/ios? 20)}
|
||||
:text (i18n/label :t/only-6-images)}]))
|
||||
|
||||
(defn on-press-confirm-selection
|
||||
[selected]
|
||||
[selected close]
|
||||
(rf/dispatch [:chat.ui/clear-sending-images])
|
||||
(doseq [item @selected]
|
||||
(rf/dispatch [:chat.ui/camera-roll-pick item]))
|
||||
(reset! selected [])
|
||||
(rf/dispatch [:navigate-back]))
|
||||
(doseq [item selected]
|
||||
(rf/dispatch [:photo-selector/camera-roll-pick item]))
|
||||
(close))
|
||||
|
||||
(defn bottom-gradient
|
||||
[selected-images insets selected]
|
||||
(when (or (seq @selected) (seq selected-images))
|
||||
(defn confirm-button
|
||||
[selected-images sending-image close]
|
||||
(when (not= selected-images sending-image)
|
||||
[linear-gradient/linear-gradient
|
||||
{:colors [:black :transparent]
|
||||
:start {:x 0 :y 1}
|
||||
:end {:x 0 :y 0}
|
||||
:style (style/gradient-container (:bottom insets))}
|
||||
:style (style/gradient-container (safe-area/get-bottom))}
|
||||
[quo/button
|
||||
{:style {:align-self :stretch
|
||||
:margin-horizontal 20
|
||||
:margin-top 12}
|
||||
:on-press #(on-press-confirm-selection selected)
|
||||
:on-press #(on-press-confirm-selection selected-images close)
|
||||
:accessibility-label :confirm-selection}
|
||||
(i18n/label :t/confirm-selection)]]))
|
||||
|
||||
(defn clear-button
|
||||
[selected]
|
||||
(when (seq @selected)
|
||||
[rn/touchable-opacity
|
||||
{:on-press #(reset! selected [])
|
||||
:style (style/clear-container)
|
||||
:accessibility-label :clear}
|
||||
[quo/text {:weight :medium} (i18n/label :t/clear)]]))
|
||||
[album? selected]
|
||||
(when (and (not album?) (seq @selected))
|
||||
[rn/view {:style style/clear-container}
|
||||
[quo/button
|
||||
{:type :grey
|
||||
:size 32
|
||||
:accessibility-label :clear
|
||||
:on-press #(reset! selected [])}
|
||||
(i18n/label :t/clear)]]))
|
||||
|
||||
(defn remove-selected
|
||||
[coll item]
|
||||
(vec (remove #(= (:uri item) (:uri %)) coll)))
|
||||
|
||||
(defn image
|
||||
(defn render-image
|
||||
[item index _ {:keys [window-width selected]}]
|
||||
[rn/touchable-opacity
|
||||
{:active-opacity 1
|
||||
:on-press (fn []
|
||||
(if (some #(= (:uri item) (:uri %)) @selected)
|
||||
(swap! selected remove-selected item)
|
||||
(if (>= (count @selected) constants/max-album-photos)
|
||||
(rf/dispatch [:toasts/upsert
|
||||
{:id :random-id
|
||||
:icon :info
|
||||
:icon-color colors/danger-50-opa-40
|
||||
:container-style {:top (when platform/ios? 20)}
|
||||
:text (i18n/label :t/only-6-images)}])
|
||||
(swap! selected conj item))))
|
||||
:accessibility-label (str "image-" index)}
|
||||
[rn/image
|
||||
{:source {:uri (:uri item)}
|
||||
:style (style/image window-width index)}]
|
||||
(when (some #(= (:uri item) (:uri %)) @selected)
|
||||
[rn/view {:style (style/overlay window-width)}])
|
||||
(when (some #(= (:uri item) (:uri %)) @selected)
|
||||
[info-count/info-count
|
||||
{:style style/image-count
|
||||
:accessibility-label (str "count-" index)}
|
||||
(inc (utils/first-index #(= (:uri item) (:uri %)) @selected))])])
|
||||
|
||||
(defn album-title
|
||||
[photos? selected temporary-selected insets close]
|
||||
(fn []
|
||||
(let [selected-album (or (rf/sub [:camera-roll/selected-album]) (i18n/label :t/recent))]
|
||||
[rn/touchable-opacity
|
||||
{:style (style/title-container)
|
||||
:active-opacity 1
|
||||
:accessibility-label :album-title
|
||||
:on-press (fn []
|
||||
;; TODO: album-selector issue:
|
||||
;; https://github.com/status-im/status-mobile/issues/15398
|
||||
(if photos?
|
||||
(do
|
||||
(reset! temporary-selected @selected)
|
||||
(rf/dispatch [:open-modal :album-selector {:insets insets}]))
|
||||
(close)))}
|
||||
[quo/text
|
||||
{:weight :medium
|
||||
:ellipsize-mode :tail
|
||||
:number-of-lines 1
|
||||
:style {:max-width 150}}
|
||||
selected-album]
|
||||
[rn/view {:style (style/chevron-container)}
|
||||
[quo/icon (if photos? :i/chevron-down :i/chevron-up)
|
||||
{:color (colors/theme-colors colors/neutral-100 colors/white)}]]])))
|
||||
(let [item-selected? (some #(= (:uri item) (:uri %)) @selected)]
|
||||
[rn/touchable-opacity
|
||||
{:on-press (fn []
|
||||
(if item-selected?
|
||||
(swap! selected remove-selected item)
|
||||
(if (>= (count @selected) constants/max-album-photos)
|
||||
(show-toast)
|
||||
(swap! selected conj item))))
|
||||
:accessibility-label (str "image-" index)}
|
||||
[rn/image
|
||||
{:source {:uri (:uri item)}
|
||||
:style (style/image window-width index)}]
|
||||
(when item-selected?
|
||||
[:<>
|
||||
[rn/view {:style (style/overlay window-width)}]
|
||||
[info-count/info-count
|
||||
{:style style/image-count
|
||||
:accessibility-label (str "count-" index)}
|
||||
(inc (utils.collection/first-index #(= (:uri item) (:uri %)) @selected))]])]))
|
||||
|
||||
(defn photo-selector
|
||||
[{:keys [scroll-enabled on-scroll close]}]
|
||||
[:f>
|
||||
(let [temporary-selected (reagent/atom [])
|
||||
{:keys [insets]} (rf/sub [:get-screen-params])] ; used when switching albums
|
||||
(fn []
|
||||
(let [selected (reagent/atom []) ; currently selected
|
||||
selected-images (rf/sub [:chats/sending-image])
|
||||
selected-album (or (rf/sub [:camera-roll/selected-album]) (i18n/label :t/recent))]
|
||||
(rn/use-effect
|
||||
(fn []
|
||||
(rf/dispatch [:chat.ui/camera-roll-get-photos 20 nil selected-album])
|
||||
(if (seq selected-images)
|
||||
(reset! selected (vec (vals selected-images)))
|
||||
(reset! selected @temporary-selected)))
|
||||
[selected-album])
|
||||
[:f>
|
||||
(fn []
|
||||
(let [window-width (:width (rn/get-window))
|
||||
camera-roll-photos (rf/sub [:camera-roll/photos])
|
||||
end-cursor (rf/sub [:camera-roll/end-cursor])
|
||||
loading? (rf/sub [:camera-roll/loading-more])
|
||||
has-next-page? (rf/sub [:camera-roll/has-next-page])]
|
||||
[rn/view {:style {:flex 1}}
|
||||
[rn/view
|
||||
{:style style/buttons-container}
|
||||
[album-title true selected temporary-selected insets close]
|
||||
[clear-button selected]]
|
||||
[gesture/flat-list
|
||||
{:key-fn identity
|
||||
:render-fn image
|
||||
:render-data {:window-width window-width :selected selected}
|
||||
:data camera-roll-photos
|
||||
:num-columns 3
|
||||
:content-container-style {:width "100%"
|
||||
:padding-bottom (+ (:bottom insets) 100)
|
||||
:padding-top 64}
|
||||
:on-scroll on-scroll
|
||||
:scroll-enabled @scroll-enabled
|
||||
:on-end-reached #(rf/dispatch [:camera-roll/on-end-reached end-cursor
|
||||
selected-album loading?
|
||||
has-next-page?])}]
|
||||
[bottom-gradient selected-images insets selected]]))])))])
|
||||
[{:keys [scroll-enabled on-scroll close] :as sheet}]
|
||||
(rf/dispatch [:photo-selector/get-photos-for-selected-album])
|
||||
(rf/dispatch [:photo-selector/camera-roll-get-albums])
|
||||
(let [album? (reagent/atom false)
|
||||
sending-image (into [] (vals (rf/sub [:chats/sending-image])))
|
||||
selected-images (reagent/atom sending-image)
|
||||
window-width (:width (rn/get-window))]
|
||||
(fn []
|
||||
(let [camera-roll-photos (rf/sub [:camera-roll/photos])
|
||||
end-cursor (rf/sub [:camera-roll/end-cursor])
|
||||
loading? (rf/sub [:camera-roll/loading-more])
|
||||
has-next-page? (rf/sub [:camera-roll/has-next-page])
|
||||
selected-album (or (rf/sub [:camera-roll/selected-album]) (i18n/label :t/recent))]
|
||||
[rn/view {:style {:flex 1 :margin-top -20}}
|
||||
[rn/view {:style style/buttons-container}
|
||||
[quo/dropdown {:type :grey :size 32 :on-change #(swap! album? not) :selected @album?}
|
||||
selected-album]
|
||||
[clear-button @album? selected-images]]
|
||||
(if @album?
|
||||
[album-selector/album-selector sheet album? selected-album]
|
||||
[:<>
|
||||
[gesture/flat-list
|
||||
{:key-fn identity
|
||||
:render-fn render-image
|
||||
:render-data {:window-width window-width :selected selected-images}
|
||||
:data camera-roll-photos
|
||||
:num-columns 3
|
||||
:content-container-style {:width "100%"
|
||||
:padding-bottom (+ (safe-area/get-bottom) 100)
|
||||
:padding-top 64}
|
||||
:on-scroll on-scroll
|
||||
:scroll-enabled @scroll-enabled
|
||||
:on-end-reached (fn []
|
||||
(when (and (not loading?) has-next-page?)
|
||||
(rf/dispatch [:photo-selector/camera-roll-loading-more true])
|
||||
(rf/dispatch [:photo-selector/get-photos-for-selected-album
|
||||
end-cursor])))}]
|
||||
[confirm-button @selected-images sending-image close]])]))))
|
||||
|
|
|
@ -1,76 +1,78 @@
|
|||
(ns status-im2.contexts.quo-preview.dropdowns.dropdown
|
||||
(:require [quo2.components.dropdowns.dropdown :as quo2]
|
||||
[quo2.foundations.colors :as colors]
|
||||
(:require [quo2.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[status-im2.contexts.quo-preview.preview :as preview]))
|
||||
[status-im2.contexts.quo-preview.preview :as preview]
|
||||
[quo2.core :as quo]))
|
||||
|
||||
(def descriptor
|
||||
[{:label "Icon"
|
||||
:key :icon
|
||||
[{:label "Type:"
|
||||
:key :type
|
||||
:type :select
|
||||
:options [{:key :main-icons/placeholder
|
||||
:value "Placeholder"}
|
||||
{:key :main-icons/locked
|
||||
:value "Wallet"}]}
|
||||
{:label "Disabled"
|
||||
:key :disabled?
|
||||
:type :boolean}
|
||||
{:label "Default item"
|
||||
:key :default-item
|
||||
:type :text}
|
||||
{:label "Use border?"
|
||||
:key :use-border?
|
||||
:type :boolean}
|
||||
{:label "Border color"
|
||||
:key :border-color
|
||||
:type :select
|
||||
:options (map
|
||||
(fn [c]
|
||||
{:key c
|
||||
:value c})
|
||||
(keys colors/customization))}
|
||||
{:label "DD color"
|
||||
:key :dd-color
|
||||
:type :text}
|
||||
{:label "Size"
|
||||
:options [{:key :primary
|
||||
:value "Primary"}
|
||||
{:key :secondary
|
||||
:value "Secondary"}
|
||||
{:key :grey
|
||||
:value "Grey"}
|
||||
{:key :dark-grey
|
||||
:value "Dark Grey"}
|
||||
{:key :outline
|
||||
:value "Outline"}
|
||||
{:key :ghost
|
||||
:value "Ghost"}
|
||||
{:key :danger
|
||||
:value "Danger"}
|
||||
{:key :positive
|
||||
:value "Positive"}]}
|
||||
{:label "Size:"
|
||||
:key :size
|
||||
:type :select
|
||||
:options [{:key :big
|
||||
:value "big"}
|
||||
{:key :medium
|
||||
:value "medium"}
|
||||
{:key :small
|
||||
:value "small"}]}])
|
||||
:options [{:key 56
|
||||
:value "56"}
|
||||
{:key 40
|
||||
:value "40"}
|
||||
{:key 32
|
||||
:value "32"}
|
||||
{:key 24
|
||||
:value "24"}]}
|
||||
{:label "Icon:"
|
||||
:key :icon
|
||||
:type :boolean}
|
||||
{:label "Before icon:"
|
||||
:key :before
|
||||
:type :boolean}
|
||||
{:label "Disabled:"
|
||||
:key :disabled
|
||||
:type :boolean}
|
||||
{:label "Label"
|
||||
:key :label
|
||||
:type :text}])
|
||||
|
||||
(defn cool-preview
|
||||
[]
|
||||
(let [items ["Banana"
|
||||
"Apple"
|
||||
"COVID +18"
|
||||
"Orange"
|
||||
"Kryptonite"
|
||||
"BMW"
|
||||
"Meh"]
|
||||
state (reagent/atom {:icon :main-icons/placeholder
|
||||
:default-item "item1"
|
||||
:use-border? false
|
||||
:dd-color (colors/custom-color :purple 50)
|
||||
:size :big})
|
||||
selected-item (reagent/cursor state [:default-item])
|
||||
on-select #(reset! selected-item %)]
|
||||
(let [state (reagent/atom {:label "Press Me"
|
||||
:size 40})
|
||||
label (reagent/cursor state [:label])
|
||||
before (reagent/cursor state [:before])
|
||||
icon (reagent/cursor state [:icon])]
|
||||
(fn []
|
||||
[rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!}
|
||||
[rn/view {:padding-bottom 150}
|
||||
[preview/customizer state descriptor]
|
||||
[rn/view
|
||||
{:padding-vertical 60
|
||||
:align-items :center}
|
||||
[rn/text (str "Selected item: " @selected-item)]
|
||||
[quo2/dropdown
|
||||
(merge @state
|
||||
{:on-select on-select
|
||||
:items items})]]]])))
|
||||
:flex-direction :row
|
||||
:justify-content :center}
|
||||
[quo/dropdown
|
||||
(merge (dissoc @state
|
||||
:theme
|
||||
:before
|
||||
:after)
|
||||
{:on-press #(println "Hello world!")}
|
||||
(when @before
|
||||
{:before :i/placeholder}))
|
||||
(if @icon :i/placeholder @label)]]]])))
|
||||
|
||||
(defn preview-dropdown
|
||||
[]
|
||||
|
|
|
@ -18,7 +18,8 @@
|
|||
status-im2.contexts.syncing.events
|
||||
status-im2.contexts.chat.events
|
||||
status-im2.common.password-authentication.events
|
||||
status-im2.contexts.communities.overview.events))
|
||||
status-im2.contexts.communities.overview.events
|
||||
status-im2.contexts.chat.photo-selector.events))
|
||||
|
||||
(re-frame/reg-cofx
|
||||
:now
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
[status-im2.contexts.add-new-contact.views :as add-new-contact]
|
||||
[status-im2.contexts.chat.lightbox.view :as lightbox]
|
||||
[status-im2.contexts.chat.messages.view :as chat]
|
||||
[status-im2.contexts.chat.photo-selector.album-selector.view :as album-selector]
|
||||
[status-im2.contexts.chat.photo-selector.view :as photo-selector]
|
||||
[status-im2.contexts.communities.discover.view :as communities.discover]
|
||||
[status-im2.contexts.communities.overview.view :as communities.overview]
|
||||
|
@ -77,10 +76,6 @@
|
|||
:options {:sheet? true}
|
||||
:component photo-selector/photo-selector}
|
||||
|
||||
{:name :album-selector
|
||||
:options {:sheet? true}
|
||||
:component album-selector/album-selector}
|
||||
|
||||
{:name :new-contact
|
||||
:options {:sheet? true}
|
||||
:component add-new-contact/new-contact}
|
||||
|
|
Loading…
Reference in New Issue