From 9473d3f40cc1b8f182f5a4c63d29e652c71732d4 Mon Sep 17 00:00:00 2001 From: Icaro Motta Date: Tue, 14 Mar 2023 12:34:13 -0300 Subject: [PATCH] Swipe gestures for Activity Center notifications with CTA (#15284) Implements swipe actions for notifications with call to action (e.g. pending contact requests, unverified identity verifications, etc). Fixes https://github.com/status-im/status-mobile/issues/15118 According to the Design team, the goal is to deliver a consistent experience to users, so whenever the user sees a notification with buttons, the same actions can be taken via the swipe buttons. Note: swipe buttons are using placeholder icons while the Design team works out which ones to use Additionally, a bunch of fixes: - Fix: outgoing pending contact requests were not being removed from the UI when cancelled. - Fix: Membership tab not showing unread indicator. - Fix: dismissed membership notification not marked as read. - Fix: dismissed membership notification was displaying decline/accept buttons. Regression came from changes in status-go related to soft deletion of notifications. - Fix: incorrect check for the pending state of a contact request. - Fixed lots of bugs for identity verification notifications, as it was completely broken. Unfortunately, somebody made lots of changes without actually testing the flows. - Add basic error handling and log if accepting, declining or canceling contact requests fail. The demo shows an identity verification with swipe actions to reply or decline. [identity-verification-swipe-to-reply.webm](https://user-images.githubusercontent.com/46027/223565755-b2ca3f68-12e2-4e1e-9e52-edd52cfcc971.webm) Out of scope: The old quo input is still in use in the identity verification notification. This will eventually be solved by issue https://github.com/status-im/status-mobile/issues/14364 ### Steps to test Notifications with one or more buttons (actions) are affected by this change, because now the user can also swipe left/right to act on them. - Membership notifications: private group chat. The following PR explains how to generate them https://github.com/status-im/status-mobile/pull/14785 - Contact requests, and community gated requests to join (Admin tab). - Identity verifications. I believe the only way to test identity verification flows at the moment is to use the Desktop app, since initiating the challenge is not implemented in Mobile yet. - Mentions and replies don't have new swipe buttons because they don't have call to action buttons throughout their lifecycle. Steps to test identity verification flows: #### Identity verification flow 1 - `A` and `B` are mutual contacts. - `A` sends a verification request to `B`. - `A` should not see any notification yet. - `B` should receive an identity verification notification. `B` can either decline or reply. - `B` declines and the status `Declined` is shown instead of buttons. - `B` can now either swipe to toggle read/unread or swipe delete the notification. - `A` should not receive any notification after `A` declined. #### Identity verification flow 2 - `A` and `B` are mutual contacts. - `A` sends a verification request to `B`. - `A` should not see any notification yet. - `B` should receive an identity verification notification. `B` can either decline or reply. - `B` press `Reply` and a bottom sheet is displayed with a text input. - `B` sends the reply/answer message and the status `Replied` is shown instead of buttons. - `B` can now either swipe to toggle read/unread or swipe to delete the notification. - `A` should receive a notification with the reply from `B`. - `A` can either mark the answer as untrustworthy or accept it (trust it) via the normal buttons, as well as via the swipe left/right buttons. - If `A` accepts the answer, then the status `Confirmed` is shown instead of buttons. On the other hand, if `A` marks as untrustworthy, then the status `Untrustworthy` is shown instead of buttons. - `B` should receive no further notifications due to `A`s actions. - `A` can now either swipe to toggle read/unread or swipe delete the notification. --- .../notifications/activity_log/view.cljs | 6 +- src/status_im/events.cljs | 1 + src/status_im2/common/bottom_sheet/view.cljs | 2 +- .../contexts/activity_center/events.cljs | 15 +- .../contexts/activity_center/events_test.cljs | 11 +- .../notification/admin/view.cljs | 162 +++++++----- .../notification/common/style.cljs | 38 +-- .../notification/common/view.cljs | 86 +++--- .../notification/contact_requests/events.cljs | 81 ++++-- .../notification/contact_requests/view.cljs | 138 ++++++---- .../contact_verification/view.cljs | 245 +++++++++++++----- .../notification/membership/view.cljs | 109 +++++--- .../notification/mentions/view.cljs | 64 ++--- .../notification/reply/view.cljs | 66 ++--- .../contexts/activity_center/view.cljs | 29 +-- .../tests/medium/test_activity_center.py | 6 +- test/appium/views/home_view.py | 3 +- 17 files changed, 672 insertions(+), 390 deletions(-) diff --git a/src/quo2/components/notifications/activity_log/view.cljs b/src/quo2/components/notifications/activity_log/view.cljs index a7c87566a5..c8f89095dc 100644 --- a/src/quo2/components/notifications/activity_log/view.cljs +++ b/src/quo2/components/notifications/activity_log/view.cljs @@ -37,7 +37,7 @@ (when on-update-reply (on-update-reply %))) :auto-capitalize :none - :auto-focus true + :auto-focus false :accessibility-label :identity-verification-reply-text-input :placeholder (i18n/label :t/type-something) :return-key-type :none @@ -129,7 +129,7 @@ (-> button (assoc :size size) (assoc :type subtype) - (assoc :disabled (and replying? (disable-when @reply-input))) + (assoc :disabled (and replying? disable-when (disable-when @reply-input))) (update :style merge common-style {:margin-right 8})) label])) @@ -142,7 +142,7 @@ :blur? blur?}]) (defn- footer - [_ _] + [_] (let [reply-input (reagent/atom "")] (fn [{:keys [replying? items] :as props}] [:<> diff --git a/src/status_im/events.cljs b/src/status_im/events.cljs index 722d1858f7..bbf52684d6 100644 --- a/src/status_im/events.cljs +++ b/src/status_im/events.cljs @@ -55,6 +55,7 @@ [status-im.wallet.core :as wallet] status-im.wallet.custom-tokens.core status-im2.contexts.activity-center.events + status-im2.contexts.activity-center.notification.contact-requests.events status-im2.contexts.shell.events status-im.chat.models.gaps [status-im2.navigation.events :as navigation])) diff --git a/src/status_im2/common/bottom_sheet/view.cljs b/src/status_im2/common/bottom_sheet/view.cljs index 96c1e3f272..94197cbdb0 100644 --- a/src/status_im2/common/bottom_sheet/view.cljs +++ b/src/status_im2/common/bottom_sheet/view.cljs @@ -177,7 +177,7 @@ (reset! expanded? true)) (and @keyboard-was-shown? (not keyboard-shown)) (reset! expanded? false)))) - [@show-bottom-sheet? @keyboard-was-shown?]) + [@show-bottom-sheet? @keyboard-was-shown? keyboard-shown]) (react/effect! #(do (when-not @gesture-running? (cond diff --git a/src/status_im2/contexts/activity_center/events.cljs b/src/status_im2/contexts/activity_center/events.cljs index 6beeb24d31..d5b49e59e6 100644 --- a/src/status_im2/contexts/activity_center/events.cljs +++ b/src/status_im2/contexts/activity_center/events.cljs @@ -5,7 +5,6 @@ [status-im2.common.toasts.events :as toasts] [status-im2.constants :as constants] [status-im2.contexts.activity-center.notification-types :as types] - status-im2.contexts.activity-center.notification.contact-requests.events [status-im2.contexts.chat.events :as chat.events] [taoensso.timbre :as log] [utils.collection :as collection] @@ -43,6 +42,12 @@ (log/warn (str "Failed to " action) {:notification-id notification-id :error error})) +(defn get-notification + [db notification-id] + (->> (get-in db [:activity-center :notifications]) + (filter #(= notification-id (:id %))) + first)) + ;;;; Notification reconciliation (defn- update-notifications @@ -94,12 +99,6 @@ ;;;; Status changes (read/dismissed/deleted) -(defn- get-notification - [db notification-id] - (->> (get-in db [:activity-center :notifications]) - (filter #(= notification-id (:id %))) - first)) - (rf/defn mark-as-read {:events [:activity-center.notifications/mark-as-read]} [{:keys [db]} notification-id] @@ -235,7 +234,7 @@ {:events [:activity-center.notifications/dismiss-success]} [{:keys [db] :as cofx} notification-id] (let [notification (get-notification db notification-id)] - (notifications-reconcile cofx [(assoc notification :dismissed true)]))) + (notifications-reconcile cofx [(assoc notification :read true :dismissed true)]))) (rf/defn delete-notification {:events [:activity-center.notifications/delete]} diff --git a/src/status_im2/contexts/activity_center/events_test.cljs b/src/status_im2/contexts/activity_center/events_test.cljs index ba690b376e..698893d007 100644 --- a/src/status_im2/contexts/activity_center/events_test.cljs +++ b/src/status_im2/contexts/activity_center/events_test.cljs @@ -137,15 +137,16 @@ :action :notification/accept}))) (deftest notification-dismissal-test - (testing "dismisses notification, but keep it in the app db" + (testing "dismisses & mark notification as read, and keep it in the app db" (h/run-test-sync (setup) (let [notif-1 {:id "0x1" :type types/private-group-chat} notif-2 {:id "0x2" :type types/admin} - dismissed-notif-1 (assoc notif-1 :dismissed true)] + dismissed-notif-1 (assoc notif-1 :dismissed true :read true)] (h/stub-fx-with-callbacks :json-rpc/call :on-success (constantly notif-2)) - (rf/dispatch [:test/assoc-in [:activity-center :notifications] - [notif-2 notif-1]]) + (rf/dispatch [:test/assoc-in [:activity-center] + {:filter {:type types/no-type :status :all} + :notifications [notif-2 notif-1]}]) (rf/dispatch [:activity-center.notifications/dismiss (:id notif-1)]) @@ -520,7 +521,7 @@ :type types/mention}] (get-in (h/db) [:activity-center :notifications])))))) - (testing "resets loading flag after an error" + (testing "resets loading state after error" (h/run-test-sync (setup) (let [spy-queue (atom [])] diff --git a/src/status_im2/contexts/activity_center/notification/admin/view.cljs b/src/status_im2/contexts/activity_center/notification/admin/view.cljs index b453cdf965..a0e63e4dcb 100644 --- a/src/status_im2/contexts/activity_center/notification/admin/view.cljs +++ b/src/status_im2/contexts/activity_center/notification/admin/view.cljs @@ -2,79 +2,111 @@ (:require [quo2.core :as quo] [quo2.foundations.colors :as colors] [status-im2.constants :as constants] - [status-im2.contexts.activity-center.notification.common.style :as style] + [status-im2.contexts.activity-center.notification.common.style :as common-style] [status-im2.contexts.activity-center.notification.common.view :as common] [utils.datetime :as datetime] [utils.i18n :as i18n] [utils.re-frame :as rf])) -(defn swipeable - [{:keys [height active-swipeable notification]} child] - (if (#{constants/activity-center-membership-status-accepted +(defn- swipe-button-accept + [{:keys [style]} _] + [common/swipe-button-container + {:style (common-style/swipe-success-container style) + :icon :i/placeholder + :text (i18n/label :t/accept)}]) + +(defn- swipe-button-decline + [{:keys [style]} _] + [common/swipe-button-container + {:style (common-style/swipe-danger-container style) + :icon :i/placeholder + :text (i18n/label :t/decline)}]) + +(defn- swipeable + [{:keys [active-swipeable notification extra-fn]} child] + (let [{:keys [community-id id membership-status]} notification] + (cond + (#{constants/activity-center-membership-status-accepted constants/activity-center-membership-status-declined} - (:membership-status notification)) - [common/swipeable - {:left-button common/left-swipe-button - :left-on-press common/left-swipe-on-press - :right-button common/right-swipe-button - :right-on-press common/right-swipe-on-press - :active-swipeable active-swipeable - :extra-fn (fn [] {:height @height :notification notification})} - child] - child)) + membership-status) + [common/swipeable + {:left-button common/swipe-button-read-or-unread + :left-on-press common/swipe-on-press-toggle-read + :right-button common/swipe-button-delete + :right-on-press common/swipe-on-press-delete + :active-swipeable active-swipeable + :extra-fn extra-fn} + child] + + (= membership-status constants/activity-center-membership-status-pending) + [common/swipeable + {:left-button swipe-button-accept + :left-on-press #(rf/dispatch [:communities.ui/accept-request-to-join-pressed community-id id]) + :right-button swipe-button-decline + :right-on-press #(rf/dispatch [:communities.ui/decline-request-to-join-pressed community-id + id]) + :active-swipeable active-swipeable + :extra-fn extra-fn} + child] + + :else + child))) (defn view - [{:keys [author community-id id membership-status read timestamp]} - set-swipeable-height] - (let [community (rf/sub [:communities/community community-id]) - community-name (:name community) - community-image (get-in community [:images :thumbnail :uri])] - [quo/activity-log - {:title (i18n/label :t/join-request) - :icon :i/add-user - :timestamp (datetime/timestamp->relative timestamp) - :unread? (not read) - :on-layout set-swipeable-height - :context [[common/user-avatar-tag author] - (i18n/label :t/wants-to-join) - [quo/context-tag - {:size :small - :override-theme :dark - :color colors/primary-50 - :style style/user-avatar-tag - :text-style style/user-avatar-tag-text} - {:uri community-image} community-name]] - :items (case membership-status - constants/activity-center-membership-status-accepted - [{:type :status - :subtype :positive - :key :status-accepted - :blur? true - :label (i18n/label :t/accepted)}] + [{:keys [notification set-swipeable-height] :as props}] + (let [{:keys [author community-id id membership-status + read timestamp]} notification + community (rf/sub [:communities/community community-id]) + community-name (:name community) + community-image (get-in community [:images :thumbnail :uri])] + [swipeable props + [quo/activity-log + {:title (i18n/label :t/join-request) + :icon :i/add-user + :timestamp (datetime/timestamp->relative timestamp) + :unread? (not read) + :on-layout set-swipeable-height + :context [[common/user-avatar-tag author] + (i18n/label :t/wants-to-join) + [quo/context-tag + {:size :small + :override-theme :dark + :color colors/primary-50 + :style common-style/user-avatar-tag + :text-style common-style/user-avatar-tag-text} + {:uri community-image} community-name]] + :items (case membership-status + constants/activity-center-membership-status-accepted + [{:type :status + :subtype :positive + :key :status-accepted + :blur? true + :label (i18n/label :t/accepted)}] - constants/activity-center-membership-status-declined - [{:type :status - :subtype :negative - :key :status-declined - :blur? true - :label (i18n/label :t/declined)}] + constants/activity-center-membership-status-declined + [{:type :status + :subtype :negative + :key :status-declined + :blur? true + :label (i18n/label :t/declined)}] - constants/activity-center-membership-status-pending - [{:type :button - :subtype :danger - :key :button-decline - :label (i18n/label :t/decline) - :accessibility-label :decline-join-request - :on-press (fn [] - (rf/dispatch [:communities.ui/decline-request-to-join-pressed - community-id id]))} - {:type :button - :subtype :positive - :key :button-accept - :label (i18n/label :t/accept) - :accessibility-label :accept-join-request - :on-press (fn [] - (rf/dispatch [:communities.ui/accept-request-to-join-pressed - community-id id]))}] + constants/activity-center-membership-status-pending + [{:type :button + :subtype :danger + :key :button-decline + :label (i18n/label :t/decline) + :accessibility-label :decline-join-request + :on-press (fn [] + (rf/dispatch + [:communities.ui/decline-request-to-join-pressed + community-id id]))} + {:type :button + :subtype :positive + :key :button-accept + :label (i18n/label :t/accept) + :accessibility-label :accept-join-request + :on-press (fn [] + (rf/dispatch [:communities.ui/accept-request-to-join-pressed + community-id id]))}] - nil)}])) + nil)}]])) diff --git a/src/status_im2/contexts/activity_center/notification/common/style.cljs b/src/status_im2/contexts/activity_center/notification/common/style.cljs index f790ec0f48..b618b48220 100644 --- a/src/status_im2/contexts/activity_center/notification/common/style.cljs +++ b/src/status_im2/contexts/activity_center/notification/common/style.cljs @@ -30,23 +30,29 @@ :outputRange [0 swipe-action-width] :extrapolate :clamp})) -(defn left-swipe-container - [style-props] - (merge {:background-color colors/primary-60 - :align-items :center - :justify-content :center - :border-radius swipe-button-border-radius - :width swipe-action-width} - style-props)) +(def swipe-base + {:align-items :center + :justify-content :center + :border-radius swipe-button-border-radius + :width swipe-action-width}) -(defn right-swipe-container - [style-props] - (merge {:background-color colors/danger-60 - :align-items :center - :justify-content :center - :border-radius swipe-button-border-radius - :width swipe-action-width} - style-props)) +(defn swipe-success-container + [style] + (merge swipe-base + {:background-color colors/success-60} + style)) + +(defn swipe-danger-container + [style] + (merge swipe-base + {:background-color colors/danger-60} + style)) + +(defn swipe-primary-container + [style] + (merge swipe-base + {:background-color colors/primary-60} + style)) (def swipe-text {:margin-top 5 diff --git a/src/status_im2/contexts/activity_center/notification/common/view.cljs b/src/status_im2/contexts/activity_center/notification/common/view.cljs index 0b999642b8..7924e21a75 100644 --- a/src/status_im2/contexts/activity_center/notification/common/view.cljs +++ b/src/status_im2/contexts/activity_center/notification/common/view.cljs @@ -54,39 +54,42 @@ (.close ^js @active-swipeable)) (reset! active-swipeable @swipeable))) -(defn left-swipe-button - [{:keys [style]} {:keys [notification]}] +(defn swipe-button-container + [{:keys [style icon text]} _] [rn/animated-view - {:accessibility-label :notification-left-swipe - :style (style/left-swipe-container style)} + {:accessibility-label :notification-swipe + :style style} [rn/view {:style style/swipe-text-wrapper} - [quo/icon - (if (:read notification) - :i/notifications - :i/check) + [quo/icon icon {:color colors/white}] [quo/text {:style style/swipe-text} - (if (:read notification) - (i18n/label :t/unread) - (i18n/label :t/read))]]]) + text]]]) -(defn right-swipe-button +(defn swipe-button-read-or-unread + [{:keys [style]} {:keys [notification]}] + [swipe-button-container + {:style (style/swipe-primary-container style) + :icon (if (:read notification) + :i/notifications + :i/check) + :text (if (:read notification) + (i18n/label :t/unread) + (i18n/label :t/read))}]) + +(defn swipe-button-delete [{:keys [style]}] - [rn/animated-view - {:accessibility-label :notification-right-swipe - :style (style/right-swipe-container style)} - [rn/view {:style style/swipe-text-wrapper} - [quo/icon :i/delete {:color colors/white}] - [quo/text {:style style/swipe-text} - (i18n/label :t/delete)]]]) + [swipe-button-container + {:style (style/swipe-danger-container style) + :icon :i/delete + :text (i18n/label :t/delete)}]) -(defn left-swipe-on-press +(defn swipe-on-press-toggle-read [{:keys [notification]}] (if (:read notification) (rf/dispatch [:activity-center.notifications/mark-as-unread (:id notification)]) (rf/dispatch [:activity-center.notifications/mark-as-read (:id notification)]))) -(defn right-swipe-on-press +(defn swipe-on-press-delete [{:keys [notification]}] (rf/dispatch [:activity-center.notifications/delete (:id notification)])) @@ -102,15 +105,15 @@ & children] (into [gesture/swipeable - {:ref #(reset! swipeable-ref %) - :accessibility-label :notification-swipeable - :friction 2 - :left-threshold style/swipe-action-width - :right-threshold style/swipe-action-width - :overshoot-left false - :overshoot-right false - :on-swipeable-will-open (close-active-swipeable active-swipeable swipeable-ref) - :render-left-actions (render-swipe-action + (merge + {:ref #(reset! swipeable-ref %) + :accessibility-label :notification-swipeable + :friction 2 + :on-swipeable-will-open (close-active-swipeable active-swipeable swipeable-ref)} + (when left-button + {:overshoot-left false + :left-threshold style/swipe-action-width + :render-left-actions (render-swipe-action {:active-swipeable active-swipeable :extra-fn extra-fn :interpolation-opacity style/left-swipe-opacity-interpolation-js @@ -118,14 +121,17 @@ style/left-swipe-translate-x-interpolation-js :on-press left-on-press :swipe-button left-button - :swipeable-ref swipeable-ref}) - :render-right-actions (render-swipe-action - {:active-swipeable active-swipeable - :extra-fn extra-fn - :interpolation-opacity style/right-swipe-opacity-interpolation-js - :interpolation-translate-x - style/right-swipe-translate-x-interpolation-js - :on-press right-on-press - :swipe-button right-button - :swipeable-ref swipeable-ref})}] + :swipeable-ref swipeable-ref})}) + (when right-button + {:overshoot-right false + :right-threshold style/swipe-action-width + :render-right-actions (render-swipe-action + {:active-swipeable active-swipeable + :extra-fn extra-fn + :interpolation-opacity style/right-swipe-opacity-interpolation-js + :interpolation-translate-x + style/right-swipe-translate-x-interpolation-js + :on-press right-on-press + :swipe-button right-button + :swipeable-ref swipeable-ref})}))] children)))) diff --git a/src/status_im2/contexts/activity_center/notification/contact_requests/events.cljs b/src/status_im2/contexts/activity_center/notification/contact_requests/events.cljs index 4bf9554bad..5ae28cd683 100644 --- a/src/status_im2/contexts/activity_center/notification/contact_requests/events.cljs +++ b/src/status_im2/contexts/activity_center/notification/contact_requests/events.cljs @@ -1,26 +1,69 @@ (ns status-im2.contexts.activity-center.notification.contact-requests.events - (:require [utils.re-frame :as rf])) + (:require [status-im2.contexts.activity-center.events :as ac-events] + [taoensso.timbre :as log] + [utils.re-frame :as rf])) (rf/defn accept-contact-request - {:events [:activity-center.contact-requests/accept-request]} - [{:keys [db]} id] - {:json-rpc/call [{:method "wakuext_acceptContactRequest" - :params [{:id id}] - :js-response true - :on-success #(rf/dispatch [:sanitize-messages-and-process-response %])}]}) + {:events [:activity-center.contact-requests/accept]} + [_ contact-id] + {:json-rpc/call + [{:method "wakuext_acceptContactRequest" + :params [{:id contact-id}] + :js-response true + :on-success #(rf/dispatch [:sanitize-messages-and-process-response %]) + :on-error #(rf/dispatch [:activity-center.contact-requests/accept-error contact-id %])}]}) + +(rf/defn accept-contact-request-error + {:events [:activity-center.contact-requests/accept-error]} + [_ contact-id error] + (log/error "Failed to accept contact-request" + {:error error + :event :activity-center.contact-requests/accept + :contact-id contact-id}) + nil) (rf/defn decline-contact-request - {:events [:activity-center.contact-requests/decline-request]} - [{:keys [db]} id] - {:json-rpc/call [{:method "wakuext_declineContactRequest" - :params [{:id id}] - :js-response true - :on-success #(rf/dispatch [:sanitize-messages-and-process-response %])}]}) + {:events [:activity-center.contact-requests/decline]} + [_ contact-id] + {:json-rpc/call + [{:method "wakuext_declineContactRequest" + :params [{:id contact-id}] + :js-response true + :on-success #(rf/dispatch [:sanitize-messages-and-process-response %]) + :on-error #(rf/dispatch [:activity-center.contact-requests/decline-error contact-id %])}]}) + +(rf/defn decline-contact-request-error + {:events [:activity-center.contact-requests/decline-error]} + [_ contact-id error] + (log/error "Failed to decline contact-request" + {:error error + :event :activity-center.contact-requests/decline + :contact-id contact-id}) + nil) (rf/defn cancel-outgoing-contact-request - {:events [:activity-center.contact-requests/cancel-outgoing-request]} - [{:keys [db]} id] - {:json-rpc/call [{:method "wakuext_cancelOutgoingContactRequest" - :params [{:id id}] - :js-response true - :on-success #(rf/dispatch [:sanitize-messages-and-process-response %])}]}) + {:events [:activity-center.contact-requests/cancel-outgoing]} + [{:keys [db]} {:keys [contact-id notification-id]}] + (when-let [notification (ac-events/get-notification db notification-id)] + {:json-rpc/call + [{:method "wakuext_cancelOutgoingContactRequest" + :params [{:id contact-id}] + :on-success #(rf/dispatch [:activity-center.contact-requests/cancel-outgoing-success + notification]) + :on-error #(rf/dispatch [:activity-center.contact-requests/cancel-outgoing-error contact-id + %])}]})) + +(rf/defn cancel-outgoing-contact-request-success + {:events [:activity-center.contact-requests/cancel-outgoing-success]} + [_ notification] + {:dispatch [:activity-center.notifications/reconcile + [(assoc notification :deleted true)]]}) + +(rf/defn cancel-outgoing-contact-request-error + {:events [:activity-center.contact-requests/cancel-outgoing-error]} + [_ contact-id error] + (log/error "Failed to cancel outgoing contact-request" + {:error error + :event :activity-center.contact-requests/cancel-outgoing + :contact-id contact-id}) + nil) diff --git a/src/status_im2/contexts/activity_center/notification/contact_requests/view.cljs b/src/status_im2/contexts/activity_center/notification/contact_requests/view.cljs index 9dbe83c65d..1a74fdba9a 100644 --- a/src/status_im2/contexts/activity_center/notification/contact_requests/view.cljs +++ b/src/status_im2/contexts/activity_center/notification/contact_requests/view.cljs @@ -2,31 +2,81 @@ (:require [quo2.core :as quo] [react-native.gesture :as gesture] [status-im2.constants :as constants] + [status-im2.contexts.activity-center.notification.common.style :as common-style] [status-im2.contexts.activity-center.notification.common.view :as common] [utils.datetime :as datetime] [utils.i18n :as i18n] [utils.re-frame :as rf])) -(defn swipeable - [{:keys [height active-swipeable notification]} child] - (let [message (or (:message notification) (:last-message notification))] - (if (#{constants/contact-request-message-state-accepted - constants/contact-request-message-state-declined} - (:contact-request-state message)) +(defn- swipe-button-accept + [{:keys [style]} _] + [common/swipe-button-container + {:style (common-style/swipe-success-container style) + :icon :i/placeholder + :text (i18n/label :t/accept)}]) + +(defn- swipe-button-decline + [{:keys [style]} _] + [common/swipe-button-container + {:style (common-style/swipe-danger-container style) + :icon :i/placeholder + :text (i18n/label :t/decline)}]) + +(defn- swipe-button-cancel-pending + [{:keys [style]} _] + [common/swipe-button-container + {:style (common-style/swipe-danger-container style) + :icon :i/placeholder + :text (i18n/label :t/cancel)}]) + +(defn- swipeable + [{:keys [active-swipeable extra-fn notification]} child] + (let [{:keys [id author message last-message]} notification + {:keys [contact-request-state]} (or (:message notification) + (:last-message notification)) + {:keys [public-key]} (rf/sub [:multiaccount/contact]) + message (or message last-message)] + (cond + (#{constants/contact-request-message-state-accepted + constants/contact-request-message-state-declined} + contact-request-state) [common/swipeable - {:left-button common/left-swipe-button - :left-on-press common/left-swipe-on-press - :right-button common/right-swipe-button - :right-on-press common/right-swipe-on-press + {:left-button common/swipe-button-read-or-unread + :left-on-press common/swipe-on-press-toggle-read + :right-button common/swipe-button-delete + :right-on-press common/swipe-on-press-delete :active-swipeable active-swipeable - :extra-fn (fn [] {:height @height :notification notification})} + :extra-fn extra-fn} child] + + (= contact-request-state constants/contact-request-message-state-pending) + (if (= public-key author) + [common/swipeable + {:right-button swipe-button-cancel-pending + :right-on-press (fn [] + (rf/dispatch + [:activity-center.contact-requests/cancel-outgoing + {:contact-id (:from message) + :notification-id id}])) + :active-swipeable active-swipeable + :extra-fn extra-fn} + child] + [common/swipeable + {:left-button swipe-button-accept + :left-on-press #(rf/dispatch [:activity-center.contact-requests/accept id]) + :right-button swipe-button-decline + :right-on-press #(rf/dispatch [:activity-center.contact-requests/decline id]) + :active-swipeable active-swipeable + :extra-fn extra-fn} + child]) + + :else child))) -(defn outgoing-contact-request-view - [{:keys [id chat-id message last-message] :as notification} - set-swipeable-height] - (let [{:keys [contact-request-state] :as message} (or message last-message)] +(defn- outgoing-contact-request-view + [{:keys [notification set-swipeable-height]}] + (let [{:keys [id chat-id message last-message]} notification + {:keys [contact-request-state] :as message} (or message last-message)] (if (= contact-request-state constants/contact-request-message-state-accepted) [quo/activity-log {:title (i18n/label :t/contact-request-was-accepted) @@ -48,7 +98,7 @@ [common/user-avatar-tag chat-id]] :message {:body (get-in message [:content :text])} :items (case contact-request-state - constants/contact-request-state-mutual + constants/contact-request-message-state-pending [{:type :button :subtype :danger :key :button-cancel @@ -56,10 +106,9 @@ :accessibility-label :cancel-contact-request :on-press (fn [] (rf/dispatch - [:activity-center.contact-requests/cancel-outgoing-request - (:from message)]) - (rf/dispatch [:activity-center.notifications/mark-as-read - id]))} + [:activity-center.contact-requests/cancel-outgoing + {:contact-id (:from message) + :notification-id id}]))} {:type :status :subtype :pending :key :status-pending @@ -75,10 +124,10 @@ nil)}]))) -(defn incoming-contact-request-view - [{:keys [id author message last-message] :as notification} - set-swipeable-height] - (let [message (or message last-message)] +(defn- incoming-contact-request-view + [{:keys [notification set-swipeable-height]}] + (let [{:keys [id author message last-message]} notification + message (or message last-message)] [quo/activity-log {:title (i18n/label :t/contact-request) :on-layout set-swipeable-height @@ -110,36 +159,31 @@ :key :button-decline :label (i18n/label :t/decline) :accessibility-label :decline-contact-request - :on-press (fn [] - (rf/dispatch [:activity-center.contact-requests/decline-request id]) - (rf/dispatch [:activity-center.notifications/mark-as-read - id]))} + :on-press #(rf/dispatch [:activity-center.contact-requests/decline id])} {:type :button :subtype :positive :key :button-accept :label (i18n/label :t/accept) :accessibility-label :accept-contact-request - :on-press (fn [] - (rf/dispatch [:activity-center.contact-requests/accept-request id]) - (rf/dispatch [:activity-center.notifications/mark-as-read - id]))}] + :on-press #(rf/dispatch [:activity-center.contact-requests/accept id])}] nil)}])) (defn view - [{:keys [author message last-message] :as notification} - set-swipeable-height] - (let [{:keys [public-key]} (rf/sub [:multiaccount/contact]) - {:keys [contact-request-state]} (or message last-message)] - (cond - (= public-key author) - [outgoing-contact-request-view notification set-swipeable-height] + [{:keys [notification] :as props}] + (let [{:keys [author message last-message]} notification + {:keys [public-key]} (rf/sub [:multiaccount/contact]) + {:keys [contact-request-state]} (or message last-message)] + [swipeable props + (cond + (= public-key author) + [outgoing-contact-request-view props] - (= contact-request-state constants/contact-request-message-state-accepted) - [gesture/touchable-without-feedback - {:on-press (fn [] - (rf/dispatch [:hide-popover]) - (rf/dispatch [:chat.ui/start-chat author]))} - [incoming-contact-request-view notification set-swipeable-height]] + (= contact-request-state constants/contact-request-message-state-accepted) + [gesture/touchable-without-feedback + {:on-press (fn [] + (rf/dispatch [:hide-popover]) + (rf/dispatch [:chat.ui/start-chat author]))} + [incoming-contact-request-view props]] - :else - [incoming-contact-request-view notification set-swipeable-height]))) + :else + [incoming-contact-request-view props])])) diff --git a/src/status_im2/contexts/activity_center/notification/contact_verification/view.cljs b/src/status_im2/contexts/activity_center/notification/contact_verification/view.cljs index 825c1f36c6..e15def6cae 100644 --- a/src/status_im2/contexts/activity_center/notification/contact_verification/view.cljs +++ b/src/status_im2/contexts/activity_center/notification/contact_verification/view.cljs @@ -1,16 +1,40 @@ (ns status-im2.contexts.activity-center.notification.contact-verification.view (:require [clojure.string :as string] - [utils.i18n :as i18n] [quo2.core :as quo] [status-im2.constants :as constants] - [utils.datetime :as datetime] + [status-im2.contexts.activity-center.notification.common.style :as common-style] [status-im2.contexts.activity-center.notification.common.view :as common] + [utils.datetime :as datetime] + [utils.i18n :as i18n] [utils.re-frame :as rf])) -(defn- hide-bottom-sheet-and-dispatch - [event] - (rf/dispatch [:bottom-sheet/hide]) - (rf/dispatch event)) +(defn- swipe-button-decline + [{:keys [style]} _] + [common/swipe-button-container + {:style (common-style/swipe-danger-container style) + :icon :i/placeholder + :text (i18n/label :t/decline)}]) + +(defn- swipe-button-reply + [{:keys [style]} _] + [common/swipe-button-container + {:style (common-style/swipe-primary-container style) + :icon :i/placeholder + :text (i18n/label :t/message-reply)}]) + +(defn- swipe-button-untrustworthy + [{:keys [style]} _] + [common/swipe-button-container + {:style (common-style/swipe-danger-container style) + :icon :i/placeholder + :text (i18n/label :t/untrustworthy)}]) + +(defn- swipe-button-trust + [{:keys [style]} _] + [common/swipe-button-container + {:style (common-style/swipe-success-container style) + :icon :i/placeholder + :text (i18n/label :t/accept)}]) (defn- context-tags [challenger? {:keys [author contact-verification-status]}] @@ -38,18 +62,6 @@ (= contact-verification-status constants/contact-verification-status-declined)) {:body (get-in message [:content :text])}))) -(defn- activity-status - [challenger? contact-verification-status] - (if challenger? - (cond (= contact-verification-status constants/contact-verification-status-trusted) - {:type :positive :label (i18n/label :t/status-confirmed)} - (= contact-verification-status constants/contact-verification-status-untrustworthy) - {:type :negative :label (i18n/label :t/untrustworthy)}) - (cond (= contact-verification-status constants/contact-verification-status-accepted) - {:type :positive :label (i18n/label :t/replied)} - (= contact-verification-status constants/contact-verification-status-declined) - {:type :negative :label (i18n/label :t/declined)}))) - (def ^:private max-reply-length 280) @@ -57,84 +69,181 @@ [reply] (<= (count reply) max-reply-length)) +(def ^:private invalid-reply? + (comp not valid-reply?)) + +(declare view) + +(defn- decline-challenge + [id] + (rf/dispatch [:bottom-sheet/hide]) + (rf/dispatch [:activity-center.contact-verification/decline id]) + (rf/dispatch [:activity-center.notifications/mark-as-read id])) + +(defn- prepare-challenge-reply + [props] + (rf/dispatch [:bottom-sheet/show-sheet + {:content view + :override-theme :dark} + (assoc props :replying? true)])) + +(defn- send-challenge-reply + [id reply] + (rf/dispatch [:bottom-sheet/hide]) + (rf/dispatch [:activity-center.contact-verification/reply id reply]) + (rf/dispatch [:activity-center.notifications/mark-as-read id])) + +(defn- mark-challenge-untrustworthy + [id] + (rf/dispatch [:activity-center.contact-verification/mark-as-untrustworthy id]) + (rf/dispatch [:activity-center.notifications/mark-as-read id])) + +(defn- mark-challenge-trusted + [id] + (rf/dispatch [:activity-center.contact-verification/mark-as-trusted id]) + (rf/dispatch [:activity-center.notifications/mark-as-read id])) + +(defn- swipeable + [{:keys [active-swipeable extra-fn notification replying?] :as props} child] + (let [{:keys [id message + contact-verification-status]} notification + challenger? (:outgoing message)] + (cond + replying? + child + + (and (not challenger?) + (= contact-verification-status constants/contact-verification-status-pending)) + [common/swipeable + {:left-button swipe-button-reply + :left-on-press #(prepare-challenge-reply props) + :right-button swipe-button-decline + :right-on-press #(decline-challenge id) + :active-swipeable active-swipeable + :extra-fn extra-fn} + child] + + (and challenger? + (= contact-verification-status constants/contact-verification-status-accepted)) + [common/swipeable + {:left-button swipe-button-trust + :left-on-press #(mark-challenge-trusted id) + :right-button swipe-button-untrustworthy + :right-on-press #(mark-challenge-untrustworthy id) + :active-swipeable active-swipeable + :extra-fn extra-fn} + child] + + (#{constants/contact-verification-status-accepted + constants/contact-verification-status-declined + constants/contact-verification-status-trusted} + contact-verification-status) + [common/swipeable + {:left-button common/swipe-button-read-or-unread + :left-on-press common/swipe-on-press-toggle-read + :right-button common/swipe-button-delete + :right-on-press common/swipe-on-press-delete + :active-swipeable active-swipeable + :extra-fn extra-fn} + child] + + :else + child))) + (defn view - [_ _] + [_] (let [reply (atom "")] - (fn [{:keys [id message contact-verification-status] :as notification} {:keys [replying?]}] - (let [challenger? (:outgoing message)] + (fn [{:keys [notification set-swipeable-height replying?] :as props}] + (let [{:keys [id message + contact-verification-status]} notification + challenger? (:outgoing message)] ;; TODO(@ilmotta): Declined challenges should only be displayed for the ;; challengee, not the challenger. ;; https://github.com/status-im/status-mobile/issues/14354 - (when-not (and challenger? - (= contact-verification-status constants/contact-verification-status-declined)) - [quo/activity-log - (merge - {:title (i18n/label :t/identity-verification-request) - :icon :i/friend - :timestamp (datetime/timestamp->relative (:timestamp notification)) - :unread? (not (:read notification)) - :on-update-reply #(reset! reply %) - :replying? replying? - :max-reply-length max-reply-length - :valid-reply? valid-reply? - :context (context-tags challenger? notification) - :message (activity-message challenger? notification) - :status (activity-status challenger? contact-verification-status) - :items - (if challenger? - (when (= contact-verification-status constants/contact-verification-status-accepted) + (when-not + (and challenger? + (= contact-verification-status constants/contact-verification-status-declined)) + [swipeable props + [quo/activity-log + (merge + (when-not replying? + {:on-layout set-swipeable-height}) + {:title (i18n/label :t/identity-verification-request) + :icon :i/friend + :timestamp (datetime/timestamp->relative (:timestamp notification)) + :unread? (not (:read notification)) + :on-update-reply #(reset! reply %) + :replying? replying? + :max-reply-length max-reply-length + :valid-reply? valid-reply? + :context (context-tags challenger? notification) + :message (activity-message challenger? notification) + :items + (cond-> [] + (and challenger? + (= contact-verification-status constants/contact-verification-status-accepted)) + (concat [{:type :button :subtype :danger :key :button-mark-as-untrustworthy :label (i18n/label :t/untrustworthy) :accessibility-label :mark-contact-verification-as-untrustworthy - :on-press (fn [] - (rf/dispatch - [:activity-center.contact-verification/mark-as-untrustworthy - id]) - (rf/dispatch [:activity-center.notifications/mark-as-read - id]))} + :on-press #(mark-challenge-untrustworthy id)} {:type :button :subtype :positive :key :button-accept :label (i18n/label :t/accept) :accessibility-label :mark-contact-verification-as-trusted - :on-press (fn [] - (rf/dispatch - [:activity-center.contact-verification/mark-as-trusted id]) - (rf/dispatch [:activity-center.notifications/mark-as-read - id]))}]) - (when (= contact-verification-status constants/contact-verification-status-pending) + :on-press #(mark-challenge-trusted id)}]) + + (and challenger? + (= contact-verification-status constants/contact-verification-status-trusted)) + (concat [{:type :status + :subtype :positive + :key :status-trusted + :label (i18n/label :t/status-confirmed)}]) + + (and challenger? + (= contact-verification-status constants/contact-verification-status-untrustworthy)) + (concat [{:type :status + :subtype :negative + :key :status-untrustworthy + :label (i18n/label :t/untrustworthy)}]) + + (and (not challenger?) + (= contact-verification-status constants/contact-verification-status-accepted)) + (concat [{:type :status + :subtype :positive + :key :status-accepted + :label (i18n/label :t/replied)}]) + + (and (not challenger?) + (= contact-verification-status constants/contact-verification-status-declined)) + (concat [{:type :status + :subtype :negative + :key :status-declined + :label (i18n/label :t/declined)}]) + + (and (not challenger?) + (= contact-verification-status constants/contact-verification-status-pending)) + (concat [{:type :button :subtype :danger :key :button-decline :label (i18n/label :t/decline) :accessibility-label :decline-contact-verification - :on-press (fn [] - (hide-bottom-sheet-and-dispatch - [:activity-center.contact-verification/decline id]) - (rf/dispatch - [:activity-center.notifications/mark-as-read id]))} + :on-press #(decline-challenge id)} (if replying? {:type :button :subtype :primary :key :button-reply :label (i18n/label :t/send-reply) :accessibility-label :reply-to-contact-verification - :disable-when #(not (valid-reply? %)) - :on-press (fn [] - (hide-bottom-sheet-and-dispatch - [:activity-center.contact-verification/reply id - @reply]) - (rf/dispatch - [:activity-center.notifications/mark-as-read id]))} + :disable-when invalid-reply? + :on-press #(send-challenge-reply id @reply)} {:type :button :subtype :primary :key :button-send-reply :label (i18n/label :t/message-reply) :accessibility-label :send-reply-to-contact-verification - :on-press (fn [] - (rf/dispatch [:bottom-sheet/show-sheet - {:content view} - {:notification notification - :replying? true}]))})]))})]))))) + :on-press #(prepare-challenge-reply props)})]))})]]))))) diff --git a/src/status_im2/contexts/activity_center/notification/membership/view.cljs b/src/status_im2/contexts/activity_center/notification/membership/view.cljs index 4100b4411b..13698aacf4 100644 --- a/src/status_im2/contexts/activity_center/notification/membership/view.cljs +++ b/src/status_im2/contexts/activity_center/notification/membership/view.cljs @@ -1,45 +1,84 @@ (ns status-im2.contexts.activity-center.notification.membership.view (:require [quo2.core :as quo] - [react-native.core :as rn] + [react-native.gesture :as gesture] + [status-im2.contexts.activity-center.notification.common.style :as common-style] [status-im2.contexts.activity-center.notification.common.view :as common] [utils.datetime :as datetime] [utils.i18n :as i18n] [utils.re-frame :as rf])) -(defn pressable - [{:keys [accepted chat-id]} & children] +(defn- pressable + [{:keys [accepted chat-id]} child] (if accepted - (into [rn/touchable-opacity - {:on-press (fn [] - (rf/dispatch [:hide-popover]) - (rf/dispatch [:chat/navigate-to-chat chat-id]))}] - children) - (into [:<>] children))) + [gesture/touchable-without-feedback + {:on-press (fn [] + (rf/dispatch [:hide-popover]) + (rf/dispatch [:chat/navigate-to-chat chat-id]))} + child] + child)) + +(defn- swipe-button-accept + [{:keys [style]} _] + [common/swipe-button-container + {:style (common-style/swipe-success-container style) + :icon :i/placeholder + :text (i18n/label :t/accept)}]) + +(defn- swipe-button-decline + [{:keys [style]} _] + [common/swipe-button-container + {:style (common-style/swipe-danger-container style) + :icon :i/placeholder + :text (i18n/label :t/decline)}]) + +(defn- swipeable + [{:keys [active-swipeable notification extra-fn]} child] + (let [{:keys [accepted dismissed id]} notification] + (if (or accepted dismissed) + [common/swipeable + {:left-button common/swipe-button-read-or-unread + :left-on-press common/swipe-on-press-toggle-read + :right-button common/swipe-button-delete + :right-on-press common/swipe-on-press-delete + :active-swipeable active-swipeable + :extra-fn extra-fn} + child] + [common/swipeable + {:left-button swipe-button-accept + :left-on-press #(rf/dispatch [:activity-center.notifications/accept id]) + :right-button swipe-button-decline + :right-on-press #(rf/dispatch [:activity-center.notifications/dismiss id]) + :active-swipeable active-swipeable + :extra-fn extra-fn} + child]))) (defn view - [{:keys [id accepted author read timestamp chat-name chat-id]}] - [pressable {:accepted accepted :chat-id chat-id} - [quo/activity-log - {:title (i18n/label :t/added-to-group-chat) - :icon :i/add-user - :timestamp (datetime/timestamp->relative timestamp) - :unread? (not read) - :context [[common/user-avatar-tag author] - (i18n/label :t/added-you-to) - [quo/group-avatar-tag chat-name - {:size :small - :color :purple}]] - :items (when-not accepted - [{:type :button - :subtype :positive - :key :button-accept - :label (i18n/label :t/accept) - :accessibility-label :accept-group-chat-invitation - :on-press #(rf/dispatch [:activity-center.notifications/accept id])} - {:type :button - :subtype :danger - :key :button-decline - :label (i18n/label :t/decline) - :accessibility-label :decline-group-chat-invitation - :on-press #(rf/dispatch [:activity-center.notifications/dismiss - id])}])}]]) + [{:keys [notification set-swipeable-height] :as props}] + (let [{:keys [id accepted dismissed author read timestamp chat-name chat-id]} notification] + [swipeable props + [pressable {:accepted accepted :chat-id chat-id} + [quo/activity-log + {:title (i18n/label :t/added-to-group-chat) + :on-layout set-swipeable-height + :icon :i/add-user + :timestamp (datetime/timestamp->relative timestamp) + :unread? (not read) + :context [[common/user-avatar-tag author] + (i18n/label :t/added-you-to) + [quo/group-avatar-tag chat-name + {:size :small + :color :purple}]] + :items (when-not (or accepted dismissed) + [{:type :button + :subtype :positive + :key :button-accept + :label (i18n/label :t/accept) + :accessibility-label :accept-group-chat-invitation + :on-press #(rf/dispatch [:activity-center.notifications/accept id])} + {:type :button + :subtype :danger + :key :button-decline + :label (i18n/label :t/decline) + :accessibility-label :decline-group-chat-invitation + :on-press #(rf/dispatch [:activity-center.notifications/dismiss + id])}])}]]])) diff --git a/src/status_im2/contexts/activity_center/notification/mentions/view.cljs b/src/status_im2/contexts/activity_center/notification/mentions/view.cljs index 0fd1bf323a..be80bae5f9 100644 --- a/src/status_im2/contexts/activity_center/notification/mentions/view.cljs +++ b/src/status_im2/contexts/activity_center/notification/mentions/view.cljs @@ -9,14 +9,14 @@ [utils.i18n :as i18n] [utils.re-frame :as rf])) -(def tag-params +(def ^:private tag-params {:size :small :override-theme :dark :color colors/primary-50 :style style/tag :text-style style/tag-text}) -(defn message-body +(defn- message-body [message] (let [parsed-text (get-in message [:content :parsed-text]) parsed-text-children (:children (first parsed-text))] @@ -35,37 +35,39 @@ literal)) parsed-text-children)))) -(defn swipeable - [{:keys [height active-swipeable notification]} child] +(defn- swipeable + [{:keys [active-swipeable extra-fn]} child] [common/swipeable - {:left-button common/left-swipe-button - :left-on-press common/left-swipe-on-press - :right-button common/right-swipe-button - :right-on-press common/right-swipe-on-press + {:left-button common/swipe-button-read-or-unread + :left-on-press common/swipe-on-press-toggle-read + :right-button common/swipe-button-delete + :right-on-press common/swipe-on-press-delete :active-swipeable active-swipeable - :extra-fn (fn [] {:height @height :notification notification})} + :extra-fn extra-fn} child]) (defn view - [{:keys [author chat-name community-id chat-id message read timestamp]} - set-swipeable-height] - (let [community-chat? (not (string/blank? community-id)) - community (rf/sub [:communities/community community-id]) - community-name (:name community) - community-image (get-in community [:images :thumbnail :uri])] - [gesture/touchable-without-feedback - {:on-press (fn [] - (rf/dispatch [:hide-popover]) - (rf/dispatch [:chat/navigate-to-chat chat-id]))} - [quo/activity-log - {:title (i18n/label :t/mention) - :on-layout set-swipeable-height - :icon :i/mention - :timestamp (datetime/timestamp->relative timestamp) - :unread? (not read) - :context [[common/user-avatar-tag author] - [quo/text {:style style/tag-text} (string/lower-case (i18n/label :t/on))] - (if community-chat? - [quo/context-tag tag-params {:uri community-image} community-name chat-name] - [quo/group-avatar-tag chat-name tag-params])] - :message {:body (message-body message)}}]])) + [{:keys [notification set-swipeable-height] :as props}] + (let [{:keys [author chat-name community-id chat-id + message read timestamp]} notification + community-chat? (not (string/blank? community-id)) + community (rf/sub [:communities/community community-id]) + community-name (:name community) + community-image (get-in community [:images :thumbnail :uri])] + [swipeable props + [gesture/touchable-without-feedback + {:on-press (fn [] + (rf/dispatch [:hide-popover]) + (rf/dispatch [:chat/navigate-to-chat chat-id]))} + [quo/activity-log + {:title (i18n/label :t/mention) + :on-layout set-swipeable-height + :icon :i/mention + :timestamp (datetime/timestamp->relative timestamp) + :unread? (not read) + :context [[common/user-avatar-tag author] + [quo/text {:style style/tag-text} (string/lower-case (i18n/label :t/on))] + (if community-chat? + [quo/context-tag tag-params {:uri community-image} community-name chat-name] + [quo/group-avatar-tag chat-name tag-params])] + :message {:body (message-body message)}}]]])) diff --git a/src/status_im2/contexts/activity_center/notification/reply/view.cljs b/src/status_im2/contexts/activity_center/notification/reply/view.cljs index 3d216ab214..f87f86d59e 100644 --- a/src/status_im2/contexts/activity_center/notification/reply/view.cljs +++ b/src/status_im2/contexts/activity_center/notification/reply/view.cljs @@ -12,7 +12,7 @@ [utils.i18n :as i18n] [utils.re-frame :as rf])) -(def tag-params +(def ^:private tag-params {:size :small :override-theme :dark :color colors/primary-50 @@ -20,7 +20,7 @@ :text-style style/tag-text}) ;; NOTE: Replies support text, image and stickers only. -(defn get-message-content +(defn- get-message-content [{:keys [content-type] :as message}] (case content-type constants/content-type-text (get-in message [:content :text]) @@ -37,38 +37,40 @@ nil)) -(defn swipeable - [{:keys [height active-swipeable notification]} child] +(defn- swipeable + [{:keys [active-swipeable extra-fn]} child] [common/swipeable - {:left-button common/left-swipe-button - :left-on-press common/left-swipe-on-press - :right-button common/right-swipe-button - :right-on-press common/right-swipe-on-press + {:left-button common/swipe-button-read-or-unread + :left-on-press common/swipe-on-press-toggle-read + :right-button common/swipe-button-delete + :right-on-press common/swipe-on-press-delete :active-swipeable active-swipeable - :extra-fn (fn [] {:height @height :notification notification})} + :extra-fn extra-fn} child]) (defn view - [{:keys [author chat-name community-id chat-id message read timestamp]} - set-swipeable-height] - (let [community-chat? (not (string/blank? community-id)) - community (rf/sub [:communities/community community-id]) - community-name (:name community) - community-image (get-in community [:images :thumbnail :uri])] - [gesture/touchable-without-feedback - {:on-press (fn [] - (rf/dispatch [:hide-popover]) - (rf/dispatch [:chat/navigate-to-chat chat-id]))} - [quo/activity-log - {:title (i18n/label :t/message-reply) - :on-layout set-swipeable-height - :icon :i/reply - :timestamp (datetime/timestamp->relative timestamp) - :unread? (not read) - :context [[common/user-avatar-tag author] - [quo/text {:style style/lowercase-text} (i18n/label :t/on)] - (if community-chat? - [quo/context-tag tag-params {:uri community-image} community-name chat-name] - [quo/group-avatar-tag chat-name tag-params])] - :message {:body-number-of-lines 1 - :body (get-message-content message)}}]])) + [{:keys [notification set-swipeable-height] :as props}] + (let [{:keys [author chat-name community-id chat-id + message read timestamp]} notification + community-chat? (not (string/blank? community-id)) + community (rf/sub [:communities/community community-id]) + community-name (:name community) + community-image (get-in community [:images :thumbnail :uri])] + [swipeable props + [gesture/touchable-without-feedback + {:on-press (fn [] + (rf/dispatch [:hide-popover]) + (rf/dispatch [:chat/navigate-to-chat chat-id]))} + [quo/activity-log + {:title (i18n/label :t/message-reply) + :on-layout set-swipeable-height + :icon :i/reply + :timestamp (datetime/timestamp->relative timestamp) + :unread? (not read) + :context [[common/user-avatar-tag author] + [quo/text {:style style/lowercase-text} (i18n/label :t/on)] + (if community-chat? + [quo/context-tag tag-params {:uri community-image} community-name chat-name] + [quo/group-avatar-tag chat-name tag-params])] + :message {:body-number-of-lines 1 + :body (get-message-content message)}}]]])) diff --git a/src/status_im2/contexts/activity_center/view.cljs b/src/status_im2/contexts/activity_center/view.cljs index 0229221571..321497d6b8 100644 --- a/src/status_im2/contexts/activity_center/view.cljs +++ b/src/status_im2/contexts/activity_center/view.cljs @@ -1,5 +1,6 @@ (ns status-im2.contexts.activity-center.view - (:require [oops.core :as oops] + (:require [clojure.set :as set] + [oops.core :as oops] [quo2.core :as quo] [quo2.foundations.colors :as colors] [react-native.core :as rn] @@ -127,7 +128,7 @@ :label (i18n/label :t/membership) :accessibility-label :tab-membership :notification-dot? (when-not is-mark-all-as-read-undoable? - (contains? types-with-unread types/membership))} + (set/subset? types/membership types-with-unread))} {:id types/system :label (i18n/label :t/system) :accessibility-label :tab-system @@ -172,32 +173,30 @@ (let [height (atom 0) set-swipeable-height #(reset! height (oops/oget % "nativeEvent.layout.height"))] (fn [{:keys [type] :as notification} index _ active-swipeable] - (let [swipeable-args {:height height - :active-swipeable active-swipeable - :notification notification}] + (let [props {:height height + :active-swipeable active-swipeable + :set-swipeable-height set-swipeable-height + :notification notification + :extra-fn (fn [] {:height @height :notification notification})}] [rn/view {:style (style/notification-container index)} (cond (= type types/contact-verification) - [contact-verification/view notification {}] + [contact-verification/view props] (= type types/contact-request) - [contact-requests/swipeable swipeable-args - [contact-requests/view notification set-swipeable-height]] + [contact-requests/view props] (= type types/mention) - [mentions/swipeable swipeable-args - [mentions/view notification set-swipeable-height]] + [mentions/view props] (= type types/reply) - [reply/swipeable swipeable-args - [reply/view notification set-swipeable-height]] + [reply/view props] (= type types/admin) - [admin/swipeable swipeable-args - [admin/view notification set-swipeable-height]] + [admin/view props] (some types/membership [type]) - [membership/view notification] + [membership/view props] :else nil)])))) diff --git a/test/appium/tests/medium/test_activity_center.py b/test/appium/tests/medium/test_activity_center.py index b984dcce52..dd0b784a10 100644 --- a/test/appium/tests/medium/test_activity_center.py +++ b/test/appium/tests/medium/test_activity_center.py @@ -286,7 +286,7 @@ class TestActivityMultipleDevicePR(MultipleSharedDeviceTestCase): self.home_1.just_fyi("Mark it as read and check filter") reply_element.swipe_right_on_element() - self.home_1.activity_left_swipe_button.click() + self.home_1.activity_notification_swipe_button.click() if reply_element.is_element_displayed(2): self.errors.append("Message is not marked as read!") self.home_1.activity_unread_filter_button.click() @@ -295,7 +295,7 @@ class TestActivityMultipleDevicePR(MultipleSharedDeviceTestCase): self.home_1.just_fyi("Mark it as unread and check filter via right swipe") reply_element.swipe_right_on_element() - self.home_1.activity_left_swipe_button.click() + self.home_1.activity_notification_swipe_button.click() if not reply_element.unread_indicator.is_element_displayed(): self.errors.append("No unread dot is shown on activity center element after marking it as unread!") @@ -310,7 +310,7 @@ class TestActivityMultipleDevicePR(MultipleSharedDeviceTestCase): self.home_1.just_fyi("Delete it from unread via left swipe") self.home_1.open_activity_center_button.click() reply_element.swipe_left_on_element() - self.home_1.activity_right_swipe_button.click() + self.home_1.activity_notification_swipe_button.click() if reply_element.is_element_displayed(): self.errors.append("Reply is still shown after removing from activity centre!") diff --git a/test/appium/views/home_view.py b/test/appium/views/home_view.py index e3622109e5..d3688108da 100644 --- a/test/appium/views/home_view.py +++ b/test/appium/views/home_view.py @@ -254,8 +254,7 @@ class HomeView(BaseView): # Activity centre self.mention_activity_tab_button = ActivityTabButton(self.driver, accessibility_id="tab-mention") self.reply_activity_tab_button = ActivityTabButton(self.driver, accessibility_id="tab-reply") - self.activity_right_swipe_button = Button(self.driver, accessibility_id="notification-right-swipe") - self.activity_left_swipe_button = Button(self.driver, accessibility_id="notification-left-swipe") + self.activity_notification_swipe_button = Button(self.driver, accessibility_id="notification-swipe") self.activity_unread_filter_button = Button(self.driver, accessibility_id="selector-filter")