[MM-16011] Update screens related to main sidebar (#2907)
* Update screens * Update login tests * Remove done * Fix failing tests * Update screens and components * Check styles fix * Update tests * Prevent setState call after component unmounts * Add empty setButtons func to dummy navigator * Remove platform check * Remove Platform import * Update react-native-navigation version * Add separate showModalOverCurrentContext function * check-style fixes * Remove overriding of AppDelegate's window * Fix modal over current context animation * Add showSearchModal navigation action * Check-style fix * Address review comments
This commit is contained in:
parent
50a738a702
commit
913f05e131
37 changed files with 455 additions and 315 deletions
|
|
@ -1,13 +1,14 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Platform} from 'react-native';
|
||||
import {Navigation} from 'react-native-navigation';
|
||||
|
||||
import merge from 'deepmerge';
|
||||
|
||||
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
|
||||
|
||||
export function resetToChannel() {
|
||||
export function resetToChannel(passProps = {}) {
|
||||
return (dispatch, getState) => {
|
||||
const theme = getTheme(getState());
|
||||
|
||||
|
|
@ -17,6 +18,7 @@ export function resetToChannel() {
|
|||
children: [{
|
||||
component: {
|
||||
name: 'Channel',
|
||||
passProps,
|
||||
options: {
|
||||
layout: {
|
||||
backgroundColor: 'transparent',
|
||||
|
|
@ -25,6 +27,8 @@ export function resetToChannel() {
|
|||
visible: true,
|
||||
},
|
||||
topBar: {
|
||||
visible: false,
|
||||
height: 0,
|
||||
backButton: {
|
||||
color: theme.sidebarHeaderTextColor,
|
||||
title: '',
|
||||
|
|
@ -35,8 +39,6 @@ export function resetToChannel() {
|
|||
title: {
|
||||
color: theme.sidebarHeaderTextColor,
|
||||
},
|
||||
visible: false,
|
||||
height: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -84,6 +86,48 @@ export function resetToSelectServer(allowOtherServers) {
|
|||
};
|
||||
}
|
||||
|
||||
export function resetToTeams(name, title, passProps = {}, options = {}) {
|
||||
return (dispatch, getState) => {
|
||||
const theme = getTheme(getState());
|
||||
const defaultOptions = {
|
||||
layout: {
|
||||
backgroundColor: theme.centerChannelBg,
|
||||
},
|
||||
statusBar: {
|
||||
visible: true,
|
||||
},
|
||||
topBar: {
|
||||
visible: true,
|
||||
title: {
|
||||
color: theme.sidebarHeaderTextColor,
|
||||
text: title,
|
||||
},
|
||||
backButton: {
|
||||
color: theme.sidebarHeaderTextColor,
|
||||
title: '',
|
||||
},
|
||||
background: {
|
||||
color: theme.sidebarHeaderBg,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
Navigation.setRoot({
|
||||
root: {
|
||||
stack: {
|
||||
children: [{
|
||||
component: {
|
||||
name,
|
||||
passProps,
|
||||
options: merge(defaultOptions, options),
|
||||
},
|
||||
}],
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function goToScreen(componentId, name, title, passProps = {}, options = {}) {
|
||||
return (dispatch, getState) => {
|
||||
const theme = getTheme(getState());
|
||||
|
|
@ -108,6 +152,119 @@ export function goToScreen(componentId, name, title, passProps = {}, options = {
|
|||
},
|
||||
};
|
||||
|
||||
Navigation.push(componentId, {
|
||||
component: {
|
||||
name,
|
||||
passProps,
|
||||
options: merge(defaultOptions, options),
|
||||
},
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function showModal(name, title, passProps = {}, options = {}) {
|
||||
return (dispatch, getState) => {
|
||||
const theme = getTheme(getState());
|
||||
const defaultOptions = {
|
||||
layout: {
|
||||
backgroundColor: theme.centerChannelBg,
|
||||
},
|
||||
statusBar: {
|
||||
visible: true,
|
||||
},
|
||||
topBar: {
|
||||
animate: true,
|
||||
visible: true,
|
||||
backButton: {
|
||||
color: theme.sidebarHeaderTextColor,
|
||||
title: '',
|
||||
},
|
||||
background: {
|
||||
color: theme.sidebarHeaderBg,
|
||||
},
|
||||
title: {
|
||||
color: theme.sidebarHeaderTextColor,
|
||||
text: title,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
Navigation.showModal({
|
||||
stack: {
|
||||
children: [{
|
||||
component: {
|
||||
name,
|
||||
passProps,
|
||||
options: merge(defaultOptions, options),
|
||||
},
|
||||
}],
|
||||
},
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function showModalOverCurrentContext(name, passProps = {}, options = {}) {
|
||||
return (dispatch) => {
|
||||
const title = '';
|
||||
const animationsEnabled = (Platform.OS === 'android').toString();
|
||||
const defaultOptions = {
|
||||
modalPresentationStyle: 'overCurrentContext',
|
||||
layout: {
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
topBar: {
|
||||
visible: false,
|
||||
height: 0,
|
||||
},
|
||||
animations: {
|
||||
showModal: {
|
||||
enabled: animationsEnabled,
|
||||
alpha: {
|
||||
from: 0,
|
||||
to: 1,
|
||||
duration: 250,
|
||||
},
|
||||
},
|
||||
dismissModal: {
|
||||
enabled: animationsEnabled,
|
||||
alpha: {
|
||||
from: 1,
|
||||
to: 0,
|
||||
duration: 250,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
const mergeOptions = merge(defaultOptions, options);
|
||||
|
||||
dispatch(showModal(name, title, passProps, mergeOptions));
|
||||
};
|
||||
}
|
||||
|
||||
export function showSearchModal(initialValue = '') {
|
||||
return (dispatch) => {
|
||||
const name = 'Search';
|
||||
const title = '';
|
||||
const passProps = {initialValue};
|
||||
const options = {
|
||||
topBar: {
|
||||
visible: false,
|
||||
height: 0,
|
||||
},
|
||||
};
|
||||
|
||||
dispatch(showModal(name, title, passProps, options));
|
||||
};
|
||||
}
|
||||
|
||||
export function peek(componentId, name, passProps = {}, options = {}) {
|
||||
return () => {
|
||||
const defaultOptions = {
|
||||
preview: {
|
||||
commit: false,
|
||||
},
|
||||
};
|
||||
|
||||
Navigation.push(componentId, {
|
||||
component: {
|
||||
name,
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ export function handleSearchDraftChanged(text) {
|
|||
};
|
||||
}
|
||||
|
||||
// TODO: Remove this once all screens/components call
|
||||
// app/actions/navigation's showSearchModal
|
||||
export function showSearchModal(navigator, initialValue = '') {
|
||||
return (dispatch, getState) => {
|
||||
const theme = getTheme(getState());
|
||||
|
|
|
|||
|
|
@ -1,20 +1,13 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`profile_picture_button should match snapshot 1`] = `
|
||||
<AttachmentButton
|
||||
<Connect(AttachmentButton)
|
||||
blurTextBox={[MockFunction]}
|
||||
browseFileTypes="public.item"
|
||||
canBrowseFiles={true}
|
||||
canBrowsePhotoLibrary={true}
|
||||
canBrowseVideoLibrary={true}
|
||||
canTakePhoto={true}
|
||||
canTakeVideo={true}
|
||||
extraOptions={
|
||||
Array [
|
||||
null,
|
||||
]
|
||||
}
|
||||
maxFileCount={5}
|
||||
maxFileSize={20971520}
|
||||
navigator={
|
||||
Object {
|
||||
|
|
@ -52,6 +45,5 @@ exports[`profile_picture_button should match snapshot 1`] = `
|
|||
}
|
||||
}
|
||||
uploadFiles={[MockFunction]}
|
||||
validMimeTypes={Array []}
|
||||
/>
|
||||
`;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@ const ShareExtension = NativeModules.MattermostShare;
|
|||
|
||||
export default class AttachmentButton extends PureComponent {
|
||||
static propTypes = {
|
||||
actions: PropTypes.shape({
|
||||
showModalOverCurrentContext: PropTypes.func.isRequired,
|
||||
}).isRequired,
|
||||
blurTextBox: PropTypes.func.isRequired,
|
||||
browseFileTypes: PropTypes.string,
|
||||
validMimeTypes: PropTypes.array,
|
||||
|
|
@ -366,6 +369,7 @@ export default class AttachmentButton extends PureComponent {
|
|||
maxFileCount,
|
||||
onShowFileMaxWarning,
|
||||
extraOptions,
|
||||
actions,
|
||||
} = this.props;
|
||||
|
||||
if (fileCount === maxFileCount) {
|
||||
|
|
@ -439,21 +443,7 @@ export default class AttachmentButton extends PureComponent {
|
|||
});
|
||||
}
|
||||
|
||||
this.props.navigator.showModal({
|
||||
screen: 'OptionsModal',
|
||||
title: '',
|
||||
animationType: 'none',
|
||||
passProps: {
|
||||
items,
|
||||
},
|
||||
navigatorStyle: {
|
||||
navBarHidden: true,
|
||||
statusBarHidden: false,
|
||||
statusBarHideWithNavBar: false,
|
||||
screenBackgroundColor: 'transparent',
|
||||
modalPresentationStyle: 'overCurrentContext',
|
||||
},
|
||||
});
|
||||
actions.showModalOverCurrentContext('OptionsModal', {items});
|
||||
};
|
||||
|
||||
render() {
|
||||
|
|
@ -13,6 +13,9 @@ jest.mock('react-intl');
|
|||
|
||||
describe('AttachmentButton', () => {
|
||||
const baseProps = {
|
||||
actions: {
|
||||
showModalOverCurrentContext: jest.fn(),
|
||||
},
|
||||
theme: Preferences.THEMES.default,
|
||||
navigator: {},
|
||||
blurTextBox: jest.fn(),
|
||||
19
app/components/attachment_button/index.js
Normal file
19
app/components/attachment_button/index.js
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {bindActionCreators} from 'redux';
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import {showModalOverCurrentContext} from 'app/actions/navigation';
|
||||
|
||||
import AttachmentButton from './attachment_button';
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators({
|
||||
showModalOverCurrentContext,
|
||||
}, dispatch),
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(AttachmentButton);
|
||||
|
|
@ -1,13 +1,15 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {bindActionCreators} from 'redux';
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import {getCurrentChannelId} from 'mattermost-redux/selectors/entities/channels';
|
||||
import {getCurrentUrl} from 'mattermost-redux/selectors/entities/general';
|
||||
|
||||
import {getCurrentLocale} from 'app/selectors/i18n';
|
||||
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
|
||||
|
||||
import {resetToTeams} from 'app/actions/navigation';
|
||||
import {getCurrentLocale} from 'app/selectors/i18n';
|
||||
import {removeProtocol} from 'app/utils/url';
|
||||
|
||||
import Root from './root';
|
||||
|
|
@ -23,4 +25,12 @@ function mapStateToProps(state) {
|
|||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(Root);
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators({
|
||||
resetToTeams,
|
||||
}, dispatch),
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Root);
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@ import {getTranslations} from 'app/i18n';
|
|||
|
||||
export default class Root extends PureComponent {
|
||||
static propTypes = {
|
||||
actions: PropTypes.shape({
|
||||
resetToTeams: PropTypes.func.isRequired,
|
||||
}).isRequired,
|
||||
children: PropTypes.node,
|
||||
navigator: PropTypes.object,
|
||||
excludeEvents: PropTypes.bool,
|
||||
|
|
@ -83,28 +86,24 @@ export default class Root extends PureComponent {
|
|||
}
|
||||
|
||||
navigateToTeamsPage = (screen) => {
|
||||
const {currentUrl, navigator, theme} = this.props;
|
||||
const {currentUrl, theme, actions} = this.props;
|
||||
const {intl} = this.refs.provider.getChildContext();
|
||||
|
||||
let navigatorButtons;
|
||||
let passProps = {theme};
|
||||
const options = {topBar: {}};
|
||||
if (Platform.OS === 'android') {
|
||||
navigatorButtons = {
|
||||
rightButtons: [{
|
||||
title: intl.formatMessage({id: 'sidebar_right_menu.logout', defaultMessage: 'Logout'}),
|
||||
id: 'logout',
|
||||
buttonColor: theme.sidebarHeaderTextColor,
|
||||
showAsAction: 'always',
|
||||
}],
|
||||
};
|
||||
options.topBar.rightButtons = [{
|
||||
id: 'logout',
|
||||
text: intl.formatMessage({id: 'sidebar_right_menu.logout', defaultMessage: 'Logout'}),
|
||||
color: theme.sidebarHeaderTextColor,
|
||||
showAsAction: 'always',
|
||||
}];
|
||||
} else {
|
||||
navigatorButtons = {
|
||||
leftButtons: [{
|
||||
title: intl.formatMessage({id: 'sidebar_right_menu.logout', defaultMessage: 'Logout'}),
|
||||
id: 'logout',
|
||||
buttonColor: theme.sidebarHeaderTextColor,
|
||||
}],
|
||||
};
|
||||
options.topBar.leftButtons = [{
|
||||
id: 'logout',
|
||||
text: intl.formatMessage({id: 'sidebar_right_menu.logout', defaultMessage: 'Logout'}),
|
||||
color: theme.sidebarHeaderTextColor,
|
||||
}];
|
||||
}
|
||||
|
||||
if (screen === 'SelectTeam') {
|
||||
|
|
@ -115,20 +114,9 @@ export default class Root extends PureComponent {
|
|||
};
|
||||
}
|
||||
|
||||
navigator.resetTo({
|
||||
screen,
|
||||
title: intl.formatMessage({id: 'mobile.routes.selectTeam', defaultMessage: 'Select Team'}),
|
||||
animated: false,
|
||||
backButtonTitle: '',
|
||||
navigatorStyle: {
|
||||
navBarTextColor: theme.sidebarHeaderTextColor,
|
||||
navBarBackgroundColor: theme.sidebarHeaderBg,
|
||||
navBarButtonColor: theme.sidebarHeaderTextColor,
|
||||
screenBackgroundColor: theme.centerChannelBg,
|
||||
},
|
||||
navigatorButtons,
|
||||
passProps,
|
||||
});
|
||||
const title = intl.formatMessage({id: 'mobile.routes.selectTeam', defaultMessage: 'Select Team'});
|
||||
|
||||
actions.resetToTeams(screen, title, passProps, options);
|
||||
}
|
||||
|
||||
handleNotificationTapped = async () => {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ 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';
|
||||
|
|
@ -53,8 +52,6 @@ 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);
|
||||
|
|
@ -69,14 +66,6 @@ export default class SafeAreaIos extends PureComponent {
|
|||
this.mounted = false;
|
||||
}
|
||||
|
||||
componentDidAppear() {
|
||||
this.getSafeAreaInsets();
|
||||
}
|
||||
|
||||
componentDidDisappear() {
|
||||
this.getSafeAreaInsets();
|
||||
}
|
||||
|
||||
getStatusBarHeight = () => {
|
||||
try {
|
||||
StatusBarManager.getHeight(
|
||||
|
|
|
|||
|
|
@ -2,11 +2,10 @@
|
|||
|
||||
exports[`ChannelItem should match snapshot 1`] = `
|
||||
<AnimatedComponent>
|
||||
<TouchableHighlight
|
||||
activeOpacity={0.85}
|
||||
delayPressOut={100}
|
||||
onLongPress={[Function]}
|
||||
<TouchablePreview
|
||||
onPress={[Function]}
|
||||
onPressIn={[Function]}
|
||||
touchableComponent={[Function]}
|
||||
underlayColor="rgba(69,120,191,0.5)"
|
||||
>
|
||||
<View
|
||||
|
|
@ -100,17 +99,16 @@ exports[`ChannelItem should match snapshot 1`] = `
|
|||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
</TouchablePreview>
|
||||
</AnimatedComponent>
|
||||
`;
|
||||
|
||||
exports[`ChannelItem should match snapshot for current user i.e currentUser (you) 1`] = `
|
||||
<AnimatedComponent>
|
||||
<TouchableHighlight
|
||||
activeOpacity={0.85}
|
||||
delayPressOut={100}
|
||||
onLongPress={[Function]}
|
||||
<TouchablePreview
|
||||
onPress={[Function]}
|
||||
onPressIn={[Function]}
|
||||
touchableComponent={[Function]}
|
||||
underlayColor="rgba(69,120,191,0.5)"
|
||||
>
|
||||
<View
|
||||
|
|
@ -215,17 +213,16 @@ exports[`ChannelItem should match snapshot for current user i.e currentUser (you
|
|||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
</TouchablePreview>
|
||||
</AnimatedComponent>
|
||||
`;
|
||||
|
||||
exports[`ChannelItem should match snapshot for current user i.e currentUser (you) when isSearchResult 1`] = `
|
||||
<AnimatedComponent>
|
||||
<TouchableHighlight
|
||||
activeOpacity={0.85}
|
||||
delayPressOut={100}
|
||||
onLongPress={[Function]}
|
||||
<TouchablePreview
|
||||
onPress={[Function]}
|
||||
onPressIn={[Function]}
|
||||
touchableComponent={[Function]}
|
||||
underlayColor="rgba(69,120,191,0.5)"
|
||||
>
|
||||
<View
|
||||
|
|
@ -330,17 +327,16 @@ exports[`ChannelItem should match snapshot for current user i.e currentUser (you
|
|||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
</TouchablePreview>
|
||||
</AnimatedComponent>
|
||||
`;
|
||||
|
||||
exports[`ChannelItem should match snapshot for deactivated user and is currentChannel 1`] = `
|
||||
<AnimatedComponent>
|
||||
<TouchableHighlight
|
||||
activeOpacity={0.85}
|
||||
delayPressOut={100}
|
||||
onLongPress={[Function]}
|
||||
<TouchablePreview
|
||||
onPress={[Function]}
|
||||
onPressIn={[Function]}
|
||||
touchableComponent={[Function]}
|
||||
underlayColor="rgba(69,120,191,0.5)"
|
||||
>
|
||||
<View
|
||||
|
|
@ -445,17 +441,16 @@ exports[`ChannelItem should match snapshot for deactivated user and is currentCh
|
|||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
</TouchablePreview>
|
||||
</AnimatedComponent>
|
||||
`;
|
||||
|
||||
exports[`ChannelItem should match snapshot for deactivated user and is searchResult 1`] = `
|
||||
<AnimatedComponent>
|
||||
<TouchableHighlight
|
||||
activeOpacity={0.85}
|
||||
delayPressOut={100}
|
||||
onLongPress={[Function]}
|
||||
<TouchablePreview
|
||||
onPress={[Function]}
|
||||
onPressIn={[Function]}
|
||||
touchableComponent={[Function]}
|
||||
underlayColor="rgba(69,120,191,0.5)"
|
||||
>
|
||||
<View
|
||||
|
|
@ -549,7 +544,7 @@ exports[`ChannelItem should match snapshot for deactivated user and is searchRes
|
|||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
</TouchablePreview>
|
||||
</AnimatedComponent>
|
||||
`;
|
||||
|
||||
|
|
@ -561,11 +556,10 @@ exports[`ChannelItem should match snapshot for showUnreadForMsgs 1`] = `null`;
|
|||
|
||||
exports[`ChannelItem should match snapshot with draft 1`] = `
|
||||
<AnimatedComponent>
|
||||
<TouchableHighlight
|
||||
activeOpacity={0.85}
|
||||
delayPressOut={100}
|
||||
onLongPress={[Function]}
|
||||
<TouchablePreview
|
||||
onPress={[Function]}
|
||||
onPressIn={[Function]}
|
||||
touchableComponent={[Function]}
|
||||
underlayColor="rgba(69,120,191,0.5)"
|
||||
>
|
||||
<View
|
||||
|
|
@ -659,17 +653,16 @@ exports[`ChannelItem should match snapshot with draft 1`] = `
|
|||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
</TouchablePreview>
|
||||
</AnimatedComponent>
|
||||
`;
|
||||
|
||||
exports[`ChannelItem should match snapshot with mentions and muted 1`] = `
|
||||
<AnimatedComponent>
|
||||
<TouchableHighlight
|
||||
activeOpacity={0.85}
|
||||
delayPressOut={100}
|
||||
onLongPress={[Function]}
|
||||
<TouchablePreview
|
||||
onPress={[Function]}
|
||||
onPressIn={[Function]}
|
||||
touchableComponent={[Function]}
|
||||
underlayColor="rgba(69,120,191,0.5)"
|
||||
>
|
||||
<View
|
||||
|
|
@ -789,6 +782,6 @@ exports[`ChannelItem should match snapshot with mentions and muted 1`] = `
|
|||
/>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
</TouchablePreview>
|
||||
</AnimatedComponent>
|
||||
`;
|
||||
|
|
|
|||
|
|
@ -2,17 +2,17 @@
|
|||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {PureComponent} from 'react';
|
||||
import {General} from 'mattermost-redux/constants';
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
Animated,
|
||||
Platform,
|
||||
TouchableHighlight,
|
||||
Text,
|
||||
View,
|
||||
} from 'react-native';
|
||||
import {intlShape} from 'react-intl';
|
||||
import {Navigation} from 'react-native-navigation';
|
||||
|
||||
import {General} from 'mattermost-redux/constants';
|
||||
|
||||
import Badge from 'app/components/badge';
|
||||
import ChannelIcon from 'app/components/channel_icon';
|
||||
|
|
@ -32,7 +32,6 @@ export default class ChannelItem extends PureComponent {
|
|||
isUnread: PropTypes.bool,
|
||||
hasDraft: PropTypes.bool,
|
||||
mentions: PropTypes.number.isRequired,
|
||||
navigator: PropTypes.object,
|
||||
onSelectChannel: PropTypes.func.isRequired,
|
||||
shouldHideChannel: PropTypes.bool,
|
||||
showUnreadForMsgs: PropTypes.bool.isRequired,
|
||||
|
|
@ -40,6 +39,7 @@ export default class ChannelItem extends PureComponent {
|
|||
unreadMsgs: PropTypes.number.isRequired,
|
||||
isSearchResult: PropTypes.bool,
|
||||
isBot: PropTypes.bool.isRequired,
|
||||
previewChannel: PropTypes.func,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
|
|
@ -58,28 +58,25 @@ export default class ChannelItem extends PureComponent {
|
|||
});
|
||||
});
|
||||
|
||||
onPreview = () => {
|
||||
const {channelId, navigator} = this.props;
|
||||
if (Platform.OS === 'ios' && navigator && this.previewRef) {
|
||||
onPreview = ({reactTag}) => {
|
||||
const {channelId, previewChannel} = this.props;
|
||||
if (previewChannel) {
|
||||
const {intl} = this.context;
|
||||
|
||||
navigator.push({
|
||||
screen: 'ChannelPeek',
|
||||
previewCommit: false,
|
||||
previewView: this.previewRef,
|
||||
previewActions: [{
|
||||
id: 'action-mark-as-read',
|
||||
title: intl.formatMessage({id: 'mobile.channel.markAsRead', defaultMessage: 'Mark As Read'}),
|
||||
}],
|
||||
passProps: {
|
||||
channelId,
|
||||
const passProps = {
|
||||
channelId,
|
||||
};
|
||||
const options = {
|
||||
preview: {
|
||||
reactTag,
|
||||
actions: [{
|
||||
id: 'action-mark-as-read',
|
||||
title: intl.formatMessage({id: 'mobile.channel.markAsRead', defaultMessage: 'Mark As Read'}),
|
||||
}],
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
setPreviewRef = (ref) => {
|
||||
this.previewRef = ref;
|
||||
previewChannel(passProps, options);
|
||||
}
|
||||
};
|
||||
|
||||
showChannelAsUnread = () => {
|
||||
|
|
@ -190,11 +187,12 @@ export default class ChannelItem extends PureComponent {
|
|||
);
|
||||
|
||||
return (
|
||||
<AnimatedView ref={this.setPreviewRef}>
|
||||
<TouchableHighlight
|
||||
<AnimatedView>
|
||||
<Navigation.TouchablePreview
|
||||
touchableComponent={TouchableHighlight}
|
||||
underlayColor={changeOpacity(theme.sidebarTextHoverBg, 0.5)}
|
||||
onPress={this.onPress}
|
||||
onLongPress={this.onPreview}
|
||||
onPressIn={this.onPreview}
|
||||
>
|
||||
<View style={[style.container, mutedStyle]}>
|
||||
{extraBorder}
|
||||
|
|
@ -210,7 +208,7 @@ export default class ChannelItem extends PureComponent {
|
|||
{badge}
|
||||
</View>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
</Navigation.TouchablePreview>
|
||||
</AnimatedView>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
import React from 'react';
|
||||
import {shallow} from 'enzyme';
|
||||
import {TouchableHighlight} from 'react-native';
|
||||
import {Navigation} from 'react-native-navigation';
|
||||
|
||||
import Preferences from 'mattermost-redux/constants/preferences';
|
||||
|
||||
|
|
@ -216,7 +216,7 @@ describe('ChannelItem', () => {
|
|||
{context: {intl: {formatMessage: jest.fn()}}},
|
||||
);
|
||||
|
||||
wrapper.find(TouchableHighlight).simulate('press');
|
||||
wrapper.find(Navigation.TouchablePreview).simulate('press');
|
||||
jest.runAllTimers();
|
||||
|
||||
const expectedChannelParams = {id: baseProps.channelId, display_name: baseProps.displayName, fake: channel.fake, type: channel.type};
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ let FilteredList = null;
|
|||
|
||||
export default class ChannelsList extends PureComponent {
|
||||
static propTypes = {
|
||||
navigator: PropTypes.object,
|
||||
onJoinChannel: PropTypes.func.isRequired,
|
||||
onSearchEnds: PropTypes.func.isRequired,
|
||||
onSearchStart: PropTypes.func.isRequired,
|
||||
|
|
@ -30,6 +29,7 @@ export default class ChannelsList extends PureComponent {
|
|||
onShowTeams: PropTypes.func.isRequired,
|
||||
theme: PropTypes.object.isRequired,
|
||||
drawerOpened: PropTypes.bool,
|
||||
previewChannel: PropTypes.func,
|
||||
};
|
||||
|
||||
static contextTypes = {
|
||||
|
|
@ -86,9 +86,9 @@ export default class ChannelsList extends PureComponent {
|
|||
render() {
|
||||
const {intl} = this.context;
|
||||
const {
|
||||
navigator,
|
||||
onShowTeams,
|
||||
theme,
|
||||
previewChannel,
|
||||
} = this.props;
|
||||
|
||||
const {searching, term} = this.state;
|
||||
|
|
@ -101,14 +101,15 @@ export default class ChannelsList extends PureComponent {
|
|||
onSelectChannel={this.onSelectChannel}
|
||||
styles={styles}
|
||||
term={term}
|
||||
previewChannel={previewChannel}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
list = (
|
||||
<List
|
||||
navigator={navigator}
|
||||
onSelectChannel={this.onSelectChannel}
|
||||
styles={styles}
|
||||
previewChannel={previewChannel}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ class FilteredList extends Component {
|
|||
styles: PropTypes.object.isRequired,
|
||||
term: PropTypes.string,
|
||||
theme: PropTypes.object.isRequired,
|
||||
previewChannel: PropTypes.func,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
|
|
@ -126,6 +127,7 @@ class FilteredList extends Component {
|
|||
isUnread={channel.isUnread}
|
||||
mentions={0}
|
||||
onSelectChannel={this.onSelectChannel}
|
||||
previewChannel={this.props.previewChannel}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {bindActionCreators} from 'redux';
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import {General} from 'mattermost-redux/constants';
|
||||
|
|
@ -17,6 +18,8 @@ import {memoizeResult} from 'mattermost-redux/utils/helpers';
|
|||
import {isAdmin as checkIsAdmin, isSystemAdmin as checkIsSystemAdmin} from 'mattermost-redux/utils/user_utils';
|
||||
import {getConfig, getLicense} from 'mattermost-redux/selectors/entities/general';
|
||||
|
||||
import {showModal} from 'app/actions/navigation';
|
||||
|
||||
import {DeviceTypes, ViewTypes} from 'app/constants';
|
||||
|
||||
import List from './list';
|
||||
|
|
@ -67,6 +70,14 @@ function mapStateToProps(state) {
|
|||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators({
|
||||
showModal,
|
||||
}, dispatch),
|
||||
};
|
||||
}
|
||||
|
||||
function areStatesEqual(next, prev) {
|
||||
const equalRoles = getCurrentUserRoles(prev) === getCurrentUserRoles(next);
|
||||
const equalChannels = next.entities.channels === prev.entities.channels;
|
||||
|
|
@ -77,4 +88,4 @@ function areStatesEqual(next, prev) {
|
|||
return equalChannels && equalConfig && equalRoles && equalUsers && equalFav;
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, null, null, {pure: true, areStatesEqual})(List);
|
||||
export default connect(mapStateToProps, mapDispatchToProps, null, {pure: true, areStatesEqual})(List);
|
||||
|
|
|
|||
|
|
@ -34,14 +34,17 @@ let UnreadIndicator = null;
|
|||
|
||||
export default class List extends PureComponent {
|
||||
static propTypes = {
|
||||
actions: PropTypes.shape({
|
||||
showModal: PropTypes.func.isRequired,
|
||||
}).isRequired,
|
||||
canCreatePrivateChannels: PropTypes.bool.isRequired,
|
||||
favoriteChannelIds: PropTypes.array.isRequired,
|
||||
navigator: PropTypes.object,
|
||||
onSelectChannel: PropTypes.func.isRequired,
|
||||
unreadChannelIds: PropTypes.array.isRequired,
|
||||
styles: PropTypes.object.isRequired,
|
||||
theme: PropTypes.object.isRequired,
|
||||
orderedChannelIds: PropTypes.array.isRequired,
|
||||
previewChannel: PropTypes.func,
|
||||
};
|
||||
|
||||
static contextTypes = {
|
||||
|
|
@ -159,7 +162,10 @@ export default class List extends PureComponent {
|
|||
};
|
||||
|
||||
showCreateChannelOptions = () => {
|
||||
const {canCreatePrivateChannels, navigator} = this.props;
|
||||
const {
|
||||
canCreatePrivateChannels,
|
||||
actions,
|
||||
} = this.props;
|
||||
|
||||
const items = [];
|
||||
const moreChannels = {
|
||||
|
|
@ -197,117 +203,87 @@ export default class List extends PureComponent {
|
|||
}
|
||||
items.push(newConversation);
|
||||
|
||||
navigator.showModal({
|
||||
screen: 'OptionsModal',
|
||||
title: '',
|
||||
animationType: 'none',
|
||||
passProps: {
|
||||
items,
|
||||
onItemPress: () => navigator.dismissModal({
|
||||
animationType: 'none',
|
||||
}),
|
||||
const screen = 'OptionsModal';
|
||||
const title = '';
|
||||
const passProps = {
|
||||
items,
|
||||
};
|
||||
const options = {
|
||||
modalPresentationStyle: 'overCurrentContext',
|
||||
layout: {
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
navigatorStyle: {
|
||||
navBarHidden: true,
|
||||
statusBarHidden: false,
|
||||
statusBarHideWithNavBar: false,
|
||||
screenBackgroundColor: 'transparent',
|
||||
modalPresentationStyle: 'overCurrentContext',
|
||||
topBar: {
|
||||
visible: false,
|
||||
height: 0,
|
||||
},
|
||||
});
|
||||
animations: {
|
||||
showModal: {
|
||||
enable: false,
|
||||
},
|
||||
dismissModal: {
|
||||
enable: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
actions.showModal(screen, title, passProps, options);
|
||||
};
|
||||
|
||||
goToCreatePublicChannel = preventDoubleTap(() => {
|
||||
const {navigator, theme} = this.props;
|
||||
const {actions} = this.props;
|
||||
const {intl} = this.context;
|
||||
const screen = 'CreateChannel';
|
||||
const title = intl.formatMessage({id: 'mobile.create_channel.public', defaultMessage: 'New Public Channel'});
|
||||
const passProps = {
|
||||
channelType: General.OPEN_CHANNEL,
|
||||
closeButton: this.closeButton,
|
||||
};
|
||||
|
||||
navigator.showModal({
|
||||
screen: 'CreateChannel',
|
||||
animationType: 'slide-up',
|
||||
title: intl.formatMessage({id: 'mobile.create_channel.public', defaultMessage: 'New Public Channel'}),
|
||||
backButtonTitle: '',
|
||||
animated: true,
|
||||
navigatorStyle: {
|
||||
navBarTextColor: theme.sidebarHeaderTextColor,
|
||||
navBarBackgroundColor: theme.sidebarHeaderBg,
|
||||
navBarButtonColor: theme.sidebarHeaderTextColor,
|
||||
screenBackgroundColor: theme.centerChannelBg,
|
||||
},
|
||||
passProps: {
|
||||
channelType: General.OPEN_CHANNEL,
|
||||
closeButton: this.closeButton,
|
||||
},
|
||||
});
|
||||
actions.showModal(screen, title, passProps);
|
||||
});
|
||||
|
||||
goToCreatePrivateChannel = preventDoubleTap(() => {
|
||||
const {navigator, theme} = this.props;
|
||||
const {actions} = this.props;
|
||||
const {intl} = this.context;
|
||||
const screen = 'CreateChannel';
|
||||
const title = intl.formatMessage({id: 'mobile.create_channel.private', defaultMessage: 'New Private Channel'});
|
||||
const passProps = {
|
||||
channelType: General.PRIVATE_CHANNEL,
|
||||
closeButton: this.closeButton,
|
||||
};
|
||||
|
||||
navigator.showModal({
|
||||
screen: 'CreateChannel',
|
||||
animationType: 'slide-up',
|
||||
title: intl.formatMessage({id: 'mobile.create_channel.private', defaultMessage: 'New Private Channel'}),
|
||||
backButtonTitle: '',
|
||||
animated: true,
|
||||
navigatorStyle: {
|
||||
navBarTextColor: theme.sidebarHeaderTextColor,
|
||||
navBarBackgroundColor: theme.sidebarHeaderBg,
|
||||
navBarButtonColor: theme.sidebarHeaderTextColor,
|
||||
screenBackgroundColor: theme.centerChannelBg,
|
||||
},
|
||||
passProps: {
|
||||
channelType: General.PRIVATE_CHANNEL,
|
||||
closeButton: this.closeButton,
|
||||
},
|
||||
});
|
||||
actions.showModal(screen, title, passProps);
|
||||
});
|
||||
|
||||
goToDirectMessages = preventDoubleTap(() => {
|
||||
const {navigator, theme} = this.props;
|
||||
const {actions} = this.props;
|
||||
const {intl} = this.context;
|
||||
|
||||
navigator.showModal({
|
||||
screen: 'MoreDirectMessages',
|
||||
title: intl.formatMessage({id: 'mobile.more_dms.title', defaultMessage: 'New Conversation'}),
|
||||
animationType: 'slide-up',
|
||||
animated: true,
|
||||
backButtonTitle: '',
|
||||
navigatorStyle: {
|
||||
navBarTextColor: theme.sidebarHeaderTextColor,
|
||||
navBarBackgroundColor: theme.sidebarHeaderBg,
|
||||
navBarButtonColor: theme.sidebarHeaderTextColor,
|
||||
screenBackgroundColor: theme.centerChannelBg,
|
||||
},
|
||||
navigatorButtons: {
|
||||
const screen = 'MoreDirectMessages';
|
||||
const title = intl.formatMessage({id: 'mobile.more_dms.title', defaultMessage: 'New Conversation'});
|
||||
const passProps = {};
|
||||
const options = {
|
||||
topBar: {
|
||||
leftButtons: [{
|
||||
id: 'close-dms',
|
||||
icon: this.closeButton,
|
||||
}],
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
actions.showModal(screen, title, passProps, options);
|
||||
});
|
||||
|
||||
goToMoreChannels = preventDoubleTap(() => {
|
||||
const {navigator, theme} = this.props;
|
||||
const {actions} = this.props;
|
||||
const {intl} = this.context;
|
||||
const screen = 'MoreChannels';
|
||||
const title = intl.formatMessage({id: 'more_channels.title', defaultMessage: 'More Channels'});
|
||||
const passProps = {
|
||||
closeButton: this.closeButton,
|
||||
};
|
||||
|
||||
navigator.showModal({
|
||||
screen: 'MoreChannels',
|
||||
animationType: 'slide-up',
|
||||
title: intl.formatMessage({id: 'more_channels.title', defaultMessage: 'More Channels'}),
|
||||
backButtonTitle: '',
|
||||
animated: true,
|
||||
navigatorStyle: {
|
||||
navBarTextColor: theme.sidebarHeaderTextColor,
|
||||
navBarBackgroundColor: theme.sidebarHeaderBg,
|
||||
navBarButtonColor: theme.sidebarHeaderTextColor,
|
||||
screenBackgroundColor: theme.centerChannelBg,
|
||||
},
|
||||
passProps: {
|
||||
closeButton: this.closeButton,
|
||||
},
|
||||
});
|
||||
actions.showModal(screen, title, passProps);
|
||||
});
|
||||
|
||||
keyExtractor = (item) => item.id || item;
|
||||
|
|
@ -349,15 +325,15 @@ export default class List extends PureComponent {
|
|||
};
|
||||
|
||||
renderItem = ({item}) => {
|
||||
const {favoriteChannelIds, unreadChannelIds} = this.props;
|
||||
const {favoriteChannelIds, unreadChannelIds, previewChannel} = this.props;
|
||||
|
||||
return (
|
||||
<ChannelItem
|
||||
channelId={item}
|
||||
isUnread={unreadChannelIds.includes(item)}
|
||||
isFavorite={favoriteChannelIds.includes(item)}
|
||||
navigator={this.props.navigator}
|
||||
onSelectChannel={this.onSelectChannel}
|
||||
previewChannel={previewChannel}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -44,9 +44,9 @@ export default class ChannelSidebar extends Component {
|
|||
currentUserId: PropTypes.string.isRequired,
|
||||
deviceWidth: PropTypes.number.isRequired,
|
||||
isLandscape: PropTypes.bool.isRequired,
|
||||
navigator: PropTypes.object,
|
||||
teamsCount: PropTypes.number.isRequired,
|
||||
theme: PropTypes.object.isRequired,
|
||||
previewChannel: PropTypes.func,
|
||||
};
|
||||
|
||||
static contextTypes = {
|
||||
|
|
@ -297,9 +297,9 @@ export default class ChannelSidebar extends Component {
|
|||
|
||||
renderNavigationView = (drawerWidth) => {
|
||||
const {
|
||||
navigator,
|
||||
teamsCount,
|
||||
theme,
|
||||
previewChannel,
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
|
|
@ -331,7 +331,6 @@ export default class ChannelSidebar extends Component {
|
|||
>
|
||||
<TeamsList
|
||||
closeChannelDrawer={this.closeChannelDrawer}
|
||||
navigator={navigator}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
|
|
@ -345,7 +344,6 @@ export default class ChannelSidebar extends Component {
|
|||
>
|
||||
<ChannelsList
|
||||
ref={this.channelListRef}
|
||||
navigator={navigator}
|
||||
onSelectChannel={this.selectChannel}
|
||||
onJoinChannel={this.joinChannel}
|
||||
onShowTeams={this.showTeams}
|
||||
|
|
@ -353,6 +351,7 @@ export default class ChannelSidebar extends Component {
|
|||
onSearchEnds={this.onSearchEnds}
|
||||
theme={theme}
|
||||
drawerOpened={this.state.drawerOpened}
|
||||
previewChannel={previewChannel}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
|
|
@ -362,7 +361,6 @@ export default class ChannelSidebar extends Component {
|
|||
navBarBackgroundColor={theme.sidebarBg}
|
||||
backgroundColor={theme.sidebarHeaderBg}
|
||||
footerColor={theme.sidebarHeaderBg}
|
||||
navigator={navigator}
|
||||
>
|
||||
<DrawerSwiper
|
||||
ref={this.drawerSwiperRef}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import {getCurrentUrl} from 'mattermost-redux/selectors/entities/general';
|
|||
import {getCurrentTeamId, getMySortedTeamIds, getJoinableTeamIds} from 'mattermost-redux/selectors/entities/teams';
|
||||
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
|
||||
|
||||
import {showModal} from 'app/actions/navigation';
|
||||
import {handleTeamChange} from 'app/actions/views/select_team';
|
||||
import {getCurrentLocale} from 'app/selectors/i18n';
|
||||
import {removeProtocol} from 'app/utils/url';
|
||||
|
|
@ -30,6 +31,7 @@ function mapDispatchToProps(dispatch) {
|
|||
return {
|
||||
actions: bindActionCreators({
|
||||
handleTeamChange,
|
||||
showModal,
|
||||
}, dispatch),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,12 +33,12 @@ export default class TeamsList extends PureComponent {
|
|||
static propTypes = {
|
||||
actions: PropTypes.shape({
|
||||
handleTeamChange: PropTypes.func.isRequired,
|
||||
showModal: PropTypes.func.isRequired,
|
||||
}).isRequired,
|
||||
closeChannelDrawer: PropTypes.func.isRequired,
|
||||
currentTeamId: PropTypes.string.isRequired,
|
||||
currentUrl: PropTypes.string.isRequired,
|
||||
hasOtherJoinableTeams: PropTypes.bool,
|
||||
navigator: PropTypes.object.isRequired,
|
||||
teamIds: PropTypes.array.isRequired,
|
||||
theme: PropTypes.object.isRequired,
|
||||
};
|
||||
|
|
@ -76,31 +76,23 @@ export default class TeamsList extends PureComponent {
|
|||
|
||||
goToSelectTeam = preventDoubleTap(() => {
|
||||
const {intl} = this.context;
|
||||
const {currentUrl, navigator, theme} = this.props;
|
||||
|
||||
navigator.showModal({
|
||||
screen: 'SelectTeam',
|
||||
title: intl.formatMessage({id: 'mobile.routes.selectTeam', defaultMessage: 'Select Team'}),
|
||||
animationType: 'slide-up',
|
||||
animated: true,
|
||||
backButtonTitle: '',
|
||||
navigatorStyle: {
|
||||
navBarTextColor: theme.sidebarHeaderTextColor,
|
||||
navBarBackgroundColor: theme.sidebarHeaderBg,
|
||||
navBarButtonColor: theme.sidebarHeaderTextColor,
|
||||
screenBackgroundColor: theme.centerChannelBg,
|
||||
},
|
||||
navigatorButtons: {
|
||||
const {currentUrl, theme, actions} = this.props;
|
||||
const screen = 'SelectTeam';
|
||||
const title = intl.formatMessage({id: 'mobile.routes.selectTeam', defaultMessage: 'Select Team'});
|
||||
const passProps = {
|
||||
currentUrl,
|
||||
theme,
|
||||
};
|
||||
const options = {
|
||||
topBar: {
|
||||
leftButtons: [{
|
||||
id: 'close-teams',
|
||||
icon: this.closeButton,
|
||||
}],
|
||||
},
|
||||
passProps: {
|
||||
currentUrl,
|
||||
theme,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
actions.showModal(screen, title, passProps, options);
|
||||
});
|
||||
|
||||
keyExtractor = (item) => {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,15 @@ const CHANNEL_POST_TEXTBOX_CURSOR_CHANGE = 'onChannelTextBoxCursorChange';
|
|||
const CHANNEL_POST_TEXTBOX_VALUE_CHANGE = 'onChannelTextBoxValueChange';
|
||||
|
||||
export default class ChannelIOS extends ChannelBase {
|
||||
previewChannel = (passProps, options) => {
|
||||
const {actions, componentId} = this.props;
|
||||
const screen = 'ChannelPeek';
|
||||
|
||||
actions.peek(componentId, screen, passProps, options);
|
||||
};
|
||||
|
||||
optionalProps = {previewChannel: this.previewChannel};
|
||||
|
||||
render() {
|
||||
const {height} = Dimensions.get('window');
|
||||
const {
|
||||
|
|
@ -82,6 +91,6 @@ export default class ChannelIOS extends ChannelBase {
|
|||
</React.Fragment>
|
||||
);
|
||||
|
||||
return this.renderChannel(drawerContent);
|
||||
return this.renderChannel(drawerContent, this.optionalProps);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ export default class ChannelBase extends PureComponent {
|
|||
selectDefaultTeam: PropTypes.func.isRequired,
|
||||
selectInitialChannel: PropTypes.func.isRequired,
|
||||
recordLoadTime: PropTypes.func.isRequired,
|
||||
peek: PropTypes.func.isRequired,
|
||||
}).isRequired,
|
||||
currentChannelId: PropTypes.string,
|
||||
channelsRequestFailed: PropTypes.bool,
|
||||
|
|
@ -259,7 +260,7 @@ export default class ChannelBase extends PureComponent {
|
|||
}
|
||||
};
|
||||
|
||||
renderChannel(drawerContent) {
|
||||
renderChannel(drawerContent, optionalProps = {}) {
|
||||
const {
|
||||
channelsRequestFailed,
|
||||
currentChannelId,
|
||||
|
|
@ -298,6 +299,7 @@ export default class ChannelBase extends PureComponent {
|
|||
ref={this.channelSidebarRef}
|
||||
blurPostTextBox={this.blurPostTextBox}
|
||||
navigator={navigator}
|
||||
{...optionalProps}
|
||||
>
|
||||
<SettingsSidebar
|
||||
ref={this.settingsSidebarRef}
|
||||
|
|
|
|||
|
|
@ -24,11 +24,11 @@ export default class ChannelSearchButton extends PureComponent {
|
|||
};
|
||||
|
||||
handlePress = preventDoubleTap(async () => {
|
||||
const {actions, navigator} = this.props;
|
||||
const {actions} = this.props;
|
||||
|
||||
Keyboard.dismiss();
|
||||
await actions.clearSearch();
|
||||
await actions.showSearchModal(navigator);
|
||||
await actions.showSearchModal();
|
||||
});
|
||||
|
||||
render() {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import {connect} from 'react-redux';
|
|||
|
||||
import {clearSearch} from 'mattermost-redux/actions/search';
|
||||
|
||||
import {showSearchModal} from 'app/actions/views/search';
|
||||
import {showSearchModal} from 'app/actions/navigation';
|
||||
|
||||
import ChannelSearchButton from './channel_search_button';
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import {
|
|||
import {connection} from 'app/actions/device';
|
||||
import {recordLoadTime} from 'app/actions/views/root';
|
||||
import {selectDefaultTeam} from 'app/actions/views/select_team';
|
||||
import {peek} from 'app/actions/navigation';
|
||||
import {isLandscape} from 'app/selectors/device';
|
||||
|
||||
import Channel from './channel';
|
||||
|
|
@ -48,6 +49,7 @@ function mapDispatchToProps(dispatch) {
|
|||
recordLoadTime,
|
||||
startPeriodicStatusUpdates,
|
||||
stopPeriodicStatusUpdates,
|
||||
peek,
|
||||
}, dispatch),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,12 +21,11 @@ export default class ChannelPeek extends PureComponent {
|
|||
currentUserId: PropTypes.string,
|
||||
lastViewedAt: PropTypes.number,
|
||||
navigator: PropTypes.object,
|
||||
postIds: PropTypes.array.isRequired,
|
||||
postIds: PropTypes.array,
|
||||
theme: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
postIds: [],
|
||||
postVisibility: 15,
|
||||
};
|
||||
|
||||
|
|
@ -65,7 +64,7 @@ export default class ChannelPeek extends PureComponent {
|
|||
}
|
||||
|
||||
getVisiblePostIds = (props) => {
|
||||
return props.postIds.slice(0, 15);
|
||||
return props.postIds?.slice(0, 15) || [];
|
||||
};
|
||||
|
||||
render() {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ const navigator = {
|
|||
push: () => {}, // eslint-disable-line no-empty-function
|
||||
setOnNavigatorEvent: () => {}, // eslint-disable-line no-empty-function
|
||||
setStyle: () => {}, // eslint-disable-line no-empty-function
|
||||
setButtons: () => {}, // eslint-disable-line no-empty-function
|
||||
};
|
||||
|
||||
export function registerScreens(store, Provider) {
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ export default class MoreChannels extends PureComponent {
|
|||
this.searchTimeoutId = 0;
|
||||
this.page = -1;
|
||||
this.next = true;
|
||||
this.mounted = false;
|
||||
|
||||
this.state = {
|
||||
channels: props.channels.slice(0, General.CHANNELS_CHUNK_SIZE),
|
||||
|
|
@ -86,10 +87,14 @@ export default class MoreChannels extends PureComponent {
|
|||
|
||||
componentDidMount() {
|
||||
this.navigationEventListener = Navigation.events().bindComponent(this);
|
||||
|
||||
this.mounted = true;
|
||||
this.doGetChannels();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.mounted = false;
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
const {term} = this.state;
|
||||
let channels;
|
||||
|
|
@ -138,7 +143,7 @@ export default class MoreChannels extends PureComponent {
|
|||
const {actions, currentTeamId} = this.props;
|
||||
const {loading, term} = this.state;
|
||||
|
||||
if (this.next && !loading && !term) {
|
||||
if (this.next && !loading && !term && this.mounted) {
|
||||
this.setState({loading: true}, () => {
|
||||
actions.getChannels(
|
||||
currentTeamId,
|
||||
|
|
@ -172,12 +177,14 @@ export default class MoreChannels extends PureComponent {
|
|||
};
|
||||
|
||||
loadedChannels = ({data}) => {
|
||||
if (data && !data.length) {
|
||||
this.next = false;
|
||||
}
|
||||
if (this.mounted) {
|
||||
if (data && !data.length) {
|
||||
this.next = false;
|
||||
}
|
||||
|
||||
this.page += 1;
|
||||
this.setState({loading: false});
|
||||
this.page += 1;
|
||||
this.setState({loading: false});
|
||||
}
|
||||
};
|
||||
|
||||
onSelectChannel = async (id) => {
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ export default class MoreDirectMessages extends PureComponent {
|
|||
this.searchTimeoutId = 0;
|
||||
this.next = true;
|
||||
this.page = -1;
|
||||
this.mounted = false;
|
||||
|
||||
this.state = {
|
||||
profiles: [],
|
||||
|
|
@ -77,10 +78,15 @@ export default class MoreDirectMessages extends PureComponent {
|
|||
|
||||
componentDidMount() {
|
||||
this.navigationEventListener = Navigation.events().bindComponent(this);
|
||||
this.mounted = true;
|
||||
|
||||
this.getProfiles();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.mounted = false;
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const {componentId, theme} = this.props;
|
||||
const {selectedCount, startingConversation} = this.state;
|
||||
|
|
@ -111,7 +117,7 @@ export default class MoreDirectMessages extends PureComponent {
|
|||
|
||||
getProfiles = debounce(() => {
|
||||
const {loading, term} = this.state;
|
||||
if (this.next && !loading && !term) {
|
||||
if (this.next && !loading && !term && this.mounted) {
|
||||
this.setState({loading: true}, () => {
|
||||
const {actions, currentTeamId, restrictDirectMessage} = this.props;
|
||||
|
||||
|
|
@ -182,13 +188,15 @@ export default class MoreDirectMessages extends PureComponent {
|
|||
};
|
||||
|
||||
loadedProfiles = ({data}) => {
|
||||
const {profiles} = this.state;
|
||||
if (data && !data.length) {
|
||||
this.next = false;
|
||||
}
|
||||
if (this.mounted) {
|
||||
const {profiles} = this.state;
|
||||
if (data && !data.length) {
|
||||
this.next = false;
|
||||
}
|
||||
|
||||
this.page += 1;
|
||||
this.setState({loading: false, profiles: [...profiles, ...data]});
|
||||
this.page += 1;
|
||||
this.setState({loading: false, profiles: [...profiles, ...data]});
|
||||
}
|
||||
};
|
||||
|
||||
makeDirectChannel = async (id) => {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import {
|
|||
TouchableWithoutFeedback,
|
||||
View,
|
||||
} from 'react-native';
|
||||
import {Navigation} from 'react-native-navigation';
|
||||
|
||||
import EventEmitter from 'mattermost-redux/utils/event_emitter';
|
||||
|
||||
|
|
@ -22,12 +23,11 @@ const DURATION = 200;
|
|||
|
||||
export default class OptionsModal extends PureComponent {
|
||||
static propTypes = {
|
||||
componentId: PropTypes.string.isRequired,
|
||||
items: PropTypes.array.isRequired,
|
||||
deviceHeight: PropTypes.number.isRequired,
|
||||
deviceWidth: PropTypes.number.isRequired,
|
||||
navigator: PropTypes.object,
|
||||
onCancelPress: PropTypes.func,
|
||||
onItemPress: PropTypes.func,
|
||||
title: PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.object,
|
||||
|
|
@ -36,7 +36,6 @@ export default class OptionsModal extends PureComponent {
|
|||
|
||||
static defaultProps = {
|
||||
onCancelPress: emptyFunction,
|
||||
onItemPress: emptyFunction,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
|
|
@ -69,16 +68,17 @@ export default class OptionsModal extends PureComponent {
|
|||
toValue: this.props.deviceHeight,
|
||||
duration: DURATION,
|
||||
}).start(() => {
|
||||
this.props.navigator.dismissModal({
|
||||
animationType: 'none',
|
||||
});
|
||||
Navigation.dismissModal(this.props.componentId);
|
||||
});
|
||||
};
|
||||
|
||||
onItemPress = () => {
|
||||
Navigation.dismissModal(this.props.componentId);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
items,
|
||||
onItemPress,
|
||||
title,
|
||||
} = this.props;
|
||||
|
||||
|
|
@ -89,7 +89,7 @@ export default class OptionsModal extends PureComponent {
|
|||
<OptionsModalList
|
||||
items={items}
|
||||
onCancelPress={this.handleCancel}
|
||||
onItemPress={onItemPress}
|
||||
onItemPress={this.onItemPress}
|
||||
title={title}
|
||||
/>
|
||||
</AnimatedView>
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ export default class Search extends PureComponent {
|
|||
selectFocusedPostId: PropTypes.func.isRequired,
|
||||
selectPost: PropTypes.func.isRequired,
|
||||
}).isRequired,
|
||||
componentId: PropTypes.string.isRequired,
|
||||
currentTeamId: PropTypes.string.isRequired,
|
||||
initialValue: PropTypes.string,
|
||||
isLandscape: PropTypes.bool.isRequired,
|
||||
|
|
@ -146,7 +147,7 @@ export default class Search extends PureComponent {
|
|||
if (this.state.preview) {
|
||||
this.refs.preview.handleClose();
|
||||
} else {
|
||||
this.props.navigator.dismissModal();
|
||||
Navigation.dismissModal(this.props.componentId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -176,9 +177,8 @@ export default class Search extends PureComponent {
|
|||
};
|
||||
|
||||
cancelSearch = preventDoubleTap(() => {
|
||||
const {navigator} = this.props;
|
||||
this.handleTextChanged('', true);
|
||||
navigator.dismissModal({animationType: 'slide-down'});
|
||||
Navigation.dismissModal(this.props.componentId);
|
||||
});
|
||||
|
||||
goToThread = (post) => {
|
||||
|
|
@ -211,7 +211,7 @@ export default class Search extends PureComponent {
|
|||
|
||||
handleHashtagPress = (hashtag) => {
|
||||
if (this.showingPermalink) {
|
||||
this.props.navigator.dismissModal();
|
||||
Navigation.dismissModal(this.props.componentId);
|
||||
this.handleClosePermalink();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,12 +4,13 @@
|
|||
import {bindActionCreators} from 'redux';
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import {handleTeamChange} from 'app/actions/views/select_team';
|
||||
|
||||
import {getTeams, joinTeam} from 'mattermost-redux/actions/teams';
|
||||
import {logout} from 'mattermost-redux/actions/users';
|
||||
import {getJoinableTeams} from 'mattermost-redux/selectors/entities/teams';
|
||||
|
||||
import {resetToChannel} from 'app/actions/navigation';
|
||||
import {handleTeamChange} from 'app/actions/views/select_team';
|
||||
|
||||
import SelectTeam from './select_team.js';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
|
|
@ -26,6 +27,7 @@ function mapDispatchToProps(dispatch) {
|
|||
handleTeamChange,
|
||||
joinTeam,
|
||||
logout,
|
||||
resetToChannel,
|
||||
}, dispatch),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,10 +45,10 @@ export default class SelectTeam extends PureComponent {
|
|||
handleTeamChange: PropTypes.func.isRequired,
|
||||
joinTeam: PropTypes.func.isRequired,
|
||||
logout: PropTypes.func.isRequired,
|
||||
resetToChannel: PropTypes.func.isRequired,
|
||||
}).isRequired,
|
||||
componentId: PropTypes.string,
|
||||
currentUrl: PropTypes.string.isRequired,
|
||||
navigator: PropTypes.object,
|
||||
userWithoutTeams: PropTypes.bool,
|
||||
teams: PropTypes.array.isRequired,
|
||||
theme: PropTypes.object,
|
||||
|
|
@ -124,27 +124,15 @@ export default class SelectTeam extends PureComponent {
|
|||
};
|
||||
|
||||
close = () => {
|
||||
this.props.navigator.dismissModal({
|
||||
animationType: 'slide-down',
|
||||
});
|
||||
Navigation.dismissModal(this.props.componentId);
|
||||
};
|
||||
|
||||
goToChannelView = () => {
|
||||
const {navigator, theme} = this.props;
|
||||
const passProps = {
|
||||
disableTermsModal: true,
|
||||
};
|
||||
|
||||
navigator.resetTo({
|
||||
screen: 'Channel',
|
||||
animated: false,
|
||||
navigatorStyle: {
|
||||
navBarHidden: true,
|
||||
statusBarHidden: false,
|
||||
statusBarHideWithNavBar: false,
|
||||
screenBackgroundColor: theme.centerChannelBg,
|
||||
},
|
||||
passProps: {
|
||||
disableTermsModal: true,
|
||||
},
|
||||
});
|
||||
this.props.actions.resetToChannel(passProps);
|
||||
};
|
||||
|
||||
onSelectTeam = async (team) => {
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ describe('SelectTeam', () => {
|
|||
handleTeamChange: jest.fn(),
|
||||
joinTeam: jest.fn(),
|
||||
logout: jest.fn(),
|
||||
resetToChannel: jest.fn(),
|
||||
};
|
||||
|
||||
const baseProps = {
|
||||
|
|
|
|||
|
|
@ -56,8 +56,6 @@ NSString* const NotificationClearAction = @"clear";
|
|||
NSURL *jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
|
||||
[ReactNativeNavigation bootstrap:jsCodeLocation launchOptions:launchOptions];
|
||||
|
||||
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
|
||||
self.window.backgroundColor = [UIColor whiteColor];
|
||||
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error: nil];
|
||||
|
||||
os_log(OS_LOG_DEFAULT, "Mattermost started!!");
|
||||
|
|
|
|||
6
package-lock.json
generated
6
package-lock.json
generated
|
|
@ -15534,9 +15534,9 @@
|
|||
"from": "github:mattermost/react-native-local-auth#cc9ce2f468fbf7b431dfad3191a31aaa9227a6ab"
|
||||
},
|
||||
"react-native-navigation": {
|
||||
"version": "2.20.2",
|
||||
"resolved": "https://registry.npmjs.org/react-native-navigation/-/react-native-navigation-2.20.2.tgz",
|
||||
"integrity": "sha512-Ok1x2bBFLcIGzYF5k9SFikkUSDr4MWp1zLYy6KernL4g20DE9flgPphOrllbOEDSA87NwDUv+QsUPbpOPeW1iw==",
|
||||
"version": "2.21.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-navigation/-/react-native-navigation-2.21.1.tgz",
|
||||
"integrity": "sha512-CcICsn02NhfUZtTEg5QnXn7MiAlewc+uA3Q+UBO3SZw2rN94j8FBmEhvbvhFSWecBzqUTRvsXueMFVo4ruTAcQ==",
|
||||
"requires": {
|
||||
"hoist-non-react-statics": "3.x.x",
|
||||
"lodash": "4.17.x",
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@
|
|||
"react-native-keychain": "3.1.3",
|
||||
"react-native-linear-gradient": "2.5.4",
|
||||
"react-native-local-auth": "github:mattermost/react-native-local-auth#cc9ce2f468fbf7b431dfad3191a31aaa9227a6ab",
|
||||
"react-native-navigation": "2.20.2",
|
||||
"react-native-navigation": "2.21.1",
|
||||
"react-native-notifications": "github:mattermost/react-native-notifications#f6d32b55ecda9f6a6765437c21b075e13ac64141",
|
||||
"react-native-passcode-status": "1.1.1",
|
||||
"react-native-permissions": "1.1.1",
|
||||
|
|
|
|||
Loading…
Reference in a new issue