* Update screens * Update login tests * Remove done * Fix failing tests * Update screens and components * Check styles fix * Update tests * Prevent setState call after component unmounts * Add empty setButtons func to dummy navigator * Remove platform check * Remove Platform import * Update react-native-navigation version * Add separate showModalOverCurrentContext function * check-style fixes * Remove overriding of AppDelegate's window * Fix modal over current context animation * Add showSearchModal navigation action * Check-style fix * Address review comments * Update SettingsSidebar and children * Update EditProfile screen * Update SettingsSidebar * Keep track of latest componentId to appear * Track componentId in state to use in navigation actions * Update FlaggedPosts and children * Update RecentMentions * Update Settings * Store componentIds in ephemeral store * Update AttachmentButton * Remove unnecessary dismissModal * Fix typo * Upate NotificationSettings * Update NotificationSettingsAutoResponder * Update NotificationSettingsMentions * Update NotificationSettingsMobile * Update CreateChannel and children * Update MoreChannels * Update ChannelPeek and children * Update ChannelNavBar and children * Update ChannelPostList and children * Update ChannelInfo and children * Update ChannelAddMembers * Update ChannelMembers * Update EditChannel * Fix setting of top bar buttons * Update Channel screen and children * Update PinnedPosts * Update LongPost * Update PostOptions * Update PostTextboxBase * Update EditPost * Check-styles fix * Update DisplaySettings * Update Timezone * Update SelectTimezone * Update IntlWrapper and Notification * Update InteractiveDialog and children * Update ExpandedAnnouncementBanner * Update ClientUpgradeListener * Update MoreDirectMessages * Update SelectorScreen * Update UserProfile * Update Thread * Update About * Update ImagePreview * Update TextPreview * Update AddReaction * Update ReactionList and children * Update Code * Update TermsOfService * Update Permalink * Update Permalink * Update ErrorTeamsList * Update Search * Remove navigator prop * Fix setButtons calls * Remove navigationComponentId * Fix test * Handle in-app notifs in global event handler * Fix in-app notification handling * Fix typo * Fix tests * Auto dismiss in-app notif after 5 seconds * Fix typo * Update overlay dismissal * Animate in-app notif dismissal and allow gesture dismissal
393 lines
13 KiB
JavaScript
393 lines
13 KiB
JavaScript
// Copyright (c) 2015-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,
|
|
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 DrawerLayout from 'app/components/sidebars/drawer_layout';
|
|
import UserStatus from 'app/components/user_status';
|
|
import {DeviceTypes, NavigationTypes} from 'app/constants';
|
|
import {confirmOutOfOfficeDisabled} from 'app/utils/status';
|
|
import {preventDoubleTap} from 'app/utils/tap';
|
|
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
|
|
import {t} from 'app/utils/i18n';
|
|
|
|
import DrawerItem from './drawer_item';
|
|
import UserInfo from './user_info';
|
|
import StatusLabel from './status_label';
|
|
|
|
const DRAWER_INITIAL_OFFSET = 80;
|
|
const DRAWER_TABLET_WIDTH = 300;
|
|
|
|
export default class SettingsDrawer extends PureComponent {
|
|
static propTypes = {
|
|
actions: PropTypes.shape({
|
|
logout: PropTypes.func.isRequired,
|
|
setStatus: PropTypes.func.isRequired,
|
|
showModal: PropTypes.func.isRequired,
|
|
showModalOverCurrentContext: PropTypes.func.isRequired,
|
|
dismissModal: PropTypes.func.isRequired,
|
|
}).isRequired,
|
|
blurPostTextBox: PropTypes.func.isRequired,
|
|
children: PropTypes.node,
|
|
currentUser: PropTypes.object.isRequired,
|
|
deviceWidth: PropTypes.number.isRequired,
|
|
isLandscape: PropTypes.bool.isRequired,
|
|
status: PropTypes.string,
|
|
theme: PropTypes.object.isRequired,
|
|
};
|
|
|
|
static defaultProps = {
|
|
currentUser: {},
|
|
status: 'offline',
|
|
};
|
|
|
|
static contextTypes = {
|
|
intl: intlShape,
|
|
};
|
|
|
|
constructor(props) {
|
|
super(props);
|
|
|
|
MaterialIcon.getImageSource('close', 20, props.theme.sidebarHeaderTextColor).then((source) => {
|
|
this.closeButton = source;
|
|
});
|
|
}
|
|
|
|
componentDidMount() {
|
|
EventEmitter.on('close_settings_sidebar', this.closeSettingsSidebar);
|
|
BackHandler.addEventListener('hardwareBackPress', this.handleAndroidBack);
|
|
}
|
|
|
|
componentWillUnmount() {
|
|
EventEmitter.off('close_settings_sidebar', this.closeSettingsSidebar);
|
|
BackHandler.removeEventListener('hardwareBackPress', this.handleAndroidBack);
|
|
}
|
|
|
|
handleAndroidBack = () => {
|
|
if (this.refs.drawer && this.drawerOpened) {
|
|
this.refs.drawer.closeDrawer();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
};
|
|
|
|
openSettingsSidebar = () => {
|
|
this.props.blurPostTextBox();
|
|
|
|
if (this.refs.drawer && !this.drawerOpened) {
|
|
this.refs.drawer.openDrawer();
|
|
}
|
|
};
|
|
|
|
closeSettingsSidebar = () => {
|
|
if (this.refs.drawer && this.drawerOpened) {
|
|
this.refs.drawer.closeDrawer();
|
|
}
|
|
};
|
|
|
|
handleDrawerClose = () => {
|
|
this.drawerOpened = false;
|
|
Keyboard.dismiss();
|
|
};
|
|
|
|
handleDrawerOpen = () => {
|
|
this.drawerOpened = true;
|
|
Keyboard.dismiss();
|
|
};
|
|
|
|
handleSetStatus = preventDoubleTap(() => {
|
|
const {actions} = this.props;
|
|
const items = [{
|
|
action: () => this.setStatus(General.ONLINE),
|
|
text: {
|
|
id: t('mobile.set_status.online'),
|
|
defaultMessage: 'Online',
|
|
},
|
|
}, {
|
|
action: () => this.setStatus(General.AWAY),
|
|
text: {
|
|
id: t('mobile.set_status.away'),
|
|
defaultMessage: 'Away',
|
|
},
|
|
}, {
|
|
action: () => this.setStatus(General.DND),
|
|
text: {
|
|
id: t('mobile.set_status.dnd'),
|
|
defaultMessage: 'Do Not Disturb',
|
|
},
|
|
}, {
|
|
action: () => this.setStatus(General.OFFLINE),
|
|
text: {
|
|
id: t('mobile.set_status.offline'),
|
|
defaultMessage: 'Offline',
|
|
},
|
|
}];
|
|
|
|
actions.showModalOverCurrentContext('OptionsModal', {items});
|
|
});
|
|
|
|
goToEditProfile = preventDoubleTap(() => {
|
|
const {currentUser} = this.props;
|
|
const {formatMessage} = this.context.intl;
|
|
const commandType = 'ShowModal';
|
|
|
|
this.openModal(
|
|
'EditProfile',
|
|
formatMessage({id: 'mobile.routes.edit_profile', defaultMessage: 'Edit Profile'}),
|
|
{currentUser, commandType}
|
|
);
|
|
});
|
|
|
|
goToFlagged = preventDoubleTap(() => {
|
|
const {formatMessage} = this.context.intl;
|
|
|
|
this.openModal(
|
|
'FlaggedPosts',
|
|
formatMessage({id: 'search_header.title3', defaultMessage: 'Flagged Posts'}),
|
|
);
|
|
});
|
|
|
|
goToMentions = preventDoubleTap(() => {
|
|
const {intl} = this.context;
|
|
|
|
this.openModal(
|
|
'RecentMentions',
|
|
intl.formatMessage({id: 'search_header.title2', defaultMessage: 'Recent Mentions'}),
|
|
);
|
|
});
|
|
|
|
goToUserProfile = preventDoubleTap(() => {
|
|
const userId = this.props.currentUser.id;
|
|
const {formatMessage} = this.context.intl;
|
|
|
|
this.openModal(
|
|
'UserProfile',
|
|
formatMessage({id: 'mobile.routes.user_profile', defaultMessage: 'Profile'}),
|
|
{userId, fromSettings: true}
|
|
);
|
|
});
|
|
|
|
goToSettings = preventDoubleTap(() => {
|
|
const {intl} = this.context;
|
|
|
|
this.openModal(
|
|
'Settings',
|
|
intl.formatMessage({id: 'mobile.routes.settings', defaultMessage: 'Settings'}),
|
|
);
|
|
});
|
|
|
|
logout = preventDoubleTap(() => {
|
|
const {logout} = this.props.actions;
|
|
this.closeSettingsSidebar();
|
|
logout();
|
|
});
|
|
|
|
openModal = (screen, title, passProps) => {
|
|
this.closeSettingsSidebar();
|
|
|
|
const {actions} = this.props;
|
|
const options = {
|
|
topBar: {
|
|
leftButtons: [{
|
|
id: 'close-settings',
|
|
icon: this.closeButton,
|
|
}],
|
|
},
|
|
};
|
|
|
|
InteractionManager.runAfterInteractions(() => {
|
|
actions.showModal(screen, title, passProps, options);
|
|
});
|
|
};
|
|
|
|
renderUserStatusIcon = (userId) => {
|
|
return (
|
|
<UserStatus
|
|
size={18}
|
|
userId={userId}
|
|
/>
|
|
);
|
|
};
|
|
|
|
renderUserStatusLabel = (userId) => {
|
|
return (
|
|
<StatusLabel userId={userId}/>
|
|
);
|
|
};
|
|
|
|
renderNavigationView = () => {
|
|
const {currentUser, 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}/>}
|
|
theme={theme}
|
|
>
|
|
<View style={style.container}>
|
|
<ScrollView
|
|
alwaysBounceVertical={false}
|
|
contentContainerStyle={style.wrapper}
|
|
>
|
|
<UserInfo
|
|
onPress={this.goToUserProfile}
|
|
user={currentUser}
|
|
/>
|
|
<View style={style.block}>
|
|
<DrawerItem
|
|
labelComponent={this.renderUserStatusLabel(currentUser.id)}
|
|
leftComponent={this.renderUserStatusIcon(currentUser.id)}
|
|
separator={false}
|
|
onPress={this.handleSetStatus}
|
|
theme={theme}
|
|
/>
|
|
</View>
|
|
<View style={style.separator}/>
|
|
<View style={style.block}>
|
|
<DrawerItem
|
|
defaultMessage='Recent Mentions'
|
|
i18nId='search_header.title2'
|
|
iconName='ios-at'
|
|
iconType='ion'
|
|
onPress={this.goToMentions}
|
|
separator={true}
|
|
theme={theme}
|
|
/>
|
|
<DrawerItem
|
|
defaultMessage='Flagged Posts'
|
|
i18nId='search_header.title3'
|
|
iconName='ios-flag'
|
|
iconType='ion'
|
|
onPress={this.goToFlagged}
|
|
separator={false}
|
|
theme={theme}
|
|
/>
|
|
</View>
|
|
<View style={style.separator}/>
|
|
<View style={style.block}>
|
|
<DrawerItem
|
|
defaultMessage='Edit Profile'
|
|
i18nId='mobile.routes.edit_profile'
|
|
iconName='ios-person'
|
|
iconType='ion'
|
|
onPress={this.goToEditProfile}
|
|
separator={true}
|
|
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>
|
|
);
|
|
};
|
|
|
|
confirmReset = (status) => {
|
|
const {intl} = this.context;
|
|
confirmOutOfOfficeDisabled(intl, status, this.updateStatus);
|
|
};
|
|
|
|
updateStatus = (status) => {
|
|
const {currentUser: {id: currentUserId}} = this.props;
|
|
this.props.actions.setStatus({
|
|
user_id: currentUserId,
|
|
status,
|
|
});
|
|
};
|
|
|
|
setStatus = (status) => {
|
|
const {status: currentUserStatus, actions} = this.props;
|
|
|
|
if (currentUserStatus === General.OUT_OF_OFFICE) {
|
|
actions.dismissModal();
|
|
this.closeSettingsSidebar();
|
|
this.confirmReset(status);
|
|
return;
|
|
}
|
|
this.updateStatus(status);
|
|
EventEmitter.emit(NavigationTypes.NAVIGATION_CLOSE_MODAL);
|
|
};
|
|
|
|
render() {
|
|
const {children, deviceWidth} = this.props;
|
|
const drawerWidth = DeviceTypes.IS_TABLET ? DRAWER_TABLET_WIDTH : (deviceWidth - DRAWER_INITIAL_OFFSET);
|
|
|
|
return (
|
|
<DrawerLayout
|
|
ref='drawer'
|
|
renderNavigationView={this.renderNavigationView}
|
|
onDrawerClose={this.handleDrawerClose}
|
|
onDrawerOpen={this.handleDrawerOpen}
|
|
drawerPosition='right'
|
|
drawerWidth={drawerWidth}
|
|
useNativeAnimations={true}
|
|
>
|
|
{children}
|
|
</DrawerLayout>
|
|
);
|
|
}
|
|
}
|
|
|
|
const getStyleSheet = makeStyleSheetFromTheme((theme) => {
|
|
return {
|
|
container: {
|
|
flex: 1,
|
|
backgroundColor: changeOpacity(theme.centerChannelColor, 0.03),
|
|
},
|
|
wrapper: {
|
|
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,
|
|
},
|
|
};
|
|
});
|