[NEW] Room swipe actions: mark as read/unread, hide, fav (#976)
* added unread and fav feature * changed the layout * fix jest * done requested changes * added requested changes
This commit is contained in:
parent
3375411433
commit
47676c2286
|
@ -2,3 +2,4 @@ export const RectButton = () => 'View';
|
||||||
export const State = () => 'View';
|
export const State = () => 'View';
|
||||||
export const LongPressGestureHandler = () => 'View';
|
export const LongPressGestureHandler = () => 'View';
|
||||||
export const BorderlessButton = () => 'View';
|
export const BorderlessButton = () => 'View';
|
||||||
|
export const PanGestureHandler = () => 'View';
|
||||||
|
|
|
@ -162,6 +162,7 @@ export default {
|
||||||
Everyone_can_access_this_channel: 'Everyone can access this channel',
|
Everyone_can_access_this_channel: 'Everyone can access this channel',
|
||||||
erasing_room: 'erasing room',
|
erasing_room: 'erasing room',
|
||||||
Error_uploading: 'Error uploading',
|
Error_uploading: 'Error uploading',
|
||||||
|
Favorite: 'Favorite',
|
||||||
Favorites: 'Favorites',
|
Favorites: 'Favorites',
|
||||||
Files: 'Files',
|
Files: 'Files',
|
||||||
File_description: 'File description',
|
File_description: 'File description',
|
||||||
|
@ -175,6 +176,7 @@ export default {
|
||||||
Forgot_Password: 'Forgot Password',
|
Forgot_Password: 'Forgot Password',
|
||||||
Group_by_favorites: 'Group favorites',
|
Group_by_favorites: 'Group favorites',
|
||||||
Group_by_type: 'Group by type',
|
Group_by_type: 'Group by type',
|
||||||
|
Hide: 'Hide',
|
||||||
Has_joined_the_channel: 'Has joined the channel',
|
Has_joined_the_channel: 'Has joined the channel',
|
||||||
Has_joined_the_conversation: 'Has joined the conversation',
|
Has_joined_the_conversation: 'Has joined the conversation',
|
||||||
Has_left_the_channel: 'Has left the channel',
|
Has_left_the_channel: 'Has left the channel',
|
||||||
|
@ -268,6 +270,7 @@ export default {
|
||||||
Reactions_are_disabled: 'Reactions are disabled',
|
Reactions_are_disabled: 'Reactions are disabled',
|
||||||
Reactions_are_enabled: 'Reactions are enabled',
|
Reactions_are_enabled: 'Reactions are enabled',
|
||||||
Reactions: 'Reactions',
|
Reactions: 'Reactions',
|
||||||
|
Read: 'Read',
|
||||||
Read_Only_Channel: 'Read Only Channel',
|
Read_Only_Channel: 'Read Only Channel',
|
||||||
Read_Only: 'Read Only',
|
Read_Only: 'Read Only',
|
||||||
Read_Receipt: 'Read Receipt',
|
Read_Receipt: 'Read Receipt',
|
||||||
|
@ -352,6 +355,7 @@ export default {
|
||||||
unarchive: 'unarchive',
|
unarchive: 'unarchive',
|
||||||
UNARCHIVE: 'UNARCHIVE',
|
UNARCHIVE: 'UNARCHIVE',
|
||||||
Unblock_user: 'Unblock user',
|
Unblock_user: 'Unblock user',
|
||||||
|
Unfavorite: 'Unfavorite',
|
||||||
Unfollowed_thread: 'Unfollowed thread',
|
Unfollowed_thread: 'Unfollowed thread',
|
||||||
Unmute: 'Unmute',
|
Unmute: 'Unmute',
|
||||||
unmuted: 'unmuted',
|
unmuted: 'unmuted',
|
||||||
|
|
|
@ -582,6 +582,12 @@ const RocketChat = {
|
||||||
// RC 0.64.0
|
// RC 0.64.0
|
||||||
return this.sdk.post('rooms.favorite', { roomId, favorite });
|
return this.sdk.post('rooms.favorite', { roomId, favorite });
|
||||||
},
|
},
|
||||||
|
toggleRead(read, roomId) {
|
||||||
|
if (read) {
|
||||||
|
return this.sdk.post('subscriptions.unread', { roomId });
|
||||||
|
}
|
||||||
|
return this.sdk.post('subscriptions.read', { rid: roomId });
|
||||||
|
},
|
||||||
getRoomMembers(rid, allUsers, skip = 0, limit = 10) {
|
getRoomMembers(rid, allUsers, skip = 0, limit = 10) {
|
||||||
// RC 0.42.0
|
// RC 0.42.0
|
||||||
return this.sdk.methodCall('getUsersOfRoom', rid, allUsers, { skip, limit });
|
return this.sdk.methodCall('getUsersOfRoom', rid, allUsers, { skip, limit });
|
||||||
|
@ -640,6 +646,9 @@ const RocketChat = {
|
||||||
// RC 0.48.0
|
// RC 0.48.0
|
||||||
return this.sdk.post(`${ this.roomTypeToApiType(t) }.unarchive`, { roomId });
|
return this.sdk.post(`${ this.roomTypeToApiType(t) }.unarchive`, { roomId });
|
||||||
},
|
},
|
||||||
|
hideRoom(roomId, t) {
|
||||||
|
return this.sdk.post(`${ this.roomTypeToApiType(t) }.close`, { roomId });
|
||||||
|
},
|
||||||
saveRoomSettings(rid, params) {
|
saveRoomSettings(rid, params) {
|
||||||
// RC 0.55.0
|
// RC 0.55.0
|
||||||
return this.sdk.methodCall('saveRoomSettings', rid, params);
|
return this.sdk.methodCall('saveRoomSettings', rid, params);
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { View, Text } from 'react-native';
|
import {
|
||||||
|
View, Text, Dimensions, Animated
|
||||||
|
} from 'react-native';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { RectButton } from 'react-native-gesture-handler';
|
import { RectButton, PanGestureHandler, State } from 'react-native-gesture-handler';
|
||||||
|
|
||||||
import Avatar from '../../containers/Avatar';
|
import Avatar from '../../containers/Avatar';
|
||||||
import I18n from '../../i18n';
|
import I18n from '../../i18n';
|
||||||
|
@ -11,9 +13,13 @@ import styles, { ROW_HEIGHT } from './styles';
|
||||||
import UnreadBadge from './UnreadBadge';
|
import UnreadBadge from './UnreadBadge';
|
||||||
import TypeIcon from './TypeIcon';
|
import TypeIcon from './TypeIcon';
|
||||||
import LastMessage from './LastMessage';
|
import LastMessage from './LastMessage';
|
||||||
|
import { CustomIcon } from '../../lib/Icons';
|
||||||
|
|
||||||
export { ROW_HEIGHT };
|
export { ROW_HEIGHT };
|
||||||
|
|
||||||
|
const OPTION_WIDTH = 80;
|
||||||
|
const SMALL_SWIPE = 80;
|
||||||
|
const ACTION_OFFSET = 220;
|
||||||
const attrs = ['name', 'unread', 'userMentions', 'showLastMessage', 'alert', 'type'];
|
const attrs = ['name', 'unread', 'userMentions', 'showLastMessage', 'alert', 'type'];
|
||||||
@connect(state => ({
|
@connect(state => ({
|
||||||
userId: state.login.user && state.login.user.id,
|
userId: state.login.user && state.login.user.id,
|
||||||
|
@ -39,7 +45,13 @@ export default class RoomItem extends React.Component {
|
||||||
token: PropTypes.string,
|
token: PropTypes.string,
|
||||||
avatarSize: PropTypes.number,
|
avatarSize: PropTypes.number,
|
||||||
testID: PropTypes.string,
|
testID: PropTypes.string,
|
||||||
height: PropTypes.number
|
height: PropTypes.number,
|
||||||
|
favorite: PropTypes.bool,
|
||||||
|
isRead: PropTypes.bool,
|
||||||
|
rid: PropTypes.string,
|
||||||
|
toggleFav: PropTypes.func,
|
||||||
|
toggleRead: PropTypes.func,
|
||||||
|
hideChannel: PropTypes.func
|
||||||
}
|
}
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
|
@ -50,10 +62,28 @@ export default class RoomItem extends React.Component {
|
||||||
// eslint-disable-next-line no-useless-constructor
|
// eslint-disable-next-line no-useless-constructor
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
const dragX = new Animated.Value(0);
|
||||||
|
const rowOffSet = new Animated.Value(0);
|
||||||
|
this.rowTranslation = Animated.add(
|
||||||
|
rowOffSet,
|
||||||
|
dragX
|
||||||
|
);
|
||||||
|
this.state = {
|
||||||
|
dragX,
|
||||||
|
rowOffSet,
|
||||||
|
rowState: 0, // 0: closed, 1: right opened, -1: left opened
|
||||||
|
leftWidth: undefined,
|
||||||
|
rightOffset: undefined
|
||||||
|
};
|
||||||
|
this._onGestureEvent = Animated.event(
|
||||||
|
[{ nativeEvent: { translationX: dragX } }]
|
||||||
|
);
|
||||||
|
this._value = 0;
|
||||||
|
this.rowTranslation.addListener(({ value }) => { this._value = value; });
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps) {
|
shouldComponentUpdate(nextProps) {
|
||||||
const { lastMessage, _updatedAt } = this.props;
|
const { lastMessage, _updatedAt, isRead } = this.props;
|
||||||
const oldlastMessage = lastMessage;
|
const oldlastMessage = lastMessage;
|
||||||
const newLastmessage = nextProps.lastMessage;
|
const newLastmessage = nextProps.lastMessage;
|
||||||
|
|
||||||
|
@ -63,10 +93,236 @@ export default class RoomItem extends React.Component {
|
||||||
if (_updatedAt && nextProps._updatedAt && nextProps._updatedAt !== _updatedAt) {
|
if (_updatedAt && nextProps._updatedAt && nextProps._updatedAt !== _updatedAt) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (isRead !== nextProps.isRead) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
// eslint-disable-next-line react/destructuring-assignment
|
// eslint-disable-next-line react/destructuring-assignment
|
||||||
return attrs.some(key => nextProps[key] !== this.props[key]);
|
return attrs.some(key => nextProps[key] !== this.props[key]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
this.rowTranslation.removeAllListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
close = () => {
|
||||||
|
this.swipeableRow.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
_onHandlerStateChange = ({ nativeEvent }) => {
|
||||||
|
if (nativeEvent.oldState === State.ACTIVE) {
|
||||||
|
this._handleRelease(nativeEvent);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_currentOffset = () => {
|
||||||
|
const { leftWidth = 0, rowState } = this.state;
|
||||||
|
const { rightOffset } = this.state;
|
||||||
|
if (rowState === 1) {
|
||||||
|
return leftWidth;
|
||||||
|
} else if (rowState === -1) {
|
||||||
|
return rightOffset;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
_handleRelease = (nativeEvent) => {
|
||||||
|
const { translationX } = nativeEvent;
|
||||||
|
const { rowState } = this.state;
|
||||||
|
let toValue = 0;
|
||||||
|
if (rowState === 0) { // if no option is opened
|
||||||
|
if (translationX > 0 && translationX < ACTION_OFFSET) {
|
||||||
|
toValue = OPTION_WIDTH; // open left option if he swipe right but not enough to trigger action
|
||||||
|
this.setState({ rowState: -1 });
|
||||||
|
} else if (translationX > ACTION_OFFSET) {
|
||||||
|
toValue = 0;
|
||||||
|
this.toggleRead();
|
||||||
|
} else if (translationX < 0 && translationX > -ACTION_OFFSET) {
|
||||||
|
toValue = -2 * OPTION_WIDTH; // open right option if he swipe left
|
||||||
|
this.setState({ rowState: 1 });
|
||||||
|
} else if (translationX < -ACTION_OFFSET) {
|
||||||
|
toValue = 0;
|
||||||
|
this.hideChannel();
|
||||||
|
} else {
|
||||||
|
toValue = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rowState === -1) { // if left option is opened
|
||||||
|
if (this._value < SMALL_SWIPE) {
|
||||||
|
toValue = 0;
|
||||||
|
this.setState({ rowState: 0 });
|
||||||
|
} else if (this._value > ACTION_OFFSET) {
|
||||||
|
toValue = 0;
|
||||||
|
this.setState({ rowState: 0 });
|
||||||
|
this.toggleRead();
|
||||||
|
} else {
|
||||||
|
toValue = OPTION_WIDTH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rowState === 1) { // if right option is opened
|
||||||
|
if (this._value > -2 * SMALL_SWIPE) {
|
||||||
|
toValue = 0;
|
||||||
|
this.setState({ rowState: 0 });
|
||||||
|
} else if (this._value < -ACTION_OFFSET) {
|
||||||
|
toValue = 0;
|
||||||
|
this.setState({ rowState: 0 });
|
||||||
|
this.hideChannel();
|
||||||
|
} else {
|
||||||
|
toValue = -2 * OPTION_WIDTH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._animateRow(toValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
_animateRow = (toValue) => {
|
||||||
|
const { dragX, rowOffSet } = this.state;
|
||||||
|
rowOffSet.setValue(this._value);
|
||||||
|
dragX.setValue(0);
|
||||||
|
Animated.spring(rowOffSet, {
|
||||||
|
toValue,
|
||||||
|
bounciness: 5
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
handleLeftButtonPress = () => {
|
||||||
|
this.toggleRead();
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
close = () => {
|
||||||
|
this._animateRow(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleFav = () => {
|
||||||
|
const { toggleFav, rid, favorite } = this.props;
|
||||||
|
if (toggleFav) {
|
||||||
|
toggleFav(rid, favorite);
|
||||||
|
}
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleRead = () => {
|
||||||
|
const { toggleRead, rid, isRead } = this.props;
|
||||||
|
if (toggleRead) {
|
||||||
|
toggleRead(rid, isRead);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleHideButtonPress = () => {
|
||||||
|
this.hideChannel();
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
hideChannel = () => {
|
||||||
|
const { hideChannel, rid, type } = this.props;
|
||||||
|
if (hideChannel) {
|
||||||
|
hideChannel(rid, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderLeftActions = () => {
|
||||||
|
const { isRead } = this.props;
|
||||||
|
const { width } = Dimensions.get('window');
|
||||||
|
const trans = this.rowTranslation.interpolate({
|
||||||
|
inputRange: [0, OPTION_WIDTH],
|
||||||
|
outputRange: [-width, -width + OPTION_WIDTH]
|
||||||
|
});
|
||||||
|
|
||||||
|
const iconTrans = this.rowTranslation.interpolate({
|
||||||
|
inputRange: [0, OPTION_WIDTH, ACTION_OFFSET - 20, ACTION_OFFSET, width],
|
||||||
|
outputRange: [0, 0, -(OPTION_WIDTH + 10), 0, 0]
|
||||||
|
});
|
||||||
|
return (
|
||||||
|
<Animated.View
|
||||||
|
style={[
|
||||||
|
styles.leftAction,
|
||||||
|
{ transform: [{ translateX: trans }] }
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<RectButton style={styles.actionButtonLeft} onPress={this.handleLeftButtonPress}>
|
||||||
|
<Animated.View
|
||||||
|
style={{ transform: [{ translateX: iconTrans }] }}
|
||||||
|
>
|
||||||
|
{isRead ? (
|
||||||
|
<View style={styles.actionView}>
|
||||||
|
<CustomIcon size={15} name='flag' color='white' />
|
||||||
|
<Text style={styles.actionText}>{I18n.t('Unread')}</Text>
|
||||||
|
</View>
|
||||||
|
) : (
|
||||||
|
<View style={styles.actionView}>
|
||||||
|
<CustomIcon size={15} name='check' color='white' />
|
||||||
|
<Text style={styles.actionText}>{I18n.t('Read')}</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</Animated.View>
|
||||||
|
</RectButton>
|
||||||
|
</Animated.View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
renderRightActions = () => {
|
||||||
|
const { favorite } = this.props;
|
||||||
|
const { width } = Dimensions.get('window');
|
||||||
|
const trans = this.rowTranslation.interpolate({
|
||||||
|
inputRange: [-OPTION_WIDTH, 0],
|
||||||
|
outputRange: [width - OPTION_WIDTH, width]
|
||||||
|
});
|
||||||
|
const iconHideTrans = this.rowTranslation.interpolate({
|
||||||
|
inputRange: [-(ACTION_OFFSET - 20), -2 * OPTION_WIDTH, 0],
|
||||||
|
outputRange: [0, 0, -OPTION_WIDTH]
|
||||||
|
});
|
||||||
|
const iconFavWidth = this.rowTranslation.interpolate({
|
||||||
|
inputRange: [-(ACTION_OFFSET + 1), -ACTION_OFFSET, -(ACTION_OFFSET - 20), -2 * OPTION_WIDTH, 0],
|
||||||
|
outputRange: [0, 0, OPTION_WIDTH + 20, OPTION_WIDTH, OPTION_WIDTH]
|
||||||
|
});
|
||||||
|
const iconHideWidth = this.rowTranslation.interpolate({
|
||||||
|
inputRange: [-(ACTION_OFFSET + 1), -ACTION_OFFSET, -(ACTION_OFFSET - 20), -2 * OPTION_WIDTH, 0],
|
||||||
|
outputRange: [(ACTION_OFFSET + 1), ACTION_OFFSET, OPTION_WIDTH + 20, OPTION_WIDTH, OPTION_WIDTH]
|
||||||
|
});
|
||||||
|
return (
|
||||||
|
<Animated.View
|
||||||
|
style={[
|
||||||
|
styles.rightAction,
|
||||||
|
{ transform: [{ translateX: trans }] }
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Animated.View
|
||||||
|
style={{ width: iconFavWidth }}
|
||||||
|
>
|
||||||
|
<RectButton style={[styles.actionButtonRightFav]} onPress={this.toggleFav}>
|
||||||
|
{favorite ? (
|
||||||
|
<View style={styles.actionView}>
|
||||||
|
<CustomIcon size={17} name='Star-filled' color='white' />
|
||||||
|
<Text style={styles.actionText}>{I18n.t('Unfavorite')}</Text>
|
||||||
|
</View>
|
||||||
|
) : (
|
||||||
|
<View style={styles.actionView}>
|
||||||
|
<CustomIcon size={17} name='star' color='white' />
|
||||||
|
<Text style={styles.actionText}>{I18n.t('Favorite')}</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</RectButton>
|
||||||
|
</Animated.View>
|
||||||
|
<Animated.View style={[
|
||||||
|
{ width: iconHideWidth },
|
||||||
|
{ transform: [{ translateX: iconHideTrans }] }
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<RectButton
|
||||||
|
style={[styles.actionButtonRightHide]}
|
||||||
|
onPress={this.handleHideButtonPress}
|
||||||
|
>
|
||||||
|
<View style={styles.actionView}>
|
||||||
|
<CustomIcon size={15} name='eye-off' color='white' />
|
||||||
|
<Text style={styles.actionText}>{I18n.t('Hide')}</Text>
|
||||||
|
</View>
|
||||||
|
</RectButton>
|
||||||
|
</Animated.View>
|
||||||
|
</Animated.View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
formatDate = date => moment(date).calendar(null, {
|
formatDate = date => moment(date).calendar(null, {
|
||||||
lastDay: `[${ I18n.t('Yesterday') }]`,
|
lastDay: `[${ I18n.t('Yesterday') }]`,
|
||||||
sameDay: 'h:mm A',
|
sameDay: 'h:mm A',
|
||||||
|
@ -97,30 +353,48 @@ export default class RoomItem extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RectButton
|
<PanGestureHandler
|
||||||
onPress={onPress}
|
minDeltaX={10}
|
||||||
activeOpacity={0.8}
|
onGestureEvent={this._onGestureEvent}
|
||||||
underlayColor='#e1e5e8'
|
onHandlerStateChange={this._onHandlerStateChange}
|
||||||
testID={testID}
|
|
||||||
>
|
>
|
||||||
<View
|
<Animated.View style={styles.upperContainer}>
|
||||||
style={[styles.container, height && { height }]}
|
{this.renderLeftActions()}
|
||||||
accessibilityLabel={accessibilityLabel}
|
{this.renderRightActions()}
|
||||||
>
|
<Animated.View
|
||||||
<Avatar text={name} size={avatarSize} type={type} baseUrl={baseUrl} style={styles.avatar} userId={userId} token={token} />
|
style={
|
||||||
<View style={styles.centerContainer}>
|
{
|
||||||
<View style={styles.titleContainer}>
|
transform: [{ translateX: this.rowTranslation }]
|
||||||
<TypeIcon type={type} id={id} prid={prid} />
|
}
|
||||||
<Text style={[styles.title, alert && styles.alert]} ellipsizeMode='tail' numberOfLines={1}>{ name }</Text>
|
}
|
||||||
{_updatedAt ? <Text style={[styles.date, alert && styles.updateAlert]} ellipsizeMode='tail' numberOfLines={1}>{ date }</Text> : null}
|
>
|
||||||
</View>
|
<RectButton
|
||||||
<View style={styles.row}>
|
onPress={onPress}
|
||||||
<LastMessage lastMessage={lastMessage} type={type} showLastMessage={showLastMessage} username={username} alert={alert} />
|
activeOpacity={0.8}
|
||||||
<UnreadBadge unread={unread} userMentions={userMentions} type={type} />
|
underlayColor='#e1e5e8'
|
||||||
</View>
|
testID={testID}
|
||||||
</View>
|
>
|
||||||
</View>
|
<View
|
||||||
</RectButton>
|
style={[styles.container, height && { height }]}
|
||||||
|
accessibilityLabel={accessibilityLabel}
|
||||||
|
>
|
||||||
|
<Avatar text={name} size={avatarSize} type={type} baseUrl={baseUrl} style={styles.avatar} userId={userId} token={token} />
|
||||||
|
<View style={styles.centerContainer}>
|
||||||
|
<View style={styles.titleContainer}>
|
||||||
|
<TypeIcon type={type} id={id} prid={prid} />
|
||||||
|
<Text style={[styles.title, alert && styles.alert]} ellipsizeMode='tail' numberOfLines={1}>{ name }</Text>
|
||||||
|
{_updatedAt ? <Text style={[styles.date, alert && styles.updateAlert]} ellipsizeMode='tail' numberOfLines={1}>{ date }</Text> : null}
|
||||||
|
</View>
|
||||||
|
<View style={styles.row}>
|
||||||
|
<LastMessage lastMessage={lastMessage} type={type} showLastMessage={showLastMessage} username={username} alert={alert} />
|
||||||
|
<UnreadBadge unread={unread} userMentions={userMentions} type={type} />
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</RectButton>
|
||||||
|
</Animated.View>
|
||||||
|
</Animated.View>
|
||||||
|
</PanGestureHandler>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,9 +9,10 @@ export const ROW_HEIGHT = 75 * PixelRatio.getFontScale();
|
||||||
|
|
||||||
export default StyleSheet.create({
|
export default StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
|
backgroundColor: COLOR_WHITE,
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
marginLeft: 14,
|
paddingLeft: 14,
|
||||||
height: ROW_HEIGHT
|
height: ROW_HEIGHT
|
||||||
},
|
},
|
||||||
centerContainer: {
|
centerContainer: {
|
||||||
|
@ -93,5 +94,44 @@ export default StyleSheet.create({
|
||||||
},
|
},
|
||||||
avatar: {
|
avatar: {
|
||||||
marginRight: 10
|
marginRight: 10
|
||||||
|
},
|
||||||
|
actionText: {
|
||||||
|
color: 'white',
|
||||||
|
fontSize: 14,
|
||||||
|
backgroundColor: 'transparent',
|
||||||
|
justifyContent: 'center'
|
||||||
|
},
|
||||||
|
actionButtonLeft: {
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: '#497AFC',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'flex-end'
|
||||||
|
},
|
||||||
|
actionButtonRightFav: {
|
||||||
|
flex: 1,
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'flex-start',
|
||||||
|
backgroundColor: '#F4BD3E'
|
||||||
|
},
|
||||||
|
actionButtonRightHide: {
|
||||||
|
flex: 1,
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'flex-start',
|
||||||
|
backgroundColor: '#55585D'
|
||||||
|
},
|
||||||
|
actionView: {
|
||||||
|
width: 80,
|
||||||
|
alignItems: 'center'
|
||||||
|
},
|
||||||
|
leftAction: {
|
||||||
|
...StyleSheet.absoluteFill,
|
||||||
|
flexDirection: 'row-reverse'
|
||||||
|
},
|
||||||
|
rightAction: {
|
||||||
|
...StyleSheet.absoluteFill,
|
||||||
|
flexDirection: 'row'
|
||||||
|
},
|
||||||
|
upperContainer: {
|
||||||
|
overflow: 'hidden'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -383,6 +383,30 @@ export default class RoomsListView extends React.Component {
|
||||||
}, 100);
|
}, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggleFav = async(rid, favorite) => {
|
||||||
|
try {
|
||||||
|
await RocketChat.toggleFavorite(rid, !favorite);
|
||||||
|
} catch (e) {
|
||||||
|
log('error_toggle_favorite', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleRead = async(rid, isRead) => {
|
||||||
|
try {
|
||||||
|
await RocketChat.toggleRead(isRead, rid);
|
||||||
|
} catch (e) {
|
||||||
|
log('error_toggle_read', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hideChannel = async(rid, type) => {
|
||||||
|
try {
|
||||||
|
await RocketChat.hideRoom(rid, type);
|
||||||
|
} catch (e) {
|
||||||
|
log('error_hide_channel', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
goDirectory = () => {
|
goDirectory = () => {
|
||||||
const { navigation } = this.props;
|
const { navigation } = this.props;
|
||||||
navigation.navigate('DirectoryView');
|
navigation.navigate('DirectoryView');
|
||||||
|
@ -404,6 +428,12 @@ export default class RoomsListView extends React.Component {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getIsRead = (item) => {
|
||||||
|
let isUnread = (item.archived !== true && item.open === true); // item is not archived and not opened
|
||||||
|
isUnread = isUnread && (item.unread > 0 || item.alert === true); // either its unread count > 0 or its alert
|
||||||
|
return !isUnread;
|
||||||
|
}
|
||||||
|
|
||||||
renderItem = ({ item }) => {
|
renderItem = ({ item }) => {
|
||||||
const {
|
const {
|
||||||
userId, baseUrl, StoreLastMessage
|
userId, baseUrl, StoreLastMessage
|
||||||
|
@ -416,12 +446,14 @@ export default class RoomsListView extends React.Component {
|
||||||
alert={item.alert}
|
alert={item.alert}
|
||||||
unread={item.unread}
|
unread={item.unread}
|
||||||
userMentions={item.userMentions}
|
userMentions={item.userMentions}
|
||||||
|
isRead={this.getIsRead(item)}
|
||||||
favorite={item.f}
|
favorite={item.f}
|
||||||
lastMessage={item.lastMessage ? JSON.parse(JSON.stringify(item.lastMessage)) : null}
|
lastMessage={item.lastMessage ? JSON.parse(JSON.stringify(item.lastMessage)) : null}
|
||||||
name={this.getRoomTitle(item)}
|
name={this.getRoomTitle(item)}
|
||||||
_updatedAt={item.roomUpdatedAt}
|
_updatedAt={item.roomUpdatedAt}
|
||||||
key={item._id}
|
key={item._id}
|
||||||
id={id}
|
id={id}
|
||||||
|
rid={item.rid}
|
||||||
type={item.t}
|
type={item.t}
|
||||||
baseUrl={baseUrl}
|
baseUrl={baseUrl}
|
||||||
prid={item.prid}
|
prid={item.prid}
|
||||||
|
@ -429,6 +461,9 @@ export default class RoomsListView extends React.Component {
|
||||||
onPress={() => this._onPressItem(item)}
|
onPress={() => this._onPressItem(item)}
|
||||||
testID={`rooms-list-view-item-${ item.name }`}
|
testID={`rooms-list-view-item-${ item.name }`}
|
||||||
height={ROW_HEIGHT}
|
height={ROW_HEIGHT}
|
||||||
|
toggleFav={this.toggleFav}
|
||||||
|
toggleRead={this.toggleRead}
|
||||||
|
hideChannel={this.hideChannel}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue