[IMPROVEMENT] User status icons (#2991)
* Add status and teams * Update icons, icon size and getUsersPresence * Minor changes * Refactor RoomTypeIcon * Minor tweaks * Update unit tests * Minor fixes * Fix styles * Small refactor * Update jest Co-authored-by: Diego Mello <diegolmello@gmail.com>
This commit is contained in:
parent
8bc8a07e72
commit
25b71155e6
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
@ -2,7 +2,8 @@ export const STATUS_COLORS = {
|
||||||
online: '#2de0a5',
|
online: '#2de0a5',
|
||||||
busy: '#f5455c',
|
busy: '#f5455c',
|
||||||
away: '#ffd21f',
|
away: '#ffd21f',
|
||||||
offline: '#cbced1'
|
offline: '#cbced1',
|
||||||
|
loading: '#9ea2a8'
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SWITCH_TRACK_COLOR = {
|
export const SWITCH_TRACK_COLOR = {
|
||||||
|
|
|
@ -3,10 +3,11 @@ import { StyleSheet } from 'react-native';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { CustomIcon } from '../lib/Icons';
|
import { CustomIcon } from '../lib/Icons';
|
||||||
import { STATUS_COLORS, themes } from '../constants/colors';
|
import { STATUS_COLORS, themes } from '../constants/colors';
|
||||||
|
import Status from './Status/Status';
|
||||||
|
import { withTheme } from '../theme';
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
icon: {
|
icon: {
|
||||||
marginTop: 3,
|
|
||||||
marginRight: 4
|
marginRight: 4
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -18,7 +19,16 @@ const RoomTypeIcon = React.memo(({
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const color = themes[theme].auxiliaryText;
|
const color = themes[theme].titleText;
|
||||||
|
const iconStyle = [
|
||||||
|
styles.icon,
|
||||||
|
{ color },
|
||||||
|
style
|
||||||
|
];
|
||||||
|
|
||||||
|
if (type === 'd' && !isGroupChat) {
|
||||||
|
return <Status style={[iconStyle, { color: STATUS_COLORS[status] ?? STATUS_COLORS.offline }]} size={size} status={status} />;
|
||||||
|
}
|
||||||
|
|
||||||
let icon = 'channel-private';
|
let icon = 'channel-private';
|
||||||
if (type === 'discussion') {
|
if (type === 'discussion') {
|
||||||
|
@ -27,7 +37,7 @@ const RoomTypeIcon = React.memo(({
|
||||||
icon = 'channel-public';
|
icon = 'channel-public';
|
||||||
} else if (type === 'd') {
|
} else if (type === 'd') {
|
||||||
if (isGroupChat) {
|
if (isGroupChat) {
|
||||||
icon = 'team';
|
icon = 'message';
|
||||||
} else {
|
} else {
|
||||||
icon = 'mention';
|
icon = 'mention';
|
||||||
}
|
}
|
||||||
|
@ -39,11 +49,7 @@ const RoomTypeIcon = React.memo(({
|
||||||
<CustomIcon
|
<CustomIcon
|
||||||
name={icon}
|
name={icon}
|
||||||
size={size}
|
size={size}
|
||||||
style={[
|
style={iconStyle}
|
||||||
type === 'l' && status ? { color: STATUS_COLORS[status] } : { color },
|
|
||||||
styles.icon,
|
|
||||||
style
|
|
||||||
]}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -61,4 +67,4 @@ RoomTypeIcon.defaultProps = {
|
||||||
size: 16
|
size: 16
|
||||||
};
|
};
|
||||||
|
|
||||||
export default RoomTypeIcon;
|
export default withTheme(RoomTypeIcon);
|
||||||
|
|
|
@ -1,36 +1,37 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { View } from 'react-native';
|
import { CustomIcon } from '../../lib/Icons';
|
||||||
import { STATUS_COLORS, themes } from '../../constants/colors';
|
import { STATUS_COLORS } from '../../constants/colors';
|
||||||
|
|
||||||
const Status = React.memo(({
|
const Status = React.memo(({
|
||||||
status, size, style, theme, ...props
|
status, size, style, ...props
|
||||||
}) => (
|
}) => {
|
||||||
<View
|
const name = `status-${ status }`;
|
||||||
style={
|
const isNameValid = CustomIcon.hasIcon(name);
|
||||||
[
|
const iconName = isNameValid ? name : 'status-offline';
|
||||||
style,
|
const calculatedStyle = [{
|
||||||
{
|
width: size, height: size, textAlignVertical: 'center'
|
||||||
borderRadius: size,
|
}, style];
|
||||||
width: size,
|
|
||||||
height: size,
|
return (
|
||||||
backgroundColor: STATUS_COLORS[status] ?? STATUS_COLORS.offline,
|
<CustomIcon
|
||||||
borderColor: themes[theme].backgroundColor
|
style={calculatedStyle}
|
||||||
}
|
size={size}
|
||||||
]}
|
name={iconName}
|
||||||
|
color={STATUS_COLORS[status] ?? STATUS_COLORS.offline}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
));
|
);
|
||||||
|
});
|
||||||
|
|
||||||
Status.propTypes = {
|
Status.propTypes = {
|
||||||
status: PropTypes.string,
|
status: PropTypes.string,
|
||||||
size: PropTypes.number,
|
size: PropTypes.number,
|
||||||
style: PropTypes.any,
|
style: PropTypes.any
|
||||||
theme: PropTypes.string
|
|
||||||
};
|
};
|
||||||
Status.defaultProps = {
|
Status.defaultProps = {
|
||||||
status: 'offline',
|
status: 'offline',
|
||||||
size: 16,
|
size: 32
|
||||||
theme: 'light'
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Status;
|
export default Status;
|
||||||
|
|
|
@ -1,32 +1,19 @@
|
||||||
import React from 'react';
|
import React, { memo } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import Status from './Status';
|
import Status from './Status';
|
||||||
import { withTheme } from '../../theme';
|
|
||||||
|
|
||||||
class StatusContainer extends React.PureComponent {
|
const StatusContainer = memo(({ style, size = 32, status }) => <Status size={size} style={style} status={status} />);
|
||||||
static propTypes = {
|
|
||||||
|
StatusContainer.propTypes = {
|
||||||
style: PropTypes.any,
|
style: PropTypes.any,
|
||||||
size: PropTypes.number,
|
size: PropTypes.number,
|
||||||
status: PropTypes.string,
|
status: PropTypes.string
|
||||||
theme: PropTypes.string
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static defaultProps = {
|
|
||||||
size: 16
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {
|
|
||||||
style, size, status, theme
|
|
||||||
} = this.props;
|
|
||||||
return <Status size={size} style={style} status={status} theme={theme} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const mapStateToProps = (state, ownProps) => ({
|
const mapStateToProps = (state, ownProps) => ({
|
||||||
status: state.meteor.connected ? (state.activeUsers[ownProps.id] && state.activeUsers[ownProps.id].status) : 'offline'
|
status: state.meteor.connected ? (state.activeUsers[ownProps.id] && state.activeUsers[ownProps.id].status) : 'loading'
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps)(withTheme(StatusContainer));
|
export default connect(mapStateToProps)(StatusContainer);
|
||||||
|
|
|
@ -55,8 +55,9 @@ export default async function getUsersPresence() {
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
const { users } = result;
|
const { users } = result;
|
||||||
|
|
||||||
const activeUsers = users.reduce((ret, item) => {
|
const activeUsers = ids.reduce((ret, id) => {
|
||||||
const { _id, status, statusText } = item;
|
const user = users.find(u => u._id === id) ?? { _id: id, status: 'offline' };
|
||||||
|
const { _id, status, statusText } = user;
|
||||||
|
|
||||||
if (loggedUser && loggedUser.id === _id) {
|
if (loggedUser && loggedUser.id === _id) {
|
||||||
reduxStore.dispatch(setUser({ status, statusText }));
|
reduxStore.dispatch(setUser({ status, statusText }));
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -78,7 +78,6 @@ const RoomItem = ({
|
||||||
prid={prid}
|
prid={prid}
|
||||||
status={status}
|
status={status}
|
||||||
isGroupChat={isGroupChat}
|
isGroupChat={isGroupChat}
|
||||||
theme={theme}
|
|
||||||
/>
|
/>
|
||||||
<Title
|
<Title
|
||||||
name={name}
|
name={name}
|
||||||
|
@ -121,7 +120,6 @@ const RoomItem = ({
|
||||||
prid={prid}
|
prid={prid}
|
||||||
status={status}
|
status={status}
|
||||||
isGroupChat={isGroupChat}
|
isGroupChat={isGroupChat}
|
||||||
theme={theme}
|
|
||||||
/>
|
/>
|
||||||
<Title
|
<Title
|
||||||
name={name}
|
name={name}
|
||||||
|
|
|
@ -1,21 +1,13 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import Status from '../../containers/Status/Status';
|
|
||||||
import RoomTypeIcon from '../../containers/RoomTypeIcon';
|
import RoomTypeIcon from '../../containers/RoomTypeIcon';
|
||||||
import styles from './styles';
|
|
||||||
|
|
||||||
const TypeIcon = React.memo(({
|
const TypeIcon = React.memo(({
|
||||||
theme, type, prid, status, isGroupChat
|
type, prid, status, isGroupChat
|
||||||
}) => {
|
}) => <RoomTypeIcon type={prid ? 'discussion' : type} isGroupChat={isGroupChat} status={status} />);
|
||||||
if (type === 'd' && !isGroupChat) {
|
|
||||||
return <Status style={styles.status} size={10} status={status} />;
|
|
||||||
}
|
|
||||||
return <RoomTypeIcon theme={theme} type={prid ? 'discussion' : type} isGroupChat={isGroupChat} status={status} />;
|
|
||||||
});
|
|
||||||
|
|
||||||
TypeIcon.propTypes = {
|
TypeIcon.propTypes = {
|
||||||
theme: PropTypes.string,
|
|
||||||
type: PropTypes.string,
|
type: PropTypes.string,
|
||||||
status: PropTypes.string,
|
status: PropTypes.string,
|
||||||
prid: PropTypes.string,
|
prid: PropTypes.string,
|
||||||
|
|
|
@ -194,11 +194,11 @@ class RoomItemContainer extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = (state, ownProps) => {
|
const mapStateToProps = (state, ownProps) => {
|
||||||
let status = 'offline';
|
let status = 'loading';
|
||||||
const { id, type, visitor = {} } = ownProps;
|
const { id, type, visitor = {} } = ownProps;
|
||||||
if (state.meteor.connected) {
|
if (state.meteor.connected) {
|
||||||
if (type === 'd') {
|
if (type === 'd') {
|
||||||
status = state.activeUsers[id]?.status || 'offline';
|
status = state.activeUsers[id]?.status || 'loading';
|
||||||
} else if (type === 'l' && visitor?.status) {
|
} else if (type === 'l' && visitor?.status) {
|
||||||
({ status } = visitor);
|
({ status } = visitor);
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,9 +52,7 @@ export default StyleSheet.create({
|
||||||
...sharedStyles.textSemibold
|
...sharedStyles.textSemibold
|
||||||
},
|
},
|
||||||
status: {
|
status: {
|
||||||
marginLeft: 4,
|
marginRight: 2
|
||||||
marginRight: 7,
|
|
||||||
marginTop: 3
|
|
||||||
},
|
},
|
||||||
markdownText: {
|
markdownText: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
|
|
|
@ -448,14 +448,20 @@ class RoomActionsView extends React.Component {
|
||||||
type={t}
|
type={t}
|
||||||
rid={rid}
|
rid={rid}
|
||||||
>
|
>
|
||||||
{t === 'd' && member._id ? <Status style={sharedStyles.status} id={member._id} /> : null }
|
{t === 'd' && member._id
|
||||||
|
? (
|
||||||
|
<View style={[sharedStyles.status, { backgroundColor: themes[theme].backgroundColor }]}>
|
||||||
|
<Status size={16} id={member._id} />
|
||||||
|
</View>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
</Avatar>
|
</Avatar>
|
||||||
<View style={styles.roomTitleContainer}>
|
<View style={styles.roomTitleContainer}>
|
||||||
{room.t === 'd'
|
{room.t === 'd'
|
||||||
? <Text style={[styles.roomTitle, { color: themes[theme].titleText }]} numberOfLines={1}>{room.fname}</Text>
|
? <Text style={[styles.roomTitle, { color: themes[theme].titleText }]} numberOfLines={1}>{room.fname}</Text>
|
||||||
: (
|
: (
|
||||||
<View style={styles.roomTitleRow}>
|
<View style={styles.roomTitleRow}>
|
||||||
<RoomTypeIcon type={room.prid ? 'discussion' : room.t} status={room.visitor?.status} theme={theme} />
|
<RoomTypeIcon type={room.prid ? 'discussion' : room.t} status={room.visitor?.status} />
|
||||||
<Text style={[styles.roomTitle, { color: themes[theme].titleText }]} numberOfLines={1}>{RocketChat.getRoomTitle(room)}</Text>
|
<Text style={[styles.roomTitle, { color: themes[theme].titleText }]} numberOfLines={1}>{RocketChat.getRoomTitle(room)}</Text>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
|
|
|
@ -41,7 +41,7 @@ const getRoomTitle = (room, type, name, username, statusText, theme) => (type ==
|
||||||
)
|
)
|
||||||
: (
|
: (
|
||||||
<View style={styles.roomTitleRow}>
|
<View style={styles.roomTitleRow}>
|
||||||
<RoomTypeIcon type={room.prid ? 'discussion' : room.t} key='room-info-type' status={room.visitor?.status} theme={theme} />
|
<RoomTypeIcon type={room.prid ? 'discussion' : room.t} key='room-info-type' status={room.visitor?.status} />
|
||||||
<Text testID='room-info-view-name' style={[styles.roomTitle, { color: themes[theme].titleText }]} key='room-info-name'>{RocketChat.getRoomTitle(room)}</Text>
|
<Text testID='room-info-view-name' style={[styles.roomTitle, { color: themes[theme].titleText }]} key='room-info-name'>{RocketChat.getRoomTitle(room)}</Text>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
|
@ -290,7 +290,13 @@ class RoomInfoView extends React.Component {
|
||||||
size={100}
|
size={100}
|
||||||
rid={room?.rid}
|
rid={room?.rid}
|
||||||
>
|
>
|
||||||
{this.t === 'd' && roomUser._id ? <Status style={[sharedStyles.status, styles.status]} theme={theme} size={24} id={roomUser._id} /> : null}
|
{this.t === 'd' && roomUser._id
|
||||||
|
? (
|
||||||
|
<View style={[sharedStyles.status, { backgroundColor: themes[theme].auxiliaryBackground }]}>
|
||||||
|
<Status size={20} id={roomUser._id} />
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
: null}
|
||||||
</Avatar>
|
</Avatar>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,11 +48,6 @@ export default StyleSheet.create({
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
alignItems: 'center'
|
alignItems: 'center'
|
||||||
},
|
},
|
||||||
status: {
|
|
||||||
borderWidth: 4,
|
|
||||||
bottom: -4,
|
|
||||||
right: -4
|
|
||||||
},
|
|
||||||
itemLabel: {
|
itemLabel: {
|
||||||
marginBottom: 10,
|
marginBottom: 10,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
|
|
|
@ -6,9 +6,9 @@ import {
|
||||||
|
|
||||||
import I18n from '../../../i18n';
|
import I18n from '../../../i18n';
|
||||||
import sharedStyles from '../../Styles';
|
import sharedStyles from '../../Styles';
|
||||||
import Icon from './Icon';
|
|
||||||
import { themes } from '../../../constants/colors';
|
import { themes } from '../../../constants/colors';
|
||||||
import Markdown from '../../../containers/markdown';
|
import Markdown from '../../../containers/markdown';
|
||||||
|
import RoomTypeIcon from '../../../containers/RoomTypeIcon';
|
||||||
|
|
||||||
const HIT_SLOP = {
|
const HIT_SLOP = {
|
||||||
top: 5, right: 5, bottom: 5, left: 5
|
top: 5, right: 5, bottom: 5, left: 5
|
||||||
|
@ -119,7 +119,7 @@ HeaderTitle.propTypes = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const Header = React.memo(({
|
const Header = React.memo(({
|
||||||
title, subtitle, parentTitle, type, status, usersTyping, width, height, prid, tmid, connecting, goRoomActionsView, roomUserId, theme
|
title, subtitle, parentTitle, type, status, usersTyping, width, height, prid, tmid, connecting, goRoomActionsView, theme, isGroupChat
|
||||||
}) => {
|
}) => {
|
||||||
const portrait = height > width;
|
const portrait = height > width;
|
||||||
let scale = 1;
|
let scale = 1;
|
||||||
|
@ -136,13 +136,7 @@ const Header = React.memo(({
|
||||||
if (tmid) {
|
if (tmid) {
|
||||||
renderFunc = () => (
|
renderFunc = () => (
|
||||||
<View style={styles.titleContainer}>
|
<View style={styles.titleContainer}>
|
||||||
<Icon
|
<RoomTypeIcon type={prid ? 'discussion' : type} isGroupChat={isGroupChat} status={status} />
|
||||||
type={prid ? 'discussion' : type}
|
|
||||||
tmid={tmid}
|
|
||||||
status={status}
|
|
||||||
roomUserId={roomUserId}
|
|
||||||
theme={theme}
|
|
||||||
/>
|
|
||||||
<Text style={[styles.subtitle, { color: themes[theme].auxiliaryText }]} numberOfLines={1}>{parentTitle}</Text>
|
<Text style={[styles.subtitle, { color: themes[theme].auxiliaryText }]} numberOfLines={1}>{parentTitle}</Text>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
@ -158,7 +152,7 @@ const Header = React.memo(({
|
||||||
hitSlop={HIT_SLOP}
|
hitSlop={HIT_SLOP}
|
||||||
>
|
>
|
||||||
<View style={styles.titleContainer}>
|
<View style={styles.titleContainer}>
|
||||||
{tmid ? null : <Icon type={prid ? 'discussion' : type} status={status} roomUserId={roomUserId} theme={theme} />}
|
{tmid ? null : <RoomTypeIcon type={prid ? 'discussion' : type} isGroupChat={isGroupChat} status={status} />}
|
||||||
<HeaderTitle
|
<HeaderTitle
|
||||||
title={title}
|
title={title}
|
||||||
tmid={tmid}
|
tmid={tmid}
|
||||||
|
@ -185,7 +179,7 @@ Header.propTypes = {
|
||||||
theme: PropTypes.string,
|
theme: PropTypes.string,
|
||||||
usersTyping: PropTypes.array,
|
usersTyping: PropTypes.array,
|
||||||
connecting: PropTypes.bool,
|
connecting: PropTypes.bool,
|
||||||
roomUserId: PropTypes.string,
|
isGroupChat: PropTypes.bool,
|
||||||
parentTitle: PropTypes.string,
|
parentTitle: PropTypes.string,
|
||||||
goRoomActionsView: PropTypes.func
|
goRoomActionsView: PropTypes.func
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,72 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import { StyleSheet } from 'react-native';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
import { STATUS_COLORS, themes } from '../../../constants/colors';
|
|
||||||
import { CustomIcon } from '../../../lib/Icons';
|
|
||||||
import Status from '../../../containers/Status/Status';
|
|
||||||
|
|
||||||
const ICON_SIZE = 15;
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
type: {
|
|
||||||
width: ICON_SIZE,
|
|
||||||
height: ICON_SIZE,
|
|
||||||
marginRight: 4,
|
|
||||||
marginLeft: -4
|
|
||||||
},
|
|
||||||
status: {
|
|
||||||
marginRight: 8
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const Icon = React.memo(({
|
|
||||||
roomUserId, type, status, theme, tmid
|
|
||||||
}) => {
|
|
||||||
if ((type === 'd' || tmid) && roomUserId) {
|
|
||||||
return <Status size={10} style={styles.status} status={status} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
let colorStyle = {};
|
|
||||||
if (type === 'l') {
|
|
||||||
colorStyle = { color: STATUS_COLORS[status] };
|
|
||||||
} else {
|
|
||||||
colorStyle = { color: themes[theme].auxiliaryText };
|
|
||||||
}
|
|
||||||
|
|
||||||
let icon;
|
|
||||||
if (type === 'discussion') {
|
|
||||||
icon = 'discussions';
|
|
||||||
} else if (type === 'c') {
|
|
||||||
icon = 'channel-public';
|
|
||||||
} else if (type === 'l') {
|
|
||||||
icon = 'omnichannel';
|
|
||||||
} else if (type === 'd') {
|
|
||||||
icon = 'team';
|
|
||||||
} else {
|
|
||||||
icon = 'channel-private';
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<CustomIcon
|
|
||||||
name={icon}
|
|
||||||
size={ICON_SIZE * 1}
|
|
||||||
style={[
|
|
||||||
styles.type,
|
|
||||||
{
|
|
||||||
width: ICON_SIZE * 1,
|
|
||||||
height: ICON_SIZE * 1
|
|
||||||
},
|
|
||||||
colorStyle
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
Icon.propTypes = {
|
|
||||||
roomUserId: PropTypes.string,
|
|
||||||
type: PropTypes.string,
|
|
||||||
status: PropTypes.string,
|
|
||||||
theme: PropTypes.string,
|
|
||||||
tmid: PropTypes.string
|
|
||||||
};
|
|
||||||
export default Icon;
|
|
|
@ -28,7 +28,8 @@ class RoomHeaderView extends Component {
|
||||||
goRoomActionsView: PropTypes.func,
|
goRoomActionsView: PropTypes.func,
|
||||||
width: PropTypes.number,
|
width: PropTypes.number,
|
||||||
height: PropTypes.number,
|
height: PropTypes.number,
|
||||||
parentTitle: PropTypes.string
|
parentTitle: PropTypes.string,
|
||||||
|
isGroupChat: PropTypes.bool
|
||||||
};
|
};
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps) {
|
shouldComponentUpdate(nextProps) {
|
||||||
|
@ -76,7 +77,24 @@ class RoomHeaderView extends Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
title, subtitle: subtitleProp, type, prid, tmid, widthOffset, status = 'offline', statusText, connecting, connected, usersTyping, goRoomActionsView, roomUserId, theme, width, height, parentTitle
|
title,
|
||||||
|
subtitle: subtitleProp,
|
||||||
|
type,
|
||||||
|
prid,
|
||||||
|
tmid,
|
||||||
|
widthOffset,
|
||||||
|
status = 'offline',
|
||||||
|
statusText,
|
||||||
|
connecting,
|
||||||
|
connected,
|
||||||
|
usersTyping,
|
||||||
|
goRoomActionsView,
|
||||||
|
roomUserId,
|
||||||
|
theme,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
parentTitle,
|
||||||
|
isGroupChat
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
let subtitle;
|
let subtitle;
|
||||||
|
@ -105,6 +123,7 @@ class RoomHeaderView extends Component {
|
||||||
goRoomActionsView={goRoomActionsView}
|
goRoomActionsView={goRoomActionsView}
|
||||||
connecting={connecting}
|
connecting={connecting}
|
||||||
parentTitle={parentTitle}
|
parentTitle={parentTitle}
|
||||||
|
isGroupChat={isGroupChat}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -306,6 +306,7 @@ class RoomView extends React.Component {
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const { rid, tmid } = this;
|
const { rid, tmid } = this;
|
||||||
const prid = room?.prid;
|
const prid = room?.prid;
|
||||||
|
const isGroupChat = RocketChat.isGroupChat(room);
|
||||||
let title = route.params?.name;
|
let title = route.params?.name;
|
||||||
let parentTitle;
|
let parentTitle;
|
||||||
if ((room.id || room.rid) && !tmid) {
|
if ((room.id || room.rid) && !tmid) {
|
||||||
|
@ -356,6 +357,7 @@ class RoomView extends React.Component {
|
||||||
type={t}
|
type={t}
|
||||||
roomUserId={roomUserId}
|
roomUserId={roomUserId}
|
||||||
visitor={visitor}
|
visitor={visitor}
|
||||||
|
isGroupChat={isGroupChat}
|
||||||
goRoomActionsView={this.goRoomActionsView}
|
goRoomActionsView={this.goRoomActionsView}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
|
|
|
@ -196,7 +196,7 @@ class Sidebar extends Component {
|
||||||
return (
|
return (
|
||||||
<SidebarItem
|
<SidebarItem
|
||||||
text={user.statusText || I18n.t('Edit_Status')}
|
text={user.statusText || I18n.t('Edit_Status')}
|
||||||
left={<Status style={styles.status} size={12} status={user && user.status} />}
|
left={<Status size={24} status={user?.status} />}
|
||||||
right={<CustomIcon name='edit' size={20} color={themes[theme].titleText} />}
|
right={<CustomIcon name='edit' size={20} color={themes[theme].titleText} />}
|
||||||
onPress={() => this.sidebarNavigate('StatusView')}
|
onPress={() => this.sidebarNavigate('StatusView')}
|
||||||
testID='sidebar-custom-status'
|
testID='sidebar-custom-status'
|
||||||
|
|
|
@ -51,9 +51,6 @@ export default StyleSheet.create({
|
||||||
avatar: {
|
avatar: {
|
||||||
marginHorizontal: 10
|
marginHorizontal: 10
|
||||||
},
|
},
|
||||||
status: {
|
|
||||||
marginRight: 5
|
|
||||||
},
|
|
||||||
currentServerText: {
|
currentServerText: {
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
...sharedStyles.textSemibold
|
...sharedStyles.textSemibold
|
||||||
|
|
|
@ -41,11 +41,11 @@ const styles = StyleSheet.create({
|
||||||
},
|
},
|
||||||
inputLeft: {
|
inputLeft: {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
top: 18,
|
top: 12,
|
||||||
left: 14
|
left: 12
|
||||||
},
|
},
|
||||||
inputStyle: {
|
inputStyle: {
|
||||||
paddingLeft: 40
|
paddingLeft: 48
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -140,7 +140,7 @@ class StatusView extends React.Component {
|
||||||
testID={`status-view-current-${ user.status }`}
|
testID={`status-view-current-${ user.status }`}
|
||||||
style={styles.inputLeft}
|
style={styles.inputLeft}
|
||||||
status={user.status}
|
status={user.status}
|
||||||
size={12}
|
size={24}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
inputStyle={styles.inputStyle}
|
inputStyle={styles.inputStyle}
|
||||||
|
@ -174,7 +174,7 @@ class StatusView extends React.Component {
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
testID={`status-view-${ id }`}
|
testID={`status-view-${ id }`}
|
||||||
left={() => <Status size={12} status={item.id} />}
|
left={() => <Status size={24} status={item.id} />}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,9 +26,9 @@ export default StyleSheet.create({
|
||||||
},
|
},
|
||||||
status: {
|
status: {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
bottom: -3,
|
bottom: -2,
|
||||||
right: -3,
|
right: -2,
|
||||||
borderWidth: 3
|
borderRadius: 10
|
||||||
},
|
},
|
||||||
textAlignCenter: {
|
textAlignCenter: {
|
||||||
textAlign: 'center'
|
textAlign: 'center'
|
||||||
|
|
BIN
ios/custom.ttf
BIN
ios/custom.ttf
Binary file not shown.
|
@ -1,5 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { ScrollView, StyleSheet } from 'react-native';
|
import { ScrollView, StyleSheet, View } from 'react-native';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import { themes } from '../../app/constants/colors';
|
import { themes } from '../../app/constants/colors';
|
||||||
|
@ -9,11 +9,6 @@ import StoriesSeparator from './StoriesSeparator';
|
||||||
import sharedStyles from '../../app/views/Styles';
|
import sharedStyles from '../../app/views/Styles';
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
status: {
|
|
||||||
borderWidth: 4,
|
|
||||||
bottom: -4,
|
|
||||||
right: -4
|
|
||||||
},
|
|
||||||
custom: {
|
custom: {
|
||||||
padding: 16
|
padding: 16
|
||||||
}
|
}
|
||||||
|
@ -117,11 +112,12 @@ const AvatarStories = ({ theme }) => (
|
||||||
server={server}
|
server={server}
|
||||||
size={56}
|
size={56}
|
||||||
>
|
>
|
||||||
|
<View style={[sharedStyles.status, { backgroundColor: themes[theme].backgroundColor }]}>
|
||||||
<Status
|
<Status
|
||||||
size={24}
|
size={20}
|
||||||
style={[sharedStyles.status, styles.status]}
|
status='online'
|
||||||
theme={theme}
|
|
||||||
/>
|
/>
|
||||||
|
</View>
|
||||||
</Avatar>
|
</Avatar>
|
||||||
<Separator title='Wrong server' theme={theme} />
|
<Separator title='Wrong server' theme={theme} />
|
||||||
<Avatar
|
<Avatar
|
||||||
|
|
|
@ -65,6 +65,7 @@ export default ({ theme }) => {
|
||||||
<RoomItem status='away' />
|
<RoomItem status='away' />
|
||||||
<RoomItem status='busy' />
|
<RoomItem status='busy' />
|
||||||
<RoomItem status='offline' />
|
<RoomItem status='offline' />
|
||||||
|
<RoomItem status='loading' />
|
||||||
<RoomItem status='wrong' />
|
<RoomItem status='wrong' />
|
||||||
|
|
||||||
<Separator title='Alerts' />
|
<Separator title='Alerts' />
|
||||||
|
|
Loading…
Reference in New Issue