Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
50759346c4 | ||
|
|
98811e3511 | ||
|
|
818b9e2bdf | ||
|
|
a79c3ad0bf |
@@ -1,8 +1,5 @@
|
||||
(ns legacy.status-im.data-store.communities
|
||||
(:require
|
||||
[clojure.set :as set]
|
||||
[clojure.walk :as walk]
|
||||
[status-im.constants :as constants]))
|
||||
(:require [clojure.set :as set]))
|
||||
|
||||
(defn rpc->channel-permissions
|
||||
[rpc-channels-permissions]
|
||||
@@ -10,66 +7,3 @@
|
||||
(fn [{:keys [viewAndPostPermissions viewOnlyPermissions]}]
|
||||
{:view-only (set/rename-keys viewOnlyPermissions {:satisfied :satisfied?})
|
||||
:view-and-post (set/rename-keys viewAndPostPermissions {:satisfied :satisfied?})})))
|
||||
|
||||
(defn <-revealed-accounts-rpc
|
||||
[accounts]
|
||||
(mapv
|
||||
#(set/rename-keys % {:isAirdropAddress :airdrop-address?})
|
||||
(js->clj accounts :keywordize-keys true)))
|
||||
|
||||
(defn <-request-to-join-community-rpc
|
||||
[r]
|
||||
(set/rename-keys r
|
||||
{:communityId :community-id
|
||||
:publicKey :public-key
|
||||
:chatId :chat-id}))
|
||||
|
||||
(defn <-requests-to-join-community-rpc
|
||||
[requests key-fn]
|
||||
(reduce #(assoc %1 (key-fn %2) (<-request-to-join-community-rpc %2)) {} requests))
|
||||
|
||||
(defn <-chats-rpc
|
||||
[chats]
|
||||
(reduce-kv (fn [acc k v]
|
||||
(assoc acc
|
||||
(name k)
|
||||
(-> v
|
||||
(assoc :can-post? (:canPost v))
|
||||
(dissoc :canPost)
|
||||
(update :members walk/stringify-keys))))
|
||||
{}
|
||||
chats))
|
||||
|
||||
(defn <-categories-rpc
|
||||
[categ]
|
||||
(reduce-kv #(assoc %1 (name %2) %3) {} categ))
|
||||
|
||||
(defn <-rpc
|
||||
[c]
|
||||
(-> c
|
||||
(set/rename-keys {:canRequestAccess :can-request-access?
|
||||
:canManageUsers :can-manage-users?
|
||||
:canDeleteMessageForEveryone :can-delete-message-for-everyone?
|
||||
:canJoin :can-join?
|
||||
:requestedToJoinAt :requested-to-join-at
|
||||
:isMember :is-member?
|
||||
:adminSettings :admin-settings
|
||||
:tokenPermissions :token-permissions
|
||||
:communityTokensMetadata :tokens-metadata
|
||||
:introMessage :intro-message
|
||||
:muteTill :muted-till})
|
||||
(update :admin-settings
|
||||
set/rename-keys
|
||||
{:pinMessageAllMembersEnabled :pin-message-all-members-enabled?})
|
||||
(update :members walk/stringify-keys)
|
||||
(update :chats <-chats-rpc)
|
||||
(update :token-permissions seq)
|
||||
(update :categories <-categories-rpc)
|
||||
(assoc :membership-permissions?
|
||||
(some #(= (:type %) constants/community-token-permission-become-member)
|
||||
(vals (:tokenPermissions c))))
|
||||
(assoc :token-images
|
||||
(reduce (fn [acc {sym :symbol image :image}]
|
||||
(assoc acc sym image))
|
||||
{}
|
||||
(:communityTokensMetadata c)))))
|
||||
|
||||
@@ -6,21 +6,14 @@
|
||||
[react-native.linear-gradient :as linear-gradient]))
|
||||
|
||||
(defn- view-internal
|
||||
[{:keys [customization-color opacity container-style height]
|
||||
:or {customization-color :blue}}]
|
||||
;; `when` added for safety, `linear-gradient` will break if `nil` is passed,
|
||||
;; the `:or` destructuring won't work because it's only applied when the
|
||||
;; `:customization-color` key is non-existent. While deleting an account the key exists
|
||||
;; and has a `nil` value.
|
||||
(when customization-color
|
||||
(let [color-top (colors/resolve-color customization-color 50 20)
|
||||
color-bottom (colors/resolve-color customization-color 50 0)]
|
||||
[linear-gradient/linear-gradient
|
||||
{:accessibility-label :gradient-cover
|
||||
:colors [color-top color-bottom]
|
||||
:start {:x 0 :y 0}
|
||||
:end {:x 0 :y 1}
|
||||
:style (merge (style/root-container opacity height)
|
||||
container-style)}])))
|
||||
[{:keys [customization-color opacity container-style height] :or {customization-color :blue}}]
|
||||
(let [color-top (colors/custom-color customization-color 50 20)
|
||||
color-bottom (colors/custom-color customization-color 50 0)]
|
||||
[linear-gradient/linear-gradient
|
||||
{:accessibility-label :gradient-cover
|
||||
:colors [color-top color-bottom]
|
||||
:start {:x 0 :y 0}
|
||||
:end {:x 0 :y 1}
|
||||
:style (merge (style/root-container opacity height) container-style)}]))
|
||||
|
||||
(def view (quo.theme/with-theme view-internal))
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
[:token {:optional true} [:or keyword? string?]]
|
||||
[:style {:optional true} map?]
|
||||
;; Ignores `token` and uses this as parameter to `rn/image`'s source.
|
||||
[:image-source {:optional true} [:maybe [:or :schema.common/image-source :string]]]]]
|
||||
[:image-source {:optional true} [:or :schema.common/image-source :string]]]]
|
||||
:any])
|
||||
|
||||
(defn- size->number
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
(defn container
|
||||
[network state theme]
|
||||
{:width 136
|
||||
{:flex 1
|
||||
:height 44
|
||||
:border-width 1
|
||||
:border-radius 12
|
||||
|
||||
@@ -10,12 +10,8 @@
|
||||
[react-native.core :as rn]))
|
||||
|
||||
(defn network-bridge-add
|
||||
[{:keys [network state theme container-style on-press]}]
|
||||
[rn/pressable
|
||||
{:style (merge (style/container network state theme)
|
||||
(style/add-container theme)
|
||||
container-style)
|
||||
:on-press on-press}
|
||||
[{:keys [network state theme]}]
|
||||
[rn/view {:style (merge (style/container network state theme) (style/add-container theme))}
|
||||
[icon/icon :i/add-circle {:size 12 :no-color true}]])
|
||||
|
||||
(defn- network->text
|
||||
@@ -25,14 +21,13 @@
|
||||
:else (string/capitalize (name network))))
|
||||
|
||||
(defn view-internal
|
||||
[{:keys [theme network status amount container-style on-press] :as args}]
|
||||
[{:keys [theme network status amount container-style] :as args}]
|
||||
(if (= status :add)
|
||||
[network-bridge-add args]
|
||||
[rn/pressable
|
||||
[rn/view
|
||||
{:style (merge (style/container network status theme) container-style)
|
||||
:accessible true
|
||||
:accessibility-label :container
|
||||
:on-press on-press}
|
||||
:accessibility-label :container}
|
||||
(if (= status :loading)
|
||||
[rn/view
|
||||
{:style (style/loading-skeleton theme)
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
(ns status-im.common.lightbox.events
|
||||
(:require [reagent.core :as reagent]
|
||||
status-im.common.lightbox.effects
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/reg-event-fx :lightbox/navigate-to-lightbox
|
||||
(fn [{:keys [db]} [animation-shared-element-id screen-params]]
|
||||
(reagent/next-tick #(rf/dispatch [:navigate-to :lightbox screen-params]))
|
||||
{:db (assoc db :animation-shared-element-id animation-shared-element-id)}))
|
||||
|
||||
(rf/reg-event-fx :lightbox/update-animation-shared-element-id
|
||||
(fn [{:keys [db]} [animation-shared-element-id]]
|
||||
{:db (assoc db :animation-shared-element-id animation-shared-element-id)}))
|
||||
|
||||
(rf/reg-event-fx :lightbox/exit-lightbox-signal
|
||||
(fn [{:keys [db]} [value]]
|
||||
{:db (assoc db :lightbox/exit-signal value)}))
|
||||
|
||||
(rf/reg-event-fx :lightbox/zoom-out-signal
|
||||
(fn [{:keys [db]} [value]]
|
||||
{:db (assoc db :lightbox/zoom-out-signal value)}))
|
||||
|
||||
(rf/reg-event-fx :lightbox/orientation-change
|
||||
(fn [{:keys [db]} [value]]
|
||||
{:db (assoc db :lightbox/orientation value)}))
|
||||
|
||||
(rf/reg-event-fx :lightbox/lightbox-scale
|
||||
(fn [{:keys [db]} [value]]
|
||||
{:db (assoc db :lightbox/scale value)}))
|
||||
|
||||
(rf/reg-event-fx :lightbox/share-image
|
||||
(fn [_ [uri]]
|
||||
{:effects.lightbox/share-image uri}))
|
||||
|
||||
(rf/reg-event-fx :lightbox/save-image-to-gallery
|
||||
(fn [_ [uri on-success]]
|
||||
{:effects.lightbox/save-image-to-gallery [uri on-success]}))
|
||||
@@ -162,7 +162,3 @@
|
||||
|
||||
(def community-accounts-selection-enabled? false)
|
||||
(def fetch-messages-enabled? (enabled? (get-config :FETCH_MESSAGES_ENABLED "1")))
|
||||
|
||||
(def wallet-feature-flags
|
||||
{:edit-default-keypair false
|
||||
:bridge-token false})
|
||||
|
||||
@@ -4,12 +4,13 @@
|
||||
[legacy.status-im.chat.models.loading :as loading]
|
||||
[legacy.status-im.data-store.chats :as chats-store]
|
||||
[re-frame.core :as re-frame]
|
||||
status-im.common.lightbox.events
|
||||
[reagent.core :as reagent]
|
||||
[status-im.common.muting.helpers :refer [format-mute-till]]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.chat.contacts.events :as contacts-store]
|
||||
status-im.contexts.chat.effects
|
||||
[status-im.contexts.chat.messenger.composer.link-preview.events :as link-preview]
|
||||
status-im.contexts.chat.messenger.lightbox.events
|
||||
status-im.contexts.chat.messenger.messages.content.reactions.events
|
||||
[status-im.contexts.chat.messenger.messages.delete-message-for-me.events :as delete-for-me]
|
||||
[status-im.contexts.chat.messenger.messages.delete-message.events :as delete-message]
|
||||
@@ -393,6 +394,38 @@
|
||||
[cofx chat-id]
|
||||
(navigation/navigate-to cofx :chat-pinned-messages {:chat-id chat-id}))
|
||||
|
||||
|
||||
(rf/defn update-shared-element-id
|
||||
{:events [:chat.ui/update-shared-element-id]}
|
||||
[{:keys [db]} shared-element-id]
|
||||
{:db (assoc db :shared-element-id shared-element-id)})
|
||||
|
||||
(rf/defn navigate-to-lightbox
|
||||
{:events [:chat.ui/navigate-to-lightbox]}
|
||||
[{:keys [db]} shared-element-id screen-params]
|
||||
(reagent/next-tick #(rf/dispatch [:navigate-to :lightbox screen-params]))
|
||||
{:db (assoc db :shared-element-id shared-element-id)})
|
||||
|
||||
(rf/defn exit-lightbox-signal
|
||||
{:events [:chat.ui/exit-lightbox-signal]}
|
||||
[{:keys [db]} value]
|
||||
{:db (assoc db :lightbox/exit-signal value)})
|
||||
|
||||
(rf/defn zoom-out-signal
|
||||
{:events [:chat.ui/zoom-out-signal]}
|
||||
[{:keys [db]} value]
|
||||
{:db (assoc db :lightbox/zoom-out-signal value)})
|
||||
|
||||
(rf/defn orientation-change
|
||||
{:events [:chat.ui/orientation-change]}
|
||||
[{:keys [db]} value]
|
||||
{:db (assoc db :lightbox/orientation value)})
|
||||
|
||||
(rf/defn lightbox-scale
|
||||
{:events [:chat.ui/lightbox-scale]}
|
||||
[{:keys [db]} value]
|
||||
{:db (assoc db :lightbox/scale value)})
|
||||
|
||||
(rf/defn check-last-chat
|
||||
{:events [:chat/check-last-chat]}
|
||||
[{:keys [db]}]
|
||||
@@ -419,15 +452,3 @@
|
||||
{:events [:chat.ui/scroll-to-bottom]}
|
||||
[_]
|
||||
{:effects.chat/scroll-to-bottom nil})
|
||||
|
||||
(rf/reg-event-fx :chat.ui/clear-sending-images
|
||||
(fn [{:keys [db]}]
|
||||
{:db (update-in db [:chat/inputs (:current-chat-id db) :metadata] assoc :sending-image {})}))
|
||||
|
||||
(rf/reg-event-fx :chat.ui/image-unselected
|
||||
(fn [{: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))})))
|
||||
|
||||
@@ -127,8 +127,9 @@
|
||||
(defn change-text
|
||||
"Update `text-value`, update cursor selection, find links, find mentions"
|
||||
[text
|
||||
{:keys [input-ref record-reset-fn]}
|
||||
{:keys [text-value cursor-position recording?]}]
|
||||
{:keys [input-ref record-reset-fn] :as props}
|
||||
{:keys [text-value cursor-position recording?]}
|
||||
scroll-to-end]
|
||||
(reset! text-value text)
|
||||
(reagent/next-tick #(when @input-ref
|
||||
(.setNativeProps ^js @input-ref
|
||||
@@ -140,6 +141,8 @@
|
||||
(rf/dispatch [:chat.ui/set-chat-input-text text])
|
||||
(debounce/debounce-and-dispatch [:link-preview/unfurl-urls text]
|
||||
constants/unfurl-debounce-ms)
|
||||
(when (string/ends-with? text (with-out-str (newline)))
|
||||
(scroll-to-end props))
|
||||
(if (string/ends-with? text "@")
|
||||
(rf/dispatch [:mention/on-change-text text])
|
||||
(debounce/debounce-and-dispatch [:mention/on-change-text text] 300)))
|
||||
|
||||
@@ -69,17 +69,11 @@
|
||||
:min-height constants/input-height})
|
||||
|
||||
(defn input-text
|
||||
[{:keys [saved-emoji-kb-extra-height]}
|
||||
{:keys [focused? maximized?]}
|
||||
{:keys [max-height theme]}]
|
||||
[{:keys [maximized?]}
|
||||
{:keys [theme]}]
|
||||
(assoc typography/paragraph-1
|
||||
:color (colors/theme-colors :black :white theme)
|
||||
:text-align-vertical :top
|
||||
:position (if @saved-emoji-kb-extra-height :relative :absolute)
|
||||
:top 0
|
||||
:left 0
|
||||
:right (when (or focused? platform/ios?) 0)
|
||||
:max-height max-height
|
||||
:padding-bottom (when @maximized? 0)))
|
||||
|
||||
(defn background
|
||||
|
||||
@@ -175,7 +175,8 @@
|
||||
:record-reset-fn (atom nil)
|
||||
:scroll-y (atom 0)
|
||||
:selection-event (atom nil)
|
||||
:selection-manager (rn/selectable-text-input-manager)})
|
||||
:selection-manager (rn/selectable-text-input-manager)
|
||||
:composer-scrollview-ref (atom nil)})
|
||||
|
||||
(defn init-reactive-state
|
||||
[]
|
||||
|
||||
@@ -68,7 +68,14 @@
|
||||
;; Cursor position, needed to determine where to display the mentions view
|
||||
cursor-pos (utils/cursor-y-position-relative-to-container
|
||||
props
|
||||
state)]
|
||||
state)
|
||||
scroll-to-end (fn []
|
||||
;; Needs to be queued, Otherwise might not be called on the right
|
||||
;; time.
|
||||
(js/setTimeout #(when @(:composer-scrollview-ref props)
|
||||
(.scrollToEnd @(:composer-scrollview-ref props)))
|
||||
50))
|
||||
chat-screen-loaded? (rf/sub [:shell/chat-screen-loaded?])]
|
||||
(effects/did-mount props)
|
||||
(effects/initialize props
|
||||
state
|
||||
@@ -90,8 +97,7 @@
|
||||
{:style style/composer-sheet-and-jump-to-container}
|
||||
[sub-view/shell-button state chat-list-scroll-y window-height]
|
||||
[gesture/gesture-detector
|
||||
{:gesture
|
||||
(drag-gesture/drag-gesture props state animations dimensions keyboard-shown)}
|
||||
{:gesture (drag-gesture/drag-gesture props state animations dimensions keyboard-shown)}
|
||||
[reanimated/view
|
||||
{:style (style/sheet-container insets state animations theme)
|
||||
:on-layout #(handler/layout % state blur-height)}
|
||||
@@ -112,36 +118,43 @@
|
||||
{:ref #(reset! (:selectable-input-ref props) %)
|
||||
:menu-items @(:menu-items state)
|
||||
:style (style/input-view state)}
|
||||
[rn/text-input
|
||||
{:ref #(reset! (:input-ref props) %)
|
||||
:default-value @(:text-value state)
|
||||
:on-focus #(handler/focus props state animations dimensions)
|
||||
:on-blur #(handler/blur state animations dimensions subscriptions)
|
||||
:on-content-size-change #(handler/content-size-change %
|
||||
state
|
||||
animations
|
||||
dimensions
|
||||
(or keyboard-shown
|
||||
(:edit subscriptions)))
|
||||
:on-scroll #(handler/scroll % props state animations dimensions)
|
||||
:on-change-text #(handler/change-text % props state)
|
||||
:on-selection-change #(handler/selection-change % props state)
|
||||
:on-selection #(selection/on-selection % props state)
|
||||
:keyboard-appearance (quo.theme/theme-value :light :dark)
|
||||
:max-font-size-multiplier 1
|
||||
:multiline true
|
||||
:placeholder (i18n/label :t/type-something)
|
||||
:placeholder-text-color (colors/theme-colors colors/neutral-40 colors/neutral-50)
|
||||
:style (style/input-text props
|
||||
state
|
||||
{:max-height max-height
|
||||
:theme theme})
|
||||
:max-length constants/max-text-size
|
||||
:accessibility-label :chat-message-input}]]]
|
||||
[:<>
|
||||
[gradients/view props state animations show-bottom-gradient?]
|
||||
[link-preview/view]
|
||||
[images/images-list]]
|
||||
;; https://github.com/facebook/react-native/issues/39660
|
||||
[rn/scroll-view
|
||||
{:on-scroll #(handler/scroll % props state animations dimensions)
|
||||
:keyboard-should-persist-taps :handled
|
||||
:scroll-event-throttle 64
|
||||
:ref #(reset! (:composer-scrollview-ref props) %)
|
||||
:shows-vertical-scroll-indicator false}
|
||||
[rn/text-input
|
||||
{:ref #(reset! (:input-ref props) %)
|
||||
:default-value @(:text-value state)
|
||||
:on-focus #(handler/focus props state animations dimensions)
|
||||
:on-blur #(handler/blur state animations dimensions subscriptions)
|
||||
:on-change-text #(handler/change-text % props state scroll-to-end)
|
||||
:on-selection-change #(handler/selection-change % props state)
|
||||
:on-content-size-change #(handler/content-size-change %1
|
||||
state
|
||||
animations
|
||||
dimensions
|
||||
(or keyboard-shown
|
||||
(:edit subscriptions)))
|
||||
:on-selection #(selection/on-selection % props state)
|
||||
:keyboard-appearance (quo.theme/theme-value :light :dark)
|
||||
:max-font-size-multiplier 1
|
||||
:multiline true
|
||||
:scroll-enabled false
|
||||
:placeholder (i18n/label :t/type-something)
|
||||
:placeholder-text-color (colors/theme-colors colors/neutral-40 colors/neutral-50)
|
||||
:style (style/input-text state
|
||||
{:max-height max-height
|
||||
:theme theme})
|
||||
:max-length constants/max-text-size
|
||||
:accessibility-label :chat-message-input}]]]]
|
||||
(when chat-screen-loaded?
|
||||
[:<>
|
||||
[gradients/view props state animations show-bottom-gradient?]
|
||||
[link-preview/view]
|
||||
[images/images-list]])
|
||||
[:f> actions/view props state animations window-height insets subscriptions]]]]]))
|
||||
|
||||
(defn f-composer
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
(ns status-im.common.lightbox.animations
|
||||
(ns status-im.contexts.chat.messenger.lightbox.animations
|
||||
(:require
|
||||
[react-native.reanimated :as reanimated]))
|
||||
|
||||
+17
-23
@@ -1,25 +1,25 @@
|
||||
(ns status-im.common.lightbox.bottom-view
|
||||
(ns status-im.contexts.chat.messenger.lightbox.bottom-view
|
||||
(:require
|
||||
[quo.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[status-im.common.lightbox.animations :as anim]
|
||||
[status-im.common.lightbox.constants :as constants]
|
||||
[status-im.common.lightbox.style :as style]
|
||||
[status-im.common.lightbox.text-sheet.view :as text-sheet]
|
||||
[status-im.contexts.chat.messenger.lightbox.animations :as anim]
|
||||
[status-im.contexts.chat.messenger.lightbox.constants :as c]
|
||||
[status-im.contexts.chat.messenger.lightbox.style :as style]
|
||||
[status-im.contexts.chat.messenger.lightbox.text-sheet.view :as text-sheet]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn get-small-item-layout
|
||||
[_ index]
|
||||
#js
|
||||
{:length constants/small-image-size
|
||||
:offset (* (+ constants/small-image-size 8) index)
|
||||
{:length c/small-image-size
|
||||
:offset (* (+ c/small-image-size 8) index)
|
||||
:index index})
|
||||
|
||||
(defn- f-small-image
|
||||
[item index _ {:keys [scroll-index props]}]
|
||||
(let [size (if (= @scroll-index index) constants/focused-image-size constants/small-image-size)
|
||||
(let [size (if (= @scroll-index index) c/focused-image-size c/small-image-size)
|
||||
size-value (anim/use-val size)
|
||||
{:keys [scroll-index-lock? small-list-ref flat-list-ref]}
|
||||
props]
|
||||
@@ -27,7 +27,7 @@
|
||||
[rn/touchable-opacity
|
||||
{:active-opacity 1
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:lightbox/zoom-out-signal @scroll-index])
|
||||
(rf/dispatch [:chat.ui/zoom-out-signal @scroll-index])
|
||||
(reset! scroll-index-lock? true)
|
||||
(js/setTimeout #(reset! scroll-index-lock? false) 500)
|
||||
(js/setTimeout
|
||||
@@ -38,9 +38,9 @@
|
||||
(.scrollToIndex ^js @flat-list-ref
|
||||
#js {:animated true :index index}))
|
||||
(if platform/ios? 50 150))
|
||||
(rf/dispatch [:lightbox/update-animation-shared-element-id (:id item)]))}
|
||||
(rf/dispatch [:chat.ui/update-shared-element-id (:message-id item)]))}
|
||||
[reanimated/fast-image
|
||||
{:source {:uri (:image item)}
|
||||
{:source {:uri (:image (:content item))}
|
||||
:style (reanimated/apply-animations-to-style {:width size-value
|
||||
:height size-value}
|
||||
{:border-radius 10})}]]))
|
||||
@@ -50,26 +50,20 @@
|
||||
[:f> f-small-image item index _ render-data])
|
||||
|
||||
(defn bottom-view
|
||||
[{:keys [images index scroll-index insets animations derived item-width props state transparent?
|
||||
bottom-text-component]}]
|
||||
(let [padding-horizontal (- (/ item-width 2) (/ constants/focused-image-size 2))]
|
||||
[messages index scroll-index insets animations derived item-width props state transparent?]
|
||||
(let [padding-horizontal (- (/ item-width 2) (/ c/focused-image-size 2))]
|
||||
[reanimated/linear-gradient
|
||||
{:colors [colors/neutral-100-opa-100 colors/neutral-100-opa-80 colors/neutral-100-opa-0]
|
||||
:location [0.2 0.9]
|
||||
:start {:x 0 :y 1}
|
||||
:end {:x 0 :y 0}
|
||||
:style (style/gradient-container insets animations derived transparent?)}
|
||||
(when bottom-text-component
|
||||
[text-sheet/view
|
||||
{:overlay-opacity (:overlay-opacity animations)
|
||||
:overlay-z-index (:overlay-z-index state)
|
||||
:text-sheet-lock? (:text-sheet-lock? props)
|
||||
:text-component bottom-text-component}])
|
||||
[text-sheet/view messages animations state props]
|
||||
[rn/flat-list
|
||||
{:ref #(reset! (:small-list-ref props) %)
|
||||
:key-fn :id
|
||||
:style {:height constants/small-list-height}
|
||||
:data images
|
||||
:key-fn :message-id
|
||||
:style {:height c/small-list-height}
|
||||
:data messages
|
||||
:render-fn small-image
|
||||
:render-data {:scroll-index scroll-index
|
||||
:props props}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
(ns status-im.common.lightbox.constants)
|
||||
(ns status-im.contexts.chat.messenger.lightbox.constants)
|
||||
|
||||
(def ^:const small-image-size 40)
|
||||
(def ^:const focused-extra-size 16)
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
(ns status-im.common.lightbox.effects
|
||||
(ns status-im.contexts.chat.messenger.lightbox.effects
|
||||
(:require [react-native.blob :as blob]
|
||||
[react-native.cameraroll :as cameraroll]
|
||||
[react-native.fs :as fs]
|
||||
@@ -10,7 +10,7 @@
|
||||
{:trusty platform/ios?
|
||||
:path (str (fs/cache-dir) "/StatusIm_Image.jpeg")})
|
||||
|
||||
(rf/reg-fx :effects.lightbox/share-image
|
||||
(rf/reg-fx :effects.chat/share-image
|
||||
(fn [uri]
|
||||
(blob/fetch uri
|
||||
config
|
||||
@@ -20,7 +20,7 @@
|
||||
#(fs/unlink downloaded-url)
|
||||
#(fs/unlink downloaded-url))))))
|
||||
|
||||
(rf/reg-fx :effects.lightbox/save-image-to-gallery
|
||||
(rf/reg-fx :effects.chat/save-image-to-gallery
|
||||
(fn [[uri on-success]]
|
||||
(blob/fetch uri
|
||||
config
|
||||
@@ -0,0 +1,23 @@
|
||||
(ns status-im.contexts.chat.messenger.lightbox.events
|
||||
(:require status-im.contexts.chat.messenger.lightbox.effects
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(rf/reg-event-fx :chat.ui/clear-sending-images
|
||||
(fn [{:keys [db]}]
|
||||
{:db (update-in db [:chat/inputs (:current-chat-id db) :metadata] assoc :sending-image {})}))
|
||||
|
||||
(rf/reg-event-fx :chat.ui/image-unselected
|
||||
(fn [{: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/reg-event-fx :chat.ui/share-image
|
||||
(fn [_ [uri]]
|
||||
{:effects.chat/share-image uri}))
|
||||
|
||||
(rf/reg-event-fx :chat.ui/save-image-to-gallery
|
||||
(fn [_ [uri on-success]]
|
||||
{:effects.chat/save-image-to-gallery [uri on-success]}))
|
||||
+6
-6
@@ -1,9 +1,9 @@
|
||||
(ns status-im.common.lightbox.style
|
||||
(ns status-im.contexts.chat.messenger.lightbox.style
|
||||
(:require
|
||||
[quo.foundations.colors :as colors]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[status-im.common.lightbox.constants :as constants]))
|
||||
[status-im.contexts.chat.messenger.lightbox.constants :as c]))
|
||||
|
||||
;;;; VIEW
|
||||
(defn image
|
||||
@@ -33,7 +33,7 @@
|
||||
{:position :absolute
|
||||
:padding-horizontal 20
|
||||
:top (if (or platform/ios? (not landscape?)) top-inset 0)
|
||||
:height constants/top-view-height
|
||||
:height c/top-view-height
|
||||
:z-index 4
|
||||
:flex-direction :row
|
||||
:justify-content :space-between
|
||||
@@ -44,7 +44,7 @@
|
||||
(defn top-gradient
|
||||
[insets]
|
||||
{:position :absolute
|
||||
:height (+ constants/top-view-height (:top insets) 0)
|
||||
:height (+ c/top-view-height (:top insets) 0)
|
||||
:top (- (:top insets))
|
||||
:left 0
|
||||
:right 0})
|
||||
@@ -71,12 +71,12 @@
|
||||
:display (if @transparent? :none :flex)
|
||||
:bottom 0
|
||||
:padding-bottom (:bottom insets)
|
||||
:padding-top constants/text-min-height
|
||||
:padding-top c/text-min-height
|
||||
:z-index 3}))
|
||||
|
||||
(defn content-container
|
||||
[padding-horizontal]
|
||||
{:padding-vertical constants/small-list-padding-vertical
|
||||
{:padding-vertical c/small-list-padding-vertical
|
||||
:padding-horizontal padding-horizontal
|
||||
:align-items :center
|
||||
:justify-content :center})
|
||||
+4
-4
@@ -1,8 +1,8 @@
|
||||
(ns status-im.common.lightbox.text-sheet.style
|
||||
(ns status-im.contexts.chat.messenger.lightbox.text-sheet.style
|
||||
(:require
|
||||
[quo.foundations.colors :as colors]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[status-im.common.lightbox.constants :as constants]))
|
||||
[status-im.contexts.chat.messenger.lightbox.constants :as constants]))
|
||||
|
||||
(defn sheet-container
|
||||
[{:keys [height top]}]
|
||||
@@ -14,10 +14,10 @@
|
||||
:right 0}))
|
||||
|
||||
(defn text-style
|
||||
[expandable-text?]
|
||||
[expanding-message?]
|
||||
{:color colors/white
|
||||
:margin-horizontal 20
|
||||
:align-items (when-not expandable-text? :center)
|
||||
:align-items (when-not expanding-message? :center)
|
||||
:flex-grow 1})
|
||||
|
||||
(def bar-container
|
||||
+4
-4
@@ -1,10 +1,10 @@
|
||||
(ns status-im.common.lightbox.text-sheet.utils
|
||||
(ns status-im.contexts.chat.messenger.lightbox.text-sheet.utils
|
||||
(:require
|
||||
[oops.core :as oops]
|
||||
[react-native.gesture :as gesture]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[reagent.core :as r]
|
||||
[status-im.common.lightbox.constants :as constants]))
|
||||
[status-im.contexts.chat.messenger.lightbox.constants :as constants]))
|
||||
|
||||
(defn- collapse-sheet
|
||||
[{:keys [derived-value overlay-opacity saved-top expanded? overlay-z-index]}]
|
||||
@@ -16,10 +16,10 @@
|
||||
|
||||
(defn sheet-gesture
|
||||
[{:keys [derived-value saved-top overlay-opacity gradient-opacity]}
|
||||
expanded-height max-height full-height overlay-z-index expanded? dragging? expandable-text?]
|
||||
expanded-height max-height full-height overlay-z-index expanded? dragging? expanding-message?]
|
||||
(let [disable-gesture-update (r/atom false)]
|
||||
(-> (gesture/gesture-pan)
|
||||
(gesture/enabled expandable-text?)
|
||||
(gesture/enabled expanding-message?)
|
||||
(gesture/on-start (fn []
|
||||
(reset! overlay-z-index 1)
|
||||
(reset! dragging? true)
|
||||
+34
-30
@@ -1,4 +1,4 @@
|
||||
(ns status-im.common.lightbox.text-sheet.view
|
||||
(ns status-im.contexts.chat.messenger.lightbox.text-sheet.view
|
||||
(:require
|
||||
[quo.foundations.colors :as colors]
|
||||
[react-native.core :as rn]
|
||||
@@ -8,31 +8,33 @@
|
||||
[react-native.reanimated :as reanimated]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.common.lightbox.constants :as constants]
|
||||
[status-im.common.lightbox.text-sheet.style :as style]
|
||||
[status-im.common.lightbox.text-sheet.utils :as utils]))
|
||||
[status-im.contexts.chat.messenger.lightbox.constants :as constants]
|
||||
[status-im.contexts.chat.messenger.lightbox.text-sheet.style :as style]
|
||||
[status-im.contexts.chat.messenger.lightbox.text-sheet.utils :as utils]
|
||||
[status-im.contexts.chat.messenger.messages.content.text.view :as message-view]))
|
||||
|
||||
(defn- text-sheet
|
||||
[_]
|
||||
[messages overlay-opacity overlay-z-index text-sheet-lock?]
|
||||
(let [text-height (reagent/atom 0)
|
||||
expanded? (reagent/atom false)
|
||||
dragging? (atom false)]
|
||||
(fn [{:keys [overlay-opacity overlay-z-index text-sheet-lock? text-component]}]
|
||||
(let [insets (safe-area/get-insets)
|
||||
window-height (:height (rn/get-window))
|
||||
max-height (- window-height
|
||||
constants/text-min-height
|
||||
constants/top-view-height
|
||||
(:bottom insets)
|
||||
(when platform/ios? (:top insets)))
|
||||
full-height (+ constants/bar-container-height
|
||||
constants/text-margin
|
||||
constants/line-height
|
||||
@text-height)
|
||||
expanded-height (min max-height full-height)
|
||||
animations (utils/init-animations overlay-opacity)
|
||||
derived (utils/init-derived-animations animations)
|
||||
expandable-text? (> @text-height (* constants/line-height 2))]
|
||||
(fn []
|
||||
(let [{:keys [chat-id content]} (first messages)
|
||||
insets (safe-area/get-insets)
|
||||
window-height (:height (rn/get-window))
|
||||
max-height (- window-height
|
||||
constants/text-min-height
|
||||
constants/top-view-height
|
||||
(:bottom insets)
|
||||
(when platform/ios? (:top insets)))
|
||||
full-height (+ constants/bar-container-height
|
||||
constants/text-margin
|
||||
constants/line-height
|
||||
@text-height)
|
||||
expanded-height (min max-height full-height)
|
||||
animations (utils/init-animations overlay-opacity)
|
||||
derived (utils/init-derived-animations animations)
|
||||
expanding-message? (> @text-height (* constants/line-height 2))]
|
||||
[rn/view
|
||||
[reanimated/linear-gradient
|
||||
{:colors [colors/neutral-100-opa-0 colors/neutral-100]
|
||||
@@ -49,10 +51,10 @@
|
||||
overlay-z-index
|
||||
expanded?
|
||||
dragging?
|
||||
expandable-text?)}
|
||||
expanding-message?)}
|
||||
[gesture/gesture-detector
|
||||
{:gesture (-> (gesture/gesture-tap)
|
||||
(gesture/enabled (and expandable-text? (not @expanded?)))
|
||||
(gesture/enabled (and expanding-message? (not @expanded?)))
|
||||
(gesture/on-start (fn []
|
||||
(utils/expand-sheet animations
|
||||
expanded-height
|
||||
@@ -61,7 +63,7 @@
|
||||
expanded?
|
||||
text-sheet-lock?))))}
|
||||
[reanimated/view {:style (style/sheet-container derived)}
|
||||
(when expandable-text?
|
||||
(when expanding-message?
|
||||
[rn/view {:style style/bar-container}
|
||||
[rn/view {:style style/bar}]])
|
||||
[linear-gradient/linear-gradient
|
||||
@@ -70,17 +72,19 @@
|
||||
:end {:x 0 :y 0}
|
||||
:locations [0.7 0.8 1]
|
||||
:style (style/bottom-gradient (:bottom insets))}]
|
||||
|
||||
[gesture/scroll-view
|
||||
{:scroll-enabled false
|
||||
:scroll-event-throttle 16
|
||||
:bounces false
|
||||
:style {:height (- max-height constants/bar-container-height)}
|
||||
:content-container-style {:padding-top (when (not expandable-text?)
|
||||
:content-container-style {:padding-top (when (not expanding-message?)
|
||||
constants/bar-container-height)}}
|
||||
[rn/view {:on-layout #(utils/on-layout % text-height)}
|
||||
text-component]]]]]]))))
|
||||
[message-view/render-parsed-text
|
||||
{:content content
|
||||
:chat-id chat-id
|
||||
:style-override (style/text-style expanding-message?)
|
||||
:on-layout #(utils/on-layout % text-height)}]]]]]]))))
|
||||
|
||||
(defn view
|
||||
[props]
|
||||
[:f> text-sheet props])
|
||||
[messages {:keys [overlay-opacity]} {:keys [overlay-z-index]} {:keys [text-sheet-lock?]}]
|
||||
[:f> text-sheet messages overlay-opacity overlay-z-index text-sheet-lock?])
|
||||
+26
-24
@@ -1,4 +1,4 @@
|
||||
(ns status-im.common.lightbox.top-view
|
||||
(ns status-im.contexts.chat.messenger.lightbox.top-view
|
||||
(:require
|
||||
[quo.core :as quo]
|
||||
[quo.foundations.colors :as colors]
|
||||
@@ -6,9 +6,10 @@
|
||||
[react-native.orientation :as orientation]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[status-im.common.lightbox.animations :as anim]
|
||||
[status-im.common.lightbox.constants :as constants]
|
||||
[status-im.common.lightbox.style :as style]
|
||||
[status-im.contexts.chat.messenger.lightbox.animations :as anim]
|
||||
[status-im.contexts.chat.messenger.lightbox.constants :as c]
|
||||
[status-im.contexts.chat.messenger.lightbox.style :as style]
|
||||
[utils.datetime :as datetime]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.url :as url]))
|
||||
@@ -16,7 +17,7 @@
|
||||
(defn animate-rotation
|
||||
[result screen-width screen-height insets
|
||||
{:keys [rotate top-view-y top-view-x top-view-width top-view-bg]}]
|
||||
(let [top-x (+ (/ constants/top-view-height 2) (:top insets))]
|
||||
(let [top-x (+ (/ c/top-view-height 2) (:top insets))]
|
||||
(cond
|
||||
(= result orientation/landscape-left)
|
||||
(do
|
||||
@@ -41,9 +42,9 @@
|
||||
(anim/animate top-view-bg colors/neutral-100-opa-0)))))
|
||||
|
||||
(defn drawer
|
||||
[images index]
|
||||
(let [{:keys [image]} (nth images index)
|
||||
uri (url/replace-port image (rf/sub [:mediaserver/port]))]
|
||||
[messages index]
|
||||
(let [{:keys [content]} (nth messages index)
|
||||
uri (url/replace-port (:image content) (rf/sub [:mediaserver/port]))]
|
||||
[quo/action-drawer
|
||||
[[{:icon :i/save
|
||||
:accessibility-label :save-image
|
||||
@@ -51,7 +52,7 @@
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:hide-bottom-sheet])
|
||||
(rf/dispatch
|
||||
[:lightbox/save-image-to-gallery
|
||||
[:chat.ui/save-image-to-gallery
|
||||
uri
|
||||
#(rf/dispatch [:toasts/upsert
|
||||
{:id :random-id
|
||||
@@ -60,19 +61,20 @@
|
||||
:text (i18n/label :t/photo-saved)}])]))}]]]))
|
||||
|
||||
(defn share-image
|
||||
[images index]
|
||||
(let [{:keys [image]} (nth images index)
|
||||
uri (url/replace-port image (rf/sub [:mediaserver/port]))]
|
||||
(rf/dispatch [:lightbox/share-image uri])))
|
||||
[messages index]
|
||||
(let [{:keys [content]} (nth messages index)
|
||||
uri (url/replace-port (:image content) (rf/sub [:mediaserver/port]))]
|
||||
(rf/dispatch [:chat.ui/share-image uri])))
|
||||
|
||||
(defn top-view
|
||||
[images insets index animations derived landscape? screen-width]
|
||||
(let [{:keys [description header]} (nth images @index)
|
||||
bg-color (if landscape?
|
||||
colors/neutral-100-opa-70
|
||||
colors/neutral-100-opa-0)
|
||||
[messages insets index animations derived landscape? screen-width]
|
||||
(let [{:keys [from timestamp]} (first messages)
|
||||
[primary-name _] (rf/sub [:contacts/contact-two-names-by-identity from])
|
||||
bg-color (if landscape?
|
||||
colors/neutral-100-opa-70
|
||||
colors/neutral-100-opa-0)
|
||||
{:keys [background-color opacity
|
||||
overlay-opacity]} animations]
|
||||
overlay-opacity]} animations]
|
||||
[reanimated/view
|
||||
{:style
|
||||
(style/top-view-container (:top insets) screen-width bg-color landscape? animations derived)}
|
||||
@@ -90,7 +92,7 @@
|
||||
(anim/animate opacity 0)
|
||||
(anim/animate overlay-opacity 0)
|
||||
(rf/dispatch (if platform/ios?
|
||||
[:lightbox/exit-lightbox-signal @index]
|
||||
[:chat.ui/exit-lightbox-signal @index]
|
||||
[:navigate-back])))
|
||||
:style style/close-container}
|
||||
[quo/icon :close {:size 20 :color colors/white}]]
|
||||
@@ -98,22 +100,22 @@
|
||||
[quo/text
|
||||
{:weight :semi-bold
|
||||
:size :paragraph-1
|
||||
:style {:color colors/white}} header]
|
||||
:style {:color colors/white}} primary-name]
|
||||
[quo/text
|
||||
{:weight :medium
|
||||
:size :paragraph-2
|
||||
:style {:color colors/neutral-40}} description]]]
|
||||
:style {:color colors/neutral-40}} (when timestamp (datetime/to-short-str timestamp))]]]
|
||||
[rn/view {:style style/top-right-buttons}
|
||||
[rn/touchable-opacity
|
||||
{:active-opacity 1
|
||||
:accessibility-label :share-image
|
||||
:on-press #(share-image images @index)
|
||||
:on-press #(share-image messages @index)
|
||||
:style (merge style/close-container {:margin-right 12})}
|
||||
[quo/icon :share {:size 20 :color colors/white}]]
|
||||
[rn/touchable-opacity
|
||||
{:active-opacity 1
|
||||
:accessibility-label :image-options
|
||||
:on-press #(rf/dispatch [:show-bottom-sheet
|
||||
{:content (fn [] [drawer images @index])}])
|
||||
{:content (fn [] [drawer messages @index])}])
|
||||
:style style/close-container}
|
||||
[quo/icon :options {:size 20 :color colors/white}]]]]))
|
||||
+8
-8
@@ -1,4 +1,4 @@
|
||||
(ns status-im.common.lightbox.utils
|
||||
(ns status-im.contexts.chat.messenger.lightbox.utils
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[oops.core :as oops]
|
||||
@@ -9,9 +9,9 @@
|
||||
[react-native.platform :as platform]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.common.lightbox.animations :as anim]
|
||||
[status-im.common.lightbox.constants :as constants]
|
||||
[status-im.common.lightbox.top-view :as top-view]
|
||||
[status-im.contexts.chat.messenger.lightbox.animations :as anim]
|
||||
[status-im.contexts.chat.messenger.lightbox.constants :as constants]
|
||||
[status-im.contexts.chat.messenger.lightbox.top-view :as top-view]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.worklets.chat.messenger.lightbox :as worklet]))
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
(if platform/ios? 250 100)))
|
||||
(swap! timers assoc :mount-index-lock (js/setTimeout #(reset! scroll-index-lock? false) 300))
|
||||
(fn []
|
||||
(rf/dispatch [:lightbox/zoom-out-signal nil])
|
||||
(rf/dispatch [:chat.ui/zoom-out-signal nil])
|
||||
(when platform/android?
|
||||
(rf/dispatch [:chat.ui/lightbox-scale 1]))
|
||||
(clear-timers timers)))))
|
||||
@@ -69,7 +69,7 @@
|
||||
landscape? (string/includes? result orientation/landscape)
|
||||
item-width (if (and landscape? platform/ios?) screen-height screen-width)]
|
||||
(when (or landscape? (= result orientation/portrait))
|
||||
(rf/dispatch [:lightbox/orientation-change result]))
|
||||
(rf/dispatch [:chat.ui/orientation-change result]))
|
||||
(cond
|
||||
landscape?
|
||||
(orientation/lock-to-landscape "lightbox")
|
||||
@@ -148,11 +148,11 @@
|
||||
:timers (atom {})})
|
||||
|
||||
(defn init-state
|
||||
[images index]
|
||||
[messages index]
|
||||
;; The initial value of data is the image that was pressed (and not the whole album) in order
|
||||
;; for the transition animation to execute properly, otherwise it would animate towards
|
||||
;; outside the screen (even if we have `initialScrollIndex` set).
|
||||
{:data (reagent/atom (if (number? index) [(nth images index)] []))
|
||||
{:data (reagent/atom (if (number? index) [(nth messages index)] []))
|
||||
:scroll-index (reagent/atom index)
|
||||
:transparent? (reagent/atom false)
|
||||
:set-full-height? (reagent/atom false)
|
||||
+42
-65
@@ -1,4 +1,4 @@
|
||||
(ns status-im.common.lightbox.view
|
||||
(ns status-im.contexts.chat.messenger.lightbox.view
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[oops.core :as oops]
|
||||
@@ -9,13 +9,13 @@
|
||||
[react-native.platform :as platform]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[status-im.common.lightbox.animations :as anim]
|
||||
[status-im.common.lightbox.bottom-view :as bottom-view]
|
||||
[status-im.common.lightbox.constants :as constants]
|
||||
[status-im.common.lightbox.style :as style]
|
||||
[status-im.common.lightbox.top-view :as top-view]
|
||||
[status-im.common.lightbox.utils :as utils]
|
||||
[status-im.common.lightbox.zoomable-image.view :as zoomable-image]
|
||||
[status-im.contexts.chat.messenger.lightbox.animations :as anim]
|
||||
[status-im.contexts.chat.messenger.lightbox.bottom-view :as bottom-view]
|
||||
[status-im.contexts.chat.messenger.lightbox.constants :as constants]
|
||||
[status-im.contexts.chat.messenger.lightbox.style :as style]
|
||||
[status-im.contexts.chat.messenger.lightbox.top-view :as top-view]
|
||||
[status-im.contexts.chat.messenger.lightbox.utils :as utils]
|
||||
[status-im.contexts.chat.messenger.lightbox.zoomable-image.view :as zoomable-image]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn get-item-layout
|
||||
@@ -33,10 +33,9 @@
|
||||
(reset! scroll-index index)
|
||||
(when @small-list-ref
|
||||
(.scrollToIndex ^js @small-list-ref #js {:animated true :index index}))
|
||||
(rf/dispatch [:lightbox/update-animation-shared-element-id
|
||||
(:id (oops/oget changed :item))]))))
|
||||
(rf/dispatch [:chat.ui/update-shared-element-id (:message-id (oops/oget changed :item))]))))
|
||||
|
||||
(defn image-view
|
||||
(defn image
|
||||
[message index _ {:keys [screen-width screen-height] :as args}]
|
||||
[rn/view
|
||||
{:style (style/image (+ screen-width constants/separator-width) screen-height)}
|
||||
@@ -44,31 +43,30 @@
|
||||
[rn/view {:style {:width constants/separator-width}}]])
|
||||
|
||||
(defn lightbox-content
|
||||
[{:keys [props state animations derived images index handle-items-changed bottom-text-component]}]
|
||||
(let [{:keys [data transparent? scroll-index
|
||||
set-full-height?]} state
|
||||
insets (safe-area/get-insets)
|
||||
window (rn/get-window)
|
||||
window-width (:width window)
|
||||
window-height (if platform/android?
|
||||
(+ (:height window) (:top insets))
|
||||
(:height window))
|
||||
curr-orientation (or (rf/sub [:lightbox/orientation]) orientation/portrait)
|
||||
landscape? (string/includes? curr-orientation orientation/landscape)
|
||||
horizontal? (or platform/android? (not landscape?))
|
||||
inverted? (and platform/ios? (= curr-orientation orientation/landscape-right))
|
||||
screen-width (if (or platform/ios? (= curr-orientation orientation/portrait))
|
||||
window-width
|
||||
window-height)
|
||||
screen-height (if (or platform/ios? (= curr-orientation orientation/portrait))
|
||||
window-height
|
||||
window-width)
|
||||
item-width (if (and landscape? platform/ios?) screen-height screen-width)]
|
||||
[props {:keys [data transparent? scroll-index set-full-height?] :as state}
|
||||
animations derived messages index handle-items-changed]
|
||||
(let [insets (safe-area/get-insets)
|
||||
window (rn/get-window)
|
||||
window-width (:width window)
|
||||
window-height (if platform/android?
|
||||
(+ (:height window) (:top insets))
|
||||
(:height window))
|
||||
curr-orientation (or (rf/sub [:lightbox/orientation]) orientation/portrait)
|
||||
landscape? (string/includes? curr-orientation orientation/landscape)
|
||||
horizontal? (or platform/android? (not landscape?))
|
||||
inverted? (and platform/ios? (= curr-orientation orientation/landscape-right))
|
||||
screen-width (if (or platform/ios? (= curr-orientation orientation/portrait))
|
||||
window-width
|
||||
window-height)
|
||||
screen-height (if (or platform/ios? (= curr-orientation orientation/portrait))
|
||||
window-height
|
||||
window-width)
|
||||
item-width (if (and landscape? platform/ios?) screen-height screen-width)]
|
||||
[reanimated/view
|
||||
{:style (reanimated/apply-animations-to-style {:background-color (:background-color animations)}
|
||||
{:height screen-height})}
|
||||
(when-not @transparent?
|
||||
[:f> top-view/top-view images insets scroll-index animations derived landscape?
|
||||
[:f> top-view/top-view messages insets scroll-index animations derived landscape?
|
||||
screen-width])
|
||||
[gesture/gesture-detector
|
||||
{:gesture (utils/drag-gesture animations (and landscape? platform/ios?) set-full-height?)}
|
||||
@@ -94,7 +92,7 @@
|
||||
:scroll-event-throttle 8
|
||||
:style {:width (+ screen-width constants/separator-width)}
|
||||
:data @data
|
||||
:render-fn image-view
|
||||
:render-fn image
|
||||
:render-data {:opacity-value (:opacity animations)
|
||||
:overlay-opacity (:overlay-opacity animations)
|
||||
:border-value (:border animations)
|
||||
@@ -120,47 +118,26 @@
|
||||
;; NOTE: not un-mounting bottom-view based on `transparent?` (like we do with the top-view
|
||||
;; above), since we need to save the state of the text-sheet position. Instead, we use
|
||||
;; the `:display` style property to hide the bottom-sheet.
|
||||
(when (and (not landscape?) (or bottom-text-component (> (count images) 1)))
|
||||
[:f> bottom-view/bottom-view
|
||||
{:images images
|
||||
:index index
|
||||
:scroll-index scroll-index
|
||||
:insets insets
|
||||
:animations animations
|
||||
:derived derived
|
||||
:item-width item-width
|
||||
:props props
|
||||
:state state
|
||||
:transparent? transparent?
|
||||
:bottom-text-component bottom-text-component}])]))
|
||||
(when (not landscape?)
|
||||
[:f> bottom-view/bottom-view messages index scroll-index insets animations derived
|
||||
item-width props state transparent?])]))
|
||||
|
||||
(defn- f-lightbox
|
||||
[]
|
||||
(let [{:keys [images index bottom-text-component]} (rf/sub [:get-screen-params])
|
||||
props
|
||||
(utils/init-props)
|
||||
state
|
||||
(utils/init-state images index)
|
||||
handle-items-changed
|
||||
(fn [e]
|
||||
(on-viewable-items-changed e props state))]
|
||||
(let [{:keys [messages index]} (rf/sub [:get-screen-params])
|
||||
props (utils/init-props)
|
||||
state (utils/init-state messages index)
|
||||
handle-items-changed (fn [e]
|
||||
(on-viewable-items-changed e props state))]
|
||||
(fn []
|
||||
(let [animations (utils/init-animations (count images) index)
|
||||
(let [animations (utils/init-animations (count messages) index)
|
||||
derived (utils/init-derived-animations animations)]
|
||||
(anim/animate (:background-color animations) colors/neutral-100)
|
||||
(reset! (:data state) images)
|
||||
(reset! (:data state) messages)
|
||||
(when platform/ios? ; issue: https://github.com/wix/react-native-navigation/issues/7726
|
||||
(utils/orientation-change props state animations))
|
||||
(utils/effect props animations index)
|
||||
[:f> lightbox-content
|
||||
{:props props
|
||||
:state state
|
||||
:animations animations
|
||||
:derived derived
|
||||
:images images
|
||||
:index index
|
||||
:handle-items-changed handle-items-changed
|
||||
:bottom-text-component bottom-text-component}]))))
|
||||
[:f> lightbox-content props state animations derived messages index handle-items-changed]))))
|
||||
|
||||
(defn lightbox
|
||||
[]
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
(ns status-im.common.lightbox.zoomable-image.constants)
|
||||
(ns status-im.contexts.chat.messenger.lightbox.zoomable-image.constants)
|
||||
|
||||
(def ^:const min-scale 1)
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
(ns status-im.common.lightbox.zoomable-image.style
|
||||
(ns status-im.contexts.chat.messenger.lightbox.zoomable-image.style
|
||||
(:require
|
||||
[react-native.platform :as platform]
|
||||
[react-native.reanimated :as reanimated]))
|
||||
+4
-4
@@ -1,4 +1,4 @@
|
||||
(ns status-im.common.lightbox.zoomable-image.utils
|
||||
(ns status-im.contexts.chat.messenger.lightbox.zoomable-image.utils
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[react-native.core :as rn]
|
||||
@@ -6,8 +6,8 @@
|
||||
[react-native.orientation :as orientation]
|
||||
[react-native.platform :as platform]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.common.lightbox.animations :as anim]
|
||||
[status-im.common.lightbox.zoomable-image.constants :as constants]
|
||||
[status-im.contexts.chat.messenger.lightbox.animations :as anim]
|
||||
[status-im.contexts.chat.messenger.lightbox.zoomable-image.constants :as constants]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
;;; Helpers
|
||||
@@ -97,7 +97,7 @@
|
||||
(rescale constants/min-scale true)
|
||||
(js/setTimeout #(rf/dispatch [:navigate-back]) 70))
|
||||
(rf/dispatch [:navigate-back]))
|
||||
(js/setTimeout #(rf/dispatch [:lightbox/exit-lightbox-signal nil]) 500)))
|
||||
(js/setTimeout #(rf/dispatch [:chat.ui/exit-lightbox-signal nil]) 500)))
|
||||
|
||||
(defn handle-zoom-out-signal
|
||||
"Zooms out when pressing on another photo from the small bottom list"
|
||||
+11
-11
@@ -1,4 +1,4 @@
|
||||
(ns status-im.common.lightbox.zoomable-image.view
|
||||
(ns status-im.contexts.chat.messenger.lightbox.zoomable-image.view
|
||||
(:require
|
||||
[oops.core :refer [oget]]
|
||||
[react-native.core :as rn]
|
||||
@@ -7,10 +7,10 @@
|
||||
[react-native.platform :as platform]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[reagent.core :as r]
|
||||
[status-im.common.lightbox.animations :as anim]
|
||||
[status-im.common.lightbox.zoomable-image.constants :as c]
|
||||
[status-im.common.lightbox.zoomable-image.style :as style]
|
||||
[status-im.common.lightbox.zoomable-image.utils :as utils]
|
||||
[status-im.contexts.chat.messenger.lightbox.animations :as anim]
|
||||
[status-im.contexts.chat.messenger.lightbox.zoomable-image.constants :as c]
|
||||
[status-im.contexts.chat.messenger.lightbox.zoomable-image.style :as style]
|
||||
[status-im.contexts.chat.messenger.lightbox.zoomable-image.utils :as utils]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.url :as url]))
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
(anim/animate-decay pan-y-start velocity [lower-bound upper-bound]))))))))
|
||||
|
||||
(defn- f-zoomable-image
|
||||
[dimensions animations state rescale curr-orientation image focused? index render-data
|
||||
[dimensions animations state rescale curr-orientation content focused? index render-data
|
||||
image-dimensions-nil?]
|
||||
(let [{:keys [transparent? set-full-height?]} render-data
|
||||
portrait? (= curr-orientation orientation/portrait)
|
||||
@@ -229,7 +229,7 @@
|
||||
(= curr-orientation orientation/portrait))}
|
||||
[reanimated/fast-image
|
||||
(merge
|
||||
{:source {:uri (url/replace-port image (rf/sub [:mediaserver/port]))}
|
||||
{:source {:uri (url/replace-port (:image content) (rf/sub [:mediaserver/port]))}
|
||||
:native-ID (when focused? :shared-element)
|
||||
:style (style/image dimensions animations render-data index)}
|
||||
(when image-dimensions-nil?
|
||||
@@ -238,12 +238,12 @@
|
||||
(defn zoomable-image
|
||||
[]
|
||||
(let [state (utils/init-state)]
|
||||
(fn [{:keys [image-width image-height image id]} index render-data]
|
||||
(let [animation-shared-element-id (rf/sub [:animation-shared-element-id])
|
||||
(fn [{:keys [image-width image-height content message-id]} index render-data]
|
||||
(let [shared-element-id (rf/sub [:shared-element-id])
|
||||
exit-lightbox-signal (rf/sub [:lightbox/exit-signal])
|
||||
zoom-out-signal (rf/sub [:lightbox/zoom-out-signal])
|
||||
{:keys [set-full-height? curr-orientation]} render-data
|
||||
focused? (= animation-shared-element-id id)
|
||||
focused? (= shared-element-id message-id)
|
||||
;; TODO - remove `image-dimensions` check, once
|
||||
;; https://github.com/status-im/status-desktop/issues/10944 is fixed
|
||||
image-dimensions-nil? (not (and image-width image-height))
|
||||
@@ -269,5 +269,5 @@
|
||||
rescale
|
||||
set-full-height?))
|
||||
(utils/handle-zoom-out-signal zoom-out-signal index (anim/get-val (:scale animations)) rescale)
|
||||
[:f> f-zoomable-image dimensions animations state rescale curr-orientation image focused?
|
||||
[:f> f-zoomable-image dimensions animations state rescale curr-orientation content focused?
|
||||
index render-data image-dimensions-nil?]))))
|
||||
@@ -7,8 +7,6 @@
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.chat.messenger.messages.content.album.style :as style]
|
||||
[status-im.contexts.chat.messenger.messages.content.image.view :as image]
|
||||
[status-im.contexts.chat.messenger.messages.content.lightbox.utils :as lightbox-utils]
|
||||
[status-im.contexts.chat.messenger.messages.content.lightbox.view :as lightbox]
|
||||
[status-im.contexts.chat.messenger.messages.content.text.view :as text]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.url :as url]))
|
||||
@@ -23,19 +21,17 @@
|
||||
|
||||
(defn album-message
|
||||
[{:keys [albumize?] :as message} context on-long-press message-container-data]
|
||||
(let [animation-shared-element-id (rf/sub [:animation-shared-element-id])
|
||||
media-server-port (rf/sub [:mediaserver/port])
|
||||
album-messages (:album message)
|
||||
first-image (first album-messages)
|
||||
album-style (if (> (:image-width first-image) (:image-height first-image))
|
||||
:landscape
|
||||
:portrait)
|
||||
images-count (count album-messages)
|
||||
(let [shared-element-id (rf/sub [:shared-element-id])
|
||||
media-server-port (rf/sub [:mediaserver/port])
|
||||
first-image (first (:album message))
|
||||
album-style (if (> (:image-width first-image) (:image-height first-image))
|
||||
:landscape
|
||||
:portrait)
|
||||
images-count (count (:album message))
|
||||
;; album images are always square, except when we have 3 images, then they must be
|
||||
;; rectangular
|
||||
;; (portrait or landscape)
|
||||
portrait? (and (= images-count rectangular-style-count)
|
||||
(= album-style :portrait))]
|
||||
portrait? (and (= images-count rectangular-style-count) (= album-style :portrait))]
|
||||
(if (and albumize? (> images-count 1))
|
||||
[:<>
|
||||
[rn/view {:style {:margin-bottom 4}} [text/text-content first-image]]
|
||||
@@ -56,21 +52,14 @@
|
||||
{:key (:message-id item)
|
||||
:active-opacity 1
|
||||
:on-long-press #(on-long-press message context)
|
||||
:on-press #(rf/dispatch
|
||||
[:lightbox/navigate-to-lightbox
|
||||
(:message-id item)
|
||||
{:index index
|
||||
:images (into []
|
||||
(map
|
||||
lightbox-utils/convert-message-to-lightbox-image
|
||||
album-messages))
|
||||
:bottom-text-component
|
||||
[lightbox/bottom-text-for-lightbox
|
||||
first-image]}])}
|
||||
:on-press #(rf/dispatch [:chat.ui/navigate-to-lightbox
|
||||
(:message-id item)
|
||||
{:messages (:album message)
|
||||
:index index}])}
|
||||
[fast-image/fast-image
|
||||
{:style (style/image dimensions index portrait? images-count)
|
||||
:source {:uri (url/replace-port (:image (:content item)) media-server-port)}
|
||||
:native-ID (when (and (= animation-shared-element-id (:message-id item))
|
||||
:native-ID (when (and (= shared-element-id (:message-id item))
|
||||
(< index constants/max-album-photos))
|
||||
:shared-element)}]
|
||||
(when (and (> images-count constants/max-album-photos)
|
||||
@@ -82,11 +71,11 @@
|
||||
:size :heading-2
|
||||
:style {:color colors/white}}
|
||||
(str "+" (- images-count (dec constants/max-album-photos)))]])]))
|
||||
album-messages)]]
|
||||
(:album message))]]
|
||||
[:<>
|
||||
(map-indexed
|
||||
(fn [index item]
|
||||
[:<> {:key (:message-id item)}
|
||||
[image/image-message index item {:on-long-press #(on-long-press message context)}
|
||||
message-container-data]])
|
||||
album-messages)])))
|
||||
(:album message))])))
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
[react-native.fast-image :as fast-image]
|
||||
[react-native.safe-area :as safe-area]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.chat.messenger.messages.content.lightbox.utils :as lightbox-utils]
|
||||
[status-im.contexts.chat.messenger.messages.content.lightbox.view :as lightbox]
|
||||
[status-im.contexts.chat.messenger.messages.content.text.view :as text]
|
||||
[utils.re-frame :as rf]
|
||||
[utils.url :as url]))
|
||||
@@ -41,7 +39,7 @@
|
||||
image-height
|
||||
max-container-width
|
||||
max-container-height)
|
||||
animation-shared-element-id (rf/sub [:animation-shared-element-id])
|
||||
shared-element-id (rf/sub [:shared-element-id])
|
||||
image-local-url (url/replace-port (:image content) (rf/sub [:mediaserver/port]))]
|
||||
[:<>
|
||||
(when (= index 0)
|
||||
@@ -50,16 +48,13 @@
|
||||
{:active-opacity 1
|
||||
:style {:margin-top 4}
|
||||
:on-long-press on-long-press
|
||||
:on-press #(rf/dispatch [:lightbox/navigate-to-lightbox
|
||||
:on-press #(rf/dispatch [:chat.ui/navigate-to-lightbox
|
||||
message-id
|
||||
{:images [(lightbox-utils/convert-message-to-lightbox-image
|
||||
message)]
|
||||
:index 0
|
||||
:insets insets
|
||||
:bottom-text-component
|
||||
[lightbox/bottom-text-for-lightbox message]}])}
|
||||
{:messages [message]
|
||||
:index 0
|
||||
:insets insets}])}
|
||||
[fast-image/fast-image
|
||||
{:source {:uri image-local-url}
|
||||
:style (merge dimensions {:border-radius 12})
|
||||
:native-ID (when (= animation-shared-element-id message-id) :shared-element)
|
||||
:native-ID (when (= shared-element-id message-id) :shared-element)
|
||||
:accessibility-label :image-message}]]]))
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
(ns status-im.contexts.chat.messenger.messages.content.lightbox.style
|
||||
(:require
|
||||
[quo.foundations.colors :as colors]))
|
||||
|
||||
(defn bottom-text
|
||||
[expandable-text?]
|
||||
{:color colors/white
|
||||
:margin-horizontal 20
|
||||
:align-items (when-not expandable-text? :center)
|
||||
:flex-grow 1})
|
||||
@@ -1,14 +0,0 @@
|
||||
(ns status-im.contexts.chat.messenger.messages.content.lightbox.utils
|
||||
(:require
|
||||
[utils.datetime :as datetime]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn convert-message-to-lightbox-image
|
||||
[{:keys [timestamp image-width image-height message-id from content]}]
|
||||
(let [[primary-name _] (rf/sub [:contacts/contact-two-names-by-identity from])]
|
||||
{:image (:image content)
|
||||
:image-width image-width
|
||||
:image-height image-height
|
||||
:id message-id
|
||||
:header primary-name
|
||||
:description (when timestamp (datetime/to-short-str timestamp))}))
|
||||
@@ -1,18 +0,0 @@
|
||||
(ns status-im.contexts.chat.messenger.messages.content.lightbox.view
|
||||
(:require
|
||||
[oops.core :as oops]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.common.lightbox.constants :as constants]
|
||||
[status-im.contexts.chat.messenger.messages.content.lightbox.style :as style]
|
||||
[status-im.contexts.chat.messenger.messages.content.text.view :as message-view]))
|
||||
|
||||
(defn bottom-text-for-lightbox
|
||||
[_]
|
||||
(let [text-height (reagent/atom 0)]
|
||||
(fn [{:keys [content chat-id] :as _message}]
|
||||
(let [expandable-text? (> @text-height (* constants/line-height 2))]
|
||||
[message-view/render-parsed-text
|
||||
{:content content
|
||||
:chat-id chat-id
|
||||
:style-override (style/bottom-text expandable-text?)
|
||||
:on-layout #(reset! text-height (oops/oget % "nativeEvent.layout.height"))}]))))
|
||||
@@ -6,7 +6,6 @@
|
||||
[legacy.status-im.chat.models.message :as models.message]
|
||||
[legacy.status-im.data-store.activities :as data-store.activities]
|
||||
[legacy.status-im.data-store.chats :as data-store.chats]
|
||||
[legacy.status-im.data-store.communities :as data-store.communities]
|
||||
[legacy.status-im.data-store.invitations :as data-store.invitations]
|
||||
[legacy.status-im.group-chats.core :as models.group]
|
||||
[legacy.status-im.multiaccounts.update.core :as update.core]
|
||||
@@ -128,7 +127,7 @@
|
||||
(seq requests-to-join-community)
|
||||
(let [requests (->> requests-to-join-community
|
||||
types/js->clj
|
||||
(map data-store.communities/<-request-to-join-community-rpc))]
|
||||
(map communities/<-request-to-join-community-rpc))]
|
||||
(js-delete response-js "requestsToJoinCommunity")
|
||||
(rf/merge cofx
|
||||
(process-next response-js sync-handler)
|
||||
|
||||
@@ -6,28 +6,25 @@
|
||||
[status-im.common.password-authentication.view :as password-authentication]
|
||||
[status-im.contexts.communities.actions.accounts-selection.style :as style]
|
||||
[status-im.contexts.communities.actions.community-rules.view :as community-rules]
|
||||
[status-im.contexts.communities.utils :as communities.utils]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- join-community-and-navigate-back
|
||||
[id]
|
||||
(rf/dispatch [:password-authentication/show {:content (fn [] [password-authentication/view])}
|
||||
(rf/dispatch [:password-authentication/show
|
||||
{:content (fn [] [password-authentication/view])}
|
||||
{:label (i18n/label :t/join-open-community)
|
||||
:on-press #(rf/dispatch [:communities/request-to-join-with-addresses
|
||||
{:community-id id :password %}])}])
|
||||
{:community-id id
|
||||
:password %}])}])
|
||||
(rf/dispatch [:navigate-back]))
|
||||
|
||||
(defn f-view-internal
|
||||
[]
|
||||
(let [{id :community-id} (rf/sub [:get-screen-params])
|
||||
{:keys [name color images]} (rf/sub [:communities/community id])
|
||||
airdrop-account (rf/sub [:communities/airdrop-account id])
|
||||
selected-accounts (rf/sub [:communities/selected-permission-accounts id])
|
||||
{:keys [highest-permission-role]} (rf/sub [:community/token-gated-overview id])
|
||||
highest-role-text (i18n/label (communities.utils/role->translation-key
|
||||
highest-permission-role
|
||||
:t/member))]
|
||||
(let [{id :community-id} (rf/sub [:get-screen-params])
|
||||
{:keys [name color images]} (rf/sub [:communities/community id])
|
||||
airdrop-account (rf/sub [:communities/airdrop-account id])
|
||||
selected-accounts (rf/sub [:communities/selected-permission-accounts id])]
|
||||
[rn/view {:style style/container}
|
||||
[quo/page-nav
|
||||
{:text-align :left
|
||||
@@ -51,7 +48,7 @@
|
||||
(i18n/label :t/address-to-share)]
|
||||
[quo/category
|
||||
{:list-type :settings
|
||||
:data [{:title (i18n/label :t/join-as-a {:role highest-role-text})
|
||||
:data [{:title (i18n/label :t/join-as-a-member)
|
||||
:on-press #(rf/dispatch [:open-modal :addresses-for-permissions
|
||||
{:community-id id}])
|
||||
:description :text
|
||||
|
||||
@@ -13,10 +13,3 @@
|
||||
:gap 4
|
||||
:justify-content :center
|
||||
:margin-bottom 8})
|
||||
|
||||
(def highest-role
|
||||
{:flex-direction :row
|
||||
:gap 4
|
||||
:justify-content :center
|
||||
:align-items :center
|
||||
:margin-bottom 8})
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
[react-native.core :as rn]
|
||||
[status-im.common.not-implemented :as not-implemented]
|
||||
[status-im.contexts.communities.actions.addresses-for-permissions.style :as style]
|
||||
[status-im.contexts.communities.utils :as communities.utils]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
@@ -23,14 +22,10 @@
|
||||
|
||||
(defn view
|
||||
[]
|
||||
(let [{id :community-id} (rf/sub [:get-screen-params])
|
||||
(let [{id :community-id} (rf/sub [:get-screen-params])
|
||||
{:keys [name color images]} (rf/sub [:communities/community id])
|
||||
{:keys [highest-permission-role]} (rf/sub [:community/token-gated-overview id])
|
||||
accounts (rf/sub [:wallet/accounts-with-customization-color])
|
||||
selected-addresses (rf/sub [:communities/selected-permission-addresses id])
|
||||
highest-role-text
|
||||
(i18n/label
|
||||
(communities.utils/role->translation-key highest-permission-role))]
|
||||
accounts (rf/sub [:wallet/accounts-with-customization-color])
|
||||
selected-addresses (rf/sub [:communities/selected-permission-addresses id])]
|
||||
[rn/safe-area-view {:style style/container}
|
||||
[quo/drawer-top
|
||||
{:type :context-tag
|
||||
@@ -48,19 +43,6 @@
|
||||
:key-fn :address
|
||||
:data accounts}]
|
||||
|
||||
(when (and highest-permission-role (seq selected-addresses))
|
||||
[rn/view
|
||||
{:style style/highest-role}
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:style {:color colors/neutral-50}}
|
||||
(i18n/label :t/eligible-to-join-as {:role ""})]
|
||||
[quo/context-tag
|
||||
{:type :icon
|
||||
:icon :i/members
|
||||
:size 24
|
||||
:context highest-role-text}]])
|
||||
|
||||
(when (empty? selected-addresses)
|
||||
[rn/view
|
||||
{:style style/error-message}
|
||||
|
||||
@@ -1,56 +1,96 @@
|
||||
(ns status-im.contexts.communities.events
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[legacy.status-im.data-store.chats :as data-store.chats]
|
||||
[legacy.status-im.data-store.communities :as data-store.communities]
|
||||
[legacy.status-im.mailserver.core :as mailserver]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.share :as share]
|
||||
[schema.core :as schema]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.chat.messenger.messages.link-preview.events :as link-preview.events]
|
||||
status-im.contexts.communities.actions.community-options.events
|
||||
status-im.contexts.communities.actions.leave.events
|
||||
[status-im.navigation.events :as navigation]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
(:require [clojure.set :as set]
|
||||
[clojure.string :as string]
|
||||
[clojure.walk :as walk]
|
||||
[legacy.status-im.data-store.chats :as data-store.chats]
|
||||
[legacy.status-im.mailserver.core :as mailserver]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.share :as share]
|
||||
[schema.core :as schema]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.chat.messenger.messages.link-preview.events :as link-preview.events]
|
||||
status-im.contexts.communities.actions.community-options.events
|
||||
status-im.contexts.communities.actions.leave.events
|
||||
[status-im.navigation.events :as navigation]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn handle-community
|
||||
[{:keys [db]} [community-js]]
|
||||
(when community-js
|
||||
(let [{:keys [token-permissions
|
||||
token-permissions-check joined id]
|
||||
:as community} (data-store.communities/<-rpc community-js)
|
||||
has-channel-perm? (fn [id-perm-tuple]
|
||||
(let [{:keys [type]} (second id-perm-tuple)]
|
||||
(or (= type constants/community-token-permission-can-view-channel)
|
||||
(=
|
||||
type
|
||||
constants/community-token-permission-can-view-and-post-channel))))]
|
||||
{:db (assoc-in db [:communities id] community)
|
||||
:fx [[:dispatch [:communities/initialize-permission-addresses id]]
|
||||
(when (not joined)
|
||||
[:dispatch [:chat.ui/spectate-community id]])
|
||||
(when (nil? token-permissions-check)
|
||||
[:dispatch [:communities/check-permissions-to-join-community id]])
|
||||
(when (some has-channel-perm? token-permissions)
|
||||
[:dispatch [:communities/check-all-community-channels-permissions id]])
|
||||
(when joined
|
||||
[:dispatch [:communities/get-revealed-accounts id]])]})))
|
||||
(defn <-request-to-join-community-rpc
|
||||
[r]
|
||||
(set/rename-keys r
|
||||
{:communityId :community-id
|
||||
:publicKey :public-key
|
||||
:chatId :chat-id}))
|
||||
|
||||
(rf/reg-event-fx :communities/handle-community handle-community)
|
||||
(defn <-requests-to-join-community-rpc
|
||||
[requests key-fn]
|
||||
(reduce #(assoc %1 (key-fn %2) (<-request-to-join-community-rpc %2)) {} requests))
|
||||
|
||||
(schema/=> handle-community
|
||||
[:=>
|
||||
[:catn
|
||||
[:cofx :schema.re-frame/cofx]
|
||||
[:args
|
||||
[:schema [:catn [:community-js map?]]]]]
|
||||
[:maybe
|
||||
[:map
|
||||
[:db [:map [:communities map?]]]
|
||||
[:fx vector?]]]])
|
||||
(defn <-chats-rpc
|
||||
[chats]
|
||||
(reduce-kv (fn [acc k v]
|
||||
(assoc acc
|
||||
(name k)
|
||||
(-> v
|
||||
(assoc :can-post? (:canPost v))
|
||||
(dissoc :canPost)
|
||||
(update :members walk/stringify-keys))))
|
||||
{}
|
||||
chats))
|
||||
|
||||
(defn <-categories-rpc
|
||||
[categ]
|
||||
(reduce-kv #(assoc %1 (name %2) %3) {} categ))
|
||||
|
||||
(defn <-rpc
|
||||
[c]
|
||||
(-> c
|
||||
(set/rename-keys {:canRequestAccess :can-request-access?
|
||||
:canManageUsers :can-manage-users?
|
||||
:canDeleteMessageForEveryone :can-delete-message-for-everyone?
|
||||
:canJoin :can-join?
|
||||
:requestedToJoinAt :requested-to-join-at
|
||||
:isMember :is-member?
|
||||
:adminSettings :admin-settings
|
||||
:tokenPermissions :token-permissions
|
||||
:communityTokensMetadata :tokens-metadata
|
||||
:introMessage :intro-message
|
||||
:muteTill :muted-till})
|
||||
(update :admin-settings
|
||||
set/rename-keys
|
||||
{:pinMessageAllMembersEnabled :pin-message-all-members-enabled?})
|
||||
(update :members walk/stringify-keys)
|
||||
(update :chats <-chats-rpc)
|
||||
(update :token-permissions seq)
|
||||
(update :categories <-categories-rpc)
|
||||
(assoc :token-images
|
||||
(reduce (fn [acc {sym :symbol image :image}]
|
||||
(assoc acc sym image))
|
||||
{}
|
||||
(:communityTokensMetadata c)))))
|
||||
|
||||
(rf/reg-event-fx :communities/handle-community
|
||||
(fn [{:keys [db]}
|
||||
[community-js]]
|
||||
(when community-js
|
||||
(let [{:keys [token-permissions
|
||||
token-permissions-check joined id]
|
||||
:as community} (<-rpc community-js)
|
||||
has-channel-perm? (fn [id-perm-tuple]
|
||||
(let [{:keys [type]} (second id-perm-tuple)]
|
||||
(or (= type constants/community-token-permission-can-view-channel)
|
||||
(=
|
||||
type
|
||||
constants/community-token-permission-can-view-and-post-channel))))]
|
||||
{:db (assoc-in db [:communities id] community)
|
||||
:fx [[:dispatch [:communities/initialize-permission-addresses id]]
|
||||
(when (not joined)
|
||||
[:dispatch [:chat.ui/spectate-community id]])
|
||||
(when (nil? token-permissions-check)
|
||||
[:dispatch [:communities/check-permissions-to-join-community id]])
|
||||
(when (some has-channel-perm? token-permissions)
|
||||
[:dispatch [:communities/check-all-community-channels-permissions id]])]}))))
|
||||
|
||||
(rf/defn handle-removed-chats
|
||||
[{:keys [db]} chat-ids]
|
||||
@@ -124,7 +164,7 @@
|
||||
(fn [{:keys [db]} [requests]]
|
||||
{:db (assoc db
|
||||
:communities/my-pending-requests-to-join
|
||||
(data-store.communities/<-requests-to-join-community-rpc requests :communityId))}))
|
||||
(<-requests-to-join-community-rpc requests :communityId))}))
|
||||
|
||||
(rf/reg-event-fx :communities/get-user-requests-to-join
|
||||
(fn [_]
|
||||
@@ -200,19 +240,12 @@
|
||||
|
||||
(defn toggle-selected-permission-address
|
||||
[{:keys [db]} [address community-id]]
|
||||
(let [selected-permission-addresses
|
||||
(get-in db [:communities community-id :selected-permission-addresses])
|
||||
updated-selected-permission-addresses
|
||||
(if (contains? selected-permission-addresses address)
|
||||
(disj selected-permission-addresses address)
|
||||
(conj selected-permission-addresses address))]
|
||||
{:db (assoc-in db
|
||||
[:communities community-id :selected-permission-addresses]
|
||||
updated-selected-permission-addresses)
|
||||
:fx [(when community-id
|
||||
[:dispatch
|
||||
[:communities/check-permissions-to-join-community community-id
|
||||
updated-selected-permission-addresses :based-on-client-selection]])]}))
|
||||
{:db (update-in db
|
||||
[:communities community-id :selected-permission-addresses]
|
||||
(fn [selected-addresses]
|
||||
(if (contains? selected-addresses address)
|
||||
(disj selected-addresses address)
|
||||
(conj selected-addresses address))))})
|
||||
|
||||
(rf/reg-event-fx :communities/toggle-selected-permission-address
|
||||
toggle-selected-permission-address)
|
||||
@@ -222,8 +255,7 @@
|
||||
(when community-id
|
||||
{:db (assoc-in db
|
||||
[:communities community-id :selected-permission-addresses]
|
||||
(get-in db [:communities community-id :previous-permission-addresses]))
|
||||
:fx [[:dispatch [:communities/check-permissions-to-join-community community-id]]]})))
|
||||
(get-in db [:communities community-id :previous-permission-addresses]))})))
|
||||
|
||||
(rf/reg-event-fx :communities/share-community-channel-url-with-data
|
||||
(fn [_ [chat-id]]
|
||||
@@ -373,54 +405,3 @@
|
||||
(if pop-to-root?
|
||||
[:dispatch [:chat/pop-to-root-and-navigate-to-chat chat-id]]
|
||||
[:dispatch [:chat/navigate-to-chat chat-id]])]})))
|
||||
|
||||
(defn get-revealed-accounts
|
||||
[{:keys [db]} [community-id]]
|
||||
(let [{:keys [joined fetching-revealed-accounts]
|
||||
:as community} (get-in db [:communities community-id])]
|
||||
(when (and community joined (not fetching-revealed-accounts))
|
||||
{:db (assoc-in db [:communities community-id :fetching-revealed-accounts] true)
|
||||
:json-rpc/call
|
||||
[{:method "wakuext_getRevealedAccounts"
|
||||
:params [community-id (get-in db [:profile/profile :public-key])]
|
||||
:js-response true
|
||||
:on-success [:communities/get-revealed-accounts-success community-id]
|
||||
:on-error (fn [err]
|
||||
(log/error {:message "failed to fetch revealed accounts"
|
||||
:community-id community-id
|
||||
:err err})
|
||||
(rf/dispatch [:communities/get-revealed-accounts-failed community-id]))}]})))
|
||||
|
||||
(rf/reg-event-fx :communities/get-revealed-accounts get-revealed-accounts)
|
||||
|
||||
(schema/=> get-revealed-accounts
|
||||
[:=>
|
||||
[:catn
|
||||
[:cofx :schema.re-frame/cofx]
|
||||
[:args
|
||||
[:schema [:catn [:community-id [:? :string]]]]]]
|
||||
[:maybe
|
||||
[:map
|
||||
[:db map?]
|
||||
[:json-rpc/call :schema.common/rpc-call]]]])
|
||||
|
||||
(rf/reg-event-fx :communities/get-revealed-accounts-success
|
||||
(fn [{:keys [db]} [community-id revealed-accounts-js]]
|
||||
(when-let [community (get-in db [:communities community-id])]
|
||||
(let [revealed-accounts
|
||||
(reduce
|
||||
(fn [acc {:keys [address] :as revealed-account}]
|
||||
(assoc acc address (dissoc revealed-account :address)))
|
||||
{}
|
||||
(data-store.communities/<-revealed-accounts-rpc revealed-accounts-js))
|
||||
|
||||
community-with-revealed-accounts
|
||||
(-> community
|
||||
(assoc :revealed-accounts revealed-accounts)
|
||||
(dissoc :fetching-revealed-accounts))]
|
||||
{:db (assoc-in db [:communities community-id] community-with-revealed-accounts)}))))
|
||||
|
||||
(rf/reg-event-fx :communities/get-revealed-accounts-failed
|
||||
(fn [{:keys [db]} [community-id]]
|
||||
(when (get-in db [:communities community-id])
|
||||
{:db (update-in db [:communities community-id] dissoc :fetching-revealed-accounts)})))
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
(:require [cljs.test :refer [deftest is testing]]
|
||||
[legacy.status-im.mailserver.core :as mailserver]
|
||||
matcher-combinators.test
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.chat.messenger.messages.link-preview.events :as link-preview.events]
|
||||
[status-im.contexts.communities.events :as events]))
|
||||
|
||||
@@ -194,79 +193,3 @@
|
||||
(is (match?
|
||||
nil
|
||||
(events/spectate-community-success {} []))))))
|
||||
|
||||
(deftest get-revealed-accounts
|
||||
(let [community {:id community-id}]
|
||||
(testing "given a unjoined community"
|
||||
(is (match?
|
||||
nil
|
||||
(events/get-revealed-accounts {:db {:communities {community-id community}}} [community-id]))))
|
||||
(testing "given a already :fetching-revealed-accounts community"
|
||||
(is (match?
|
||||
nil
|
||||
(events/get-revealed-accounts
|
||||
{:db {:communities {community-id (assoc community :fetching-revealed-accounts true)}}}
|
||||
[community-id]))))
|
||||
(testing "given joined community"
|
||||
(let [community (assoc community :joined true)
|
||||
db {:communities {community-id community}
|
||||
:profile/profile {:public-key "profile-public-key"}}
|
||||
effects (events/get-revealed-accounts {:db db} [community-id])]
|
||||
(is (match? (assoc-in db [:communities community-id :fetching-revealed-accounts] true)
|
||||
(:db effects)))
|
||||
(is (match? {:method "wakuext_getRevealedAccounts"
|
||||
:params [community-id "profile-public-key"]}
|
||||
(-> effects :json-rpc/call first (select-keys [:method :params]))))))))
|
||||
|
||||
(deftest handle-community
|
||||
(let [community {:id community-id}]
|
||||
(testing "given a unjoined community"
|
||||
(let [effects (events/handle-community {} [community])]
|
||||
(is (match? community-id
|
||||
(-> effects :db :communities (get community-id) :id)))
|
||||
(is (match?
|
||||
[[:dispatch [:communities/initialize-permission-addresses community-id]]
|
||||
[:dispatch [:chat.ui/spectate-community community-id]]
|
||||
[:dispatch [:communities/check-permissions-to-join-community community-id]]]
|
||||
(filter some? (:fx effects))))))
|
||||
(testing "given a joined community"
|
||||
(let [community (assoc community :joined true)
|
||||
effects (events/handle-community {} [community])]
|
||||
(is (match?
|
||||
[[:dispatch [:communities/initialize-permission-addresses community-id]]
|
||||
[:dispatch [:communities/check-permissions-to-join-community community-id]]
|
||||
[:dispatch [:communities/get-revealed-accounts community-id]]]
|
||||
(filter some? (:fx effects))))))
|
||||
(testing "given a community with token-permissions-check"
|
||||
(let [community (assoc community :token-permissions-check :fake-token-permissions-check)
|
||||
effects (events/handle-community {} [community])]
|
||||
(is (match?
|
||||
[[:dispatch [:communities/initialize-permission-addresses community-id]]
|
||||
[:dispatch [:chat.ui/spectate-community community-id]]]
|
||||
(filter some? (:fx effects))))))
|
||||
(testing "given a community with view channel permission"
|
||||
(let [community (assoc community
|
||||
:token-permissions
|
||||
[["perm-id" {:type constants/community-token-permission-can-view-channel}]])
|
||||
effects (events/handle-community {} [community])]
|
||||
(is (match?
|
||||
[[:dispatch [:communities/initialize-permission-addresses community-id]]
|
||||
[:dispatch [:chat.ui/spectate-community community-id]]
|
||||
[:dispatch [:communities/check-permissions-to-join-community community-id]]
|
||||
[:dispatch
|
||||
[:communities/check-all-community-channels-permissions community-id]]]
|
||||
(filter some? (:fx effects))))))
|
||||
|
||||
(testing "given a community with post in channel permission"
|
||||
(let [community (assoc community
|
||||
:token-permissions
|
||||
[["perm-id"
|
||||
{:type constants/community-token-permission-can-view-and-post-channel}]])
|
||||
effects (events/handle-community {} [community])]
|
||||
(is (match?
|
||||
[[:dispatch [:communities/initialize-permission-addresses community-id]]
|
||||
[:dispatch [:chat.ui/spectate-community community-id]]
|
||||
[:dispatch [:communities/check-permissions-to-join-community community-id]]
|
||||
[:dispatch
|
||||
[:communities/check-all-community-channels-permissions community-id]]]
|
||||
(filter some? (:fx effects))))))))
|
||||
|
||||
@@ -34,31 +34,26 @@
|
||||
:communities/check-all-community-channels-permissions}))}]]]})))
|
||||
|
||||
(rf/reg-event-fx :communities/check-permissions-to-join-community-success
|
||||
(fn [{:keys [db]} [community-id based-on-client-selection? result]]
|
||||
(let [token-permissions-check (cond-> result
|
||||
based-on-client-selection? (assoc :based-on-client-selection? true))]
|
||||
{:db (-> db
|
||||
(assoc-in [:communities community-id :checking-permissions?] false)
|
||||
(assoc-in [:communities community-id :token-permissions-check]
|
||||
token-permissions-check))})))
|
||||
(fn [{:keys [db]} [community-id result]]
|
||||
{:db (-> db
|
||||
(assoc-in [:communities community-id :checking-permissions?] false)
|
||||
(assoc-in [:communities community-id :token-permissions-check] result))}))
|
||||
|
||||
(rf/reg-event-fx :communities/check-permissions-to-join-community-failed
|
||||
(fn [{:keys [db]} [community-id]]
|
||||
{:db (assoc-in db [:communities community-id :checking-permissions?] false)}))
|
||||
|
||||
(rf/reg-event-fx :communities/check-permissions-to-join-community
|
||||
(fn [{:keys [db]} [community-id addresses based-on-client-selection?]]
|
||||
(fn [{:keys [db]} [community-id]]
|
||||
(when-let [community (get-in db [:communities community-id])]
|
||||
(when-not (:checking-permissions? community)
|
||||
{:db (-> db
|
||||
(assoc-in [:communities community-id :checking-permissions?] true)
|
||||
(assoc-in [:communities community-id :can-request-access?] false))
|
||||
:json-rpc/call [{:method "wakuext_checkPermissionsToJoinCommunity"
|
||||
:params [(cond-> {:communityId community-id}
|
||||
addresses
|
||||
(assoc :addresses addresses))]
|
||||
:params [{:communityId community-id}]
|
||||
:on-success [:communities/check-permissions-to-join-community-success
|
||||
community-id based-on-client-selection?]
|
||||
community-id]
|
||||
:on-error (fn [err]
|
||||
(rf/dispatch
|
||||
[:communities/check-permissions-to-join-community-failed
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
[status-im.contexts.communities.actions.community-options.view :as options]
|
||||
[status-im.contexts.communities.overview.style :as style]
|
||||
[status-im.contexts.communities.overview.utils :as utils]
|
||||
[status-im.contexts.communities.utils :as communities.utils]
|
||||
[utils.debounce :as debounce]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
@@ -141,11 +140,7 @@
|
||||
[]
|
||||
(fn [{:keys [id color]}]
|
||||
(let [{:keys [can-request-access?
|
||||
number-of-hold-tokens tokens
|
||||
highest-permission-role]} (rf/sub [:community/token-gated-overview id])
|
||||
highest-role-text
|
||||
(i18n/label
|
||||
(communities.utils/role->translation-key highest-permission-role :t/member))]
|
||||
number-of-hold-tokens tokens]} (rf/sub [:community/token-gated-overview id])]
|
||||
[rn/view {:style (style/token-gated-container)}
|
||||
[rn/view
|
||||
{:style {:padding-horizontal 12
|
||||
@@ -155,7 +150,7 @@
|
||||
:flex 1}}
|
||||
[quo/text {:weight :medium}
|
||||
(if can-request-access?
|
||||
(i18n/label :t/you-eligible-to-join-as {:role highest-role-text})
|
||||
(i18n/label :t/you-eligible-to-join)
|
||||
(i18n/label :t/you-not-eligible-to-join))]
|
||||
[info-button]]
|
||||
(when (pos? number-of-hold-tokens)
|
||||
@@ -168,26 +163,23 @@
|
||||
{:tokens tokens
|
||||
:padding? true}]
|
||||
[quo/button
|
||||
{:on-press
|
||||
(if config/community-accounts-selection-enabled?
|
||||
#(rf/dispatch [:open-modal :community-account-selection {:community-id id}])
|
||||
#(join-gated-community id))
|
||||
{:on-press #(join-gated-community id)
|
||||
:accessibility-label :join-community-button
|
||||
:customization-color color
|
||||
:container-style {:margin-horizontal 12 :margin-top 12 :margin-bottom 12}
|
||||
:disabled? (not can-request-access?)
|
||||
:icon-left (if can-request-access? :i/unlocked :i/locked)}
|
||||
:container-style {:margin-horizontal 12 :margin-top 12 :margin-bottom 12}
|
||||
:disabled? (not can-request-access?)
|
||||
:icon-left (if can-request-access? :i/unlocked :i/locked)}
|
||||
(i18n/label :t/join-open-community)]])))
|
||||
|
||||
(defn join-community
|
||||
[{:keys [joined color permissions token-permissions membership-permissions? id] :as community}
|
||||
[{:keys [joined color permissions token-permissions id] :as community}
|
||||
pending?]
|
||||
(let [access-type (get-access-type (:access permissions))
|
||||
unknown-access? (= access-type :unknown-access)
|
||||
invite-only? (= access-type :invite-only)]
|
||||
[:<>
|
||||
(when-not (or joined pending? invite-only? unknown-access?)
|
||||
(if membership-permissions?
|
||||
(if (seq token-permissions)
|
||||
[token-gates community]
|
||||
[quo/button
|
||||
{:on-press
|
||||
@@ -198,7 +190,7 @@
|
||||
:accessibility-label :show-request-to-join-screen-button
|
||||
:customization-color color
|
||||
:icon-left :i/communities}
|
||||
(i18n/label :t/request-to-join)]))
|
||||
(i18n/label :t/request-to-join-community)]))
|
||||
|
||||
(when (not (or joined pending? token-permissions))
|
||||
[quo/text
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
(ns status-im.contexts.communities.utils
|
||||
(:require
|
||||
[status-im.constants :as constants]))
|
||||
|
||||
(defn role->translation-key
|
||||
([role] (role->translation-key role nil))
|
||||
([role fallback-to]
|
||||
(condp = role
|
||||
constants/community-token-permission-become-token-owner :t/token-owner
|
||||
constants/community-token-permission-become-token-master :t/token-master
|
||||
constants/community-token-permission-become-admin :t/admin
|
||||
constants/community-token-permission-become-member :t/member
|
||||
fallback-to)))
|
||||
@@ -2,7 +2,6 @@
|
||||
(:require
|
||||
[quo.foundations.colors :as colors]
|
||||
[react-native.platform :as platform]
|
||||
[react-native.reanimated :as reanimated]
|
||||
[status-im.contexts.shell.jump-to.utils :as utils]))
|
||||
|
||||
(defn bottom-tabs-container
|
||||
@@ -29,11 +28,10 @@
|
||||
|
||||
(defn bottom-tabs-blur-overlay
|
||||
[height]
|
||||
(reanimated/apply-animations-to-style
|
||||
{:height height}
|
||||
[{:height height}
|
||||
{:position :absolute
|
||||
:left 0
|
||||
:right 0
|
||||
:bottom 0
|
||||
:height (utils/bottom-tabs-container-height)
|
||||
:background-color colors/neutral-100-opa-70-blur}))
|
||||
:background-color colors/neutral-100-opa-70-blur}])
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
(ns status-im.contexts.shell.share.wallet.style
|
||||
(:require
|
||||
[quo.foundations.colors :as colors]))
|
||||
|
||||
(defn indicator-wrapper-style
|
||||
[active?]
|
||||
{:width 8
|
||||
:height 8
|
||||
:border-radius 4
|
||||
:background-color colors/white
|
||||
:opacity (if active? 1.0 0.5)})
|
||||
|
||||
(def indicator-list-style
|
||||
{:display :flex
|
||||
:flex-direction :row
|
||||
:align-items :center
|
||||
:justify-content :center
|
||||
:gap 8})
|
||||
@@ -6,7 +6,6 @@
|
||||
[react-native.share :as share]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.contexts.shell.share.style :as style]
|
||||
[status-im.contexts.shell.share.wallet.style :as wallet-style]
|
||||
[status-im.contexts.wallet.common.sheets.network-preferences.view :as network-preferences]
|
||||
[status-im.contexts.wallet.common.utils :as utils]
|
||||
[utils.i18n :as i18n]
|
||||
@@ -44,11 +43,10 @@
|
||||
(rf/dispatch [:hide-bottom-sheet])
|
||||
(reset! selected-networks (map #(get utils/id->network %)
|
||||
chain-ids)))}])}]))
|
||||
(defn- wallet-qr-code-item-internal
|
||||
[props]
|
||||
(let [{:keys [account width index]} props
|
||||
selected-networks (reagent/atom [:ethereum :optimism :arbitrum])
|
||||
wallet-type (reagent/atom :wallet-legacy)]
|
||||
(defn wallet-qr-code-item
|
||||
[account width index]
|
||||
(let [selected-networks (reagent/atom [:ethereum :optimism :arbitrum])
|
||||
wallet-type (reagent/atom :wallet-legacy)]
|
||||
(fn []
|
||||
(let [share-title (str (:name account) " " (i18n/label :t/address))
|
||||
qr-url (utils/get-wallet-qr {:wallet-type @wallet-type
|
||||
@@ -59,7 +57,7 @@
|
||||
:port (rf/sub [:mediaserver/port])
|
||||
:qr-size qr-size
|
||||
:error-level :highest})]
|
||||
[rn/view {:style {:height qr-size :width width :margin-left (if (zero? index) 0 -30)}}
|
||||
[rn/view {:style {:width width :margin-left (if (zero? index) 0 -30)}}
|
||||
[rn/view {:style style/qr-code-container}
|
||||
[quo/share-qr-code
|
||||
{:type @wallet-type
|
||||
@@ -75,54 +73,18 @@
|
||||
:on-legacy-press #(reset! wallet-type :wallet-legacy)
|
||||
:on-settings-press #(open-preferences @selected-networks)}]]]))))
|
||||
|
||||
(def wallet-qr-code-item (memoize wallet-qr-code-item-internal))
|
||||
|
||||
(defn- indicator
|
||||
[active?]
|
||||
[rn/view
|
||||
{:style (wallet-style/indicator-wrapper-style active?)}])
|
||||
|
||||
(defn- indicator-list
|
||||
[indicator-count current-index]
|
||||
[rn/view
|
||||
{:style wallet-style/indicator-list-style}
|
||||
(for [i (range indicator-count)]
|
||||
(let [current-index (cond (<= current-index 0) 0
|
||||
(>= current-index (dec indicator-count)) (dec indicator-count)
|
||||
:else current-index)]
|
||||
^{:key i} [indicator (= current-index i)]))])
|
||||
|
||||
(defn render-item
|
||||
[item]
|
||||
(let [width (rf/sub [:dimensions/window-width])]
|
||||
[wallet-qr-code-item
|
||||
{:account item
|
||||
:index (:position item)
|
||||
:width width}]))
|
||||
|
||||
(defn wallet-tab
|
||||
[]
|
||||
(let [accounts (rf/sub [:wallet/accounts])
|
||||
width (rf/sub [:dimensions/window-width])
|
||||
current-index (reagent/atom 0)]
|
||||
(fn []
|
||||
[rn/view
|
||||
[rn/flat-list
|
||||
{:horizontal true
|
||||
:deceleration-rate 0.9
|
||||
:snap-to-alignment :start
|
||||
:snap-to-interval (- width 30)
|
||||
:disable-interval-momentum true
|
||||
:scroll-event-throttle 64
|
||||
:data accounts
|
||||
:directional-lock-enabled true
|
||||
:shows-horizontal-scroll-indicator false
|
||||
:on-scroll (fn [e]
|
||||
(reset! current-index (js/Math.ceil
|
||||
(/ e.nativeEvent.contentOffset.x
|
||||
width))))
|
||||
:render-fn render-item}]
|
||||
(when (> (count accounts) 1)
|
||||
[rn/view
|
||||
{:style {:margin-top 20}}
|
||||
(indicator-list (count accounts) @current-index)])])))
|
||||
(let [accounts (rf/sub [:wallet/accounts])
|
||||
width (rf/sub [:dimensions/window-width])]
|
||||
[rn/flat-list
|
||||
{:horizontal true
|
||||
:deceleration-rate 0.9
|
||||
:snap-to-alignment "start"
|
||||
:snap-to-interval (- width 30)
|
||||
:disable-interval-momentum true
|
||||
:scroll-event-throttle 64
|
||||
:data accounts
|
||||
:directional-lock-enabled true
|
||||
:render-fn (fn [account index]
|
||||
(wallet-qr-code-item account width index))}]))
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
[quo.core :as quo]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.config :as config]
|
||||
[status-im.contexts.wallet.account.style :as style]
|
||||
[status-im.contexts.wallet.account.tabs.view :as tabs]
|
||||
[status-im.contexts.wallet.common.account-switcher.view :as account-switcher]
|
||||
@@ -53,9 +52,7 @@
|
||||
:receive-action #(rf/dispatch [:open-modal :wallet-share-address {:status :receive}])
|
||||
:buy-action #(rf/dispatch [:show-bottom-sheet
|
||||
{:content buy-drawer}])
|
||||
:bridge-action (if (:bridge-token config/wallet-feature-flags)
|
||||
#(rf/dispatch [:open-modal :wallet-bridge])
|
||||
#(js/alert "feature disabled in config file"))}])
|
||||
:bridge-action #(rf/dispatch [:open-modal :wallet-bridge])}])
|
||||
[quo/tabs
|
||||
{:style style/tabs
|
||||
:size 32
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
[quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[status-im.contexts.wallet.collectible.tabs.about.style :as style]
|
||||
[status-im.contexts.wallet.temp :as temp]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
@@ -13,8 +14,7 @@
|
||||
(let [window-width (rf/sub [:dimensions/window-width])
|
||||
item-width (- (/ window-width 2) link-card-space)
|
||||
{:keys [collectible-data]} (rf/sub [:wallet/last-collectible-details])
|
||||
link-card-container-style (style/link-card item-width)
|
||||
collectible-about {:cards []}]
|
||||
link-card-container-style (style/link-card item-width)]
|
||||
[:<>
|
||||
[rn/view {:style style/title}
|
||||
[quo/text
|
||||
@@ -25,13 +25,12 @@
|
||||
[quo/text
|
||||
{:size :paragraph-2}
|
||||
(:description collectible-data)]]
|
||||
(when (count collectible-about)
|
||||
[quo/section-label
|
||||
{:container-style style/section-label
|
||||
:section (i18n/label :t/on-the-web)}]
|
||||
[rn/view {:style style/link-cards-container}
|
||||
(for [item (:cards collectible-about)]
|
||||
^{:key (:title item)}
|
||||
[quo/link-card (assoc item :container-style link-card-container-style)])])]))
|
||||
[quo/section-label
|
||||
{:container-style style/section-label
|
||||
:section (i18n/label :t/on-the-web)}]
|
||||
[rn/view {:style style/link-cards-container}
|
||||
(for [item (:cards temp/collectible-about)]
|
||||
^{:key (:title item)}
|
||||
[quo/link-card (assoc item :container-style link-card-container-style)])]]))
|
||||
|
||||
(def view (quo.theme/with-theme view-internal))
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
(ns status-im.contexts.wallet.collectible.tabs.activity.view
|
||||
(:require [quo.core :as quo]
|
||||
[react-native.core :as rn]))
|
||||
[react-native.core :as rn]
|
||||
[status-im.contexts.wallet.temp :as temp]))
|
||||
|
||||
(defn activity-item
|
||||
[item]
|
||||
@@ -11,6 +12,6 @@
|
||||
(defn view
|
||||
[]
|
||||
[rn/flat-list
|
||||
{:data nil
|
||||
{:data temp/collectible-activities
|
||||
:style {:flex 1}
|
||||
:render-fn activity-item}])
|
||||
|
||||
@@ -75,14 +75,12 @@
|
||||
(let [selected-tab (reagent/atom :overview)
|
||||
on-tab-change #(reset! selected-tab %)]
|
||||
(fn []
|
||||
(let [collectible (rf/sub [:wallet/last-collectible-details])
|
||||
animation-shared-element-id (rf/sub [:animation-shared-element-id])
|
||||
(let [collectible (rf/sub [:wallet/last-collectible-details])
|
||||
{:keys [collectible-data preview-url
|
||||
collection-data id]} collectible
|
||||
token-id (:token-id id)
|
||||
collection-data]} collectible
|
||||
{collection-image :image-url
|
||||
collection-name :name} collection-data
|
||||
{collectible-name :name} collectible-data]
|
||||
collection-name :name} collection-data
|
||||
{collectible-name :name} collectible-data]
|
||||
[scroll-page/scroll-page
|
||||
{:navigate-back? true
|
||||
:height 148
|
||||
@@ -97,26 +95,9 @@
|
||||
:picture preview-url}}
|
||||
[rn/view {:style style/container}
|
||||
[rn/view {:style style/preview-container}
|
||||
[rn/touchable-opacity
|
||||
{:active-opacity 1
|
||||
:on-press #(rf/dispatch [:lightbox/navigate-to-lightbox
|
||||
token-id
|
||||
{:images [{:image preview-url
|
||||
:image-width 300 ; collectibles don't have
|
||||
; width/height but we need
|
||||
; to pass something
|
||||
:image-height 300 ; without it animation
|
||||
; doesn't work smoothly and
|
||||
; :border-radius not
|
||||
; applied
|
||||
:id token-id
|
||||
:header collectible-name
|
||||
:description collection-name}]
|
||||
:index 0}])}
|
||||
[rn/image
|
||||
{:source preview-url
|
||||
:style style/preview
|
||||
:native-ID (when (= animation-shared-element-id token-id) :shared-element)}]]]
|
||||
[rn/image
|
||||
{:source preview-url
|
||||
:style style/preview}]]
|
||||
[header collectible-name collection-name collection-image]
|
||||
[cta-buttons]
|
||||
[quo/tabs
|
||||
|
||||
@@ -32,13 +32,12 @@
|
||||
|
||||
(defn- options
|
||||
[{:keys [theme show-account-selector? options-height]}]
|
||||
(let [{:keys [name color emoji address watch-only?
|
||||
default-account?]} (rf/sub [:wallet/current-viewing-account])
|
||||
network-preference-details (rf/sub [:wallet/network-preference-details])
|
||||
multichain-address (utils/get-multichain-address
|
||||
network-preference-details
|
||||
address)
|
||||
share-title (i18n/label :t/share-address-title {:address name})]
|
||||
(let [{:keys [name color emoji address watch-only?]} (rf/sub [:wallet/current-viewing-account])
|
||||
network-preference-details (rf/sub [:wallet/network-preference-details])
|
||||
multichain-address (utils/get-multichain-address
|
||||
network-preference-details
|
||||
address)
|
||||
share-title (str name " " (i18n/label :t/address))]
|
||||
[rn/view
|
||||
{:on-layout #(reset! options-height (oops/oget % "nativeEvent.layout.height"))
|
||||
:style (when show-account-selector? style/options-container)}
|
||||
@@ -93,16 +92,15 @@
|
||||
#(rf/dispatch [:wallet/share-account
|
||||
{:title share-title :content multichain-address}])
|
||||
600))}
|
||||
(when-not default-account?
|
||||
{:add-divider? (not show-account-selector?)
|
||||
:icon :i/delete
|
||||
:accessibility-label :remove-account
|
||||
:label (i18n/label :t/remove-account)
|
||||
:danger? true
|
||||
:on-press #(rf/dispatch [:show-bottom-sheet
|
||||
{:content
|
||||
(fn []
|
||||
[remove-account/view])}])})]]]
|
||||
{:add-divider? (not show-account-selector?)
|
||||
:icon :i/delete
|
||||
:accessibility-label :remove-account
|
||||
:label (i18n/label :t/remove-account)
|
||||
:danger? true
|
||||
:on-press #(rf/dispatch [:show-bottom-sheet
|
||||
{:content
|
||||
(fn []
|
||||
[remove-account/view])}])}]]]
|
||||
(when show-account-selector?
|
||||
[:<>
|
||||
[quo/divider-line {:container-style style/divider-label}]
|
||||
|
||||
@@ -11,17 +11,13 @@
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- footer
|
||||
[{:keys [address submit-disabled? toast-message]}]
|
||||
[{:keys [submit-disabled?]}]
|
||||
[quo/bottom-actions
|
||||
{:actions :2-actions
|
||||
:customization-color :danger
|
||||
:button-one-label (i18n/label :t/remove)
|
||||
:button-one-props {:on-press
|
||||
(fn []
|
||||
(rf/dispatch [:wallet/remove-account
|
||||
{:address address
|
||||
:toast-message toast-message}]))
|
||||
:type :danger
|
||||
:button-one-props {:on-press #(js/alert "Will be implemented")
|
||||
:type :danger
|
||||
:disabled? submit-disabled?}
|
||||
:button-two-label (i18n/label :t/cancel)
|
||||
:button-two-props {:on-press #(rf/dispatch [:hide-bottom-sheet])
|
||||
@@ -30,7 +26,7 @@
|
||||
(defn- recovery-phase-flow
|
||||
[]
|
||||
(let [confirmed? (reagent/atom false)]
|
||||
(fn [{:keys [address name emoji path color] :as _account}]
|
||||
(fn [{:keys [name emoji path color] :as _account}]
|
||||
(let [formatted-path (utils/format-derivation-path path)]
|
||||
[:<>
|
||||
[quo/drawer-top
|
||||
@@ -68,13 +64,10 @@
|
||||
:checked? @confirmed?
|
||||
:on-change #(swap! confirmed? not)}]
|
||||
[quo/text (i18n/label :t/remove-account-confirmation)]]
|
||||
[footer
|
||||
{:submit-disabled? (not @confirmed?)
|
||||
:address address
|
||||
:toast-message (i18n/label :t/account-removed)}]]))))
|
||||
[footer {:submit-disabled? (not @confirmed?)}]]))))
|
||||
|
||||
(defn- watched-address-flow
|
||||
[{:keys [address name emoji color] :as _account}]
|
||||
[{:keys [name emoji color] :as _account}]
|
||||
[:<>
|
||||
[quo/drawer-top
|
||||
{:title (i18n/label :t/remove-watched-address-title)
|
||||
@@ -86,17 +79,13 @@
|
||||
[rn/view {:style style/desc-container}
|
||||
[quo/text {:weight :medium}
|
||||
(i18n/label :t/remove-watched-address-desc)]]
|
||||
[footer
|
||||
{:submit-disabled? false
|
||||
:address address
|
||||
:toast-message (i18n/label :t/watched-account-removed)}]])
|
||||
[footer {:submit-disabled? false}]])
|
||||
|
||||
(defn- view-internal
|
||||
[]
|
||||
(let [{:keys [type] :as account} (rf/sub [:wallet/current-viewing-account])]
|
||||
(case type
|
||||
:generated [recovery-phase-flow account]
|
||||
:watch [watched-address-flow account]
|
||||
nil)))
|
||||
:watch [watched-address-flow account])))
|
||||
|
||||
(def view (quo.theme/with-theme view-internal))
|
||||
|
||||
@@ -185,11 +185,6 @@
|
||||
constants/arbitrum-chain-id :arbitrum
|
||||
constants/arbitrum-test-chain-id :arbitrum})
|
||||
|
||||
(def short-name->id
|
||||
{:eth constants/mainnet-chain-id
|
||||
:opt constants/optimism-chain-id
|
||||
:arb1 constants/arbitrum-chain-id})
|
||||
|
||||
(defn get-standard-fiat-format
|
||||
[crypto-value currency-symbol fiat-value]
|
||||
(if (string/includes? crypto-value "<")
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
[reagent.core :as reagent]
|
||||
[status-im.common.emoji-picker.utils :as emoji-picker.utils]
|
||||
[status-im.common.standard-authentication.core :as standard-auth]
|
||||
[status-im.config :as config]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.common.utils :as utils]
|
||||
[status-im.contexts.wallet.create-account.style :as style]
|
||||
@@ -32,9 +31,7 @@
|
||||
:size :xxs
|
||||
:customization-color account-color}
|
||||
:action :button
|
||||
:action-props {:on-press (if (:edit-default-keypair config/wallet-feature-flags)
|
||||
#(rf/dispatch [:navigate-to :wallet-select-keypair])
|
||||
#(js/alert "feature disabled in config file"))
|
||||
:action-props {:on-press #(rf/dispatch [:navigate-to :wallet-select-keypair])
|
||||
:button-text (i18n/label :t/edit)
|
||||
:alignment :flex-start}
|
||||
:description :text
|
||||
@@ -43,7 +40,7 @@
|
||||
:image :icon
|
||||
:image-props :i/derivated-path
|
||||
:action :button
|
||||
:action-props {:on-press #(js/alert "Coming soon!")
|
||||
:action-props {:on-press #(js/alert "Button pressed!")
|
||||
:button-text (i18n/label :t/edit)
|
||||
:icon-left :i/placeholder
|
||||
:alignment :flex-start}
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
(update :test-preferred-chain-ids chain-ids-string->set)
|
||||
(update :type keyword)
|
||||
(update :color #(if (seq %) (keyword %) constants/account-default-customization-color))
|
||||
(assoc :default-account? (:wallet account))
|
||||
add-keys-to-account))
|
||||
|
||||
(defn rpc->accounts
|
||||
@@ -50,8 +49,7 @@
|
||||
:color :colorId})
|
||||
(update :prodPreferredChainIds chain-ids-set->string)
|
||||
(update :testPreferredChainIds chain-ids-set->string)
|
||||
(dissoc :watch-only?)
|
||||
(dissoc :default-account?)))
|
||||
(dissoc :watch-only?)))
|
||||
|
||||
(defn- rpc->balances-per-chain
|
||||
[token]
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
:updated-key :name
|
||||
:new-value @edited-account-name}))]
|
||||
(fn []
|
||||
(let [{:keys [name emoji address color watch-only? default-account?]
|
||||
(let [{:keys [name emoji address color watch-only?]
|
||||
:as account} (rf/sub [:wallet/current-viewing-account])
|
||||
network-details (rf/sub [:wallet/network-preference-details])
|
||||
test-networks-enabled? (rf/sub [:profile/test-networks-enabled?])
|
||||
@@ -62,14 +62,13 @@
|
||||
button-disabled? (or (nil? @edited-account-name)
|
||||
(= name @edited-account-name))]
|
||||
[create-or-edit-account/view
|
||||
{:page-nav-right-side [(when-not default-account?
|
||||
{:icon-name :i/delete
|
||||
:on-press
|
||||
(fn []
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:content
|
||||
(fn []
|
||||
[remove-account/view])}]))})]
|
||||
{:page-nav-right-side [{:icon-name :i/delete
|
||||
:on-press
|
||||
(fn []
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
{:content
|
||||
(fn []
|
||||
[remove-account/view])}]))}]
|
||||
:account-name account-name
|
||||
:account-emoji emoji
|
||||
:account-color color
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
[status-im.contexts.wallet.data-store :as data-store]
|
||||
[status-im.contexts.wallet.events.collectibles]
|
||||
[status-im.contexts.wallet.item-types :as item-types]
|
||||
[status-im.contexts.wallet.temp :as temp]
|
||||
[taoensso.timbre :as log]
|
||||
[utils.collection]
|
||||
[utils.ethereum.chain :as chain]
|
||||
[utils.ethereum.eip.eip55 :as eip55]
|
||||
[utils.i18n :as i18n]
|
||||
@@ -52,9 +52,10 @@
|
||||
wallet-db (get db :wallet)
|
||||
new-account? (:new-account? wallet-db)
|
||||
navigate-to-account (:navigate-to-account wallet-db)]
|
||||
{:db (assoc-in db
|
||||
[:wallet :accounts]
|
||||
(utils.collection/index-by :address (data-store/rpc->accounts wallet-accounts)))
|
||||
{:db (reduce (fn [db {:keys [address] :as account}]
|
||||
(assoc-in db [:wallet :accounts address] account))
|
||||
db
|
||||
(data-store/rpc->accounts wallet-accounts))
|
||||
:fx [[:dispatch [:wallet/get-wallet-token]]
|
||||
[:dispatch [:wallet/request-collectibles {:start-at-index 0 :new-request? true}]]
|
||||
(when new-account?
|
||||
@@ -84,30 +85,6 @@
|
||||
{:error %
|
||||
:event :wallet/save-account})}]]]}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet/show-account-deleted-toast
|
||||
(fn [_ [toast-message]]
|
||||
{:fx [[:dispatch [:toasts/upsert {:type :positive :text toast-message}]]]}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet/remove-account-success
|
||||
(fn [_ [toast-message _]]
|
||||
{:fx [[:dispatch [:hide-bottom-sheet]]
|
||||
[:dispatch [:pop-to-root :shell-stack]]
|
||||
[:dispatch [:wallet/get-accounts]]
|
||||
[:dispatch [:wallet/show-account-deleted-toast toast-message]]]}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet/remove-account
|
||||
(fn [_ [{:keys [address toast-message]}]]
|
||||
{:fx [[:json-rpc/call
|
||||
[{:method "accounts_deleteAccount"
|
||||
:params [address]
|
||||
:on-success [:wallet/remove-account-success toast-message]
|
||||
:on-error #(log/info "failed to remove account "
|
||||
{:error %
|
||||
:event :wallet/remove-account})}]]]}))
|
||||
|
||||
(rf/reg-event-fx
|
||||
:wallet/get-wallet-token
|
||||
(fn [{:keys [db]}]
|
||||
@@ -157,10 +134,10 @@
|
||||
|
||||
(rf/reg-event-fx :wallet/create-derived-addresses
|
||||
(fn [{:keys [db]} [{:keys [sha3-pwd path]} on-success]]
|
||||
(let [{:keys [address]} (:profile/profile db)]
|
||||
(let [{:keys [wallet-root-address]} (:profile/profile db)]
|
||||
{:fx [[:json-rpc/call
|
||||
[{:method "wallet_getDerivedAddresses"
|
||||
:params [sha3-pwd address [path]]
|
||||
:params [sha3-pwd wallet-root-address [path]]
|
||||
:on-success on-success
|
||||
:on-error #(log/info "failed to derive address " %)}]]]})))
|
||||
|
||||
@@ -265,15 +242,30 @@
|
||||
|
||||
|
||||
(rf/reg-event-fx :wallet/fetch-address-suggestions
|
||||
(fn [{:keys [db]} [_address]]
|
||||
(fn [{:keys [db]} [address]]
|
||||
{:db (assoc db
|
||||
:wallet/local-suggestions nil
|
||||
:wallet/valid-ens-or-address? false)}))
|
||||
:wallet/local-suggestions
|
||||
(cond
|
||||
(= address
|
||||
(get-in
|
||||
temp/address-local-suggestion-saved-contact-address-mock
|
||||
[:accounts 0 :address]))
|
||||
[temp/address-local-suggestion-saved-contact-address-mock]
|
||||
(= address
|
||||
(get temp/address-local-suggestion-saved-address-mock
|
||||
:address))
|
||||
[temp/address-local-suggestion-saved-address-mock]
|
||||
:else (temp/find-matching-addresses address))
|
||||
:wallet/valid-ens-or-address?
|
||||
false)}))
|
||||
|
||||
(rf/reg-event-fx :wallet/ens-validation-success
|
||||
(fn [{:keys [db]} [_ens]]
|
||||
(fn [{:keys [db]} [ens]]
|
||||
{:db (assoc db
|
||||
:wallet/local-suggestions nil
|
||||
:wallet/local-suggestions (if (= ens
|
||||
(:ens temp/ens-local-suggestion-saved-address-mock))
|
||||
[temp/ens-local-suggestion-saved-address-mock]
|
||||
[temp/ens-local-suggestion-mock])
|
||||
:wallet/valid-ens-or-address? true)}))
|
||||
|
||||
(rf/reg-event-fx :wallet/address-validation-success
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
(:require
|
||||
[camel-snake-kebab.core :as csk]
|
||||
[camel-snake-kebab.extras :as cske]
|
||||
[clojure.string :as string]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contexts.wallet.common.utils :as utils]
|
||||
[status-im.contexts.wallet.send.utils :as send-utils]
|
||||
@@ -58,23 +57,16 @@
|
||||
|
||||
(rf/reg-event-fx :wallet/select-send-address
|
||||
(fn [{:keys [db]} [{:keys [address token recipient stack-id]}]]
|
||||
(let [[prefix to-address] (utils/split-prefix-and-address address)
|
||||
prefix-seq (string/split prefix #":")
|
||||
selected-networks (mapv #(utils/short-name->id (keyword %)) prefix-seq)]
|
||||
(let [[prefix to-address] (utils/split-prefix-and-address address)]
|
||||
{:db (-> db
|
||||
(assoc-in [:wallet :ui :send :recipient] (or recipient address))
|
||||
(assoc-in [:wallet :ui :send :to-address] to-address)
|
||||
(assoc-in [:wallet :ui :send :address-prefix] prefix)
|
||||
(assoc-in [:wallet :ui :send :selected-networks] selected-networks))
|
||||
(assoc-in [:wallet :ui :send :address-prefix] prefix))
|
||||
:fx [[:navigate-to-within-stack
|
||||
(if token
|
||||
[:wallet-send-input-amount stack-id]
|
||||
[:wallet-select-asset stack-id])]]})))
|
||||
|
||||
(rf/reg-event-fx :wallet/update-receiver-networks
|
||||
(fn [{:keys [db]} [selected-networks]]
|
||||
{:db (assoc-in db [:wallet :ui :send :selected-networks] selected-networks)}))
|
||||
|
||||
(rf/reg-event-fx :wallet/send-select-token
|
||||
(fn [{:keys [db]} [{:keys [token stack-id]}]]
|
||||
{:db (assoc-in db [:wallet :ui :send :token] token)
|
||||
@@ -100,11 +92,10 @@
|
||||
(let [wallet-address (get-in db [:wallet :current-viewing-account-address])
|
||||
token (get-in db [:wallet :ui :send :token])
|
||||
account-address (get-in db [:wallet :ui :send :send-account-address])
|
||||
selected-networks (get-in db [:wallet :ui :send :selected-networks])
|
||||
to-address (or account-address (get-in db [:wallet :ui :send :to-address]))
|
||||
token-decimal (:decimals token)
|
||||
token-id (:symbol token)
|
||||
network-preferences selected-networks
|
||||
network-preferences []
|
||||
gas-rates constants/gas-rate-medium
|
||||
amount-in (send-utils/amount-in-hex amount token-decimal)
|
||||
from-address wallet-address
|
||||
|
||||
@@ -44,8 +44,7 @@
|
||||
:market-values-per-currency {:usd {:price 10}}}
|
||||
:wallet/wallet-send-loading-suggested-routes? false
|
||||
:wallet/wallet-send-route {:route []}
|
||||
:wallet/wallet-send-suggested-routes {:candidates []}
|
||||
:wallet/wallet-send-selected-networks []})
|
||||
:wallet/wallet-send-suggested-routes {:candidates []}})
|
||||
|
||||
(h/describe "Send > input amount screen"
|
||||
(h/setup-restorable-re-frame)
|
||||
|
||||
@@ -54,6 +54,13 @@
|
||||
(normalize-input current v)
|
||||
current))
|
||||
|
||||
(defn- find-affordable-networks
|
||||
[{:keys [balances-per-chain]} input-value]
|
||||
(->> balances-per-chain
|
||||
(filter (fn [[_ {:keys [balance]}]]
|
||||
(>= (js/parseFloat balance) input-value)))
|
||||
(map first)))
|
||||
|
||||
(defn- reset-input-error
|
||||
[new-value prev-value input-error]
|
||||
(reset! input-error
|
||||
@@ -122,22 +129,21 @@
|
||||
(<= input-num-value 0)
|
||||
(> input-num-value (:amount @current-limit)))
|
||||
amount (str @input-value " " token-symbol)
|
||||
{:keys [color]} (rf/sub [:wallet/current-viewing-account])
|
||||
fetch-routes (fn []
|
||||
(rf/dispatch [:wallet/clean-suggested-routes])
|
||||
(when-not (or
|
||||
(empty? @input-value)
|
||||
(<= input-num-value 0)
|
||||
(> input-num-value (:amount @current-limit)))
|
||||
(debounce/debounce-and-dispatch [:wallet/get-suggested-routes
|
||||
@input-value]
|
||||
100)))]
|
||||
{:keys [color]} (rf/sub [:wallet/current-viewing-account])]
|
||||
(rn/use-effect
|
||||
(fn []
|
||||
(let [dismiss-keyboard-fn #(when (= % "active") (rn/dismiss-keyboard!))
|
||||
app-keyboard-listener (.addEventListener rn/app-state "change" dismiss-keyboard-fn)]
|
||||
#(.remove app-keyboard-listener))))
|
||||
(rn/use-effect #(fetch-routes) [@input-value])
|
||||
(rn/use-effect (fn []
|
||||
(rf/dispatch [:wallet/clean-suggested-routes])
|
||||
(when-not (or
|
||||
(empty? @input-value)
|
||||
(<= input-num-value 0)
|
||||
(> input-num-value (:amount @current-limit)))
|
||||
(debounce/debounce-and-dispatch [:wallet/get-suggested-routes @input-value]
|
||||
100)))
|
||||
[@input-value])
|
||||
[rn/view
|
||||
{:style style/screen
|
||||
:accessibility-label (str "container" (when @input-error "-error"))}
|
||||
@@ -160,11 +166,10 @@
|
||||
:on-change-text (fn [text]
|
||||
(handle-on-change text))}]
|
||||
[routes/view
|
||||
{:amount amount
|
||||
:routes suggested-routes
|
||||
:token token
|
||||
:input-value @input-value
|
||||
:fetch-routes fetch-routes}]
|
||||
{:amount amount
|
||||
:routes suggested-routes
|
||||
:loading-networks (find-affordable-networks token @input-value)
|
||||
:networks (:networks token)}]
|
||||
[quo/bottom-actions
|
||||
{:actions :1-action
|
||||
:button-one-label (i18n/label :t/confirm)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
(ns status-im.contexts.wallet.send.routes.style
|
||||
(:require [quo.foundations.colors :as colors]))
|
||||
(ns status-im.contexts.wallet.send.routes.style)
|
||||
|
||||
(def routes-container
|
||||
{:padding-horizontal 20
|
||||
@@ -31,26 +30,3 @@
|
||||
{:flex-grow 1
|
||||
:align-items :center
|
||||
:justify-content :center})
|
||||
|
||||
(def add-network
|
||||
{:margin-top 8
|
||||
:align-self :flex-end
|
||||
:left 12})
|
||||
|
||||
(defn warning-container
|
||||
[color theme]
|
||||
{:flex-direction :row
|
||||
:border-width 1
|
||||
:border-color (colors/resolve-color color theme 10)
|
||||
:background-color (colors/resolve-color color theme 5)
|
||||
:margin-horizontal 20
|
||||
:margin-top 4
|
||||
:margin-bottom 8
|
||||
:padding-left 12
|
||||
:padding-vertical 11
|
||||
:border-radius 12})
|
||||
|
||||
(def warning-text
|
||||
{:margin-left 8
|
||||
:margin-right 12
|
||||
:padding-right 12})
|
||||
|
||||
@@ -1,134 +1,39 @@
|
||||
(ns status-im.contexts.wallet.send.routes.view
|
||||
(:require
|
||||
[clojure.string :as string]
|
||||
[quo.core :as quo]
|
||||
[quo.foundations.colors :as colors]
|
||||
[quo.foundations.resources :as resources]
|
||||
[quo.theme :as quo.theme]
|
||||
[react-native.core :as rn]
|
||||
[reagent.core :as reagent]
|
||||
[status-im.contexts.wallet.common.utils :as utils]
|
||||
[status-im.contexts.wallet.send.routes.style :as style]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn- find-affordable-networks
|
||||
[{:keys [balances-per-chain]} input-value selected-networks]
|
||||
(->> balances-per-chain
|
||||
(filter (fn [[_ {:keys [balance chain-id]}]]
|
||||
(and
|
||||
(>= (js/parseFloat balance) input-value)
|
||||
(some #(= % chain-id) selected-networks))))
|
||||
(map first)))
|
||||
|
||||
(defn- make-network-item
|
||||
[{:keys [network-name chain-id] :as _network}
|
||||
{:keys [title color on-change network-preferences] :as _options}]
|
||||
{:title (or title (string/capitalize (name network-name)))
|
||||
:image :icon-avatar
|
||||
:image-props {:icon (resources/get-network network-name)
|
||||
:size :size-20}
|
||||
:action :selector
|
||||
:action-props {:type :checkbox
|
||||
:customization-color color
|
||||
:checked? (some #(= % chain-id) @network-preferences)
|
||||
:on-change on-change}})
|
||||
|
||||
(defn networks-drawer
|
||||
[{:keys [fetch-routes theme]}]
|
||||
(let [network-details (rf/sub [:wallet/network-details])
|
||||
{:keys [color]} (rf/sub [:wallet/current-viewing-account])
|
||||
selected-networks (rf/sub [:wallet/wallet-send-selected-networks])
|
||||
prefix (rf/sub [:wallet/wallet-send-address-prefix])
|
||||
prefix-seq (string/split prefix #":")
|
||||
grouped-details (group-by #(contains? (set prefix-seq) (:short-name %)) network-details)
|
||||
preferred (get grouped-details true [])
|
||||
not-preferred (get grouped-details false [])
|
||||
network-preferences (reagent/atom selected-networks)
|
||||
toggle-network (fn [{:keys [chain-id]}]
|
||||
(swap! network-preferences
|
||||
(fn [preferences]
|
||||
(if (some #(= % chain-id) preferences)
|
||||
(vec (remove #(= % chain-id) preferences))
|
||||
(conj preferences chain-id)))))]
|
||||
(fn []
|
||||
[rn/view
|
||||
[quo/drawer-top {:title (i18n/label :t/edit-receiver-networks)}]
|
||||
[quo/category
|
||||
{:list-type :settings
|
||||
:label (i18n/label :t/preferred-by-receiver)
|
||||
:data (mapv (fn [network]
|
||||
(make-network-item network
|
||||
{:color color
|
||||
:network-preferences network-preferences
|
||||
:on-change #(toggle-network network)}))
|
||||
preferred)}]
|
||||
(when (pos? (count not-preferred))
|
||||
[quo/category
|
||||
{:list-type :settings
|
||||
:label (i18n/label :t/not-preferred-by-receiver)
|
||||
:data (mapv (fn [network]
|
||||
(make-network-item network
|
||||
{:color color
|
||||
:network-preferences network-preferences
|
||||
:on-change #(toggle-network network)}))
|
||||
not-preferred)}])
|
||||
(when (not= selected-networks @network-preferences)
|
||||
[rn/view {:style (style/warning-container color theme)}
|
||||
[quo/icon :i/info {:color (colors/resolve-color color theme)}]
|
||||
[quo/text
|
||||
{:size :paragraph-2
|
||||
:style style/warning-text} (i18n/label :t/receiver-networks-warning)]])
|
||||
[quo/bottom-actions
|
||||
{:button-one-label (i18n/label :t/apply-changes)
|
||||
:button-one-props {:disabled? (= selected-networks @network-preferences)
|
||||
:on-press (fn []
|
||||
(rf/dispatch [:wallet/update-receiver-networks
|
||||
@network-preferences])
|
||||
(rf/dispatch [:hide-bottom-sheet])
|
||||
(fetch-routes))
|
||||
:customization-color color}}]])))
|
||||
|
||||
(defn route-item
|
||||
[{:keys [amount from-network to-network status theme fetch-routes]}]
|
||||
(if (= status :add)
|
||||
[quo/network-bridge
|
||||
{:status :add
|
||||
:container-style style/add-network
|
||||
:on-press #(rf/dispatch [:show-bottom-sheet
|
||||
{:content (fn [] [networks-drawer
|
||||
{:theme theme
|
||||
:fetch-routes fetch-routes}])}])}]
|
||||
[rn/view {:style style/routes-inner-container}
|
||||
[quo/network-bridge
|
||||
{:amount amount
|
||||
:network from-network
|
||||
:status status}]
|
||||
(if (= status :default)
|
||||
[quo/network-link
|
||||
{:shape :linear
|
||||
:source from-network
|
||||
:destination to-network
|
||||
:container-style style/network-link}]
|
||||
[rn/view {:style {:width 73}}])
|
||||
[quo/network-bridge
|
||||
{:amount amount
|
||||
:network to-network
|
||||
:status status
|
||||
:container-style {:right 12}}]]))
|
||||
[{:keys [amount from-network to-network status]}]
|
||||
[rn/view {:style style/routes-inner-container}
|
||||
[quo/network-bridge
|
||||
{:amount amount
|
||||
:network from-network
|
||||
:status status}]
|
||||
(if (= status :default)
|
||||
[quo/network-link
|
||||
{:shape :linear
|
||||
:source from-network
|
||||
:destination to-network
|
||||
:container-style style/network-link}]
|
||||
[rn/view {:style {:width 73}}])
|
||||
[quo/network-bridge
|
||||
{:amount amount
|
||||
:network to-network
|
||||
:status status
|
||||
:container-style {:right 12}}]])
|
||||
|
||||
(defn- view-internal
|
||||
[{:keys [amount routes token input-value theme fetch-routes]}]
|
||||
(let [selected-networks (rf/sub [:wallet/wallet-send-selected-networks])
|
||||
loading-networks (find-affordable-networks token input-value selected-networks)
|
||||
loading-suggested-routes? (rf/sub [:wallet/wallet-send-loading-suggested-routes?])
|
||||
best-routes (:best routes)
|
||||
data (if loading-suggested-routes? loading-networks best-routes)]
|
||||
(if (or (and (not-empty loading-networks) loading-suggested-routes?) (not-empty best-routes))
|
||||
(defn view
|
||||
[{:keys [amount routes loading-networks]}]
|
||||
(let [loading-suggested-routes? (rf/sub [:wallet/wallet-send-loading-suggested-routes?])
|
||||
candidates (:candidates routes)]
|
||||
(if (or (and (not-empty loading-networks) loading-suggested-routes?) (not-empty candidates))
|
||||
[rn/flat-list
|
||||
{:data (if (and (< (count data) 3) (pos? (count data)))
|
||||
(concat data [{:status :add}])
|
||||
data)
|
||||
{:data (if loading-suggested-routes? loading-networks candidates)
|
||||
:content-container-style style/routes-container
|
||||
:header [rn/view {:style style/routes-header-container}
|
||||
[quo/section-label
|
||||
@@ -140,12 +45,7 @@
|
||||
:render-fn (fn [item]
|
||||
[route-item
|
||||
{:amount amount
|
||||
:theme theme
|
||||
:fetch-routes fetch-routes
|
||||
:status (cond
|
||||
(= (:status item) :add) :add
|
||||
loading-suggested-routes? :loading
|
||||
:else :default)
|
||||
:status (if loading-suggested-routes? :loading :default)
|
||||
:from-network (if loading-suggested-routes?
|
||||
(utils/id->network item)
|
||||
(utils/id->network (get-in item [:from :chain-id])))
|
||||
@@ -154,7 +54,5 @@
|
||||
(utils/id->network (get-in item
|
||||
[:to :chain-id])))}])}]
|
||||
[rn/view {:style style/empty-container}
|
||||
(when (and (not (nil? best-routes)) (not loading-suggested-routes?))
|
||||
(when (and (not (nil? candidates)) (not loading-suggested-routes?))
|
||||
[quo/text (i18n/label :t/no-routes-found)])])))
|
||||
|
||||
(def view (quo.theme/with-theme view-internal))
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
(ns status-im.contexts.wallet.temp
|
||||
(:require [clojure.string :as string]
|
||||
[quo.foundations.resources :as quo.resources]
|
||||
[status-im.common.resources :as resources]
|
||||
[status-im.contexts.wallet.item-types :as types]))
|
||||
|
||||
(def ens-local-suggestion-saved-address-mock
|
||||
{:type types/saved-address
|
||||
:name "Pedro"
|
||||
:ens "pedro.eth"
|
||||
:address "0x4732894732894738294783294723894723984"
|
||||
:customization-color :purple
|
||||
:networks [{:network-name :ethereum
|
||||
:short-name "eth"}
|
||||
{:network-name :optimism
|
||||
:short-name "opt"}]})
|
||||
|
||||
(def ens-local-suggestion-mock
|
||||
{:type types/address
|
||||
:ens "pedro.eth"
|
||||
:address "0x4732894732894738294783294723894723984"
|
||||
:networks [{:network-name :ethereum
|
||||
:short-name "eth"}
|
||||
{:network-name :optimism
|
||||
:short-name "opt"}]})
|
||||
|
||||
(def address-local-suggestion-saved-contact-address-mock
|
||||
{:type types/saved-contact-address
|
||||
:customization-color :blue
|
||||
:accounts [{:name "New House"
|
||||
:address "0x62cf6E0Ba4C4530735616e1Ee7ff5FbCB726fBd2"
|
||||
:emoji "🍔"
|
||||
:customization-color :blue}]
|
||||
:contact-props {:full-name "Mark Libot"
|
||||
:profile-picture (resources/get-mock-image :user-picture-male4)
|
||||
:customization-color :purple}})
|
||||
|
||||
(def address-local-suggestion-saved-address-mock
|
||||
{:type types/saved-address
|
||||
:name "Peter Lamborginski"
|
||||
:address "0x12FaBc34De56Ef78A9B0Cd12Ef3456AbC7D8E9F0"
|
||||
:customization-color :magenta
|
||||
:networks [{:network-name :ethereum
|
||||
:short-name "eth"}
|
||||
{:network-name :optimism
|
||||
:short-name "opt"}]})
|
||||
|
||||
(def address-local-suggestion-mock
|
||||
{:type types/address
|
||||
:address "0x1233cD34De56Ef78A9B0Cd12Ef3456AbC7123dee"
|
||||
:networks [{:network-name :ethereum
|
||||
:short-name "eth"}
|
||||
{:network-name :optimism
|
||||
:short-name "opt"}]})
|
||||
|
||||
(defn find-matching-addresses
|
||||
[substring]
|
||||
(let [all-addresses [address-local-suggestion-saved-address-mock
|
||||
address-local-suggestion-mock]]
|
||||
(vec (filter #(string/starts-with? (:address %) substring) all-addresses))))
|
||||
|
||||
(def collectible-activities
|
||||
[{:transaction :receive
|
||||
:timestamp "Today 22:20"
|
||||
:status :finalised
|
||||
:counter 1
|
||||
:first-tag {:size 24
|
||||
:type :collectible
|
||||
:collectible (resources/mock-images :collectible)
|
||||
:collectible-name "Collectible"
|
||||
:collectible-number "123"}
|
||||
:second-tag-prefix :t/from
|
||||
:second-tag {:size 24
|
||||
:type :default
|
||||
:full-name "Aretha Gosling"
|
||||
:profile-picture (resources/mock-images :user-picture-female2)}
|
||||
:third-tag-prefix :t/to
|
||||
:third-tag {:size 24
|
||||
:type :account
|
||||
:account-name "Piggy bank"
|
||||
:emoji "🐷"}
|
||||
|
||||
:fourth-tag-prefix :t/via
|
||||
:fourth-tag {:size 24
|
||||
:type :network
|
||||
:network-logo (quo.resources/get-network :ethereum)
|
||||
:network-name "Mainnet"}}
|
||||
{:transaction :mint
|
||||
:timestamp "Yesterday"
|
||||
:status :finalised
|
||||
:counter 1
|
||||
:first-tag {:size 24
|
||||
:type :collectible
|
||||
:collectible (resources/mock-images :collectible)
|
||||
:collectible-name "Collectible"
|
||||
:collectible-number "123"}
|
||||
:second-tag-prefix :t/at
|
||||
:second-tag
|
||||
{:size 24
|
||||
:type :address
|
||||
:address
|
||||
"0x04fcf40c526b09ff9fb22f4a5dbd08490ef9b64af700870f8a0ba2133f4251d5607ed83cd9047b8c2796576bc83fa0de23a13a4dced07654b8ff137fe744047917"}
|
||||
:third-tag-prefix :t/on
|
||||
:third-tag {:size 24
|
||||
:type :network
|
||||
:network-logo (quo.resources/get-network :ethereum)
|
||||
:network-name "Mainnet"}}])
|
||||
|
||||
(def collectible-about
|
||||
{:cards [{:title "BAYC"
|
||||
:icon :social/link
|
||||
:address "boredapeyachtclub"
|
||||
:customization-color :social/link
|
||||
:on-press #(js/alert "pressed")}
|
||||
{:title "Twitter"
|
||||
:icon :social/twitter
|
||||
:address "@BoredApeYC"
|
||||
:customization-color :social/twitter
|
||||
:on-press #(js/alert "pressed")}
|
||||
{:title "Opensea"
|
||||
:icon :social/opensea
|
||||
:address "Bored Ape Yacht Club"
|
||||
:customization-color :social/opensea
|
||||
:on-press #(js/alert "pressed")}]})
|
||||
@@ -2,13 +2,13 @@
|
||||
(:require
|
||||
[legacy.status-im.ui.screens.screens :as old-screens]
|
||||
[status-im.common.emoji-picker.view :as emoji-picker]
|
||||
[status-im.common.lightbox.view :as lightbox]
|
||||
[status-im.config :as config]
|
||||
[status-im.contexts.chat.group-details.view :as group-details]
|
||||
[status-im.contexts.chat.home.add-new-contact.scan.scan-profile-qr-page :as scan-profile-qr-page]
|
||||
[status-im.contexts.chat.home.add-new-contact.views :as add-new-contact]
|
||||
[status-im.contexts.chat.home.new-chat.view :as new-chat]
|
||||
[status-im.contexts.chat.messenger.camera.view :as camera-screen]
|
||||
[status-im.contexts.chat.messenger.lightbox.view :as lightbox]
|
||||
[status-im.contexts.chat.messenger.messages.view :as chat]
|
||||
[status-im.contexts.chat.messenger.photo-selector.view :as photo-selector]
|
||||
[status-im.contexts.communities.actions.accounts-selection.view :as communities.accounts-selection]
|
||||
|
||||
@@ -297,62 +297,32 @@
|
||||
(fn [collapsed-categories [_ community-id]]
|
||||
(get collapsed-categories community-id)))
|
||||
|
||||
(defn- permission-id->permission-value
|
||||
[token-permissions permission-id]
|
||||
(get (into {} token-permissions) permission-id))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:community/token-gated-overview
|
||||
(fn [[_ community-id]]
|
||||
[(re-frame/subscribe [:communities/community community-id])])
|
||||
(fn [[{:keys [token-permissions-check token-permissions checking-permissions? token-images]}] _]
|
||||
(let [can-request-access? (:satisfied token-permissions-check)
|
||||
role-permissions #{constants/community-token-permission-become-admin
|
||||
constants/community-token-permission-become-member
|
||||
constants/community-token-permission-become-token-master
|
||||
constants/community-token-permission-become-token-owner}
|
||||
highest-permission-role
|
||||
(when can-request-access?
|
||||
(->> token-permissions-check
|
||||
:permissions
|
||||
(reduce-kv
|
||||
(fn [highest-permission-role permission-id {:keys [criteria]}]
|
||||
(if-let [permission-type
|
||||
(and (first criteria)
|
||||
(some #{(:type (permission-id->permission-value token-permissions
|
||||
permission-id))}
|
||||
role-permissions))]
|
||||
(if highest-permission-role
|
||||
(min highest-permission-role permission-type)
|
||||
permission-type)
|
||||
highest-permission-role))
|
||||
nil)))
|
||||
highest-permission-role (if (and can-request-access? (nil? highest-permission-role))
|
||||
constants/community-token-permission-become-member
|
||||
highest-permission-role)]
|
||||
{:can-request-access? can-request-access?
|
||||
:highest-permission-role highest-permission-role
|
||||
:number-of-hold-tokens (reduce
|
||||
(fn [acc [_ {:keys [criteria]}]]
|
||||
(reduce #(+ %1 (if %2 1 0)) acc criteria))
|
||||
0
|
||||
(:permissions token-permissions-check))
|
||||
:tokens (->>
|
||||
token-permissions
|
||||
(filter (fn [[_ {:keys [type]}]]
|
||||
(= type constants/community-token-permission-become-member)))
|
||||
(map (fn [[perm-key {:keys [token_criteria]}]]
|
||||
(let [check-criteria (get-in token-permissions-check
|
||||
[:permissions perm-key :criteria])]
|
||||
(map
|
||||
(fn [{sym :symbol amount :amount} sufficient?]
|
||||
{:symbol sym
|
||||
:sufficient? (when (seq check-criteria) sufficient?)
|
||||
:loading? checking-permissions?
|
||||
:amount amount
|
||||
:img-src (get token-images sym)})
|
||||
token_criteria
|
||||
(or check-criteria token_criteria))))))})))
|
||||
{:can-request-access? (:satisfied token-permissions-check)
|
||||
:number-of-hold-tokens (reduce
|
||||
(fn [acc [_ {:keys [criteria]}]]
|
||||
(reduce #(+ %1 (if %2 1 0)) acc criteria))
|
||||
0
|
||||
(:permissions token-permissions-check))
|
||||
:tokens (->> token-permissions
|
||||
(filter (fn [[_ {:keys [type]}]]
|
||||
(= type constants/community-token-permission-become-member)))
|
||||
(map (fn [[perm-key {:keys [token_criteria]}]]
|
||||
(let [check-criteria (get-in token-permissions-check
|
||||
[:permissions perm-key :criteria])]
|
||||
(map
|
||||
(fn [{sym :symbol amount :amount} sufficient?]
|
||||
{:symbol sym
|
||||
:sufficient? (when (seq check-criteria) sufficient?)
|
||||
:loading? checking-permissions?
|
||||
:amount amount
|
||||
:img-src (get token-images sym)})
|
||||
token_criteria
|
||||
(or check-criteria token_criteria))))))}))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:community/images
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns status-im.subs.communities-test
|
||||
(:require
|
||||
[cljs.test :refer [is testing]]
|
||||
matcher-combinators.test
|
||||
[re-frame.db :as rf-db]
|
||||
[status-im.constants :as constants]
|
||||
status-im.subs.communities
|
||||
@@ -18,7 +17,7 @@
|
||||
(swap! rf-db/app-db assoc
|
||||
:communities
|
||||
raw-communities)
|
||||
(is (match? raw-communities (rf/sub [sub-name]))))))
|
||||
(is (= raw-communities (rf/sub [sub-name]))))))
|
||||
|
||||
(h/deftest-sub :communities/section-list
|
||||
[sub-name]
|
||||
@@ -27,29 +26,29 @@
|
||||
:communities
|
||||
{"0x1" {:name "civilized monkeys"}
|
||||
"0x2" {:name "Civilized rats"}})
|
||||
(is (match? [{:title "C"
|
||||
:data [{:name "civilized monkeys"}
|
||||
{:name "Civilized rats"}]}]
|
||||
(rf/sub [sub-name]))))
|
||||
(is (= [{:title "C"
|
||||
:data [{:name "civilized monkeys"}
|
||||
{:name "Civilized rats"}]}]
|
||||
(rf/sub [sub-name]))))
|
||||
|
||||
(testing "sorts by section ascending"
|
||||
(swap! rf-db/app-db assoc
|
||||
:communities
|
||||
{"0x3" {:name "Memorable"}
|
||||
"0x1" {:name "Civilized monkeys"}})
|
||||
(is (match? [{:title "C" :data [{:name "Civilized monkeys"}]}
|
||||
{:title "M" :data [{:name "Memorable"}]}]
|
||||
(rf/sub [sub-name]))))
|
||||
(is (= [{:title "C" :data [{:name "Civilized monkeys"}]}
|
||||
{:title "M" :data [{:name "Memorable"}]}]
|
||||
(rf/sub [sub-name]))))
|
||||
|
||||
(testing "builds default section for communities without a name"
|
||||
(swap! rf-db/app-db assoc
|
||||
:communities
|
||||
{"0x2" {:id "0x2"}
|
||||
"0x1" {:id "0x1"}})
|
||||
(is (match? [{:title ""
|
||||
:data [{:id "0x2"}
|
||||
{:id "0x1"}]}]
|
||||
(rf/sub [sub-name])))))
|
||||
(is (= [{:title ""
|
||||
:data [{:id "0x2"}
|
||||
{:id "0x1"}]}]
|
||||
(rf/sub [sub-name])))))
|
||||
|
||||
(h/deftest-sub :communities/unviewed-counts
|
||||
[sub-name]
|
||||
@@ -65,17 +64,17 @@
|
||||
"0x102" {:community-id community-id
|
||||
:unviewed-mentions-count 5
|
||||
:unviewed-messages-count 1}})
|
||||
(is (match? {:unviewed-messages-count 3
|
||||
:unviewed-mentions-count 8}
|
||||
(rf/sub [sub-name community-id]))))
|
||||
(is (= {:unviewed-messages-count 3
|
||||
:unviewed-mentions-count 8}
|
||||
(rf/sub [sub-name community-id]))))
|
||||
|
||||
(testing "defaults to zero when count keys are not present"
|
||||
(swap! rf-db/app-db assoc
|
||||
:chats
|
||||
{"0x100" {:community-id community-id}})
|
||||
(is (match? {:unviewed-messages-count 0
|
||||
:unviewed-mentions-count 0}
|
||||
(rf/sub [sub-name community-id])))))
|
||||
(is (= {:unviewed-messages-count 0
|
||||
:unviewed-mentions-count 0}
|
||||
(rf/sub [sub-name community-id])))))
|
||||
|
||||
(h/deftest-sub :communities/categorized-channels
|
||||
[sub-name]
|
||||
@@ -351,16 +350,16 @@
|
||||
(swap! rf-db/app-db assoc
|
||||
:communities/my-pending-requests-to-join
|
||||
{})
|
||||
(is (match? {}
|
||||
(rf/sub [sub-name]))))
|
||||
(is (= {}
|
||||
(rf/sub [sub-name]))))
|
||||
(testing "users requests to join different communities"
|
||||
(swap! rf-db/app-db assoc
|
||||
:communities/my-pending-requests-to-join
|
||||
{:community-id-1 {:id :request-id-1}
|
||||
:community-id-2 {:id :request-id-2}})
|
||||
(is (match? {:community-id-1 {:id :request-id-1}
|
||||
:community-id-2 {:id :request-id-2}}
|
||||
(rf/sub [sub-name])))))
|
||||
(is (= {:community-id-1 {:id :request-id-1}
|
||||
:community-id-2 {:id :request-id-2}}
|
||||
(rf/sub [sub-name])))))
|
||||
|
||||
(h/deftest-sub :communities/my-pending-request-to-join
|
||||
[sub-name]
|
||||
@@ -368,15 +367,15 @@
|
||||
(swap! rf-db/app-db assoc
|
||||
:communities/my-pending-requests-to-join
|
||||
{})
|
||||
(is (match? nil
|
||||
(rf/sub [sub-name :community-id-1]))))
|
||||
(is (= nil
|
||||
(rf/sub [sub-name :community-id-1]))))
|
||||
(testing "users request to join a specific communities"
|
||||
(swap! rf-db/app-db assoc
|
||||
:communities/my-pending-requests-to-join
|
||||
{:community-id-1 {:id :request-id-1}
|
||||
:community-id-2 {:id :request-id-2}})
|
||||
(is (match? :request-id-1
|
||||
(rf/sub [sub-name :community-id-1])))))
|
||||
(is (= :request-id-1
|
||||
(rf/sub [sub-name :community-id-1])))))
|
||||
|
||||
(h/deftest-sub :community/token-gated-overview
|
||||
[sub-name]
|
||||
@@ -386,7 +385,6 @@
|
||||
community {:id community-id
|
||||
:checking-permissions? checking-permissions?
|
||||
:permissions {:access 3}
|
||||
:highest-permission-role constants/community-token-permission-become-admin
|
||||
:token-images {"ETH" token-image-eth}
|
||||
:token-permissions [[:permission-id-01
|
||||
{:id "permission-id-01"
|
||||
@@ -453,14 +451,14 @@
|
||||
:outroMessage "bla"
|
||||
:verified false}]
|
||||
(swap! rf-db/app-db assoc-in [:communities community-id] community)
|
||||
(is (match? {:can-request-access? true
|
||||
:number-of-hold-tokens 2
|
||||
:tokens [[{:symbol "ETH"
|
||||
:amount "0.001"
|
||||
:sufficient? nil
|
||||
:loading? checking-permissions?
|
||||
:img-src token-image-eth}]]}
|
||||
(rf/sub [sub-name community-id])))))
|
||||
(is (= {:can-request-access? true
|
||||
:number-of-hold-tokens 2
|
||||
:tokens [[{:symbol "ETH"
|
||||
:amount "0.001"
|
||||
:sufficient? nil
|
||||
:loading? checking-permissions?
|
||||
:img-src token-image-eth}]]}
|
||||
(rf/sub [sub-name community-id])))))
|
||||
|
||||
(h/deftest-sub :communities/airdrop-account
|
||||
[sub-name]
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
;;view
|
||||
(reg-root-key-sub :view-id :view-id)
|
||||
(reg-root-key-sub :screen-params :navigation/screen-params)
|
||||
(reg-root-key-sub :animation-shared-element-id :animation-shared-element-id)
|
||||
(reg-root-key-sub :shared-element-id :shared-element-id)
|
||||
|
||||
;;bottom sheet
|
||||
(reg-root-key-sub :bottom-sheet :bottom-sheet)
|
||||
|
||||
@@ -48,11 +48,6 @@
|
||||
:<- [:wallet/wallet-send]
|
||||
:-> :address-prefix)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/wallet-send-selected-networks
|
||||
:<- [:wallet/wallet-send]
|
||||
:-> :selected-networks)
|
||||
|
||||
(rf/reg-sub
|
||||
:wallet/wallet-send-route
|
||||
:<- [:wallet/wallet-send]
|
||||
|
||||
@@ -45,27 +45,20 @@ class TestDeepLinksOneDevice(MultipleSharedDeviceTestCase):
|
||||
self.errors.append("Profile was not opened by the profile url %s" % url)
|
||||
self.home.navigate_back_to_chat_view()
|
||||
|
||||
closed_community_urls = {
|
||||
"https://status.app/c/G8EAAMR_fz8tsCQ-aR2QrCS5sVAvvzc_N3mAA-En_Zxy4JA3j7Dl1A50Pd4DbooQOMbWf7E1_4wipgDyGe8XZEappDn-Qomf9l_xyXhSYBuSQic8InCEUBSRGR0oixSTh3iw5ZCxzkGSI95Iyu1EBpcIlFOEMPHpKUBIdkkoKBJglMDKko8O8dBvBtIYncOA8mwztwLpx3C0rK_u59PldFuXe4cx#zQ3shwQnEfMtcXpHXF4qJPyCGgw2F18N3nbGzYbzsVHnMq4yK":
|
||||
"Status mobile QA community max",
|
||||
"https://status.app/c/GyoAAORtA48geFrtWr2mu-G5DnFaI0sgqUIIaBFX_DJ_mRbXmzoMnCJnqwI=#zQ3shQhL414wEjDJMEpgTjd14aHCiBDnk6Bq5YTWoi4b7wvnu":
|
||||
"test_comm_enc",
|
||||
"https://status.app/c/G00AAGS9TbI9mSR-ZNmFrhRjNuEeXAAbcAIUaLLJyjMOG3ACJQ12oIHD78QhzO9s_T5bUeU7rnATWJg3mGgTUemrAg==#zQ3shspPKCZ1VPVQ9dLXGufUGvGphjxVwrcZ6rkZc7S39T4b3":
|
||||
"closed community",
|
||||
"https://status.app/c/GyAAAOQbK4dMy1OMI8s2nGvJR3QRqBQqbExff0-cgmN0T-4C#zQ3shqQ4voo845RAkip2JkYTjL4dpiGnRhaNHjVDxPdEZ1xvP":
|
||||
"e2e_open",
|
||||
"https://status.app/c/G0UAAMTyNsn2QZDEG0EXftOl8pOEfwEBOOSA_YTfIk85xmADDgINGmxpUHAXzK36bN0fK42Xf4YD2yjPk1z2pbFwFw==#zQ3shgkDFQEnwxji7CvMTokMrShmC2UgxiJ549X5Aw746zQrK":
|
||||
"open community"
|
||||
}
|
||||
for url, text in closed_community_urls.items():
|
||||
closed_community_urls = [
|
||||
"https://status.app/c/G8EAAGTiXKuwNbVVAu0GNLD-XzX4oz_E8oC1-7qSLikaTnCuG9Ag13ZgQKrMd8En9Qcpuaj3Qx3mfZ1atZzH8Zw-x_sFJ_MDv0P_7YfqoV-pNr3V4dsza-jVk41GaCGWasJb92Oer8qggaoNWf0tYCgSH19VonXciKPUz3ITdgke#zQ3shbmfT3hvh4mKa1v6uAjjyztQEroh8Mfn6Ckegjd7LT3XK",
|
||||
"https://status.app/c/Ow==#zQ3shbmfT3hvh4mKa1v6uAjjyztQEroh8Mfn6Ckegjd7LT3XK",
|
||||
"https://status.app/c#zQ3shbmfT3hvh4mKa1v6uAjjyztQEroh8Mfn6Ckegjd7LT3XK",
|
||||
"https://status.app/c/ixiACjAKCHRlc3RDb21tEhZkemZ4Z2Nodmpra2xra2xrbCAgbGxsGAYiByM4OEIwRkYqARQD#zQ3shuK3RAMBGtNWJ5QAKtuGeyEhiwko5gXhyGg6T89Q2xrHq"
|
||||
]
|
||||
for url in closed_community_urls:
|
||||
self.channel.chat_message_input.clear()
|
||||
self.channel.send_message(url)
|
||||
self.channel.chat_element_by_text(url).click_on_link_inside_message_body()
|
||||
if not self.community_view.join_button.is_element_displayed(
|
||||
10) or self.community_view.community_title.text != text:
|
||||
if not self.channel.element_by_translation_id(
|
||||
"community-admins-will-review-your-request").is_element_displayed(10):
|
||||
self.errors.append("Closed community was not requested to join by the url %s" % url)
|
||||
if text != "open community": # the last one
|
||||
self.home.jump_to_card_by_text(self.community_name)
|
||||
self.home.jump_to_card_by_text(self.community_name)
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
|
||||
@@ -91,22 +84,16 @@ class TestDeepLinksOneDevice(MultipleSharedDeviceTestCase):
|
||||
self.errors.append("Profile was not opened by the profile deep link %s" % link)
|
||||
self.browser_view.click_system_back_button()
|
||||
|
||||
community_links = {
|
||||
"status.app://c/G8EAAMR_fz8tsCQ-aR2QrCS5sVAvvzc_N3mAA-En_Zxy4JA3j7Dl1A50Pd4DbooQOMbWf7E1_4wipgDyGe8XZEappDn-Qomf9l_xyXhSYBuSQic8InCEUBSRGR0oixSTh3iw5ZCxzkGSI95Iyu1EBpcIlFOEMPHpKUBIdkkoKBJglMDKko8O8dBvBtIYncOA8mwztwLpx3C0rK_u59PldFuXe4cx#zQ3shwQnEfMtcXpHXF4qJPyCGgw2F18N3nbGzYbzsVHnMq4yK":
|
||||
"Status mobile QA community max",
|
||||
"status.app://c/GyoAAORtA48geFrtWr2mu-G5DnFaI0sgqUIIaBFX_DJ_mRbXmzoMnCJnqwI=#zQ3shQhL414wEjDJMEpgTjd14aHCiBDnk6Bq5YTWoi4b7wvnu":
|
||||
"test_comm_enc",
|
||||
"status.app://c/G00AAGS9TbI9mSR-ZNmFrhRjNuEeXAAbcAIUaLLJyjMOG3ACJQ12oIHD78QhzO9s_T5bUeU7rnATWJg3mGgTUemrAg==#zQ3shspPKCZ1VPVQ9dLXGufUGvGphjxVwrcZ6rkZc7S39T4b3":
|
||||
"closed community",
|
||||
"status.app://c/G0UAAMTyNsn2QZDEG0EXftOl8pOEfwEBOOSA_YTfIk85xmADDgINGmxpUHAXzK36bN0fK42Xf4YD2yjPk1z2pbFwFw==#zQ3shgkDFQEnwxji7CvMTokMrShmC2UgxiJ549X5Aw746zQrK":
|
||||
"open community",
|
||||
"status.app://c/GyAAAOQbK4dMy1OMI8s2nGvJR3QRqBQqbExff0-cgmN0T-4C#zQ3shqQ4voo845RAkip2JkYTjL4dpiGnRhaNHjVDxPdEZ1xvP":
|
||||
"e2e_open"
|
||||
}
|
||||
for link, text in community_links.items():
|
||||
community_links = [
|
||||
"status-app://c/G8EAAGTiXKuwNbVVAu0GNLD-XzX4oz_E8oC1-7qSLikaTnCuG9Ag13ZgQKrMd8En9Qcpuaj3Qx3mfZ1atZzH8Zw-x_sFJ_MDv0P_7YfqoV-pNr3V4dsza-jVk41GaCGWasJb92Oer8qggaoNWf0tYCgSH19VonXciKPUz3ITdgke#zQ3shbmfT3hvh4mKa1v6uAjjyztQEroh8Mfn6Ckegjd7LT3XK",
|
||||
"status-app://c/Ow==#zQ3shbmfT3hvh4mKa1v6uAjjyztQEroh8Mfn6Ckegjd7LT3XK",
|
||||
"status-app://c#zQ3shbmfT3hvh4mKa1v6uAjjyztQEroh8Mfn6Ckegjd7LT3XK",
|
||||
"status-app://c/ixiACjAKCHRlc3RDb21tEhZkemZ4Z2Nodmpra2xra2xrbCAgbGxsGAYiByM4OEIwRkYqARQD#zQ3shuK3RAMBGtNWJ5QAKtuGeyEhiwko5gXhyGg6T89Q2xrHq"
|
||||
]
|
||||
for link in community_links:
|
||||
self.browser_view.open_url(link)
|
||||
if not self.community_view.join_button.is_element_displayed(
|
||||
10) or self.community_view.community_title.text != text:
|
||||
if not self.channel.element_by_translation_id(
|
||||
"community-admins-will-review-your-request").is_element_displayed(10):
|
||||
self.errors.append("Closed community was not requested to join by the deep link %s" % link)
|
||||
self.home.navigate_back_to_home_view()
|
||||
self.home.browser_tab.click()
|
||||
|
||||
@@ -425,7 +425,6 @@ class CommunityView(HomeView):
|
||||
self.close_community_view_button = Button(
|
||||
self.driver,
|
||||
xpath="//*[@content-desc='community-options-for-community']/../*[1]//android.widget.ImageView")
|
||||
self.community_title = Text(self.driver, accessibility_id="community-title")
|
||||
self.community_description_text = Text(self.driver, accessibility_id="community-description-text")
|
||||
self.community_status_joined = Text(self.driver, accessibility_id="status-tag-positive")
|
||||
self.community_status_pending = Text(self.driver, accessibility_id="status-tag-pending")
|
||||
|
||||
+4
-16
@@ -184,7 +184,7 @@
|
||||
"no-addresses-selected": "At least 1 address must be shared with community",
|
||||
"confirm-changes": "Confirm changes",
|
||||
"airdrop-addresses": "Address for airdrops",
|
||||
"join-as-a": "Join as a {{role}}",
|
||||
"join-as-a-member": "Join as a Member",
|
||||
"all-addresses": "All addresses",
|
||||
"for-airdrops": "For airdrops",
|
||||
"members-label": "Members",
|
||||
@@ -2016,9 +2016,6 @@
|
||||
"mentions": "Mentions",
|
||||
"mention": "Mention",
|
||||
"admin": "Admin",
|
||||
"member": "Member",
|
||||
"token-master": "Token Master",
|
||||
"token-owner": "Token Owner",
|
||||
"replies": "Replies",
|
||||
"replied": "Replied",
|
||||
"identity-verification": "Identity verification",
|
||||
@@ -2255,9 +2252,7 @@
|
||||
"sync-devices-complete-title": "Device sync complete!",
|
||||
"sync-devices-complete-sub-title": "Your devices are now in sync",
|
||||
"synced-with": "Synced with",
|
||||
"eligible-to-join-as": "Eligible to join as {{role}}",
|
||||
"you-eligible-to-join": "You’re eligible to join",
|
||||
"you-eligible-to-join-as": "You’re eligible to join as {{role}}",
|
||||
"you-not-eligible-to-join": "You’re not eligible to join",
|
||||
"you-hold-number-of-hold-tokens-of-these": "You hold {{number-of-hold-tokens}} of these:",
|
||||
"token-gated-communities": "Token gated communities",
|
||||
@@ -2458,10 +2453,11 @@
|
||||
"share-details": "Share details",
|
||||
"what-are-you-waiting-for": "What are you waiting for?",
|
||||
"no-relevant-tokens": "No relevant tokens",
|
||||
"on-the-web": "On the web",
|
||||
"sending-with-ellipsis": "Sending...",
|
||||
"sending-with-elipsis": "Sending...",
|
||||
"transaction-confirmed": "Transaction confirmed!",
|
||||
"transacation-finalised": "Transaction finalised!",
|
||||
"no-relevant-tokens": "No relevant tokens",
|
||||
"from-label": "From",
|
||||
"to-label": "To",
|
||||
"oops-wrong-word": "Oops! Wrong word",
|
||||
@@ -2473,13 +2469,5 @@
|
||||
"remove-account-title": "Remove account",
|
||||
"remove-account-desc": "The account will be removed from all of your synced devices. Make sure you have a backup of your keypair or recovery phrase and derivation path (if it’s not default).",
|
||||
"derivation-path-copied": "Derivation path copied",
|
||||
"remove-account-confirmation": "I have taken note of the derivation path",
|
||||
"edit-receiver-networks": "Edit receiver networks",
|
||||
"preferred-by-receiver": "Preferred by receiver",
|
||||
"not-preferred-by-receiver": "Not preferred by receiver",
|
||||
"apply-changes": "Apply changes",
|
||||
"receiver-networks-warning": "Changing these settings may result in sending tokens to networks the recipient doesn't use",
|
||||
"watched-account-removed": "Watched address has been removed",
|
||||
"account-removed": "Account has been removed",
|
||||
"share-address-title": "{{address}} address"
|
||||
"remove-account-confirmation": "I have taken note of the derivation path"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user