RN-466 DND status support (#1115)

* DND status support

* Feedback review
This commit is contained in:
enahum 2017-11-10 12:51:33 -03:00 committed by GitHub
parent bc4df84519
commit 380f5d884a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 284 additions and 84 deletions

View file

@ -9,7 +9,7 @@ import {
} from 'react-native';
import Icon from 'react-native-vector-icons/FontAwesome';
import {OnlineStatus, AwayStatus, OfflineStatus} from 'app/components/status_icons';
import {AwayAvatar, DndAvatar, OfflineAvatar, OnlineAvatar} from 'app/components/status_icons';
import {General} from 'mattermost-redux/constants';
@ -90,30 +90,43 @@ export default class ChannelIcon extends React.PureComponent {
</View>
);
} else if (type === General.DM_CHANNEL) {
if (status === General.ONLINE) {
switch (status) {
case General.AWAY:
icon = (
<OnlineStatus
width={size}
height={size}
color={theme.onlineIndicator}
/>
);
} else if (status === General.AWAY) {
icon = (
<AwayStatus
<AwayAvatar
width={size}
height={size}
color={theme.awayIndicator}
/>
);
} else {
break;
case General.DND:
icon = (
<OfflineStatus
<DndAvatar
width={size}
height={size}
color={theme.dndIndicator}
/>
);
break;
case General.ONLINE:
icon = (
<OnlineAvatar
width={size}
height={size}
color={theme.onlineIndicator}
/>
);
break;
default:
icon = (
<OfflineAvatar
width={size}
height={size}
color={offlineColor}
/>
);
break;
}
}

View file

@ -77,7 +77,6 @@ class ChannelIntro extends PureComponent {
size={64}
statusBorderWidth={2}
statusSize={25}
statusIconSize={15}
/>
</TouchableOpacity>
));

View file

