[NEW] Settings view (#900)

* new settings view

* fix eslint

* fix eslint

* fix eslint

* fix eslint

* fix eslint

* fix eslint

* fix eslint

* fix eslint

* fix eslint

* fix eslint

* fix eslint

* eslint fixed all bugs and setup on my device

* move version from sidebar to settingsView

* add server Version not hard coded

* goto root stack after change language

* support RTL

* fix the ui of last section

* fixed bugs done requested changes

* added actions for contact us and license

* done requested changes

* removed verticle scroll indicator

* removed default export of device info

* fixed separator styling

* refactor Items in settings view

* changed language view

* change activeOpacity

* done requested changes

* fixed lint

* changed layout

* added test

* fix bug

* fix bug

* added e2e tests

* undone unnessary changes

* undone unnessary changes

* removed firebase

* Comment slash e2e tests

* Refactor Settings

* Refactor LanguageView

* Separator

* Unified styles

* fix indentation
This commit is contained in:
pranavpandey1998official 2019-06-11 19:31:40 +05:30 committed by Diego Mello
parent 82afb63327
commit c14714f16f
15 changed files with 556 additions and 234 deletions

View File

@ -0,0 +1,3 @@
export default {
createSagaMonitor: () => {}
};

View File

@ -14,9 +14,12 @@ const styles = StyleSheet.create({
}
});
export const DisclosureImage = React.memo(() => <Image source={{ uri: 'disclosure_indicator' }} style={styles.disclosureIndicator} />);
const DisclosureIndicator = React.memo(() => (
<View style={styles.disclosureContainer}>
<Image source={{ uri: 'disclosure_indicator' }} style={styles.disclosureIndicator} />
<DisclosureImage />
</View>
));
export default DisclosureIndicator;

View File

@ -0,0 +1,93 @@
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
import PropTypes from 'prop-types';
import { RectButton } from 'react-native-gesture-handler';
import { COLOR_TEXT } from '../constants/colors';
import sharedStyles from '../views/Styles';
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
height: 56,
paddingHorizontal: 15
},
disabled: {
opacity: 0.3
},
textContainer: {
flex: 1,
justifyContent: 'center'
},
title: {
fontSize: 16,
...sharedStyles.textColorNormal,
...sharedStyles.textRegular
},
subtitle: {
fontSize: 14,
...sharedStyles.textColorNormal,
...sharedStyles.textRegular
}
});
const Content = React.memo(({
title, subtitle, disabled, testID, right
}) => (
<View style={[styles.container, disabled && styles.disabled]} testID={testID}>
<View style={styles.textContainer}>
<Text style={styles.title}>{title}</Text>
{subtitle
? <Text style={styles.subtitle}>{subtitle}</Text>
: null
}
</View>
{right ? right() : null}
</View>
));
const Button = React.memo(({
onPress, ...props
}) => (
<RectButton
onPress={onPress}
activeOpacity={0.1}
underlayColor={COLOR_TEXT}
enabled={!props.disabled}
>
<Content {...props} />
</RectButton>
));
const Item = React.memo(({ ...props }) => {
if (props.onPress) {
return <Button {...props} />;
}
return <Content {...props} />;
});
Item.propTypes = {
onPress: PropTypes.func
};
Content.propTypes = {
title: PropTypes.string.isRequired,
subtitle: PropTypes.string,
right: PropTypes.func,
disabled: PropTypes.bool,
testID: PropTypes.string
};
Button.propTypes = {
onPress: PropTypes.func,
disabled: PropTypes.bool
};
Button.defaultProps = {
disabled: false
};
export default Item;

View File

@ -0,0 +1,21 @@
import React from 'react';
import { View, StyleSheet } from 'react-native';
import PropTypes from 'prop-types';
import { COLOR_SEPARATOR } from '../constants/colors';
const styles = StyleSheet.create({
separator: {
height: StyleSheet.hairlineWidth,
backgroundColor: COLOR_SEPARATOR
}
});
const Separator = React.memo(({ style }) => <View style={[styles.separator, style]} />);
Separator.propTypes = {
style: PropTypes.object
};
export default Separator;

View File

