diff --git a/src/quo2/components/drawers/action_drawers/view.cljs b/src/quo2/components/drawers/action_drawers/view.cljs index ee1274bd8c..80036515d5 100644 --- a/src/quo2/components/drawers/action_drawers/view.cljs +++ b/src/quo2/components/drawers/action_drawers/view.cljs @@ -6,10 +6,10 @@ [quo2.components.drawers.action-drawers.style :as style])) (defn- get-icon-color - [danger?] + [danger? override-theme] (if danger? colors/danger-50 - (colors/theme-colors colors/neutral-50 colors/neutral-40))) + (colors/theme-colors colors/neutral-50 colors/neutral-40 override-theme))) (def divider [rn/view @@ -25,6 +25,7 @@ danger? on-press add-divider? + override-theme accessibility-label] :as action-props}] (when action-props @@ -33,7 +34,7 @@ [rn/touchable-highlight {:accessibility-label accessibility-label :style (style/container sub-label) - :underlay-color (colors/theme-colors colors/neutral-5 colors/neutral-90) + :underlay-color (colors/theme-colors colors/neutral-5 colors/neutral-90 override-theme) :on-press on-press} [rn/view {:style (style/row-container sub-label)} @@ -42,7 +43,7 @@ :accessible true :style style/left-icon} [icon/icon icon - {:color (get-icon-color danger?) + {:color (get-icon-color danger? override-theme) :size 20}]] [rn/view {:style style/text-container} @@ -50,14 +51,15 @@ {:size :paragraph-1 :weight :medium :style {:color - (when danger? - (colors/theme-colors colors/danger-50 colors/danger-60))}} + (cond + danger? (colors/theme-colors colors/danger-50 colors/danger-60 override-theme) + :else (colors/theme-colors colors/neutral-100 colors/white override-theme))}} label] (when sub-label [text/text {:size :paragraph-2 :style {:color - (colors/theme-colors colors/neutral-50 colors/neutral-40)}} + (colors/theme-colors colors/neutral-50 colors/neutral-40 override-theme)}} sub-label])] (when right-icon [rn/view @@ -65,7 +67,7 @@ :accessible true :accessibility-label :right-icon-for-action} [icon/icon right-icon - {:color (get-icon-color danger?) + {:color (get-icon-color danger? override-theme) :size 20}]])]]])) (defn action-drawer diff --git a/src/quo2/components/notifications/toast.cljs b/src/quo2/components/notifications/toast.cljs index 8ac476a306..9c94f96084 100644 --- a/src/quo2/components/notifications/toast.cljs +++ b/src/quo2/components/notifications/toast.cljs @@ -18,8 +18,8 @@ :light {:background-color :colors/white-opa-5}}}) (defn- merge-theme-style - [component-key styles] - (merge (get-in themes [component-key (theme/get-theme)]) styles)) + [component-key styles override-theme] + (merge (get-in themes [component-key (or override-theme (theme/get-theme))]) styles)) (defn toast-action-container [{:keys [on-press style]} & children] @@ -41,17 +41,17 @@ children]]) (defn toast-undo-action - [duration on-press] + [duration on-press override-theme] [toast-action-container {:on-press on-press :accessibility-label :toast-undo-action} [rn/view {:style {:margin-right 5}} [count-down-circle/circle-timer {:duration duration}]] [text/text - {:size :paragraph-2 :weight :medium :style (merge-theme-style :text {})} + {:size :paragraph-2 :weight :medium :style (merge-theme-style :text {} override-theme)} [i18n/label :t/undo]]]) (defn- toast-container - [{:keys [left middle right container-style]}] + [{:keys [left middle right container-style override-theme]}] [rn/view {:style (merge {:padding-left 12 :padding-right 12} container-style)} [rn/view {:style (merge-theme-style :container @@ -62,27 +62,31 @@ :padding-vertical 8 :padding-left 10 :padding-right 8 - :border-radius 12})} + :border-radius 12} + override-theme)} [rn/view {:style {:padding 2}} left] [rn/view {:style {:padding 4 :flex 1}} [text/text {:size :paragraph-2 :weight :medium - :style (merge-theme-style :text {}) + :style (merge-theme-style :text {} override-theme) :accessibility-label :toast-content} middle]] (when right right)]]) (defn toast - [{:keys [icon icon-color text action undo-duration undo-on-press container-style]}] + [{:keys [icon icon-color text action undo-duration undo-on-press container-style override-theme]}] [toast-container {:left (when icon [icon/icon icon {:container-style {:width 20 :height 20} :color (or icon-color - (get-in themes [:icon (theme/get-theme) :color]))}]) + (get-in themes + [:icon (or override-theme (theme/get-theme)) + :color]))}]) :middle text :right (if undo-duration - [toast-undo-action undo-duration undo-on-press] + [toast-undo-action undo-duration undo-on-press override-theme] action) - :container-style container-style}]) + :container-style container-style + :override-theme override-theme}]) diff --git a/src/status_im/data_store/activities.cljs b/src/status_im/data_store/activities.cljs index f347ae97d6..90cacd61cd 100644 --- a/src/status_im/data_store/activities.cljs +++ b/src/status_im/data_store/activities.cljs @@ -4,6 +4,10 @@ [status-im.data-store.messages :as messages] [status-im2.contexts.activity-center.notification-types :as notification-types])) +(defn mark-notifications-as-read + [notifications] + (map #(assoc % :read true) notifications)) + (defn- rpc->type [{:keys [type name] :as chat}] (case type diff --git a/src/status_im2/common/bottom_sheet/styles.cljs b/src/status_im2/common/bottom_sheet/styles.cljs index 177b655eda..ccda491270 100644 --- a/src/status_im2/common/bottom_sheet/styles.cljs +++ b/src/status_im2/common/bottom_sheet/styles.cljs @@ -4,12 +4,12 @@ (def border-radius 20) (defn handle - [] + [override-theme] {:position :absolute :top 8 :width 32 :height 4 - :background-color (colors/theme-colors colors/neutral-100 colors/white) + :background-color (colors/theme-colors colors/neutral-100 colors/white override-theme) :opacity 0.1 :border-radius 100 :align-self :center}) @@ -40,17 +40,17 @@ :padding-bottom (if bottom-safe-area-spacing? (:bottom insets) 0)}) (defn selected-background - [] + [override-theme] {:border-radius 12 :padding-left 12 :margin-horizontal 8 :margin-bottom 10 :height 48 - :background-color (colors/theme-colors colors/white colors/neutral-90)}) + :background-color (colors/theme-colors colors/white colors/neutral-90 override-theme)}) (defn background - [] - {:background-color (colors/theme-colors colors/white colors/neutral-95) + [override-theme] + {:background-color (colors/theme-colors colors/white colors/neutral-95 override-theme) :flex 1 :border-top-left-radius border-radius :border-top-right-radius border-radius}) diff --git a/src/status_im2/common/bottom_sheet/view.cljs b/src/status_im2/common/bottom_sheet/view.cljs index 7213d2229e..bbffd898ba 100644 --- a/src/status_im2/common/bottom_sheet/view.cljs +++ b/src/status_im2/common/bottom_sheet/view.cljs @@ -70,14 +70,14 @@ (reset! expanded? false)))))))) (defn handle-comp - [window-width] + [window-width override-theme] [rn/view {:style {:width window-width :position :absolute :background-color :transparent :top 0 :height 20}} - [rn/view {:style (styles/handle)}]]) + [rn/view {:style (styles/handle override-theme)}]]) (defn bottom-sheet [props children] @@ -90,6 +90,7 @@ bottom-safe-area-spacing? :bottom-safe-area-spacing? selected-item :selected-item is-initially-expanded? :expanded? + override-theme :override-theme :or {show-handle? true backdrop-dismiss? true expandable? false @@ -125,7 +126,7 @@ window-height (if selected-item (- height 72) height) {:keys [keyboard-shown]} (hooks/use-keyboard) bg-height-expanded (- window-height (:top insets)) - bg-height (max (min @content-height bg-height-expanded) 200) + bg-height (max (min @content-height bg-height-expanded) 109) bottom-sheet-dy (reanimated/use-shared-value 0) pan-y (reanimated/use-shared-value 0) translate-y (.useTranslateY ^js bottom-sheet-js window-height bottom-sheet-dy pan-y) @@ -154,7 +155,7 @@ close-bottom-sheet gesture-running?) handle-comp [gesture/gesture-detector {:gesture bottom-sheet-gesture} - [handle-comp window-width]]] + [handle-comp window-width override-theme]]] (react/effect! #(do (cond @@ -221,9 +222,9 @@ :height window-height})} [rn/view {:style styles/container} (when selected-item - [rn/view {:style (styles/selected-background)} + [rn/view {:style (styles/selected-background override-theme)} [selected-item]]) - [rn/view {:style (styles/background)} + [rn/view {:style (styles/background override-theme)} [rn/keyboard-avoiding-view {:behaviour (if platform/ios? :padding :height) :style {:flex 1}} diff --git a/src/status_im2/constants.cljs b/src/status_im2/constants.cljs index a56861b34d..e7c10fb79c 100644 --- a/src/status_im2/constants.cljs +++ b/src/status_im2/constants.cljs @@ -36,6 +36,8 @@ (def ^:const activity-center-membership-status-accepted 2) (def ^:const activity-center-membership-status-declined 3) +(def ^:const activity-center-mark-all-as-read-undo-time-limit-ms 4000) + (def ^:const emoji-reaction-love 1) (def ^:const emoji-reaction-thumbs-up 2) (def ^:const emoji-reaction-thumbs-down 3) diff --git a/src/status_im2/contexts/activity_center/events.cljs b/src/status_im2/contexts/activity_center/events.cljs index 2631ec3abb..134626eb60 100644 --- a/src/status_im2/contexts/activity_center/events.cljs +++ b/src/status_im2/contexts/activity_center/events.cljs @@ -4,7 +4,8 @@ [status-im2.contexts.activity-center.notification-types :as types] [status-im2.contexts.chat.events :as chat.events] [taoensso.timbre :as log] - [utils.re-frame :as rf])) + [utils.re-frame :as rf] + [status-im2.constants :as constants])) (def defaults {:filter-status :unread @@ -153,6 +154,66 @@ [cofx notification] (notifications-reconcile cofx [(assoc notification :read true)])) +(rf/defn mark-all-as-read + {:events [:activity-center.notifications/mark-all-as-read]} + [{:keys [db now]}] + (when-let [undoable-till (get-in db [:activity-center :mark-all-as-read-undoable-till])] + (when (>= now undoable-till) + {:json-rpc/call [{:method "wakuext_markAllActivityCenterNotificationsRead" + :params [] + :on-success #(rf/dispatch + [:activity-center.notifications/mark-all-as-read-success]) + :on-error #(rf/dispatch [:activity-center/process-notification-failure + nil + :notification/mark-all-as-read + %])}]}))) + +(rf/defn mark-all-as-read-success + {:events [:activity-center.notifications/mark-all-as-read-success]} + [{:keys [db]}] + {:db (-> (reduce (fn [acc notification-type] + (assoc-in acc [:activity-center :unread-counts-by-type notification-type] 0)) + db + types/all-supported) + (update :activity-center dissoc :mark-all-as-read-undoable-till))}) + +(rf/defn undo-mark-all-as-read + {:events [:activity-center.notifications/undo-mark-all-as-read-locally]} + [{:keys [db]} {:keys [notifications]}] + {:db (-> db + (update-in [:activity-center :notifications] + update-notifications + notifications) + (update :activity-center dissoc :mark-all-as-read-undoable-till))}) + +(rf/defn mark-all-as-read-locally + {:events [:activity-center.notifications/mark-all-as-read-locally]} + [{:keys [db now]} get-toast-ui-props] + (let [unread-notifications (get-in db [:activity-center :notifications types/no-type :unread :data]) + undo-time-limit-ms constants/activity-center-mark-all-as-read-undo-time-limit-ms + undoable-till (+ now undo-time-limit-ms)] + {:db (-> db + (update-in [:activity-center :notifications] + update-notifications + (data-store.activities/mark-notifications-as-read + unread-notifications)) + (assoc-in [:activity-center :mark-all-as-read-undoable-till] + undoable-till)) + :dispatch [:toasts/upsert + (merge + {:id :activity-center-mark-all-as-read + :duration undo-time-limit-ms + :undo-duration (/ undo-time-limit-ms 1000) + :undo-on-press + (fn [] + (rf/dispatch + [:activity-center.notifications/undo-mark-all-as-read-locally + {:notifications unread-notifications}]) + (rf/dispatch [:toasts/close :activity-center-mark-all-as-read]))} + (get-toast-ui-props))] + :utils/dispatch-later [{:dispatch [:activity-center.notifications/mark-all-as-read] + :ms undo-time-limit-ms}]})) + ;;;; Acceptance/dismissal (rf/defn accept-notification diff --git a/src/status_im2/contexts/activity_center/style.cljs b/src/status_im2/contexts/activity_center/style.cljs index 294958f00d..2c1ec7e088 100644 --- a/src/status_im2/contexts/activity_center/style.cljs +++ b/src/status_im2/contexts/activity_center/style.cljs @@ -3,9 +3,11 @@ (def screen-padding 20) -(def header-button - {:margin-bottom 12 - :margin-left screen-padding}) +(def header-container + {:flex-direction :row + :justify-content :space-between + :padding-horizontal screen-padding + :margin-bottom 12}) (def header-heading {:padding-horizontal screen-padding diff --git a/src/status_im2/contexts/activity_center/view.cljs b/src/status_im2/contexts/activity_center/view.cljs index 1cb63a0208..5380bbec09 100644 --- a/src/status_im2/contexts/activity_center/view.cljs +++ b/src/status_im2/contexts/activity_center/view.cljs @@ -1,7 +1,7 @@ (ns status-im2.contexts.activity-center.view - (:require [utils.i18n :as i18n] - [quo.react :as react] + (:require [quo.react :as react] [quo2.core :as quo] + [quo2.foundations.colors :as colors] [react-native.core :as rn] [react-native.safe-area :as safe-area] [status-im2.contexts.activity-center.notification-types :as types] @@ -13,6 +13,7 @@ [status-im2.contexts.activity-center.notification.mentions.view :as mentions] [status-im2.contexts.activity-center.notification.reply.view :as reply] [status-im2.contexts.activity-center.style :as style] + [utils.i18n :as i18n] [utils.re-frame :as rf])) (defn filter-selector-read-toggle @@ -27,6 +28,28 @@ :all :unread)}])}])) +(defn options-bottom-sheet-content + [] + (let [unread-count (rf/sub [:activity-center/unread-count])] + [quo/action-drawer + [[{:icon :i/check + :override-theme :dark + :label (i18n/label :t/mark-all-notifications-as-read) + :on-press (fn [] + (if (pos? unread-count) + (rf/dispatch [:activity-center.notifications/mark-all-as-read-locally + (fn [] + {:icon :up-to-date + :icon-color colors/success-50 + :text (i18n/label :t/notifications-marked-as-read + {:count unread-count}) + :override-theme :dark})]) + ;; Need design improvements if there is NO unread + ;; notifications to mark as read + ;; https://github.com/status-im/status-mobile/issues/14983 + (js/alert "No unread notifications to mark as read")) + (rf/dispatch [:bottom-sheet/hide]))}]]])) + (defn empty-tab [] (let [filter-status (rf/sub [:activity-center/filter-status])] @@ -50,8 +73,10 @@ (defn tabs [] - (let [filter-type (rf/sub [:activity-center/filter-type]) - types-with-unread (rf/sub [:activity-center/notification-types-with-unread])] + (let [filter-type (rf/sub [:activity-center/filter-type]) + types-with-unread (rf/sub [:activity-center/notification-types-with-unread]) + is-mark-all-as-read-undoable? (boolean (rf/sub + [:activity-center/mark-all-as-read-undoable-till]))] [quo/tabs {:size 32 :scrollable? true @@ -69,49 +94,67 @@ {:id types/admin :label (i18n/label :t/admin) :accessibility-label :tab-admin - :notification-dot? (contains? types-with-unread types/admin)} + :notification-dot? (when-not is-mark-all-as-read-undoable? + (contains? types-with-unread types/admin))} {:id types/mention :label (i18n/label :t/mentions) :accessibility-label :tab-mention - :notification-dot? (contains? types-with-unread types/mention)} + :notification-dot? (when-not is-mark-all-as-read-undoable? + (contains? types-with-unread types/mention))} {:id types/reply :label (i18n/label :t/replies) :accessibility-label :tab-reply - :notification-dot? (contains? types-with-unread types/reply)} + :notification-dot? (when-not is-mark-all-as-read-undoable? + (contains? types-with-unread types/reply))} {:id types/contact-request :label (i18n/label :t/contact-requests) :accessibility-label :tab-contact-request - :notification-dot? (contains? types-with-unread types/contact-request)} + :notification-dot? (when-not is-mark-all-as-read-undoable? + (contains? types-with-unread types/contact-request))} {:id types/contact-verification :label (i18n/label :t/identity-verification) :accessibility-label :tab-contact-verification - :notification-dot? (contains? types-with-unread - types/contact-verification)} + :notification-dot? (when-not is-mark-all-as-read-undoable? + (contains? types-with-unread + types/contact-verification))} {:id types/tx :label (i18n/label :t/transactions) :accessibility-label :tab-tx - :notification-dot? (contains? types-with-unread types/tx)} + :notification-dot? (when-not is-mark-all-as-read-undoable? + (contains? types-with-unread types/tx))} {:id types/membership :label (i18n/label :t/membership) :accessibility-label :tab-membership - :notification-dot? (contains? types-with-unread types/membership)} + :notification-dot? (when-not is-mark-all-as-read-undoable? + (contains? types-with-unread types/membership))} {:id types/system :label (i18n/label :t/system) :accessibility-label :tab-system - :notification-dot? (contains? types-with-unread types/system)}]}])) + :notification-dot? (when-not is-mark-all-as-read-undoable? + (contains? types-with-unread types/system))}]}])) (defn header [] [rn/view - [quo/button - {:icon true - :type :blur-bg - :size 32 - :accessibility-label :close-activity-center - :override-theme :dark - :style style/header-button - :on-press #(rf/dispatch [:hide-popover])} - :i/close] + [rn/view {:style style/header-container} + [quo/button + {:icon true + :type :blur-bg + :size 32 + :accessibility-label :close-activity-center + :override-theme :dark + :on-press #(rf/dispatch [:hide-popover])} + :i/close] + [quo/button + {:icon true + :type :blur-bg + :size 32 + :accessibility-label :activity-center-open-more + :override-theme :dark + :on-press #(rf/dispatch [:bottom-sheet/show-sheet + {:content options-bottom-sheet-content + :override-theme :dark}])} + :i/options]] [quo/text {:size :heading-1 :weight :semi-bold diff --git a/src/status_im2/subs/activity_center.cljs b/src/status_im2/subs/activity_center.cljs index 73ed041f3a..67ac46b4df 100644 --- a/src/status_im2/subs/activity_center.cljs +++ b/src/status_im2/subs/activity_center.cljs @@ -34,6 +34,12 @@ vals (reduce + 0)))) +(re-frame/reg-sub + :activity-center/mark-all-as-read-undoable-till + :<- [:activity-center] + (fn [activity-center] + (:mark-all-as-read-undoable-till activity-center))) + (re-frame/reg-sub :activity-center/filter-status :<- [:activity-center] diff --git a/translations/en.json b/translations/en.json index 7f3243afb0..5d7642000b 100644 --- a/translations/en.json +++ b/translations/en.json @@ -1960,5 +1960,7 @@ "my-albums": "My albums", "images": "images", "only-6-images": "You can only add 6 images to your message", - "delivered": "Delivered" + "delivered": "Delivered", + "mark-all-notifications-as-read": "Mark all notifications as read", + "notifications-marked-as-read": "{{count}} notifications marked as read" }