Add chat actions in home screen
This commit adds the following chat actions on the home screen: - Mute chat - Delete chat - View profile (one to ones only) - Clear history It adds also integration tests for muting and deleting a chat. To accommodate multiple dividers in the bottom sheet, the interface has been changed to accept a sequence of sequences, instead of a map.
This commit is contained in:
parent
b492ed2969
commit
b774ecbcb4
|
@ -5,64 +5,70 @@
|
|||
[quo2.components.icon :as icon]
|
||||
[quo2.foundations.colors :as colors]))
|
||||
|
||||
(defn- get-icon-color [section]
|
||||
(if (= section :bottom)
|
||||
(defn- get-icon-color [danger?]
|
||||
(if danger?
|
||||
(colors/theme-colors colors/danger-50 colors/danger-60)
|
||||
(colors/theme-colors colors/neutral-50 colors/neutral-40)))
|
||||
|
||||
(defn action [section]
|
||||
(fn [{:keys [icon label sub-label right-icon on-press]}]
|
||||
[rn/touchable-opacity {:on-press on-press}
|
||||
[react/view {:style
|
||||
{:flex 1
|
||||
:height (if sub-label 56 47)
|
||||
:margin-horizontal 20
|
||||
:flex-direction :row}}
|
||||
[react/view {:style
|
||||
{:height 20
|
||||
:margin-top :auto
|
||||
:margin-bottom :auto
|
||||
:margin-right 12
|
||||
:width 20}}
|
||||
[icon/icon icon
|
||||
{:color (get-icon-color section)
|
||||
:size 20}]]
|
||||
[react/view
|
||||
{:style
|
||||
{:flex 1
|
||||
:justify-content :center}}
|
||||
(defn action [{:keys [icon
|
||||
label
|
||||
sub-label
|
||||
right-icon
|
||||
danger?
|
||||
on-press]}]
|
||||
[rn/touchable-opacity {:on-press on-press}
|
||||
[react/view {:style
|
||||
{:height (if sub-label 56 47)
|
||||
:margin-horizontal 20
|
||||
:flex-direction :row}}
|
||||
[react/view {:style
|
||||
{:height 20
|
||||
:margin-top :auto
|
||||
:margin-bottom :auto
|
||||
:margin-right 12
|
||||
:width 20}}
|
||||
[icon/icon icon
|
||||
{:color (get-icon-color danger?)
|
||||
:size 20}]]
|
||||
[react/view
|
||||
{:style
|
||||
{:flex 1
|
||||
:justify-content :center}}
|
||||
[text/text
|
||||
{:size :paragraph-1
|
||||
:weight :medium
|
||||
:style {:color
|
||||
(when danger?
|
||||
(colors/theme-colors colors/danger-50 colors/danger-60))}}
|
||||
label]
|
||||
(when sub-label
|
||||
[text/text
|
||||
{:size :paragraph-1
|
||||
:weight :medium
|
||||
:style
|
||||
{:color (when (= section :bottom)
|
||||
(colors/theme-colors colors/danger-50 colors/danger-60))}}
|
||||
label]
|
||||
(when sub-label [text/text
|
||||
{:size :paragraph-2
|
||||
:style
|
||||
{:color (colors/theme-colors colors/neutral-50 colors/neutral-40)}}
|
||||
sub-label])]
|
||||
(when right-icon
|
||||
[react/view {:style
|
||||
{:height 20
|
||||
:margin-top :auto
|
||||
:margin-bottom :auto
|
||||
:width 20}}
|
||||
[icon/icon right-icon
|
||||
{:color (get-icon-color section)
|
||||
:size 20}]])]]))
|
||||
{:size :paragraph-2
|
||||
:style {:color
|
||||
(colors/theme-colors colors/neutral-50 colors/neutral-40)}}
|
||||
sub-label])]
|
||||
(when right-icon
|
||||
[react/view {:style
|
||||
{:height 20
|
||||
:margin-top :auto
|
||||
:margin-bottom :auto
|
||||
:width 20}}
|
||||
[icon/icon right-icon
|
||||
{:color (get-icon-color danger?)
|
||||
:size 20}]])]])
|
||||
|
||||
(defn action-drawer [{:keys [actions actions-with-consequence]}]
|
||||
(defn divider []
|
||||
[rn/view {:style {:border-top-width 1
|
||||
:border-top-color (colors/theme-colors colors/neutral-10 colors/neutral-80)
|
||||
:margin-top 8
|
||||
:margin-bottom 7
|
||||
:align-items :center
|
||||
:flex-direction :row}}])
|
||||
|
||||
(defn action-drawer [sections]
|
||||
[:<> {:style
|
||||
{:flex 1}}
|
||||
(map (action :top) actions)
|
||||
(when actions-with-consequence
|
||||
[:<>
|
||||
[rn/view {:style {:border-top-width 1
|
||||
:border-top-color (colors/theme-colors colors/neutral-10 colors/neutral-80)
|
||||
:margin-top 8
|
||||
:margin-bottom 7
|
||||
:align-items :center
|
||||
:flex-direction :row}}]
|
||||
(map (action :bottom) actions-with-consequence)])])
|
||||
(interpose
|
||||
[divider]
|
||||
(for [actions sections]
|
||||
(map action actions)))])
|
||||
|
|
|
@ -14,24 +14,27 @@
|
|||
:key :show-red-options?
|
||||
:type :boolean}])
|
||||
|
||||
(def options-with-consequences [{:icon :main-icons2/share-context
|
||||
:label "Clear history"}])
|
||||
(def options-with-consequences [{:icon :main-icons2/delete
|
||||
:danger? true
|
||||
:label "Clear history"}])
|
||||
|
||||
(defn render-action-sheet [state]
|
||||
[quo2/action-drawer {:actions-with-consequence (when (:show-red-options? @state) options-with-consequences)
|
||||
:actions [{:icon :main-icons2/share-context
|
||||
:label "View channel members and details"}
|
||||
{:icon :main-icons2/communities
|
||||
:label "Mark as read"}
|
||||
{:icon :main-icons2/muted
|
||||
:label (if (:muted? @state) "Unmute channel" "Mute channel")
|
||||
:right-icon :main-icons2/chevron-right
|
||||
:sub-label (when (:muted? @state) "Muted for 15 min")}
|
||||
{:icon :main-icons2/scan
|
||||
:right-icon :main-icons2/chevron-right
|
||||
:label "Fetch messages"}
|
||||
{:icon :main-icons2/add-user
|
||||
:label "Share link to the channel"}]}])
|
||||
[quo2/action-drawer (cond-> [[{:icon :main-icons2/friend
|
||||
:label "View channel members and details"}
|
||||
{:icon :main-icons2/communities
|
||||
:label "Mark as read"}
|
||||
{:icon :main-icons2/muted
|
||||
:label (if (:muted? @state) "Unmute channel" "Mute channel")
|
||||
:right-icon :main-icons2/chevron-right
|
||||
:sub-label (when (:muted? @state) "Muted for 15 min")}
|
||||
{:icon :main-icons2/scan
|
||||
:right-icon :main-icons2/chevron-right
|
||||
:label "Fetch messages"}
|
||||
{:icon :main-icons2/add-user
|
||||
:label "Share link to the channel"}]]
|
||||
|
||||
(:show-red-options? @state)
|
||||
(conj options-with-consequences))])
|
||||
|
||||
(defn cool-preview []
|
||||
(let [state (reagent/atom {:muted? true
|
||||
|
|
|
@ -176,6 +176,11 @@
|
|||
:on-error #(log/error "failed to clear history " chat-id %)}]}
|
||||
(clear-history chat-id remove-chat?)))
|
||||
|
||||
(fx/defn chat-deactivated
|
||||
{:events [::chat-deactivated]}
|
||||
[_ chat-id]
|
||||
(log/debug "chat deactivated" chat-id))
|
||||
|
||||
(fx/defn deactivate-chat
|
||||
"Deactivate chat in db, no side effects"
|
||||
[{:keys [db now] :as cofx} chat-id]
|
||||
|
@ -185,10 +190,10 @@
|
|||
(assoc-in db [:chats chat-id :active] false)
|
||||
(update db :chats dissoc chat-id))
|
||||
(update :chats-home-list disj chat-id)
|
||||
(assoc-in [:current-chat-id] nil))
|
||||
(assoc :current-chat-id nil))
|
||||
::json-rpc/call [{:method "wakuext_deactivateChat"
|
||||
:params [{:id chat-id}]
|
||||
:on-success #(log/debug "chat deactivated" chat-id)
|
||||
:on-success #(re-frame/dispatch [::chat-deactivated chat-id])
|
||||
:on-error #(log/error "failed to create public chat" chat-id %)}]}
|
||||
(clear-history chat-id true)))
|
||||
|
||||
|
@ -227,9 +232,7 @@
|
|||
{:clear-message-notifications
|
||||
[[chat-id] (get-in db [:multiaccount :remote-push-notifications-enabled?])]}
|
||||
(deactivate-chat chat-id)
|
||||
(offload-messages chat-id)
|
||||
(when (not (= (:view-id db) :home))
|
||||
(navigation/pop-to-root-tab :chat-stack))))
|
||||
(offload-messages chat-id)))
|
||||
|
||||
(fx/defn show-more-chats
|
||||
{:events [:chat.ui/show-more-chats]}
|
||||
|
@ -385,6 +388,11 @@
|
|||
(log/error "mute chat failed" chat-id error)
|
||||
{:db (assoc-in db [:chats chat-id :muted] (not muted?))})
|
||||
|
||||
(fx/defn mute-chat-toggled-successfully
|
||||
{:events [::mute-chat-toggled-successfully]}
|
||||
[_ chat-id]
|
||||
(log/debug "muted chat successfully" chat-id))
|
||||
|
||||
(fx/defn mute-chat
|
||||
{:events [::mute-chat-toggled]}
|
||||
[{:keys [db] :as cofx} chat-id muted?]
|
||||
|
@ -393,7 +401,7 @@
|
|||
::json-rpc/call [{:method method
|
||||
:params [chat-id]
|
||||
:on-error #(re-frame/dispatch [::mute-chat-failed chat-id muted? %])
|
||||
:on-success #(log/debug "muted chat successfully")}]}))
|
||||
:on-success #(re-frame/dispatch [::mute-chat-toggled-successfully chat-id])}]}))
|
||||
|
||||
(fx/defn show-profile
|
||||
{:events [:chat.ui/show-profile]}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
[clojure.string :as string]
|
||||
[re-frame.core :as rf]
|
||||
status-im.events
|
||||
[status-im.chat.models :as chat.models]
|
||||
[status-im.utils.security :as security]
|
||||
[status-im.multiaccounts.logout.core :as logout]
|
||||
[status-im.transport.core :as transport]
|
||||
|
@ -231,5 +232,65 @@
|
|||
(logout!) (rf-test/wait-for [::logout/logout-method] ; we need to logout to make sure the node is not in an inconsistent state between tests
|
||||
(assert-logout))))))))
|
||||
|
||||
(deftest delete-chat-test
|
||||
(log/info "========= delete-chat-test ==================")
|
||||
(rf-test/run-test-async
|
||||
(initialize-app!)
|
||||
(rf-test/wait-for
|
||||
[:status-im.init.core/initialize-view]
|
||||
(generate-and-derive-addresses!)
|
||||
(rf-test/wait-for
|
||||
[:multiaccount-generate-and-derive-addresses-success] ; wait for the keys
|
||||
(assert-multiaccount-loaded)
|
||||
(create-multiaccount!)
|
||||
(rf-test/wait-for
|
||||
[::transport/messenger-started]
|
||||
(assert-messenger-started)
|
||||
(rf/dispatch-sync [:chat.ui/start-chat chat-id]) ;; start a new chat
|
||||
(rf-test/wait-for
|
||||
[:status-im.chat.models/one-to-one-chat-created]
|
||||
(rf/dispatch-sync [:chat.ui/navigate-to-chat chat-id])
|
||||
(is (= chat-id @(rf/subscribe [:chats/current-chat-id])))
|
||||
(is @(rf/subscribe [:chats/chat chat-id]))
|
||||
(rf/dispatch-sync [:chat.ui/remove-chat-pressed chat-id])
|
||||
(rf/dispatch-sync [:chat.ui/remove-chat chat-id])
|
||||
(rf-test/wait-for
|
||||
[::chat.models/chat-deactivated]
|
||||
(is (not @(rf/subscribe [:chats/chat chat-id])))
|
||||
(logout!) (rf-test/wait-for [::logout/logout-method] ; we need to logout to make sure the node is not in an inconsistent state between tests
|
||||
(assert-logout)))))))))
|
||||
|
||||
(deftest mute-chat-test
|
||||
(log/info "========= mute-chat-test ==================")
|
||||
(rf-test/run-test-async
|
||||
(initialize-app!)
|
||||
(rf-test/wait-for
|
||||
[:status-im.init.core/initialize-view]
|
||||
(generate-and-derive-addresses!)
|
||||
(rf-test/wait-for
|
||||
[:multiaccount-generate-and-derive-addresses-success] ; wait for the keys
|
||||
(assert-multiaccount-loaded)
|
||||
(create-multiaccount!)
|
||||
(rf-test/wait-for
|
||||
[::transport/messenger-started]
|
||||
(assert-messenger-started)
|
||||
(rf/dispatch-sync [:chat.ui/start-chat chat-id]) ;; start a new chat
|
||||
(rf-test/wait-for
|
||||
[:status-im.chat.models/one-to-one-chat-created]
|
||||
(rf/dispatch-sync [:chat.ui/navigate-to-chat chat-id])
|
||||
(is (= chat-id @(rf/subscribe [:chats/current-chat-id])))
|
||||
(is @(rf/subscribe [:chats/chat chat-id]))
|
||||
(rf/dispatch-sync [::chat.models/mute-chat-toggled chat-id true])
|
||||
(rf-test/wait-for
|
||||
[::chat.models/mute-chat-toggled-successfully]
|
||||
(is @(rf/subscribe [:chats/muted chat-id]))
|
||||
(rf/dispatch-sync [::chat.models/mute-chat-toggled chat-id false])
|
||||
(rf-test/wait-for
|
||||
[::chat.models/mute-chat-toggled-successfully]
|
||||
|
||||
(is (not @(rf/subscribe [:chats/muted chat-id])))
|
||||
(logout!) (rf-test/wait-for [::logout/logout-method] ; we need to logout to make sure the node is not in an inconsistent state between tests
|
||||
(assert-logout))))))))))
|
||||
|
||||
(comment
|
||||
(run-tests))
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
(ns status-im.ui2.screens.chat.actions
|
||||
(:require
|
||||
[status-im.chat.models :as chat.models]
|
||||
[status-im.chat.models.pin-message :as models.pin-message]
|
||||
[status-im.i18n.i18n :as i18n]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.utils.handlers :refer [<sub >evt]]
|
||||
[quo2.components.drawers.action-drawers :as drawer]))
|
||||
|
||||
(defn- entry [icon label on-press danger?]
|
||||
{:pre [(keyword? icon)
|
||||
(string? label)
|
||||
(fn? on-press)
|
||||
(boolean? danger?)]}
|
||||
{:icon icon
|
||||
:label label
|
||||
:on-press on-press
|
||||
:danger? danger?})
|
||||
|
||||
(defn hide-sheet-and-dispatch [event]
|
||||
(>evt [:bottom-sheet/hide])
|
||||
(>evt event))
|
||||
|
||||
(defn show-profile-action [chat-id]
|
||||
(hide-sheet-and-dispatch [:chat.ui/show-profile chat-id])
|
||||
(>evt [::models.pin-message/load-pin-messages chat-id]))
|
||||
|
||||
(defn mark-all-read-action [chat-id]
|
||||
(hide-sheet-and-dispatch [:chat/mark-all-as-read chat-id]))
|
||||
|
||||
(defn edit-nickname-action [chat-id]
|
||||
(hide-sheet-and-dispatch [:chat.ui/edit-nickname chat-id]))
|
||||
|
||||
(defn mute-chat-action [chat-id]
|
||||
(hide-sheet-and-dispatch [::chat.models/mute-chat-toggled chat-id true]))
|
||||
|
||||
(defn unmute-chat-action [chat-id]
|
||||
(hide-sheet-and-dispatch [::chat.models/mute-chat-toggled chat-id false]))
|
||||
|
||||
(defn clear-history-action [chat-id]
|
||||
(hide-sheet-and-dispatch [:chat.ui/clear-history-pressed chat-id]))
|
||||
|
||||
(defn delete-chat-action [chat-id]
|
||||
(hide-sheet-and-dispatch [:chat.ui/remove-chat-pressed chat-id]))
|
||||
|
||||
(defn mute-chat-entry [muted? chat-id]
|
||||
(entry :main-icons2/muted
|
||||
(i18n/label
|
||||
(if muted?
|
||||
:unmute-chat
|
||||
:mute-chat))
|
||||
(if muted?
|
||||
#(unmute-chat-action chat-id)
|
||||
#(mute-chat-action chat-id))
|
||||
false))
|
||||
|
||||
(defn mark-as-read-entry [chat-id]
|
||||
(entry :main-icons2/check
|
||||
(i18n/label :mark-as-read)
|
||||
#(mark-all-read-action chat-id)
|
||||
false))
|
||||
|
||||
(defn clear-history-entry [chat-id]
|
||||
(entry :main-icons2/delete
|
||||
(i18n/label :clear-history)
|
||||
#(clear-history-action chat-id)
|
||||
true))
|
||||
|
||||
(defn delete-chat-entry [chat-id]
|
||||
(entry :main-icons2/delete
|
||||
(i18n/label :delete-chat)
|
||||
#(delete-chat-action chat-id)
|
||||
true))
|
||||
|
||||
(defn view-profile-entry [chat-id]
|
||||
(entry :main-icons2/friend
|
||||
(i18n/label :view-profile)
|
||||
#(show-profile-action chat-id)
|
||||
false))
|
||||
|
||||
(defn edit-nickname-entry [chat-id]
|
||||
(entry :main-icons2/edit
|
||||
(i18n/label :edit-nickname)
|
||||
#(edit-nickname-action chat-id)
|
||||
false))
|
||||
|
||||
(defn destructive-actions [chat-id]
|
||||
[(clear-history-entry chat-id)
|
||||
(delete-chat-entry chat-id)])
|
||||
|
||||
(defn notification-actions [muted? chat-id]
|
||||
[(mute-chat-entry muted? chat-id)
|
||||
(mark-as-read-entry chat-id)])
|
||||
|
||||
(defn one-to-one-actions [muted? chat-id]
|
||||
[drawer/action-drawer [[(view-profile-entry chat-id)
|
||||
(edit-nickname-entry chat-id)]
|
||||
(notification-actions muted? chat-id)
|
||||
(destructive-actions chat-id)]])
|
||||
|
||||
(defn public-chat-actions [muted? chat-id]
|
||||
[drawer/action-drawer [(notification-actions muted? chat-id)
|
||||
(destructive-actions chat-id)]])
|
||||
|
||||
(defn private-group-chat-actions [muted? chat-id]
|
||||
[drawer/action-drawer [(notification-actions muted? chat-id)
|
||||
(destructive-actions chat-id)]])
|
||||
|
||||
(defn actions [chat-type chat-id]
|
||||
(let [muted? (<sub [:chats/muted chat-id])]
|
||||
(case chat-type
|
||||
constants/one-to-one-chat-type
|
||||
[one-to-one-actions muted? chat-id]
|
||||
constants/public-chat-type
|
||||
[public-chat-actions muted? chat-id]
|
||||
constants/private-group-chat-type
|
||||
[private-group-chat-actions muted? chat-id])))
|
|
@ -8,6 +8,7 @@
|
|||
[status-im.ui.components.list.views :as list]
|
||||
[status-im.ui.components.react :as react]
|
||||
[status-im.ui.screens.home.styles :as styles]
|
||||
[status-im.ui2.screens.chat.actions :as actions]
|
||||
[status-im.ui.screens.home.views.inner-item :refer [home-list-item]]
|
||||
[quo.design-system.colors :as quo.colors]
|
||||
[quo.core :as quo]
|
||||
|
@ -19,7 +20,6 @@
|
|||
[status-im.utils.utils :as utils]
|
||||
[status-im.ui.components.topbar :as topbar]
|
||||
[status-im.ui.components.plus-button :as components.plus-button]
|
||||
[status-im.ui.screens.chat.sheets :as sheets]
|
||||
[status-im.ui.components.tabbar.core :as tabbar]
|
||||
[status-im.ui.components.invite.views :as invite]
|
||||
[status-im.utils.handlers :refer [<sub >evt]]
|
||||
|
@ -117,7 +117,7 @@
|
|||
(re-frame/dispatch [:set :public-group-topic nil])
|
||||
(re-frame/dispatch [:search/home-filter-changed nil]))}])])))
|
||||
|
||||
(defn render-fn [{:keys [chat-id] :as home-item}]
|
||||
(defn render-fn [{:keys [chat-id chat-type] :as home-item}]
|
||||
[home-list-item
|
||||
home-item
|
||||
{:on-press (fn []
|
||||
|
@ -129,7 +129,9 @@
|
|||
(re-frame/dispatch [:accept-all-activity-center-notifications-from-chat chat-id]))
|
||||
:on-long-press #(re-frame/dispatch [:bottom-sheet/show-sheet
|
||||
{:content (fn []
|
||||
[sheets/actions home-item])}])}])
|
||||
[actions/actions
|
||||
chat-type
|
||||
chat-id])}])}])
|
||||
|
||||
(defn- render-contact [{:keys [public-key] :as row}]
|
||||
(let [[first-name second-name] (multiaccounts/contact-two-names row true)
|
||||
|
|
|
@ -1480,6 +1480,7 @@
|
|||
"page-camera-request-blocked": "camera requests blocked. To enable camera requests go to Settings",
|
||||
"nickname": "Nickname",
|
||||
"add-nickname": "Add a nickname (optional)",
|
||||
"edit-nickname": "Edit nickname",
|
||||
"nickname-description": "Nicknames help you identify others in Status.\nOnly you can see the nicknames you’ve added",
|
||||
"accept": "Accept",
|
||||
"group-invite": "Group invite",
|
||||
|
@ -1510,6 +1511,8 @@
|
|||
"name-optional": "Name (optional)",
|
||||
"mute": "Mute",
|
||||
"unmute": "Unmute",
|
||||
"mute-chat": "Mute chat",
|
||||
"unmute-chat": "Unmute chat",
|
||||
"mute-community": "Mute community",
|
||||
"unmute-community": "Unmute community",
|
||||
"scan-tokens": "Scan tokens",
|
||||
|
|
Loading…
Reference in New Issue