@ -127,6 +127,7 @@ export default {
Connected: 'Connected',
connecting_server: 'connecting to server',
Connecting: 'Connecting...',
Contact_us: 'Contact us',
Continue_with: 'Continue with',
Copied_to_clipboard: 'Copied to clipboard!',
Copy: 'Copy',
@ -190,6 +191,7 @@ export default {
leaving_room: 'leaving room',
leave: 'leave',
Legal: 'Legal',
License: 'License',
Livechat: 'Livechat',
Login: 'Login',
Login_error: 'Your credentials were rejected! Please try again.',
@ -304,14 +306,17 @@ export default {
Select_Users: 'Select Users',
Send: 'Send',
Send_audio_message: 'Send audio message',
Send_crash_report: 'Send crash report',
Send_message: 'Send message',
Sent_an_attachment: 'Sent an attachment',
Server: 'Server',
Servers: 'Servers',
Server_version: 'Server version: {{version}}',
Set_username_subtitle: 'The username is used to allow others to mention you in messages',
Settings: 'Settings',
Settings_succesfully_changed: 'Settings succesfully changed!',
Share: 'Share',
Share_this_app: 'Share this app',
Sign_in_your_server: 'Sign in your server',
Sign_Up: 'Sign Up',
Some_field_is_invalid_or_empty: 'Some field is invalid or empty',
@ -328,6 +333,7 @@ export default {
tap_to_change_status: 'tap to change status',
Tap_to_view_servers_list: 'Tap to view servers list',
Terms_of_Service: ' Terms of Service ',
Theme: 'Theme',
The_URL_is_invalid: 'The URL you entered is invalid. Check it and try again, please!',
There_was_an_error_while_action: 'There was an error while {{action}}!',
This_room_is_blocked: 'This room is blocked',
@ -381,5 +387,8 @@ export default {
you_were_mentioned: 'you were mentioned',
you: 'you',
You: 'You',
You_will_not_be_able_to_recover_this_message: 'You will not be able to recover this message!'
Version_no: 'Version: {{version}}',
You_will_not_be_able_to_recover_this_message: 'You will not be able to recover this message!',
Change_Language: 'Change Language',
Crash_report_disclaimer: 'We never track the content of your chats. The crash report only contains relevant information for us in order '
};

View File

@ -23,6 +23,7 @@ import Navigation from './lib/Navigation';
import Sidebar from './views/SidebarView';
import ProfileView from './views/ProfileView';
import SettingsView from './views/SettingsView';
import LanguageView from './views/LanguageView';
import AdminPanelView from './views/AdminPanelView';
import RoomActionsView from './views/RoomActionsView';
import RoomInfoView from './views/RoomInfoView';
@ -148,7 +149,8 @@ ProfileStack.navigationOptions = ({ navigation }) => {
};
const SettingsStack = createStackNavigator({
SettingsView
SettingsView,
LanguageView
}, {
defaultNavigationOptions: defaultHeader
});

View File

@ -8,11 +8,4 @@ export const isIOS = Platform.OS === 'ios';
export const isAndroid = !isIOS;
export const getReadableVersion = DeviceInfo.getReadableVersion();
export const getBundleId = DeviceInfo.getBundleId();
export default {
isNotch,
isIOS,
isAndroid,
getReadableVersion,
getBundleId
};
export const getDeviceModel = DeviceInfo.getModel();

View File

@ -0,0 +1,158 @@
import React from 'react';
import PropTypes from 'prop-types';
import { FlatList } from 'react-native';
import { connect } from 'react-redux';
import { SafeAreaView, NavigationActions } from 'react-navigation';
import RocketChat from '../../lib/rocketchat';
import I18n from '../../i18n';
import Loading from '../../containers/Loading';
import { showErrorAlert } from '../../utils/info';
import log from '../../utils/log';
import { setUser as setUserAction } from '../../actions/login';
import StatusBar from '../../containers/StatusBar';
import { CustomIcon } from '../../lib/Icons';
import sharedStyles from '../Styles';
import ListItem from '../../containers/ListItem';
import Separator from '../../containers/Separator';
const LANGUAGES = [
{
label: '简体中文',
value: 'zh-CN'
}, {
label: 'Deutsch',
value: 'de'
}, {
label: 'English',
value: 'en'
}, {
label: 'Français',
value: 'fr'
}, {
label: 'Português (BR)',
value: 'pt-BR'
}, {
label: 'Português (PT)',
value: 'pt-PT'
}, {
label: 'Russian',
value: 'ru'
}
];
@connect(state => ({
userLanguage: state.login.user && state.login.user.language
}), dispatch => ({
setUser: params => dispatch(setUserAction(params))
}))
/** @extends React.Component */
export default class LanguageView extends React.Component {
static navigationOptions = () => ({
title: I18n.t('Change_Language')
})
static propTypes = {
userLanguage: PropTypes.string,
navigation: PropTypes.object,
setUser: PropTypes.func
}
constructor(props) {
super(props);
this.state = {
language: props.userLanguage ? props.userLanguage : 'en',
saving: false
};
}
shouldComponentUpdate(nextProps, nextState) {
const { language, saving } = this.state;
const { userLanguage } = this.props;
if (nextState.language !== language) {
return true;
}
if (nextState.saving !== saving) {
return true;
}
if (nextProps.userLanguage !== userLanguage) {
return true;
}
return false;
}
formIsChanged = (language) => {
const { userLanguage } = this.props;
return (userLanguage !== language);
}
submit = async(language) => {
if (!this.formIsChanged(language)) {
return;
}
this.setState({ saving: true });
const { userLanguage, setUser, navigation } = this.props;
const params = {};
// language
if (userLanguage !== language) {
params.language = language;
}
try {
await RocketChat.saveUserPreferences(params);
setUser({ language: params.language });
this.setState({ saving: false });
setTimeout(() => {
navigation.reset([NavigationActions.navigate({ routeName: 'SettingsView' })], 0);
navigation.navigate('RoomsListView');
}, 300);
} catch (e) {
this.setState({ saving: false });
setTimeout(() => {
showErrorAlert(I18n.t('There_was_an_error_while_action', { action: I18n.t('saving_preferences') }));
log('err_save_user_preferences', e);
}, 300);
}
}
renderSeparator = () => <Separator />
renderIcon = () => <CustomIcon name='check' size={20} style={sharedStyles.colorPrimary} />
renderItem = ({ item }) => {
const { value, label } = item;
const { language } = this.state;
const isSelected = language === value;
return (
<ListItem
title={label}
onPress={() => this.submit(value)}
testID={`language-view-${ value }`}
right={isSelected ? this.renderIcon : null}
/>
);
}
render() {
const { saving } = this.state;
return (
<SafeAreaView style={sharedStyles.listSafeArea} testID='language-view' forceInset={{ bottom: 'never' }}>
<StatusBar />
<FlatList
data={LANGUAGES}
keyExtractor={item => item.value}
contentContainerStyle={sharedStyles.listContentContainer}
renderItem={this.renderItem}
ItemSeparatorComponent={this.renderSeparator}
/>
<Loading visible={saving} />
</SafeAreaView>
);
}
}

View File

@ -1,236 +1,160 @@
import React from 'react';
import PropTypes from 'prop-types';
import {
View, ScrollView, Switch, Text, StyleSheet, AsyncStorage
View, Linking, ScrollView, AsyncStorage, SafeAreaView, Switch
} from 'react-native';
import RNPickerSelect from 'react-native-picker-select';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { SafeAreaView } from 'react-navigation';
import firebase from 'react-native-firebase';
import RocketChat, { MARKDOWN_KEY } from '../../lib/rocketchat';
import KeyboardView from '../../presentation/KeyboardView';
import sharedStyles from '../Styles';
import RCTextInput from '../../containers/TextInput';
import scrollPersistTaps from '../../utils/scrollPersistTaps';
import I18n from '../../i18n';
import Button from '../../containers/Button';
import Loading from '../../containers/Loading';
import { showErrorAlert, Toast } from '../../utils/info';
import log from '../../utils/log';
import { setUser as setUserAction } from '../../actions/login';
import { toggleMarkdown as toggleMarkdownAction } from '../../actions/markdown';
import { COLOR_DANGER, COLOR_SUCCESS } from '../../constants/colors';
import { DrawerButton } from '../../containers/HeaderButton';
import StatusBar from '../../containers/StatusBar';
import { isAndroid } from '../../utils/deviceInfo';
import {
COLOR_WHITE, COLOR_SEPARATOR, COLOR_DANGER, COLOR_SUCCESS
} from '../../constants/colors';
import ListItem from '../../containers/ListItem';
import { DisclosureImage } from '../../containers/DisclosureIndicator';
import Separator from '../../containers/Separator';
import I18n from '../../i18n';
import { MARKDOWN_KEY } from '../../lib/rocketchat';
import { getReadableVersion, getDeviceModel, isAndroid } from '../../utils/deviceInfo';
import openLink from '../../utils/openLink';
import scrollPersistTaps from '../../utils/scrollPersistTaps';
import { showErrorAlert } from '../../utils/info';
import styles from './styles';
import sharedStyles from '../Styles';
const styles = StyleSheet.create({
swithContainer: {
backgroundColor: COLOR_WHITE,
alignItems: 'center',
justifyContent: 'space-between',
flexDirection: 'row'
},
label: {
fontSize: 17,
flex: 1,
...sharedStyles.textMedium,
...sharedStyles.textColorNormal
},
separator: {
flex: 1,
height: 1,
backgroundColor: COLOR_SEPARATOR,
marginVertical: 10
}
});
const LICENSE_LINK = 'https://github.com/RocketChat/Rocket.Chat.ReactNative/blob/develop/LICENSE';
const SectionSeparator = React.memo(() => <View style={styles.sectionSeparatorBorder} />);
const SWITCH_TRACK_COLOR = {
false: isAndroid ? COLOR_DANGER : null,
true: COLOR_SUCCESS
};
@connect(state => ({
userLanguage: state.login.user && state.login.user.language,
server: state.server,
useMarkdown: state.markdown.useMarkdown
}), dispatch => ({
setUser: params => dispatch(setUserAction(params)),
toggleMarkdown: params => dispatch(toggleMarkdownAction(params))
}))
export default class SettingsView extends React.Component {
static navigationOptions = ({ navigation }) => ({
headerLeft: <DrawerButton navigation={navigation} />,
title: I18n.t('Settings')
})
});
static propTypes = {
componentId: PropTypes.string,
userLanguage: PropTypes.string,
navigation: PropTypes.object,
server: PropTypes.object,
useMarkdown: PropTypes.bool,
setUser: PropTypes.func,
toggleMarkdown: PropTypes.func
}
constructor(props) {
super(props);
this.state = {
placeholder: {},
language: props.userLanguage ? props.userLanguage : 'en',
languages: [{
label: 'English',
value: 'en'
}, {
label: 'Português (BR)',
value: 'pt-BR'
}, {
label: 'Russian',
value: 'ru'
}, {
label: '简体中文',
value: 'zh-CN'
}, {
label: 'Français',
value: 'fr'
}, {
label: 'Deutsch',
value: 'de'
}, {
label: 'Português (PT)',
value: 'pt-PT'
}],
saving: false
};
}
shouldComponentUpdate(nextProps, nextState) {
const { language, saving } = this.state;
const { userLanguage, useMarkdown } = this.props;
if (nextState.language !== language) {
return true;
}
if (nextState.saving !== saving) {
return true;
}
if (nextProps.useMarkdown !== useMarkdown) {
return true;
}
if (nextProps.userLanguage !== userLanguage) {
return true;
}
return false;
}
getLabel = (language) => {
const { languages } = this.state;
const l = languages.find(i => i.value === language);
if (l && l.label) {
return l.label;
}
return null;
}
formIsChanged = () => {
const { userLanguage } = this.props;
const { language } = this.state;
return !(userLanguage === language);
}
submit = async() => {
this.setState({ saving: true });
const { language } = this.state;
const { userLanguage, setUser } = this.props;
if (!this.formIsChanged()) {
return;
}
const params = {};
// language
if (userLanguage !== language) {
params.language = language;
}
try {
await RocketChat.saveUserPreferences(params);
setUser({ language: params.language });
this.setState({ saving: false });
setTimeout(() => {
this.toast.show(I18n.t('Preferences_saved'));
}, 300);
} catch (e) {
this.setState({ saving: false });
setTimeout(() => {
showErrorAlert(I18n.t('There_was_an_error_while_action', { action: I18n.t('saving_preferences') }));
log('err_save_user_preferences', e);
}, 300);
}
}
toggleMarkdown = (value) => {
AsyncStorage.setItem(MARKDOWN_KEY, JSON.stringify(value));
const { toggleMarkdown } = this.props;
toggleMarkdown(value);
firebase.analytics().logEvent('toggle_markdown', { value });
}
navigateToRoom = (room) => {
const { navigation } = this.props;
navigation.navigate(room);
}
sendEmail = async() => {
const subject = encodeURI('React Native 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) {
showErrorAlert(I18n.t('error-email-send-failed', { message: 'support@rocket.chat' }));
}
}
onPressLicense = () => openLink(LICENSE_LINK)
renderDisclosure = () => <DisclosureImage />
renderMarkdownSwitch = () => {
const { useMarkdown } = this.props;
return (
<Switch
value={useMarkdown}
trackColor={SWITCH_TRACK_COLOR}
onValueChange={this.toggleMarkdown}
/>
);
}
render() {
const {
language, languages, placeholder, saving
} = this.state;
const { useMarkdown } = this.props;
const { server } = this.props;
return (
<KeyboardView
contentContainerStyle={sharedStyles.container}
keyboardVerticalOffset={128}
>
<SafeAreaView style={sharedStyles.listSafeArea} testID='settings-view'>
<StatusBar />
<ScrollView
contentContainerStyle={sharedStyles.containerScrollView}
testID='settings-view-list'
{...scrollPersistTaps}
contentContainerStyle={sharedStyles.listContentContainer}
showsVerticalScrollIndicator={false}
testID='settings-view-list'
>
<SafeAreaView style={sharedStyles.container} testID='settings-view' forceInset={{ bottom: 'never' }}>
<RNPickerSelect
items={languages}
onValueChange={(value) => {
this.setState({ language: value });
}}
value={language}
placeholder={placeholder}
>
<RCTextInput
inputRef={(e) => { this.name = e; }}
label={I18n.t('Language')}
placeholder={I18n.t('Language')}
value={this.getLabel(language)}
<ListItem
title={I18n.t('Contact_us')}
onPress={this.sendEmail}
showActionIndicator
testID='settings-view-contact'
right={this.renderDisclosure}
/>
<Separator />
<ListItem
title={I18n.t('Language')}
onPress={() => this.navigateToRoom('LanguageView')}
showActionIndicator
testID='settings-view-language'
right={this.renderDisclosure}
/>
</RNPickerSelect>
<View style={sharedStyles.alignItemsFlexStart}>
<Button
title={I18n.t('Save_Changes')}
type='primary'
onPress={this.submit}
disabled={!this.formIsChanged()}
testID='settings-view-button'
<Separator />
<ListItem
title={I18n.t('Theme')}
showActionIndicator
disabled
testID='settings-view-theme'
/>
</View>
<View style={styles.separator} />
<View style={styles.swithContainer}>
<Text style={styles.label}>{I18n.t('Enable_markdown')}</Text>
<Switch
value={useMarkdown}
onValueChange={this.toggleMarkdown}
onTintColor={COLOR_SUCCESS}
tintColor={isAndroid ? COLOR_DANGER : null}
<Separator />
<ListItem
title={I18n.t('Share_this_app')}
showActionIndicator
disabled
testID='settings-view-share-app'
/>
<SectionSeparator />
<ListItem
title={I18n.t('License')}
onPress={this.onPressLicense}
showActionIndicator
testID='settings-view-license'
right={this.renderDisclosure}
/>
<Separator />
<ListItem title={I18n.t('Version_no', { version: getReadableVersion })} testID='settings-view-version' />
<Separator />
<ListItem
title={I18n.t('Server_version', { version: server.version })}
subtitle={`${ server.server.split('//')[1] }`}
testID='settings-view-server-version'
/>
<SectionSeparator />
<ListItem
title={I18n.t('Enable_markdown')}
testID='settings-view-markdown'
right={() => this.renderMarkdownSwitch()}
/>
</View>
<Loading visible={saving} />
<Toast ref={toast => this.toast = toast} />
</SafeAreaView>
</ScrollView>
</KeyboardView>
</SafeAreaView>
);
}
}

View File

@ -0,0 +1,12 @@
import { StyleSheet } from 'react-native';
import { COLOR_BACKGROUND_CONTAINER } from '../../constants/colors';
import sharedStyles from '../Styles';
export default StyleSheet.create({
sectionSeparatorBorder: {
...sharedStyles.separatorVertical,
backgroundColor: COLOR_BACKGROUND_CONTAINER,
height: 10
}
});

View File

@ -15,7 +15,6 @@ import RocketChat from '../../lib/rocketchat';
import log from '../../utils/log';
import I18n from '../../i18n';
import scrollPersistTaps from '../../utils/scrollPersistTaps';
import { getReadableVersion } from '../../utils/deviceInfo';
import { CustomIcon } from '../../lib/Icons';
import styles from './styles';
import SidebarItem from './SidebarItem';
@ -279,9 +278,6 @@ export default class Sidebar extends Component {
{!showStatus ? this.renderNavigation() : null}
{showStatus ? this.renderStatus() : null}
</ScrollView>
<Text style={styles.version}>
{getReadableVersion}
</Text>
</SafeAreaView>
);
}

View File

@ -1,7 +1,7 @@
import { StyleSheet, Platform } from 'react-native';
import {
COLOR_DANGER, COLOR_BUTTON_PRIMARY, COLOR_SEPARATOR, COLOR_TEXT, COLOR_TEXT_DESCRIPTION, COLOR_TITLE
COLOR_DANGER, COLOR_BUTTON_PRIMARY, COLOR_SEPARATOR, COLOR_TEXT, COLOR_TEXT_DESCRIPTION, COLOR_TITLE, COLOR_BACKGROUND_CONTAINER, COLOR_WHITE, COLOR_PRIMARY
} from '../constants/colors';
export default StyleSheet.create({
@ -176,7 +176,21 @@ export default StyleSheet.create({
textColorDescription: {
color: COLOR_TEXT_DESCRIPTION
},
colorPrimary: {
color: COLOR_PRIMARY
},
inputLastChild: {
marginBottom: 15
},
listSafeArea: {
flex: 1,
backgroundColor: COLOR_BACKGROUND_CONTAINER
},
listContentContainer: {
borderColor: COLOR_SEPARATOR,
borderTopWidth: StyleSheet.hairlineWidth,
borderBottomWidth: StyleSheet.hairlineWidth,
backgroundColor: COLOR_WHITE,
marginVertical: 10
}
});

View File

@ -159,30 +159,30 @@ describe('Room screen', () => {
await element(by.id('messagebox-input')).clearText();
});
it('should show and tap on slash command autocomplete and send slash command', async() => {
await element(by.id('messagebox-input')).tap();
await element(by.id('messagebox-input')).typeText('/');
await waitFor(element(by.id('messagebox-container'))).toBeVisible().withTimeout(10000);
await expect(element(by.id('messagebox-container'))).toBeVisible();
await element(by.id('mention-item-shrug')).tap();
await expect(element(by.id('messagebox-input'))).toHaveText('/shrug ');
await element(by.id('messagebox-input')).typeText('joy'); // workaround for number keyboard
await element(by.id('messagebox-send-message')).tap();
await waitFor(element(by.text(`joy ¯\_(ツ)_/¯`))).toBeVisible().withTimeout(60000);
});
// it('should show and tap on slash command autocomplete and send slash command', async() => {
// await element(by.id('messagebox-input')).tap();
// await element(by.id('messagebox-input')).typeText('/');
// await waitFor(element(by.id('messagebox-container'))).toBeVisible().withTimeout(10000);
// await expect(element(by.id('messagebox-container'))).toBeVisible();
// await element(by.id('mention-item-shrug')).tap();
// await expect(element(by.id('messagebox-input'))).toHaveText('/shrug ');
// await element(by.id('messagebox-input')).typeText('joy'); // workaround for number keyboard
// await element(by.id('messagebox-send-message')).tap();
// await waitFor(element(by.text(`joy ¯\_(ツ)_/¯`))).toBeVisible().withTimeout(60000);
// });
it('should show command Preview', async() => {
await element(by.id('messagebox-input')).tap();
await element(by.id('messagebox-input')).replaceText('/giphy');
await waitFor(element(by.id('messagebox-container'))).toBeVisible().withTimeout(10000);
await expect(element(by.id('messagebox-container'))).toBeVisible();
await element(by.id('mention-item-giphy')).tap();
await expect(element(by.id('messagebox-input'))).toHaveText('/giphy ');
await element(by.id('messagebox-input')).typeText('no'); // workaround for number keyboard
await waitFor(element(by.id('commandbox-container'))).toBeVisible().withTimeout(10000);
await expect(element(by.id('commandbox-container'))).toBeVisible();
await element(by.id('messagebox-input')).clearText();
});
// it('should show command Preview', async() => {
// await element(by.id('messagebox-input')).tap();
// await element(by.id('messagebox-input')).replaceText('/giphy');
// await waitFor(element(by.id('messagebox-container'))).toBeVisible().withTimeout(10000);
// await expect(element(by.id('messagebox-container'))).toBeVisible();
// await element(by.id('mention-item-giphy')).tap();
// await expect(element(by.id('messagebox-input'))).toHaveText('/giphy ');
// await element(by.id('messagebox-input')).typeText('no'); // workaround for number keyboard
// await waitFor(element(by.id('commandbox-container'))).toBeVisible().withTimeout(10000);
// await expect(element(by.id('commandbox-container'))).toBeVisible();
// await element(by.id('messagebox-input')).clearText();
// });
});
describe('Message', async() => {

94
e2e/14-setting.spec.js Normal file
View File

@ -0,0 +1,94 @@
const {
device, expect, element, by, waitFor
} = require('detox');
const { takeScreenshot } = require('./helpers/screenshot');
const { logout, navigateToLogin, login } = require('./helpers/app');
describe('Settings screen', () => {
before(async() => {
await device.reloadReactNative();
await expect(element(by.id('rooms-list-view'))).toBeVisible();
await element(by.id('rooms-list-view-sidebar')).tap();
await waitFor(element(by.id('sidebar-view'))).toBeVisible().withTimeout(2000);
await waitFor(element(by.id('sidebar-settings'))).toBeVisible().withTimeout(2000);
await element(by.id('sidebar-settings')).tap();
await waitFor(element(by.id('settings-view'))).toBeVisible().withTimeout(2000);
});
describe('Render', async() => {
it('should have settings view', async() => {
await expect(element(by.id('settings-view'))).toBeVisible();
});
it('should have language', async() => {
await expect(element(by.id('settings-view-language'))).toExist();
});
it('should have theme', async() => {
await expect(element(by.id('settings-view-theme'))).toExist();
});
it('should have share app', async() => {
await expect(element(by.id('settings-view-share-app'))).toExist();
});
it('should have licence', async() => {
await expect(element(by.id('settings-view-license'))).toExist();
});
it('should have version no', async() => {
await expect(element(by.id('settings-view-version'))).toExist();
});
it('should have server version', async() => {
await expect(element(by.id('settings-view-server-version'))).toExist();
});
it('should have enable markdown', async() => {
await expect(element(by.id('settings-view-markdown'))).toExist();
});
after(async() => {
takeScreenshot();
});
});
describe('Language', async() => {
it('should navigate to language view', async() => {
await element(by.id('settings-view-language')).tap();
await waitFor(element(by.id('language-view'))).toBeVisible().withTimeout(60000);
await expect(element(by.id('language-view-zh-CN'))).toExist();
await expect(element(by.id('language-view-de'))).toExist();
await expect(element(by.id('language-view-en'))).toExist();
await expect(element(by.id('language-view-fr'))).toExist();
await expect(element(by.id('language-view-pt-BR'))).toExist();
await expect(element(by.id('language-view-pt-PT'))).toExist();
await expect(element(by.id('language-view-ru'))).toExist();
});
it('should navigate to change language', async() => {
await expect(element(by.id('language-view-zh-CN'))).toExist();
await element(by.id('language-view-zh-CN')).tap()
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(60000);
await expect(element(by.id('rooms-list-view'))).toBeVisible();
await element(by.id('rooms-list-view-sidebar')).tap();
await waitFor(element(by.id('sidebar-view'))).toBeVisible().withTimeout(2000);
await waitFor(element(by.text('设置'))).toBeVisible().withTimeout(2000);
await element(by.text('设置')).tap();
await waitFor(element(by.id('settings-view'))).toBeVisible().withTimeout(2000);
await element(by.id('settings-view-language')).tap();
await element(by.id('language-view-en')).tap();
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(60000);
await expect(element(by.id('rooms-list-view'))).toBeVisible();
await element(by.id('rooms-list-view-sidebar')).tap();
await waitFor(element(by.id('sidebar-view'))).toBeVisible().withTimeout(2000);
await expect(element(by.text('Settings'))).toBeVisible();
await element(by.text('Settings')).tap();
await expect(element(by.id('settings-view'))).toBeVisible();
});
after(async() => {
takeScreenshot();
});
});
});