diff --git a/app/constants/screens.ts b/app/constants/screens.ts index c1e0d53b8a..0475730aec 100644 --- a/app/constants/screens.ts +++ b/app/constants/screens.ts @@ -40,6 +40,7 @@ export const SEARCH = 'Search'; export const SELECT_TEAM = 'SelectTeam'; export const SERVER = 'Server'; export const SETTINGS = 'Settings'; +export const NOTIFICATION_SETTINGS = 'NotificationSettings'; export const SNACK_BAR = 'SnackBar'; export const SSO = 'SSO'; export const THREAD = 'Thread'; @@ -79,6 +80,7 @@ export default { LOGIN, MENTIONS, MFA, + NOTIFICATION_SETTINGS, PERMALINK, POST_OPTIONS, REACTIONS, diff --git a/app/screens/index.tsx b/app/screens/index.tsx index 5a28418e16..6407123746 100644 --- a/app/screens/index.tsx +++ b/app/screens/index.tsx @@ -185,6 +185,9 @@ Navigation.setLazyComponentRegistrator((screenName) => { case Screens.SETTINGS: screen = withServerDatabase(require('@screens/settings').default); break; + case Screens.NOTIFICATION_SETTINGS: + screen = withServerDatabase(require('@screens/settings/notifications').default); + break; } if (screen) { diff --git a/app/screens/settings/constant.ts b/app/screens/settings/constant.ts index cc5ca275c8..6610872ceb 100644 --- a/app/screens/settings/constant.ts +++ b/app/screens/settings/constant.ts @@ -35,3 +35,27 @@ export const SettingOptionConfig = { showArrow: false, }, }; + +export const NotificationsOptionConfig = { + mentions: { + iconName: 'at', + testID: 'notification_settings.mentions_replies.action', + }, + push_notification: { + defaultMessage: 'Push Notifications', + i18nId: t('mobile.notification_settings.mobile'), + iconName: 'cellphone', + testID: 'notification_settings.push_notification', + }, + automatic_dm_replies: { + defaultMessage: 'Automatic Direct Message Replies', + i18nId: t('mobile.notification_settings.ooo_auto_responder'), + iconName: 'reply-outline', + testID: 'notification_settings.automatic_dm_replies', + }, +}; + +export default { + ...SettingOptionConfig, + ...NotificationsOptionConfig, +}; diff --git a/app/screens/settings/index.tsx b/app/screens/settings/index.tsx index dfca8eaff5..bc87a39c91 100644 --- a/app/screens/settings/index.tsx +++ b/app/screens/settings/index.tsx @@ -6,7 +6,7 @@ import withObservables from '@nozbe/with-observables'; import {of as of$} from 'rxjs'; import {switchMap} from 'rxjs/operators'; -import {observeConfig} from '@queries/servers/system'; +import {observeConfigValue} from '@queries/servers/system'; import {isValidUrl} from '@utils/url'; import Settings from './settings'; @@ -14,9 +14,8 @@ import Settings from './settings'; import type {WithDatabaseArgs} from '@typings/database/database'; const enhanced = withObservables([], ({database}: WithDatabaseArgs) => { - const config = observeConfig(database); - const siteName = config.pipe(switchMap((c) => of$(c?.SiteName))); - const showHelp = observeConfig(database).pipe(switchMap((c) => of$(c?.HelpLink ? isValidUrl(c.HelpLink) : false))); + const siteName = observeConfigValue(database, 'SiteName'); + const showHelp = observeConfigValue(database, 'HelpLink').pipe(switchMap((link) => of$(link ? isValidUrl(link) : false))); return { showHelp, diff --git a/app/screens/settings/notifications/index.tsx b/app/screens/settings/notifications/index.tsx new file mode 100644 index 0000000000..547ce268cf --- /dev/null +++ b/app/screens/settings/notifications/index.tsx @@ -0,0 +1,22 @@ +// 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 {observeConfigBooleanValue} from '@queries/servers/system'; +import {observeIsCRTEnabled} from '@queries/servers/thread'; +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, + }; +}); + +export default withDatabase(enhanced(NotificationSettings)); diff --git a/app/screens/settings/notifications/notifications.tsx b/app/screens/settings/notifications/notifications.tsx new file mode 100644 index 0000000000..b6f5e76b9b --- /dev/null +++ b/app/screens/settings/notifications/notifications.tsx @@ -0,0 +1,91 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React from 'react'; +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 {useTheme} from '@context/theme'; +import {t} from '@i18n'; +import SettingOption from '@screens/settings/setting_option'; + +const getStyleSheet = makeStyleSheetFromTheme((theme) => { + return { + container: { + flex: 1, + backgroundColor: theme.centerChannelBg, + }, + wrapper: { + backgroundColor: changeOpacity(theme.centerChannelColor, 0.06), + ...Platform.select({ + ios: { + flex: 1, + paddingTop: 35, + }, + }), + }, + divider: { + backgroundColor: changeOpacity(theme.centerChannelColor, 0.1), + height: 1, + width: '100%', + }, + }; +}); +const edges: Edge[] = ['left', 'right']; + +type NotificationsProps = { + isCRTEnabled: boolean; + enableAutoResponder: boolean; +} +const Notifications = ({isCRTEnabled, enableAutoResponder}: NotificationsProps) => { + const theme = useTheme(); + const styles = getStyleSheet(theme); + + let mentionsI18nId = t('mobile.notification_settings.mentions_replies'); + let mentionsI18nDefault = 'Mentions and Replies'; + if (isCRTEnabled) { + mentionsI18nId = t('mobile.notification_settings.mentions'); + mentionsI18nDefault = 'Mentions'; + } + + const onPressHandler = () => { + return Alert.alert( + 'The functionality you are trying to use has not yet been implemented.', + ); + }; + + return ( + + + + + + {enableAutoResponder && ( + + )} + + + + ); +}; + +export default Notifications; diff --git a/app/screens/settings/setting_option.tsx b/app/screens/settings/setting_option.tsx index 57dbb788ec..78928b16ae 100644 --- a/app/screens/settings/setting_option.tsx +++ b/app/screens/settings/setting_option.tsx @@ -9,10 +9,11 @@ import {useTheme} from '@context/theme'; import {makeStyleSheetFromTheme} from '@utils/theme'; import {typography} from '@utils/typography'; -import {SettingOptionConfig} from './constant'; +import Options, {NotificationsOptionConfig, SettingOptionConfig} from './constant'; -type Props = { - type: 'notification' | 'display' | 'advanced_settings' | 'about' | 'help'; +type SettingsConfig = keyof typeof SettingOptionConfig | keyof typeof NotificationsOptionConfig +type SettingOptionProps = { + optionName: SettingsConfig; onPress: () => void; } & Omit; @@ -25,11 +26,10 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { }; }); -const SettingOption = ({type, onPress, ...rest}: Props) => { +const SettingOption = ({onPress, optionName, ...rest}: SettingOptionProps) => { const theme = useTheme(); const styles = getStyleSheet(theme); - const optionConfig = SettingOptionConfig[type]; - const options = {...optionConfig, ...rest}; + const props = {...rest, ...Options[optionName]} as unknown as Omit; return ( { separator={true} showArrow={Platform.select({ios: true, default: false})} theme={theme} - {...options} + {...props} /> ); }; diff --git a/app/screens/settings/settings.tsx b/app/screens/settings/settings.tsx index 10c97b7aba..b17bcd0ff0 100644 --- a/app/screens/settings/settings.tsx +++ b/app/screens/settings/settings.tsx @@ -121,6 +121,13 @@ const Settings = ({componentId, showHelp, siteName}: SettingsProps) => { ); }; + const goToNotifications = preventDoubleTap(() => { + const screen = 'NotificationSettings'; + const title = intl.formatMessage({id: 'user.settings.modal.notifications', defaultMessage: 'Notifications'}); + + goToScreen(screen, title); + }); + const goToAbout = preventDoubleTap(() => { const screen = Screens.ABOUT; const title = intl.formatMessage({id: 'about.title', defaultMessage: 'About {appTitle}'}, {appTitle: serverName}); @@ -148,19 +155,19 @@ const Settings = ({componentId, showHelp, siteName}: SettingsProps) => { style={styles.group} > + - { > {showHelp &&