diff --git a/app/actions/views/channel.js b/app/actions/views/channel.js index ce11e28e6..990e30482 100644 --- a/app/actions/views/channel.js +++ b/app/actions/views/channel.js @@ -7,6 +7,7 @@ import {ViewTypes} from 'app/constants'; import {fetchMyChannelsAndMembers, getMyChannelMembers, selectChannel} from 'service/actions/channels'; import {getPosts} from 'service/actions/posts'; +import {savePreferences, deletePreferences} from 'service/actions/preferences'; import {getTeamMembersByIds} from 'service/actions/teams'; import {Constants, UsersTypes} from 'service/constants'; import {getChannelByName, getDirectChannelName} from 'service/utils/channel_utils'; @@ -114,3 +115,31 @@ export function handlePostDraftChanged(postDraft) { }, getState); }; } + +export function closeDMChannel(channel) { + return async(dispatch, getState) => { + const state = getState(); + const userId = state.entities.users.currentId; + + const dm = [{ + user_id: userId, + category: Constants.CATEGORY_DIRECT_CHANNEL_SHOW, + name: channel.teammate_id, + value: 'false' + }]; + + if (channel.isFavorite) { + const fav = [{ + user_id: userId, + category: Constants.CATEGORY_FAVORITE_CHANNEL, + name: channel.id + }]; + deletePreferences(fav)(dispatch, getState); + } + savePreferences(dm)(dispatch, getState).then(() => { + if (channel.isCurrent) { + selectInitialChannel(state.entities.teams.currentId)(dispatch, getState); + } + }); + }; +} diff --git a/app/components/channel_drawer/channel_drawer.js b/app/components/channel_drawer/channel_drawer.js index 3b5f1d1a8..3cb2a1a48 100644 --- a/app/components/channel_drawer/channel_drawer.js +++ b/app/components/channel_drawer/channel_drawer.js @@ -14,6 +14,7 @@ export default class ChannelDrawer extends React.Component { actions: React.PropTypes.shape({ selectChannel: React.PropTypes.func.isRequired, viewChannel: React.PropTypes.func.isRequired, + closeDMChannel: React.PropTypes.func.isRequired, closeChannelDrawer: React.PropTypes.func.isRequired }).isRequired, currentTeam: React.PropTypes.object, @@ -93,6 +94,7 @@ export default class ChannelDrawer extends React.Component { theme={theme} onSelectChannel={this.props.actions.selectChannel} onViewChannel={this.props.actions.viewChannel} + handleCloseDM={this.props.actions.closeDMChannel} closeChannelDrawer={this.props.actions.closeChannelDrawer} /> } diff --git a/app/components/channel_drawer/channel_drawer_container.js b/app/components/channel_drawer/channel_drawer_container.js index 0893da2c5..bbcc094dc 100644 --- a/app/components/channel_drawer/channel_drawer_container.js +++ b/app/components/channel_drawer/channel_drawer_container.js @@ -5,6 +5,7 @@ import {bindActionCreators} from 'redux'; import {connect} from 'react-redux'; import {selectChannel, viewChannel} from 'service/actions/channels'; +import {closeDMChannel} from 'app/actions/views/channel'; import {getChannelsByCategory} from 'service/selectors/entities/channels'; import {closeChannelDrawer} from 'app/actions/views/drawer'; import ChannelDrawer from './channel_drawer'; @@ -25,6 +26,7 @@ function mapDispatchToProps(dispatch) { actions: bindActionCreators({ selectChannel, viewChannel, + closeDMChannel, closeChannelDrawer }, dispatch) }; diff --git a/app/components/channel_drawer/channel_item.js b/app/components/channel_drawer/channel_item.js index ef5a739b4..95642dc99 100644 --- a/app/components/channel_drawer/channel_item.js +++ b/app/components/channel_drawer/channel_item.js @@ -16,6 +16,7 @@ export default class ChannelItem extends React.Component { static propTypes = { channel: React.PropTypes.object.isRequired, onSelectChannel: React.PropTypes.func.isRequired, + handleClose: React.PropTypes.func, isActive: React.PropTypes.bool.isRequired, hasUnread: React.PropTypes.bool.isRequired, mentions: React.PropTypes.number.isRequired, @@ -28,7 +29,8 @@ export default class ChannelItem extends React.Component { theme, mentions, hasUnread, - isActive + isActive, + handleClose } = this.props; let iconColor = changeOpacity(theme.centerChannelColor, 0.7); @@ -39,7 +41,7 @@ export default class ChannelItem extends React.Component { if (mentions && !isActive) { const badgeStyle = { position: 'absolute', - top: 10, + top: 12, right: 10, flexDirection: 'row', backgroundColor: theme.mentionBj @@ -63,7 +65,7 @@ export default class ChannelItem extends React.Component { const itemStyle = { alignItems: 'center', - height: 40, + height: 45, paddingLeft: 20, paddingRight: 10, flex: 1, @@ -73,12 +75,13 @@ export default class ChannelItem extends React.Component { const style = { marginLeft: 5, opacity: 0.6, + fontSize: 15, color: theme.sidebarText }; const activeStyle = { width: 5, - height: 40, + height: 45, backgroundColor: theme.sidebarTextActiveBorder, position: 'absolute' }; @@ -149,6 +152,33 @@ export default class ChannelItem extends React.Component { } } + let closeButton = null; + if (handleClose && !badge) { + const closeStyle = { + position: 'absolute', + justifyContent: 'center', + alignItems: 'center', + opacity: 0.4, + width: 50, + height: 50, + right: 0, + flexDirection: 'row' + }; + + closeButton = ( + handleClose(channel)} + > + + + ); + } + return ( {badge} + {closeButton} diff --git a/app/components/channel_drawer/channel_list.js b/app/components/channel_drawer/channel_list.js index f13ee8c6c..78458aa10 100644 --- a/app/components/channel_drawer/channel_list.js +++ b/app/components/channel_drawer/channel_list.js @@ -3,8 +3,10 @@ import React from 'react'; -import {StyleSheet, Text, View, ListView} from 'react-native'; +import {Alert, StyleSheet, Text, View, ListView} from 'react-native'; +import {injectIntl, intlShape} from 'react-intl'; import {buildDisplayNameAndTypeComparable} from 'service/utils/channel_utils'; +import {Constants} from 'service/constants'; import LineDivider from 'app/components/line_divider'; import ChannelItem from './channel_item'; import FormattedText from 'app/components/formatted_text'; @@ -48,8 +50,9 @@ const Styles = StyleSheet.create({ } }); -export default class ChannelList extends React.Component { +class ChannelList extends React.Component { static propTypes = { + intl: intlShape.isRequired, currentTeam: React.PropTypes.object.isRequired, currentChannel: React.PropTypes.object, channels: React.PropTypes.object.isRequired, @@ -57,6 +60,7 @@ export default class ChannelList extends React.Component { theme: React.PropTypes.object.isRequired, onSelectChannel: React.PropTypes.func.isRequired, onViewChannel: React.PropTypes.func.isRequired, + handleCloseDM: React.PropTypes.func.isRequired, closeChannelDrawer: React.PropTypes.func.isRequired }; @@ -140,6 +144,25 @@ export default class ChannelList extends React.Component { this.props.closeChannelDrawer(); }; + handleClose = (channel) => { + const {formatMessage} = this.props.intl; + Alert.alert( + formatMessage({id: 'mobile.channel_list.alertTitleCloseDM', defaultMessage: 'Close Direct Message'}), + formatMessage({ + id: 'mobile.channel_list.alertMessageCloseDM', + defaultMessage: 'Are you sure you want to close the DM with {username}' + }, { + username: channel.display_name + }), + [ + {text: formatMessage({id: 'mobile.channel_list.alertNo', defaultMessage: 'No'})}, + { + text: formatMessage({id: 'mobile.channel_list.alertYes', defaultMessage: 'Yes'}), + onPress: () => this.props.handleCloseDM(channel) + }] + ); + }; + getUnreadMessages = (channel) => { const member = this.props.channelMembers[channel.id]; let mentions = 0; @@ -186,6 +209,7 @@ export default class ChannelList extends React.Component { hasUnread={unread} mentions={mentions} onSelectChannel={this.onSelectChannel} + handleClose={channel.type === Constants.DM_CHANNEL ? this.handleClose : null} isActive={channel.isCurrent} theme={this.props.theme} /> @@ -336,3 +360,5 @@ export default class ChannelList extends React.Component { ); } } + +export default injectIntl(ChannelList); diff --git a/assets/base/i18n/en.json b/assets/base/i18n/en.json index 0709b14bf..e1e72238b 100644 --- a/assets/base/i18n/en.json +++ b/assets/base/i18n/en.json @@ -1480,6 +1480,10 @@ "member_list.noUsersAdd": "No users to add.", "members_popover.msg": "Message", "members_popover.title": "Members", + "mobile.channel_list.alertTitleCloseDM": "Close Direct Message", + "mobile.channel_list.alertMessageCloseDM": "Are you sure you want to close the DM with {username}", + "mobile.channel_list.alertNo": "No", + "mobile.channel_list.alertYes": "Yes", "mobile.components.channels_list_view.yourChannels": "Your channels:", "mobile.components.select_server_view.enterServerUrl": "Enter Server URL", "mobile.components.select_server_view.continue": "Continue", diff --git a/service/utils/channel_utils.js b/service/utils/channel_utils.js index cc0e25d9b..0378a7733 100644 --- a/service/utils/channel_utils.js +++ b/service/utils/channel_utils.js @@ -98,7 +98,8 @@ function isDirectChannelVisible(userId, myPreferences, channel) { function isFavoriteChannel(myPreferences, channel) { const fav = myPreferences[`${Constants.CATEGORY_FAVORITE_CHANNEL}--${channel.id}`]; - return fav && fav.value === 'true'; + channel.isFavorite = fav && fav.value === 'true'; + return channel.isFavorite; } function createMissingDirectChannels(currentUserId, allChannels, myPreferences) {