Remove ChannelPeek (#3897)

Introduced large number of unnecessary re-renders when opening channels, and ideally should not be a part of the channel switching/opening code path. Although this was discovered while trying to investigate an [Android-specific issue](https://mattermost.atlassian.net/browse/MM-22253), this extra code path made it difficult to see what Android is potentially doing differently than iOS.

Functionality originally introduced in #1203.

Conversation for removal is [here](https://community.mattermost.com/core/pl/hfcogf6pr7rw8k3ryq14c69c7e)
This commit is contained in:
Mattermost Build 2020-02-07 02:46:09 +01:00 committed by GitHub
parent 6806337b23
commit b7970c3a34
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 709 additions and 918 deletions

View file

@ -4,13 +4,11 @@
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {
Animated,
TouchableHighlight,
Text,
View,
} from 'react-native';
import {intlShape} from 'react-intl';
import {Navigation} from 'react-native-navigation';
import {General} from 'mattermost-redux/constants';
import {paddingLeft as padding} from 'app/components/safe_area_view/iphone_x_spacing';
@ -19,8 +17,6 @@ import ChannelIcon from 'app/components/channel_icon';
import {preventDoubleTap} from 'app/utils/tap';
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
const {View: AnimatedView} = Animated;
export default class ChannelItem extends PureComponent {
static propTypes = {
channelId: PropTypes.string.isRequired,
@ -40,7 +36,6 @@ export default class ChannelItem extends PureComponent {
unreadMsgs: PropTypes.number.isRequired,
isSearchResult: PropTypes.bool,
isBot: PropTypes.bool.isRequired,
previewChannel: PropTypes.func,
isLandscape: PropTypes.bool.isRequired,
};
@ -61,27 +56,6 @@ export default class ChannelItem extends PureComponent {
});
});
onPreview = ({reactTag}) => {
const {channelId, previewChannel} = this.props;
if (previewChannel) {
const {intl} = this.context;
const passProps = {
channelId,
};
const options = {
preview: {
reactTag,
actions: [{
id: 'action-mark-as-read',
title: intl.formatMessage({id: 'mobile.channel.markAsRead', defaultMessage: 'Mark As Read'}),
}],
},
};
previewChannel(passProps, options);
}
};
showChannelAsUnread = () => {
return this.props.mentions > 0 || (this.props.unreadMsgs > 0 && this.props.showUnreadForMsgs);
};
@ -192,29 +166,25 @@ export default class ChannelItem extends PureComponent {
);
return (
<AnimatedView>
<Navigation.TouchablePreview
touchableComponent={TouchableHighlight}
underlayColor={changeOpacity(theme.sidebarTextHoverBg, 0.5)}
onPress={this.onPress}
onPressIn={this.onPreview}
>
<View style={[style.container, mutedStyle, padding(isLandscape)]}>
{extraBorder}
<View style={[style.item, extraItemStyle]}>
{icon}
<Text
style={[style.text, extraTextStyle]}
ellipsizeMode='tail'
numberOfLines={1}
>
{channelDisplayName}
</Text>
{badge}
</View>
<TouchableHighlight
underlayColor={changeOpacity(theme.sidebarTextHoverBg, 0.5)}
onPress={this.onPress}
>
<View style={[style.container, mutedStyle, padding(isLandscape)]}>
{extraBorder}
<View style={[style.item, extraItemStyle]}>
{icon}
<Text
style={[style.text, extraTextStyle]}
ellipsizeMode='tail'
numberOfLines={1}
>
{channelDisplayName}
</Text>
{badge}
</View>
</Navigation.TouchablePreview>
</AnimatedView>
</View>
</TouchableHighlight>
);
}
}

View file

