[IMPROVEMENT] Tap on avatar/username/channel to show info (#1097)

* added feature to tab on mentions and avtar

* fixed lint

* removed room param from roomActionView

* removed room param from roomActionView

* Update tests
This commit is contained in:
pranavpandey1998official 2019-08-22 23:38:07 +05:30 committed by Diego Mello
parent 80570b0591
commit 857d23ee88
10 changed files with 4358 additions and 2663 deletions

File diff suppressed because it is too large Load Diff

View File

@ -28,6 +28,7 @@ const Content = React.memo((props) => {
numberOfLines={props.tmid ? 1 : 0}
getCustomEmoji={props.getCustomEmoji}
useMarkdown={props.useMarkdown}
navToRoomInfo={props.navToRoomInfo}
/>
);
}
@ -50,6 +51,7 @@ Content.propTypes = {
user: PropTypes.object,
mentions: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
channels: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
navToRoomInfo: PropTypes.func,
getCustomEmoji: PropTypes.func
};
Content.displayName = 'MessageContent';

View File

@ -48,7 +48,7 @@ const emojiCount = (str) => {
};
const Markdown = React.memo(({
msg, style, rules, baseUrl, username, isEdited, numberOfLines, mentions, channels, getCustomEmoji, useMarkdown = true
msg, style, rules, baseUrl, username, isEdited, numberOfLines, mentions, channels, getCustomEmoji, useMarkdown = true, navToRoomInfo
}) => {
if (!msg) {
return null;
@ -92,8 +92,17 @@ const Markdown = React.memo(({
};
}
if (mentions && mentions.length && mentions.findIndex(mention => mention.username === content) !== -1) {
const index = mentions.findIndex(mention => mention.username === content);
const navParam = {
t: 'd',
rid: mentions[index]._id
};
return (
<Text style={mentionStyle} key={key}>
<Text
style={mentionStyle}
key={key}
onPress={() => navToRoomInfo(navParam)}
>
&nbsp;{content}&nbsp;
</Text>
);
@ -103,8 +112,17 @@ const Markdown = React.memo(({
hashtag: (node) => {
const { content, key } = node;
if (channels && channels.length && channels.findIndex(channel => channel.name === content) !== -1) {
const index = channels.findIndex(channel => channel.name === content);
const navParam = {
t: 'c',
rid: channels[index]._id
};
return (
<Text key={key} style={styles.mention}>
<Text
key={key}
style={styles.mention}
onPress={() => navToRoomInfo(navParam)}
>
&nbsp;#{content}&nbsp;
</Text>
);
@ -161,7 +179,8 @@ Markdown.propTypes = {
useMarkdown: PropTypes.bool,
mentions: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
channels: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
getCustomEmoji: PropTypes.func
getCustomEmoji: PropTypes.func,
navToRoomInfo: PropTypes.func
};
Markdown.displayName = 'MessageMarkdown';

View File

@ -1,24 +1,34 @@
import React from 'react';
import PropTypes from 'prop-types';
import { TouchableOpacity } from 'react-native';
import Avatar from '../Avatar';
import styles from './styles';
const MessageAvatar = React.memo(({
isHeader, avatar, author, baseUrl, user, small
isHeader, avatar, author, baseUrl, user, small, navToRoomInfo
}) => {
if (isHeader) {
const navParam = {
t: 'd',
rid: author._id
};
return (
<Avatar
style={small ? styles.avatarSmall : styles.avatar}
text={avatar ? '' : author.username}
size={small ? 20 : 36}
borderRadius={small ? 2 : 4}
avatar={avatar}
baseUrl={baseUrl}
userId={user.id}
token={user.token}
/>
<TouchableOpacity
onPress={() => navToRoomInfo(navParam)}
disabled={author._id === user.id}
>
<Avatar
style={small ? styles.avatarSmall : styles.avatar}
text={avatar ? '' : author.username}
size={small ? 20 : 36}
borderRadius={small ? 2 : 4}
avatar={avatar}
baseUrl={baseUrl}
userId={user.id}
token={user.token}
/>
</TouchableOpacity>
);
}
return null;
@ -30,7 +40,8 @@ MessageAvatar.propTypes = {
author: PropTypes.obj,
baseUrl: PropTypes.string,
user: PropTypes.obj,
small: PropTypes.bool
small: PropTypes.bool,
navToRoomInfo: PropTypes.func
};
MessageAvatar.displayName = 'MessageAvatar';

View File

@ -39,7 +39,8 @@ export default class MessageContainer extends React.Component {
toggleReactionPicker: PropTypes.func,
fetchThreadName: PropTypes.func,
onOpenFileModal: PropTypes.func,
onReactionLongPress: PropTypes.func
onReactionLongPress: PropTypes.func,
navToRoomInfo: PropTypes.func
}
static defaultProps = {
@ -199,7 +200,7 @@ export default class MessageContainer extends React.Component {
render() {
const {
item, user, style, archived, baseUrl, useRealName, broadcast, fetchThreadName, customThreadTimeFormat, onOpenFileModal, timeFormat, useMarkdown, isReadReceiptEnabled, autoTranslateRoom, autoTranslateLanguage
item, user, style, archived, baseUrl, useRealName, broadcast, fetchThreadName, customThreadTimeFormat, onOpenFileModal, timeFormat, useMarkdown, isReadReceiptEnabled, autoTranslateRoom, autoTranslateLanguage, navToRoomInfo
} = this.props;
const {
_id, msg, ts, attachments, urls, reactions, t, avatar, u, alias, editedBy, role, drid, dcount, dlm, tmid, tcount, tlm, tmsg, mentions, channels, unread, autoTranslate: autoTranslateMessage
@ -263,6 +264,7 @@ export default class MessageContainer extends React.Component {
onDiscussionPress={this.onDiscussionPress}
onOpenFileModal={onOpenFileModal}
getCustomEmoji={getCustomEmoji}
navToRoomInfo={navToRoomInfo}
/>
);
}

View File

@ -640,6 +640,10 @@ const RocketChat = {
// RC 0.48.0
return this.sdk.get('users.info', { userId });
},
getRoomInfo(roomId) {
// RC 0.72.0
return this.sdk.get('rooms.info', { roomId });
},
getRoomMemberId(rid, currentUserId) {
if (rid === `${ currentUserId }${ currentUserId }`) {
return currentUserId;

View File

@ -184,7 +184,7 @@ class RoomActionsView extends React.Component {
name: I18n.t('Room_Info'),
route: 'RoomInfoView',
// forward room only if room isn't joined
params: { rid, t, room: joined ? null : room },
params: { rid, t },
testID: 'room-actions-info'
}],
renderItem: this.renderRoomInfo

View File

@ -9,7 +9,7 @@ import Status from '../../containers/Status';
import Avatar from '../../containers/Avatar';
import styles from './styles';
import sharedStyles from '../Styles';
import database, { safeAddListener } from '../../lib/realm';
import database from '../../lib/realm';
import RocketChat from '../../lib/rocketchat';
import RoomTypeIcon from '../../containers/RoomTypeIcon';
import I18n from '../../i18n';
@ -20,8 +20,8 @@ import log from '../../utils/log';
const PERMISSION_EDIT_ROOM = 'edit-room';
const camelize = str => str.replace(/^(.)/, (match, chr) => chr.toUpperCase());
const getRoomTitle = room => (room.t === 'd'
? <Text testID='room-info-view-name' style={styles.roomTitle}>{room.fname}</Text>
const getRoomTitle = (room, type, name) => (type === 'd'
? <Text testID='room-info-view-name' style={styles.roomTitle}>{name}</Text>
: (
<View style={styles.roomTitleRow}>
<RoomTypeIcon type={room.prid ? 'discussion' : room.t} key='room-info-type' />
@ -59,28 +59,18 @@ class RoomInfoView extends React.Component {
constructor(props) {
super(props);
this.rid = props.navigation.getParam('rid');
const room = props.navigation.getParam('room');
this.t = props.navigation.getParam('t');
this.rooms = database.objects('subscriptions').filtered('rid = $0', this.rid);
this.roles = database.objects('roles');
this.sub = {
unsubscribe: () => {}
};
this.state = {
room: this.rooms[0] || room || {},
room: {},
roomUser: {}
};
}
async componentDidMount() {
safeAddListener(this.rooms, this.updateRoom);
const { room } = this.state;
const permissions = RocketChat.hasPermission([PERMISSION_EDIT_ROOM], room.rid);
if (permissions[PERMISSION_EDIT_ROOM] && !room.prid) {
const { navigation } = this.props;
navigation.setParams({ showEdit: true });
}
if (this.t === 'd') {
const { user } = this.props;
const roomUserId = RocketChat.getRoomMemberId(this.rid, user.id);
@ -92,11 +82,30 @@ class RoomInfoView extends React.Component {
} catch (error) {
log('err_get_user_info', error);
}
return;
}
const rooms = database.objects('subscriptions').filtered('rid = $0', this.rid);
let room = {};
if (rooms.length > 0) {
this.setState({ room: rooms[0] });
[room] = rooms;
} else {
try {
const result = await RocketChat.getRoomInfo(this.rid);
if (result.success) {
// eslint-disable-next-line prefer-destructuring
room = result.room;
this.setState({ room });
}
} catch (error) {
log('err_get_room_info', error);
}
}
const permissions = RocketChat.hasPermission([PERMISSION_EDIT_ROOM], room.rid);
if (permissions[PERMISSION_EDIT_ROOM] && !room.prid) {
const { navigation } = this.props;
navigation.setParams({ showEdit: true });
}
}
componentWillUnmount() {
this.rooms.removeAllListeners();
}
getRoleDescription = (id) => {
@ -107,10 +116,7 @@ class RoomInfoView extends React.Component {
return null;
}
isDirect = () => {
const { room: { t } } = this.state;
return t === 'd';
}
isDirect = () => this.t === 'd'
updateRoom = () => {
if (this.rooms.length > 0) {
@ -181,15 +187,15 @@ class RoomInfoView extends React.Component {
return (
<Avatar
text={room.name}
text={room.name || roomUser.username}
size={100}
style={styles.avatar}
type={room.t}
type={this.t}
baseUrl={baseUrl}
userId={user.id}
token={user.token}
>
{room.t === 'd' && roomUser._id ? <Status style={[sharedStyles.status, styles.status]} size={24} id={roomUser._id} /> : null}
{this.t === 'd' && roomUser._id ? <Status style={[sharedStyles.status, styles.status]} size={24} id={roomUser._id} /> : null}
</Avatar>
);
}
@ -231,6 +237,29 @@ class RoomInfoView extends React.Component {
return null;
}
renderChannel = () => {
const { room } = this.state;
return (
<React.Fragment>
{this.renderItem('description', room)}
{this.renderItem('topic', room)}
{this.renderItem('announcement', room)}
{room.broadcast ? this.renderBroadcast() : null}
</React.Fragment>
);
}
renderDirect = () => {
const { roomUser } = this.state;
return (
<React.Fragment>
{this.renderRoles()}
{this.renderTimezone()}
{this.renderCustomFields(roomUser._id)}
</React.Fragment>
);
}
render() {
const { room, roomUser } = this.state;
if (!room) {
@ -242,15 +271,9 @@ class RoomInfoView extends React.Component {
<SafeAreaView style={styles.container} testID='room-info-view' forceInset={{ vertical: 'never' }}>
<View style={styles.avatarContainer}>
{this.renderAvatar(room, roomUser)}
<View style={styles.roomTitleContainer}>{ getRoomTitle(room) }</View>
<View style={styles.roomTitleContainer}>{ getRoomTitle(room, this.t, roomUser && roomUser.name) }</View>
</View>
{!this.isDirect() ? this.renderItem('description', room) : null}
{!this.isDirect() ? this.renderItem('topic', room) : null}
{!this.isDirect() ? this.renderItem('announcement', room) : null}
{this.isDirect() ? this.renderRoles() : null}
{this.isDirect() ? this.renderTimezone() : null}
{this.isDirect() ? this.renderCustomFields(roomUser._id) : null}
{room.broadcast ? this.renderBroadcast() : null}
{this.isDirect() ? this.renderDirect() : this.renderChannel()}
</SafeAreaView>
</ScrollView>
);

View File

@ -452,6 +452,14 @@ class RoomView extends React.Component {
}
}
navToRoomInfo = (navParam) => {
const { navigation, user } = this.props;
if (navParam.rid === user.id) {
return;
}
navigation.navigate('RoomInfoView', navParam);
}
renderItem = (item, previousItem) => {
const { room, lastOpen, canAutoTranslate } = this.state;
const {
@ -500,6 +508,7 @@ class RoomView extends React.Component {
isReadReceiptEnabled={Message_Read_Receipt_Enabled}
autoTranslateRoom={canAutoTranslate && room.autoTranslate}
autoTranslateLanguage={room.autoTranslateLanguage}
navToRoomInfo={this.navToRoomInfo}
/>
);

View File

@ -8754,7 +8754,7 @@ pad-component@0.0.1:
resolved "https://registry.yarnpkg.com/pad-component/-/pad-component-0.0.1.tgz#ad1f22ce1bf0fdc0d6ddd908af17f351a404b8ac"
integrity sha1-rR8izhvw/cDW3dkIrxfzUaQEuKw=
"paho-mqtt@github:eclipse/paho.mqtt.javascript#master":
paho-mqtt@eclipse/paho.mqtt.javascript#master:
version "1.1.0"
resolved "https://codeload.github.com/eclipse/paho.mqtt.javascript/tar.gz/f5859463aba9a9b7c19f99ab7c4849a723f8d832"