Introduce marking all notifications as read in Activity Center (#14952)
* [Feature][#14902][#14917] Added marking all notifications as read * [Fix] Lint Fix
This commit is contained in:
parent
3fbb7cb0a7
commit
8ed64f810f
|
@ -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
|
||||
|
|
|
@ -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}])
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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})
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue