Remove drawer (#653)
* Remove drawer (layout needs to be changed in future releases, though) * Don't navigate outside on logout if there's other logged server * Update react-native-navigation
This commit is contained in:
parent
2ef2be51d3
commit
f3ddf60a57
11
app/index.js
11
app/index.js
|
@ -18,16 +18,9 @@ const startLogged = () => {
|
|||
Navigation.loadView('RoomHeaderView');
|
||||
Navigation.loadView('SettingsView');
|
||||
Navigation.loadView('SidebarView');
|
||||
|
||||
Navigation.setRoot({
|
||||
root: {
|
||||
sideMenu: {
|
||||
left: {
|
||||
component: {
|
||||
id: 'SidebarView',
|
||||
name: 'SidebarView'
|
||||
}
|
||||
},
|
||||
center: {
|
||||
stack: {
|
||||
id: 'AppRoot',
|
||||
children: [{
|
||||
|
@ -38,8 +31,6 @@ const startLogged = () => {
|
|||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -6,11 +6,12 @@ import {
|
|||
import Navigation from '../lib/Navigation';
|
||||
import * as types from '../actions/actionsTypes';
|
||||
import { appStart } from '../actions';
|
||||
import { serverFinishAdd } from '../actions/server';
|
||||
import { serverFinishAdd, selectServerRequest } from '../actions/server';
|
||||
import { loginFailure, loginSuccess } from '../actions/login';
|
||||
import RocketChat from '../lib/rocketchat';
|
||||
import log from '../utils/log';
|
||||
import I18n from '../i18n';
|
||||
import database from '../lib/realm';
|
||||
|
||||
const getServer = state => state.server.server;
|
||||
const loginWithPasswordCall = args => RocketChat.loginWithPassword(args);
|
||||
|
@ -60,8 +61,26 @@ const handleLogout = function* handleLogout() {
|
|||
if (server) {
|
||||
try {
|
||||
yield call(logoutCall, { server });
|
||||
const { serversDB } = database.databases;
|
||||
// all servers
|
||||
const servers = yield serversDB.objects('servers');
|
||||
// filter logging out server and delete it
|
||||
const serverRecord = servers.filtered('id = $0', server);
|
||||
serversDB.write(() => {
|
||||
serversDB.delete(serverRecord);
|
||||
});
|
||||
// see if there's other logged in servers and selects first one
|
||||
if (servers.length > 0) {
|
||||
const newServer = servers[0].id;
|
||||
const token = yield AsyncStorage.getItem(`${ RocketChat.TOKEN_KEY }-${ newServer }`);
|
||||
if (token) {
|
||||
return yield put(selectServerRequest(newServer));
|
||||
}
|
||||
}
|
||||
// if there's no servers, go outside
|
||||
yield put(appStart('outside'));
|
||||
} catch (e) {
|
||||
yield put(appStart('outside'));
|
||||
log('handleLogout', e);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
View, ScrollView, Keyboard, BackHandler
|
||||
} from 'react-native';
|
||||
import { View, ScrollView, Keyboard } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import Dialog from 'react-native-dialog';
|
||||
import SHA256 from 'js-sha256';
|
||||
|
@ -12,7 +10,6 @@ import RNPickerSelect from 'react-native-picker-select';
|
|||
import SafeAreaView from 'react-native-safe-area-view';
|
||||
import equal from 'deep-equal';
|
||||
|
||||
import Navigation from '../../lib/Navigation';
|
||||
import LoggedView from '../View';
|
||||
import KeyboardView from '../../presentation/KeyboardView';
|
||||
import sharedStyles from '../Styles';
|
||||
|
@ -26,9 +23,7 @@ import I18n from '../../i18n';
|
|||
import Button from '../../containers/Button';
|
||||
import Avatar from '../../containers/Avatar';
|
||||
import Touch from '../../utils/touch';
|
||||
import { appStart as appStartAction } from '../../actions';
|
||||
import { setUser as setUserAction } from '../../actions/login';
|
||||
import Icons from '../../lib/Icons';
|
||||
|
||||
@connect(state => ({
|
||||
user: {
|
||||
|
@ -42,7 +37,6 @@ import Icons from '../../lib/Icons';
|
|||
Accounts_CustomFields: state.settings.Accounts_CustomFields,
|
||||
baseUrl: state.settings.Site_Url || state.server ? state.server.server : ''
|
||||
}), dispatch => ({
|
||||
appStart: () => dispatch(appStartAction()),
|
||||
setUser: params => dispatch(setUserAction(params))
|
||||
}))
|
||||
/** @extends React.Component */
|
||||
|
@ -50,32 +44,17 @@ export default class ProfileView extends LoggedView {
|
|||
static options() {
|
||||
return {
|
||||
topBar: {
|
||||
leftButtons: [{
|
||||
id: 'settings',
|
||||
icon: Icons.getSource('settings'),
|
||||
testID: 'rooms-list-view-sidebar'
|
||||
}],
|
||||
title: {
|
||||
text: I18n.t('Profile')
|
||||
}
|
||||
},
|
||||
sideMenu: {
|
||||
left: {
|
||||
enabled: true
|
||||
},
|
||||
right: {
|
||||
enabled: true
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
baseUrl: PropTypes.string,
|
||||
componentId: PropTypes.string,
|
||||
user: PropTypes.object,
|
||||
Accounts_CustomFields: PropTypes.string,
|
||||
appStart: PropTypes.func,
|
||||
setUser: PropTypes.func
|
||||
}
|
||||
|
||||
|
@ -94,8 +73,6 @@ export default class ProfileView extends LoggedView {
|
|||
avatarSuggestions: {},
|
||||
customFields: {}
|
||||
};
|
||||
Navigation.events().bindComponent(this);
|
||||
BackHandler.addEventListener('hardwareBackPress', this.handleBackPress);
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
|
@ -126,22 +103,6 @@ export default class ProfileView extends LoggedView {
|
|||
return false;
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
BackHandler.removeEventListener('hardwareBackPress', this.handleBackPress);
|
||||
}
|
||||
|
||||
navigationButtonPressed = ({ buttonId }) => {
|
||||
if (buttonId === 'settings') {
|
||||
Navigation.toggleDrawer();
|
||||
}
|
||||
}
|
||||
|
||||
handleBackPress = () => {
|
||||
const { appStart } = this.props;
|
||||
appStart('background');
|
||||
return false;
|
||||
}
|
||||
|
||||
setAvatar = (avatar) => {
|
||||
this.setState({ avatar });
|
||||
}
|
||||
|
|
|
@ -81,6 +81,13 @@ export default class ServerDropdown extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.newServerTimeout) {
|
||||
clearTimeout(this.newServerTimeout);
|
||||
this.newServerTimeout = false;
|
||||
}
|
||||
}
|
||||
|
||||
updateState = () => {
|
||||
const { servers } = this;
|
||||
this.setState({ servers });
|
||||
|
@ -137,12 +144,7 @@ export default class ServerDropdown extends Component {
|
|||
const token = await AsyncStorage.getItem(`${ RocketChat.TOKEN_KEY }-${ server }`);
|
||||
if (!token) {
|
||||
appStart();
|
||||
try {
|
||||
this.sdk.disconnect();
|
||||
} catch (error) {
|
||||
console.warn(error);
|
||||
}
|
||||
setTimeout(() => {
|
||||
this.newServerTimeout = setTimeout(() => {
|
||||
EventEmitter.emit('NewServer', { server });
|
||||
}, 1000);
|
||||
} else {
|
||||
|
|
|
@ -270,7 +270,22 @@ export default class RoomsListView extends LoggedView {
|
|||
}
|
||||
});
|
||||
} else if (buttonId === 'settings') {
|
||||
Navigation.toggleDrawer();
|
||||
Navigation.showModal({
|
||||
stack: {
|
||||
children: [{
|
||||
component: {
|
||||
name: 'SidebarView',
|
||||
options: {
|
||||
topBar: {
|
||||
title: {
|
||||
text: I18n.t('Settings')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
});
|
||||
} else if (buttonId === 'search') {
|
||||
this.initSearchingAndroid();
|
||||
} else if (buttonId === 'back') {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { View, ScrollView, BackHandler } from 'react-native';
|
||||
import { View, ScrollView } from 'react-native';
|
||||
import RNPickerSelect from 'react-native-picker-select';
|
||||
import { connect } from 'react-redux';
|
||||
import SafeAreaView from 'react-native-safe-area-view';
|
||||
|
@ -18,36 +18,20 @@ import Loading from '../../containers/Loading';
|
|||
import { showErrorAlert, showToast } from '../../utils/info';
|
||||
import log from '../../utils/log';
|
||||
import { setUser as setUserAction } from '../../actions/login';
|
||||
import { appStart as appStartAction } from '../../actions';
|
||||
import Icons from '../../lib/Icons';
|
||||
|
||||
@connect(state => ({
|
||||
userLanguage: state.login.user && state.login.user.language
|
||||
}), dispatch => ({
|
||||
setUser: params => dispatch(setUserAction(params)),
|
||||
appStart: () => dispatch(appStartAction())
|
||||
setUser: params => dispatch(setUserAction(params))
|
||||
}))
|
||||
/** @extends React.Component */
|
||||
export default class SettingsView extends LoggedView {
|
||||
static options() {
|
||||
return {
|
||||
topBar: {
|
||||
leftButtons: [{
|
||||
id: 'settings',
|
||||
icon: Icons.getSource('settings'),
|
||||
testID: 'rooms-list-view-sidebar'
|
||||
}],
|
||||
title: {
|
||||
text: I18n.t('Settings')
|
||||
}
|
||||
},
|
||||
sideMenu: {
|
||||
left: {
|
||||
enabled: true
|
||||
},
|
||||
right: {
|
||||
enabled: true
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -55,8 +39,7 @@ export default class SettingsView extends LoggedView {
|
|||
static propTypes = {
|
||||
componentId: PropTypes.string,
|
||||
userLanguage: PropTypes.string,
|
||||
setUser: PropTypes.func,
|
||||
appStart: PropTypes.func
|
||||
setUser: PropTypes.func
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
|
@ -85,8 +68,6 @@ export default class SettingsView extends LoggedView {
|
|||
}],
|
||||
saving: false
|
||||
};
|
||||
Navigation.events().bindComponent(this);
|
||||
BackHandler.addEventListener('hardwareBackPress', this.handleBackPress);
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
|
@ -104,22 +85,6 @@ export default class SettingsView extends LoggedView {
|
|||
return false;
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
BackHandler.removeEventListener('hardwareBackPress', this.handleBackPress);
|
||||
}
|
||||
|
||||
navigationButtonPressed = ({ buttonId }) => {
|
||||
if (buttonId === 'settings') {
|
||||
Navigation.toggleDrawer();
|
||||
}
|
||||
}
|
||||
|
||||
handleBackPress = () => {
|
||||
const { appStart } = this.props;
|
||||
appStart('background');
|
||||
return false;
|
||||
}
|
||||
|
||||
getLabel = (language) => {
|
||||
const { languages } = this.state;
|
||||
const l = languages.find(i => i.value === language);
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
ScrollView, Text, View, StyleSheet, FlatList, LayoutAnimation, SafeAreaView
|
||||
ScrollView, Text, View, StyleSheet, FlatList, LayoutAnimation, SafeAreaView, Image
|
||||
} from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import Icon from 'react-native-vector-icons/MaterialIcons';
|
||||
import equal from 'deep-equal';
|
||||
|
||||
import Navigation from '../lib/Navigation';
|
||||
import { setStackRoot as setStackRootAction } from '../actions';
|
||||
import { logout as logoutAction } from '../actions/login';
|
||||
import Avatar from '../containers/Avatar';
|
||||
import Status from '../containers/status';
|
||||
|
@ -18,7 +17,8 @@ import RocketChat from '../lib/rocketchat';
|
|||
import log from '../utils/log';
|
||||
import I18n from '../i18n';
|
||||
import scrollPersistTaps from '../utils/scrollPersistTaps';
|
||||
import { getReadableVersion } from '../utils/deviceInfo';
|
||||
import { getReadableVersion, isIOS, isAndroid } from '../utils/deviceInfo';
|
||||
import Icons from '../lib/Icons';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
|
@ -34,14 +34,14 @@ const styles = StyleSheet.create({
|
|||
width: 30,
|
||||
alignItems: 'center'
|
||||
},
|
||||
itemCenter: {
|
||||
flex: 1
|
||||
},
|
||||
itemText: {
|
||||
marginVertical: 16,
|
||||
fontWeight: 'bold',
|
||||
color: '#292E35'
|
||||
},
|
||||
itemSelected: {
|
||||
backgroundColor: '#F7F8FA'
|
||||
},
|
||||
separator: {
|
||||
borderBottomWidth: StyleSheet.hairlineWidth,
|
||||
borderColor: '#ddd',
|
||||
|
@ -79,13 +79,22 @@ const styles = StyleSheet.create({
|
|||
fontWeight: '600',
|
||||
color: '#292E35',
|
||||
fontSize: 13
|
||||
},
|
||||
disclosureContainer: {
|
||||
marginLeft: 6,
|
||||
marginRight: 9,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
},
|
||||
disclosureIndicator: {
|
||||
width: 20,
|
||||
height: 20
|
||||
}
|
||||
});
|
||||
const keyExtractor = item => item.id;
|
||||
|
||||
@connect(state => ({
|
||||
Site_Name: state.settings.Site_Name,
|
||||
stackRoot: state.app.stackRoot,
|
||||
user: {
|
||||
id: state.login.user && state.login.user.id,
|
||||
language: state.login.user && state.login.user.language,
|
||||
|
@ -95,18 +104,27 @@ const keyExtractor = item => item.id;
|
|||
},
|
||||
baseUrl: state.settings.Site_Url || state.server ? state.server.server : ''
|
||||
}), dispatch => ({
|
||||
logout: () => dispatch(logoutAction()),
|
||||
setStackRoot: stackRoot => dispatch(setStackRootAction(stackRoot))
|
||||
logout: () => dispatch(logoutAction())
|
||||
}))
|
||||
export default class Sidebar extends Component {
|
||||
static options() {
|
||||
return {
|
||||
topBar: {
|
||||
leftButtons: [{
|
||||
id: 'cancel',
|
||||
icon: isAndroid ? Icons.getSource('close', false) : undefined,
|
||||
systemItem: 'cancel'
|
||||
}]
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
baseUrl: PropTypes.string,
|
||||
componentId: PropTypes.string,
|
||||
Site_Name: PropTypes.string.isRequired,
|
||||
stackRoot: PropTypes.string.isRequired,
|
||||
user: PropTypes.object,
|
||||
logout: PropTypes.func.isRequired,
|
||||
setStackRoot: PropTypes.func
|
||||
logout: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
|
@ -131,18 +149,13 @@ export default class Sidebar extends Component {
|
|||
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
const { status, showStatus } = this.state;
|
||||
const {
|
||||
Site_Name, stackRoot, user, baseUrl
|
||||
} = this.props;
|
||||
const { Site_Name, user, baseUrl } = this.props;
|
||||
if (nextState.showStatus !== showStatus) {
|
||||
return true;
|
||||
}
|
||||
if (nextProps.Site_Name !== Site_Name) {
|
||||
return true;
|
||||
}
|
||||
if (nextProps.stackRoot !== stackRoot) {
|
||||
return true;
|
||||
}
|
||||
if (nextProps.Site_Name !== Site_Name) {
|
||||
return true;
|
||||
}
|
||||
|
@ -166,11 +179,6 @@ export default class Sidebar extends Component {
|
|||
return false;
|
||||
}
|
||||
|
||||
handleChangeStack = (event) => {
|
||||
const { stack } = event;
|
||||
this.setStack(stack);
|
||||
}
|
||||
|
||||
navigationButtonPressed = ({ buttonId }) => {
|
||||
if (buttonId === 'cancel') {
|
||||
const { componentId } = this.props;
|
||||
|
@ -196,37 +204,30 @@ export default class Sidebar extends Component {
|
|||
});
|
||||
}
|
||||
|
||||
setStack = async(stack) => {
|
||||
const { stackRoot, setStackRoot } = this.props;
|
||||
if (stackRoot !== stack) {
|
||||
await Navigation.setStackRoot('AppRoot', {
|
||||
component: {
|
||||
id: stack,
|
||||
name: stack
|
||||
}
|
||||
});
|
||||
setStackRoot(stack);
|
||||
}
|
||||
}
|
||||
|
||||
closeDrawer = () => {
|
||||
Navigation.toggleDrawer();
|
||||
}
|
||||
|
||||
toggleStatus = () => {
|
||||
LayoutAnimation.easeInEaseOut();
|
||||
this.setState(prevState => ({ showStatus: !prevState.showStatus }));
|
||||
}
|
||||
|
||||
sidebarNavigate = (stack) => {
|
||||
this.closeDrawer();
|
||||
this.setStack(stack);
|
||||
sidebarNavigate = (route) => {
|
||||
const { componentId } = this.props;
|
||||
Navigation.push(componentId, {
|
||||
component: {
|
||||
name: route
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
logout = () => {
|
||||
const { componentId, logout } = this.props;
|
||||
Navigation.dismissModal(componentId);
|
||||
logout();
|
||||
}
|
||||
|
||||
renderSeparator = key => <View key={key} style={styles.separator} />;
|
||||
|
||||
renderItem = ({
|
||||
text, left, onPress, testID, current
|
||||
text, left, onPress, testID, disclosure
|
||||
}) => (
|
||||
<Touch
|
||||
key={text}
|
||||
|
@ -235,14 +236,17 @@ export default class Sidebar extends Component {
|
|||
activeOpacity={0.3}
|
||||
testID={testID}
|
||||
>
|
||||
<View style={[styles.item, current && styles.itemSelected]}>
|
||||
<View style={styles.item}>
|
||||
<View style={styles.itemLeft}>
|
||||
{left}
|
||||
</View>
|
||||
<View style={styles.itemCenter}>
|
||||
<Text style={styles.itemText}>
|
||||
{text}
|
||||
</Text>
|
||||
</View>
|
||||
{disclosure ? this.renderDisclosure() : null}
|
||||
</View>
|
||||
</Touch>
|
||||
)
|
||||
|
||||
|
@ -254,7 +258,6 @@ export default class Sidebar extends Component {
|
|||
left: <View style={[styles.status, { backgroundColor: STATUS_COLORS[item.id] }]} />,
|
||||
current: user.status === item.id,
|
||||
onPress: () => {
|
||||
this.closeDrawer();
|
||||
this.toggleStatus();
|
||||
if (user.status !== item.id) {
|
||||
try {
|
||||
|
@ -268,42 +271,42 @@ export default class Sidebar extends Component {
|
|||
);
|
||||
}
|
||||
|
||||
renderNavigation = () => {
|
||||
const { stackRoot } = this.props;
|
||||
const { logout } = this.props;
|
||||
// Remove it after https://github.com/RocketChat/Rocket.Chat.ReactNative/pull/643
|
||||
renderDisclosure = () => {
|
||||
if (isIOS) {
|
||||
return (
|
||||
<View style={styles.disclosureContainer}>
|
||||
<Image source={{ uri: 'disclosure_indicator' }} style={styles.disclosureIndicator} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
renderNavigation = () => (
|
||||
[
|
||||
this.renderItem({
|
||||
text: I18n.t('Chats'),
|
||||
left: <Icon name='chat-bubble' size={20} />,
|
||||
onPress: () => this.sidebarNavigate('RoomsListView'),
|
||||
testID: 'sidebar-chats',
|
||||
current: stackRoot === 'RoomsListView'
|
||||
}),
|
||||
this.renderItem({
|
||||
text: I18n.t('Profile'),
|
||||
left: <Icon name='person' size={20} />,
|
||||
onPress: () => this.sidebarNavigate('ProfileView'),
|
||||
testID: 'sidebar-profile',
|
||||
current: stackRoot === 'ProfileView'
|
||||
disclosure: true
|
||||
}),
|
||||
this.renderItem({
|
||||
text: I18n.t('Settings'),
|
||||
left: <Icon name='settings' size={20} />,
|
||||
onPress: () => this.sidebarNavigate('SettingsView'),
|
||||
testID: 'sidebar-settings',
|
||||
current: stackRoot === 'SettingsView'
|
||||
disclosure: true
|
||||
}),
|
||||
this.renderSeparator('separator-logout'),
|
||||
this.renderItem({
|
||||
text: I18n.t('Logout'),
|
||||
left: <Icon name='exit-to-app' size={20} />,
|
||||
onPress: () => logout(),
|
||||
onPress: () => this.logout(),
|
||||
testID: 'sidebar-logout'
|
||||
})
|
||||
]
|
||||
);
|
||||
}
|
||||
)
|
||||
|
||||
renderStatus = () => {
|
||||
const { status } = this.state;
|
||||
|
|
|
@ -169,7 +169,7 @@ describe('Room screen', () => {
|
|||
await element(by.text(`${ data.random }message`)).longPress();
|
||||
await waitFor(element(by.text('Message actions'))).toBeVisible().withTimeout(5000);
|
||||
await expect(element(by.text('Message actions'))).toBeVisible();
|
||||
await element(by.text('Copy Permalink')).tap();
|
||||
await element(by.text('Permalink')).tap();
|
||||
await expect(element(by.text('Permalink copied to clipboard!'))).toBeVisible();
|
||||
await waitFor(element(by.text('Permalink copied to clipboard!'))).toBeNotVisible().withTimeout(5000);
|
||||
|
||||
|
@ -180,7 +180,7 @@ describe('Room screen', () => {
|
|||
await element(by.text(`${ data.random }message`)).longPress();
|
||||
await waitFor(element(by.text('Message actions'))).toBeVisible().withTimeout(5000);
|
||||
await expect(element(by.text('Message actions'))).toBeVisible();
|
||||
await element(by.text('Copy Message')).tap();
|
||||
await element(by.text('Copy')).tap();
|
||||
await expect(element(by.text('Copied to clipboard!'))).toBeVisible();
|
||||
await waitFor(element(by.text('Copied to clipboard!'))).toBeNotVisible().withTimeout(5000);
|
||||
// TODO: test clipboard
|
||||
|
|
Loading…
Reference in New Issue