Updating room indicator (#609)
Shows "Updating..." when requesting rooms from Rest API.
This commit is contained in:
parent
0f516083f4
commit
db0cd5abd1
|
@ -330,6 +330,7 @@ export default {
|
||||||
Unread: 'Unread',
|
Unread: 'Unread',
|
||||||
Unread_on_top: 'Unread on top',
|
Unread_on_top: 'Unread on top',
|
||||||
Unstar: 'Unstar',
|
Unstar: 'Unstar',
|
||||||
|
Updating: 'Updating...',
|
||||||
Uploading: 'Uploading',
|
Uploading: 'Uploading',
|
||||||
Upload_file_question_mark: 'Upload file?',
|
Upload_file_question_mark: 'Upload file?',
|
||||||
User_added_by: 'User {{userAdded}} added by {{userBy}}',
|
User_added_by: 'User {{userAdded}} added by {{userBy}}',
|
||||||
|
|
|
@ -328,6 +328,7 @@ export default {
|
||||||
Unread: 'Não lidas',
|
Unread: 'Não lidas',
|
||||||
Unread_on_top: 'Não lidas no topo',
|
Unread_on_top: 'Não lidas no topo',
|
||||||
Unstar: 'Remover favorito',
|
Unstar: 'Remover favorito',
|
||||||
|
Updating: 'Atualizando...',
|
||||||
Uploading: 'Subindo arquivo',
|
Uploading: 'Subindo arquivo',
|
||||||
Upload_file_question_mark: 'Enviar arquivo?',
|
Upload_file_question_mark: 'Enviar arquivo?',
|
||||||
User_added_by: 'Usuário {{userAdded}} adicionado por {{userBy}}',
|
User_added_by: 'Usuário {{userAdded}} adicionado por {{userBy}}',
|
||||||
|
|
|
@ -1,8 +1,4 @@
|
||||||
import { InteractionManager } from 'react-native';
|
|
||||||
|
|
||||||
import mergeSubscriptionsRooms from './helpers/mergeSubscriptionsRooms';
|
|
||||||
import database from '../realm';
|
import database from '../realm';
|
||||||
import log from '../../utils/log';
|
|
||||||
|
|
||||||
const lastMessage = () => {
|
const lastMessage = () => {
|
||||||
const message = database
|
const message = database
|
||||||
|
@ -12,26 +8,11 @@ const lastMessage = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function() {
|
export default function() {
|
||||||
return new Promise(async(resolve, reject) => {
|
const updatedSince = lastMessage();
|
||||||
try {
|
// subscriptions.get: Since RC 0.60.0
|
||||||
const updatedSince = lastMessage();
|
// rooms.get: Since RC 0.62.0
|
||||||
// subscriptions.get: Since RC 0.60.0
|
if (updatedSince) {
|
||||||
// rooms.get: Since RC 0.62.0
|
return Promise.all([this.sdk.get('subscriptions.get', { updatedSince }), this.sdk.get('rooms.get', { updatedSince })]);
|
||||||
const [subscriptionsResult, roomsResult] = await (updatedSince
|
}
|
||||||
? Promise.all([this.sdk.get('subscriptions.get', { updatedSince }), this.sdk.get('rooms.get', { updatedSince })])
|
return Promise.all([this.sdk.get('subscriptions.get'), this.sdk.get('rooms.get')]);
|
||||||
: Promise.all([this.sdk.get('subscriptions.get'), this.sdk.get('rooms.get')])
|
|
||||||
);
|
|
||||||
const { subscriptions } = mergeSubscriptionsRooms(subscriptionsResult, roomsResult);
|
|
||||||
|
|
||||||
InteractionManager.runAfterInteractions(() => {
|
|
||||||
database.write(() => {
|
|
||||||
subscriptions.forEach(subscription => database.create('subscriptions', subscription, true));
|
|
||||||
});
|
|
||||||
resolve(subscriptions);
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
log('getRooms', e);
|
|
||||||
reject(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@ import protectedFunction from '../helpers/protectedFunction';
|
||||||
import messagesStatus from '../../../constants/messagesStatus';
|
import messagesStatus from '../../../constants/messagesStatus';
|
||||||
import log from '../../../utils/log';
|
import log from '../../../utils/log';
|
||||||
import random from '../../../utils/random';
|
import random from '../../../utils/random';
|
||||||
|
import store from '../../createStore';
|
||||||
|
import { roomsRequest } from '../../../actions/rooms';
|
||||||
|
|
||||||
export default async function subscribeRooms() {
|
export default async function subscribeRooms() {
|
||||||
let timer = null;
|
let timer = null;
|
||||||
|
@ -11,15 +13,11 @@ export default async function subscribeRooms() {
|
||||||
if (timer) {
|
if (timer) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
timer = setTimeout(async() => {
|
timer = setTimeout(() => {
|
||||||
try {
|
clearTimeout(timer);
|
||||||
clearTimeout(timer);
|
timer = false;
|
||||||
timer = false;
|
if (this.sdk.userId) {
|
||||||
if (this.sdk.userId) {
|
store.dispatch(roomsRequest());
|
||||||
await this.getRooms();
|
|
||||||
loop();
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
loop();
|
loop();
|
||||||
}
|
}
|
||||||
}, 5000);
|
}, 5000);
|
||||||
|
@ -27,7 +25,7 @@ export default async function subscribeRooms() {
|
||||||
|
|
||||||
this.sdk.onStreamData('connected', () => {
|
this.sdk.onStreamData('connected', () => {
|
||||||
if (this.sdk.userId) {
|
if (this.sdk.userId) {
|
||||||
this.getRooms();
|
store.dispatch(roomsRequest());
|
||||||
}
|
}
|
||||||
clearTimeout(timer);
|
clearTimeout(timer);
|
||||||
timer = false;
|
timer = false;
|
||||||
|
|
|
@ -39,6 +39,7 @@ import sendMessage, { getMessage, sendMessageCall } from './methods/sendMessage'
|
||||||
import { sendFileMessage, cancelUpload, isUploadActive } from './methods/sendFileMessage';
|
import { sendFileMessage, cancelUpload, isUploadActive } from './methods/sendFileMessage';
|
||||||
|
|
||||||
import { getDeviceToken } from '../push';
|
import { getDeviceToken } from '../push';
|
||||||
|
import { roomsRequest } from '../actions/rooms';
|
||||||
|
|
||||||
const TOKEN_KEY = 'reactnativemeteor_usertoken';
|
const TOKEN_KEY = 'reactnativemeteor_usertoken';
|
||||||
const SORT_PREFS_KEY = 'RC_SORT_PREFS_KEY';
|
const SORT_PREFS_KEY = 'RC_SORT_PREFS_KEY';
|
||||||
|
@ -134,7 +135,7 @@ const RocketChat = {
|
||||||
},
|
},
|
||||||
loginSuccess({ user }) {
|
loginSuccess({ user }) {
|
||||||
reduxStore.dispatch(setUser(user));
|
reduxStore.dispatch(setUser(user));
|
||||||
this.getRooms().catch(e => console.log(e));
|
reduxStore.dispatch(roomsRequest());
|
||||||
this.subscribeRooms();
|
this.subscribeRooms();
|
||||||
this.sdk.subscribe('activeUsers');
|
this.sdk.subscribe('activeUsers');
|
||||||
this.sdk.subscribe('roles');
|
this.sdk.subscribe('roles');
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import * as types from '../actions/actionsTypes';
|
import * as types from '../actions/actionsTypes';
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
isFetching: false,
|
isFetching: true,
|
||||||
failure: false,
|
failure: false,
|
||||||
|
errorMessage: {},
|
||||||
searchText: '',
|
searchText: '',
|
||||||
showServerDropdown: false,
|
showServerDropdown: false,
|
||||||
closeServerDropdown: false,
|
closeServerDropdown: false,
|
||||||
|
@ -15,7 +16,9 @@ export default function login(state = initialState, action) {
|
||||||
case types.ROOMS.REQUEST:
|
case types.ROOMS.REQUEST:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
isFetching: true
|
isFetching: true,
|
||||||
|
failure: false,
|
||||||
|
errorMessage: {}
|
||||||
};
|
};
|
||||||
case types.ROOMS.SUCCESS:
|
case types.ROOMS.SUCCESS:
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { all } from 'redux-saga/effects';
|
import { all } from 'redux-saga/effects';
|
||||||
import login from './login';
|
import login from './login';
|
||||||
import rooms from './rooms';
|
import rooms from './rooms';
|
||||||
|
import room from './room';
|
||||||
import messages from './messages';
|
import messages from './messages';
|
||||||
import selectServer from './selectServer';
|
import selectServer from './selectServer';
|
||||||
import createChannel from './createChannel';
|
import createChannel from './createChannel';
|
||||||
|
@ -14,6 +15,7 @@ const root = function* root() {
|
||||||
init(),
|
init(),
|
||||||
createChannel(),
|
createChannel(),
|
||||||
rooms(),
|
rooms(),
|
||||||
|
room(),
|
||||||
login(),
|
login(),
|
||||||
messages(),
|
messages(),
|
||||||
selectServer(),
|
selectServer(),
|
||||||
|
|
|
@ -0,0 +1,156 @@
|
||||||
|
import { Alert } from 'react-native';
|
||||||
|
import {
|
||||||
|
put, call, takeLatest, take, select, race, fork, cancel, takeEvery
|
||||||
|
} from 'redux-saga/effects';
|
||||||
|
import { delay } from 'redux-saga';
|
||||||
|
import EJSON from 'ejson';
|
||||||
|
|
||||||
|
import Navigation from '../lib/Navigation';
|
||||||
|
import * as types from '../actions/actionsTypes';
|
||||||
|
import { addUserTyping, removeUserTyping } from '../actions/room';
|
||||||
|
import { messagesRequest, editCancel, replyCancel } from '../actions/messages';
|
||||||
|
import RocketChat from '../lib/rocketchat';
|
||||||
|
import database from '../lib/realm';
|
||||||
|
import log from '../utils/log';
|
||||||
|
import I18n from '../i18n';
|
||||||
|
|
||||||
|
|
||||||
|
let sub;
|
||||||
|
let thread;
|
||||||
|
|
||||||
|
const cancelTyping = function* cancelTyping(username) {
|
||||||
|
while (true) {
|
||||||
|
const { typing, timeout } = yield race({
|
||||||
|
typing: take(types.ROOM.SOMEONE_TYPING),
|
||||||
|
timeout: call(delay, 5000)
|
||||||
|
});
|
||||||
|
if (timeout || (typing.username === username && !typing.typing)) {
|
||||||
|
return yield put(removeUserTyping(username));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const usersTyping = function* usersTyping({ rid }) {
|
||||||
|
while (true) {
|
||||||
|
const { _rid, username, typing } = yield take(types.ROOM.SOMEONE_TYPING);
|
||||||
|
if (_rid === rid) {
|
||||||
|
yield (typing ? put(addUserTyping(username)) : put(removeUserTyping(username)));
|
||||||
|
if (typing) {
|
||||||
|
yield fork(cancelTyping, username);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleMessageReceived = function* handleMessageReceived({ message }) {
|
||||||
|
try {
|
||||||
|
const room = yield select(state => state.room);
|
||||||
|
|
||||||
|
if (message.rid === room.rid) {
|
||||||
|
database.write(() => {
|
||||||
|
database.create('messages', EJSON.fromJSONValue(message), true);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (room._id) {
|
||||||
|
RocketChat.readMessages(room.rid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('handleMessageReceived', e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let opened = false;
|
||||||
|
|
||||||
|
const watchRoomOpen = function* watchRoomOpen({ room }) {
|
||||||
|
try {
|
||||||
|
if (opened) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
opened = true;
|
||||||
|
|
||||||
|
const auth = yield select(state => state.login.isAuthenticated);
|
||||||
|
if (!auth) {
|
||||||
|
yield take(types.LOGIN.SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
yield put(messagesRequest({ ...room }));
|
||||||
|
|
||||||
|
if (room._id) {
|
||||||
|
RocketChat.readMessages(room.rid);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub = yield RocketChat.subscribeRoom(room);
|
||||||
|
|
||||||
|
thread = yield fork(usersTyping, { rid: room.rid });
|
||||||
|
yield race({
|
||||||
|
open: take(types.ROOM.OPEN),
|
||||||
|
close: take(types.ROOM.CLOSE)
|
||||||
|
});
|
||||||
|
opened = false;
|
||||||
|
cancel(thread);
|
||||||
|
sub.stop();
|
||||||
|
yield put(editCancel());
|
||||||
|
yield put(replyCancel());
|
||||||
|
} catch (e) {
|
||||||
|
log('watchRoomOpen', e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const watchuserTyping = function* watchuserTyping({ status }) {
|
||||||
|
const auth = yield select(state => state.login.isAuthenticated);
|
||||||
|
if (!auth) {
|
||||||
|
yield take(types.LOGIN.SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
const room = yield select(state => state.room);
|
||||||
|
|
||||||
|
if (!room) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
yield RocketChat.emitTyping(room.rid, status);
|
||||||
|
|
||||||
|
if (status) {
|
||||||
|
yield call(delay, 5000);
|
||||||
|
yield RocketChat.emitTyping(room.rid, false);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
log('watchuserTyping', e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleLeaveRoom = function* handleLeaveRoom({ rid, t }) {
|
||||||
|
try {
|
||||||
|
const result = yield RocketChat.leaveRoom(rid, t);
|
||||||
|
if (result.success) {
|
||||||
|
yield Navigation.popToRoot('RoomsListView');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
if (e.data && e.data.errorType === 'error-you-are-last-owner') {
|
||||||
|
Alert.alert(I18n.t('Oops'), I18n.t(e.data.errorType));
|
||||||
|
} else {
|
||||||
|
Alert.alert(I18n.t('Oops'), I18n.t('There_was_an_error_while_action', { action: I18n.t('leaving_room') }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleEraseRoom = function* handleEraseRoom({ rid, t }) {
|
||||||
|
try {
|
||||||
|
const result = yield RocketChat.eraseRoom(rid, t);
|
||||||
|
if (result.success) {
|
||||||
|
yield Navigation.popToRoot('RoomsListView');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
Alert.alert(I18n.t('Oops'), I18n.t('There_was_an_error_while_action', { action: I18n.t('erasing_room') }));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const root = function* root() {
|
||||||
|
yield takeLatest(types.ROOM.USER_TYPING, watchuserTyping);
|
||||||
|
yield takeEvery(types.ROOM.OPEN, watchRoomOpen);
|
||||||
|
yield takeEvery(types.ROOM.MESSAGE_RECEIVED, handleMessageReceived);
|
||||||
|
yield takeLatest(types.ROOM.LEAVE, handleLeaveRoom);
|
||||||
|
yield takeLatest(types.ROOM.ERASE, handleEraseRoom);
|
||||||
|
};
|
||||||
|
export default root;
|
|
@ -1,155 +1,28 @@
|
||||||
import { Alert } from 'react-native';
|
import { put, takeLatest } from 'redux-saga/effects';
|
||||||
import {
|
|
||||||
put, call, takeLatest, take, select, race, fork, cancel, takeEvery
|
|
||||||
} from 'redux-saga/effects';
|
|
||||||
import { delay } from 'redux-saga';
|
|
||||||
import EJSON from 'ejson';
|
|
||||||
|
|
||||||
import Navigation from '../lib/Navigation';
|
|
||||||
import * as types from '../actions/actionsTypes';
|
import * as types from '../actions/actionsTypes';
|
||||||
import { addUserTyping, removeUserTyping } from '../actions/room';
|
import { roomsSuccess, roomsFailure } from '../actions/rooms';
|
||||||
import { messagesRequest, editCancel, replyCancel } from '../actions/messages';
|
|
||||||
import RocketChat from '../lib/rocketchat';
|
import RocketChat from '../lib/rocketchat';
|
||||||
import database from '../lib/realm';
|
import database from '../lib/realm';
|
||||||
import log from '../utils/log';
|
import log from '../utils/log';
|
||||||
import I18n from '../i18n';
|
import mergeSubscriptionsRooms from '../lib/methods/helpers/mergeSubscriptionsRooms';
|
||||||
|
|
||||||
let sub;
|
const handleRoomsRequest = function* handleRoomsRequest() {
|
||||||
let thread;
|
try {
|
||||||
|
const [subscriptionsResult, roomsResult] = yield RocketChat.getRooms();
|
||||||
|
const { subscriptions } = mergeSubscriptionsRooms(subscriptionsResult, roomsResult);
|
||||||
|
|
||||||
const cancelTyping = function* cancelTyping(username) {
|
database.write(() => {
|
||||||
while (true) {
|
subscriptions.forEach(subscription => database.create('subscriptions', subscription, true));
|
||||||
const { typing, timeout } = yield race({
|
|
||||||
typing: take(types.ROOM.SOMEONE_TYPING),
|
|
||||||
timeout: call(delay, 5000)
|
|
||||||
});
|
});
|
||||||
if (timeout || (typing.username === username && !typing.typing)) {
|
yield put(roomsSuccess());
|
||||||
return yield put(removeUserTyping(username));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const usersTyping = function* usersTyping({ rid }) {
|
|
||||||
while (true) {
|
|
||||||
const { _rid, username, typing } = yield take(types.ROOM.SOMEONE_TYPING);
|
|
||||||
if (_rid === rid) {
|
|
||||||
yield (typing ? put(addUserTyping(username)) : put(removeUserTyping(username)));
|
|
||||||
if (typing) {
|
|
||||||
yield fork(cancelTyping, username);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const handleMessageReceived = function* handleMessageReceived({ message }) {
|
|
||||||
try {
|
|
||||||
const room = yield select(state => state.room);
|
|
||||||
|
|
||||||
if (message.rid === room.rid) {
|
|
||||||
database.write(() => {
|
|
||||||
database.create('messages', EJSON.fromJSONValue(message), true);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (room._id) {
|
|
||||||
RocketChat.readMessages(room.rid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn('handleMessageReceived', e);
|
yield put(roomsFailure(e));
|
||||||
}
|
log('handleRoomsRequest', e);
|
||||||
};
|
|
||||||
|
|
||||||
let opened = false;
|
|
||||||
|
|
||||||
const watchRoomOpen = function* watchRoomOpen({ room }) {
|
|
||||||
try {
|
|
||||||
if (opened) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
opened = true;
|
|
||||||
|
|
||||||
const auth = yield select(state => state.login.isAuthenticated);
|
|
||||||
if (!auth) {
|
|
||||||
yield take(types.LOGIN.SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
yield put(messagesRequest({ ...room }));
|
|
||||||
|
|
||||||
if (room._id) {
|
|
||||||
RocketChat.readMessages(room.rid);
|
|
||||||
}
|
|
||||||
|
|
||||||
sub = yield RocketChat.subscribeRoom(room);
|
|
||||||
|
|
||||||
thread = yield fork(usersTyping, { rid: room.rid });
|
|
||||||
yield race({
|
|
||||||
open: take(types.ROOM.OPEN),
|
|
||||||
close: take(types.ROOM.CLOSE)
|
|
||||||
});
|
|
||||||
opened = false;
|
|
||||||
cancel(thread);
|
|
||||||
sub.stop();
|
|
||||||
yield put(editCancel());
|
|
||||||
yield put(replyCancel());
|
|
||||||
} catch (e) {
|
|
||||||
log('watchRoomOpen', e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const watchuserTyping = function* watchuserTyping({ status }) {
|
|
||||||
const auth = yield select(state => state.login.isAuthenticated);
|
|
||||||
if (!auth) {
|
|
||||||
yield take(types.LOGIN.SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
const room = yield select(state => state.room);
|
|
||||||
|
|
||||||
if (!room) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
yield RocketChat.emitTyping(room.rid, status);
|
|
||||||
|
|
||||||
if (status) {
|
|
||||||
yield call(delay, 5000);
|
|
||||||
yield RocketChat.emitTyping(room.rid, false);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
log('watchuserTyping', e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleLeaveRoom = function* handleLeaveRoom({ rid, t }) {
|
|
||||||
try {
|
|
||||||
const result = yield RocketChat.leaveRoom(rid, t);
|
|
||||||
if (result.success) {
|
|
||||||
yield Navigation.popToRoot('RoomsListView');
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
if (e.data && e.data.errorType === 'error-you-are-last-owner') {
|
|
||||||
Alert.alert(I18n.t('Oops'), I18n.t(e.data.errorType));
|
|
||||||
} else {
|
|
||||||
Alert.alert(I18n.t('Oops'), I18n.t('There_was_an_error_while_action', { action: I18n.t('leaving_room') }));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleEraseRoom = function* handleEraseRoom({ rid, t }) {
|
|
||||||
try {
|
|
||||||
const result = yield RocketChat.eraseRoom(rid, t);
|
|
||||||
if (result.success) {
|
|
||||||
yield Navigation.popToRoot('RoomsListView');
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
Alert.alert(I18n.t('Oops'), I18n.t('There_was_an_error_while_action', { action: I18n.t('erasing_room') }));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const root = function* root() {
|
const root = function* root() {
|
||||||
yield takeLatest(types.ROOM.USER_TYPING, watchuserTyping);
|
yield takeLatest(types.ROOMS.REQUEST, handleRoomsRequest);
|
||||||
yield takeEvery(types.ROOM.OPEN, watchRoomOpen);
|
|
||||||
yield takeEvery(types.ROOM.MESSAGE_RECEIVED, handleMessageReceived);
|
|
||||||
yield takeLatest(types.ROOM.LEAVE, handleLeaveRoom);
|
|
||||||
yield takeLatest(types.ROOM.ERASE, handleEraseRoom);
|
|
||||||
};
|
};
|
||||||
export default root;
|
export default root;
|
||||||
|
|
|
@ -5,6 +5,8 @@ import {
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { TextInput } from 'react-native-gesture-handler';
|
import { TextInput } from 'react-native-gesture-handler';
|
||||||
|
|
||||||
|
import I18n from '../../../i18n';
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
|
@ -18,6 +20,13 @@ const styles = StyleSheet.create({
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
color: '#FFF'
|
color: '#FFF'
|
||||||
},
|
},
|
||||||
|
serverSmall: {
|
||||||
|
fontSize: 16
|
||||||
|
},
|
||||||
|
updating: {
|
||||||
|
fontSize: 14,
|
||||||
|
color: '#FFF'
|
||||||
|
},
|
||||||
disclosure: {
|
disclosure: {
|
||||||
marginLeft: 9,
|
marginLeft: 9,
|
||||||
marginTop: 1,
|
marginTop: 1,
|
||||||
|
@ -30,7 +39,7 @@ const styles = StyleSheet.create({
|
||||||
});
|
});
|
||||||
|
|
||||||
const Header = ({
|
const Header = ({
|
||||||
onPress, serverName, showServerDropdown, setSearchInputRef, showSearchHeader, onSearchChangeText
|
isFetching, serverName, showServerDropdown, width, setSearchInputRef, showSearchHeader, onSearchChangeText, onPress
|
||||||
}) => {
|
}) => {
|
||||||
if (showSearchHeader) {
|
if (showSearchHeader) {
|
||||||
return (
|
return (
|
||||||
|
@ -46,10 +55,11 @@ const Header = ({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={[styles.container, { width: width - 150 }]}>
|
||||||
<TouchableOpacity onPress={onPress} testID='rooms-list-header-server-dropdown-button'>
|
<TouchableOpacity onPress={onPress} testID='rooms-list-header-server-dropdown-button'>
|
||||||
|
{isFetching ? <Text style={styles.updating}>{I18n.t('Updating')}</Text> : null}
|
||||||
<View style={styles.button}>
|
<View style={styles.button}>
|
||||||
<Text style={styles.server}>{serverName}</Text>
|
<Text style={[styles.server, isFetching && styles.serverSmall]}>{serverName}</Text>
|
||||||
<Image style={[styles.disclosure, showServerDropdown && styles.upsideDown]} source={{ uri: 'disclosure_indicator_server' }} />
|
<Image style={[styles.disclosure, showServerDropdown && styles.upsideDown]} source={{ uri: 'disclosure_indicator_server' }} />
|
||||||
</View>
|
</View>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
@ -63,7 +73,9 @@ Header.propTypes = {
|
||||||
onPress: PropTypes.func.isRequired,
|
onPress: PropTypes.func.isRequired,
|
||||||
onSearchChangeText: PropTypes.func.isRequired,
|
onSearchChangeText: PropTypes.func.isRequired,
|
||||||
setSearchInputRef: PropTypes.func.isRequired,
|
setSearchInputRef: PropTypes.func.isRequired,
|
||||||
serverName: PropTypes.string
|
isFetching: PropTypes.bool,
|
||||||
|
serverName: PropTypes.string,
|
||||||
|
width: PropTypes.number
|
||||||
};
|
};
|
||||||
|
|
||||||
Header.defaultProps = {
|
Header.defaultProps = {
|
||||||
|
|
|
@ -35,14 +35,23 @@ const styles = StyleSheet.create({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const Header = ({ onPress, serverName, showServerDropdown }) => (
|
const HeaderTitle = ({ isFetching }) => {
|
||||||
|
if (isFetching) {
|
||||||
|
return <Text style={styles.title}>{I18n.t('Updating')}</Text>;
|
||||||
|
}
|
||||||
|
return <Text style={styles.title}>{I18n.t('Messages')}</Text>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Header = ({
|
||||||
|
isFetching, serverName, showServerDropdown, onPress
|
||||||
|
}) => (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
testID='rooms-list-header-server-dropdown-button'
|
testID='rooms-list-header-server-dropdown-button'
|
||||||
style={styles.container}
|
style={styles.container}
|
||||||
>
|
>
|
||||||
<Text style={styles.title}>{I18n.t('Messages')}</Text>
|
<HeaderTitle isFetching={isFetching} />
|
||||||
<View style={styles.button}>
|
<View style={styles.button}>
|
||||||
<Text style={styles.server}>{serverName}</Text>
|
<Text style={styles.server}>{serverName}</Text>
|
||||||
<Image style={[styles.disclosure, showServerDropdown && styles.upsideDown]} source={{ uri: 'disclosure_indicator_server' }} />
|
<Image style={[styles.disclosure, showServerDropdown && styles.upsideDown]} source={{ uri: 'disclosure_indicator_server' }} />
|
||||||
|
@ -52,13 +61,18 @@ const Header = ({ onPress, serverName, showServerDropdown }) => (
|
||||||
);
|
);
|
||||||
|
|
||||||
Header.propTypes = {
|
Header.propTypes = {
|
||||||
onPress: PropTypes.func.isRequired,
|
isFetching: PropTypes.bool,
|
||||||
serverName: PropTypes.string,
|
serverName: PropTypes.string,
|
||||||
showServerDropdown: PropTypes.bool.isRequired
|
showServerDropdown: PropTypes.bool.isRequired,
|
||||||
|
onPress: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
Header.defaultProps = {
|
Header.defaultProps = {
|
||||||
serverName: 'Rocket.Chat'
|
serverName: 'Rocket.Chat'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
HeaderTitle.propTypes = {
|
||||||
|
isFetching: PropTypes.bool
|
||||||
|
};
|
||||||
|
|
||||||
export default Header;
|
export default Header;
|
||||||
|
|
|
@ -1,16 +1,19 @@
|
||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
import { responsive } from 'react-native-responsive-ui';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
toggleServerDropdown, closeServerDropdown, closeSortDropdown, setSearch as setSearchAction
|
toggleServerDropdown, closeServerDropdown, closeSortDropdown, setSearch as setSearchAction
|
||||||
} from '../../../actions/rooms';
|
} from '../../../actions/rooms';
|
||||||
import Header from './Header';
|
import Header from './Header';
|
||||||
|
|
||||||
|
@responsive
|
||||||
@connect(state => ({
|
@connect(state => ({
|
||||||
showServerDropdown: state.rooms.showServerDropdown,
|
showServerDropdown: state.rooms.showServerDropdown,
|
||||||
showSortDropdown: state.rooms.showSortDropdown,
|
showSortDropdown: state.rooms.showSortDropdown,
|
||||||
showSearchHeader: state.rooms.showSearchHeader,
|
showSearchHeader: state.rooms.showSearchHeader,
|
||||||
|
isFetching: state.rooms.isFetching,
|
||||||
serverName: state.settings.Site_Name
|
serverName: state.settings.Site_Name
|
||||||
}), dispatch => ({
|
}), dispatch => ({
|
||||||
close: () => dispatch(closeServerDropdown()),
|
close: () => dispatch(closeServerDropdown()),
|
||||||
|
@ -24,10 +27,12 @@ export default class RoomsListHeaderView extends PureComponent {
|
||||||
showSortDropdown: PropTypes.bool,
|
showSortDropdown: PropTypes.bool,
|
||||||
showSearchHeader: PropTypes.bool,
|
showSearchHeader: PropTypes.bool,
|
||||||
serverName: PropTypes.string,
|
serverName: PropTypes.string,
|
||||||
|
isFetching: PropTypes.bool,
|
||||||
open: PropTypes.func,
|
open: PropTypes.func,
|
||||||
close: PropTypes.func,
|
close: PropTypes.func,
|
||||||
closeSort: PropTypes.func,
|
closeSort: PropTypes.func,
|
||||||
setSearch: PropTypes.func
|
setSearch: PropTypes.func,
|
||||||
|
window: PropTypes.object
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
|
@ -66,14 +71,18 @@ export default class RoomsListHeaderView extends PureComponent {
|
||||||
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { serverName, showServerDropdown, showSearchHeader } = this.props;
|
const {
|
||||||
|
serverName, showServerDropdown, showSearchHeader, isFetching, window: { width }
|
||||||
|
} = this.props;
|
||||||
return (
|
return (
|
||||||
<Header
|
<Header
|
||||||
onPress={this.onPress}
|
|
||||||
serverName={serverName}
|
serverName={serverName}
|
||||||
showServerDropdown={showServerDropdown}
|
showServerDropdown={showServerDropdown}
|
||||||
showSearchHeader={showSearchHeader}
|
showSearchHeader={showSearchHeader}
|
||||||
|
isFetching={isFetching}
|
||||||
|
width={width}
|
||||||
setSearchInputRef={this.setSearchInputRef}
|
setSearchInputRef={this.setSearchInputRef}
|
||||||
|
onPress={this.onPress}
|
||||||
onSearchChangeText={text => this.onSearchChangeText(text)}
|
onSearchChangeText={text => this.onSearchChangeText(text)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
|
@ -20,7 +20,12 @@ import I18n from '../../i18n';
|
||||||
import SortDropdown from './SortDropdown';
|
import SortDropdown from './SortDropdown';
|
||||||
import ServerDropdown from './ServerDropdown';
|
import ServerDropdown from './ServerDropdown';
|
||||||
import Touch from '../../utils/touch';
|
import Touch from '../../utils/touch';
|
||||||
import { toggleSortDropdown as toggleSortDropdownAction, openSearchHeader as openSearchHeaderAction, closeSearchHeader as closeSearchHeaderAction } from '../../actions/rooms';
|
import {
|
||||||
|
toggleSortDropdown as toggleSortDropdownAction,
|
||||||
|
openSearchHeader as openSearchHeaderAction,
|
||||||
|
closeSearchHeader as closeSearchHeaderAction,
|
||||||
|
roomsRequest as roomsRequestAction
|
||||||
|
} from '../../actions/rooms';
|
||||||
import { appStart as appStartAction } from '../../actions';
|
import { appStart as appStartAction } from '../../actions';
|
||||||
import debounce from '../../utils/debounce';
|
import debounce from '../../utils/debounce';
|
||||||
import { isIOS, isAndroid } from '../../utils/deviceInfo';
|
import { isIOS, isAndroid } from '../../utils/deviceInfo';
|
||||||
|
@ -69,7 +74,8 @@ if (isAndroid) {
|
||||||
toggleSortDropdown: () => dispatch(toggleSortDropdownAction()),
|
toggleSortDropdown: () => dispatch(toggleSortDropdownAction()),
|
||||||
openSearchHeader: () => dispatch(openSearchHeaderAction()),
|
openSearchHeader: () => dispatch(openSearchHeaderAction()),
|
||||||
closeSearchHeader: () => dispatch(closeSearchHeaderAction()),
|
closeSearchHeader: () => dispatch(closeSearchHeaderAction()),
|
||||||
appStart: () => dispatch(appStartAction())
|
appStart: () => dispatch(appStartAction()),
|
||||||
|
roomsRequest: () => dispatch(roomsRequestAction())
|
||||||
}))
|
}))
|
||||||
/** @extends React.Component */
|
/** @extends React.Component */
|
||||||
export default class RoomsListView extends LoggedView {
|
export default class RoomsListView extends LoggedView {
|
||||||
|
@ -114,7 +120,8 @@ export default class RoomsListView extends LoggedView {
|
||||||
toggleSortDropdown: PropTypes.func,
|
toggleSortDropdown: PropTypes.func,
|
||||||
openSearchHeader: PropTypes.func,
|
openSearchHeader: PropTypes.func,
|
||||||
closeSearchHeader: PropTypes.func,
|
closeSearchHeader: PropTypes.func,
|
||||||
appStart: PropTypes.func
|
appStart: PropTypes.func,
|
||||||
|
roomsRequest: PropTypes.func
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -215,7 +222,7 @@ export default class RoomsListView extends LoggedView {
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
const {
|
const {
|
||||||
sortBy, groupByType, showFavorites, showUnread, appState
|
sortBy, groupByType, showFavorites, showUnread, appState, roomsRequest
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
if (!(
|
if (!(
|
||||||
|
@ -226,7 +233,7 @@ export default class RoomsListView extends LoggedView {
|
||||||
)) {
|
)) {
|
||||||
this.getSubscriptions();
|
this.getSubscriptions();
|
||||||
} else if (appState === 'foreground' && appState !== prevProps.appState) {
|
} else if (appState === 'foreground' && appState !== prevProps.appState) {
|
||||||
RocketChat.getRooms().catch(e => console.log(e));
|
roomsRequest();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue