diff --git a/app/actions/views/channel.js b/app/actions/views/channel.js index e09806294..fc3f00775 100644 --- a/app/actions/views/channel.js +++ b/app/actions/views/channel.js @@ -345,3 +345,10 @@ export function setPostTooltipVisible(visible = true) { visible }; } + +export function setChannelDisplayName(displayName) { + return { + type: ViewTypes.SET_CHANNEL_DISPLAY_NAME, + displayName + }; +} diff --git a/app/actions/views/select_team.js b/app/actions/views/select_team.js index 320b93f4b..f9186e3c8 100644 --- a/app/actions/views/select_team.js +++ b/app/actions/views/select_team.js @@ -5,6 +5,8 @@ import {batchActions} from 'redux-batched-actions'; import {ChannelTypes, TeamTypes} from 'mattermost-redux/action_types'; +import {setChannelDisplayName} from './channel'; + export function handleTeamChange(team) { return async (dispatch, getState) => { const {currentTeamId} = getState().entities.teams; @@ -15,6 +17,8 @@ export function handleTeamChange(team) { const state = getState(); const lastChannelId = state.views.team.lastChannelForTeam[team.id] || ''; + dispatch(setChannelDisplayName(''), getState); + dispatch(batchActions([ {type: TeamTypes.SELECT_TEAM, data: team.id}, {type: ChannelTypes.SELECT_CHANNEL, data: lastChannelId} diff --git a/app/components/channel_drawer_list/channel_drawer_item.js b/app/components/channel_drawer_list/channel_drawer_item.js index 020fc8660..02f420db3 100644 --- a/app/components/channel_drawer_list/channel_drawer_item.js +++ b/app/components/channel_drawer_list/channel_drawer_item.js @@ -24,14 +24,20 @@ export default class ChannelDrawerItem extends PureComponent { theme: PropTypes.object.isRequired }; + onPress = () => { + const {channel, onSelectChannel} = this.props; + setTimeout(() => { + preventDoubleTap(onSelectChannel, this, channel); + }, 100); + }; + render() { const { channel, theme, mentions, hasUnread, - isActive, - onSelectChannel + isActive } = this.props; const style = getStyleSheet(theme); @@ -80,7 +86,7 @@ export default class ChannelDrawerItem extends PureComponent { return ( preventDoubleTap(onSelectChannel, this, channel)} + onPress={this.onPress} > {activeBorder} diff --git a/app/components/channel_drawer_list/channel_drawer_list.js b/app/components/channel_drawer_list/channel_drawer_list.js index dd7b69cd0..dfd299dd9 100644 --- a/app/components/channel_drawer_list/channel_drawer_list.js +++ b/app/components/channel_drawer_list/channel_drawer_list.js @@ -28,6 +28,9 @@ import UnreadIndicator from './unread_indicator'; class ChannelDrawerList extends Component { static propTypes = { + actions: PropTypes.shape({ + setChannelDisplayName: PropTypes.func.isRequired + }).isRequired, canCreatePrivateChannels: PropTypes.bool.isRequired, channels: PropTypes.object.isRequired, channelMembers: PropTypes.object, @@ -98,6 +101,7 @@ class ChannelDrawerList extends Component { }; onSelectChannel = (channel) => { + this.props.actions.setChannelDisplayName(channel.display_name); this.props.onSelectChannel(channel.id); }; diff --git a/app/components/channel_drawer_list/index.js b/app/components/channel_drawer_list/index.js index a1a046be1..3168119a7 100644 --- a/app/components/channel_drawer_list/index.js +++ b/app/components/channel_drawer_list/index.js @@ -1,6 +1,7 @@ // Copyright (c) 2017-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'; @@ -8,6 +9,8 @@ import {getCurrentUserId, getCurrentUserRoles} from 'mattermost-redux/selectors/ import {showCreateOption} from 'mattermost-redux/utils/channel_utils'; import {isAdmin, isSystemAdmin} from 'mattermost-redux/utils/user_utils'; +import {setChannelDisplayName} from 'app/actions/views/channel'; + import ChannelDrawerList from './channel_drawer_list'; function mapStateToProps(state, ownProps) { @@ -20,4 +23,12 @@ function mapStateToProps(state, ownProps) { }; } -export default connect(mapStateToProps)(ChannelDrawerList); +function mapDispatchToProps(dispatch) { + return { + actions: bindActionCreators({ + setChannelDisplayName + }, dispatch) + }; +} + +export default connect(mapStateToProps, mapDispatchToProps)(ChannelDrawerList); diff --git a/app/components/channel_drawer_teams/channel_drawer_teams.js b/app/components/channel_drawer_teams/channel_drawer_teams.js index 4e28f3224..ca13dea1f 100644 --- a/app/components/channel_drawer_teams/channel_drawer_teams.js +++ b/app/components/channel_drawer_teams/channel_drawer_teams.js @@ -134,7 +134,11 @@ class ChannelDrawerTeams extends PureComponent { preventDoubleTap(this.selectTeam, this, item)} + onPress={() => { + setTimeout(() => { + preventDoubleTap(this.selectTeam, this, item); + }, 100); + }} > diff --git a/app/components/drawer.js b/app/components/drawer.js index a3de8fe70..9c4ed0a19 100644 --- a/app/components/drawer.js +++ b/app/components/drawer.js @@ -11,6 +11,9 @@ export default class Drawer extends BaseDrawer { onRequestClose: PropTypes.func.isRequired }; + // To fix the android onLayout issue give this a value of 100% as it does not need another one + getHeight = () => '100%'; + processTapGestures = () => { // Note that we explicitly don't support tap to open or double tap because I didn't copy them over diff --git a/app/components/root/index.js b/app/components/root/index.js index df11f6e94..525595681 100644 --- a/app/components/root/index.js +++ b/app/components/root/index.js @@ -2,11 +2,11 @@ // See License.txt for license information. import {connect} from 'react-redux'; +import DeviceInfo from 'react-native-device-info'; import {getCurrentChannelId} from 'mattermost-redux/selectors/entities/channels'; import {getTheme} from 'app/selectors/preferences'; -import Config from 'assets/config.json'; import Root from './root'; @@ -14,7 +14,7 @@ function mapStateToProps(state, ownProps) { const users = state.entities.users; const {currentUserId} = users; - let locale = Config.DefaultLocale; + let locale = DeviceInfo.getDeviceLocale().split('-')[0]; if (currentUserId && users.profiles[currentUserId]) { locale = users.profiles[currentUserId].locale; } diff --git a/app/constants/view.js b/app/constants/view.js index 45ce4a116..dd299919d 100644 --- a/app/constants/view.js +++ b/app/constants/view.js @@ -35,6 +35,7 @@ const ViewTypes = keyMirror({ SET_CHANNEL_LOADER: null, SET_CHANNEL_REFRESHING: null, + SET_CHANNEL_DISPLAY_NAME: null, POST_TOOLTIP_VISIBLE: null, diff --git a/app/reducers/views/channel.js b/app/reducers/views/channel.js index 8c5a66b27..9e195ccda 100644 --- a/app/reducers/views/channel.js +++ b/app/reducers/views/channel.js @@ -6,6 +6,15 @@ import {ChannelTypes, FileTypes} from 'mattermost-redux/action_types'; import {ViewTypes} from 'app/constants'; +function displayName(state = '', action) { + switch (action.type) { + case ViewTypes.SET_CHANNEL_DISPLAY_NAME: + return action.displayName; + default: + return state; + } +} + function drafts(state = {}, action) { switch (action.type) { case ViewTypes.POST_DRAFT_CHANGED: { @@ -191,6 +200,7 @@ function tooltipVisible(state = false, action) { } export default combineReducers({ + displayName, drafts, loading, refreshing, diff --git a/app/reducers/views/i18n.js b/app/reducers/views/i18n.js index e39772062..d5d66e9c2 100644 --- a/app/reducers/views/i18n.js +++ b/app/reducers/views/i18n.js @@ -2,19 +2,20 @@ // See License.txt for license information. import {combineReducers} from 'redux'; - -import Config from 'assets/config.json'; +import DeviceInfo from 'react-native-device-info'; import {UserTypes} from 'mattermost-redux/action_types'; -function locale(state = Config.DefaultLocale, action) { +const defaultLocale = DeviceInfo.getDeviceLocale().split('-')[0]; + +function locale(state = defaultLocale, action) { switch (action.type) { case UserTypes.RECEIVED_ME: { const data = action.data || action.payload; return data.locale; } case UserTypes.LOGOUT_SUCCESS: - return Config.DefaultLocale; + return defaultLocale; } return state; diff --git a/app/screens/channel/channel.js b/app/screens/channel/channel.js index b26e8d559..4bba9bf99 100644 --- a/app/screens/channel/channel.js +++ b/app/screens/channel/channel.js @@ -193,10 +193,12 @@ class Channel extends PureComponent { style={{flex: 1, backgroundColor: theme.centerChannelBg}} keyboardVerticalOffset={0} > - + + + { paddingTop: 20 } }) + }, + postList: { + flex: 1, + ...Platform.select({ + android: { + marginTop: 46 + }, + ios: { + marginTop: 64 + } + }) } }); }); diff --git a/app/screens/channel/channel_post_list/index.js b/app/screens/channel/channel_post_list/index.js index 140dd5de8..6424266d8 100644 --- a/app/screens/channel/channel_post_list/index.js +++ b/app/screens/channel/channel_post_list/index.js @@ -3,9 +3,9 @@ import {bindActionCreators} from 'redux'; import {connect} from 'react-redux'; -import {createSelector} from 'reselect'; + import {selectPost, getPostsBefore} from 'mattermost-redux/actions/posts'; -import {getAllPosts, getPostsInCurrentChannel} from 'mattermost-redux/selectors/entities/posts'; +import {makeGetPostsInChannel} from 'mattermost-redux/selectors/entities/posts'; import {getMyCurrentChannelMembership} from 'mattermost-redux/selectors/entities/channels'; import {loadPostsIfNecessary} from 'app/actions/views/channel'; @@ -13,58 +13,12 @@ import {getTheme} from 'app/selectors/preferences'; import ChannelPostList from './channel_post_list'; -const getPostsInCurrentChannelWithReplyProps = createSelector( - getAllPosts, - getPostsInCurrentChannel, - (allPosts, postsInChannel) => { - const posts = []; - - for (let i = 0; i < postsInChannel.length; i++) { - let post = postsInChannel[i]; - - if (post.root_id) { - let isFirstReply = false; - let isLastReply = false; - let commentedOnPost; - - if (i + 1 <= postsInChannel.length) { - const previousPost = postsInChannel[i + 1]; - - if (previousPost.root_id !== post.root_id) { - isFirstReply = true; - - if (previousPost.id !== post.root_id) { - commentedOnPost = allPosts[post.root_id]; - } - } - } else { - // The first visible comment will always be the first comment in a thread and will be - // commenting on a post that isn't visible - isFirstReply = true; - commentedOnPost = allPosts[post.root_id]; - } - - if (i - 1 < 0 || postsInChannel[i - 1].root_id !== post.root_id) { - isLastReply = true; - } - - post = { - ...post, - isFirstReply, - isLastReply, - commentedOnPost - }; - } - - posts.push(post); - } - - return posts; - } -); +const getPostsInCurrentChannelWithReplyProps = makeGetPostsInChannel(); function mapStateToProps(state, ownProps) { const {loading, refreshing} = state.views.channel; + const {currentChannelId} = state.entities.channels; + return { ...ownProps, applicationInitializing: state.views.root.appInitializing, @@ -72,7 +26,7 @@ function mapStateToProps(state, ownProps) { channelIsRefreshing: refreshing, myMember: getMyCurrentChannelMembership(state), postsRequests: state.requests.posts, - posts: getPostsInCurrentChannelWithReplyProps(state), + posts: getPostsInCurrentChannelWithReplyProps(state, currentChannelId) || [], theme: getTheme(state), networkOnline: state.offline.online }; diff --git a/app/screens/channel/channel_title.js b/app/screens/channel/channel_title.js index 1182caf53..7ada87cc2 100644 --- a/app/screens/channel/channel_title.js +++ b/app/screens/channel/channel_title.js @@ -20,7 +20,7 @@ function ChannelTitle(props) { return null; } - const channelName = props.currentChannel.display_name; + const channelName = props.displayName || props.currentChannel.display_name; let icon; if (channelName) { icon = ( @@ -58,12 +58,14 @@ function ChannelTitle(props) { ChannelTitle.propTypes = { applicationInitializing: PropTypes.bool.isRequired, currentChannel: PropTypes.object, + displayName: PropTypes.string, onPress: PropTypes.func, theme: PropTypes.object }; ChannelTitle.defaultProps = { currentChannel: {}, + displayName: null, theme: {} }; @@ -71,6 +73,7 @@ function mapStateToProps(state) { return { applicationInitializing: state.views.root.appInitializing, currentChannel: getCurrentChannel(state), + displayName: state.views.channel.displayName, theme: getTheme(state) }; } diff --git a/app/screens/load_team/load_team.js b/app/screens/load_team/load_team.js index d59193c42..e27fb57d5 100644 --- a/app/screens/load_team/load_team.js +++ b/app/screens/load_team/load_team.js @@ -1,15 +1,11 @@ // Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -import React, {PureComponent} from 'react'; +import {PureComponent} from 'react'; import PropTypes from 'prop-types'; -import {View} from 'react-native'; import {RequestStatus} from 'mattermost-redux/constants'; -import ChannelLoader from 'app/components/channel_loader'; -import StatusBar from 'app/components/status_bar'; - export default class LoadTeam extends PureComponent { static propTypes = { navigator: PropTypes.object, @@ -80,11 +76,6 @@ export default class LoadTeam extends PureComponent { }; render() { - return ( - - - - - ); + return null; } } diff --git a/assets/base/config.json b/assets/base/config.json index 1ea80e91a..ee04e2a5d 100644 --- a/assets/base/config.json +++ b/assets/base/config.json @@ -1,7 +1,6 @@ { "DefaultServerUrl": "", "TestServerUrl": "http://localhost:8065", - "DefaultLocale": "en", "DefaultTheme": "default", "ShowErrorsList": false, "MinServerVersion": "3.8.0" diff --git a/test/mocks.js b/test/mocks.js index b5e26f910..cc1aef723 100644 --- a/test/mocks.js +++ b/test/mocks.js @@ -2,7 +2,8 @@ import {addMock} from 'mocha-react-native'; addMock('react-native-device-info', { getBuildNumber: () => true, - getVersion: () => true + getVersion: () => true, + getDeviceLocale: () => 'en' }); addMock('react-native-linear-gradient', {}); addMock('UIManager', {}); diff --git a/yarn.lock b/yarn.lock index ec39379ed..f417aa29d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3645,7 +3645,7 @@ makeerror@1.0.x: mattermost-redux@mattermost/mattermost-redux#master: version "0.0.1" - resolved "https://codeload.github.com/mattermost/mattermost-redux/tar.gz/969e3ef432a077025ae13d3ad917bf5aaf054086" + resolved "https://codeload.github.com/mattermost/mattermost-redux/tar.gz/9a2e8099daea436dab76aa612be60492311387b3" dependencies: deep-equal "1.0.1" harmony-reflect "1.5.1"