[MM-16136] Update channel related screens (#2915)
* 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 * Fix typo * Use goToScreen for Android too * Remove navigationComponentId
This commit is contained in:
parent
74c7805e65
commit
b65ce5d283
37 changed files with 738 additions and 774 deletions
|
|
@ -312,10 +312,8 @@ export function peek(name, passProps = {}, options = {}) {
|
|||
};
|
||||
}
|
||||
|
||||
export function setButtons(buttons = {leftButtons: [], rightButtons: []}) {
|
||||
export function setButtons(componentId, buttons = {leftButtons: [], rightButtons: []}) {
|
||||
return () => {
|
||||
const componentId = EphemeralStore.getTopComponentId();
|
||||
|
||||
Navigation.mergeOptions(componentId, {
|
||||
topBar: {
|
||||
...buttons,
|
||||
|
|
|
|||
|
|
@ -18,12 +18,14 @@ const {View: AnimatedView} = Animated;
|
|||
|
||||
export default class AnnouncementBanner extends PureComponent {
|
||||
static propTypes = {
|
||||
actions: PropTypes.shape({
|
||||
goToScreen: PropTypes.func.isRequired,
|
||||
}).isRequired,
|
||||
bannerColor: PropTypes.string,
|
||||
bannerDismissed: PropTypes.bool,
|
||||
bannerEnabled: PropTypes.bool,
|
||||
bannerText: PropTypes.string,
|
||||
bannerTextColor: PropTypes.string,
|
||||
navigator: PropTypes.object.isRequired,
|
||||
theme: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
|
|
@ -52,23 +54,16 @@ export default class AnnouncementBanner extends PureComponent {
|
|||
}
|
||||
|
||||
handlePress = () => {
|
||||
const {navigator, theme} = this.props;
|
||||
const {actions} = this.props;
|
||||
const {intl} = this.context;
|
||||
|
||||
navigator.push({
|
||||
screen: 'ExpandedAnnouncementBanner',
|
||||
title: this.context.intl.formatMessage({
|
||||
id: 'mobile.announcement_banner.title',
|
||||
defaultMessage: 'Announcement',
|
||||
}),
|
||||
animated: true,
|
||||
backButtonTitle: '',
|
||||
navigatorStyle: {
|
||||
navBarTextColor: theme.sidebarHeaderTextColor,
|
||||
navBarBackgroundColor: theme.sidebarHeaderBg,
|
||||
navBarButtonColor: theme.sidebarHeaderTextColor,
|
||||
screenBackgroundColor: theme.centerChannelBg,
|
||||
},
|
||||
const screen = 'ExpandedAnnouncementBanner';
|
||||
const title = intl.formatMessage({
|
||||
id: 'mobile.announcement_banner.title',
|
||||
defaultMessage: 'Announcement',
|
||||
});
|
||||
|
||||
actions.goToScreen(screen, title);
|
||||
};
|
||||
|
||||
toggleBanner = (show = true) => {
|
||||
|
|
|
|||
|
|
@ -12,12 +12,14 @@ jest.useFakeTimers();
|
|||
|
||||
describe('AnnouncementBanner', () => {
|
||||
const baseProps = {
|
||||
actions: {
|
||||
goToScreen: jest.fn(),
|
||||
},
|
||||
bannerColor: '#ddd',
|
||||
bannerDismissed: false,
|
||||
bannerEnabled: true,
|
||||
bannerText: 'Banner Text',
|
||||
bannerTextColor: '#fff',
|
||||
navigator: {},
|
||||
theme: Preferences.THEMES.default,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,14 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {bindActionCreators} from 'redux';
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import {getConfig, getLicense} from 'mattermost-redux/selectors/entities/general';
|
||||
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
|
||||
|
||||
import {goToScreen} from 'app/actions/navigation';
|
||||
|
||||
import AnnouncementBanner from './announcement_banner';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
|
|
@ -23,4 +26,12 @@ function mapStateToProps(state) {
|
|||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(AnnouncementBanner);
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators({
|
||||
goToScreen,
|
||||
}, dispatch),
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(AnnouncementBanner);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
import React, {PureComponent} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
Platform,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
|
|
@ -21,11 +20,13 @@ import {t} from 'app/utils/i18n';
|
|||
|
||||
class ChannelIntro extends PureComponent {
|
||||
static propTypes = {
|
||||
actions: PropTypes.shape({
|
||||
goToScreen: PropTypes.func.isRequired,
|
||||
}).isRequired,
|
||||
creator: PropTypes.object,
|
||||
currentChannel: PropTypes.object.isRequired,
|
||||
currentChannelMembers: PropTypes.array.isRequired,
|
||||
intl: intlShape.isRequired,
|
||||
navigator: PropTypes.object.isRequired,
|
||||
theme: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
|
|
@ -34,28 +35,14 @@ class ChannelIntro extends PureComponent {
|
|||
};
|
||||
|
||||
goToUserProfile = (userId) => {
|
||||
const {intl, navigator, theme} = this.props;
|
||||
const options = {
|
||||
screen: 'UserProfile',
|
||||
title: intl.formatMessage({id: 'mobile.routes.user_profile', defaultMessage: 'Profile'}),
|
||||
animated: true,
|
||||
backButtonTitle: '',
|
||||
passProps: {
|
||||
userId,
|
||||
},
|
||||
navigatorStyle: {
|
||||
navBarTextColor: theme.sidebarHeaderTextColor,
|
||||
navBarBackgroundColor: theme.sidebarHeaderBg,
|
||||
navBarButtonColor: theme.sidebarHeaderTextColor,
|
||||
screenBackgroundColor: theme.centerChannelBg,
|
||||
},
|
||||
const {actions, intl} = this.props;
|
||||
const screen = 'UserProfile';
|
||||
const title = intl.formatMessage({id: 'mobile.routes.user_profile', defaultMessage: 'Profile'});
|
||||
const passProps = {
|
||||
userId,
|
||||
};
|
||||
|
||||
if (Platform.OS === 'ios') {
|
||||
navigator.push(options);
|
||||
} else {
|
||||
navigator.showModal(options);
|
||||
}
|
||||
actions.goToScreen(screen, title, passProps);
|
||||
};
|
||||
|
||||
getDisplayName = (member) => {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {bindActionCreators} from 'redux';
|
||||
import {connect} from 'react-redux';
|
||||
import {createSelector} from 'reselect';
|
||||
|
||||
|
|
@ -10,6 +11,7 @@ import {getCurrentUserId, getUser, makeGetProfilesInChannel} from 'mattermost-re
|
|||
|
||||
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
|
||||
|
||||
import {goToScreen} from 'app/actions/navigation';
|
||||
import {getChannelMembersForDm} from 'app/selectors/channel';
|
||||
|
||||
import ChannelIntro from './channel_intro';
|
||||
|
|
@ -52,4 +54,12 @@ function makeMapStateToProps() {
|
|||
};
|
||||
}
|
||||
|
||||
export default connect(makeMapStateToProps)(ChannelIntro);
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators({
|
||||
goToScreen,
|
||||
}, dispatch),
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(makeMapStateToProps, mapDispatchToProps)(ChannelIntro);
|
||||
|
|
|
|||
415
app/components/edit_channel_info/edit_channel_info.js
Normal file
415
app/components/edit_channel_info/edit_channel_info.js
Normal file
|
|
@ -0,0 +1,415 @@
|
|||
// 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 {
|
||||
Platform,
|
||||
TouchableWithoutFeedback,
|
||||
View,
|
||||
Text,
|
||||
findNodeHandle,
|
||||
} from 'react-native';
|
||||
import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view';
|
||||
|
||||
import ErrorText from 'app/components/error_text';
|
||||
import FormattedText from 'app/components/formatted_text';
|
||||
import Loading from 'app/components/loading';
|
||||
import StatusBar from 'app/components/status_bar';
|
||||
import TextInputWithLocalizedPlaceholder from 'app/components/text_input_with_localized_placeholder';
|
||||
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
|
||||
import {General} from 'mattermost-redux/constants';
|
||||
import {getShortenedURL} from 'app/utils/url';
|
||||
import {t} from 'app/utils/i18n';
|
||||
|
||||
export default class EditChannelInfo extends PureComponent {
|
||||
static propTypes = {
|
||||
actions: PropTypes.shape({
|
||||
dismissModal: PropTypes.func.isRequired,
|
||||
popTopScreen: PropTypes.func.isRequired,
|
||||
}),
|
||||
theme: PropTypes.object.isRequired,
|
||||
deviceWidth: PropTypes.number.isRequired,
|
||||
deviceHeight: PropTypes.number.isRequired,
|
||||
channelType: PropTypes.string,
|
||||
enableRightButton: PropTypes.func,
|
||||
saving: PropTypes.bool.isRequired,
|
||||
editing: PropTypes.bool,
|
||||
error: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
|
||||
displayName: PropTypes.string,
|
||||
currentTeamUrl: PropTypes.string,
|
||||
channelURL: PropTypes.string,
|
||||
purpose: PropTypes.string,
|
||||
header: PropTypes.string,
|
||||
onDisplayNameChange: PropTypes.func,
|
||||
onChannelURLChange: PropTypes.func,
|
||||
onPurposeChange: PropTypes.func,
|
||||
onHeaderChange: PropTypes.func,
|
||||
oldDisplayName: PropTypes.string,
|
||||
oldChannelURL: PropTypes.string,
|
||||
oldHeader: PropTypes.string,
|
||||
oldPurpose: PropTypes.string,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
editing: false,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.nameInput = React.createRef();
|
||||
this.urlInput = React.createRef();
|
||||
this.purposeInput = React.createRef();
|
||||
this.headerInput = React.createRef();
|
||||
this.lastText = React.createRef();
|
||||
this.scroll = React.createRef();
|
||||
}
|
||||
|
||||
blur = () => {
|
||||
if (this.nameInput?.current) {
|
||||
this.nameInput.current.blur();
|
||||
}
|
||||
|
||||
// TODO: uncomment below once the channel URL field is added
|
||||
// if (this.urlInput?.current) {
|
||||
// this.urlInput.current.blur();
|
||||
// }
|
||||
|
||||
if (this.purposeInput?.current) {
|
||||
this.purposeInput.current.blur();
|
||||
}
|
||||
if (this.headerInput?.current) {
|
||||
this.headerInput.current.blur();
|
||||
}
|
||||
|
||||
if (this.scroll?.current) {
|
||||
this.scroll.current.scrollToPosition(0, 0, true);
|
||||
}
|
||||
};
|
||||
|
||||
close = (goBack = false) => {
|
||||
const {actions} = this.props;
|
||||
if (goBack) {
|
||||
actions.popTopScreen();
|
||||
} else {
|
||||
actions.dismissModal();
|
||||
}
|
||||
};
|
||||
|
||||
canUpdate = (displayName, channelURL, purpose, header) => {
|
||||
const {
|
||||
oldDisplayName,
|
||||
oldChannelURL,
|
||||
oldPurpose,
|
||||
oldHeader,
|
||||
} = this.props;
|
||||
|
||||
return displayName !== oldDisplayName || channelURL !== oldChannelURL ||
|
||||
purpose !== oldPurpose || header !== oldHeader;
|
||||
};
|
||||
|
||||
enableRightButton = (enable = false) => {
|
||||
this.props.enableRightButton(enable);
|
||||
};
|
||||
|
||||
onDisplayNameChangeText = (displayName) => {
|
||||
const {editing, onDisplayNameChange} = this.props;
|
||||
onDisplayNameChange(displayName);
|
||||
|
||||
if (editing) {
|
||||
const {channelURL, purpose, header} = this.props;
|
||||
const canUpdate = this.canUpdate(displayName, channelURL, purpose, header);
|
||||
this.enableRightButton(canUpdate);
|
||||
return;
|
||||
}
|
||||
|
||||
const displayNameExists = displayName && displayName.length >= 2;
|
||||
this.props.enableRightButton(displayNameExists);
|
||||
};
|
||||
|
||||
onDisplayURLChangeText = (channelURL) => {
|
||||
const {editing, onChannelURLChange} = this.props;
|
||||
onChannelURLChange(channelURL);
|
||||
|
||||
if (editing) {
|
||||
const {displayName, purpose, header} = this.props;
|
||||
const canUpdate = this.canUpdate(displayName, channelURL, purpose, header);
|
||||
this.enableRightButton(canUpdate);
|
||||
}
|
||||
};
|
||||
|
||||
onPurposeChangeText = (purpose) => {
|
||||
const {editing, onPurposeChange} = this.props;
|
||||
onPurposeChange(purpose);
|
||||
|
||||
if (editing) {
|
||||
const {displayName, channelURL, header} = this.props;
|
||||
const canUpdate = this.canUpdate(displayName, channelURL, purpose, header);
|
||||
this.enableRightButton(canUpdate);
|
||||
}
|
||||
};
|
||||
|
||||
onHeaderChangeText = (header) => {
|
||||
const {editing, onHeaderChange} = this.props;
|
||||
onHeaderChange(header);
|
||||
|
||||
if (editing) {
|
||||
const {displayName, channelURL, purpose} = this.props;
|
||||
const canUpdate = this.canUpdate(displayName, channelURL, purpose, header);
|
||||
this.enableRightButton(canUpdate);
|
||||
}
|
||||
};
|
||||
|
||||
scrollToEnd = () => {
|
||||
if (this.scroll?.current && this.lastText?.current) {
|
||||
this.scroll.current.scrollToFocusedInput(findNodeHandle(this.lastText.current));
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
theme,
|
||||
editing,
|
||||
channelType,
|
||||
currentTeamUrl,
|
||||
deviceWidth,
|
||||
deviceHeight,
|
||||
displayName,
|
||||
channelURL,
|
||||
header,
|
||||
purpose,
|
||||
} = this.props;
|
||||
const {error, saving} = this.props;
|
||||
const fullUrl = currentTeamUrl + '/channels';
|
||||
const shortUrl = getShortenedURL(fullUrl, 35);
|
||||
|
||||
const style = getStyleSheet(theme);
|
||||
|
||||
const displayHeaderOnly = channelType === General.DM_CHANNEL ||
|
||||
channelType === General.GM_CHANNEL;
|
||||
|
||||
if (saving) {
|
||||
return (
|
||||
<View style={style.container}>
|
||||
<StatusBar/>
|
||||
<Loading/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
let displayError;
|
||||
if (error) {
|
||||
displayError = (
|
||||
<View style={[style.errorContainer, {width: deviceWidth}]}>
|
||||
<View style={style.errorWrapper}>
|
||||
<ErrorText error={error}/>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={style.container}>
|
||||
<StatusBar/>
|
||||
<KeyboardAwareScrollView
|
||||
ref={this.scroll}
|
||||
style={style.container}
|
||||
>
|
||||
{displayError}
|
||||
<TouchableWithoutFeedback onPress={this.blur}>
|
||||
<View style={[style.scrollView, {height: deviceHeight + (Platform.OS === 'android' ? 200 : 0)}]}>
|
||||
{!displayHeaderOnly && (
|
||||
<View>
|
||||
<View>
|
||||
<FormattedText
|
||||
style={style.title}
|
||||
id='channel_modal.name'
|
||||
defaultMessage='Name'
|
||||
/>
|
||||
</View>
|
||||
<View style={style.inputContainer}>
|
||||
<TextInputWithLocalizedPlaceholder
|
||||
ref={this.nameInput}
|
||||
value={displayName}
|
||||
onChangeText={this.onDisplayNameChangeText}
|
||||
style={style.input}
|
||||
autoCapitalize='none'
|
||||
autoCorrect={false}
|
||||
placeholder={{id: t('channel_modal.nameEx'), defaultMessage: 'E.g.: "Bugs", "Marketing", "客户支持"'}}
|
||||
placeholderTextColor={changeOpacity('#000', 0.5)}
|
||||
underlineColorAndroid='transparent'
|
||||
disableFullscreenUI={true}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
{/*TODO: Hide channel url field until it's added to CreateChannel */}
|
||||
{false && editing && !displayHeaderOnly && (
|
||||
<View>
|
||||
<View style={style.titleContainer30}>
|
||||
<FormattedText
|
||||
style={style.title}
|
||||
id='rename_channel.url'
|
||||
defaultMessage='URL'
|
||||
/>
|
||||
<Text style={style.optional}>
|
||||
{shortUrl}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={style.inputContainer}>
|
||||
<TextInputWithLocalizedPlaceholder
|
||||
ref={this.urlInput}
|
||||
value={channelURL}
|
||||
onChangeText={this.onDisplayURLChangeText}
|
||||
style={style.input}
|
||||
autoCapitalize='none'
|
||||
autoCorrect={false}
|
||||
placeholder={{id: t('rename_channel.handleHolder'), defaultMessage: 'lowercase alphanumeric characters'}}
|
||||
placeholderTextColor={changeOpacity('#000', 0.5)}
|
||||
underlineColorAndroid='transparent'
|
||||
disableFullscreenUI={true}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
{!displayHeaderOnly && (
|
||||
<View>
|
||||
<View style={style.titleContainer30}>
|
||||
<FormattedText
|
||||
style={style.title}
|
||||
id='channel_modal.purpose'
|
||||
defaultMessage='Purpose'
|
||||
/>
|
||||
<FormattedText
|
||||
style={style.optional}
|
||||
id='channel_modal.optional'
|
||||
defaultMessage='(optional)'
|
||||
/>
|
||||
</View>
|
||||
<View style={style.inputContainer}>
|
||||
<TextInputWithLocalizedPlaceholder
|
||||
ref={this.purposeInput}
|
||||
value={purpose}
|
||||
onChangeText={this.onPurposeChangeText}
|
||||
style={[style.input, {height: 110}]}
|
||||
autoCapitalize='none'
|
||||
autoCorrect={false}
|
||||
placeholder={{id: t('channel_modal.purposeEx'), defaultMessage: 'E.g.: "A channel to file bugs and improvements"'}}
|
||||
placeholderTextColor={changeOpacity('#000', 0.5)}
|
||||
multiline={true}
|
||||
blurOnSubmit={false}
|
||||
textAlignVertical='top'
|
||||
underlineColorAndroid='transparent'
|
||||
disableFullscreenUI={true}
|
||||
/>
|
||||
</View>
|
||||
<View>
|
||||
<FormattedText
|
||||
style={style.helpText}
|
||||
id='channel_modal.descriptionHelp'
|
||||
defaultMessage='Describe how this channel should be used.'
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
<View style={style.titleContainer15}>
|
||||
<FormattedText
|
||||
style={style.title}
|
||||
id='channel_modal.header'
|
||||
defaultMessage='Header'
|
||||
/>
|
||||
<FormattedText
|
||||
style={style.optional}
|
||||
id='channel_modal.optional'
|
||||
defaultMessage='(optional)'
|
||||
/>
|
||||
</View>
|
||||
<View style={style.inputContainer}>
|
||||
<TextInputWithLocalizedPlaceholder
|
||||
ref={this.headerInput}
|
||||
value={header}
|
||||
onChangeText={this.onHeaderChangeText}
|
||||
style={[style.input, {height: 110}]}
|
||||
autoCapitalize='none'
|
||||
autoCorrect={false}
|
||||
placeholder={{id: t('channel_modal.headerEx'), defaultMessage: 'E.g.: "[Link Title](http://example.com)"'}}
|
||||
placeholderTextColor={changeOpacity('#000', 0.5)}
|
||||
multiline={true}
|
||||
blurOnSubmit={false}
|
||||
onFocus={this.scrollToEnd}
|
||||
textAlignVertical='top'
|
||||
underlineColorAndroid='transparent'
|
||||
disableFullscreenUI={true}
|
||||
/>
|
||||
</View>
|
||||
<View ref={this.lastText}>
|
||||
<FormattedText
|
||||
style={style.helpText}
|
||||
id='channel_modal.headerHelp'
|
||||
defaultMessage={'Set text that will appear in the header of the channel beside the channel name. For example, include frequently used links by typing [Link Title](http://example.com).'}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableWithoutFeedback>
|
||||
</KeyboardAwareScrollView>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const getStyleSheet = makeStyleSheetFromTheme((theme) => {
|
||||
return {
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: theme.centerChannelBg,
|
||||
},
|
||||
scrollView: {
|
||||
flex: 1,
|
||||
backgroundColor: changeOpacity(theme.centerChannelColor, 0.03),
|
||||
paddingTop: 10,
|
||||
},
|
||||
errorContainer: {
|
||||
backgroundColor: changeOpacity(theme.centerChannelColor, 0.03),
|
||||
},
|
||||
errorWrapper: {
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
inputContainer: {
|
||||
marginTop: 10,
|
||||
backgroundColor: '#fff',
|
||||
},
|
||||
input: {
|
||||
color: '#333',
|
||||
fontSize: 14,
|
||||
height: 40,
|
||||
paddingHorizontal: 15,
|
||||
},
|
||||
titleContainer30: {
|
||||
flexDirection: 'row',
|
||||
marginTop: 30,
|
||||
},
|
||||
titleContainer15: {
|
||||
flexDirection: 'row',
|
||||
marginTop: 15,
|
||||
},
|
||||
title: {
|
||||
fontSize: 14,
|
||||
color: theme.centerChannelColor,
|
||||
marginLeft: 15,
|
||||
},
|
||||
optional: {
|
||||
color: changeOpacity(theme.centerChannelColor, 0.5),
|
||||
fontSize: 14,
|
||||
marginLeft: 5,
|
||||
},
|
||||
helpText: {
|
||||
fontSize: 14,
|
||||
color: changeOpacity(theme.centerChannelColor, 0.5),
|
||||
marginTop: 10,
|
||||
marginHorizontal: 15,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
|
@ -1,414 +1,23 @@
|
|||
// 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 {bindActionCreators} from 'redux';
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import {
|
||||
Platform,
|
||||
TouchableWithoutFeedback,
|
||||
View,
|
||||
Text,
|
||||
findNodeHandle,
|
||||
} from 'react-native';
|
||||
import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view';
|
||||
dismissModal,
|
||||
popTopScreen,
|
||||
} from 'app/actions/navigation';
|
||||
|
||||
import ErrorText from 'app/components/error_text';
|
||||
import FormattedText from 'app/components/formatted_text';
|
||||
import Loading from 'app/components/loading';
|
||||
import StatusBar from 'app/components/status_bar';
|
||||
import TextInputWithLocalizedPlaceholder from 'app/components/text_input_with_localized_placeholder';
|
||||
import EditChannelInfo from './edit_channel_info';
|
||||
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
|
||||
import {General} from 'mattermost-redux/constants';
|
||||
import {getShortenedURL} from 'app/utils/url';
|
||||
import {t} from 'app/utils/i18n';
|
||||
|
||||
export default class EditChannelInfo extends PureComponent {
|
||||
static propTypes = {
|
||||
navigator: PropTypes.object.isRequired,
|
||||
theme: PropTypes.object.isRequired,
|
||||
deviceWidth: PropTypes.number.isRequired,
|
||||
deviceHeight: PropTypes.number.isRequired,
|
||||
channelType: PropTypes.string,
|
||||
enableRightButton: PropTypes.func,
|
||||
saving: PropTypes.bool.isRequired,
|
||||
editing: PropTypes.bool,
|
||||
error: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
|
||||
displayName: PropTypes.string,
|
||||
currentTeamUrl: PropTypes.string,
|
||||
channelURL: PropTypes.string,
|
||||
purpose: PropTypes.string,
|
||||
header: PropTypes.string,
|
||||
onDisplayNameChange: PropTypes.func,
|
||||
onChannelURLChange: PropTypes.func,
|
||||
onPurposeChange: PropTypes.func,
|
||||
onHeaderChange: PropTypes.func,
|
||||
oldDisplayName: PropTypes.string,
|
||||
oldChannelURL: PropTypes.string,
|
||||
oldHeader: PropTypes.string,
|
||||
oldPurpose: PropTypes.string,
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators({
|
||||
dismissModal,
|
||||
popTopScreen,
|
||||
}, dispatch),
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
editing: false,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.nameInput = React.createRef();
|
||||
this.urlInput = React.createRef();
|
||||
this.purposeInput = React.createRef();
|
||||
this.headerInput = React.createRef();
|
||||
this.lastText = React.createRef();
|
||||
this.scroll = React.createRef();
|
||||
}
|
||||
|
||||
blur = () => {
|
||||
if (this.nameInput?.current) {
|
||||
this.nameInput.current.blur();
|
||||
}
|
||||
|
||||
// TODO: uncomment below once the channel URL field is added
|
||||
// if (this.urlInput?.current) {
|
||||
// this.urlInput.current.blur();
|
||||
// }
|
||||
|
||||
if (this.purposeInput?.current) {
|
||||
this.purposeInput.current.blur();
|
||||
}
|
||||
if (this.headerInput?.current) {
|
||||
this.headerInput.current.blur();
|
||||
}
|
||||
|
||||
if (this.scroll?.current) {
|
||||
this.scroll.current.scrollToPosition(0, 0, true);
|
||||
}
|
||||
};
|
||||
|
||||
close = (goBack = false) => {
|
||||
if (goBack) {
|
||||
this.props.navigator.pop({animated: true});
|
||||
} else {
|
||||
this.props.navigator.dismissModal({
|
||||
animationType: 'slide-down',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
canUpdate = (displayName, channelURL, purpose, header) => {
|
||||
const {
|
||||
oldDisplayName,
|
||||
oldChannelURL,
|
||||
oldPurpose,
|
||||
oldHeader,
|
||||
} = this.props;
|
||||
|
||||
return displayName !== oldDisplayName || channelURL !== oldChannelURL ||
|
||||
purpose !== oldPurpose || header !== oldHeader;
|
||||
};
|
||||
|
||||
enableRightButton = (enable = false) => {
|
||||
this.props.enableRightButton(enable);
|
||||
};
|
||||
|
||||
onDisplayNameChangeText = (displayName) => {
|
||||
const {editing, onDisplayNameChange} = this.props;
|
||||
onDisplayNameChange(displayName);
|
||||
|
||||
if (editing) {
|
||||
const {channelURL, purpose, header} = this.props;
|
||||
const canUpdate = this.canUpdate(displayName, channelURL, purpose, header);
|
||||
this.enableRightButton(canUpdate);
|
||||
return;
|
||||
}
|
||||
|
||||
const displayNameExists = displayName && displayName.length >= 2;
|
||||
this.props.enableRightButton(displayNameExists);
|
||||
};
|
||||
|
||||
onDisplayURLChangeText = (channelURL) => {
|
||||
const {editing, onChannelURLChange} = this.props;
|
||||
onChannelURLChange(channelURL);
|
||||
|
||||
if (editing) {
|
||||
const {displayName, purpose, header} = this.props;
|
||||
const canUpdate = this.canUpdate(displayName, channelURL, purpose, header);
|
||||
this.enableRightButton(canUpdate);
|
||||
}
|
||||
};
|
||||
|
||||
onPurposeChangeText = (purpose) => {
|
||||
const {editing, onPurposeChange} = this.props;
|
||||
onPurposeChange(purpose);
|
||||
|
||||
if (editing) {
|
||||
const {displayName, channelURL, header} = this.props;
|
||||
const canUpdate = this.canUpdate(displayName, channelURL, purpose, header);
|
||||
this.enableRightButton(canUpdate);
|
||||
}
|
||||
};
|
||||
|
||||
onHeaderChangeText = (header) => {
|
||||
const {editing, onHeaderChange} = this.props;
|
||||
onHeaderChange(header);
|
||||
|
||||
if (editing) {
|
||||
const {displayName, channelURL, purpose} = this.props;
|
||||
const canUpdate = this.canUpdate(displayName, channelURL, purpose, header);
|
||||
this.enableRightButton(canUpdate);
|
||||
}
|
||||
};
|
||||
|
||||
scrollToEnd = () => {
|
||||
if (this.scroll?.current && this.lastText?.current) {
|
||||
this.scroll.current.scrollToFocusedInput(findNodeHandle(this.lastText.current));
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
theme,
|
||||
editing,
|
||||
channelType,
|
||||
currentTeamUrl,
|
||||
deviceWidth,
|
||||
deviceHeight,
|
||||
displayName,
|
||||
channelURL,
|
||||
header,
|
||||
purpose,
|
||||
} = this.props;
|
||||
const {error, saving} = this.props;
|
||||
const fullUrl = currentTeamUrl + '/channels';
|
||||
const shortUrl = getShortenedURL(fullUrl, 35);
|
||||
|
||||
const style = getStyleSheet(theme);
|
||||
|
||||
const displayHeaderOnly = channelType === General.DM_CHANNEL ||
|
||||
channelType === General.GM_CHANNEL;
|
||||
|
||||
if (saving) {
|
||||
return (
|
||||
<View style={style.container}>
|
||||
<StatusBar/>
|
||||
<Loading/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
let displayError;
|
||||
if (error) {
|
||||
displayError = (
|
||||
<View style={[style.errorContainer, {width: deviceWidth}]}>
|
||||
<View style={style.errorWrapper}>
|
||||
<ErrorText error={error}/>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={style.container}>
|
||||
<StatusBar/>
|
||||
<KeyboardAwareScrollView
|
||||
ref={this.scroll}
|
||||
style={style.container}
|
||||
>
|
||||
{displayError}
|
||||
<TouchableWithoutFeedback onPress={this.blur}>
|
||||
<View style={[style.scrollView, {height: deviceHeight + (Platform.OS === 'android' ? 200 : 0)}]}>
|
||||
{!displayHeaderOnly && (
|
||||
<View>
|
||||
<View>
|
||||
<FormattedText
|
||||
style={style.title}
|
||||
id='channel_modal.name'
|
||||
defaultMessage='Name'
|
||||
/>
|
||||
</View>
|
||||
<View style={style.inputContainer}>
|
||||
<TextInputWithLocalizedPlaceholder
|
||||
ref={this.nameInput}
|
||||
value={displayName}
|
||||
onChangeText={this.onDisplayNameChangeText}
|
||||
style={style.input}
|
||||
autoCapitalize='none'
|
||||
autoCorrect={false}
|
||||
placeholder={{id: t('channel_modal.nameEx'), defaultMessage: 'E.g.: "Bugs", "Marketing", "客户支持"'}}
|
||||
placeholderTextColor={changeOpacity('#000', 0.5)}
|
||||
underlineColorAndroid='transparent'
|
||||
disableFullscreenUI={true}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
{/*TODO: Hide channel url field until it's added to CreateChannel */}
|
||||
{false && editing && !displayHeaderOnly && (
|
||||
<View>
|
||||
<View style={style.titleContainer30}>
|
||||
<FormattedText
|
||||
style={style.title}
|
||||
id='rename_channel.url'
|
||||
defaultMessage='URL'
|
||||
/>
|
||||
<Text style={style.optional}>
|
||||
{shortUrl}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={style.inputContainer}>
|
||||
<TextInputWithLocalizedPlaceholder
|
||||
ref={this.urlInput}
|
||||
value={channelURL}
|
||||
onChangeText={this.onDisplayURLChangeText}
|
||||
style={style.input}
|
||||
autoCapitalize='none'
|
||||
autoCorrect={false}
|
||||
placeholder={{id: t('rename_channel.handleHolder'), defaultMessage: 'lowercase alphanumeric characters'}}
|
||||
placeholderTextColor={changeOpacity('#000', 0.5)}
|
||||
underlineColorAndroid='transparent'
|
||||
disableFullscreenUI={true}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
{!displayHeaderOnly && (
|
||||
<View>
|
||||
<View style={style.titleContainer30}>
|
||||
<FormattedText
|
||||
style={style.title}
|
||||
id='channel_modal.purpose'
|
||||
defaultMessage='Purpose'
|
||||
/>
|
||||
<FormattedText
|
||||
style={style.optional}
|
||||
id='channel_modal.optional'
|
||||
defaultMessage='(optional)'
|
||||
/>
|
||||
</View>
|
||||
<View style={style.inputContainer}>
|
||||
<TextInputWithLocalizedPlaceholder
|
||||
ref={this.purposeInput}
|
||||
value={purpose}
|
||||
onChangeText={this.onPurposeChangeText}
|
||||
style={[style.input, {height: 110}]}
|
||||
autoCapitalize='none'
|
||||
autoCorrect={false}
|
||||
placeholder={{id: t('channel_modal.purposeEx'), defaultMessage: 'E.g.: "A channel to file bugs and improvements"'}}
|
||||
placeholderTextColor={changeOpacity('#000', 0.5)}
|
||||
multiline={true}
|
||||
blurOnSubmit={false}
|
||||
textAlignVertical='top'
|
||||
underlineColorAndroid='transparent'
|
||||
disableFullscreenUI={true}
|
||||
/>
|
||||
</View>
|
||||
<View>
|
||||
<FormattedText
|
||||
style={style.helpText}
|
||||
id='channel_modal.descriptionHelp'
|
||||
defaultMessage='Describe how this channel should be used.'
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
<View style={style.titleContainer15}>
|
||||
<FormattedText
|
||||
style={style.title}
|
||||
id='channel_modal.header'
|
||||
defaultMessage='Header'
|
||||
/>
|
||||
<FormattedText
|
||||
style={style.optional}
|
||||
id='channel_modal.optional'
|
||||
defaultMessage='(optional)'
|
||||
/>
|
||||
</View>
|
||||
<View style={style.inputContainer}>
|
||||
<TextInputWithLocalizedPlaceholder
|
||||
ref={this.headerInput}
|
||||
value={header}
|
||||
onChangeText={this.onHeaderChangeText}
|
||||
style={[style.input, {height: 110}]}
|
||||
autoCapitalize='none'
|
||||
autoCorrect={false}
|
||||
placeholder={{id: t('channel_modal.headerEx'), defaultMessage: 'E.g.: "[Link Title](http://example.com)"'}}
|
||||
placeholderTextColor={changeOpacity('#000', 0.5)}
|
||||
multiline={true}
|
||||
blurOnSubmit={false}
|
||||
onFocus={this.scrollToEnd}
|
||||
textAlignVertical='top'
|
||||
underlineColorAndroid='transparent'
|
||||
disableFullscreenUI={true}
|
||||
/>
|
||||
</View>
|
||||
<View ref={this.lastText}>
|
||||
<FormattedText
|
||||
style={style.helpText}
|
||||
id='channel_modal.headerHelp'
|
||||
defaultMessage={'Set text that will appear in the header of the channel beside the channel name. For example, include frequently used links by typing [Link Title](http://example.com).'}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableWithoutFeedback>
|
||||
</KeyboardAwareScrollView>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const getStyleSheet = makeStyleSheetFromTheme((theme) => {
|
||||
return {
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: theme.centerChannelBg,
|
||||
},
|
||||
scrollView: {
|
||||
flex: 1,
|
||||
backgroundColor: changeOpacity(theme.centerChannelColor, 0.03),
|
||||
paddingTop: 10,
|
||||
},
|
||||
errorContainer: {
|
||||
backgroundColor: changeOpacity(theme.centerChannelColor, 0.03),
|
||||
},
|
||||
errorWrapper: {
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
inputContainer: {
|
||||
marginTop: 10,
|
||||
backgroundColor: '#fff',
|
||||
},
|
||||
input: {
|
||||
color: '#333',
|
||||
fontSize: 14,
|
||||
height: 40,
|
||||
paddingHorizontal: 15,
|
||||
},
|
||||
titleContainer30: {
|
||||
flexDirection: 'row',
|
||||
marginTop: 30,
|
||||
},
|
||||
titleContainer15: {
|
||||
flexDirection: 'row',
|
||||
marginTop: 15,
|
||||
},
|
||||
title: {
|
||||
fontSize: 14,
|
||||
color: theme.centerChannelColor,
|
||||
marginLeft: 15,
|
||||
},
|
||||
optional: {
|
||||
color: changeOpacity(theme.centerChannelColor, 0.5),
|
||||
fontSize: 14,
|
||||
marginLeft: 5,
|
||||
},
|
||||
helpText: {
|
||||
fontSize: 14,
|
||||
color: changeOpacity(theme.centerChannelColor, 0.5),
|
||||
marginTop: 10,
|
||||
marginHorizontal: 15,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
export default connect(null, mapDispatchToProps)(EditChannelInfo);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {bindActionCreators} from 'redux';
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import {showModal} from 'app/actions/navigation';
|
||||
|
||||
import InteractiveDialogController from './interactive_dialog_controller';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
|
|
@ -12,4 +15,12 @@ function mapStateToProps(state) {
|
|||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(InteractiveDialogController);
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators({
|
||||
showModal,
|
||||
}, dispatch),
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(InteractiveDialogController);
|
||||
|
|
|
|||
|
|
@ -7,9 +7,11 @@ import MaterialIcon from 'react-native-vector-icons/MaterialIcons';
|
|||
|
||||
export default class InteractiveDialogController extends PureComponent {
|
||||
static propTypes = {
|
||||
actions: PropTypes.shape({
|
||||
showModal: PropTypes.func.isRequired,
|
||||
}).isRequired,
|
||||
triggerId: PropTypes.string,
|
||||
dialog: PropTypes.object,
|
||||
navigator: PropTypes.object,
|
||||
theme: PropTypes.object,
|
||||
};
|
||||
|
||||
|
|
@ -22,7 +24,7 @@ export default class InteractiveDialogController extends PureComponent {
|
|||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const triggerId = this.props.triggerId;
|
||||
const {actions, triggerId} = this.props;
|
||||
if (!triggerId) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -41,33 +43,24 @@ export default class InteractiveDialogController extends PureComponent {
|
|||
return;
|
||||
}
|
||||
|
||||
const theme = this.props.theme;
|
||||
|
||||
this.props.navigator.showModal({
|
||||
backButtonTitle: '',
|
||||
screen: 'InteractiveDialog',
|
||||
title: dialogData.dialog.title,
|
||||
animated: true,
|
||||
navigatorStyle: {
|
||||
navBarTextColor: theme.sidebarHeaderTextColor,
|
||||
navBarBackgroundColor: theme.sidebarHeaderBg,
|
||||
navBarButtonColor: theme.sidebarHeaderTextColor,
|
||||
screenBackgroundColor: theme.centerChannelBg,
|
||||
},
|
||||
navigatorButtons: {
|
||||
const screen = 'InteractiveDialog';
|
||||
const title = dialogData.dialog.title;
|
||||
const passProps = {};
|
||||
const options = {
|
||||
topBar: {
|
||||
leftButtons: [{
|
||||
id: 'close-dialog',
|
||||
icon: this.closeButton,
|
||||
}],
|
||||
rightButtons: [
|
||||
{
|
||||
id: 'submit-dialog',
|
||||
showAsAction: 'always',
|
||||
title: dialogData.dialog.submit_label,
|
||||
},
|
||||
],
|
||||
rightButtons: [{
|
||||
id: 'submit-dialog',
|
||||
showAsAction: 'always',
|
||||
text: dialogData.dialog.submit_label,
|
||||
}],
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
actions.showModal(screen, title, passProps, options);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import {getConfig, getCurrentUrl} from 'mattermost-redux/selectors/entities/gene
|
|||
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
|
||||
import {makePreparePostIdsForPostList, START_OF_NEW_MESSAGES} from 'mattermost-redux/utils/post_list';
|
||||
|
||||
import {showModalOverCurrentContext} from 'app/actions/navigation';
|
||||
import {handleSelectChannelByName, loadChannelsByTeamName, refreshChannelWithRetry} from 'app/actions/views/channel';
|
||||
import {setDeepLinkURL} from 'app/actions/views/root';
|
||||
|
||||
|
|
@ -42,6 +43,7 @@ function mapDispatchToProps(dispatch) {
|
|||
refreshChannelWithRetry,
|
||||
selectFocusedPostId,
|
||||
setDeepLinkURL,
|
||||
showModalOverCurrentContext,
|
||||
}, dispatch),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ export default class PostList extends PureComponent {
|
|||
refreshChannelWithRetry: PropTypes.func.isRequired,
|
||||
selectFocusedPostId: PropTypes.func.isRequired,
|
||||
setDeepLinkURL: PropTypes.func.isRequired,
|
||||
showModalOverCurrentContext: PropTypes.func.isRequired,
|
||||
}).isRequired,
|
||||
channelId: PropTypes.string,
|
||||
deepLinkURL: PropTypes.string,
|
||||
|
|
@ -51,7 +52,6 @@ export default class PostList extends PureComponent {
|
|||
isSearchResult: PropTypes.bool,
|
||||
lastPostIndex: PropTypes.number.isRequired,
|
||||
lastViewedAt: PropTypes.number, // Used by container // eslint-disable-line no-unused-prop-types
|
||||
navigator: PropTypes.object,
|
||||
onLoadMoreUp: PropTypes.func,
|
||||
onHashtagPress: PropTypes.func,
|
||||
onPermalinkPress: PropTypes.func,
|
||||
|
|
@ -250,7 +250,6 @@ export default class PostList extends PureComponent {
|
|||
isSearchResult: this.props.isSearchResult,
|
||||
location: this.props.location,
|
||||
managedConfig: mattermostManaged.getCachedConfig(),
|
||||
navigator: this.props.navigator,
|
||||
onHashtagPress: this.props.onHashtagPress,
|
||||
onPermalinkPress: this.handlePermalinkPress,
|
||||
onPress: this.props.onPostPress,
|
||||
|
|
@ -303,29 +302,24 @@ export default class PostList extends PureComponent {
|
|||
};
|
||||
|
||||
showPermalinkView = (postId) => {
|
||||
const {actions, navigator} = this.props;
|
||||
const {actions} = this.props;
|
||||
|
||||
actions.selectFocusedPostId(postId);
|
||||
|
||||
if (!this.showingPermalink) {
|
||||
const screen = 'Permalink';
|
||||
const passProps = {
|
||||
isPermalink: true,
|
||||
onClose: this.handleClosePermalink,
|
||||
};
|
||||
const options = {
|
||||
screen: 'Permalink',
|
||||
animationType: 'none',
|
||||
backButtonTitle: '',
|
||||
overrideBackPress: true,
|
||||
navigatorStyle: {
|
||||
navBarHidden: true,
|
||||
screenBackgroundColor: changeOpacity('#000', 0.2),
|
||||
modalPresentationStyle: 'overCurrentContext',
|
||||
},
|
||||
passProps: {
|
||||
isPermalink: true,
|
||||
onClose: this.handleClosePermalink,
|
||||
layout: {
|
||||
backgroundColor: changeOpacity('#000', 0.2),
|
||||
},
|
||||
};
|
||||
|
||||
this.showingPermalink = true;
|
||||
navigator.showModal(options);
|
||||
actions.showModalOverCurrentContext(screen, passProps, options);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -18,11 +18,9 @@ describe('PostList', () => {
|
|||
refreshChannelWithRetry: jest.fn(),
|
||||
selectFocusedPostId: jest.fn(),
|
||||
setDeepLinkURL: jest.fn(),
|
||||
showModalOverCurrentContext: jest.fn(),
|
||||
},
|
||||
deepLinkURL: '',
|
||||
navigator: {
|
||||
showModal: jest.fn(),
|
||||
},
|
||||
lastPostIndex: -1,
|
||||
postIds: ['post-id-1', 'post-id-2'],
|
||||
serverURL,
|
||||
|
|
@ -47,7 +45,7 @@ describe('PostList', () => {
|
|||
wrapper.setProps({deepLinkURL: deepLinks.permalink});
|
||||
expect(baseProps.actions.setDeepLinkURL).toHaveBeenCalled();
|
||||
expect(baseProps.actions.selectFocusedPostId).toHaveBeenCalled();
|
||||
expect(baseProps.navigator.showModal).toHaveBeenCalled();
|
||||
expect(baseProps.actions.showModalOverCurrentContext).toHaveBeenCalled();
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -6,12 +6,12 @@ import PropTypes from 'prop-types';
|
|||
import {intlShape} from 'react-intl';
|
||||
import {
|
||||
Keyboard,
|
||||
Platform,
|
||||
StyleSheet,
|
||||
View,
|
||||
} from 'react-native';
|
||||
|
||||
import {Navigation} from 'react-native-navigation';
|
||||
import MaterialIcon from 'react-native-vector-icons/MaterialIcons';
|
||||
|
||||
import EventEmitter from 'mattermost-redux/utils/event_emitter';
|
||||
|
||||
import {app} from 'app/mattermost';
|
||||
|
|
@ -40,12 +40,14 @@ export default class ChannelBase extends PureComponent {
|
|||
selectInitialChannel: PropTypes.func.isRequired,
|
||||
recordLoadTime: PropTypes.func.isRequired,
|
||||
peek: PropTypes.func.isRequired,
|
||||
goToScreen: PropTypes.func.isRequired,
|
||||
showModalOverCurrentContext: PropTypes.func.isRequired,
|
||||
}).isRequired,
|
||||
componentId: PropTypes.string.isRequired,
|
||||
currentChannelId: PropTypes.string,
|
||||
channelsRequestFailed: PropTypes.bool,
|
||||
currentTeamId: PropTypes.string,
|
||||
isLandscape: PropTypes.bool,
|
||||
navigator: PropTypes.object,
|
||||
theme: PropTypes.object.isRequired,
|
||||
showTermsOfService: PropTypes.bool,
|
||||
disableTermsModal: PropTypes.bool,
|
||||
|
|
@ -65,8 +67,10 @@ export default class ChannelBase extends PureComponent {
|
|||
this.postTextbox = React.createRef();
|
||||
this.keyboardTracker = React.createRef();
|
||||
|
||||
props.navigator.setStyle({
|
||||
screenBackgroundColor: props.theme.centerChannelBg,
|
||||
Navigation.mergeOptions(props.componentId, {
|
||||
layout: {
|
||||
backgroundColor: props.theme.centerChannelBg,
|
||||
},
|
||||
});
|
||||
|
||||
if (LocalConfig.EnableMobileClientUpgrade && !ClientUpgradeListener) {
|
||||
|
|
@ -104,8 +108,10 @@ export default class ChannelBase extends PureComponent {
|
|||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (this.props.theme !== nextProps.theme) {
|
||||
this.props.navigator.setStyle({
|
||||
screenBackgroundColor: nextProps.theme.centerChannelBg,
|
||||
Navigation.mergeOptions(this.props.componentId, {
|
||||
layout: {
|
||||
backgroundColor: nextProps.theme.centerChannelBg,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -161,53 +167,32 @@ export default class ChannelBase extends PureComponent {
|
|||
};
|
||||
|
||||
showTermsOfServiceModal = async () => {
|
||||
const {navigator, theme} = this.props;
|
||||
const {actions, theme} = this.props;
|
||||
const closeButton = await MaterialIcon.getImageSource('close', 20, theme.sidebarHeaderTextColor);
|
||||
navigator.showModal({
|
||||
screen: 'TermsOfService',
|
||||
animationType: 'slide-up',
|
||||
title: '',
|
||||
backButtonTitle: '',
|
||||
animated: true,
|
||||
navigatorStyle: {
|
||||
navBarTextColor: theme.centerChannelColor,
|
||||
navBarBackgroundColor: theme.centerChannelBg,
|
||||
navBarButtonColor: theme.buttonBg,
|
||||
screenBackgroundColor: theme.centerChannelBg,
|
||||
modalPresentationStyle: 'overCurrentContext',
|
||||
},
|
||||
overrideBackPress: true,
|
||||
passProps: {
|
||||
closeButton,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
goToChannelInfo = preventDoubleTap(() => {
|
||||
const {intl} = this.context;
|
||||
const {navigator, theme} = this.props;
|
||||
const screen = 'TermsOfService';
|
||||
const passProps = {
|
||||
closeButton,
|
||||
};
|
||||
const options = {
|
||||
screen: 'ChannelInfo',
|
||||
title: intl.formatMessage({id: 'mobile.routes.channelInfo', defaultMessage: 'Info'}),
|
||||
animated: true,
|
||||
backButtonTitle: '',
|
||||
navigatorStyle: {
|
||||
navBarTextColor: theme.sidebarHeaderTextColor,
|
||||
navBarBackgroundColor: theme.sidebarHeaderBg,
|
||||
navBarButtonColor: theme.sidebarHeaderTextColor,
|
||||
screenBackgroundColor: theme.centerChannelBg,
|
||||
layout: {
|
||||
backgroundColor: theme.centerChannelBg,
|
||||
},
|
||||
};
|
||||
|
||||
actions.showModalOverCurrentContext(screen, passProps, options);
|
||||
};
|
||||
|
||||
goToChannelInfo = preventDoubleTap(() => {
|
||||
const {actions} = this.props;
|
||||
const {intl} = this.context;
|
||||
const screen = 'ChannelInfo';
|
||||
const title = intl.formatMessage({id: 'mobile.routes.channelInfo', defaultMessage: 'Info'});
|
||||
|
||||
Keyboard.dismiss();
|
||||
|
||||
if (Platform.OS === 'android') {
|
||||
navigator.showModal(options);
|
||||
} else {
|
||||
requestAnimationFrame(() => {
|
||||
navigator.push(options);
|
||||
});
|
||||
}
|
||||
requestAnimationFrame(() => {
|
||||
actions.goToScreen(screen, title);
|
||||
});
|
||||
});
|
||||
|
||||
handleAutoComplete = (value) => {
|
||||
|
|
@ -265,7 +250,6 @@ export default class ChannelBase extends PureComponent {
|
|||
channelsRequestFailed,
|
||||
currentChannelId,
|
||||
isLandscape,
|
||||
navigator,
|
||||
theme,
|
||||
} = this.props;
|
||||
|
||||
|
|
@ -282,7 +266,7 @@ export default class ChannelBase extends PureComponent {
|
|||
|
||||
const Loading = require('app/components/channel_loader').default;
|
||||
return (
|
||||
<SafeAreaView navigator={navigator}>
|
||||
<SafeAreaView>
|
||||
<View style={style.flex}>
|
||||
<EmptyToolbar
|
||||
theme={theme}
|
||||
|
|
@ -298,18 +282,15 @@ export default class ChannelBase extends PureComponent {
|
|||
<MainSidebar
|
||||
ref={this.channelSidebarRef}
|
||||
blurPostTextBox={this.blurPostTextBox}
|
||||
navigator={navigator}
|
||||
{...optionalProps}
|
||||
>
|
||||
<SettingsSidebar
|
||||
ref={this.settingsSidebarRef}
|
||||
blurPostTextBox={this.blurPostTextBox}
|
||||
navigator={navigator}
|
||||
>
|
||||
{drawerContent}
|
||||
</SettingsSidebar>
|
||||
<InteractiveDialogController
|
||||
navigator={navigator}
|
||||
theme={theme}
|
||||
/>
|
||||
</MainSidebar>
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ const {
|
|||
export default class ChannelNavBar extends PureComponent {
|
||||
static propTypes = {
|
||||
isLandscape: PropTypes.bool.isRequired,
|
||||
navigator: PropTypes.object.isRequired,
|
||||
openChannelDrawer: PropTypes.func.isRequired,
|
||||
openSettingsDrawer: PropTypes.func.isRequired,
|
||||
onPress: PropTypes.func.isRequired,
|
||||
|
|
@ -32,7 +31,7 @@ export default class ChannelNavBar extends PureComponent {
|
|||
};
|
||||
|
||||
render() {
|
||||
const {isLandscape, navigator, onPress, theme} = this.props;
|
||||
const {isLandscape, onPress, theme} = this.props;
|
||||
const {openChannelDrawer, openSettingsDrawer} = this.props;
|
||||
const style = getStyleFromTheme(theme);
|
||||
const padding = {paddingHorizontal: 0};
|
||||
|
|
@ -72,7 +71,6 @@ export default class ChannelNavBar extends PureComponent {
|
|||
/>
|
||||
<ChannelTitle onPress={onPress}/>
|
||||
<ChannelSearchButton
|
||||
navigator={navigator}
|
||||
theme={theme}
|
||||
/>
|
||||
<SettingDrawerButton openDrawer={openSettingsDrawer}/>
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ export default class ChannelSearchButton extends PureComponent {
|
|||
clearSearch: PropTypes.func.isRequired,
|
||||
showSearchModal: PropTypes.func.isRequired,
|
||||
}).isRequired,
|
||||
navigator: PropTypes.object,
|
||||
theme: PropTypes.object,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -33,13 +33,14 @@ export default class ChannelPostList extends PureComponent {
|
|||
selectPost: PropTypes.func.isRequired,
|
||||
recordLoadTime: PropTypes.func.isRequired,
|
||||
refreshChannelWithRetry: PropTypes.func.isRequired,
|
||||
showModal: PropTypes.func.isRequired,
|
||||
goToScreen: PropTypes.func.isRequired,
|
||||
}).isRequired,
|
||||
channelId: PropTypes.string.isRequired,
|
||||
channelRefreshingFailed: PropTypes.bool,
|
||||
currentUserId: PropTypes.string,
|
||||
lastViewedAt: PropTypes.number,
|
||||
loadMorePostsVisible: PropTypes.bool.isRequired,
|
||||
navigator: PropTypes.object,
|
||||
postIds: PropTypes.array,
|
||||
postVisibility: PropTypes.number,
|
||||
refreshing: PropTypes.bool.isRequired,
|
||||
|
|
@ -105,36 +106,23 @@ export default class ChannelPostList extends PureComponent {
|
|||
|
||||
goToThread = (post) => {
|
||||
telemetry.start(['post_list:thread']);
|
||||
const {actions, channelId, navigator, theme} = this.props;
|
||||
const {actions, channelId} = this.props;
|
||||
const rootId = (post.root_id || post.id);
|
||||
|
||||
Keyboard.dismiss();
|
||||
actions.loadThreadIfNecessary(rootId);
|
||||
actions.selectPost(rootId);
|
||||
|
||||
const options = {
|
||||
screen: 'Thread',
|
||||
animated: true,
|
||||
backButtonTitle: '',
|
||||
navigatorStyle: {
|
||||
navBarTextColor: theme.sidebarHeaderTextColor,
|
||||
navBarBackgroundColor: theme.sidebarHeaderBg,
|
||||
navBarButtonColor: theme.sidebarHeaderTextColor,
|
||||
screenBackgroundColor: theme.centerChannelBg,
|
||||
},
|
||||
passProps: {
|
||||
channelId,
|
||||
rootId,
|
||||
},
|
||||
const screen = 'Thread';
|
||||
const title = '';
|
||||
const passProps = {
|
||||
channelId,
|
||||
rootId,
|
||||
};
|
||||
|
||||
if (Platform.OS === 'android') {
|
||||
navigator.showModal(options);
|
||||
} else {
|
||||
requestAnimationFrame(() => {
|
||||
navigator.push(options);
|
||||
});
|
||||
}
|
||||
requestAnimationFrame(() => {
|
||||
actions.goToScreen(screen, title, passProps);
|
||||
});
|
||||
};
|
||||
|
||||
loadMorePostsTop = () => {
|
||||
|
|
@ -181,7 +169,6 @@ export default class ChannelPostList extends PureComponent {
|
|||
return (
|
||||
<ChannelIntro
|
||||
channelId={this.props.channelId}
|
||||
navigator={this.props.navigator}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
@ -194,7 +181,6 @@ export default class ChannelPostList extends PureComponent {
|
|||
currentUserId,
|
||||
lastViewedAt,
|
||||
loadMorePostsVisible,
|
||||
navigator,
|
||||
refreshing,
|
||||
theme,
|
||||
} = this.props;
|
||||
|
|
@ -223,7 +209,6 @@ export default class ChannelPostList extends PureComponent {
|
|||
currentUserId={currentUserId}
|
||||
lastViewedAt={lastViewedAt}
|
||||
channelId={channelId}
|
||||
navigator={navigator}
|
||||
renderFooter={this.renderFooter}
|
||||
refreshing={refreshing}
|
||||
scrollViewNativeID={channelId}
|
||||
|
|
@ -234,7 +219,7 @@ export default class ChannelPostList extends PureComponent {
|
|||
return (
|
||||
<View style={style.container}>
|
||||
{component}
|
||||
<AnnouncementBanner navigator={navigator}/>
|
||||
<AnnouncementBanner/>
|
||||
<RetryBarIndicator/>
|
||||
</View>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import {getCurrentChannelId} from 'mattermost-redux/selectors/entities/channels'
|
|||
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
|
||||
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
|
||||
|
||||
import {goToScreen} from 'app/actions/navigation';
|
||||
import {loadPostsIfNecessaryWithRetry, loadThreadIfNecessary, increasePostVisibility, refreshChannelWithRetry} from 'app/actions/views/channel';
|
||||
import {recordLoadTime} from 'app/actions/views/root';
|
||||
|
||||
|
|
@ -42,6 +43,7 @@ function mapDispatchToProps(dispatch) {
|
|||
selectPost,
|
||||
recordLoadTime,
|
||||
refreshChannelWithRetry,
|
||||
goToScreen,
|
||||
}, dispatch),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import {
|
|||
import {connection} from 'app/actions/device';
|
||||
import {recordLoadTime} from 'app/actions/views/root';
|
||||
import {selectDefaultTeam} from 'app/actions/views/select_team';
|
||||
import {peek} from 'app/actions/navigation';
|
||||
import {peek, goToScreen, showModalOverCurrentContext} from 'app/actions/navigation';
|
||||
import {isLandscape} from 'app/selectors/device';
|
||||
|
||||
import Channel from './channel';
|
||||
|
|
@ -50,6 +50,8 @@ function mapDispatchToProps(dispatch) {
|
|||
startPeriodicStatusUpdates,
|
||||
stopPeriodicStatusUpdates,
|
||||
peek,
|
||||
goToScreen,
|
||||
showModalOverCurrentContext,
|
||||
}, dispatch),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ export default class ChannelAddMembers extends PureComponent {
|
|||
getProfilesNotInChannel: PropTypes.func.isRequired,
|
||||
handleAddChannelMembers: PropTypes.func.isRequired,
|
||||
searchProfiles: PropTypes.func.isRequired,
|
||||
setButtons: PropTypes.func.isRequired,
|
||||
popTopScreen: PropTypes.func.isRequired,
|
||||
}).isRequired,
|
||||
componentId: PropTypes.string,
|
||||
currentChannelId: PropTypes.string.isRequired,
|
||||
|
|
@ -40,7 +42,6 @@ export default class ChannelAddMembers extends PureComponent {
|
|||
currentTeamId: PropTypes.string.isRequired,
|
||||
currentUserId: PropTypes.string.isRequired,
|
||||
profilesNotInChannel: PropTypes.array.isRequired,
|
||||
navigator: PropTypes.object,
|
||||
theme: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
|
|
@ -68,13 +69,13 @@ export default class ChannelAddMembers extends PureComponent {
|
|||
};
|
||||
|
||||
this.addButton = {
|
||||
disabled: true,
|
||||
enalbed: false,
|
||||
id: 'add-members',
|
||||
title: context.intl.formatMessage({id: 'integrations.add', defaultMessage: 'Add'}),
|
||||
text: context.intl.formatMessage({id: 'integrations.add', defaultMessage: 'Add'}),
|
||||
showAsAction: 'always',
|
||||
};
|
||||
|
||||
props.navigator.setButtons({
|
||||
props.actions.setButtons(props.componentId, {
|
||||
rightButtons: [this.addButton],
|
||||
});
|
||||
}
|
||||
|
|
@ -113,12 +114,13 @@ export default class ChannelAddMembers extends PureComponent {
|
|||
};
|
||||
|
||||
close = () => {
|
||||
this.props.navigator.pop({animated: true});
|
||||
this.props.actions.popTopScreen();
|
||||
};
|
||||
|
||||
enableAddOption = (enabled) => {
|
||||
this.props.navigator.setButtons({
|
||||
rightButtons: [{...this.addButton, disabled: !enabled}],
|
||||
const {actions, componentId} = this.props;
|
||||
actions.setButtons(componentId, {
|
||||
rightButtons: [{...this.addButton, enabled}],
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -16,15 +16,13 @@ describe('ChannelAddMembers', () => {
|
|||
getProfilesNotInChannel: jest.fn().mockResolvedValue({}),
|
||||
handleAddChannelMembers: jest.fn().mockResolvedValue({}),
|
||||
searchProfiles: jest.fn().mockResolvedValue({data: []}),
|
||||
setButtons: jest.fn(),
|
||||
popTopScreen: jest.fn(),
|
||||
},
|
||||
currentChannelId: 'current_channel_id',
|
||||
currentTeamId: 'current_team_id',
|
||||
currentUserId: 'current_user_id',
|
||||
profilesNotInChannel: [],
|
||||
navigator: {
|
||||
pop: jest.fn(),
|
||||
setButtons: jest.fn(),
|
||||
},
|
||||
theme: Preferences.THEMES.default,
|
||||
componentId: 'component-id',
|
||||
};
|
||||
|
|
@ -35,10 +33,10 @@ describe('ChannelAddMembers', () => {
|
|||
expect(baseProps.actions.getTeamStats).toBeCalledTimes(1);
|
||||
expect(baseProps.actions.getTeamStats).toBeCalledWith(baseProps.currentTeamId);
|
||||
|
||||
const button = {disabled: true, id: 'add-members', title: 'Add', showAsAction: 'always'};
|
||||
expect(baseProps.navigator.setButtons).toBeCalledTimes(2);
|
||||
expect(baseProps.navigator.setButtons.mock.calls[0][0]).toEqual({rightButtons: [button]});
|
||||
expect(baseProps.navigator.setButtons.mock.calls[1][0]).toEqual({rightButtons: [button]});
|
||||
const button = {enabled: false, id: 'add-members', text: 'Add', showAsAction: 'always'};
|
||||
expect(baseProps.actions.setButtons).toBeCalledTimes(2);
|
||||
expect(baseProps.actions.setButtons.mock.calls[0][0]).toEqual(baseProps.componentId, {rightButtons: [button]});
|
||||
expect(baseProps.actions.setButtons.mock.calls[1][0]).toEqual(baseProps.componentId, {rightButtons: [button]});
|
||||
});
|
||||
|
||||
test('should match state on clearSearch', () => {
|
||||
|
|
@ -50,12 +48,11 @@ describe('ChannelAddMembers', () => {
|
|||
wrapper.setState({term: '', searchResults: []});
|
||||
});
|
||||
|
||||
test('should call props.navigator on close', () => {
|
||||
test('should call props.popTopScreen on close', () => {
|
||||
const wrapper = shallowWithIntl(<ChannelAddMembers {...baseProps}/>);
|
||||
|
||||
wrapper.instance().close();
|
||||
expect(baseProps.navigator.pop).toBeCalledTimes(1);
|
||||
expect(baseProps.navigator.pop).toBeCalledWith({animated: true});
|
||||
expect(baseProps.actions.popTopScreen).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
test('should match state on onProfilesLoaded', () => {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
|
|||
import {getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams';
|
||||
import {getCurrentUserId, getProfilesNotInCurrentChannel} from 'mattermost-redux/selectors/entities/users';
|
||||
|
||||
import {setButtons, popTopScreen} from 'app/actions/navigation';
|
||||
import {handleAddChannelMembers} from 'app/actions/views/channel_add_members';
|
||||
|
||||
import ChannelAddMembers from './channel_add_members';
|
||||
|
|
@ -35,6 +36,8 @@ function mapDispatchToProps(dispatch) {
|
|||
getProfilesNotInChannel,
|
||||
handleAddChannelMembers,
|
||||
searchProfiles,
|
||||
setButtons,
|
||||
popTopScreen,
|
||||
}, dispatch),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,10 @@ export default class ChannelInfo extends PureComponent {
|
|||
selectPenultimateChannel: PropTypes.func.isRequired,
|
||||
handleSelectChannel: PropTypes.func.isRequired,
|
||||
setChannelDisplayName: PropTypes.func.isRequired,
|
||||
popTopScreen: PropTypes.func.isRequired,
|
||||
goToScreen: PropTypes.func.isRequired,
|
||||
dismissModal: PropTypes.func.isRequired,
|
||||
showModalOverCurrentContext: PropTypes.func.isRequired,
|
||||
}),
|
||||
componentId: PropTypes.string,
|
||||
viewArchivedChannels: PropTypes.bool.isRequired,
|
||||
|
|
@ -50,7 +54,6 @@ export default class ChannelInfo extends PureComponent {
|
|||
currentChannelCreatorName: PropTypes.string,
|
||||
currentChannelMemberCount: PropTypes.number,
|
||||
currentUserId: PropTypes.string,
|
||||
navigator: PropTypes.object,
|
||||
status: PropTypes.string,
|
||||
theme: PropTypes.object.isRequired,
|
||||
isChannelMuted: PropTypes.bool.isRequired,
|
||||
|
|
@ -105,95 +108,61 @@ export default class ChannelInfo extends PureComponent {
|
|||
}
|
||||
|
||||
close = (redirect = true) => {
|
||||
const {actions} = this.props;
|
||||
|
||||
if (redirect) {
|
||||
this.props.actions.setChannelDisplayName('');
|
||||
actions.setChannelDisplayName('');
|
||||
}
|
||||
if (Platform.OS === 'android') {
|
||||
this.props.navigator.dismissModal({animated: true});
|
||||
actions.dismissModal();
|
||||
} else {
|
||||
this.props.navigator.pop({animated: true});
|
||||
actions.popTopScreen();
|
||||
}
|
||||
};
|
||||
|
||||
goToChannelAddMembers = preventDoubleTap(() => {
|
||||
const {actions} = this.props;
|
||||
const {intl} = this.context;
|
||||
const {navigator, theme} = this.props;
|
||||
navigator.push({
|
||||
backButtonTitle: '',
|
||||
screen: 'ChannelAddMembers',
|
||||
title: intl.formatMessage({id: 'channel_header.addMembers', defaultMessage: 'Add Members'}),
|
||||
animated: true,
|
||||
navigatorStyle: {
|
||||
navBarTextColor: theme.sidebarHeaderTextColor,
|
||||
navBarBackgroundColor: theme.sidebarHeaderBg,
|
||||
navBarButtonColor: theme.sidebarHeaderTextColor,
|
||||
screenBackgroundColor: theme.centerChannelBg,
|
||||
},
|
||||
});
|
||||
const screen = 'ChannelAddMembers';
|
||||
const title = intl.formatMessage({id: 'channel_header.addMembers', defaultMessage: 'Add Members'});
|
||||
|
||||
actions.goToScreen(screen, title);
|
||||
});
|
||||
|
||||
goToChannelMembers = preventDoubleTap(() => {
|
||||
const {actions, canManageUsers} = this.props;
|
||||
const {intl} = this.context;
|
||||
const {canManageUsers, navigator, theme} = this.props;
|
||||
const id = canManageUsers ? t('channel_header.manageMembers') : t('channel_header.viewMembers');
|
||||
const defaultMessage = canManageUsers ? 'Manage Members' : 'View Members';
|
||||
const screen = 'ChannelMembers';
|
||||
const title = intl.formatMessage({id, defaultMessage});
|
||||
|
||||
navigator.push({
|
||||
backButtonTitle: '',
|
||||
screen: 'ChannelMembers',
|
||||
title: intl.formatMessage({id, defaultMessage}),
|
||||
animated: true,
|
||||
navigatorStyle: {
|
||||
navBarTextColor: theme.sidebarHeaderTextColor,
|
||||
navBarBackgroundColor: theme.sidebarHeaderBg,
|
||||
navBarButtonColor: theme.sidebarHeaderTextColor,
|
||||
screenBackgroundColor: theme.centerChannelBg,
|
||||
},
|
||||
});
|
||||
actions.goToScreen(screen, title);
|
||||
});
|
||||
|
||||
goToPinnedPosts = preventDoubleTap(() => {
|
||||
const {actions, currentChannel} = this.props;
|
||||
const {formatMessage} = this.context.intl;
|
||||
const {actions, currentChannel, navigator, theme} = this.props;
|
||||
const id = t('channel_header.pinnedPosts');
|
||||
const defaultMessage = 'Pinned Posts';
|
||||
const screen = 'PinnedPosts';
|
||||
const title = formatMessage({id, defaultMessage});
|
||||
const passProps = {
|
||||
currentChannelId: currentChannel.id,
|
||||
};
|
||||
|
||||
actions.clearPinnedPosts(currentChannel.id);
|
||||
navigator.push({
|
||||
backButtonTitle: '',
|
||||
screen: 'PinnedPosts',
|
||||
title: formatMessage({id, defaultMessage}),
|
||||
animated: true,
|
||||
navigatorStyle: {
|
||||
navBarTextColor: theme.sidebarHeaderTextColor,
|
||||
navBarBackgroundColor: theme.sidebarHeaderBg,
|
||||
navBarButtonColor: theme.sidebarHeaderTextColor,
|
||||
screenBackgroundColor: theme.centerChannelBg,
|
||||
},
|
||||
passProps: {
|
||||
currentChannelId: currentChannel.id,
|
||||
},
|
||||
});
|
||||
actions.goToScreen(screen, title, passProps);
|
||||
});
|
||||
|
||||
handleChannelEdit = preventDoubleTap(() => {
|
||||
const {actions} = this.props;
|
||||
const {intl} = this.context;
|
||||
const {navigator, theme} = this.props;
|
||||
const id = t('mobile.channel_info.edit');
|
||||
const defaultMessage = 'Edit Channel';
|
||||
const screen = 'EditChannel';
|
||||
const title = intl.formatMessage({id, defaultMessage});
|
||||
|
||||
navigator.push({
|
||||
backButtonTitle: '',
|
||||
screen: 'EditChannel',
|
||||
title: intl.formatMessage({id, defaultMessage}),
|
||||
animated: true,
|
||||
navigatorStyle: {
|
||||
navBarTextColor: theme.sidebarHeaderTextColor,
|
||||
navBarBackgroundColor: theme.sidebarHeaderBg,
|
||||
navBarButtonColor: theme.sidebarHeaderTextColor,
|
||||
screenBackgroundColor: theme.centerChannelBg,
|
||||
},
|
||||
});
|
||||
actions.goToScreen(screen, title);
|
||||
});
|
||||
|
||||
handleLeave = () => {
|
||||
|
|
@ -337,30 +306,22 @@ export default class ChannelInfo extends PureComponent {
|
|||
});
|
||||
|
||||
showPermalinkView = (postId) => {
|
||||
const {actions, navigator} = this.props;
|
||||
const {actions} = this.props;
|
||||
const screen = 'Permalink';
|
||||
const passProps = {
|
||||
isPermalink: true,
|
||||
onClose: this.handleClosePermalink,
|
||||
};
|
||||
const options = {
|
||||
layout: {
|
||||
backgroundColor: changeOpacity('#000', 0.2),
|
||||
},
|
||||
};
|
||||
|
||||
actions.selectFocusedPostId(postId);
|
||||
|
||||
if (!this.showingPermalink) {
|
||||
const options = {
|
||||
screen: 'Permalink',
|
||||
animationType: 'none',
|
||||
backButtonTitle: '',
|
||||
overrideBackPress: true,
|
||||
navigatorStyle: {
|
||||
navBarHidden: true,
|
||||
screenBackgroundColor: changeOpacity('#000', 0.2),
|
||||
modalPresentationStyle: 'overCurrentContext',
|
||||
},
|
||||
passProps: {
|
||||
isPermalink: true,
|
||||
onClose: this.handleClosePermalink,
|
||||
},
|
||||
};
|
||||
|
||||
this.showingPermalink = true;
|
||||
navigator.showModal(options);
|
||||
}
|
||||
this.showingPermalink = true;
|
||||
actions.showModalOverCurrentContext(screen, passProps, options);
|
||||
};
|
||||
|
||||
renderViewOrManageMembersRow = () => {
|
||||
|
|
@ -510,7 +471,6 @@ export default class ChannelInfo extends PureComponent {
|
|||
currentChannel,
|
||||
currentChannelCreatorName,
|
||||
currentChannelMemberCount,
|
||||
navigator,
|
||||
status,
|
||||
theme,
|
||||
isBot,
|
||||
|
|
@ -545,7 +505,6 @@ export default class ChannelInfo extends PureComponent {
|
|||
displayName={currentChannel.display_name}
|
||||
header={currentChannel.header}
|
||||
memberCount={currentChannelMemberCount}
|
||||
navigator={navigator}
|
||||
onPermalinkPress={this.handlePermalinkPress}
|
||||
purpose={currentChannel.purpose}
|
||||
status={status}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ export default class ChannelInfoHeader extends React.PureComponent {
|
|||
memberCount: PropTypes.number,
|
||||
displayName: PropTypes.string.isRequired,
|
||||
header: PropTypes.string,
|
||||
navigator: PropTypes.object.isRequired,
|
||||
onPermalinkPress: PropTypes.func,
|
||||
purpose: PropTypes.string,
|
||||
status: PropTypes.string,
|
||||
|
|
@ -41,7 +40,6 @@ export default class ChannelInfoHeader extends React.PureComponent {
|
|||
displayName,
|
||||
header,
|
||||
memberCount,
|
||||
navigator,
|
||||
onPermalinkPress,
|
||||
purpose,
|
||||
status,
|
||||
|
|
@ -88,7 +86,6 @@ export default class ChannelInfoHeader extends React.PureComponent {
|
|||
defaultMessage='Purpose'
|
||||
/>
|
||||
<Markdown
|
||||
navigator={navigator}
|
||||
onPermalinkPress={onPermalinkPress}
|
||||
baseTextStyle={baseTextStyle}
|
||||
textStyles={textStyles}
|
||||
|
|
@ -105,7 +102,6 @@ export default class ChannelInfoHeader extends React.PureComponent {
|
|||
defaultMessage='Header'
|
||||
/>
|
||||
<Markdown
|
||||
navigator={navigator}
|
||||
onPermalinkPress={onPermalinkPress}
|
||||
baseTextStyle={baseTextStyle}
|
||||
textStyles={textStyles}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,12 @@ import {areChannelMentionsIgnored, getUserIdFromChannelName, isChannelMuted, sho
|
|||
import {isAdmin as checkIsAdmin, isChannelAdmin as checkIsChannelAdmin, isSystemAdmin as checkIsSystemAdmin} from 'mattermost-redux/utils/user_utils';
|
||||
import {getConfig, getLicense} from 'mattermost-redux/selectors/entities/general';
|
||||
|
||||
import {
|
||||
popTopScreen,
|
||||
goToScreen,
|
||||
dismissModal,
|
||||
showModalOverCurrentContext,
|
||||
} from 'app/actions/navigation';
|
||||
import {
|
||||
closeDMChannel,
|
||||
closeGMChannel,
|
||||
|
|
@ -119,6 +125,10 @@ function mapDispatchToProps(dispatch) {
|
|||
selectPenultimateChannel,
|
||||
setChannelDisplayName,
|
||||
handleSelectChannel,
|
||||
popTopScreen,
|
||||
goToScreen,
|
||||
dismissModal,
|
||||
showModalOverCurrentContext,
|
||||
}, dispatch),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,13 +32,14 @@ export default class ChannelMembers extends PureComponent {
|
|||
getProfilesInChannel: PropTypes.func.isRequired,
|
||||
handleRemoveChannelMembers: PropTypes.func.isRequired,
|
||||
searchProfiles: PropTypes.func.isRequired,
|
||||
setButtons: PropTypes.func.isRequired,
|
||||
popTopScreen: PropTypes.func.isRequired,
|
||||
}).isRequired,
|
||||
componentId: PropTypes.string,
|
||||
canManageUsers: PropTypes.bool.isRequired,
|
||||
currentChannelId: PropTypes.string.isRequired,
|
||||
currentChannelMembers: PropTypes.array,
|
||||
currentUserId: PropTypes.string.isRequired,
|
||||
navigator: PropTypes.object,
|
||||
theme: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
|
|
@ -63,14 +64,14 @@ export default class ChannelMembers extends PureComponent {
|
|||
};
|
||||
|
||||
this.removeButton = {
|
||||
disabled: true,
|
||||
enabled: false,
|
||||
id: 'remove-members',
|
||||
showAsAction: 'always',
|
||||
title: context.intl.formatMessage({id: 'channel_members_modal.remove', defaultMessage: 'Remove'}),
|
||||
text: context.intl.formatMessage({id: 'channel_members_modal.remove', defaultMessage: 'Remove'}),
|
||||
};
|
||||
|
||||
if (props.canManageUsers) {
|
||||
props.navigator.setButtons({
|
||||
props.actions.setButtons(props.componentId, {
|
||||
rightButtons: [this.removeButton],
|
||||
});
|
||||
}
|
||||
|
|
@ -105,13 +106,14 @@ export default class ChannelMembers extends PureComponent {
|
|||
};
|
||||
|
||||
close = () => {
|
||||
this.props.navigator.pop({animated: true});
|
||||
this.props.actions.popTopScreen();
|
||||
};
|
||||
|
||||
enableRemoveOption = (enabled) => {
|
||||
if (this.props.canManageUsers) {
|
||||
this.props.navigator.setButtons({
|
||||
rightButtons: [{...this.removeButton, disabled: !enabled}],
|
||||
const {actions, canManageUsers, componentId} = this.props;
|
||||
if (canManageUsers) {
|
||||
actions.setButtons(componentId, {
|
||||
rightButtons: [{...this.removeButton, enabled}],
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -10,11 +10,6 @@ import CustomList from 'app/components/custom_list';
|
|||
import ChannelMembers from './channel_members';
|
||||
|
||||
describe('ChannelMembers', () => {
|
||||
const navigator = {
|
||||
setOnNavigatorEvent: jest.fn(),
|
||||
setButtons: jest.fn(),
|
||||
};
|
||||
|
||||
const baseProps = {
|
||||
theme: Preferences.THEMES.default,
|
||||
currentUserId: 'current-user-id',
|
||||
|
|
@ -24,8 +19,9 @@ describe('ChannelMembers', () => {
|
|||
getProfilesInChannel: jest.fn().mockImplementation(() => Promise.resolve()),
|
||||
handleRemoveChannelMembers: jest.fn(),
|
||||
searchProfiles: jest.fn(),
|
||||
setButtons: jest.fn(),
|
||||
popTopScreen: jest.fn(),
|
||||
},
|
||||
navigator,
|
||||
componentId: 'component-id',
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -4,12 +4,14 @@
|
|||
import {bindActionCreators} from 'redux';
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import {handleRemoveChannelMembers} from 'app/actions/views/channel_members';
|
||||
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
|
||||
import {getCurrentChannel, canManageChannelMembers} from 'mattermost-redux/selectors/entities/channels';
|
||||
import {makeGetProfilesInChannel} from 'mattermost-redux/selectors/entities/users';
|
||||
import {getProfilesInChannel, searchProfiles} from 'mattermost-redux/actions/users';
|
||||
|
||||
import {setButtons, popTopScreen} from 'app/actions/navigation';
|
||||
import {handleRemoveChannelMembers} from 'app/actions/views/channel_members';
|
||||
|
||||
import ChannelMembers from './channel_members';
|
||||
|
||||
function makeMapStateToProps() {
|
||||
|
|
@ -40,6 +42,8 @@ function mapDispatchToProps(dispatch) {
|
|||
getProfilesInChannel,
|
||||
handleRemoveChannelMembers,
|
||||
searchProfiles,
|
||||
setButtons,
|
||||
popTopScreen,
|
||||
}, dispatch),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ export default class ChannelPeek extends PureComponent {
|
|||
channelId: PropTypes.string.isRequired,
|
||||
currentUserId: PropTypes.string,
|
||||
lastViewedAt: PropTypes.number,
|
||||
navigator: PropTypes.object,
|
||||
postIds: PropTypes.array,
|
||||
theme: PropTypes.object.isRequired,
|
||||
};
|
||||
|
|
@ -72,7 +71,6 @@ export default class ChannelPeek extends PureComponent {
|
|||
channelId,
|
||||
currentUserId,
|
||||
lastViewedAt,
|
||||
navigator,
|
||||
theme,
|
||||
} = this.props;
|
||||
|
||||
|
|
@ -89,7 +87,6 @@ export default class ChannelPeek extends PureComponent {
|
|||
currentUserId={currentUserId}
|
||||
lastViewedAt={lastViewedAt}
|
||||
channelId={channelId}
|
||||
navigator={navigator}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ import {setNavigatorStyles} from 'app/utils/theme';
|
|||
export default class CreateChannel extends PureComponent {
|
||||
static propTypes = {
|
||||
componentId: PropTypes.string,
|
||||
navigator: PropTypes.object.isRequired,
|
||||
theme: PropTypes.object.isRequired,
|
||||
deviceWidth: PropTypes.number.isRequired,
|
||||
deviceHeight: PropTypes.number.isRequired,
|
||||
|
|
@ -28,6 +27,9 @@ export default class CreateChannel extends PureComponent {
|
|||
closeButton: PropTypes.object,
|
||||
actions: PropTypes.shape({
|
||||
handleCreateChannel: PropTypes.func.isRequired,
|
||||
setButtons: PropTypes.func.isRequired,
|
||||
dismissModal: PropTypes.func.isRequired,
|
||||
popTopScreen: PropTypes.func.isRequired,
|
||||
}),
|
||||
};
|
||||
|
||||
|
|
@ -45,7 +47,7 @@ export default class CreateChannel extends PureComponent {
|
|||
|
||||
rightButton = {
|
||||
id: 'create-channel',
|
||||
disabled: true,
|
||||
enabled: false,
|
||||
showAsAction: 'always',
|
||||
};
|
||||
|
||||
|
|
@ -60,7 +62,7 @@ export default class CreateChannel extends PureComponent {
|
|||
header: '',
|
||||
};
|
||||
|
||||
this.rightButton.title = context.intl.formatMessage({id: 'mobile.create_channel', defaultMessage: 'Create'});
|
||||
this.rightButton.text = context.intl.formatMessage({id: 'mobile.create_channel', defaultMessage: 'Create'});
|
||||
|
||||
if (props.closeButton) {
|
||||
this.left = {...this.leftButton, icon: props.closeButton};
|
||||
|
|
@ -74,7 +76,7 @@ export default class CreateChannel extends PureComponent {
|
|||
buttons.leftButtons = [this.left];
|
||||
}
|
||||
|
||||
props.navigator.setButtons(buttons);
|
||||
props.actions.setButtons(props.componentId, buttons);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
|
|
@ -123,37 +125,38 @@ export default class CreateChannel extends PureComponent {
|
|||
}
|
||||
|
||||
close = (goBack = false) => {
|
||||
const {actions} = this.props;
|
||||
if (goBack) {
|
||||
this.props.navigator.pop({animated: true});
|
||||
actions.popTopScreen();
|
||||
} else {
|
||||
this.props.navigator.dismissModal({
|
||||
animationType: 'slide-down',
|
||||
});
|
||||
actions.dismissModal();
|
||||
}
|
||||
};
|
||||
|
||||
emitCanCreateChannel = (enabled) => {
|
||||
const {actions, componentId} = this.props;
|
||||
const buttons = {
|
||||
rightButtons: [{...this.rightButton, disabled: !enabled}],
|
||||
rightButtons: [{...this.rightButton, enabled}],
|
||||
};
|
||||
|
||||
if (this.left) {
|
||||
buttons.leftButtons = [this.left];
|
||||
}
|
||||
|
||||
this.props.navigator.setButtons(buttons);
|
||||
actions.setButtons(componentId, buttons);
|
||||
};
|
||||
|
||||
emitCreating = (loading) => {
|
||||
const {actions, componentId} = this.props;
|
||||
const buttons = {
|
||||
rightButtons: [{...this.rightButton, disabled: loading}],
|
||||
rightButtons: [{...this.rightButton, enabled: !loading}],
|
||||
};
|
||||
|
||||
if (this.left) {
|
||||
buttons.leftButtons = [this.left];
|
||||
}
|
||||
|
||||
this.props.navigator.setButtons(buttons);
|
||||
actions.setButtons(componentId, buttons);
|
||||
};
|
||||
|
||||
onCreateChannel = () => {
|
||||
|
|
@ -176,7 +179,6 @@ export default class CreateChannel extends PureComponent {
|
|||
|
||||
render() {
|
||||
const {
|
||||
navigator,
|
||||
theme,
|
||||
deviceWidth,
|
||||
deviceHeight,
|
||||
|
|
@ -191,7 +193,6 @@ export default class CreateChannel extends PureComponent {
|
|||
|
||||
return (
|
||||
<EditChannelInfo
|
||||
navigator={navigator}
|
||||
theme={theme}
|
||||
enableRightButton={this.emitCanCreateChannel}
|
||||
error={error}
|
||||
|
|
|
|||
|
|
@ -4,9 +4,14 @@
|
|||
import {bindActionCreators} from 'redux';
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import {handleCreateChannel} from 'app/actions/views/create_channel';
|
||||
|
||||
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
|
||||
|
||||
import {
|
||||
setButtons,
|
||||
dismissModal,
|
||||
popTopScreen,
|
||||
} from 'app/actions/navigation';
|
||||
import {handleCreateChannel} from 'app/actions/views/create_channel';
|
||||
import {getDimensions} from 'app/selectors/device';
|
||||
|
||||
import CreateChannel from './create_channel';
|
||||
|
|
@ -27,6 +32,9 @@ function mapDispatchToProps(dispatch) {
|
|||
return {
|
||||
actions: bindActionCreators({
|
||||
handleCreateChannel,
|
||||
setButtons,
|
||||
dismissModal,
|
||||
popTopScreen,
|
||||
}, dispatch),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,9 +56,10 @@ export default class EditChannel extends PureComponent {
|
|||
patchChannel: PropTypes.func.isRequired,
|
||||
getChannel: PropTypes.func.isRequired,
|
||||
setChannelDisplayName: PropTypes.func.isRequired,
|
||||
setButtons: PropTypes.func.isRequired,
|
||||
popTopScreen: PropTypes.func.isRequired,
|
||||
}),
|
||||
componentId: PropTypes.string,
|
||||
navigator: PropTypes.object.isRequired,
|
||||
theme: PropTypes.object.isRequired,
|
||||
deviceWidth: PropTypes.number.isRequired,
|
||||
deviceHeight: PropTypes.number.isRequired,
|
||||
|
|
@ -74,7 +75,7 @@ export default class EditChannel extends PureComponent {
|
|||
|
||||
rightButton = {
|
||||
id: 'edit-channel',
|
||||
disabled: true,
|
||||
enabled: false,
|
||||
showAsAction: 'always',
|
||||
};
|
||||
|
||||
|
|
@ -98,13 +99,13 @@ export default class EditChannel extends PureComponent {
|
|||
header,
|
||||
};
|
||||
|
||||
this.rightButton.title = context.intl.formatMessage({id: 'mobile.edit_channel', defaultMessage: 'Save'});
|
||||
this.rightButton.text = context.intl.formatMessage({id: 'mobile.edit_channel', defaultMessage: 'Save'});
|
||||
|
||||
const buttons = {
|
||||
rightButtons: [this.rightButton],
|
||||
};
|
||||
|
||||
props.navigator.setButtons(buttons);
|
||||
props.actions.setButtons(props.componentId, buttons);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
|
|
@ -161,23 +162,25 @@ export default class EditChannel extends PureComponent {
|
|||
this.props.actions.setChannelDisplayName(this.state.displayName);
|
||||
}
|
||||
|
||||
this.props.navigator.pop({animated: true});
|
||||
this.props.actions.popTopScreen();
|
||||
};
|
||||
|
||||
emitCanUpdateChannel = (enabled) => {
|
||||
const {actions, componentId} = this.props;
|
||||
const buttons = {
|
||||
rightButtons: [{...this.rightButton, disabled: !enabled}],
|
||||
rightButtons: [{...this.rightButton, enabled}],
|
||||
};
|
||||
|
||||
this.props.navigator.setButtons(buttons);
|
||||
actions.setButtons(componentId, buttons);
|
||||
};
|
||||
|
||||
emitUpdating = (loading) => {
|
||||
const {actions, componentId} = this.props;
|
||||
const buttons = {
|
||||
rightButtons: [{...this.rightButton, disabled: loading}],
|
||||
rightButtons: [{...this.rightButton, enabled: !loading}],
|
||||
};
|
||||
|
||||
this.props.navigator.setButtons(buttons);
|
||||
actions.setButtons(componentId, buttons);
|
||||
};
|
||||
|
||||
validateDisplayName = (displayName) => {
|
||||
|
|
@ -277,7 +280,6 @@ export default class EditChannel extends PureComponent {
|
|||
purpose: oldPurpose,
|
||||
type,
|
||||
},
|
||||
navigator,
|
||||
theme,
|
||||
currentTeamUrl,
|
||||
deviceWidth,
|
||||
|
|
@ -294,7 +296,6 @@ export default class EditChannel extends PureComponent {
|
|||
|
||||
return (
|
||||
<EditChannelInfo
|
||||
navigator={navigator}
|
||||
theme={theme}
|
||||
enableRightButton={this.emitCanUpdateChannel}
|
||||
error={error}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import {getCurrentTeamUrl} from 'mattermost-redux/selectors/entities/teams';
|
|||
import {patchChannel, getChannel} from 'mattermost-redux/actions/channels';
|
||||
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
|
||||
|
||||
import {setButtons, popTopScreen} from 'app/actions/navigation';
|
||||
import {setChannelDisplayName} from 'app/actions/views/channel';
|
||||
import {getDimensions} from 'app/selectors/device';
|
||||
|
||||
|
|
@ -35,6 +36,8 @@ function mapDispatchToProps(dispatch) {
|
|||
patchChannel,
|
||||
getChannel,
|
||||
setChannelDisplayName,
|
||||
setButtons,
|
||||
popTopScreen,
|
||||
}, dispatch),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,6 +92,7 @@ export default class EditProfile extends PureComponent {
|
|||
dismissModal: PropTypes.func.isRequired,
|
||||
setButtons: PropTypes.func.isRequired,
|
||||
}).isRequired,
|
||||
componentId: PropTypes.string,
|
||||
currentUser: PropTypes.object.isRequired,
|
||||
firstNameDisabled: PropTypes.bool.isRequired,
|
||||
lastNameDisabled: PropTypes.bool.isRequired,
|
||||
|
|
@ -107,7 +108,7 @@ export default class EditProfile extends PureComponent {
|
|||
|
||||
rightButton = {
|
||||
id: 'update-profile',
|
||||
disabled: true,
|
||||
enabled: false,
|
||||
showAsAction: 'always',
|
||||
};
|
||||
|
||||
|
|
@ -118,9 +119,9 @@ export default class EditProfile extends PureComponent {
|
|||
const buttons = {
|
||||
rightButtons: [this.rightButton],
|
||||
};
|
||||
this.rightButton.title = context.intl.formatMessage({id: t('mobile.account.settings.save'), defaultMessage: 'Save'});
|
||||
this.rightButton.text = context.intl.formatMessage({id: t('mobile.account.settings.save'), defaultMessage: 'Save'});
|
||||
|
||||
props.actions.setButtons(buttons);
|
||||
props.actions.setButtons(props.componentId, buttons);
|
||||
|
||||
this.state = {
|
||||
email,
|
||||
|
|
@ -187,11 +188,12 @@ export default class EditProfile extends PureComponent {
|
|||
};
|
||||
|
||||
emitCanUpdateAccount = (enabled) => {
|
||||
const {actions, componentId} = this.props;
|
||||
const buttons = {
|
||||
rightButtons: [{...this.rightButton, disabled: !enabled}],
|
||||
rightButtons: [{...this.rightButton, enabled}],
|
||||
};
|
||||
|
||||
this.props.actions.setButtons(buttons);
|
||||
actions.setButtons(componentId, buttons);
|
||||
};
|
||||
|
||||
handleRequestError = (error) => {
|
||||
|
|
|
|||
|
|
@ -12,11 +12,12 @@ import {getCurrentUserId, getCurrentUserRoles} from 'mattermost-redux/selectors/
|
|||
import {getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams';
|
||||
import {showCreateOption} from 'mattermost-redux/utils/channel_utils';
|
||||
import {isAdmin, isSystemAdmin} from 'mattermost-redux/utils/user_utils';
|
||||
|
||||
import {handleSelectChannel, setChannelDisplayName} from 'app/actions/views/channel';
|
||||
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
|
||||
import {getConfig, getLicense} from 'mattermost-redux/selectors/entities/general';
|
||||
|
||||
import {setButtons, dismissModal, goToScreen} from 'app/actions/navigation';
|
||||
import {handleSelectChannel, setChannelDisplayName} from 'app/actions/views/channel';
|
||||
|
||||
import MoreChannels from './more_channels';
|
||||
|
||||
const joinableChannels = createSelector(
|
||||
|
|
@ -53,6 +54,9 @@ function mapDispatchToProps(dispatch) {
|
|||
getChannels,
|
||||
searchChannels,
|
||||
setChannelDisplayName,
|
||||
setButtons,
|
||||
dismissModal,
|
||||
goToScreen,
|
||||
}, dispatch),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,9 @@ export default class MoreChannels extends PureComponent {
|
|||
getChannels: PropTypes.func.isRequired,
|
||||
searchChannels: PropTypes.func.isRequired,
|
||||
setChannelDisplayName: PropTypes.func.isRequired,
|
||||
setButtons: PropTypes.func.isRequired,
|
||||
dismissModal: PropTypes.func.isRequired,
|
||||
goToScreen: PropTypes.func.isRequired,
|
||||
}).isRequired,
|
||||
componentId: PropTypes.string,
|
||||
canCreateChannels: PropTypes.bool.isRequired,
|
||||
|
|
@ -36,7 +39,6 @@ export default class MoreChannels extends PureComponent {
|
|||
closeButton: PropTypes.object,
|
||||
currentUserId: PropTypes.string.isRequired,
|
||||
currentTeamId: PropTypes.string.isRequired,
|
||||
navigator: PropTypes.object,
|
||||
theme: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
|
|
@ -65,7 +67,7 @@ export default class MoreChannels extends PureComponent {
|
|||
|
||||
this.rightButton = {
|
||||
id: 'create-pub-channel',
|
||||
title: context.intl.formatMessage({id: 'mobile.create_channel', defaultMessage: 'Create'}),
|
||||
text: context.intl.formatMessage({id: 'mobile.create_channel', defaultMessage: 'Create'}),
|
||||
showAsAction: 'always',
|
||||
};
|
||||
|
||||
|
|
@ -82,7 +84,7 @@ export default class MoreChannels extends PureComponent {
|
|||
buttons.rightButtons = [this.rightButton];
|
||||
}
|
||||
|
||||
props.navigator.setButtons(buttons);
|
||||
props.actions.setButtons(props.componentId, buttons);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
|
|
@ -136,7 +138,7 @@ export default class MoreChannels extends PureComponent {
|
|||
};
|
||||
|
||||
close = () => {
|
||||
this.props.navigator.dismissModal({animationType: 'slide-down'});
|
||||
this.props.actions.dismissModal();
|
||||
};
|
||||
|
||||
doGetChannels = () => {
|
||||
|
|
@ -164,16 +166,16 @@ export default class MoreChannels extends PureComponent {
|
|||
getChannels = debounce(this.doGetChannels, 100);
|
||||
|
||||
headerButtons = (createEnabled) => {
|
||||
const {canCreateChannels} = this.props;
|
||||
const {actions, canCreateChannels, componentId} = this.props;
|
||||
const buttons = {
|
||||
leftButtons: [this.leftButton],
|
||||
};
|
||||
|
||||
if (canCreateChannels) {
|
||||
buttons.rightButtons = [{...this.rightButton, disabled: !createEnabled}];
|
||||
buttons.rightButtons = [{...this.rightButton, enabled: createEnabled}];
|
||||
}
|
||||
|
||||
this.props.navigator.setButtons(buttons);
|
||||
actions.setButtons(componentId, buttons);
|
||||
};
|
||||
|
||||
loadedChannels = ({data}) => {
|
||||
|
|
@ -228,25 +230,16 @@ export default class MoreChannels extends PureComponent {
|
|||
};
|
||||
|
||||
onCreateChannel = () => {
|
||||
const {actions} = this.props;
|
||||
const {formatMessage} = this.context.intl;
|
||||
const {navigator, theme} = this.props;
|
||||
|
||||
navigator.push({
|
||||
screen: 'CreateChannel',
|
||||
animationType: 'slide-up',
|
||||
title: formatMessage({id: 'mobile.create_channel.public', defaultMessage: 'New Public Channel'}),
|
||||
backButtonTitle: '',
|
||||
animated: true,
|
||||
navigatorStyle: {
|
||||
navBarTextColor: theme.sidebarHeaderTextColor,
|
||||
navBarBackgroundColor: theme.sidebarHeaderBg,
|
||||
navBarButtonColor: theme.sidebarHeaderTextColor,
|
||||
screenBackgroundColor: theme.centerChannelBg,
|
||||
},
|
||||
passProps: {
|
||||
channelType: General.OPEN_CHANNEL,
|
||||
},
|
||||
});
|
||||
const screen = 'CreateChannel';
|
||||
const title = formatMessage({id: 'mobile.create_channel.public', defaultMessage: 'New Public Channel'});
|
||||
const passProps = {
|
||||
channelType: General.OPEN_CHANNEL,
|
||||
};
|
||||
|
||||
actions.goToScreen(screen, title, passProps);
|
||||
};
|
||||
|
||||
renderLoading = () => {
|
||||
|
|
|
|||
|
|
@ -11,18 +11,15 @@ import MoreChannels from './more_channels.js';
|
|||
jest.mock('react-intl');
|
||||
|
||||
describe('MoreChannels', () => {
|
||||
const navigator = {
|
||||
setButtons: jest.fn(),
|
||||
dismissModal: jest.fn(),
|
||||
push: jest.fn(),
|
||||
};
|
||||
|
||||
const actions = {
|
||||
handleSelectChannel: jest.fn(),
|
||||
joinChannel: jest.fn(),
|
||||
getChannels: jest.fn().mockResolvedValue({data: [{id: 'id2', name: 'name2', display_name: 'display_name2'}]}),
|
||||
searchChannels: jest.fn(),
|
||||
setChannelDisplayName: jest.fn(),
|
||||
setButtons: jest.fn(),
|
||||
dismissModal: jest.fn(),
|
||||
goToScreen: jest.fn(),
|
||||
};
|
||||
|
||||
const baseProps = {
|
||||
|
|
@ -32,7 +29,6 @@ describe('MoreChannels', () => {
|
|||
closeButton: {},
|
||||
currentUserId: 'current_user_id',
|
||||
currentTeamId: 'current_team_id',
|
||||
navigator,
|
||||
theme: Preferences.THEMES.default,
|
||||
componentId: 'component-id',
|
||||
};
|
||||
|
|
@ -46,27 +42,25 @@ describe('MoreChannels', () => {
|
|||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should call props.navigator.dismissModal on close', () => {
|
||||
test('should call props.actions.dismissModal on close', () => {
|
||||
const wrapper = shallow(
|
||||
<MoreChannels {...baseProps}/>,
|
||||
{context: {intl: {formatMessage: jest.fn()}}},
|
||||
);
|
||||
|
||||
wrapper.instance().close();
|
||||
expect(baseProps.navigator.dismissModal).toHaveBeenCalledTimes(1);
|
||||
expect(baseProps.navigator.dismissModal).toHaveBeenCalledWith({animationType: 'slide-down'});
|
||||
expect(baseProps.actions.dismissModal).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('should call props.navigator.setButtons on headerButtons', () => {
|
||||
const props = {...baseProps, navigator: {...navigator, setButtons: jest.fn()}};
|
||||
test('should call props.actions.setButtons on headerButtons', () => {
|
||||
const wrapper = shallow(
|
||||
<MoreChannels {...props}/>,
|
||||
<MoreChannels {...baseProps}/>,
|
||||
{context: {intl: {formatMessage: jest.fn()}}},
|
||||
);
|
||||
|
||||
expect(props.navigator.setButtons).toHaveBeenCalledTimes(1);
|
||||
expect(baseProps.actions.setButtons).toHaveBeenCalledTimes(1);
|
||||
wrapper.instance().headerButtons(true);
|
||||
expect(props.navigator.setButtons).toHaveBeenCalledTimes(2);
|
||||
expect(baseProps.actions.setButtons).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
test('should match return value of filterChannels', () => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue