diff --git a/app/components/__snapshots__/profile_picture_button.test.js.snap b/app/components/__snapshots__/profile_picture_button.test.js.snap index 3cba2c9bd..c93aadecd 100644 --- a/app/components/__snapshots__/profile_picture_button.test.js.snap +++ b/app/components/__snapshots__/profile_picture_button.test.js.snap @@ -21,7 +21,6 @@ exports[`profile_picture_button should match snapshot 1`] = ` "dismissModal": [MockFunction], "push": [MockFunction], "setButtons": [MockFunction], - "setOnNavigatorEvent": [MockFunction], } } theme={ diff --git a/app/components/profile_picture_button.test.js b/app/components/profile_picture_button.test.js index a10138e75..a46a1a09c 100644 --- a/app/components/profile_picture_button.test.js +++ b/app/components/profile_picture_button.test.js @@ -11,7 +11,6 @@ import {Client4} from 'mattermost-redux/client'; describe('profile_picture_button', () => { const navigator = { - setOnNavigatorEvent: jest.fn(), setButtons: jest.fn(), dismissModal: jest.fn(), push: jest.fn(), diff --git a/app/components/safe_area_view/safe_area_view.ios.js b/app/components/safe_area_view/safe_area_view.ios.js index 8477a78b7..b69b77ec9 100644 --- a/app/components/safe_area_view/safe_area_view.ios.js +++ b/app/components/safe_area_view/safe_area_view.ios.js @@ -5,6 +5,7 @@ import React, {PureComponent} from 'react'; import PropTypes from 'prop-types'; import {Dimensions, Keyboard, NativeModules, View} from 'react-native'; import SafeArea from 'react-native-safe-area'; +import {Navigation} from 'react-native-navigation'; import {DeviceTypes} from 'app/constants'; import mattermostManaged from 'app/mattermost_managed'; @@ -33,10 +34,6 @@ export default class SafeAreaIos extends PureComponent { constructor(props) { super(props); - if (props.navigator) { - props.navigator.setOnNavigatorEvent(this.onNavigatorEvent); - } - this.state = { keyboard: false, safeAreaInsets: { @@ -56,6 +53,8 @@ export default class SafeAreaIos extends PureComponent { } componentDidMount() { + this.navigationEventListener = Navigation.events().bindComponent(this); + Dimensions.addEventListener('change', this.getSafeAreaInsets); this.keyboardDidShowListener = Keyboard.addListener('keyboardWillShow', this.keyboardWillShow); this.keyboardDidHideListener = Keyboard.addListener('keyboardWillHide', this.keyboardWillHide); @@ -70,6 +69,14 @@ export default class SafeAreaIos extends PureComponent { this.mounted = false; } + componentDidAppear() { + this.getSafeAreaInsets(); + } + + componentDidDisappear() { + this.getSafeAreaInsets(); + } + getStatusBarHeight = () => { try { StatusBarManager.getHeight( @@ -106,15 +113,6 @@ export default class SafeAreaIos extends PureComponent { this.setState({keyboard: true}); }; - onNavigatorEvent = (event) => { - switch (event.id) { - case 'willAppear': - case 'didDisappear': - this.getSafeAreaInsets(); - break; - } - }; - renderTopBar = () => { const {safeAreaInsets, statusBarHeight} = this.state; const {headerComponent, excludeHeader, forceTop, navBarBackgroundColor, theme} = this.props; diff --git a/app/components/sidebars/settings/settings_sidebar.js b/app/components/sidebars/settings/settings_sidebar.js index 9d552978b..726b9db4f 100644 --- a/app/components/sidebars/settings/settings_sidebar.js +++ b/app/components/sidebars/settings/settings_sidebar.js @@ -194,6 +194,9 @@ export default class SettingsDrawer extends PureComponent { goToSettings = preventDoubleTap(() => { const {intl} = this.context; + // TODO: Ensure all styles used in app/utils/theme's setNavigatorStyles + // are passed to Settings when this showModal call is updated to RNN v2, + // then remove setNavigatorStyles call in app/screens/settings/general/settings.js this.openModal( 'Settings', intl.formatMessage({id: 'mobile.routes.settings', defaultMessage: 'Settings'}), diff --git a/app/screens/about/about.js b/app/screens/about/about.js index 69aa156a4..dc056e9ec 100644 --- a/app/screens/about/about.js +++ b/app/screens/about/about.js @@ -23,6 +23,7 @@ const MATTERMOST_BUNDLE_IDS = ['com.mattermost.rnbeta', 'com.mattermost.rn']; export default class About extends PureComponent { static propTypes = { + componentId: PropTypes.string, config: PropTypes.object.isRequired, license: PropTypes.object.isRequired, navigator: PropTypes.object.isRequired, @@ -31,7 +32,7 @@ export default class About extends PureComponent { componentWillReceiveProps(nextProps) { if (this.props.theme !== nextProps.theme) { - setNavigatorStyles(this.props.navigator, nextProps.theme); + setNavigatorStyles(this.props.componentId, nextProps.theme); } } diff --git a/app/screens/add_reaction/add_reaction.js b/app/screens/add_reaction/add_reaction.js index ff4183c2f..f24978bf5 100644 --- a/app/screens/add_reaction/add_reaction.js +++ b/app/screens/add_reaction/add_reaction.js @@ -7,6 +7,7 @@ import { StyleSheet, View, } from 'react-native'; +import {Navigation} from 'react-native-navigation'; import EmojiPicker from 'app/components/emoji_picker'; import {emptyFunction} from 'app/utils/general'; @@ -14,6 +15,7 @@ import {setNavigatorStyles} from 'app/utils/theme'; export default class AddReaction extends PureComponent { static propTypes = { + componentId: PropTypes.string, closeButton: PropTypes.object, navigator: PropTypes.object.isRequired, onEmojiPress: PropTypes.func, @@ -31,15 +33,24 @@ export default class AddReaction extends PureComponent { constructor(props) { super(props); - props.navigator.setOnNavigatorEvent(this.onNavigatorEvent); props.navigator.setButtons({ leftButtons: [{...this.leftButton, icon: props.closeButton}], }); } + componentDidMount() { + this.navigationEventListener = Navigation.events().bindComponent(this); + } + componentWillReceiveProps(nextProps) { if (this.props.theme !== nextProps.theme) { - setNavigatorStyles(this.props.navigator, nextProps.theme); + setNavigatorStyles(this.props.componentId, nextProps.theme); + } + } + + navigationButtonPressed({buttonId}) { + if (buttonId === 'close-edit-post') { + this.close(); } } @@ -49,16 +60,6 @@ export default class AddReaction extends PureComponent { }); }; - onNavigatorEvent = (event) => { - if (event.type === 'NavBarButtonPress') { - switch (event.id) { - case 'close-edit-post': - this.close(); - break; - } - } - }; - handleEmojiPress = (emoji) => { this.props.onEmojiPress(emoji); this.close(); diff --git a/app/screens/channel_add_members/channel_add_members.js b/app/screens/channel_add_members/channel_add_members.js index b7b0da221..11e42ea88 100644 --- a/app/screens/channel_add_members/channel_add_members.js +++ b/app/screens/channel_add_members/channel_add_members.js @@ -9,6 +9,7 @@ import { Platform, View, } from 'react-native'; +import {Navigation} from 'react-native-navigation'; import {debounce} from 'mattermost-redux/actions/helpers'; import {General} from 'mattermost-redux/constants'; @@ -33,6 +34,7 @@ export default class ChannelAddMembers extends PureComponent { handleAddChannelMembers: PropTypes.func.isRequired, searchProfiles: PropTypes.func.isRequired, }).isRequired, + componentId: PropTypes.string, currentChannelId: PropTypes.string.isRequired, currentChannelGroupConstrained: PropTypes.bool, currentTeamId: PropTypes.string.isRequired, @@ -72,13 +74,14 @@ export default class ChannelAddMembers extends PureComponent { showAsAction: 'always', }; - props.navigator.setOnNavigatorEvent(this.onNavigatorEvent); props.navigator.setButtons({ rightButtons: [this.addButton], }); } componentDidMount() { + this.navigationEventListener = Navigation.events().bindComponent(this); + const {actions, currentTeamId} = this.props; actions.getTeamStats(currentTeamId); @@ -88,14 +91,20 @@ export default class ChannelAddMembers extends PureComponent { } componentDidUpdate(prevProps) { - const {navigator, theme} = this.props; + const {componentId, theme} = this.props; const {adding, selectedIds} = this.state; const enabled = Object.keys(selectedIds).length > 0 && !adding; this.enableAddOption(enabled); if (theme !== prevProps.theme) { - setNavigatorStyles(navigator, theme); + setNavigatorStyles(componentId, theme); + } + } + + navigationButtonPressed({buttonId}) { + if (buttonId === this.addButton.id) { + this.handleAddMembersPress(); } } @@ -188,14 +197,6 @@ export default class ChannelAddMembers extends PureComponent { }); }; - onNavigatorEvent = (event) => { - if (event.type === 'NavBarButtonPress') { - if (event.id === this.addButton.id) { - this.handleAddMembersPress(); - } - } - }; - onSearch = (text) => { if (text) { this.setState({term: text}); 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 700dd6483..3d5eaed74 100644 --- a/app/screens/channel_add_members/channel_add_members.test.js +++ b/app/screens/channel_add_members/channel_add_members.test.js @@ -24,9 +24,9 @@ describe('ChannelAddMembers', () => { navigator: { pop: jest.fn(), setButtons: jest.fn(), - setOnNavigatorEvent: jest.fn(), }, theme: Preferences.THEMES.default, + componentId: 'component-id', }; test('should render without error and call functions on mount', () => { @@ -39,8 +39,6 @@ describe('ChannelAddMembers', () => { 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]}); - - expect(baseProps.navigator.setOnNavigatorEvent).toBeCalledTimes(1); }); test('should match state on clearSearch', () => { diff --git a/app/screens/channel_info/channel_info.js b/app/screens/channel_info/channel_info.js index d2e892cc8..cb2e3b08e 100644 --- a/app/screens/channel_info/channel_info.js +++ b/app/screens/channel_info/channel_info.js @@ -43,6 +43,7 @@ export default class ChannelInfo extends PureComponent { handleSelectChannel: PropTypes.func.isRequired, setChannelDisplayName: PropTypes.func.isRequired, }), + componentId: PropTypes.string, viewArchivedChannels: PropTypes.bool.isRequired, canDeleteChannel: PropTypes.bool.isRequired, currentChannel: PropTypes.object.isRequired, @@ -82,7 +83,7 @@ export default class ChannelInfo extends PureComponent { componentWillReceiveProps(nextProps) { if (this.props.theme !== nextProps.theme) { - setNavigatorStyles(this.props.navigator, nextProps.theme); + setNavigatorStyles(this.props.componentId, nextProps.theme); } let isFavorite = this.state.isFavorite; diff --git a/app/screens/channel_members/channel_members.js b/app/screens/channel_members/channel_members.js index 1eb4fc40d..607582710 100644 --- a/app/screens/channel_members/channel_members.js +++ b/app/screens/channel_members/channel_members.js @@ -9,6 +9,7 @@ import { View, } from 'react-native'; import {intlShape} from 'react-intl'; +import {Navigation} from 'react-native-navigation'; import {debounce} from 'mattermost-redux/actions/helpers'; import {General} from 'mattermost-redux/constants'; @@ -32,6 +33,7 @@ export default class ChannelMembers extends PureComponent { handleRemoveChannelMembers: PropTypes.func.isRequired, searchProfiles: PropTypes.func.isRequired, }).isRequired, + componentId: PropTypes.string, canManageUsers: PropTypes.bool.isRequired, currentChannelId: PropTypes.string.isRequired, currentChannelMembers: PropTypes.array, @@ -67,7 +69,6 @@ export default class ChannelMembers extends PureComponent { title: context.intl.formatMessage({id: 'channel_members_modal.remove', defaultMessage: 'Remove'}), }; - props.navigator.setOnNavigatorEvent(this.onNavigatorEvent); if (props.canManageUsers) { props.navigator.setButtons({ rightButtons: [this.removeButton], @@ -76,18 +77,26 @@ export default class ChannelMembers extends PureComponent { } componentDidMount() { + this.navigationEventListener = Navigation.events().bindComponent(this); + this.getProfiles(); } componentDidUpdate(prevProps) { - const {navigator, theme} = this.props; + const {componentId, theme} = this.props; const {removing, selectedIds} = this.state; const enabled = Object.keys(selectedIds).length > 0 && !removing; this.enableRemoveOption(enabled); if (theme !== prevProps.theme) { - setNavigatorStyles(navigator, theme); + setNavigatorStyles(componentId, theme); + } + } + + navigationButtonPressed({buttonId}) { + if (buttonId === this.removeButton.id) { + this.handleRemoveMembersPress(); } } @@ -188,14 +197,6 @@ export default class ChannelMembers extends PureComponent { this.setState({loading: false, profiles: [...profiles, ...data]}); }; - onNavigatorEvent = (event) => { - if (event.type === 'NavBarButtonPress') { - if (event.id === this.removeButton.id) { - this.handleRemoveMembersPress(); - } - } - }; - onSearch = (text) => { if (text) { this.setState({term: text}); diff --git a/app/screens/channel_peek/channel_peek.js b/app/screens/channel_peek/channel_peek.js index 3fe98c4be..081952558 100644 --- a/app/screens/channel_peek/channel_peek.js +++ b/app/screens/channel_peek/channel_peek.js @@ -4,6 +4,7 @@ import React, {PureComponent} from 'react'; import PropTypes from 'prop-types'; import {Platform, View} from 'react-native'; +import {Navigation} from 'react-native-navigation'; import {getLastPostIndex} from 'mattermost-redux/utils/post_list'; @@ -32,13 +33,16 @@ export default class ChannelPeek extends PureComponent { constructor(props) { super(props); - this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent); props.actions.loadPostsIfNecessaryWithRetry(props.channelId); this.state = { visiblePostIds: this.getVisiblePostIds(props), }; } + componentDidMount() { + this.navigationEventListener = Navigation.events().bindComponent(this); + } + componentWillReceiveProps(nextProps) { const {postIds: nextPostIds} = nextProps; @@ -53,19 +57,17 @@ export default class ChannelPeek extends PureComponent { }); } + navigationButtonPressed({buttonId}) { + if (buttonId === 'action-mark-as-read') { + const {actions, channelId} = this.props; + actions.markChannelViewedAndRead(channelId); + } + } + getVisiblePostIds = (props) => { return props.postIds.slice(0, 15); }; - onNavigatorEvent = (event) => { - if (event.type === 'PreviewActionPress') { - if (event.id === 'action-mark-as-read') { - const {actions, channelId} = this.props; - actions.markChannelViewedAndRead(channelId); - } - } - }; - render() { const { channelId, diff --git a/app/screens/client_upgrade/client_upgrade.js b/app/screens/client_upgrade/client_upgrade.js index ac7d6608b..9ce684d33 100644 --- a/app/screens/client_upgrade/client_upgrade.js +++ b/app/screens/client_upgrade/client_upgrade.js @@ -12,6 +12,7 @@ import { View, } from 'react-native'; import {intlShape} from 'react-intl'; +import {Navigation} from 'react-native-navigation'; import FormattedText from 'app/components/formatted_text'; import StatusBar from 'app/components/status_bar'; @@ -26,6 +27,7 @@ export default class ClientUpgrade extends PureComponent { logError: PropTypes.func.isRequired, setLastUpgradeCheck: PropTypes.func.isRequired, }).isRequired, + componentId: PropTypes.string, currentVersion: PropTypes.string, closeAction: PropTypes.func, userCheckedForUpgrade: PropTypes.bool, @@ -44,13 +46,14 @@ export default class ClientUpgrade extends PureComponent { constructor(props) { super(props); - this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent); this.state = { upgradeType: UpgradeTypes.NO_UPGRADE, }; } componentDidMount() { + this.navigationEventListener = Navigation.events().bindComponent(this); + if (this.props.userCheckedForUpgrade) { this.checkUpgrade(this.props); } @@ -58,7 +61,15 @@ export default class ClientUpgrade extends PureComponent { componentWillReceiveProps(nextProps) { if (this.props.theme !== nextProps.theme) { - setNavigatorStyles(this.props.navigator, nextProps.theme); + setNavigatorStyles(this.props.componentId, nextProps.theme); + } + } + + navigationButtonPressed({buttonId}) { + if (buttonId === 'close-upgrade') { + this.props.navigator.dismissModal({ + animationType: 'slide-down', + }); } } @@ -117,16 +128,6 @@ export default class ClientUpgrade extends PureComponent { }); }; - onNavigatorEvent = (event) => { - if (event.type === 'NavBarButtonPress') { - if (event.id === 'close-upgrade') { - this.props.navigator.dismissModal({ - animationType: 'slide-down', - }); - } - } - }; - renderMustUpgrade() { const {theme} = this.props; const styles = getStyleFromTheme(theme); diff --git a/app/screens/code/code.js b/app/screens/code/code.js index 414933cd8..831538c8a 100644 --- a/app/screens/code/code.js +++ b/app/screens/code/code.js @@ -18,6 +18,7 @@ import {changeOpacity, makeStyleSheetFromTheme, setNavigatorStyles} from 'app/ut export default class Code extends React.PureComponent { static propTypes = { + componentId: PropTypes.string, navigator: PropTypes.object.isRequired, theme: PropTypes.object.isRequired, content: PropTypes.string.isRequired, @@ -29,7 +30,7 @@ export default class Code extends React.PureComponent { componentWillReceiveProps(nextProps) { if (this.props.theme !== nextProps.theme) { - setNavigatorStyles(this.props.navigator, nextProps.theme); + setNavigatorStyles(this.props.componentId, nextProps.theme); } } diff --git a/app/screens/create_channel/create_channel.js b/app/screens/create_channel/create_channel.js index 14cc18317..18c379e73 100644 --- a/app/screens/create_channel/create_channel.js +++ b/app/screens/create_channel/create_channel.js @@ -8,6 +8,7 @@ import { Keyboard, InteractionManager, } from 'react-native'; +import {Navigation} from 'react-native-navigation'; import {General, RequestStatus} from 'mattermost-redux/constants'; import EventEmitter from 'mattermost-redux/utils/event_emitter'; @@ -17,6 +18,7 @@ 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, @@ -72,17 +74,17 @@ export default class CreateChannel extends PureComponent { buttons.leftButtons = [this.left]; } - props.navigator.setOnNavigatorEvent(this.onNavigatorEvent); props.navigator.setButtons(buttons); } componentDidMount() { + this.navigationEventListener = Navigation.events().bindComponent(this); this.emitCanCreateChannel(false); } componentWillReceiveProps(nextProps) { if (this.props.theme !== nextProps.theme) { - setNavigatorStyles(this.props.navigator, nextProps.theme); + setNavigatorStyles(this.props.componentId, nextProps.theme); } const {createChannelRequest} = nextProps; @@ -109,6 +111,17 @@ export default class CreateChannel extends PureComponent { } } + navigationButtonPressed({buttonId}) { + switch (buttonId) { + case 'close-new-channel': + this.close(!this.props.closeButton); + break; + case 'create-channel': + this.onCreateChannel(); + break; + } + } + close = (goBack = false) => { if (goBack) { this.props.navigator.pop({animated: true}); @@ -149,19 +162,6 @@ export default class CreateChannel extends PureComponent { this.props.actions.handleCreateChannel(displayName, purpose, header, this.props.channelType); }; - onNavigatorEvent = (event) => { - if (event.type === 'NavBarButtonPress') { - switch (event.id) { - case 'close-new-channel': - this.close(!this.props.closeButton); - break; - case 'create-channel': - this.onCreateChannel(); - break; - } - } - }; - onDisplayNameChange = (displayName) => { this.setState({displayName}); }; diff --git a/app/screens/edit_channel/edit_channel.js b/app/screens/edit_channel/edit_channel.js index b992de2dc..137324c5a 100644 --- a/app/screens/edit_channel/edit_channel.js +++ b/app/screens/edit_channel/edit_channel.js @@ -8,6 +8,7 @@ import { Keyboard, InteractionManager, } from 'react-native'; +import {Navigation} from 'react-native-navigation'; import {General, RequestStatus} from 'mattermost-redux/constants'; import EventEmitter from 'mattermost-redux/utils/event_emitter'; @@ -56,6 +57,7 @@ export default class EditChannel extends PureComponent { getChannel: PropTypes.func.isRequired, setChannelDisplayName: PropTypes.func.isRequired, }), + componentId: PropTypes.string, navigator: PropTypes.object.isRequired, theme: PropTypes.object.isRequired, deviceWidth: PropTypes.number.isRequired, @@ -102,17 +104,18 @@ export default class EditChannel extends PureComponent { rightButtons: [this.rightButton], }; - props.navigator.setOnNavigatorEvent(this.onNavigatorEvent); props.navigator.setButtons(buttons); } componentDidMount() { + this.navigationEventListener = Navigation.events().bindComponent(this); + this.emitCanUpdateChannel(false); } componentWillReceiveProps(nextProps) { if (this.props.theme !== nextProps.theme) { - setNavigatorStyles(this.props.navigator, nextProps.theme); + setNavigatorStyles(this.props.componentId, nextProps.theme); } const {updateChannelRequest} = nextProps; @@ -139,6 +142,17 @@ export default class EditChannel extends PureComponent { } } + navigationButtonPressed({buttonId}) { + switch (buttonId) { + case 'close-edit-channel': + this.close(); + break; + case 'edit-channel': + this.onUpdateChannel(); + break; + } + } + close = () => { const {channel: {type}} = this.props; const isDirect = type === General.DM_CHANNEL || type === General.GM_CHANNEL; @@ -238,19 +252,6 @@ export default class EditChannel extends PureComponent { } }; - onNavigatorEvent = (event) => { - if (event.type === 'NavBarButtonPress') { - switch (event.id) { - case 'close-edit-channel': - this.close(); - break; - case 'edit-channel': - this.onUpdateChannel(); - break; - } - } - }; - onDisplayNameChange = (displayName) => { this.setState({displayName}); }; diff --git a/app/screens/edit_post/edit_post.js b/app/screens/edit_post/edit_post.js index eb053d287..8a7af8838 100644 --- a/app/screens/edit_post/edit_post.js +++ b/app/screens/edit_post/edit_post.js @@ -7,6 +7,7 @@ import { Platform, View, } from 'react-native'; +import {Navigation} from 'react-native-navigation'; import ErrorText from 'app/components/error_text'; import Loading from 'app/components/loading'; @@ -22,6 +23,7 @@ export default class EditPost extends PureComponent { actions: PropTypes.shape({ editPost: PropTypes.func.isRequired, }), + componentId: PropTypes.string, closeButton: PropTypes.object, deviceHeight: PropTypes.number, deviceWidth: PropTypes.number, @@ -50,7 +52,6 @@ export default class EditPost extends PureComponent { this.state = {message: props.post.message}; this.rightButton.title = context.intl.formatMessage({id: 'edit_post.save', defaultMessage: 'Save'}); - props.navigator.setOnNavigatorEvent(this.onNavigatorEvent); props.navigator.setButtons({ leftButtons: [{...this.leftButton, icon: props.closeButton}], rightButtons: [this.rightButton], @@ -58,12 +59,14 @@ export default class EditPost extends PureComponent { } componentDidMount() { + this.navigationEventListener = Navigation.events().bindComponent(this); + this.focus(); } componentWillReceiveProps(nextProps) { if (this.props.theme !== nextProps.theme) { - setNavigatorStyles(this.props.navigator, nextProps.theme); + setNavigatorStyles(this.props.componentId, nextProps.theme); } const {editPostRequest} = nextProps; @@ -87,6 +90,17 @@ export default class EditPost extends PureComponent { } } + navigationButtonPressed({buttonId}) { + switch (buttonId) { + case 'close-edit-post': + this.close(); + break; + case 'edit-post': + this.onEditPost(); + break; + } + } + close = () => { this.props.navigator.dismissModal({ animationType: 'slide-down', @@ -121,19 +135,6 @@ export default class EditPost extends PureComponent { this.props.actions.editPost(post); }; - onNavigatorEvent = (event) => { - if (event.type === 'NavBarButtonPress') { - switch (event.id) { - case 'close-edit-post': - this.close(); - break; - case 'edit-post': - this.onEditPost(); - break; - } - } - }; - onPostChangeText = (message) => { this.setState({message}); if (message) { diff --git a/app/screens/edit_profile/__snapshots__/edit_profile.test.js.snap b/app/screens/edit_profile/__snapshots__/edit_profile.test.js.snap index d97a63400..9c8aa9c0e 100644 --- a/app/screens/edit_profile/__snapshots__/edit_profile.test.js.snap +++ b/app/screens/edit_profile/__snapshots__/edit_profile.test.js.snap @@ -52,19 +52,6 @@ exports[`edit_profile should match snapshot 1`] = ` }, ], }, - "setOnNavigatorEvent": [MockFunction] { - "calls": Array [ - Array [ - [Function], - ], - ], - "results": Array [ - Object { - "type": "return", - "value": undefined, - }, - ], - }, } } onShowFileSizeWarning={[Function]} diff --git a/app/screens/edit_profile/edit_profile.js b/app/screens/edit_profile/edit_profile.js index 0f6927ef5..bfae5a109 100644 --- a/app/screens/edit_profile/edit_profile.js +++ b/app/screens/edit_profile/edit_profile.js @@ -8,6 +8,7 @@ import {Alert, View} from 'react-native'; import RNFetchBlob from 'rn-fetch-blob'; import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view'; import {DocumentPickerUtil} from 'react-native-document-picker'; +import {Navigation} from 'react-native-navigation'; import {Client4} from 'mattermost-redux/client'; @@ -114,7 +115,6 @@ export default class EditProfile extends PureComponent { }; this.rightButton.title = context.intl.formatMessage({id: t('mobile.account.settings.save'), defaultMessage: 'Save'}); - props.navigator.setOnNavigatorEvent(this.onNavigatorEvent); props.navigator.setButtons(buttons); this.state = { @@ -127,6 +127,21 @@ export default class EditProfile extends PureComponent { }; } + componentDidMount() { + this.navigationEventListener = Navigation.events().bindComponent(this); + } + + navigationButtonPressed({buttonId}) { + switch (buttonId) { + case 'update-profile': + this.submitUser(); + break; + case 'close-settings': + this.close(); + break; + } + } + canUpdate = (updatedField) => { const {currentUser} = this.props; const keys = Object.keys(this.state); @@ -276,19 +291,6 @@ export default class EditProfile extends PureComponent { }); }; - onNavigatorEvent = (event) => { - if (event.type === 'NavBarButtonPress') { - switch (event.id) { - case 'update-profile': - this.submitUser(); - break; - case 'close-settings': - this.close(); - break; - } - } - }; - onShowFileSizeWarning = (filename) => { const {formatMessage} = this.context.intl; const fileSizeWarning = formatMessage({ diff --git a/app/screens/edit_profile/edit_profile.test.js b/app/screens/edit_profile/edit_profile.test.js index 69682f745..c2b2fe3fc 100644 --- a/app/screens/edit_profile/edit_profile.test.js +++ b/app/screens/edit_profile/edit_profile.test.js @@ -18,7 +18,6 @@ jest.mock('app/utils/theme', () => { describe('edit_profile', () => { const navigator = { - setOnNavigatorEvent: jest.fn(), setButtons: jest.fn(), dismissModal: jest.fn(), push: jest.fn(), @@ -46,6 +45,7 @@ describe('edit_profile', () => { position: 'position', }, commandType: 'ShowModal', + componentId: 'component-id', }; test('should match snapshot', async () => { @@ -59,7 +59,6 @@ describe('edit_profile', () => { test('should match state on handleRemoveProfileImage', () => { const newNavigator = { dismissModal: jest.fn(), - setOnNavigatorEvent: jest.fn(), setButtons: jest.fn(), }; const wrapper = shallow( diff --git a/app/screens/error_teams_list/error_teams_list.js b/app/screens/error_teams_list/error_teams_list.js index 7d303751b..a795920c8 100644 --- a/app/screens/error_teams_list/error_teams_list.js +++ b/app/screens/error_teams_list/error_teams_list.js @@ -7,6 +7,7 @@ import { InteractionManager, View, } from 'react-native'; +import {Navigation} from 'react-native-navigation'; import FailedNetworkAction from 'app/components/failed_network_action'; import Loading from 'app/components/loading'; @@ -32,22 +33,33 @@ export default class ErrorTeamsList extends PureComponent { logout: PropTypes.func.isRequired, selectDefaultTeam: PropTypes.func.isRequired, }).isRequired, + componentId: PropTypes.string, navigator: PropTypes.object, theme: PropTypes.object, }; constructor(props) { super(props); - props.navigator.setOnNavigatorEvent(this.onNavigatorEvent); this.state = { loading: false, }; } + componentDidMount() { + this.navigationEventListener = Navigation.events().bindComponent(this); + } + componentWillReceiveProps(nextProps) { if (this.props.theme !== nextProps.theme) { - setNavigatorStyles(this.props.navigator, nextProps.theme); + setNavigatorStyles(this.props.componentId, nextProps.theme); + } + } + + navigationButtonPressed({buttonId}) { + const {logout} = this.props.actions; + if (buttonId === 'logout') { + InteractionManager.runAfterInteractions(logout); } } @@ -83,15 +95,6 @@ export default class ErrorTeamsList extends PureComponent { } } - onNavigatorEvent = (event) => { - if (event.type === 'NavBarButtonPress') { - const {logout} = this.props.actions; - if (event.id === 'logout') { - InteractionManager.runAfterInteractions(logout); - } - } - }; - render() { const {theme} = this.props; const styles = getStyleSheet(theme); diff --git a/app/screens/error_teams_list/error_teams_list.test.js b/app/screens/error_teams_list/error_teams_list.test.js index dcf9af079..1a8c053dc 100644 --- a/app/screens/error_teams_list/error_teams_list.test.js +++ b/app/screens/error_teams_list/error_teams_list.test.js @@ -10,10 +10,6 @@ import FailedNetworkAction from 'app/components/failed_network_action'; import ErrorTeamsList from './error_teams_list'; describe('ErrorTeamsList', () => { - const navigator = { - setOnNavigatorEvent: () => {}, // eslint-disable-line no-empty-function - }; - const loadMe = async () => { return { data: {}, @@ -27,8 +23,8 @@ describe('ErrorTeamsList', () => { logout: () => {}, // eslint-disable-line no-empty-function selectDefaultTeam: () => {}, // eslint-disable-line no-empty-function }, + componentId: 'component-id', theme: Preferences.THEMES.default, - navigator, }; test('should match snapshot', () => { diff --git a/app/screens/flagged_posts/flagged_posts.js b/app/screens/flagged_posts/flagged_posts.js index c12964ed8..ca5b27681 100644 --- a/app/screens/flagged_posts/flagged_posts.js +++ b/app/screens/flagged_posts/flagged_posts.js @@ -11,6 +11,7 @@ import { SafeAreaView, View, } from 'react-native'; +import {Navigation} from 'react-native-navigation'; import {isDateLine, getDateForDateLine} from 'mattermost-redux/utils/post_list'; @@ -54,11 +55,22 @@ export default class FlaggedPosts extends PureComponent { constructor(props) { super(props); - props.navigator.setOnNavigatorEvent(this.onNavigatorEvent); props.actions.clearSearch(); props.actions.getFlaggedPosts(); } + componentDidMount() { + this.navigationEventListener = Navigation.events().bindComponent(this); + } + + navigationButtonPressed({buttonId}) { + if (buttonId === 'close-settings') { + this.props.navigator.dismissModal({ + animationType: 'slide-down', + }); + } + } + goToThread = (post) => { const {actions, navigator, theme} = this.props; const channelId = post.channel_id; @@ -108,16 +120,6 @@ export default class FlaggedPosts extends PureComponent { keyExtractor = (item) => item; - onNavigatorEvent = (event) => { - if (event.type === 'NavBarButtonPress') { - if (event.id === 'close-settings') { - this.props.navigator.dismissModal({ - animationType: 'slide-down', - }); - } - } - }; - previewPost = (post) => { Keyboard.dismiss(); diff --git a/app/screens/interactive_dialog/interactive_dialog.js b/app/screens/interactive_dialog/interactive_dialog.js index 8f181a89d..eda0cf7ca 100644 --- a/app/screens/interactive_dialog/interactive_dialog.js +++ b/app/screens/interactive_dialog/interactive_dialog.js @@ -4,6 +4,7 @@ import React, {PureComponent} from 'react'; import PropTypes from 'prop-types'; import {ScrollView, View} from 'react-native'; +import {Navigation} from 'react-native-navigation'; import {checkDialogElementForError, checkIfErrorsMatchElements} from 'mattermost-redux/utils/integration_utils'; @@ -16,6 +17,7 @@ import DialogElement from './dialog_element.js'; export default class InteractiveDialog extends PureComponent { static propTypes = { + componentId: PropTypes.string, url: PropTypes.string.isRequired, callbackId: PropTypes.string, elements: PropTypes.arrayOf(PropTypes.object).isRequired, @@ -36,8 +38,6 @@ export default class InteractiveDialog extends PureComponent { constructor(props) { super(props); - props.navigator.setOnNavigatorEvent(this.onNavigatorEvent); - const values = {}; props.elements.forEach((e) => { values[e.name] = e.default || null; @@ -50,19 +50,21 @@ export default class InteractiveDialog extends PureComponent { }; } - onNavigatorEvent = (event) => { - if (event.type === 'NavBarButtonPress') { - switch (event.id) { - case 'submit-dialog': - this.handleSubmit(); - break; - case 'close-dialog': - this.notifyOnCancelIfNeeded(); - this.handleHide(); - break; - } + componentDidMount() { + this.navigationEventListener = Navigation.events().bindComponent(this); + } + + navigationButtonPressed({buttonId}) { + switch (buttonId) { + case 'submit-dialog': + this.handleSubmit(); + break; + case 'close-dialog': + this.notifyOnCancelIfNeeded(); + this.handleHide(); + break; } - }; + } handleSubmit = async () => { const {elements} = this.props; diff --git a/app/screens/interactive_dialog/interactive_dialog.test.js b/app/screens/interactive_dialog/interactive_dialog.test.js index 7f36358bb..4219edf33 100644 --- a/app/screens/interactive_dialog/interactive_dialog.test.js +++ b/app/screens/interactive_dialog/interactive_dialog.test.js @@ -21,9 +21,9 @@ describe('InteractiveDialog', () => { submitInteractiveDialog: jest.fn(), }, navigator: { - setOnNavigatorEvent: jest.fn(), dismissModal: jest.fn(), }, + componentId: 'component-id', }; test('should set default values', async () => { @@ -74,7 +74,7 @@ describe('InteractiveDialog', () => { cancelled: true, }; - wrapper.instance().onNavigatorEvent({type: 'NavBarButtonPress', id: 'close-dialog'}); + wrapper.instance().navigationButtonPressed({buttonId: 'close-dialog'}); expect(submitInteractiveDialog).toHaveBeenCalledTimes(1); expect(submitInteractiveDialog).toHaveBeenCalledWith(dialog); }); @@ -89,7 +89,7 @@ describe('InteractiveDialog', () => { />, ); - wrapper.instance().onNavigatorEvent({type: 'NavBarButtonPress', id: 'close-dialog'}); + wrapper.instance().navigationButtonPressed({buttonId: 'close-dialog'}); expect(submitInteractiveDialog).not.toHaveBeenCalled(); }); }); diff --git a/app/screens/long_post/long_post.js b/app/screens/long_post/long_post.js index c28f86fd1..554227e67 100644 --- a/app/screens/long_post/long_post.js +++ b/app/screens/long_post/long_post.js @@ -11,6 +11,7 @@ import { import {intlShape} from 'react-intl'; import * as Animatable from 'react-native-animatable'; import MaterialIcon from 'react-native-vector-icons/MaterialIcons'; +import {Navigation} from 'react-native-navigation'; import FileAttachmentList from 'app/components/file_attachment_list'; import FormattedText from 'app/components/formatted_text'; @@ -65,10 +66,14 @@ export default class LongPost extends PureComponent { intl: intlShape.isRequired, }; - constructor(props) { - super(props); + componentDidMount() { + this.navigationEventListener = Navigation.events().bindComponent(this); + } - props.navigator.setOnNavigatorEvent(this.onNavigatorEvent); + navigationButtonPressed({buttonId}) { + if (buttonId === 'backPress') { + this.handleClose(); + } } goToThread = preventDoubleTap((post) => { @@ -117,16 +122,6 @@ export default class LongPost extends PureComponent { } }; - onNavigatorEvent = (event) => { - switch (event.id) { - case 'backPress': - this.handleClose(); - break; - default: - break; - } - }; - renderFileAttachments(style) { const { fileIds, diff --git a/app/screens/more_channels/more_channels.js b/app/screens/more_channels/more_channels.js index 1d9a79a1f..0330b8c59 100644 --- a/app/screens/more_channels/more_channels.js +++ b/app/screens/more_channels/more_channels.js @@ -5,6 +5,7 @@ import React, {PureComponent} from 'react'; import PropTypes from 'prop-types'; import {intlShape} from 'react-intl'; import {Platform, View} from 'react-native'; +import {Navigation} from 'react-native-navigation'; import {debounce} from 'mattermost-redux/actions/helpers'; import {General} from 'mattermost-redux/constants'; @@ -29,6 +30,7 @@ export default class MoreChannels extends PureComponent { searchChannels: PropTypes.func.isRequired, setChannelDisplayName: PropTypes.func.isRequired, }).isRequired, + componentId: PropTypes.string, canCreateChannels: PropTypes.bool.isRequired, channels: PropTypes.array, closeButton: PropTypes.object, @@ -79,11 +81,12 @@ export default class MoreChannels extends PureComponent { buttons.rightButtons = [this.rightButton]; } - props.navigator.setOnNavigatorEvent(this.onNavigatorEvent); props.navigator.setButtons(buttons); } componentDidMount() { + this.navigationEventListener = Navigation.events().bindComponent(this); + this.doGetChannels(); } @@ -92,7 +95,7 @@ export default class MoreChannels extends PureComponent { let channels; if (this.props.theme !== nextProps.theme) { - setNavigatorStyles(this.props.navigator, nextProps.theme); + setNavigatorStyles(this.props.componentId, nextProps.theme); } if (nextProps.channels !== this.props.channels) { @@ -107,6 +110,17 @@ export default class MoreChannels extends PureComponent { } } + navigationButtonPressed({buttonId}) { + switch (buttonId) { + case 'close-more-channels': + this.close(); + break; + case 'create-pub-channel': + this.onCreateChannel(); + break; + } + } + cancelSearch = () => { const {channels} = this.props; @@ -166,19 +180,6 @@ export default class MoreChannels extends PureComponent { this.setState({loading: false}); }; - onNavigatorEvent = (event) => { - if (event.type === 'NavBarButtonPress') { - switch (event.id) { - case 'close-more-channels': - this.close(); - break; - case 'create-pub-channel': - this.onCreateChannel(); - break; - } - } - }; - onSelectChannel = async (id) => { const {intl} = this.context; const {actions, currentTeamId, currentUserId} = this.props; diff --git a/app/screens/more_channels/more_channels.test.js b/app/screens/more_channels/more_channels.test.js index 51787ffcc..32eaee752 100644 --- a/app/screens/more_channels/more_channels.test.js +++ b/app/screens/more_channels/more_channels.test.js @@ -12,7 +12,6 @@ jest.mock('react-intl'); describe('MoreChannels', () => { const navigator = { - setOnNavigatorEvent: jest.fn(), setButtons: jest.fn(), dismissModal: jest.fn(), push: jest.fn(), @@ -35,6 +34,7 @@ describe('MoreChannels', () => { currentTeamId: 'current_team_id', navigator, theme: Preferences.THEMES.default, + componentId: 'component-id', }; test('should match snapshot', () => { diff --git a/app/screens/more_dms/more_dms.js b/app/screens/more_dms/more_dms.js index f16f5e99a..1af96f318 100644 --- a/app/screens/more_dms/more_dms.js +++ b/app/screens/more_dms/more_dms.js @@ -5,6 +5,7 @@ import React, {PureComponent} from 'react'; import PropTypes from 'prop-types'; import {intlShape} from 'react-intl'; import {Platform, View} from 'react-native'; +import {Navigation} from 'react-native-navigation'; import {debounce} from 'mattermost-redux/actions/helpers'; import {General} from 'mattermost-redux/constants'; @@ -39,6 +40,7 @@ export default class MoreDirectMessages extends PureComponent { searchProfiles: PropTypes.func.isRequired, setChannelDisplayName: PropTypes.func.isRequired, }).isRequired, + componentId: PropTypes.string, allProfiles: PropTypes.object.isRequired, currentDisplayName: PropTypes.string, currentTeamId: PropTypes.string.isRequired, @@ -70,23 +72,32 @@ export default class MoreDirectMessages extends PureComponent { selectedCount: 0, }; - props.navigator.setOnNavigatorEvent(this.onNavigatorEvent); this.updateNavigationButtons(false, context); } componentDidMount() { + this.navigationEventListener = Navigation.events().bindComponent(this); + this.getProfiles(); } componentDidUpdate(prevProps) { - const {navigator, theme} = this.props; + const {componentId, theme} = this.props; const {selectedCount, startingConversation} = this.state; const canStart = selectedCount > 0 && !startingConversation; this.updateNavigationButtons(canStart); if (theme !== prevProps.theme) { - setNavigatorStyles(navigator, theme); + setNavigatorStyles(componentId, theme); + } + } + + navigationButtonPressed({buttonId}) { + if (buttonId === START_BUTTON) { + this.startConversation(); + } else if (buttonId === CLOSE_BUTTON) { + this.close(); } } @@ -235,16 +246,6 @@ export default class MoreDirectMessages extends PureComponent { return !result.error; }; - onNavigatorEvent = (event) => { - if (event.type === 'NavBarButtonPress') { - if (event.id === START_BUTTON) { - this.startConversation(); - } else if (event.id === CLOSE_BUTTON) { - this.close(); - } - } - }; - onSearch = (text) => { if (text) { this.setState({term: text}); diff --git a/app/screens/permalink/permalink.js b/app/screens/permalink/permalink.js index 81f3f2763..38b688174 100644 --- a/app/screens/permalink/permalink.js +++ b/app/screens/permalink/permalink.js @@ -13,6 +13,7 @@ import {intlShape} from 'react-intl'; import * as Animatable from 'react-native-animatable'; import MaterialIcon from 'react-native-vector-icons/MaterialIcons'; import AwesomeIcon from 'react-native-vector-icons/FontAwesome'; +import {Navigation} from 'react-native-navigation'; import {General} from 'mattermost-redux/constants'; import EventEmitter from 'mattermost-redux/utils/event_emitter'; @@ -57,6 +58,7 @@ export default class Permalink extends PureComponent { setChannelDisplayName: PropTypes.func.isRequired, setChannelLoading: PropTypes.func.isRequired, }).isRequired, + componentId: PropTypes.string, channelId: PropTypes.string, channelIsArchived: PropTypes.bool, channelName: PropTypes.string, @@ -131,8 +133,6 @@ export default class Permalink extends PureComponent { loading = false; } - props.navigator.setOnNavigatorEvent(this.onNavigatorEvent); - this.state = { title: channelName, loading, @@ -146,6 +146,8 @@ export default class Permalink extends PureComponent { } componentDidMount() { + this.navigationEventListener = Navigation.events().bindComponent(this); + this.mounted = true; if (this.state.loading) { @@ -163,6 +165,12 @@ export default class Permalink extends PureComponent { this.mounted = false; } + navigationButtonPressed({buttonId}) { + if (buttonId === 'backPress') { + this.handleClose(); + } + } + goToThread = preventDoubleTap((post) => { const {actions, navigator, theme} = this.props; const channelId = post.channel_id; @@ -315,16 +323,6 @@ export default class Permalink extends PureComponent { } }; - onNavigatorEvent = (event) => { - switch (event.id) { - case 'backPress': - this.handleClose(); - break; - default: - break; - } - }; - retry = () => { if (this.mounted) { this.setState({loading: true, error: null, retry: false}); diff --git a/app/screens/permalink/permalink.test.js b/app/screens/permalink/permalink.test.js index e639645c6..5cc33b09c 100644 --- a/app/screens/permalink/permalink.test.js +++ b/app/screens/permalink/permalink.test.js @@ -16,7 +16,6 @@ describe('Permalink', () => { dismissModal: jest.fn(), push: jest.fn(), resetTo: jest.fn(), - setOnNavigatorEvent: jest.fn(), }; const actions = { @@ -48,6 +47,7 @@ describe('Permalink', () => { onPress: jest.fn(), postIds: ['post_id_1', 'focused_post_id', 'post_id_3'], theme: Preferences.THEMES.default, + componentId: 'component-id', }; test('should match snapshot', () => { @@ -82,7 +82,7 @@ describe('Permalink', () => { ); wrapper.instance().handleClose = jest.fn(); - wrapper.instance().onNavigatorEvent({id: 'backPress'}); + wrapper.instance().navigationButtonPressed({buttonId: 'backPress'}); expect(wrapper.instance().handleClose).toHaveBeenCalledTimes(1); }); diff --git a/app/screens/pinned_posts/pinned_posts.js b/app/screens/pinned_posts/pinned_posts.js index 121235508..899331ebb 100644 --- a/app/screens/pinned_posts/pinned_posts.js +++ b/app/screens/pinned_posts/pinned_posts.js @@ -11,6 +11,7 @@ import { SafeAreaView, View, } from 'react-native'; +import {Navigation} from 'react-native-navigation'; import {isDateLine, getDateForDateLine} from 'mattermost-redux/utils/post_list'; @@ -27,6 +28,7 @@ import noResultsImage from 'assets/images/no_results/pin.png'; export default class PinnedPosts extends PureComponent { static propTypes = { + componentId: PropTypes.string, actions: PropTypes.shape({ clearSearch: PropTypes.func.isRequired, loadChannelsByTeamName: PropTypes.func.isRequired, @@ -52,18 +54,22 @@ export default class PinnedPosts extends PureComponent { intl: intlShape.isRequired, }; - constructor(props) { - super(props); - - props.navigator.setOnNavigatorEvent(this.onNavigatorEvent); - } - componentDidMount() { + this.navigationEventListener = Navigation.events().bindComponent(this); + const {actions, currentChannelId} = this.props; actions.clearSearch(); actions.getPinnedPosts(currentChannelId); } + navigationButtonPressed({buttonId}) { + if (buttonId === 'close-settings') { + this.props.navigator.dismissModal({ + animationType: 'slide-down', + }); + } + } + goToThread = (post) => { const {actions, navigator, theme} = this.props; const channelId = post.channel_id; @@ -113,16 +119,6 @@ export default class PinnedPosts extends PureComponent { keyExtractor = (item) => item; - onNavigatorEvent = (event) => { - if (event.type === 'NavBarButtonPress') { - if (event.id === 'close-settings') { - this.props.navigator.dismissModal({ - animationType: 'slide-down', - }); - } - } - }; - previewPost = (post) => { Keyboard.dismiss(); diff --git a/app/screens/reaction_list/__snapshots__/reaction_list.test.js.snap b/app/screens/reaction_list/__snapshots__/reaction_list.test.js.snap index 60ce984e2..bb73b1098 100644 --- a/app/screens/reaction_list/__snapshots__/reaction_list.test.js.snap +++ b/app/screens/reaction_list/__snapshots__/reaction_list.test.js.snap @@ -24,23 +24,6 @@ exports[`ReactionList should match snapshot 1`] = ` > { - if (event.type === 'NavBarButtonPress') { - if (event.id === 'close-reaction-list') { - this.close(); - } + navigationButtonPressed({buttonId}) { + if (buttonId === 'close-reaction-list') { + this.close(); } - }; + } close = () => { this.props.navigator.dismissModal({ diff --git a/app/screens/reaction_list/reaction_list.test.js b/app/screens/reaction_list/reaction_list.test.js index 8f1eba9ae..a1fbdb093 100644 --- a/app/screens/reaction_list/reaction_list.test.js +++ b/app/screens/reaction_list/reaction_list.test.js @@ -17,11 +17,11 @@ describe('ReactionList', () => { getMissingProfilesByIds: jest.fn(), }, allUserIds: ['user_id_1', 'user_id_2'], - navigator: {setOnNavigatorEvent: jest.fn()}, reactions: {'user_id_1-smile': {emoji_name: 'smile', user_id: 'user_id_1'}, 'user_id_2-+1': {emoji_name: '+1', user_id: 'user_id_2'}}, theme: Preferences.THEMES.default, teammateNameDisplay: 'username', userProfiles: [{id: 'user_id_1', username: 'username_1'}, {id: 'user_id_2', username: 'username_2'}], + componentId: 'component-id', }; test('should match snapshot', () => { diff --git a/app/screens/recent_mentions/recent_mentions.js b/app/screens/recent_mentions/recent_mentions.js index 2bcef54d1..e836194d9 100644 --- a/app/screens/recent_mentions/recent_mentions.js +++ b/app/screens/recent_mentions/recent_mentions.js @@ -11,6 +11,7 @@ import { StyleSheet, View, } from 'react-native'; +import {Navigation} from 'react-native-navigation'; import {isDateLine, getDateForDateLine} from 'mattermost-redux/utils/post_list'; @@ -54,11 +55,14 @@ export default class RecentMentions extends PureComponent { constructor(props) { super(props); - props.navigator.setOnNavigatorEvent(this.onNavigatorEvent); props.actions.clearSearch(); props.actions.getRecentMentions(); } + componentDidMount() { + this.navigationEventListener = Navigation.events().bindComponent(this); + } + goToThread = (post) => { const {actions, navigator, theme} = this.props; const channelId = post.channel_id; @@ -108,15 +112,13 @@ export default class RecentMentions extends PureComponent { keyExtractor = (item) => item; - onNavigatorEvent = (event) => { - if (event.type === 'NavBarButtonPress') { - if (event.id === 'close-settings') { - this.props.navigator.dismissModal({ - animationType: 'slide-down', - }); - } + navigationButtonPressed({buttonId}) { + if (buttonId === 'close-settings') { + this.props.navigator.dismissModal({ + animationType: 'slide-down', + }); } - }; + } previewPost = (post) => { Keyboard.dismiss(); diff --git a/app/screens/search/search.js b/app/screens/search/search.js index 9e98ddd73..23ef8a56b 100644 --- a/app/screens/search/search.js +++ b/app/screens/search/search.js @@ -12,6 +12,7 @@ import { View, } from 'react-native'; import AwesomeIcon from 'react-native-vector-icons/FontAwesome'; +import {Navigation} from 'react-native-navigation'; import {debounce} from 'mattermost-redux/actions/helpers'; import {RequestStatus} from 'mattermost-redux/constants'; @@ -85,8 +86,6 @@ export default class Search extends PureComponent { constructor(props) { super(props); - props.navigator.setOnNavigatorEvent(this.onNavigatorEvent); - this.contentOffsetY = 0; this.state = { channelName: '', @@ -97,6 +96,8 @@ export default class Search extends PureComponent { } componentDidMount() { + this.navigationEventListener = Navigation.events().bindComponent(this); + if (this.props.initialValue) { this.search(this.props.initialValue); } @@ -140,6 +141,16 @@ export default class Search extends PureComponent { } } + navigationButtonPressed({buttonId}) { + if (buttonId === 'backPress') { + if (this.state.preview) { + this.refs.preview.handleClose(); + } else { + this.props.navigator.dismissModal(); + } + } + } + archivedIndicator = (postID, style) => { const channelIsArchived = this.props.archivedPostIds.includes(postID); let archivedIndicator = null; @@ -298,16 +309,6 @@ export default class Search extends PureComponent { } }, 100); - onNavigatorEvent = (event) => { - if (event.id === 'backPress') { - if (this.state.preview) { - this.refs.preview.handleClose(); - } else { - this.props.navigator.dismissModal(); - } - } - }; - previewPost = (post) => { Keyboard.dismiss(); diff --git a/app/screens/select_server/select_server.js b/app/screens/select_server/select_server.js index 6dc4cfc02..91e9458e1 100644 --- a/app/screens/select_server/select_server.js +++ b/app/screens/select_server/select_server.js @@ -84,6 +84,8 @@ export default class SelectServer extends PureComponent { } componentDidMount() { + this.navigationEventListener = Navigation.events().bindComponent(this); + const {allowOtherServers, serverUrl} = this.props; if (!allowOtherServers && serverUrl) { // If the app is managed or AutoSelectServerUrl is true in the Config, the server url is set and the user can't change it diff --git a/app/screens/select_team/select_team.js b/app/screens/select_team/select_team.js index d6d9971b8..54661ee00 100644 --- a/app/screens/select_team/select_team.js +++ b/app/screens/select_team/select_team.js @@ -10,6 +10,7 @@ import { TouchableOpacity, View, } from 'react-native'; +import {Navigation} from 'react-native-navigation'; import {RequestStatus} from 'mattermost-redux/constants'; import EventEmitter from 'mattermost-redux/utils/event_emitter'; @@ -45,6 +46,7 @@ export default class SelectTeam extends PureComponent { joinTeam: PropTypes.func.isRequired, logout: PropTypes.func.isRequired, }).isRequired, + componentId: PropTypes.string, currentUrl: PropTypes.string.isRequired, navigator: PropTypes.object, userWithoutTeams: PropTypes.bool, @@ -59,7 +61,6 @@ export default class SelectTeam extends PureComponent { constructor(props) { super(props); - props.navigator.setOnNavigatorEvent(this.onNavigatorEvent); this.state = { loading: false, @@ -71,12 +72,14 @@ export default class SelectTeam extends PureComponent { } componentDidMount() { + this.navigationEventListener = Navigation.events().bindComponent(this); + this.getTeams(); } componentWillReceiveProps(nextProps) { if (this.props.theme !== nextProps.theme) { - setNavigatorStyles(this.props.navigator, nextProps.theme); + setNavigatorStyles(this.props.componentId, nextProps.theme); } if (this.props.teams !== nextProps.teams) { @@ -84,6 +87,19 @@ export default class SelectTeam extends PureComponent { } } + navigationButtonPressed({buttonId}) { + const {logout} = this.props.actions; + + switch (buttonId) { + case 'close-teams': + this.close(); + break; + case 'logout': + InteractionManager.runAfterInteractions(logout); + break; + } + } + getTeams = () => { this.setState({loading: true}); this.props.actions.getTeams(this.state.page, TEAMS_PER_PAGE).then(() => { @@ -131,21 +147,6 @@ export default class SelectTeam extends PureComponent { }); }; - onNavigatorEvent = (event) => { - if (event.type === 'NavBarButtonPress') { - const {logout} = this.props.actions; - - switch (event.id) { - case 'close-teams': - this.close(); - break; - case 'logout': - InteractionManager.runAfterInteractions(logout); - break; - } - } - }; - onSelectTeam = async (team) => { this.setState({joining: true}); const {userWithoutTeams} = this.props; diff --git a/app/screens/select_team/select_team.test.js b/app/screens/select_team/select_team.test.js index c722e2f20..19e3d6440 100644 --- a/app/screens/select_team/select_team.test.js +++ b/app/screens/select_team/select_team.test.js @@ -35,15 +35,13 @@ describe('SelectTeam', () => { actions, currentChannelId: 'someId', currentUrl: 'test', - navigator: { - setOnNavigatorEvent: jest.fn(), - }, userWithoutTeams: false, teams: [], theme: Preferences.THEMES.default, teamsRequest: { status: RequestStatus.FAILURE, }, + componentId: 'component-id', }; test('should match snapshot for fail of teams', async () => { diff --git a/app/screens/selector_screen/selector_screen.js b/app/screens/selector_screen/selector_screen.js index 39037bab2..2694641e7 100644 --- a/app/screens/selector_screen/selector_screen.js +++ b/app/screens/selector_screen/selector_screen.js @@ -35,6 +35,7 @@ export default class SelectorScreen extends PureComponent { searchProfiles: PropTypes.func.isRequired, searchChannels: PropTypes.func.isRequired, }), + componentId: PropTypes.string, currentTeamId: PropTypes.string.isRequired, data: PropTypes.arrayOf(PropTypes.object), dataSource: PropTypes.string, @@ -65,8 +66,6 @@ export default class SelectorScreen extends PureComponent { searchResults: [], term: '', }; - - props.navigator.setOnNavigatorEvent(this.onNavigatorEvent); } componentDidMount() { @@ -85,7 +84,7 @@ export default class SelectorScreen extends PureComponent { componentDidUpdate(prevProps) { if (this.props.theme !== prevProps.theme) { - setNavigatorStyles(this.props.navigator, this.props.theme); + setNavigatorStyles(this.props.componentId, this.props.theme); } } diff --git a/app/screens/selector_screen/selector_screen.test.js b/app/screens/selector_screen/selector_screen.test.js index a63b9239d..b017809f9 100644 --- a/app/screens/selector_screen/selector_screen.test.js +++ b/app/screens/selector_screen/selector_screen.test.js @@ -72,9 +72,6 @@ describe('SelectorScreen', () => { const baseProps = { actions, currentTeamId: 'someId', - navigator: { - setOnNavigatorEvent: jest.fn(), - }, onSelect: jest.fn(), data: [{text: 'text', value: 'value'}], dataSource: null, diff --git a/app/screens/settings/display_settings/display_settings.js b/app/screens/settings/display_settings/display_settings.js index 02c920e8e..24ffdca47 100644 --- a/app/screens/settings/display_settings/display_settings.js +++ b/app/screens/settings/display_settings/display_settings.js @@ -8,6 +8,7 @@ import { Platform, View, } from 'react-native'; +import {Navigation} from 'react-native-navigation'; import SettingsItem from 'app/screens/settings/settings_item'; import StatusBar from 'app/components/status_bar'; @@ -18,6 +19,7 @@ import ClockDisplay from 'app/screens/clock_display'; export default class DisplaySettings extends PureComponent { static propTypes = { + componentId: PropTypes.string, navigator: PropTypes.object.isRequired, theme: PropTypes.object.isRequired, enableTheme: PropTypes.bool.isRequired, @@ -32,9 +34,14 @@ export default class DisplaySettings extends PureComponent { showClockDisplaySettings: false, }; - constructor(props) { - super(props); - props.navigator.setOnNavigatorEvent(this.onNavigatorEvent); + componentDidMount() { + this.navigationEventListener = Navigation.events().bindComponent(this); + } + + // TODO: Remove this once styles are passed in push call in + // app/screens/settings/general/settings.js + componentDidAppear() { + setNavigatorStyles(this.props.componentId, this.props.theme); } closeClockDisplaySettings = () => { @@ -100,12 +107,6 @@ export default class DisplaySettings extends PureComponent { }); }); - onNavigatorEvent = (event) => { - if (event.id === 'willAppear') { - setNavigatorStyles(this.props.navigator, this.props.theme); - } - }; - render() { const {theme, enableTimezone, enableTheme} = this.props; const {showClockDisplaySettings} = this.state; diff --git a/app/screens/settings/display_settings/display_settings.test.js b/app/screens/settings/display_settings/display_settings.test.js index 1d1b40804..bd401a916 100644 --- a/app/screens/settings/display_settings/display_settings.test.js +++ b/app/screens/settings/display_settings/display_settings.test.js @@ -17,8 +17,8 @@ describe('DisplaySettings', () => { enableTimezone: false, navigator: { push: jest.fn(), - setOnNavigatorEvent: jest.fn(), }, + componentId: 'component-id', }; test('should match snapshot', () => { diff --git a/app/screens/settings/general/settings.js b/app/screens/settings/general/settings.js index 732672eb1..f1569a2fc 100644 --- a/app/screens/settings/general/settings.js +++ b/app/screens/settings/general/settings.js @@ -11,6 +11,7 @@ import { View, } from 'react-native'; import DeviceInfo from 'react-native-device-info'; +import {Navigation} from 'react-native-navigation'; import SettingsItem from 'app/screens/settings/settings_item'; import StatusBar from 'app/components/status_bar'; @@ -27,6 +28,7 @@ class Settings extends PureComponent { clearErrors: PropTypes.func.isRequired, purgeOfflineStore: PropTypes.func.isRequired, }).isRequired, + componentId: PropTypes.string, config: PropTypes.object.isRequired, currentTeamId: PropTypes.string.isRequired, currentUserId: PropTypes.string.isRequired, @@ -43,9 +45,22 @@ class Settings extends PureComponent { joinableTeams: [], }; - constructor(props) { - super(props); - this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent); + componentDidMount() { + this.navigationEventListener = Navigation.events().bindComponent(this); + } + + // TODO: Remove this once styles are passed in push/showModal call in + // app/components/sidebars/settings/settings_sidebar.js + componentDidAppear() { + setNavigatorStyles(this.props.componentId, this.props.theme); + } + + navigationButtonPressed({buttonId}) { + if (buttonId === 'close-settings') { + this.props.navigator.dismissModal({ + animationType: 'slide-down', + }); + } } errorEmailBody = () => { @@ -107,6 +122,10 @@ class Settings extends PureComponent { goToDisplaySettings = preventDoubleTap(() => { const {intl, navigator, theme} = this.props; + + // TODO: Ensure all styles used in app/utils/theme's setNavigatorStyles + // are passed to DisplaySettings when this push call is updated to RNN v2 + // then remove setNavigatorStyles call in app/screens/settings/display_settings/display_settings.js navigator.push({ screen: 'DisplaySettings', title: intl.formatMessage({id: 'user.settings.modal.display', defaultMessage: 'Display'}), @@ -178,20 +197,6 @@ class Settings extends PureComponent { }); }); - onNavigatorEvent = (event) => { - if (event.id === 'willAppear') { - setNavigatorStyles(this.props.navigator, this.props.theme); - } - - if (event.type === 'NavBarButtonPress') { - if (event.id === 'close-settings') { - this.props.navigator.dismissModal({ - animationType: 'slide-down', - }); - } - } - }; - openErrorEmail = preventDoubleTap(() => { const {config} = this.props; const recipient = config.SupportEmail; diff --git a/app/screens/settings/notification_settings/notification_settings.js b/app/screens/settings/notification_settings/notification_settings.js index 4e0ddb351..2d269a132 100644 --- a/app/screens/settings/notification_settings/notification_settings.js +++ b/app/screens/settings/notification_settings/notification_settings.js @@ -27,6 +27,7 @@ class NotificationSettings extends PureComponent { actions: PropTypes.shape({ updateMe: PropTypes.func.isRequired, }), + componentId: PropTypes.string, currentUser: PropTypes.object.isRequired, intl: intlShape.isRequired, navigator: PropTypes.object, @@ -38,7 +39,7 @@ class NotificationSettings extends PureComponent { componentWillReceiveProps(nextProps) { if (this.props.theme !== nextProps.theme) { - setNavigatorStyles(this.props.navigator, nextProps.theme); + setNavigatorStyles(this.props.componentId, nextProps.theme); } const {updateMeRequest, intl} = nextProps; diff --git a/app/screens/settings/notification_settings_auto_responder/notification_settings_auto_responder.js b/app/screens/settings/notification_settings_auto_responder/notification_settings_auto_responder.js index 1a20646b8..3f7cbb5cf 100644 --- a/app/screens/settings/notification_settings_auto_responder/notification_settings_auto_responder.js +++ b/app/screens/settings/notification_settings_auto_responder/notification_settings_auto_responder.js @@ -7,9 +7,11 @@ import PropTypes from 'prop-types'; import { View, } from 'react-native'; -import {General} from 'mattermost-redux/constants'; +import {Navigation} from 'react-native-navigation'; import {intlShape} from 'react-intl'; +import {General} from 'mattermost-redux/constants'; + import FormattedText from 'app/components/formatted_text'; import StatusBar from 'app/components/status_bar'; import TextInputWithLocalizedPlaceholder from 'app/components/text_input_with_localized_placeholder'; @@ -44,8 +46,6 @@ export default class NotificationSettingsAutoResponder extends PureComponent { defaultMessage: 'Hello, I am out of office and unable to respond to messages.', }); - props.navigator.setOnNavigatorEvent(this.onNavigatorEvent); - let autoResponderActive = 'false'; if (props.currentUserStatus === General.OUT_OF_OFFICE && notifyProps.auto_responder_active) { autoResponderActive = 'true'; @@ -58,15 +58,13 @@ export default class NotificationSettingsAutoResponder extends PureComponent { }; } - onNavigatorEvent = (event) => { - if (event.type === 'ScreenChangedEvent') { - switch (event.id) { - case 'willDisappear': - this.saveUserNotifyProps(); - break; - } - } - }; + componentDidMount() { + this.navigationEventListener = Navigation.events().bindComponent(this); + } + + componentWillUnmount() { + this.saveUserNotifyProps(); + } saveUserNotifyProps = () => { this.props.onBack({ diff --git a/app/screens/settings/notification_settings_email/notification_settings_email.android.test.js b/app/screens/settings/notification_settings_email/notification_settings_email.android.test.js index f79b5c26d..dc797176d 100644 --- a/app/screens/settings/notification_settings_email/notification_settings_email.android.test.js +++ b/app/screens/settings/notification_settings_email/notification_settings_email.android.test.js @@ -6,7 +6,6 @@ import React from 'react'; import Preferences from 'mattermost-redux/constants/preferences'; import {shallowWithIntl} from 'test/intl-test-helper'; -import {emptyFunction} from 'app/utils/general'; import RadioButtonGroup from 'app/components/radio_button'; @@ -23,7 +22,6 @@ describe('NotificationSettingsEmailAndroid', () => { currentUser: {id: 'current_user_id'}, emailInterval: '30', enableEmailBatching: false, - navigator: {setOnNavigatorEvent: emptyFunction}, actions: { updateMe: jest.fn(), savePreferences: jest.fn(), @@ -31,6 +29,7 @@ describe('NotificationSettingsEmailAndroid', () => { sendEmailNotifications: true, siteName: 'Mattermost', theme: Preferences.THEMES.default, + componentId: 'component-id', }; test('should match snapshot', () => { @@ -154,13 +153,15 @@ describe('NotificationSettingsEmailAndroid', () => { const instance = wrapper.instance(); instance.saveEmailNotifyProps = jest.fn(); - // should not save preference on back button on Android + // Back button on Android should close the modal and trigger + // componentDidDisappear. + // Should not save preference on back button on Android as // saving email preference on Android is done via Save button - instance.onNavigatorEvent({type: 'ScreenChangedEvent', id: 'willDisappear'}); + instance.componentDidDisappear(); expect(instance.saveEmailNotifyProps).toHaveBeenCalledTimes(0); wrapper.setState({newInterval: '0'}); - instance.onNavigatorEvent({type: 'ScreenChangedEvent', id: 'willDisappear'}); + instance.componentDidDisappear(); expect(instance.saveEmailNotifyProps).toHaveBeenCalledTimes(0); }); }); diff --git a/app/screens/settings/notification_settings_email/notification_settings_email.ios.test.js b/app/screens/settings/notification_settings_email/notification_settings_email.ios.test.js index dcb068ec4..5c5cee410 100644 --- a/app/screens/settings/notification_settings_email/notification_settings_email.ios.test.js +++ b/app/screens/settings/notification_settings_email/notification_settings_email.ios.test.js @@ -6,8 +6,6 @@ import {shallow} from 'enzyme'; import Preferences from 'mattermost-redux/constants/preferences'; -import {emptyFunction} from 'app/utils/general'; - import SectionItem from 'app/screens/settings/section_item'; import NotificationSettingsEmailIos from './notification_settings_email.ios.js'; @@ -31,7 +29,6 @@ describe('NotificationSettingsEmailIos', () => { currentUser: {id: 'current_user_id'}, emailInterval: '30', enableEmailBatching: false, - navigator: {setOnNavigatorEvent: emptyFunction}, actions: { updateMe: jest.fn(), savePreferences: jest.fn(), @@ -39,6 +36,7 @@ describe('NotificationSettingsEmailIos', () => { sendEmailNotifications: true, siteName: 'Mattermost', theme: Preferences.THEMES.default, + componentId: 'component-id', }; test('should match snapshot, renderEmailSection', () => { @@ -57,13 +55,13 @@ describe('NotificationSettingsEmailIos', () => { const instance = wrapper.instance(); // should not save preference if email interval has not changed. - instance.onNavigatorEvent({type: 'ScreenChangedEvent', id: 'willDisappear'}); + instance.componentDidDisappear(); expect(baseProps.actions.updateMe).toHaveBeenCalledTimes(0); expect(baseProps.actions.savePreferences).toHaveBeenCalledTimes(0); // should save preference if email interval has changed. wrapper.setState({newInterval: '0'}); - instance.onNavigatorEvent({type: 'ScreenChangedEvent', id: 'willDisappear'}); + instance.componentDidDisappear(); expect(baseProps.actions.updateMe).toHaveBeenCalledTimes(1); expect(baseProps.actions.savePreferences).toHaveBeenCalledTimes(1); }); diff --git a/app/screens/settings/notification_settings_email/notification_settings_email_base.js b/app/screens/settings/notification_settings_email/notification_settings_email_base.js index c63dda1a7..60f56ab8c 100644 --- a/app/screens/settings/notification_settings_email/notification_settings_email_base.js +++ b/app/screens/settings/notification_settings_email/notification_settings_email_base.js @@ -4,6 +4,7 @@ import {PureComponent} from 'react'; import {Platform} from 'react-native'; import PropTypes from 'prop-types'; +import {Navigation} from 'react-native-navigation'; import {Preferences} from 'mattermost-redux/constants'; import {getEmailInterval} from 'mattermost-redux/utils/notify_props'; @@ -17,10 +18,10 @@ export default class NotificationSettingsEmailBase extends PureComponent { savePreferences: PropTypes.func.isRequired, updateMe: PropTypes.func.isRequired, }), + componentId: PropTypes.string, currentUser: PropTypes.object.isRequired, emailInterval: PropTypes.string.isRequired, enableEmailBatching: PropTypes.bool.isRequired, - navigator: PropTypes.object, sendEmailNotifications: PropTypes.bool.isRequired, siteName: PropTypes.string, theme: PropTypes.object.isRequired, @@ -33,7 +34,6 @@ export default class NotificationSettingsEmailBase extends PureComponent { currentUser, emailInterval, enableEmailBatching, - navigator, sendEmailNotifications, } = props; @@ -44,13 +44,15 @@ export default class NotificationSettingsEmailBase extends PureComponent { newInterval: this.computeEmailInterval(notifyProps?.email === 'true' && sendEmailNotifications, enableEmailBatching, emailInterval), showEmailNotificationsModal: false, }; + } - navigator.setOnNavigatorEvent(this.onNavigatorEvent); + componentDidMount() { + this.navigationEventListener = Navigation.events().bindComponent(this); } componentWillReceiveProps(nextProps) { if (this.props.theme !== nextProps.theme) { - setNavigatorStyles(this.props.navigator, nextProps.theme); + setNavigatorStyles(this.props.componentId, nextProps.theme); } const { @@ -74,15 +76,11 @@ export default class NotificationSettingsEmailBase extends PureComponent { } } - onNavigatorEvent = (event) => { - if (Platform.OS === 'ios' && event.type === 'ScreenChangedEvent') { - switch (event.id) { - case 'willDisappear': - this.saveEmailNotifyProps(); - break; - } + componentDidDisappear() { + if (Platform.OS === 'ios') { + this.saveEmailNotifyProps(); } - }; + } setEmailInterval = (value) => { this.setState({newInterval: value}); diff --git a/app/screens/settings/notification_settings_mentions/notification_settings_mention_base.js b/app/screens/settings/notification_settings_mentions/notification_settings_mention_base.js index 79609d5f2..b7a976468 100644 --- a/app/screens/settings/notification_settings_mentions/notification_settings_mention_base.js +++ b/app/screens/settings/notification_settings_mentions/notification_settings_mention_base.js @@ -4,12 +4,14 @@ import {PureComponent} from 'react'; import PropTypes from 'prop-types'; import {intlShape} from 'react-intl'; +import {Navigation} from 'react-native-navigation'; import {getNotificationProps} from 'app/utils/notify_props'; import {setNavigatorStyles} from 'app/utils/theme'; export default class NotificationSettingsMentionsBase extends PureComponent { static propTypes = { + componentId: PropTypes.string, currentUser: PropTypes.object.isRequired, intl: intlShape.isRequired, navigator: PropTypes.object, @@ -27,27 +29,25 @@ export default class NotificationSettingsMentionsBase extends PureComponent { const {currentUser} = props; const notifyProps = getNotificationProps(currentUser); - props.navigator.setOnNavigatorEvent(this.onNavigatorEvent); - this.goingBack = true; //use to identify if the navigator is popping this screen this.state = this.setStateFromNotifyProps(notifyProps); } + componentDidMount() { + this.navigationEventListener = Navigation.events().bindComponent(this); + } + componentWillReceiveProps(nextProps) { if (this.props.theme !== nextProps.theme) { - setNavigatorStyles(this.props.navigator, nextProps.theme); + setNavigatorStyles(this.props.componentId, nextProps.theme); } } - onNavigatorEvent = (event) => { - if (event.type === 'ScreenChangedEvent' && this.goingBack) { - switch (event.id) { - case 'willDisappear': - this.saveUserNotifyProps(); - break; - } + componentDidDisappear() { + if (this.goingBack) { + this.saveUserNotifyProps(); } - }; + } setStateFromNotifyProps = (notifyProps) => { const mentionKeys = (notifyProps.mention_keys || '').split(','); diff --git a/app/screens/settings/notification_settings_mentions_keywords/notification_settings_mentions_keywords.js b/app/screens/settings/notification_settings_mentions_keywords/notification_settings_mentions_keywords.js index 4e4f411a1..77e9bd541 100644 --- a/app/screens/settings/notification_settings_mentions_keywords/notification_settings_mentions_keywords.js +++ b/app/screens/settings/notification_settings_mentions_keywords/notification_settings_mentions_keywords.js @@ -3,6 +3,7 @@ import React, {PureComponent} from 'react'; import PropTypes from 'prop-types'; import {ScrollView, View} from 'react-native'; +import {Navigation} from 'react-native-navigation'; import FormattedText from 'app/components/formatted_text'; import StatusBar from 'app/components/status_bar'; @@ -11,6 +12,7 @@ import {changeOpacity, makeStyleSheetFromTheme, setNavigatorStyles} from 'app/ut export default class NotificationSettingsMentionsKeywords extends PureComponent { static propTypes = { + componentId: PropTypes.string, keywords: PropTypes.string, navigator: PropTypes.object, onBack: PropTypes.func.isRequired, @@ -23,13 +25,15 @@ export default class NotificationSettingsMentionsKeywords extends PureComponent this.state = { keywords: props.keywords, }; + } - props.navigator.setOnNavigatorEvent(this.onNavigatorEvent); + componentDidMount() { + this.navigationEventListener = Navigation.events().bindComponent(this); } componentWillReceiveProps(nextProps) { if (this.props.theme !== nextProps.theme) { - setNavigatorStyles(this.props.navigator, nextProps.theme); + setNavigatorStyles(this.props.componentId, nextProps.theme); } } @@ -45,15 +49,9 @@ export default class NotificationSettingsMentionsKeywords extends PureComponent return this.setState({keywords}); }; - onNavigatorEvent = (event) => { - if (event.type === 'ScreenChangedEvent') { - switch (event.id) { - case 'willDisappear': - this.props.onBack(this.state.keywords); - break; - } - } - }; + componentDidDisappear() { + this.props.onBack(this.state.keywords); + } render() { const {theme} = this.props; diff --git a/app/screens/settings/notification_settings_mobile/notification_settings_mobile_base.js b/app/screens/settings/notification_settings_mobile/notification_settings_mobile_base.js index ad38701ee..15481a7e9 100644 --- a/app/screens/settings/notification_settings_mobile/notification_settings_mobile_base.js +++ b/app/screens/settings/notification_settings_mobile/notification_settings_mobile_base.js @@ -5,12 +5,14 @@ import {PureComponent} from 'react'; import {Platform} from 'react-native'; import PropTypes from 'prop-types'; import {intlShape} from 'react-intl'; +import {Navigation} from 'react-native-navigation'; import {getNotificationProps} from 'app/utils/notify_props'; import {setNavigatorStyles} from 'app/utils/theme'; export default class NotificationSettingsMobileBase extends PureComponent { static propTypes = { + componentId: PropTypes.string, config: PropTypes.object.isRequired, currentUser: PropTypes.object.isRequired, intl: intlShape.isRequired, @@ -37,12 +39,15 @@ export default class NotificationSettingsMobileBase extends PureComponent { showMobilePushStatusModal: false, showMobileSoundsModal: false, }; - props.navigator.setOnNavigatorEvent(this.onNavigatorEvent); + } + + componentDidMount() { + this.navigationEventListener = Navigation.events().bindComponent(this); } componentWillReceiveProps(nextProps) { if (this.props.theme !== nextProps.theme) { - setNavigatorStyles(this.props.navigator, nextProps.theme); + setNavigatorStyles(this.props.componentId, nextProps.theme); } } @@ -79,15 +84,9 @@ export default class NotificationSettingsMobileBase extends PureComponent { return {}; }; - onNavigatorEvent = (event) => { - if (event.type === 'ScreenChangedEvent') { - switch (event.id) { - case 'willDisappear': - this.saveUserNotifyProps(); - break; - } - } - }; + componentDidDisappear() { + this.saveUserNotifyProps(); + } setMobilePush = (push) => { this.setState({push}); diff --git a/app/screens/terms_of_service/__snapshots__/terms_of_service.test.js.snap b/app/screens/terms_of_service/__snapshots__/terms_of_service.test.js.snap index 81ed4d889..f323d4cbd 100644 --- a/app/screens/terms_of_service/__snapshots__/terms_of_service.test.js.snap +++ b/app/screens/terms_of_service/__snapshots__/terms_of_service.test.js.snap @@ -124,19 +124,6 @@ exports[`TermsOfService should enable/disable navigator buttons on setNavigatorB }, ], }, - "setOnNavigatorEvent": [MockFunction] { - "calls": Array [ - Array [ - [Function], - ], - ], - "results": Array [ - Object { - "type": "return", - "value": undefined, - }, - ], - }, } } textStyles={ @@ -376,19 +363,6 @@ exports[`TermsOfService should enable/disable navigator buttons on setNavigatorB }, ], }, - "setOnNavigatorEvent": [MockFunction] { - "calls": Array [ - Array [ - [Function], - ], - ], - "results": Array [ - Object { - "type": "return", - "value": undefined, - }, - ], - }, } } textStyles={ @@ -677,19 +651,6 @@ exports[`TermsOfService should match snapshot on enableNavigatorLogout 1`] = ` }, ], }, - "setOnNavigatorEvent": [MockFunction] { - "calls": Array [ - Array [ - [Function], - ], - ], - "results": Array [ - Object { - "type": "return", - "value": undefined, - }, - ], - }, } } textStyles={ diff --git a/app/screens/terms_of_service/terms_of_service.js b/app/screens/terms_of_service/terms_of_service.js index f6dd2ba13..850b36e57 100644 --- a/app/screens/terms_of_service/terms_of_service.js +++ b/app/screens/terms_of_service/terms_of_service.js @@ -9,6 +9,7 @@ import { View, } from 'react-native'; import {intlShape} from 'react-intl'; +import {Navigation} from 'react-native-navigation'; import FailedNetworkAction from 'app/components/failed_network_action'; import Loading from 'app/components/loading'; @@ -36,6 +37,7 @@ export default class TermsOfService extends PureComponent { getTermsOfService: PropTypes.func.isRequired, updateMyTermsOfServiceStatus: PropTypes.func.isRequired, }).isRequired, + componentId: PropTypes.string, closeButton: PropTypes.object, navigator: PropTypes.object, siteName: PropTypes.string, @@ -72,37 +74,36 @@ export default class TermsOfService extends PureComponent { this.rightButton.title = context.intl.formatMessage({id: 'terms_of_service.agreeButton', defaultMessage: 'I Agree'}); this.leftButton.icon = props.closeButton; - props.navigator.setOnNavigatorEvent(this.onNavigatorEvent); this.setNavigatorButtons(false); } componentDidMount() { + this.navigationEventListener = Navigation.events().bindComponent(this); + this.getTerms(); } componentDidUpdate(prevProps) { if (this.props.theme !== prevProps.theme) { - setNavigatorStyles(this.props.navigator, this.props.theme); + setNavigatorStyles(this.props.componentId, this.props.theme); } } - onNavigatorEvent = (event) => { - if (event.type === 'NavBarButtonPress') { - switch (event.id) { - case 'close-terms-of-service': - this.closeTermsAndLogout(); - break; + navigationButtonPressed({buttonId}) { + switch (buttonId) { + case 'close-terms-of-service': + this.closeTermsAndLogout(); + break; - case 'reject-terms-of-service': - this.handleRejectTerms(); - break; + case 'reject-terms-of-service': + this.handleRejectTerms(); + break; - case 'accept-terms-of-service': - this.handleAcceptTerms(); - break; - } + case 'accept-terms-of-service': + this.handleAcceptTerms(); + break; } - }; + } setNavigatorButtons = (enabled = true) => { const buttons = { diff --git a/app/screens/terms_of_service/terms_of_service.test.js b/app/screens/terms_of_service/terms_of_service.test.js index 33a544f55..817dce5d5 100644 --- a/app/screens/terms_of_service/terms_of_service.test.js +++ b/app/screens/terms_of_service/terms_of_service.test.js @@ -31,11 +31,11 @@ describe('TermsOfService', () => { dismissAllModals: jest.fn(), dismissModal: jest.fn(), setButtons: jest.fn(), - setOnNavigatorEvent: jest.fn(), }, theme: Preferences.THEMES.default, closeButton: {}, siteName: 'Mattermost', + componentId: 'component-id', }; test('should match snapshot', () => { diff --git a/app/screens/text_preview/text_preview.js b/app/screens/text_preview/text_preview.js index 532da4efa..68e7b214b 100644 --- a/app/screens/text_preview/text_preview.js +++ b/app/screens/text_preview/text_preview.js @@ -17,6 +17,7 @@ import {changeOpacity, makeStyleSheetFromTheme, setNavigatorStyles} from 'app/ut export default class TextPreview extends React.PureComponent { static propTypes = { + componentId: PropTypes.string, navigator: PropTypes.object.isRequired, theme: PropTypes.object.isRequired, content: PropTypes.string.isRequired, @@ -24,7 +25,7 @@ export default class TextPreview extends React.PureComponent { componentWillReceiveProps(nextProps) { if (this.props.theme !== nextProps.theme) { - setNavigatorStyles(this.props.navigator, nextProps.theme); + setNavigatorStyles(this.props.componentId, nextProps.theme); } } diff --git a/app/screens/theme/theme.js b/app/screens/theme/theme.js index a2a37d43f..0fed665d1 100644 --- a/app/screens/theme/theme.js +++ b/app/screens/theme/theme.js @@ -27,11 +27,11 @@ export default class Theme extends React.PureComponent { actions: PropTypes.shape({ savePreferences: PropTypes.func.isRequired, }).isRequired, + componentId: PropTypes.string, allowedThemes: PropTypes.arrayOf(PropTypes.object), customTheme: PropTypes.object, isLandscape: PropTypes.bool.isRequired, isTablet: PropTypes.bool.isRequired, - navigator: PropTypes.object.isRequired, teamId: PropTypes.string.isRequired, theme: PropTypes.object.isRequired, userId: PropTypes.string.isRequired, @@ -56,7 +56,7 @@ export default class Theme extends React.PureComponent { componentDidUpdate(prevProps) { if (prevProps.theme !== this.props.theme) { - setNavigatorStyles(this.props.navigator, this.props.theme); + setNavigatorStyles(this.props.componentId, this.props.theme); } } diff --git a/app/screens/theme/theme.test.js b/app/screens/theme/theme.test.js index 3a2651ba5..486b751fe 100644 --- a/app/screens/theme/theme.test.js +++ b/app/screens/theme/theme.test.js @@ -131,9 +131,6 @@ describe('Theme', () => { allowedThemes, isLandscape: false, isTablet: false, - navigator: { - setOnNavigatorEvent: jest.fn(), - }, teamId: 'test-team', theme: Preferences.THEMES.default, userId: 'test-user', diff --git a/app/screens/thread/thread_base.js b/app/screens/thread/thread_base.js index 95718d020..468142ebd 100644 --- a/app/screens/thread/thread_base.js +++ b/app/screens/thread/thread_base.js @@ -17,6 +17,7 @@ export default class ThreadBase extends PureComponent { actions: PropTypes.shape({ selectPost: PropTypes.func.isRequired, }).isRequired, + componentId: PropTypes.string, channelId: PropTypes.string.isRequired, channelType: PropTypes.string, displayName: PropTypes.string, @@ -63,7 +64,7 @@ export default class ThreadBase extends PureComponent { componentWillReceiveProps(nextProps) { if (this.props.theme !== nextProps.theme) { - setNavigatorStyles(this.props.navigator, nextProps.theme); + setNavigatorStyles(this.props.componentId, nextProps.theme); } if (this.props.postIds !== nextProps.postIds && !nextProps.postIds.length) { diff --git a/app/screens/user_profile/user_profile.js b/app/screens/user_profile/user_profile.js index f1bf1ba34..130ffd3a1 100644 --- a/app/screens/user_profile/user_profile.js +++ b/app/screens/user_profile/user_profile.js @@ -10,6 +10,7 @@ import { Linking, } from 'react-native'; import {intlShape} from 'react-intl'; +import {Navigation} from 'react-native-navigation'; import {displayUsername} from 'mattermost-redux/utils/user_utils'; import {getUserCurrentTimezone} from 'mattermost-redux/utils/timezone_utils'; @@ -33,6 +34,7 @@ export default class UserProfile extends PureComponent { setChannelDisplayName: PropTypes.func.isRequired, loadBot: PropTypes.func.isRequired, }).isRequired, + componentId: PropTypes.string, config: PropTypes.object.isRequired, currentDisplayName: PropTypes.string, navigator: PropTypes.object, @@ -65,23 +67,35 @@ export default class UserProfile extends PureComponent { rightButtons: [this.rightButton], }; - props.navigator.setOnNavigatorEvent(this.onNavigatorEvent); props.navigator.setButtons(buttons); } } componentWillReceiveProps(nextProps) { if (this.props.theme !== nextProps.theme) { - setNavigatorStyles(this.props.navigator, nextProps.theme); + setNavigatorStyles(this.props.componentId, nextProps.theme); } } componentDidMount() { + this.navigationEventListener = Navigation.events().bindComponent(this); + if (this.props.user && this.props.user.is_bot) { this.props.actions.loadBot(this.props.user.id); } } + navigationButtonPressed({buttonId}) { + switch (buttonId) { + case this.rightButton.id: + this.goToEditProfile(); + break; + case 'close-settings': + this.close(); + break; + } + } + close = () => { const {navigator, theme} = this.props; @@ -241,19 +255,6 @@ export default class UserProfile extends PureComponent { }); }; - onNavigatorEvent = (event) => { - if (event.type === 'NavBarButtonPress') { - switch (event.id) { - case this.rightButton.id: - this.goToEditProfile(); - break; - case 'close-settings': - this.close(); - break; - } - } - }; - renderAdditionalOptions = () => { if (!Config.ExperimentalProfileLinks) { return null; diff --git a/app/screens/user_profile/user_profile.test.js b/app/screens/user_profile/user_profile.test.js index e1dac798e..af4e8d903 100644 --- a/app/screens/user_profile/user_profile.test.js +++ b/app/screens/user_profile/user_profile.test.js @@ -39,6 +39,7 @@ describe('user_profile', () => { enableTimezone: false, militaryTime: false, isMyUser: false, + componentId: 'component-id', }; const user = { @@ -126,8 +127,8 @@ describe('user_profile', () => { {context: {intl: {formatMessage: jest.fn()}}}, ); - const event = {type: 'NavBarButtonPress', id: wrapper.instance().rightButton.id}; - wrapper.instance().onNavigatorEvent(event); + const event = {buttonId: wrapper.instance().rightButton.id}; + wrapper.instance().navigationButtonPressed(event); setTimeout(() => { expect(props.navigator.push).toHaveBeenCalledTimes(1); }, 0); @@ -144,13 +145,13 @@ describe('user_profile', () => { {context: {intl: {formatMessage: jest.fn()}}}, ); - const event = {type: 'NavBarButtonPress', id: 'close-settings'}; - wrapper.instance().onNavigatorEvent(event); + const event = {buttonId: 'close-settings'}; + wrapper.instance().navigationButtonPressed(event); expect(props.navigator.dismissModal).toHaveBeenCalledTimes(1); props.fromSettings = false; wrapper.setProps({...props}); - wrapper.instance().onNavigatorEvent(event); + wrapper.instance().navigationButtonPressed(event); expect(props.navigator.resetTo).toHaveBeenCalledTimes(1); }); }); diff --git a/app/utils/theme.js b/app/utils/theme.js index f307f6398..c8c751371 100644 --- a/app/utils/theme.js +++ b/app/utils/theme.js @@ -2,6 +2,7 @@ // See LICENSE.txt for license information. import {StyleSheet} from 'react-native'; +import {Navigation} from 'react-native-navigation'; import * as ThemeUtils from 'mattermost-redux/utils/theme_utils'; @@ -19,12 +20,21 @@ export function concatStyles(...styles) { return [].concat(styles); } -export function setNavigatorStyles(navigator, theme) { - navigator.setStyle({ - navBarTextColor: theme.sidebarHeaderTextColor, - navBarBackgroundColor: theme.sidebarHeaderBg, - navBarButtonColor: theme.sidebarHeaderTextColor, - screenBackgroundColor: theme.centerChannelBg, +export function setNavigatorStyles(componentId, theme) { + Navigation.mergeOptions(componentId, { + topBar: { + title: { + color: theme.sidebarHeaderTextColor, + }, + background: { + color: theme.sidebarHeaderBg, + }, + leftButtonColor: theme.sidebarHeaderTextColor, + rightButtonColor: theme.sidebarHeaderTextColor, + }, + layout: { + backgroundColor: theme.centerChannelBg, + }, }); } diff --git a/package-lock.json b/package-lock.json index 622671a11..e688da4d8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5238,6 +5238,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, + "optional": true, "requires": { "is-extendable": "^0.1.0" } @@ -5282,7 +5283,8 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true + "dev": true, + "optional": true }, "is-glob": { "version": "4.0.1", @@ -7662,25 +7664,25 @@ "dependencies": { "abbrev": { "version": "1.1.1", - "resolved": false, + "resolved": "", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "optional": true }, "ansi-regex": { "version": "2.1.1", - "resolved": false, + "resolved": "", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "optional": true }, "aproba": { "version": "1.2.0", - "resolved": false, + "resolved": "", "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "optional": true }, "are-we-there-yet": { "version": "1.1.5", - "resolved": false, + "resolved": "", "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", "optional": true, "requires": { @@ -7690,14 +7692,15 @@ }, "balanced-match": { "version": "1.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "optional": true }, "brace-expansion": { "version": "1.1.11", - "resolved": false, + "resolved": "", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -7705,37 +7708,37 @@ }, "chownr": { "version": "1.1.1", - "resolved": false, + "resolved": "", "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==", "optional": true }, "code-point-at": { "version": "1.1.0", - "resolved": false, + "resolved": "", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "optional": true }, "concat-map": { "version": "0.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "optional": true }, "console-control-strings": { "version": "1.1.0", - "resolved": false, + "resolved": "", "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", "optional": true }, "core-util-is": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "optional": true }, "debug": { "version": "4.1.1", - "resolved": false, + "resolved": "", "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "optional": true, "requires": { @@ -7744,25 +7747,25 @@ }, "deep-extend": { "version": "0.6.0", - "resolved": false, + "resolved": "", "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "optional": true }, "delegates": { "version": "1.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "optional": true }, "detect-libc": { "version": "1.0.3", - "resolved": false, + "resolved": "", "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "optional": true }, "fs-minipass": { "version": "1.2.5", - "resolved": false, + "resolved": "", "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", "optional": true, "requires": { @@ -7771,13 +7774,13 @@ }, "fs.realpath": { "version": "1.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "optional": true }, "gauge": { "version": "2.7.4", - "resolved": false, + "resolved": "", "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "optional": true, "requires": { @@ -7793,7 +7796,7 @@ }, "glob": { "version": "7.1.3", - "resolved": false, + "resolved": "", "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "optional": true, "requires": { @@ -7807,13 +7810,13 @@ }, "has-unicode": { "version": "2.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "optional": true }, "iconv-lite": { "version": "0.4.24", - "resolved": false, + "resolved": "", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "optional": true, "requires": { @@ -7822,7 +7825,7 @@ }, "ignore-walk": { "version": "3.0.1", - "resolved": false, + "resolved": "", "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", "optional": true, "requires": { @@ -7831,7 +7834,7 @@ }, "inflight": { "version": "1.0.6", - "resolved": false, + "resolved": "", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "optional": true, "requires": { @@ -7841,48 +7844,51 @@ }, "inherits": { "version": "2.0.3", - "resolved": false, + "resolved": "", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "optional": true }, "ini": { "version": "1.3.5", - "resolved": false, + "resolved": "", "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "optional": true, "requires": { "number-is-nan": "^1.0.0" } }, "isarray": { "version": "1.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "optional": true }, "minimatch": { "version": "3.0.4", - "resolved": false, + "resolved": "", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "resolved": false, + "resolved": "", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "optional": true }, "minipass": { "version": "2.3.5", - "resolved": false, + "resolved": "", "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -7890,7 +7896,7 @@ }, "minizlib": { "version": "1.2.1", - "resolved": false, + "resolved": "", "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==", "optional": true, "requires": { @@ -7899,21 +7905,22 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": false, + "resolved": "", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "optional": true, "requires": { "minimist": "0.0.8" } }, "ms": { "version": "2.1.1", - "resolved": false, + "resolved": "", "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", "optional": true }, "needle": { "version": "2.3.0", - "resolved": false, + "resolved": "", "integrity": "sha512-QBZu7aAFR0522EyaXZM0FZ9GLpq6lvQ3uq8gteiDUp7wKdy0lSd2hPlgFwVuW1CBkfEs9PfDQsQzZghLs/psdg==", "optional": true, "requires": { @@ -7924,7 +7931,7 @@ }, "node-pre-gyp": { "version": "0.12.0", - "resolved": false, + "resolved": "", "integrity": "sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==", "optional": true, "requires": { @@ -7942,7 +7949,7 @@ }, "nopt": { "version": "4.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "optional": true, "requires": { @@ -7952,13 +7959,13 @@ }, "npm-bundled": { "version": "1.0.6", - "resolved": false, + "resolved": "", "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==", "optional": true }, "npm-packlist": { "version": "1.4.1", - "resolved": false, + "resolved": "", "integrity": "sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==", "optional": true, "requires": { @@ -7968,7 +7975,7 @@ }, "npmlog": { "version": "4.1.2", - "resolved": false, + "resolved": "", "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "optional": true, "requires": { @@ -7980,39 +7987,40 @@ }, "number-is-nan": { "version": "1.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "optional": true }, "object-assign": { "version": "4.1.1", - "resolved": false, + "resolved": "", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "optional": true }, "once": { "version": "1.4.0", - "resolved": false, + "resolved": "", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "optional": true, "requires": { "wrappy": "1" } }, "os-homedir": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "optional": true }, "os-tmpdir": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "optional": true }, "osenv": { "version": "0.1.5", - "resolved": false, + "resolved": "", "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "optional": true, "requires": { @@ -8022,19 +8030,19 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "optional": true }, "process-nextick-args": { "version": "2.0.0", - "resolved": false, + "resolved": "", "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", "optional": true }, "rc": { "version": "1.2.8", - "resolved": false, + "resolved": "", "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "optional": true, "requires": { @@ -8046,7 +8054,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": false, + "resolved": "", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "optional": true } @@ -8054,7 +8062,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": false, + "resolved": "", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "optional": true, "requires": { @@ -8069,7 +8077,7 @@ }, "rimraf": { "version": "2.6.3", - "resolved": false, + "resolved": "", "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "optional": true, "requires": { @@ -8078,44 +8086,45 @@ }, "safe-buffer": { "version": "5.1.2", - "resolved": false, + "resolved": "", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "optional": true }, "safer-buffer": { "version": "2.1.2", - "resolved": false, + "resolved": "", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "optional": true }, "sax": { "version": "1.2.4", - "resolved": false, + "resolved": "", "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "optional": true }, "semver": { "version": "5.7.0", - "resolved": false, + "resolved": "", "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", "optional": true }, "set-blocking": { "version": "2.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "optional": true }, "signal-exit": { "version": "3.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "optional": true }, "string-width": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -8124,7 +8133,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": false, + "resolved": "", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "optional": true, "requires": { @@ -8133,21 +8142,22 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "optional": true, "requires": { "ansi-regex": "^2.0.0" } }, "strip-json-comments": { "version": "2.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "optional": true }, "tar": { "version": "4.4.8", - "resolved": false, + "resolved": "", "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==", "optional": true, "requires": { @@ -8162,13 +8172,13 @@ }, "util-deprecate": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "optional": true }, "wide-align": { "version": "1.1.3", - "resolved": false, + "resolved": "", "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", "optional": true, "requires": { @@ -8177,13 +8187,13 @@ }, "wrappy": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "optional": true }, "yallist": { "version": "3.0.3", - "resolved": false, + "resolved": "", "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", "optional": true } @@ -14170,7 +14180,7 @@ "dependencies": { "ansi-regex": { "version": "3.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true }, @@ -14182,7 +14192,7 @@ }, "cliui": { "version": "4.1.0", - "resolved": false, + "resolved": "", "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", "dev": true, "requires": { @@ -14211,7 +14221,7 @@ }, "find-up": { "version": "3.0.0", - "resolved": false, + "resolved": "", "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, "requires": { @@ -14226,13 +14236,13 @@ }, "invert-kv": { "version": "2.0.0", - "resolved": false, + "resolved": "", "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", "dev": true }, "lcid": { "version": "2.0.0", - "resolved": false, + "resolved": "", "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", "dev": true, "requires": { @@ -14241,7 +14251,7 @@ }, "locate-path": { "version": "3.0.0", - "resolved": false, + "resolved": "", "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, "requires": { @@ -14268,7 +14278,7 @@ }, "os-locale": { "version": "3.1.0", - "resolved": false, + "resolved": "", "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", "dev": true, "requires": { @@ -14288,7 +14298,7 @@ }, "p-locate": { "version": "3.0.0", - "resolved": false, + "resolved": "", "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "dev": true, "requires": { @@ -14309,7 +14319,7 @@ }, "resolve-from": { "version": "4.0.0", - "resolved": false, + "resolved": "", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, @@ -14343,7 +14353,7 @@ }, "strip-ansi": { "version": "4.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { @@ -14352,13 +14362,13 @@ }, "uuid": { "version": "3.3.2", - "resolved": false, + "resolved": "", "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", "dev": true }, "y18n": { "version": "4.0.0", - "resolved": false, + "resolved": "", "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", "dev": true }, @@ -16045,7 +16055,8 @@ "version": "0.3.2", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true + "dev": true, + "optional": true }, "braces": { "version": "2.3.2", @@ -16308,7 +16319,8 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true + "dev": true, + "optional": true }, "micromatch": { "version": "3.1.10",