From b5038ba55e01caa7c6aae6705fa1f9ecad5a8379 Mon Sep 17 00:00:00 2001 From: Avinash Lingaloo Date: Thu, 26 May 2022 17:25:03 +0400 Subject: [PATCH] MM-39711 - Gekidou Notification Mention main screen (#6309) * added chevron to menu item component * starting with the skeleton * starting with the skeleton * starting with the skeleton * starting with the skeleton * remove extra line * tested on tablets * some corrections * corrections as per review * starting with notification skeleton * attached notification settings to navigation * added auto responder * update translation * update snapshot * updated snapshot * correction after review * removed unnecessary screen * refactored * updated the testIDs * Update Package.resolved * refactor * removed Mattermost as default server name * fix ts * refactored settings constant * display settings skeleton - pending: query for allowed themes * added 'allowedThemes' query * added section item * mention screen skeleton in place * added section and sectionItem component * added reply section to the mention screen * update i18n * rename screens properly * update i18n * Refactored to MentionSettings component * Refactored to ReplySettings component * style clean up * textTransform uppercase * rename Section/SectionItem to Block/BlockItem * adding text to those two components * correction following review --- app/components/{section => block}/index.tsx | 20 +- .../{section_item => block_item}/index.tsx | 4 +- app/constants/screens.ts | 12 +- .../channel_info_form.tsx | 4 +- app/screens/index.tsx | 9 +- app/screens/settings/constant.ts | 2 +- .../settings/notification_mention/index.tsx | 20 ++ .../notification_mention/mention_settings.tsx | 198 ++++++++++++++++++ .../notification_mention.tsx | 70 +++++++ .../notification_mention/reply_settings.tsx | 103 +++++++++ app/screens/settings/notifications/index.tsx | 6 +- .../settings/notifications/notifications.tsx | 20 +- app/screens/settings/settings.tsx | 10 +- assets/base/i18n/en.json | 20 +- 14 files changed, 460 insertions(+), 38 deletions(-) rename app/components/{section => block}/index.tsx (82%) rename app/components/{section_item => block_item}/index.tsx (96%) create mode 100644 app/screens/settings/notification_mention/index.tsx create mode 100644 app/screens/settings/notification_mention/mention_settings.tsx create mode 100644 app/screens/settings/notification_mention/notification_mention.tsx create mode 100644 app/screens/settings/notification_mention/reply_settings.tsx diff --git a/app/components/section/index.tsx b/app/components/block/index.tsx similarity index 82% rename from app/components/section/index.tsx rename to app/components/block/index.tsx index 84d736624..051c189f6 100644 --- a/app/components/section/index.tsx +++ b/app/components/block/index.tsx @@ -3,7 +3,7 @@ import {MessageDescriptor} from '@formatjs/intl/src/types'; import React from 'react'; -import {StyleProp, View, ViewStyle} from 'react-native'; +import {StyleProp, TextStyle, View, ViewStyle} from 'react-native'; import FormattedText from '@components/formatted_text'; import {useTheme} from '@context/theme'; @@ -49,37 +49,41 @@ type SectionProps = { footerText?: SectionText; headerText: SectionText; containerStyles?: StyleProp; + headerStyles?: StyleProp; + footerStyles?: StyleProp; } -const Section = ({ +const Block = ({ children, containerStyles, disableFooter, disableHeader, footerText, + headerStyles, headerText, + footerStyles, }: SectionProps) => { const theme = useTheme(); - const style = getStyleSheet(theme); + const styles = getStyleSheet(theme); return ( - + {(headerText && !disableHeader) && } - + {children} {(footerText && !disableFooter) && } @@ -87,4 +91,4 @@ const Section = ({ ); }; -export default Section; +export default Block; diff --git a/app/components/section_item/index.tsx b/app/components/block_item/index.tsx similarity index 96% rename from app/components/section_item/index.tsx rename to app/components/block_item/index.tsx index 95eab0eeb..1545e0311 100644 --- a/app/components/section_item/index.tsx +++ b/app/components/block_item/index.tsx @@ -69,7 +69,7 @@ type Props = { testID?: string; } -const SectionItem = ({testID = 'sectionItem', action, actionType, actionValue, label, selected, description, icon}: Props) => { +const BlockItem = ({testID = 'sectionItem', action, actionType, actionValue, label, selected, description, icon}: Props) => { const theme = useTheme(); const style = getStyleSheet(theme); @@ -154,4 +154,4 @@ const SectionItem = ({testID = 'sectionItem', action, actionType, actionValue, l return component; }; -export default SectionItem; +export default BlockItem; diff --git a/app/constants/screens.ts b/app/constants/screens.ts index 45878baaa..5078e8203 100644 --- a/app/constants/screens.ts +++ b/app/constants/screens.ts @@ -8,15 +8,14 @@ export const BOTTOM_SHEET = 'BottomSheet'; export const BROWSE_CHANNELS = 'BrowseChannels'; export const CHANNEL = 'Channel'; export const CHANNEL_ADD_PEOPLE = 'ChannelAddPeople'; -export const CHANNEL_INFO = 'ChannelInfo'; export const CHANNEL_EDIT = 'ChannelEdit'; +export const CHANNEL_INFO = 'ChannelInfo'; export const CODE = 'Code'; export const CREATE_DIRECT_MESSAGE = 'CreateDirectMessage'; export const CREATE_OR_EDIT_CHANNEL = 'CreateOrEditChannel'; export const CREATE_TEAM = 'CreateTeam'; export const CUSTOM_STATUS = 'CustomStatus'; export const CUSTOM_STATUS_CLEAR_AFTER = 'CustomStatusClearAfter'; -export const DISPLAY_SETTINGS = 'DisplaySettings'; export const EDIT_POST = 'EditPost'; export const EDIT_PROFILE = 'EditProfile'; export const EDIT_SERVER = 'EditServer'; @@ -33,7 +32,6 @@ export const LATEX = 'Latex'; export const LOGIN = 'Login'; export const MENTIONS = 'Mentions'; export const MFA = 'MFA'; -export const NOTIFICATION_SETTINGS = 'NotificationSettings'; export const PERMALINK = 'Permalink'; export const POST_OPTIONS = 'PostOptions'; export const REACTIONS = 'Reactions'; @@ -42,6 +40,9 @@ export const SEARCH = 'Search'; export const SELECT_TEAM = 'SelectTeam'; export const SERVER = 'Server'; export const SETTINGS = 'Settings'; +export const SETTINGS_DISPLAY = 'SettingsDisplay'; +export const SETTINGS_NOTIFICATION = 'SettingsNotification'; +export const SETTINGS_NOTIFICATION_MENTION = 'SettingsNotificationMention'; export const SNACK_BAR = 'SnackBar'; export const SSO = 'SSO'; export const THREAD = 'Thread'; @@ -65,7 +66,6 @@ export default { CREATE_TEAM, CUSTOM_STATUS, CUSTOM_STATUS_CLEAR_AFTER, - DISPLAY_SETTINGS, EDIT_POST, EDIT_PROFILE, EDIT_SERVER, @@ -82,7 +82,6 @@ export default { LOGIN, MENTIONS, MFA, - NOTIFICATION_SETTINGS, PERMALINK, POST_OPTIONS, REACTIONS, @@ -91,6 +90,9 @@ export default { SELECT_TEAM, SERVER, SETTINGS, + SETTINGS_DISPLAY, + SETTINGS_NOTIFICATION, + SETTINGS_NOTIFICATION_MENTION, SNACK_BAR, SSO, THREAD, diff --git a/app/screens/create_or_edit_channel/channel_info_form.tsx b/app/screens/create_or_edit_channel/channel_info_form.tsx index 07816e7f6..1965f0ece 100644 --- a/app/screens/create_or_edit_channel/channel_info_form.tsx +++ b/app/screens/create_or_edit_channel/channel_info_form.tsx @@ -17,11 +17,11 @@ import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view'; import {SafeAreaView} from 'react-native-safe-area-context'; import Autocomplete from '@components/autocomplete'; +import BlockItem from '@components/block_item'; import ErrorText from '@components/error_text'; import FloatingTextInput from '@components/floating_text_input_label'; import FormattedText from '@components/formatted_text'; import Loading from '@components/loading'; -import SectionItem from '@components/section_item'; import {General, Channel} from '@constants'; import {useTheme} from '@context/theme'; import {useIsTablet} from '@hooks/device'; @@ -246,7 +246,7 @@ export default function ChannelInfoForm({ > {showSelector && ( - { case Screens.SETTINGS: screen = withServerDatabase(require('@screens/settings').default); break; - case Screens.NOTIFICATION_SETTINGS: + case Screens.SETTINGS_DISPLAY: + screen = withServerDatabase(require('@screens/settings/display').default); + break; + case Screens.SETTINGS_NOTIFICATION: screen = withServerDatabase(require('@screens/settings/notifications').default); break; - case Screens.DISPLAY_SETTINGS: - screen = withServerDatabase(require('@screens/settings/display').default); + case Screens.SETTINGS_NOTIFICATION_MENTION: + screen = withServerDatabase(require('@screens/settings/notification_mention').default); break; } diff --git a/app/screens/settings/constant.ts b/app/screens/settings/constant.ts index 868dc1285..ed59467df 100644 --- a/app/screens/settings/constant.ts +++ b/app/screens/settings/constant.ts @@ -39,7 +39,7 @@ export const SettingOptionConfig = { export const NotificationsOptionConfig = { mentions: { iconName: 'at', - testID: 'notification_settings.mentions_replies.action', + testID: 'notification_settings.mentions_replies', }, push_notification: { defaultMessage: 'Push Notifications', diff --git a/app/screens/settings/notification_mention/index.tsx b/app/screens/settings/notification_mention/index.tsx new file mode 100644 index 000000000..07e15a990 --- /dev/null +++ b/app/screens/settings/notification_mention/index.tsx @@ -0,0 +1,20 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider'; +import withObservables from '@nozbe/with-observables'; + +import {observeIsCRTEnabled} from '@queries/servers/thread'; +import {observeCurrentUser} from '@queries/servers/user'; +import {WithDatabaseArgs} from '@typings/database/database'; + +import Mentions from './notification_mention'; + +const enhanced = withObservables([], ({database}: WithDatabaseArgs) => { + return { + isCRTEnabled: observeIsCRTEnabled(database), + currentUser: observeCurrentUser(database), + }; +}); + +export default withDatabase(enhanced(Mentions)); diff --git a/app/screens/settings/notification_mention/mention_settings.tsx b/app/screens/settings/notification_mention/mention_settings.tsx new file mode 100644 index 000000000..1516062b5 --- /dev/null +++ b/app/screens/settings/notification_mention/mention_settings.tsx @@ -0,0 +1,198 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React, {useReducer} from 'react'; +import {Alert, Text, View} from 'react-native'; + +import Block from '@components/block'; +import BlockItem from '@components/block_item'; +import FormattedText from '@components/formatted_text'; +import {useTheme} from '@context/theme'; +import {t} from '@i18n'; +import UserModel from '@typings/database/models/servers/user'; +import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; +import {typography} from '@utils/typography'; + +const UPDATE_MENTION_PREF = 'UPDATE_MENTION_PREF'; +const INITIAL_STATE = { + firstName: false, + usernameMention: false, + channel: false, +}; +type Action = { + type: string; + data: Partial; +} +const reducer = (state: typeof INITIAL_STATE, action: Action) => { + switch (action.type) { + case UPDATE_MENTION_PREF: + return { + ...state, + ...action.data, + }; + + default: + return state; + } +}; + +const mentionHeaderText = { + id: t('notification_settings.mentions.wordsTrigger'), + defaultMessage: 'Words that trigger mentions', +}; + +const getStyleSheet = makeStyleSheetFromTheme((theme) => { + return { + separator: { + backgroundColor: changeOpacity(theme.centerChannelColor, 0.1), + flex: 1, + height: 1, + marginLeft: 15, + }, + area: { + paddingHorizontal: 16, + }, + upperCase: { + textTransform: 'uppercase', + }, + label: { + color: theme.centerChannelColor, + ...typography('Body', 400, 'Regular'), + fontSize: 16, + lineHeight: 24, + }, + }; +}); + +type MentionSectionProps = { + currentUser?: UserModel; + mentionKeys: string; +} +const MentionSettings = ({currentUser, mentionKeys}: MentionSectionProps) => { + const [{firstName, usernameMention, channel}, dispatch] = useReducer(reducer, INITIAL_STATE); + const theme = useTheme(); + const styles = getStyleSheet(theme); + + let mentionKeysComponent; + if (mentionKeys) { + mentionKeysComponent = ({mentionKeys}); + } else { + mentionKeysComponent = ( + + ); + } + + const toggleChannelMentions = () => { + dispatch({ + type: UPDATE_MENTION_PREF, + data: { + channel: !channel, + }, + }); + }; + const toggleUsernameMention = () => { + dispatch({ + type: UPDATE_MENTION_PREF, + data: { + usernameMention: !usernameMention, + }, + }); + }; + const toggleFirstNameMention = () => { + dispatch({ + type: UPDATE_MENTION_PREF, + data: { + firstName: !firstName, + }, + }); + }; + const goToNotificationSettingsMentionKeywords = () => { + return Alert.alert( + 'The functionality you are trying to use has not yet been implemented.', + ); + }; + + return ( + + { Boolean(currentUser?.firstName) && ( + <> + + {currentUser!.firstName} + + )} + description={( + + )} + action={toggleFirstNameMention} + actionType='toggle' + selected={firstName} + /> + + + ) + } + {Boolean(currentUser?.username) && ( + + {currentUser!.username} + + )} + description={( + + )} + selected={usernameMention} + action={toggleUsernameMention} + actionType='toggle' + /> + )} + + + {'@channel, @all, @here'} + + )} + description={( + + )} + action={toggleChannelMentions} + actionType='toggle' + selected={channel} + /> + + + )} + description={mentionKeysComponent} + action={goToNotificationSettingsMentionKeywords} + actionType='arrow' + /> + + ); +}; + +export default MentionSettings; diff --git a/app/screens/settings/notification_mention/notification_mention.tsx b/app/screens/settings/notification_mention/notification_mention.tsx new file mode 100644 index 000000000..28eed27db --- /dev/null +++ b/app/screens/settings/notification_mention/notification_mention.tsx @@ -0,0 +1,70 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React from 'react'; +import {ScrollView} from 'react-native'; +import {SafeAreaView} from 'react-native-safe-area-context'; + +import {useTheme} from '@context/theme'; +import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; + +import MentionSettings from './mention_settings'; +import ReplySettings from './reply_settings'; + +import type UserModel from '@typings/database/models/servers/user'; + +const getStyleSheet = makeStyleSheetFromTheme((theme) => { + return { + container: { + flex: 1, + backgroundColor: theme.centerChannelBg, + }, + input: { + color: theme.centerChannelColor, + fontSize: 12, + height: 40, + }, + scrollView: { + flex: 1, + backgroundColor: changeOpacity(theme.centerChannelColor, 0.06), + }, + scrollViewContent: { + paddingVertical: 35, + }, + }; +}); + +type NotificationMentionProps = { + isCRTEnabled?: boolean; + currentUser?: UserModel; + mentionKeys: string; +} +const NotificationMention = ({currentUser, mentionKeys, isCRTEnabled}: NotificationMentionProps) => { + const theme = useTheme(); + const styles = getStyleSheet(theme); + + return ( + + + + {!isCRTEnabled && ( + + )} + + + ); +}; + +export default NotificationMention; + diff --git a/app/screens/settings/notification_mention/reply_settings.tsx b/app/screens/settings/notification_mention/reply_settings.tsx new file mode 100644 index 000000000..b11bbea36 --- /dev/null +++ b/app/screens/settings/notification_mention/reply_settings.tsx @@ -0,0 +1,103 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React, {useState} from 'react'; +import {View} from 'react-native'; + +import Block from '@components/block'; +import BlockItem from '@components/block_item'; +import FormattedText from '@components/formatted_text'; +import {useTheme} from '@context/theme'; +import {t} from '@i18n'; +import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; +import {typography} from '@utils/typography'; + +const replyHeaderText = { + id: t('notification_settings.mention.reply'), + defaultMessage: 'Send reply notifications for', +}; + +const getStyleSheet = makeStyleSheetFromTheme((theme) => { + return { + area: { + paddingHorizontal: 16, + }, + separator: { + backgroundColor: changeOpacity(theme.centerChannelColor, 0.1), + flex: 1, + height: 1, + marginLeft: 15, + }, + upperCase: { + textTransform: 'uppercase', + }, + label: { + color: theme.centerChannelColor, + ...typography('Body', 400, 'Regular'), + fontSize: 16, + lineHeight: 24, + }, + }; +}); + +const ReplySettings = () => { + const [replyNotificationType, setReplyNotificationType] = useState('any'); //todo: initialize with value from db/api + const theme = useTheme(); + const styles = getStyleSheet(theme); + + const setReplyNotifications = (notifType: string) => { + setReplyNotificationType(notifType); + }; + + return ( + + + )} + action={setReplyNotifications} + actionType='select' + actionValue='any' + selected={replyNotificationType === 'any'} + /> + + + )} + action={setReplyNotifications} + actionType='select' + actionValue='root' + selected={replyNotificationType === 'root'} + /> + + + )} + action={setReplyNotifications} + actionType='select' + actionValue='never' + selected={replyNotificationType === 'never'} + /> + + ); +}; + +export default ReplySettings; diff --git a/app/screens/settings/notifications/index.tsx b/app/screens/settings/notifications/index.tsx index 547ce268c..e2bd616f5 100644 --- a/app/screens/settings/notifications/index.tsx +++ b/app/screens/settings/notifications/index.tsx @@ -11,11 +11,9 @@ import {WithDatabaseArgs} from '@typings/database/database'; import NotificationSettings from './notifications'; const enhanced = withObservables([], ({database}: WithDatabaseArgs) => { - const isCRTEnabled = observeIsCRTEnabled(database); - const enableAutoResponder = observeConfigBooleanValue(database, 'ExperimentalEnableAutomaticReplies'); return { - isCRTEnabled, - enableAutoResponder, + isCRTEnabled: observeIsCRTEnabled(database), + enableAutoResponder: observeConfigBooleanValue(database, 'ExperimentalEnableAutomaticReplies'), }; }); diff --git a/app/screens/settings/notifications/notifications.tsx b/app/screens/settings/notifications/notifications.tsx index b6f5e76b9..f0ebdff83 100644 --- a/app/screens/settings/notifications/notifications.tsx +++ b/app/screens/settings/notifications/notifications.tsx @@ -2,12 +2,15 @@ // See LICENSE.txt for license information. import React from 'react'; +import {useIntl} from 'react-intl'; import {Alert, Platform, ScrollView, View} from 'react-native'; import {Edge, SafeAreaView} from 'react-native-safe-area-context'; import {changeOpacity, makeStyleSheetFromTheme} from '@app/utils/theme'; +import {Screens} from '@constants'; import {useTheme} from '@context/theme'; import {t} from '@i18n'; +import {goToScreen} from '@screens/navigation'; import SettingOption from '@screens/settings/setting_option'; const getStyleSheet = makeStyleSheetFromTheme((theme) => { @@ -41,11 +44,12 @@ type NotificationsProps = { const Notifications = ({isCRTEnabled, enableAutoResponder}: NotificationsProps) => { const theme = useTheme(); const styles = getStyleSheet(theme); + const intl = useIntl(); - let mentionsI18nId = t('mobile.notification_settings.mentions_replies'); + let mentionsI18nId = t('notification_settings.mentions_replies'); let mentionsI18nDefault = 'Mentions and Replies'; if (isCRTEnabled) { - mentionsI18nId = t('mobile.notification_settings.mentions'); + mentionsI18nId = t('notification_settings.mentions'); mentionsI18nDefault = 'Mentions'; } @@ -55,6 +59,16 @@ const Notifications = ({isCRTEnabled, enableAutoResponder}: NotificationsProps) ); }; + const goToNotificationSettingsMentions = () => { + const screen = Screens.SETTINGS_NOTIFICATION_MENTION; + + const id = isCRTEnabled ? t('notification_settings.mentions') : t('notification_settings.mentions_replies'); + const defaultMessage = isCRTEnabled ? 'Mentions' : 'Mentions and Replies'; + const title = intl.formatMessage({id, defaultMessage}); + + goToScreen(screen, title); + }; + return ( { }; const goToNotifications = preventDoubleTap(() => { - const screen = Screens.NOTIFICATION_SETTINGS; - const title = intl.formatMessage({id: 'user.settings.notifications', defaultMessage: 'Notifications'}); + const screen = Screens.SETTINGS_NOTIFICATION; + const title = intl.formatMessage({id: 'settings.notifications', defaultMessage: 'Notifications'}); goToScreen(screen, title); }); const goToDisplaySettings = preventDoubleTap(() => { - const screen = Screens.DISPLAY_SETTINGS; - const title = intl.formatMessage({id: 'user.settings.display', defaultMessage: 'Display'}); + const screen = Screens.SETTINGS_DISPLAY; + const title = intl.formatMessage({id: 'settings.display', defaultMessage: 'Display'}); goToScreen(screen, title); }); const goToAbout = preventDoubleTap(() => { const screen = Screens.ABOUT; - const title = intl.formatMessage({id: 'about.title', defaultMessage: 'About {appTitle}'}, {appTitle: serverName}); + const title = intl.formatMessage({id: 'settings.about', defaultMessage: 'About {appTitle}'}, {appTitle: serverName}); goToScreen(screen, title); }); diff --git a/assets/base/i18n/en.json b/assets/base/i18n/en.json index c62209bb9..9e17f3743 100644 --- a/assets/base/i18n/en.json +++ b/assets/base/i18n/en.json @@ -9,7 +9,6 @@ "about.teamEditionSt": "All your team communication in one place, instantly searchable and accessible anywhere.", "about.teamEditiont0": "Team Edition", "about.teamEditiont1": "Enterprise Edition", - "about.title": "About {appTitle}", "account.logout": "Log out", "account.logout_from": "Log out of {serverName}", "account.saved_messages": "Saved Messages", @@ -409,8 +408,6 @@ "mobile.notice_mobile_link": "mobile apps", "mobile.notice_platform_link": "server", "mobile.notice_text": "Mattermost is made possible by the open source software used in our {platform} and {mobile}.", - "mobile.notification_settings.mentions": "Mentions", - "mobile.notification_settings.mentions_replies": "Mentions and Replies", "mobile.notification_settings.mobile": "Push Notifications", "mobile.notification_settings.ooo_auto_responder": "Automatic Direct Message Replies", "mobile.oauth.failed_to_login": "Your login attempt failed. Please try again.", @@ -523,6 +520,18 @@ "more_messages.text": "{count} new {count, plural, one {message} other {messages}}", "msg_typing.areTyping": "{users} and {last} are typing...", "msg_typing.isTyping": "{user} is typing...", + "notification_settings.mention.reply": "Send reply notifications for", + "notification_settings.mentions": "Mentions", + "notification_settings.mentions_replies": "Mentions and Replies", + "notification_settings.mentions.channelWide": "Channel-wide mentions", + "notification_settings.mentions.keywords": "Keywords", + "notification_settings.mentions.keywordsDescription": "Other words that trigger a mention", + "notification_settings.mentions.sensitiveName": "Your case sensitive first name", + "notification_settings.mentions.sensitiveUsername": "Your non-case sensitive username", + "notification_settings.mentions.wordsTrigger": "Words that trigger mentions", + "notification_settings.threads_mentions": "Mentions in threads", + "notification_settings.threads_start": "Threads that I start", + "notification_settings.threads_start_participate": "Threads that I start or participate in", "notification.message_not_found": "Message not found", "notification.not_channel_member": "This message belongs to a channel where you are not a member.", "notification.not_team_member": "This message belongs to a team where you are not a member.", @@ -586,6 +595,9 @@ "servers.login": "Log in", "servers.logout": "Log out", "servers.remove": "Remove", + "settings.about": "About {appTitle}", + "settings.display": "Display", + "settings.notifications": "Notifications", "snack.bar.favorited.channel": "This channel was favorited", "snack.bar.link.copied": "Link copied to clipboard", "snack.bar.message.copied": "Text copied to clipboard", @@ -632,7 +644,6 @@ "threads.unfollowThread": "Unfollow Thread", "user.edit_profile.email.auth_service": "Login occurs through {service}. Email cannot be updated. Email address used for notifications is {email}.", "user.edit_profile.email.web_client": "Email must be updated using a web client or desktop application.", - "user.settings.display": "Display", "user.settings.general.email": "Email", "user.settings.general.field_handled_externally": "Some fields below are handled through your login provider. If you want to change them, you’ll need to do so through your login provider.", "user.settings.general.firstName": "First Name", @@ -640,7 +651,6 @@ "user.settings.general.nickname": "Nickname", "user.settings.general.position": "Position", "user.settings.general.username": "Username", - "user.settings.notifications": "Notifications", "video.download": "Download video", "video.failed_description": "An error occurred while trying to play the video.\n", "video.failed_title": "Video playback failed",