From 0ef1dd44ea3bbef685506874f0a097394cf38625 Mon Sep 17 00:00:00 2001 From: Avinash Lingaloo Date: Thu, 5 Aug 2021 08:48:36 +0400 Subject: [PATCH] Gekidou about screen (#5591) * Added about screen * Remove TS error * Needs clean up * Testing login flow * Converted About screen to functional component * Improvements * Sort imports * Prevents double tapping * Apply suggestions from code review Co-authored-by: Elias Nahum * Code clean up * Adding translation keys * Added some keys * Updated AppVersion component * Missed translation key Co-authored-by: Avinash Lingaloo <> Co-authored-by: Elias Nahum --- app/components/app_version/index.tsx | 36 +- app/constants/screens.ts | 2 + app/screens/about/index.tsx | 347 ++++++++++++++++++ app/screens/about/learn_more.tsx | 75 ++++ app/screens/about/server_version.tsx | 59 +++ app/screens/about/subtitle.tsx | 49 +++ app/screens/about/title.tsx | 53 +++ app/screens/about/tos_privacy.tsx | 73 ++++ .../channel_guest_label/index.tsx | 2 +- app/screens/channel/index.tsx | 40 +- app/screens/index.tsx | 6 +- app/screens/login/index.tsx | 2 +- app/screens/mfa/index.tsx | 2 +- app/utils/draft/index.ts | 2 +- app/utils/i18n.ts | 6 - assets/base/i18n/en.json | 22 ++ babel.config.js | 2 +- ios/Podfile.lock | 2 +- 18 files changed, 742 insertions(+), 38 deletions(-) create mode 100644 app/screens/about/index.tsx create mode 100644 app/screens/about/learn_more.tsx create mode 100644 app/screens/about/server_version.tsx create mode 100644 app/screens/about/subtitle.tsx create mode 100644 app/screens/about/title.tsx create mode 100644 app/screens/about/tos_privacy.tsx delete mode 100644 app/utils/i18n.ts diff --git a/app/components/app_version/index.tsx b/app/components/app_version/index.tsx index 98138a8e4..21b29e595 100644 --- a/app/components/app_version/index.tsx +++ b/app/components/app_version/index.tsx @@ -2,9 +2,10 @@ // See LICENSE.txt for license information. import React from 'react'; -import {StyleSheet, View} from 'react-native'; +import {StyleSheet, TextStyle, View} from 'react-native'; import DeviceInfo from 'react-native-device-info'; +import {t} from '@i18n'; import FormattedText from '@components/formatted_text'; const style = StyleSheet.create({ @@ -17,19 +18,32 @@ const style = StyleSheet.create({ }, }); -const AppVersion = () => { +type AppVersionProps = { + isWrapped?: boolean; + textStyle?: TextStyle; +} + +const AppVersion = ({isWrapped = true, textStyle = {}}: AppVersionProps) => { + const appVersion = ( + + ); + + if (!isWrapped) { + return appVersion; + } + return ( - + {appVersion} ); diff --git a/app/constants/screens.ts b/app/constants/screens.ts index 4959165f1..f7995d0a3 100644 --- a/app/constants/screens.ts +++ b/app/constants/screens.ts @@ -1,6 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. +export const ABOUT = 'About'; export const CHANNEL = 'Channel'; export const FORGOT_PASSWORD = 'ForgotPassword'; export const LOGIN = 'Login'; @@ -13,6 +14,7 @@ export const SSO = 'SSO'; export const THREAD = 'Thread'; export default { + ABOUT, CHANNEL, FORGOT_PASSWORD, LOGIN, diff --git a/app/screens/about/index.tsx b/app/screens/about/index.tsx new file mode 100644 index 000000000..00e9dee47 --- /dev/null +++ b/app/screens/about/index.tsx @@ -0,0 +1,347 @@ +// 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 React, {useCallback} from 'react'; +import {useIntl} from 'react-intl'; +import {Alert, ScrollView, Text, View} from 'react-native'; +import DeviceInfo from 'react-native-device-info'; +import {SafeAreaView} from 'react-native-safe-area-context'; + +import Config from '@assets/config.json'; +import AppVersion from '@components/app_version'; +import CompassIcon from '@components/compass_icon'; +import FormattedText from '@components/formatted_text'; +import StatusBar from '@components/status_bar'; +import AboutLinks from '@constants/about_links'; +import {MM_TABLES, SYSTEM_IDENTIFIERS} from '@constants/database'; +import {useTheme} from '@context/theme'; +import {t} from '@i18n'; +import {preventDoubleTap} from '@utils/tap'; +import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; +import {tryOpenURL} from '@utils/url'; + +import LearnMore from './learn_more'; +import ServerVersion from './server_version'; +import Subtitle from './subtitle'; +import Title from './title'; +import TosPrivacyContainer from './tos_privacy'; + +import type {WithDatabaseArgs} from '@typings/database/database'; +import type SystemModel from '@typings/database/models/servers/system'; + +const MATTERMOST_BUNDLE_IDS = ['com.mattermost.rnbeta', 'com.mattermost.rn']; + +type ConnectedAboutProps = { + config: SystemModel; + license: SystemModel; +} + +const ConnectedAbout = ({config, license}: ConnectedAboutProps) => { + const intl = useIntl(); + const theme = useTheme(); + const style = getStyleSheet(theme); + + const openURL = useCallback((url: string) => { + const onError = () => { + Alert.alert( + intl.formatMessage({ + id: 'mobile.link.error.title', + defaultMessage: 'Error', + }), + intl.formatMessage({ + id: 'mobile.link.error.text', + defaultMessage: 'Unable to open the link.', + }), + ); + }; + + tryOpenURL(url, onError); + }, []); + + const handleAboutTeam = useCallback(preventDoubleTap(() => { + return openURL(Config.AboutTeamURL); + }), []); + + const handleAboutEnterprise = useCallback(preventDoubleTap(() => { + return openURL(Config.AboutEnterpriseURL); + }), []); + + const handlePlatformNotice = useCallback(preventDoubleTap(() => { + return openURL(Config.PlatformNoticeURL); + }), []); + + const handleMobileNotice = useCallback(preventDoubleTap(() => { + return openURL(Config.MobileNoticeURL); + }), []); + + const handleTermsOfService = useCallback(preventDoubleTap(() => { + return openURL(AboutLinks.TERMS_OF_SERVICE); + }), []); + + const handlePrivacyPolicy = useCallback(preventDoubleTap(() => { + return openURL(AboutLinks.PRIVACY_POLICY); + }), []); + + return ( + + + + + + + + + + {`${config.value.SiteName} `} + + + </View> + <Subtitle config={config}/> + <AppVersion + isWrapped={false} + textStyle={style.info} + /> + <ServerVersion config={config}/> + <FormattedText + id={t('mobile.about.database')} + defaultMessage='Database: {type}' + style={style.info} + values={{ + type: config.value.SQLDriverName, + }} + testID='about.database' + /> + {license.value.IsLicensed === 'true' && ( + <View style={style.licenseContainer}> + <FormattedText + id={t('mobile.about.licensed')} + defaultMessage='Licensed to: {company}' + style={style.info} + values={{ + company: license.value.Company, + }} + testID='about.licensee' + /> + </View> + )} + <LearnMore + config={config} + onHandleAboutEnterprise={handleAboutEnterprise} + onHandleAboutTeam={handleAboutTeam} + /> + {!MATTERMOST_BUNDLE_IDS.includes(DeviceInfo.getBundleId()) && + <FormattedText + id={t('mobile.about.powered_by')} + defaultMessage='{site} is powered by Mattermost' + style={style.footerText} + values={{ + site: config.value.SiteName, + }} + testID='about.powered_by' + /> + } + <FormattedText + id={t('mobile.about.copyright')} + defaultMessage='Copyright 2015-{currentYear} Mattermost, Inc. All rights reserved' + style={[style.footerText, style.copyrightText]} + values={{ + currentYear: new Date().getFullYear(), + }} + testID='about.copyright' + /> + <View style={style.tosPrivacyContainer}> + <TosPrivacyContainer + config={config} + onPressTOS={handleTermsOfService} + onPressPrivacyPolicy={handlePrivacyPolicy} + /> + </View> + <View style={style.noticeContainer}> + <View style={style.footerGroup}> + <FormattedText + id={t('mobile.notice_text')} + defaultMessage='Mattermost is made possible by the open source software used in our {platform} and {mobile}.' + style={style.footerText} + values={{ + platform: ( + <FormattedText + id={t('mobile.notice_platform_link')} + defaultMessage='server' + style={style.noticeLink} + onPress={handlePlatformNotice} + /> + ), + mobile: ( + <FormattedText + id={t('mobile.notice_mobile_link')} + defaultMessage='mobile apps' + style={[style.noticeLink, {marginLeft: 5}]} + onPress={handleMobileNotice} + /> + ), + }} + testID='about.notice_text' + /> + </View> + </View> + <View style={style.hashContainer}> + <View style={style.footerGroup}> + <FormattedText + id={t('about.hash')} + defaultMessage='Build Hash:' + style={style.footerTitleText} + testID='about.build_hash.title' + /> + <Text + style={style.footerText} + testID='about.build_hash.value' + > + {config.value.BuildHash} + </Text> + </View> + <View style={style.footerGroup}> + <FormattedText + id={t('about.hashee')} + defaultMessage='EE Build Hash:' + style={style.footerTitleText} + testID='about.build_hash_enterprise.title' + /> + <Text + style={style.footerText} + testID='about.build_hash_enterprise.value' + > + {config.value.BuildHashEnterprise} + </Text> + </View> + </View> + <View style={style.footerGroup}> + <FormattedText + id={t('about.date')} + defaultMessage='Build Date:' + style={style.footerTitleText} + testID='about.build_date.title' + /> + <Text + style={style.footerText} + testID='about.build_date.value' + > + {config.value.BuildDate} + </Text> + </View> + </View> + </ScrollView> + </SafeAreaView> + ); +}; + +const getStyleSheet = makeStyleSheetFromTheme((theme) => { + return { + container: { + flex: 1, + }, + scrollView: { + flex: 1, + backgroundColor: changeOpacity(theme.centerChannelColor, 0.06), + }, + scrollViewContent: { + paddingBottom: 30, + }, + logoContainer: { + alignItems: 'center', + flex: 1, + height: 200, + paddingVertical: 40, + }, + infoContainer: { + flex: 1, + flexDirection: 'column', + paddingHorizontal: 20, + }, + titleContainer: { + flex: 1, + marginBottom: 20, + }, + title: { + fontSize: 22, + color: theme.centerChannelColor, + }, + subtitle: { + color: changeOpacity(theme.centerChannelColor, 0.5), + fontSize: 19, + marginBottom: 15, + }, + info: { + color: theme.centerChannelColor, + fontSize: 16, + lineHeight: 19, + }, + licenseContainer: { + flex: 1, + flexDirection: 'row', + marginTop: 20, + }, + noticeContainer: { + flex: 1, + flexDirection: 'column', + }, + noticeLink: { + color: theme.linkColor, + fontSize: 11, + lineHeight: 13, + }, + hashContainer: { + flex: 1, + flexDirection: 'column', + }, + footerGroup: { + flex: 1, + }, + footerTitleText: { + color: changeOpacity(theme.centerChannelColor, 0.5), + fontSize: 11, + fontWeight: '600', + lineHeight: 13, + }, + footerText: { + color: changeOpacity(theme.centerChannelColor, 0.5), + fontSize: 11, + lineHeight: 13, + marginBottom: 10, + }, + copyrightText: { + marginBottom: 0, + }, + tosPrivacyContainer: { + flex: 1, + flexDirection: 'row', + marginBottom: 10, + }, + }; +}); + +export default withDatabase(withObservables([], ({database}: WithDatabaseArgs) => ({ + config: database.collections.get(MM_TABLES.SERVER.SYSTEM).findAndObserve(SYSTEM_IDENTIFIERS.CONFIG), + license: database.collections.get(MM_TABLES.SERVER.SYSTEM).findAndObserve(SYSTEM_IDENTIFIERS.LICENSE), +}))(ConnectedAbout)); + diff --git a/app/screens/about/learn_more.tsx b/app/screens/about/learn_more.tsx new file mode 100644 index 000000000..31632f6b1 --- /dev/null +++ b/app/screens/about/learn_more.tsx @@ -0,0 +1,75 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React from 'react'; +import {Text, TouchableOpacity, View} from 'react-native'; + +import Config from '@assets/config.json'; +import FormattedText from '@components/formatted_text'; +import {useTheme} from '@context/theme'; +import {t} from '@i18n'; +import {makeStyleSheetFromTheme} from '@utils/theme'; + +import type SystemModel from '@typings/database/models/servers/system'; + +type LearnMoreProps = { + config: SystemModel; + onHandleAboutEnterprise: () => void; + onHandleAboutTeam: () => void; +}; + +const LearnMore = ({config, onHandleAboutEnterprise, onHandleAboutTeam}: LearnMoreProps) => { + const theme = useTheme(); + const style = getStyleSheet(theme); + + let id = t('about.teamEditionLearn'); + let defaultMessage = 'Join the Mattermost community at '; + let onPress = onHandleAboutTeam; + let url = Config.TeamEditionLearnURL; + + if (config.value?.BuildEnterpriseReady === 'true') { + id = t('about.enterpriseEditionLearn'); + defaultMessage = 'Learn more about Enterprise Edition at '; + onPress = onHandleAboutEnterprise; + url = Config.EELearnURL; + } + + return ( + <View style={style.learnContainer}> + <FormattedText + id={id} + defaultMessage={defaultMessage} + style={style.learn} + testID='about.learn_more' + /> + <TouchableOpacity onPress={onPress}> + <Text + style={style.learnLink} + testID='about.learn_more.url' + > + {url} + </Text> + </TouchableOpacity> + </View> + ); +}; + +const getStyleSheet = makeStyleSheetFromTheme((theme) => { + return { + learnContainer: { + flex: 1, + flexDirection: 'column', + marginVertical: 20, + }, + learn: { + color: theme.centerChannelColor, + fontSize: 16, + }, + learnLink: { + color: theme.linkColor, + fontSize: 16, + }, + }; +}); + +export default LearnMore; diff --git a/app/screens/about/server_version.tsx b/app/screens/about/server_version.tsx new file mode 100644 index 000000000..b27d4f3d9 --- /dev/null +++ b/app/screens/about/server_version.tsx @@ -0,0 +1,59 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React from 'react'; + +import FormattedText from '@components/formatted_text'; +import {useTheme} from '@context/theme'; +import {t} from '@i18n'; +import {makeStyleSheetFromTheme} from '@utils/theme'; + +import type SystemModel from '@typings/database/models/servers/system'; + +type ServerVersionProps = { + config: SystemModel; +} + +const ServerVersion = ({config}: ServerVersionProps) => { + const buildNumber = config.value.BuildNumber; + const version = config.value.Version; + const theme = useTheme(); + const style = getStyleSheet(theme); + + let id = t('mobile.about.serverVersion'); + let defaultMessage = 'Server Version: {version} (Build {number})'; + let values = { + version, + number: buildNumber, + }; + + if (buildNumber === version) { + id = t('mobile.about.serverVersionNoBuild'); + defaultMessage = 'Server Version: {version}'; + values = { + version, + number: undefined, + }; + } + return ( + <FormattedText + id={id} + defaultMessage={defaultMessage} + style={style.info} + values={values} + testID='about.server_version' + /> + ); +}; + +const getStyleSheet = makeStyleSheetFromTheme((theme) => { + return { + info: { + color: theme.centerChannelColor, + fontSize: 16, + lineHeight: 19, + }, + }; +}); + +export default ServerVersion; diff --git a/app/screens/about/subtitle.tsx b/app/screens/about/subtitle.tsx new file mode 100644 index 000000000..7d02f7267 --- /dev/null +++ b/app/screens/about/subtitle.tsx @@ -0,0 +1,49 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React from 'react'; + +import FormattedText from '@components/formatted_text'; +import {useTheme} from '@context/theme'; +import {t} from '@i18n'; +import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; + +import type SystemModel from '@typings/database/models/servers/system'; + +type SubtitleProps = { + config: SystemModel; +} + +const Subtitle = ({config}: SubtitleProps) => { + const theme = useTheme(); + const style = getStyleSheet(theme); + + let id = t('about.teamEditionSt'); + let defaultMessage = 'All your team communication in one place, instantly searchable and accessible anywhere.'; + + if (config.value.BuildEnterpriseReady === 'true') { + id = t('about.enterpriseEditionSt'); + defaultMessage = 'Modern communication from behind your firewall.'; + } + + return ( + <FormattedText + id={id} + defaultMessage={defaultMessage} + style={style.subtitle} + testID='about.subtitle' + /> + ); +}; + +const getStyleSheet = makeStyleSheetFromTheme((theme) => { + return { + subtitle: { + color: changeOpacity(theme.centerChannelColor, 0.5), + fontSize: 19, + marginBottom: 15, + }, + }; +}); + +export default Subtitle; diff --git a/app/screens/about/title.tsx b/app/screens/about/title.tsx new file mode 100644 index 000000000..1ca879848 --- /dev/null +++ b/app/screens/about/title.tsx @@ -0,0 +1,53 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import FormattedText from '@components/formatted_text'; +import React from 'react'; + +import {useTheme} from '@context/theme'; +import {t} from '@i18n'; +import {makeStyleSheetFromTheme} from '@utils/theme'; + +import type SystemModel from '@typings/database/models/servers/system'; + +type TitleProps = { + config: SystemModel; + license: SystemModel; +} + +const Title = ({config, license}: TitleProps) => { + const theme = useTheme(); + const style = getStyleSheet(theme); + + let id = t('about.teamEditiont0'); + let defaultMessage = 'Team Edition'; + + if (config.value.BuildEnterpriseReady === 'true') { + id = t('about.teamEditiont1'); + defaultMessage = 'Enterprise Edition'; + + if (license.value.IsLicensed === 'true') { + id = t('about.enterpriseEditione1'); + defaultMessage = 'Enterprise Edition'; + } + } + return ( + <FormattedText + id={id} + defaultMessage={defaultMessage} + style={style.title} + testID='about.title' + /> + ); +}; + +const getStyleSheet = makeStyleSheetFromTheme((theme) => { + return { + title: { + fontSize: 22, + color: theme.centerChannelColor, + }, + }; +}); + +export default Title; diff --git a/app/screens/about/tos_privacy.tsx b/app/screens/about/tos_privacy.tsx new file mode 100644 index 000000000..567ea8739 --- /dev/null +++ b/app/screens/about/tos_privacy.tsx @@ -0,0 +1,73 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React from 'react'; +import {Text} from 'react-native'; + +import FormattedText from '@components/formatted_text'; +import {useTheme} from '@context/theme'; +import {t} from '@i18n'; +import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; + +import type SystemModel from '@typings/database/models/servers/system'; + +type TosPrivacyContainerProps = { + config: SystemModel; + onPressTOS: () => void; + onPressPrivacyPolicy: () => void; +} + +const TosPrivacyContainer = ({config, onPressTOS, onPressPrivacyPolicy}: TosPrivacyContainerProps) => { + const hasTermsOfServiceLink = config.value?.TermsOfServiceLink; + const hasPrivacyPolicyLink = config.value?.PrivacyPolicyLink; + const theme = useTheme(); + const style = getStyleSheet(theme); + return ( + <> + {hasTermsOfServiceLink && ( + <FormattedText + id={t('mobile.tos_link')} + defaultMessage='Terms of Service' + style={style.noticeLink} + onPress={onPressTOS} + testID='about.terms_of_service' + /> + )} + {hasTermsOfServiceLink && hasPrivacyPolicyLink && ( + <Text style={[style.footerText, style.hyphenText]}> + {' - '} + </Text> + )} + {hasPrivacyPolicyLink && ( + <FormattedText + id={t('mobile.privacy_link')} + defaultMessage='Privacy Policy' + style={style.noticeLink} + onPress={onPressPrivacyPolicy} + testID='about.privacy_policy' + /> + )} + </> + ); +}; + +const getStyleSheet = makeStyleSheetFromTheme((theme) => { + return { + noticeLink: { + color: theme.linkColor, + fontSize: 11, + lineHeight: 13, + }, + footerText: { + color: changeOpacity(theme.centerChannelColor, 0.5), + fontSize: 11, + lineHeight: 13, + marginBottom: 10, + }, + hyphenText: { + marginBottom: 0, + }, + }; +}); + +export default TosPrivacyContainer; diff --git a/app/screens/channel/channel_nav_bar/channel_title/channel_guest_label/index.tsx b/app/screens/channel/channel_nav_bar/channel_title/channel_guest_label/index.tsx index a4ebc2b81..e43656262 100644 --- a/app/screens/channel/channel_nav_bar/channel_title/channel_guest_label/index.tsx +++ b/app/screens/channel/channel_nav_bar/channel_title/channel_guest_label/index.tsx @@ -6,7 +6,7 @@ import {View} from 'react-native'; import FormattedText from '@components/formatted_text'; import {General} from '@constants'; -import {t} from '@utils/i18n'; +import {t} from '@i18n'; import {makeStyleSheetFromTheme} from '@utils/theme'; type ChannelGuestLabelProps = { diff --git a/app/screens/channel/index.tsx b/app/screens/channel/index.tsx index 60e3085a3..c1703b2a8 100644 --- a/app/screens/channel/index.tsx +++ b/app/screens/channel/index.tsx @@ -3,32 +3,32 @@ import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider'; import withObservables from '@nozbe/with-observables'; +import {goToScreen} from '@screens/navigation'; import React, {useMemo, useState} from 'react'; +import {useIntl} from 'react-intl'; import {Text, View, ScrollView} from 'react-native'; import {SafeAreaView} from 'react-native-safe-area-context'; import {logout} from '@actions/remote/session'; +import Markdown from '@components/markdown'; +import JumboEmoji from '@components/jumbo_emoji'; +import ProgressiveImage from '@components/progressive_image'; import ServerVersion from '@components/server_version'; import StatusBar from '@components/status_bar'; -import {MM_TABLES, SYSTEM_IDENTIFIERS} from '@constants/database'; +import {Screens, Database} from '@constants'; import {useServerUrl} from '@context/server_url'; import {useTheme} from '@context/theme'; import {makeStyleSheetFromTheme} from '@utils/theme'; +import {getMarkdownBlockStyles, getMarkdownTextStyles} from '@utils/markdown'; import ChannelNavBar from './channel_nav_bar'; - -import type SystemModel from '@typings/database/models/servers/system'; -import type {LaunchProps} from '@typings/launch'; -import type {WithDatabaseArgs} from '@typings/database/database'; - import FailedChannels from './failed_channels'; import FailedTeams from './failed_teams'; - -import Markdown from '@components/markdown'; -import {getMarkdownBlockStyles, getMarkdownTextStyles} from '@utils/markdown'; import md from './md.json'; -import ProgressiveImage from '@components/progressive_image'; -import JumboEmoji from '@components/jumbo_emoji'; + +import type {WithDatabaseArgs} from '@typings/database/database'; +import type SystemModel from '@typings/database/models/servers/system'; +import type {LaunchProps} from '@typings/launch'; type ChannelProps = WithDatabaseArgs & LaunchProps & { currentChannelId: SystemModel; @@ -36,6 +36,7 @@ type ChannelProps = WithDatabaseArgs & LaunchProps & { time?: number; }; +const {MM_TABLES, SYSTEM_IDENTIFIERS} = Database; const {SERVER: {SYSTEM}} = MM_TABLES; const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ @@ -69,6 +70,7 @@ const Channel = ({currentChannelId, currentTeamId, time}: ChannelProps) => { //todo: https://mattermost.atlassian.net/browse/MM-37266 const theme = useTheme(); + const intl = useIntl(); const styles = getStyleSheet(theme); const serverUrl = useServerUrl(); @@ -77,6 +79,11 @@ const Channel = ({currentChannelId, currentTeamId, time}: ChannelProps) => { logout(serverUrl!); }; + const goToAbout = () => { + const title = intl.formatMessage({id: 'about.title', defaultMessage: 'About {appTitle}'}, {appTitle: 'Mattermost'}); + goToScreen(Screens.ABOUT, title); + }; + const renderComponent = useMemo(() => { if (!currentTeamId.value) { return <FailedTeams/>; @@ -140,6 +147,14 @@ const Channel = ({currentChannelId, currentTeamId, time}: ChannelProps) => { {`Loaded in: ${time || 0}ms. Logout from ${serverUrl}`} </Text> </View> + <View style={styles.sectionContainer}> + <Text + onPress={goToAbout} + style={styles.sectionTitle} + > + {'Go to About Screen'} + </Text> + </View> </ScrollView> </> ); @@ -147,8 +162,9 @@ const Channel = ({currentChannelId, currentTeamId, time}: ChannelProps) => { const [inViewport, setInViewport] = useState(false); - setTimeout(async () => { + const viewPortTimer = setTimeout(async () => { setInViewport(true); + clearTimeout(viewPortTimer); }, 3000); return ( diff --git a/app/screens/index.tsx b/app/screens/index.tsx index 73b858807..e07ad9469 100644 --- a/app/screens/index.tsx +++ b/app/screens/index.tsx @@ -51,9 +51,9 @@ Navigation.setLazyComponentRegistrator((screenName) => { let screen: any|undefined; let extraStyles: StyleProp<ViewStyle>; switch (screenName) { - // case 'About': - // screen = require('@screens/about').default; - // break; + case 'About': + screen = withServerDatabase(require('@screens/about').default); + break; // case 'AddReaction': // screen = require('@screens/add_reaction').default; // break; diff --git a/app/screens/login/index.tsx b/app/screens/login/index.tsx index 063ec336c..f657caa5c 100644 --- a/app/screens/login/index.tsx +++ b/app/screens/login/index.tsx @@ -26,8 +26,8 @@ import {FORGOT_PASSWORD, MFA} from '@constants/screens'; import FormattedText from '@components/formatted_text'; import {useManagedConfig} from '@mattermost/react-native-emm'; import {login} from '@actions/remote/session'; +import {t} from '@i18n'; import {goToScreen, resetToChannel} from '@screens/navigation'; -import {t} from '@utils/i18n'; import {preventDoubleTap} from '@utils/tap'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; diff --git a/app/screens/mfa/index.tsx b/app/screens/mfa/index.tsx index 1156f9fbb..043f9d163 100644 --- a/app/screens/mfa/index.tsx +++ b/app/screens/mfa/index.tsx @@ -19,7 +19,7 @@ import {SafeAreaView} from 'react-native-safe-area-context'; import ErrorText from '@components/error_text'; import FormattedText from '@components/formatted_text'; import {login} from '@actions/remote/session'; -import {t} from '@utils/i18n'; +import {t} from '@i18n'; import {preventDoubleTap} from '@utils/tap'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; diff --git a/app/utils/draft/index.ts b/app/utils/draft/index.ts index 9c1c64836..b08d4bbd2 100644 --- a/app/utils/draft/index.ts +++ b/app/utils/draft/index.ts @@ -6,7 +6,7 @@ import {Alert, AlertButton} from 'react-native'; import type {IntlShape} from 'react-intl'; -import {t} from '@utils/i18n'; +import {t} from '@i18n'; export function errorBadChannel(intl: IntlShape) { const message = { diff --git a/app/utils/i18n.ts b/app/utils/i18n.ts deleted file mode 100644 index b8d23d715..000000000 --- a/app/utils/i18n.ts +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -export function t(v: string) { - return v; -} diff --git a/assets/base/i18n/en.json b/assets/base/i18n/en.json index ff0ac1e1b..90ccfaeb3 100644 --- a/assets/base/i18n/en.json +++ b/assets/base/i18n/en.json @@ -1,4 +1,15 @@ { + "about.date": "Build Date:", + "about.enterpriseEditione1": "Enterprise Edition", + "about.enterpriseEditionLearn": "Learn more about Enterprise Edition at ", + "about.enterpriseEditionSt": "Modern communication from behind your firewall.", + "about.hash": "Build Hash:", + "about.hashee": "EE Build Hash:", + "about.teamEditionLearn": "Join the Mattermost community at ", + "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}", "channel_header.directchannel.you": "{displayname} (you)", "channel_loader.someone": "Someone", "channel.channelHasGuests": "This channel has guests", @@ -48,6 +59,12 @@ "login.username": "Username", "login.userNotFound": "We couldn't find an account matching your login credentials.", "mobile.about.appVersion": "App Version: {version} (Build {number})", + "mobile.about.copyright": "Copyright 2015-{currentYear} Mattermost, Inc. All rights reserved", + "mobile.about.database": "Database: {type}", + "mobile.about.licensed": "Licensed to: {company}", + "mobile.about.powered_by": "{site} is powered by Mattermost", + "mobile.about.serverVersion": "Server Version: {version} (Build {number})", + "mobile.about.serverVersionNoBuild": "Server Version: {version}", "mobile.components.select_server_view.connect": "Connect", "mobile.components.select_server_view.connecting": "Connecting...", "mobile.components.select_server_view.enterServerUrl": "Enter Server URL", @@ -74,6 +91,9 @@ "mobile.markdown.image.too_large": "Image exceeds max dimensions of {maxWidth} by {maxHeight}:", "mobile.markdown.link.copy_url": "Copy URL", "mobile.mention.copy_mention": "Copy Mention", + "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.oauth.failed_to_login": "Your login attempt failed. Please try again.", "mobile.oauth.failed_to_open_link": "The link failed to open. Please try again.", "mobile.oauth.failed_to_open_link_no_browser": "The link failed to open. Please verify if a browser is installed in the current space.", @@ -82,6 +102,7 @@ "mobile.oauth.switch_to_browser": "Please use your browser to complete the login", "mobile.oauth.try_again": "Try again", "mobile.post.cancel": "Cancel", + "mobile.privacy_link": "Privacy Policy", "mobile.push_notification_reply.button": "Send", "mobile.push_notification_reply.placeholder": "Write a reply...", "mobile.push_notification_reply.title": "Reply", @@ -107,6 +128,7 @@ "mobile.server_url.empty": "Please enter a valid server URL", "mobile.server_url.invalid_format": "URL must start with http:// or https://", "mobile.session_expired": "Session Expired: Please log in to continue receiving notifications. Sessions for {siteName} are configured to expire every {daysCount, number} {daysCount, plural, one {day} other {days}}.", + "mobile.tos_link": "Terms of Service", "mobile.unsupported_server.message": "Attachments, link previews, reactions and embed data may not be displayed correctly. If this issue persists contact your System Administrator to upgrade your Mattermost server.", "mobile.unsupported_server.ok": "OK", "mobile.unsupported_server.title": "Unsupported server version", diff --git a/babel.config.js b/babel.config.js index 2b647a29a..90566e9c7 100644 --- a/babel.config.js +++ b/babel.config.js @@ -21,7 +21,7 @@ module.exports = { alias: { '@actions': './app/actions', '@app': './app/', - '@assets': './dist/assets', + '@assets': './dist/assets/', '@client': './app/client', '@components': './app/components', '@constants': './app/constants', diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 5edb4a92c..f467a3c93 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -710,7 +710,7 @@ SPEC CHECKSUMS: EXFileSystem: 0a04aba8da751b9ac954065911bcf166503f8267 ExpoModulesCore: 2734852616127a6c1fc23012197890a6f3763dc7 FBLazyVector: e686045572151edef46010a6f819ade377dfeb4b - FBReactNativeSpec: cef0cc6d50abc92e8cf52f140aa22b5371cfec0b + FBReactNativeSpec: d35931295aacfe996e833c01a3701d4aa7a80cb4 glog: 73c2498ac6884b13ede40eda8228cb1eee9d9d62 jail-monkey: 07b83767601a373db876e939b8dbf3f5eb15f073 libwebp: e90b9c01d99205d03b6bb8f2c8c415e5a4ef66f0