Files
mattermost-mobile/app/screens/notification/notification.js
Elias Nahum 1a1c73279b Upgrade Dependencies (#4034)
* Upgrade Navigation library

* Fix background color on Select Server

* Upgrade Navigation library

* Apply patch to nav lib

* Upgrade RNN to 6.1.1

* Update Dependencies

* Feedback review

* Call clearNavigationComponents when reset to channel
2020-03-18 19:09:20 -03:00

403 lines
12 KiB
JavaScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {
Image,
InteractionManager,
Platform,
StyleSheet,
TouchableOpacity,
Text,
View,
} from 'react-native';
import {Navigation} from 'react-native-navigation';
import * as Animatable from 'react-native-animatable';
import {PanGestureHandler} from 'react-native-gesture-handler';
import {Client4} from 'mattermost-redux/client';
import {isDirectChannel} from 'mattermost-redux/utils/channel_utils';
import EventEmitter from 'mattermost-redux/utils/event_emitter';
import {displayUsername} from 'mattermost-redux/utils/user_utils';
import {popToRoot, dismissAllModals, dismissOverlay} from 'app/actions/navigation';
import FormattedText from 'app/components/formatted_text';
import ProfilePicture from 'app/components/profile_picture';
import {NavigationTypes} from 'app/constants';
import {changeOpacity} from 'app/utils/theme';
import logo from 'assets/images/icon.png';
import webhookIcon from 'assets/images/icons/webhook.jpg';
const IMAGE_SIZE = 33;
const AUTO_DISMISS_TIME_MILLIS = 5000;
export default class Notification extends PureComponent {
static propTypes = {
actions: PropTypes.shape({
loadFromPushNotification: PropTypes.func.isRequired,
}).isRequired,
componentId: PropTypes.string.isRequired,
channel: PropTypes.object,
config: PropTypes.object,
deviceWidth: PropTypes.number.isRequired,
notification: PropTypes.object.isRequired,
teammateNameDisplay: PropTypes.string,
theme: PropTypes.object.isRequired,
user: PropTypes.object,
};
state = {
keyFrames: {
from: {
translateY: -100,
},
to: {
translateY: 0,
},
},
}
tapped = false;
componentDidMount() {
this.setDismissTimer();
this.setDidDisappearListener();
this.setShowOverlayListener();
}
componentWillUnmount() {
this.clearDismissTimer();
this.clearDidDisappearListener();
this.clearShowOverlayListener();
}
setDismissTimer = () => {
this.dismissTimer = setTimeout(() => {
if (!this.tapped) {
this.animateDismissOverlay();
}
}, AUTO_DISMISS_TIME_MILLIS);
}
clearDismissTimer = () => {
if (this.dismissTimer) {
clearTimeout(this.dismissTimer);
this.dismissTimer = null;
}
}
setDidDisappearListener = () => {
this.didDismissListener = Navigation.events().registerComponentDidDisappearListener(async ({componentId}) => {
if (componentId === this.props.componentId && this.tapped) {
await dismissAllModals();
await popToRoot();
}
});
}
clearDidDisappearListener = () => {
this.didDismissListener.remove();
}
setShowOverlayListener = () => {
EventEmitter.on(NavigationTypes.NAVIGATION_SHOW_OVERLAY, this.onNewOverlay);
}
clearShowOverlayListener = () => {
EventEmitter.off(NavigationTypes.NAVIGATION_SHOW_OVERLAY, this.onNewOverlay);
}
onNewOverlay = () => {
// Dismiss this overlay so that there is only ever one.
this.dismissOverlay();
}
dismissOverlay = () => {
this.clearDismissTimer();
const {componentId} = this.props;
dismissOverlay(componentId);
}
animateDismissOverlay = () => {
this.clearDismissTimer();
this.setState({
keyFrames: {
from: {
translateY: 0,
},
to: {
translateY: -100,
},
},
});
setTimeout(() => this.dismissOverlay(), 1000);
}
notificationTapped = () => {
this.tapped = true;
this.clearDismissTimer();
const {actions, notification} = this.props;
EventEmitter.emit(NavigationTypes.CLOSE_MAIN_SIDEABR);
EventEmitter.emit(NavigationTypes.CLOSE_SETTINGS_SIDEBAR);
this.dismissOverlay();
InteractionManager.runAfterInteractions(() => {
if (!notification.localNotification) {
actions.loadFromPushNotification(notification);
}
});
};
getNotificationIcon = () => {
const {config, notification, user} = this.props;
const {data} = notification;
let icon = (
<Image
source={logo}
style={style.icon}
/>
);
if (data.from_webhook && config.EnablePostIconOverride === 'true' && data.use_user_icon !== 'true') {
const overrideIconURL = Client4.getAbsoluteUrl(data.override_icon_url); // eslint-disable-line camelcase
const wsIcon = data.override_icon_url ? {uri: overrideIconURL} : webhookIcon;
icon = (
<Image
source={wsIcon}
style={style.icon}
/>
);
} else if (user) {
icon = (
<ProfilePicture
userId={user.id}
size={IMAGE_SIZE}
/>
);
}
return icon;
};
getNotificationTitle = (notification) => {
const {channel} = this.props;
const {message, data} = notification;
if (data.version === 'v2') {
if (data.channel_name) {
return (
<Text
numberOfLines={1}
ellipsizeMode='tail'
style={style.title}
>
{data.channel_name}
</Text>
);
}
return null;
}
const msg = message.split(':');
const titleText = msg.shift();
let title = (
<Text
numberOfLines={1}
ellipsizeMode='tail'
style={style.title}
>
{titleText}
</Text>
);
const userName = this.getNotificationUserName();
if (userName && channel) {
let channelName;
let inText;
if (!isDirectChannel(channel)) {
inText = (
<FormattedText
id='mobile.notification.in'
defaultMessage=' in '
style={style.message}
/>
);
channelName = (
<Text
numberOfLines={1}
ellipsizeMode='tail'
style={[style.title, style.channelName]}
>
{channel.display_name}
</Text>
);
}
title = (
<View style={{flex: 1, flexDirection: 'row'}}>
{userName}
{inText}
{channelName}
</View>
);
}
return title;
};
getNotificationUserName = () => {
const {config, notification, teammateNameDisplay, user} = this.props;
const {data} = notification;
let userName;
if (data.override_username && config.EnablePostUsernameOverride === 'true') {
userName = (
<Text style={style.title}>
{data.override_username}
</Text>
);
} else if (user) {
userName = (
<Text style={style.title}>
{displayUsername(user, teammateNameDisplay)}
</Text>
);
}
return userName;
};
render() {
const {notification} = this.props;
const {data, message} = notification;
if (message) {
let messageText;
if (data.version !== 'v2') {
const msg = message.split(':');
messageText = msg.join('').trim();
} else if (Platform.OS === 'ios') {
messageText = message.body || message;
} else {
messageText = message;
}
const title = this.getNotificationTitle(notification);
const icon = this.getNotificationIcon();
return (
<PanGestureHandler
onGestureEvent={this.animateDismissOverlay}
minOffsetY={-20}
>
<Animatable.View
duration={250}
style={style.container}
useNativeDriver={true}
animation={this.state.keyFrames}
>
<View style={{flex: 1}}>
<TouchableOpacity
style={{flex: 1, flexDirection: 'row'}}
onPress={this.notificationTapped}
activeOpacity={1}
>
<View style={style.iconContainer}>
{icon}
</View>
<View style={style.textContainer}>
{title}
<View style={{flex: 1}}>
<Text
numberOfLines={1}
ellipsizeMode='tail'
style={style.message}
>
{messageText}
</Text>
</View>
</View>
</TouchableOpacity>
</View>
</Animatable.View>
</PanGestureHandler>
);
}
return null;
}
}
const style = StyleSheet.create({
container: {
alignItems: 'flex-start',
backgroundColor: changeOpacity('#000', 1),
flexDirection: 'row',
justifyContent: 'flex-start',
paddingHorizontal: 10,
width: '100%',
...Platform.select({
android: {
height: 68,
},
ios: {
height: 88,
},
}),
},
iconContainer: {
...Platform.select({
android: {
paddingTop: 17,
},
ios: {
paddingTop: 37,
},
}),
},
icon: {
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: '#FFFFFF',
fontSize: 14,
},
});