diff --git a/_locales/en/messages.json b/_locales/en/messages.json
index 15d48eebe..7b5f04fb1 100644
--- a/_locales/en/messages.json
+++ b/_locales/en/messages.json
@@ -416,5 +416,6 @@
"pinConversationLimitToastDescription": "You can only pin $number$ conversations",
"latestUnreadIsAbove": "First unread message is above",
"sendRecoveryPhraseTitle": "Sending Recovery Phrase",
- "sendRecoveryPhraseMessage": "You are attempting to send your recovery phrase which can be used to access your account. Are you sure you want to send this message?"
+ "sendRecoveryPhraseMessage": "You are attempting to send your recovery phrase which can be used to access your account. Are you sure you want to send this message?",
+ "notificationSubtitle": "Notifications - $setting$"
}
diff --git a/ts/components/ConversationListItem.tsx b/ts/components/ConversationListItem.tsx
index 58938d68c..8098b6944 100644
--- a/ts/components/ConversationListItem.tsx
+++ b/ts/components/ConversationListItem.tsx
@@ -13,7 +13,7 @@ import { ConversationAvatar } from './session/usingClosedConversationDetails';
import { MemoConversationListItemContextMenu } from './session/menu/ConversationListItemContextMenu';
import { createPortal } from 'react-dom';
import { OutgoingMessageStatus } from './conversation/message/OutgoingMessageStatus';
-import { useTheme } from 'styled-components';
+import styled, { useTheme } from 'styled-components';
import { PubKey } from '../session/types';
import {
LastMessageType,
@@ -27,10 +27,20 @@ import { useDispatch, useSelector } from 'react-redux';
import { SectionType } from '../state/ducks/section';
import { getFocusedSection } from '../state/selectors/section';
import { getFirstUnreadMessageIdInConversation } from '../data/data';
+import { ConversationNotificationSettingType } from '../models/conversation';
// tslint:disable-next-line: no-empty-interface
export interface ConversationListItemProps extends ReduxConversationType {}
+export const StyledConversationListItemIconWrapper = styled.div`
+ svg {
+ margin: 0px 2px;
+ }
+
+ display: flex;
+ flex-direction: row;
+`;
+
type PropsHousekeeping = {
style?: Object;
};
@@ -50,6 +60,7 @@ const HeaderItem = (props: {
profileName?: string;
conversationId: string;
isPinned: boolean;
+ currentNotificationSetting: ConversationNotificationSettingType;
}) => {
const {
unreadCount,
@@ -60,6 +71,7 @@ const HeaderItem = (props: {
conversationId,
profileName,
name,
+ currentNotificationSetting,
} = props;
const theme = useTheme();
@@ -80,6 +92,36 @@ const HeaderItem = (props: {
iconSize={SessionIconSize.Tiny}
/>
) : null;
+
+ const NotificationSettingIcon = () => {
+ if (!isMessagesSection) {
+ return null;
+ }
+
+ switch (currentNotificationSetting) {
+ case 'all':
+ return null;
+ case 'disabled':
+ return (
+
+ );
+ case 'mentions_only':
+ return (
+
+ );
+ default:
+ return null;
+ }
+ };
+
return (
- {pinIcon}
+
+
+ {pinIcon}
+
+
{unreadCountDiv}
{atSymbol}
{
@@ -282,6 +328,7 @@ const ConversationListItem = (props: Props) => {
conversationId={conversationId}
name={name}
profileName={profileName}
+ currentNotificationSetting={currentNotificationSetting}
/>
diff --git a/ts/components/conversation/ConversationHeader.tsx b/ts/components/conversation/ConversationHeader.tsx
index d9cc42b81..e46377b3e 100644
--- a/ts/components/conversation/ConversationHeader.tsx
+++ b/ts/components/conversation/ConversationHeader.tsx
@@ -7,12 +7,13 @@ import { SessionIconButton, SessionIconSize, SessionIconType } from '../session/
import { SessionButton, SessionButtonColor, SessionButtonType } from '../session/SessionButton';
import { ConversationAvatar } from '../session/usingClosedConversationDetails';
import { MemoConversationHeaderMenu } from '../session/menu/ConversationHeaderMenu';
-import { contextMenu } from 'react-contexify';
-import { useTheme } from 'styled-components';
+import { contextMenu, theme } from 'react-contexify';
+import styled, { ThemeProvider, useTheme } from 'styled-components';
import { ConversationNotificationSettingType } from '../../models/conversation';
import {
getConversationHeaderProps,
getConversationHeaderTitleProps,
+ getCurrentNotificationSettingText,
getSelectedConversation,
getSelectedMessageIds,
isMessageDetailView,
@@ -28,6 +29,7 @@ import {
openRightPanel,
resetSelectedMessageIds,
} from '../../state/ducks/conversations';
+import { getTheme } from '../../state/selectors/theme';
export interface TimerOption {
name: string;
@@ -74,7 +76,6 @@ const SelectionOverlay = (props: {
}) => {
const { onDeleteSelectedMessages, onCloseOverlay, isPublic } = props;
const { i18n } = window;
- const theme = useTheme();
const isServerDeletable = isPublic;
const deleteMessageButtonText = i18n(isServerDeletable ? 'deleteForEveryone' : 'delete');
@@ -86,7 +87,6 @@ const SelectionOverlay = (props: {
iconType={SessionIconType.Exit}
iconSize={SessionIconSize.Medium}
onClick={onCloseOverlay}
- theme={theme}
/>
@@ -104,7 +104,6 @@ const SelectionOverlay = (props: {
const TripleDotsMenu = (props: { triggerId: string; showBackButton: boolean }) => {
const { showBackButton } = props;
- const theme = useTheme();
if (showBackButton) {
return <>>;
}
@@ -118,11 +117,7 @@ const TripleDotsMenu = (props: { triggerId: string; showBackButton: boolean }) =
});
}}
>
-
+
);
};
@@ -175,7 +170,6 @@ const AvatarHeader = (props: {
const BackButton = (props: { onGoBack: () => void; showBackButton: boolean }) => {
const { onGoBack, showBackButton } = props;
- const theme = useTheme();
if (!showBackButton) {
return null;
}
@@ -186,11 +180,30 @@ const BackButton = (props: { onGoBack: () => void; showBackButton: boolean }) =>
iconSize={SessionIconSize.Large}
iconRotation={90}
onClick={onGoBack}
- theme={theme}
/>
);
};
+interface StyledSubtitleContainerProps {
+ margin?: string;
+}
+export const StyledSubtitleContainer = styled.div`
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+
+ span {
+ margin-bottom: ${(p: StyledSubtitleContainerProps) => {
+ return p.margin || '5px';
+ }};
+ }
+
+ span:last-child {
+ margin-bottom: 0;
+ }
+`;
+
export type ConversationHeaderTitleProps = {
phoneNumber: string;
profileName?: string;
@@ -201,6 +214,7 @@ export type ConversationHeaderTitleProps = {
subscriberCount?: number;
isKickedFromGroup: boolean;
name?: string;
+ currentNotificationSetting?: ConversationNotificationSettingType;
};
const ConversationHeaderTitle = () => {
@@ -239,27 +253,43 @@ const ConversationHeaderTitle = () => {
}
})();
- let text = '';
+ let memberCountText = '';
if (isGroup && memberCount > 0) {
const count = String(memberCount);
- text = i18n('members', [count]);
+ memberCountText = i18n('members', [count]);
}
- const textEl =
- text === '' || isKickedFromGroup ? null : (
- {text}
- );
-
+ const notificationSetting = useSelector(getCurrentNotificationSettingText);
+ const notificationSubtitle = notificationSetting
+ ? window.i18n('notificationSubtitle', notificationSetting)
+ : null;
const title = profileName || name || phoneNumber;
+ const marginXS = useTheme().common.margins.xs;
return (
{title}
- {textEl}
+
+ {isKickedFromGroup ? null : }
+
+
);
};
+/**
+ * The subtitle beneath a conversation title when looking at a conversation screen.
+ * @param props props for subtitle. Text to be displayed
+ * @returns JSX Element of the subtitle of conversation header
+ */
+export const ConversationHeaderSubtitle = (props: { text?: string | null }): JSX.Element | null => {
+ const { text } = props;
+ if (!text) {
+ return null;
+ }
+ return {text};
+};
+
export const ConversationHeaderWithDetails = () => {
const headerProps = useSelector(getConversationHeaderProps);
diff --git a/ts/components/session/icon/Icons.tsx b/ts/components/session/icon/Icons.tsx
index 266181d3d..e82f6866e 100644
--- a/ts/components/session/icon/Icons.tsx
+++ b/ts/components/session/icon/Icons.tsx
@@ -1,6 +1,7 @@
export enum SessionIconType {
AddUser = 'addUser',
Arrow = 'arrow',
+ Bell = 'bell',
Caret = 'caret',
ChatBubble = 'chatBubble',
Check = 'check',
@@ -23,6 +24,7 @@ export enum SessionIconType {
Lock = 'lock',
Microphone = 'microphone',
Moon = 'moon',
+ Mute = 'mute',
Oxen = 'oxen',
Pause = 'pause',
Pencil = 'pencil',
@@ -80,6 +82,12 @@ export const icons = {
viewBox: '0 -4 37 37',
ratio: 1,
},
+ [SessionIconType.Bell]: {
+ path:
+ 'M68.16 6.889c18.129 3.653 31.889 19.757 31.889 38.921 0 22.594-2.146 39.585 20.592 54.716H0c22.8-15.173 20.647-32.49 20.647-54.716 0-19.267 13.91-35.439 32.182-38.979 1.054-9.14 14.345-9.096 15.331.058zm8.551 102.301c-1.398 7.785-8.205 13.688-16.392 13.688s-14.992-5.902-16.393-13.688h32.785z',
+ viewBox: '0 0 120.641 122.878',
+ ratio: 1,
+ },
[SessionIconType.Caret]: {
path: 'M127.5 191.25L255 63.75L0 63.75L127.5 191.25Z',
viewBox: '-200 -200 640 640',
@@ -214,6 +222,12 @@ export const icons = {
viewBox: '0.5 0.5 22 22',
ratio: 1,
},
+ [SessionIconType.Mute]: {
+ path:
+ 'M7.02 28.81h28.65c.6 0 1.09.49 1.09 1.09v44.09L17.76 93H7c-3.85 0-7-3.15-7-7V35.83c0-3.86 3.16-7.02 7.02-7.02zM111.29 6.02l11.59 11.59-93.17 93.17-11.59-11.59 93.17-93.17zM42.33 27.67C59.03 18.51 75.73 9.35 92.42.19c1.6-.88 3.32 1.49 3.32 3.32v11.5L41.66 69.1V28.34c0-.37.35-.49.67-.67zm53.41 23.99v65.6c0 1.92-1.82 4.45-3.5 3.5L50.29 97.11l45.45-45.45z',
+ viewBox: '0 0 122.88 120.97',
+ ratio: 1,
+ },
[SessionIconType.Oxen]: {
path:
'M1033.9 1319.4h1v122h-1c-1.7-1.9-1.6-4.3-1.6-6.6v-108.7c0-2.4-.2-4.8 1.6-6.7zM773.4 1441.4c-21 0-42-.1-63 .1-4.2 0-6.9-1.4-9.2-4.6-10.2-14.5-16.9-30.2-18.5-48.2-2.3-24.5 4.9-45.8 19-65.4 1.9-2.7 4.3-4.1 7.9-4.1 42.3.1 84.6.2 127 0 4.5 0 5.8 1.4 5.5 5.7-.4 5.1-.3 10.3 0 15.5.3 4-1.1 5.1-5.1 5-22.8-.2-45.7-.1-68.5-.1-15 0-30 .1-45-.1-3.1 0-4.8 1-6 3.9-1.7 4-2.9 8.1-4.1 12.3-1.1 3.8 0 5 4 5 23.3-.1 46.7-.1 70-.1 13.3 0 26.7.1 40-.1 3.8-.1 5 1.1 4.8 4.8-.3 5.5-.3 11 0 16.5.3 4.5-1 6-5.7 5.9-33.8-.2-67.6-.1-101.5-.1-2.8 0-5.7.3-8.5-.1-3.8-.4-4.1 1.4-3.4 4.3 0 .2 0 .3.1.5 3 16.2 4.4 17.3 20.6 17.3 34.3 0 68.6.1 103-.1 4 0 5.7.9 5.4 5.2-.4 5.5-.3 11 0 16.5.2 3.6-1.2 4.5-4.6 4.5-21.6-.1-42.9 0-64.2 0zM397.2 1319.3c20 0 40 .1 60-.1 3.6 0 5.8 1.3 7.8 4.1 13.9 19.4 20.7 40.9 18.8 64.7-1.5 18.8-8.7 35.7-19.9 50.8-1.4 1.9-3.2 2.6-5.6 2.6-40.8-.1-81.6-.1-122.4 0-2.2 0-3.7-.7-5-2.5-11.5-14.8-18.2-31.4-20-50.1-2.2-21.7 3.6-41.4 14.7-59.7.2-.3.3-.6.5-.9 3.6-6.3 8-9.6 16.2-9.2 18.2.9 36.6.3 54.9.3zM1033.9 1319.4v121.9c-5.7 0-11.4-.3-17 .2-6.6.6-12-1.9-17-5.8-32.5-25.1-64.9-50.2-97.4-75.2-1.6-1.2-3.2-2.3-5.6-4.1v5.8c0 24.5-.1 49 .1 73.5 0 4.7-1.4 6-5.9 5.7-6.3-.4-12.7-.2-19 0-2.8.1-4.2-.6-4.2-3.8.1-38.2.1-76.3 0-114.5 0-3.2 1.3-3.9 4.2-3.9 6 .2 12 .1 18 .1 7.3 0 12.1 5.2 17.3 9.1 21.4 16.3 42.7 32.7 64 49.2 11.3 8.7 22.5 17.4 33.9 26.2 1.3-1.8.7-3.5.7-5.1 0-24.8.1-49.7-.1-74.5 0-3.9 1-5.3 5-5.1 7.6.5 15.3.3 23 .3zM488.8 1319.4c14.1 0 27-.1 39.9.1 4.3.1 7.9 2.6 11 5.3 12.9 11.2 25.9 22.3 38.7 33.7 2.7 2.4 4.6 1.8 6.9-.2 10.5-9.1 21.1-18.3 31.6-27.5 2.9-2.5 5.7-5.1 8.7-7.5 2.8-2.2 6.1-3.8 9.6-3.9 12.6-.2 25.2-.1 37.9-.1.1 2.1-1.4 2.8-2.5 3.7-13.3 11.5-26.7 23-40 34.5-7.9 6.8-15.8 13.7-23.8 20.5-2.5 2.1-1.5 3.5.4 5.1 10.1 8.6 20.2 17.3 30.3 26 12.2 10.5 24.4 21 37.5 32.2-14.2 0-27.4.4-40.6-.2-7.3-.3-11.7-6.5-16.9-10.9-10.8-9.1-21.4-18.5-32-27.8-2.4-2.1-4.5-2.3-7-.2-12.5 10.9-25.2 21.7-37.6 32.7-4.8 4.3-10 6.7-16.7 6.5-11.3-.3-22.7-.1-34.6-.1 4.5-5.4 9.8-9.2 14.6-13.5 13.3-11.8 26.9-23.2 40.4-34.8 3.9-3.3 7.8-6.7 11.8-9.9 2.6-2.1 2.6-3.5-.1-5.8-14-11.8-27.7-23.8-41.6-35.7-8.3-7-16.7-14.3-25.9-22.2zM153.9 1273.4c5.4 1.3 10.9 2.3 16.3 3.9 41.5 12.6 67.5 40.1 76.6 82.4 6.7 31.3-.6 60.2-19.9 85.5-18.2 23.9-42.5 37.5-72.4 41.2-27.9 3.4-53.1-3.5-75.7-19.9-24.1-17.5-37.8-41.4-42.8-70.6-.2-1-.1-2-1.1-2.6v-26c1.6-19.6 9.1-36.9 20.8-52.5 15.4-20.4 35.8-33.4 60.5-39.7 4.2-1.1 8.5-.7 12.7-1.8 8.3.1 16.6.1 25 .1zM142.8 1379.4c2.3 6 8.1 8.5 12.4 12.5 10.7 9.7 21.8 18.9 32.8 28.3 4.8 4.1 9.4 8.3 14.8 12.9H80.9c6.2-5.5 12-10.5 17.8-15.6 13.2-11.4 26.4-22.7 39.6-34.1 1.2-1.1 2.7-2.1 2.6-4 .7-.5 1.3-.5 1.9 0zM142.8 1379.4h-1.9c-12.9-11-25.7-22-38.6-33-7-6-14-12.1-21.6-18.7h122.5c-20.6 17.6-40.5 34.6-60.4 51.7zM397.2 1415.4c-14.2 0-28.3-.2-42.5.1-5.1.1-8-1.1-10.1-6.3-7.9-20.1-7.8-39.8 1-59.5 1.4-3.1 3.1-4.4 6.8-4.4 30 .2 60 .1 90 0 3.6 0 5.2 1.3 6.6 4.5 4.1 9.3 6.4 19 6.7 28.9.3 11.9-2.5 23.4-7.6 34.2-1.2 2.6-3.2 2.4-5.4 2.4-15.2.1-30.4.1-45.5.1zM153.9 1273.4c292.2 0 584.3 0 876.5-.1 3.7 0 4.7.8 4.6 4.6-.3 13.8-.1 27.7-.1 41.5-.4.4-.9.7-1.4.9-6.8 1-13.6.3-20.4.5-5.2.2-5.7.5-5.7 5.8 0 23.3 0 46.6-.1 70 0 2.7 1.2 6.5-1.8 7.7-2.5 1.1-4.6-2-6.7-3.6-31.9-24.6-64-49-95.8-73.8-6.7-5.3-13.9-6.3-22-6.1-13.3.4-11.7-1.3-11.7 11.8-.1 33.5 0 67 0 100.4 0 6.8.1 7 7 7 4.5 0 9 .1 13.5 0 5.1-.1 5.7-.6 5.7-5.8 0-23 0-46 .1-69 0-2.9-1.2-6.9 1.6-8.4 2.9-1.5 5.3 2 7.6 3.7 31.8 24.5 63.7 48.8 95.4 73.5 5.2 4 10.7 6.4 17.4 6.1 5.3-.3 10.7-.6 15.9.4.5.3 1 .6 1.4.9 0 15-.1 30 .1 45 0 2.5-.6 3.5-3.1 3-.5-.1-1 0-1.5 0-330.3 0-660.7 0-991 .1-3.7 0-4.6-.8-4.6-4.6.2-30.5.1-61 .1-91.5 3.4 1 2.6 4.3 3.1 6.6 3.1 16 9.4 30.6 19.2 43.5 18.3 24.2 42.6 38.3 72.8 41.7 30.1 3.5 56.7-4.8 79.9-24.2 21.4-17.9 33.4-40.9 36.9-68.7 6.6-53-29.2-105-84.8-115.9-2.8-.4-6.5.7-8.1-3zM128.9 1273.4c-2.8 1.6-6 1.5-9 2.2-20.6 4.6-38.6 14.1-53.5 28.9-16.7 16.7-26.7 36.9-30.5 60.2-.2 1-.1 2-1 2.6 0-30.3 0-60.5-.1-90.8 0-2.8.6-3.3 3.3-3.3 30.3.2 60.5.2 90.8.2zM107.2 0C48 0 0 48 0 107.2s48 107.2 107.2 107.2 107.2-48 107.2-107.2S166.4 0 107.2 0zM45.3 160.3l61.7-53.4 61.7 53.4H45.3zm61.7-53.5L45.3 53.4h123.4L107 106.8zM426.9 46H297.7s-22.6 25.2-22.4 60.9c.2 35.7 22.4 60.9 22.4 60.9h129s21.7-25.8 22.4-60.4C449.7 73 426.9 46 426.9 46zm-6 61.4c-.4 19.9-9.1 34.9-9.1 34.9h-99.3s-8.8-14.6-8.9-35.2c-.1-20.6 8.9-35.2 8.9-35.2h99.4s9.3 15.5 9 35.5zM454.3 46l70.6 60.9-70.6 60.9h38.4s6.7-.1 12.8-5.6c6.1-5.5 41.5-35.9 41.5-35.9l45.5 39.1s3 2.3 9.8 2.5 37.7 0 37.7 0L569.4 107 640 46h-38.3s-5.2-.9-12.7 5.5c-7.5 6.4-41.8 36.3-41.8 36.3l-44.7-38s-2.7-3.8-12.2-3.8c-9.5-.1-36 0-36 0zM806.8 71.9V46h-137s-22.6 25.2-22.4 60.9 22.4 60.9 22.4 60.9h137v-25.6H684.6s-5.4-8.9-7.8-22.6h120V92.9H677c2.5-12.8 7.6-21.1 7.6-21.1h122.2zM833.1 167.9V46h20.4s5.9-.2 10.7 3.4c4.7 3.6 107.4 82.5 107.4 82.5V46h28.3v121.8h-21.6s-5.6.4-10.3-3.4c-4.7-3.7-106.5-82-106.5-82v85.4l-28.4.1z',
diff --git a/ts/state/selectors/conversations.ts b/ts/state/selectors/conversations.ts
index f24683956..4a4f6879e 100644
--- a/ts/state/selectors/conversations.ts
+++ b/ts/state/selectors/conversations.ts
@@ -238,9 +238,31 @@ export const getConversationHeaderTitleProps = createSelector(getSelectedConvers
name: state.name,
subscriberCount: state.subscriberCount,
isGroup: state.type === 'group',
+ currentNotificationSetting: state.currentNotificationSetting,
};
});
+/**
+ * Returns the formatted text for notification setting.
+ */
+export const getCurrentNotificationSettingText = createSelector(getSelectedConversation, (state):
+ | string
+ | undefined => {
+ if (!state) {
+ return undefined;
+ }
+ switch (state.currentNotificationSetting) {
+ case 'all':
+ return window.i18n('notificationForConvo_all');
+ case 'mentions_only':
+ return window.i18n('notificationForConvo_mentions_only');
+ case 'disabled':
+ return window.i18n('notificationForConvo_mentions_disabled');
+ default:
+ return window.i18n('notificationForConvo_all');
+ }
+});
+
export const getConversationHeaderProps = createSelector(getSelectedConversation, (state):
| ConversationHeaderProps
| undefined => {