parent
8f90565e55
commit
061c313e3f
|
@ -71,7 +71,8 @@ export const MESSAGES = createRequestTypes('MESSAGES', [
|
||||||
'TOGGLE_PIN_FAILURE',
|
'TOGGLE_PIN_FAILURE',
|
||||||
'SET_INPUT',
|
'SET_INPUT',
|
||||||
'CLEAR_INPUT',
|
'CLEAR_INPUT',
|
||||||
'TOGGLE_REACTION_PICKER'
|
'TOGGLE_REACTION_PICKER',
|
||||||
|
'REPLY_BROADCAST'
|
||||||
]);
|
]);
|
||||||
export const CREATE_CHANNEL = createRequestTypes('CREATE_CHANNEL', [...defaultTypes]);
|
export const CREATE_CHANNEL = createRequestTypes('CREATE_CHANNEL', [...defaultTypes]);
|
||||||
export const SELECTED_USERS = createRequestTypes('SELECTED_USERS', ['ADD_USER', 'REMOVE_USER', 'RESET', 'SET_LOADING']);
|
export const SELECTED_USERS = createRequestTypes('SELECTED_USERS', ['ADD_USER', 'REMOVE_USER', 'RESET', 'SET_LOADING']);
|
||||||
|
|
|
@ -183,3 +183,10 @@ export function toggleReactionPicker(message) {
|
||||||
message
|
message
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function replyBroadcast(message) {
|
||||||
|
return {
|
||||||
|
type: types.MESSAGES.REPLY_BROADCAST,
|
||||||
|
message
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,10 @@ const styles = StyleSheet.create({
|
||||||
});
|
});
|
||||||
|
|
||||||
const RoomTypeIcon = ({ type, size }) => {
|
const RoomTypeIcon = ({ type, size }) => {
|
||||||
|
if (!type) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const icon = {
|
const icon = {
|
||||||
c: 'pound',
|
c: 'pound',
|
||||||
p: 'lock',
|
p: 'lock',
|
||||||
|
@ -21,7 +25,7 @@ const RoomTypeIcon = ({ type, size }) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
RoomTypeIcon.propTypes = {
|
RoomTypeIcon.propTypes = {
|
||||||
type: PropTypes.string.isRequired,
|
type: PropTypes.string,
|
||||||
size: PropTypes.number
|
size: PropTypes.number
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -18,10 +18,28 @@ import Reply from './Reply';
|
||||||
import ReactionsModal from './ReactionsModal';
|
import ReactionsModal from './ReactionsModal';
|
||||||
import Emoji from './Emoji';
|
import Emoji from './Emoji';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
import { actionsShow, errorActionsShow, toggleReactionPicker } from '../../actions/messages';
|
import { actionsShow, errorActionsShow, toggleReactionPicker, replyBroadcast } from '../../actions/messages';
|
||||||
import messagesStatus from '../../constants/messagesStatus';
|
import messagesStatus from '../../constants/messagesStatus';
|
||||||
import Touch from '../../utils/touch';
|
import Touch from '../../utils/touch';
|
||||||
|
|
||||||
|
const SYSTEM_MESSAGES = [
|
||||||
|
'r',
|
||||||
|
'au',
|
||||||
|
'ru',
|
||||||
|
'ul',
|
||||||
|
'uj',
|
||||||
|
'rm',
|
||||||
|
'user-muted',
|
||||||
|
'user-unmuted',
|
||||||
|
'message_pinned',
|
||||||
|
'subscription-role-added',
|
||||||
|
'subscription-role-removed',
|
||||||
|
'room_changed_description',
|
||||||
|
'room_changed_announcement',
|
||||||
|
'room_changed_topic',
|
||||||
|
'room_changed_privacy'
|
||||||
|
];
|
||||||
|
|
||||||
const getInfoMessage = ({
|
const getInfoMessage = ({
|
||||||
t, role, msg, u
|
t, role, msg, u
|
||||||
}) => {
|
}) => {
|
||||||
|
@ -68,7 +86,8 @@ const getInfoMessage = ({
|
||||||
}), dispatch => ({
|
}), dispatch => ({
|
||||||
actionsShow: actionMessage => dispatch(actionsShow(actionMessage)),
|
actionsShow: actionMessage => dispatch(actionsShow(actionMessage)),
|
||||||
errorActionsShow: actionMessage => dispatch(errorActionsShow(actionMessage)),
|
errorActionsShow: actionMessage => dispatch(errorActionsShow(actionMessage)),
|
||||||
toggleReactionPicker: message => dispatch(toggleReactionPicker(message))
|
toggleReactionPicker: message => dispatch(toggleReactionPicker(message)),
|
||||||
|
replyBroadcast: message => dispatch(replyBroadcast(message))
|
||||||
}))
|
}))
|
||||||
export default class Message extends React.Component {
|
export default class Message extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -83,17 +102,20 @@ export default class Message extends React.Component {
|
||||||
editing: PropTypes.bool,
|
editing: PropTypes.bool,
|
||||||
errorActionsShow: PropTypes.func,
|
errorActionsShow: PropTypes.func,
|
||||||
toggleReactionPicker: PropTypes.func,
|
toggleReactionPicker: PropTypes.func,
|
||||||
|
replyBroadcast: PropTypes.func,
|
||||||
onReactionPress: PropTypes.func,
|
onReactionPress: PropTypes.func,
|
||||||
style: ViewPropTypes.style,
|
style: ViewPropTypes.style,
|
||||||
onLongPress: PropTypes.func,
|
onLongPress: PropTypes.func,
|
||||||
_updatedAt: PropTypes.instanceOf(Date),
|
_updatedAt: PropTypes.instanceOf(Date),
|
||||||
archived: PropTypes.bool
|
archived: PropTypes.bool,
|
||||||
|
broadcast: PropTypes.bool
|
||||||
}
|
}
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
onLongPress: () => {},
|
onLongPress: () => {},
|
||||||
_updatedAt: new Date(),
|
_updatedAt: new Date(),
|
||||||
archived: false
|
archived: false,
|
||||||
|
broadcast: false
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -116,6 +138,9 @@ export default class Message extends React.Component {
|
||||||
if (!equal(this.props.reactions, nextProps.reactions)) {
|
if (!equal(this.props.reactions, nextProps.reactions)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (this.props.broadcast !== nextProps.broadcast) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return this.props._updatedAt.toGMTString() !== nextProps._updatedAt.toGMTString();
|
return this.props._updatedAt.toGMTString() !== nextProps._updatedAt.toGMTString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,25 +175,11 @@ export default class Message extends React.Component {
|
||||||
parseMessage = () => JSON.parse(JSON.stringify(this.props.item));
|
parseMessage = () => JSON.parse(JSON.stringify(this.props.item));
|
||||||
|
|
||||||
isInfoMessage() {
|
isInfoMessage() {
|
||||||
return [
|
return SYSTEM_MESSAGES.includes(this.props.item.t);
|
||||||
'r',
|
|
||||||
'au',
|
|
||||||
'ru',
|
|
||||||
'ul',
|
|
||||||
'uj',
|
|
||||||
'rm',
|
|
||||||
'user-muted',
|
|
||||||
'user-unmuted',
|
|
||||||
'message_pinned',
|
|
||||||
'subscription-role-added',
|
|
||||||
'subscription-role-removed',
|
|
||||||
'room_changed_description',
|
|
||||||
'room_changed_announcement',
|
|
||||||
'room_changed_topic',
|
|
||||||
'room_changed_privacy'
|
|
||||||
].includes(this.props.item.t);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isOwn = () => this.props.item.u && this.props.item.u._id === this.props.user.id;
|
||||||
|
|
||||||
isDeleted() {
|
isDeleted() {
|
||||||
return this.props.item.t === 'rm';
|
return this.props.item.t === 'rm';
|
||||||
}
|
}
|
||||||
|
@ -187,7 +198,7 @@ export default class Message extends React.Component {
|
||||||
if (previousItem && (
|
if (previousItem && (
|
||||||
(previousItem.ts.toDateString() === item.ts.toDateString()) &&
|
(previousItem.ts.toDateString() === item.ts.toDateString()) &&
|
||||||
(previousItem.u.username === item.u.username) &&
|
(previousItem.u.username === item.u.username) &&
|
||||||
!(previousItem.groupable === false || item.groupable === false) &&
|
!(previousItem.groupable === false || item.groupable === false || this.props.broadcast === true) &&
|
||||||
(previousItem.status === item.status) &&
|
(previousItem.status === item.status) &&
|
||||||
(item.ts - previousItem.ts < this.props.Message_GroupingPeriod * 1000)
|
(item.ts - previousItem.ts < this.props.Message_GroupingPeriod * 1000)
|
||||||
)) {
|
)) {
|
||||||
|
@ -303,6 +314,20 @@ export default class Message extends React.Component {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderBroadcastReply() {
|
||||||
|
if (!this.props.broadcast || this.isOwn()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<TouchableOpacity
|
||||||
|
style={styles.broadcastButton}
|
||||||
|
onPress={() => this.props.replyBroadcast(this.parseMessage())}
|
||||||
|
>
|
||||||
|
<Text style={styles.broadcastButtonText}>Reply</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
item, message, editing, style, archived
|
item, message, editing, style, archived
|
||||||
|
@ -329,6 +354,7 @@ export default class Message extends React.Component {
|
||||||
{this.renderAttachment()}
|
{this.renderAttachment()}
|
||||||
{this.renderUrl()}
|
{this.renderUrl()}
|
||||||
{this.renderReactions()}
|
{this.renderReactions()}
|
||||||
|
{this.renderBroadcastReply()}
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
{this.state.reactionsModal &&
|
{this.state.reactionsModal &&
|
||||||
|
|
|
@ -84,5 +84,18 @@ export default StyleSheet.create({
|
||||||
padding: 10,
|
padding: 10,
|
||||||
paddingRight: 12,
|
paddingRight: 12,
|
||||||
paddingLeft: 0
|
paddingLeft: 0
|
||||||
|
},
|
||||||
|
broadcastButton: {
|
||||||
|
borderColor: '#1d74f5',
|
||||||
|
borderWidth: 2,
|
||||||
|
borderRadius: 2,
|
||||||
|
paddingVertical: 10,
|
||||||
|
width: 100,
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
marginTop: 6
|
||||||
|
},
|
||||||
|
broadcastButtonText: {
|
||||||
|
color: '#1d74f5'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,6 +4,9 @@ import normalizeMessage from './normalizeMessage';
|
||||||
export const merge = (subscription, room) => {
|
export const merge = (subscription, room) => {
|
||||||
subscription.muted = [];
|
subscription.muted = [];
|
||||||
if (room) {
|
if (room) {
|
||||||
|
if (room.rid) {
|
||||||
|
subscription.rid = room.rid;
|
||||||
|
}
|
||||||
subscription.roomUpdatedAt = room._updatedAt;
|
subscription.roomUpdatedAt = room._updatedAt;
|
||||||
subscription.lastMessage = normalizeMessage(room.lastMessage);
|
subscription.lastMessage = normalizeMessage(room.lastMessage);
|
||||||
subscription.ro = room.ro;
|
subscription.ro = room.ro;
|
||||||
|
@ -13,6 +16,7 @@ export const merge = (subscription, room) => {
|
||||||
subscription.reactWhenReadOnly = room.reactWhenReadOnly;
|
subscription.reactWhenReadOnly = room.reactWhenReadOnly;
|
||||||
subscription.archived = room.archived;
|
subscription.archived = room.archived;
|
||||||
subscription.joinCodeRequired = room.joinCodeRequired;
|
subscription.joinCodeRequired = room.joinCodeRequired;
|
||||||
|
subscription.broadcast = room.broadcast;
|
||||||
|
|
||||||
if (room.muted && room.muted.length) {
|
if (room.muted && room.muted.length) {
|
||||||
subscription.muted = room.muted.filter(user => user).map(user => ({ value: user }));
|
subscription.muted = room.muted.filter(user => user).map(user => ({ value: user }));
|
||||||
|
@ -28,7 +32,8 @@ export const merge = (subscription, room) => {
|
||||||
subscription.notifications = false;
|
subscription.notifications = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
subscription.blocked = !!subscription.blocker;
|
subscription.blocker = !!subscription.blocker;
|
||||||
|
subscription.blocked = !!subscription.blocked;
|
||||||
return subscription;
|
return subscription;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -51,16 +51,24 @@ export default async function subscribeRooms(id) {
|
||||||
const [type, data] = ddpMessage.fields.args;
|
const [type, data] = ddpMessage.fields.args;
|
||||||
const [, ev] = ddpMessage.fields.eventName.split('/');
|
const [, ev] = ddpMessage.fields.eventName.split('/');
|
||||||
if (/subscriptions/.test(ev)) {
|
if (/subscriptions/.test(ev)) {
|
||||||
const tpm = merge(data);
|
const rooms = database.objects('rooms').filtered('_id == $0', data.rid);
|
||||||
|
const tpm = merge(data, rooms[0]);
|
||||||
database.write(() => {
|
database.write(() => {
|
||||||
database.create('subscriptions', tpm, true);
|
database.create('subscriptions', tpm, true);
|
||||||
|
database.delete(rooms);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (/rooms/.test(ev) && type === 'updated') {
|
if (/rooms/.test(ev)) {
|
||||||
const [sub] = database.objects('subscriptions').filtered('rid == $0', data._id);
|
if (type === 'updated') {
|
||||||
database.write(() => {
|
const [sub] = database.objects('subscriptions').filtered('rid == $0', data._id);
|
||||||
merge(sub, data);
|
database.write(() => {
|
||||||
});
|
merge(sub, data);
|
||||||
|
});
|
||||||
|
} else if (type === 'inserted') {
|
||||||
|
database.write(() => {
|
||||||
|
database.create('rooms', data, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (/message/.test(ev)) {
|
if (/message/.test(ev)) {
|
||||||
const [args] = ddpMessage.fields.args;
|
const [args] = ddpMessage.fields.args;
|
||||||
|
|
|
@ -49,10 +49,7 @@ const roomsSchema = {
|
||||||
primaryKey: '_id',
|
primaryKey: '_id',
|
||||||
properties: {
|
properties: {
|
||||||
_id: 'string',
|
_id: 'string',
|
||||||
t: 'string',
|
broadcast: { type: 'bool', optional: true }
|
||||||
lastMessage: 'messages',
|
|
||||||
description: { type: 'string', optional: true },
|
|
||||||
_updatedAt: { type: 'date', optional: true }
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -97,11 +94,13 @@ const subscriptionSchema = {
|
||||||
announcement: { type: 'string', optional: true },
|
announcement: { type: 'string', optional: true },
|
||||||
topic: { type: 'string', optional: true },
|
topic: { type: 'string', optional: true },
|
||||||
blocked: { type: 'bool', optional: true },
|
blocked: { type: 'bool', optional: true },
|
||||||
|
blocker: { type: 'bool', optional: true },
|
||||||
reactWhenReadOnly: { type: 'bool', optional: true },
|
reactWhenReadOnly: { type: 'bool', optional: true },
|
||||||
archived: { type: 'bool', optional: true },
|
archived: { type: 'bool', optional: true },
|
||||||
joinCodeRequired: { type: 'bool', optional: true },
|
joinCodeRequired: { type: 'bool', optional: true },
|
||||||
notifications: { type: 'bool', optional: true },
|
notifications: { type: 'bool', optional: true },
|
||||||
muted: { type: 'list', objectType: 'usersMuted' }
|
muted: { type: 'list', objectType: 'usersMuted' },
|
||||||
|
broadcast: { type: 'bool', optional: true }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -49,8 +49,10 @@ const RocketChat = {
|
||||||
subscribeRooms,
|
subscribeRooms,
|
||||||
subscribeRoom,
|
subscribeRoom,
|
||||||
canOpenRoom,
|
canOpenRoom,
|
||||||
createChannel({ name, users, type }) {
|
createChannel({
|
||||||
return call(type ? 'createChannel' : 'createPrivateGroup', name, users, type);
|
name, users, type, readOnly, broadcast
|
||||||
|
}) {
|
||||||
|
return call(type ? 'createPrivateGroup' : 'createChannel', name, users, readOnly, {}, { broadcast });
|
||||||
},
|
},
|
||||||
async createDirectMessageAndWait(username) {
|
async createDirectMessageAndWait(username) {
|
||||||
const room = await RocketChat.createDirectMessage(username);
|
const room = await RocketChat.createDirectMessage(username);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { takeLatest, put, call } from 'redux-saga/effects';
|
import { delay } from 'redux-saga';
|
||||||
|
import { takeLatest, put, call, select } from 'redux-saga/effects';
|
||||||
import { MESSAGES } from '../actions/actionsTypes';
|
import { MESSAGES } from '../actions/actionsTypes';
|
||||||
import {
|
import {
|
||||||
messagesSuccess,
|
messagesSuccess,
|
||||||
|
@ -12,9 +13,13 @@ import {
|
||||||
permalinkSuccess,
|
permalinkSuccess,
|
||||||
permalinkFailure,
|
permalinkFailure,
|
||||||
togglePinSuccess,
|
togglePinSuccess,
|
||||||
togglePinFailure
|
togglePinFailure,
|
||||||
|
setInput
|
||||||
} from '../actions/messages';
|
} from '../actions/messages';
|
||||||
import RocketChat from '../lib/rocketchat';
|
import RocketChat from '../lib/rocketchat';
|
||||||
|
import database from '../lib/realm';
|
||||||
|
import { goRoom } from '../containers/routes/NavigationService';
|
||||||
|
import log from '../utils/log';
|
||||||
|
|
||||||
const deleteMessage = message => RocketChat.deleteMessage(message);
|
const deleteMessage = message => RocketChat.deleteMessage(message);
|
||||||
const editMessage = message => RocketChat.editMessage(message);
|
const editMessage = message => RocketChat.editMessage(message);
|
||||||
|
@ -81,6 +86,25 @@ const handleTogglePinRequest = function* handleTogglePinRequest({ message }) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleReplyBroadcast = function* handleReplyBroadcast({ message }) {
|
||||||
|
try {
|
||||||
|
const { username } = message.u;
|
||||||
|
const subscriptions = database.objects('subscriptions').filtered('name = $0', username);
|
||||||
|
if (subscriptions.length) {
|
||||||
|
goRoom({ rid: subscriptions[0].rid, name: subscriptions[0].name });
|
||||||
|
} else {
|
||||||
|
const room = yield RocketChat.createDirectMessage(username);
|
||||||
|
goRoom({ rid: room.rid, name: username });
|
||||||
|
}
|
||||||
|
yield delay(100);
|
||||||
|
const server = yield select(state => state.server.server);
|
||||||
|
const msg = `[ ](${ server }/direct/${ username }?msg=${ message._id })`;
|
||||||
|
yield put(setInput({ msg }));
|
||||||
|
} catch (e) {
|
||||||
|
log('handleReplyBroadcast', e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const root = function* root() {
|
const root = function* root() {
|
||||||
yield takeLatest(MESSAGES.REQUEST, get);
|
yield takeLatest(MESSAGES.REQUEST, get);
|
||||||
yield takeLatest(MESSAGES.DELETE_REQUEST, handleDeleteRequest);
|
yield takeLatest(MESSAGES.DELETE_REQUEST, handleDeleteRequest);
|
||||||
|
@ -88,5 +112,6 @@ const root = function* root() {
|
||||||
yield takeLatest(MESSAGES.TOGGLE_STAR_REQUEST, handleToggleStarRequest);
|
yield takeLatest(MESSAGES.TOGGLE_STAR_REQUEST, handleToggleStarRequest);
|
||||||
yield takeLatest(MESSAGES.PERMALINK_REQUEST, handlePermalinkRequest);
|
yield takeLatest(MESSAGES.PERMALINK_REQUEST, handlePermalinkRequest);
|
||||||
yield takeLatest(MESSAGES.TOGGLE_PIN_REQUEST, handleTogglePinRequest);
|
yield takeLatest(MESSAGES.TOGGLE_PIN_REQUEST, handleTogglePinRequest);
|
||||||
|
yield takeLatest(MESSAGES.REPLY_BROADCAST, handleReplyBroadcast);
|
||||||
};
|
};
|
||||||
export default root;
|
export default root;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { View, Text, Switch, TouchableOpacity, SafeAreaView, ScrollView } from 'react-native';
|
import { View, Text, Switch, SafeAreaView, ScrollView, Platform } from 'react-native';
|
||||||
|
|
||||||
import RCTextInput from '../containers/TextInput';
|
import RCTextInput from '../containers/TextInput';
|
||||||
import Loading from '../containers/Loading';
|
import Loading from '../containers/Loading';
|
||||||
|
@ -10,6 +10,7 @@ import { createChannelRequest } from '../actions/createChannel';
|
||||||
import styles from './Styles';
|
import styles from './Styles';
|
||||||
import KeyboardView from '../presentation/KeyboardView';
|
import KeyboardView from '../presentation/KeyboardView';
|
||||||
import scrollPersistTaps from '../utils/scrollPersistTaps';
|
import scrollPersistTaps from '../utils/scrollPersistTaps';
|
||||||
|
import Button from '../containers/Button';
|
||||||
|
|
||||||
@connect(
|
@connect(
|
||||||
state => ({
|
state => ({
|
||||||
|
@ -35,22 +36,28 @@ export default class CreateChannelView extends LoggedView {
|
||||||
super('CreateChannelView', props);
|
super('CreateChannelView', props);
|
||||||
this.state = {
|
this.state = {
|
||||||
channelName: '',
|
channelName: '',
|
||||||
type: true
|
type: true,
|
||||||
|
readOnly: false,
|
||||||
|
broadcast: false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
submit() {
|
submit = () => {
|
||||||
if (!this.state.channelName.trim() || this.props.createChannel.isFetching) {
|
if (!this.state.channelName.trim() || this.props.createChannel.isFetching) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { channelName, type = true } = this.state;
|
const {
|
||||||
|
channelName, type, readOnly, broadcast
|
||||||
|
} = this.state;
|
||||||
let { users } = this.props;
|
let { users } = this.props;
|
||||||
|
|
||||||
// transform users object into array of usernames
|
// transform users object into array of usernames
|
||||||
users = users.map(user => user.name);
|
users = users.map(user => user.name);
|
||||||
|
|
||||||
// create channel
|
// create channel
|
||||||
this.props.create({ name: channelName, users, type });
|
this.props.create({
|
||||||
|
name: channelName, users, type, readOnly, broadcast
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
renderChannelNameError() {
|
renderChannelNameError() {
|
||||||
|
@ -68,20 +75,62 @@ export default class CreateChannelView extends LoggedView {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderTypeSwitch() {
|
renderSwitch = ({
|
||||||
return (
|
id, value, label, description, onValueChange, disabled = false
|
||||||
<View style={[styles.view_white, styles.switchContainer]}>
|
}) => (
|
||||||
|
<View style={{ marginBottom: 15 }}>
|
||||||
|
<View style={styles.switchContainer}>
|
||||||
<Switch
|
<Switch
|
||||||
style={[{ flexGrow: 0, flexShrink: 1 }]}
|
value={value}
|
||||||
value={this.state.type}
|
onValueChange={onValueChange}
|
||||||
onValueChange={type => this.setState({ type })}
|
testID={`create-channel-${ id }`}
|
||||||
testID='create-channel-type'
|
onTintColor='#2de0a5'
|
||||||
|
tintColor={Platform.OS === 'android' ? '#f5455c' : null}
|
||||||
|
disabled={disabled}
|
||||||
/>
|
/>
|
||||||
<Text style={[styles.label_white, styles.switchLabel]}>
|
<Text style={styles.switchLabel}>{label}</Text>
|
||||||
{this.state.type ? 'Public' : 'Private'}
|
|
||||||
</Text>
|
|
||||||
</View>
|
</View>
|
||||||
);
|
<Text style={styles.switchDescription}>{description}</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
|
||||||
|
renderType() {
|
||||||
|
const { type } = this.state;
|
||||||
|
return this.renderSwitch({
|
||||||
|
id: 'type',
|
||||||
|
value: type,
|
||||||
|
label: type ? 'Private Channel' : 'Public Channel',
|
||||||
|
description: type ? 'Just invited people can access this channel' : 'Everyone can access this channel',
|
||||||
|
onValueChange: value => this.setState({ type: value })
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
renderReadOnly() {
|
||||||
|
const { readOnly, broadcast } = this.state;
|
||||||
|
return this.renderSwitch({
|
||||||
|
id: 'readonly',
|
||||||
|
value: readOnly,
|
||||||
|
label: 'Read Only Channel',
|
||||||
|
description: readOnly ? 'Only authorized users can write new messages' : 'All users in the channel can write new messages',
|
||||||
|
onValueChange: value => this.setState({ readOnly: value }),
|
||||||
|
disabled: broadcast
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
renderBroadcast() {
|
||||||
|
const { broadcast, readOnly } = this.state;
|
||||||
|
return this.renderSwitch({
|
||||||
|
id: 'broadcast',
|
||||||
|
value: broadcast,
|
||||||
|
label: 'Broadcast Channel',
|
||||||
|
description: 'Only authorized users can write new messages, but the other users will be able to reply',
|
||||||
|
onValueChange: (value) => {
|
||||||
|
this.setState({
|
||||||
|
broadcast: value,
|
||||||
|
readOnly: value ? true : readOnly
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -102,36 +151,18 @@ export default class CreateChannelView extends LoggedView {
|
||||||
testID='create-channel-name'
|
testID='create-channel-name'
|
||||||
/>
|
/>
|
||||||
{this.renderChannelNameError()}
|
{this.renderChannelNameError()}
|
||||||
{this.renderTypeSwitch()}
|
{this.renderType()}
|
||||||
<Text
|
{this.renderReadOnly()}
|
||||||
style={[
|
{this.renderBroadcast()}
|
||||||
styles.label_white,
|
<View style={styles.alignItemsFlexStart}>
|
||||||
{
|
<Button
|
||||||
color: '#9ea2a8',
|
title='Create'
|
||||||
flexGrow: 1,
|
type='primary'
|
||||||
paddingHorizontal: 0,
|
onPress={this.submit}
|
||||||
marginBottom: 20
|
disabled={this.state.channelName.length === 0 || this.props.createChannel.isFetching}
|
||||||
}
|
testID='create-channel-submit'
|
||||||
]}
|
/>
|
||||||
>
|
</View>
|
||||||
{this.state.type ? (
|
|
||||||
'Everyone can access this channel'
|
|
||||||
) : (
|
|
||||||
'Just invited people can access this channel'
|
|
||||||
)}
|
|
||||||
</Text>
|
|
||||||
<TouchableOpacity
|
|
||||||
onPress={() => this.submit()}
|
|
||||||
style={[
|
|
||||||
styles.buttonContainer_white,
|
|
||||||
this.state.channelName.length === 0 || this.props.createChannel.isFetching
|
|
||||||
? styles.disabledButton
|
|
||||||
: styles.enabledButton
|
|
||||||
]}
|
|
||||||
testID='create-channel-submit'
|
|
||||||
>
|
|
||||||
<Text style={styles.button_white}>CREATE</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
<Loading visible={this.props.createChannel.isFetching} />
|
<Loading visible={this.props.createChannel.isFetching} />
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
|
@ -71,6 +71,11 @@ export default class RoomActionsView extends LoggedView {
|
||||||
|
|
||||||
updateRoomMembers = async() => {
|
updateRoomMembers = async() => {
|
||||||
const { t } = this.state.room;
|
const { t } = this.state.room;
|
||||||
|
|
||||||
|
if (!this.canViewMembers) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
if (t === 'c' || t === 'p') {
|
if (t === 'c' || t === 'p') {
|
||||||
let onlineMembers = [];
|
let onlineMembers = [];
|
||||||
let allMembers = [];
|
let allMembers = [];
|
||||||
|
@ -123,9 +128,20 @@ export default class RoomActionsView extends LoggedView {
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
get canViewMembers() {
|
||||||
|
const { rid, t, broadcast } = this.state.room;
|
||||||
|
if (broadcast) {
|
||||||
|
const viewBroadcastMemberListPermission = 'view-broadcast-member-list';
|
||||||
|
const permissions = RocketChat.hasPermission([viewBroadcastMemberListPermission], rid);
|
||||||
|
if (!permissions[viewBroadcastMemberListPermission]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (t === 'c' || t === 'p');
|
||||||
|
}
|
||||||
get sections() {
|
get sections() {
|
||||||
const {
|
const {
|
||||||
rid, t, blocked, notifications
|
rid, t, blocker, notifications
|
||||||
} = this.room;
|
} = this.room;
|
||||||
const { onlineMembers } = this.state;
|
const { onlineMembers } = this.state;
|
||||||
|
|
||||||
|
@ -219,7 +235,7 @@ export default class RoomActionsView extends LoggedView {
|
||||||
data: [
|
data: [
|
||||||
{
|
{
|
||||||
icon: 'block',
|
icon: 'block',
|
||||||
name: `${ blocked ? 'Unblock' : 'Block' } user`,
|
name: `${ blocker ? 'Unblock' : 'Block' } user`,
|
||||||
type: 'danger',
|
type: 'danger',
|
||||||
event: () => this.toggleBlockUser(),
|
event: () => this.toggleBlockUser(),
|
||||||
testID: 'room-actions-block-user'
|
testID: 'room-actions-block-user'
|
||||||
|
@ -228,14 +244,18 @@ export default class RoomActionsView extends LoggedView {
|
||||||
renderItem: this.renderItem
|
renderItem: this.renderItem
|
||||||
});
|
});
|
||||||
} else if (t === 'c' || t === 'p') {
|
} else if (t === 'c' || t === 'p') {
|
||||||
const actions = [{
|
const actions = [];
|
||||||
icon: 'ios-people',
|
|
||||||
name: 'Members',
|
if (this.canViewMembers) {
|
||||||
description: (onlineMembers.length === 1 ? `${ onlineMembers.length } member` : `${ onlineMembers.length } members`),
|
actions.push({
|
||||||
route: 'RoomMembers',
|
icon: 'ios-people',
|
||||||
params: { rid, members: onlineMembers },
|
name: 'Members',
|
||||||
testID: 'room-actions-members'
|
description: (onlineMembers.length === 1 ? `${ onlineMembers.length } member` : `${ onlineMembers.length } members`),
|
||||||
}];
|
route: 'RoomMembers',
|
||||||
|
params: { rid, members: onlineMembers },
|
||||||
|
testID: 'room-actions-members'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (this.canAddUser) {
|
if (this.canAddUser) {
|
||||||
actions.push({
|
actions.push({
|
||||||
|
@ -276,10 +296,10 @@ export default class RoomActionsView extends LoggedView {
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleBlockUser = async() => {
|
toggleBlockUser = async() => {
|
||||||
const { rid, blocked } = this.state.room;
|
const { rid, blocker } = this.state.room;
|
||||||
const { member } = this.state;
|
const { member } = this.state;
|
||||||
try {
|
try {
|
||||||
RocketChat.toggleBlockUser(rid, member._id, !blocked);
|
RocketChat.toggleBlockUser(rid, member._id, !blocker);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log('toggleBlockUser', e);
|
log('toggleBlockUser', e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -324,10 +324,10 @@ export default class RoomInfoEditView extends LoggedView {
|
||||||
rightLabelPrimary='Read Only'
|
rightLabelPrimary='Read Only'
|
||||||
rightLabelSecondary='Only authorized users can write new messages'
|
rightLabelSecondary='Only authorized users can write new messages'
|
||||||
onValueChange={value => this.setState({ ro: value })}
|
onValueChange={value => this.setState({ ro: value })}
|
||||||
disabled={!this.permissions[PERMISSION_SET_READONLY]}
|
disabled={!this.permissions[PERMISSION_SET_READONLY] || room.broadcast}
|
||||||
testID='room-info-edit-view-ro'
|
testID='room-info-edit-view-ro'
|
||||||
/>
|
/>
|
||||||
{ro &&
|
{ro && !room.broadcast &&
|
||||||
<SwitchContainer
|
<SwitchContainer
|
||||||
value={reactWhenReadOnly}
|
value={reactWhenReadOnly}
|
||||||
leftLabelPrimary='No Reactions'
|
leftLabelPrimary='No Reactions'
|
||||||
|
@ -339,6 +339,12 @@ export default class RoomInfoEditView extends LoggedView {
|
||||||
testID='room-info-edit-view-react-when-ro'
|
testID='room-info-edit-view-react-when-ro'
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
{room.broadcast &&
|
||||||
|
[
|
||||||
|
<Text style={styles.broadcast}>Broadcast channel</Text>,
|
||||||
|
<View style={styles.divider} />
|
||||||
|
]
|
||||||
|
}
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={[sharedStyles.buttonContainer, !this.formIsChanged() && styles.buttonContainerDisabled]}
|
style={[sharedStyles.buttonContainer, !this.formIsChanged() && styles.buttonContainerDisabled]}
|
||||||
onPress={this.submit}
|
onPress={this.submit}
|
||||||
|
|
|
@ -42,5 +42,9 @@ export default StyleSheet.create({
|
||||||
borderColor: '#ddd',
|
borderColor: '#ddd',
|
||||||
borderBottomWidth: StyleSheet.hairlineWidth,
|
borderBottomWidth: StyleSheet.hairlineWidth,
|
||||||
marginVertical: 20
|
marginVertical: 20
|
||||||
|
},
|
||||||
|
broadcast: {
|
||||||
|
fontWeight: 'bold',
|
||||||
|
textAlign: 'center'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -21,8 +21,11 @@ const PERMISSION_EDIT_ROOM = 'edit-room';
|
||||||
|
|
||||||
const camelize = str => str.replace(/^(.)/, (match, chr) => chr.toUpperCase());
|
const camelize = str => str.replace(/^(.)/, (match, chr) => chr.toUpperCase());
|
||||||
const getRoomTitle = room => (room.t === 'd' ?
|
const getRoomTitle = room => (room.t === 'd' ?
|
||||||
<Text testID='room-info-view-name'>{room.fname}</Text> :
|
<Text testID='room-info-view-name' style={styles.roomTitle}>{room.fname}</Text> :
|
||||||
[<RoomTypeIcon type={room.t} />, <Text testID='room-info-view-name'>{room.name}</Text>]
|
[
|
||||||
|
<RoomTypeIcon type={room.t} key='room-info-type' />,
|
||||||
|
<Text testID='room-info-view-name' style={styles.roomTitle} key='room-info-name'>{room.name}</Text>
|
||||||
|
]
|
||||||
);
|
);
|
||||||
@connect(state => ({
|
@connect(state => ({
|
||||||
baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
|
baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
|
||||||
|
@ -184,6 +187,17 @@ export default class RoomInfoView extends LoggedView {
|
||||||
</Avatar>
|
</Avatar>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
renderBroadcast = () => (
|
||||||
|
<View style={styles.item}>
|
||||||
|
<Text style={styles.itemLabel}>Broadcast Channel</Text>
|
||||||
|
<Text
|
||||||
|
style={styles.itemContent}
|
||||||
|
testID='room-info-view-broadcast'
|
||||||
|
>Only authorized users can write new messages, but the other users will be able to reply
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { room, roomUser } = this.state;
|
const { room, roomUser } = this.state;
|
||||||
if (!room) {
|
if (!room) {
|
||||||
|
@ -193,13 +207,14 @@ export default class RoomInfoView extends LoggedView {
|
||||||
<ScrollView style={styles.container}>
|
<ScrollView style={styles.container}>
|
||||||
<View style={styles.avatarContainer} testID='room-info-view'>
|
<View style={styles.avatarContainer} testID='room-info-view'>
|
||||||
{this.renderAvatar(room, roomUser)}
|
{this.renderAvatar(room, roomUser)}
|
||||||
<View style={styles.roomTitle}>{ getRoomTitle(room) }</View>
|
<View style={styles.roomTitleContainer}>{ getRoomTitle(room) }</View>
|
||||||
</View>
|
</View>
|
||||||
{!this.isDirect() && this.renderItem('description', room)}
|
{!this.isDirect() && this.renderItem('description', room)}
|
||||||
{!this.isDirect() && this.renderItem('topic', room)}
|
{!this.isDirect() && this.renderItem('topic', room)}
|
||||||
{!this.isDirect() && this.renderItem('announcement', room)}
|
{!this.isDirect() && this.renderItem('announcement', room)}
|
||||||
{this.isDirect() && this.renderRoles()}
|
{this.isDirect() && this.renderRoles()}
|
||||||
{this.isDirect() && this.renderTimezone(roomUser._id)}
|
{this.isDirect() && this.renderTimezone(roomUser._id)}
|
||||||
|
{room.broadcast && this.renderBroadcast()}
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,11 +29,13 @@ export default StyleSheet.create({
|
||||||
avatar: {
|
avatar: {
|
||||||
marginHorizontal: 10
|
marginHorizontal: 10
|
||||||
},
|
},
|
||||||
roomTitle: {
|
roomTitleContainer: {
|
||||||
fontSize: 18,
|
|
||||||
paddingTop: 20,
|
paddingTop: 20,
|
||||||
flexDirection: 'row'
|
flexDirection: 'row'
|
||||||
},
|
},
|
||||||
|
roomTitle: {
|
||||||
|
fontSize: 18
|
||||||
|
},
|
||||||
roomDescription: {
|
roomDescription: {
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: '#ccc',
|
color: '#ccc',
|
||||||
|
|
|
@ -153,6 +153,22 @@ export default class RoomView extends LoggedView {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
isOwner = () => this.state.room && this.state.room.roles && Array.from(Object.keys(this.state.room.roles), i => this.state.room.roles[i].value).includes('owner');
|
||||||
|
|
||||||
|
isMuted = () => this.state.room && this.state.room.muted && Array.from(Object.keys(this.state.room.muted), i => this.state.room.muted[i].value).includes(this.props.user.username);
|
||||||
|
|
||||||
|
isReadOnly = () => this.state.room.ro && this.isMuted() && !this.isOwner();
|
||||||
|
|
||||||
|
isBlocked = () => {
|
||||||
|
if (this.state.room) {
|
||||||
|
const { t, blocked, blocker } = this.state.room;
|
||||||
|
if (t === 'd' && (blocked || blocker)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
renderItem = (item, previousItem) => (
|
renderItem = (item, previousItem) => (
|
||||||
<Message
|
<Message
|
||||||
key={item._id}
|
key={item._id}
|
||||||
|
@ -164,6 +180,7 @@ export default class RoomView extends LoggedView {
|
||||||
onReactionPress={this.onReactionPress}
|
onReactionPress={this.onReactionPress}
|
||||||
onLongPress={this.onMessageLongPress}
|
onLongPress={this.onMessageLongPress}
|
||||||
archived={this.state.room.archived}
|
archived={this.state.room.archived}
|
||||||
|
broadcast={this.state.room.broadcast}
|
||||||
previousItem={previousItem}
|
previousItem={previousItem}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -179,13 +196,20 @@ export default class RoomView extends LoggedView {
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (this.state.room.ro || this.state.room.archived) {
|
if (this.state.room.archived || this.isReadOnly()) {
|
||||||
return (
|
return (
|
||||||
<View style={styles.readOnly}>
|
<View style={styles.readOnly}>
|
||||||
<Text>This room is read only</Text>
|
<Text>This room is read only</Text>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (this.isBlocked()) {
|
||||||
|
return (
|
||||||
|
<View style={styles.blockedOrBlocker}>
|
||||||
|
<Text>This room is blocked</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
return <MessageBox onSubmit={this.sendMessage} rid={this.rid} />;
|
return <MessageBox onSubmit={this.sendMessage} rid={this.rid} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,9 @@ export default StyleSheet.create({
|
||||||
readOnly: {
|
readOnly: {
|
||||||
padding: 10
|
padding: 10
|
||||||
},
|
},
|
||||||
|
blockedOrBlocker: {
|
||||||
|
padding: 10
|
||||||
|
},
|
||||||
reactionPickerContainer: {
|
reactionPickerContainer: {
|
||||||
// width: width - 20,
|
// width: width - 20,
|
||||||
// height: width - 20,
|
// height: width - 20,
|
||||||
|
|
|
@ -80,12 +80,18 @@ export default StyleSheet.create({
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
justifyContent: 'flex-start',
|
justifyContent: 'flex-start',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
paddingHorizontal: 0
|
paddingHorizontal: 0,
|
||||||
|
paddingBottom: 5
|
||||||
},
|
},
|
||||||
switchLabel: {
|
switchLabel: {
|
||||||
flexGrow: 1,
|
fontSize: 16,
|
||||||
|
color: '#2f343d',
|
||||||
paddingHorizontal: 10
|
paddingHorizontal: 10
|
||||||
},
|
},
|
||||||
|
switchDescription: {
|
||||||
|
fontSize: 16,
|
||||||
|
color: '#9ea2a8'
|
||||||
|
},
|
||||||
disabledButton: {
|
disabledButton: {
|
||||||
backgroundColor: '#e1e5e8'
|
backgroundColor: '#e1e5e8'
|
||||||
},
|
},
|
||||||
|
|
|
@ -59,7 +59,9 @@ describe('Create room screen', () => {
|
||||||
await expect(element(by.id('create-channel-view'))).toBeVisible();
|
await expect(element(by.id('create-channel-view'))).toBeVisible();
|
||||||
await expect(element(by.id('create-channel-name'))).toBeVisible();
|
await expect(element(by.id('create-channel-name'))).toBeVisible();
|
||||||
await expect(element(by.id('create-channel-type'))).toBeVisible();
|
await expect(element(by.id('create-channel-type'))).toBeVisible();
|
||||||
await expect(element(by.id('create-channel-submit'))).toBeVisible();
|
await expect(element(by.id('create-channel-readonly'))).toBeVisible();
|
||||||
|
await expect(element(by.id('create-channel-broadcast'))).toExist();
|
||||||
|
await expect(element(by.id('create-channel-submit'))).toExist();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should get invalid room', async() => {
|
it('should get invalid room', async() => {
|
||||||
|
@ -69,28 +71,9 @@ describe('Create room screen', () => {
|
||||||
await expect(element(by.id('create-channel-error'))).toBeVisible();
|
await expect(element(by.id('create-channel-error'))).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create private room', async() => {
|
|
||||||
await element(by.id('create-channel-name')).replaceText(`private${ data.random }`);
|
|
||||||
await element(by.id('create-channel-type')).tap();
|
|
||||||
await element(by.id('create-channel-submit')).tap();
|
|
||||||
await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(60000);
|
|
||||||
await expect(element(by.id('room-view'))).toBeVisible();
|
|
||||||
await waitFor(element(by.id('room-view-title'))).toHaveText(`private${ data.random }`).withTimeout(60000);
|
|
||||||
await expect(element(by.id('room-view-title'))).toHaveText(`private${ data.random }`);
|
|
||||||
await element(by.id('header-back')).tap();
|
|
||||||
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(2000);
|
|
||||||
await waitFor(element(by.id(`rooms-list-view-item-private${ data.random }`))).toBeVisible().withTimeout(60000);
|
|
||||||
await expect(element(by.id(`rooms-list-view-item-private${ data.random }`))).toBeVisible();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create public room', async() => {
|
it('should create public room', async() => {
|
||||||
await element(by.id('rooms-list-view-create-channel')).tap();
|
|
||||||
await waitFor(element(by.id('select-users-view'))).toBeVisible().withTimeout(2000);
|
|
||||||
await element(by.id('select-users-view-item-rocket.cat')).tap();
|
|
||||||
await waitFor(element(by.id('selected-user-rocket.cat'))).toBeVisible().withTimeout(5000);
|
|
||||||
await element(by.id('selected-users-view-submit')).tap();
|
|
||||||
await waitFor(element(by.id('create-channel-view'))).toBeVisible().withTimeout(5000);
|
|
||||||
await element(by.id('create-channel-name')).replaceText(`public${ data.random }`);
|
await element(by.id('create-channel-name')).replaceText(`public${ data.random }`);
|
||||||
|
await element(by.id('create-channel-type')).tap();
|
||||||
await element(by.id('create-channel-submit')).tap();
|
await element(by.id('create-channel-submit')).tap();
|
||||||
await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(60000);
|
await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(60000);
|
||||||
await expect(element(by.id('room-view'))).toBeVisible();
|
await expect(element(by.id('room-view'))).toBeVisible();
|
||||||
|
@ -102,6 +85,25 @@ describe('Create room screen', () => {
|
||||||
await expect(element(by.id(`rooms-list-view-item-public${ data.random }`))).toBeVisible();
|
await expect(element(by.id(`rooms-list-view-item-public${ data.random }`))).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should create private room', async() => {
|
||||||
|
await element(by.id('rooms-list-view-create-channel')).tap();
|
||||||
|
await waitFor(element(by.id('select-users-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await element(by.id('select-users-view-item-rocket.cat')).tap();
|
||||||
|
await waitFor(element(by.id('selected-user-rocket.cat'))).toBeVisible().withTimeout(5000);
|
||||||
|
await element(by.id('selected-users-view-submit')).tap();
|
||||||
|
await waitFor(element(by.id('create-channel-view'))).toBeVisible().withTimeout(5000);
|
||||||
|
await element(by.id('create-channel-name')).replaceText(`private${ data.random }`);
|
||||||
|
await element(by.id('create-channel-submit')).tap();
|
||||||
|
await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id('room-view'))).toBeVisible();
|
||||||
|
await waitFor(element(by.id('room-view-title'))).toHaveText(`private${ data.random }`).withTimeout(60000);
|
||||||
|
await expect(element(by.id('room-view-title'))).toHaveText(`private${ data.random }`);
|
||||||
|
await element(by.id('header-back')).tap();
|
||||||
|
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await waitFor(element(by.id(`rooms-list-view-item-private${ data.random }`))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id(`rooms-list-view-item-private${ data.random }`))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
afterEach(async() => {
|
afterEach(async() => {
|
||||||
takeScreenshot();
|
takeScreenshot();
|
||||||
});
|
});
|
||||||
|
|
|
@ -176,12 +176,6 @@ describe('Room screen', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Message', async() => {
|
describe('Message', async() => {
|
||||||
before(async() => {
|
|
||||||
await mockMessage('reply');
|
|
||||||
await mockMessage('edit');
|
|
||||||
await mockMessage('quote');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should show message actions', async() => {
|
it('should show message actions', async() => {
|
||||||
await element(by.text(`${ data.random }message`)).longPress();
|
await element(by.text(`${ data.random }message`)).longPress();
|
||||||
await waitFor(element(by.text('Messages actions'))).toBeVisible().withTimeout(5000);
|
await waitFor(element(by.text('Messages actions'))).toBeVisible().withTimeout(5000);
|
||||||
|
@ -190,27 +184,6 @@ describe('Room screen', () => {
|
||||||
await waitFor(element(by.text('Cancel'))).toBeNotVisible().withTimeout(2000);
|
await waitFor(element(by.text('Cancel'))).toBeNotVisible().withTimeout(2000);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should reply message', async() => {
|
|
||||||
await element(by.text(`${ data.random }reply`)).longPress();
|
|
||||||
await waitFor(element(by.text('Messages actions'))).toBeVisible().withTimeout(5000);
|
|
||||||
await expect(element(by.text('Messages actions'))).toBeVisible();
|
|
||||||
await element(by.text('Reply')).tap();
|
|
||||||
await element(by.id('messagebox-input')).typeText('replied');
|
|
||||||
await element(by.id('messagebox-send-message')).tap();
|
|
||||||
// TODO: test if reply was sent
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should edit message', async() => {
|
|
||||||
await element(by.text(`${ data.random }edit`)).longPress();
|
|
||||||
await waitFor(element(by.text('Messages actions'))).toBeVisible().withTimeout(5000);
|
|
||||||
await expect(element(by.text('Messages actions'))).toBeVisible();
|
|
||||||
await element(by.text('Edit')).tap();
|
|
||||||
await element(by.id('messagebox-input')).typeText('ed');
|
|
||||||
await element(by.id('messagebox-send-message')).tap();
|
|
||||||
await waitFor(element(by.text(`${ data.random }edited`))).toBeVisible().withTimeout(60000);
|
|
||||||
await expect(element(by.text(`${ data.random }edited`))).toBeVisible();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should copy permalink', async() => {
|
it('should copy permalink', async() => {
|
||||||
await element(by.text(`${ data.random }message`)).longPress();
|
await element(by.text(`${ data.random }message`)).longPress();
|
||||||
await waitFor(element(by.text('Messages actions'))).toBeVisible().withTimeout(5000);
|
await waitFor(element(by.text('Messages actions'))).toBeVisible().withTimeout(5000);
|
||||||
|
@ -232,16 +205,6 @@ describe('Room screen', () => {
|
||||||
// TODO: test clipboard
|
// TODO: test clipboard
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should quote message', async() => {
|
|
||||||
await element(by.text(`${ data.random }quote`)).longPress();
|
|
||||||
await waitFor(element(by.text('Messages actions'))).toBeVisible().withTimeout(5000);
|
|
||||||
await expect(element(by.text('Messages actions'))).toBeVisible();
|
|
||||||
await element(by.text('Quote')).tap();
|
|
||||||
await element(by.id('messagebox-input')).typeText(`${ data.random }quoted`);
|
|
||||||
await element(by.id('messagebox-send-message')).tap();
|
|
||||||
// TODO: test if quote was sent
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should star message', async() => {
|
it('should star message', async() => {
|
||||||
await element(by.text(`${ data.random }message`)).longPress();
|
await element(by.text(`${ data.random }message`)).longPress();
|
||||||
await waitFor(element(by.text('Messages actions'))).toBeVisible().withTimeout(5000);
|
await waitFor(element(by.text('Messages actions'))).toBeVisible().withTimeout(5000);
|
||||||
|
@ -288,6 +251,40 @@ describe('Room screen', () => {
|
||||||
await expect(element(by.id('message-reaction-:grinning:'))).toBeNotVisible();
|
await expect(element(by.id('message-reaction-:grinning:'))).toBeNotVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should reply message', async() => {
|
||||||
|
await mockMessage('reply');
|
||||||
|
await element(by.text(`${ data.random }reply`)).longPress();
|
||||||
|
await waitFor(element(by.text('Messages actions'))).toBeVisible().withTimeout(5000);
|
||||||
|
await expect(element(by.text('Messages actions'))).toBeVisible();
|
||||||
|
await element(by.text('Reply')).tap();
|
||||||
|
await element(by.id('messagebox-input')).typeText('replied');
|
||||||
|
await element(by.id('messagebox-send-message')).tap();
|
||||||
|
// TODO: test if reply was sent
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should edit message', async() => {
|
||||||
|
await mockMessage('edit');
|
||||||
|
await element(by.text(`${ data.random }edit`)).longPress();
|
||||||
|
await waitFor(element(by.text('Messages actions'))).toBeVisible().withTimeout(5000);
|
||||||
|
await expect(element(by.text('Messages actions'))).toBeVisible();
|
||||||
|
await element(by.text('Edit')).tap();
|
||||||
|
await element(by.id('messagebox-input')).typeText('ed');
|
||||||
|
await element(by.id('messagebox-send-message')).tap();
|
||||||
|
await waitFor(element(by.text(`${ data.random }edited`))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.text(`${ data.random }edited`))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should quote message', async() => {
|
||||||
|
await mockMessage('quote');
|
||||||
|
await element(by.text(`${ data.random }quote`)).longPress();
|
||||||
|
await waitFor(element(by.text('Messages actions'))).toBeVisible().withTimeout(5000);
|
||||||
|
await expect(element(by.text('Messages actions'))).toBeVisible();
|
||||||
|
await element(by.text('Quote')).tap();
|
||||||
|
await element(by.id('messagebox-input')).typeText(`${ data.random }quoted`);
|
||||||
|
await element(by.id('messagebox-send-message')).tap();
|
||||||
|
// TODO: test if quote was sent
|
||||||
|
});
|
||||||
|
|
||||||
it('should pin message', async() => {
|
it('should pin message', async() => {
|
||||||
await element(by.text(`${ data.random }edited`)).longPress();
|
await element(by.text(`${ data.random }edited`)).longPress();
|
||||||
await waitFor(element(by.text('Messages actions'))).toBeVisible().withTimeout(5000);
|
await waitFor(element(by.text('Messages actions'))).toBeVisible().withTimeout(5000);
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
const {
|
||||||
|
device, expect, element, by, waitFor
|
||||||
|
} = require('detox');
|
||||||
|
const { takeScreenshot } = require('./helpers/screenshot');
|
||||||
|
const { logout, navigateToLogin } = require('./helpers/app');
|
||||||
|
const data = require('./data');
|
||||||
|
|
||||||
|
describe('Broadcast room', () => {
|
||||||
|
before(async() => {
|
||||||
|
await device.reloadReactNative();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create broadcast room', async() => {
|
||||||
|
await element(by.id('rooms-list-view-create-channel')).tap();
|
||||||
|
await waitFor(element(by.id('select-users-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await element(by.id(`select-users-view-item-${ data.alternateUser }`)).tap();
|
||||||
|
await waitFor(element(by.id(`selected-user-${ data.alternateUser }`))).toBeVisible().withTimeout(5000);
|
||||||
|
await element(by.id('selected-users-view-submit')).tap();
|
||||||
|
await waitFor(element(by.id('create-channel-view'))).toBeVisible().withTimeout(5000);
|
||||||
|
await element(by.id('create-channel-name')).replaceText(`broadcast${ data.random }`);
|
||||||
|
await element(by.id('create-channel-broadcast')).tap();
|
||||||
|
await element(by.id('create-channel-submit')).tap();
|
||||||
|
await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id('room-view'))).toBeVisible();
|
||||||
|
await waitFor(element(by.id('room-view-title'))).toHaveText(`broadcast${ data.random }`).withTimeout(60000);
|
||||||
|
await expect(element(by.id('room-view-title'))).toHaveText(`broadcast${ data.random }`);
|
||||||
|
await element(by.id('room-view-title')).tap();
|
||||||
|
await waitFor(element(by.id('room-info-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await waitFor(element(by.id('room-info-view-broadcast'))).toBeVisible().withTimeout(2000);
|
||||||
|
await expect(element(by.id('room-info-view-broadcast'))).toBeVisible();
|
||||||
|
await element(by.id('header-back')).atIndex(0).tap();
|
||||||
|
await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await element(by.id('header-back')).atIndex(0).tap();
|
||||||
|
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await waitFor(element(by.id(`rooms-list-view-item-broadcast${ data.random }`))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id(`rooms-list-view-item-broadcast${ data.random }`))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should send message', async() => {
|
||||||
|
await element(by.id(`rooms-list-view-item-broadcast${ data.random }`)).tap();
|
||||||
|
await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(5000);
|
||||||
|
await element(by.id('messagebox-input')).tap();
|
||||||
|
await element(by.id('messagebox-input')).typeText(`${ data.random }message`);
|
||||||
|
await element(by.id('messagebox-send-message')).tap();
|
||||||
|
await waitFor(element(by.text(`${ data.random }message`))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.text(`${ data.random }message`))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should login as user without write message authorization and enter room', async() => {
|
||||||
|
await element(by.id('header-back')).tap();
|
||||||
|
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(2000);
|
||||||
|
await expect(element(by.id('rooms-list-view'))).toBeVisible();
|
||||||
|
await logout();
|
||||||
|
await navigateToLogin();
|
||||||
|
await element(by.id('login-view-email')).replaceText(data.alternateUser);
|
||||||
|
await element(by.id('login-view-password')).replaceText(data.alternateUserPassword);
|
||||||
|
await element(by.id('login-view-submit')).tap();
|
||||||
|
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(10000);
|
||||||
|
await waitFor(element(by.id(`rooms-list-view-item-broadcast${ data.random }`))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.id(`rooms-list-view-item-broadcast${ data.random }`))).toBeVisible();
|
||||||
|
await element(by.id(`rooms-list-view-item-broadcast${ data.random }`)).tap();
|
||||||
|
await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(5000);
|
||||||
|
await expect(element(by.id('room-view-title'))).toHaveText(`broadcast${ data.random }`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not have messagebox', async() => {
|
||||||
|
await expect(element(by.id('messagebox'))).toBeNotVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be read only', async() => {
|
||||||
|
await expect(element(by.text('This room is read only'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have the message created earlier', async() => {
|
||||||
|
await waitFor(element(by.text(`${ data.random }message`))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.text(`${ data.random }message`))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have reply button', async() => {
|
||||||
|
await expect(element(by.text('Reply'))).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should tap on reply button and navigate to direct room', async() => {
|
||||||
|
await element(by.text('Reply')).tap();
|
||||||
|
await waitFor(element(by.id('room-view-title'))).toHaveText(data.user).withTimeout(60000);
|
||||||
|
await expect(element(by.id('room-view-title'))).toHaveText(data.user);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should reply broadcasted message', async() => {
|
||||||
|
await element(by.id('messagebox-input')).tap();
|
||||||
|
await element(by.id('messagebox-input')).typeText(`${ data.random }broadcastreply`);
|
||||||
|
await element(by.id('messagebox-send-message')).tap();
|
||||||
|
await waitFor(element(by.text(`${ data.random }message`))).toBeVisible().withTimeout(60000);
|
||||||
|
await expect(element(by.text(`${ data.random }message`))).toBeVisible(); // broadcasted message
|
||||||
|
await expect(element(by.text(` ${ data.random }broadcastreply`))).toBeVisible(); // reply
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async() => {
|
||||||
|
takeScreenshot();
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,10 +1,12 @@
|
||||||
const random = require('./helpers/random');
|
const random = require('./helpers/random');
|
||||||
const value = random(20);
|
const value = random(20);
|
||||||
const data = {
|
const data = {
|
||||||
server: 'https://unstable.rocket.chat',
|
server: 'https://stable.rocket.chat',
|
||||||
alternateServer: 'https://stable.rocket.chat',
|
alternateServer: 'https://unstable.rocket.chat',
|
||||||
user: `user${ value }`,
|
user: `user${ value }`,
|
||||||
password: `password${ value }`,
|
password: `password${ value }`,
|
||||||
|
alternateUser: 'detoxrn',
|
||||||
|
alternateUserPassword: '123',
|
||||||
email: `detoxrn+${ value }@rocket.chat`,
|
email: `detoxrn+${ value }@rocket.chat`,
|
||||||
random: value
|
random: value
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue