diff --git a/app/actions/navigation/index.js b/app/actions/navigation/index.js index cfa50112e..f70208fd0 100644 --- a/app/actions/navigation/index.js +++ b/app/actions/navigation/index.js @@ -232,7 +232,13 @@ export function requestCloseModal() { export function renderDrawer() { return async (dispatch, getState) => { - dispatch({type: NavigationTypes.NAVIGATION_RENDER_LEFT_DRAWER}, getState); + dispatch({type: NavigationTypes.NAVIGATION_RENDER_LEFT_DRAWER, data: true}, getState); + }; +} + +export function unrenderDrawer() { + return async (dispatch, getState) => { + dispatch({type: NavigationTypes.NAVIGATION_RENDER_LEFT_DRAWER, data: false}, getState); }; } diff --git a/app/components/channel_drawer_list/channel_drawer_item.js b/app/components/channel_drawer_list/channel_drawer_item.js index 594e9b139..479af7a9f 100644 --- a/app/components/channel_drawer_list/channel_drawer_item.js +++ b/app/components/channel_drawer_list/channel_drawer_item.js @@ -23,6 +23,12 @@ export default class ChannelDrawerItem extends PureComponent { theme: PropTypes.object.isRequired }; + handleLongPress = (channel) => { + if (this.props.onLongPress) { + this.props.onLongPress(channel); + } + }; + render() { const { channel, @@ -81,7 +87,7 @@ export default class ChannelDrawerItem extends PureComponent { onPress={() => this.props.onSelectChannel(channel)} delayLongPress={1000} onLongPress={() => { - this.props.onLongPress(channel); + this.handleLongPress(channel); }} > @@ -142,10 +148,11 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => { badgeContainer: { alignItems: 'center', backgroundColor: theme.mentionBj, + borderRadius: 7, height: 15, justifyContent: 'center', marginRight: 16, - width: 15 + width: 16 }, badge: { color: theme.mentionColor, diff --git a/app/components/channel_drawer_list/channel_drawer_list.js b/app/components/channel_drawer_list/channel_drawer_list.js index a69364cb3..456d62c81 100644 --- a/app/components/channel_drawer_list/channel_drawer_list.js +++ b/app/components/channel_drawer_list/channel_drawer_list.js @@ -154,133 +154,6 @@ class ChannelDrawerList extends Component { ); }; - onShowModal = (channel) => { - const {formatMessage} = this.props.intl; - let open; - let close; - let favorite; - let term; - let title; - - switch (channel.type) { - case Constants.DM_CHANNEL: - title = formatMessage({ - id: 'mobile.channel_list.modalTitle', - defaultMessage: 'Select an action for the {term} {name}'}, - { - name: channel.display_name, - term: formatMessage({id: 'mobile.channel_list.dm', defaultMessage: 'Direct Message'}).toLowerCase() - }); - - open = { - action: () => { - this.props.actions.closeOptionsModal(); - this.onSelectChannel(channel); - }, - text: formatMessage({id: 'mobile.channel_list.openDM', defaultMessage: 'Open Direct Message'}) - }; - - close = { - action: () => { - this.handleClose(channel); - }, - text: formatMessage({id: 'mobile.channel_list.closeDM', defaultMessage: 'Close Direct Message'}), - textStyle: { - color: '#CC3239' - } - }; - break; - case Constants.GM_CHANNEL: - title = formatMessage({ - id: 'mobile.channel_list.modalTitle', - defaultMessage: 'Select an action for the {term} {name}'}, - { - name: channel.display_name, - term: formatMessage({id: 'mobile.channel_list.gm', defaultMessage: 'Group Message'}).toLowerCase() - }); - - open = { - action: () => { - this.props.actions.closeOptionsModal(); - this.onSelectChannel(channel); - }, - text: formatMessage({id: 'mobile.channel_list.openGM', defaultMessage: 'Open Group Message'}) - }; - - close = { - action: () => { - this.handleClose(channel); - }, - text: formatMessage({id: 'mobile.channel_list.closeGM', defaultMessage: 'Close Group Message'}), - textStyle: { - color: '#CC3239' - } - }; - break; - default: - term = channel.type === Constants.OPEN_CHANNEL ? - formatMessage({id: 'mobile.channel_list.publicChannel', defaultMessage: 'Public Channel'}) : - formatMessage({id: 'mobile.channel_list.privateChannel', defaultMessage: 'Private Channel'}); - - title = formatMessage({ - id: 'mobile.channel_list.modalTitle', - defaultMessage: 'Select an action for the {term} {name}'}, - { - name: channel.display_name, - term: term.toLowerCase() - }); - - open = { - action: () => { - this.props.actions.closeOptionsModal(); - this.onSelectChannel(channel); - }, - text: formatMessage({id: 'mobile.channel_list.openChannel', defaultMessage: 'Open {term}'}, { - term - }) - }; - - if (channel.name !== Constants.DEFAULT_CHANNEL) { - close = { - action: () => { - this.handleLeave(channel, term); - }, - text: formatMessage({id: 'channel_header.leave', defaultMessage: 'Leave {term}'}, { - term - }), - textStyle: { - color: '#CC3239' - } - }; - } - break; - } - - if (channel.isFavorite) { - favorite = { - action: () => { - this.props.actions.closeOptionsModal(); - this.props.actions.unmarkFavorite(channel.id); - }, - text: formatMessage({id: 'channelHeader.removeFromFavorites', defaultMessage: 'Remove from Favorites'}) - }; - } else { - favorite = { - action: () => { - this.props.actions.closeOptionsModal(); - this.props.actions.markFavorite(channel.id); - }, - text: formatMessage({id: 'channelHeader.addToFavorites', defaultMessage: 'Add to Favorites'}) - }; - } - - const options = [open, favorite]; - if (close) { - options.push(close); - } - this.props.actions.showOptionsModal({title, items: options}); - }; - getUnreadMessages = (channel) => { const member = this.props.channelMembers[channel.id]; let mentions = 0; @@ -328,7 +201,6 @@ class ChannelDrawerList extends Component { hasUnread={unread} mentions={mentions} onSelectChannel={this.onSelectChannel} - onLongPress={this.onShowModal} isActive={channel.isCurrent} theme={this.props.theme} /> @@ -557,7 +429,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => { width: 50 }, settings: { - color: theme.sidebarText, + color: theme.sidebarHeaderTextColor, fontSize: 18, fontWeight: '300' }, @@ -578,7 +450,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => { lineHeight: 18 }, divider: { - backgroundColor: changeOpacity(theme.centerChannelColor, 0.1), + backgroundColor: changeOpacity(theme.sidebarText, 0.1), height: 1 }, actionContainer: { diff --git a/app/components/channel_icon.js b/app/components/channel_icon.js index f8090cae1..da73c9f5d 100644 --- a/app/components/channel_icon.js +++ b/app/components/channel_icon.js @@ -49,7 +49,7 @@ function channelIcon(props) { return ( ); } else if (type === Constants.GM_CHANNEL) { @@ -90,7 +90,7 @@ function channelIcon(props) { ); @@ -116,6 +116,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => { paddingRight: 12 }, groupBox: { + alignSelf: 'flex-start', alignItems: 'center', borderWidth: 1, borderColor: changeOpacity(theme.sidebarText, 0.4), diff --git a/app/components/custom_list/index.js b/app/components/custom_list/index.js index 22bd67b09..5d891d39b 100644 --- a/app/components/custom_list/index.js +++ b/app/components/custom_list/index.js @@ -1,46 +1,10 @@ // Copyright (c) 2017 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. import React, {PropTypes, PureComponent} from 'react'; -import {ListView, StyleSheet, Text, View} from 'react-native'; +import {ListView, Platform, StyleSheet, Text, View} from 'react-native'; import FormattedText from 'app/components/formatted_text'; import {makeStyleSheetFromTheme, changeOpacity} from 'app/utils/theme'; -const getStyleFromTheme = makeStyleSheetFromTheme((theme) => { - return StyleSheet.create({ - listView: { - flex: 1, - backgroundColor: theme.centerChannelBg - }, - loadingText: { - color: changeOpacity(theme.centerChannelColor, 0.6) - }, - sectionContainer: { - backgroundColor: theme.sidebarHeaderBg, - paddingLeft: 10, - paddingVertical: 2 - }, - sectionText: { - fontWeight: '600', - color: theme.sidebarHeaderTextColor - }, - separator: { - height: 1, - flex: 1, - backgroundColor: changeOpacity(theme.centerChannelColor, 0.1) - }, - noResultContainer: { - flex: 1, - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'center' - }, - noResultText: { - fontSize: 26, - color: changeOpacity(theme.centerChannelColor, 0.5) - } - }); -}); - export default class CustomList extends PureComponent { static propTypes = { data: PropTypes.array.isRequired, @@ -225,3 +189,44 @@ export default class CustomList extends PureComponent { ); } } + +const getStyleFromTheme = makeStyleSheetFromTheme((theme) => { + return StyleSheet.create({ + listView: { + flex: 1, + backgroundColor: theme.centerChannelBg, + ...Platform.select({ + android: { + marginBottom: 20 + } + }) + }, + loadingText: { + color: changeOpacity(theme.centerChannelColor, 0.6) + }, + sectionContainer: { + backgroundColor: theme.sidebarHeaderBg, + paddingLeft: 10, + paddingVertical: 2 + }, + sectionText: { + fontWeight: '600', + color: theme.sidebarHeaderTextColor + }, + separator: { + height: 1, + flex: 1, + backgroundColor: changeOpacity(theme.centerChannelColor, 0.1) + }, + noResultContainer: { + flex: 1, + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center' + }, + noResultText: { + fontSize: 26, + color: changeOpacity(theme.centerChannelColor, 0.5) + } + }); +}); diff --git a/app/components/root/root.js b/app/components/root/root.js index 1e75e44a1..a37f5b267 100644 --- a/app/components/root/root.js +++ b/app/components/root/root.js @@ -1,8 +1,8 @@ // Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -import React, {PropTypes, PureComponent} from 'react'; -import {AppState, View} from 'react-native'; +import React, {Component, PropTypes} from 'react'; +import {AppState, StatusBar, View} from 'react-native'; import {IntlProvider} from 'react-intl'; import DeviceInfo from 'react-native-device-info'; @@ -13,7 +13,7 @@ import {Constants} from 'mattermost-redux/constants'; import {getTranslations} from 'app/i18n'; import EventEmitter from 'mattermost-redux/utils/event_emitter'; -export default class Root extends PureComponent { +export default class Root extends Component { static propTypes = { children: PropTypes.node, currentTeamId: PropTypes.string, @@ -66,6 +66,7 @@ export default class Root extends PureComponent { messages={getTranslations(locale)} > + {this.props.children} diff --git a/app/components/search_bar/search_bar.ios.js b/app/components/search_bar/search_bar.ios.js index 2307410a8..ad882e80d 100644 --- a/app/components/search_bar/search_bar.ios.js +++ b/app/components/search_bar/search_bar.ios.js @@ -26,7 +26,7 @@ export default class SearchBarIos extends PureComponent { static defaultProps = { barStyle: 'default', - searchBarStyle: 'default', + searchBarStyle: 'minimal', placeholder: 'Search', showCancelButton: true, hideBackground: true, @@ -77,7 +77,7 @@ export default class SearchBarIos extends PureComponent { text={this.props.text} placeholder={this.props.placeholder} showsCancelButton={this.state.displayCancelButton} - hideBackground={this.props.hideBackground} + hideBackground={false} textFieldBackgroundColor={this.props.textFieldBackgroundColor} placeholderTextColor={this.props.placeholderTextColor} textColor={this.props.textColor} diff --git a/app/components/status_icons/away.js b/app/components/status_icons/away.js index 1f2a84d73..1b06d2cba 100644 --- a/app/components/status_icons/away.js +++ b/app/components/status_icons/away.js @@ -2,6 +2,7 @@ // See License.txt for license information. import React from 'react'; +import {View} from 'react-native'; import Svg, { Ellipse, G, @@ -16,30 +17,33 @@ export default class AwayStatus extends React.Component { }; render() { + const {color, height, width} = this.props; return ( - - - + + + + + + - - - + + ); } } diff --git a/app/components/status_icons/offline.js b/app/components/status_icons/offline.js index 24c34702e..d52e1a6eb 100644 --- a/app/components/status_icons/offline.js +++ b/app/components/status_icons/offline.js @@ -2,6 +2,7 @@ // See License.txt for license information. import React from 'react'; +import {View} from 'react-native'; import Svg, { Ellipse, G, @@ -16,34 +17,37 @@ export default class OfflineStatus extends React.Component { }; render() { + const {color, height, width} = this.props; return ( - - + + + + + + + + - - - - - - + + ); } } diff --git a/app/components/status_icons/online.js b/app/components/status_icons/online.js index 764541dc6..b184d896b 100644 --- a/app/components/status_icons/online.js +++ b/app/components/status_icons/online.js @@ -2,6 +2,7 @@ // See License.txt for license information. import React from 'react'; +import {View} from 'react-native'; import Svg, { Ellipse, G, @@ -16,38 +17,41 @@ export default class OnlineStatus extends React.Component { }; render() { + const {color, height, width} = this.props; return ( - - - - - - - + + + - - + + + + + + + + ); } } diff --git a/app/navigation/router.js b/app/navigation/router.js index 0aef77256..ad645d812 100644 --- a/app/navigation/router.js +++ b/app/navigation/router.js @@ -203,7 +203,7 @@ class Router extends Component { deviceWidth: event.nativeEvent.layout.width }); } - } + }; handleDrawerTween = (ratio) => { const opacity = (ratio / 2); @@ -216,8 +216,8 @@ class Router extends Component { opacity }, drawerOverlay: { - backgroundColor: '#000', - opacity: (1 - ratio) / 2 + backgroundColor: ratio ? '#000' : '#FFF', + opacity: ratio ? (1 - ratio) / 2 : 1 } }; }; diff --git a/app/reducers/navigation/index.js b/app/reducers/navigation/index.js index c4236d7b7..1006f66d8 100644 --- a/app/reducers/navigation/index.js +++ b/app/reducers/navigation/index.js @@ -213,7 +213,7 @@ export default function(state = initialState, action) { case NavigationTypes.NAVIGATION_RENDER_LEFT_DRAWER: { return { ...state, - shouldRenderDrawer: true + shouldRenderDrawer: action.data }; } diff --git a/app/scenes/channel_info/channel_info.js b/app/scenes/channel_info/channel_info.js index 83d75596d..4ed5e6c89 100644 --- a/app/scenes/channel_info/channel_info.js +++ b/app/scenes/channel_info/channel_info.js @@ -156,6 +156,7 @@ class ChannelInfo extends PureComponent { currentChannelCreatorName, currentChannelMemberCount, canManageUsers, + status, theme } = this.props; @@ -186,6 +187,7 @@ class ChannelInfo extends PureComponent { displayName={currentChannel.display_name} header={currentChannel.header} purpose={currentChannel.purpose} + status={status} theme={theme} type={currentChannel.type} /> @@ -200,14 +202,19 @@ class ChannelInfo extends PureComponent { theme={theme} /> - true} - defaultMessage='Notification Preferences' - icon='bell-o' - textId='channel_header.notificationPreferences' - theme={theme} - /> - + { + + /** + true} + defaultMessage='Notification Preferences' + icon='bell-o' + textId='channel_header.notificationPreferences' + theme={theme} + /> + + **/ + } { @@ -101,6 +107,7 @@ export default class SelectServer extends PureComponent { style={{flex: 1}} keyboardVerticalOffset={0} > + this.onSelectTeam(team)} - style={GlobalStyles.buttonListItemText} - containerStyle={GlobalStyles.buttonListItem} - > - {team.display_name} - - - ); - } - } + const content = this.props.teams.map((team) => { + return ( + + ); + }); return ( - - - {this.props.config.SiteName} - - - - {content} + + + + {this.props.config.SiteName} + + + + {content} + ); } diff --git a/app/scenes/select_team/select_team_container.js b/app/scenes/select_team/select_team_container.js index 92ed7e859..33b294344 100644 --- a/app/scenes/select_team/select_team_container.js +++ b/app/scenes/select_team/select_team_container.js @@ -8,17 +8,26 @@ import navigationSceneConnect from '../navigationSceneConnect'; import {closeDrawers, closeModal, goBack} from 'app/actions/navigation'; import {handleTeamChange} from 'app/actions/views/select_team'; -import {getCurrentTeam} from 'mattermost-redux/selectors/entities/teams'; +import {getCurrentTeam, getTeams, getTeamMemberships} from 'mattermost-redux/selectors/entities/teams'; +import {getCurrentUser} from 'mattermost-redux/selectors/entities/users'; import SelectTeam from './select_team.js'; function mapStateToProps(state) { + const allTeams = Object.values(getTeams(state)); + const myMembers = getTeamMemberships(state); + const user = getCurrentUser(state); + const myTeams = allTeams.filter((team) => myMembers.hasOwnProperty(team.id)); + + function sortTeams(a, b) { + return a.display_name.localeCompare(b.display_name, user.locale, {numeric: true}); + } + return { config: state.entities.general.config, teamsRequest: state.requests.teams.allTeams, - teams: state.entities.teams.teams, - currentTeam: getCurrentTeam(state), - myMembers: state.entities.teams.myMembers + teams: myTeams.sort(sortTeams), + currentTeam: getCurrentTeam(state) }; }