[16315] Implement Community Channel option: view channel members and details (#18489)

This commit is contained in:
Ibrahem Khalil 2024-04-09 10:38:48 +02:00 committed by GitHub
parent 4e1851d53c
commit c847cb5d03
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 334 additions and 70 deletions

View File

@ -19,10 +19,11 @@
(defn emoji-size
[size]
{:font-size (case size
:size-64 24
:size-32 15
11)})
{:text-align :center
:font-size (case size
:size-64 24
:size-32 15
11)})
(defn lock-container
[size theme]

View File

@ -65,8 +65,9 @@
:align-items :center
:background-color (colors/resolve-color customization-color theme)}))
(def indicator-color
{:online colors/success-50
(defn indicator-color
[]
{:online (colors/theme-colors colors/success-50 colors/success-60)
:offline colors/neutral-40})
(defn outer

View File

@ -49,7 +49,7 @@
font-size (get-in style/sizes [size :font-size])
amount-initials (if (#{:xs :xxs :xxxs} size) 1 2)
sizes (get style/sizes size)
indicator-color (get style/indicator-color (if online? :online :offline))
indicator-color (get (style/indicator-color) (if online? :online :offline))
profile-picture-fn (:fn profile-picture)]
[rn/view {:style outer-styles :accessibility-label :user-avatar}

View File

@ -1,4 +1,5 @@
(ns quo.components.text-combinations.style)
(ns quo.components.text-combinations.style
(:require [quo.foundations.colors :as colors]))
(def title-container
{:flex-direction :row
@ -6,7 +7,8 @@
:align-items :center})
(def avatar-container
{:margin-right 9})
{:margin-right 9
:text-align :center})
(def description-description-text
{:margin-top 8})
@ -16,3 +18,15 @@
:letter-spacing 2
:font-size 13
:line-height 20.5})
(defn textual-emoji
[size customization-color theme]
{:border-radius size
:margin-top -5
:border-width 0
:border-color :transparent
:width size
:height size
:justify-content :center
:align-items :center
:background-color (colors/resolve-color customization-color theme 10)})

View File

@ -7,20 +7,23 @@
[react-native.core :as rn]))
(defn icon
[source size]
[rn/image
{:source (if (string? source)
{:uri source}
source)
:style {:border-radius 50
:border-width 0
:border-color :transparent
:width size
:height size}}])
[{:keys [source size customization-color theme]}]
(if customization-color
[rn/view {:style (style/textual-emoji size customization-color theme)}
[text/text
source]]
[rn/image
{:source source
:style {:border-radius 50
:border-width 0
:border-color :transparent
:width size
:height size}}]))
(defn view-internal
[{:keys [container-style
title
theme
title-number-of-lines
avatar
title-accessibility-label
@ -29,7 +32,8 @@
button-icon
button-on-press
customization-color
emoji-hash]
emoji-hash
emoji]
:or {title-number-of-lines 1}}]
[rn/view {:style container-style}
[rn/view
@ -38,7 +42,10 @@
[rn/view {:style style/title-container}
(when avatar
[rn/view {:style style/avatar-container}
[icon avatar 32]])
[icon {:source avatar :size 32}]])
(when emoji
[rn/view {:style style/avatar-container}
[icon {:source emoji :size 32 :customization-color customization-color :theme theme}]])
[text/text
{:accessibility-label title-accessibility-label
:weight :semi-bold

View File

@ -12,5 +12,5 @@
(defn contacts-section-header
[{:keys [title]}]
(let [theme (quo.theme/use-theme-value)]
[rn/view (style/contacts-section-header theme)
[quo/divider-label title]]))
[quo/divider-label {:container-style {:background-color (style/contacts-section-header theme)}}
title]))

View File

@ -452,27 +452,29 @@
(let [current-pub-key (rf/sub [:multiaccount/public-key])]
[quo/action-drawer
[[(view-profile-entry public-key)
(remove-from-contacts-entry contact)
(rename-entry)
(when-not (= current-pub-key public-key) (remove-from-contacts-entry contact))
(when-not (= current-pub-key public-key) (rename-entry))
(show-qr-entry)
(share-profile-entry)]
[(mark-untrustworthy-entry)
(block-user-entry contact)]
[(when-not (= current-pub-key public-key) (mark-untrustworthy-entry))
(when-not (= current-pub-key public-key) (block-user-entry contact))]
(when (and admin? chat-id)
[(if (= current-pub-key public-key)
(leave-group-entry contact extra-data)
(remove-from-group-entry contact chat-id))])]]))
(defn chat-actions
[{:keys [chat-type] :as chat} inside-chat?]
(condp = chat-type
constants/one-to-one-chat-type
[one-to-one-actions chat inside-chat?]
constants/private-group-chat-type
[private-group-chat-actions chat inside-chat?]
constants/community-chat-type
[communities-chat-actions/actions chat inside-chat?]
nil))
([{:keys [chat-type] :as chat} inside-chat? hide-show-members?]
(condp = chat-type
constants/one-to-one-chat-type
[one-to-one-actions chat inside-chat?]
constants/private-group-chat-type
[private-group-chat-actions chat inside-chat?]
constants/community-chat-type
[communities-chat-actions/actions chat inside-chat? hide-show-members?]
nil))
([chat inside-chat?]
(chat-actions chat inside-chat? nil)))
(defn group-details-actions
[{:keys [admins] :as group}]

View File

@ -0,0 +1,14 @@
(ns status-im.contexts.communities.actions.channel-view-details.style)
(def channel-actions-wrapper {:height 102})
(def footer {:margin-top 8})
(def text-combinations {:margin-top 12 :margin-horizontal 20})
(def wrapper {:padding 20})
(def floating-shell-button
{:position :absolute
:bottom 34
:z-index 3})

View File

@ -0,0 +1,120 @@
(ns status-im.contexts.communities.actions.channel-view-details.view
(:require [clojure.string :as string]
[quo.core :as quo]
[quo.theme]
[react-native.core :as rn]
[status-im.common.contact-list-item.view :as contact-list-item]
[status-im.common.contact-list.view :as contact-list]
[status-im.common.home.actions.view :as home.actions]
[status-im.contexts.communities.actions.channel-view-details.style :as style]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
(defn- contact-item
[public-key]
(let [show-profile-actions #(rf/dispatch
[:show-bottom-sheet
{:content (fn [] [home.actions/contact-actions
{:public-key public-key}])}])
[primary-name secondary-name] (rf/sub [:contacts/contact-two-names-by-identity
public-key])
{:keys [ens-verified added? compressed-key]} (rf/sub [:contacts/contact-by-address public-key])
theme (quo.theme/use-theme-value)]
[contact-list-item/contact-list-item
{:on-press #(rf/dispatch [:chat.ui/show-profile public-key])
:on-long-press show-profile-actions
:accessory {:type :options
:on-press show-profile-actions}}
{:primary-name primary-name
:secondary-name secondary-name
:compressed-key compressed-key
:public-key public-key
:ens-verified ens-verified
:added? added?}
theme]))
(defn- footer
[]
[rn/view {:style style/footer}])
(defn- get-item-layout
[_ index]
#js {:length 200 :offset (* 200 index) :index index})
(defn- members
[items]
[rn/section-list
{:key-fn :public-key
:content-container-style {:padding-bottom 20}
:get-item-layout get-item-layout
:content-inset-adjustment-behavior :never
:sections items
:sticky-section-headers-enabled false
:render-section-header-fn contact-list/contacts-section-header
:render-section-footer-fn footer
:render-fn contact-item
:scroll-event-throttle 8}])
(defn view
[_args]
(fn []
(let [{:keys [chat-id community-id]} (rf/sub [:get-screen-params
:screen/chat.view-channel-members-and-details])
{:keys [description chat-name emoji muted chat-type color]
:as chat} (rf/sub [:chats/chat-by-id chat-id])
pins-count (rf/sub [:chats/pin-messages-count chat-id])
items (rf/sub [:communities/sorted-community-members-section-list
community-id])
theme (quo.theme/use-theme-value)]
(rn/use-mount (fn []
(rf/dispatch [:pin-message/load-pin-messages chat-id])))
[:<>
[quo/floating-shell-button
{:jump-to {:on-press #(rf/dispatch [:shell/navigate-to-jump-to])
:customization-color color
:label (i18n/label :t/jump-to)}}
style/floating-shell-button]
[quo/gradient-cover {:customization-color color :opacity 0.4}]
[quo/page-nav
{:background :blur
:icon-name :i/arrow-left
:on-press #(rf/dispatch [:navigate-back])
:right-side [{:icon-name :i/options
:on-press #(rf/dispatch [:show-bottom-sheet
{:content (fn [] [home.actions/chat-actions
chat
false
true])}])}]}]
[quo/text-combinations
{:container-style style/text-combinations
:title [quo/channel-name
{:channel-name chat-name
:unlocked? true}]
:theme theme
:emoji (when (not (string/blank? emoji)) (string/trim emoji))
:customization-color color
:title-accessibility-label :welcome-title
:description description
:description-accessibility-label :welcome-sub-title}]
[rn/view {:style style/wrapper}
[rn/view
{:style style/channel-actions-wrapper}
[quo/channel-actions
{:actions
[{:big? true
:label (i18n/label :t/pinned-messages-2)
:customization-color color
:icon :i/pin
:counter-value pins-count
:on-press (fn []
(rf/dispatch [:dismiss-keyboard])
(rf/dispatch [:pin-message/show-pins-bottom-sheet
chat-id]))}
{:label (if muted (i18n/label :t/unmute-channel) (i18n/label :t/mute-channel))
:customization-color color
:icon (if muted :i/muted :i/activity-center)
:on-press (fn []
(if muted
(home.actions/unmute-chat-action chat-id)
(home.actions/mute-chat-action chat-id chat-type muted)))}]}]]]
[members items color]])))

View File

@ -30,11 +30,12 @@
(hide-sheet-and-dispatch [:chat.ui/mute chat-id false 0]))
(defn- action-view-members-and-details
[]
[community-id chat-id]
{:icon :i/members
:accessibility-label :chat-view-members-and-details
:label (i18n/label :t/view-channel-members-and-details)
:on-press not-implemented/alert})
:on-press #(rf/dispatch [:navigate-to :screen/chat.view-channel-members-and-details
{:community-id community-id :chat-id chat-id}])})
(defn- action-token-requirements
[]
@ -110,7 +111,7 @@
:label (i18n/label :t/share-channel)})
(defn actions
[{:keys [locked? chat-id]} inside-chat?]
[{:keys [locked? chat-id community-id]} inside-chat? hide-view-members?]
(let [{:keys [muted muted-till chat-type]} (rf/sub [:chats/chat-by-id chat-id])]
(cond
locked?
@ -122,7 +123,7 @@
(and (not inside-chat?) (not locked?))
[quo/action-drawer
[[(action-view-members-and-details)
[[(when-not hide-view-members? (action-view-members-and-details community-id chat-id))
(action-mark-as-read)
(action-toggle-muted chat-id muted muted-till chat-type)
(action-notification-settings)
@ -133,7 +134,7 @@
(and inside-chat? (not locked?))
[quo/action-drawer
[[(action-view-members-and-details)
[[(action-view-members-and-details community-id chat-id)
(action-token-requirements)
(action-mark-as-read)
(action-toggle-muted chat-id muted muted-till chat-type)

View File

@ -34,8 +34,8 @@
(oops/oget event "nativeEvent.layout.y"))
(defn- channel-chat-item
[community-id community-color
{:keys [name emoji muted? id mentions-count unread-messages? on-press locked?] :as chat}]
[community-id
{:keys [name emoji muted? id mentions-count unread-messages? on-press locked? color] :as chat}]
(let [sheet-content [actions/chat-actions
(assoc chat
:chat-type constants/community-chat-type
@ -48,7 +48,7 @@
:else nil)
channel-options {:name name
:emoji emoji
:customization-color community-color
:customization-color color
:mentions-count mentions-count
;; NOTE: this is a troolean, nil/true/false have different meaning
:locked? locked?
@ -62,7 +62,7 @@
:on-long-press #(rf/dispatch [:show-bottom-sheet channel-sheet-data]))]]))
(defn- channel-list-component
[{:keys [on-category-layout community-id community-color on-first-channel-height-changed]}
[{:keys [on-category-layout community-id on-first-channel-height-changed]}
channels-list]
[rn/view
{:on-layout #(on-first-channel-height-changed
@ -86,7 +86,7 @@
[rn/view {:style {:padding-horizontal 8}}
(for [chat chats]
^{:key (:id chat)}
[channel-chat-item community-id community-color chat])])])])
[channel-chat-item community-id chat])])])])
(defn- get-access-type
[access]
@ -254,7 +254,7 @@
{:keys [on-category-layout
collapsed?
on-first-channel-height-changed]}]
(let [{:keys [name description joined spectated images tags color id membership-permissions?]
(let [{:keys [name description joined spectated images tags id membership-permissions?]
:as community}
(rf/sub [:communities/community id])
joined-or-spectated (or joined spectated)
@ -275,7 +275,6 @@
[channel-list-component
{:on-category-layout on-category-layout
:community-id id
:community-color color
:on-first-channel-height-changed on-first-channel-height-changed}
(add-handlers-to-categorized-chats id chats-by-category joined-or-spectated)])])))

View File

@ -16,6 +16,8 @@
[status-im.contexts.communities.actions.accounts-selection.view :as communities.accounts-selection]
[status-im.contexts.communities.actions.addresses-for-permissions.view :as addresses-for-permissions]
[status-im.contexts.communities.actions.airdrop-addresses.view :as airdrop-addresses]
[status-im.contexts.communities.actions.channel-view-details.view :as
channel-view-channel-members-and-details]
[status-im.contexts.communities.actions.request-to-join.view :as join-menu]
[status-im.contexts.communities.actions.share-community-channel.view :as share-community-channel]
[status-im.contexts.communities.discover.view :as communities.discover]
@ -141,6 +143,10 @@
:options {:insets {:top? true}}
:component communities.accounts-selection/view}
{:name :screen/chat.view-channel-members-and-details
:options {:insets {:top? true}}
:component channel-view-channel-members-and-details/view}
{:name :addresses-for-permissions
:options {:insets {:top? true}}
:component addresses-for-permissions/view}

View File

@ -0,0 +1,7 @@
(ns status-im.subs.chat.utils
(:require [status-im.constants :as constants]))
(defn online?
[visibility-status-type]
(or (= visibility-status-type constants/visibility-status-automatic)
(= visibility-status-type constants/visibility-status-always-online)))

View File

@ -107,6 +107,12 @@
(fn [chats [_ chat-id]]
(get chats chat-id)))
(re-frame/reg-sub
:chats/chat-members-by-id
:<- [:chats/chats]
(fn [chats [_ chat-id]]
(get-in chats [chat-id :members])))
(re-frame/reg-sub
:chats/muted
(fn [[_ chat-id] _]

View File

@ -4,6 +4,7 @@
[legacy.status-im.ui.screens.profile.visibility-status.utils :as visibility-status-utils]
[re-frame.core :as re-frame]
[status-im.constants :as constants]
[status-im.subs.chat.utils :as subs.utils]
[utils.i18n :as i18n]
[utils.money :as money]))
@ -65,12 +66,22 @@
(fn [[{:keys [members]}] _]
members))
(re-frame/reg-sub
:communities/current-community-members
:<- [:chats/current-chat]
:<- [:communities]
(fn [[{:keys [community-id]} communities]]
(get-in communities [community-id :members])))
(defn- keys->names
[public-keys profile]
(reduce (fn [acc contact-identity]
(assoc acc
contact-identity
(when (= (:public-key profile) contact-identity)
(:primary-name profile)
contact-identity)))
{}
public-keys))
(defn- sort-members-by-name
[names descending? members]
(if descending?
(sort-by #(get names (first %)) #(compare %2 %1) members)
(sort-by #(get names (first %)) members)))
(re-frame/reg-sub
:communities/sorted-community-members
@ -79,18 +90,39 @@
members (re-frame/subscribe [:communities/community-members community-id])]
[profile members]))
(fn [[profile members] _]
(let [names (reduce (fn [acc contact-identity]
(assoc acc
contact-identity
(when (= (:public-key profile) contact-identity)
(:primary-name profile)
contact-identity)))
{}
(keys members))]
(let [names (keys->names (keys members) profile)]
(->> members
(sort-by #(get names (get % 0)))
(sort-members-by-name names false)
(sort-by #(visibility-status-utils/visibility-status-order (get % 0)))))))
(re-frame/reg-sub
:communities/sorted-community-members-section-list
(fn [[_ community-id]]
(let [profile (re-frame/subscribe [:profile/profile])
members (re-frame/subscribe [:communities/community-members
community-id])
visibility-status-updates (re-frame/subscribe
[:visibility-status-updates])
my-status-update (re-frame/subscribe
[:multiaccount/current-user-visibility-status])]
[profile members visibility-status-updates my-status-update]))
(fn [[profile members visibility-status-updates my-status-update] _]
(let [online? (fn [public-key]
(let [{visibility-status-type :status-type}
(if (or (string/blank? (:public-key profile))
(= (:public-key profile) public-key))
my-status-update
(get visibility-status-updates public-key))]
(subs.utils/online? visibility-status-type)))
names (keys->names (keys members) profile)]
(->> members
(sort-members-by-name names true)
keys
(group-by online?)
(map (fn [[k v]]
{:title (if k (i18n/label :t/online) (i18n/label :t/offline))
:data v}))))))
(re-frame/reg-sub
:communities/featured-contract-communities
:<- [:contract-communities]
@ -272,7 +304,8 @@
(let [category-id (if (seq categoryID) categoryID constants/empty-category-id)
{:keys [unviewed-messages-count
unviewed-mentions-count
muted]} (get full-chats-data
muted
color]} (get full-chats-data
(str community-id id))
acc-with-category (if (get acc category-id)
acc
@ -298,7 +331,8 @@
;; -> has access
:locked? locked?
:hide-if-permissions-not-met? (and hide-if-permissions-not-met? locked?)
:id id}]
:id id
:color color}]
(update-in acc-with-category [category-id :chats] conj categorized-chat))))
(re-frame/reg-sub

View File

@ -5,6 +5,7 @@
[re-frame.db :as rf-db]
[status-im.constants :as constants]
status-im.subs.communities
[status-im.subs.profile-test :as profile-test]
[test-helpers.unit :as h]
[utils.i18n :as i18n]
[utils.re-frame :as rf]))
@ -482,3 +483,52 @@
(is
(match? []
(rf/sub [sub-name community-id]))))))
(h/deftest-sub :communities/sorted-community-members-section-list
[sub-name]
(testing "returns sorted community members per online status"
(let [token-image-eth "data:image/jpeg;base64,/9j/2w"
community {:id community-id
:permissions {:access 3}
:token-images {"ETH" token-image-eth}
:name "Community super name"
:chats {"89f98a1e-6776-4e5f-8626-8ab9f855253f"
{:description "x"
:emoji "🎲"
:permissions {:access 1}
:color "#88B0FF"
:name "random"
:categoryID "0c3c64e7-d56e-439b-a3fb-a946d83cb056"
:id "89f98a1e-6776-4e5f-8626-8ab9f855253f"
:position 4
:can-post? false
:members {"0x04" {"roles" [1]}}}
"a076358e-4638-470e-a3fb-584d0a542ce6"
{:description "General channel for the community"
:emoji "🥔"
:permissions {:access 1}
:color "#4360DF"
:name "general"
:categoryID "0c3c64e7-d56e-439b-a3fb-a946d83cb056"
:id "a076358e-4638-470e-a3fb-584d0a542ce6"
:position 0
:can-post? false
:members {"0x04" {"roles" [1]}}}}
:members {"0x01" {"roles" [1]}
"0x02" {"roles" [1]}
"0x03" {"roles" [1]}
"0x04" {"roles" [1]}}
:can-request-access? false
:outroMessage "bla"
:verified false}]
(swap! rf-db/app-db assoc-in [:communities community-id] community)
(swap! rf-db/app-db assoc :profile/profile profile-test/sample-profile)
(swap! rf-db/app-db assoc
:visibility-status-updates
{"0x01" {:status-type constants/visibility-status-always-online}
"0x02" {:status-type constants/visibility-status-always-online}})
(is (= [{:title (i18n/label :t/online)
:data ["0x01" "0x02"]}
{:title (i18n/label :t/offline)
:data ["0x03" "0x04"]}]
(rf/sub [sub-name community-id]))))))

View File

@ -6,7 +6,7 @@
[legacy.status-im.utils.build :as build]
[legacy.status-im.utils.mobile-sync :as mobile-network-utils]
[re-frame.core :as re-frame]
[status-im.constants :as constants]
[status-im.subs.chat.utils :as chat.utils]
[utils.ethereum.chain :as chain]))
(re-frame/reg-sub
@ -25,8 +25,7 @@
[(re-frame/subscribe [:visibility-status-updates/visibility-status-update public-key])])
(fn [[status-update]]
(let [visibility-status-type (:status-type status-update)]
(or (= visibility-status-type constants/visibility-status-automatic)
(= visibility-status-type constants/visibility-status-always-online)))))
(chat.utils/online? visibility-status-type))))
(re-frame/reg-sub
:multiaccount/logged-in?

View File

@ -191,6 +191,7 @@
[:map
[:color string?]
[:theme :schema.common/theme]
[:background-color {:optional true} [:maybe string?]]
[:size number?]
[:ratio float?]
[:uppercase-ratio number?]

View File

@ -1496,7 +1496,7 @@
"view-gitcoin": "View in Gitcoin",
"view-members": "View members",
"view-profile": "View profile",
"view-channel-members-and-details": "View channel member and details",
"view-channel-members-and-details": "View channel members and details",
"view-details": "View Details",
"view-signing": "View signing phrase",
"view-superrare": "View in SuperRare",
@ -2573,5 +2573,7 @@
"key-name-error-emoji": "Emojis are not allowed",
"key-name-error-special-char": "Special characters are not allowed",
"display": "Display",
"testnet-mode-enabled": "Testnet mode enabled"
"testnet-mode-enabled": "Testnet mode enabled",
"online-community-member": "Online",
"offline-community-member": "Offline"
}