@ -3,7 +3,7 @@
import React from 'react';
import {shallow} from 'enzyme';
import {Navigation} from 'react-native-navigation';
import {TouchableHighlight} from 'react-native';
import Preferences from 'mattermost-redux/constants/preferences';
@ -217,7 +217,7 @@ describe('ChannelItem', () => {
{context: {intl: {formatMessage: jest.fn()}}},
);
wrapper.find(Navigation.TouchablePreview).simulate('press');
wrapper.find(TouchableHighlight).simulate('press');
jest.runAllTimers();
const expectedChannelParams = {id: baseProps.channelId, display_name: baseProps.displayName, fake: channel.fake, type: channel.type};

View file

@ -34,7 +34,6 @@ export default class ChannelsList extends PureComponent {
onShowTeams: PropTypes.func.isRequired,
theme: PropTypes.object.isRequired,
drawerOpened: PropTypes.bool,
previewChannel: PropTypes.func,
isLandscape: PropTypes.bool.isRequired,
};
@ -98,7 +97,6 @@ export default class ChannelsList extends PureComponent {
const {
onShowTeams,
theme,
previewChannel,
isLandscape,
} = this.props;
@ -112,7 +110,6 @@ export default class ChannelsList extends PureComponent {
onSelectChannel={this.onSelectChannel}
styles={styles}
term={term}
previewChannel={previewChannel}
/>
);
} else {
@ -120,7 +117,6 @@ export default class ChannelsList extends PureComponent {
<List
onSelectChannel={this.onSelectChannel}
styles={styles}
previewChannel={previewChannel}
/>
);
}

View file

@ -50,7 +50,6 @@ class FilteredList extends Component {
styles: PropTypes.object.isRequired,
term: PropTypes.string,
theme: PropTypes.object.isRequired,
previewChannel: PropTypes.func,
isLandscape: PropTypes.bool.isRequired,
};
@ -350,7 +349,6 @@ class FilteredList extends Component {
isUnread={item.isUnread}
mentions={0}
onSelectChannel={this.onSelectChannel}
previewChannel={this.props.previewChannel}
/>
);
};

View file

