[NEW] Onboarding (#407)
<!-- INSTRUCTION: Keep the line below to notify all core developers about this new PR --> @RocketChat/ReactNative <!-- INSTRUCTION: Inform the issue number that this PR closes, or remove the line below --> Closes #392 <!-- INSTRUCTION: Tell us more about your PR with screen shots if you can --> ![aug-07-2018 17-03-50](https://user-images.githubusercontent.com/804994/43799447-f62074dc-9a63-11e8-8aac-bf2c4c5a8a2b.gif) ![aug-07-2018 17-03-35](https://user-images.githubusercontent.com/804994/43799446-f5f84a70-9a63-11e8-8947-265113ae9bf4.gif) ![aug-07-2018 17-03-13](https://user-images.githubusercontent.com/804994/43799445-f5d70ee6-9a63-11e8-94a9-f49c7d69fbba.gif)
|
@ -71,12 +71,12 @@ jobs:
|
||||||
- run:
|
- run:
|
||||||
name: Build
|
name: Build
|
||||||
command: |
|
command: |
|
||||||
detox build
|
detox build --configuration ios.sim.release
|
||||||
|
|
||||||
- run:
|
- run:
|
||||||
name: Test
|
name: Test
|
||||||
command: |
|
command: |
|
||||||
detox test
|
detox test --configuration ios.sim.release --cleanup
|
||||||
|
|
||||||
- store_artifacts:
|
- store_artifacts:
|
||||||
path: /tmp/screenshots
|
path: /tmp/screenshots
|
||||||
|
|
|
@ -102,6 +102,7 @@ exports[`render channel 1`] = `
|
||||||
"fontStyle": "normal",
|
"fontStyle": "normal",
|
||||||
"fontWeight": "normal",
|
"fontWeight": "normal",
|
||||||
},
|
},
|
||||||
|
Object {},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -259,6 +260,7 @@ exports[`render no icon 1`] = `
|
||||||
"fontStyle": "normal",
|
"fontStyle": "normal",
|
||||||
"fontWeight": "normal",
|
"fontWeight": "normal",
|
||||||
},
|
},
|
||||||
|
Object {},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -416,6 +418,7 @@ exports[`render private group 1`] = `
|
||||||
"fontStyle": "normal",
|
"fontStyle": "normal",
|
||||||
"fontWeight": "normal",
|
"fontWeight": "normal",
|
||||||
},
|
},
|
||||||
|
Object {},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -636,6 +639,7 @@ exports[`render unread +999 1`] = `
|
||||||
"fontStyle": "normal",
|
"fontStyle": "normal",
|
||||||
"fontWeight": "normal",
|
"fontWeight": "normal",
|
||||||
},
|
},
|
||||||
|
Object {},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -875,6 +879,7 @@ exports[`render unread 1`] = `
|
||||||
"fontStyle": "normal",
|
"fontStyle": "normal",
|
||||||
"fontWeight": "normal",
|
"fontWeight": "normal",
|
||||||
},
|
},
|
||||||
|
Object {},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -1114,6 +1119,7 @@ exports[`renders correctly 1`] = `
|
||||||
"fontStyle": "normal",
|
"fontStyle": "normal",
|
||||||
"fontWeight": "normal",
|
"fontWeight": "normal",
|
||||||
},
|
},
|
||||||
|
Object {},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|
|
@ -460,6 +460,7 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
|
||||||
"fontStyle": "normal",
|
"fontStyle": "normal",
|
||||||
"fontWeight": "normal",
|
"fontWeight": "normal",
|
||||||
},
|
},
|
||||||
|
Object {},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -674,6 +675,7 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
|
||||||
"fontStyle": "normal",
|
"fontStyle": "normal",
|
||||||
"fontWeight": "normal",
|
"fontWeight": "normal",
|
||||||
},
|
},
|
||||||
|
Object {},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -892,6 +894,7 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
|
||||||
"fontStyle": "normal",
|
"fontStyle": "normal",
|
||||||
"fontWeight": "normal",
|
"fontWeight": "normal",
|
||||||
},
|
},
|
||||||
|
Object {},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -1126,6 +1129,7 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
|
||||||
"fontStyle": "normal",
|
"fontStyle": "normal",
|
||||||
"fontWeight": "normal",
|
"fontWeight": "normal",
|
||||||
},
|
},
|
||||||
|
Object {},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -1364,6 +1368,7 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
|
||||||
"fontStyle": "normal",
|
"fontStyle": "normal",
|
||||||
"fontWeight": "normal",
|
"fontWeight": "normal",
|
||||||
},
|
},
|
||||||
|
Object {},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -1598,6 +1603,7 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
|
||||||
"fontStyle": "normal",
|
"fontStyle": "normal",
|
||||||
"fontWeight": "normal",
|
"fontWeight": "normal",
|
||||||
},
|
},
|
||||||
|
Object {},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -1832,6 +1838,7 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
|
||||||
"fontStyle": "normal",
|
"fontStyle": "normal",
|
||||||
"fontWeight": "normal",
|
"fontWeight": "normal",
|
||||||
},
|
},
|
||||||
|
Object {},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -2066,6 +2073,7 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
|
||||||
"fontStyle": "normal",
|
"fontStyle": "normal",
|
||||||
"fontWeight": "normal",
|
"fontWeight": "normal",
|
||||||
},
|
},
|
||||||
|
Object {},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -2300,6 +2308,7 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
|
||||||
"fontStyle": "normal",
|
"fontStyle": "normal",
|
||||||
"fontWeight": "normal",
|
"fontWeight": "normal",
|
||||||
},
|
},
|
||||||
|
Object {},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -2514,6 +2523,7 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
|
||||||
"fontStyle": "normal",
|
"fontStyle": "normal",
|
||||||
"fontWeight": "normal",
|
"fontWeight": "normal",
|
||||||
},
|
},
|
||||||
|
Object {},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -2728,6 +2738,7 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
|
||||||
"fontStyle": "normal",
|
"fontStyle": "normal",
|
||||||
"fontWeight": "normal",
|
"fontWeight": "normal",
|
||||||
},
|
},
|
||||||
|
Object {},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|
|
@ -10,9 +10,10 @@ const icons = {
|
||||||
[`${ prefix }-menu`]: [30, Ionicons, 'menu'],
|
[`${ prefix }-menu`]: [30, Ionicons, 'menu'],
|
||||||
[`${ prefix }-star`]: [30, Ionicons, 'star'],
|
[`${ prefix }-star`]: [30, Ionicons, 'star'],
|
||||||
[`${ prefix }-star-outline`]: [30, Ionicons, 'starOutline'],
|
[`${ prefix }-star-outline`]: [30, Ionicons, 'starOutline'],
|
||||||
[isIOS ? 'ios-create-outline' : 'md-create']: [30, Ionicons, 'create'],
|
[isIOS ? 'ios-create' : 'md-create']: [30, Ionicons, 'create'],
|
||||||
[`${ prefix }-more`]: [30, Ionicons, 'more'],
|
[`${ prefix }-more`]: [30, Ionicons, 'more'],
|
||||||
[`${ prefix }-add`]: [30, Ionicons, 'add']
|
[`${ prefix }-add`]: [30, Ionicons, 'add'],
|
||||||
|
[`${ prefix }-close`]: [30, Ionicons, 'close']
|
||||||
};
|
};
|
||||||
|
|
||||||
const iconsMap = {};
|
const iconsMap = {};
|
||||||
|
|
|
@ -8,6 +8,7 @@ class NavigationActionsClass {
|
||||||
popToRoot = params => this.navigator && this.navigator.popToRoot(params);
|
popToRoot = params => this.navigator && this.navigator.popToRoot(params);
|
||||||
resetTo = params => this.navigator && this.navigator.resetTo(params);
|
resetTo = params => this.navigator && this.navigator.resetTo(params);
|
||||||
toggleDrawer = params => this.navigator && this.navigator.toggleDrawer(params);
|
toggleDrawer = params => this.navigator && this.navigator.toggleDrawer(params);
|
||||||
|
dismissModal = params => this.navigator && this.navigator.dismissModal(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const NavigationActions = new NavigationActionsClass();
|
export const NavigationActions = new NavigationActionsClass();
|
||||||
|
|
|
@ -76,9 +76,7 @@ export const NAVIGATION = createRequestTypes('NAVIGATION', ['SET']);
|
||||||
export const SERVER = createRequestTypes('SERVER', [
|
export const SERVER = createRequestTypes('SERVER', [
|
||||||
...defaultTypes,
|
...defaultTypes,
|
||||||
'SELECT_SUCCESS',
|
'SELECT_SUCCESS',
|
||||||
'SELECT_REQUEST',
|
'SELECT_REQUEST'
|
||||||
'CHANGED',
|
|
||||||
'ADD'
|
|
||||||
]);
|
]);
|
||||||
export const METEOR = createRequestTypes('METEOR_CONNECT', [...defaultTypes, 'DISCONNECT', 'DISCONNECT_BY_USER']);
|
export const METEOR = createRequestTypes('METEOR_CONNECT', [...defaultTypes, 'DISCONNECT', 'DISCONNECT_BY_USER']);
|
||||||
export const LOGOUT = 'LOGOUT'; // logout is always success
|
export const LOGOUT = 'LOGOUT'; // logout is always success
|
||||||
|
|
|
@ -21,14 +21,6 @@ export function serverRequest(server) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function addServer(server) {
|
|
||||||
return {
|
|
||||||
type: SERVER.ADD,
|
|
||||||
server
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export function serverSuccess() {
|
export function serverSuccess() {
|
||||||
return {
|
return {
|
||||||
type: SERVER.SUCCESS
|
type: SERVER.SUCCESS
|
||||||
|
@ -41,11 +33,3 @@ export function serverFailure(err) {
|
||||||
err
|
err
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function changedServer(server) {
|
|
||||||
return {
|
|
||||||
type: SERVER.CHANGED,
|
|
||||||
server
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,48 +1,53 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { StyleSheet, View, Text, Platform } from 'react-native';
|
import { StyleSheet, View, Text, Platform, ActivityIndicator } from 'react-native';
|
||||||
|
|
||||||
import { COLOR_BUTTON_PRIMARY, COLOR_TEXT } from '../../constants/colors';
|
import { COLOR_BUTTON_PRIMARY, COLOR_TEXT } from '../../constants/colors';
|
||||||
import Touch from '../../utils/touch';
|
import Touch from '../../utils/touch';
|
||||||
|
import { scale, moderateScale, verticalScale } from '../../utils/scaling';
|
||||||
|
|
||||||
const colors = {
|
const colors = {
|
||||||
backgroundPrimary: COLOR_BUTTON_PRIMARY,
|
background_primary: COLOR_BUTTON_PRIMARY,
|
||||||
backgroundSecondary: 'white',
|
background_secondary: 'white',
|
||||||
|
|
||||||
textColorPrimary: 'white',
|
text_color_primary: 'white',
|
||||||
textColorSecondary: COLOR_TEXT
|
text_color_secondary: COLOR_TEXT
|
||||||
};
|
};
|
||||||
|
|
||||||
/* eslint-disable react-native/no-unused-styles */
|
/* eslint-disable react-native/no-unused-styles */
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
paddingHorizontal: 15,
|
paddingHorizontal: scale(15),
|
||||||
paddingVertical: 10
|
justifyContent: 'center',
|
||||||
|
height: scale(48)
|
||||||
},
|
},
|
||||||
text: {
|
text: {
|
||||||
|
fontSize: moderateScale(18),
|
||||||
|
height: verticalScale(20),
|
||||||
|
lineHeight: verticalScale(20),
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
fontWeight: '700'
|
fontWeight: '500'
|
||||||
},
|
},
|
||||||
background_primary: {
|
background_primary: {
|
||||||
backgroundColor: colors.backgroundPrimary
|
backgroundColor: colors.background_primary
|
||||||
},
|
},
|
||||||
background_secondary: {
|
background_secondary: {
|
||||||
backgroundColor: colors.backgroundSecondary
|
backgroundColor: colors.background_secondary
|
||||||
},
|
},
|
||||||
text_color_primary: {
|
text_color_primary: {
|
||||||
color: colors.textColorPrimary
|
color: colors.text_color_primary
|
||||||
},
|
},
|
||||||
text_color_secondary: {
|
text_color_secondary: {
|
||||||
color: colors.textColorSecondary
|
color: colors.text_color_secondary
|
||||||
},
|
},
|
||||||
margin: {
|
margin: {
|
||||||
marginBottom: 10
|
marginBottom: verticalScale(10)
|
||||||
},
|
},
|
||||||
disabled: {
|
disabled: {
|
||||||
opacity: 0.5
|
opacity: 0.5
|
||||||
},
|
},
|
||||||
border: {
|
border: {
|
||||||
borderRadius: 2
|
borderRadius: scale(2)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -53,26 +58,28 @@ export default class Button extends React.PureComponent {
|
||||||
onPress: PropTypes.func,
|
onPress: PropTypes.func,
|
||||||
disabled: PropTypes.bool,
|
disabled: PropTypes.bool,
|
||||||
margin: PropTypes.any,
|
margin: PropTypes.any,
|
||||||
backgroundColor: PropTypes.string
|
backgroundColor: PropTypes.string,
|
||||||
|
loading: PropTypes.bool
|
||||||
}
|
}
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
title: 'Press me!',
|
title: 'Press me!',
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
onPress: () => alert('It works!'),
|
onPress: () => alert('It works!'),
|
||||||
disabled: false
|
disabled: false,
|
||||||
|
loading: false
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
title, type, onPress, disabled, margin, backgroundColor, ...otherProps
|
title, type, onPress, disabled, margin, backgroundColor, loading, ...otherProps
|
||||||
} = this.props;
|
} = this.props;
|
||||||
return (
|
return (
|
||||||
<Touch
|
<Touch
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
accessibilityTraits='button'
|
accessibilityTraits='button'
|
||||||
style={Platform.OS === 'ios' && [(margin || styles.margin), styles.border]}
|
style={Platform.OS === 'ios' && [(margin || styles.margin), styles.border]}
|
||||||
disabled={disabled}
|
disabled={disabled || loading}
|
||||||
{...otherProps}
|
{...otherProps}
|
||||||
>
|
>
|
||||||
<View
|
<View
|
||||||
|
@ -84,7 +91,11 @@ export default class Button extends React.PureComponent {
|
||||||
disabled && styles.disabled
|
disabled && styles.disabled
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<Text style={[styles.text, styles[`text_color_${ type }`]]}>{title}</Text>
|
{
|
||||||
|
loading ?
|
||||||
|
<ActivityIndicator color={colors[`text_color_${ type }`]} /> :
|
||||||
|
<Text style={[styles.text, styles[`text_color_${ type }`]]}>{title}</Text>
|
||||||
|
}
|
||||||
</View>
|
</View>
|
||||||
</Touch>
|
</Touch>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { ScrollView, Text, View, StyleSheet, FlatList, LayoutAnimation, SafeAreaView } from 'react-native';
|
import { ScrollView, Text, View, StyleSheet, FlatList, LayoutAnimation, SafeAreaView, AsyncStorage } from 'react-native';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import FastImage from 'react-native-fast-image';
|
import FastImage from 'react-native-fast-image';
|
||||||
import Icon from 'react-native-vector-icons/MaterialIcons';
|
import Icon from 'react-native-vector-icons/MaterialIcons';
|
||||||
|
|
||||||
import database from '../lib/realm';
|
import database from '../lib/realm';
|
||||||
import { selectServerRequest } from '../actions/server';
|
import { selectServerRequest } from '../actions/server';
|
||||||
|
import { appStart } from '../actions';
|
||||||
import { logout } from '../actions/login';
|
import { logout } from '../actions/login';
|
||||||
import Avatar from '../containers/Avatar';
|
import Avatar from '../containers/Avatar';
|
||||||
import Status from '../containers/status';
|
import Status from '../containers/status';
|
||||||
|
@ -16,6 +17,7 @@ import RocketChat from '../lib/rocketchat';
|
||||||
import log from '../utils/log';
|
import log from '../utils/log';
|
||||||
import I18n from '../i18n';
|
import I18n from '../i18n';
|
||||||
import { NavigationActions } from '../Navigation';
|
import { NavigationActions } from '../Navigation';
|
||||||
|
import scrollPersistTaps from '../utils/scrollPersistTaps';
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
|
@ -86,7 +88,8 @@ const keyExtractor = item => item.id;
|
||||||
}
|
}
|
||||||
}), dispatch => ({
|
}), dispatch => ({
|
||||||
selectServerRequest: server => dispatch(selectServerRequest(server)),
|
selectServerRequest: server => dispatch(selectServerRequest(server)),
|
||||||
logout: () => dispatch(logout())
|
logout: () => dispatch(logout()),
|
||||||
|
appStart: () => dispatch(appStart('outside'))
|
||||||
}))
|
}))
|
||||||
export default class Sidebar extends Component {
|
export default class Sidebar extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -94,7 +97,8 @@ export default class Sidebar extends Component {
|
||||||
server: PropTypes.string.isRequired,
|
server: PropTypes.string.isRequired,
|
||||||
selectServerRequest: PropTypes.func.isRequired,
|
selectServerRequest: PropTypes.func.isRequired,
|
||||||
user: PropTypes.object,
|
user: PropTypes.object,
|
||||||
logout: PropTypes.func.isRequired
|
logout: PropTypes.func.isRequired,
|
||||||
|
appStart: PropTypes.func
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -206,7 +210,7 @@ export default class Sidebar extends Component {
|
||||||
try {
|
try {
|
||||||
RocketChat.setUserPresenceDefaultStatus(item.id);
|
RocketChat.setUserPresenceDefaultStatus(item.id);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log('onPressModalButton', e);
|
log('setUserPresenceDefaultStatus', e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -226,6 +230,21 @@ export default class Sidebar extends Component {
|
||||||
this.toggleServers();
|
this.toggleServers();
|
||||||
if (this.props.server !== item.id) {
|
if (this.props.server !== item.id) {
|
||||||
this.props.selectServerRequest(item.id);
|
this.props.selectServerRequest(item.id);
|
||||||
|
const token = await AsyncStorage.getItem(`${ RocketChat.TOKEN_KEY }-${ item.id }`);
|
||||||
|
if (!token) {
|
||||||
|
this.props.appStart();
|
||||||
|
setTimeout(() => {
|
||||||
|
NavigationActions.push({
|
||||||
|
screen: 'NewServerView',
|
||||||
|
passProps: {
|
||||||
|
server: item.id
|
||||||
|
},
|
||||||
|
navigatorStyle: {
|
||||||
|
navBarHidden: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
testID: `sidebar-${ item.id }`
|
testID: `sidebar-${ item.id }`
|
||||||
|
@ -289,9 +308,12 @@ export default class Sidebar extends Component {
|
||||||
onPress: () => {
|
onPress: () => {
|
||||||
this.closeDrawer();
|
this.closeDrawer();
|
||||||
this.toggleServers();
|
this.toggleServers();
|
||||||
NavigationActions.push({
|
this.props.navigator.showModal({
|
||||||
screen: 'NewServerView',
|
screen: 'NewServerView',
|
||||||
title: I18n.t('Add_Server')
|
title: I18n.t('Add_Server'),
|
||||||
|
passProps: {
|
||||||
|
previousServer: this.props.server
|
||||||
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
testID: 'sidebar-add-server'
|
testID: 'sidebar-add-server'
|
||||||
|
@ -305,8 +327,8 @@ export default class Sidebar extends Component {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<ScrollView style={styles.container}>
|
<SafeAreaView testID='sidebar' style={styles.container}>
|
||||||
<SafeAreaView testID='sidebar' style={styles.container}>
|
<ScrollView style={styles.container} {...scrollPersistTaps}>
|
||||||
<Touch
|
<Touch
|
||||||
onPress={() => this.toggleServers()}
|
onPress={() => this.toggleServers()}
|
||||||
underlayColor='rgba(255, 255, 255, 0.5)'
|
underlayColor='rgba(255, 255, 255, 0.5)'
|
||||||
|
@ -338,8 +360,8 @@ export default class Sidebar extends Component {
|
||||||
|
|
||||||
{!this.state.showServers ? this.renderNavigation() : null}
|
{!this.state.showServers ? this.renderNavigation() : null}
|
||||||
{this.state.showServers ? this.renderServers() : null}
|
{this.state.showServers ? this.renderServers() : null}
|
||||||
</SafeAreaView>
|
</ScrollView>
|
||||||
</ScrollView>
|
</SafeAreaView>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { View, StyleSheet, Text, TextInput, ViewPropTypes, Platform } from 'react-native';
|
import { View, StyleSheet, Text, TextInput, ViewPropTypes, Platform } from 'react-native';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
|
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||||
|
|
||||||
import sharedStyles from '../views/Styles';
|
import sharedStyles from '../views/Styles';
|
||||||
|
@ -21,13 +20,11 @@ const styles = StyleSheet.create({
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
paddingTop: 12,
|
paddingTop: 12,
|
||||||
paddingBottom: 12,
|
paddingBottom: 12,
|
||||||
// paddingTop: 5,
|
|
||||||
// paddingBottom: 5,
|
|
||||||
paddingHorizontal: 10,
|
paddingHorizontal: 10,
|
||||||
borderWidth: 2,
|
borderWidth: 1.5,
|
||||||
borderRadius: 4,
|
borderRadius: 2,
|
||||||
backgroundColor: 'white',
|
backgroundColor: 'white',
|
||||||
borderColor: 'rgba(0,0,0,.15)',
|
borderColor: '#E7EBF2',
|
||||||
color: 'black'
|
color: 'black'
|
||||||
},
|
},
|
||||||
labelError: {
|
labelError: {
|
||||||
|
|
|
@ -65,7 +65,8 @@ export default class Markdown extends React.Component {
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
blocklink: () => {},
|
hardbreak: () => null,
|
||||||
|
blocklink: () => null,
|
||||||
image: node => (
|
image: node => (
|
||||||
// TODO: should use Image component
|
// TODO: should use Image component
|
||||||
<Image key={node.key} style={styles.inlineImage} source={{ uri: node.attributes.src }} />
|
<Image key={node.key} style={styles.inlineImage} source={{ uri: node.attributes.src }} />
|
||||||
|
|
|
@ -116,6 +116,7 @@ export default {
|
||||||
Code: 'Code',
|
Code: 'Code',
|
||||||
Colaborative: 'Colaborative',
|
Colaborative: 'Colaborative',
|
||||||
Connect: 'Connect',
|
Connect: 'Connect',
|
||||||
|
Connect_to_a_server: 'Connect to a server',
|
||||||
Connected_to: 'Connected to',
|
Connected_to: 'Connected to',
|
||||||
Connecting: 'Connecting',
|
Connecting: 'Connecting',
|
||||||
Copied_to_clipboard: 'Copied to clipboard!',
|
Copied_to_clipboard: 'Copied to clipboard!',
|
||||||
|
@ -123,6 +124,7 @@ export default {
|
||||||
Copy_Permalink: 'Copy Permalink',
|
Copy_Permalink: 'Copy Permalink',
|
||||||
Create_account: 'Create account',
|
Create_account: 'Create account',
|
||||||
Create_Channel: 'Create Channel',
|
Create_Channel: 'Create Channel',
|
||||||
|
Create_a_new_workspace: 'Create a new workspace',
|
||||||
Create: 'Create',
|
Create: 'Create',
|
||||||
Delete_Room_Warning: 'Deleting a room will delete all messages posted within the room. This cannot be undone.',
|
Delete_Room_Warning: 'Deleting a room will delete all messages posted within the room. This cannot be undone.',
|
||||||
delete: 'delete',
|
delete: 'delete',
|
||||||
|
@ -153,6 +155,7 @@ export default {
|
||||||
is_a_valid_RocketChat_instance: 'is a valid Rocket.Chat instance',
|
is_a_valid_RocketChat_instance: 'is a valid Rocket.Chat instance',
|
||||||
is_not_a_valid_RocketChat_instance: 'is not a valid Rocket.Chat instance',
|
is_not_a_valid_RocketChat_instance: 'is not a valid Rocket.Chat instance',
|
||||||
is_typing: 'is typing',
|
is_typing: 'is typing',
|
||||||
|
Join_the_community: 'Join the community',
|
||||||
Just_invited_people_can_access_this_channel: 'Just invited people can access this channel',
|
Just_invited_people_can_access_this_channel: 'Just invited people can access this channel',
|
||||||
Language: 'Language',
|
Language: 'Language',
|
||||||
last_message: 'last message',
|
last_message: 'last message',
|
||||||
|
@ -197,9 +200,11 @@ export default {
|
||||||
Notify_active_in_this_room: 'Notify active users in this room',
|
Notify_active_in_this_room: 'Notify active users in this room',
|
||||||
Notify_all_in_this_room: 'Notify all in this room',
|
Notify_all_in_this_room: 'Notify all in this room',
|
||||||
Offline: 'Offline',
|
Offline: 'Offline',
|
||||||
|
Oops: 'Oops!',
|
||||||
Online: 'Online',
|
Online: 'Online',
|
||||||
Only_authorized_users_can_write_new_messages: 'Only authorized users can write new messages',
|
Only_authorized_users_can_write_new_messages: 'Only authorized users can write new messages',
|
||||||
Open_emoji_selector: 'Open emoji selector',
|
Open_emoji_selector: 'Open emoji selector',
|
||||||
|
Open_Source_Communication: 'Open Source Communication',
|
||||||
Or_continue_using_social_accounts: 'Or continue using social accounts',
|
Or_continue_using_social_accounts: 'Or continue using social accounts',
|
||||||
Password: 'Password',
|
Password: 'Password',
|
||||||
Permalink_copied_to_clipboard: 'Permalink copied to clipboard!',
|
Permalink_copied_to_clipboard: 'Permalink copied to clipboard!',
|
||||||
|
@ -274,6 +279,7 @@ export default {
|
||||||
tap_to_change_status: 'tap to change status',
|
tap_to_change_status: 'tap to change status',
|
||||||
Tap_to_view_servers_list: 'Tap to view servers list',
|
Tap_to_view_servers_list: 'Tap to view servers list',
|
||||||
Terms_of_Service: ' Terms of Service ',
|
Terms_of_Service: ' Terms of Service ',
|
||||||
|
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}}!',
|
There_was_an_error_while_action: 'There was an error while {{action}}!',
|
||||||
This_room_is_blocked: 'This room is blocked',
|
This_room_is_blocked: 'This room is blocked',
|
||||||
This_room_is_read_only: 'This room is read only',
|
This_room_is_read_only: 'This room is read only',
|
||||||
|
@ -307,6 +313,7 @@ export default {
|
||||||
Welcome: 'Welcome',
|
Welcome: 'Welcome',
|
||||||
Welcome_title_pt_1: 'Prepare to take off with',
|
Welcome_title_pt_1: 'Prepare to take off with',
|
||||||
Welcome_title_pt_2: 'the ultimate chat platform',
|
Welcome_title_pt_2: 'the ultimate chat platform',
|
||||||
|
Welcome_to_RocketChat: 'Welcome to Rocket.Chat',
|
||||||
Yes_action_it: 'Yes, {{action}} it!',
|
Yes_action_it: 'Yes, {{action}} it!',
|
||||||
Yesterday: 'Yesterday',
|
Yesterday: 'Yesterday',
|
||||||
You_are_in_preview_mode: 'You are in preview mode',
|
You_are_in_preview_mode: 'You are in preview mode',
|
||||||
|
|
25
app/index.js
|
@ -4,7 +4,6 @@ import { Navigation } from 'react-native-navigation';
|
||||||
|
|
||||||
import store from './lib/createStore';
|
import store from './lib/createStore';
|
||||||
import { appInit } from './actions';
|
import { appInit } from './actions';
|
||||||
import database from './lib/realm';
|
|
||||||
import { iconsLoaded } from './Icons';
|
import { iconsLoaded } from './Icons';
|
||||||
import { registerScreens } from './views';
|
import { registerScreens } from './views';
|
||||||
import { deepLinkingOpen } from './actions/deepLinking';
|
import { deepLinkingOpen } from './actions/deepLinking';
|
||||||
|
@ -27,21 +26,21 @@ const startLogged = () => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const startNotLogged = (route) => {
|
const startNotLogged = () => {
|
||||||
Navigation.startSingleScreenApp({
|
Navigation.startSingleScreenApp({
|
||||||
screen: {
|
screen: {
|
||||||
screen: route,
|
screen: 'OnboardingView',
|
||||||
title: route === 'NewServerView' ? I18n.t('New_Server') : I18n.t('Servers')
|
navigatorStyle: {
|
||||||
|
navBarHidden: true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
animationType: 'fade'
|
animationType: 'fade',
|
||||||
|
appStyle: {
|
||||||
|
orientation: 'portrait'
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const hasServers = () => {
|
|
||||||
const db = database.databases.serversDB.objects('servers');
|
|
||||||
return db.length > 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleOpenURL = ({ url }) => {
|
const handleOpenURL = ({ url }) => {
|
||||||
if (url) {
|
if (url) {
|
||||||
url = url.replace(/rocketchat:\/\/|https:\/\/go.rocket.chat\//, '');
|
url = url.replace(/rocketchat:\/\/|https:\/\/go.rocket.chat\//, '');
|
||||||
|
@ -77,11 +76,7 @@ export default class App extends Component {
|
||||||
if (this.currentRoot !== root) {
|
if (this.currentRoot !== root) {
|
||||||
this.currentRoot = root;
|
this.currentRoot = root;
|
||||||
if (root === 'outside') {
|
if (root === 'outside') {
|
||||||
if (hasServers()) {
|
startNotLogged();
|
||||||
startNotLogged('ListServerView');
|
|
||||||
} else {
|
|
||||||
startNotLogged('NewServerView');
|
|
||||||
}
|
|
||||||
} else if (root === 'inside') {
|
} else if (root === 'inside') {
|
||||||
startLogged();
|
startLogged();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,9 @@ import normalizeMessage from './normalizeMessage';
|
||||||
// TODO: delete and update
|
// TODO: delete and update
|
||||||
|
|
||||||
export const merge = (subscription, room) => {
|
export const merge = (subscription, room) => {
|
||||||
|
if (!subscription) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (room) {
|
if (room) {
|
||||||
if (room.rid) {
|
if (room.rid) {
|
||||||
subscription.rid = room.rid;
|
subscription.rid = room.rid;
|
||||||
|
|
|
@ -3,11 +3,10 @@ import { SERVER } from '../actions/actionsTypes';
|
||||||
const initialState = {
|
const initialState = {
|
||||||
connecting: false,
|
connecting: false,
|
||||||
connected: false,
|
connected: false,
|
||||||
errorMessage: '',
|
|
||||||
failure: false,
|
failure: false,
|
||||||
server: '',
|
server: '',
|
||||||
adding: false,
|
loading: true,
|
||||||
loading: true
|
adding: true
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -17,14 +16,8 @@ export default function server(state = initialState, action) {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
connecting: true,
|
connecting: true,
|
||||||
failure: false
|
failure: false,
|
||||||
};
|
adding: true
|
||||||
case SERVER.SUCCESS:
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
connecting: false,
|
|
||||||
connected: true,
|
|
||||||
failure: false
|
|
||||||
};
|
};
|
||||||
case SERVER.FAILURE:
|
case SERVER.FAILURE:
|
||||||
return {
|
return {
|
||||||
|
@ -32,24 +25,22 @@ export default function server(state = initialState, action) {
|
||||||
connecting: false,
|
connecting: false,
|
||||||
connected: false,
|
connected: false,
|
||||||
failure: true,
|
failure: true,
|
||||||
errorMessage: action.err
|
adding: false
|
||||||
};
|
|
||||||
case SERVER.ADD:
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
adding: true
|
|
||||||
};
|
};
|
||||||
case SERVER.SELECT_REQUEST:
|
case SERVER.SELECT_REQUEST:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
server: action.server,
|
server: action.server,
|
||||||
|
connecting: true,
|
||||||
|
connected: false,
|
||||||
loading: true
|
loading: true
|
||||||
};
|
};
|
||||||
case SERVER.SELECT_SUCCESS:
|
case SERVER.SELECT_SUCCESS:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
server: action.server,
|
server: action.server,
|
||||||
adding: false,
|
connecting: false,
|
||||||
|
connected: true,
|
||||||
loading: false
|
loading: false
|
||||||
};
|
};
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -12,7 +12,7 @@ const create = function* create(data) {
|
||||||
|
|
||||||
const handleRequest = function* handleRequest({ data }) {
|
const handleRequest = function* handleRequest({ data }) {
|
||||||
try {
|
try {
|
||||||
yield delay(1000);
|
// yield delay(1000);
|
||||||
const auth = yield select(state => state.login.isAuthenticated);
|
const auth = yield select(state => state.login.isAuthenticated);
|
||||||
if (!auth) {
|
if (!auth) {
|
||||||
yield take(LOGIN.SUCCESS);
|
yield take(LOGIN.SUCCESS);
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { takeLatest, take, select, put } from 'redux-saga/effects';
|
||||||
|
|
||||||
import * as types from '../actions/actionsTypes';
|
import * as types from '../actions/actionsTypes';
|
||||||
import { appStart } from '../actions';
|
import { appStart } from '../actions';
|
||||||
import { selectServerRequest, addServer } from '../actions/server';
|
import { selectServerRequest } from '../actions/server';
|
||||||
import database from '../lib/realm';
|
import database from '../lib/realm';
|
||||||
import RocketChat from '../lib/rocketchat';
|
import RocketChat from '../lib/rocketchat';
|
||||||
import { NavigationActions } from '../Navigation';
|
import { NavigationActions } from '../Navigation';
|
||||||
|
@ -73,7 +73,7 @@ const handleOpen = function* handleOpen({ params }) {
|
||||||
yield navigate({ params, sameServer: false });
|
yield navigate({ params, sameServer: false });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
yield put(addServer(host));
|
yield put(selectServerRequest(host));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,6 +23,7 @@ import {
|
||||||
import RocketChat from '../lib/rocketchat';
|
import RocketChat from '../lib/rocketchat';
|
||||||
import log from '../utils/log';
|
import log from '../utils/log';
|
||||||
import I18n from '../i18n';
|
import I18n from '../i18n';
|
||||||
|
import { NavigationActions } from '../Navigation';
|
||||||
|
|
||||||
const getUser = state => state.login.user;
|
const getUser = state => state.login.user;
|
||||||
const getServer = state => state.server.server;
|
const getServer = state => state.server.server;
|
||||||
|
@ -44,6 +45,7 @@ const handleLoginSuccess = function* handleLoginSuccess() {
|
||||||
yield put(registerIncomplete());
|
yield put(registerIncomplete());
|
||||||
} else {
|
} else {
|
||||||
yield delay(300);
|
yield delay(300);
|
||||||
|
NavigationActions.dismissModal();
|
||||||
yield put(appStart('inside'));
|
yield put(appStart('inside'));
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -103,7 +105,10 @@ const handleLogout = function* handleLogout() {
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRegisterIncomplete = function* handleRegisterIncomplete() {
|
const handleRegisterIncomplete = function* handleRegisterIncomplete() {
|
||||||
yield put(appStart('outside'));
|
const server = yield select(state => state.server);
|
||||||
|
if (!server.adding) {
|
||||||
|
yield put(appStart('outside'));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleForgotPasswordRequest = function* handleForgotPasswordRequest({ email }) {
|
const handleForgotPasswordRequest = function* handleForgotPasswordRequest({ email }) {
|
||||||
|
|
|
@ -1,17 +1,15 @@
|
||||||
import { put, call, takeLatest } from 'redux-saga/effects';
|
import { put, call, takeLatest } from 'redux-saga/effects';
|
||||||
import { delay } from 'redux-saga';
|
|
||||||
import { AsyncStorage } from 'react-native';
|
import { AsyncStorage } from 'react-native';
|
||||||
|
|
||||||
import { NavigationActions } from '../Navigation';
|
import { NavigationActions } from '../Navigation';
|
||||||
import { SERVER } from '../actions/actionsTypes';
|
import { SERVER } from '../actions/actionsTypes';
|
||||||
import * as actions from '../actions';
|
import * as actions from '../actions';
|
||||||
import { connectRequest } from '../actions/connect';
|
import { connectRequest } from '../actions/connect';
|
||||||
import { serverSuccess, serverFailure, selectServerRequest, selectServerSuccess } from '../actions/server';
|
import { serverFailure, selectServerRequest, selectServerSuccess } from '../actions/server';
|
||||||
import { setRoles } from '../actions/roles';
|
import { setRoles } from '../actions/roles';
|
||||||
import RocketChat from '../lib/rocketchat';
|
import RocketChat from '../lib/rocketchat';
|
||||||
import database from '../lib/realm';
|
import database from '../lib/realm';
|
||||||
import log from '../utils/log';
|
import log from '../utils/log';
|
||||||
import I18n from '../i18n';
|
|
||||||
|
|
||||||
const validate = function* validate(server) {
|
const validate = function* validate(server) {
|
||||||
return yield RocketChat.testServer(server);
|
return yield RocketChat.testServer(server);
|
||||||
|
@ -24,8 +22,6 @@ const handleSelectServer = function* handleSelectServer({ server }) {
|
||||||
const token = yield AsyncStorage.getItem(`${ RocketChat.TOKEN_KEY }-${ server }`);
|
const token = yield AsyncStorage.getItem(`${ RocketChat.TOKEN_KEY }-${ server }`);
|
||||||
if (token) {
|
if (token) {
|
||||||
yield put(actions.appStart('inside'));
|
yield put(actions.appStart('inside'));
|
||||||
} else {
|
|
||||||
yield put(actions.appStart('outside'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const settings = database.objects('settings');
|
const settings = database.objects('settings');
|
||||||
|
@ -45,33 +41,22 @@ const handleSelectServer = function* handleSelectServer({ server }) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const validateServer = function* validateServer({ server }) {
|
const handleServerRequest = function* handleServerRequest({ server }) {
|
||||||
try {
|
try {
|
||||||
yield delay(1000);
|
|
||||||
yield call(validate, server);
|
yield call(validate, server);
|
||||||
yield put(serverSuccess());
|
yield call(NavigationActions.push, { screen: 'LoginSignupView', title: server });
|
||||||
} catch (e) {
|
|
||||||
console.warn('validateServer', e);
|
|
||||||
yield put(serverFailure(e));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const addServer = function* addServer({ server }) {
|
|
||||||
try {
|
|
||||||
yield put(actions.appStart('outside'));
|
|
||||||
yield call(NavigationActions.resetTo, { screen: 'ListServerView', title: I18n.t('Servers') });
|
|
||||||
database.databases.serversDB.write(() => {
|
database.databases.serversDB.write(() => {
|
||||||
database.databases.serversDB.create('servers', { id: server, current: false }, true);
|
database.databases.serversDB.create('servers', { id: server, current: false }, true);
|
||||||
});
|
});
|
||||||
yield put(selectServerRequest(server));
|
yield put(selectServerRequest(server));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log('addServer', e);
|
yield put(serverFailure());
|
||||||
|
log('handleServerRequest', e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const root = function* root() {
|
const root = function* root() {
|
||||||
yield takeLatest(SERVER.REQUEST, validateServer);
|
|
||||||
yield takeLatest(SERVER.SELECT_REQUEST, handleSelectServer);
|
yield takeLatest(SERVER.SELECT_REQUEST, handleSelectServer);
|
||||||
yield takeLatest(SERVER.ADD, addServer);
|
yield takeLatest(SERVER.REQUEST, handleServerRequest);
|
||||||
};
|
};
|
||||||
export default root;
|
export default root;
|
||||||
|
|
After Width: | Height: | Size: 1021 B |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 3.0 KiB |
After Width: | Height: | Size: 312 B |
After Width: | Height: | Size: 486 B |
After Width: | Height: | Size: 684 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 94 B |
Before Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 48 KiB |
After Width: | Height: | Size: 111 KiB |
After Width: | Height: | Size: 177 KiB |
Before Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 223 B |
After Width: | Height: | Size: 371 B |
After Width: | Height: | Size: 527 B |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 73 KiB |
|
@ -1,4 +1,4 @@
|
||||||
import CustomTabsAndroid from '../nativeModules/CustomTabsAndroid';
|
import CustomTabsAndroid from '../../nativeModules/CustomTabsAndroid';
|
||||||
|
|
||||||
const openLink = url => CustomTabsAndroid.openURL(url);
|
const openLink = url => CustomTabsAndroid.openURL(url);
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { Dimensions } from 'react-native';
|
||||||
|
|
||||||
|
const { width, height } = Dimensions.get('window');
|
||||||
|
|
||||||
|
const guidelineBaseWidth = 375;
|
||||||
|
const guidelineBaseHeight = 667;
|
||||||
|
|
||||||
|
const scale = size => (width / guidelineBaseWidth) * size;
|
||||||
|
const verticalScale = size => (height / guidelineBaseHeight) * size;
|
||||||
|
const moderateScale = (size, factor = 0.5) => size + ((scale(size) - size) * factor);
|
||||||
|
|
||||||
|
export { scale, verticalScale, moderateScale };
|
|
@ -1,205 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import Icon from 'react-native-vector-icons/Ionicons';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { View, Text, SectionList, StyleSheet, SafeAreaView } from 'react-native';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
|
|
||||||
import LoggedView from './View';
|
|
||||||
import { selectServerRequest } from '../actions/server';
|
|
||||||
import database from '../lib/realm';
|
|
||||||
import Fade from '../animations/fade';
|
|
||||||
import Touch from '../utils/touch';
|
|
||||||
import I18n from '../i18n';
|
|
||||||
import { iconsMap } from '../Icons';
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
container: {
|
|
||||||
flex: 1,
|
|
||||||
backgroundColor: '#fff'
|
|
||||||
},
|
|
||||||
separator: {
|
|
||||||
height: 1,
|
|
||||||
backgroundColor: '#eee'
|
|
||||||
},
|
|
||||||
headerStyle: {
|
|
||||||
backgroundColor: '#eee',
|
|
||||||
lineHeight: 24,
|
|
||||||
paddingLeft: 14,
|
|
||||||
color: '#888'
|
|
||||||
},
|
|
||||||
serverItem: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center',
|
|
||||||
backgroundColor: '#fff',
|
|
||||||
padding: 14
|
|
||||||
},
|
|
||||||
listItem: {
|
|
||||||
color: '#666',
|
|
||||||
flexGrow: 1,
|
|
||||||
lineHeight: 30
|
|
||||||
},
|
|
||||||
serverChecked: {
|
|
||||||
flexGrow: 0
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
@connect(state => ({
|
|
||||||
server: state.server.server,
|
|
||||||
login: state.login,
|
|
||||||
connected: state.meteor.connected
|
|
||||||
}), dispatch => ({
|
|
||||||
selectServerRequest: server => dispatch(selectServerRequest(server))
|
|
||||||
}))
|
|
||||||
/** @extends React.Component */
|
|
||||||
export default class ListServerView extends LoggedView {
|
|
||||||
static propTypes = {
|
|
||||||
navigator: PropTypes.object,
|
|
||||||
login: PropTypes.object.isRequired,
|
|
||||||
selectServerRequest: PropTypes.func.isRequired,
|
|
||||||
server: PropTypes.string
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super('ListServerView', props);
|
|
||||||
this.focused = true;
|
|
||||||
this.state = {
|
|
||||||
sections: []
|
|
||||||
};
|
|
||||||
this.data = database.databases.serversDB.objects('servers');
|
|
||||||
this.data.addListener(this.updateState);
|
|
||||||
props.navigator.setOnNavigatorEvent(this.onNavigatorEvent.bind(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentWillMount() {
|
|
||||||
this.props.navigator.setButtons({
|
|
||||||
rightButtons: [{
|
|
||||||
id: 'addServer',
|
|
||||||
icon: iconsMap.add
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.updateState();
|
|
||||||
this.jumpToSelectedServer();
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
|
||||||
if (this.props.server !== nextProps.server && nextProps.server && !this.props.login.isRegistering) {
|
|
||||||
this.timeout = setTimeout(() => {
|
|
||||||
this.openLogin(nextProps.server);
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
this.data.removeAllListeners();
|
|
||||||
if (this.timeout) {
|
|
||||||
clearTimeout(this.timeout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onNavigatorEvent(event) {
|
|
||||||
if (event.type === 'NavBarButtonPress') {
|
|
||||||
if (event.id === 'addServer') {
|
|
||||||
this.props.navigator.push({
|
|
||||||
screen: 'NewServerView',
|
|
||||||
title: I18n.t('New_Server')
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else if (event.type === 'ScreenChangedEvent') {
|
|
||||||
this.focused = event.id === 'didAppear' || event.id === 'onActivityResumed';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onPressItem = (item) => {
|
|
||||||
this.selectAndNavigateTo(item.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
getState = () => {
|
|
||||||
const sections = [{
|
|
||||||
title: I18n.t('My_servers'),
|
|
||||||
data: this.data
|
|
||||||
}];
|
|
||||||
|
|
||||||
return {
|
|
||||||
...this.state,
|
|
||||||
sections
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
openLogin = (server) => {
|
|
||||||
if (this.focused) {
|
|
||||||
this.props.navigator.push({
|
|
||||||
screen: 'LoginSignupView',
|
|
||||||
title: server
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
selectAndNavigateTo = (server) => {
|
|
||||||
this.props.selectServerRequest(server);
|
|
||||||
this.openLogin(server);
|
|
||||||
}
|
|
||||||
|
|
||||||
jumpToSelectedServer() {
|
|
||||||
if (this.props.server && !this.props.login.isRegistering) {
|
|
||||||
setTimeout(() => {
|
|
||||||
this.openLogin(this.props.server);
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updateState = () => {
|
|
||||||
this.setState(this.getState());
|
|
||||||
}
|
|
||||||
|
|
||||||
renderItem = ({ item }) => (
|
|
||||||
<Touch
|
|
||||||
underlayColor='#ccc'
|
|
||||||
accessibilityTraits='button'
|
|
||||||
onPress={() => { this.onPressItem(item); }}
|
|
||||||
>
|
|
||||||
<View style={styles.serverItem}>
|
|
||||||
<Text
|
|
||||||
style={[styles.listItem]}
|
|
||||||
adjustsFontSizeToFit
|
|
||||||
>
|
|
||||||
{item.id}
|
|
||||||
</Text>
|
|
||||||
<Fade visible={this.props.server === item.id}>
|
|
||||||
<Icon
|
|
||||||
iconSize={24}
|
|
||||||
size={24}
|
|
||||||
style={styles.serverChecked}
|
|
||||||
name='ios-checkmark-circle-outline'
|
|
||||||
/>
|
|
||||||
</Fade>
|
|
||||||
</View>
|
|
||||||
</Touch>
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
renderSectionHeader = ({ section }) => (
|
|
||||||
<Text style={styles.headerStyle}>{section.title}</Text>
|
|
||||||
);
|
|
||||||
|
|
||||||
renderSeparator = () => (
|
|
||||||
<View style={styles.separator} />
|
|
||||||
);
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<SafeAreaView style={styles.container} testID='list-server-view'>
|
|
||||||
<SectionList
|
|
||||||
style={styles.list}
|
|
||||||
sections={this.state.sections}
|
|
||||||
renderItem={this.renderItem}
|
|
||||||
renderSectionHeader={this.renderSectionHeader}
|
|
||||||
keyExtractor={item => item.id}
|
|
||||||
ItemSeparatorComponent={this.renderSeparator}
|
|
||||||
/>
|
|
||||||
</SafeAreaView>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -281,16 +281,11 @@ export default class LoginSignupView extends LoggedView {
|
||||||
>
|
>
|
||||||
<SafeAreaView style={sharedStyles.container} testID='welcome-view'>
|
<SafeAreaView style={sharedStyles.container} testID='welcome-view'>
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<Image
|
|
||||||
source={require('../static/images/logo.png')}
|
|
||||||
style={sharedStyles.loginLogo}
|
|
||||||
resizeMode='center'
|
|
||||||
/>
|
|
||||||
<Text style={[sharedStyles.loginText, styles.header, { color: '#81848A' }]}>{I18n.t('Welcome_title_pt_1')}</Text>
|
<Text style={[sharedStyles.loginText, styles.header, { color: '#81848A' }]}>{I18n.t('Welcome_title_pt_1')}</Text>
|
||||||
<Text style={[sharedStyles.loginText, styles.header]}>{I18n.t('Welcome_title_pt_2')}</Text>
|
<Text style={[sharedStyles.loginText, styles.header]}>{I18n.t('Welcome_title_pt_2')}</Text>
|
||||||
<Image
|
<Image
|
||||||
style={styles.planetImage}
|
style={styles.planetImage}
|
||||||
source={require('../static/images/planet.png')}
|
source={require('../static/images/server.png')}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
title={I18n.t('I_have_an_account')}
|
title={I18n.t('I_have_an_account')}
|
||||||
|
|
|
@ -1,70 +1,137 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Text, ScrollView, View, Keyboard, SafeAreaView } from 'react-native';
|
import { Text, ScrollView, Keyboard, SafeAreaView, Image, Alert, StyleSheet, Platform } from 'react-native';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { serverRequest, addServer } from '../actions/server';
|
import { serverRequest } from '../actions/server';
|
||||||
import KeyboardView from '../presentation/KeyboardView';
|
import sharedStyles from './Styles';
|
||||||
import styles from './Styles';
|
|
||||||
import scrollPersistTaps from '../utils/scrollPersistTaps';
|
import scrollPersistTaps from '../utils/scrollPersistTaps';
|
||||||
import Button from '../containers/Button';
|
import Button from '../containers/Button';
|
||||||
import TextInput from '../containers/TextInput';
|
import TextInput from '../containers/TextInput';
|
||||||
import Loading from '../containers/Loading';
|
|
||||||
import LoggedView from './View';
|
import LoggedView from './View';
|
||||||
import I18n from '../i18n';
|
import I18n from '../i18n';
|
||||||
|
import { scale, verticalScale, moderateScale } from '../utils/scaling';
|
||||||
|
import KeyboardView from '../presentation/KeyboardView';
|
||||||
|
import { iconsMap } from '../Icons';
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
image: {
|
||||||
|
alignSelf: 'center',
|
||||||
|
marginVertical: verticalScale(20)
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
alignSelf: 'center',
|
||||||
|
color: '#2F343D',
|
||||||
|
fontSize: moderateScale(22),
|
||||||
|
fontWeight: 'bold',
|
||||||
|
height: verticalScale(28),
|
||||||
|
lineHeight: verticalScale(28)
|
||||||
|
},
|
||||||
|
inputContainer: {
|
||||||
|
marginTop: scale(20),
|
||||||
|
marginBottom: scale(20)
|
||||||
|
},
|
||||||
|
input: {
|
||||||
|
color: '#9EA2A8',
|
||||||
|
fontSize: moderateScale(17),
|
||||||
|
paddingTop: scale(14),
|
||||||
|
paddingBottom: scale(14),
|
||||||
|
paddingHorizontal: scale(16)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const defaultServer = 'https://open.rocket.chat';
|
||||||
|
|
||||||
@connect(state => ({
|
@connect(state => ({
|
||||||
validInstance: !state.server.failure && !state.server.connecting,
|
connecting: state.server.connecting,
|
||||||
validating: state.server.connecting,
|
failure: state.server.failure,
|
||||||
addingServer: state.server.adding
|
currentServer: state.server.server
|
||||||
}), dispatch => ({
|
}), dispatch => ({
|
||||||
validateServer: url => dispatch(serverRequest(url)),
|
connectServer: (url, adding) => dispatch(serverRequest(url, adding))
|
||||||
addServer: url => dispatch(addServer(url))
|
|
||||||
}))
|
}))
|
||||||
/** @extends React.Component */
|
/** @extends React.Component */
|
||||||
export default class NewServerView extends LoggedView {
|
export default class NewServerView extends LoggedView {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
navigator: PropTypes.object,
|
navigator: PropTypes.object,
|
||||||
validateServer: PropTypes.func.isRequired,
|
server: PropTypes.string,
|
||||||
addServer: PropTypes.func.isRequired,
|
connecting: PropTypes.bool.isRequired,
|
||||||
validating: PropTypes.bool.isRequired,
|
failure: PropTypes.bool.isRequired,
|
||||||
validInstance: PropTypes.bool.isRequired,
|
connectServer: PropTypes.func.isRequired,
|
||||||
addingServer: PropTypes.bool.isRequired
|
previousServer: PropTypes.string,
|
||||||
|
currentServer: PropTypes.string
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super('NewServerView', props);
|
super('NewServerView', props);
|
||||||
this.state = {
|
this.state = {
|
||||||
defaultServer: 'https://open.rocket.chat'
|
text: ''
|
||||||
};
|
};
|
||||||
props.validateServer(this.state.defaultServer); // Need to call because in case of submit with empty field
|
props.navigator.setOnNavigatorEvent(this.onNavigatorEvent.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillMount() {
|
||||||
|
// if previousServer exists, New Server View is a modal
|
||||||
|
if (this.props.previousServer) {
|
||||||
|
const closeButton = {
|
||||||
|
id: 'close',
|
||||||
|
testID: 'new-server-close',
|
||||||
|
title: I18n.t('Close')
|
||||||
|
};
|
||||||
|
if (Platform.OS === 'android') {
|
||||||
|
closeButton.icon = iconsMap.close;
|
||||||
|
}
|
||||||
|
this.props.navigator.setButtons({
|
||||||
|
leftButtons: [closeButton]
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
setTimeout(() => {
|
const { server } = this.props;
|
||||||
this.input.focus();
|
if (server) {
|
||||||
}, 600);
|
this.props.connectServer(server);
|
||||||
|
this.setState({ text: server });
|
||||||
|
} else {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.input.focus();
|
||||||
|
}, 600);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps(nextProps) {
|
||||||
|
if (nextProps.failure && nextProps.failure !== this.props.failure) {
|
||||||
|
Alert.alert(I18n.t('Oops'), I18n.t('The_URL_is_invalid'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onNavigatorEvent(event) {
|
||||||
|
if (event.type === 'NavBarButtonPress') {
|
||||||
|
if (event.id === 'close') {
|
||||||
|
const {
|
||||||
|
navigator, connectServer, previousServer, currentServer
|
||||||
|
} = this.props;
|
||||||
|
navigator.dismissModal();
|
||||||
|
if (previousServer !== currentServer) {
|
||||||
|
connectServer(previousServer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onChangeText = (text) => {
|
onChangeText = (text) => {
|
||||||
this.setState({ text });
|
this.setState({ text });
|
||||||
this.props.validateServer(this.completeUrl(text));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
submit = () => {
|
submit = () => {
|
||||||
if (this.props.validInstance) {
|
if (this.state.text) {
|
||||||
Keyboard.dismiss();
|
Keyboard.dismiss();
|
||||||
this.props.addServer(this.completeUrl(this.state.text));
|
this.props.connectServer(this.completeUrl(this.state.text));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
completeUrl = (url) => {
|
completeUrl = (url) => {
|
||||||
url = url && url.trim();
|
url = url && url.trim();
|
||||||
|
|
||||||
if (!url) {
|
|
||||||
return this.state.defaultServer;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (/^(\w|[0-9-_]){3,}$/.test(url) &&
|
if (/^(\w|[0-9-_]){3,}$/.test(url) &&
|
||||||
/^(htt(ps?)?)|(loca((l)?|(lh)?|(lho)?|(lhos)?|(lhost:?\d*)?)$)/.test(url) === false) {
|
/^(htt(ps?)?)|(loca((l)?|(lh)?|(lho)?|(lhos)?|(lhost:?\d*)?)$)/.test(url) === false) {
|
||||||
url = `${ url }.rocket.chat`;
|
url = `${ url }.rocket.chat`;
|
||||||
|
@ -81,60 +148,39 @@ export default class NewServerView extends LoggedView {
|
||||||
return url.replace(/\/+$/, '');
|
return url.replace(/\/+$/, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
renderValidation = () => {
|
|
||||||
if (this.props.validating) {
|
|
||||||
return (
|
|
||||||
<Text style={[styles.validateText, styles.validatingText]}>
|
|
||||||
{I18n.t('Validating')} {this.state.text || 'open'} ...
|
|
||||||
</Text>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.props.validInstance) {
|
|
||||||
return (
|
|
||||||
<Text style={[styles.validateText, styles.validText]}>
|
|
||||||
{this.state.url} {I18n.t('is_a_valid_RocketChat_instance')}
|
|
||||||
</Text>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<Text style={[styles.validateText, styles.invalidText]}>
|
|
||||||
{this.state.url} {I18n.t('is_not_a_valid_RocketChat_instance')}
|
|
||||||
</Text>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { validInstance } = this.props;
|
const { connecting } = this.props;
|
||||||
|
const { text } = this.state;
|
||||||
return (
|
return (
|
||||||
<KeyboardView
|
<KeyboardView
|
||||||
contentContainerStyle={styles.container}
|
contentContainerStyle={sharedStyles.container}
|
||||||
keyboardVerticalOffset={128}
|
keyboardVerticalOffset={128}
|
||||||
|
key='login-view'
|
||||||
>
|
>
|
||||||
<ScrollView {...scrollPersistTaps} contentContainerStyle={styles.containerScrollView}>
|
<ScrollView {...scrollPersistTaps} contentContainerStyle={sharedStyles.containerScrollView}>
|
||||||
<SafeAreaView style={styles.container} testID='new-server-view'>
|
<SafeAreaView style={sharedStyles.container} testID='new-server-view'>
|
||||||
<Text style={[styles.loginText, styles.loginTitle]}>{I18n.t('Sign_in_your_server')}</Text>
|
<Image style={styles.image} source={require('../static/images/server.png')} />
|
||||||
|
<Text style={styles.title}>{I18n.t('Sign_in_your_server')}</Text>
|
||||||
<TextInput
|
<TextInput
|
||||||
inputRef={e => this.input = e}
|
inputRef={e => this.input = e}
|
||||||
containerStyle={{ marginBottom: 5 }}
|
containerStyle={styles.inputContainer}
|
||||||
label={I18n.t('Your_server')}
|
inputStyle={styles.input}
|
||||||
placeholder={this.state.defaultServer}
|
placeholder={defaultServer}
|
||||||
|
value={text}
|
||||||
returnKeyType='done'
|
returnKeyType='done'
|
||||||
onChangeText={this.onChangeText}
|
onChangeText={this.onChangeText}
|
||||||
testID='new-server-view-input'
|
testID='new-server-view-input'
|
||||||
onSubmitEditing={this.submit}
|
onSubmitEditing={this.submit}
|
||||||
|
clearButtonMode='while-editing'
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
title={I18n.t('Connect')}
|
||||||
|
type='primary'
|
||||||
|
onPress={this.submit}
|
||||||
|
disabled={text.length === 0}
|
||||||
|
loading={connecting}
|
||||||
|
testID='new-server-view-button'
|
||||||
/>
|
/>
|
||||||
{this.renderValidation()}
|
|
||||||
<View style={[styles.alignItemsFlexStart, { marginTop: 20 }]}>
|
|
||||||
<Button
|
|
||||||
title={I18n.t('Connect')}
|
|
||||||
type='primary'
|
|
||||||
onPress={this.submit}
|
|
||||||
disabled={!validInstance}
|
|
||||||
testID='new-server-view-button'
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
<Loading visible={this.props.addingServer} />
|
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</KeyboardView>
|
</KeyboardView>
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { connect } from 'react-redux';
|
||||||
|
|
||||||
import RocketChat from '../lib/rocketchat';
|
import RocketChat from '../lib/rocketchat';
|
||||||
import I18n from '../i18n';
|
import I18n from '../i18n';
|
||||||
|
import { iconsMap } from '../Icons';
|
||||||
|
|
||||||
const userAgentAndroid = 'Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.0 Mobile/14E304 Safari/602.1';
|
const userAgentAndroid = 'Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.0 Mobile/14E304 Safari/602.1';
|
||||||
const userAgent = Platform.OS === 'ios' ? 'UserAgent' : userAgentAndroid;
|
const userAgent = Platform.OS === 'ios' ? 'UserAgent' : userAgentAndroid;
|
||||||
|
@ -16,7 +17,8 @@ export default class TermsServiceView extends React.PureComponent {
|
||||||
static navigatorButtons = {
|
static navigatorButtons = {
|
||||||
leftButtons: [{
|
leftButtons: [{
|
||||||
id: 'close',
|
id: 'close',
|
||||||
title: I18n.t('Close')
|
title: I18n.t('Close'),
|
||||||
|
icon: Platform.OS === 'android' ? iconsMap.close : undefined
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { View, Text, TouchableWithoutFeedback, Image } from 'react-native';
|
||||||
|
|
||||||
|
import styles from './styles';
|
||||||
|
|
||||||
|
export default class Button extends React.PureComponent {
|
||||||
|
static propTypes = {
|
||||||
|
title: PropTypes.string,
|
||||||
|
subtitle: PropTypes.string,
|
||||||
|
type: PropTypes.string,
|
||||||
|
icon: PropTypes.node.isRequired,
|
||||||
|
testID: PropTypes.string.isRequired,
|
||||||
|
onPress: PropTypes.func
|
||||||
|
}
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
title: 'Press me!',
|
||||||
|
type: 'primary',
|
||||||
|
onPress: () => alert('It works!')
|
||||||
|
}
|
||||||
|
|
||||||
|
state = {
|
||||||
|
active: false
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
title, subtitle, type, onPress, icon, testID
|
||||||
|
} = this.props;
|
||||||
|
const { active } = this.state;
|
||||||
|
const activeStyle = active && styles.buttonActive;
|
||||||
|
return (
|
||||||
|
<TouchableWithoutFeedback
|
||||||
|
onPress={onPress}
|
||||||
|
onPressIn={() => this.setState({ active: true })}
|
||||||
|
onPressOut={() => this.setState({ active: false })}
|
||||||
|
testID={testID}
|
||||||
|
>
|
||||||
|
<View style={[styles.buttonContainer, styles[`button_container_${ type }`]]}>
|
||||||
|
<View style={styles.buttonIconContainer}>
|
||||||
|
{icon}
|
||||||
|
</View>
|
||||||
|
<View style={styles.buttonCenter}>
|
||||||
|
<Text style={[styles.buttonTitle, styles[`button_text_${ type }`], activeStyle]}>{title}</Text>
|
||||||
|
{subtitle ? <Text style={[styles.buttonSubtitle, activeStyle]}>{subtitle}</Text> : null}
|
||||||
|
</View>
|
||||||
|
{type === 'secondary' ? <Image source={require('../../static/images/disclosureIndicator.png')} style={styles.buttonIcon} /> : null}
|
||||||
|
</View>
|
||||||
|
</TouchableWithoutFeedback>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,79 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { View, Text, Image, SafeAreaView } from 'react-native';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import I18n from '../../i18n';
|
||||||
|
import openLink from '../../utils/openLink';
|
||||||
|
import Button from './Button';
|
||||||
|
import styles from './styles';
|
||||||
|
import LoggedView from '../View';
|
||||||
|
|
||||||
|
/** @extends React.Component */
|
||||||
|
export default class OnboardingView extends LoggedView {
|
||||||
|
static propTypes = {
|
||||||
|
navigator: PropTypes.object
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super('CreateChannelView', props);
|
||||||
|
}
|
||||||
|
|
||||||
|
connectServer = () => {
|
||||||
|
this.props.navigator.push({
|
||||||
|
screen: 'NewServerView',
|
||||||
|
navigatorStyle: {
|
||||||
|
navBarHidden: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
joinCommunity = () => {
|
||||||
|
this.props.navigator.push({
|
||||||
|
screen: 'NewServerView',
|
||||||
|
passProps: {
|
||||||
|
server: 'https://open.rocket.chat'
|
||||||
|
},
|
||||||
|
navigatorStyle: {
|
||||||
|
navBarHidden: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
createWorkspace = () => {
|
||||||
|
openLink('https://cloud.rocket.chat/trial');
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<SafeAreaView style={styles.container} testID='onboarding-view'>
|
||||||
|
<Image style={styles.onboarding} source={require('../../static/images/onboarding.png')} />
|
||||||
|
<Text style={styles.title}>{I18n.t('Welcome_to_RocketChat')}</Text>
|
||||||
|
<Text style={styles.subtitle}>{I18n.t('Open_Source_Communication')}</Text>
|
||||||
|
<View style={styles.buttonsContainer}>
|
||||||
|
<Button
|
||||||
|
type='secondary'
|
||||||
|
title={I18n.t('Connect_to_a_server')}
|
||||||
|
icon={<Image source={require('../../static/images/connectServer.png')} />}
|
||||||
|
onPress={this.connectServer}
|
||||||
|
testID='connect-server-button'
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
type='secondary'
|
||||||
|
title={I18n.t('Join_the_community')}
|
||||||
|
subtitle='open.rocket.chat'
|
||||||
|
icon={<Image source={require('../../static/images/logoSmall.png')} />}
|
||||||
|
onPress={this.joinCommunity}
|
||||||
|
testID='join-community-button'
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
type='primary'
|
||||||
|
title={I18n.t('Create_a_new_workspace')}
|
||||||
|
icon={<Image source={require('../../static/images/plusWhite.png')} />}
|
||||||
|
onPress={this.createWorkspace}
|
||||||
|
testID='create-workspace-button'
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</SafeAreaView>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,98 @@
|
||||||
|
import { StyleSheet } from 'react-native';
|
||||||
|
|
||||||
|
import { verticalScale, scale, moderateScale } from '../../utils/scaling';
|
||||||
|
|
||||||
|
const colors = {
|
||||||
|
backgroundPrimary: '#1D74F5',
|
||||||
|
backgroundSecondary: 'white',
|
||||||
|
|
||||||
|
textColorPrimary: 'white',
|
||||||
|
textColorSecondary: '#1D74F5',
|
||||||
|
|
||||||
|
borderColorPrimary: '#1D74F5',
|
||||||
|
borderColorSecondary: '#E1E5E8'
|
||||||
|
};
|
||||||
|
|
||||||
|
export default StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
flexDirection: 'column',
|
||||||
|
backgroundColor: '#fff'
|
||||||
|
},
|
||||||
|
onboarding: {
|
||||||
|
alignSelf: 'center',
|
||||||
|
paddingHorizontal: scale(45),
|
||||||
|
marginTop: verticalScale(30),
|
||||||
|
marginBottom: verticalScale(50),
|
||||||
|
maxHeight: verticalScale(250),
|
||||||
|
resizeMode: 'contain'
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
alignSelf: 'center',
|
||||||
|
color: '#2F343D',
|
||||||
|
fontSize: moderateScale(24),
|
||||||
|
height: moderateScale(28),
|
||||||
|
lineHeight: moderateScale(28),
|
||||||
|
fontWeight: 'bold'
|
||||||
|
},
|
||||||
|
subtitle: {
|
||||||
|
alignSelf: 'center',
|
||||||
|
color: '#54585E',
|
||||||
|
fontSize: moderateScale(16),
|
||||||
|
height: moderateScale(20),
|
||||||
|
lineHeight: moderateScale(20),
|
||||||
|
fontWeight: 'normal'
|
||||||
|
},
|
||||||
|
buttonsContainer: {
|
||||||
|
marginBottom: verticalScale(10),
|
||||||
|
marginTop: verticalScale(30)
|
||||||
|
},
|
||||||
|
buttonContainer: {
|
||||||
|
marginHorizontal: scale(15),
|
||||||
|
marginVertical: scale(5),
|
||||||
|
flexDirection: 'row',
|
||||||
|
height: verticalScale(60),
|
||||||
|
alignItems: 'center',
|
||||||
|
borderWidth: StyleSheet.hairlineWidth,
|
||||||
|
borderRadius: moderateScale(2)
|
||||||
|
},
|
||||||
|
buttonCenter: {
|
||||||
|
flex: 1,
|
||||||
|
flexDirection: 'column',
|
||||||
|
justifyContent: 'center'
|
||||||
|
},
|
||||||
|
buttonTitle: {
|
||||||
|
fontSize: moderateScale(16),
|
||||||
|
fontWeight: '600'
|
||||||
|
},
|
||||||
|
buttonSubtitle: {
|
||||||
|
color: '#9EA2A8',
|
||||||
|
fontSize: moderateScale(14),
|
||||||
|
height: moderateScale(18)
|
||||||
|
},
|
||||||
|
buttonIconContainer: {
|
||||||
|
width: 65,
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
},
|
||||||
|
buttonIcon: {
|
||||||
|
marginHorizontal: scale(20)
|
||||||
|
},
|
||||||
|
buttonActive: {
|
||||||
|
opacity: 0.5
|
||||||
|
},
|
||||||
|
button_container_primary: {
|
||||||
|
backgroundColor: colors.backgroundPrimary,
|
||||||
|
borderColor: colors.borderColorPrimary
|
||||||
|
},
|
||||||
|
button_container_secondary: {
|
||||||
|
backgroundColor: colors.backgroundSecondary,
|
||||||
|
borderColor: colors.borderColorSecondary
|
||||||
|
},
|
||||||
|
button_text_primary: {
|
||||||
|
color: colors.textColorPrimary
|
||||||
|
},
|
||||||
|
button_text_secondary: {
|
||||||
|
color: colors.textColorSecondary
|
||||||
|
}
|
||||||
|
});
|
|
@ -17,6 +17,7 @@ import { leaveRoom } from '../../actions/room';
|
||||||
import log from '../../utils/log';
|
import log from '../../utils/log';
|
||||||
import RoomTypeIcon from '../../containers/RoomTypeIcon';
|
import RoomTypeIcon from '../../containers/RoomTypeIcon';
|
||||||
import I18n from '../../i18n';
|
import I18n from '../../i18n';
|
||||||
|
import scrollPersistTaps from '../../utils/scrollPersistTaps';
|
||||||
|
|
||||||
const renderSeparator = () => <View style={styles.separator} />;
|
const renderSeparator = () => <View style={styles.separator} />;
|
||||||
const getRoomTitle = room => (room.t === 'd' ? <Text>{room.fname}</Text> : <Text><RoomTypeIcon type={room.t} /> {room.name}</Text>);
|
const getRoomTitle = room => (room.t === 'd' ? <Text>{room.fname}</Text> : <Text><RoomTypeIcon type={room.t} /> {room.name}</Text>);
|
||||||
|
@ -122,13 +123,13 @@ export default class RoomActionsView extends LoggedView {
|
||||||
}, {
|
}, {
|
||||||
data: [
|
data: [
|
||||||
{
|
{
|
||||||
icon: 'ios-call-outline',
|
icon: 'ios-call',
|
||||||
name: I18n.t('Voice_call'),
|
name: I18n.t('Voice_call'),
|
||||||
disabled: true,
|
disabled: true,
|
||||||
testID: 'room-actions-voice'
|
testID: 'room-actions-voice'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'ios-videocam-outline',
|
icon: 'ios-videocam',
|
||||||
name: I18n.t('Video_call'),
|
name: I18n.t('Video_call'),
|
||||||
disabled: true,
|
disabled: true,
|
||||||
testID: 'room-actions-video'
|
testID: 'room-actions-video'
|
||||||
|
@ -145,14 +146,14 @@ export default class RoomActionsView extends LoggedView {
|
||||||
testID: 'room-actions-files'
|
testID: 'room-actions-files'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'ios-at-outline',
|
icon: 'ios-at',
|
||||||
name: I18n.t('Mentions'),
|
name: I18n.t('Mentions'),
|
||||||
route: 'MentionedMessagesView',
|
route: 'MentionedMessagesView',
|
||||||
params: { rid },
|
params: { rid },
|
||||||
testID: 'room-actions-mentioned'
|
testID: 'room-actions-mentioned'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'ios-star-outline',
|
icon: 'ios-star',
|
||||||
name: I18n.t('Starred'),
|
name: I18n.t('Starred'),
|
||||||
route: 'StarredMessagesView',
|
route: 'StarredMessagesView',
|
||||||
params: { rid },
|
params: { rid },
|
||||||
|
@ -166,7 +167,7 @@ export default class RoomActionsView extends LoggedView {
|
||||||
testID: 'room-actions-search'
|
testID: 'room-actions-search'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'ios-share-outline',
|
icon: 'ios-share',
|
||||||
name: I18n.t('Share'),
|
name: I18n.t('Share'),
|
||||||
disabled: true,
|
disabled: true,
|
||||||
testID: 'room-actions-share'
|
testID: 'room-actions-share'
|
||||||
|
@ -186,7 +187,7 @@ export default class RoomActionsView extends LoggedView {
|
||||||
testID: 'room-actions-snippeted'
|
testID: 'room-actions-snippeted'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: `ios-notifications${ notifications ? '' : '-off' }-outline`,
|
icon: `ios-notifications${ notifications ? '' : '-off' }`,
|
||||||
name: I18n.t(`${ notifications ? 'Enable' : 'Disable' }_notifications`),
|
name: I18n.t(`${ notifications ? 'Enable' : 'Disable' }_notifications`),
|
||||||
event: () => this.toggleNotifications(),
|
event: () => this.toggleNotifications(),
|
||||||
testID: 'room-actions-notifications'
|
testID: 'room-actions-notifications'
|
||||||
|
@ -403,6 +404,7 @@ export default class RoomActionsView extends LoggedView {
|
||||||
ItemSeparatorComponent={renderSeparator}
|
ItemSeparatorComponent={renderSeparator}
|
||||||
keyExtractor={item => item.name}
|
keyExtractor={item => item.name}
|
||||||
testID='room-actions-list'
|
testID='room-actions-list'
|
||||||
|
{...scrollPersistTaps}
|
||||||
/>
|
/>
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
);
|
);
|
||||||
|
|
|
@ -72,7 +72,7 @@ export default class RoomView extends LoggedView {
|
||||||
props.navigator.setOnNavigatorEvent(this.onNavigatorEvent.bind(this));
|
props.navigator.setOnNavigatorEvent(this.onNavigatorEvent.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
async componentWillMount() {
|
componentWillMount() {
|
||||||
this.props.navigator.setButtons({
|
this.props.navigator.setButtons({
|
||||||
rightButtons: [{
|
rightButtons: [{
|
||||||
id: 'more',
|
id: 'more',
|
||||||
|
@ -267,7 +267,7 @@ export default class RoomView extends LoggedView {
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return <MessageBox onSubmit={this.sendMessage} rid={this.rid} />;
|
return <MessageBox key='room-view-messagebox' onSubmit={this.sendMessage} rid={this.rid} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
renderHeader = () => {
|
renderHeader = () => {
|
||||||
|
@ -282,14 +282,17 @@ export default class RoomView extends LoggedView {
|
||||||
return <ActivityIndicator style={styles.loading} />;
|
return <ActivityIndicator style={styles.loading} />;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<List
|
[
|
||||||
key='room-view-messages'
|
<List
|
||||||
end={this.state.end}
|
key='room-view-messages'
|
||||||
room={this.rid}
|
end={this.state.end}
|
||||||
renderFooter={this.renderHeader}
|
room={this.rid}
|
||||||
onEndReached={this.onEndReached}
|
renderFooter={this.renderHeader}
|
||||||
renderRow={this.renderItem}
|
onEndReached={this.onEndReached}
|
||||||
/>
|
renderRow={this.renderItem}
|
||||||
|
/>,
|
||||||
|
this.renderFooter()
|
||||||
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,7 +300,6 @@ export default class RoomView extends LoggedView {
|
||||||
return (
|
return (
|
||||||
<SafeAreaView style={styles.container} testID='room-view'>
|
<SafeAreaView style={styles.container} testID='room-view'>
|
||||||
{this.renderList()}
|
{this.renderList()}
|
||||||
{this.renderFooter()}
|
|
||||||
{this.state.room._id && this.props.showActions ?
|
{this.state.room._id && this.props.showActions ?
|
||||||
<MessageActions room={this.state.room} user={this.props.user} /> :
|
<MessageActions room={this.state.room} user={this.props.user} /> :
|
||||||
null}
|
null}
|
||||||
|
|
|
@ -8,7 +8,7 @@ export default StyleSheet.create({
|
||||||
flex: 1
|
flex: 1
|
||||||
},
|
},
|
||||||
containerScrollView: {
|
containerScrollView: {
|
||||||
padding: 20
|
padding: 15
|
||||||
},
|
},
|
||||||
label: {
|
label: {
|
||||||
lineHeight: 40,
|
lineHeight: 40,
|
||||||
|
@ -191,11 +191,6 @@ export default StyleSheet.create({
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
marginBottom: 20
|
marginBottom: 20
|
||||||
},
|
},
|
||||||
loginLogo: {
|
|
||||||
width: 50,
|
|
||||||
height: 50,
|
|
||||||
marginVertical: 25
|
|
||||||
},
|
|
||||||
headerButton: {
|
headerButton: {
|
||||||
backgroundColor: 'transparent',
|
backgroundColor: 'transparent',
|
||||||
height: 44,
|
height: 44,
|
||||||
|
|
|
@ -3,12 +3,12 @@ import { Provider } from 'react-redux';
|
||||||
|
|
||||||
import CreateChannelView from './CreateChannelView';
|
import CreateChannelView from './CreateChannelView';
|
||||||
import ForgotPasswordView from './ForgotPasswordView';
|
import ForgotPasswordView from './ForgotPasswordView';
|
||||||
import ListServerView from './ListServerView';
|
|
||||||
import LoginSignupView from './LoginSignupView';
|
import LoginSignupView from './LoginSignupView';
|
||||||
import LoginView from './LoginView';
|
import LoginView from './LoginView';
|
||||||
import MentionedMessagesView from './MentionedMessagesView';
|
import MentionedMessagesView from './MentionedMessagesView';
|
||||||
import NewServerView from './NewServerView';
|
import NewServerView from './NewServerView';
|
||||||
import OAuthView from './OAuthView';
|
import OAuthView from './OAuthView';
|
||||||
|
import OnboardingView from './OnboardingView';
|
||||||
import PinnedMessagesView from './PinnedMessagesView';
|
import PinnedMessagesView from './PinnedMessagesView';
|
||||||
import PrivacyPolicyView from './PrivacyPolicyView';
|
import PrivacyPolicyView from './PrivacyPolicyView';
|
||||||
import ProfileView from './ProfileView';
|
import ProfileView from './ProfileView';
|
||||||
|
@ -32,12 +32,12 @@ import TermsServiceView from './TermsServiceView';
|
||||||
export const registerScreens = (store) => {
|
export const registerScreens = (store) => {
|
||||||
Navigation.registerComponent('CreateChannelView', () => CreateChannelView, store, Provider);
|
Navigation.registerComponent('CreateChannelView', () => CreateChannelView, store, Provider);
|
||||||
Navigation.registerComponent('ForgotPasswordView', () => ForgotPasswordView, store, Provider);
|
Navigation.registerComponent('ForgotPasswordView', () => ForgotPasswordView, store, Provider);
|
||||||
Navigation.registerComponent('ListServerView', () => ListServerView, store, Provider);
|
|
||||||
Navigation.registerComponent('LoginSignupView', () => LoginSignupView, store, Provider);
|
Navigation.registerComponent('LoginSignupView', () => LoginSignupView, store, Provider);
|
||||||
Navigation.registerComponent('LoginView', () => LoginView, store, Provider);
|
Navigation.registerComponent('LoginView', () => LoginView, store, Provider);
|
||||||
Navigation.registerComponent('MentionedMessagesView', () => MentionedMessagesView, store, Provider);
|
Navigation.registerComponent('MentionedMessagesView', () => MentionedMessagesView, store, Provider);
|
||||||
Navigation.registerComponent('NewServerView', () => NewServerView, store, Provider);
|
Navigation.registerComponent('NewServerView', () => NewServerView, store, Provider);
|
||||||
Navigation.registerComponent('OAuthView', () => OAuthView, store, Provider);
|
Navigation.registerComponent('OAuthView', () => OAuthView, store, Provider);
|
||||||
|
Navigation.registerComponent('OnboardingView', () => OnboardingView, store, Provider);
|
||||||
Navigation.registerComponent('PinnedMessagesView', () => PinnedMessagesView, store, Provider);
|
Navigation.registerComponent('PinnedMessagesView', () => PinnedMessagesView, store, Provider);
|
||||||
Navigation.registerComponent('PrivacyPolicyView', () => PrivacyPolicyView, store, Provider);
|
Navigation.registerComponent('PrivacyPolicyView', () => PrivacyPolicyView, store, Provider);
|
||||||
Navigation.registerComponent('ProfileView', () => ProfileView, store, Provider);
|
Navigation.registerComponent('ProfileView', () => ProfileView, store, Provider);
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
const {
|
|
||||||
device, expect, element, by, waitFor
|
|
||||||
} = require('detox');
|
|
||||||
const { takeScreenshot } = require('./helpers/screenshot');
|
|
||||||
const data = require('./data');
|
|
||||||
|
|
||||||
describe('Add server', () => {
|
|
||||||
before(async() => {
|
|
||||||
await waitFor(element(by.id('new-server-view'))).toBeVisible().withTimeout(2000);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Render', async() => {
|
|
||||||
it('should have add server screen', async() => {
|
|
||||||
await expect(element(by.id('new-server-view'))).toBeVisible();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should have server input', async() => {
|
|
||||||
await expect(element(by.id('new-server-view-input'))).toBeVisible();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should have submit button', async() => {
|
|
||||||
await expect(element(by.id('new-server-view-button'))).toBeVisible();
|
|
||||||
});
|
|
||||||
|
|
||||||
after(async() => {
|
|
||||||
takeScreenshot();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Usage', async() => {
|
|
||||||
it('should insert "invalidtest" and get an invalid instance', async() => {
|
|
||||||
await element(by.id('new-server-view-input')).replaceText('invalidtest');
|
|
||||||
await waitFor(element(by.text(' is not a valid Rocket.Chat instance'))).toBeVisible().withTimeout(60000);
|
|
||||||
await expect(element(by.text(' is not a valid Rocket.Chat instance'))).toBeVisible();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should have a button to add a new server', async() => {
|
|
||||||
await element(by.id('new-server-view-input')).replaceText(data.server);
|
|
||||||
await waitFor(element(by.text(' is a valid Rocket.Chat instance'))).toBeVisible().withTimeout(60000);
|
|
||||||
await expect(element(by.id('new-server-view-button'))).toBeVisible();
|
|
||||||
await element(by.id('new-server-view-button')).tap();
|
|
||||||
await waitFor(element(by.id('welcome-view'))).toBeVisible().withTimeout(60000);
|
|
||||||
await expect(element(by.id('welcome-view'))).toBeVisible();
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(async() => {
|
|
||||||
takeScreenshot();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
const {
|
||||||
|
device, expect, element, by, waitFor
|
||||||
|
} = require('detox');
|
||||||
|
const { takeScreenshot } = require('./helpers/screenshot');
|
||||||
|
const data = require('./data');
|
||||||
|
|
||||||
|
describe('Onboarding', () => {
|
||||||
|
before(async() => {
|
||||||
|
await waitFor(element(by.id('onboarding-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Render', async() => {
|
||||||
|
it('should have onboarding screen', async() => {
|
||||||
|
await expect(element(by.id('onboarding-view'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have "Connect to a server"', async() => {
|
||||||
|
await expect(element(by.id('connect-server-button'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have "Join the community"', async() => {
|
||||||
|
await expect(element(by.id('join-community-button'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have "Create a new workspace"', async() => {
|
||||||
|
await expect(element(by.id('create-workspace-button'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async() => {
|
||||||
|
takeScreenshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Usage', async() => {
|
||||||
|
it('should navigate to create new workspace', async() => {
|
||||||
|
// webviews are not supported by detox: https://github.com/wix/detox/issues/136#issuecomment-306591554
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should navigate to join community', async() => {
|
||||||
|
await element(by.id('join-community-button')).tap();
|
||||||
|
await waitFor(element(by.id('welcome-view'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id('welcome-view'))).toBeVisible();
|
||||||
|
await waitFor(element(by.text('https://open.rocket.chat'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.text('https://open.rocket.chat'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should navigate to new server', async() => {
|
||||||
|
await device.reloadReactNative();
|
||||||
|
await waitFor(element(by.id('onboarding-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await element(by.id('connect-server-button')).tap();
|
||||||
|
await waitFor(element(by.id('new-server-view'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id('new-server-view'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should enter an invalid server and get error', async() => {
|
||||||
|
await element(by.id('new-server-view-input')).replaceText('invalidtest');
|
||||||
|
await element(by.id('new-server-view-button')).tap();
|
||||||
|
const errorText = 'The URL you entered is invalid. Check it and try again, please!';
|
||||||
|
await waitFor(element(by.text(errorText))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.text(errorText))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should enter a valid server and navigate to welcome', async() => {
|
||||||
|
await element(by.text('OK')).tap();
|
||||||
|
await element(by.id('new-server-view-input')).replaceText(data.server);
|
||||||
|
await element(by.id('new-server-view-button')).tap();
|
||||||
|
await waitFor(element(by.id('welcome-view'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id('welcome-view'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
afterEach(async() => {
|
||||||
|
takeScreenshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -5,16 +5,17 @@ const { takeScreenshot } = require('./helpers/screenshot');
|
||||||
const { logout, sleep } = require('./helpers/app');
|
const { logout, sleep } = require('./helpers/app');
|
||||||
const data = require('./data');
|
const data = require('./data');
|
||||||
|
|
||||||
async function navigateToRegister() {
|
|
||||||
await waitFor(element(by.id('welcome-view'))).toBeVisible().withTimeout(2000);
|
|
||||||
await element(by.id('welcome-view-register')).tap();
|
|
||||||
await waitFor(element(by.id('register-view'))).toBeVisible().withTimeout(2000);
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('Create user screen', () => {
|
describe('Create user screen', () => {
|
||||||
before(async() => {
|
before(async() => {
|
||||||
await device.reloadReactNative();
|
await device.reloadReactNative();
|
||||||
await navigateToRegister();
|
await waitFor(element(by.id('onboarding-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await element(by.id('connect-server-button')).tap();
|
||||||
|
await waitFor(element(by.id('new-server-view'))).toBeVisible().withTimeout(60000);
|
||||||
|
await element(by.id('new-server-view-input')).replaceText(data.server);
|
||||||
|
await element(by.id('new-server-view-button')).tap();
|
||||||
|
await waitFor(element(by.id('welcome-view'))).toBeVisible().withTimeout(60000);
|
||||||
|
await element(by.id('welcome-view-register')).tap();
|
||||||
|
await waitFor(element(by.id('register-view'))).toBeVisible().withTimeout(2000);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Render', () => {
|
describe('Render', () => {
|
||||||
|
|
|
@ -63,7 +63,8 @@ describe('Login screen', () => {
|
||||||
await tapBack('Welcome');
|
await tapBack('Welcome');
|
||||||
await waitFor(element(by.id('welcome-view'))).toBeVisible().withTimeout(2000);
|
await waitFor(element(by.id('welcome-view'))).toBeVisible().withTimeout(2000);
|
||||||
await expect(element(by.id('welcome-view'))).toBeVisible();
|
await expect(element(by.id('welcome-view'))).toBeVisible();
|
||||||
await navigateToLogin();
|
await element(by.id('welcome-view-login')).tap();
|
||||||
|
await expect(element(by.id('login-view'))).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should insert wrong password and get error', async() => {
|
it('should insert wrong password and get error', async() => {
|
||||||
|
|
|
@ -6,9 +6,9 @@ const { login, navigateToLogin, tapBack } = require('./helpers/app');
|
||||||
const data = require('./data');
|
const data = require('./data');
|
||||||
|
|
||||||
describe('Rooms list screen', () => {
|
describe('Rooms list screen', () => {
|
||||||
before(async() => {
|
// before(async() => {
|
||||||
await device.reloadReactNative(); // TODO: remove this after fix logout subscription
|
// await device.reloadReactNative(); // TODO: remove this after fix logout subscription
|
||||||
});
|
// });
|
||||||
|
|
||||||
describe('Render', async() => {
|
describe('Render', async() => {
|
||||||
it('should have rooms list screen', async() => {
|
it('should have rooms list screen', async() => {
|
||||||
|
@ -71,7 +71,7 @@ describe('Rooms list screen', () => {
|
||||||
await element(by.id('sidebar-add-server')).tap();
|
await element(by.id('sidebar-add-server')).tap();
|
||||||
await waitFor(element(by.id('new-server-view'))).toBeVisible().withTimeout(2000);
|
await waitFor(element(by.id('new-server-view'))).toBeVisible().withTimeout(2000);
|
||||||
await expect(element(by.id('new-server-view'))).toBeVisible();
|
await expect(element(by.id('new-server-view'))).toBeVisible();
|
||||||
await tapBack('Messages');
|
await element(by.text('Close')).tap();
|
||||||
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(2000);
|
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(2000);
|
||||||
await expect(element(by.id('rooms-list-view'))).toBeVisible();
|
await expect(element(by.id('rooms-list-view'))).toBeVisible();
|
||||||
});
|
});
|
||||||
|
@ -81,15 +81,18 @@ describe('Rooms list screen', () => {
|
||||||
await waitFor(element(by.id('sidebar'))).toBeVisible().withTimeout(2000);
|
await waitFor(element(by.id('sidebar'))).toBeVisible().withTimeout(2000);
|
||||||
await waitFor(element(by.id('sidebar-logout'))).toBeVisible().withTimeout(2000);
|
await waitFor(element(by.id('sidebar-logout'))).toBeVisible().withTimeout(2000);
|
||||||
await element(by.id('sidebar-logout')).tap();
|
await element(by.id('sidebar-logout')).tap();
|
||||||
await waitFor(element(by.id('welcome-view'))).toBeVisible().withTimeout(60000);
|
await waitFor(element(by.id('onboarding-view'))).toBeVisible().withTimeout(60000);
|
||||||
await expect(element(by.id('welcome-view'))).toBeVisible();
|
await expect(element(by.id('onboarding-view'))).toBeVisible();
|
||||||
await navigateToLogin();
|
|
||||||
await login();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(async() => {
|
afterEach(async() => {
|
||||||
takeScreenshot();
|
takeScreenshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
after(async() => {
|
||||||
|
await navigateToLogin();
|
||||||
|
await login();
|
||||||
|
})
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,7 +7,7 @@ const { tapBack } = require('./helpers/app');
|
||||||
|
|
||||||
describe('Create room screen', () => {
|
describe('Create room screen', () => {
|
||||||
before(async() => {
|
before(async() => {
|
||||||
await device.reloadReactNative(); // TODO: remove this after fix logout subscription
|
// await device.reloadReactNative(); // TODO: remove this after fix logout subscription
|
||||||
await element(by.id('rooms-list-view-create-channel')).tap();
|
await element(by.id('rooms-list-view-create-channel')).tap();
|
||||||
await waitFor(element(by.id('select-users-view'))).toBeVisible().withTimeout(2000);
|
await waitFor(element(by.id('select-users-view'))).toBeVisible().withTimeout(2000);
|
||||||
});
|
});
|
||||||
|
|
|
@ -149,7 +149,7 @@ describe('Room screen', () => {
|
||||||
await element(by.id('messagebox-input')).typeText('#general');
|
await element(by.id('messagebox-input')).typeText('#general');
|
||||||
await waitFor(element(by.id('messagebox-container'))).toBeVisible().withTimeout(60000);
|
await waitFor(element(by.id('messagebox-container'))).toBeVisible().withTimeout(60000);
|
||||||
await expect(element(by.id('messagebox-container'))).toBeVisible();
|
await expect(element(by.id('messagebox-container'))).toBeVisible();
|
||||||
await element(by.id('mention-item-general')).tap();
|
await element(by.id('mention-item-general')).atIndex(0).tap();
|
||||||
await expect(element(by.id('messagebox-input'))).toHaveText('#general ');
|
await expect(element(by.id('messagebox-input'))).toHaveText('#general ');
|
||||||
await element(by.id('messagebox-input')).clearText();
|
await element(by.id('messagebox-input')).clearText();
|
||||||
});
|
});
|
||||||
|
|
|
@ -289,22 +289,21 @@ describe('Room actions screen', () => {
|
||||||
|
|
||||||
describe('Add User', async() => {
|
describe('Add User', async() => {
|
||||||
it('should add user to the room', async() => {
|
it('should add user to the room', async() => {
|
||||||
const user = 'detoxrn';
|
|
||||||
await waitFor(element(by.id('room-actions-add-user'))).toBeVisible().whileElement(by.id('room-actions-list')).scroll(scrollDown, 'up');
|
await waitFor(element(by.id('room-actions-add-user'))).toBeVisible().whileElement(by.id('room-actions-list')).scroll(scrollDown, 'up');
|
||||||
await element(by.id('room-actions-add-user')).tap();
|
await element(by.id('room-actions-add-user')).tap();
|
||||||
await element(by.id('select-users-view-search')).tap();
|
await element(by.id('select-users-view-search')).tap();
|
||||||
await element(by.id('select-users-view-search')).replaceText(user);
|
await element(by.id('select-users-view-search')).replaceText(data.alternateUser);
|
||||||
await waitFor(element(by.id(`select-users-view-item-${ user }`))).toBeVisible().withTimeout(60000);
|
await waitFor(element(by.id(`select-users-view-item-${ data.alternateUser }`))).toBeVisible().withTimeout(60000);
|
||||||
await expect(element(by.id(`select-users-view-item-${ user }`))).toBeVisible();
|
await expect(element(by.id(`select-users-view-item-${ data.alternateUser }`))).toBeVisible();
|
||||||
await element(by.id(`select-users-view-item-${ user }`)).tap();
|
await element(by.id(`select-users-view-item-${ data.alternateUser }`)).tap();
|
||||||
await waitFor(element(by.id(`selected-user-${ user }`))).toBeVisible().withTimeout(5000);
|
await waitFor(element(by.id(`selected-user-${ data.alternateUser }`))).toBeVisible().withTimeout(5000);
|
||||||
await expect(element(by.id(`selected-user-${ user }`))).toBeVisible();
|
await expect(element(by.id(`selected-user-${ data.alternateUser }`))).toBeVisible();
|
||||||
await element(by.id('selected-users-view-submit')).tap();
|
await element(by.id('selected-users-view-submit')).tap();
|
||||||
await waitFor(element(by.id('room-actions-view'))).toBeVisible().withTimeout(2000);
|
await waitFor(element(by.id('room-actions-view'))).toBeVisible().withTimeout(2000);
|
||||||
await element(by.id('room-actions-members')).tap();
|
await element(by.id('room-actions-members')).tap();
|
||||||
await element(by.id('room-members-view-toggle-status')).tap();
|
await element(by.id('room-members-view-toggle-status')).tap();
|
||||||
await waitFor(element(by.id(`room-members-view-item-${ user }`))).toBeVisible().withTimeout(60000);
|
await waitFor(element(by.id(`room-members-view-item-${ data.alternateUser }`))).toBeVisible().withTimeout(60000);
|
||||||
await expect(element(by.id(`room-members-view-item-${ user }`))).toBeVisible();
|
await expect(element(by.id(`room-members-view-item-${ data.alternateUser }`))).toBeVisible();
|
||||||
await backToActions();
|
await backToActions();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -314,7 +313,6 @@ describe('Room actions screen', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Room Members', async() => {
|
describe('Room Members', async() => {
|
||||||
const user = 'detoxrn';
|
|
||||||
before(async() => {
|
before(async() => {
|
||||||
await element(by.id('room-actions-members')).tap();
|
await element(by.id('room-actions-members')).tap();
|
||||||
await waitFor(element(by.id('room-members-view'))).toExist().withTimeout(2000);
|
await waitFor(element(by.id('room-members-view'))).toExist().withTimeout(2000);
|
||||||
|
@ -323,24 +321,24 @@ describe('Room actions screen', () => {
|
||||||
|
|
||||||
it('should show all users', async() => {
|
it('should show all users', async() => {
|
||||||
await element(by.id('room-members-view-toggle-status')).tap();
|
await element(by.id('room-members-view-toggle-status')).tap();
|
||||||
await waitFor(element(by.id(`room-members-view-item-${ user }`))).toBeVisible().withTimeout(60000);
|
await waitFor(element(by.id(`room-members-view-item-${ data.alternateUser }`))).toBeVisible().withTimeout(60000);
|
||||||
await expect(element(by.id(`room-members-view-item-${ user }`))).toBeVisible();
|
await expect(element(by.id(`room-members-view-item-${ data.alternateUser }`))).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should filter user', async() => {
|
it('should filter user', async() => {
|
||||||
await waitFor(element(by.id(`room-members-view-item-${ user }`))).toBeVisible().withTimeout(60000);
|
await waitFor(element(by.id(`room-members-view-item-${ data.alternateUser }`))).toBeVisible().withTimeout(60000);
|
||||||
await expect(element(by.id(`room-members-view-item-${ user }`))).toBeVisible();
|
await expect(element(by.id(`room-members-view-item-${ data.alternateUser }`))).toBeVisible();
|
||||||
await element(by.id('room-members-view-search')).replaceText('rocket');
|
await element(by.id('room-members-view-search')).replaceText('rocket');
|
||||||
await waitFor(element(by.id(`room-members-view-item-${ user }`))).toBeNotVisible().withTimeout(60000);
|
await waitFor(element(by.id(`room-members-view-item-${ data.alternateUser }`))).toBeNotVisible().withTimeout(60000);
|
||||||
await expect(element(by.id(`room-members-view-item-${ user }`))).toBeNotVisible();
|
await expect(element(by.id(`room-members-view-item-${ data.alternateUser }`))).toBeNotVisible();
|
||||||
await element(by.id('room-members-view-search')).tap();
|
await element(by.id('room-members-view-search')).tap();
|
||||||
await element(by.id('room-members-view-search')).clearText('');
|
await element(by.id('room-members-view-search')).clearText('');
|
||||||
await waitFor(element(by.id(`room-members-view-item-${ user }`))).toBeVisible().withTimeout(60000);
|
await waitFor(element(by.id(`room-members-view-item-${ data.alternateUser }`))).toBeVisible().withTimeout(60000);
|
||||||
await expect(element(by.id(`room-members-view-item-${ user }`))).toBeVisible();
|
await expect(element(by.id(`room-members-view-item-${ data.alternateUser }`))).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should mute user', async() => {
|
it('should mute user', async() => {
|
||||||
await element(by.id(`room-members-view-item-${ user }`)).longPress();
|
await element(by.id(`room-members-view-item-${ data.alternateUser }`)).longPress();
|
||||||
await waitFor(element(by.text('Mute'))).toBeVisible().withTimeout(5000);
|
await waitFor(element(by.text('Mute'))).toBeVisible().withTimeout(5000);
|
||||||
await expect(element(by.text('Mute'))).toBeVisible();
|
await expect(element(by.text('Mute'))).toBeVisible();
|
||||||
await element(by.text('Mute')).tap();
|
await element(by.text('Mute')).tap();
|
||||||
|
@ -348,7 +346,7 @@ describe('Room actions screen', () => {
|
||||||
await expect(element(by.text('User has been muted!'))).toBeVisible();
|
await expect(element(by.text('User has been muted!'))).toBeVisible();
|
||||||
await waitFor(element(by.text('User has been muted!'))).toBeNotVisible().withTimeout(60000);
|
await waitFor(element(by.text('User has been muted!'))).toBeNotVisible().withTimeout(60000);
|
||||||
await expect(element(by.text('User has been muted!'))).toBeNotVisible();
|
await expect(element(by.text('User has been muted!'))).toBeNotVisible();
|
||||||
await element(by.id(`room-members-view-item-${ user }`)).longPress();
|
await element(by.id(`room-members-view-item-${ data.alternateUser }`)).longPress();
|
||||||
await waitFor(element(by.text('Unmute'))).toBeVisible().withTimeout(2000);
|
await waitFor(element(by.text('Unmute'))).toBeVisible().withTimeout(2000);
|
||||||
await expect(element(by.text('Unmute'))).toBeVisible();
|
await expect(element(by.text('Unmute'))).toBeVisible();
|
||||||
await element(by.text('Unmute')).tap();
|
await element(by.text('Unmute')).tap();
|
||||||
|
@ -359,12 +357,12 @@ describe('Room actions screen', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should navigate to direct room', async() => {
|
it('should navigate to direct room', async() => {
|
||||||
await waitFor(element(by.id(`room-members-view-item-${ user }`))).toExist().withTimeout(5000);
|
await waitFor(element(by.id(`room-members-view-item-${ data.alternateUser }`))).toExist().withTimeout(5000);
|
||||||
await element(by.id(`room-members-view-item-${ user }`)).tap();
|
await element(by.id(`room-members-view-item-${ data.alternateUser }`)).tap();
|
||||||
await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(60000);
|
await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(60000);
|
||||||
await expect(element(by.id('room-view'))).toBeVisible();
|
await expect(element(by.id('room-view'))).toBeVisible();
|
||||||
await waitFor(element(by.text(user))).toBeVisible().withTimeout(60000);
|
await waitFor(element(by.text(data.alternateUser))).toBeVisible().withTimeout(60000);
|
||||||
await expect(element(by.text(user))).toBeVisible();
|
await expect(element(by.text(data.alternateUser))).toBeVisible();
|
||||||
await tapBack('Messages');
|
await tapBack('Messages');
|
||||||
await waitFor(element(by.id('room-list-view'))).toBeVisible().withTimeout(2000);
|
await waitFor(element(by.id('room-list-view'))).toBeVisible().withTimeout(2000);
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,6 +7,7 @@ const data = require('./data');
|
||||||
describe('Change server', () => {
|
describe('Change server', () => {
|
||||||
before(async() => {
|
before(async() => {
|
||||||
await device.reloadReactNative();
|
await device.reloadReactNative();
|
||||||
|
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(10000);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add server and create new user', async() => {
|
it('should add server and create new user', async() => {
|
||||||
|
@ -16,10 +17,9 @@ describe('Change server', () => {
|
||||||
await element(by.id('sidebar-toggle-server')).tap();
|
await element(by.id('sidebar-toggle-server')).tap();
|
||||||
await waitFor(element(by.id('sidebar-add-server'))).toBeVisible().withTimeout(2000);
|
await waitFor(element(by.id('sidebar-add-server'))).toBeVisible().withTimeout(2000);
|
||||||
await element(by.id('sidebar-add-server')).tap();
|
await element(by.id('sidebar-add-server')).tap();
|
||||||
await waitFor(element(by.id('new-server-view'))).toBeVisible().withTimeout(2000);
|
// Add server
|
||||||
// Add server
|
await waitFor(element(by.id('new-server-view'))).toBeVisible().withTimeout(60000);
|
||||||
await element(by.id('new-server-view-input')).replaceText(data.alternateServer);
|
await element(by.id('new-server-view-input')).replaceText(data.alternateServer);
|
||||||
await waitFor(element(by.text(' is a valid Rocket.Chat instance'))).toBeVisible().withTimeout(60000);
|
|
||||||
await element(by.id('new-server-view-button')).tap();
|
await element(by.id('new-server-view-button')).tap();
|
||||||
// Navigate to register
|
// Navigate to register
|
||||||
await waitFor(element(by.id('welcome-view'))).toBeVisible().withTimeout(2000);
|
await waitFor(element(by.id('welcome-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
@ -36,7 +36,6 @@ describe('Change server', () => {
|
||||||
await element(by.id('register-view-submit-username')).tap();
|
await element(by.id('register-view-submit-username')).tap();
|
||||||
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(60000);
|
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(60000);
|
||||||
await expect(element(by.id('rooms-list-view'))).toBeVisible();
|
await expect(element(by.id('rooms-list-view'))).toBeVisible();
|
||||||
// await expect(element(by.id('rooms-list-view-sidebar'))).toHaveLabel(`Connected to ${ data.alternateServer }. Tap to view servers list.`);
|
|
||||||
// For a sanity test, to make sure roomslist is showing correct rooms
|
// For a sanity test, to make sure roomslist is showing correct rooms
|
||||||
// app CANNOT show public room created on previous tests
|
// app CANNOT show public room created on previous tests
|
||||||
await waitFor(element(by.id(`rooms-list-view-item-public${ data.random }`))).toBeNotVisible().withTimeout(60000);
|
await waitFor(element(by.id(`rooms-list-view-item-public${ data.random }`))).toBeNotVisible().withTimeout(60000);
|
||||||
|
|
|
@ -89,8 +89,8 @@ describe('Broadcast room', () => {
|
||||||
|
|
||||||
it('should tap on reply button and navigate to direct room', async() => {
|
it('should tap on reply button and navigate to direct room', async() => {
|
||||||
await element(by.text('Reply')).tap();
|
await element(by.text('Reply')).tap();
|
||||||
await waitFor(element(by.text(data.user))).toBeVisible().withTimeout(60000);
|
await waitFor(element(by.text(data.user)).atIndex(0)).toBeVisible().withTimeout(60000);
|
||||||
await expect(element(by.text(data.user))).toBeVisible();
|
await expect(element(by.text(data.user)).atIndex(0)).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should reply broadcasted message', async() => {
|
it('should reply broadcasted message', async() => {
|
||||||
|
|
|
@ -86,7 +86,7 @@ describe('Profile screen', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should change email and password', async() => {
|
it('should change email and password', async() => {
|
||||||
await element(by.id('profile-view-email')).replaceText(`test${ data.email }`);
|
await element(by.id('profile-view-email')).replaceText(`diego.mello+e2e${ data.random }test@rocket.chat`);
|
||||||
await element(by.id('profile-view-new-password')).replaceText(`${ data.password }new`);
|
await element(by.id('profile-view-new-password')).replaceText(`${ data.password }new`);
|
||||||
await element(by.id('profile-view-submit')).tap();
|
await element(by.id('profile-view-submit')).tap();
|
||||||
await waitFor(element(by.id('profile-view-typed-password'))).toBeVisible().withTimeout(10000);
|
await waitFor(element(by.id('profile-view-typed-password'))).toBeVisible().withTimeout(10000);
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
const random = require('./helpers/random');
|
const random = require('./helpers/random');
|
||||||
const value = random(20);
|
const value = random(20);
|
||||||
const data = {
|
const data = {
|
||||||
server: 'https://unstable.rocket.chat',
|
server: 'https://stable.rocket.chat',
|
||||||
alternateServer: 'https://stable.rocket.chat',
|
alternateServer: 'https://open.rocket.chat',
|
||||||
user: `user${ value }`,
|
user: `user${ value }`,
|
||||||
password: `password${ value }`,
|
password: `password${ value }`,
|
||||||
alternateUser: 'detoxrn',
|
alternateUser: 'detox',
|
||||||
alternateUserPassword: '123',
|
alternateUserPassword: '123',
|
||||||
email: `detoxrn+${ value }@rocket.chat`,
|
email: `diego.mello+e2e${ value }@rocket.chat`,
|
||||||
random: value
|
random: value
|
||||||
}
|
}
|
||||||
module.exports = data;
|
module.exports = data;
|
|
@ -4,14 +4,16 @@ const {
|
||||||
const data = require('../data');
|
const data = require('../data');
|
||||||
|
|
||||||
async function addServer() {
|
async function addServer() {
|
||||||
await waitFor(element(by.id('new-server-view'))).toBeVisible().withTimeout(2000);
|
await waitFor(element(by.id('onboarding-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await element(by.id('connect-server-button')).tap();
|
||||||
|
await waitFor(element(by.id('new-server-view'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id('new-server-view'))).toBeVisible();
|
||||||
await element(by.id('new-server-view-input')).replaceText(data.server);
|
await element(by.id('new-server-view-input')).replaceText(data.server);
|
||||||
await waitFor(element(by.text(' is a valid Rocket.Chat instance'))).toBeVisible().withTimeout(2000);
|
|
||||||
await waitFor(element(by.id('new-server-view-button'))).toBeVisible().withTimeout(2000);
|
|
||||||
await element(by.id('new-server-view-button')).tap();
|
await element(by.id('new-server-view-button')).tap();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function navigateToLogin() {
|
async function navigateToLogin() {
|
||||||
|
await addServer();
|
||||||
await waitFor(element(by.id('welcome-view'))).toBeVisible().withTimeout(2000);
|
await waitFor(element(by.id('welcome-view'))).toBeVisible().withTimeout(2000);
|
||||||
await element(by.id('welcome-view-login')).tap();
|
await element(by.id('welcome-view-login')).tap();
|
||||||
await waitFor(element(by.id('login-view'))).toBeVisible().withTimeout(2000);
|
await waitFor(element(by.id('login-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
@ -30,8 +32,8 @@ async function logout() {
|
||||||
await waitFor(element(by.id('sidebar'))).toBeVisible().withTimeout(2000);
|
await waitFor(element(by.id('sidebar'))).toBeVisible().withTimeout(2000);
|
||||||
await waitFor(element(by.id('sidebar-logout'))).toBeVisible().withTimeout(2000);
|
await waitFor(element(by.id('sidebar-logout'))).toBeVisible().withTimeout(2000);
|
||||||
await element(by.id('sidebar-logout')).tap();
|
await element(by.id('sidebar-logout')).tap();
|
||||||
await waitFor(element(by.id('welcome-view'))).toBeVisible().withTimeout(2000);
|
await waitFor(element(by.id('onboarding-view'))).toBeVisible().withTimeout(2000);
|
||||||
await expect(element(by.id('welcome-view'))).toBeVisible();
|
await expect(element(by.id('onboarding-view'))).toBeVisible();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function tapBack(label) {
|
async function tapBack(label) {
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>IDEDidComputeMac32BitWarning</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
57
package.json
|
@ -25,17 +25,18 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/polyfill": "^7.0.0-beta.47",
|
"@babel/polyfill": "^7.0.0-beta.47",
|
||||||
"@remobile/react-native-toast": "^1.0.7",
|
"@remobile/react-native-toast": "^1.0.7",
|
||||||
"@storybook/addons": "^3.4.8",
|
"@storybook/addons": "^3.4.10",
|
||||||
"@storybook/react-native": "^3.4.8",
|
"@storybook/react-native": "^3.4.10",
|
||||||
"deep-equal": "^1.0.1",
|
"deep-equal": "^1.0.1",
|
||||||
"ejson": "^2.1.2",
|
"ejson": "^2.1.2",
|
||||||
"js-base64": "^2.4.6",
|
"js-base64": "^2.4.8",
|
||||||
"js-sha256": "^0.9.0",
|
"js-sha256": "^0.9.0",
|
||||||
"lodash": "^4.17.10",
|
"lodash": "^4.17.10",
|
||||||
"markdown-it-flowdock": "^0.3.7",
|
"markdown-it-flowdock": "^0.3.7",
|
||||||
"moment": "^2.22.2",
|
"moment": "^2.22.2",
|
||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.6.2",
|
||||||
"react": "^16.4.1",
|
"react": "^16.4.2",
|
||||||
|
"react-clone-referenced-element": "^1.0.1",
|
||||||
"react-emojione": "^5.0.0",
|
"react-emojione": "^5.0.0",
|
||||||
"react-native": "^0.56.0",
|
"react-native": "^0.56.0",
|
||||||
"react-native-actionsheet": "^2.4.2",
|
"react-native-actionsheet": "^2.4.2",
|
||||||
|
@ -43,51 +44,51 @@
|
||||||
"react-native-dialog": "^5.1.0",
|
"react-native-dialog": "^5.1.0",
|
||||||
"react-native-fabric": "^0.5.1",
|
"react-native-fabric": "^0.5.1",
|
||||||
"react-native-fast-image": "^4.0.14",
|
"react-native-fast-image": "^4.0.14",
|
||||||
"react-native-i18n": "^2.0.14",
|
"react-native-i18n": "^2.0.15",
|
||||||
"react-native-image-crop-picker": "git+https://github.com/RocketChat/react-native-image-crop-picker.git",
|
"react-native-image-crop-picker": "git+https://github.com/RocketChat/react-native-image-crop-picker.git",
|
||||||
"react-native-image-zoom-viewer": "^2.2.13",
|
"react-native-image-zoom-viewer": "^2.2.14",
|
||||||
"react-native-keyboard-aware-scroll-view": "^0.6.0",
|
"react-native-keyboard-aware-scroll-view": "^0.6.0",
|
||||||
"react-native-keyboard-input": "^5.2.3",
|
"react-native-keyboard-input": "^5.2.3",
|
||||||
"react-native-keyboard-tracking-view": "^5.4.4",
|
"react-native-keyboard-tracking-view": "^5.4.4",
|
||||||
"react-native-markdown-renderer": "^3.2.8",
|
"react-native-markdown-renderer": "^3.2.8",
|
||||||
"react-native-meteor": "^1.4.0",
|
"react-native-meteor": "^1.4.0",
|
||||||
"react-native-modal": "^6.4.0",
|
"react-native-modal": "^6.5.0",
|
||||||
"react-native-navigation": "^1.1.474",
|
"react-native-navigation": "^1.1.479",
|
||||||
"react-native-notifications": "git+https://github.com/RocketChat/react-native-notifications.git",
|
"react-native-notifications": "git+https://github.com/RocketChat/react-native-notifications.git",
|
||||||
"react-native-optimized-flatlist": "^1.0.4",
|
"react-native-optimized-flatlist": "^1.0.4",
|
||||||
"react-native-picker-select": "^4.0.0",
|
"react-native-picker-select": "^4.2.0",
|
||||||
"react-native-responsive-ui": "^1.1.1",
|
"react-native-responsive-ui": "^1.1.1",
|
||||||
"react-native-safari-view": "^2.1.0",
|
"react-native-safari-view": "^2.1.0",
|
||||||
"react-native-scrollable-tab-view": "git+https://github.com/skv-headless/react-native-scrollable-tab-view.git",
|
"react-native-scrollable-tab-view": "git+https://github.com/skv-headless/react-native-scrollable-tab-view.git",
|
||||||
"react-native-slider": "^0.11.0",
|
"react-native-slider": "^0.11.0",
|
||||||
"react-native-svg": "^6.4.1",
|
"react-native-svg": "^6.5.2",
|
||||||
"react-native-svg-image": "^2.0.1",
|
"react-native-svg-image": "^2.0.1",
|
||||||
"react-native-vector-icons": "^4.6.0",
|
"react-native-vector-icons": "^5.0.0",
|
||||||
"react-native-video": "^3.0.0",
|
"react-native-video": "^3.2.0",
|
||||||
"react-native-video-controls": "^2.2.3",
|
"react-native-video-controls": "^2.2.3",
|
||||||
"react-native-zeroconf": "^0.9.0",
|
"react-native-zeroconf": "^0.9.0",
|
||||||
"react-redux": "^5.0.6",
|
"react-redux": "^5.0.6",
|
||||||
"realm": "^2.13.0",
|
"realm": "^2.14.2",
|
||||||
"redux": "^4.0.0",
|
"redux": "^4.0.0",
|
||||||
"redux-enhancer-react-native-appstate": "^0.3.1",
|
"redux-enhancer-react-native-appstate": "^0.3.1",
|
||||||
"redux-immutable-state-invariant": "^2.1.0",
|
"redux-immutable-state-invariant": "^2.1.0",
|
||||||
"redux-saga": "^0.16.0",
|
"redux-saga": "^0.16.0",
|
||||||
"regenerator-runtime": "^0.12.0",
|
"regenerator-runtime": "^0.12.1",
|
||||||
"rn-fetch-blob": "^0.10.11",
|
"rn-fetch-blob": "^0.10.12",
|
||||||
"snyk": "^1.88.1",
|
"snyk": "^1.90.0",
|
||||||
"strip-ansi": "^4.0.0"
|
"strip-ansi": "^4.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "7.0.0-beta.47",
|
"@babel/core": "7.0.0-beta.47",
|
||||||
"@babel/plugin-proposal-decorators": "7.0.0-beta.47",
|
"@babel/plugin-proposal-decorators": "7.0.0-beta.47",
|
||||||
"@storybook/addon-storyshots": "^3.4.8",
|
"@storybook/addon-storyshots": "^3.4.10",
|
||||||
"babel-core": "^7.0.0-beta.47",
|
"babel-core": "^7.0.0-beta.47",
|
||||||
"babel-eslint": "^8.2.6",
|
"babel-eslint": "^8.2.6",
|
||||||
"babel-jest": "^23.4.0",
|
"babel-jest": "^23.4.2",
|
||||||
"babel-plugin-transform-remove-console": "^6.9.4",
|
"babel-plugin-transform-remove-console": "^6.9.4",
|
||||||
"babel-preset-react-native": "^5.0.2",
|
"babel-preset-react-native": "^5.0.2",
|
||||||
"codecov": "^3.0.2",
|
"codecov": "^3.0.4",
|
||||||
"detox": "^8.0.0",
|
"detox": "^8.1.4",
|
||||||
"eslint": "^4.19.1",
|
"eslint": "^4.19.1",
|
||||||
"eslint-config-airbnb": "^16.1.0",
|
"eslint-config-airbnb": "^16.1.0",
|
||||||
"eslint-plugin-import": "^2.13.0",
|
"eslint-plugin-import": "^2.13.0",
|
||||||
|
@ -95,12 +96,12 @@
|
||||||
"eslint-plugin-react": "^7.10.0",
|
"eslint-plugin-react": "^7.10.0",
|
||||||
"eslint-plugin-react-native": "^3.2.0",
|
"eslint-plugin-react-native": "^3.2.0",
|
||||||
"identity-obj-proxy": "^3.0.0",
|
"identity-obj-proxy": "^3.0.0",
|
||||||
"jest": "^23.4.1",
|
"jest": "^23.4.2",
|
||||||
"jest-cli": "^23.4.1",
|
"jest-cli": "^23.4.2",
|
||||||
"mocha": "^5.2.0",
|
"mocha": "^5.2.0",
|
||||||
"react-dom": "^16.4.1",
|
"react-dom": "^16.4.2",
|
||||||
"react-native-bundle-visualizer": "^1.3.0",
|
"react-native-bundle-visualizer": "^1.3.0",
|
||||||
"react-test-renderer": "^16.4.1",
|
"react-test-renderer": "^16.4.2",
|
||||||
"reactotron-react-native": "^2.0.0",
|
"reactotron-react-native": "^2.0.0",
|
||||||
"reactotron-redux": "^2.0.0",
|
"reactotron-redux": "^2.0.0",
|
||||||
"reactotron-redux-saga": "^2.0.0"
|
"reactotron-redux-saga": "^2.0.0"
|
||||||
|
@ -128,7 +129,13 @@
|
||||||
"configurations": {
|
"configurations": {
|
||||||
"ios.sim.debug": {
|
"ios.sim.debug": {
|
||||||
"binaryPath": "ios/build/Build/Products/Debug-iphonesimulator/RocketChatRN.app",
|
"binaryPath": "ios/build/Build/Products/Debug-iphonesimulator/RocketChatRN.app",
|
||||||
"build": "xcodebuild -project ios/RocketChatRN.xcodeproj -scheme RocketChatRN -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build",
|
"build": "xcodebuild -workspace ios/RocketChatRN.xcworkspace -scheme RocketChatRN -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build",
|
||||||
|
"type": "ios.simulator",
|
||||||
|
"name": "iPhone 7"
|
||||||
|
},
|
||||||
|
"ios.sim.release": {
|
||||||
|
"binaryPath": "ios/build/Build/Products/Release-iphonesimulator/RocketChatRN.app",
|
||||||
|
"build": "xcodebuild -workspace ios/RocketChatRN.xcworkspace -scheme RocketChatRN -configuration Release -sdk iphonesimulator -derivedDataPath ios/build",
|
||||||
"type": "ios.simulator",
|
"type": "ios.simulator",
|
||||||
"name": "iPhone 7"
|
"name": "iPhone 7"
|
||||||
}
|
}
|
||||||
|
|