From 49e9738ff898999a82ca57e814b1a0df4d5f7523 Mon Sep 17 00:00:00 2001 From: Omar Basem Date: Tue, 29 Nov 2022 10:41:19 +0400 Subject: [PATCH] Group Details Screen (2) (#14427) * feat: group details screen (2) --- src/status_im/contact/core.cljs | 5 + src/status_im/group_chats/core.cljs | 76 ++++----- .../screens/chat/styles/message/message.cljs | 2 +- .../ui2/screens/chat/group_details/style.cljs | 20 +++ .../ui2/screens/chat/group_details/view.cljs | 117 +++++++++----- .../ui2/screens/chat/messages/message.cljs | 15 +- .../ui2/screens/common/contact_list/view.cljs | 19 +++ .../common/contact_list_item/view.cljs | 66 +++++--- src/status_im2/common/home/actions/view.cljs | 144 +++++++++++------- .../chat/home/chat_list_item/style.cljs | 2 +- .../chat/home/chat_list_item/view.cljs | 2 +- src/status_im2/contexts/chat/home/view.cljs | 12 +- src/status_im2/navigation/view.cljs | 2 +- src/status_im2/subs/contact.cljs | 38 ++++- src/status_im2/subs/root.cljs | 1 + translations/en.json | 6 +- 16 files changed, 355 insertions(+), 172 deletions(-) create mode 100644 src/status_im/ui2/screens/common/contact_list/view.cljs diff --git a/src/status_im/contact/core.cljs b/src/status_im/contact/core.cljs index 6a2db9730c..dbb068a38c 100644 --- a/src/status_im/contact/core.cljs +++ b/src/status_im/contact/core.cljs @@ -151,3 +151,8 @@ :mutual-contact-enabled? enabled? nil)) + +(fx/defn set-search-query + {:events [:contacts/set-search-query]} + [{:keys [db] :as cofx} value] + {:db (assoc db :contacts/search-query value)}) diff --git a/src/status_im/group_chats/core.cljs b/src/status_im/group_chats/core.cljs index 3044cb4c92..76eb1c60d7 100644 --- a/src/status_im/group_chats/core.cljs +++ b/src/status_im/group_chats/core.cljs @@ -21,89 +21,89 @@ {:events [:chat-removed]} [cofx response] (fx/merge cofx - {:db (dissoc (:db cofx) :current-chat-id) + {:db (dissoc (:db cofx) :current-chat-id) :dispatch-n [[:sanitize-messages-and-process-response response] [:pop-to-root-tab :chat-stack]]} (notification-center/get-activity-center-notifications-count))) (fx/defn handle-chat-update {:events [:chat-updated]} - [_ response] + [_ response do-not-navigate?] {:dispatch-n [[:sanitize-messages-and-process-response response] - [:navigate-chat-updated (.-id (aget (.-chats response) 0))]]}) + (when-not do-not-navigate? [:navigate-chat-updated (.-id (aget (.-chats response) 0))])]}) (fx/defn remove-member "Format group update message and sign membership" {:events [:group-chats.ui/remove-member-pressed]} - [_ chat-id member] - {::json-rpc/call [{:method "wakuext_removeMemberFromGroupChat" - :params [nil chat-id member] + [_ chat-id member do-not-navigate?] + {::json-rpc/call [{:method "wakuext_removeMemberFromGroupChat" + :params [nil chat-id member] :js-response true - :on-success #(re-frame/dispatch [:chat-updated %])}]}) + :on-success #(re-frame/dispatch [:chat-updated % do-not-navigate?])}]}) (fx/defn join-chat {:events [:group-chats.ui/join-pressed]} [_ chat-id] - {::json-rpc/call [{:method "wakuext_confirmJoiningGroup" - :params [chat-id] + {::json-rpc/call [{:method "wakuext_confirmJoiningGroup" + :params [chat-id] :js-response true - :on-success #(re-frame/dispatch [:chat-updated %])}]}) + :on-success #(re-frame/dispatch [:chat-updated %])}]}) (fx/defn create - {:events [:group-chats.ui/create-pressed] + {:events [:group-chats.ui/create-pressed] :interceptors [(re-frame/inject-cofx :random-guid-generator)]} [{:keys [db] :as cofx} group-name] (let [selected-contacts (:group/selected-contacts db)] - {::json-rpc/call [{:method "wakuext_createGroupChatWithMembers" - :params [nil group-name (into [] selected-contacts)] + {::json-rpc/call [{:method "wakuext_createGroupChatWithMembers" + :params [nil group-name (into [] selected-contacts)] :js-response true - :on-success #(re-frame/dispatch [:chat-updated %])}]})) + :on-success #(re-frame/dispatch [:chat-updated %])}]})) (fx/defn create-from-link [cofx {:keys [chat-id invitation-admin chat-name]}] (if (get-in cofx [:db :chats chat-id]) {:dispatch-n [[:accept-all-activity-center-notifications-from-chat chat-id] [:chat.ui/navigate-to-chat chat-id]]} - {::json-rpc/call [{:method "wakuext_createGroupChatFromInvitation" - :params [chat-name chat-id invitation-admin] + {::json-rpc/call [{:method "wakuext_createGroupChatFromInvitation" + :params [chat-name chat-id invitation-admin] :js-response true - :on-success #(re-frame/dispatch [:chat-updated %])}]})) + :on-success #(re-frame/dispatch [:chat-updated %])}]})) (fx/defn make-admin {:events [:group-chats.ui/make-admin-pressed]} [_ chat-id member] - {::json-rpc/call [{:method "wakuext_addAdminsToGroupChat" - :params [nil chat-id [member]] + {::json-rpc/call [{:method "wakuext_addAdminsToGroupChat" + :params [nil chat-id [member]] :js-response true - :on-success #(re-frame/dispatch [:chat-updated %])}]}) + :on-success #(re-frame/dispatch [:chat-updated %])}]}) (fx/defn add-members "Add members to a group chat" {:events [:group-chats.ui/add-members-pressed]} [{{:keys [current-chat-id selected-participants]} :db :as cofx}] - {::json-rpc/call [{:method "wakuext_addMembersToGroupChat" - :params [nil current-chat-id selected-participants] + {::json-rpc/call [{:method "wakuext_addMembersToGroupChat" + :params [nil current-chat-id selected-participants] :js-response true - :on-success #(re-frame/dispatch [:chat-updated %])}]}) + :on-success #(re-frame/dispatch [:chat-updated %])}]}) (fx/defn add-members-from-invitation "Add members to a group chat" {:events [:group-chats.ui/add-members-from-invitation]} [{{:keys [current-chat-id] :as db} :db :as cofx} id participant] {:db (assoc-in db [:group-chat/invitations id :state] constants/invitation-state-approved) - ::json-rpc/call [{:method "wakuext_addMembersToGroupChat" - :params [nil current-chat-id [participant]] + ::json-rpc/call [{:method "wakuext_addMembersToGroupChat" + :params [nil current-chat-id [participant]] :js-response true - :on-success #(re-frame/dispatch [:chat-updated %])}]}) + :on-success #(re-frame/dispatch [:chat-updated %])}]}) (fx/defn leave "Leave chat" {:events [:group-chats.ui/leave-chat-confirmed]} [{:keys [db] :as cofx} chat-id] - {::json-rpc/call [{:method "wakuext_leaveGroupChat" - :params [nil chat-id true] + {::json-rpc/call [{:method "wakuext_leaveGroupChat" + :params [nil chat-id true] :js-response true - :on-success #(re-frame/dispatch [:chat-removed %])}]}) + :on-success #(re-frame/dispatch [:chat-removed %])}]}) (fx/defn remove "Remove chat" @@ -125,10 +125,10 @@ [{:keys [db] :as cofx} chat-id new-name] (when (valid-name? new-name) {:db (assoc-in db [:chats chat-id :name] new-name) - ::json-rpc/call [{:method "wakuext_changeGroupChatName" - :params [nil chat-id new-name] + ::json-rpc/call [{:method "wakuext_changeGroupChatName" + :params [nil chat-id new-name] :js-response true - :on-success #(re-frame/dispatch [:chat-updated %])}]})) + :on-success #(re-frame/dispatch [:chat-updated %])}]})) (fx/defn membership-retry {:events [:group-chats.ui/membership-retry]} @@ -147,19 +147,19 @@ (let [{:keys [invitation-admin]} (get chats current-chat-id) message (get-in db [:chat/memberships current-chat-id :message])] {:db (assoc-in db [:chat/memberships current-chat-id] nil) - ::json-rpc/call [{:method "wakuext_sendGroupChatInvitationRequest" - :params [nil current-chat-id invitation-admin message] + ::json-rpc/call [{:method "wakuext_sendGroupChatInvitationRequest" + :params [nil current-chat-id invitation-admin message] :js-response true - :on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])}]})) + :on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])}]})) (fx/defn send-group-chat-membership-rejection "Send group chat membership rejection" {:events [:send-group-chat-membership-rejection]} [cofx invitation-id] - {::json-rpc/call [{:method "wakuext_sendGroupChatInvitationRejection" - :params [nil invitation-id] + {::json-rpc/call [{:method "wakuext_sendGroupChatInvitationRejection" + :params [nil invitation-id] :js-response true - :on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])}]}) + :on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])}]}) (fx/defn handle-invitations [{db :db} invitations] diff --git a/src/status_im/ui/screens/chat/styles/message/message.cljs b/src/status_im/ui/screens/chat/styles/message/message.cljs index a6af5d99f1..f5dceed131 100644 --- a/src/status_im/ui/screens/chat/styles/message/message.cljs +++ b/src/status_im/ui/screens/chat/styles/message/message.cljs @@ -77,7 +77,7 @@ (defn pin-indicator-container [] {:margin-top 4 - :margin-left 68 + :margin-left 54 :top 4 :justify-content :center :align-self :flex-start diff --git a/src/status_im/ui2/screens/chat/group_details/style.cljs b/src/status_im/ui2/screens/chat/group_details/style.cljs index 0654f7247d..320e77fe91 100644 --- a/src/status_im/ui2/screens/chat/group_details/style.cljs +++ b/src/status_im/ui2/screens/chat/group_details/style.cljs @@ -18,3 +18,23 @@ :height 16 :border-radius 6 :background-color (colors/theme-colors colors/neutral-80-opa-5 colors/white-opa-5)}) + +(defn close-icon [] + {:background-color (colors/theme-colors colors/neutral-10 colors/neutral-80) + :margin-left 20 + :width 32 + :height 32 + :border-radius 10 + :justify-content :center + :align-items :center + :margin-bottom 24}) + +(def bottom-container + {:position :absolute + :padding-horizontal 20 + :padding-vertical 12 + :padding-bottom 33 + :width "100%" + :background-color colors/white + :flex-direction :row + :bottom 0}) diff --git a/src/status_im/ui2/screens/chat/group_details/view.cljs b/src/status_im/ui2/screens/chat/group_details/view.cljs index 9783bd2045..13880c21cc 100644 --- a/src/status_im/ui2/screens/chat/group_details/view.cljs +++ b/src/status_im/ui2/screens/chat/group_details/view.cljs @@ -5,24 +5,40 @@ [quo2.core :as quo2] [utils.re-frame :as rf] [i18n.i18n :as i18n] - [status-im2.common.contact-list-item.view :as contact-item])) + [status-im.chat.models :as chat.models] + [status-im2.common.contact-list-item.view :as contact-list-item] + [status-im.ui2.screens.chat.messages.message :as message] + [quo.components.safe-area :as safe-area] + [reagent.core :as reagent] + [status-im2.common.home.actions.view :as actions] + [status-im.ui2.screens.common.contact-list.view :as contact-list] + [oops.core :refer [oget]])) (defn back-button [] [quo2/button {:type :grey :size 32 + :width 32 :style {:margin-left 20} :accessibility-label :back-button - :on-press #(rf/dispatch [:navigate-back]) - :icon true} - :i/arrow-left]) + :on-press #(rf/dispatch [:navigate-back])} + [quo2/icon :i/arrow-left {:color (colors/theme-colors colors/neutral-100 colors/white)}]]) (defn options-button [] - [quo2/button {:type :grey - :size 32 - :style {:margin-right 20} - :accessibility-label :options-button - :icon true} - :i/options]) + (let [group (rf/sub [:chats/current-chat])] + [quo2/button {:type :grey + :size 32 + :width 32 + :style {:margin-right 20} + :accessibility-label :options-button + :on-press #(rf/dispatch [:bottom-sheet/show-sheet + {:content (fn [] [actions/group-details-actions group])}])} + [quo2/icon :i/options {:color (colors/theme-colors colors/neutral-100 colors/white)}]])) + +(defn top-buttons [] + [rn/view {:style {:flex-direction :row + :padding-horizontal 20 + :justify-content :space-between}} + [back-button] [options-button]]) (defn count-container [count] [rn/view {:style (style/count-container)} @@ -30,35 +46,58 @@ :weight :medium :style {:text-align :center}} count]]) -(defn prepare-members [members] - (let [admins (filter :admin? members) - online (filter #(and (not (:admin? %)) (:online? %)) members) - offline (filter #(and (not (:admin? %)) (not (:online? %))) members)] - (vals (cond-> {} - (seq admins) (assoc :owner {:title "Owner" :data admins}) - (seq online) (assoc :online {:title "Online" :data online}) - (seq offline) (assoc :offline {:title "Offline" :data offline}))))) - (defn contacts-section-header [{:keys [title]}] [rn/view {:style {:padding-horizontal 20 :border-top-width 1 :border-top-color colors/neutral-20 :padding-vertical 8 :margin-top 8}} [quo2/text {:size :paragraph-2 :weight :medium :style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40)}} title]]) +(def added (reagent/atom ())) + +(defn contact-requests-sheet [group] + (let [added (reagent/atom ())] + (fn [] + [:f> + (fn [] + (let [{window-height :height} (rn/use-window-dimensions) + safe-area (safe-area/use-safe-area)] + [rn/view {:style {:height (- window-height (:top safe-area))}} + [rn/touchable-opacity + {:on-press #(rf/dispatch [:bottom-sheet/hide]) + :style (style/close-icon)} + [quo2/icon :i/close {:color (colors/theme-colors colors/neutral-100 colors/white)}]] + [quo2/text {:size :heading-1 + :weight :semi-bold + :style {:margin-left 20}} + (i18n/label :t/add-members)] + [rn/text-input {:placeholder (str (i18n/label :t/search) "...") + :style {:height 32 + :padding-horizontal 20 + :margin-vertical 12} + :on-change (fn [e] (rf/dispatch [:contacts/set-search-query (oget e "nativeEvent.text")]))}] + [contact-list/contact-list {:icon :check + :group group + :added added + :search? true}] + [rn/view {:style style/bottom-container} + [quo2/button {:style {:flex 1} + :on-press #(rf/dispatch [:bottom-sheet/hide]) + :disabled (zero? (count @added))} + (i18n/label :t/save)]]]))]))) + (defn group-details [] - (let [{:keys [admins chat-id chat-name color public?]} (rf/sub [:chats/current-chat]) - members (rf/sub [:contacts/current-chat-contacts]) - sectioned-members (prepare-members members) + (let [{:keys [admins chat-id chat-name color public? muted contacts] :as group} (rf/sub [:chats/current-chat]) + members (rf/sub [:contacts/group-members-sections]) pinned-messages (rf/sub [:chats/pinned chat-id]) - current-pk (rf/sub [:multiaccount/public-key]) - admin? (get admins current-pk)] + current-pk (rf/sub [:multiaccount/public-key]) + admin? (get admins current-pk)] [rn/view {:style {:flex 1 :background-color (colors/theme-colors colors/white colors/neutral-95)}} [quo2/header {:left-component [back-button] :right-component [options-button] :background (colors/theme-colors colors/white colors/neutral-95)}] [rn/view {:style {:flex-direction :row - :margin-top 12 + :margin-top 24 :padding-horizontal 20}} [quo2/group-avatar {:color color :size :medium}] @@ -68,23 +107,33 @@ [rn/view {:style {:margin-top 8}} [quo2/icon (if public? :i/world :i/privacy) {:size 20 :color (colors/theme-colors colors/neutral-50 colors/neutral-40)}]]] [rn/view {:style (style/actions-view)} - [rn/touchable-opacity {:style (style/action-container color)} + [rn/touchable-opacity {:style (style/action-container color) + :on-press (fn [] + (rf/dispatch [:bottom-sheet/show-sheet + {:content #(message/pinned-messages-list chat-id)}]))} [rn/view {:style {:flex-direction :row :justify-content :space-between}} [quo2/icon :i/pin {:size 20 :color (colors/theme-colors colors/neutral-100 colors/white)}] [count-container (count pinned-messages)]] - [quo2/text {:style {:margin-top 16} :size :paragraph-1 :weight :medium} (i18n/label :t/pinned-messages-2)]] - [rn/touchable-opacity {:style (style/action-container color)} - [quo2/icon :i/activity-center {:size 20 :color (colors/theme-colors colors/neutral-100 colors/white)}] - [quo2/text {:style {:margin-top 16} :size :paragraph-1 :weight :medium} (i18n/label :t/mute-group)]] - [rn/touchable-opacity {:style (style/action-container color)} + [quo2/text {:style {:margin-top 16} :size :paragraph-1 :weight :medium} (i18n/label :t/pinned-messages)]] + [rn/touchable-opacity {:style (style/action-container color) + :on-press #(rf/dispatch [::chat.models/mute-chat-toggled chat-id (not muted)])} + [quo2/icon (if muted :i/muted :i/activity-center) {:size 20 :color (colors/theme-colors colors/neutral-100 colors/white)}] + [quo2/text {:style {:margin-top 16} :size :paragraph-1 :weight :medium} (i18n/label (if muted :unmute-group :mute-group))]] + [rn/touchable-opacity {:style (style/action-container color) + :on-press #(rf/dispatch + [:bottom-sheet/show-sheet + {:content (fn [] [contact-requests-sheet group])}])} [rn/view {:style {:flex-direction :row :justify-content :space-between}} [quo2/icon :i/add-user {:size 20 :color (colors/theme-colors colors/neutral-100 colors/white)}] - [count-container (count members)]] + [count-container (count contacts)]] [quo2/text {:style {:margin-top 16} :size :paragraph-1 :weight :medium} (i18n/label (if admin? :t/manage-members :t/add-members))]]] [rn/section-list {:key-fn :title :sticky-section-headers-enabled false - :sections sectioned-members + :sections members :render-section-header-fn contacts-section-header - :render-fn contact-item/contact-item}]])) + :render-fn contact-list-item/contact-list-item + :render-data {:chat-id chat-id + :admin? admin? + :icon :options}}]])) diff --git a/src/status_im/ui2/screens/chat/messages/message.cljs b/src/status_im/ui2/screens/chat/messages/message.cljs index 24541bd668..c7b6ee255c 100644 --- a/src/status_im/ui2/screens/chat/messages/message.cljs +++ b/src/status_im/ui2/screens/chat/messages/message.cljs @@ -41,7 +41,8 @@ [quo2.components.avatars.user-avatar :as user-avatar] [quo2.components.markdown.text :as text] [status-im.utils.utils :as utils] - [status-im2.contexts.chat.home.chat-list-item.view :as home.chat-list-item]) + [status-im2.contexts.chat.home.chat-list-item.view :as home.chat-list-item] + [quo2.core :as quo2]) (:require-macros [status-im.utils.views :refer [defview letsubs]])) (defview mention-element [from] @@ -774,8 +775,9 @@ current-chat (rf/sub [:chats/current-chat]) community (rf/sub [:communities/community (:community-id current-chat)])] [rn/view {:accessibility-label :pinned-messages-list} - [rn/text {:style (merge typography/heading-1 typography/font-semi-bold {:margin-horizontal 20 - :color (colors/theme-colors colors/neutral-100 colors/white)})} + [quo2/text {:size :heading-1 + :weight :semi-bold + :style {:margin-horizontal 20}} (i18n/label :t/pinned-messages)] (when community [rn/view {:style {:flex-direction :row @@ -804,15 +806,16 @@ :separator [rn/view {:background-color (colors/theme-colors colors/neutral-10 colors/neutral-80) :height 1 :margin-top 8}]}] [rn/view {:style {:justify-content :center :align-items :center - :flex 1 :margin-top 20}} [rn/view {:style {:width 120 :height 120 :justify-content :center :align-items :center :border-width 1}} [icons/icon :i/placeholder]] - [rn/text {:style (merge typography/paragraph-1 typography/font-semi-bold {:margin-top 20})} (i18n/label :t/no-pinned-messages)] - [rn/text {:style (merge typography/paragraph-2 typography/font-regular)} + [quo2/text {:weight :semi-bold + :style {:margin-top 20}} + (i18n/label :t/no-pinned-messages)] + [quo2/text {:size :paragraph-2} (i18n/label (if community :t/no-pinned-messages-community-desc :t/no-pinned-messages-desc))]])])) (defn pin-system-message [{:keys [from in-popover? timestamp-str chat-id] :as message} {:keys [modal close-modal]}] diff --git a/src/status_im/ui2/screens/common/contact_list/view.cljs b/src/status_im/ui2/screens/common/contact_list/view.cljs new file mode 100644 index 0000000000..78cea5ae67 --- /dev/null +++ b/src/status_im/ui2/screens/common/contact_list/view.cljs @@ -0,0 +1,19 @@ +(ns status-im.ui2.screens.common.contact-list.view + (:require [react-native.core :as rn] + [status-im2.common.contact-list-item.view :as contact-list-item] + [utils.re-frame :as rf] + [quo2.core :as quo])) + +(defn contacts-section-header [{:keys [title]}] + [quo/divider-label {:label title}]) + +(defn contact-list [data] + (let [contacts (rf/sub [:contacts/filtered-active-sections])] + [rn/section-list + {:key-fn :title + :sticky-section-headers-enabled false + :sections contacts + :render-section-header-fn contacts-section-header + :content-container-style {:padding-bottom 120} + :render-data data + :render-fn contact-list-item/contact-list-item}])) diff --git a/src/status_im2/common/contact_list_item/view.cljs b/src/status_im2/common/contact_list_item/view.cljs index 09b0e6f094..4d0500cd49 100644 --- a/src/status_im2/common/contact_list_item/view.cljs +++ b/src/status_im2/common/contact_list_item/view.cljs @@ -1,28 +1,47 @@ (ns status-im2.common.contact-list-item.view - (:require [utils.re-frame :as rf] - [react-native.core :as rn] + (:require [quo2.foundations.colors :as colors] + [status-im2.contexts.chat.home.chat-list-item.style :as style] + [utils.re-frame :as rf] + [status-im2.common.home.actions.view :as actions] [quo2.core :as quo] - [quo2.foundations.colors :as colors] - [status-im2.common.contact-list-item.style :as style] - [utils.address :as utils.address] - [status-im2.common.home.actions.view :as actions])) + [react-native.core :as rn] + [react-native.platform :as platform] + [utils.address :as utils.address])) (defn open-chat [chat-id] - (rf/dispatch [:dismiss-keyboard]) - (rf/dispatch [:chat.ui/navigate-to-chat-nav2 chat-id]) - (rf/dispatch [:search/home-filter-changed nil]) - (rf/dispatch [:accept-all-activity-center-notifications-from-chat chat-id])) + (let [view-id (rf/sub [:view-id])] + (when (= view-id :shell-stack) + (rf/dispatch [:dismiss-keyboard]) + (if platform/android? + (rf/dispatch [:chat.ui/navigate-to-chat-nav2 chat-id]) + (rf/dispatch [:chat.ui/navigate-to-chat chat-id])) + (rf/dispatch [:search/home-filter-changed nil]) + (rf/dispatch [:accept-all-activity-center-notifications-from-chat chat-id])))) -(defn contact-item [item] +(defn action-icon [{:keys [public-key] :as item} {:keys [icon group added] :as extra-data}] + (let [{:keys [contacts]} group + member? (contains? contacts public-key)] + [rn/touchable-opacity {:on-press #(rf/dispatch [:bottom-sheet/show-sheet + {:content (fn [] [actions/actions item extra-data])}]) + :style {:position :absolute + :right 20}} + (if (= icon :options) + [quo/icon :i/options {:size 20 :color (colors/theme-colors colors/neutral-50 colors/neutral-40)}] + [quo/checkbox {:default-checked? member? + :on-change (fn [selected] (if selected + (swap! added conj public-key) + (reset! added (remove #(= % public-key) @added))))}])])) + +(defn contact-list-item [item _ _ extra-data] (let [{:keys [public-key ens-verified added? images]} item display-name (first (rf/sub [:contacts/contact-two-names-by-identity public-key])) - photo-path (when (seq images) (rf/sub [:chats/photo-path public-key])) - current-pk (rf/sub [:multiaccount/public-key])] - [rn/touchable-opacity (merge {:style style/container - :on-press #(open-chat public-key) - :on-long-press #(when-not (= current-pk public-key) - (rf/dispatch [:bottom-sheet/show-sheet - {:content (fn [] [actions/actions item])}]))}) + photo-path (when (seq images) (rf/sub [:chats/photo-path public-key])) + current-pk (rf/sub [:multiaccount/public-key])] + [rn/touchable-opacity (merge {:style (style/container) + :active-opacity 1 + :on-press #(open-chat public-key) + :on-long-press #(rf/dispatch [:bottom-sheet/show-sheet + {:content (fn [] [actions/actions item extra-data])}])}) [quo/user-avatar {:full-name display-name :profile-picture photo-path :status-indicator? true @@ -38,12 +57,9 @@ (when added? [rn/view {:style {:margin-left 5 :margin-top 4}} [quo/icon :i/contact {:no-color true :size 12 :color (colors/theme-colors colors/primary-50 colors/primary-60)}]]))] - [quo/text {:style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40)}} + [quo/text {:size :paragraph-1 + :style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40)}} (utils.address/get-shortened-address public-key)]] (when-not (= current-pk public-key) - [rn/touchable-opacity {:style {:position :absolute - :right 20} - :active-opacity 1 - :on-press #(rf/dispatch [:bottom-sheet/show-sheet - {:content (fn [] [actions/actions item])}])} - [quo/icon :i/options {:size 20 :color (colors/theme-colors colors/neutral-50 colors/neutral-40)}]])])) + [action-icon item extra-data])])) + diff --git a/src/status_im2/common/home/actions/view.cljs b/src/status_im2/common/home/actions/view.cljs index dbfb921db4..7b7adb5892 100644 --- a/src/status_im2/common/home/actions/view.cljs +++ b/src/status_im2/common/home/actions/view.cljs @@ -4,7 +4,7 @@ [quo2.components.drawers.action-drawers :as drawer] [status-im2.common.confirmation-drawer.view :as confirmation-drawer] - ;;TODO move to status-im2 + ;;TODO move to status-im2 [status-im.constants :as constants] [status-im.chat.models :as chat.models] [status-im.chat.models.pin-message :as models.pin-message])) @@ -46,45 +46,43 @@ (defn clear-history-action [{:keys [chat-id] :as item}] (hide-sheet-and-dispatch [:bottom-sheet/show-sheet {:content (fn [] - (confirmation-drawer/confirmation-drawer - {:title (i18n/label :t/clear-history?) - :description (i18n/label :t/clear-history-confirmation-content) - :context item - :button-text (i18n/label :t/clear-history) - :on-press #(hide-sheet-and-dispatch [:chat.ui/clear-history chat-id])}))}])) + (confirmation-drawer/confirmation-drawer {:title (i18n/label :t/clear-history?) + :description (i18n/label :t/clear-history-confirmation-content) + :context item + :button-text (i18n/label :t/clear-history) + :on-press #(hide-sheet-and-dispatch [:chat.ui/clear-history chat-id])}))}])) (defn delete-chat-action [{:keys [chat-id] :as item}] (hide-sheet-and-dispatch [:bottom-sheet/show-sheet {:content (fn [] - (confirmation-drawer/confirmation-drawer - {:title (i18n/label :t/delete-chat?) - :description (i18n/label :t/delete-chat-confirmation) - :context item - :button-text (i18n/label :t/delete-chat) - :on-press #(hide-sheet-and-dispatch [:chat.ui/remove-chat chat-id])}))}])) + (confirmation-drawer/confirmation-drawer {:title (i18n/label :t/delete-chat?) + :description (i18n/label :t/delete-chat-confirmation) + :context item + :button-text (i18n/label :t/delete-chat) + :on-press #(hide-sheet-and-dispatch [:chat.ui/remove-chat chat-id])}))}])) -(defn leave-group-action [{:keys [chat-id] :as item}] +(defn leave-group-action [item chat-id] (hide-sheet-and-dispatch [:bottom-sheet/show-sheet {:content (fn [] - (confirmation-drawer/confirmation-drawer - {:title (i18n/label :t/leave-group?) - :description (i18n/label :t/leave-chat-confirmation) - :context item - :button-text (i18n/label :t/leave-group) - :on-press #(hide-sheet-and-dispatch [:chat.ui/leave-chat chat-id])}))}])) + (confirmation-drawer/confirmation-drawer {:title (i18n/label :t/leave-group?) + :description (i18n/label :t/leave-chat-confirmation) + :context item + :button-text (i18n/label :t/leave-group) + :on-press #(do + (rf/dispatch [:navigate-back]) + (hide-sheet-and-dispatch [:group-chats.ui/leave-chat-confirmed chat-id]))}))}])) (defn block-user-action [{:keys [public-key] :as item}] (hide-sheet-and-dispatch [:bottom-sheet/show-sheet - {:content (fn [] (confirmation-drawer/confirmation-drawer - {:title (i18n/label :t/block-user?) - :description (i18n/label :t/block-contact-details) - :context item - :button-text (i18n/label :t/block-user) - :on-press #(hide-sheet-and-dispatch [:contact.ui/block-contact-confirmed public-key])}))}])) + {:content (fn [] (confirmation-drawer/confirmation-drawer {:title (i18n/label :t/block-user?) + :description (i18n/label :t/block-contact-details) + :context item + :button-text (i18n/label :t/block-user) + :on-press #(hide-sheet-and-dispatch [:contact.ui/block-contact-confirmed public-key])}))}])) (defn mute-chat-entry [chat-id] (let [muted? (rf/sub [:chats/muted chat-id])] - (entry {:icon :i/muted + (entry {:icon (if muted? :i/muted :i/activity-center) :label (i18n/label (if muted? :unmute-chat @@ -122,13 +120,14 @@ :sub-label nil :chevron? false})) -(defn leave-group-entry [item] - (entry {:icon :i/log-out - :label (i18n/label :t/leave-group) - :on-press #(leave-group-action item) - :danger? true - :sub-label nil - :chevron? false})) +(defn leave-group-entry [item extra-data] + (entry {:icon :i/log-out + :label (i18n/label :t/leave-group) + :on-press #(leave-group-action item (if extra-data (:chat-id extra-data) (:chat-id item))) + :danger? true + :sub-label nil + :chevron? false + :add-divider? extra-data})) (defn view-profile-entry [chat-id] (entry {:icon :i/friend @@ -146,14 +145,26 @@ :sub-label nil :chevron? false})) -(defn notifications-entry [] - (entry {:icon :i/notifications - :label (i18n/label :t/notifications) +;; TODO(OmarBasem): Requires design input. +(defn edit-name-image-entry [] + (entry {:icon :i/edit + :label (i18n/label :t/edit-name-and-image) :on-press #(js/alert "TODO: to be implemented, requires design input") :danger? false - :sub-label "All messages" ; TODO: placeholder - :chevron? true})) + :sub-label nil + :chevron? false})) +;; TODO(OmarBasem): Requires design input. +(defn notifications-entry [add-divider?] + (entry {:icon :i/notifications + :label (i18n/label :t/notifications) + :on-press #(js/alert "TODO: to be implemented, requires design input") + :danger? false + :sub-label "All messages" ; TODO: placeholder + :chevron? true + :add-divider? add-divider?})) + +;; TODO(OmarBasem): Requires design input. (defn fetch-messages-entry [] (entry {:icon :i/save :label (i18n/label :t/fetch-messages) @@ -162,6 +173,7 @@ :sub-label nil :chevron? true})) +;; TODO(OmarBasem): Requires design input. (defn pinned-messages-entry [] (entry {:icon :i/pin :label (i18n/label :t/pinned-messages) @@ -178,6 +190,7 @@ :sub-label nil :chevron? false})) +;; TODO(OmarBasem): Requires design input. (defn rename-entry [] (entry {:icon :i/edit :label (i18n/label :t/rename) @@ -186,6 +199,7 @@ :sub-label nil :chevron? false})) +;; TODO(OmarBasem): Requires design input. (defn show-qr-entry [] (entry {:icon :i/qr-code :label (i18n/label :t/show-qr) @@ -194,6 +208,7 @@ :sub-label nil :chevron? false})) +;; TODO(OmarBasem): to be implemented. (defn share-profile-entry [] (entry {:icon :i/share :label (i18n/label :t/share-profile) @@ -202,6 +217,7 @@ :sub-label nil :chevron? false})) +;; TODO(OmarBasem): to be implemented. (defn share-group-entry [] (entry {:icon :i/share :label (i18n/label :t/share) @@ -210,6 +226,7 @@ :sub-label nil :chevron? false})) +;; TODO(OmarBasem): Requires status-go impl. (defn mark-untrustworthy-entry [] (entry {:icon :i/alert :label (i18n/label :t/mark-untrustworthy) @@ -227,6 +244,16 @@ :sub-label nil :chevron? false})) +(defn remove-from-group-entry [{:keys [public-key]} chat-id] + (let [username (first (rf/sub [:contacts/contact-two-names-by-identity public-key]))] + (entry {:icon :i/placeholder + :label (i18n/label :t/remove-user-from-group {:username username}) + :on-press #(hide-sheet-and-dispatch [:group-chats.ui/remove-member-pressed chat-id public-key true]) + :danger? true + :sub-label nil + :chevron? false + :add-divider? true}))) + (defn group-details-entry [chat-id] (entry {:icon :i/members :label (i18n/label :t/group-details) @@ -235,6 +262,7 @@ :sub-label nil :chevron? false})) +;; TODO(OmarBasem): to be implemented. (defn add-members-entry [] (entry {:icon :i/add-user :label (i18n/label :t/add-members) @@ -243,6 +271,7 @@ :sub-label nil :chevron? false})) +;; TODO(OmarBasem): to be implemented. (defn manage-members-entry [] (entry {:icon :i/add-user :label (i18n/label :t/manage-members) @@ -251,6 +280,7 @@ :sub-label nil :chevron? false})) +;; TODO(OmarBasem): to be implemented. (defn edit-group-entry [] (entry {:icon :i/edit :label (i18n/label :t/edit-name-and-image) @@ -259,6 +289,7 @@ :sub-label nil :chevron? false})) +;; TODO(OmarBasem): to be implemented. (defn group-privacy-entry [] (entry {:icon :i/privacy :label (i18n/label :t/change-group-privacy) @@ -270,13 +301,13 @@ (defn destructive-actions [{:keys [group-chat] :as item}] [(clear-history-entry item) (if group-chat - (leave-group-entry item) + (leave-group-entry item nil) (delete-chat-entry item))]) (defn notification-actions [{:keys [chat-id group-chat public?]} inside-chat?] [(mark-as-read-entry chat-id) (mute-chat-entry chat-id) - (notifications-entry) + (notifications-entry false) (if inside-chat? (fetch-messages-entry) (pinned-messages-entry)) @@ -288,8 +319,8 @@ (share-group-entry))]) (defn group-actions [{:keys [chat-id admins]} inside-chat?] - (let [current-pk (rf/sub [:multiaccount/public-key]) - admin? (get admins current-pk)] + (let [current-pub-key (rf/sub [:multiaccount/public-key]) + admin? (get admins current-pub-key)] [(group-details-entry chat-id) (when inside-chat? (if admin? @@ -316,17 +347,21 @@ (notification-actions item inside-chat?) (destructive-actions item)]]) -(defn contact-actions [{:keys [public-key added] :as contact}] - [drawer/action-drawer [[(view-profile-entry public-key) - (when added +(defn contact-actions [{:keys [public-key] :as contact} {:keys [chat-id admin?] :as extra-data}] + (let [current-pub-key (rf/sub [:multiaccount/public-key])] + [drawer/action-drawer [[(view-profile-entry public-key) (remove-from-contacts-entry contact) (rename-entry) (show-qr-entry) - (share-profile-entry))] - [(mark-untrustworthy-entry) - (block-user-entry contact)]]]) + (share-profile-entry)] + [(mark-untrustworthy-entry) + (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 actions [{:keys [chat-type] :as item} inside-chat?] +(defn actions [{:keys [chat-type] :as item} {:keys [inside-chat?] :as extra-data}] (case chat-type constants/one-to-one-chat-type [one-to-one-actions item inside-chat?] @@ -334,4 +369,11 @@ [public-chat-actions item inside-chat?] constants/private-group-chat-type [private-group-chat-actions item inside-chat?] - [contact-actions item])) + [contact-actions item extra-data])) + +(defn group-details-actions [{:keys [admins] :as group}] + (let [current-pub-key (rf/sub [:multiaccount/public-key]) + admin? (get admins current-pub-key)] + [drawer/action-drawer [(when admin? [(edit-name-image-entry)]) + [(notifications-entry admin?)] + (destructive-actions group)]])) diff --git a/src/status_im2/contexts/chat/home/chat_list_item/style.cljs b/src/status_im2/contexts/chat/home/chat_list_item/style.cljs index 7e78ac6385..e2f27c935c 100644 --- a/src/status_im2/contexts/chat/home/chat_list_item/style.cljs +++ b/src/status_im2/contexts/chat/home/chat_list_item/style.cljs @@ -1,7 +1,7 @@ (ns status-im2.contexts.chat.home.chat-list-item.style (:require [quo2.foundations.colors :as colors])) -(def container +(defn container [] {:margin-top 8 :margin-horizontal 8 :padding-vertical 8 diff --git a/src/status_im2/contexts/chat/home/chat_list_item/view.cljs b/src/status_im2/contexts/chat/home/chat_list_item/view.cljs index 736c55bfef..6fb85dd7bd 100644 --- a/src/status_im2/contexts/chat/home/chat_list_item/view.cljs +++ b/src/status_im2/contexts/chat/home/chat_list_item/view.cljs @@ -108,7 +108,7 @@ display-name (if group-chat name (first (rf/sub [:contacts/contact-two-names-by-identity chat-id]))) contact (when-not group-chat (rf/sub [:contacts/contact-by-address chat-id])) photo-path (when-not (empty? (:images contact)) (rf/sub [:chats/photo-path chat-id]))] - [rn/touchable-opacity (merge {:style style/container + [rn/touchable-opacity (merge {:style (style/container) :on-press (open-chat chat-id) :on-long-press #(rf/dispatch [:bottom-sheet/show-sheet {:content (fn [] [actions/actions item false])}])}) diff --git a/src/status_im2/contexts/chat/home/view.cljs b/src/status_im2/contexts/chat/home/view.cljs index 356433c259..828c5c15a7 100644 --- a/src/status_im2/contexts/chat/home/view.cljs +++ b/src/status_im2/contexts/chat/home/view.cljs @@ -8,7 +8,7 @@ [status-im2.common.home.view :as common.home] [status-im2.contexts.chat.home.contact-request.view :as contact-request] [status-im2.contexts.chat.home.chat-list-item.view :as chat-list-item] - [status-im2.common.contact-list-item.view :as contact-list-item])) + [status-im.ui2.screens.common.contact-list.view :as contact-list])) (defn get-item-layout [_ index] #js {:length 64 :offset (* 64 index) :index index}) @@ -44,9 +44,6 @@ [quo/text {:weight :semi-bold} (i18n/label :t/no-contacts)] [quo/text (i18n/label :t/blank-contacts-text)]]) -(defn contacts-section-header [{:keys [title]}] - [quo/divider-label {:label title}]) - (defn contacts [contact-requests] (let [items (rf/sub [:contacts/active-sections])] (if (empty? items) @@ -54,12 +51,7 @@ [:<> (when (pos? (count contact-requests)) [contact-request/contact-requests contact-requests]) - [rn/section-list - {:key-fn :title - :sticky-section-headers-enabled false - :sections items - :render-section-header-fn contacts-section-header - :render-fn contact-list-item/contact-item}]]))) + [contact-list/contact-list {:icon :options}]]))) (defn tabs [] (let [selected-tab (reagent/atom :recent)] diff --git a/src/status_im2/navigation/view.cljs b/src/status_im2/navigation/view.cljs index d4be3aa64d..d9c37d9ace 100644 --- a/src/status_im2/navigation/view.cljs +++ b/src/status_im2/navigation/view.cljs @@ -8,7 +8,7 @@ [status-im2.setup.config :as config] [status-im2.setup.hot-reload :as reloader] - ;; TODO (14/11/22 flexsurfer) move to status-im2 namespace + ;; TODO (14/11/22 flexsurfer) move to status-im2 namespace [status-im.ui.screens.popover.views :as popover] [status-im.ui.screens.profile.visibility-status.views :as visibility-status-views] [status-im.ui.screens.bottom-sheets.views :as bottom-sheets] diff --git a/src/status_im2/subs/contact.cljs b/src/status_im2/subs/contact.cljs index ba18c046aa..876bf73fcc 100644 --- a/src/status_im2/subs/contact.cljs +++ b/src/status_im2/subs/contact.cljs @@ -3,10 +3,11 @@ [status-im.contact.db :as contact.db] [status-im.utils.image-server :as image-server] [status-im.ui.screens.profile.visibility-status.utils :as visibility-status-utils] - [clojure.string :as string] [status-im.multiaccounts.core :as multiaccounts] [status-im.utils.gfycat.core :as gfycat] - [status-im.ethereum.core :as ethereum])) + [status-im.ethereum.core :as ethereum] + [clojure.string :as string] + [i18n.i18n :as i18n])) (re-frame/reg-sub ::query-current-chat-contacts @@ -251,4 +252,35 @@ (assoc acc address contact) acc)) {} - contacts))) \ No newline at end of file + contacts))) + +(re-frame/reg-sub + :contacts/filtered-active-sections + :<- [:contacts/active-sections] + :<- [:contacts/search-query] + (fn [[contacts query]] + (if (empty? query) + contacts + (->> contacts + (map (fn [item] + (update item :data (fn [data] + (filter #(string/includes? + (string/lower-case (:alias %)) + (string/lower-case query)) + data))))) + (remove #(empty? (:data %))))))) + +(re-frame/reg-sub + :contacts/group-members-sections + :<- [:contacts/current-chat-contacts] + (fn [members] + (let [admins (filter :admin? members) + online (filter #(and (not (:admin? %)) (:online? %)) members) + offline (filter #(and (not (:admin? %)) (not (:online? %))) members)] + (vals (cond-> {} + (seq admins) (assoc :owner {:title (i18n/label :t/owner) :data admins}) + (seq online) (assoc :online {:title (i18n/label :t/online) :data online}) + (seq offline) (assoc :offline {:title (i18n/label :t/offline) :data offline})))))) + + + diff --git a/src/status_im2/subs/root.cljs b/src/status_im2/subs/root.cljs index 74f398adae..e25617da8e 100644 --- a/src/status_im2/subs/root.cljs +++ b/src/status_im2/subs/root.cljs @@ -140,6 +140,7 @@ (reg-root-key-sub :contacts/new-identity :contacts/new-identity) (reg-root-key-sub :group/selected-contacts :group/selected-contacts) (reg-root-key-sub :contacts/blocked-set :contacts/blocked) +(reg-root-key-sub :contacts/search-query :contacts/search-query) ;;wallet (reg-root-key-sub :wallet :wallet) diff --git a/translations/en.json b/translations/en.json index 1d73e25cbb..1cd3a3b2f4 100644 --- a/translations/en.json +++ b/translations/en.json @@ -1870,5 +1870,9 @@ "italic": "Italic", "strikethrough": "Strikethrough", "add-text": "Add text", - "send": "Send" + "send": "Send", + "unmute-group": "Unmute group", + "remove-user-from-group": "Remove {{username}} from the group", + "edit-name-image": "Edit name and image", + "owner": "Owner" }