Feat: add copy to clipboard button in "about" mattermost page (#7134)

* feat: add copy to clip board button in about page

* add intl format text

* make suggested changes.

- fix: wrap copyToClipBoard function in useCallBack
- remove annonymous function onPress, provide function pointer
- make code readable in copyToClipBoard function

* formatting

* small fix

* change copy to clipboard position

- created a custom button eith icon and text
- usd button theme color

* button styling

* divider color

* use predefined btn element

* Add e2e test for copy info button

* feat: refactor the styles for thin lines

- fix: change touchable opacity to view
- add margin top to footer text

* change icon size to 15

* remove unnecessary view

* add config to dependency of callback

* suggeste changes on onClick func

* modified en.json file after running i18-extract

* Improve translations

* Address feedback

* Fix non updated default messages

---------

Co-authored-by: Daniel Espino García <larkox@gmail.com>
This commit is contained in:
Sudhanva-Nadiger 2023-07-26 18:30:06 +05:30 committed by GitHub
parent 871e3964ea
commit 37b245d461
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 73 additions and 37 deletions

View file

@ -1,21 +1,23 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import Clipboard from '@react-native-clipboard/clipboard';
import React, {useCallback, useMemo} from 'react';
import {useIntl} from 'react-intl';
import {Alert, Text, View} from 'react-native';
import DeviceInfo from 'react-native-device-info';
import Config from '@assets/config.json';
import Button from '@components/button';
import CompassIcon from '@components/compass_icon';
import FormattedText from '@components/formatted_text';
import SettingContainer from '@components/settings/container';
import SettingSeparator from '@components/settings/separator';
import AboutLinks from '@constants/about_links';
import {useTheme} from '@context/theme';
import useAndroidHardwareBackHandler from '@hooks/android_back_handler';
import {t} from '@i18n';
import {popTopScreen} from '@screens/navigation';
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
import {preventDoubleTap} from '@utils/tap';
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
import {typography} from '@utils/typography';
@ -80,7 +82,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => {
footerText: {
color: changeOpacity(theme.centerChannelColor, 0.64),
...typography('Body', 50),
marginBottom: 10,
marginVertical: 10,
},
copyrightText: {
marginBottom: 0,
@ -92,6 +94,17 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => {
group: {
flexDirection: 'row',
},
copyInfoButtonContainer: {
width: 120,
marginTop: 10,
position: 'relative',
},
thinLine: {
height: 0.2,
backgroundColor: changeOpacity(theme.centerChannelColor, 0.2),
alignSelf: 'stretch',
marginVertical: 20,
},
};
});
@ -146,31 +159,31 @@ const About = ({componentId, config, license}: AboutProps) => {
const buildNumber = config.BuildNumber;
const version = config.Version;
let id = t('settings.about.server.version.value');
let defaultMessage = '{version} (Build {number})';
let values: {version: string; number?: string} = {
version,
number: buildNumber,
};
if (buildNumber === version) {
id = t('settings.about.serverVersionNoBuild');
defaultMessage = '{version}';
values = {
version,
number: undefined,
};
return version;
}
return {
id, defaultMessage, values,
};
}, [config]);
return intl.formatMessage({id: 'settings.about.server.version.value', defaultMessage: '{version} (Build {buildNumber})'}, {version, buildNumber});
}, [config, intl]);
useAndroidHardwareBackHandler(componentId, () => {
popTopScreen(componentId);
});
const copyToClipboard = useCallback(
() => {
const appVersion = intl.formatMessage({id: 'settings.about.app.version', defaultMessage: 'App Version: {version} (Build {number})'}, {version: DeviceInfo.getVersion(), number: DeviceInfo.getBuildNumber()});
const buildNumber = config.BuildNumber;
const version = config.Version;
const server = buildNumber === version ? intl.formatMessage({id: 'settings.about.server.version.noBuild', defaultMessage: 'Server Version: {version}'}, {version}) : intl.formatMessage({id: 'settings.about.server.version', defaultMessage: 'Server Version: {version} (Build {buildNumber})'}, {version, buildNumber});
const database = intl.formatMessage({id: 'settings.about.database', defaultMessage: 'Database: {driverName}'}, {driverName: config.SQLDriverName});
const databaseSchemaVersion = intl.formatMessage({id: 'settings.about.database.schema', defaultMessage: 'Database Schema Version: {version}'}, {version: config.SchemaVersion});
const copiedString = `${appVersion}\n${server}\n${database}\n${databaseSchemaVersion}`;
Clipboard.setString(copiedString);
},
[intl, config],
);
return (
<SettingContainer testID='about'>
<View style={styles.logoContainer}>
@ -185,21 +198,24 @@ const About = ({componentId, config, license}: AboutProps) => {
license={license}
/>
<Subtitle config={config}/>
<SettingSeparator lineStyles={styles.lineStyles}/>
<View
style={styles.thinLine}
/>
</View>
<View style={styles.infoContainer}>
<View style={styles.group}>
<Text
style={styles.leftHeading}
testID='about.app_version.title'
>
{intl.formatMessage({id: 'settings.about.version', defaultMessage: 'App Version:'})}
{intl.formatMessage({id: 'settings.about.app.version.title', defaultMessage: 'App Version:'})}
</Text>
<Text
style={styles.rightHeading}
testID='about.app_version.value'
>
{intl.formatMessage({id: 'settings.about.build', defaultMessage: '{version} (Build {number})'},
{intl.formatMessage({id: 'settings.about.app.version.value', defaultMessage: '{version} (Build {number})'},
{version: DeviceInfo.getVersion(), number: DeviceInfo.getBuildNumber()})}
</Text>
</View>
@ -208,13 +224,13 @@ const About = ({componentId, config, license}: AboutProps) => {
style={styles.leftHeading}
testID='about.server_version.title'
>
{intl.formatMessage({id: 'settings.about.server.version.desc', defaultMessage: 'Server Version:'})}
{intl.formatMessage({id: 'settings.about.server.version.title', defaultMessage: 'Server Version:'})}
</Text>
<Text
style={styles.rightHeading}
testID='about.server_version.value'
>
{intl.formatMessage({id: serverVersion.id, defaultMessage: serverVersion.defaultMessage}, serverVersion.values)}
{serverVersion}
</Text>
</View>
<View style={styles.group}>
@ -222,13 +238,13 @@ const About = ({componentId, config, license}: AboutProps) => {
style={styles.leftHeading}
testID='about.database.title'
>
{intl.formatMessage({id: 'settings.about.database', defaultMessage: 'Database:'})}
{intl.formatMessage({id: 'settings.about.database.title', defaultMessage: 'Database:'})}
</Text>
<Text
style={styles.rightHeading}
testID='about.database.value'
>
{intl.formatMessage({id: 'settings.about.database.value', defaultMessage: `${config.SQLDriverName}`})}
{config.SQLDriverName}
</Text>
</View>
<View style={styles.group}>
@ -236,18 +252,26 @@ const About = ({componentId, config, license}: AboutProps) => {
style={styles.leftHeading}
testID='about.database_schema_version.title'
>
{intl.formatMessage({id: 'settings.about.database.schema', defaultMessage: 'Database Schema Version:'})}
{intl.formatMessage({id: 'settings.about.database.schema.title', defaultMessage: 'Database Schema Version:'})}
</Text>
<Text
style={styles.rightHeading}
testID='about.database_schema_version.value'
>
{intl.formatMessage({
id: 'settings.about.database.schema.value',
defaultMessage: `${config.SchemaVersion}`,
})}
{config.SchemaVersion}
</Text>
</View>
<Button
theme={theme}
backgroundStyle={[buttonBackgroundStyle(theme, 'm', 'tertiary'), styles.copyInfoButtonContainer]}
onPress={copyToClipboard}
textStyle={buttonTextStyle(theme, 'm', 'tertiary', 'default')}
text={intl.formatMessage({id: 'settings.about.button.copyInfo', defaultMessage: 'Copy info'})}
testID={'about.copy_info'}
iconName='content-copy'
iconSize={15}
buttonType={'default'}
/>
{license.IsLicensed === 'true' && (
<View style={styles.licenseContainer}>
<FormattedText
@ -272,6 +296,9 @@ const About = ({componentId, config, license}: AboutProps) => {
values={{site: config.SiteName}}
/>
}
<View
style={styles.thinLine}
/>
<FormattedText
defaultMessage='Copyright 2015-{currentYear} Mattermost, Inc. All rights reserved'
id={t('settings.about.copyright')}

View file

@ -928,16 +928,21 @@
"settings_display.timezone.off": "Off",
"settings_display.timezone.select": "Select Timezone",
"settings.about": "About {appTitle}",
"settings.about.build": "{version} (Build {number})",
"settings.about.app.version": "App Version: {version} (Build {number})",
"settings.about.app.version.title": "App Version:",
"settings.about.app.version.value": "{version} (Build {number})",
"settings.about.button.copyInfo": "Copy info",
"settings.about.copyright": "Copyright 2015-{currentYear} Mattermost, Inc. All rights reserved",
"settings.about.database": "Database:",
"settings.about.database.schema": "Database Schema Version:",
"settings.about.database": "Database: {driverName}",
"settings.about.database.schema": "Database Schema Version: {version}",
"settings.about.database.schema.title": "Database Schema Version:",
"settings.about.database.title": "Database:",
"settings.about.licensed": "Licensed to: {company}",
"settings.about.powered_by": "{site} is powered by Mattermost",
"settings.about.server.version.desc": "Server Version:",
"settings.about.server.version": "Server Version: {version} (Build {buildNumber}",
"settings.about.server.version.noBuild": "Server Version: {version}",
"settings.about.server.version.title": "Server Version:",
"settings.about.server.version.value": "{version} (Build {number})",
"settings.about.serverVersionNoBuild": "{version}",
"settings.about.version": "App Version:",
"settings.advanced_settings": "Advanced Settings",
"settings.advanced.cancel": "Cancel",
"settings.advanced.delete": "Delete",

View file

@ -22,6 +22,7 @@ class AboutScreen {
databaseValue: 'about.database.value',
databaseSchemaVersionTitle: 'about.database_schema_version.title',
databaseSchemaVersionValue: 'about.database_schema_version.value',
copInfoButton: 'about.copy_info',
licensee: 'about.licensee',
learnMoreText: 'about.learn_more.text',
learnMoreUrl: 'about.learn_more.url',
@ -51,6 +52,7 @@ class AboutScreen {
serverVersionValue = element(by.id(this.testID.serverVersionValue));
databaseTitle = element(by.id(this.testID.databaseTitle));
databaseValue = element(by.id(this.testID.databaseValue));
copyInfoButton = element(by.id(this.testID.copInfoButton));
databaseSchemaVersionTitle = element(by.id(this.testID.databaseSchemaVersionTitle));
databaseSchemaVersionValue = element(by.id(this.testID.databaseSchemaVersionValue));
licensee = element(by.id(this.testID.licensee));

View file

@ -68,6 +68,8 @@ describe('Account - Settings - About', () => {
await expect(AboutScreen.databaseValue).toBeVisible();
await expect(AboutScreen.databaseSchemaVersionTitle).toHaveText('Database Schema Version:');
await expect(AboutScreen.databaseSchemaVersionValue).toBeVisible();
await expect(AboutScreen.copyInfoButton).toBeVisible();
await expect(AboutScreen.copyInfoButton).toHaveText('Copy info');
if (isLicensed) {
await expect(AboutScreen.licensee).toBeVisible();
} else {