@ -48,7 +48,6 @@ export default class List extends PureComponent {
styles: PropTypes.object.isRequired,
theme: PropTypes.object.isRequired,
orderedChannelIds: PropTypes.array.isRequired,
previewChannel: PropTypes.func,
isLandscape: PropTypes.bool.isRequired,
};
@ -309,7 +308,7 @@ export default class List extends PureComponent {
};
renderItem = ({item}) => {
const {favoriteChannelIds, unreadChannelIds, previewChannel} = this.props;
const {favoriteChannelIds, unreadChannelIds} = this.props;
return (
<ChannelItem
@ -317,7 +316,6 @@ export default class List extends PureComponent {
isUnread={unreadChannelIds.includes(item)}
isFavorite={favoriteChannelIds.includes(item)}
onSelectChannel={this.onSelectChannel}
previewChannel={previewChannel}
/>
);
};

View file

@ -45,7 +45,6 @@ export default class ChannelSidebar extends Component {
currentUserId: PropTypes.string.isRequired,
teamsCount: PropTypes.number.isRequired,
theme: PropTypes.object.isRequired,
previewChannel: PropTypes.func,
};
static contextTypes = {
@ -318,7 +317,6 @@ export default class ChannelSidebar extends Component {
const {
teamsCount,
theme,
previewChannel,
} = this.props;
const {
@ -372,7 +370,6 @@ export default class ChannelSidebar extends Component {
onSearchEnds={this.onSearchEnds}
theme={theme}
drawerOpened={this.state.drawerOpened}
previewChannel={previewChannel}
/>
</View>,
);

View file

@ -12,7 +12,6 @@ import PostTextbox from 'app/components/post_textbox';
import SafeAreaView from 'app/components/safe_area_view';
import StatusBar from 'app/components/status_bar';
import {DeviceTypes} from 'app/constants';
import {peek} from 'app/actions/navigation';
import LocalConfig from 'assets/config';
@ -25,14 +24,6 @@ const CHANNEL_POST_TEXTBOX_CURSOR_CHANGE = 'onChannelTextBoxCursorChange';
const CHANNEL_POST_TEXTBOX_VALUE_CHANGE = 'onChannelTextBoxValueChange';
export default class ChannelIOS extends ChannelBase {
previewChannel = (passProps, options) => {
const screen = 'ChannelPeek';
peek(screen, passProps, options);
};
optionalProps = {previewChannel: this.previewChannel};
render() {
const {height} = Dimensions.get('window');
const {currentChannelId} = this.props;
@ -84,6 +75,6 @@ export default class ChannelIOS extends ChannelBase {
</React.Fragment>
);
return this.renderChannel(drawerContent, this.optionalProps);
return this.renderChannel(drawerContent);
}
}

View file

@ -268,7 +268,7 @@ export default class ChannelBase extends PureComponent {
}
};
renderChannel(drawerContent, optionalProps = {}) {
renderChannel(drawerContent) {
const {
channelsRequestFailed,
currentChannelId,
@ -318,7 +318,6 @@ export default class ChannelBase extends PureComponent {
<MainSidebar
ref={this.channelSidebarRef}
blurPostTextBox={this.blurPostTextBox}
{...optionalProps}
>
<SettingsSidebar
ref={this.settingsSidebarRef}

View file

@ -1,103 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {Platform, View} from 'react-native';
import {Navigation} from 'react-native-navigation';
import {getLastPostIndex} from 'mattermost-redux/utils/post_list';
import PostList from 'app/components/post_list';
import {makeStyleSheetFromTheme} from 'app/utils/theme';
export default class ChannelPeek extends PureComponent {
static propTypes = {
actions: PropTypes.shape({
loadPostsIfNecessaryWithRetry: PropTypes.func.isRequired,
markChannelViewedAndRead: PropTypes.func.isRequired,
}).isRequired,
channelId: PropTypes.string.isRequired,
currentUserId: PropTypes.string,
lastViewedAt: PropTypes.number,
postIds: PropTypes.array,
theme: PropTypes.object.isRequired,
};
static defaultProps = {
postVisibility: 15,
};
constructor(props) {
super(props);
props.actions.loadPostsIfNecessaryWithRetry(props.channelId);
this.state = {
visiblePostIds: this.getVisiblePostIds(props),
};
}
componentDidMount() {
this.navigationEventListener = Navigation.events().bindComponent(this);
}
componentWillReceiveProps(nextProps) {
const {postIds: nextPostIds} = nextProps;
let visiblePostIds = this.state.visiblePostIds;
if (nextPostIds !== this.props.postIds) {
visiblePostIds = this.getVisiblePostIds(nextProps);
}
this.setState({
visiblePostIds,
});
}
navigationButtonPressed({buttonId}) {
if (buttonId === 'action-mark-as-read') {
const {actions, channelId} = this.props;
actions.markChannelViewedAndRead(channelId);
}
}
getVisiblePostIds = (props) => {
return props.postIds?.slice(0, 15) || [];
};
render() {
const {
channelId,
currentUserId,
lastViewedAt,
theme,
} = this.props;
const {visiblePostIds} = this.state;
const style = getStyle(theme);
return (
<View style={style.container}>
<PostList
postIds={visiblePostIds}
lastPostIndex={Platform.OS === 'android' ? getLastPostIndex(visiblePostIds) : -1}
renderReplies={true}
indicateNewMessages={true}
currentUserId={currentUserId}
lastViewedAt={lastViewedAt}
channelId={channelId}
/>
</View>
);
}
}
const getStyle = makeStyleSheetFromTheme((theme) => {
return {
container: {
flex: 1,
backgroundColor: theme.centerChannelBg,
},
};
});

View file

@ -1,37 +0,0 @@
// 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 {getPostIdsInChannel} from 'mattermost-redux/selectors/entities/posts';
import {getMyChannelMember} from 'mattermost-redux/selectors/entities/channels';
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
import {loadPostsIfNecessaryWithRetry, markChannelViewedAndRead} from 'app/actions/views/channel';
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
import ChannelPeek from './channel_peek';
function mapStateToProps(state, ownProps) {
const channelId = ownProps.channelId;
const myMember = getMyChannelMember(state, channelId);
return {
channelId,
currentUserId: getCurrentUserId(state),
postIds: getPostIdsInChannel(state, channelId),
lastViewedAt: myMember && myMember.last_viewed_at,
theme: getTheme(state),
};
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators({
loadPostsIfNecessaryWithRetry,
markChannelViewedAndRead,
}, dispatch),
};
}
export default connect(mapStateToProps, mapDispatchToProps)(ChannelPeek);

View file

@ -26,7 +26,6 @@ export function registerScreens(store, Provider) {
Navigation.registerComponent('ChannelAddMembers', () => wrapper(require('app/screens/channel_add_members').default), () => require('app/screens/channel_add_members').default);
Navigation.registerComponent('ChannelInfo', () => wrapper(require('app/screens/channel_info').default), () => require('app/screens/channel_info').default);
Navigation.registerComponent('ChannelMembers', () => wrapper(require('app/screens/channel_members').default), () => require('app/screens/channel_members').default);
Navigation.registerComponent('ChannelPeek', () => wrapper(require('app/screens/channel_peek').default), () => require('app/screens/channel_peek').default);
Navigation.registerComponent('ClientUpgrade', () => wrapper(require('app/screens/client_upgrade').default), () => require('app/screens/client_upgrade').default);
Navigation.registerComponent('ClockDisplaySettings', () => wrapper(require('app/screens/settings/clock_display').default), () => require('app/screens/settings/clock_display').default);
Navigation.registerComponent('Code', () => wrapper(require('app/screens/code').default), () => require('app/screens/code').default);

View file

@ -183,7 +183,6 @@
"mobile.channel_list.not_member": "NOT A MEMBER",
"mobile.channel_list.unreads": "UNREADS",
"mobile.channel_members.add_members_alert": "You must select at least one member to add to the channel.",
"mobile.channel.markAsRead": "Mark As Read",
"mobile.client_upgrade": "Update App",
"mobile.client_upgrade.can_upgrade_subtitle": "A new version is available for download.",
"mobile.client_upgrade.can_upgrade_title": "Update Available",