Skip to content

Commit

Permalink
Updating room indicator (#609)
Browse files Browse the repository at this point in the history
Shows "Updating..." when requesting rooms from Rest API.
  • Loading branch information
diegolmello committed Feb 7, 2019
1 parent ca43210 commit f943104
Show file tree
Hide file tree
Showing 13 changed files with 252 additions and 194 deletions.
1 change: 1 addition & 0 deletions app/i18n/locales/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,7 @@ export default {
Unread: 'Unread',
Unread_on_top: 'Unread on top',
Unstar: 'Unstar',
Updating: 'Updating...',
Uploading: 'Uploading',
Upload_file_question_mark: 'Upload file?',
User_added_by: 'User {{userAdded}} added by {{userBy}}',
Expand Down
1 change: 1 addition & 0 deletions app/i18n/locales/pt-BR.js
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,7 @@ export default {
Unread: 'Não lidas',
Unread_on_top: 'Não lidas no topo',
Unstar: 'Remover favorito',
Updating: 'Atualizando...',
Uploading: 'Subindo arquivo',
Upload_file_question_mark: 'Enviar arquivo?',
User_added_by: 'Usuário {{userAdded}} adicionado por {{userBy}}',
Expand Down
33 changes: 7 additions & 26 deletions app/lib/methods/getRooms.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
import { InteractionManager } from 'react-native';

import mergeSubscriptionsRooms from './helpers/mergeSubscriptionsRooms';
import database from '../realm';
import log from '../../utils/log';

const lastMessage = () => {
const message = database
Expand All @@ -12,26 +8,11 @@ const lastMessage = () => {
};

export default function() {
return new Promise(async(resolve, reject) => {
try {
const updatedSince = lastMessage();
// subscriptions.get: Since RC 0.60.0
// rooms.get: Since RC 0.62.0
const [subscriptionsResult, roomsResult] = await (updatedSince
? Promise.all([this.sdk.get('subscriptions.get', { updatedSince }), this.sdk.get('rooms.get', { updatedSince })])
: 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);
}
});
const updatedSince = lastMessage();
// subscriptions.get: Since RC 0.60.0
// rooms.get: Since RC 0.62.0
if (updatedSince) {
return 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')]);
}
18 changes: 8 additions & 10 deletions app/lib/methods/subscriptions/rooms.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,28 @@ import protectedFunction from '../helpers/protectedFunction';
import messagesStatus from '../../../constants/messagesStatus';
import log from '../../../utils/log';
import random from '../../../utils/random';
import store from '../../createStore';
import { roomsRequest } from '../../../actions/rooms';

export default async function subscribeRooms() {
let timer = null;
const loop = () => {
if (timer) {
return;
}
timer = setTimeout(async() => {
try {
clearTimeout(timer);
timer = false;
if (this.sdk.userId) {
await this.getRooms();
loop();
}
} catch (e) {
timer = setTimeout(() => {
clearTimeout(timer);
timer = false;
if (this.sdk.userId) {
store.dispatch(roomsRequest());
loop();
}
}, 5000);
};

this.sdk.onStreamData('connected', () => {
if (this.sdk.userId) {
this.getRooms();
store.dispatch(roomsRequest());
}
clearTimeout(timer);
timer = false;
Expand Down
3 changes: 2 additions & 1 deletion app/lib/rocketchat.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import sendMessage, { getMessage, sendMessageCall } from './methods/sendMessage'
import { sendFileMessage, cancelUpload, isUploadActive } from './methods/sendFileMessage';

import { getDeviceToken } from '../push';
import { roomsRequest } from '../actions/rooms';

const TOKEN_KEY = 'reactnativemeteor_usertoken';
const SORT_PREFS_KEY = 'RC_SORT_PREFS_KEY';
Expand Down Expand Up @@ -134,7 +135,7 @@ const RocketChat = {
},
loginSuccess({ user }) {
reduxStore.dispatch(setUser(user));
this.getRooms().catch(e => console.log(e));
reduxStore.dispatch(roomsRequest());
this.subscribeRooms();
this.sdk.subscribe('activeUsers');
this.sdk.subscribe('roles');
Expand Down
7 changes: 5 additions & 2 deletions app/reducers/rooms.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import * as types from '../actions/actionsTypes';

const initialState = {
isFetching: false,
isFetching: true,
failure: false,
errorMessage: {},
searchText: '',
showServerDropdown: false,
closeServerDropdown: false,
Expand All @@ -15,7 +16,9 @@ export default function login(state = initialState, action) {
case types.ROOMS.REQUEST:
return {
...state,
isFetching: true
isFetching: true,
failure: false,
errorMessage: {}
};
case types.ROOMS.SUCCESS:
return {
Expand Down
2 changes: 2 additions & 0 deletions app/sagas/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { all } from 'redux-saga/effects';
import login from './login';
import rooms from './rooms';
import room from './room';
import messages from './messages';
import selectServer from './selectServer';
import createChannel from './createChannel';
Expand All @@ -14,6 +15,7 @@ const root = function* root() {
init(),
createChannel(),
rooms(),
room(),
login(),
messages(),
selectServer(),
Expand Down
156 changes: 156 additions & 0 deletions app/sagas/room.js
Original file line number Diff line number Diff line change
@@ -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;
Loading

0 comments on commit f943104

Please sign in to comment.