diff --git a/app/actions/navigation.js b/app/actions/navigation.js
index 56eb887af..ca261c905 100644
--- a/app/actions/navigation.js
+++ b/app/actions/navigation.js
@@ -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,
diff --git a/app/components/announcement_banner/announcement_banner.js b/app/components/announcement_banner/announcement_banner.js
index 3da97744b..67b4b6d91 100644
--- a/app/components/announcement_banner/announcement_banner.js
+++ b/app/components/announcement_banner/announcement_banner.js
@@ -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) => {
diff --git a/app/components/announcement_banner/announcement_banner.test.js b/app/components/announcement_banner/announcement_banner.test.js
index 5312962ba..73085ebf1 100644
--- a/app/components/announcement_banner/announcement_banner.test.js
+++ b/app/components/announcement_banner/announcement_banner.test.js
@@ -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,
};
diff --git a/app/components/announcement_banner/index.js b/app/components/announcement_banner/index.js
index f560c461d..f06d6eea1 100644
--- a/app/components/announcement_banner/index.js
+++ b/app/components/announcement_banner/index.js
@@ -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);
diff --git a/app/components/channel_intro/channel_intro.js b/app/components/channel_intro/channel_intro.js
index d50e434d2..b9d0200ea 100644
--- a/app/components/channel_intro/channel_intro.js
+++ b/app/components/channel_intro/channel_intro.js
@@ -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) => {
diff --git a/app/components/channel_intro/index.js b/app/components/channel_intro/index.js
index 5495a4d01..8d6ccf49e 100644
--- a/app/components/channel_intro/index.js
+++ b/app/components/channel_intro/index.js
@@ -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);
diff --git a/app/components/edit_channel_info/edit_channel_info.js b/app/components/edit_channel_info/edit_channel_info.js
new file mode 100644
index 000000000..028240bdc
--- /dev/null
+++ b/app/components/edit_channel_info/edit_channel_info.js
@@ -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 (
+
+
+
+
+ );
+ }
+
+ let displayError;
+ if (error) {
+ displayError = (
+
+
+
+
+
+ );
+ }
+
+ return (
+
+
+
+ {displayError}
+
+
+ {!displayHeaderOnly && (
+
+
+
+
+
+
+
+
+ )}
+ {/*TODO: Hide channel url field until it's added to CreateChannel */}
+ {false && editing && !displayHeaderOnly && (
+
+
+
+
+ {shortUrl}
+
+
+
+
+
+
+ )}
+ {!displayHeaderOnly && (
+
+
+
+
+
+
+
+
+
+
+
+
+ )}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+}
+
+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,
+ },
+ };
+});
diff --git a/app/components/edit_channel_info/index.js b/app/components/edit_channel_info/index.js
index 66927a3f1..a523704f5 100644
--- a/app/components/edit_channel_info/index.js
+++ b/app/components/edit_channel_info/index.js
@@ -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 (
-
-
-
-
- );
- }
-
- let displayError;
- if (error) {
- displayError = (
-
-
-
-
-
- );
- }
-
- return (
-
-
-
- {displayError}
-
-
- {!displayHeaderOnly && (
-
-
-
-
-
-
-
-
- )}
- {/*TODO: Hide channel url field until it's added to CreateChannel */}
- {false && editing && !displayHeaderOnly && (
-
-
-
-
- {shortUrl}
-
-
-
-
-
-
- )}
- {!displayHeaderOnly && (
-
-
-
-
-
-
-
-
-
-
-
-
- )}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
- }
}
-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);
diff --git a/app/components/interactive_dialog_controller/index.js b/app/components/interactive_dialog_controller/index.js
index 10d93d094..a2577835a 100644
--- a/app/components/interactive_dialog_controller/index.js
+++ b/app/components/interactive_dialog_controller/index.js
@@ -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);
diff --git a/app/components/interactive_dialog_controller/interactive_dialog_controller.js b/app/components/interactive_dialog_controller/interactive_dialog_controller.js
index fcba9b347..7ec4e0177 100644
--- a/app/components/interactive_dialog_controller/interactive_dialog_controller.js
+++ b/app/components/interactive_dialog_controller/interactive_dialog_controller.js
@@ -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() {
diff --git a/app/components/post_list/index.js b/app/components/post_list/index.js
index 92168b4ba..1c8f430ef 100644
--- a/app/components/post_list/index.js
+++ b/app/components/post_list/index.js
@@ -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),
};
}
diff --git a/app/components/post_list/post_list.js b/app/components/post_list/post_list.js
index 3cc733f04..39e16dcac 100644
--- a/app/components/post_list/post_list.js
+++ b/app/components/post_list/post_list.js
@@ -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);
}
};
diff --git a/app/components/post_list/post_list.test.js b/app/components/post_list/post_list.test.js
index 0c6455843..a4219bf89 100644
--- a/app/components/post_list/post_list.test.js
+++ b/app/components/post_list/post_list.test.js
@@ -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();
});
diff --git a/app/screens/channel/channel_base.js b/app/screens/channel/channel_base.js
index 53e40b4ef..0a96f4250 100644
--- a/app/screens/channel/channel_base.js
+++ b/app/screens/channel/channel_base.js
@@ -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 (
-
+
{drawerContent}
diff --git a/app/screens/channel/channel_nav_bar/channel_nav_bar.js b/app/screens/channel/channel_nav_bar/channel_nav_bar.js
index d84a2cd6f..9e203e057 100644
--- a/app/screens/channel/channel_nav_bar/channel_nav_bar.js
+++ b/app/screens/channel/channel_nav_bar/channel_nav_bar.js
@@ -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 {
/>
diff --git a/app/screens/channel/channel_nav_bar/channel_search_button/channel_search_button.js b/app/screens/channel/channel_nav_bar/channel_search_button/channel_search_button.js
index c40a87411..554d14f55 100644
--- a/app/screens/channel/channel_nav_bar/channel_search_button/channel_search_button.js
+++ b/app/screens/channel/channel_nav_bar/channel_search_button/channel_search_button.js
@@ -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,
};
diff --git a/app/screens/channel/channel_post_list/channel_post_list.js b/app/screens/channel/channel_post_list/channel_post_list.js
index 26e2383a6..dc8ca68bc 100644
--- a/app/screens/channel/channel_post_list/channel_post_list.js
+++ b/app/screens/channel/channel_post_list/channel_post_list.js
@@ -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 (
);
};
@@ -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 (
{component}
-
+
);
diff --git a/app/screens/channel/channel_post_list/index.js b/app/screens/channel/channel_post_list/index.js
index 2e34bdea1..dd5cd8368 100644
--- a/app/screens/channel/channel_post_list/index.js
+++ b/app/screens/channel/channel_post_list/index.js
@@ -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),
};
}
diff --git a/app/screens/channel/index.js b/app/screens/channel/index.js
index 1c9fc4c26..e26fc7e13 100644
--- a/app/screens/channel/index.js
+++ b/app/screens/channel/index.js
@@ -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),
};
}
diff --git a/app/screens/channel_add_members/channel_add_members.js b/app/screens/channel_add_members/channel_add_members.js
index 11e42ea88..95eb6010a 100644
--- a/app/screens/channel_add_members/channel_add_members.js
+++ b/app/screens/channel_add_members/channel_add_members.js
@@ -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}],
});
};
diff --git a/app/screens/channel_add_members/channel_add_members.test.js b/app/screens/channel_add_members/channel_add_members.test.js
index 3d5eaed74..0684d5685 100644
--- a/app/screens/channel_add_members/channel_add_members.test.js
+++ b/app/screens/channel_add_members/channel_add_members.test.js
@@ -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();
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', () => {
diff --git a/app/screens/channel_add_members/index.js b/app/screens/channel_add_members/index.js
index f44704853..c2efa8625 100644
--- a/app/screens/channel_add_members/index.js
+++ b/app/screens/channel_add_members/index.js
@@ -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),
};
}
diff --git a/app/screens/channel_info/channel_info.js b/app/screens/channel_info/channel_info.js
index cb2e3b08e..c2a07a787 100644
--- a/app/screens/channel_info/channel_info.js
+++ b/app/screens/channel_info/channel_info.js
@@ -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}
diff --git a/app/screens/channel_info/channel_info_header.js b/app/screens/channel_info/channel_info_header.js
index 0f10ef56e..fad941d7a 100644
--- a/app/screens/channel_info/channel_info_header.js
+++ b/app/screens/channel_info/channel_info_header.js
@@ -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'
/>
{
- 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}],
});
}
};
diff --git a/app/screens/channel_members/channel_members.test.js b/app/screens/channel_members/channel_members.test.js
index efb4e750e..4ad691310 100644
--- a/app/screens/channel_members/channel_members.test.js
+++ b/app/screens/channel_members/channel_members.test.js
@@ -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',
};
diff --git a/app/screens/channel_members/index.js b/app/screens/channel_members/index.js
index b37975c3f..5c6b54f50 100644
--- a/app/screens/channel_members/index.js
+++ b/app/screens/channel_members/index.js
@@ -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),
};
}
diff --git a/app/screens/channel_peek/channel_peek.js b/app/screens/channel_peek/channel_peek.js
index 162cdd85b..f517ba967 100644
--- a/app/screens/channel_peek/channel_peek.js
+++ b/app/screens/channel_peek/channel_peek.js
@@ -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}
/>
);
diff --git a/app/screens/create_channel/create_channel.js b/app/screens/create_channel/create_channel.js
index 18c379e73..1e5994e7c 100644
--- a/app/screens/create_channel/create_channel.js
+++ b/app/screens/create_channel/create_channel.js
@@ -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 (
{
+ 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 (
{
+ 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) => {
diff --git a/app/screens/more_channels/index.js b/app/screens/more_channels/index.js
index 679744979..fa8617a0b 100644
--- a/app/screens/more_channels/index.js
+++ b/app/screens/more_channels/index.js
@@ -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),
};
}
diff --git a/app/screens/more_channels/more_channels.js b/app/screens/more_channels/more_channels.js
index ac118b36f..416a0bf53 100644
--- a/app/screens/more_channels/more_channels.js
+++ b/app/screens/more_channels/more_channels.js
@@ -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 = () => {
diff --git a/app/screens/more_channels/more_channels.test.js b/app/screens/more_channels/more_channels.test.js
index 32eaee752..7fe062b9f 100644
--- a/app/screens/more_channels/more_channels.test.js
+++ b/app/screens/more_channels/more_channels.test.js
@@ -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(
,
{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(
- ,
+ ,
{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', () => {