Skip to content

Commit

Permalink
@mentions notifications
Browse files Browse the repository at this point in the history
  • Loading branch information
EvanHahn-Signal committed Aug 5, 2021
1 parent 3bbe859 commit 6b290a0
Show file tree
Hide file tree
Showing 29 changed files with 627 additions and 51 deletions.
24 changes: 24 additions & 0 deletions _locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -3451,6 +3451,10 @@
"message": "Mute notifications",
"description": "Label for the mute notifications drop-down selector"
},
"notMuted": {
"message": "Not muted",
"description": "Label when the conversation is not muted"
},
"muteHour": {
"message": "Mute for one hour",
"description": "Label for muting the conversation"
Expand Down Expand Up @@ -4964,6 +4968,10 @@
"message": "When enabled, messages sent and received in this group will disappear after they've been seen.",
"description": "This is the info about the disappearing messages setting"
},
"ConversationDetails--notifications": {
"message": "Notifications",
"description": "This is the label for notifications in the conversation details screen"
},
"ConversationDetails--group-info-label": {
"message": "Who can edit group info",
"description": "This is the label for the 'who can edit the group' panel"
Expand Down Expand Up @@ -5070,6 +5078,22 @@
"message": "See all",
"description": "This is a button on the conversation details to show all members"
},
"ConversationNotificationsSettings__mentions__label": {
"message": "Mentions",
"description": "In the conversation notifications settings, this is the label for the mentions option"
},
"ConversationNotificationsSettings__mentions__info": {
"message": "Receive notifications when you're mentioned in muted chats",
"description": "In the conversation notifications settings, this is the sub-label for the mentions option"
},
"ConversationNotificationsSettings__mentions__select__always-notify": {
"message": "Always notify",
"description": "In the conversation notifications settings, this is the option that always notifies you for @mentions"
},
"ConversationNotificationsSettings__mentions__select__dont-notify-for-mentions-if-muted": {
"message": "Don't notify if muted",
"description": "In the conversation notifications settings, this is the option that doesn't notify you for @mentions if the conversation is muted"
},
"GroupLinkManagement--clipboard": {
"message": "Group link copied.",
"description": "Shown in a toast when a user selects to copy group link"
Expand Down
1 change: 1 addition & 0 deletions images/icons/v2/at-24.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions images/icons/v2/bell-disabled-outline-24.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions images/icons/v2/bell-disabled-solid-24.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions images/icons/v2/sound-outline-24.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions js/modules/signal.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ const { createLeftPane } = require('../../ts/state/roots/createLeftPane');
const {
createMessageDetail,
} = require('../../ts/state/roots/createMessageDetail');
const {
createConversationNotificationsSettings,
} = require('../../ts/state/roots/createConversationNotificationsSettings');
const {
createGroupV2Permissions,
} = require('../../ts/state/roots/createGroupV2Permissions');
Expand Down Expand Up @@ -363,6 +366,7 @@ exports.setup = (options = {}) => {
createGroupV2Permissions,
createLeftPane,
createMessageDetail,
createConversationNotificationsSettings,
createPendingInvites,
createSafetyNumberViewer,
createShortcutGuideModal,
Expand Down
13 changes: 7 additions & 6 deletions protos/SignalStorage.proto
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,13 @@ message GroupV1Record {
}

message GroupV2Record {
optional bytes masterKey = 1;
optional bool blocked = 2;
optional bool whitelisted = 3;
optional bool archived = 4;
optional bool markedUnread = 5;
optional uint64 mutedUntilTimestamp = 6;
optional bytes masterKey = 1;
optional bool blocked = 2;
optional bool whitelisted = 3;
optional bool archived = 4;
optional bool markedUnread = 5;
optional uint64 mutedUntilTimestamp = 6;
optional bool dontNotifyForMentionsIfMuted = 7;
}

message AccountRecord {
Expand Down
45 changes: 45 additions & 0 deletions stylesheets/_modules.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2862,6 +2862,51 @@ button.module-conversation-details__action-button {
}
}

&--notifications {
&::after {
-webkit-mask: url('../images/icons/v2/sound-outline-24.svg') no-repeat
center;

@include light-theme {
background-color: $color-gray-75;
}

@include dark-theme {
background-color: $color-gray-15;
}
}
}

&--mute {
&::after {
@include light-theme {
-webkit-mask: url('../images/icons/v2/bell-disabled-outline-24.svg')
no-repeat center;
background-color: $color-gray-75;
}

@include dark-theme {
-webkit-mask: url('../images/icons/v2/bell-disabled-solid-24.svg')
no-repeat center;
background-color: $color-gray-15;
}
}
}

&--mention {
&::after {
-webkit-mask: url('../images/icons/v2/at-24.svg') no-repeat center;

@include light-theme {
background-color: $color-gray-75;
}

@include dark-theme {
background-color: $color-gray-15;
}
}
}

&--lock {
&::after {
-webkit-mask: url(../images/icons/v2/lock-outline-24.svg) no-repeat
Expand Down
13 changes: 13 additions & 0 deletions ts/components/Select.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,16 @@ story.add('Normal', () => {
/>
);
});

story.add('With disabled options', () => (
<Select
options={[
{ value: 'a', text: 'Apples' },
{ value: 'b', text: 'Bananas', disabled: true },
{ value: 'c', text: 'Cabbage' },
{ value: 'd', text: 'Durian', disabled: true },
]}
onChange={action('onChange')}
value="c"
/>
));
10 changes: 8 additions & 2 deletions ts/components/Select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import React, { ChangeEvent } from 'react';
import classNames from 'classnames';

export type Option = Readonly<{
disabled?: boolean;
text: string;
value: string | number;
}>;
Expand All @@ -26,9 +27,14 @@ export function Select(props: PropsType): JSX.Element {
return (
<div className={classNames(['module-select', moduleClassName])}>
<select value={value} onChange={onSelectChange}>
{options.map(({ text, value: optionValue }) => {
{options.map(({ disabled, text, value: optionValue }) => {
return (
<option value={optionValue} key={optionValue} aria-label={text}>
<option
disabled={disabled}
value={optionValue}
key={optionValue}
aria-label={text}
>
{text}
</option>
);
Expand Down
37 changes: 2 additions & 35 deletions ts/components/conversation/ConversationHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

import React, { ReactNode } from 'react';
import Measure from 'react-measure';
import moment from 'moment';
import classNames from 'classnames';
import {
ContextMenu,
Expand All @@ -19,9 +18,8 @@ import { InContactsIcon } from '../InContactsIcon';

import { LocalizerType } from '../../types/Util';
import { ConversationType } from '../../state/ducks/conversations';
import { MuteOption, getMuteOptions } from '../../util/getMuteOptions';
import { getMuteOptions } from '../../util/getMuteOptions';
import * as expirationTimer from '../../util/expirationTimer';
import { isMuted } from '../../util/isMuted';
import { missingCaseError } from '../../util/missingCaseError';
import { isInSystemContacts } from '../../util/isInSystemContacts';

Expand Down Expand Up @@ -395,38 +393,7 @@ export class ConversationHeader extends React.Component<PropsType, StateType> {
onMoveToInbox,
} = this.props;

const muteOptions: Array<MuteOption> = [];
if (isMuted(muteExpiresAt)) {
const expires = moment(muteExpiresAt);

let muteExpirationLabel: string;
if (Number(muteExpiresAt) >= Number.MAX_SAFE_INTEGER) {
muteExpirationLabel = i18n('muteExpirationLabelAlways');
} else {
const muteExpirationUntil = moment().isSame(expires, 'day')
? expires.format('hh:mm A')
: expires.format('M/D/YY, hh:mm A');

muteExpirationLabel = i18n('muteExpirationLabel', [
muteExpirationUntil,
]);
}

muteOptions.push(
...[
{
name: muteExpirationLabel,
disabled: true,
value: 0,
},
{
name: i18n('unmute'),
value: 0,
},
]
);
}
muteOptions.push(...getMuteOptions(i18n));
const muteOptions = getMuteOptions(muteExpiresAt, i18n);

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const disappearingTitle = i18n('disappearingMessages') as any;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ const createProps = (hasGroupLink = false, expireTimer?: number): Props => ({
showGroupChatColorEditor: action('showGroupChatColorEditor'),
showGroupLinkManagement: action('showGroupLinkManagement'),
showGroupV2Permissions: action('showGroupV2Permissions'),
showConversationNotificationsSettings: action(
'showConversationNotificationsSettings'
),
showPendingInvites: action('showPendingInvites'),
showLightboxForMedia: action('showLightboxForMedia'),
updateGroupAttributes: async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import React, { useState, ReactNode } from 'react';

import { ConversationType } from '../../../state/ducks/conversations';
import { assert } from '../../../util/assert';
import { getMutedUntilText } from '../../../util/getMutedUntilText';

import { LocalizerType } from '../../../types/Util';
import { MediaItemType } from '../../LightboxGallery';
Expand Down Expand Up @@ -62,6 +63,7 @@ export type StateProps = {
selectedMediaItem: MediaItemType,
media: Array<MediaItemType>
) => void;
showConversationNotificationsSettings: () => void;
updateGroupAttributes: (
_: Readonly<{
avatar?: undefined | ArrayBuffer;
Expand Down Expand Up @@ -95,6 +97,7 @@ export const ConversationDetails: React.ComponentType<Props> = ({
showGroupV2Permissions,
showPendingInvites,
showLightboxForMedia,
showConversationNotificationsSettings,
updateGroupAttributes,
onBlock,
onLeave,
Expand Down Expand Up @@ -284,6 +287,21 @@ export const ConversationDetails: React.ComponentType<Props> = ({
/>
}
/>
<PanelRow
icon={
<ConversationDetailsIcon
ariaLabel={i18n('ConversationDetails--notifications')}
icon="notifications"
/>
}
label={i18n('ConversationDetails--notifications')}
onClick={showConversationNotificationsSettings}
right={
conversation.muteExpiresAt
? getMutedUntilText(conversation.muteExpiresAt, i18n)
: undefined
}
/>
</PanelSection>

<ConversationDetailsMembershipList
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only

import * as React from 'react';

import { storiesOf } from '@storybook/react';
import { action } from '@storybook/addon-actions';

import { setup as setupI18n } from '../../../../js/modules/i18n';
import enMessages from '../../../../_locales/en/messages.json';
import { ConversationNotificationsSettings } from './ConversationNotificationsSettings';

const i18n = setupI18n('en', enMessages);

const story = storiesOf(
'Components/Conversation/ConversationDetails/ConversationNotificationsSettings',
module
);

const getCommonProps = () => ({
muteExpiresAt: undefined,
conversationType: 'group' as const,
dontNotifyForMentionsIfMuted: false,
i18n,
setDontNotifyForMentionsIfMuted: action('setDontNotifyForMentionsIfMuted'),
setMuteExpiration: action('setMuteExpiration'),
});

story.add('Group conversation, all default', () => (
<ConversationNotificationsSettings {...getCommonProps()} />
));

story.add('Group conversation, muted', () => (
<ConversationNotificationsSettings
{...getCommonProps()}
muteExpiresAt={Date.UTC(2099, 5, 9)}
/>
));

story.add('Group conversation, @mentions muted', () => (
<ConversationNotificationsSettings
{...getCommonProps()}
dontNotifyForMentionsIfMuted
/>
));

0 comments on commit 6b290a0

Please sign in to comment.