[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:
|
||||
name: Build
|
||||
command: |
|
||||
detox build
|
||||
detox build --configuration ios.sim.release
|
||||
|
||||
- run:
|
||||
name: Test
|
||||
command: |
|
||||
detox test
|
||||
detox test --configuration ios.sim.release --cleanup
|
||||
|
||||
- store_artifacts:
|
||||
path: /tmp/screenshots
|
||||
|
|
|
@ -102,6 +102,7 @@ exports[`render channel 1`] = `
|
|||
"fontStyle": "normal",
|
||||
"fontWeight": "normal",
|
||||
},
|
||||
Object {},
|
||||
]
|
||||
}
|
||||
>
|
||||
|
@ -259,6 +260,7 @@ exports[`render no icon 1`] = `
|
|||
"fontStyle": "normal",
|
||||
"fontWeight": "normal",
|
||||
},
|
||||
Object {},
|
||||
]
|
||||
}
|
||||
>
|
||||
|
@ -416,6 +418,7 @@ exports[`render private group 1`] = `
|
|||
"fontStyle": "normal",
|
||||
"fontWeight": "normal",
|
||||
},
|
||||
Object {},
|
||||
]
|
||||
}
|
||||
>
|
||||
|
@ -636,6 +639,7 @@ exports[`render unread +999 1`] = `
|
|||
"fontStyle": "normal",
|
||||
"fontWeight": "normal",
|
||||
},
|
||||
Object {},
|
||||
]
|
||||
}
|
||||
>
|
||||
|
@ -875,6 +879,7 @@ exports[`render unread 1`] = `
|
|||
"fontStyle": "normal",
|
||||
"fontWeight": "normal",
|
||||
},
|
||||
Object {},
|
||||
]
|
||||
}
|
||||
>
|
||||
|
@ -1114,6 +1119,7 @@ exports[`renders correctly 1`] = `
|
|||
"fontStyle": "normal",
|
||||
"fontWeight": "normal",
|
||||
},
|
||||
Object {},
|
||||
]
|
||||
}
|
||||
>
|
||||
|
|
|
@ -460,6 +460,7 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
|
|||
"fontStyle": "normal",
|
||||
"fontWeight": "normal",
|
||||
},
|
||||
Object {},
|
||||
]
|
||||
}
|
||||
>
|
||||
|
@ -674,6 +675,7 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
|
|||
"fontStyle": "normal",
|
||||
"fontWeight": "normal",
|
||||
},
|
||||
Object {},
|
||||
]
|
||||
}
|
||||
>
|
||||
|
@ -892,6 +894,7 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
|
|||
"fontStyle": "normal",
|
||||
"fontWeight": "normal",
|
||||
},
|
||||
Object {},
|
||||
]
|
||||
}
|
||||
>
|
||||
|
@ -1126,6 +1129,7 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
|
|||
"fontStyle": "normal",
|
||||
"fontWeight": "normal",
|
||||
},
|
||||
Object {},
|
||||
]
|
||||
}
|
||||
>
|
||||
|
@ -1364,6 +1368,7 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
|
|||
"fontStyle": "normal",
|
||||
"fontWeight": "normal",
|
||||
},
|
||||
Object {},
|
||||
]
|
||||
}
|
||||
>
|
||||
|
@ -1598,6 +1603,7 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
|
|||
"fontStyle": "normal",
|
||||
"fontWeight": "normal",
|
||||
},
|
||||
Object {},
|
||||
]
|
||||
}
|
||||
>
|
||||
|
@ -1832,6 +1838,7 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
|
|||
"fontStyle": "normal",
|
||||
"fontWeight": "normal",
|
||||
},
|
||||
Object {},
|
||||
]
|
||||
}
|
||||
>
|
||||
|
@ -2066,6 +2073,7 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
|
|||
"fontStyle": "normal",
|
||||
"fontWeight": "normal",
|
||||
},
|
||||
Object {},
|
||||
]
|
||||
}
|
||||
>
|
||||
|
@ -2300,6 +2308,7 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
|
|||
"fontStyle": "normal",
|
||||
"fontWeight": "normal",
|
||||
},
|
||||
Object {},
|
||||
]
|
||||
}
|
||||
>
|
||||
|
@ -2514,6 +2523,7 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
|
|||
"fontStyle": "normal",
|
||||
"fontWeight": "normal",
|
||||
},
|
||||
Object {},
|
||||
]
|
||||
}
|
||||
>
|
||||
|
@ -2728,6 +2738,7 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
|
|||
"fontStyle": "normal",
|
||||
"fontWeight": "normal",
|
||||
},
|
||||
Object {},
|
||||
]
|
||||
}
|
||||
>
|
||||
|
|
|
@ -10,9 +10,10 @@ const icons = {
|
|||
[`${ prefix }-menu`]: [30, Ionicons, 'menu'],
|
||||
[`${ prefix }-star`]: [30, Ionicons, 'star'],
|
||||
[`${ 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 }-add`]: [30, Ionicons, 'add']
|
||||
[`${ prefix }-add`]: [30, Ionicons, 'add'],
|
||||
[`${ prefix }-close`]: [30, Ionicons, 'close']
|
||||
};
|
||||
|
||||
const iconsMap = {};
|
||||
|
|
|
@ -8,6 +8,7 @@ class NavigationActionsClass {
|
|||
popToRoot = params => this.navigator && this.navigator.popToRoot(params);
|
||||
resetTo = params => this.navigator && this.navigator.resetTo(params);
|
||||
toggleDrawer = params => this.navigator && this.navigator.toggleDrawer(params);
|
||||
dismissModal = params => this.navigator && this.navigator.dismissModal(params);
|
||||
}
|
||||
|
||||
export const NavigationActions = new NavigationActionsClass();
|
||||
|
|
|
@ -76,9 +76,7 @@ export const NAVIGATION = createRequestTypes('NAVIGATION', ['SET']);
|
|||
export const SERVER = createRequestTypes('SERVER', [
|
||||
...defaultTypes,
|
||||
'SELECT_SUCCESS',
|
||||
'SELECT_REQUEST',
|
||||
'CHANGED',
|
||||
'ADD'
|
||||
'SELECT_REQUEST'
|
||||
]);
|
||||
export const METEOR = createRequestTypes('METEOR_CONNECT', [...defaultTypes, 'DISCONNECT', 'DISCONNECT_BY_USER']);
|
||||
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() {
|
||||
return {
|
||||
type: SERVER.SUCCESS
|
||||
|
@ -41,11 +33,3 @@ export function serverFailure(err) {
|
|||
err
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export function changedServer(server) {
|
||||
return {
|
||||
type: SERVER.CHANGED,
|
||||
server
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,48 +1,53 @@
|
|||
import React from 'react';
|
||||
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 Touch from '../../utils/touch';
|
||||
import { scale, moderateScale, verticalScale } from '../../utils/scaling';
|
||||
|
||||
const colors = {
|
||||
backgroundPrimary: COLOR_BUTTON_PRIMARY,
|
||||
backgroundSecondary: 'white',
|
||||
background_primary: COLOR_BUTTON_PRIMARY,
|
||||
background_secondary: 'white',
|
||||
|
||||
textColorPrimary: 'white',
|
||||
textColorSecondary: COLOR_TEXT
|
||||
text_color_primary: 'white',
|
||||
text_color_secondary: COLOR_TEXT
|
||||
};
|
||||
|
||||
/* eslint-disable react-native/no-unused-styles */
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
paddingHorizontal: 15,
|
||||
paddingVertical: 10
|
||||
paddingHorizontal: scale(15),
|
||||
justifyContent: 'center',
|
||||
height: scale(48)
|
||||
},
|
||||
text: {
|
||||
fontSize: moderateScale(18),
|
||||
height: verticalScale(20),
|
||||
lineHeight: verticalScale(20),
|
||||
textAlign: 'center',
|
||||
fontWeight: '700'
|
||||
fontWeight: '500'
|
||||
},
|
||||
background_primary: {
|
||||
backgroundColor: colors.backgroundPrimary
|
||||
backgroundColor: colors.background_primary
|
||||
},
|
||||
background_secondary: {
|
||||
backgroundColor: colors.backgroundSecondary
|
||||
backgroundColor: colors.background_secondary
|
||||
},
|
||||
text_color_primary: {
|
||||
color: colors.textColorPrimary
|
||||
color: colors.text_color_primary
|
||||
},
|
||||
text_color_secondary: {
|
||||
color: colors.textColorSecondary
|
||||
color: colors.text_color_secondary
|
||||
},
|
||||
margin: {
|
||||
marginBottom: 10
|
||||
marginBottom: verticalScale(10)
|
||||
},
|
||||
disabled: {
|
||||
opacity: 0.5
|
||||
},
|
||||
border: {
|
||||
borderRadius: 2
|
||||
borderRadius: scale(2)
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -53,26 +58,28 @@ export default class Button extends React.PureComponent {
|
|||
onPress: PropTypes.func,
|
||||
disabled: PropTypes.bool,
|
||||
margin: PropTypes.any,
|
||||
backgroundColor: PropTypes.string
|
||||
backgroundColor: PropTypes.string,
|
||||
loading: PropTypes.bool
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
title: 'Press me!',
|
||||
type: 'primary',
|
||||
onPress: () => alert('It works!'),
|
||||
disabled: false
|
||||
disabled: false,
|
||||
loading: false
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
title, type, onPress, disabled, margin, backgroundColor, ...otherProps
|
||||
title, type, onPress, disabled, margin, backgroundColor, loading, ...otherProps
|
||||
} = this.props;
|
||||
return (
|
||||
<Touch
|
||||
onPress={onPress}
|
||||
accessibilityTraits='button'
|
||||
style={Platform.OS === 'ios' && [(margin || styles.margin), styles.border]}
|
||||
disabled={disabled}
|
||||
disabled={disabled || loading}
|
||||
{...otherProps}
|
||||
>
|
||||
<View
|
||||
|
@ -84,7 +91,11 @@ export default class Button extends React.PureComponent {
|
|||
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>
|
||||
</Touch>
|
||||
);
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import React, { Component } from 'react';
|
||||
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 FastImage from 'react-native-fast-image';
|
||||
import Icon from 'react-native-vector-icons/MaterialIcons';
|
||||
|
||||
import database from '../lib/realm';
|
||||
import { selectServerRequest } from '../actions/server';
|
||||
import { appStart } from '../actions';
|
||||
import { logout } from '../actions/login';
|
||||
import Avatar from '../containers/Avatar';
|
||||
import Status from '../containers/status';
|
||||
|
@ -16,6 +17,7 @@ import RocketChat from '../lib/rocketchat';
|
|||
import log from '../utils/log';
|
||||
import I18n from '../i18n';
|
||||
import { NavigationActions } from '../Navigation';
|
||||
import scrollPersistTaps from '../utils/scrollPersistTaps';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
|
@ -86,7 +88,8 @@ const keyExtractor = item => item.id;
|
|||
}
|
||||
}), dispatch => ({
|
||||
selectServerRequest: server => dispatch(selectServerRequest(server)),
|
||||
logout: () => dispatch(logout())
|
||||
logout: () => dispatch(logout()),
|
||||
appStart: () => dispatch(appStart('outside'))
|
||||
}))
|
||||
export default class Sidebar extends Component {
|
||||
static propTypes = {
|
||||
|
@ -94,7 +97,8 @@ export default class Sidebar extends Component {
|
|||
server: PropTypes.string.isRequired,
|
||||
selectServerRequest: PropTypes.func.isRequired,
|
||||
user: PropTypes.object,
|
||||
logout: PropTypes.func.isRequired
|
||||
logout: PropTypes.func.isRequired,
|
||||
appStart: PropTypes.func
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
|
@ -206,7 +210,7 @@ export default class Sidebar extends Component {
|
|||
try {
|
||||
RocketChat.setUserPresenceDefaultStatus(item.id);
|
||||
} catch (e) {
|
||||
log('onPressModalButton', e);
|
||||
log('setUserPresenceDefaultStatus', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -226,6 +230,21 @@ export default class Sidebar extends Component {
|
|||
this.toggleServers();
|
||||
if (this.props.server !== 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 }`
|
||||
|
@ -289,9 +308,12 @@ export default class Sidebar extends Component {
|
|||
onPress: () => {
|
||||
this.closeDrawer();
|
||||
this.toggleServers();
|
||||
NavigationActions.push({
|
||||
this.props.navigator.showModal({
|
||||
screen: 'NewServerView',
|
||||
title: I18n.t('Add_Server')
|
||||
title: I18n.t('Add_Server'),
|
||||
passProps: {
|
||||
previousServer: this.props.server
|
||||
}
|
||||
});
|
||||
},
|
||||
testID: 'sidebar-add-server'
|
||||
|
@ -305,8 +327,8 @@ export default class Sidebar extends Component {
|
|||
return null;
|
||||
}
|
||||
return (
|
||||
<ScrollView style={styles.container}>
|
||||
<SafeAreaView testID='sidebar' style={styles.container}>
|
||||
<SafeAreaView testID='sidebar' style={styles.container}>
|
||||
<ScrollView style={styles.container} {...scrollPersistTaps}>
|
||||
<Touch
|
||||
onPress={() => this.toggleServers()}
|
||||
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.renderServers() : null}
|
||||
</SafeAreaView>
|
||||
</ScrollView>
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import React from 'react';
|
||||
import { View, StyleSheet, Text, TextInput, ViewPropTypes, Platform } from 'react-native';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||
|
||||
import sharedStyles from '../views/Styles';
|
||||
|
@ -21,13 +20,11 @@ const styles = StyleSheet.create({
|
|||
fontSize: 14,
|
||||
paddingTop: 12,
|
||||
paddingBottom: 12,
|
||||
// paddingTop: 5,
|
||||
// paddingBottom: 5,
|
||||
paddingHorizontal: 10,
|
||||
borderWidth: 2,
|
||||
borderRadius: 4,
|
||||
borderWidth: 1.5,
|
||||
borderRadius: 2,
|
||||
backgroundColor: 'white',
|
||||
borderColor: 'rgba(0,0,0,.15)',
|
||||
borderColor: '#E7EBF2',
|
||||
color: 'black'
|
||||
},
|
||||
labelError: {
|
||||
|
|
|
@ -65,7 +65,8 @@ export default class Markdown extends React.Component {
|
|||
}
|
||||
return null;
|
||||
},
|
||||
blocklink: () => {},
|
||||
hardbreak: () => null,
|
||||
blocklink: () => null,
|
||||
image: node => (
|
||||
// TODO: should use Image component
|
||||
<Image key={node.key} style={styles.inlineImage} source={{ uri: node.attributes.src }} />
|
||||
|
|
|
@ -116,6 +116,7 @@ export default {
|
|||
Code: 'Code',
|
||||
Colaborative: 'Colaborative',
|
||||
Connect: 'Connect',
|
||||
Connect_to_a_server: 'Connect to a server',
|
||||
Connected_to: 'Connected to',
|
||||
Connecting: 'Connecting',
|
||||
Copied_to_clipboard: 'Copied to clipboard!',
|
||||
|
@ -123,6 +124,7 @@ export default {
|
|||
Copy_Permalink: 'Copy Permalink',
|
||||
Create_account: 'Create account',
|
||||
Create_Channel: 'Create Channel',
|
||||
Create_a_new_workspace: 'Create a new workspace',
|
||||
Create: 'Create',
|
||||
Delete_Room_Warning: 'Deleting a room will delete all messages posted within the room. This cannot be undone.',
|
||||
delete: 'delete',
|
||||
|
@ -153,6 +155,7 @@ export default {
|
|||
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_typing: 'is typing',
|
||||
Join_the_community: 'Join the community',
|
||||
Just_invited_people_can_access_this_channel: 'Just invited people can access this channel',
|
||||
Language: 'Language',
|
||||
last_message: 'last message',
|
||||
|
@ -197,9 +200,11 @@ export default {
|
|||
Notify_active_in_this_room: 'Notify active users in this room',
|
||||
Notify_all_in_this_room: 'Notify all in this room',
|
||||
Offline: 'Offline',
|
||||
Oops: 'Oops!',
|
||||
Online: 'Online',
|
||||
Only_authorized_users_can_write_new_messages: 'Only authorized users can write new messages',
|
||||
Open_emoji_selector: 'Open emoji selector',
|
||||
Open_Source_Communication: 'Open Source Communication',
|
||||
Or_continue_using_social_accounts: 'Or continue using social accounts',
|
||||
Password: 'Password',
|
||||
Permalink_copied_to_clipboard: 'Permalink copied to clipboard!',
|
||||
|
@ -274,6 +279,7 @@ export default {
|
|||
tap_to_change_status: 'tap to change status',
|
||||
Tap_to_view_servers_list: 'Tap to view servers list',
|
||||
Terms_of_Service: ' Terms of Service ',
|
||||
The_URL_is_invalid: 'The URL you entered is invalid. Check it and try again, please!',
|
||||
There_was_an_error_while_action: 'There was an error while {{action}}!',
|
||||
This_room_is_blocked: 'This room is blocked',
|
||||
This_room_is_read_only: 'This room is read only',
|
||||
|
@ -307,6 +313,7 @@ export default {
|
|||
Welcome: 'Welcome',
|
||||
Welcome_title_pt_1: 'Prepare to take off with',
|
||||
Welcome_title_pt_2: 'the ultimate chat platform',
|
||||
Welcome_to_RocketChat: 'Welcome to Rocket.Chat',
|
||||
Yes_action_it: 'Yes, {{action}} it!',
|
||||
Yesterday: 'Yesterday',
|
||||
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 { appInit } from './actions';
|
||||
import database from './lib/realm';
|
||||
import { iconsLoaded } from './Icons';
|
||||
import { registerScreens } from './views';
|
||||
import { deepLinkingOpen } from './actions/deepLinking';
|
||||
|
@ -27,21 +26,21 @@ const startLogged = () => {
|
|||
});
|
||||
};
|
||||
|
||||
const startNotLogged = (route) => {
|
||||
const startNotLogged = () => {
|
||||
Navigation.startSingleScreenApp({
|
||||
screen: {
|
||||
screen: route,
|
||||
title: route === 'NewServerView' ? I18n.t('New_Server') : I18n.t('Servers')
|
||||
screen: 'OnboardingView',
|
||||
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 }) => {
|
||||
if (url) {
|
||||
url = url.replace(/rocketchat:\/\/|https:\/\/go.rocket.chat\//, '');
|
||||
|
@ -77,11 +76,7 @@ export default class App extends Component {
|
|||
if (this.currentRoot !== root) {
|
||||
this.currentRoot = root;
|
||||
if (root === 'outside') {
|
||||
if (hasServers()) {
|
||||
startNotLogged('ListServerView');
|
||||
} else {
|
||||
startNotLogged('NewServerView');
|
||||
}
|
||||
startNotLogged();
|
||||
} else if (root === 'inside') {
|
||||
startLogged();
|
||||
}
|
||||
|
|
|
@ -2,6 +2,9 @@ import normalizeMessage from './normalizeMessage';
|
|||
// TODO: delete and update
|
||||
|
||||
export const merge = (subscription, room) => {
|
||||
if (!subscription) {
|
||||
return;
|
||||
}
|
||||
if (room) {
|
||||
if (room.rid) {
|
||||
subscription.rid = room.rid;
|
||||
|
|
|
@ -3,11 +3,10 @@ import { SERVER } from '../actions/actionsTypes';
|
|||
const initialState = {
|
||||
connecting: false,
|
||||
connected: false,
|
||||
errorMessage: '',
|
||||
failure: false,
|
||||
server: '',
|
||||
adding: false,
|
||||
loading: true
|
||||
loading: true,
|
||||
adding: true
|
||||
};
|
||||
|
||||
|
||||
|
@ -17,14 +16,8 @@ export default function server(state = initialState, action) {
|
|||
return {
|
||||
...state,
|
||||
connecting: true,
|
||||
failure: false
|
||||
};
|
||||
case SERVER.SUCCESS:
|
||||
return {
|
||||
...state,
|
||||
connecting: false,
|
||||
connected: true,
|
||||
failure: false
|
||||
failure: false,
|
||||
adding: true
|
||||
};
|
||||
case SERVER.FAILURE:
|
||||
return {
|
||||
|
@ -32,24 +25,22 @@ export default function server(state = initialState, action) {
|
|||
connecting: false,
|
||||
connected: false,
|
||||
failure: true,
|
||||
errorMessage: action.err
|
||||
};
|
||||
case SERVER.ADD:
|
||||
return {
|
||||
...state,
|
||||
adding: true
|
||||
adding: false
|
||||
};
|
||||
case SERVER.SELECT_REQUEST:
|
||||
return {
|
||||
...state,
|
||||
server: action.server,
|
||||
connecting: true,
|
||||
connected: false,
|
||||
loading: true
|
||||
};
|
||||
case SERVER.SELECT_SUCCESS:
|
||||
return {
|
||||
...state,
|
||||
server: action.server,
|
||||
adding: false,
|
||||
connecting: false,
|
||||
connected: true,
|
||||
loading: false
|
||||
};
|
||||
default:
|
||||
|
|
|
@ -12,7 +12,7 @@ const create = function* create(data) {
|
|||
|
||||
const handleRequest = function* handleRequest({ data }) {
|
||||
try {
|
||||
yield delay(1000);
|
||||
// yield delay(1000);
|
||||
const auth = yield select(state => state.login.isAuthenticated);
|
||||
if (!auth) {
|
||||
yield take(LOGIN.SUCCESS);
|
||||
|
|
|
@ -3,7 +3,7 @@ import { takeLatest, take, select, put } from 'redux-saga/effects';
|
|||
|
||||
import * as types from '../actions/actionsTypes';
|
||||
import { appStart } from '../actions';
|
||||
import { selectServerRequest, addServer } from '../actions/server';
|
||||
import { selectServerRequest } from '../actions/server';
|
||||
import database from '../lib/realm';
|
||||
import RocketChat from '../lib/rocketchat';
|
||||
import { NavigationActions } from '../Navigation';
|
||||
|
@ -73,7 +73,7 @@ const handleOpen = function* handleOpen({ params }) {
|
|||
yield navigate({ params, sameServer: false });
|
||||
}
|
||||
} else {
|
||||
yield put(addServer(host));
|
||||
yield put(selectServerRequest(host));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -23,6 +23,7 @@ import {
|
|||
import RocketChat from '../lib/rocketchat';
|
||||
import log from '../utils/log';
|
||||
import I18n from '../i18n';
|
||||
import { NavigationActions } from '../Navigation';
|
||||
|
||||
const getUser = state => state.login.user;
|
||||
const getServer = state => state.server.server;
|
||||
|
@ -44,6 +45,7 @@ const handleLoginSuccess = function* handleLoginSuccess() {
|
|||
yield put(registerIncomplete());
|
||||
} else {
|
||||
yield delay(300);
|
||||
NavigationActions.dismissModal();
|
||||
yield put(appStart('inside'));
|
||||
}
|
||||
} catch (e) {
|
||||
|
@ -103,7 +105,10 @@ const handleLogout = function* handleLogout() {
|
|||
};
|
||||
|
||||
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 }) {
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
import { put, call, takeLatest } from 'redux-saga/effects';
|
||||
import { delay } from 'redux-saga';
|
||||
import { AsyncStorage } from 'react-native';
|
||||
|
||||
import { NavigationActions } from '../Navigation';
|
||||
import { SERVER } from '../actions/actionsTypes';
|
||||
import * as actions from '../actions';
|
||||
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 RocketChat from '../lib/rocketchat';
|
||||
import database from '../lib/realm';
|
||||
import log from '../utils/log';
|
||||
import I18n from '../i18n';
|
||||
|
||||
const validate = function* validate(server) {
|
||||
return yield RocketChat.testServer(server);
|
||||
|
@ -24,8 +22,6 @@ const handleSelectServer = function* handleSelectServer({ server }) {
|
|||
const token = yield AsyncStorage.getItem(`${ RocketChat.TOKEN_KEY }-${ server }`);
|
||||
if (token) {
|
||||
yield put(actions.appStart('inside'));
|
||||
} else {
|
||||
yield put(actions.appStart('outside'));
|
||||
}
|
||||
|
||||
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 {
|
||||
yield delay(1000);
|
||||
yield call(validate, server);
|
||||
yield put(serverSuccess());
|
||||
} 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') });
|
||||
yield call(NavigationActions.push, { screen: 'LoginSignupView', title: server });
|
||||
database.databases.serversDB.write(() => {
|
||||
database.databases.serversDB.create('servers', { id: server, current: false }, true);
|
||||
});
|
||||
yield put(selectServerRequest(server));
|
||||
} catch (e) {
|
||||
log('addServer', e);
|
||||
yield put(serverFailure());
|
||||
log('handleServerRequest', e);
|
||||
}
|
||||
};
|
||||
|
||||
const root = function* root() {
|
||||
yield takeLatest(SERVER.REQUEST, validateServer);
|
||||
yield takeLatest(SERVER.SELECT_REQUEST, handleSelectServer);
|
||||
yield takeLatest(SERVER.ADD, addServer);
|
||||
yield takeLatest(SERVER.REQUEST, handleServerRequest);
|
||||
};
|
||||
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);
|
||||
|
|
@ -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'>
|
||||
<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]}>{I18n.t('Welcome_title_pt_2')}</Text>
|
||||
<Image
|
||||
style={styles.planetImage}
|
||||
source={require('../static/images/planet.png')}
|
||||
source={require('../static/images/server.png')}
|
||||
/>
|
||||
<Button
|
||||
title={I18n.t('I_have_an_account')}
|
||||
|
|
|
@ -1,70 +1,137 @@
|
|||
import React from 'react';
|
||||
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 { serverRequest, addServer } from '../actions/server';
|
||||
import KeyboardView from '../presentation/KeyboardView';
|
||||
import styles from './Styles';
|
||||
import { serverRequest } from '../actions/server';
|
||||
import sharedStyles from './Styles';
|
||||
import scrollPersistTaps from '../utils/scrollPersistTaps';
|
||||
import Button from '../containers/Button';
|
||||
import TextInput from '../containers/TextInput';
|
||||
import Loading from '../containers/Loading';
|
||||
import LoggedView from './View';
|
||||
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 => ({
|
||||
validInstance: !state.server.failure && !state.server.connecting,
|
||||
validating: state.server.connecting,
|
||||
addingServer: state.server.adding
|
||||
connecting: state.server.connecting,
|
||||
failure: state.server.failure,
|
||||
currentServer: state.server.server
|
||||
}), dispatch => ({
|
||||
validateServer: url => dispatch(serverRequest(url)),
|
||||
addServer: url => dispatch(addServer(url))
|
||||
connectServer: (url, adding) => dispatch(serverRequest(url, adding))
|
||||
}))
|
||||
/** @extends React.Component */
|
||||
export default class NewServerView extends LoggedView {
|
||||
static propTypes = {
|
||||
navigator: PropTypes.object,
|
||||
validateServer: PropTypes.func.isRequired,
|
||||
addServer: PropTypes.func.isRequired,
|
||||
validating: PropTypes.bool.isRequired,
|
||||
validInstance: PropTypes.bool.isRequired,
|
||||
addingServer: PropTypes.bool.isRequired
|
||||
server: PropTypes.string,
|
||||
connecting: PropTypes.bool.isRequired,
|
||||
failure: PropTypes.bool.isRequired,
|
||||
connectServer: PropTypes.func.isRequired,
|
||||
previousServer: PropTypes.string,
|
||||
currentServer: PropTypes.string
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super('NewServerView', props);
|
||||
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() {
|
||||
setTimeout(() => {
|
||||
this.input.focus();
|
||||
}, 600);
|
||||
const { server } = this.props;
|
||||
if (server) {
|
||||
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) => {
|
||||
this.setState({ text });
|
||||
this.props.validateServer(this.completeUrl(text));
|
||||
}
|
||||
|
||||
submit = () => {
|
||||
if (this.props.validInstance) {
|
||||
if (this.state.text) {
|
||||
Keyboard.dismiss();
|
||||
this.props.addServer(this.completeUrl(this.state.text));
|
||||
this.props.connectServer(this.completeUrl(this.state.text));
|
||||
}
|
||||
}
|
||||
|
||||
completeUrl = (url) => {
|
||||
url = url && url.trim();
|
||||
|
||||
if (!url) {
|
||||
return this.state.defaultServer;
|
||||
}
|
||||
|
||||
if (/^(\w|[0-9-_]){3,}$/.test(url) &&
|
||||
/^(htt(ps?)?)|(loca((l)?|(lh)?|(lho)?|(lhos)?|(lhost:?\d*)?)$)/.test(url) === false) {
|
||||
url = `${ url }.rocket.chat`;
|
||||
|
@ -81,60 +148,39 @@ export default class NewServerView extends LoggedView {
|
|||
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() {
|
||||
const { validInstance } = this.props;
|
||||
const { connecting } = this.props;
|
||||
const { text } = this.state;
|
||||
return (
|
||||
<KeyboardView
|
||||
contentContainerStyle={styles.container}
|
||||
contentContainerStyle={sharedStyles.container}
|
||||
keyboardVerticalOffset={128}
|
||||
key='login-view'
|
||||
>
|
||||
<ScrollView {...scrollPersistTaps} contentContainerStyle={styles.containerScrollView}>
|
||||
<SafeAreaView style={styles.container} testID='new-server-view'>
|
||||
<Text style={[styles.loginText, styles.loginTitle]}>{I18n.t('Sign_in_your_server')}</Text>
|
||||
<ScrollView {...scrollPersistTaps} contentContainerStyle={sharedStyles.containerScrollView}>
|
||||
<SafeAreaView style={sharedStyles.container} testID='new-server-view'>
|
||||
<Image style={styles.image} source={require('../static/images/server.png')} />
|
||||
<Text style={styles.title}>{I18n.t('Sign_in_your_server')}</Text>
|
||||
<TextInput
|
||||
inputRef={e => this.input = e}
|
||||
containerStyle={{ marginBottom: 5 }}
|
||||
label={I18n.t('Your_server')}
|
||||
placeholder={this.state.defaultServer}
|
||||
containerStyle={styles.inputContainer}
|
||||
inputStyle={styles.input}
|
||||
placeholder={defaultServer}
|
||||
value={text}
|
||||
returnKeyType='done'
|
||||
onChangeText={this.onChangeText}
|
||||
testID='new-server-view-input'
|
||||
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>
|
||||
</ScrollView>
|
||||
</KeyboardView>
|
||||
|
|
|
@ -5,6 +5,7 @@ import { connect } from 'react-redux';
|
|||
|
||||
import RocketChat from '../lib/rocketchat';
|
||||
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 userAgent = Platform.OS === 'ios' ? 'UserAgent' : userAgentAndroid;
|
||||
|
@ -16,7 +17,8 @@ export default class TermsServiceView extends React.PureComponent {
|
|||
static navigatorButtons = {
|
||||
leftButtons: [{
|
||||
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 RoomTypeIcon from '../../containers/RoomTypeIcon';
|
||||
import I18n from '../../i18n';
|
||||
import scrollPersistTaps from '../../utils/scrollPersistTaps';
|
||||
|
||||
const renderSeparator = () => <View style={styles.separator} />;
|
||||
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: [
|
||||
{
|
||||
icon: 'ios-call-outline',
|
||||
icon: 'ios-call',
|
||||
name: I18n.t('Voice_call'),
|
||||
disabled: true,
|
||||
testID: 'room-actions-voice'
|
||||
},
|
||||
{
|
||||
icon: 'ios-videocam-outline',
|
||||
icon: 'ios-videocam',
|
||||
name: I18n.t('Video_call'),
|
||||
disabled: true,
|
||||
testID: 'room-actions-video'
|
||||
|
@ -145,14 +146,14 @@ export default class RoomActionsView extends LoggedView {
|
|||
testID: 'room-actions-files'
|
||||
},
|
||||
{
|
||||
icon: 'ios-at-outline',
|
||||
icon: 'ios-at',
|
||||
name: I18n.t('Mentions'),
|
||||
route: 'MentionedMessagesView',
|
||||
params: { rid },
|
||||
testID: 'room-actions-mentioned'
|
||||
},
|
||||
{
|
||||
icon: 'ios-star-outline',
|
||||
icon: 'ios-star',
|
||||
name: I18n.t('Starred'),
|
||||
route: 'StarredMessagesView',
|
||||
params: { rid },
|
||||
|
@ -166,7 +167,7 @@ export default class RoomActionsView extends LoggedView {
|
|||
testID: 'room-actions-search'
|
||||
},
|
||||
{
|
||||
icon: 'ios-share-outline',
|
||||
icon: 'ios-share',
|
||||
name: I18n.t('Share'),
|
||||
disabled: true,
|
||||
testID: 'room-actions-share'
|
||||
|
@ -186,7 +187,7 @@ export default class RoomActionsView extends LoggedView {
|
|||
testID: 'room-actions-snippeted'
|
||||
},
|
||||
{
|
||||
icon: `ios-notifications${ notifications ? '' : '-off' }-outline`,
|
||||
icon: `ios-notifications${ notifications ? '' : '-off' }`,
|
||||
name: I18n.t(`${ notifications ? 'Enable' : 'Disable' }_notifications`),
|
||||
event: () => this.toggleNotifications(),
|
||||
testID: 'room-actions-notifications'
|
||||
|
@ -403,6 +404,7 @@ export default class RoomActionsView extends LoggedView {
|
|||
ItemSeparatorComponent={renderSeparator}
|
||||
keyExtractor={item => item.name}
|
||||
testID='room-actions-list'
|
||||
{...scrollPersistTaps}
|
||||
/>
|
||||
</SafeAreaView>
|
||||
);
|
||||
|
|
|
@ -72,7 +72,7 @@ export default class RoomView extends LoggedView {
|
|||
props.navigator.setOnNavigatorEvent(this.onNavigatorEvent.bind(this));
|
||||
}
|
||||
|
||||
async componentWillMount() {
|
||||
componentWillMount() {
|
||||
this.props.navigator.setButtons({
|
||||
rightButtons: [{
|
||||
id: 'more',
|
||||
|
@ -267,7 +267,7 @@ export default class RoomView extends LoggedView {
|
|||
</View>
|
||||
);
|
||||
}
|
||||
return <MessageBox onSubmit={this.sendMessage} rid={this.rid} />;
|
||||
return <MessageBox key='room-view-messagebox' onSubmit={this.sendMessage} rid={this.rid} />;
|
||||
};
|
||||
|
||||
renderHeader = () => {
|
||||
|
@ -282,14 +282,17 @@ export default class RoomView extends LoggedView {
|
|||
return <ActivityIndicator style={styles.loading} />;
|
||||
}
|
||||
return (
|
||||
<List
|
||||
key='room-view-messages'
|
||||
end={this.state.end}
|
||||
room={this.rid}
|
||||
renderFooter={this.renderHeader}
|
||||
onEndReached={this.onEndReached}
|
||||
renderRow={this.renderItem}
|
||||
/>
|
||||
[
|
||||
<List
|
||||
key='room-view-messages'
|
||||
end={this.state.end}
|
||||
room={this.rid}
|
||||
renderFooter={this.renderHeader}
|
||||
onEndReached={this.onEndReached}
|
||||
renderRow={this.renderItem}
|
||||
/>,
|
||||
this.renderFooter()
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -297,7 +300,6 @@ export default class RoomView extends LoggedView {
|
|||
return (
|
||||
<SafeAreaView style={styles.container} testID='room-view'>
|
||||
{this.renderList()}
|
||||
{this.renderFooter()}
|
||||
{this.state.room._id && this.props.showActions ?
|
||||
<MessageActions room={this.state.room} user={this.props.user} /> :
|
||||
null}
|
||||
|
|
|
@ -8,7 +8,7 @@ export default StyleSheet.create({
|
|||
flex: 1
|
||||
},
|
||||
containerScrollView: {
|
||||
padding: 20
|
||||
padding: 15
|
||||
},
|
||||
label: {
|
||||
lineHeight: 40,
|
||||
|
@ -191,11 +191,6 @@ export default StyleSheet.create({
|
|||
fontSize: 20,
|
||||
marginBottom: 20
|
||||
},
|
||||
loginLogo: {
|
||||
width: 50,
|
||||
height: 50,
|
||||
marginVertical: 25
|
||||
},
|
||||
headerButton: {
|
||||
backgroundColor: 'transparent',
|
||||
height: 44,
|
||||
|
|
|
@ -3,12 +3,12 @@ import { Provider } from 'react-redux';
|
|||
|
||||
import CreateChannelView from './CreateChannelView';
|
||||
import ForgotPasswordView from './ForgotPasswordView';
|
||||
import ListServerView from './ListServerView';
|
||||
import LoginSignupView from './LoginSignupView';
|
||||
import LoginView from './LoginView';
|
||||
import MentionedMessagesView from './MentionedMessagesView';
|
||||
import NewServerView from './NewServerView';
|
||||
import OAuthView from './OAuthView';
|
||||
import OnboardingView from './OnboardingView';
|
||||
import PinnedMessagesView from './PinnedMessagesView';
|
||||
import PrivacyPolicyView from './PrivacyPolicyView';
|
||||
import ProfileView from './ProfileView';
|
||||
|
@ -32,12 +32,12 @@ import TermsServiceView from './TermsServiceView';
|
|||
export const registerScreens = (store) => {
|
||||
Navigation.registerComponent('CreateChannelView', () => CreateChannelView, store, Provider);
|
||||
Navigation.registerComponent('ForgotPasswordView', () => ForgotPasswordView, store, Provider);
|
||||
Navigation.registerComponent('ListServerView', () => ListServerView, store, Provider);
|
||||
Navigation.registerComponent('LoginSignupView', () => LoginSignupView, store, Provider);
|
||||
Navigation.registerComponent('LoginView', () => LoginView, store, Provider);
|
||||
Navigation.registerComponent('MentionedMessagesView', () => MentionedMessagesView, store, Provider);
|
||||
Navigation.registerComponent('NewServerView', () => NewServerView, store, Provider);
|
||||
Navigation.registerComponent('OAuthView', () => OAuthView, store, Provider);
|
||||
Navigation.registerComponent('OnboardingView', () => OnboardingView, store, Provider);
|
||||
Navigation.registerComponent('PinnedMessagesView', () => PinnedMessagesView, store, Provider);
|
||||
Navigation.registerComponent('PrivacyPolicyView', () => PrivacyPolicyView, 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 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', () => {
|
||||
before(async() => {
|
||||
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', () => {
|
||||
|
|
|
@ -63,7 +63,8 @@ describe('Login screen', () => {
|
|||
await tapBack('Welcome');
|
||||
await waitFor(element(by.id('welcome-view'))).toBeVisible().withTimeout(2000);
|
||||
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() => {
|
||||
|
|
|
@ -6,9 +6,9 @@ const { login, navigateToLogin, tapBack } = require('./helpers/app');
|
|||
const data = require('./data');
|
||||
|
||||
describe('Rooms list screen', () => {
|
||||
before(async() => {
|
||||
await device.reloadReactNative(); // TODO: remove this after fix logout subscription
|
||||
});
|
||||
// before(async() => {
|
||||
// await device.reloadReactNative(); // TODO: remove this after fix logout subscription
|
||||
// });
|
||||
|
||||
describe('Render', 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 waitFor(element(by.id('new-server-view'))).toBeVisible().withTimeout(2000);
|
||||
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 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-logout'))).toBeVisible().withTimeout(2000);
|
||||
await element(by.id('sidebar-logout')).tap();
|
||||
await waitFor(element(by.id('welcome-view'))).toBeVisible().withTimeout(60000);
|
||||
await expect(element(by.id('welcome-view'))).toBeVisible();
|
||||
await navigateToLogin();
|
||||
await login();
|
||||
await waitFor(element(by.id('onboarding-view'))).toBeVisible().withTimeout(60000);
|
||||
await expect(element(by.id('onboarding-view'))).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(async() => {
|
||||
takeScreenshot();
|
||||
});
|
||||
|
||||
after(async() => {
|
||||
await navigateToLogin();
|
||||
await login();
|
||||
})
|
||||
});
|
||||
});
|
||||
|
|
|
@ -7,7 +7,7 @@ const { tapBack } = require('./helpers/app');
|
|||
|
||||
describe('Create room screen', () => {
|
||||
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 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 waitFor(element(by.id('messagebox-container'))).toBeVisible().withTimeout(60000);
|
||||
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 element(by.id('messagebox-input')).clearText();
|
||||
});
|
||||
|
|
|
@ -289,22 +289,21 @@ describe('Room actions screen', () => {
|
|||
|
||||
describe('Add User', 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 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')).replaceText(user);
|
||||
await waitFor(element(by.id(`select-users-view-item-${ user }`))).toBeVisible().withTimeout(60000);
|
||||
await expect(element(by.id(`select-users-view-item-${ user }`))).toBeVisible();
|
||||
await element(by.id(`select-users-view-item-${ user }`)).tap();
|
||||
await waitFor(element(by.id(`selected-user-${ user }`))).toBeVisible().withTimeout(5000);
|
||||
await expect(element(by.id(`selected-user-${ user }`))).toBeVisible();
|
||||
await element(by.id('select-users-view-search')).replaceText(data.alternateUser);
|
||||
await waitFor(element(by.id(`select-users-view-item-${ data.alternateUser }`))).toBeVisible().withTimeout(60000);
|
||||
await expect(element(by.id(`select-users-view-item-${ data.alternateUser }`))).toBeVisible();
|
||||
await element(by.id(`select-users-view-item-${ data.alternateUser }`)).tap();
|
||||
await waitFor(element(by.id(`selected-user-${ data.alternateUser }`))).toBeVisible().withTimeout(5000);
|
||||
await expect(element(by.id(`selected-user-${ data.alternateUser }`))).toBeVisible();
|
||||
await element(by.id('selected-users-view-submit')).tap();
|
||||
await waitFor(element(by.id('room-actions-view'))).toBeVisible().withTimeout(2000);
|
||||
await element(by.id('room-actions-members')).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 expect(element(by.id(`room-members-view-item-${ user }`))).toBeVisible();
|
||||
await waitFor(element(by.id(`room-members-view-item-${ data.alternateUser }`))).toBeVisible().withTimeout(60000);
|
||||
await expect(element(by.id(`room-members-view-item-${ data.alternateUser }`))).toBeVisible();
|
||||
await backToActions();
|
||||
});
|
||||
|
||||
|
@ -314,7 +313,6 @@ describe('Room actions screen', () => {
|
|||
});
|
||||
|
||||
describe('Room Members', async() => {
|
||||
const user = 'detoxrn';
|
||||
before(async() => {
|
||||
await element(by.id('room-actions-members')).tap();
|
||||
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() => {
|
||||
await element(by.id('room-members-view-toggle-status')).tap();
|
||||
await waitFor(element(by.id(`room-members-view-item-${ user }`))).toBeVisible().withTimeout(60000);
|
||||
await expect(element(by.id(`room-members-view-item-${ user }`))).toBeVisible();
|
||||
await waitFor(element(by.id(`room-members-view-item-${ data.alternateUser }`))).toBeVisible().withTimeout(60000);
|
||||
await expect(element(by.id(`room-members-view-item-${ data.alternateUser }`))).toBeVisible();
|
||||
});
|
||||
|
||||
it('should filter user', async() => {
|
||||
await waitFor(element(by.id(`room-members-view-item-${ user }`))).toBeVisible().withTimeout(60000);
|
||||
await expect(element(by.id(`room-members-view-item-${ user }`))).toBeVisible();
|
||||
await waitFor(element(by.id(`room-members-view-item-${ data.alternateUser }`))).toBeVisible().withTimeout(60000);
|
||||
await expect(element(by.id(`room-members-view-item-${ data.alternateUser }`))).toBeVisible();
|
||||
await element(by.id('room-members-view-search')).replaceText('rocket');
|
||||
await waitFor(element(by.id(`room-members-view-item-${ user }`))).toBeNotVisible().withTimeout(60000);
|
||||
await expect(element(by.id(`room-members-view-item-${ user }`))).toBeNotVisible();
|
||||
await waitFor(element(by.id(`room-members-view-item-${ data.alternateUser }`))).toBeNotVisible().withTimeout(60000);
|
||||
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')).clearText('');
|
||||
await waitFor(element(by.id(`room-members-view-item-${ user }`))).toBeVisible().withTimeout(60000);
|
||||
await expect(element(by.id(`room-members-view-item-${ user }`))).toBeVisible();
|
||||
await waitFor(element(by.id(`room-members-view-item-${ data.alternateUser }`))).toBeVisible().withTimeout(60000);
|
||||
await expect(element(by.id(`room-members-view-item-${ data.alternateUser }`))).toBeVisible();
|
||||
});
|
||||
|
||||
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 expect(element(by.text('Mute'))).toBeVisible();
|
||||
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 waitFor(element(by.text('User has been muted!'))).toBeNotVisible().withTimeout(60000);
|
||||
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 expect(element(by.text('Unmute'))).toBeVisible();
|
||||
await element(by.text('Unmute')).tap();
|
||||
|
@ -359,12 +357,12 @@ describe('Room actions screen', () => {
|
|||
});
|
||||
|
||||
it('should navigate to direct room', async() => {
|
||||
await waitFor(element(by.id(`room-members-view-item-${ user }`))).toExist().withTimeout(5000);
|
||||
await element(by.id(`room-members-view-item-${ user }`)).tap();
|
||||
await waitFor(element(by.id(`room-members-view-item-${ data.alternateUser }`))).toExist().withTimeout(5000);
|
||||
await element(by.id(`room-members-view-item-${ data.alternateUser }`)).tap();
|
||||
await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(60000);
|
||||
await expect(element(by.id('room-view'))).toBeVisible();
|
||||
await waitFor(element(by.text(user))).toBeVisible().withTimeout(60000);
|
||||
await expect(element(by.text(user))).toBeVisible();
|
||||
await waitFor(element(by.text(data.alternateUser))).toBeVisible().withTimeout(60000);
|
||||
await expect(element(by.text(data.alternateUser))).toBeVisible();
|
||||
await tapBack('Messages');
|
||||
await waitFor(element(by.id('room-list-view'))).toBeVisible().withTimeout(2000);
|
||||
});
|
||||
|
|
|
@ -7,6 +7,7 @@ const data = require('./data');
|
|||
describe('Change server', () => {
|
||||
before(async() => {
|
||||
await device.reloadReactNative();
|
||||
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(10000);
|
||||
});
|
||||
|
||||
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 waitFor(element(by.id('sidebar-add-server'))).toBeVisible().withTimeout(2000);
|
||||
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 waitFor(element(by.text(' is a valid Rocket.Chat instance'))).toBeVisible().withTimeout(60000);
|
||||
await element(by.id('new-server-view-button')).tap();
|
||||
// Navigate to register
|
||||
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 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-sidebar'))).toHaveLabel(`Connected to ${ data.alternateServer }. Tap to view servers list.`);
|
||||
// For a sanity test, to make sure roomslist is showing correct rooms
|
||||
// app CANNOT show public room created on previous tests
|
||||
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() => {
|
||||
await element(by.text('Reply')).tap();
|
||||
await waitFor(element(by.text(data.user))).toBeVisible().withTimeout(60000);
|
||||
await expect(element(by.text(data.user))).toBeVisible();
|
||||
await waitFor(element(by.text(data.user)).atIndex(0)).toBeVisible().withTimeout(60000);
|
||||
await expect(element(by.text(data.user)).atIndex(0)).toBeVisible();
|
||||
});
|
||||
|
||||
it('should reply broadcasted message', async() => {
|
||||
|
|
|
@ -86,7 +86,7 @@ describe('Profile screen', () => {
|
|||
});
|
||||
|
||||
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-submit')).tap();
|
||||
await waitFor(element(by.id('profile-view-typed-password'))).toBeVisible().withTimeout(10000);
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
const random = require('./helpers/random');
|
||||
const value = random(20);
|
||||
const data = {
|
||||
server: 'https://unstable.rocket.chat',
|
||||
alternateServer: 'https://stable.rocket.chat',
|
||||
server: 'https://stable.rocket.chat',
|
||||
alternateServer: 'https://open.rocket.chat',
|
||||
user: `user${ value }`,
|
||||
password: `password${ value }`,
|
||||
alternateUser: 'detoxrn',
|
||||
alternateUser: 'detox',
|
||||
alternateUserPassword: '123',
|
||||
email: `detoxrn+${ value }@rocket.chat`,
|
||||
email: `diego.mello+e2e${ value }@rocket.chat`,
|
||||
random: value
|
||||
}
|
||||
module.exports = data;
|
|
@ -4,14 +4,16 @@ const {
|
|||
const data = require('../data');
|
||||
|
||||
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 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();
|
||||
}
|
||||
|
||||
async function navigateToLogin() {
|
||||
await addServer();
|
||||
await waitFor(element(by.id('welcome-view'))).toBeVisible().withTimeout(2000);
|
||||
await element(by.id('welcome-view-login')).tap();
|
||||
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-logout'))).toBeVisible().withTimeout(2000);
|
||||
await element(by.id('sidebar-logout')).tap();
|
||||
await waitFor(element(by.id('welcome-view'))).toBeVisible().withTimeout(2000);
|
||||
await expect(element(by.id('welcome-view'))).toBeVisible();
|
||||
await waitFor(element(by.id('onboarding-view'))).toBeVisible().withTimeout(2000);
|
||||
await expect(element(by.id('onboarding-view'))).toBeVisible();
|
||||
}
|
||||
|
||||
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": {
|
||||
"@babel/polyfill": "^7.0.0-beta.47",
|
||||
"@remobile/react-native-toast": "^1.0.7",
|
||||
"@storybook/addons": "^3.4.8",
|
||||
"@storybook/react-native": "^3.4.8",
|
||||
"@storybook/addons": "^3.4.10",
|
||||
"@storybook/react-native": "^3.4.10",
|
||||
"deep-equal": "^1.0.1",
|
||||
"ejson": "^2.1.2",
|
||||
"js-base64": "^2.4.6",
|
||||
"js-base64": "^2.4.8",
|
||||
"js-sha256": "^0.9.0",
|
||||
"lodash": "^4.17.10",
|
||||
"markdown-it-flowdock": "^0.3.7",
|
||||
"moment": "^2.22.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-native": "^0.56.0",
|
||||
"react-native-actionsheet": "^2.4.2",
|
||||
|
@ -43,51 +44,51 @@
|
|||
"react-native-dialog": "^5.1.0",
|
||||
"react-native-fabric": "^0.5.1",
|
||||
"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-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-input": "^5.2.3",
|
||||
"react-native-keyboard-tracking-view": "^5.4.4",
|
||||
"react-native-markdown-renderer": "^3.2.8",
|
||||
"react-native-meteor": "^1.4.0",
|
||||
"react-native-modal": "^6.4.0",
|
||||
"react-native-navigation": "^1.1.474",
|
||||
"react-native-modal": "^6.5.0",
|
||||
"react-native-navigation": "^1.1.479",
|
||||
"react-native-notifications": "git+https://github.com/RocketChat/react-native-notifications.git",
|
||||
"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-safari-view": "^2.1.0",
|
||||
"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-svg": "^6.4.1",
|
||||
"react-native-svg": "^6.5.2",
|
||||
"react-native-svg-image": "^2.0.1",
|
||||
"react-native-vector-icons": "^4.6.0",
|
||||
"react-native-video": "^3.0.0",
|
||||
"react-native-vector-icons": "^5.0.0",
|
||||
"react-native-video": "^3.2.0",
|
||||
"react-native-video-controls": "^2.2.3",
|
||||
"react-native-zeroconf": "^0.9.0",
|
||||
"react-redux": "^5.0.6",
|
||||
"realm": "^2.13.0",
|
||||
"realm": "^2.14.2",
|
||||
"redux": "^4.0.0",
|
||||
"redux-enhancer-react-native-appstate": "^0.3.1",
|
||||
"redux-immutable-state-invariant": "^2.1.0",
|
||||
"redux-saga": "^0.16.0",
|
||||
"regenerator-runtime": "^0.12.0",
|
||||
"rn-fetch-blob": "^0.10.11",
|
||||
"snyk": "^1.88.1",
|
||||
"regenerator-runtime": "^0.12.1",
|
||||
"rn-fetch-blob": "^0.10.12",
|
||||
"snyk": "^1.90.0",
|
||||
"strip-ansi": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "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-eslint": "^8.2.6",
|
||||
"babel-jest": "^23.4.0",
|
||||
"babel-jest": "^23.4.2",
|
||||
"babel-plugin-transform-remove-console": "^6.9.4",
|
||||
"babel-preset-react-native": "^5.0.2",
|
||||
"codecov": "^3.0.2",
|
||||
"detox": "^8.0.0",
|
||||
"codecov": "^3.0.4",
|
||||
"detox": "^8.1.4",
|
||||
"eslint": "^4.19.1",
|
||||
"eslint-config-airbnb": "^16.1.0",
|
||||
"eslint-plugin-import": "^2.13.0",
|
||||
|
@ -95,12 +96,12 @@
|
|||
"eslint-plugin-react": "^7.10.0",
|
||||
"eslint-plugin-react-native": "^3.2.0",
|
||||
"identity-obj-proxy": "^3.0.0",
|
||||
"jest": "^23.4.1",
|
||||
"jest-cli": "^23.4.1",
|
||||
"jest": "^23.4.2",
|
||||
"jest-cli": "^23.4.2",
|
||||
"mocha": "^5.2.0",
|
||||
"react-dom": "^16.4.1",
|
||||
"react-dom": "^16.4.2",
|
||||
"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-redux": "^2.0.0",
|
||||
"reactotron-redux-saga": "^2.0.0"
|
||||
|
@ -128,7 +129,13 @@
|
|||
"configurations": {
|
||||
"ios.sim.debug": {
|
||||
"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",
|
||||
"name": "iPhone 7"
|
||||
}
|
||||
|
|