diff --git a/app/components/channel_drawer/channel_drawer.js b/app/components/channel_drawer/channel_drawer.js
index 71efe029e..3138eb2dc 100644
--- a/app/components/channel_drawer/channel_drawer.js
+++ b/app/components/channel_drawer/channel_drawer.js
@@ -179,6 +179,7 @@ export default class ChannelDrawer extends PureComponent {
);
diff --git a/app/components/channel_drawer_list/channel_drawer_list.js b/app/components/channel_drawer_list/channel_drawer_list.js
index 30c6a9aec..e8108231a 100644
--- a/app/components/channel_drawer_list/channel_drawer_list.js
+++ b/app/components/channel_drawer_list/channel_drawer_list.js
@@ -567,9 +567,16 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => {
},
settingsContainer: {
alignItems: 'center',
- height: 44,
justifyContent: 'center',
- width: 50
+ width: 50,
+ ...Platform.select({
+ android: {
+ height: 46
+ },
+ ios: {
+ height: 44
+ }
+ })
},
settings: {
color: theme.sidebarHeaderTextColor,
diff --git a/app/components/channel_drawer_teams/channel_drawer_teams.js b/app/components/channel_drawer_teams/channel_drawer_teams.js
index 3513c1dbd..dbc94fa84 100644
--- a/app/components/channel_drawer_teams/channel_drawer_teams.js
+++ b/app/components/channel_drawer_teams/channel_drawer_teams.js
@@ -12,33 +12,56 @@ import {
TouchableHighlight,
View
} from 'react-native';
+import {injectIntl, intlShape} from 'react-intl';
import IonIcon from 'react-native-vector-icons/Ionicons';
+import MaterialIcon from 'react-native-vector-icons/MaterialIcons';
import Badge from 'app/components/badge';
import FormattedText from 'app/components/formatted_text';
import {preventDoubleTap} from 'app/utils/tap';
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
-export default class ChannelDrawerTeams extends PureComponent {
+class ChannelDrawerTeams extends PureComponent {
static propTypes = {
actions: PropTypes.shape({
- handleTeamChange: PropTypes.func.isRequired
+ getTeams: PropTypes.func.isRequired,
+ handleTeamChange: PropTypes.func.isRequired,
+ markChannelAsRead: PropTypes.func.isRequired
}).isRequired,
canCreateTeams: PropTypes.bool.isRequired,
- canJoinTeams: PropTypes.bool.isRequired,
closeChannelDrawer: PropTypes.func.isRequired,
+ currentChannelId: PropTypes.string,
currentTeamId: PropTypes.string.isRequired,
currentUrl: PropTypes.string.isRequired,
+ intl: intlShape.isRequired,
+ joinableTeams: PropTypes.object.isRequired,
myTeamMembers: PropTypes.object.isRequired,
+ navigator: PropTypes.object.isRequired,
teams: PropTypes.array.isRequired,
theme: PropTypes.object.isRequired
};
+ constructor(props) {
+ super(props);
+
+ MaterialIcon.getImageSource('close', 20, props.theme.sidebarHeaderTextColor).
+ then((source) => {
+ this.closeButton = source;
+ });
+ }
+
+ componentWillMount() {
+ this.props.actions.getTeams();
+ }
+
selectTeam = (team) => {
- const {actions, closeChannelDrawer, currentTeamId} = this.props;
+ const {actions, closeChannelDrawer, currentChannelId, currentTeamId} = this.props;
if (team.id === currentTeamId) {
closeChannelDrawer();
} else {
+ if (currentChannelId) {
+ actions.markChannelAsRead(currentChannelId);
+ }
closeChannelDrawer();
InteractionManager.runAfterInteractions(() => {
actions.handleTeamChange(team);
@@ -46,6 +69,34 @@ export default class ChannelDrawerTeams extends PureComponent {
}
};
+ goToSelectTeam = () => {
+ const {currentUrl, intl, 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: {
+ leftButtons: [{
+ id: 'close-teams',
+ icon: this.closeButton
+ }]
+ },
+ passProps: {
+ currentUrl,
+ theme
+ }
+ });
+ };
+
renderItem = ({item}) => {
const {currentTeamId, currentUrl, myTeamMembers, theme} = this.props;
const styles = getStyleSheet(theme);
@@ -121,10 +172,25 @@ export default class ChannelDrawerTeams extends PureComponent {
};
render() {
- const {teams, theme} = this.props;
+ const {joinableTeams, teams, theme} = this.props;
const styles = getStyleSheet(theme);
let moreAction;
+ if (Object.keys(joinableTeams).length) {
+ moreAction = (
+ preventDoubleTap(this.goToSelectTeam)}
+ underlayColor={changeOpacity(theme.sidebarHeaderBg, 0.5)}
+ >
+
+ {'+'}
+
+
+ );
+ }
return (
@@ -188,6 +254,23 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => {
fontSize: 17,
fontWeight: 'normal'
},
+ moreActionContainer: {
+ alignItems: 'center',
+ justifyContent: 'center',
+ width: 50,
+ ...Platform.select({
+ android: {
+ height: 46
+ },
+ ios: {
+ height: 44
+ }
+ })
+ },
+ moreAction: {
+ color: theme.sidebarHeaderTextColor,
+ fontSize: 30
+ },
teamWrapper: {
marginTop: 20
},
@@ -250,3 +333,5 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => {
}
});
});
+
+export default injectIntl(ChannelDrawerTeams);
diff --git a/app/components/channel_drawer_teams/index.js b/app/components/channel_drawer_teams/index.js
index 051576fa4..2a93f156a 100644
--- a/app/components/channel_drawer_teams/index.js
+++ b/app/components/channel_drawer_teams/index.js
@@ -4,8 +4,11 @@
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
+import {markChannelAsRead} from 'mattermost-redux/actions/channels';
+import {getTeams} from 'mattermost-redux/actions/teams';
+import {getCurrentChannelId} from 'mattermost-redux/selectors/entities/channels';
import {getCurrentUrl} from 'mattermost-redux/selectors/entities/general';
-import {getCurrentTeamId, getMyTeams} from 'mattermost-redux/selectors/entities/teams';
+import {getCurrentTeamId, getJoinableTeams, getMyTeams} from 'mattermost-redux/selectors/entities/teams';
import {getCurrentUser} from 'mattermost-redux/selectors/entities/users';
import {handleTeamChange} from 'app/actions/views/select_team';
@@ -27,7 +30,8 @@ function mapStateToProps(state, ownProps) {
return {
canCreateTeams: false,
- canJoinTeams: false,
+ joinableTeams: getJoinableTeams(state),
+ currentChannelId: getCurrentChannelId(state),
currentTeamId: getCurrentTeamId(state),
currentUrl: removeProtocol(getCurrentUrl(state)),
teams: getMyTeams(state).sort(sortTeams.bind(null, (user.locale))),
@@ -39,7 +43,9 @@ function mapStateToProps(state, ownProps) {
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators({
- handleTeamChange
+ getTeams,
+ handleTeamChange,
+ markChannelAsRead
}, dispatch)
};
}
diff --git a/app/screens/select_team/index.js b/app/screens/select_team/index.js
index abba16342..d93a9cc82 100644
--- a/app/screens/select_team/index.js
+++ b/app/screens/select_team/index.js
@@ -7,36 +7,34 @@ import {connect} from 'react-redux';
import {handleTeamChange} from 'app/actions/views/select_team';
import {markChannelAsRead} from 'mattermost-redux/actions/channels';
+import {getTeams, joinTeam} from 'mattermost-redux/actions/teams';
import {getCurrentChannelId} from 'mattermost-redux/selectors/entities/channels';
-import {getCurrentTeam, getTeams, getTeamMemberships} from 'mattermost-redux/selectors/entities/teams';
+import {getJoinableTeams} from 'mattermost-redux/selectors/entities/teams';
import {getCurrentUser} from 'mattermost-redux/selectors/entities/users';
import SelectTeam from './select_team.js';
function mapStateToProps(state, ownProps) {
- 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 {
- ...ownProps,
- config: state.entities.general.config,
- teamsRequest: state.requests.teams.allTeams,
- teams: myTeams.sort(sortTeams),
- currentTeam: getCurrentTeam(state),
- currentChannelId: getCurrentChannelId(state)
+ teamsRequest: state.requests.teams.getTeams,
+ teams: Object.values(getJoinableTeams(state)).sort(sortTeams),
+ currentChannelId: getCurrentChannelId(state),
+ ...ownProps
};
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators({
+ getTeams,
handleTeamChange,
+ joinTeam,
markChannelAsRead
}, dispatch)
};
diff --git a/app/screens/select_team/select_team.js b/app/screens/select_team/select_team.js
index 3de46f462..c1204d7cc 100644
--- a/app/screens/select_team/select_team.js
+++ b/app/screens/select_team/select_team.js
@@ -4,107 +4,209 @@
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {
- Image,
+ FlatList,
InteractionManager,
- ScrollView,
+ StyleSheet,
Text,
+ TouchableOpacity,
View
} from 'react-native';
-import Button from 'react-native-button';
-import Icon from 'react-native-vector-icons/MaterialIcons';
import EventEmitter from 'mattermost-redux/utils/event_emitter';
-import {GlobalStyles} from 'app/styles';
import FormattedText from 'app/components/formatted_text';
-
-import logo from 'assets/images/logo.png';
+import Loading from 'app/components/loading';
+import {preventDoubleTap} from 'app/utils/tap';
+import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
export default class SelectTeam extends PureComponent {
static propTypes = {
- config: PropTypes.object.isRequired,
+ actions: PropTypes.shape({
+ getTeams: PropTypes.func.isRequired,
+ handleTeamChange: PropTypes.func.isRequired,
+ joinTeam: PropTypes.func.isRequired,
+ markChannelAsRead: PropTypes.func.isRequired
+ }).isRequired,
currentChannelId: PropTypes.string,
+ currentUrl: PropTypes.string.isRequired,
navigator: PropTypes.object,
teams: PropTypes.array.isRequired,
- actions: PropTypes.shape({
- handleTeamChange: PropTypes.func.isRequired,
- markChannelAsRead: PropTypes.func.isRequired
- }).isRequired
+ theme: PropTypes.object
};
- state = {
- disableButtons: false
+ constructor(props) {
+ super(props);
+ props.navigator.setOnNavigatorEvent(this.onNavigatorEvent);
+
+ this.state = {
+ joining: false
+ };
+ }
+
+ close = () => {
+ this.props.navigator.dismissModal({
+ animationType: 'slide-down'
+ });
};
- onSelectTeam = async (team) => {
- if (!this.state.disableButtons) {
- this.setState({disableButtons: true});
- const {
- currentChannelId,
- handleTeamChange,
- markChannelAsRead
- } = this.props.actions;
-
- if (currentChannelId) {
- markChannelAsRead(currentChannelId);
+ onNavigatorEvent = (event) => {
+ if (event.type === 'NavBarButtonPress') {
+ if (event.id === 'close-teams') {
+ this.close();
}
- handleTeamChange(team);
- EventEmitter.emit('close_channel_drawer');
- InteractionManager.runAfterInteractions(() => {
- this.props.navigator.dismissModal({
- animationType: 'slide-down'
- });
- });
}
};
- render() {
- const content = this.props.teams.map((team) => {
- return (
-
- );
+ onSelectTeam = async (team) => {
+ this.setState({joining: true});
+ const {currentChannelId} = this.props;
+ const {
+ joinTeam,
+ handleTeamChange,
+ markChannelAsRead
+ } = this.props.actions;
+
+ if (currentChannelId) {
+ markChannelAsRead(currentChannelId);
+ }
+ await joinTeam(team.invite_id, team.id);
+ handleTeamChange(team);
+ EventEmitter.emit('close_channel_drawer');
+ InteractionManager.runAfterInteractions(() => {
+ this.close();
});
+ };
+
+ renderItem = ({item}) => {
+ const {currentUrl, theme} = this.props;
+ const styles = getStyleSheet(theme);
return (
-
-
+ preventDoubleTap(this.onSelectTeam, this, item)}
>
-
-
- {this.props.config.SiteName}
-
-
-
- {content}
-
+
+
+
+ {item.display_name.substr(0, 2).toUpperCase()}
+
+
+
+
+ {item.display_name}
+
+
+ {`${currentUrl}/${item.name}`}
+
+
+
+
+
+ );
+ };
+
+ render() {
+ const {teams, theme} = this.props;
+ const styles = getStyleSheet(theme);
+
+ if (this.state.joining) {
+ return ;
+ }
+
+ return (
+
+
+
+
+
+
+
+ item.id}
+ viewabilityConfig={{
+ viewAreaCoveragePercentThreshold: 3,
+ waitForInteraction: false
+ }}
+ />
);
}
}
+
+const getStyleSheet = makeStyleSheetFromTheme((theme) => {
+ return StyleSheet.create({
+ container: {
+ backgroundColor: theme.centerChannelBg,
+ flex: 1
+ },
+ headingContainer: {
+ alignItems: 'center',
+ flexDirection: 'row',
+ marginHorizontal: 16,
+ marginTop: 20
+ },
+ headingWrapper: {
+ marginRight: 15
+ },
+ heading: {
+ color: changeOpacity(theme.centerChannelColor, 0.5),
+ fontSize: 13
+ },
+ line: {
+ backgroundColor: changeOpacity(theme.centerChannelColor, 0.2),
+ width: '100%',
+ height: StyleSheet.hairlineWidth
+ },
+ teamWrapper: {
+ marginTop: 20
+ },
+ teamContainer: {
+ alignItems: 'center',
+ flex: 1,
+ flexDirection: 'row',
+ marginHorizontal: 16
+ },
+ teamIconContainer: {
+ alignItems: 'center',
+ backgroundColor: theme.buttonBg,
+ borderRadius: 2,
+ height: 40,
+ justifyContent: 'center',
+ width: 40
+ },
+ teamIcon: {
+ color: theme.buttonColor,
+ fontFamily: 'OpenSans',
+ fontSize: 18,
+ fontWeight: '600'
+ },
+ teamNameContainer: {
+ flex: 1,
+ flexDirection: 'column',
+ marginLeft: 10
+ },
+ teamName: {
+ color: theme.centerChannelColor,
+ fontSize: 18
+ },
+ teamUrl: {
+ color: changeOpacity(theme.centerChannelColor, 0.5),
+ fontSize: 12
+ }
+ });
+});
diff --git a/assets/base/i18n/en.json b/assets/base/i18n/en.json
index cbca4aa22..733667e35 100644
--- a/assets/base/i18n/en.json
+++ b/assets/base/i18n/en.json
@@ -1755,7 +1755,7 @@
"mobile.routes.thread_dm": "Direct Message Thread",
"mobile.routes.user_profile": "Profile",
"mobile.routes.user_profile.send_message": "Send Message",
- "mobile.select_team.choose": "Your teams:",
+ "mobile.select_team.join_open": "Open teams you can join",
"mobile.server_ping_failed": "Cannot connect to the server. Please check your server URL and internet connection.",
"mobile.server_url.invalid_format": "URL must start with http:// or https://",
"mobile.session_expired": "Session Expired: Please log in to continue receiving notifications.",
diff --git a/ios/Mattermost/AppDelegate.m b/ios/Mattermost/AppDelegate.m
index d19c371ff..bca1affdc 100644
--- a/ios/Mattermost/AppDelegate.m
+++ b/ios/Mattermost/AppDelegate.m
@@ -38,7 +38,7 @@
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.window.backgroundColor = [UIColor whiteColor];
- [[RCCManager sharedInstance] initBridgeWithBundleURL:jsCodeLocation];
+ [[RCCManager sharedInstance] initBridgeWithBundleURL:jsCodeLocation launchOptions:launchOptions];
return YES;
}
diff --git a/yarn.lock b/yarn.lock
index 8dacf229e..c933480d8 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/17b85854e5fda76d4e91b1e28d1e26b4ad57394d"
+ resolved "https://codeload.github.com/mattermost/mattermost-redux/tar.gz/67a40ea6c89a5065b751f434094183956817b1d3"
dependencies:
deep-equal "1.0.1"
harmony-reflect "1.5.1"