// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. import React from 'react'; import {injectIntl} from 'react-intl'; import { Alert, Modal, Platform, ScrollView, Text, TouchableOpacity, View, } from 'react-native'; import deepEqual from 'deep-equal'; import PropTypes from 'prop-types'; import {RequestStatus} from '@mm-redux/constants'; import FormattedText from 'app/components/formatted_text'; import RadioButtonGroup from 'app/components/radio_button'; import NotificationPreferences from 'app/notification_preferences'; import PushNotifications from 'app/push_notifications'; import StatusBar from 'app/components/status_bar'; import SectionItem from 'app/screens/settings/section_item'; import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme'; import {getNotificationProps} from 'app/utils/notify_props'; import NotificationSettingsMobileBase from './notification_settings_mobile_base'; class NotificationSettingsMobileAndroid extends NotificationSettingsMobileBase { static propTypes = { ...NotificationSettingsMobileBase.propTypes, updateMeRequest: PropTypes.object.isRequired, } static defaultProps = { currentUser: {}, } cancelMobilePushModal = () => { this.setState({ newPush: this.state.push, showMobilePushModal: false, }); }; cancelMobilePushStatusModal = () => { this.setState({ newPushStatus: this.state.push_status, showMobilePushStatusModal: false, }); }; cancelMobileSoundsModal = () => { this.setState({ newSound: this.state.selectedUri, showMobileSoundsModal: false, }); }; onMobilePushChanged = (value) => { this.setState({newPush: value}); }; onMobilePushStatusChanged = (value) => { this.setState({newPushStatus: value}); }; onMobileSoundChanged = (value) => { this.setState({newSound: value}); if (value && value !== 'none') { NotificationPreferences.play(value); } }; renderMobileBlinkSection(style) { const {config, theme} = this.props; const {shouldBlink} = this.state; const showSection = config.SendPushNotifications === 'true' && this.state.push !== 'none'; if (!showSection) { return null; } return ( )} action={this.toggleBlink} actionType='toggle' selected={shouldBlink} theme={theme} /> ); } renderMobilePushModal(style) { const {config, intl} = this.props; const pushNotificationsEnabled = config.SendPushNotifications === 'true'; const {newPush} = this.state; const options = [{ label: intl.formatMessage({ id: 'user.settings.notifications.allActivity', defaultMessage: 'For all activity', }), value: 'all', checked: newPush === 'all', }, { label: intl.formatMessage({ id: 'user.settings.notifications.onlyMentions', defaultMessage: 'Only for mentions and direct messages', }), value: 'mention', checked: newPush === 'mention', }, { label: intl.formatMessage({ id: 'user.settings.notifications.never', defaultMessage: 'Never', }), value: 'none', checked: newPush === 'none', }]; return ( {pushNotificationsEnabled && } {!pushNotificationsEnabled && } {pushNotificationsEnabled && } ); } renderMobilePushStatusModal(style) { const {intl} = this.props; const {newPushStatus} = this.state; const options = [{ label: intl.formatMessage({ id: 'user.settings.push_notification.online', defaultMessage: 'Online, away or offline', }), value: 'online', checked: newPushStatus === 'online', }, { label: intl.formatMessage({ id: 'user.settings.push_notification.away', defaultMessage: 'Away or offline', }), value: 'away', checked: newPushStatus === 'away', }, { label: intl.formatMessage({ id: 'user.settings.push_notification.offline', defaultMessage: 'Offline', }), value: 'offline', checked: newPushStatus === 'offline', }]; return ( ); } renderMobileSoundsModal(style) { const {defaultSound, newSound} = this.state; const {intl, notificationPreferences} = this.props; const {defaultUri, sounds} = notificationPreferences; const soundsArray = [{ label: intl.formatMessage({ id: 'mobile.notification_settings_mobile.default_sound', defaultMessage: 'Default ({sound})', }, {sound: defaultSound}), value: defaultUri, checked: newSound === null, }, { label: intl.formatMessage({ id: 'mobile.notification_settings_mobile.no_sound', defaultMessage: 'None', }), value: 'none', checked: newSound === 'none', }]; if (sounds && sounds.length) { const filteredSounds = sounds.filter((s) => s.uri !== defaultUri).map((s) => { return { label: s.name, value: s.uri, checked: s.uri === newSound, }; }); soundsArray.push(...filteredSounds); } return ( ); } componentDidUpdate(prevProps) { const {updateMeRequest, intl} = this.props; if (updateMeRequest !== prevProps.updateMeRequest && updateMeRequest.status === RequestStatus.FAILURE) { Alert.alert( intl.formatMessage({ id: 'mobile.notification_settings.save_failed_title', defaultMessage: 'Connection issue', }), intl.formatMessage({ id: 'mobile.notification_settings.save_failed_description', defaultMessage: 'The notification settings failed to save due to a connection issue, please try again.', }), ); } } renderMobilePushSection() { const {config, theme} = this.props; const pushNotificationsEnabled = config.SendPushNotifications === 'true'; let i18nId; let i18nMessage; const props = {}; if (pushNotificationsEnabled) { switch (this.state.push) { case 'all': i18nId = 'user.settings.notifications.allActivity'; i18nMessage = 'For all activity'; break; case 'none': i18nId = 'user.settings.notifications.never'; i18nMessage = 'Never'; break; case 'mention': default: i18nId = 'user.settings.notifications.onlyMentions'; i18nMessage = 'Only for mentions and direct messages'; break; } props.description = ( ); } else { props.description = ( ); } return ( )} action={this.showMobilePushModal} actionType='default' theme={theme} /> ); } renderMobilePushStatusSection(style) { const {config, theme} = this.props; const showSection = config.SendPushNotifications === 'true' && this.state.push !== 'none'; if (!showSection) { return null; } let i18nId; let i18nMessage; switch (this.state.push_status) { case 'away': i18nId = 'user.settings.push_notification.away'; i18nMessage = 'Away or offline'; break; case 'offline': i18nId = 'user.settings.push_notification.offline'; i18nMessage = 'Offline'; break; case 'online': default: i18nId = 'user.settings.push_notification.online'; i18nMessage = 'Online, away or offline'; break; } return ( )} label={( )} action={this.showMobilePushStatusModal} actionType='default' theme={theme} /> ); } renderMobileSoundSection(style) { const {config, theme} = this.props; const {defaultSound, sound} = this.state; const showSection = config.SendPushNotifications === 'true' && this.state.push !== 'none'; if (!showSection) { return null; } let description; if (sound === 'none') { description = ( ); } else if (sound) { description = ( {sound} ); } else { description = ( ); } return ( )} action={this.showMobileSoundsModal} actionType='default' theme={theme} /> ); } renderMobileTestSection(style) { const {config, theme} = this.props; const showSection = config.SendPushNotifications === 'true' && this.state.push !== 'none'; if (!showSection) { return null; } return ( )} action={this.sendTestNotification} actionType='default' theme={theme} /> ); } renderMobileVibrateSection(style) { const {config, theme} = this.props; const {shouldVibrate} = this.state; const showSection = config.SendPushNotifications === 'true' && this.state.push !== 'none'; if (!showSection) { return null; } return ( )} action={this.toggleVibrate} actionType='toggle' selected={shouldVibrate} theme={theme} /> ); } renderNotificationOptions(style) { if (Platform.Version >= 26) { return null; } return ( {this.renderMobileSoundSection(style)} {this.renderMobileVibrateSection(style)} {this.renderMobileBlinkSection(style)} ); } saveMobilePushModal = () => { this.setState({showMobilePushModal: false}); this.setMobilePush(this.state.newPush, this.saveNotificationProps); }; saveMobilePushStatusModal = () => { this.setState({showMobilePushStatusModal: false}); this.setMobilePushStatus(this.state.newPushStatus, this.saveNotificationProps); }; saveNotificationProps = () => { const { channel, comments, desktop, email, first_name: firstName, mention_keys: mentionKeys, push, push_status: pushStatus, } = this.state; const {currentUser} = this.props; const notifyProps = { channel, comments, desktop, email, first_name: firstName, mention_keys: mentionKeys, push, push_status: pushStatus, user_id: currentUser.id, }; const {user_id: userId} = notifyProps; const previousProps = { ...getNotificationProps(currentUser), user_id: userId, }; if (!deepEqual(previousProps, notifyProps)) { this.props.actions.updateMe({notify_props: notifyProps}); } }; saveMobileSoundsModal = () => { const {defaultSound, newSound} = this.state; const {intl, notificationPreferences} = this.props; const {defaultUri, sounds} = notificationPreferences; let sound; let selectedUri = null; if (newSound === defaultUri) { sound = defaultSound; } else if (newSound === 'none') { selectedUri = 'none'; sound = intl.formatMessage({ id: 'mobile.notification_settings_mobile.no_sound', defaultMessage: 'None', }); } else { selectedUri = newSound; const selected = sounds.find((s) => s.uri === selectedUri); sound = selected ? selected.name : 'none'; } NotificationPreferences.setNotificationSound(selectedUri); this.setState({selectedUri, sound, showMobileSoundsModal: false}); }; sendTestNotification = () => { const {intl} = this.props; PushNotifications.localNotification({ message: intl.formatMessage({ id: 'mobile.notification_settings_mobile.test_push', defaultMessage: 'This is a test push notification', }), userInfo: { localNotification: true, localTest: true, }, }); }; showMobilePushModal = () => { this.setState({showMobilePushModal: true}); }; showMobilePushStatusModal = () => { this.setState({showMobilePushStatusModal: true}); }; showMobileSoundsModal = () => { this.setState({showMobileSoundsModal: true}); }; toggleBlink = () => { NotificationPreferences.setShouldBlink(!this.state.shouldBlink); this.setState({shouldBlink: !this.state.shouldBlink}); }; toggleVibrate = () => { NotificationPreferences.setShouldVibrate(!this.state.shouldVibrate); this.setState({shouldVibrate: !this.state.shouldVibrate}); }; render() { const {theme} = this.props; const style = getStyleSheet(theme); return ( {this.renderMobilePushSection()} {this.renderMobilePushStatusSection(style)} {this.renderNotificationOptions(style)} {this.renderMobileTestSection(style)} {this.renderMobilePushModal(style)} {this.renderMobilePushStatusModal(style)} {this.renderMobileSoundsModal(style)} ); } } const getStyleSheet = makeStyleSheetFromTheme((theme) => { return { container: { flex: 1, }, input: { color: theme.centerChannelColor, fontSize: 12, height: 40, }, separator: { backgroundColor: changeOpacity(theme.centerChannelColor, 0.1), height: 1, width: '100%', }, scrollView: { flex: 1, backgroundColor: changeOpacity(theme.centerChannelColor, 0.06), }, scrollViewContent: { paddingVertical: 0, }, modalOverlay: { backgroundColor: changeOpacity('#000000', 0.6), alignItems: 'center', flex: 1, }, modal: { backgroundColor: theme.centerChannelBg, borderRadius: 4, marginTop: 20, width: '95%', }, modalBody: { maxHeight: '80%', paddingHorizontal: 24, }, modalTitleContainer: { marginBottom: 30, marginTop: 20, }, modalTitle: { color: theme.centerChannelColor, fontSize: 19, }, modalOptionDisabled: { color: changeOpacity(theme.centerChannelColor, 0.5), fontSize: 17, }, modalFooter: { alignItems: 'flex-end', height: 58, marginTop: 40, width: '100%', }, modalFooterContainer: { alignItems: 'center', flex: 1, flexDirection: 'row', paddingRight: 24, }, modalFooterOptionContainer: { alignItems: 'center', height: 40, justifyContent: 'center', paddingHorizontal: 10, paddingVertical: 5, }, modalFooterOption: { color: theme.linkColor, fontSize: 14, }, }; }); export default injectIntl(NotificationSettingsMobileAndroid);