Compare commits

..
Author SHA1 Message Date
Volodymyr Kozieiev 7b858e3dd0 Gating on Status community 2023-02-16 14:19:47 +00:00
30 changed files with 386 additions and 658 deletions
+3 -17
View File
@@ -1,4 +1,4 @@
# Code Style Guidelines
# Guidelines
>The goal of this document is to help all contributors (core and external) to
>write code in _unison_ and help establish good practices that serve the Status
@@ -77,21 +77,7 @@ Joshua Comeau.
[rn/view {:style {:padding-horizontal 20}}]
```
### Don't prepend booleans with is-
It is a common practice in JavaScript and other languages to prepend boolean variable names with `is-*`.
In ClojureScript it is common practice to suffix boolean variable names with a `?`.
There is no need for both of these and so it is preferable to stick with the latter.
```clojure
;; bad
(let [is-open? true] ...)
;; good
(let [open? true] ...)
```
### Styles def vs defn
#### Styles def vs defn
Always use `def` over `defn`, unless the style relies on dynamic values, such as
deref'ed atoms.
@@ -184,7 +170,7 @@ Use the simple `defn` to declare components. Don't use `utils.views/defview` and
(do-something window-width)))
```
### Use `[]` instead of `()` in Reagent components
#### Use `[]` instead of `()` in Reagent components
- The `()` version [does NOT work with Form-2 and
Form-3](https://github.com/reagent-project/reagent/blob/master/doc/UsingSquareBracketsInsteadOfParens.md#a-further-significant-why)
@@ -1,70 +0,0 @@
(ns quo2.components.drawers.drawer-buttons.component-spec
(:require [quo2.components.drawers.drawer-buttons.view :as drawer-buttons]
[react-native.core :as rn]
[test-helpers.component :as h]))
(h/describe "drawer-buttons"
(h/test "the top heading and subheading render"
(h/render [drawer-buttons/view
{:top-card {:heading :top-heading}
:bottom-card {:heading :bottom-heading}}
:top-sub-heading
:bottom-sub-heading])
(-> (js/expect (h/get-by-text "top-heading"))
(.toBeTruthy))
(-> (js/expect (h/get-by-text "top-sub-heading"))
(.toBeTruthy)))
(h/test "the bottom heading and subheading render"
(h/render [drawer-buttons/view
{:top-card {:heading :top-heading}
:bottom-card {:heading :bottom-heading}}
:top-sub-heading
:bottom-sub-heading])
(-> (js/expect (h/get-by-text "bottom-heading"))
(.toBeTruthy))
(-> (js/expect (h/get-by-text "bottom-sub-heading"))
(.toBeTruthy)))
(h/test "it clicks the top card"
(let [event (h/mock-fn)]
(h/render [drawer-buttons/view
{:top-card {:on-press event
:heading :top-heading}
:bottom-card {:heading :bottom-heading}}
:top-sub-heading
:bottom-sub-heading])
(h/fire-event :press (h/get-by-text "top-heading"))
(-> (js/expect event)
(.toHaveBeenCalled))))
(h/test "it clicks the bottom card"
(let [event (h/mock-fn)]
(h/render [drawer-buttons/view
{:top-card {:heading :top-heading}
:bottom-card {:on-press event
:heading :bottom-heading}}
:top-sub-heading
:bottom-sub-heading])
(h/fire-event :press (h/get-by-text "bottom-heading"))
(-> (js/expect event)
(.toHaveBeenCalled))))
(h/test "the top card child renders with a render prop"
(h/render [drawer-buttons/view
{:top-card {:heading :top-heading}
:bottom-card {:heading :bottom-heading}}
[rn/text :top-render-fn]
:bottom-sub-heading])
(-> (js/expect (h/get-by-text "top-render-fn"))
(.toBeTruthy)))
(h/test "the bottom card child renders with a render prop"
(h/render [drawer-buttons/view
{:top-card {:heading :top-heading}
:bottom-card {:heading :bottom-heading}}
:top-sub-heading
[rn/text :bottom-render-fn]])
(-> (js/expect (h/get-by-text "bottom-render-fn"))
(.toBeTruthy))))
@@ -1,48 +0,0 @@
(ns quo2.components.drawers.drawer-buttons.style
(:require [quo2.foundations.colors :as colors]))
(def outer-container {:height 216})
(def top-card
{:flex 1
:padding-vertical 12
:padding-horizontal 20
:border-radius 20
:background-color colors/neutral-80})
(def bottom-card
{:position :absolute
:top 80
:left 0
:right 0
:bottom 0
:padding-vertical 12
:padding-horizontal 20
:border-radius 20
:background-color (colors/alpha colors/white 0.05)})
(def bottom-container
{:flex-direction :row
:justify-content :space-between})
(def bottom-icon
{:border-radius 40
:border-width 1
:margin-left 24
:height 28
:width 28
:justify-content :center
:align-items :center
:border-color (colors/alpha colors/white 0.05)})
(def bottom-text
{:flex 1
:color (colors/alpha colors/white 0.7)})
(def top-text
{:color (colors/alpha colors/white 0.7)})
(defn heading-text
[gap]
{:color colors/white
:margin-bottom gap})
@@ -1,80 +0,0 @@
(ns quo2.components.drawers.drawer-buttons.view
(:require [react-native.core :as rn]
[quo2.components.icon :as icon]
[quo2.components.markdown.text :as text]
[quo2.foundations.colors :as colors]
[quo2.components.drawers.drawer-buttons.style :as style]))
(defn render-bottom
[children]
[rn/view {:style style/bottom-container}
children
[rn/view
{:style style/bottom-icon}
[icon/icon :arrow-right
{:color colors/white
:size 20}]]])
(defn label? [el] (or (string? el) (keyword? el)))
(defn render-children-bottom
[children]
(if (label? children)
[render-bottom
[text/text
{:size :paragraph-2
:style style/bottom-text
:weight :semi-bold}
children]]
[render-bottom children]))
(defn render-children-top
[children]
(if (label? children)
[text/text
{:size :paragraph-2
:style style/top-text
:weight :semi-bold}
children]
children))
(defn card
[{:keys [on-press style heading gap top?]} children]
[rn/touchable-highlight
{:on-press on-press
:border-radius 20
:style style
:underlay-color (:background-color style)}
[rn/view {}
[text/text
{:size :heading-1
:style (style/heading-text gap)
:weight :semi-bold}
heading]
(if top?
[render-children-top children]
[render-children-bottom children])]])
(defn view
"[view opts]
opts
{:container-style style-object
:top-card { :on-press event
:heading string}
:bottom-card { :on-press event
:heading string}}
child-1 string, keyword or hiccup
child-2 string, keyword or hiccup
"
[{:keys [container-style top-card bottom-card]} child-1 child-2]
[rn/view
{:style (merge container-style style/outer-container)}
[card
(merge {:gap 4
:top? true
:style style/top-card}
top-card) child-1]
[card
(merge {:style style/bottom-card
:gap 20}
bottom-card) child-2]])
@@ -173,7 +173,7 @@
(utils/truncate-str (:info content) 24)])]]]])
(defn system-message
[{:keys [type style non-pressable? animate-landing? labels on-long-press] :as message}]
[{:keys [type style non-pressable? animate-landing? labels] :as message}]
[:f>
(fn []
(let [sv-color (reanimated/use-shared-value
@@ -186,17 +186,16 @@
:linear
1000))
[reanimated/touchable-opacity
{:on-press #(when-not non-pressable?
(reanimated/set-shared-value sv-color (get-color :bg :pressed type)))
:on-long-press on-long-press
:style (reanimated/apply-animations-to-style
{:background-color sv-color}
(merge
{:flex-direction :row
:flex 1
:border-radius 16
:padding-vertical 9
:padding-horizontal 11
:background-color sv-color}
style))}
{:on-press #(when-not non-pressable?
(reanimated/set-shared-value sv-color (get-color :bg :pressed type)))
:style (reanimated/apply-animations-to-style
{:background-color sv-color}
(merge
{:flex-direction :row
:flex 1
:border-radius 16
:padding-vertical 9
:padding-horizontal 11
:background-color sv-color}
style))}
[sm-render message labels]]))])
-2
View File
@@ -21,7 +21,6 @@
quo2.components.dividers.divider-label
quo2.components.dividers.new-messages
quo2.components.drawers.action-drawers.view
quo2.components.drawers.drawer-buttons.view
quo2.components.drawers.permission-context.view
quo2.components.dropdowns.dropdown
quo2.components.header
@@ -127,7 +126,6 @@
;;;; DRAWERS
(def action-drawer quo2.components.drawers.action-drawers.view/action-drawer)
(def drawer-buttons quo2.components.drawers.drawer-buttons.view/view)
(def permission-context quo2.components.drawers.permission-context.view/view)
;;;; LIST ITEMS
-1
View File
@@ -4,7 +4,6 @@
[quo2.components.counter.--tests--.counter-component-spec]
[quo2.components.dividers.--tests--.divider-label-component-spec]
[quo2.components.drawers.action-drawers.component-spec]
[quo2.components.drawers.drawer-buttons.component-spec]
[quo2.components.drawers.permission-context.component-spec]
[quo2.components.markdown.--tests--.text-component-spec]
[quo2.components.onboarding.small-option-card.component-spec]
+6 -5
View File
@@ -14,7 +14,8 @@
[status-im2.contexts.activity-center.events :as activity-center]
[status-im2.common.toasts.events :as toasts]
[status-im2.navigation.events :as navigation]
[taoensso.timbre :as log]))
[taoensso.timbre :as log]
[status-im.communities.mock :as mock]))
(def crop-size 1000)
@@ -100,10 +101,10 @@
(rf/defn handle-communities
{:events [::fetched]}
[{:keys [db]} communities]
{:db (reduce (fn [db {:keys [id] :as community}]
(assoc-in db [:communities id] (<-rpc community)))
db
communities)})
{:db (mock/add-mock-data (reduce (fn [db {:keys [id] :as community}]
(assoc-in db [:communities id] (<-rpc community)))
db
communities))})
(rf/defn handle-response
[_ response-js]
+42
View File
@@ -0,0 +1,42 @@
(ns status-im.communities.mock
(:require [status-im2.constants :as constants]))
(def status-channel-to-mock "5c328f54-4d40-4984-ae96-b946247d8dba")
(def community-gates
{:join [[{:token "KNC"
:amount 200}
{:token "MANA"
:amount 10}
{:token "RARE"
:amount 50}]
[{:token "KNC"
:amount 200}
{:token "MANA"
:amount 50}]]})
(def channel-gates
{:read [[{:token "KNC"
:amount 100}
{:token "RARE"
:amount 50}]
[{:token "KNC"
:amount 200}
{:token "MANA"
:amount 50}]]
:write [[{:token "KNC"
:amount 400}]
[{:token "KNC"
:amount 100}
{:token "RARE"
:amount 50}]]})
(defn add-mock-data
[db]
(if (get-in db [:communities constants/status-community-id])
(-> db
(assoc-in [:communities constants/status-community-id :gates] community-gates)
(assoc-in [:communities constants/status-community-id :status] :gated)
(assoc-in [:communities constants/status-community-id :chats status-channel-to-mock :gates]
channel-gates))
db))
+3 -4
View File
@@ -66,16 +66,15 @@
(assoc contact' :two-names (contact-two-names contact' true))))
(defn displayed-name
"Use preferred name, display-name, name or alias in that order"
[{:keys [name display-name preferred-name alias public-key ens-verified]}]
"Use preferred name, name or alias in that order"
[{:keys [name preferred-name alias public-key ens-verified]}]
(let [ens-name (or preferred-name
display-name
name)]
;; Preferred name is our own otherwise we make sure it's verified
(if (or preferred-name (and ens-verified name))
(let [username (stateofus/username ens-name)]
(or username ens-name))
(or display-name alias (gfycat/generate-gfy public-key)))))
(or alias (gfycat/generate-gfy public-key)))))
(defn contact-by-identity
[contacts identity]
+2 -1
View File
@@ -412,7 +412,8 @@
(communities/fetch)
(logging/set-log-level (:log-level multiaccount))
(activity-center/notifications-fetch-unread-contact-requests)
(activity-center/notifications-fetch-unread-count))))
(activity-center/notifications-fetch-unread-count)
#_(communities/resolve-mock-community-info))))
(re-frame/reg-fx
::open-last-chat
@@ -45,7 +45,7 @@
[from username current-public-key]
(or (and (= from current-public-key)
(i18n/label :t/You))
(when username (format-author username))))
(format-author username)))
(defn reply-deleted-message
[]
@@ -4,13 +4,15 @@
[quo.react-native :as rn]
[quo2.components.icon :as icons]
[quo2.components.markdown.text :as text]
[quo2.core :as quo]
[quo2.foundations.colors :as colors]
[quo2.foundations.typography :as typography]
[re-frame.core :as re-frame]
[reagent.core :as reagent]
[status-im2.constants :as constants]
[utils.i18n :as i18n]
[status-im.react-native.resources :as resources]
[status-im.ui.components.fast-image :as fast-image]
[status-im.ui.components.react :as react]
[status-im.ui.screens.chat.image.preview.views :as preview]
[status-im.ui.screens.chat.message.audio :as message.audio]
[status-im.ui.screens.chat.message.gap :as message.gap]
@@ -19,14 +21,14 @@
[status-im.ui.screens.chat.utils :as chat.utils]
[status-im.ui.screens.communities.icon :as communities.icon]
[status-im.ui2.screens.chat.components.reply.view :as components.reply]
[status-im2.config :as config]
[utils.datetime :as datetime]
[status-im.utils.utils :as utils]
[status-im2.constants :as constants]
[status-im2.contexts.chat.home.chat-list-item.view :as home.chat-list-item]
[status-im2.contexts.chat.messages.delete-message-for-me.events]
[status-im2.contexts.chat.messages.delete-message.events]
[utils.datetime :as datetime]
[utils.i18n :as i18n]
[utils.re-frame :as rf])
[utils.re-frame :as rf]
[quo2.core :as quo])
(:require-macros [status-im.utils.views :refer [defview letsubs]]))
(defn system-text?
@@ -228,6 +230,58 @@
(re-frame/dispatch [:pin-message/show-pin-limit-modal chat-id]))
(re-frame/dispatch [:pin-message/send-pin-message (assoc message :pinned (not pinned))]))))
(defn on-long-press-fn
[on-long-press
{:keys [pinned message-pin-enabled outgoing edit-enabled show-input? community?
can-delete-message-for-everyone?]
:as message} content]
(on-long-press
(concat
(when (and outgoing edit-enabled)
[{:type :main
:on-press #(re-frame/dispatch [:chat.ui/edit-message message])
:label (i18n/label :t/edit-message)
:icon :i/edit
:id :edit}])
(when show-input?
[{:type :main
:on-press #(re-frame/dispatch [:chat.ui/reply-to-message message])
:label (i18n/label :t/message-reply)
:icon :i/reply
:id :reply}])
[{:type :main
:on-press #(react/copy-to-clipboard
(components.reply/get-quoted-text-with-mentions
(get content :parsed-text)))
:label (i18n/label :t/copy-text)
:icon :i/copy
:id :copy}]
(when message-pin-enabled
[{:type :main
:on-press #(pin-message message)
:label (i18n/label (if pinned
(if community? :t/unpin-from-channel :t/unpin-from-chat)
(if community? :t/pin-to-channel :t/pin-to-chat)))
:icon :i/pin
:id (if pinned :unpin :pin)}])
(when-not pinned
[{:type :danger
:on-press (fn []
(re-frame/dispatch
[:chat.ui/delete-message-for-me message
config/delete-message-for-me-undo-time-limit-ms]))
:label (i18n/label :t/delete-for-me)
:icon :i/delete
:id :delete-for-me}])
(when (and (or outgoing can-delete-message-for-everyone?) config/delete-message-enabled?)
[{:type :danger
:on-press #(re-frame/dispatch [:chat.ui/delete-message
message
config/delete-message-undo-time-limit-ms])
:label (i18n/label :t/delete-for-everyone)
:icon :i/delete
:id :delete-for-all}]))))
;; STATUS ? whats that ?
(defmethod ->message constants/content-type-status
[{:keys [content content-type]}]
+1
View File
@@ -34,6 +34,7 @@
(def communities-enabled? (enabled? (get-config :COMMUNITIES_ENABLED "0")))
(def database-management-enabled? (enabled? (get-config :DATABASE_MANAGEMENT_ENABLED "0")))
(def debug-webview? (enabled? (get-config :DEBUG_WEBVIEW "0")))
(def delete-message-enabled? (enabled? (get-config :DELETE_MESSAGE_ENABLED "0")))
(def collectibles-enabled? (enabled? (get-config :COLLECTIBLES_ENABLED "1")))
(def test-stateofus? (enabled? (get-config :TEST_STATEOFUS "0")))
(def two-minutes-syncing? (enabled? (get-config :TWO_MINUTES_SYNCING "0")))
@@ -41,7 +41,7 @@
{:type :negative :label (i18n/label :t/declined)}
nil)}
(case (:contact-request-state message)
constants/contact-request-message-state-pending
constants/contact-request-state-mutual
{:button-1 {:label (i18n/label :t/decline)
:accessibility-label :decline-contact-request
:type :danger
@@ -1,7 +1,6 @@
(ns status-im2.contexts.chat.messages.content.deleted.view
(:require [quo2.core :as quo]
[react-native.core :as rn]
[status-im2.contexts.chat.messages.drawers.view :as drawers]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
@@ -21,20 +20,8 @@
[quo/text {:style {:margin-left 4} :size :paragraph-2}
(i18n/label :t/deleted-this-message)]])
(defn- compute-on-long-press-fn
[{:keys [deleted? pinned] :as message}
{:keys [message-pin-enabled] :as context}]
;; only show drawer for user who has the permission to unpin messages
(when (and pinned deleted? message-pin-enabled)
(fn []
(rf/dispatch [:dismiss-keyboard])
(rf/dispatch [:bottom-sheet/show-sheet
{:content (drawers/reactions-and-actions message
context)}]))))
(defn deleted-by-message
[{:keys [deleted-by deleted-undoable-till timestamp-str deleted-for-me-undoable-till from]}
on-long-press-fn]
[{:keys [deleted-by deleted-undoable-till timestamp-str deleted-for-me-undoable-till from]}]
(let [;; deleted message with nil deleted-by is deleted by (:from message)
display-name (first (rf/sub [:contacts/contact-two-names-by-identity (or deleted-by from)]))
contact (rf/sub [:contacts/contact-by-address (or deleted-by from)])
@@ -45,25 +32,21 @@
:timestamp-str timestamp-str
:child [user-xxx-deleted-this-message
{:display-name display-name :profile-picture photo-path}]
:on-long-press on-long-press-fn
:non-pressable? (if on-long-press-fn false true)
:non-pressable? true
:animate-landing? (or deleted-undoable-till deleted-for-me-undoable-till)}]))
(defn deleted-message
[{:keys [deleted? deleted-by deleted-undoable-till timestamp-str deleted-for-me-undoable-till from]
:as message}
context]
(let [pub-key (rf/sub [:multiaccount/public-key])
deleted-by-me? (= (or deleted-by from) pub-key)
on-long-press-fn (compute-on-long-press-fn message context)]
(if-not deleted-by-me?
[deleted-by-message message on-long-press-fn]
:as message}]
(let [pub-key (rf/sub [:multiaccount/public-key])
deleted-by-me? (= (or deleted-by from) pub-key)]
(if (not deleted-by-me?)
[deleted-by-message message]
[quo/system-message
{:type :deleted
:label (if deleted? :message-deleted :message-deleted-for-you)
:labels {:message-deleted (i18n/label :t/message-deleted-for-everyone)
:message-deleted-for-you (i18n/label :t/message-deleted-for-you)}
:on-long-press on-long-press-fn
:timestamp-str timestamp-str
:non-pressable? (if on-long-press-fn false true)
:non-pressable? true
:animate-landing? (or deleted-undoable-till deleted-for-me-undoable-till)}])))
@@ -1,10 +1,10 @@
(ns status-im2.contexts.chat.messages.delete-message.events
(:require
[utils.i18n :as i18n]
[quo2.foundations.colors :as colors]
[status-im2.contexts.chat.messages.list.events :as message-list]
[taoensso.timbre :as log]
[utils.datetime :as datetime]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn- update-db-clear-undo-timer
@@ -47,26 +47,6 @@
(when (get-in db [:messages chat-id message-id])
(update-in db [:messages chat-id message-id] assoc :deleted? true :deleted-by deleted-by)))
(defn- should-and-able-to-unpin-to-be-deleted-message
"check
1. if the to-be deleted message is pinned
2. if user has the permission to unpin message in current chat"
[db {:keys [chat-id message-id]}]
(let [{:keys [group-chat chat-id public? community-id admins]} (get-in db [:chats chat-id])
community (get-in db [:communities community-id])
community-admin? (get community :admin false)
pub-key (get-in db [:multiaccount :public-key])
group-admin? (get admins pub-key)
message-pin-enabled (and (not public?)
(or (not group-chat)
(and group-chat
(or group-admin?
community-admin?))))
pinned (get-in db
[:pin-messages chat-id
message-id])]
(and pinned message-pin-enabled)))
(rf/defn delete
"Delete message now locally and broadcast after undo time limit timeout"
{:events [:chat.ui/delete-message]}
@@ -76,22 +56,14 @@
;; new delete operation will reset prev pending deletes' undo timelimit
;; undo will undo all pending deletes
;; all pending deletes are stored in toast
(let [unpin? (should-and-able-to-unpin-to-be-deleted-message
db
{:chat-id chat-id :message-id message-id})
pub-key (get-in db [:multiaccount :public-key])
;; compute deleted by
(let [pub-key (get-in db [:multiaccount :public-key])
message-from (get message :from)
deleted-by (when (not= pub-key message-from) pub-key)
existing-undo-toast (get-in db [:toasts :toasts :delete-message-for-everyone])
toast-count (inc (get existing-undo-toast :message-deleted-for-everyone-count 0))
existing-undos
(-> existing-undo-toast
(get :message-deleted-for-everyone-undos [])
(conj {:message-id message-id :chat-id chat-id :should-pin-back? unpin?}))]
existing-undos (-> existing-undo-toast
(get :message-deleted-for-everyone-undos [])
(conj {:message-id message-id :chat-id chat-id}))]
(assoc
(message-list/rebuild-message-list
{:db (reduce
@@ -117,10 +89,7 @@
:undo-duration (/ undo-time-limit-ms 1000)
:undo-on-press #(do (rf/dispatch [:chat.ui/undo-all-delete-message])
(rf/dispatch [:toasts/close
:delete-message-for-everyone]))}]
(when unpin?
[:pin-message/send-pin-message-locally
{:chat-id chat-id :message-id message-id :pinned false}])]
:delete-message-for-everyone]))}]]
:utils/dispatch-later (mapv (fn [{:keys [chat-id message-id]}]
{:dispatch [:chat.ui/delete-message-and-send
{:chat-id chat-id :message-id message-id}]
@@ -129,16 +98,11 @@
(rf/defn undo
{:events [:chat.ui/undo-delete-message]}
[{:keys [db]} {:keys [chat-id message-id should-pin-back?]}]
[{:keys [db]} {:keys [chat-id message-id]}]
(when (get-in db [:messages chat-id message-id])
(let [effects (message-list/rebuild-message-list
{:db (update-db-undo-locally db chat-id message-id)}
chat-id)
message (get-in effects [:db :messages chat-id message-id])]
(cond-> effects
should-pin-back?
(assoc :dispatch
[:pin-message/send-pin-message-locally (assoc message :pinned true)])))))
(message-list/rebuild-message-list
{:db (update-db-undo-locally db chat-id message-id)}
chat-id)))
(rf/defn undo-all
{:events [:chat.ui/undo-all-delete-message]}
@@ -162,32 +126,19 @@
[{:keys [db]} {:keys [message-id chat-id]} force?]
(when-let [message (get-in db [:messages chat-id message-id])]
(when (or force? (check-before-delete-and-send db chat-id message-id))
(let [unpin-locally?
;; this only check against local client data
;; generally msg is already unpinned at delete locally phase when user
;; has unpin permission
;;
;; will be true only if
;; 1. admin delete an unpinned msg
;; 2. another admin pin the msg within the undo time limit
;; 3. msg finally deleted
(should-and-able-to-unpin-to-be-deleted-message db
{:chat-id chat-id
:message-id message-id})]
{:db (update-db-clear-undo-timer db chat-id message-id)
:json-rpc/call [{:method "wakuext_deleteMessageAndSend"
:params [message-id]
:js-response true
:on-error #(log/error "failed to delete message "
{:message-id message-id :error %})
:on-success #(rf/dispatch
[:sanitize-messages-and-process-response
%])}]
:dispatch [:pin-message/send-pin-message
{:chat-id chat-id
:message-id message-id
:pinned false
:remote-only? (not unpin-locally?)}]}))))
(cond-> {:db (update-db-clear-undo-timer db chat-id message-id)
:json-rpc/call [{:method "wakuext_deleteMessageAndSend"
:params [message-id]
:js-response true
:on-error #(log/error "failed to delete message "
{:message-id message-id :error %})
:on-success #(rf/dispatch
[:sanitize-messages-and-process-response
%])}]}
(get-in db [:pin-messages chat-id message-id])
(assoc :dispatch
[:pin-message/send-pin-message
{:chat-id chat-id :message-id message-id :pinned false}])))))
(defn- filter-pending-send-messages
"traverse all messages find not yet synced deleted? messages"
@@ -1,12 +1,13 @@
(ns status-im2.contexts.chat.messages.drawers.view
(:require [quo2.core :as quo]
[react-native.core :as rn]
(:require [react-native.core :as rn]
[status-im2.constants :as constants]
[utils.re-frame :as rf]
[quo2.core :as quo]
[utils.i18n :as i18n]
[status-im2.config :as config]
[status-im.ui.components.react :as react]
[status-im.ui2.screens.chat.components.reply.view :as components.reply]
[status-im2.common.not-implemented :as not-implemented]
[status-im2.constants :as constants]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
[status-im2.common.not-implemented :as not-implemented]))
(defn pin-message
[{:keys [chat-id pinned pinned-by] :as message-data}]
@@ -20,39 +21,37 @@
(assoc message-data :pinned message-not-pinned?)]))))
(defn get-actions
[{:keys [outgoing content pinned outgoing-status deleted? deleted-for-me?] :as message-data}
{:keys [edit-enabled show-input? community? can-delete-message-for-everyone?
message-pin-enabled group-chat group-admin?]}]
[{:keys [outgoing content pinned-by outgoing-status] :as message-data}
{:keys [edit-enabled show-input? can-delete-message-for-everyone? community? message-pin-enabled]}]
(concat
(when (and outgoing edit-enabled (not (or deleted? deleted-for-me?)))
(when (and outgoing edit-enabled)
[{:type :main
:on-press #(rf/dispatch [:chat.ui/edit-message message-data])
:label (i18n/label :t/edit-message)
:icon :i/edit
:id :edit}])
(when (and show-input? (not= outgoing-status :sending) (not (or deleted? deleted-for-me?)))
(when (and show-input? (not= outgoing-status :sending))
[{:type :main
:on-press #(rf/dispatch [:chat.ui/reply-to-message message-data])
:label (i18n/label :t/message-reply)
:icon :i/reply
:id :reply}])
(when-not (or deleted? deleted-for-me?)
[{:type :main
:on-press #(react/copy-to-clipboard
(components.reply/get-quoted-text-with-mentions
(get content :parsed-text)))
:label (i18n/label :t/copy-text)
:icon :i/copy
:id :copy}])
[{:type :main
:on-press #(react/copy-to-clipboard
(components.reply/get-quoted-text-with-mentions
(get content :parsed-text)))
:label (i18n/label :t/copy-text)
:icon :i/copy
:id :copy}]
(when message-pin-enabled
[{:type :main
:on-press #(pin-message message-data)
:label (i18n/label (if pinned
:label (i18n/label (if pinned-by
(if community? :t/unpin-from-channel :t/unpin-from-chat)
(if community? :t/pin-to-channel :t/pin-to-chat)))
:icon :i/pin
:id (if pinned :unpin :pin)}])
(when-not (or pinned deleted? deleted-for-me?)
:id (if pinned-by :unpin :pin)}])
(when-not pinned-by
[{:type :danger
:on-press (fn []
(rf/dispatch
@@ -63,13 +62,7 @@
:label (i18n/label :t/delete-for-me)
:icon :i/delete
:id :delete-for-me}])
(when (cond
deleted? false
deleted-for-me? false
outgoing true
community? can-delete-message-for-everyone?
group-chat group-admin?
:else false)
(when (and (or outgoing can-delete-message-for-everyone?) config/delete-message-enabled?)
[{:type :danger
:on-press (fn []
(rf/dispatch [:bottom-sheet/hide])
@@ -126,8 +119,7 @@
icon]])))]))
(defn reactions-and-actions
[{:keys [message-id outgoing-status deleted? deleted-for-me?] :as message-data}
{:keys [chat-id] :as context}]
[{:keys [message-id outgoing-status] :as message-data} {:keys [chat-id] :as context}]
(fn []
(let [actions (get-actions message-data context)
main-actions (filter #(= (:type %) :main) actions)
@@ -135,7 +127,7 @@
admin-actions (filter #(= (:type %) :admin) actions)]
[:<>
;; REACTIONS
(when (and (not= outgoing-status :sending) (not (or deleted? deleted-for-me?)))
(when (not= outgoing-status :sending)
[reactions {:chat-id chat-id :message-id message-id}])
;; MAIN ACTIONS
@@ -1,19 +1,19 @@
(ns status-im2.contexts.chat.messages.list.view
(:require [oops.core :as oops]
(:require [utils.i18n :as i18n]
[oops.core :as oops]
[quo2.core :as quo]
[react-native.background-timer :as background-timer]
[react-native.core :as rn]
[react-native.platform :as platform]
[reagent.core :as reagent]
[status-im.ui.screens.chat.group :as chat.group]
[status-im.ui.screens.chat.message.gap :as message.gap]
[status-im2.common.not-implemented :as not-implemented]
[utils.re-frame :as rf]
[status-im2.contexts.chat.messages.content.view :as message]
[status-im2.constants :as constants]
[status-im2.contexts.chat.messages.content.deleted.view :as content.deleted]
[status-im2.contexts.chat.messages.content.view :as message]
[status-im2.common.not-implemented :as not-implemented]
[status-im.ui.screens.chat.group :as chat.group]
[status-im2.contexts.chat.messages.list.state :as state]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
[status-im.ui.screens.chat.message.gap :as message.gap]))
(defonce messages-list-ref (atom nil))
@@ -69,7 +69,6 @@
(if platform/low-device? 700 200))))
(defn get-render-data
"compute data used to render message list, including pinned message list and message list in chats"
[{:keys [group-chat chat-id public? community-id admins space-keeper show-input? edit-enabled
in-pinned-view?]}]
(let [current-public-key (rf/sub [:multiaccount/public-key])
@@ -83,7 +82,6 @@
(or group-admin?
community-admin?))))]
{:group-chat group-chat
:group-admin? group-admin?
:public? public?
:community? (not (nil? community-id))
:current-public-key current-public-key
@@ -125,7 +123,7 @@
[message.gap/gap message-data]]
[rn/view {:padding-horizontal 8}
(if (or deleted? deleted-for-me?)
[content.deleted/deleted-message message-data context]
[content.deleted/deleted-message message-data]
[message/message-with-reactions message-data context])]))])
(defn messages-list
@@ -1,21 +1,15 @@
(ns status-im2.contexts.chat.messages.pin.banner.view
(:require [quo2.core :as quo]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn banner
[chat-id]
(let [pinned-messages (rf/sub [:chats/pinned-sorted-list
chat-id])
latest-pinned-message (last pinned-messages)
latest-pin-text (get-in latest-pinned-message [:content :text])
{:keys [deleted? deleted-for-me?]} latest-pinned-message
pins-count (count pinned-messages)
latest-pin-text
(cond deleted? (i18n/label :t/message-deleted-for-everyone)
deleted-for-me? (i18n/label :t/message-deleted-for-you)
:else latest-pin-text)]
(let [pinned-messages (rf/sub [:chats/pinned-sorted-list chat-id])
latest-pin-text (->> pinned-messages
last
:content
:text)
pins-count (count pinned-messages)]
[quo/banner
{:latest-pin-text latest-pin-text
:pins-count pins-count
@@ -1,14 +1,14 @@
(ns status-im2.contexts.chat.messages.pin.events
(:require [quo2.foundations.colors :as colors]
[re-frame.core :as re-frame]
[status-im.data-store.pin-messages :as data-store.pin-messages]
[status-im.transport.message.protocol :as protocol]
(:require [re-frame.core :as re-frame]
[utils.i18n :as i18n]
[quo2.foundations.colors :as colors]
[status-im2.contexts.chat.messages.list.events :as message-list]
[status-im2.common.toasts.events :as toasts]
[status-im2.constants :as constants]
[status-im2.contexts.chat.messages.list.events :as message-list]
[taoensso.timbre :as log]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
[status-im.data-store.pin-messages :as data-store.pin-messages]
[status-im.transport.message.protocol :as protocol]
[utils.re-frame :as rf]
[taoensso.timbre :as log]))
(rf/defn handle-failed-loading-pin-messages
{:events [:pin-message/failed-loading-pin-messages]}
@@ -59,34 +59,23 @@
(assoc-in [:pin-message-lists chat-id]
(message-list/add-many nil (vals all-messages))))}))))
(rf/defn send-pin-message-locally
"Pin message, rebuild pinned messages list locally"
{:events [:pin-message/send-pin-message-locally]}
(rf/defn send-pin-message
"Pin message, rebuild pinned messages list"
{:events [:pin-message/send-pin-message]}
[{:keys [db] :as cofx} {:keys [chat-id message-id pinned] :as pin-message}]
(let [current-public-key (get-in db [:multiaccount :public-key])
message (merge pin-message {:pinned-by current-public-key})
pin-message-lists-exist? (some? (get-in db [:pin-message-lists chat-id]))]
(let [current-public-key (get-in db [:multiaccount :public-key])
message (merge pin-message {:pinned-by current-public-key})
preferred-name (get-in db [:multiaccount :preferred-name])]
(rf/merge cofx
{:db (cond-> db
pinned
(->
(update-in [:pin-message-lists chat-id] message-list/add message)
(assoc-in [:pin-messages chat-id message-id] message))
(and (not pinned) pin-message-lists-exist?)
(not pinned)
(->
(update-in [:pin-message-lists chat-id] message-list/remove-message pin-message)
(update-in [:pin-messages chat-id] dissoc message-id)))})))
(rf/defn send-pin-message
"Pin message, rebuild pinned messages list"
{:events [:pin-message/send-pin-message]}
[{:keys [db] :as cofx} {:keys [chat-id message-id pinned remote-only?] :as pin-message}]
(let [current-public-key (get-in db [:multiaccount :public-key])
message (merge pin-message {:pinned-by current-public-key})
preferred-name (get-in db [:multiaccount :preferred-name])]
(rf/merge cofx
(when-not remote-only? (send-pin-message-locally pin-message))
(update-in [:pin-messages chat-id] dissoc message-id)))}
(data-store.pin-messages/send-pin-message {:chat-id (pin-message :chat-id)
:message_id (pin-message :message-id)
:pinned (pin-message :pinned)})
@@ -1,33 +1,37 @@
(ns status-im2.contexts.chat.messages.pin.list.view
(:require [quo2.core :as quo]
(:require [utils.i18n :as i18n]
[quo2.core :as quo]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
[status-im2.contexts.chat.messages.content.deleted.view :as content.deleted]
[status-im2.contexts.chat.messages.content.view :as message]
[status-im2.contexts.chat.messages.list.view :as list.view]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
[utils.re-frame :as rf]
[utils.datetime :as datetime]))
(def list-key-fn #(or (:message-id %) (:value %)))
(defn message-render-fn
[{:keys [deleted? deleted-for-me?] :as message} _ _ context]
[{:keys [whisper-timestamp] :as message}
_
{:keys [group-chat public? community? current-public-key show-input? edit-enabled]}]
;; TODO (flexsurfer) probably we don't want reactions here
(if (or deleted? deleted-for-me?)
[content.deleted/deleted-message message context]
[message/message-with-reactions message context]))
[message/message-with-reactions
message
{:group-chat group-chat
:public? public?
:community? community?
:current-public-key current-public-key
:show-input? show-input?
:message-pin-enabled true
:in-pinned-view? true
:pinned true
:timestamp-str (datetime/timestamp->time whisper-timestamp)
:edit-enabled edit-enabled}])
(defn pinned-messages-list
[chat-id]
(let [pinned-messages (rf/sub [:chats/pinned-sorted-list
chat-id])
current-chat (rf/sub [:chat-by-id chat-id])
{:keys [group-chat chat-id public? community-id admins]}
current-chat
community (rf/sub [:communities/community
community-id])]
(let [pinned-messages (vec (vals (rf/sub [:chats/pinned chat-id])))
current-chat (rf/sub [:chat-by-id chat-id])
community (rf/sub [:communities/community (:community-id current-chat)])]
[rn/view {:accessibility-label :pinned-messages-list}
;; TODO (flexsurfer) this should be a component in quo2
;; https://github.com/status-im/status-mobile/issues/14529
@@ -58,18 +62,10 @@
(str "# " (:chat-name current-chat))]])]
(if (> (count pinned-messages) 0)
[rn/flat-list
{:data pinned-messages
:render-data (list.view/get-render-data {:group-chat group-chat
:chat-id chat-id
:public? public?
:community-id community-id
:show-input? false
:admins admins
:edit-enabled true
:in-pinned-view? true})
:render-fn message-render-fn
:key-fn list-key-fn
:separator quo/separator}]
{:data pinned-messages
:render-fn message-render-fn
:key-fn list-key-fn
:separator quo/separator}]
[rn/view
{:style {:justify-content :center
:align-items :center
@@ -31,7 +31,7 @@
(utils/join-existing-users-string user-list)]])
(defn channel-token-gating-details
[name token-gating emoji channel-color]
[name gates emoji channel-color]
[rn/view {:height 350 :margin-top 20}
[quo/token-gating
{:channel {:name name
@@ -42,15 +42,15 @@
(js/alert
"Entered channel"
"Wuhuu!! You successfully entered the channel :)"))
:gates token-gating}}]])
:gates gates}}]])
(defn open-channel-token-gating-details
[name token-gating emoji channel-color]
[name gates emoji channel-color]
(rf/dispatch
[:bottom-sheet/show-sheet
{:content
(fn []
[channel-token-gating-details name token-gating emoji channel-color])
[channel-token-gating-details name gates emoji channel-color])
:content-height 210}]))
(defn layout-y
@@ -160,13 +160,13 @@
:gates tokens}}]])
(defn add-on-press-handler
[community-id {:keys [name emoji id locked? token-gating] :or {locked? false} :as chat}]
[community-id {:keys [name emoji id locked? gates] :or {locked? false} :as chat}]
(merge
chat
(if (and locked? token-gating)
(if (and locked? gates)
{:on-press #(open-channel-token-gating-details
name
token-gating
gates
emoji
(colors/custom-color :pink 50))}
@@ -210,14 +210,16 @@
(defn community-content
[{:keys [name description locked joined images
status tokens tags requested-to-join-at id]
status tags requested-to-join-at id]
:as community}
{:keys [on-categories-heights-changed
on-first-channel-height-changed]}]
(let [pending? (pos? requested-to-join-at)
thumbnail-image (get-in images [:thumbnail])
chats-by-category (rf/sub [:communities/categorized-channels id])
users (rf/sub [:communities/users id])]
(let [pending? (pos? requested-to-join-at)
thumbnail-image (get-in images [:thumbnail])
chats-by-category (rf/sub [:communities/categorized-channels id])
users (rf/sub [:communities/users id])
join-gates (rf/sub [:community/join-gates id])
permission-tag-tokens (rf/sub [:community/permission-tag-tokens id])]
[rn/view
[rn/view {:padding-horizontal 20}
(when (and (not joined)
@@ -230,7 +232,7 @@
[quo/permission-tag-container
{:locked locked
:status status
:tokens tokens
:tokens permission-tag-tokens
:on-press #(rf/dispatch
[:bottom-sheet/show-sheet
{:content-height 210
@@ -239,7 +241,7 @@
[community-token-gating-details
name
thumbnail-image
tokens])}])}]])
join-gates])}])}]])
(when (or pending? joined)
[rn/view
{:position :absolute
@@ -1,74 +0,0 @@
(ns status-im2.contexts.quo-preview.drawers.drawer-buttons
(:require [quo2.core :as quo]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
[reagent.core :as reagent]
[status-im2.contexts.quo-preview.preview :as preview]))
(def descriptor
[{:label "Top Heading"
:key :top-heading
:type :text}
{:label "Top Sub heading"
:key :top-sub-heading
:type :text}
{:label "Bottom heading"
:key :bottom-heading
:type :text}])
(defn text-with-link
[]
[quo/text
{:style {:flex 1
:flex-wrap :wrap}}
[quo/text
{:size :paragraph-2
:style {:flex 1
:color (colors/alpha colors/white 0.7)}
:weight :semi-bold}
"By continuing you accept our "]
[quo/text
{:on-press #(js/alert "Terms of use clicked")
:size :paragraph-2
:style {:flex 1
:color colors/white}
:weight :semi-bold}
"Terms of Use"]])
(defn render-drawer-buttons
[state]
[rn/view
{:height 300
:background-color (colors/theme-colors colors/white colors/neutral-95)}
[quo/drawer-buttons
{:container-style {:margin-left 40
:margin-right 24}
:top-card {:on-press #(js/alert "top card clicked")
:heading (:top-heading @state)}
:bottom-card {:on-press #(js/alert "bottom card clicked")
:heading (:bottom-heading @state)}}
(:top-sub-heading @state) [text-with-link]]])
(defn cool-preview
[]
(let [state (reagent/atom {:top-heading "Sign in "
:top-sub-heading "You already use Status"
:bottom-heading "I'm new to status"})]
(fn []
[rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!}
[rn/view {:padding-bottom 400}
[preview/customizer state descriptor]
[rn/view {:padding-vertical 60}
[render-drawer-buttons state]]]])))
(defn preview-drawer-buttons
[]
[rn/view
{:background-color (colors/theme-colors colors/white colors/neutral-95)
:flex 1}
[rn/flat-list
{:flex 1
:nestedScrollEnabled true
:keyboardShouldPersistTaps :always
:header [cool-preview]
:key-fn :id}]])
@@ -29,8 +29,7 @@
[status-im2.contexts.quo-preview.dividers.date :as divider-date]
[status-im2.contexts.quo-preview.dividers.divider-label :as divider-label]
[status-im2.contexts.quo-preview.dividers.new-messages :as new-messages]
[status-im2.contexts.quo-preview.drawers.action-drawers :as action-drawers]
[status-im2.contexts.quo-preview.drawers.drawer-buttons :as drawer-buttons]
[status-im2.contexts.quo-preview.drawers.action-drawers :as drawers]
[status-im2.contexts.quo-preview.drawers.permission-drawers :as permission-drawers]
[status-im2.contexts.quo-preview.dropdowns.dropdown :as dropdown]
[status-im2.contexts.quo-preview.foundations.shadows :as shadows]
@@ -139,10 +138,7 @@
:component divider-date/preview-divider-date}]
:drawers [{:name :action-drawers
:insets {:top false}
:component action-drawers/preview-action-drawers}
{:name :drawer-buttons
:insets {:top false}
:component drawer-buttons/preview-drawer-buttons}
:component drawers/preview-action-drawers}
{:name :permission-drawers
:insets {:top false}
:component permission-drawers/preview-permission-drawers}]
+13 -17
View File
@@ -1,9 +1,9 @@
(ns status-im2.subs.chat.messages
(:require [re-frame.core :as re-frame]
[status-im.chat.models.reactions :as models.reactions]
[status-im2.constants :as constants]
[status-im2.contexts.chat.messages.list.events :as models.message-list]
[utils.datetime :as datetime]))
[status-im.chat.models.reactions :as models.reactions]
[utils.datetime :as datetime]
[status-im2.constants :as constants]))
(defn intersperse-datemark
"Reduce step which expects the input list of messages to be sorted by clock value.
@@ -24,7 +24,7 @@
:acc (conj acc msg)}
(and (not= last-datemark datemark) ; not the same day
(< whisper-timestamp last-timestamp)) ; not out-of-order
(< whisper-timestamp last-timestamp)) ; not out-of-order
{:last-timestamp whisper-timestamp
:last-datemark datemark
:acc (conj acc
@@ -32,7 +32,7 @@
:type :datemark}
msg)}
:else
{:last-timestamp (min whisper-timestamp last-timestamp) ; use last datemark
{:last-timestamp (min whisper-timestamp last-timestamp) ; use last datemark
:last-datemark last-datemark
:acc (conj acc (assoc msg :datemark last-datemark))}))
@@ -158,18 +158,14 @@
[(re-frame/subscribe [:messages/pin-messages])
(re-frame/subscribe [:chats/chat-messages chat-id])])
(fn [[pin-messages messages] [_ chat-id]]
(let [pinned-messages (get pin-messages chat-id {})]
(reduce-kv
(fn [pinned-messages pinned-message-id pinned-message]
(let [{:keys [deleted? deleted-for-me? deleted-by]} (get messages pinned-message-id)
pinned-message (assoc pinned-message
:deleted? deleted?
:deleted-for-me? deleted-for-me?
:deleted-by deleted-by
:pinned true)]
(assoc pinned-messages pinned-message-id pinned-message)))
pinned-messages
pinned-messages))))
(let [pin-messages (get pin-messages chat-id {})]
(reduce-kv (fn [acc message-id message]
(let [{:keys [deleted? deleted-for-me?]} (get messages message-id)]
(if (or deleted? deleted-for-me?)
acc
(assoc acc message-id message))))
{}
pin-messages))))
;; local messages will not have a :pinned-at key until user navigates away and to
;; chat screen. For this reason we want to retain order of local messages with :pinned-at nil
+45 -85
View File
@@ -1,10 +1,10 @@
(ns status-im2.subs.chat.messages-test
(:require [cljs.test :refer [deftest is testing]]
[re-frame.db :as rf-db]
[status-im2.constants :as constants]
[status-im2.subs.chat.messages :as messages]
[test-helpers.unit :as h]
[utils.re-frame :as rf]))
[utils.re-frame :as rf]
[re-frame.db :as rf-db]
[status-im2.constants :as constants]))
(def messages-state
[{:message-id "0x111" :album-id "abc" :albumize? true}
@@ -109,91 +109,51 @@
[sub-name]
(testing "It sorts three messages with pinned-at property"
(swap! rf-db/app-db assoc :pin-messages pinned-messages-state)
(is (= [{:chat-id :0xChat
:message-id :0x1
:pinned-at 1000
:pinned-by :test-user
:pinned true
:deleted? nil
:deleted-for-me? nil
:deleted-by nil}
{:chat-id :0xChat
:message-id :0x2
:pinned-at 2000
:pinned-by :test-user
:pinned true
:deleted? nil
:deleted-for-me? nil
:deleted-by nil}
{:chat-id :0xChat
:message-id :0x3
:pinned-at 3000
:pinned-by :test-user
:pinned true
:deleted? nil
:deleted-for-me? nil
:deleted-by nil}]
(is (= [{:chat-id :0xChat
:message-id :0x1
:pinned-at 1000
:pinned-by :test-user}
{:chat-id :0xChat
:message-id :0x2
:pinned-at 2000
:pinned-by :test-user}
{:chat-id :0xChat
:message-id :0x3
:pinned-at 3000
:pinned-by :test-user}]
(rf/sub [sub-name :0xChat]))))
(testing "It sorts messages from backend with pinned-at property and 1 new local pinned message"
(swap! rf-db/app-db assoc :pin-messages pinned-messages-state-with-1-new-local-message)
(is (= [{:chat-id :0xChat
:message-id :0x1
:pinned-at 2000
:pinned-by :test-user
:pinned true
:deleted? nil
:deleted-for-me? nil
:deleted-by nil}
{:chat-id :0xChat
:message-id :0x2
:pinned-at 3000
:pinned-by :test-user
:pinned true
:deleted? nil
:deleted-for-me? nil
:deleted-by nil}
{:chat-id :0xChat
:message-id :0x3
:pinned-at nil
:pinned-by :test-user
:pinned true
:deleted? nil
:deleted-for-me? nil
:deleted-by nil}]
(is (= [{:chat-id :0xChat
:message-id :0x1
:pinned-at 2000
:pinned-by :test-user}
{:chat-id :0xChat
:message-id :0x2
:pinned-at 3000
:pinned-by :test-user}
{:chat-id :0xChat
:message-id :0x3
:pinned-at nil
:pinned-by :test-user}]
(rf/sub [sub-name :0xChat]))))
(testing "It sorts messages from backend with pinned-at property and 2 new local pinned messages"
(swap! rf-db/app-db assoc :pin-messages pinned-messages-state-with-2-new-local-messages)
(is
(= [{:chat-id :0xChat
:message-id :0x1
:pinned-at 2000
:pinned-by :test-user
:pinned true
:deleted? nil
:deleted-for-me? nil
:deleted-by nil}
{:chat-id :0xChat
:message-id :0x2
:pinned-at 3000
:pinned-by :test-user
:pinned true
:deleted? nil
:deleted-for-me? nil
:deleted-by nil}
{:chat-id :0xChat
:message-id :0x3
:pinned-at nil
:pinned-by :test-user
:pinned true
:deleted? nil
:deleted-for-me? nil
:deleted-by nil}
{:chat-id :0xChat
:message-id :0x4
:pinned-at nil
:pinned-by :test-user
:pinned true
:deleted? nil
:deleted-for-me? nil
:deleted-by nil}]
(rf/sub [sub-name :0xChat])))))
(is (= [{:chat-id :0xChat
:message-id :0x1
:pinned-at 2000
:pinned-by :test-user}
{:chat-id :0xChat
:message-id :0x2
:pinned-at 3000
:pinned-by :test-user}
{:chat-id :0xChat
:message-id :0x3
:pinned-at nil
:pinned-by :test-user}
{:chat-id :0xChat
:message-id :0x4
:pinned-at nil
:pinned-by :test-user}]
(rf/sub [sub-name :0xChat])))))
+64 -1
View File
@@ -216,6 +216,34 @@
(sort-by :position)
(into []))))
(def token-images
{"KNC" (js/require "../resources/images/tokens/mainnet/KNC.png")
"MANA" (js/require "../resources/images/tokens/mainnet/MANA.png")
"RARE" (js/require "../resources/images/tokens/mainnet/RARE.png")
"ETH" (js/require "../resources/images/tokens/mainnet/ETH.png")
"DAI" (js/require "../resources/images/tokens/mainnet/DAI.png")})
(defn token-image
[token]
(get token-images token))
(defn enrich-gate-for-ui
[{:keys [token] :as gate}]
(assoc gate :token-img-src (token-image token) :is-sufficient? false))
(defn enrich-gates-vector-for-ui
[gates]
(vec (map enrich-gate-for-ui gates)))
(defn enrich-gates-for-ui
[gates]
(vec (map (fn [v]
(if (vector? v)
(enrich-gates-vector-for-ui v)
(enrich-gate-for-ui v)))
gates)))
(re-frame/reg-sub
:communities/categorized-channels
(fn [[_ community-id]]
@@ -223,7 +251,7 @@
(re-frame/subscribe [:chats/chats])])
(fn [[{:keys [joined categories chats]} full-chats-data] [_ community-id]]
(reduce
(fn [acc [_ {:keys [name categoryID id emoji can-post?]}]]
(fn [acc [_ {:keys [name categoryID id emoji can-post? gates]}]]
(let [category (keyword
(get-in categories
[categoryID :name]
@@ -235,6 +263,11 @@
#(vec (conj %1 %2))
{:name name
:emoji emoji
:gates (merge
(when (contains? gates :read)
{:read (enrich-gates-for-ui (:read gates))})
(when (contains? gates :write)
{:write (enrich-gates-for-ui (:write gates))}))
:unread-messages? (pos? unviewed-messages-count)
:mentions-count (or unviewed-mentions-count 0)
:locked? (or (not joined) (not can-post?))
@@ -250,3 +283,33 @@
{:full-name "Marcus C"}
{:full-name "MNO PQR"}
{:full-name "STU VWX"}]))
(re-frame/reg-sub
:community/join-gates
(fn [[_ community-id]]
[(re-frame/subscribe [:communities/community community-id])])
(fn [[{:keys [gates]}] _]
(when gates
{:join (enrich-gates-for-ui (gates :join))})))
(defn icons-for-permission-tag
[gates]
(vec (map-indexed (fn [i {:keys [token]}]
{:id i :token-icon (token-image token)})
gates)))
(re-frame/reg-sub
:community/permission-tag-tokens
(fn [[_ community-id]]
[(re-frame/subscribe [:communities/community community-id])])
(fn [[{:keys [gates]}] _]
(when gates
(let [join-gates (gates :join)
first-item (first join-gates)]
(if (vector? first-item)
(vec (map-indexed (fn [i v]
{:id i
:group (icons-for-permission-tag v)})
join-gates))
[{:id 0
:group (icons-for-permission-tag join-gates)}])))))
+3 -3
View File
@@ -3,7 +3,7 @@
"_comment": "Instead use: scripts/update-status-go.sh <rev>",
"owner": "status-im",
"repo": "status-go",
"version": "v0.131.7",
"commit-sha1": "97579ee36393955705e51f364fce3ab40d1d6921",
"src-sha256": "0b15kv6f1f1935lljl4bmvmndsr5smb9kxazx0fxz6xfsyjd1x5i"
"version": "v0.131.4",
"commit-sha1": "0b2f0ef28923d2bc3c9051d038e7c512bfdc741f",
"src-sha256": "1pql2dkzwny5yv8ggi2dikfc6dbp64cyxjnm8k0nyl2wfs8ax2cg"
}
+1 -1
View File
@@ -12,7 +12,7 @@ module.exports = {
},
"testTimeout": 60000,
"transformIgnorePatterns": [
"/node_modules/(?!(@react-native|react-native-haptic-feedback|react-native-redash|react-native-image-crop-picker|@react-native-community|react-native-linear-gradient|react-native-background-timer|react-native|rn-emoji-keyboard|react-native-languages|react-native-shake|react-native-reanimated|react-native-redash|react-native-permissions|@react-native-community/blur)/).*/"
"/node_modules/(?!(@react-native|react-native-haptic-feedback|react-native-redash|react-native-image-crop-picker|@react-native-community|react-native-linear-gradient|react-native-background-timer|react-native|rn-emoji-keyboard|react-native-languages|react-native-shake|react-native-reanimated|react-native-redash|react-native-permissions)/).*/"
],
"globals": {
"__TEST__": true