import CookieManager from '@react-native-cookies/cookies'; import { StackNavigationOptions } from '@react-navigation/stack'; import FastImage from 'react-native-fast-image'; import React from 'react'; import { Linking, Share } from 'react-native'; import Clipboard from '@react-native-clipboard/clipboard'; import { connect } from 'react-redux'; import { appStart } from '../../actions/app'; import { logout } from '../../actions/login'; import { selectServerRequest } from '../../actions/server'; import { APP_STORE_LINK, FDROID_MARKET_LINK, LICENSE_LINK, PLAY_MARKET_LINK, isFDroidBuild, themes } from '../../lib/constants'; import * as HeaderButton from '../../containers/HeaderButton'; import * as List from '../../containers/List'; import SafeAreaView from '../../containers/SafeAreaView'; import StatusBar from '../../containers/StatusBar'; import { LISTENER } from '../../containers/Toast'; import { IApplicationState, IBaseScreen, IUser, RootEnum } from '../../definitions'; import I18n from '../../i18n'; import database from '../../lib/database'; import { IServer } from '../../reducers/server'; import { getUserSelector } from '../../selectors/login'; import { SettingsStackParamList } from '../../stacks/types'; import { withTheme } from '../../theme'; import { getDeviceModel, getReadableVersion, isAndroid } from '../../lib/methods/helpers'; import EventEmitter from '../../lib/methods/helpers/events'; import { showConfirmationAlert, showErrorAlert } from '../../lib/methods/helpers/info'; import { events, logEvent } from '../../lib/methods/helpers/log'; import openLink from '../../lib/methods/helpers/openLink'; import { onReviewPress } from '../../lib/methods/helpers/review'; import SidebarView from '../SidebarView'; import { clearCache } from '../../lib/methods'; import { Services } from '../../lib/services'; type TLogScreenName = 'SE_GO_LANGUAGE' | 'SE_GO_DEFAULTBROWSER' | 'SE_GO_THEME' | 'SE_GO_PROFILE' | 'SE_GO_SECURITYPRIVACY'; interface ISettingsViewProps extends IBaseScreen<SettingsStackParamList, 'SettingsView'> { server: IServer; user: IUser; } class SettingsView extends React.Component<ISettingsViewProps> { static navigationOptions = ({ navigation, isMasterDetail }: ISettingsViewProps): StackNavigationOptions => ({ headerLeft: () => isMasterDetail ? ( <HeaderButton.CloseModal navigation={navigation} testID='settings-view-close' /> ) : ( <HeaderButton.Drawer navigation={navigation} testID='settings-view-drawer' /> ), title: I18n.t('Settings') }); checkCookiesAndLogout = async () => { const { dispatch, user } = this.props; const db = database.servers; const usersCollection = db.get('users'); try { const userRecord = await usersCollection.find(user.id); if (userRecord.isFromWebView) { showConfirmationAlert({ title: I18n.t('Clear_cookies_alert'), message: I18n.t('Clear_cookies_desc'), confirmationText: I18n.t('Clear_cookies_yes'), dismissText: I18n.t('Clear_cookies_no'), onPress: async () => { await CookieManager.clearAll(true); dispatch(logout()); }, onCancel: () => { dispatch(logout()); } }); } else { dispatch(logout()); } } catch { // Do nothing: user not found } }; handleLogout = () => { logEvent(events.SE_LOG_OUT); showConfirmationAlert({ message: I18n.t('You_will_be_logged_out_of_this_application'), confirmationText: I18n.t('Logout'), onPress: this.checkCookiesAndLogout }); }; handleClearCache = () => { logEvent(events.SE_CLEAR_LOCAL_SERVER_CACHE); showConfirmationAlert({ message: I18n.t('This_will_clear_all_your_offline_data'), confirmationText: I18n.t('Clear'), onPress: async () => { const { server: { server }, dispatch } = this.props; dispatch(appStart({ root: RootEnum.ROOT_LOADING, text: I18n.t('Clear_cache_loading') })); await clearCache({ server }); await FastImage.clearMemoryCache(); await FastImage.clearDiskCache(); Services.disconnect(); dispatch(selectServerRequest(server)); } }); }; navigateToScreen = (screen: keyof SettingsStackParamList) => { const screenName = screen.replace('View', '').toUpperCase(); logEvent(events[`SE_GO_${screenName}` as TLogScreenName]); const { navigation } = this.props; navigation.navigate(screen); }; sendEmail = async () => { logEvent(events.SE_CONTACT_US); const subject = encodeURI('Rocket.Chat Mobile App Support'); const email = encodeURI('support@rocket.chat'); const description = encodeURI(` version: ${getReadableVersion} device: ${getDeviceModel} `); try { await Linking.openURL(`mailto:${email}?subject=${subject}&body=${description}`); } catch (e) { logEvent(events.SE_CONTACT_US_F); showErrorAlert(I18n.t('error-email-send-failed', { message: 'support@rocket.chat' })); } }; shareApp = () => { let message; if (isAndroid) { message = PLAY_MARKET_LINK; if (isFDroidBuild) { message = FDROID_MARKET_LINK; } } else { message = APP_STORE_LINK; } Share.share({ message }); }; copyServerVersion = () => { const { server: { version } } = this.props; const vers = version as string; logEvent(events.SE_COPY_SERVER_VERSION, { serverVersion: vers }); this.saveToClipboard(vers); }; copyAppVersion = () => { logEvent(events.SE_COPY_APP_VERSION, { appVersion: getReadableVersion }); this.saveToClipboard(getReadableVersion); }; saveToClipboard = async (content: string) => { await Clipboard.setString(content); EventEmitter.emit(LISTENER, { message: I18n.t('Copied_to_clipboard') }); }; onPressLicense = () => { logEvent(events.SE_READ_LICENSE); const { theme } = this.props; openLink(LICENSE_LINK, theme); }; render() { const { server, isMasterDetail, theme } = this.props; return ( <SafeAreaView testID='settings-view'> <StatusBar /> <List.Container> {isMasterDetail ? ( <> <List.Section> <List.Separator /> <SidebarView theme={theme} /> <List.Separator /> </List.Section> <List.Section> <List.Separator /> <List.Item title='Display' onPress={() => this.navigateToScreen('DisplayPrefsView')} showActionIndicator /> <List.Separator /> <List.Item title='Profile' onPress={() => this.navigateToScreen('ProfileView')} showActionIndicator testID='settings-profile' /> <List.Separator /> </List.Section> </> ) : null} <List.Section> <List.Separator /> <List.Item title='Contact_us' onPress={this.sendEmail} showActionIndicator testID='settings-view-contact' /> <List.Separator /> <List.Item title='Language' onPress={() => this.navigateToScreen('LanguageView')} showActionIndicator testID='settings-view-language' /> <List.Separator /> {!isFDroidBuild ? ( <> <List.Item title='Review_this_app' showActionIndicator onPress={onReviewPress} testID='settings-view-review-app' /> </> ) : null} <List.Separator /> <List.Item title='Share_this_app' showActionIndicator onPress={this.shareApp} testID='settings-view-share-app' /> <List.Separator /> <List.Item title='Default_browser' showActionIndicator onPress={() => this.navigateToScreen('DefaultBrowserView')} testID='settings-view-default-browser' /> <List.Separator /> <List.Item title='Theme' showActionIndicator onPress={() => this.navigateToScreen('ThemeView')} testID='settings-view-theme' /> <List.Separator /> <List.Item title='Security_and_privacy' showActionIndicator onPress={() => this.navigateToScreen('SecurityPrivacyView')} testID='settings-view-security-privacy' /> <List.Separator /> </List.Section> <List.Section> <List.Separator /> <List.Item title='License' onPress={this.onPressLicense} showActionIndicator testID='settings-view-license' /> <List.Separator /> <List.Item title={I18n.t('Version_no', { version: getReadableVersion })} onPress={this.copyAppVersion} testID='settings-view-version' translateTitle={false} /> <List.Separator /> <List.Item title={I18n.t('Server_version', { version: server.version })} onPress={this.copyServerVersion} subtitle={`${server.server.split('//')[1]}`} testID='settings-view-server-version' translateTitle={false} translateSubtitle={false} /> <List.Separator /> </List.Section> <List.Section> <List.Separator /> <List.Item title='Clear_cache' testID='settings-view-clear-cache' onPress={this.handleClearCache} showActionIndicator color={themes[theme].dangerColor} /> <List.Separator /> <List.Item title='Logout' testID='settings-logout' onPress={this.handleLogout} showActionIndicator color={themes[theme].dangerColor} /> <List.Separator /> </List.Section> </List.Container> </SafeAreaView> ); } } const mapStateToProps = (state: IApplicationState) => ({ server: state.server, user: getUserSelector(state), isMasterDetail: state.app.isMasterDetail }); export default connect(mapStateToProps)(withTheme(SettingsView));