@ -4,8 +4,10 @@
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {Image, Platform, View} from 'react-native';
import Icon from 'react-native-vector-icons/FontAwesome';
import {General} from 'mattermost-redux/constants';
import {AwayIcon, DndIcon, OfflineIcon, OnlineIcon} from 'app/components/status_icons';
import {makeStyleSheetFromTheme} from 'app/utils/theme';
import placeholder from 'assets/images/profile.jpg';
@ -13,8 +15,10 @@ import placeholder from 'assets/images/profile.jpg';
import {Client4} from 'mattermost-redux/client';
const statusToIcon = {
online: 'check',
away: 'minus'
away: AwayIcon,
dnd: DndIcon,
offline: OfflineIcon,
online: OnlineIcon
};
const STATUS_BUFFER = Platform.select({
@ -27,7 +31,6 @@ export default class ProfilePicture extends PureComponent {
size: PropTypes.number,
statusBorderWidth: PropTypes.number,
statusSize: PropTypes.number,
statusIconSize: PropTypes.number,
user: PropTypes.object,
status: PropTypes.string,
theme: PropTypes.object.isRequired,
@ -39,8 +42,7 @@ export default class ProfilePicture extends PureComponent {
static defaultProps = {
size: 128,
statusBorderWidth: 2,
statusSize: 14,
statusIconSize: 8
statusSize: 14
};
componentDidMount() {
@ -50,38 +52,46 @@ export default class ProfilePicture extends PureComponent {
}
render() {
const style = getStyleSheet(this.props.theme);
const {theme} = this.props;
const style = getStyleSheet(theme);
let pictureUrl;
if (this.props.user) {
pictureUrl = Client4.getProfilePictureUrl(this.props.user.id, this.props.user.last_picture_update);
}
let statusIcon;
let Icon;
let iconColor;
if (this.props.status && statusToIcon[this.props.status]) {
statusIcon = (
<Icon
style={style.status}
name={statusToIcon[this.props.status]}
size={this.props.statusIconSize}
/>
);
Icon = statusToIcon[this.props.status];
switch (this.props.status) {
case General.AWAY:
iconColor = theme.awayIndicator;
break;
case General.DND:
iconColor = theme.dndIndicator;
break;
case General.ONLINE:
iconColor = theme.onlineIndicator;
break;
default:
iconColor = theme.centerChannelColor;
break;
}
} else {
statusIcon = (
<View
style={[style.offlineIcon, {
borderRadius: this.props.statusSize / 2,
height: this.props.statusSize - this.props.statusBorderWidth,
width: this.props.statusSize - this.props.statusBorderWidth,
borderWidth: Platform.select({
ios: this.props.statusBorderWidth,
android: this.props.statusBorderWidth / 2
})
}]}
/>
);
Icon = statusToIcon.offline;
iconColor = theme.centerChannelColor;
}
const statusIcon = (
<Icon
height={this.props.statusSize}
width={this.props.statusSize}
color={iconColor}
/>
);
return (
<View style={{width: this.props.size + STATUS_BUFFER, height: this.props.size + STATUS_BUFFER}}>
<Image
@ -91,32 +101,8 @@ export default class ProfilePicture extends PureComponent {
defaultSource={placeholder}
/>
{this.props.status &&
<View
style={[
style.statusWrapper,
{
width: this.props.statusSize,
height: this.props.statusSize,
borderWidth: this.props.statusBorderWidth,
borderRadius: this.props.statusSize / 2,
borderColor: this.props.theme.centerChannelBg
}
]}
>
<View
style={[
style.statusContainer,
{
width: this.props.statusSize - this.props.statusBorderWidth,
height: this.props.statusSize - this.props.statusBorderWidth,
borderRadius: (this.props.statusSize - this.props.statusBorderWidth) / 2,
padding: this.props.statusBorderWidth
},
style[this.props.status]
]}
>
{statusIcon}
</View>
<View style={[style.statusWrapper, {borderRadius: this.props.statusSize / 2}]}>
{statusIcon}
</View>
}
</View>
@ -131,13 +117,9 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => {
bottom: 0,
right: 0,
overflow: 'hidden',
alignItems: 'center',
justifyContent: 'center'
},
statusContainer: {
alignItems: 'center',
justifyContent: 'center',
overflow: 'hidden'
backgroundColor: theme.centerChannelBg
},
status: {
color: theme.centerChannelBg
@ -148,6 +130,9 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => {
away: {
backgroundColor: theme.awayIndicator
},
dnd: {
backgroundColor: 'red'
},
offline: {
backgroundColor: theme.centerChannelBg
},

View file

@ -0,0 +1,49 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {View} from 'react-native';
import Svg, {
Circle,
G,
Path
} from 'react-native-svg';
export default class AwayAvatar extends PureComponent {
static propTypes = {
width: PropTypes.number.isRequired,
height: PropTypes.number.isRequired,
color: PropTypes.string.isRequired
};
render() {
const {color, height, width} = this.props;
return (
<View style={{height, width, alignItems: 'flex-start'}}>
<Svg
width={width}
height={height}
viewBox='0 0 12 12'
>
<G transform='matrix(1,0,0,1,299,-391)'>
<Circle
cx='-294.5'
cy='394'
r='2.5'
fill={color}
/>
<Path
d='M-294.3,399.7C-294.3,399.3 -294.2,398.9 -294.1,398.5C-294.2,398.5 -294.3,398.5 -294.5,398.5C-297,398.5 -297,396.5 -297,396.5C-297,396.5 -298,396.6 -298.2,397C-298.6,397.6 -298.8,398.7 -298.9,399.5C-298.9,399.6 -299,400 -298.9,400.1C-298.7,401.4 -296.7,402.4 -294.5,402.5L-294.3,402.5C-294,402.5 -293.6,402.5 -293.3,402.4C-293.9,401.6 -294.3,400.7 -294.3,399.7Z'
fill={color}
/>
</G>
<Path
d='M8.415,5C8.614,5 8.775,5.161 8.775,5.36L8.775,8.352L11.49,10.334C11.651,10.451 11.686,10.677 11.569,10.837L10.932,11.709C10.814,11.87 10.589,11.905 10.429,11.788L7.261,9.475C7.243,9.463 7.226,9.451 7.21,9.437L7.123,9.374C7.009,9.291 6.959,9.154 6.98,9.024C6.977,8.999 6.975,8.973 6.975,8.946L6.975,5.36C6.975,5.161 7.137,5 7.335,5L8.415,5Z'
fill={color}
/>
</Svg>
</View>
);
}
}

View file

@ -0,0 +1,37 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {View} from 'react-native';
import Svg, {
Path
} from 'react-native-svg';
export default class AwayIcon extends PureComponent {
static propTypes = {
width: PropTypes.number.isRequired,
height: PropTypes.number.isRequired,
color: PropTypes.string.isRequired
};
render() {
const {color, height, width} = this.props;
return (
<View style={{height, width, alignItems: 'flex-start'}}>
<Svg
width={width}
height={height}
viewBox='0 0 20 20'
>
<Path
d='M10,0C15.519,0 20,4.481 20,10C20,15.519 15.519,20 10,20C4.481,20 0,15.519 0,10C0,4.481 4.481,0 10,0ZM10.27,3C10.949,3 11.5,3.586 11.5,4.307L11.5,9.379L15.002,12.881C15.492,13.37 15.499,14.158 15.019,14.638L14.638,15.019C14.158,15.499 13.37,15.492 12.881,15.002L8.887,11.008C8.739,10.861 8.636,10.686 8.576,10.501C8.528,10.402 8.5,10.299 8.5,10.193L8.5,4.307C8.5,3.586 9.051,3 9.73,3L10.27,3Z'
fill={color}
fillRule='evenodd'
/>
</Svg>
</View>
);
}
}

View file

@ -1,4 +1,4 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import React, {PureComponent} from 'react';
@ -10,7 +10,7 @@ import Svg, {
Path
} from 'react-native-svg';
export default class AwayStatus extends PureComponent {
export default class DndAvatar extends PureComponent {
static propTypes = {
width: PropTypes.number.isRequired,
height: PropTypes.number.isRequired,

View file

@ -0,0 +1,35 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {View} from 'react-native';
import Svg, {
Path
} from 'react-native-svg';
export default class DndIcon extends PureComponent {
static propTypes = {
width: PropTypes.number.isRequired,
height: PropTypes.number.isRequired,
color: PropTypes.string.isRequired
};
render() {
const {color, height, width} = this.props;
return (
<View style={{height, width, alignItems: 'flex-start'}}>
<Svg
width={width}
height={height}
viewBox='0 0 20 20'
>
<Path
d='M10,0c5.519,0 10,4.481 10,10c0,5.519 -4.481,10 -10,10c-5.519,0 -10,-4.481 -10,-10c0,-5.519 4.481,-10 10,-10Zm5.25,8.5l-10.5,0c-0.414,0 -0.75,0.336 -0.75,0.75l0,1.5c0,0.414 0.336,0.75 0.75,0.75l10.5,0c0.414,0 0.75,-0.336 0.75,-0.75l0,-1.5c0,-0.414 -0.336,-0.75 -0.75,-0.75Z'
fill={color}
fillRule='evenodd'
/>
</Svg>
</View>
);
}
}

View file

@ -1,12 +1,22 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import OnlineStatus from './online';
import AwayStatus from './away';
import OfflineStatus from './offline';
import AwayAvatar from './away_avatar';
import AwayIcon from './away_icon';
import DndAvatar from './dnd_avatar';
import DndIcon from './dnd_icon';
import OfflineAvatar from './offline_avatar';
import OfflineIcon from './offline_icon';
import OnlineAvatar from './online_avatar';
import OnlineIcon from './online_icon';
export {
OnlineStatus,
AwayStatus,
OfflineStatus
AwayAvatar,
AwayIcon,
DndAvatar,
DndIcon,
OfflineAvatar,
OfflineIcon,
OnlineAvatar,
OnlineIcon
};

View file

@ -0,0 +1,37 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {View} from 'react-native';
import Svg, {
Path
} from 'react-native-svg';
export default class OfflineIcon extends PureComponent {
static propTypes = {
width: PropTypes.number.isRequired,
height: PropTypes.number.isRequired,
color: PropTypes.string.isRequired
};
render() {
const {color, height, width} = this.props;
return (
<View style={{height, width, alignItems: 'flex-start'}}>
<Svg
width={width}
height={height}
viewBox='0 0 20 20'
>
<Path
d='M10,0c5.519,0 10,4.481 10,10c0,5.519 -4.481,10 -10,10c-5.519,0 -10,-4.481 -10,-10c0,-5.519 4.481,-10 10,-10Zm0,2c4.415,0 8,3.585 8,8c0,4.415 -3.585,8 -8,8c-4.415,0 -8,-3.585 -8,-8c0,-4.415 3.585,-8 8,-8Z'
fill={color}
fillOpacity={0.5}
fillRule='evenodd'
/>
</Svg>
</View>
);
}
}

View file

@ -0,0 +1,36 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {View} from 'react-native';
import Svg, {
Path
} from 'react-native-svg';
export default class OnlineIcon extends PureComponent {
static propTypes = {
width: PropTypes.number.isRequired,
height: PropTypes.number.isRequired,
color: PropTypes.string.isRequired
};
render() {
const {color, height, width} = this.props;
return (
<View style={{height, width, alignItems: 'flex-start'}}>
<Svg
width={width}
height={height}
viewBox='0 0 20 20'
>
<Path
d='M10,0c5.519,0 10,4.481 10,10c0,5.519 -4.481,10 -10,10c-5.519,0 -10,-4.481 -10,-10c0,-5.519 4.481,-10 10,-10Zm6.19,7.18c0,0.208 -0.075,0.384 -0.224,0.53l-5.782,5.64l-1.087,1.059c-0.149,0.146 -0.33,0.218 -0.543,0.218c-0.213,0 -0.394,-0.072 -0.543,-0.218l-1.086,-1.059l-2.891,-2.82c-0.149,-0.146 -0.224,-0.322 -0.224,-0.53c0,-0.208 0.075,-0.384 0.224,-0.53l1.086,-1.059c0.149,-0.146 0.33,-0.218 0.543,-0.218c0.213,0 0.394,0.072 0.543,0.218l2.348,2.298l5.24,-5.118c0.149,-0.146 0.33,-0.218 0.543,-0.218c0.213,0 0.394,0.072 0.543,0.218l1.086,1.059c0.149,0.146 0.224,0.322 0.224,0.53Z'
fill={color}
fillRule='evenodd'
/>
</Svg>
</View>
);
}
}

View file

@ -160,7 +160,6 @@ class UserProfile extends PureComponent {
size={150}
statusBorderWidth={6}
statusSize={40}
statusIconSize={18}
/>
{this.getDisplayName()}
<Text style={style.username}>{`@${user.username}`}</Text>

View file

@ -39,7 +39,7 @@
"react-native-passcode-status": "1.1.0",
"react-native-sentry": "0.15.1",
"react-native-status-bar-size": "0.3.2",
"react-native-svg": "5.4.2",
"react-native-svg": "6.0.0",
"react-native-tooltip": "enahum/react-native-tooltip",
"react-native-vector-icons": "4.4.2",
"react-native-youtube": "1.0.1",

View file

@ -3938,7 +3938,7 @@ makeerror@1.0.x:
mattermost-redux@mattermost/mattermost-redux#master:
version "1.0.1"
resolved "https://codeload.github.com/mattermost/mattermost-redux/tar.gz/c00dc5a7464d5a96e0370b8d210a3b1b0449327b"
resolved "https://codeload.github.com/mattermost/mattermost-redux/tar.gz/5c0383e2ab08b4419c8a99b79f402ab9ba1fa6c8"
dependencies:
deep-equal "1.0.1"
form-data "2.3.1"