diff --git a/app/components/root/root.js b/app/components/root/root.js index a8a7914d1..791362551 100644 --- a/app/components/root/root.js +++ b/app/components/root/root.js @@ -37,7 +37,7 @@ export default class Root extends PureComponent { navigator.showInAppNotification({ screen: 'Notification', position: 'top', - autoDismissTimerSec: 15, + autoDismissTimerSec: 5, dismissWithSwipe: true, passProps: { notification diff --git a/app/mattermost.js b/app/mattermost.js index 854071e22..e78369586 100644 --- a/app/mattermost.js +++ b/app/mattermost.js @@ -128,6 +128,11 @@ export default class Mattermost { notification = { data: { channel_id: deviceNotification.channel_id, + channel_name: deviceNotification.channel_name, + sender_id: deviceNotification.sender_id, + override_username: deviceNotification.override_username, + override_icon_url: deviceNotification.override_icon_url, + from_webhook: deviceNotification.from_webhook, team_id: deviceNotification.team_id }, message diff --git a/app/screens/index.js b/app/screens/index.js index f5980dbad..17a216224 100644 --- a/app/screens/index.js +++ b/app/screens/index.js @@ -61,7 +61,7 @@ export function registerScreens(store, Provider) { Navigation.registerComponent('MoreChannels', () => wrapWithContextProvider(MoreChannels), store, Provider); Navigation.registerComponent('MoreDirectMessages', () => wrapWithContextProvider(MoreDirectMessages), store, Provider); Navigation.registerComponent('OptionsModal', () => wrapWithContextProvider(OptionsModal), store, Provider); - Navigation.registerComponent('Notification', () => Notification, store, Provider); + Navigation.registerComponent('Notification', () => wrapWithContextProvider(Notification), store, Provider); Navigation.registerComponent('Root', () => Root, store, Provider); Navigation.registerComponent('SelectServer', () => wrapWithContextProvider(SelectServer), store, Provider); Navigation.registerComponent('SelectTeam', () => wrapWithContextProvider(SelectTeam), store, Provider); diff --git a/app/screens/notification/index.js b/app/screens/notification/index.js index 928a726ff..47c3ff663 100644 --- a/app/screens/notification/index.js +++ b/app/screens/notification/index.js @@ -7,11 +7,31 @@ import {connect} from 'react-redux'; import {goToNotification} from 'app/actions/views/root'; import {getTheme} from 'app/selectors/preferences'; +import {getChannel} from 'mattermost-redux/selectors/entities/channels'; +import {getMyPreferences} from 'mattermost-redux/selectors/entities/preferences'; +import {getUser} from 'mattermost-redux/selectors/entities/users'; + import Notification from './notification'; function mapStateToProps(state, ownProps) { + const {data} = ownProps.notification; + + let user; + if (data.sender_id) { + user = getUser(state, data.sender_id); + } + + let channel; + if (data.channel_id) { + channel = getChannel(state, data.channel_id); + } + return { ...ownProps, + config: state.entities.general.config, + channel, + user, + myPreferences: getMyPreferences(state), theme: getTheme(state) }; } diff --git a/app/screens/notification/notification.js b/app/screens/notification/notification.js index a107bde5e..45b7b91db 100644 --- a/app/screens/notification/notification.js +++ b/app/screens/notification/notification.js @@ -13,18 +13,30 @@ import { View } from 'react-native'; +import FormattedText from 'app/components/formatted_text'; +import ProfilePicture from 'app/components/profile_picture'; import {changeOpacity} from 'app/utils/theme'; -import icon from 'assets/images/icon.png'; +import {isDirectChannel} from 'mattermost-redux/utils/channel_utils'; +import {displayUsername} from 'mattermost-redux/utils/user_utils'; + +import logo from 'assets/images/icon.png'; +import webhookIcon from 'assets/images/icons/webhook.jpg'; + +const IMAGE_SIZE = 33; export default class Notification extends PureComponent { static propTypes = { actions: PropTypes.shape({ goToNotification: PropTypes.func.isRequired }).isRequired, + channel: PropTypes.object, + config: PropTypes.object, notification: PropTypes.object.isRequired, + myPreferences: PropTypes.object.isRequired, navigator: PropTypes.object, - theme: PropTypes.object.isRequired + theme: PropTypes.object.isRequired, + user: PropTypes.object }; notificationTapped = () => { @@ -46,57 +58,209 @@ export default class Notification extends PureComponent { } }; - render() { - return ( - - - - - - - - {this.props.notification.message} - - - - + getNotificationIcon = () => { + const {config, notification, user} = this.props; + const {data} = notification; + + let icon = ( + ); + + if (data.from_webhook && config.EnablePostIconOverride === 'true') { + const wsIcon = data.override_icon_url ? {uri: data.override_icon_url} : webhookIcon; + icon = ( + + ); + } else if (user) { + icon = ( + + ); + } + + return icon; + }; + + getNotificationTitle = (titleText) => { + const {channel} = this.props; + + let title = ( + + {titleText} + + ); + + const userName = this.getNotificationUserName(); + if (userName && channel) { + let channelName; + let inText; + if (!isDirectChannel(channel)) { + inText = ( + + ); + + channelName = ( + + {channel.display_name} + + ); + } + + title = ( + + {userName} + {inText} + {channelName} + + ); + } + + return title; + }; + + getNotificationUserName = () => { + const {config, notification, myPreferences, user} = this.props; + const {data} = notification; + + let userName; + if (data.override_username && config.EnablePostUsernameOverride === 'true') { + userName = ( + + {data.override_username} + + ); + } else if (user) { + userName = ( + + {displayUsername(user, myPreferences)} + + ); + } + + return userName; + }; + + render() { + const {message} = this.props.notification; + + if (message) { + const msg = message.split(':'); + const titleText = msg.shift(); + const messageText = msg.join('').trim(); + + const title = this.getNotificationTitle(titleText); + const icon = this.getNotificationIcon(); + + return ( + + + + {icon} + + + {title} + + + {messageText} + + + + + + ); + } + + return null; } } const style = StyleSheet.create({ container: { - alignItems: 'center', + alignItems: 'flex-start', backgroundColor: changeOpacity('#000', 0.9), flexDirection: 'row', justifyContent: 'flex-start', - padding: 10, + paddingHorizontal: 10, width: Dimensions.get('window').width, ...Platform.select({ android: { - height: 60 + height: 68 }, ios: { - height: 80 + height: 88 + } + }) + }, + iconContainer: { + ...Platform.select({ + android: { + paddingTop: 17 + }, + ios: { + paddingTop: 37 } }) }, icon: { - borderRadius: 15, - height: 30, - width: 30 + borderRadius: (IMAGE_SIZE / 2), + height: IMAGE_SIZE, + width: IMAGE_SIZE + }, + textContainer: { + flex: 1, + flexDirection: 'column', + alignSelf: 'stretch', + alignItems: 'flex-start', + marginLeft: 10, + ...Platform.select({ + android: { + marginTop: 17, + height: 50 + }, + ios: { + paddingTop: 37 + } + }) + }, + title: { + color: '#FFFFFF', + fontSize: 14, + fontWeight: '600' + }, + channelName: { + alignSelf: 'stretch', + alignItems: 'flex-start', + flex: 1 }, message: { - color: 'white', - fontSize: 13 + color: '#FFFFFF', + fontSize: 14 } }); diff --git a/app/screens/select_team/select_team.js b/app/screens/select_team/select_team.js index 71e8690ba..b59d783c3 100644 --- a/app/screens/select_team/select_team.js +++ b/app/screens/select_team/select_team.js @@ -99,7 +99,7 @@ export default class SelectTeam extends PureComponent { /> {content} diff --git a/app/screens/settings/settings.js b/app/screens/settings/settings.js index a3d446c49..7f4b557bb 100644 --- a/app/screens/settings/settings.js +++ b/app/screens/settings/settings.js @@ -156,7 +156,7 @@ class Settings extends PureComponent { {showTeamSelection && this.handlePress(this.goToSelectTeam)} diff --git a/assets/base/i18n/en.json b/assets/base/i18n/en.json index 6e75579a5..1124cc5c7 100644 --- a/assets/base/i18n/en.json +++ b/assets/base/i18n/en.json @@ -1712,6 +1712,7 @@ "mobile.loading_members": "Loading Members...", "mobile.loading_posts": "Loading Messages...", "mobile.login_options.choose_title": "Choose your login method", + "mobile.notification.in": " in ", "mobile.offlineIndicator.connected": "Connected", "mobile.offlineIndicator.connecting": "Connecting...", "mobile.offlineIndicator.offline": "No internet connection", @@ -1743,6 +1744,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.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/yarn.lock b/yarn.lock index ba3650cd7..63de2378e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3526,7 +3526,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/dad1a74263edb36271bf422cef977a06ac56815c" + resolved "https://codeload.github.com/mattermost/mattermost-redux/tar.gz/6990daa5f010539075fe3657d379a6cd131b971a" dependencies: deep-equal "1.0.1" harmony-reflect "1.5.1"