[14556, 14259] Allow users to mute community channels and to mute chats for specific duration (#15128)
This commit is contained in:
parent
db44ee67e6
commit
7aa40b8adf
|
@ -38,13 +38,13 @@
|
|||
uses `ring-background` to display the ring behind the initials when given. Otherwise,
|
||||
shows the `profile-picture` which already comes with the ring drawn."
|
||||
[{:keys [full-name status-indicator? online? size profile-picture ring-background
|
||||
customization-color static?]
|
||||
customization-color static? muted?]
|
||||
:or {status-indicator? true
|
||||
online? true
|
||||
size :big
|
||||
customization-color :turquoise}}]
|
||||
(let [full-name (or full-name "empty name")
|
||||
draw-ring? (and ring-background (valid-ring-sizes size))
|
||||
draw-ring? (when-not muted? (and ring-background (valid-ring-sizes size)))
|
||||
outer-styles (style/outer size)
|
||||
;; Once image is loaded, fast image rerenders view with the help of reagent atom,
|
||||
;; But dynamic updates don't work when user-avatar is used inside hole-view
|
||||
|
|
|
@ -35,7 +35,8 @@
|
|||
on-press
|
||||
add-divider?
|
||||
override-theme
|
||||
accessibility-label]
|
||||
accessibility-label
|
||||
icon-color]
|
||||
:as action-props}]
|
||||
(when action-props
|
||||
[:<> {:key label}
|
||||
|
@ -53,7 +54,7 @@
|
|||
:accessible true
|
||||
:style style/left-icon}
|
||||
[icon/icon icon
|
||||
{:color (get-icon-color danger? override-theme)
|
||||
{:color (or icon-color (get-icon-color danger? override-theme))
|
||||
:size 20}]]
|
||||
[rn/view
|
||||
{:style style/text-container}
|
||||
|
|
|
@ -56,8 +56,8 @@
|
|||
(when (and (not locked?)
|
||||
muted?)
|
||||
[quo2.icons/icon :i/muted
|
||||
{:size 20
|
||||
:no-color true}])
|
||||
{:size 20
|
||||
:color colors/neutral-40}])
|
||||
(when (and (not locked?)
|
||||
(not muted?)
|
||||
(pos? (int mentions-count)))
|
||||
|
|
|
@ -65,7 +65,8 @@
|
|||
:lastMessage :last-message
|
||||
:lastClockValue :last-clock-value
|
||||
:invitationAdmin :invitation-admin
|
||||
:profile :profile-public-key})
|
||||
:profile :profile-public-key
|
||||
:muteTill :muted-till})
|
||||
rpc->type
|
||||
unmarshal-members
|
||||
(update :last-message #(when % (messages/<-rpc %)))
|
||||
|
@ -81,7 +82,7 @@
|
|||
:alias (.-alias chat)
|
||||
:muted (.-muted chat)
|
||||
:joined (.-joined chat)
|
||||
:muted-till (.-mutetill chat)
|
||||
:muted-till (.-muteTill chat)
|
||||
:chat-id (.-id chat)
|
||||
:community-id (.-communityId chat)
|
||||
:synced-from (.-syncedFrom chat)
|
||||
|
|
|
@ -7,7 +7,9 @@
|
|||
[status-im2.constants :as constants]
|
||||
[status-im2.contexts.contacts.drawers.nickname-drawer.view :as nickname-drawer]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
[utils.re-frame :as rf]
|
||||
[status-im2.common.mute-chat-drawer.view :as mute-chat-drawer]
|
||||
[utils.datetime :as datetime]))
|
||||
|
||||
(defn- entry
|
||||
[{:keys [icon label on-press danger? sub-label chevron? add-divider? accessibility-label]}]
|
||||
|
@ -51,8 +53,11 @@
|
|||
:accessibility-label :edit-nickname}])}]))
|
||||
|
||||
(defn mute-chat-action
|
||||
[chat-id]
|
||||
(hide-sheet-and-dispatch [:chat.ui/mute chat-id true constants/mute-till-unmuted]))
|
||||
[chat-id chat-type]
|
||||
(hide-sheet-and-dispatch [:show-bottom-sheet
|
||||
{:content (fn []
|
||||
[mute-chat-drawer/mute-chat-drawer chat-id
|
||||
:mute-chat-for-duration chat-type])}]))
|
||||
|
||||
(defn unmute-chat-action
|
||||
[chat-id]
|
||||
|
@ -118,19 +123,22 @@
|
|||
public-key])}])}]))
|
||||
|
||||
(defn mute-chat-entry
|
||||
[chat-id]
|
||||
[chat-id chat-type muted-till]
|
||||
(let [muted? (rf/sub [:chats/muted chat-id])]
|
||||
(entry {:icon (if muted? :i/muted :i/activity-center)
|
||||
:label (i18n/label
|
||||
(if muted?
|
||||
:unmute-chat
|
||||
:mute-chat))
|
||||
:sub-label (when (and muted? (some? muted-till))
|
||||
(str (i18n/label :t/muted-until)
|
||||
" "
|
||||
(datetime/format-mute-till muted-till)))
|
||||
:on-press (if muted?
|
||||
#(unmute-chat-action chat-id)
|
||||
#(mute-chat-action chat-id))
|
||||
#(mute-chat-action chat-id chat-type))
|
||||
:danger? false
|
||||
:accessibility-label :mute-chat
|
||||
:sub-label nil
|
||||
:chevron? true})))
|
||||
|
||||
(defn mark-as-read-entry
|
||||
|
@ -237,7 +245,7 @@
|
|||
:label (i18n/label :t/notifications)
|
||||
:on-press #(js/alert "TODO: to be implemented, requires design input")
|
||||
:danger? false
|
||||
:sub-label "All messages" ; TODO: placeholder
|
||||
:sub-label (i18n/label :t/all-messages)
|
||||
:accessibility-label :manage-notifications
|
||||
:chevron? true
|
||||
:add-divider? add-divider?}))
|
||||
|
@ -296,7 +304,7 @@
|
|||
:sub-label nil
|
||||
:chevron? false}))
|
||||
|
||||
;; TODO(OmarBasem): to be implemented.
|
||||
;; TODO(OmarBasem): to be implemented.chat/check-channel-muted?
|
||||
(defn share-group-entry
|
||||
[]
|
||||
(entry {:icon :i/share
|
||||
|
@ -404,9 +412,9 @@
|
|||
(delete-chat-entry item inside-chat?))])
|
||||
|
||||
(defn notification-actions
|
||||
[{:keys [chat-id group-chat public?]} inside-chat? needs-divider?]
|
||||
[{:keys [chat-id group-chat public? chat-type muted-till]} inside-chat? needs-divider?]
|
||||
[(mark-as-read-entry chat-id needs-divider?)
|
||||
(mute-chat-entry chat-id)
|
||||
(mute-chat-entry chat-id chat-type muted-till)
|
||||
(notifications-entry false)
|
||||
(when inside-chat?
|
||||
(fetch-messages-entry))
|
||||
|
|
|
@ -4,20 +4,25 @@
|
|||
[react-native.core :as rn]
|
||||
[status-im2.constants :as constants]
|
||||
[utils.re-frame :as rf]
|
||||
[status-im2.common.mute-chat-drawer.style :as style]))
|
||||
[status-im2.common.mute-chat-drawer.style :as style]
|
||||
[utils.chats :as chat-utils]))
|
||||
|
||||
(defn hide-sheet-and-dispatch
|
||||
[event]
|
||||
(rf/dispatch [:bottom-sheet/hide])
|
||||
(rf/dispatch [:hide-bottom-sheet])
|
||||
(rf/dispatch event))
|
||||
|
||||
(defn mute-chat-drawer
|
||||
[chat-id accessibility-label]
|
||||
[chat-id accessibility-label chat-type]
|
||||
[rn/view {:accessibility-label accessibility-label}
|
||||
[quo/text
|
||||
{:weight :medium
|
||||
:size :paragraph-2
|
||||
:style (style/header-text)} (i18n/label :t/mute-channel)]
|
||||
:style (style/header-text)}
|
||||
(i18n/label
|
||||
(if (chat-utils/not-community-chat? chat-type)
|
||||
:t/mute-chat-capitialized
|
||||
:t/mute-channel))]
|
||||
[quo/menu-item
|
||||
{:type :transparent
|
||||
:title (i18n/label :t/mute-for-15-mins)
|
||||
|
|
|
@ -334,3 +334,29 @@
|
|||
(def ^:const auth-method-none "none")
|
||||
|
||||
(def ^:const image-description-in-lightbox? false)
|
||||
(def ^:const int->weekday
|
||||
"Maps the corresponding string representation of a weekday
|
||||
By it's numeric index as in cljs-time"
|
||||
{1 "mon"
|
||||
2 "tue"
|
||||
3 "wed"
|
||||
4 "thu"
|
||||
5 "fri"
|
||||
6 "sat"
|
||||
7 "sun"})
|
||||
|
||||
(def ^:const months
|
||||
"Maps the corresponding string representation of a weekday
|
||||
By it's numeric index as in cljs-time"
|
||||
{1 "jan"
|
||||
2 "feb"
|
||||
3 "mar"
|
||||
4 "apr"
|
||||
5 "may"
|
||||
6 "jun"
|
||||
7 "jul"
|
||||
8 "aug"
|
||||
9 "sep"
|
||||
10 "oct"
|
||||
11 "nov"
|
||||
12 "dec"})
|
||||
|
|
|
@ -16,7 +16,10 @@
|
|||
[status-im.multiaccounts.model :as multiaccounts.model]
|
||||
[status-im.utils.clocks :as utils.clocks]
|
||||
[status-im.utils.types :as types]
|
||||
[reagent.core :as reagent]))
|
||||
[reagent.core :as reagent]
|
||||
[quo2.foundations.colors :as colors]
|
||||
[utils.datetime :as datetime]
|
||||
[utils.chats :as chat-utils]))
|
||||
|
||||
(defn- get-chat
|
||||
[cofx chat-id]
|
||||
|
@ -253,8 +256,6 @@
|
|||
(update-in [:chats chat-id :unviewed-mentions-count]
|
||||
#(max (- % countWithMentions) 0)))})
|
||||
|
||||
;;;; UI
|
||||
|
||||
(rf/defn start-chat
|
||||
"Start a chat, making sure it exists"
|
||||
{:events [:chat.ui/start-chat]}
|
||||
|
@ -297,20 +298,64 @@
|
|||
|
||||
(rf/defn mute-chat-toggled-successfully
|
||||
{:events [:chat/mute-successfully]}
|
||||
[{:keys [db]} chat-id muted-till]
|
||||
[{:keys [db]} chat-id muted-till mute-type muted? chat-type]
|
||||
(log/debug "muted chat successfully" chat-id " for" muted-till)
|
||||
{:db (assoc-in db [:chats chat-id :muted-till] muted-till)})
|
||||
(let [time-string (fn [duration-kw unmute-time]
|
||||
(i18n/label duration-kw {:duration unmute-time}))
|
||||
not-community-chat? (chat-utils/not-community-chat? chat-type)
|
||||
mute-duration-text
|
||||
(fn [unmute-time]
|
||||
(if unmute-time
|
||||
(str
|
||||
(condp = mute-type
|
||||
constants/mute-for-15-mins-type (time-string
|
||||
(if (chat-utils/not-community-chat? chat-type)
|
||||
:t/chat-muted-for-15-minutes
|
||||
:t/channel-muted-for-15-minutes)
|
||||
unmute-time)
|
||||
constants/mute-for-1-hour-type (time-string
|
||||
(if (chat-utils/not-community-chat? chat-type)
|
||||
:t/chat-muted-for-1-hour
|
||||
:t/channel-muted-for-1-hour)
|
||||
unmute-time)
|
||||
constants/mute-for-8-hours-type (time-string
|
||||
(if (chat-utils/not-community-chat? chat-type)
|
||||
:t/chat-muted-for-8-hours
|
||||
:t/channel-muted-for-8-hours)
|
||||
unmute-time)
|
||||
constants/mute-for-1-week (time-string
|
||||
(if (chat-utils/not-community-chat? chat-type)
|
||||
:t/chat-muted-for-1-week
|
||||
:t/channel-muted-for-1-week)
|
||||
unmute-time)
|
||||
constants/mute-till-unmuted (time-string
|
||||
(if (chat-utils/not-community-chat? chat-type)
|
||||
:t/chat-muted-till-unmuted
|
||||
:t/channel-muted-till-unmuted)
|
||||
unmute-time)))
|
||||
(i18n/label (if (chat-utils/not-community-chat? chat-type)
|
||||
:t/chat-unmuted-successfully
|
||||
:t/channel-unmuted-successfully))))]
|
||||
{:db (assoc-in db [:chats chat-id :muted-till] muted-till)
|
||||
:dispatch [:toasts/upsert
|
||||
{:icon :correct
|
||||
:icon-color (colors/theme-colors colors/success-60
|
||||
colors/success-50)
|
||||
:text (mute-duration-text (when (some? muted-till)
|
||||
(str (datetime/format-mute-till muted-till))))}]}))
|
||||
|
||||
(rf/defn mute-chat
|
||||
{:events [:chat.ui/mute]}
|
||||
[{:keys [db]} chat-id muted? mute-type]
|
||||
(let [method (if muted? "wakuext_muteChatV2" "wakuext_unmuteChat")
|
||||
params (if muted? [{:chatId chat-id :mutedType mute-type}] [chat-id])]
|
||||
(let [method (if muted? "wakuext_muteChatV2" "wakuext_unmuteChat")
|
||||
params (if muted? [{:chatId chat-id :mutedType mute-type}] [chat-id])
|
||||
chat-type (get-in db [:chats chat-id :chat-type])]
|
||||
{:db (assoc-in db [:chats chat-id :muted] muted?)
|
||||
:json-rpc/call [{:method method
|
||||
:params params
|
||||
:on-error #(rf/dispatch [:chat/mute-failed chat-id muted? %])
|
||||
:on-success #(rf/dispatch [:chat/mute-successfully chat-id %])}]}))
|
||||
:on-success #(rf/dispatch [:chat/mute-successfully chat-id % mute-type
|
||||
(not muted?) chat-type])}]}))
|
||||
|
||||
(rf/defn show-clear-history-confirmation
|
||||
{:events [:chat.ui/show-clear-history-confirmation]}
|
||||
|
|
|
@ -21,8 +21,15 @@
|
|||
:top 16
|
||||
:background-color (colors/theme-colors colors/neutral-40 colors/neutral-60)})
|
||||
|
||||
(def muted-icon
|
||||
{:position :absolute
|
||||
:right 19
|
||||
:top 16})
|
||||
|
||||
(defn timestamp
|
||||
[]
|
||||
{:color (colors/theme-colors colors/neutral-50 colors/neutral-40)
|
||||
[muted?]
|
||||
{:color (or (when muted?
|
||||
colors/neutral-50)
|
||||
(colors/theme-colors colors/neutral-50 colors/neutral-40))
|
||||
:margin-top 3
|
||||
:margin-left 8})
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
[utils.re-frame :as rf]
|
||||
[status-im2.constants :as constants]
|
||||
[clojure.string :as string]
|
||||
[utils.i18n :as i18n]))
|
||||
[utils.i18n :as i18n]
|
||||
[quo2.components.icon :as quo2.icons]))
|
||||
|
||||
(def max-subheader-length 50)
|
||||
|
||||
|
@ -177,25 +178,21 @@
|
|||
:color (colors/theme-colors colors/primary-50 colors/primary-60)}]])))
|
||||
|
||||
(defn name-view
|
||||
[display-name contact timestamp]
|
||||
[rn/view
|
||||
{:style {:flex 1
|
||||
:flex-direction :row}}
|
||||
[display-name contact timestamp muted?]
|
||||
[rn/view {:style {:flex-direction :row}}
|
||||
[quo/text
|
||||
{:weight :semi-bold
|
||||
:accessibility-label :chat-name-text
|
||||
:style {:flex-shrink 1}
|
||||
:number-of-lines 1
|
||||
:ellipsize-mode :tail}
|
||||
:style {:color (when muted? colors/neutral-50)}}
|
||||
display-name]
|
||||
[verified-or-contact-icon contact]
|
||||
[quo/text
|
||||
{:size :label
|
||||
:style (style/timestamp)}
|
||||
:style (style/timestamp muted?)}
|
||||
(datetime/to-short-str timestamp)]])
|
||||
|
||||
(defn avatar-view
|
||||
[{:keys [contact chat-id full-name color]}]
|
||||
[{:keys [contact chat-id full-name color muted?]}]
|
||||
(if contact ; `contact` is passed when it's not a group chat
|
||||
(let [online? (rf/sub [:visibility-status-updates/online? chat-id])
|
||||
photo-path (rf/sub [:chats/photo-path chat-id])
|
||||
|
@ -204,7 +201,8 @@
|
|||
{:full-name full-name
|
||||
:size :small
|
||||
:online? online?
|
||||
image-key photo-path}])
|
||||
image-key photo-path
|
||||
:muted? muted?}])
|
||||
[quo/group-avatar
|
||||
{:color color
|
||||
:size :medium}]))
|
||||
|
@ -228,15 +226,18 @@
|
|||
{:contact contact
|
||||
:chat-id chat-id
|
||||
:full-name display-name
|
||||
:color color}]
|
||||
[rn/view
|
||||
{:style {:flex 1
|
||||
:margin-left 8
|
||||
:margin-right (if show-unread-badge? 36 0)}}
|
||||
[name-view display-name contact timestamp]
|
||||
[last-message-preview group-chat last-message]]
|
||||
(when show-unread-badge?
|
||||
[quo/info-count
|
||||
{:style {:top 16
|
||||
:right 16}}
|
||||
unviewed-messages-count])]))
|
||||
:color color
|
||||
:muted? muted}]
|
||||
[rn/view {:style {:margin-left 8}}
|
||||
[name-view display-name contact timestamp muted]
|
||||
[last-message-preview group-chat last-message muted]]
|
||||
(if-not muted
|
||||
(when show-unread-badge?
|
||||
[quo/info-count
|
||||
{:style {:top 16
|
||||
:right 16}}
|
||||
unviewed-messages-count])
|
||||
[quo2.icons/icon :i/muted
|
||||
{:size 20
|
||||
:color colors/neutral-40
|
||||
:container-style style/muted-icon}])]))
|
||||
|
|
|
@ -1,7 +1,26 @@
|
|||
(ns status-im2.contexts.communities.actions.chat.view
|
||||
(:require [quo2.core :as quo]
|
||||
[status-im2.common.not-implemented :as not-implemented]
|
||||
[utils.i18n :as i18n]))
|
||||
[utils.datetime :as datetime]
|
||||
[utils.i18n :as i18n]
|
||||
[status-im2.common.mute-chat-drawer.view :as mute-chat-drawer]
|
||||
[utils.re-frame :as rf]))
|
||||
|
||||
(defn hide-sheet-and-dispatch
|
||||
[event]
|
||||
(rf/dispatch [:hide-bottom-sheet])
|
||||
(rf/dispatch event))
|
||||
|
||||
(defn- mute-channel-action
|
||||
[chat-id chat-type]
|
||||
(hide-sheet-and-dispatch [:show-bottom-sheet
|
||||
{:content (fn []
|
||||
[mute-chat-drawer/mute-chat-drawer chat-id
|
||||
:mute-chat-for-duration chat-type])}]))
|
||||
|
||||
(defn- unmute-channel-action
|
||||
[chat-id]
|
||||
(hide-sheet-and-dispatch [:chat.ui/mute chat-id false 0]))
|
||||
|
||||
(defn- action-view-members-and-details
|
||||
[]
|
||||
|
@ -26,12 +45,19 @@
|
|||
:label (i18n/label :t/mark-as-read)})
|
||||
|
||||
(defn- action-toggle-muted
|
||||
[]
|
||||
{:icon :i/muted
|
||||
:right-icon :i/chevron-right
|
||||
:accessibility-label :chat-toggle-muted
|
||||
:on-press not-implemented/alert
|
||||
:label (i18n/label :t/mute-channel)})
|
||||
[id muted? muted-till chat-type]
|
||||
(let [muted (and muted? (some? muted-till))]
|
||||
{:icon :i/muted
|
||||
:right-icon :i/chevron-right
|
||||
:accessibility-label :chat-toggle-muted
|
||||
:sub-label (when muted
|
||||
(str (i18n/label :t/muted-until) " " (datetime/format-mute-till muted-till)))
|
||||
:on-press (if muted?
|
||||
#(unmute-channel-action id)
|
||||
#(mute-channel-action id chat-type))
|
||||
:label (i18n/label (if muted
|
||||
:t/unmute-channel
|
||||
:t/mute-channel))}))
|
||||
|
||||
(defn- action-notification-settings
|
||||
[]
|
||||
|
@ -80,36 +106,37 @@
|
|||
:label (i18n/label :t/share-channel)})
|
||||
|
||||
(defn actions
|
||||
[{:keys [locked?]} inside-chat?]
|
||||
(cond
|
||||
locked?
|
||||
[quo/action-drawer
|
||||
[[(action-invite-people)
|
||||
(action-token-requirements)
|
||||
(action-qr-code)
|
||||
(action-share)]]]
|
||||
[{:keys [locked? id community-id]} inside-chat?]
|
||||
(let [{:keys [muted muted-till chat-type]} (rf/sub [:chat-by-id (str community-id id)])]
|
||||
(cond
|
||||
locked?
|
||||
[quo/action-drawer
|
||||
[[(action-invite-people)
|
||||
(action-token-requirements)
|
||||
(action-qr-code)
|
||||
(action-share)]]]
|
||||
|
||||
(and (not inside-chat?) (not locked?))
|
||||
[quo/action-drawer
|
||||
[[(action-view-members-and-details)
|
||||
(action-mark-as-read)
|
||||
(action-toggle-muted)
|
||||
(action-notification-settings)
|
||||
(action-pinned-messages)
|
||||
(action-invite-people)
|
||||
(action-qr-code)
|
||||
(action-share)]]]
|
||||
(and (not inside-chat?) (not locked?))
|
||||
[quo/action-drawer
|
||||
[[(action-view-members-and-details)
|
||||
(action-mark-as-read)
|
||||
(action-toggle-muted (str community-id id) muted muted-till chat-type)
|
||||
(action-notification-settings)
|
||||
(action-pinned-messages)
|
||||
(action-invite-people)
|
||||
(action-qr-code)
|
||||
(action-share)]]]
|
||||
|
||||
(and inside-chat? (not locked?))
|
||||
[quo/action-drawer
|
||||
[[(action-view-members-and-details)
|
||||
(action-token-requirements)
|
||||
(action-mark-as-read)
|
||||
(action-toggle-muted)
|
||||
(action-notification-settings)
|
||||
(action-fetch-messages)
|
||||
(action-invite-people)
|
||||
(action-qr-code)
|
||||
(action-share)]]]
|
||||
(and inside-chat? (not locked?))
|
||||
[quo/action-drawer
|
||||
[[(action-view-members-and-details)
|
||||
(action-token-requirements)
|
||||
(action-mark-as-read)
|
||||
(action-toggle-muted (str community-id id) muted muted-till chat-type)
|
||||
(action-notification-settings)
|
||||
(action-fetch-messages)
|
||||
(action-invite-people)
|
||||
(action-qr-code)
|
||||
(action-share)]]]
|
||||
|
||||
:else nil))
|
||||
:else nil)))
|
||||
|
|
|
@ -15,7 +15,8 @@
|
|||
[status-im2.contexts.communities.overview.style :as style]
|
||||
[status-im2.contexts.communities.overview.utils :as utils]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.re-frame :as rf]))
|
||||
[utils.re-frame :as rf]
|
||||
[status-im2.contexts.communities.actions.chat.view :as chat-actions]))
|
||||
|
||||
(defn preview-user-list
|
||||
[user-list]
|
||||
|
@ -77,13 +78,20 @@
|
|||
{:style {:margin-left 8
|
||||
:margin-top 10
|
||||
:margin-bottom 8}}
|
||||
(for [chat chats
|
||||
:let [chat (assoc chat :chat-type constants/community-chat-type)]]
|
||||
(for [{:keys [muted? id] :as chat} chats
|
||||
:let [chat (assoc chat
|
||||
:chat-type
|
||||
constants/community-chat-type)
|
||||
channel-muted? (or muted?
|
||||
(rf/sub [:chat/check-channel-muted?
|
||||
community-id id]))]]
|
||||
[rn/view
|
||||
{:key (:id chat)
|
||||
:style {:margin-top 4}}
|
||||
[quo/channel-list-item
|
||||
(assoc chat
|
||||
:muted?
|
||||
channel-muted?
|
||||
:on-long-press
|
||||
(fn []
|
||||
(rf/dispatch [:show-bottom-sheet
|
||||
|
@ -206,22 +214,30 @@
|
|||
(i18n/label :t/joined)
|
||||
(i18n/label :t/pending))}]]))
|
||||
|
||||
(defn add-on-press-handler
|
||||
[community-id {:keys [id locked?] :or {locked? false} :as chat}]
|
||||
(defn add-handlers
|
||||
[community-id
|
||||
{:keys [id locked?]
|
||||
:or {locked? false}
|
||||
:as chat}]
|
||||
(merge
|
||||
chat
|
||||
(when (and (not locked?) id)
|
||||
{:on-press (fn []
|
||||
(rf/dispatch [:dismiss-keyboard])
|
||||
(rf/dispatch [:chat/navigate-to-chat (str community-id id)]))})))
|
||||
{:on-press (fn []
|
||||
(rf/dispatch [:dismiss-keyboard])
|
||||
(rf/dispatch [:chat/navigate-to-chat (str community-id id)]))
|
||||
:on-long-press #(rf/dispatch
|
||||
[:show-bottom-sheet
|
||||
{:content (fn []
|
||||
[chat-actions/actions community-id id])}])
|
||||
:community-id community-id})))
|
||||
|
||||
(defn add-on-press-handler-to-chats
|
||||
(defn add-handlers-to-chats
|
||||
[community-id chats]
|
||||
(mapv (partial add-on-press-handler community-id) chats))
|
||||
(mapv (partial add-handlers community-id) chats))
|
||||
|
||||
(defn add-on-press-handler-to-categorized-chats
|
||||
(defn add-handlers-to-categorized-chats
|
||||
[community-id categorized-chats]
|
||||
(let [add-on-press (partial add-on-press-handler-to-chats community-id)]
|
||||
(let [add-on-press (partial add-handlers-to-chats community-id)]
|
||||
(map (fn [[category v]]
|
||||
[category (update v :chats add-on-press)])
|
||||
categorized-chats)))
|
||||
|
@ -268,7 +284,7 @@
|
|||
{:on-category-layout on-category-layout
|
||||
:community-id id
|
||||
:on-first-channel-height-changed on-first-channel-height-changed}
|
||||
(add-on-press-handler-to-categorized-chats id chats-by-category)]]))
|
||||
(add-handlers-to-categorized-chats id chats-by-category)]]))
|
||||
|
||||
(defn sticky-category-header
|
||||
[_]
|
||||
|
|
|
@ -419,3 +419,10 @@
|
|||
:<- [:chats/link-previews-unfurled]
|
||||
(fn [previews]
|
||||
(boolean (seq previews))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
:chat/check-channel-muted?
|
||||
(fn [[_ community-id channel-id]]
|
||||
[(re-frame/subscribe [:chats/chat (str community-id channel-id)])])
|
||||
(fn [[chat]]
|
||||
(:muted? chat)))
|
||||
|
|
|
@ -165,9 +165,13 @@
|
|||
|
||||
(defn calculate-unviewed-counts
|
||||
[chats]
|
||||
(reduce (fn [acc {:keys [unviewed-mentions-count unviewed-messages-count]}]
|
||||
{:unviewed-messages-count (+ (:unviewed-messages-count acc) (or unviewed-messages-count 0))
|
||||
:unviewed-mentions-count (+ (:unviewed-mentions-count acc) (or unviewed-mentions-count 0))})
|
||||
(reduce (fn [acc {:keys [unviewed-mentions-count unviewed-messages-count muted]}]
|
||||
{:unviewed-messages-count (if-not muted
|
||||
(+ (:unviewed-messages-count acc) (or unviewed-messages-count 0))
|
||||
0)
|
||||
:unviewed-mentions-count (if-not muted
|
||||
(+ (:unviewed-mentions-count acc) (or unviewed-mentions-count 0))
|
||||
0)})
|
||||
{:unviewed-messages-count 0
|
||||
:unviewed-mentions-count 0}
|
||||
chats))
|
||||
|
@ -213,28 +217,30 @@
|
|||
full-chats-data]
|
||||
(fn [acc
|
||||
[_ {:keys [name categoryID position id emoji can-post?]}]]
|
||||
(let [category-id (if (seq categoryID) categoryID constants/empty-category-id)
|
||||
(let [category-id (if (seq categoryID) categoryID constants/empty-category-id)
|
||||
{:keys [unviewed-messages-count
|
||||
unviewed-mentions-count]} (get full-chats-data
|
||||
(str community-id id))
|
||||
acc-with-category (if (get acc category-id)
|
||||
acc
|
||||
(assoc acc
|
||||
category-id
|
||||
(assoc
|
||||
(or (get categories category-id)
|
||||
{:name (i18n/label :t/none)})
|
||||
:collapsed? (get collapsed-categories
|
||||
category-id)
|
||||
:chats [])))
|
||||
chat {:name name
|
||||
:emoji emoji
|
||||
:unread-messages? (pos? unviewed-messages-count)
|
||||
:position position
|
||||
:mentions-count (or unviewed-mentions-count 0)
|
||||
:locked? (or (not joined)
|
||||
(not can-post?))
|
||||
:id id}]
|
||||
unviewed-mentions-count
|
||||
muted]} (get full-chats-data
|
||||
(str community-id id))
|
||||
acc-with-category (if (get acc category-id)
|
||||
acc
|
||||
(assoc acc
|
||||
category-id
|
||||
(assoc
|
||||
(or (get categories category-id)
|
||||
{:name (i18n/label :t/none)})
|
||||
:collapsed? (get collapsed-categories
|
||||
category-id)
|
||||
:chats [])))
|
||||
chat {:name name
|
||||
:emoji emoji
|
||||
:muted? muted
|
||||
:unread-messages? (pos? unviewed-messages-count)
|
||||
:position position
|
||||
:mentions-count (or unviewed-mentions-count 0)
|
||||
:locked? (or (not joined)
|
||||
(not can-post?))
|
||||
:id id}]
|
||||
(update-in acc-with-category [category-id :chats] conj chat))))
|
||||
|
||||
(re-frame/reg-sub
|
||||
|
|
|
@ -84,9 +84,27 @@
|
|||
(swap! rf-db/app-db assoc
|
||||
:communities
|
||||
{"0x1" {:id "0x1"
|
||||
:chats {"0x1" {:id "0x1" :position 1 :name "chat1" :categoryID "1" :can-post? true}
|
||||
"0x2" {:id "0x2" :position 2 :name "chat2" :categoryID "1" :can-post? false}
|
||||
"0x3" {:id "0x3" :position 3 :name "chat3" :categoryID "2" :can-post? true}}
|
||||
:chats {"0x1"
|
||||
{:id "0x1"
|
||||
:position 1
|
||||
:name "chat1"
|
||||
:muted? nil
|
||||
:categoryID "1"
|
||||
:can-post? true}
|
||||
"0x2"
|
||||
{:id "0x2"
|
||||
:position 2
|
||||
:name "chat2"
|
||||
:muted? nil
|
||||
:categoryID "1"
|
||||
:can-post? false}
|
||||
"0x3"
|
||||
{:id "0x3"
|
||||
:position 3
|
||||
:name "chat3"
|
||||
:muted? nil
|
||||
:categoryID "2"
|
||||
:can-post? true}}
|
||||
:categories {"1" {:id "1"
|
||||
:position 2
|
||||
:name "category1"}
|
||||
|
@ -103,6 +121,7 @@
|
|||
:chats [{:name "chat3"
|
||||
:position 3
|
||||
:emoji nil
|
||||
:muted? nil
|
||||
:locked? false
|
||||
:id "0x3"
|
||||
:unread-messages? false
|
||||
|
@ -115,6 +134,7 @@
|
|||
:chats [{:name "chat1"
|
||||
:emoji nil
|
||||
:position 1
|
||||
:muted? nil
|
||||
:locked? false
|
||||
:id "0x1"
|
||||
:unread-messages? false
|
||||
|
@ -122,6 +142,7 @@
|
|||
{:name "chat2"
|
||||
:emoji nil
|
||||
:position 2
|
||||
:muted? nil
|
||||
:locked? true
|
||||
:id "0x2"
|
||||
:unread-messages? false
|
||||
|
@ -131,9 +152,21 @@
|
|||
(swap! rf-db/app-db assoc
|
||||
:communities
|
||||
{"0x1" {:id "0x1"
|
||||
:chats {"0x1" {:id "0x1" :position 1 :name "chat1" :categoryID "1" :can-post? true}
|
||||
"0x2" {:id "0x2" :position 2 :name "chat2" :categoryID "1" :can-post? false}
|
||||
"0x3" {:id "0x3" :position 3 :name "chat3" :can-post? true}}
|
||||
:chats {"0x1"
|
||||
{:id "0x1"
|
||||
:position 1
|
||||
:name "chat1"
|
||||
:categoryID "1"
|
||||
:can-post? true
|
||||
:muted? nil}
|
||||
"0x2"
|
||||
{:id "0x2"
|
||||
:position 2
|
||||
:name "chat2"
|
||||
:categoryID "1"
|
||||
:can-post? false
|
||||
:muted? nil}
|
||||
"0x3" {:id "0x3" :position 3 :name "chat3" :can-post? true :muted? nil}}
|
||||
:categories {"1" {:id "1"
|
||||
:position 1
|
||||
:name "category1"}
|
||||
|
@ -150,6 +183,7 @@
|
|||
:emoji nil
|
||||
:position 3
|
||||
:locked? false
|
||||
:muted? nil
|
||||
:id "0x3"
|
||||
:unread-messages? false
|
||||
:mentions-count 0}]}]
|
||||
|
@ -162,6 +196,7 @@
|
|||
:emoji nil
|
||||
:position 1
|
||||
:locked? false
|
||||
:muted? nil
|
||||
:id "0x1"
|
||||
:unread-messages? false
|
||||
:mentions-count 0}
|
||||
|
@ -170,6 +205,7 @@
|
|||
:position 2
|
||||
:locked? true
|
||||
:id "0x2"
|
||||
:muted? nil
|
||||
:unread-messages? false
|
||||
:mentions-count 0}]}]]
|
||||
(rf/sub [sub-name "0x1"]))))
|
||||
|
@ -194,12 +230,14 @@
|
|||
:position 1
|
||||
:locked? false
|
||||
:id "0x1"
|
||||
:muted? nil
|
||||
:unread-messages? true
|
||||
:mentions-count 2}
|
||||
{:name "chat2"
|
||||
:emoji nil
|
||||
:position 2
|
||||
:locked? true
|
||||
:muted? nil
|
||||
:id "0x2"
|
||||
:unread-messages? false
|
||||
:mentions-count 0}]}]]
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
(ns ^{:doc "Utils needed for chat related operations"}
|
||||
utils.chats
|
||||
(:require [status-im2.constants :as constants]))
|
||||
|
||||
(defn not-community-chat?
|
||||
[chat-type]
|
||||
(contains? #{constants/public-chat-type
|
||||
constants/private-group-chat-type
|
||||
constants/one-to-one-chat-type}
|
||||
chat-type))
|
|
@ -5,7 +5,8 @@
|
|||
[cljs-time.format :as t.format]
|
||||
[clojure.string :as string]
|
||||
[utils.i18n :as i18n]
|
||||
[utils.i18n-goog :as i18n-goog]))
|
||||
[utils.i18n-goog :as i18n-goog]
|
||||
[status-im2.constants :as constants]))
|
||||
|
||||
(defn now [] (t/now))
|
||||
|
||||
|
@ -102,6 +103,13 @@
|
|||
(= (t/month now) (t/month datetime))
|
||||
(= (t/day now) (t/day datetime)))))
|
||||
|
||||
(defn tomorrow?
|
||||
[datetime]
|
||||
(= (-> (t/now)
|
||||
(t/plus (t/days 1))
|
||||
t/day)
|
||||
(t/day datetime)))
|
||||
|
||||
(defn within-last-n-days?
|
||||
"Returns true if `datetime` is within last `n` days (inclusive on both ends)."
|
||||
[datetime n]
|
||||
|
@ -259,3 +267,39 @@
|
|||
[ms]
|
||||
(let [sec (quot ms 1000)]
|
||||
(gstring/format "%02d:%02d" (quot sec 60) (mod sec 60))))
|
||||
|
||||
(def ^:const go-default-time
|
||||
"Zero value for golang's time var"
|
||||
"0001-01-01T00:00:00Z")
|
||||
|
||||
(defn- add-leading-zero
|
||||
[input-string]
|
||||
(if (> 10 input-string)
|
||||
(str "0" input-string)
|
||||
input-string))
|
||||
|
||||
(defn format-mute-till
|
||||
[muted-till-string]
|
||||
(let [parsed-time (t.format/parse (t.format/formatters :date-time-no-ms) muted-till-string)
|
||||
hours-and-minutes (str (add-leading-zero (t/hour (t/plus parsed-time time-zone-offset)))
|
||||
":"
|
||||
(add-leading-zero (t/minute parsed-time)))
|
||||
when-to-unmute (cond (= go-default-time
|
||||
muted-till-string) (i18n/label :t/until-you-turn-it-back-on)
|
||||
(today? parsed-time) (str hours-and-minutes " today")
|
||||
(tomorrow? parsed-time) (str hours-and-minutes " tomorrow")
|
||||
:else (str hours-and-minutes
|
||||
" "
|
||||
(i18n/label
|
||||
(keyword "t"
|
||||
(get constants/int->weekday
|
||||
(t/day-of-week
|
||||
parsed-time))))
|
||||
" "
|
||||
(t/day parsed-time)
|
||||
" "
|
||||
(i18n/label
|
||||
(keyword "t"
|
||||
(get constants/months
|
||||
(t/month parsed-time))))))]
|
||||
when-to-unmute))
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
(ns utils.datetime-test
|
||||
(:require [cljs-time.coerce :as time-coerce]
|
||||
[cljs-time.core :as t]
|
||||
[cljs.test :refer-macros [deftest testing is]]
|
||||
[cljs-time.format :as t.format]
|
||||
[cljs.test :refer-macros [deftest testing is are]]
|
||||
[clojure.string :as string]
|
||||
[utils.datetime :as datetime]
|
||||
[utils.i18n-goog :as i18n-goog]
|
||||
[utils.datetime :as datetime]))
|
||||
[status-im2.constants :as constants]))
|
||||
|
||||
(defn match
|
||||
[name symbols]
|
||||
|
@ -189,3 +192,75 @@
|
|||
"it"
|
||||
#'utils.datetime/medium-date-time-format)]
|
||||
(is (= (datetime/day-relative epoch) "01 gen 1970, 12:00:00 AM")))))
|
||||
|
||||
(deftest format-mute-till-test
|
||||
(let [remove-msecs #(string/replace % #"\.\w*Z" "Z")
|
||||
time-str-to-obj #(t.format/parse (remove-msecs (time-coerce/to-string %)))
|
||||
curr-time (t/now)
|
||||
custom-HH-MM-formatter (t.format/formatter "HH:mm")
|
||||
custom-DD-formatter (t.format/formatter "DD")
|
||||
get-hh-mm #(t.format/unparse custom-HH-MM-formatter %)
|
||||
get-day #(t.format/unparse custom-DD-formatter %)
|
||||
get-week-day #(->> %
|
||||
t/day-of-week
|
||||
(get constants/int->weekday))
|
||||
mock-today (t.format/unparse (t.format/formatters :date-time-no-ms) curr-time)
|
||||
in-n-days #(-> (time-str-to-obj mock-today)
|
||||
(t/plus (t/days %)))
|
||||
in-n-minutes #(-> (time-str-to-obj mock-today)
|
||||
(t/plus (t/minutes %)))
|
||||
in-n-hours #(-> (time-str-to-obj mock-today)
|
||||
(t/plus (t/hours %)))
|
||||
mock-tomorrow (in-n-days 1)
|
||||
mock-in-two-days (in-n-days 2)
|
||||
mock-in-three-days (in-n-days 3)
|
||||
mock-in-four-days (in-n-days 4)
|
||||
mock-in-five-days (in-n-days 5)
|
||||
mock-in-six-days (in-n-days 6)
|
||||
mock-in-15-minutes (in-n-minutes 15)
|
||||
mock-in-1-hour (in-n-hours 1)
|
||||
mock-in-8-hour (in-n-hours 8)
|
||||
get-month-day-int #(int (get-day %))
|
||||
today? (fn [mocked curr-time]
|
||||
(=
|
||||
(t.format/unparse (t.format/formatter "MM:DD") mocked)
|
||||
(t.format/unparse (t.format/formatter "MM:DD") curr-time)))
|
||||
tomorrow? (fn [mocked curr-time]
|
||||
(some #(= %
|
||||
(-
|
||||
(int (get-month-day-int mocked))
|
||||
(int (get-month-day-int curr-time))))
|
||||
[1 30 29 27]))
|
||||
form-full-date #(str (get-hh-mm %)
|
||||
" " (string/capitalize (get-week-day %))
|
||||
" " (get-month-day-int %)
|
||||
" " (string/capitalize (get constants/months (t/month %))))
|
||||
today-date #(str (get-hh-mm %) " today")
|
||||
tomorrow-date #(str (get-hh-mm %) " tomorrow")
|
||||
write-date #(cond (today? % curr-time) (today-date %)
|
||||
(tomorrow? % curr-time) (tomorrow-date %)
|
||||
:else (form-full-date %))
|
||||
will-unmute-in-1-hour (remove-msecs (time-coerce/to-string mock-in-1-hour))
|
||||
will-unmute-in-8-hours (remove-msecs (time-coerce/to-string mock-in-8-hour))
|
||||
will-unmute-in-15-mins (remove-msecs (time-coerce/to-string mock-in-15-minutes))
|
||||
will-unmute-in-two-days (remove-msecs (time-coerce/to-string mock-in-two-days))
|
||||
will-unmute-tomorrow (remove-msecs (time-coerce/to-string mock-tomorrow))
|
||||
will-unmute-in-three-days (remove-msecs (time-coerce/to-string mock-in-three-days))
|
||||
will-unmute-in-four-days (remove-msecs (time-coerce/to-string mock-in-four-days))
|
||||
will-unmute-in-five-days (remove-msecs (time-coerce/to-string mock-in-five-days))
|
||||
will-unmute-in-six-days (remove-msecs (time-coerce/to-string mock-in-six-days))]
|
||||
(testing "Mute for minutes and hours"
|
||||
(are [arg expected] (= (datetime/format-mute-till arg) expected)
|
||||
will-unmute-in-15-mins (write-date mock-in-15-minutes)
|
||||
will-unmute-in-1-hour (write-date mock-in-1-hour)
|
||||
will-unmute-in-8-hours (write-date mock-in-8-hour)))
|
||||
(testing "Weekdays"
|
||||
(are [arg expected] (= (datetime/format-mute-till arg) expected)
|
||||
will-unmute-tomorrow (write-date mock-tomorrow)
|
||||
will-unmute-in-two-days (write-date mock-in-two-days)
|
||||
will-unmute-in-three-days (write-date mock-in-three-days)
|
||||
will-unmute-in-four-days (write-date mock-in-four-days)
|
||||
will-unmute-in-five-days (write-date mock-in-five-days)
|
||||
will-unmute-in-six-days (write-date mock-in-six-days)))
|
||||
(testing "Until the user turns it back on"
|
||||
(is (= "you turn it back on" (datetime/format-mute-till datetime/go-default-time))))))
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"_comment": "Instead use: scripts/update-status-go.sh <rev>",
|
||||
"owner": "status-im",
|
||||
"repo": "status-go",
|
||||
"version": "v0.159.4",
|
||||
"commit-sha1": "7da1ed38d4da3c6f9f5bd6fb32657b4183e8fa74",
|
||||
"src-sha256": "10j8p8ng0i6jkv8bplfwwq847yfvyvnz1r2xf5csiy0b86gdwn8n"
|
||||
"version": "v0.159.5",
|
||||
"commit-sha1": "d3e650d5e5d2fecb06a925eb7ccc3ba400d9633c",
|
||||
"src-sha256": "1g353jh27glhm106q65q6m8lamvg42yqsig59qzq38zamm957qaq"
|
||||
}
|
||||
|
|
|
@ -1650,6 +1650,7 @@
|
|||
"mute": "Mute",
|
||||
"unmute": "Unmute",
|
||||
"mute-chat": "Mute chat",
|
||||
"mute-chat-capitialized": "Mute Chat",
|
||||
"unmute-chat": "Unmute chat",
|
||||
"mute-community": "Mute community",
|
||||
"unmute-community": "Unmute community",
|
||||
|
@ -2200,5 +2201,43 @@
|
|||
"token-gated-communities": "Token gated communities",
|
||||
"read-more": "Read more",
|
||||
"token-gated-communities-info": "Here will be something relevant about this topic. This will help the user get more context and therefore have a better understanding of it.",
|
||||
"dont-yell-at-me": "Don’t yell at me"
|
||||
"dont-yell-at-me": "Don’t yell at me",
|
||||
"view-channel-members-and-details": "View channel members and details",
|
||||
"unmute-channel": "Unmute channel",
|
||||
"share-channel": "Share channel",
|
||||
"all-messages": "All messages",
|
||||
"muted-until": "Muted until",
|
||||
"until-you-turn-it-back-on": "you turn it back on",
|
||||
"mon": "Mon",
|
||||
"tue": "Tue",
|
||||
"wed": "Wed",
|
||||
"thu": "Thu",
|
||||
"fri": "Fri",
|
||||
"sat": "Sat",
|
||||
"sun": "Sun",
|
||||
"jan": "Jan",
|
||||
"feb": "Feb",
|
||||
"mar": "Mar",
|
||||
"apr": "Apr",
|
||||
"may": "May",
|
||||
"jun": "Jun",
|
||||
"jul": "Jul",
|
||||
"aug": "Aug",
|
||||
"sep": "Sep",
|
||||
"oct": "Oct",
|
||||
"nov": "Nov",
|
||||
"dec": "Dec",
|
||||
"channel-muted-for-15-minutes": "Channel muted for 15 minutes\n (until {{duration}}) ",
|
||||
"channel-muted-for-1-hour": "Channel muted for 1 hour\n (until {{duration}}) ",
|
||||
"channel-muted-for-8-hours": "Channel muted for 8 hours\n (until {{duration}}) ",
|
||||
"channel-muted-for-1-week": "Channel muted for 1 week \n (until {{duration}}) ",
|
||||
"channel-muted-till-unmuted": "Channel muted till unmuted\n (until {{duration}}) ",
|
||||
"chat-muted-for-15-minutes": "Chat muted for 15 minutes\n (until {{duration}}) ",
|
||||
"chat-muted-for-1-hour": "Chat muted for 1 hour\n (until {{duration}}) ",
|
||||
"chat-muted-for-8-hours": "Chat muted for 8 hours\n (until {{duration}}) ",
|
||||
"chat-muted-for-1-week": "Chat muted for 1 week\n (until {{duration}}) ",
|
||||
"chat-muted-till-unmuted": "Chat muted till unmuted\n (until {{duration}}) ",
|
||||
"until": "until",
|
||||
"chat-unmuted-successfully": "Chat unmuted successfully! ",
|
||||
"channel-unmuted-successfully": "Channel unmuted successfully! "
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue