* Add set status feature Small code refactoring Add Do Not Disturb option * Add Account Settings screen Add username, nicname, and position fields Add email field get deviceHeight from redux Clean up onPress handler in Settings Refactor each account settings item to it's own component Clean up email field and updateUser action method Use mobile localization format in en.json Update profile image Clean up ProfilePicture for editing Add loading and error components in AccountSettings Refactor updateRequest state into a function Follow design specs Remove unnecessary this.state.emailUpdated Polish AccountSettings and secondary components Refactor AttachmentButton into it's own componentg Add Account Settings icon in General Settings Add TODO comments * Update user status * Edit Profile screen refactored * Fix edit profile item text color
399 lines
12 KiB
JavaScript
399 lines
12 KiB
JavaScript
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
|
|
// See License.txt for license information.
|
|
|
|
import React, {PureComponent} from 'react';
|
|
import PropTypes from 'prop-types';
|
|
import {intlShape} from 'react-intl';
|
|
import {
|
|
BackHandler,
|
|
InteractionManager,
|
|
Keyboard,
|
|
Platform,
|
|
ScrollView,
|
|
View
|
|
} from 'react-native';
|
|
import MaterialIcon from 'react-native-vector-icons/MaterialIcons';
|
|
|
|
import {General} from 'mattermost-redux/constants';
|
|
import EventEmitter from 'mattermost-redux/utils/event_emitter';
|
|
|
|
import SafeAreaView from 'app/components/safe_area_view';
|
|
import Drawer from 'app/components/drawer';
|
|
import UserStatus from 'app/components/user_status';
|
|
import {NavigationTypes} from 'app/constants';
|
|
import {wrapWithPreventDoubleTap} from 'app/utils/tap';
|
|
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
|
|
|
|
import DrawerItem from './drawer_item';
|
|
import UserInfo from './user_info';
|
|
import StatusLabel from './status_label';
|
|
|
|
const DRAWER_INITIAL_OFFSET = 80;
|
|
|
|
export default class SettingsDrawer extends PureComponent {
|
|
static propTypes = {
|
|
actions: PropTypes.shape({
|
|
logout: PropTypes.func.isRequired,
|
|
setStatus: PropTypes.func.isRequired
|
|
}).isRequired,
|
|
blurPostTextBox: PropTypes.func.isRequired,
|
|
children: PropTypes.node,
|
|
currentUser: PropTypes.object.isRequired,
|
|
navigator: PropTypes.object,
|
|
theme: PropTypes.object.isRequired
|
|
};
|
|
|
|
static defaultProps = {
|
|
currentUser: {}
|
|
};
|
|
|
|
static contextTypes = {
|
|
intl: intlShape
|
|
};
|
|
|
|
constructor(props) {
|
|
super(props);
|
|
|
|
this.closeHandle = null;
|
|
this.openHandle = null;
|
|
|
|
MaterialIcon.getImageSource('close', 20, this.props.theme.sidebarHeaderTextColor).then((source) => {
|
|
this.closeButton = source;
|
|
});
|
|
}
|
|
|
|
componentDidMount() {
|
|
BackHandler.addEventListener('hardwareBackPress', this.handleAndroidBack);
|
|
}
|
|
|
|
componentWillUnmount() {
|
|
BackHandler.removeEventListener('hardwareBackPress', this.handleAndroidBack);
|
|
}
|
|
|
|
handleAndroidBack = () => {
|
|
if (this.refs.drawer && this.refs.drawer.isOpened()) {
|
|
this.refs.drawer.close();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
};
|
|
|
|
openSettingsDrawer = () => {
|
|
this.props.blurPostTextBox();
|
|
|
|
if (this.refs.drawer && !this.refs.drawer.isOpened()) {
|
|
this.refs.drawer.open();
|
|
}
|
|
};
|
|
|
|
closeSettingsDrawer = () => {
|
|
if (this.refs.drawer && this.refs.drawer.isOpened()) {
|
|
this.refs.drawer.close();
|
|
}
|
|
};
|
|
|
|
handleDrawerTween = (ratio) => {
|
|
const opacity = (ratio / 2);
|
|
|
|
EventEmitter.emit('drawer_opacity', opacity);
|
|
|
|
return {
|
|
mainOverlay: {
|
|
backgroundColor: '#000',
|
|
elevation: 3,
|
|
opacity
|
|
}
|
|
};
|
|
};
|
|
|
|
handleDrawerClose = () => {
|
|
if (this.closeHandle) {
|
|
InteractionManager.clearInteractionHandle(this.closeHandle);
|
|
this.closeHandle = null;
|
|
}
|
|
};
|
|
|
|
handleDrawerCloseStart = () => {
|
|
if (!this.closeHandle) {
|
|
this.closeHandle = InteractionManager.createInteractionHandle();
|
|
}
|
|
};
|
|
|
|
handleDrawerOpen = () => {
|
|
Keyboard.dismiss();
|
|
|
|
if (this.openHandle) {
|
|
InteractionManager.clearInteractionHandle(this.openHandle);
|
|
this.openHandle = null;
|
|
}
|
|
};
|
|
|
|
handleDrawerOpenStart = () => {
|
|
if (!this.openHandle) {
|
|
this.openHandle = InteractionManager.createInteractionHandle();
|
|
}
|
|
};
|
|
|
|
handleSetStatus = wrapWithPreventDoubleTap(() => {
|
|
const items = [{
|
|
action: () => this.setStatus(General.ONLINE),
|
|
text: {
|
|
id: 'mobile.set_status.online',
|
|
defaultMessage: 'Online'
|
|
}
|
|
}, {
|
|
action: () => this.setStatus(General.AWAY),
|
|
text: {
|
|
id: 'mobile.set_status.away',
|
|
defaultMessage: 'Away'
|
|
}
|
|
}, {
|
|
action: () => this.setStatus(General.DND),
|
|
text: {
|
|
id: 'mobile.set_status.dnd',
|
|
defaultMessage: 'Do Not Disturb'
|
|
}
|
|
}, {
|
|
action: () => this.setStatus(General.OFFLINE),
|
|
text: {
|
|
id: 'mobile.set_status.offline',
|
|
defaultMessage: 'Offline'
|
|
}
|
|
}];
|
|
|
|
this.props.navigator.showModal({
|
|
screen: 'OptionsModal',
|
|
title: '',
|
|
animationType: 'none',
|
|
passProps: {
|
|
items
|
|
},
|
|
navigatorStyle: {
|
|
navBarHidden: true,
|
|
statusBarHidden: false,
|
|
statusBarHideWithNavBar: false,
|
|
screenBackgroundColor: 'transparent',
|
|
modalPresentationStyle: 'overCurrentContext'
|
|
}
|
|
});
|
|
});
|
|
|
|
goToEditProfile = wrapWithPreventDoubleTap(() => {
|
|
const {currentUser, navigator, theme} = this.props;
|
|
const {formatMessage} = this.context.intl;
|
|
|
|
this.closeSettingsDrawer();
|
|
navigator.showModal({
|
|
screen: 'EditProfile',
|
|
title: formatMessage({id: 'mobile.routes.edit_profile', defaultMessage: 'Edit Profile'}),
|
|
animationType: 'slide-up',
|
|
animated: true,
|
|
backButtonTitle: '',
|
|
navigatorStyle: {
|
|
navBarTextColor: theme.sidebarHeaderTextColor,
|
|
navBarBackgroundColor: theme.sidebarHeaderBg,
|
|
navBarButtonColor: theme.sidebarHeaderTextColor,
|
|
screenBackgroundColor: theme.centerChannelBg
|
|
},
|
|
navigatorButtons: {
|
|
leftButtons: [{
|
|
id: 'close-settings',
|
|
icon: this.closeButton
|
|
}]
|
|
},
|
|
passProps: {
|
|
currentUser
|
|
}
|
|
});
|
|
});
|
|
|
|
goToSettings = wrapWithPreventDoubleTap(() => {
|
|
const {intl} = this.context;
|
|
const {navigator, theme} = this.props;
|
|
|
|
this.closeSettingsDrawer();
|
|
navigator.showModal({
|
|
screen: 'Settings',
|
|
title: intl.formatMessage({id: 'mobile.routes.settings', defaultMessage: 'Settings'}),
|
|
animationType: 'slide-up',
|
|
animated: true,
|
|
backButtonTitle: '',
|
|
navigatorStyle: {
|
|
navBarTextColor: theme.sidebarHeaderTextColor,
|
|
navBarBackgroundColor: theme.sidebarHeaderBg,
|
|
navBarButtonColor: theme.sidebarHeaderTextColor,
|
|
screenBackgroundColor: theme.centerChannelBg
|
|
},
|
|
navigatorButtons: {
|
|
leftButtons: [{
|
|
id: 'close-settings',
|
|
icon: this.closeButton
|
|
}]
|
|
}
|
|
});
|
|
});
|
|
|
|
logout = wrapWithPreventDoubleTap(() => {
|
|
const {logout} = this.props.actions;
|
|
this.closeSettingsDrawer();
|
|
InteractionManager.runAfterInteractions(logout);
|
|
});
|
|
|
|
renderUserStatusIcon = (userId) => {
|
|
return (
|
|
<UserStatus
|
|
size={18}
|
|
userId={userId}
|
|
/>
|
|
);
|
|
};
|
|
|
|
renderUserStatusLabel = (userId) => {
|
|
return (
|
|
<StatusLabel userId={userId}/>
|
|
);
|
|
};
|
|
|
|
renderContent = () => {
|
|
const {currentUser, navigator, theme} = this.props;
|
|
const style = getStyleSheet(theme);
|
|
|
|
return (
|
|
<SafeAreaView
|
|
backgroundColor={theme.centerChannelBg}
|
|
navBarBackgroundColor={theme.centerChannelBg}
|
|
footerColor={theme.centerChannelBg}
|
|
footerComponent={<View style={style.container}/>}
|
|
headerComponent={<View style={style.container}/>}
|
|
navigator={navigator}
|
|
theme={theme}
|
|
>
|
|
<View style={style.container}>
|
|
<ScrollView
|
|
alwaysBounceVertical={false}
|
|
contentContainerStyle={style.wrapper}
|
|
>
|
|
<UserInfo
|
|
onPress={this.goToEditProfile}
|
|
user={currentUser}
|
|
/>
|
|
<View style={style.block}>
|
|
<DrawerItem
|
|
labelComponent={this.renderUserStatusLabel(currentUser.id)}
|
|
leftComponent={this.renderUserStatusIcon(currentUser.id)}
|
|
separator={true}
|
|
onPress={this.handleSetStatus}
|
|
theme={theme}
|
|
/>
|
|
<DrawerItem
|
|
defaultMessage='Settings'
|
|
i18nId='mobile.routes.settings'
|
|
iconName='ios-options'
|
|
iconType='ion'
|
|
onPress={this.goToSettings}
|
|
separator={false}
|
|
theme={theme}
|
|
/>
|
|
</View>
|
|
<View style={style.separator}/>
|
|
<View style={style.block}>
|
|
<DrawerItem
|
|
centered={true}
|
|
defaultMessage='Logout'
|
|
i18nId='sidebar_right_menu.logout'
|
|
isDestructor={true}
|
|
onPress={this.logout}
|
|
separator={false}
|
|
theme={theme}
|
|
/>
|
|
</View>
|
|
</ScrollView>
|
|
</View>
|
|
</SafeAreaView>
|
|
);
|
|
};
|
|
|
|
setStatus = (status) => {
|
|
const {currentUser: {id: currentUserId}} = this.props;
|
|
this.props.actions.setStatus({
|
|
user_id: currentUserId,
|
|
status
|
|
});
|
|
EventEmitter.emit(NavigationTypes.NAVIGATION_CLOSE_MODAL);
|
|
};
|
|
|
|
render() {
|
|
const {children} = this.props;
|
|
|
|
return (
|
|
<Drawer
|
|
ref='drawer'
|
|
onOpenStart={this.handleDrawerOpenStart}
|
|
onOpen={this.handleDrawerOpen}
|
|
onClose={this.handleDrawerClose}
|
|
onCloseStart={this.handleDrawerCloseStart}
|
|
side='right'
|
|
captureGestures='open'
|
|
type='overlay'
|
|
acceptTap={true}
|
|
acceptPanOnDrawer={false}
|
|
disabled={false}
|
|
content={this.renderContent()}
|
|
tapToClose={true}
|
|
openDrawerOffset={DRAWER_INITIAL_OFFSET}
|
|
onRequestClose={this.closeSettingsDrawer}
|
|
panOpenMask={0.05}
|
|
panCloseMask={DRAWER_INITIAL_OFFSET}
|
|
panThreshold={0.25}
|
|
acceptPan={true}
|
|
negotiatePan={true}
|
|
useInteractionManager={false}
|
|
tweenDuration={100}
|
|
tweenHandler={this.handleDrawerTween}
|
|
elevation={5}
|
|
bottomPanOffset={Platform.OS === 'ios' ? 46 : 64}
|
|
topPanOffset={Platform.OS === 'ios' ? 64 : 46}
|
|
styles={{
|
|
main: {
|
|
shadowColor: '#000000',
|
|
shadowOpacity: 0.4,
|
|
shadowRadius: 12,
|
|
shadowOffset: {
|
|
width: -4,
|
|
height: 0
|
|
}
|
|
}
|
|
}}
|
|
>
|
|
{children}
|
|
</Drawer>
|
|
);
|
|
}
|
|
}
|
|
|
|
const getStyleSheet = makeStyleSheetFromTheme((theme) => {
|
|
return {
|
|
container: {
|
|
flex: 1,
|
|
backgroundColor: changeOpacity(theme.centerChannelColor, 0.03)
|
|
},
|
|
wrapper: {
|
|
flex: 1,
|
|
paddingTop: 0
|
|
},
|
|
block: {
|
|
borderBottomColor: changeOpacity(theme.centerChannelColor, 0.1),
|
|
borderBottomWidth: 1,
|
|
borderTopColor: changeOpacity(theme.centerChannelColor, 0.1),
|
|
borderTopWidth: 1
|
|
},
|
|
divider: {
|
|
backgroundColor: changeOpacity(theme.centerChannelColor, 0.1),
|
|
height: 1
|
|
},
|
|
separator: {
|
|
marginTop: 35
|
|
}
|
|
};
|
|
});
|