From d810c28c306d17ec6a267f793baa8df525fed29c Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Fri, 3 Apr 2020 15:02:10 -0300 Subject: [PATCH 01/38] [FIX] Direct Message between multiple users REST (#1974) --- app/lib/rocketchat.js | 6 +++--- app/sagas/createChannel.js | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index 1604880af..cc176ea03 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -627,11 +627,11 @@ const RocketChat = { }, createGroupChat() { - let { users } = reduxStore.getState().selectedUsers; - users = users.map(u => u.name); + const { users } = reduxStore.getState().selectedUsers; + const usernames = users.map(u => u.name).join(','); // RC 3.1.0 - return this.methodCall('createDirectMessage', ...users); + return this.post('im.create', { usernames }); }, createDiscussion({ diff --git a/app/sagas/createChannel.js b/app/sagas/createChannel.js index 86a5b613b..37d249a74 100644 --- a/app/sagas/createChannel.js +++ b/app/sagas/createChannel.js @@ -28,7 +28,10 @@ const handleRequest = function* handleRequest({ data }) { let sub; if (data.group) { - sub = yield call(createGroupChat); + const result = yield call(createGroupChat); + if (result.success) { + ({ room: sub } = result); + } } else { sub = yield call(createChannel, data); } From ee0e7bb9d17aebafe13f6660dea53c5494250820 Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Fri, 3 Apr 2020 15:03:53 -0300 Subject: [PATCH 02/38] [FIX] Investigate app losing connection issues (#1890) * [WIP] Reopen without timeOut & ping with 5 sec & Fix Unsubscribe * [FIX] Remove duplicated close * [FIX] Use no-dist lib * [FIX] Try minor fix * [FIX] Try reopen connection when app was put on foreground * [FIX] Remove timeout * [FIX] Build * [FIX] Patch * [FIX] Snapshot * [IMPROVEMENT] Decrease time to reopen * [FIX] Some fixes * [FIX] Update sdk version * [FIX] Subscribe Room Once * [CHORE] Update sdk * [FIX] Subscribe Room * [FIX] Try to resend missed subs * [FIX] Users never show status when start app without network * [FIX] Subscribe to room * [FIX] Multiple servers * [CHORE] Update SDK * [FIX] Don't duplicate streams on subscribeAll * [FIX] Server version when start the app offline * [FIX] Server version cached * [CHORE] Remove unnecessary code * [FIX] Offline server version * [FIX] Subscribe before connect * [FIX] Remove unncessary props * [FIX] Update sdk * [FIX] User status & Unsubscribe Typing * [FIX] Typing at incorrect room * [FIX] Multiple Servers * [CHORE] Update SDK * [REVERT] Undo some changes on SDK * [CHORE] Update sdk to prevent incorrect subscribes * [FIX] Prevent no reconnect * [FIX] Remove close on open * [FIX] Clear typing when disconnect/connect to SDK * [CHORE] Update SDK * [CHORE] Update SDK * Update SDK * fix merge develop Co-authored-by: Diego Mello --- __mocks__/@rocket.chat/sdk.js | 2 + .../__snapshots__/Storyshots.test.js.snap | 190 +++++++++--------- app/lib/methods/getUsersPresence.js | 43 ++-- app/lib/methods/subscriptions/room.js | 3 +- app/lib/rocketchat.js | 21 +- app/presentation/RoomItem/index.js | 9 +- app/sagas/login.js | 4 +- app/sagas/selectServer.js | 9 +- app/views/RoomView/Header/index.js | 4 +- app/views/RoomView/index.js | 12 +- app/views/RoomsListView/index.js | 4 + package.json | 4 +- patches/@rocket.chat+sdk+1.0.0-alpha.41.patch | 63 ------ yarn.lock | 9 +- 14 files changed, 172 insertions(+), 205 deletions(-) create mode 100644 __mocks__/@rocket.chat/sdk.js delete mode 100644 patches/@rocket.chat+sdk+1.0.0-alpha.41.patch diff --git a/__mocks__/@rocket.chat/sdk.js b/__mocks__/@rocket.chat/sdk.js new file mode 100644 index 000000000..b469d9125 --- /dev/null +++ b/__mocks__/@rocket.chat/sdk.js @@ -0,0 +1,2 @@ +export class Rocketchat {} +export const settings = {}; diff --git a/__tests__/__snapshots__/Storyshots.test.js.snap b/__tests__/__snapshots__/Storyshots.test.js.snap index 792cd66d0..2fa6d1061 100644 --- a/__tests__/__snapshots__/Storyshots.test.js.snap +++ b/__tests__/__snapshots__/Storyshots.test.js.snap @@ -3751,7 +3751,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -4013,7 +4013,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -4275,7 +4275,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -4515,7 +4515,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -4945,7 +4945,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -5324,7 +5324,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -5582,7 +5582,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -5862,7 +5862,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -6124,7 +6124,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -6396,7 +6396,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -6729,7 +6729,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -7199,7 +7199,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -7584,7 +7584,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -8025,7 +8025,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://pbs.twimg.com/profile_images/1016397063649660929/14EIApTi_400x400.jpg", } @@ -8287,7 +8287,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -8549,7 +8549,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -8977,7 +8977,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -9244,7 +9244,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -9511,7 +9511,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -9906,7 +9906,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -10173,7 +10173,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -10472,7 +10472,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -10793,7 +10793,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -11055,7 +11055,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -11659,7 +11659,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -12707,7 +12707,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/rocket.cat?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -12947,7 +12947,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -13187,7 +13187,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/rocket.cat?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -13427,7 +13427,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -13689,7 +13689,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/rocket.cat?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -13991,7 +13991,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -14371,7 +14371,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/rocket.cat?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -14656,7 +14656,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -14918,7 +14918,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -15235,7 +15235,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -15606,7 +15606,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -15920,7 +15920,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -16187,7 +16187,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -17299,7 +17299,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -17660,7 +17660,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -18075,7 +18075,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -18410,7 +18410,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -18811,7 +18811,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -19146,7 +19146,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -19569,7 +19569,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -19801,7 +19801,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -20033,7 +20033,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -20265,7 +20265,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -20497,7 +20497,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -20729,7 +20729,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -20961,7 +20961,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -21125,7 +21125,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -21465,7 +21465,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -21614,7 +21614,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -21763,7 +21763,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -22015,7 +22015,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -22164,7 +22164,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -22313,7 +22313,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -22462,7 +22462,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -22626,7 +22626,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -22960,7 +22960,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -23296,7 +23296,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -23632,7 +23632,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -23990,7 +23990,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -24369,7 +24369,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -24864,7 +24864,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -25497,7 +25497,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -26213,7 +26213,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -26558,7 +26558,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -26803,7 +26803,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -27313,7 +27313,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -27581,7 +27581,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -27848,7 +27848,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -28017,7 +28017,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -28186,7 +28186,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -28355,7 +28355,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -28524,7 +28524,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -28693,7 +28693,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -28862,7 +28862,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -29031,7 +29031,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -29200,7 +29200,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -29369,7 +29369,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -29538,7 +29538,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -29707,7 +29707,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -29876,7 +29876,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -30045,7 +30045,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -30214,7 +30214,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -30383,7 +30383,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -30645,7 +30645,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -31225,7 +31225,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -31670,7 +31670,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -32127,7 +32127,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -32376,7 +32376,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -32745,7 +32745,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -33039,7 +33039,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { - "headers": Object {}, + "headers": undefined, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=50&&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } diff --git a/app/lib/methods/getUsersPresence.js b/app/lib/methods/getUsersPresence.js index 2d8fe5926..91c82ff47 100644 --- a/app/lib/methods/getUsersPresence.js +++ b/app/lib/methods/getUsersPresence.js @@ -3,12 +3,13 @@ import semver from 'semver'; import reduxStore from '../createStore'; import { setActiveUsers } from '../../actions/activeUsers'; +import { setUser } from '../../actions/login'; export function subscribeUsersPresence() { const serverVersion = reduxStore.getState().server.version; // if server is lower than 1.1.0 - if (serverVersion && semver.lt(semver.coerce(serverVersion), '1.1.0')) { + if (serverVersion && semver.lt(serverVersion, '1.1.0')) { if (this.activeUsersSubTimeout) { clearTimeout(this.activeUsersSubTimeout); this.activeUsersSubTimeout = false; @@ -25,35 +26,43 @@ let ids = []; export default async function getUsersPresence() { const serverVersion = reduxStore.getState().server.version; + const { user: loggedUser } = reduxStore.getState().login; // if server is greather than or equal 1.1.0 - if (serverVersion && !semver.lt(semver.coerce(serverVersion), '1.1.0')) { + if (serverVersion && semver.gte(serverVersion, '1.1.0')) { let params = {}; // if server is greather than or equal 3.0.0 - if (serverVersion && !semver.lt(semver.coerce(serverVersion), '3.0.0')) { + if (serverVersion && semver.gte(serverVersion, '3.0.0')) { // if not have any id if (!ids.length) { return; } // Request userPresence on demand params = { ids: ids.join(',') }; - ids = []; } - // RC 1.1.0 - const result = await this.sdk.get('users.presence', params); - if (result.success) { - const activeUsers = result.users.reduce((ret, item) => { - ret[item._id] = { - status: item.status, - statusText: item.statusText - }; - return ret; - }, {}); - InteractionManager.runAfterInteractions(() => { - reduxStore.dispatch(setActiveUsers(activeUsers)); - }); + try { + // RC 1.1.0 + const result = await this.sdk.get('users.presence', params); + if (result.success) { + const activeUsers = result.users.reduce((ret, item) => { + const { _id, status, statusText } = item; + + if (loggedUser && loggedUser.id === _id) { + reduxStore.dispatch(setUser({ status, statusText })); + } + + ret[_id] = { status, statusText }; + return ret; + }, {}); + InteractionManager.runAfterInteractions(() => { + reduxStore.dispatch(setActiveUsers(activeUsers)); + }); + ids = []; + } + } catch { + // do nothing } } } diff --git a/app/lib/methods/subscriptions/room.js b/app/lib/methods/subscriptions/room.js index e00bb1124..507c36b09 100644 --- a/app/lib/methods/subscriptions/room.js +++ b/app/lib/methods/subscriptions/room.js @@ -51,11 +51,11 @@ export default class RoomSubscription { // do nothing } } + reduxStore.dispatch(clearUserTyping()); this.removeListener(this.connectedListener); this.removeListener(this.disconnectedListener); this.removeListener(this.notifyRoomListener); this.removeListener(this.messageReceivedListener); - reduxStore.dispatch(clearUserTyping()); if (this.timer) { clearTimeout(this.timer); } @@ -73,6 +73,7 @@ export default class RoomSubscription { }; handleConnection = () => { + reduxStore.dispatch(clearUserTyping()); RocketChat.loadMissedMessages({ rid: this.rid }).catch(e => console.log(e)); }; diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index cc176ea03..e7247c2ce 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -63,13 +63,12 @@ const RocketChat = { TOKEN_KEY, callJitsi, async subscribeRooms() { - if (this.roomsSub) { - this.roomsSub.stop(); - } - try { - this.roomsSub = await subscribeRooms.call(this); - } catch (e) { - log(e); + if (!this.roomsSub) { + try { + this.roomsSub = await subscribeRooms.call(this); + } catch (e) { + log(e); + } } }, canOpenRoom, @@ -189,6 +188,7 @@ const RocketChat = { if (this.roomsSub) { this.roomsSub.stop(); + this.roomsSub = null; } if (this.sdk) { @@ -206,7 +206,7 @@ const RocketChat = { this.sdk = new RocketchatClient({ host: server, protocol: 'ddp', useSsl }); this.getSettings(); - this.sdk.connect() + const sdkConnect = () => this.sdk.connect() .then(() => { if (user && user.token) { reduxStore.dispatch(loginRequest({ resume: user.token }, logoutOnError)); @@ -217,10 +217,12 @@ const RocketChat = { // when `connect` raises an error, we try again in 10 seconds this.connectTimeout = setTimeout(() => { - this.connect({ server, user }); + sdkConnect(); }, 10000); }); + sdkConnect(); + this.connectedListener = this.sdk.onStreamData('connected', () => { reduxStore.dispatch(connectSuccess()); }); @@ -410,6 +412,7 @@ const RocketChat = { async logout({ server }) { if (this.roomsSub) { this.roomsSub.stop(); + this.roomsSub = null; } if (this.activeUsersSubTimeout) { diff --git a/app/presentation/RoomItem/index.js b/app/presentation/RoomItem/index.js index a284ca956..a28bacdcb 100644 --- a/app/presentation/RoomItem/index.js +++ b/app/presentation/RoomItem/index.js @@ -27,6 +27,7 @@ const attrs = [ 'isRead', 'favorite', 'status', + 'connected', 'theme' ]; @@ -40,13 +41,13 @@ const arePropsEqual = (oldProps, newProps) => { }; const RoomItem = React.memo(({ - onPress, width, favorite, toggleFav, isRead, rid, toggleRead, hideChannel, testID, unread, userMentions, name, _updatedAt, alert, type, avatarSize, baseUrl, userId, username, token, id, prid, showLastMessage, hideUnreadStatus, lastMessage, status, avatar, useRealName, getUserPresence, isGroupChat, theme + onPress, width, favorite, toggleFav, isRead, rid, toggleRead, hideChannel, testID, unread, userMentions, name, _updatedAt, alert, type, avatarSize, baseUrl, userId, username, token, id, prid, showLastMessage, hideUnreadStatus, lastMessage, status, avatar, useRealName, getUserPresence, isGroupChat, connected, theme }) => { useEffect(() => { - if (type === 'd') { + if (connected && type === 'd' && id) { getUserPresence(id); } - }, []); + }, [connected]); const date = formatDate(_updatedAt); @@ -197,6 +198,7 @@ RoomItem.propTypes = { hideUnreadStatus: PropTypes.bool, useRealName: PropTypes.bool, getUserPresence: PropTypes.func, + connected: PropTypes.bool, isGroupChat: PropTypes.bool, theme: PropTypes.string }; @@ -208,6 +210,7 @@ RoomItem.defaultProps = { }; const mapStateToProps = (state, ownProps) => ({ + connected: state.meteor.connected, status: state.meteor.connected && ownProps.type === 'd' ? state.activeUsers[ownProps.id] && state.activeUsers[ownProps.id].status diff --git a/app/sagas/login.js b/app/sagas/login.js index 1eb504722..80d158ddc 100644 --- a/app/sagas/login.js +++ b/app/sagas/login.js @@ -73,7 +73,7 @@ const registerPushToken = function* registerPushToken() { const fetchUsersPresence = function* fetchUserPresence() { yield RocketChat.getUsersPresence(); - yield RocketChat.subscribeUsersPresence(); + RocketChat.subscribeUsersPresence(); }; const handleLoginSuccess = function* handleLoginSuccess({ user }) { @@ -81,6 +81,8 @@ const handleLoginSuccess = function* handleLoginSuccess({ user }) { const adding = yield select(state => state.server.adding); yield RNUserDefaults.set(RocketChat.TOKEN_KEY, user.token); + RocketChat.getUserPresence(user.id); + const server = yield select(getServer); yield put(roomsRequest()); yield fork(fetchPermissions); diff --git a/app/sagas/selectServer.js b/app/sagas/selectServer.js index 23a716bc6..ee2cfc7dd 100644 --- a/app/sagas/selectServer.js +++ b/app/sagas/selectServer.js @@ -38,7 +38,10 @@ const getServerInfo = function* getServerInfo({ server, raiseError = true }) { return; } - const validVersion = semver.coerce(serverInfo.version); + let serverVersion = semver.valid(serverInfo.version); + if (!serverVersion) { + ({ version: serverVersion } = semver.coerce(serverInfo.version)); + } const serversDB = database.servers; const serversCollection = serversDB.collections.get('servers'); @@ -46,12 +49,12 @@ const getServerInfo = function* getServerInfo({ server, raiseError = true }) { try { const serverRecord = await serversCollection.find(server); await serverRecord.update((record) => { - record.version = validVersion; + record.version = serverVersion; }); } catch (e) { await serversCollection.create((record) => { record._raw = sanitizedRaw({ id: server }, serversCollection.schema); - record.version = validVersion; + record.version = serverVersion; }); } }); diff --git a/app/views/RoomView/Header/index.js b/app/views/RoomView/Header/index.js index 7e91d3afe..5d3dc2592 100644 --- a/app/views/RoomView/Header/index.js +++ b/app/views/RoomView/Header/index.js @@ -101,8 +101,10 @@ const mapStateToProps = (state, ownProps) => { if (type === 'd') { const user = getUserSelector(state); if (user.id) { - if (state.activeUsers[roomUserId]) { + if (state.activeUsers[roomUserId] && state.meteor.connected) { ({ status, statusText } = state.activeUsers[roomUserId]); + } else { + status = 'offline'; } } } diff --git a/app/views/RoomView/index.js b/app/views/RoomView/index.js index 47566d4a9..82c91f696 100644 --- a/app/views/RoomView/index.js +++ b/app/views/RoomView/index.js @@ -222,10 +222,13 @@ class RoomView extends React.Component { if (this.tmid) { navigation.setParams({ toggleFollowThread: this.toggleFollowThread, goRoomActionsView: this.goRoomActionsView }); } - if (isAuthenticated && this.rid) { - this.init(); - } else if (this.rid) { - EventEmitter.addEventListener('connected', this.handleConnected); + if (this.rid) { + this.sub.subscribe(); + if (isAuthenticated) { + this.init(); + } else { + EventEmitter.addEventListener('connected', this.handleConnected); + } } if (isIOS && this.rid) { this.updateUnreadCount(); @@ -361,7 +364,6 @@ class RoomView extends React.Component { this.setLastOpen(null); } RocketChat.readMessages(room.rid, newLastOpen, true).catch(e => console.log(e)); - this.sub.subscribe(); } } diff --git a/app/views/RoomsListView/index.js b/app/views/RoomsListView/index.js index d8b6e4728..61f41d43c 100644 --- a/app/views/RoomsListView/index.js +++ b/app/views/RoomsListView/index.js @@ -174,6 +174,7 @@ class RoomsListView extends React.Component { roomsRequest: PropTypes.func, closeServerDropdown: PropTypes.func, useRealName: PropTypes.bool, + connected: PropTypes.bool, split: PropTypes.bool }; @@ -302,6 +303,7 @@ class RoomsListView extends React.Component { showFavorites, showUnread, appState, + connected, roomsRequest } = this.props; @@ -317,6 +319,7 @@ class RoomsListView extends React.Component { } else if ( appState === 'foreground' && appState !== prevProps.appState + && connected ) { roomsRequest(); } @@ -894,6 +897,7 @@ class RoomsListView extends React.Component { const mapStateToProps = state => ({ user: getUserSelector(state), server: state.server.server, + connected: state.server.connected, searchText: state.rooms.searchText, loadingServer: state.server.loading, showServerDropdown: state.rooms.showServerDropdown, diff --git a/package.json b/package.json index 5894e508b..c2f701807 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "@react-native-community/cameraroll": "^1.3.0", "@react-native-community/datetimepicker": "^2.1.0", "@react-native-community/slider": "2.0.5", - "@rocket.chat/sdk": "1.0.0-alpha.41", + "@rocket.chat/sdk": "djorkaeffalexandre/Rocket.Chat.js.SDK#test.fix-ddp", "@rocket.chat/ui-kit": "^0.2.0-alpha.25", "base-64": "^0.1.0", "bugsnag-react-native": "2.23.2", @@ -70,7 +70,7 @@ "react-native-keyboard-tracking-view": "^5.6.1", "react-native-keycommands": "2.0.3", "react-native-localize": "1.3.1", - "react-native-mime-types": "^2.2.1", + "react-native-mime-types": "2.2.1", "react-native-modal": "11.5.3", "react-native-modalize": "^1.3.6", "react-native-navigation-bar-color": "^1.0.0", diff --git a/patches/@rocket.chat+sdk+1.0.0-alpha.41.patch b/patches/@rocket.chat+sdk+1.0.0-alpha.41.patch deleted file mode 100644 index 9dfff7688..000000000 --- a/patches/@rocket.chat+sdk+1.0.0-alpha.41.patch +++ /dev/null @@ -1,63 +0,0 @@ -diff --git a/node_modules/@rocket.chat/sdk/lib/api/api.js b/node_modules/@rocket.chat/sdk/lib/api/api.js -index 5b7dc21..49f1af5 100644 ---- a/node_modules/@rocket.chat/sdk/lib/api/api.js -+++ b/node_modules/@rocket.chat/sdk/lib/api/api.js -@@ -62,6 +62,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); - var log_1 = require("../log"); - var message_1 = require("../message"); - var tiny_events_1 = require("tiny-events"); -+var settings = require("../settings"); - var Client = /** @class */ (function () { - function Client(_a) { - var _b = _a.host, host = _b === void 0 ? 'http://localhost:3000' : _b; -@@ -70,7 +71,7 @@ var Client = /** @class */ (function () { - } - Object.defineProperty(Client.prototype, "headers", { - get: function () { -- return __assign({ 'Content-Type': 'application/json' }, this._headers); -+ return __assign({ 'Content-Type': 'application/json', ...settings.customHeaders }, this._headers); - }, - set: function (obj) { - this._headers = obj; -diff --git a/node_modules/@rocket.chat/sdk/lib/drivers/ddp.js b/node_modules/@rocket.chat/sdk/lib/drivers/ddp.js -index e3510c7..e3216cc 100644 ---- a/node_modules/@rocket.chat/sdk/lib/drivers/ddp.js -+++ b/node_modules/@rocket.chat/sdk/lib/drivers/ddp.js -@@ -110,6 +110,7 @@ tiny_events_1.EventEmitter.prototype.removeAllListeners = function (event) { - var interfaces_1 = require("../../interfaces"); - var util_1 = require("../util"); - var js_sha256_1 = require("js-sha256"); -+var settings = require("../settings"); - /** Websocket handler class, manages connections and subscriptions by DDP */ - var Socket = /** @class */ (function (_super) { - __extends(Socket, _super); -@@ -145,7 +146,7 @@ var Socket = /** @class */ (function (_super) { - return !_this.alive() && _this.reopen(); - }, ms); - try { -- connection = new universal_websocket_client_1.default(this.host); -+ connection = new universal_websocket_client_1.default(this.host, null, { headers: settings.customHeaders }); - connection.onerror = reject; - } - catch (err) { -diff --git a/node_modules/@rocket.chat/sdk/lib/settings.d.ts b/node_modules/@rocket.chat/sdk/lib/settings.d.ts -index 99eb828..8c99307 100644 ---- a/node_modules/@rocket.chat/sdk/lib/settings.d.ts -+++ b/node_modules/@rocket.chat/sdk/lib/settings.d.ts -@@ -17,3 +17,4 @@ export declare let dmCacheMaxAge: number; - export declare let token: string; - export declare let rid: string; - export declare let department: string; -+export declare let customHeaders: object; -diff --git a/node_modules/@rocket.chat/sdk/lib/settings.js b/node_modules/@rocket.chat/sdk/lib/settings.js -index 822c286..ce8f805 100644 ---- a/node_modules/@rocket.chat/sdk/lib/settings.js -+++ b/node_modules/@rocket.chat/sdk/lib/settings.js -@@ -29,4 +29,6 @@ exports.dmCacheMaxAge = 1000 * parseInt(process.env.DM_ROOM_CACHE_MAX_AGE || '10 - exports.token = process.env.LIVECHAT_TOKEN || ''; - exports.rid = process.env.LIVECHAT_ROOM || ''; - exports.department = process.env.LIVECHAT_DEPARTMENT || ''; -+// Headers settings -+exports.customHeaders = {}; - //# sourceMappingURL=settings.js.map -\ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 504d7f655..9688e69b8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1915,10 +1915,9 @@ resolved "https://registry.yarnpkg.com/@redux-saga/types/-/types-1.1.0.tgz#0e81ce56b4883b4b2a3001ebe1ab298b84237204" integrity sha512-afmTuJrylUU/0OtqzaRkbyYFFNgCF73Bvel/sw90pvGrWIZ+vyoIJqA6eMSoA6+nb443kTmulmBtC9NerXboNg== -"@rocket.chat/sdk@1.0.0-alpha.41": - version "1.0.0-alpha.41" - resolved "https://registry.yarnpkg.com/@rocket.chat/sdk/-/sdk-1.0.0-alpha.41.tgz#8fcae2885786bec56a56b6d9a8cccaa365b77364" - integrity sha512-jQ+/exEQMOv+bwH+yzPTC0oJGIKj/AlMc95IvWAn/vHDLjjS3aGzpIpZhBwsMOBVvb/5N8rnq6kEleCkEJk28g== +"@rocket.chat/sdk@djorkaeffalexandre/Rocket.Chat.js.SDK#test.fix-ddp": + version "1.0.0-dj.15" + resolved "https://codeload.github.com/djorkaeffalexandre/Rocket.Chat.js.SDK/tar.gz/216de62f7e52dd4a9f73d7989d6943ced550a92a" dependencies: js-sha256 "^0.9.0" lru-cache "^4.1.1" @@ -9965,7 +9964,7 @@ react-native-localize@1.3.1: resolved "https://registry.yarnpkg.com/react-native-localize/-/react-native-localize-1.3.1.tgz#d0b7046acd4214ac2bcb61102317374351400c76" integrity sha512-Y3LzTHyrgsIsDYvjWSRguARBKjiLaahcbJg663ZqP1Tcpan4LYn/f3iusM+Oh6qYvClnlo9AlBkLdCZbWwe7Tw== -react-native-mime-types@^2.2.1: +react-native-mime-types@2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/react-native-mime-types/-/react-native-mime-types-2.2.1.tgz#a9760e9916e4e7df03512c60516668f23543f2c0" integrity sha512-2H0jjW5l2driXiiKx9PZsJDCFgS8LeMaVLVZPy3iRkBrNcstpQosEr6+YJfihLbW3WvFtmS2qcyFKB7mYw/iJg== From afb68c74c17f666a0d7a7a04930d0f8ef4260710 Mon Sep 17 00:00:00 2001 From: Diego Mello Date: Mon, 6 Apr 2020 16:07:23 -0300 Subject: [PATCH 03/38] [FIX] Single message thread inserting thread without rid (#1999) --- app/views/RoomView/index.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/views/RoomView/index.js b/app/views/RoomView/index.js index 82c91f696..9774e020b 100644 --- a/app/views/RoomView/index.js +++ b/app/views/RoomView/index.js @@ -670,7 +670,6 @@ class RoomView extends React.Component { // eslint-disable-next-line react/sort-comp fetchThreadName = async(tmid, messageId) => { try { - const { room } = this.state; const db = database.active; const threadCollection = db.collections.get('threads'); const messageCollection = db.collections.get('messages'); @@ -693,7 +692,7 @@ class RoomView extends React.Component { await db.batch( threadCollection.prepareCreate((t) => { t._raw = sanitizedRaw({ id: thread._id }, threadCollection.schema); - t.subscription.set(room); + t.subscription.id = this.rid; Object.assign(t, thread); }), messageRecord.prepareUpdate((m) => { @@ -703,7 +702,7 @@ class RoomView extends React.Component { }); } } catch (e) { - log(e); + // log(e); } } From 0298c38b3d10dfb4f0ee9049184fec5cae51e5df Mon Sep 17 00:00:00 2001 From: Diego Mello Date: Mon, 6 Apr 2020 16:07:40 -0300 Subject: [PATCH 04/38] [FIX] ThreadMessagesView crashing on load (#1997) --- app/views/ThreadMessagesView/index.js | 38 +++++++++++++++------------ 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/app/views/ThreadMessagesView/index.js b/app/views/ThreadMessagesView/index.js index 33001d915..eb664d672 100644 --- a/app/views/ThreadMessagesView/index.js +++ b/app/views/ThreadMessagesView/index.js @@ -71,12 +71,10 @@ class ThreadMessagesView extends React.Component { } componentWillUnmount() { + console.countReset(`${ this.constructor.name }.render calls`); if (this.mountInteraction && this.mountInteraction.cancel) { this.mountInteraction.cancel(); } - if (this.loadInteraction && this.loadInteraction.cancel) { - this.loadInteraction.cancel(); - } if (this.syncInteraction && this.syncInteraction.cancel) { this.syncInteraction.cancel(); } @@ -89,13 +87,14 @@ class ThreadMessagesView extends React.Component { } // eslint-disable-next-line react/sort-comp - subscribeData = () => { + subscribeData = async() => { try { const db = database.active; - this.subObservable = db.collections + const subscription = await db.collections .get('subscriptions') - .findAndObserve(this.rid); - this.subSubscription = this.subObservable + .find(this.rid); + const observable = subscription.observe(); + this.subSubscription = observable .subscribe((data) => { this.subscription = data; }); @@ -116,14 +115,14 @@ class ThreadMessagesView extends React.Component { } }); } catch (e) { - log(e); + // Do nothing } } // eslint-disable-next-line react/sort-comp init = () => { if (!this.subscription) { - return; + this.load(); } try { const lastThreadSync = new Date(); @@ -138,6 +137,13 @@ class ThreadMessagesView extends React.Component { } updateThreads = async({ update, remove, lastThreadSync }) => { + // if there's no subscription, manage data on this.state.messages + // note: sync will never be called without subscription + if (!this.subscription) { + this.setState(({ messages }) => ({ messages: [...messages, ...update] })); + return; + } + try { const db = database.active; const threadsCollection = db.collections.get('threads'); @@ -198,13 +204,10 @@ class ThreadMessagesView extends React.Component { rid: this.rid, count: API_FETCH_COUNT, offset: messages.length }); if (result.success) { - this.loadInteraction = InteractionManager.runAfterInteractions(() => { - this.updateThreads({ update: result.threads, lastThreadSync }); - - this.setState({ - loading: false, - end: result.count < API_FETCH_COUNT - }); + this.updateThreads({ update: result.threads, lastThreadSync }); + this.setState({ + loading: false, + end: result.count < API_FETCH_COUNT }); } } catch (e) { @@ -319,6 +322,7 @@ class ThreadMessagesView extends React.Component { } render() { + console.count(`${ this.constructor.name }.render calls`); const { loading, messages } = this.state; const { theme } = this.props; @@ -335,7 +339,7 @@ class ThreadMessagesView extends React.Component { renderItem={this.renderItem} style={[styles.list, { backgroundColor: themes[theme].backgroundColor }]} contentContainerStyle={styles.contentContainer} - keyExtractor={item => item.id} + keyExtractor={item => item._id} onEndReached={this.load} onEndReachedThreshold={0.5} maxToRenderPerBatch={5} From 32d105051d63f1ce204001254640201de0497450 Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Mon, 6 Apr 2020 16:15:13 -0300 Subject: [PATCH 05/38] [FIX] Saml (#1996) * [FIX] SAML incorrect close * [FIX] Pathname Co-authored-by: Diego Mello --- app/views/AuthenticationWebView.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/AuthenticationWebView.js b/app/views/AuthenticationWebView.js index b129d821b..28de76a37 100644 --- a/app/views/AuthenticationWebView.js +++ b/app/views/AuthenticationWebView.js @@ -79,11 +79,11 @@ class AuthenticationWebView extends React.PureComponent { if (this.authType === 'saml' || this.authType === 'cas') { const { navigation } = this.props; const ssoToken = navigation.getParam('ssoToken'); - if (url.includes('ticket') || url.includes('validate') || url.includes('saml_idp_credentialToken')) { + const parsedUrl = parse(url, true); + if (parsedUrl.pathname?.includes('ticket') || parsedUrl.pathname?.includes('validate') || parsedUrl.query?.saml_idp_credentialToken) { let payload; if (this.authType === 'saml') { - const parsedUrl = parse(url, true); - const token = (parsedUrl.query && parsedUrl.query.saml_idp_credentialToken) || ssoToken; + const token = parsedUrl.query?.saml_idp_credentialToken || ssoToken; const credentialToken = { credentialToken: token }; payload = { ...credentialToken, saml: true }; } else { From c24c16c932df32d9636386bc782f301833047a5d Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Mon, 6 Apr 2020 16:32:58 -0300 Subject: [PATCH 06/38] [FIX] Change user own status (#1995) * [FIX] Change user own status * [IMPROVEMENT] Set activeUsers Co-authored-by: Diego Mello --- app/lib/rocketchat.js | 7 ++----- app/sagas/login.js | 8 +++++++- app/views/StatusView.js | 12 ++++++++++-- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index e7247c2ce..f0dbf2489 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -769,12 +769,9 @@ const RocketChat = { setUserPresenceOnline() { return this.methodCall('UserPresence:online'); }, - setUserPresenceDefaultStatus(status) { - return this.methodCall('UserPresence:setDefaultStatus', status); - }, - setUserStatus(message) { + setUserStatus(status, message) { // RC 1.2.0 - return this.post('users.setStatus', { message }); + return this.post('users.setStatus', { status, message }); }, setReaction(emoji, messageId) { // RC 0.62.2 diff --git a/app/sagas/login.js b/app/sagas/login.js index 80d158ddc..4fc4a3504 100644 --- a/app/sagas/login.js +++ b/app/sagas/login.js @@ -21,6 +21,7 @@ import database from '../lib/database'; import EventEmitter from '../utils/events'; import { inviteLinksRequest } from '../actions/inviteLinks'; import { showErrorAlert } from '../utils/info'; +import { setActiveUsers } from '../actions/activeUsers'; const getServer = state => state.server.server; const loginWithPasswordCall = args => RocketChat.loginWithPassword(args); @@ -188,11 +189,16 @@ const handleLogout = function* handleLogout({ forcedByServer }) { } }; -const handleSetUser = function handleSetUser({ user }) { +const handleSetUser = function* handleSetUser({ user }) { if (user && user.language) { I18n.locale = user.language; moment.locale(toMomentLocale(user.language)); } + + if (user && user.status) { + const userId = yield select(state => state.login.user.id); + yield put(setActiveUsers({ [userId]: user })); + } }; const root = function* root() { diff --git a/app/views/StatusView.js b/app/views/StatusView.js index 1f142794c..335529907 100644 --- a/app/views/StatusView.js +++ b/app/views/StatusView.js @@ -21,6 +21,8 @@ import { withSplit } from '../split'; import { themedHeader } from '../utils/navigation'; import { getUserSelector } from '../selectors/login'; import { CustomHeaderButtons, Item, CancelModalButton } from '../containers/HeaderButton'; +import store from '../lib/createStore'; +import { setUser } from '../actions/login'; const STATUS = [{ id: 'online', @@ -75,6 +77,7 @@ class StatusView extends React.Component { static propTypes = { user: PropTypes.shape({ + id: PropTypes.string, status: PropTypes.string, statusText: PropTypes.string }), @@ -112,11 +115,12 @@ class StatusView extends React.Component { setCustomStatus = async() => { const { statusText } = this.state; + const { user } = this.props; this.setState({ loading: true }); try { - const result = await RocketChat.setUserStatus(statusText); + const result = await RocketChat.setUserStatus(user.status, statusText); if (result.success) { EventEmitter.emit(LISTENER, { message: I18n.t('Status_saved_successfully') }); } else { @@ -163,6 +167,7 @@ class StatusView extends React.Component { } renderItem = ({ item }) => { + const { statusText } = this.state; const { theme, user } = this.props; const { id, name } = item; return ( @@ -171,7 +176,10 @@ class StatusView extends React.Component { onPress={async() => { if (user.status !== item.id) { try { - await RocketChat.setUserPresenceDefaultStatus(item.id); + const result = await RocketChat.setUserStatus(item.id, statusText); + if (result.success) { + store.dispatch(setUser({ status: item.id })); + } } catch (e) { log(e); } From 78441bf3454ac54bce0952241f39c52c1f6fdb4c Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Mon, 6 Apr 2020 17:23:13 -0300 Subject: [PATCH 07/38] [FIX] Loading all updated rooms after app resume (#1998) * [FIX] Loading all updated rooms after app resume * Fix room date on RoomItem Co-authored-by: Diego Mello --- .../methods/helpers/findSubscriptionsRooms.js | 78 +++++++++++++++++++ .../helpers/mergeSubscriptionsRooms.js | 6 +- app/presentation/RoomItem/index.js | 2 +- app/sagas/rooms.js | 2 +- 4 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 app/lib/methods/helpers/findSubscriptionsRooms.js diff --git a/app/lib/methods/helpers/findSubscriptionsRooms.js b/app/lib/methods/helpers/findSubscriptionsRooms.js new file mode 100644 index 000000000..9773c5f7d --- /dev/null +++ b/app/lib/methods/helpers/findSubscriptionsRooms.js @@ -0,0 +1,78 @@ +import { Q } from '@nozbe/watermelondb'; + +import database from '../../database'; + +export default async(subscriptions = [], rooms = []) => { + try { + const db = database.active; + const subCollection = db.collections.get('subscriptions'); + + const roomIds = rooms.filter(r => !subscriptions.find(s => s.rid === r._id)).map(r => r._id); + let existingSubs = await subCollection.query(Q.where('rid', Q.oneOf(roomIds))).fetch(); + existingSubs = existingSubs.map(s => ({ + _id: s._id, + f: s.f, + t: s.t, + ts: s.ts, + ls: s.ls, + name: s.name, + fname: s.fname, + rid: s.rid, + open: s.open, + alert: s.alert, + unread: s.unread, + userMentions: s.userMentions, + roomUpdatedAt: s.roomUpdatedAt, + ro: s.ro, + lastOpen: s.lastOpen, + description: s.description, + announcement: s.announcement, + topic: s.topic, + blocked: s.blocked, + blocker: s.blocker, + reactWhenReadOnly: s.reactWhenReadOnly, + archived: s.archived, + joinCodeRequired: s.joinCodeRequired, + muted: s.muted, + broadcast: s.broadcast, + prid: s.prid, + draftMessage: s.draftMessage, + lastThreadSync: s.lastThreadSync, + jitsiTimeout: s.jitsiTimeout, + autoTranslate: s.autoTranslate, + autoTranslateLanguage: s.autoTranslateLanguage, + lastMessage: s.lastMessage, + usernames: s.usernames, + uids: s.uids + })); + subscriptions = subscriptions.concat(existingSubs); + + const subsIds = subscriptions.filter(s => !rooms.find(r => s.rid === r._id)).map(s => s._id); + let existingRooms = await subCollection.query(Q.where('id', Q.oneOf(subsIds))).fetch(); + existingRooms = existingRooms.map(r => ({ + _updatedAt: r._updatedAt, + lastMessage: r.lastMessage, + description: r.description, + topic: r.topic, + announcement: r.announcement, + reactWhenReadOnly: r.reactWhenReadOnly, + archived: r.archived, + joinCodeRequired: r.joinCodeRequired, + jitsiTimeout: r.jitsiTimeout, + usernames: r.usernames, + uids: r.uids, + ro: r.ro, + broadcast: r.broadcast, + muted: r.muted, + sysMes: r.sysMes + })); + rooms = rooms.concat(existingRooms); + } catch { + // do nothing + } + + return { + subscriptions, + rooms + }; +}; diff --git a/app/lib/methods/helpers/mergeSubscriptionsRooms.js b/app/lib/methods/helpers/mergeSubscriptionsRooms.js index ba26294ce..2ab12f652 100644 --- a/app/lib/methods/helpers/mergeSubscriptionsRooms.js +++ b/app/lib/methods/helpers/mergeSubscriptionsRooms.js @@ -1,6 +1,7 @@ import EJSON from 'ejson'; import normalizeMessage from './normalizeMessage'; +import findSubscriptionsRooms from './findSubscriptionsRooms'; // TODO: delete and update export const merge = (subscription, room) => { @@ -46,11 +47,14 @@ export const merge = (subscription, room) => { return subscription; }; -export default (subscriptions = [], rooms = []) => { +export default async(subscriptions = [], rooms = []) => { if (subscriptions.update) { subscriptions = subscriptions.update; rooms = rooms.update; } + + ({ subscriptions, rooms } = await findSubscriptionsRooms(subscriptions, rooms)); + return { subscriptions: subscriptions.map((s) => { const index = rooms.findIndex(({ _id }) => _id === s.rid); diff --git a/app/presentation/RoomItem/index.js b/app/presentation/RoomItem/index.js index a28bacdcb..dc39fe303 100644 --- a/app/presentation/RoomItem/index.js +++ b/app/presentation/RoomItem/index.js @@ -49,7 +49,7 @@ const RoomItem = React.memo(({ } }, [connected]); - const date = formatDate(_updatedAt); + const date = lastMessage && formatDate(lastMessage.ts); let accessibilityLabel = name; if (unread === 1) { diff --git a/app/sagas/rooms.js b/app/sagas/rooms.js index 02f989d54..1b5940d1a 100644 --- a/app/sagas/rooms.js +++ b/app/sagas/rooms.js @@ -41,7 +41,7 @@ const handleRoomsRequest = function* handleRoomsRequest({ params }) { ({ roomsUpdatedAt } = serverRecord); } const [subscriptionsResult, roomsResult] = yield RocketChat.getRooms(roomsUpdatedAt); - const { subscriptions } = mergeSubscriptionsRooms(subscriptionsResult, roomsResult); + const { subscriptions } = yield mergeSubscriptionsRooms(subscriptionsResult, roomsResult); const db = database.active; const subCollection = db.collections.get('subscriptions'); From c313a63d8a99d1d31baeac448eda569af729862e Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Mon, 6 Apr 2020 18:40:18 -0300 Subject: [PATCH 08/38] [FIX] Change notifications preferences (#2000) * [FIX] Change notifications preferences * [IMPROVEMENT] Picker View * [I18N] Translations * [FIX] Picker Selection * [FIX] List border * [FIX] Prevent crash * [FIX] Not-Pref tablet * [FIX] Use same style of LanguageView * [IMPROVEMENT] Send listItem title Co-authored-by: Diego Mello --- app/containers/Check.js | 3 +- app/containers/ListItem.js | 3 +- app/i18n/locales/en.js | 1 + app/i18n/locales/pt-BR.js | 1 + app/index.js | 6 ++ .../NotificationPreferencesView/index.js | 89 ++++++++++------- .../NotificationPreferencesView/styles.js | 3 - app/views/PickerView.js | 96 +++++++++++++++++++ 8 files changed, 160 insertions(+), 42 deletions(-) create mode 100644 app/views/PickerView.js diff --git a/app/containers/Check.js b/app/containers/Check.js index e3f4f5147..e9a6b73b8 100644 --- a/app/containers/Check.js +++ b/app/containers/Check.js @@ -13,9 +13,10 @@ const styles = StyleSheet.create({ } }); -const Check = React.memo(({ theme }) => ); +const Check = React.memo(({ theme, style }) => ); Check.propTypes = { + style: PropTypes.object, theme: PropTypes.string }; diff --git a/app/containers/ListItem.js b/app/containers/ListItem.js index faccf4c0b..6b7498dd8 100644 --- a/app/containers/ListItem.js +++ b/app/containers/ListItem.js @@ -52,7 +52,7 @@ const Button = React.memo(({ onPress, ...props }) => ( onPress(props.title)} style={{ backgroundColor: themes[props.theme].backgroundColor }} enabled={!props.disabled} theme={props.theme} @@ -89,6 +89,7 @@ Content.propTypes = { }; Button.propTypes = { + title: PropTypes.string, onPress: PropTypes.func, disabled: PropTypes.bool, theme: PropTypes.string diff --git a/app/i18n/locales/en.js b/app/i18n/locales/en.js index c4b925962..6b485ea72 100644 --- a/app/i18n/locales/en.js +++ b/app/i18n/locales/en.js @@ -414,6 +414,7 @@ export default { Select_Server: 'Select Server', Select_Users: 'Select Users', Select_a_Channel: 'Select a Channel', + Select_an_option: 'Select an option', Send: 'Send', Send_audio_message: 'Send audio message', Send_crash_report: 'Send crash report', diff --git a/app/i18n/locales/pt-BR.js b/app/i18n/locales/pt-BR.js index 78210f2df..5cd3fb3e1 100644 --- a/app/i18n/locales/pt-BR.js +++ b/app/i18n/locales/pt-BR.js @@ -377,6 +377,7 @@ export default { Select_Server: 'Selecionar Servidor', Select_Users: 'Selecionar Usuários', Select_a_Channel: 'Selecione um canal', + Select_an_option: 'Selecione uma opção', Send: 'Enviar', Send_audio_message: 'Enviar mensagem de áudio', Send_message: 'Enviar mensagem', diff --git a/app/index.js b/app/index.js index 9a10476b7..cbc099457 100644 --- a/app/index.js +++ b/app/index.js @@ -166,6 +166,9 @@ const ChatsStack = createStackNavigator({ NotificationPrefView: { getScreen: () => require('./views/NotificationPreferencesView').default }, + PickerView: { + getScreen: () => require('./views/PickerView').default + }, ...RoomRoutes }, { defaultNavigationOptions: defaultHeader, @@ -448,6 +451,9 @@ const RoomActionsStack = createStackNavigator({ }, AttachmentView: { getScreen: () => require('./views/AttachmentView').default + }, + PickerView: { + getScreen: () => require('./views/PickerView').default } }, { defaultNavigationOptions: defaultHeader, diff --git a/app/views/NotificationPreferencesView/index.js b/app/views/NotificationPreferencesView/index.js index b6f8790e5..52acad338 100644 --- a/app/views/NotificationPreferencesView/index.js +++ b/app/views/NotificationPreferencesView/index.js @@ -3,9 +3,9 @@ import { View, ScrollView, Switch, Text } from 'react-native'; import PropTypes from 'prop-types'; -import RNPickerSelect from 'react-native-picker-select'; import { SafeAreaView } from 'react-navigation'; +import database from '../../lib/database'; import { SWITCH_TRACK_COLOR, themes } from '../../constants/colors'; import StatusBar from '../../containers/StatusBar'; import ListItem from '../../containers/ListItem'; @@ -15,9 +15,9 @@ import scrollPersistTaps from '../../utils/scrollPersistTaps'; import styles from './styles'; import sharedStyles from '../Styles'; import RocketChat from '../../lib/rocketchat'; -import log from '../../utils/log'; import { withTheme } from '../../theme'; import { themedHeader } from '../../utils/navigation'; +import protectedFunction from '../../lib/methods/helpers/protectedFunction'; const SectionTitle = React.memo(({ title, theme }) => ( { - const params = { - [key]: value ? '1' : '0' - }; + saveNotificationSettings = async(key, value, params) => { + const { room } = this.state; + const db = database.active; + + await db.action(async() => { + await room.update(protectedFunction((r) => { + r[key] = value; + })); + }); + try { - await RocketChat.saveNotificationSettings(this.rid, params); - } catch (e) { - log(e); + const result = await RocketChat.saveNotificationSettings(this.rid, params); + if (result.success) { + return; + } + } catch { + // do nothing } + + await db.action(async() => { + await room.update(protectedFunction((r) => { + r[key] = room[key]; + })); + }); } - onValueChangePicker = async(key, value) => { - const params = { - [key]: value.toString() - }; - try { - await RocketChat.saveNotificationSettings(this.rid, params); - } catch (e) { - log(e); - } + onValueChangeSwitch = (key, value) => this.saveNotificationSettings(key, value, { [key]: value ? '1' : '0' }); + + onValueChangePicker = (key, value) => this.saveNotificationSettings(key, value, { [key]: value.toString() }); + + pickerSelection = (title, key) => { + const { room } = this.state; + const { navigation } = this.props; + navigation.navigate('PickerView', { + title, + data: OPTIONS[key], + value: room[key], + onChangeValue: value => this.onValueChangePicker(key, value) + }); } - renderPicker = (key) => { + renderPickerOption = (key) => { const { room } = this.state; const { theme } = this.props; - return ( - this.onValueChangePicker(key, value)} - items={OPTIONS[key]} - /> - ); + const text = room[key] ? OPTIONS[key].find(option => option.value === room[key]) : OPTIONS[key][0]; + return {text?.label}; } renderSwitch = (key) => { @@ -283,7 +292,8 @@ class NotificationPreferencesView extends React.Component { this.renderPicker('desktopNotifications')} + onPress={title => this.pickerSelection(title, 'desktopNotifications')} + right={() => this.renderPickerOption('desktopNotifications')} theme={theme} /> @@ -296,7 +306,8 @@ class NotificationPreferencesView extends React.Component { this.renderPicker('mobilePushNotifications')} + onPress={title => this.pickerSelection(title, 'mobilePushNotifications')} + right={() => this.renderPickerOption('mobilePushNotifications')} theme={theme} /> @@ -309,21 +320,24 @@ class NotificationPreferencesView extends React.Component { this.renderPicker('audioNotifications')} + onPress={title => this.pickerSelection(title, 'audioNotifications')} + right={() => this.renderPickerOption('audioNotifications')} theme={theme} /> this.renderPicker('audioNotificationValue')} + onPress={title => this.pickerSelection(title, 'audioNotificationValue')} + right={() => this.renderPickerOption('audioNotificationValue')} theme={theme} /> this.renderPicker('desktopNotificationDuration')} + onPress={title => this.pickerSelection(title, 'desktopNotificationDuration')} + right={() => this.renderPickerOption('desktopNotificationDuration')} theme={theme} /> @@ -335,7 +349,8 @@ class NotificationPreferencesView extends React.Component { this.renderPicker('emailNotifications')} + onPress={title => this.pickerSelection(title, 'emailNotifications')} + right={() => this.renderPickerOption('emailNotifications')} theme={theme} /> diff --git a/app/views/NotificationPreferencesView/styles.js b/app/views/NotificationPreferencesView/styles.js index 61b39cb6d..9b4c9e0e6 100644 --- a/app/views/NotificationPreferencesView/styles.js +++ b/app/views/NotificationPreferencesView/styles.js @@ -24,9 +24,6 @@ export default StyleSheet.create({ paddingVertical: 10, fontSize: 14 }, - viewContainer: { - justifyContent: 'center' - }, pickerText: { ...sharedStyles.textRegular, fontSize: 16 diff --git a/app/views/PickerView.js b/app/views/PickerView.js new file mode 100644 index 000000000..5a8c73f2a --- /dev/null +++ b/app/views/PickerView.js @@ -0,0 +1,96 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { FlatList, StyleSheet } from 'react-native'; + +import I18n from '../i18n'; +import { themedHeader } from '../utils/navigation'; +import { withTheme } from '../theme'; +import { themes } from '../constants/colors'; +import sharedStyles from './Styles'; + +import ListItem from '../containers/ListItem'; +import Check from '../containers/Check'; +import Separator from '../containers/Separator'; + +const styles = StyleSheet.create({ + check: { + marginHorizontal: 0 + } +}); + +const Item = React.memo(({ + item, + selected, + onItemPress, + theme +}) => ( + )} + onPress={onItemPress} + theme={theme} + /> +)); +Item.propTypes = { + item: PropTypes.object, + selected: PropTypes.bool, + onItemPress: PropTypes.func, + theme: PropTypes.string +}; + +class PickerView extends React.PureComponent { + static navigationOptions = ({ navigation, screenProps }) => ({ + title: navigation.getParam('title', I18n.t('Select_an_option')), + ...themedHeader(screenProps.theme) + }) + + static propTypes = { + navigation: PropTypes.object, + theme: PropTypes.string + } + + constructor(props) { + super(props); + const data = props.navigation.getParam('data', []); + const value = props.navigation.getParam('value'); + this.state = { data, value }; + } + + onChangeValue = (value) => { + const { navigation } = this.props; + const onChange = navigation.getParam('onChangeValue', () => {}); + onChange(value); + navigation.goBack(); + } + + render() { + const { data, value } = this.state; + const { theme } = this.props; + + return ( + item.value} + renderItem={({ item }) => ( + this.onChangeValue(item.value)} + /> + )} + ItemSeparatorComponent={() => } + contentContainerStyle={[ + sharedStyles.listContentContainer, + { + backgroundColor: themes[theme].auxiliaryBackground, + borderColor: themes[theme].separatorColor + } + ]} + style={{ backgroundColor: themes[theme].auxiliaryBackground }} + /> + ); + } +} + +export default withTheme(PickerView); From 46660572c3d50a01c371fbcce4dbe8505439bd5a Mon Sep 17 00:00:00 2001 From: Diego Mello Date: Mon, 6 Apr 2020 18:52:06 -0300 Subject: [PATCH 09/38] Bump version to 4.6.1 (#2001) --- android/app/build.gradle | 2 +- ios/RocketChatRN/Info.plist | 2 +- ios/ShareRocketChatRN/Info.plist | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 886b1f87e..8a335c4e2 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -138,7 +138,7 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion versionCode VERSIONCODE as Integer - versionName "4.6.0" + versionName "4.6.1" vectorDrawables.useSupportLibrary = true manifestPlaceholders = [BugsnagAPIKey: BugsnagAPIKey as String] } diff --git a/ios/RocketChatRN/Info.plist b/ios/RocketChatRN/Info.plist index 0d086fe1d..018499f57 100644 --- a/ios/RocketChatRN/Info.plist +++ b/ios/RocketChatRN/Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 4.6.0 + 4.6.1 CFBundleSignature ???? CFBundleURLTypes diff --git a/ios/ShareRocketChatRN/Info.plist b/ios/ShareRocketChatRN/Info.plist index b6538c764..676d0c728 100644 --- a/ios/ShareRocketChatRN/Info.plist +++ b/ios/ShareRocketChatRN/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType XPC! CFBundleShortVersionString - 4.6.0 + 4.6.1 CFBundleVersion 1 NSAppTransportSecurity From 2e65a795df604ddd684412d66cd36ce0170435bb Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Thu, 9 Apr 2020 02:20:57 -0300 Subject: [PATCH 10/38] [FIX] DM header blink (#2011) --- app/lib/methods/canOpenRoom.js | 11 +++++++++-- app/lib/rocketchat.js | 4 +++- app/sagas/deepLinking.js | 7 ++++++- app/views/RoomActionsView/index.js | 3 +-- app/views/RoomView/index.js | 4 ++-- app/views/RoomsListView/index.js | 5 +---- 6 files changed, 22 insertions(+), 12 deletions(-) diff --git a/app/lib/methods/canOpenRoom.js b/app/lib/methods/canOpenRoom.js index ab79d1cd3..1578837aa 100644 --- a/app/lib/methods/canOpenRoom.js +++ b/app/lib/methods/canOpenRoom.js @@ -61,8 +61,15 @@ export default async function canOpenRoom({ rid, path }) { if (rid) { try { - await subsCollection.find(rid); - return { rid }; + const room = await subsCollection.find(rid); + return { + rid, + t: room.t, + name: room.name, + fname: room.fname, + prid: room.prid, + uids: room.uids + }; } catch (e) { // Do nothing } diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index f0dbf2489..ced274270 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -812,7 +812,9 @@ const RocketChat = { return this.sdk.get('rooms.info', { roomId }); }, - getUidDirectMessage(room, userId) { + getUidDirectMessage(room) { + const { id: userId } = reduxStore.getState().login.user; + // legacy method if (!room.uids && room.rid && room.t === 'd') { return room.rid.replace(userId, '').trim(); diff --git a/app/sagas/deepLinking.js b/app/sagas/deepLinking.js index 86467d3e2..a5427ea4f 100644 --- a/app/sagas/deepLinking.js +++ b/app/sagas/deepLinking.js @@ -34,7 +34,12 @@ const navigate = function* navigate({ params }) { const [type, name] = params.path.split('/'); if (room) { yield Navigation.navigate('RoomsListView'); - Navigation.navigate('RoomView', { name, t: roomTypes[type], ...room }); + Navigation.navigate('RoomView', { + name, + t: roomTypes[type], + roomUserId: RocketChat.getUidDirectMessage(room), + ...room + }); } } else { yield handleInviteLink({ params }); diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index 7fe261a84..21dc281f0 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -384,11 +384,10 @@ class RoomActionsView extends React.Component { updateRoomMember = async() => { const { room } = this.state; - const { user } = this.props; try { if (!RocketChat.isGroupChat(room)) { - const roomUserId = RocketChat.getUidDirectMessage(room, user.id); + const roomUserId = RocketChat.getUidDirectMessage(room); const result = await RocketChat.getUserInfo(roomUserId); if (result.success) { this.setState({ member: result.user }); diff --git a/app/views/RoomView/index.js b/app/views/RoomView/index.js index 9774e020b..ce34d46e8 100644 --- a/app/views/RoomView/index.js +++ b/app/views/RoomView/index.js @@ -390,10 +390,10 @@ class RoomView extends React.Component { const { t } = room; if (t === 'd' && !RocketChat.isGroupChat(room)) { - const { user, navigation } = this.props; + const { navigation } = this.props; try { - const roomUserId = RocketChat.getUidDirectMessage(room, user.id); + const roomUserId = RocketChat.getUidDirectMessage(room); navigation.setParams({ roomUserId }); diff --git a/app/views/RoomsListView/index.js b/app/views/RoomsListView/index.js index 61f41d43c..84aa0027b 100644 --- a/app/views/RoomsListView/index.js +++ b/app/views/RoomsListView/index.js @@ -531,10 +531,7 @@ class RoomsListView extends React.Component { getUserPresence = uid => RocketChat.getUserPresence(uid) - getUidDirectMessage = (room) => { - const { user: { id } } = this.props; - return RocketChat.getUidDirectMessage(room, id); - } + getUidDirectMessage = room => RocketChat.getUidDirectMessage(room); goRoom = (item) => { const { navigation } = this.props; From 00a21808edbd32d2799a9287a7f4b8d6139591fa Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Thu, 9 Apr 2020 02:26:28 -0300 Subject: [PATCH 11/38] [FIX] Split get settings into two requests (#2017) * [FIX] Split get settings into two requests * [FIX] Clear settings only when change server * [IMPROVEMENT] Move the way to clear settings * [REVERT] Revert some changes * [FIX] Server Icon Co-authored-by: Diego Mello --- app/lib/methods/getSettings.js | 20 ++++++++++++++++++-- app/sagas/selectServer.js | 5 ++--- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/app/lib/methods/getSettings.js b/app/lib/methods/getSettings.js index 35cd20ade..0e13d378b 100644 --- a/app/lib/methods/getSettings.js +++ b/app/lib/methods/getSettings.js @@ -13,6 +13,22 @@ import fetch from '../../utils/fetch'; const serverInfoKeys = ['Site_Name', 'UI_Use_Real_Name', 'FileUpload_MediaTypeWhiteList', 'FileUpload_MaxFileSize']; +// these settings are used only on onboarding process +const loginSettings = [ + 'API_Gitlab_URL', + 'CAS_enabled', + 'CAS_login_url', + 'Accounts_EmailVerification', + 'Accounts_ManuallyApproveNewUsers', + 'Accounts_ShowFormLogin', + 'Site_Url', + 'Accounts_RegistrationForm', + 'Accounts_RegistrationForm_LinkReplacementText', + 'Accounts_EmailOrUsernamePlaceholder', + 'Accounts_PasswordPlaceholder', + 'Accounts_PasswordReset' +]; + const serverInfoUpdate = async(serverInfo, iconSetting) => { const serversDB = database.servers; const serverId = reduxStore.getState().server.server; @@ -54,7 +70,7 @@ const serverInfoUpdate = async(serverInfo, iconSetting) => { export async function getLoginSettings({ server }) { try { - const settingsParams = JSON.stringify(['Accounts_ShowFormLogin', 'Accounts_RegistrationForm']); + const settingsParams = JSON.stringify(loginSettings); const result = await fetch(`${ server }/api/v1/settings.public?query={"_id":{"$in":${ settingsParams }}}`).then(response => response.json()); if (result.success && result.settings.length) { @@ -84,7 +100,7 @@ export async function setSettings() { export default async function() { try { const db = database.active; - const settingsParams = JSON.stringify(Object.keys(settings)); + const settingsParams = JSON.stringify(Object.keys(settings).filter(key => !loginSettings.includes(key))); // RC 0.60.0 const result = await fetch(`${ this.sdk.client.host }/api/v1/settings.public?query={"_id":{"$in":${ settingsParams }}}`).then(response => response.json()); diff --git a/app/sagas/selectServer.js b/app/sagas/selectServer.js index ee2cfc7dd..ed26c4541 100644 --- a/app/sagas/selectServer.js +++ b/app/sagas/selectServer.js @@ -12,8 +12,8 @@ import * as actions from '../actions'; import { serverFailure, selectServerRequest, selectServerSuccess, selectServerFailure } from '../actions/server'; -import { setUser } from '../actions/login'; import { clearSettings } from '../actions/settings'; +import { setUser } from '../actions/login'; import RocketChat from '../lib/rocketchat'; import database from '../lib/database'; import log, { logServerVersion } from '../utils/log'; @@ -98,9 +98,8 @@ const handleSelectServer = function* handleSelectServer({ server, version, fetch const basicAuth = yield RNUserDefaults.get(`${ BASIC_AUTH_KEY }-${ server }`); setBasicAuth(basicAuth); - yield put(clearSettings()); - if (user) { + yield put(clearSettings()); yield RocketChat.connect({ server, user, logoutOnError: true }); yield put(setUser(user)); yield put(actions.appStart('inside')); From 1427e530bff6594f67af291c91919cda88d25f32 Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Thu, 9 Apr 2020 02:27:00 -0300 Subject: [PATCH 12/38] [REGRESSION] Invite Links (#2007) Co-authored-by: Diego Mello --- app/sagas/deepLinking.js | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/app/sagas/deepLinking.js b/app/sagas/deepLinking.js index a5427ea4f..86aa2df69 100644 --- a/app/sagas/deepLinking.js +++ b/app/sagas/deepLinking.js @@ -30,19 +30,21 @@ const handleInviteLink = function* handleInviteLink({ params, requireLogin = fal const navigate = function* navigate({ params }) { yield put(appStart('inside')); if (params.path) { - const room = yield RocketChat.canOpenRoom(params); const [type, name] = params.path.split('/'); - if (room) { - yield Navigation.navigate('RoomsListView'); - Navigation.navigate('RoomView', { - name, - t: roomTypes[type], - roomUserId: RocketChat.getUidDirectMessage(room), - ...room - }); + if (type !== 'invite') { + const room = yield RocketChat.canOpenRoom(params); + if (room) { + yield Navigation.navigate('RoomsListView'); + Navigation.navigate('RoomView', { + name, + t: roomTypes[type], + roomUserId: RocketChat.getUidDirectMessage(room), + ...room + }); + } + } else { + yield handleInviteLink({ params }); } - } else { - yield handleInviteLink({ params }); } }; From 404c381ca2cfe87b20856b474a4b0fdcfa2e3b6c Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Mon, 13 Apr 2020 09:51:16 -0300 Subject: [PATCH 13/38] [FIX] Read only channel/broadcast (#1951) * [FIX] Read only channel/broadcast * [FIX] Roles missing * [FIX] Check roles to readOnly * [FIX] Can post * [FIX] Respect post-readonly permission * [FIX] Search a room readOnly Co-authored-by: Diego Mello --- app/lib/database/index.js | 3 +- app/lib/methods/subscriptions/rooms.js | 1 + app/lib/rocketchat.js | 30 ++++++++++---- app/utils/room.js | 19 +++++++-- app/views/DirectoryView/index.js | 12 ++++-- app/views/RoomView/index.js | 55 ++++++++++++++++++++------ app/views/RoomsListView/index.js | 5 ++- app/views/ShareView/index.js | 23 ++++++++--- 8 files changed, 113 insertions(+), 35 deletions(-) diff --git a/app/lib/database/index.js b/app/lib/database/index.js index c17b18b21..67f1188ae 100644 --- a/app/lib/database/index.js +++ b/app/lib/database/index.js @@ -79,7 +79,8 @@ class DB { Message, Thread, ThreadMessage, - Upload + Upload, + Permission ], actionsEnabled: true }); diff --git a/app/lib/methods/subscriptions/rooms.js b/app/lib/methods/subscriptions/rooms.js index e954e6f14..d80f3dd84 100644 --- a/app/lib/methods/subscriptions/rooms.js +++ b/app/lib/methods/subscriptions/rooms.js @@ -72,6 +72,7 @@ const createOrUpdateSubscription = async(subscription, room) => { autoTranslate: s.autoTranslate, autoTranslateLanguage: s.autoTranslateLanguage, lastMessage: s.lastMessage, + roles: s.roles, usernames: s.usernames, uids: s.uids }; diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index ced274270..3f33071b5 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -289,14 +289,11 @@ const RocketChat = { user = { id: userRecord.id, token: userRecord.token, - username: userRecord.username + username: userRecord.username, + roles: userRecord.roles }; } - reduxStore.dispatch(shareSetUser({ - id: user.id, - token: user.token, - username: user.username - })); + reduxStore.dispatch(shareSetUser(user)); await RocketChat.login({ resume: user.token }); } catch (e) { log(e); @@ -308,6 +305,8 @@ const RocketChat = { this.shareSDK = null; } database.share = null; + + reduxStore.dispatch(shareSetUser(null)); }, updateJitsiTimeout(rid) { @@ -580,6 +579,19 @@ const RocketChat = { } data = data.slice(0, 7); + data = data.map((sub) => { + if (sub.t !== 'd') { + return ({ + rid: sub.rid, + name: sub.name, + fname: sub.fname, + t: sub.t, + search: true + }); + } + return sub; + }); + const usernames = data.map(sub => sub.name); try { if (data.length < 7) { @@ -951,7 +963,7 @@ const RocketChat = { // get the room from database const room = await subsCollection.find(rid); // get room roles - roomRoles = room.roles; + roomRoles = room.roles || []; } catch (error) { console.log('hasPermission -> Room not found'); return permissions.reduce((result, permission) => { @@ -962,8 +974,10 @@ const RocketChat = { // get permissions from database try { const permissionsFiltered = await permissionsCollection.query(Q.where('id', Q.oneOf(permissions))).fetch(); + const shareUser = reduxStore.getState().share.user; + const loginUser = reduxStore.getState().login.user; // get user roles on the server from redux - const userRoles = (reduxStore.getState().login.user && reduxStore.getState().login.user.roles) || []; + const userRoles = (shareUser.roles || loginUser.roles) || []; // merge both roles const mergedRoles = [...new Set([...roomRoles, ...userRoles])]; diff --git a/app/utils/room.js b/app/utils/room.js index 3131a6407..6a58c1e8f 100644 --- a/app/utils/room.js +++ b/app/utils/room.js @@ -1,13 +1,26 @@ import moment from 'moment'; import I18n from '../i18n'; +import RocketChat from '../lib/rocketchat'; -export const isOwner = room => room && room.roles && room.roles.length && !!room.roles.find(role => role === 'owner'); +export const canPost = async({ rid }) => { + try { + const permission = await RocketChat.hasPermission(['post-readonly'], rid); + return permission && permission['post-readonly']; + } catch { + // do nothing + } + return false; +}; export const isMuted = (room, user) => room && room.muted && room.muted.find && !!room.muted.find(m => m === user.username); -export const isReadOnly = (room, user) => { - if (isOwner(room)) { +export const isReadOnly = async(room, user) => { + if (room.archived) { + return true; + } + const allowPost = await canPost(room); + if (allowPost) { return false; } return (room && room.ro) || isMuted(room, user); diff --git a/app/views/DirectoryView/index.js b/app/views/DirectoryView/index.js index 3828a7474..180acde91 100644 --- a/app/views/DirectoryView/index.js +++ b/app/views/DirectoryView/index.js @@ -125,10 +125,14 @@ class DirectoryView extends React.Component { this.setState(({ showOptionsDropdown }) => ({ showOptionsDropdown: !showOptionsDropdown })); } - goRoom = async({ rid, name, t }) => { + goRoom = async({ + rid, name, t, search + }) => { const { navigation } = this.props; await navigation.navigate('RoomsListView'); - navigation.navigate('RoomView', { rid, name, t }); + navigation.navigate('RoomView', { + rid, name, t, search + }); } onPressItem = async(item) => { @@ -139,7 +143,9 @@ class DirectoryView extends React.Component { this.goRoom({ rid: result.room._id, name: item.username, t: 'd' }); } } else { - this.goRoom({ rid: item._id, name: item.name, t: 'c' }); + this.goRoom({ + rid: item._id, name: item.name, t: 'c', search: true + }); } } diff --git a/app/views/RoomView/index.js b/app/views/RoomView/index.js index ce34d46e8..001f33277 100644 --- a/app/views/RoomView/index.js +++ b/app/views/RoomView/index.js @@ -65,9 +65,10 @@ const stateAttrsUpdate = [ 'editing', 'replying', 'reacting', + 'readOnly', 'member' ]; -const roomAttrsUpdate = ['f', 'ro', 'blocked', 'blocker', 'archived', 'muted', 'jitsiTimeout', 'announcement', 'sysMes', 'topic', 'name', 'fname']; +const roomAttrsUpdate = ['f', 'ro', 'blocked', 'blocker', 'archived', 'muted', 'jitsiTimeout', 'announcement', 'sysMes', 'topic', 'name', 'fname', 'roles']; class RoomView extends React.Component { static navigationOptions = ({ navigation, screenProps }) => { @@ -164,6 +165,7 @@ class RoomView extends React.Component { const selectedMessage = props.navigation.getParam('message'); const name = props.navigation.getParam('name'); const fname = props.navigation.getParam('fname'); + const search = props.navigation.getParam('search'); const prid = props.navigation.getParam('prid'); this.state = { joined: true, @@ -183,7 +185,7 @@ class RoomView extends React.Component { replying: !!selectedMessage, replyWithMention: false, reacting: false, - announcement: null + readOnly: false }; if (room && room.observe) { @@ -192,6 +194,12 @@ class RoomView extends React.Component { this.findAndObserveRoom(this.rid); } + this.setReadOnly(); + + if (search) { + this.updateRoom(); + } + this.messagebox = React.createRef(); this.list = React.createRef(); this.mounted = false; @@ -278,6 +286,9 @@ class RoomView extends React.Component { if (roomUpdate.topic !== prevState.roomUpdate.topic) { navigation.setParams({ subtitle: roomUpdate.topic }); } + if (!isEqual(prevState.roomUpdate.roles, roomUpdate.roles)) { + this.setReadOnly(); + } } if (((roomUpdate.fname !== prevState.roomUpdate.fname) || (roomUpdate.name !== prevState.roomUpdate.name)) && !this.tmid) { navigation.setParams({ name: this.getRoomTitle(room) }); @@ -346,6 +357,32 @@ class RoomView extends React.Component { }); } + setReadOnly = async() => { + const { room } = this.state; + const { user } = this.props; + const readOnly = await isReadOnly(room, user); + this.setState({ readOnly }); + } + + updateRoom = async() => { + const db = database.active; + + try { + const subCollection = db.collections.get('subscriptions'); + const sub = await subCollection.find(this.rid); + + const { room } = await RocketChat.getRoomInfo(this.rid); + + await db.action(async() => { + await sub.update((s) => { + Object.assign(s, room); + }); + }); + } catch { + // do nothing + } + } + init = async() => { try { this.setState({ loading: true }); @@ -762,12 +799,6 @@ class RoomView extends React.Component { } } - get isReadOnly() { - const { room } = this.state; - const { user } = this.props; - return isReadOnly(room, user); - } - blockAction = ({ actionId, appId, value, blockId, rid, mid }) => RocketChat.triggerBlockAction({ @@ -855,7 +886,7 @@ class RoomView extends React.Component { renderFooter = () => { const { - joined, room, selectedMessage, editing, replying, replyWithMention + joined, room, selectedMessage, editing, replying, replyWithMention, readOnly } = this.state; const { navigation, theme } = this.props; @@ -876,7 +907,7 @@ class RoomView extends React.Component { ); } - if (this.isReadOnly || room.archived) { + if (readOnly) { return ( {I18n.t('This_room_is_read_only')} @@ -914,7 +945,7 @@ class RoomView extends React.Component { renderActions = () => { const { - room, selectedMessage, showActions, showErrorActions, joined + room, selectedMessage, showActions, showErrorActions, joined, readOnly } = this.state; const { user, navigation @@ -935,7 +966,7 @@ class RoomView extends React.Component { editInit={this.onEditInit} replyInit={this.onReplyInit} reactionInit={this.onReactionInit} - isReadOnly={this.isReadOnly} + isReadOnly={readOnly} /> ) : null diff --git a/app/views/RoomsListView/index.js b/app/views/RoomsListView/index.js index 84aa0027b..9cccdfc5b 100644 --- a/app/views/RoomsListView/index.js +++ b/app/views/RoomsListView/index.js @@ -542,8 +542,9 @@ class RoomsListView extends React.Component { name: this.getRoomTitle(item), t: item.t, prid: item.prid, - roomUserId: this.getUidDirectMessage(item), - room: item + room: item, + search: item.search, + roomUserId: this.getUidDirectMessage(item) }); } diff --git a/app/views/ShareView/index.js b/app/views/ShareView/index.js index f55523319..1582b3524 100644 --- a/app/views/ShareView/index.js +++ b/app/views/ShareView/index.js @@ -69,18 +69,29 @@ class ShareView extends React.Component { fileInfo, room, loading: false, + readOnly: false, file: { name: fileInfo ? fileInfo.name : '', description: '' } }; + + this.setReadOnly(); } componentDidMount() { + const { navigation } = this.props; + navigation.setParams({ sendMessage: this._sendMessage }); + } + + setReadOnly = async() => { const { room } = this.state; const { navigation, user } = this.props; const { username } = user; - navigation.setParams({ sendMessage: this._sendMessage, canSend: !(isReadOnly(room, { username }) || isBlocked(room)) }); + const readOnly = await isReadOnly(room, { username }); + + this.setState({ readOnly }); + navigation.setParams({ canSend: !(readOnly || isBlocked(room)) }); } bytesToSize = bytes => `${ (bytes / 1048576).toFixed(2) }MB`; @@ -237,8 +248,9 @@ class ShareView extends React.Component { renderError = () => { const { room } = this.state; + const { theme } = this.props; return ( - + { isBlocked(room) ? I18n.t('This_room_is_blocked') : I18n.t('This_room_is_read_only') @@ -249,13 +261,12 @@ class ShareView extends React.Component { } render() { - const { user, theme } = this.props; - const { username } = user; + const { theme } = this.props; const { - name, loading, isMedia, room + name, loading, isMedia, room, readOnly } = this.state; - if (isReadOnly(room, { username }) || isBlocked(room)) { + if (readOnly || isBlocked(room)) { return this.renderError(); } From acf70790cd739e15c455c7be859eed7b8aa1a65e Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Mon, 13 Apr 2020 10:11:51 -0300 Subject: [PATCH 14/38] [FIX] Cas auth (#2024) Co-authored-by: Diego Mello --- app/views/AuthenticationWebView.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/views/AuthenticationWebView.js b/app/views/AuthenticationWebView.js index 28de76a37..cf169cf98 100644 --- a/app/views/AuthenticationWebView.js +++ b/app/views/AuthenticationWebView.js @@ -80,7 +80,8 @@ class AuthenticationWebView extends React.PureComponent { const { navigation } = this.props; const ssoToken = navigation.getParam('ssoToken'); const parsedUrl = parse(url, true); - if (parsedUrl.pathname?.includes('ticket') || parsedUrl.pathname?.includes('validate') || parsedUrl.query?.saml_idp_credentialToken) { + // ticket -> cas / validate & saml_idp_credentialToken -> saml + if (parsedUrl.pathname?.includes('validate') || parsedUrl.query?.ticket || parsedUrl.query?.saml_idp_credentialToken) { let payload; if (this.authType === 'saml') { const token = parsedUrl.query?.saml_idp_credentialToken || ssoToken; From 2b3ccf4df57b9479928a19de8355938ded009cf4 Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Mon, 13 Apr 2020 10:25:31 -0300 Subject: [PATCH 15/38] [FIX] Login TOTP Compatibility to older servers (#2018) * [FIX] Login TOTP Compatibility to older servers * [FIX] Android crashes if use double negation Co-authored-by: Diego Mello --- app/containers/TwoFactor/index.js | 3 ++- app/containers/TwoFactor/styles.js | 3 ++- app/lib/rocketchat.js | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/containers/TwoFactor/index.js b/app/containers/TwoFactor/index.js index 9d1d9daab..3d1c9fe6d 100644 --- a/app/containers/TwoFactor/index.js +++ b/app/containers/TwoFactor/index.js @@ -48,6 +48,7 @@ const TwoFactor = React.memo(({ theme, split }) => { useDeepCompareEffect(() => { if (!_.isEmpty(data)) { + setCode(''); setVisible(true); } else { setVisible(false); @@ -94,7 +95,7 @@ const TwoFactor = React.memo(({ theme, split }) => { {I18n.t(method?.title || 'Two_Factor_Authentication')} - {I18n.t(method?.text)} + {method?.text ? {I18n.t(method.text)} : null} Date: Mon, 13 Apr 2020 10:26:59 -0300 Subject: [PATCH 16/38] Bump version to 4.6.4 (#2029) Co-authored-by: Diego Mello --- android/app/build.gradle | 2 +- ios/RocketChatRN/Info.plist | 2 +- ios/ShareRocketChatRN/Info.plist | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 8a335c4e2..89bd6bbdb 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -138,7 +138,7 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion versionCode VERSIONCODE as Integer - versionName "4.6.1" + versionName "4.6.4" vectorDrawables.useSupportLibrary = true manifestPlaceholders = [BugsnagAPIKey: BugsnagAPIKey as String] } diff --git a/ios/RocketChatRN/Info.plist b/ios/RocketChatRN/Info.plist index 018499f57..14d5d2666 100644 --- a/ios/RocketChatRN/Info.plist +++ b/ios/RocketChatRN/Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 4.6.1 + 4.6.4 CFBundleSignature ???? CFBundleURLTypes diff --git a/ios/ShareRocketChatRN/Info.plist b/ios/ShareRocketChatRN/Info.plist index 676d0c728..3a866bf68 100644 --- a/ios/ShareRocketChatRN/Info.plist +++ b/ios/ShareRocketChatRN/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType XPC! CFBundleShortVersionString - 4.6.1 + 4.6.4 CFBundleVersion 1 NSAppTransportSecurity From 8445bafad61ffc5751187e505c257543a694b15c Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Mon, 13 Apr 2020 10:56:30 -0300 Subject: [PATCH 17/38] [FIX] Lint (#2030) --- app/utils/isReadOnly.js | 24 ++++++++++++++++++++++++ app/utils/room.js | 24 ------------------------ app/views/RoomView/index.js | 3 ++- app/views/ShareView/index.js | 3 ++- 4 files changed, 28 insertions(+), 26 deletions(-) create mode 100644 app/utils/isReadOnly.js diff --git a/app/utils/isReadOnly.js b/app/utils/isReadOnly.js new file mode 100644 index 000000000..8a6f9c36f --- /dev/null +++ b/app/utils/isReadOnly.js @@ -0,0 +1,24 @@ +import RocketChat from '../lib/rocketchat'; + +const canPost = async({ rid }) => { + try { + const permission = await RocketChat.hasPermission(['post-readonly'], rid); + return permission && permission['post-readonly']; + } catch { + // do nothing + } + return false; +}; + +const isMuted = (room, user) => room && room.muted && room.muted.find && !!room.muted.find(m => m === user.username); + +export const isReadOnly = async(room, user) => { + if (room.archived) { + return true; + } + const allowPost = await canPost(room); + if (allowPost) { + return false; + } + return (room && room.ro) || isMuted(room, user); +}; diff --git a/app/utils/room.js b/app/utils/room.js index 6a58c1e8f..4775fa757 100644 --- a/app/utils/room.js +++ b/app/utils/room.js @@ -1,30 +1,6 @@ import moment from 'moment'; import I18n from '../i18n'; -import RocketChat from '../lib/rocketchat'; - -export const canPost = async({ rid }) => { - try { - const permission = await RocketChat.hasPermission(['post-readonly'], rid); - return permission && permission['post-readonly']; - } catch { - // do nothing - } - return false; -}; - -export const isMuted = (room, user) => room && room.muted && room.muted.find && !!room.muted.find(m => m === user.username); - -export const isReadOnly = async(room, user) => { - if (room.archived) { - return true; - } - const allowPost = await canPost(room); - if (allowPost) { - return false; - } - return (room && room.ro) || isMuted(room, user); -}; export const isBlocked = (room) => { if (room) { diff --git a/app/views/RoomView/index.js b/app/views/RoomView/index.js index 001f33277..341df6ce6 100644 --- a/app/views/RoomView/index.js +++ b/app/views/RoomView/index.js @@ -34,7 +34,8 @@ import { themes } from '../../constants/colors'; import debounce from '../../utils/debounce'; import ReactionsModal from '../../containers/ReactionsModal'; import { LISTENER } from '../../containers/Toast'; -import { isReadOnly, isBlocked } from '../../utils/room'; +import { isBlocked } from '../../utils/room'; +import { isReadOnly } from '../../utils/isReadOnly'; import { isIOS, isTablet } from '../../utils/deviceInfo'; import { showErrorAlert } from '../../utils/info'; import { withTheme } from '../../theme'; diff --git a/app/views/ShareView/index.js b/app/views/ShareView/index.js index 1582b3524..84889d272 100644 --- a/app/views/ShareView/index.js +++ b/app/views/ShareView/index.js @@ -13,7 +13,8 @@ import styles from './styles'; import TextInput from '../../containers/TextInput'; import ActivityIndicator from '../../containers/ActivityIndicator'; import { CustomHeaderButtons, Item } from '../../containers/HeaderButton'; -import { isReadOnly, isBlocked } from '../../utils/room'; +import { isBlocked } from '../../utils/room'; +import { isReadOnly } from '../../utils/isReadOnly'; import { withTheme } from '../../theme'; import { themedHeader } from '../../utils/navigation'; From 91ff6e48d5958b4d3bec7bc209d1aaabac7484f5 Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Mon, 13 Apr 2020 10:56:57 -0300 Subject: [PATCH 18/38] [FIX] UIKit with only one block (#2022) * [FIX] Message with only one block * [FIX] Update headers Co-authored-by: Diego Mello --- app/containers/message/Blocks.js | 3 +-- app/views/ModalBlockView.js | 12 +++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/app/containers/message/Blocks.js b/app/containers/message/Blocks.js index 76a5e273f..ba74ebe20 100644 --- a/app/containers/message/Blocks.js +++ b/app/containers/message/Blocks.js @@ -6,8 +6,7 @@ const Blocks = React.memo(({ blocks, id: mid, rid, blockAction }) => { if (blocks && blocks.length > 0) { - const [, secondBlock] = blocks; - const { appId = '' } = secondBlock; + const appId = blocks[0]?.appId || ''; return React.createElement( messageBlockWithContext({ action: async({ actionId, value, blockId }) => { diff --git a/app/views/ModalBlockView.js b/app/views/ModalBlockView.js index e00c84931..3c6314e2b 100644 --- a/app/views/ModalBlockView.js +++ b/app/views/ModalBlockView.js @@ -67,7 +67,7 @@ class ModalBlockView extends React.Component { return { title: textParser([title]), ...themedHeader(theme), - headerLeft: ( + headerLeft: close ? ( - ), - headerRight: ( + ) : null, + headerRight: submit ? ( - ) + ) : null }; } @@ -136,7 +136,7 @@ class ModalBlockView extends React.Component { const { navigation } = this.props; const oldData = prevProps.navigation.getParam('data', {}); const newData = navigation.getParam('data', {}); - if (!isEqual(oldData, newData)) { + if (oldData.viewId !== newData.viewId) { navigation.push('ModalBlockView', { data: newData }); } } @@ -148,12 +148,14 @@ class ModalBlockView extends React.Component { } handleUpdate = ({ type, ...data }) => { + const { navigation } = this.props; if ([MODAL_ACTIONS.ERRORS].includes(type)) { const { errors } = data; this.setState({ errors }); } else { this.setState({ data }); } + navigation.setParams({ data }); }; cancel = async({ closeModal }) => { From 5698701a14b886838150739a8bdd8ccf4409982a Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Tue, 14 Apr 2020 19:04:46 -0300 Subject: [PATCH 19/38] Bump version to 4.7.0 (#2035) --- android/app/build.gradle | 2 +- ios/RocketChatRN/Info.plist | 2 +- ios/ShareRocketChatRN/Info.plist | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 89bd6bbdb..44b16c639 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -138,7 +138,7 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion versionCode VERSIONCODE as Integer - versionName "4.6.4" + versionName "4.7.0" vectorDrawables.useSupportLibrary = true manifestPlaceholders = [BugsnagAPIKey: BugsnagAPIKey as String] } diff --git a/ios/RocketChatRN/Info.plist b/ios/RocketChatRN/Info.plist index 14d5d2666..486ef610d 100644 --- a/ios/RocketChatRN/Info.plist +++ b/ios/RocketChatRN/Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 4.6.4 + 4.7.0 CFBundleSignature ???? CFBundleURLTypes diff --git a/ios/ShareRocketChatRN/Info.plist b/ios/ShareRocketChatRN/Info.plist index 3a866bf68..d88f511bc 100644 --- a/ios/ShareRocketChatRN/Info.plist +++ b/ios/ShareRocketChatRN/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType XPC! CFBundleShortVersionString - 4.6.4 + 4.7.0 CFBundleVersion 1 NSAppTransportSecurity From e3cfcf7f5b9f4cab19c9a3660e2f05476d16577f Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Thu, 30 Apr 2020 13:00:39 -0300 Subject: [PATCH 20/38] [FIX] Action Tint Color on Black theme (#2081) --- app/constants/colors.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/constants/colors.js b/app/constants/colors.js index d38ac2cbf..ea465a5fa 100644 --- a/app/constants/colors.js +++ b/app/constants/colors.js @@ -100,7 +100,7 @@ export const themes = { infoText: '#6d6d72', tintColor: '#1e9bfe', auxiliaryTintColor: '#cdcdcd', - actionTintColor: '#1ea1fe', + actionTintColor: '#1e9bfe', separatorColor: '#272728', navbarBackground: '#0d0d0d', headerBorder: '#323232', From cce5efe6a9fa9380d81f6f2bae3451e3d8dcf7f0 Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Thu, 30 Apr 2020 13:01:36 -0300 Subject: [PATCH 21/38] [FIX] Prevent crash when thread is not found (#2080) Co-authored-by: Diego Mello --- app/views/RoomView/List.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/RoomView/List.js b/app/views/RoomView/List.js index 5ca13644b..8860b8de7 100644 --- a/app/views/RoomView/List.js +++ b/app/views/RoomView/List.js @@ -96,7 +96,7 @@ class List extends React.Component { this.messagesSubscription = this.messagesObservable .subscribe((data) => { this.interaction = InteractionManager.runAfterInteractions(() => { - if (tmid) { + if (tmid && this.thread) { data = [this.thread, ...data]; } const messages = orderBy(data, ['ts'], ['desc']); From f3b98c29c5791920b780e98823f6debf05c3070c Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Thu, 30 Apr 2020 13:03:07 -0300 Subject: [PATCH 22/38] [FIX] Prevent double click (#2079) Co-authored-by: Diego Mello --- app/views/RoomsListView/index.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/views/RoomsListView/index.js b/app/views/RoomsListView/index.js index 9cccdfc5b..719a43f58 100644 --- a/app/views/RoomsListView/index.js +++ b/app/views/RoomsListView/index.js @@ -549,6 +549,10 @@ class RoomsListView extends React.Component { } _onPressItem = async(item = {}) => { + const { navigation } = this.props; + if (!navigation.isFocused()) { + return; + } if (!item.search) { return this.goRoom(item); } From 6c2bc1c6358b60ff94a5e67327cde887f0d80d57 Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Thu, 30 Apr 2020 13:05:31 -0300 Subject: [PATCH 23/38] [FIX] Show slash commands when disconnected (#2078) Co-authored-by: Diego Mello --- app/containers/MessageBox/Mentions/MentionItem.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/containers/MessageBox/Mentions/MentionItem.js b/app/containers/MessageBox/Mentions/MentionItem.js index de4489b26..6a3505da2 100644 --- a/app/containers/MessageBox/Mentions/MentionItem.js +++ b/app/containers/MessageBox/Mentions/MentionItem.js @@ -64,7 +64,7 @@ const MentionItem = ({ content = ( <> / - { item.command} + {item.id} ); } From 8201602291c334a7c649eaaef9c7c87901389ad9 Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Thu, 30 Apr 2020 13:06:58 -0300 Subject: [PATCH 24/38] [FIX] Backhandler onboarding (#2077) Co-authored-by: Diego Mello --- app/views/NewServerView.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/app/views/NewServerView.js b/app/views/NewServerView.js index 38c3acbf5..edbbd15f0 100644 --- a/app/views/NewServerView.js +++ b/app/views/NewServerView.js @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { - Text, Keyboard, StyleSheet, TouchableOpacity, View, Alert + Text, Keyboard, StyleSheet, TouchableOpacity, View, Alert, BackHandler } from 'react-native'; import { connect } from 'react-redux'; import * as FileSystem from 'expo-file-system'; @@ -105,6 +105,7 @@ class NewServerView extends React.Component { certificate: null }; EventEmitter.addEventListener('NewServer', this.handleNewServerEvent); + BackHandler.addEventListener('hardwareBackPress', this.handleBackPress); } componentDidMount() { @@ -116,6 +117,16 @@ class NewServerView extends React.Component { componentWillUnmount() { EventEmitter.removeListener('NewServer', this.handleNewServerEvent); + BackHandler.removeEventListener('hardwareBackPress', this.handleBackPress); + } + + handleBackPress = () => { + const { navigation } = this.props; + if (navigation.isFocused() && this.previousServer) { + this.close(); + return true; + } + return false; } onChangeText = (text) => { From 200f94e2443cceebc8cb4a6c8505801ff5e1bfac Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Thu, 30 Apr 2020 13:24:49 -0300 Subject: [PATCH 25/38] [FIX] Respect UI_Allow_room_names_with_special_chars setting (#2076) Co-authored-by: Diego Mello --- app/constants/settings.js | 3 +++ app/lib/rocketchat.js | 5 ++++- app/views/RoomActionsView/index.js | 4 ++-- app/views/RoomInfoEditView/index.js | 4 ++-- app/views/RoomInfoView/index.js | 2 +- app/views/RoomView/index.js | 13 ++++--------- 6 files changed, 16 insertions(+), 15 deletions(-) diff --git a/app/constants/settings.js b/app/constants/settings.js index 5287367fb..0103fb58f 100644 --- a/app/constants/settings.js +++ b/app/constants/settings.js @@ -125,6 +125,9 @@ export default { uniqueID: { type: 'valueAsString' }, + UI_Allow_room_names_with_special_chars: { + type: 'valueAsBoolean' + }, UI_Use_Real_Name: { type: 'valueAsBoolean' }, diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index 9147eb97b..ad54ac35b 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -1226,11 +1226,14 @@ const RocketChat = { return this.methodCall('autoTranslate.translateMessage', message, targetLanguage); }, getRoomTitle(room) { - const { UI_Use_Real_Name: useRealName } = reduxStore.getState().settings; + const { UI_Use_Real_Name: useRealName, UI_Allow_room_names_with_special_chars: allowSpecialChars } = reduxStore.getState().settings; const { username } = reduxStore.getState().login.user; if (RocketChat.isGroupChat(room) && !(room.name && room.name.length)) { return room.usernames.filter(u => u !== username).sort((u1, u2) => u1.localeCompare(u2)).join(', '); } + if (allowSpecialChars && room.t !== 'd') { + return room.fname || room.name; + } return ((room.prid || useRealName) && room.fname) || room.name; }, getRoomAvatar(room) { diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index 21dc281f0..5e6a30f8e 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -442,7 +442,7 @@ class RoomActionsView extends React.Component { Alert.alert( I18n.t('Are_you_sure_question_mark'), - I18n.t('Are_you_sure_you_want_to_leave_the_room', { room: room.t === 'd' ? room.fname : room.name }), + I18n.t('Are_you_sure_you_want_to_leave_the_room', { room: RocketChat.getRoomTitle(room) }), [ { text: I18n.t('Cancel'), @@ -484,7 +484,7 @@ class RoomActionsView extends React.Component { : ( - {room.prid ? room.fname : room.name} + {RocketChat.getRoomTitle(room)} ) } diff --git a/app/views/RoomInfoEditView/index.js b/app/views/RoomInfoEditView/index.js index 63de0c02c..592ff8467 100644 --- a/app/views/RoomInfoEditView/index.js +++ b/app/views/RoomInfoEditView/index.js @@ -125,13 +125,13 @@ class RoomInfoEditView extends React.Component { init = (room) => { const { - name, description, topic, announcement, t, ro, reactWhenReadOnly, joinCodeRequired, sysMes + description, topic, announcement, t, ro, reactWhenReadOnly, joinCodeRequired, sysMes } = room; // fake password just to user knows about it this.randomValue = random(15); this.setState({ room, - name, + name: RocketChat.getRoomTitle(room), description, topic, announcement, diff --git a/app/views/RoomInfoView/index.js b/app/views/RoomInfoView/index.js index 184109ea7..1e1139f9a 100644 --- a/app/views/RoomInfoView/index.js +++ b/app/views/RoomInfoView/index.js @@ -36,7 +36,7 @@ const getRoomTitle = (room, type, name, username, statusText, theme) => (type == : ( - {room.prid ? room.fname : room.name} + {RocketChat.getRoomTitle(room)} ) ); diff --git a/app/views/RoomView/index.js b/app/views/RoomView/index.js index 341df6ce6..9599e0326 100644 --- a/app/views/RoomView/index.js +++ b/app/views/RoomView/index.js @@ -218,7 +218,7 @@ class RoomView extends React.Component { } = this.props; if ((room.id || room.rid) && !this.tmid) { navigation.setParams({ - name: this.getRoomTitle(room), + name: RocketChat.getRoomTitle(room), subtitle: room.topic, avatar: room.name, t: room.t, @@ -292,7 +292,7 @@ class RoomView extends React.Component { } } if (((roomUpdate.fname !== prevState.roomUpdate.fname) || (roomUpdate.name !== prevState.roomUpdate.name)) && !this.tmid) { - navigation.setParams({ name: this.getRoomTitle(room) }); + navigation.setParams({ name: RocketChat.getRoomTitle(room) }); } } @@ -456,7 +456,7 @@ class RoomView extends React.Component { this.setState({ room }); if (!this.tmid) { navigation.setParams({ - name: this.getRoomTitle(room), + name: RocketChat.getRoomTitle(room), subtitle: room.topic, avatar: room.name, t: room.t @@ -645,7 +645,7 @@ class RoomView extends React.Component { const { room } = this.state; if (rid === this.rid) { Navigation.navigate('RoomsListView'); - showErrorAlert(I18n.t('You_were_removed_from_channel', { channel: this.getRoomTitle(room) }), I18n.t('Oops')); + showErrorAlert(I18n.t('You_were_removed_from_channel', { channel: RocketChat.getRoomTitle(room) }), I18n.t('Oops')); } } @@ -667,11 +667,6 @@ class RoomView extends React.Component { }); }; - getRoomTitle = (room) => { - const { useRealName } = this.props; - return ((room.prid || useRealName) && room.fname) || room.name; - } - getMessages = () => { const { room } = this.state; if (room.lastOpen) { From 022b0330bf9dd4064addb9a3c7345e02383b9ade Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Thu, 30 Apr 2020 14:38:57 -0300 Subject: [PATCH 26/38] [FIX] RoomsList update sometimes isn't fired (#2071) Co-authored-by: Diego Mello --- app/views/RoomsListView/index.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/views/RoomsListView/index.js b/app/views/RoomsListView/index.js index 719a43f58..bb95377ef 100644 --- a/app/views/RoomsListView/index.js +++ b/app/views/RoomsListView/index.js @@ -212,13 +212,17 @@ class RoomsListView extends React.Component { this.willFocusListener = navigation.addListener('willFocus', () => { // Check if there were changes while not focused (it's set on sCU) if (this.shouldUpdate) { - // animateNextTransition(); this.forceUpdate(); this.shouldUpdate = false; } }); this.didFocusListener = navigation.addListener('didFocus', () => { this.animated = true; + // Check if there were changes while not focused (it's set on sCU) + if (this.shouldUpdate) { + this.forceUpdate(); + this.shouldUpdate = false; + } this.backHandler = BackHandler.addEventListener('hardwareBackPress', this.handleBackPress); }); this.willBlurListener = navigation.addListener('willBlur', () => { From 4e948f897c4e83b786f7466066e5ad2e08d31842 Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Thu, 30 Apr 2020 14:53:35 -0300 Subject: [PATCH 27/38] [IMPROVEMENT] Stop inserting last message as message object from rooms stream if room is focused (#2069) * [IMPROVEMENT] No insert last message if the room is focused * fix discussion/threads Co-authored-by: Diego Mello --- app/actions/actionsTypes.js | 2 +- app/actions/room.js | 14 ++++++++++++++ app/lib/methods/subscriptions/room.js | 5 +++++ app/lib/methods/subscriptions/rooms.js | 3 ++- app/reducers/room.js | 14 +++++++++++++- 5 files changed, 35 insertions(+), 3 deletions(-) diff --git a/app/actions/actionsTypes.js b/app/actions/actionsTypes.js index 33e202a56..13be7e6a0 100644 --- a/app/actions/actionsTypes.js +++ b/app/actions/actionsTypes.js @@ -31,7 +31,7 @@ export const ROOMS = createRequestTypes('ROOMS', [ 'OPEN_SEARCH_HEADER', 'CLOSE_SEARCH_HEADER' ]); -export const ROOM = createRequestTypes('ROOM', ['LEAVE', 'DELETE', 'REMOVED', 'USER_TYPING']); +export const ROOM = createRequestTypes('ROOM', ['SUBSCRIBE', 'UNSUBSCRIBE', 'LEAVE', 'DELETE', 'REMOVED', 'USER_TYPING']); export const APP = createRequestTypes('APP', ['START', 'READY', 'INIT', 'INIT_LOCAL_SETTINGS']); export const MESSAGES = createRequestTypes('MESSAGES', ['REPLY_BROADCAST']); export const CREATE_CHANNEL = createRequestTypes('CREATE_CHANNEL', [...defaultTypes]); diff --git a/app/actions/room.js b/app/actions/room.js index 76a37b656..3b3b213f2 100644 --- a/app/actions/room.js +++ b/app/actions/room.js @@ -1,5 +1,19 @@ import * as types from './actionsTypes'; +export function subscribeRoom(rid) { + return { + type: types.ROOM.SUBSCRIBE, + rid + }; +} + +export function unsubscribeRoom(rid) { + return { + type: types.ROOM.UNSUBSCRIBE, + rid + }; +} + export function leaveRoom(rid, t) { return { type: types.ROOM.LEAVE, diff --git a/app/lib/methods/subscriptions/room.js b/app/lib/methods/subscriptions/room.js index 507c36b09..f6df8b343 100644 --- a/app/lib/methods/subscriptions/room.js +++ b/app/lib/methods/subscriptions/room.js @@ -10,6 +10,7 @@ import reduxStore from '../../createStore'; import { addUserTyping, removeUserTyping, clearUserTyping } from '../../../actions/usersTyping'; import debounce from '../../../utils/debounce'; import RocketChat from '../../rocketchat'; +import { subscribeRoom, unsubscribeRoom } from '../../../actions/room'; const WINDOW_TIME = 1000; @@ -38,6 +39,8 @@ export default class RoomSubscription { if (!this.isAlive) { this.unsubscribe(); } + + reduxStore.dispatch(subscribeRoom(this.rid)); } unsubscribe = async() => { @@ -59,6 +62,8 @@ export default class RoomSubscription { if (this.timer) { clearTimeout(this.timer); } + + reduxStore.dispatch(unsubscribeRoom(this.rid)); } removeListener = async(promise) => { diff --git a/app/lib/methods/subscriptions/rooms.js b/app/lib/methods/subscriptions/rooms.js index d80f3dd84..85e0ac3a9 100644 --- a/app/lib/methods/subscriptions/rooms.js +++ b/app/lib/methods/subscriptions/rooms.js @@ -141,7 +141,8 @@ const createOrUpdateSubscription = async(subscription, room) => { } } - if (tmp.lastMessage) { + const { rooms } = store.getState().room; + if (tmp.lastMessage && !rooms.includes(tmp.rid)) { const lastMessage = buildMessage(tmp.lastMessage); const messagesCollection = db.collections.get('messages'); let messageRecord; diff --git a/app/reducers/room.js b/app/reducers/room.js index 6a34aa8d5..762905fea 100644 --- a/app/reducers/room.js +++ b/app/reducers/room.js @@ -2,11 +2,23 @@ import { ROOM } from '../actions/actionsTypes'; const initialState = { rid: null, - isDeleting: false + isDeleting: false, + rooms: [] }; export default function(state = initialState, action) { switch (action.type) { + case ROOM.SUBSCRIBE: + return { + ...state, + rooms: [action.rid, ...state.rooms] + }; + case ROOM.UNSUBSCRIBE: + return { + ...state, + rooms: state.rooms + .filter(room => room.rid === action.rid) + }; case ROOM.LEAVE: return { ...state, From a34929fb9b2eb4103382d07671d7024f59039d52 Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Thu, 30 Apr 2020 14:54:42 -0300 Subject: [PATCH 28/38] [FIX] Hide system messages (#2067) Co-authored-by: Diego Mello --- app/containers/UIKit/MultiSelect/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/containers/UIKit/MultiSelect/index.js b/app/containers/UIKit/MultiSelect/index.js index 6aa671a36..6cd584b1b 100644 --- a/app/containers/UIKit/MultiSelect/index.js +++ b/app/containers/UIKit/MultiSelect/index.js @@ -43,14 +43,14 @@ export const MultiSelect = React.memo(({ inputStyle, theme }) => { - const [selected, select] = useState(values || []); + const [selected, select] = useState(Array.isArray(values) ? values : []); const [open, setOpen] = useState(false); const [search, onSearchChange] = useState(''); const [currentValue, setCurrentValue] = useState(''); const [showContent, setShowContent] = useState(false); useEffect(() => { - if (values) { + if (Array.isArray(values)) { select(values); } }, [values]); From 56dc7243dd86bc175940ad0944386928878fcea2 Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Thu, 30 Apr 2020 15:04:39 -0300 Subject: [PATCH 29/38] [FIX] Pending update (#2066) Co-authored-by: Diego Mello --- app/lib/methods/subscriptions/room.js | 63 +++++++++++---------------- 1 file changed, 26 insertions(+), 37 deletions(-) diff --git a/app/lib/methods/subscriptions/room.js b/app/lib/methods/subscriptions/room.js index f6df8b343..8dfb45d01 100644 --- a/app/lib/methods/subscriptions/room.js +++ b/app/lib/methods/subscriptions/room.js @@ -160,22 +160,17 @@ export default class RoomSubscription { const msgCollection = db.collections.get('messages'); const threadsCollection = db.collections.get('threads'); const threadMessagesCollection = db.collections.get('thread_messages'); - let messageRecord; - let threadRecord; - let threadMessageRecord; // Create or update message try { - messageRecord = await msgCollection.find(message._id); - } catch (error) { - // Do nothing - } - if (messageRecord) { - const update = messageRecord.prepareUpdate((m) => { - Object.assign(m, message); - }); - this._messagesBatch[message._id] = update; - } else { + const messageRecord = await msgCollection.find(message._id); + if (!messageRecord._hasPendingUpdate) { + const update = messageRecord.prepareUpdate(protectedFunction((m) => { + Object.assign(m, message); + })); + this._messagesBatch[message._id] = update; + } + } catch { const create = msgCollection.prepareCreate(protectedFunction((m) => { m._raw = sanitizedRaw({ id: message._id }, msgCollection.schema); m.subscription.id = this.rid; @@ -187,17 +182,14 @@ export default class RoomSubscription { // Create or update thread if (message.tlm) { try { - threadRecord = await threadsCollection.find(message._id); - } catch (error) { - // Do nothing - } - - if (threadRecord) { - const updateThread = threadRecord.prepareUpdate(protectedFunction((t) => { - Object.assign(t, message); - })); - this._threadsBatch[message._id] = updateThread; - } else { + const threadRecord = await threadsCollection.find(message._id); + if (!threadRecord._hasPendingUpdate) { + const updateThread = threadRecord.prepareUpdate(protectedFunction((t) => { + Object.assign(t, message); + })); + this._threadsBatch[message._id] = updateThread; + } + } catch { const createThread = threadsCollection.prepareCreate(protectedFunction((t) => { t._raw = sanitizedRaw({ id: message._id }, threadsCollection.schema); t.subscription.id = this.rid; @@ -210,19 +202,16 @@ export default class RoomSubscription { // Create or update thread message if (message.tmid) { try { - threadMessageRecord = await threadMessagesCollection.find(message._id); - } catch (error) { - // Do nothing - } - - if (threadMessageRecord) { - const updateThreadMessage = threadMessageRecord.prepareUpdate(protectedFunction((tm) => { - Object.assign(tm, message); - tm.rid = message.tmid; - delete tm.tmid; - })); - this._threadMessagesBatch[message._id] = updateThreadMessage; - } else { + const threadMessageRecord = await threadMessagesCollection.find(message._id); + if (!threadMessageRecord._hasPendingUpdate) { + const updateThreadMessage = threadMessageRecord.prepareUpdate(protectedFunction((tm) => { + Object.assign(tm, message); + tm.rid = message.tmid; + delete tm.tmid; + })); + this._threadMessagesBatch[message._id] = updateThreadMessage; + } + } catch { const createThreadMessage = threadMessagesCollection.prepareCreate(protectedFunction((tm) => { tm._raw = sanitizedRaw({ id: message._id }, threadMessagesCollection.schema); Object.assign(tm, message); From 3f79ab79538274ac4d0029cef6257696722b28fc Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Thu, 30 Apr 2020 15:07:07 -0300 Subject: [PATCH 30/38] [FIX] Prevent crash when room.uids was not inserted yet (#2055) Co-authored-by: Diego Mello --- app/lib/rocketchat.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index ad54ac35b..52e8f6236 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -1238,7 +1238,7 @@ const RocketChat = { }, getRoomAvatar(room) { if (RocketChat.isGroupChat(room)) { - return room.uids.length + room.usernames.join(); + return room.uids?.length + room.usernames?.join(); } return room.prid ? room.fname : room.name; }, From 25b5c95775013e6a3153d6fa0c2ef61a5fbf94a6 Mon Sep 17 00:00:00 2001 From: Prateek Jain Date: Thu, 30 Apr 2020 23:38:48 +0530 Subject: [PATCH 31/38] [FEATURE] Save video (#2063) * added-feature-save-video * fix sha256 Co-authored-by: Djorkaeff Alexandre Co-authored-by: Diego Mello --- app/i18n/locales/en.js | 1 + app/views/AttachmentView.js | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/app/i18n/locales/en.js b/app/i18n/locales/en.js index 6b485ea72..e89b9df7b 100644 --- a/app/i18n/locales/en.js +++ b/app/i18n/locales/en.js @@ -18,6 +18,7 @@ export default { 'error-email-domain-blacklisted': 'The email domain is blacklisted', 'error-email-send-failed': 'Error trying to send email: {{message}}', 'error-save-image': 'Error while saving image', + 'error-save-video': 'Error while saving video', 'error-field-unavailable': '{{field}} is already in use :(', 'error-file-too-large': 'File is too large', 'error-importer-not-defined': 'The importer was not defined correctly, it is missing the Import class.', diff --git a/app/views/AttachmentView.js b/app/views/AttachmentView.js index 51646896e..c94a8e84b 100644 --- a/app/views/AttachmentView.js +++ b/app/views/AttachmentView.js @@ -33,11 +33,11 @@ class AttachmentView extends React.Component { const attachment = navigation.getParam('attachment'); const from = navigation.getParam('from'); const handleSave = navigation.getParam('handleSave', () => {}); - const { title, video_url } = attachment; + const { title } = attachment; const options = { title, ...themedHeader(theme), - headerRight: !video_url ? : null + headerRight: }; if (from !== 'MessagesView') { options.gesturesEnabled = false; @@ -84,8 +84,11 @@ class AttachmentView extends React.Component { handleSave = async() => { const { attachment } = this.state; const { user, baseUrl } = this.props; - const { image_url, image_type } = attachment; - const img = formatAttachmentUrl(image_url, user.id, user.token, baseUrl); + const { + image_url, image_type, video_url, video_type + } = attachment; + const url = image_url || video_url; + const mediaAttachment = formatAttachmentUrl(url, user.id, user.token, baseUrl); if (isAndroid) { const rationale = { @@ -100,13 +103,13 @@ class AttachmentView extends React.Component { this.setState({ loading: true }); try { - const extension = `.${ mime.extension(image_type) || 'jpg' }`; - const file = `${ FileSystem.documentDirectory + SHA256(image_url) + extension }`; - const { uri } = await FileSystem.downloadAsync(img, file); + const extension = image_url ? `.${ mime.extension(image_type) || 'jpg' }` : `.${ mime.extension(video_type) || 'mp4' }`; + const file = `${ FileSystem.documentDirectory + SHA256(url) + extension }`; + const { uri } = await FileSystem.downloadAsync(mediaAttachment, file); await CameraRoll.save(uri, { album: 'Rocket.Chat' }); EventEmitter.emit(LISTENER, { message: I18n.t('saved_to_gallery') }); } catch (e) { - EventEmitter.emit(LISTENER, { message: I18n.t('error-save-image') }); + EventEmitter.emit(LISTENER, { message: I18n.t(image_url ? 'error-save-image' : 'error-save-video') }); } this.setState({ loading: false }); }; From c4a749c2e54388dcf8efd40b6c90975f28439f4d Mon Sep 17 00:00:00 2001 From: Prateek Jain Date: Thu, 30 Apr 2020 23:39:17 +0530 Subject: [PATCH 32/38] [FIX] Send totp-code to meteor call (#2050) * fixed-issue * removed-variable-name-errors * reverted-last-commit Co-authored-by: Diego Mello --- app/lib/rocketchat.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index 52e8f6236..5333f28e3 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -909,7 +909,7 @@ const RocketChat = { methodCall(...args) { return new Promise(async(resolve, reject) => { try { - const result = await this.sdk.methodCall(...args, this.code); + const result = await this.sdk.methodCall(...args, this.code || ''); return resolve(result); } catch (e) { if (e.error && (e.error === 'totp-required' || e.error === 'totp-invalid')) { From a52056988e55f7e5076a6df3b2af88ab45bcb705 Mon Sep 17 00:00:00 2001 From: Prateek Jain Date: Thu, 30 Apr 2020 23:40:19 +0530 Subject: [PATCH 33/38] [FIX] MessageBox mention shouldn't show group DMs (#2049) * fixed-issue * [FIX] Filter users only if it's not a group chat Co-authored-by: Djorkaeff Alexandre Co-authored-by: Diego Mello --- app/lib/rocketchat.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index 5333f28e3..098717d26 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -573,9 +573,9 @@ const RocketChat = { ).fetch(); if (filterUsers && !filterRooms) { - data = data.filter(item => item.t === 'd'); + data = data.filter(item => item.t === 'd' && !RocketChat.isGroupChat(item)); } else if (!filterUsers && filterRooms) { - data = data.filter(item => item.t !== 'd'); + data = data.filter(item => item.t !== 'd' || RocketChat.isGroupChat(item)); } data = data.slice(0, 7); From 6d80f147ac16ab738b3c6f0eb7a8ec7fdb86301c Mon Sep 17 00:00:00 2001 From: Siddharth Padhi Date: Thu, 30 Apr 2020 23:41:34 +0530 Subject: [PATCH 34/38] [FIX] AttachmentView (Android)(Tablet) (#2047) * [fix]Tablet attachment View and Room Navigation * fix weird navigation and margin bottom Co-authored-by: Djorkaeff Alexandre Co-authored-by: Diego Mello --- app/index.js | 4 +-- app/views/RoomActionsView/index.js | 48 ++++++++++++++++-------------- 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/app/index.js b/app/index.js index cbc099457..832729a62 100644 --- a/app/index.js +++ b/app/index.js @@ -514,7 +514,7 @@ class CustomModalStack extends React.Component { const pageSheetViews = ['AttachmentView']; const pageSheet = pageSheetViews.includes(getActiveRouteName(navigation.state)); - const androidProps = isAndroid && { + const androidProps = isAndroid && !pageSheet && { style: { marginBottom: 0 } }; @@ -524,7 +524,7 @@ class CustomModalStack extends React.Component { ); - if (isAndroid) { + if (isAndroid && !pageSheet) { content = ( {content} diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index 5e6a30f8e..08fa24aaa 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -87,35 +87,37 @@ class RoomActionsView extends React.Component { async componentDidMount() { this.mounted = true; const { room, member } = this.state; - if (!room.id) { - try { - const result = await RocketChat.getChannelInfo(room.rid); - if (result.success) { - this.setState({ room: { ...result.channel, rid: result.channel._id } }); + if (room.rid) { + if (!room.id) { + try { + const result = await RocketChat.getChannelInfo(room.rid); + if (result.success) { + this.setState({ room: { ...result.channel, rid: result.channel._id } }); + } + } catch (e) { + log(e); } - } catch (e) { - log(e); } - } - if (room && room.t !== 'd' && this.canViewMembers()) { - try { - const counters = await RocketChat.getRoomCounters(room.rid, room.t); - if (counters.success) { - this.setState({ membersCount: counters.members, joined: counters.joined }); + if (room && room.t !== 'd' && this.canViewMembers()) { + try { + const counters = await RocketChat.getRoomCounters(room.rid, room.t); + if (counters.success) { + this.setState({ membersCount: counters.members, joined: counters.joined }); + } + } catch (e) { + log(e); } - } catch (e) { - log(e); + } else if (room.t === 'd' && _.isEmpty(member)) { + this.updateRoomMember(); } - } else if (room.t === 'd' && _.isEmpty(member)) { - this.updateRoomMember(); + + const canAutoTranslate = await RocketChat.canAutoTranslate(); + this.setState({ canAutoTranslate }); + + this.canAddUser(); + this.canInviteUser(); } - - const canAutoTranslate = await RocketChat.canAutoTranslate(); - this.setState({ canAutoTranslate }); - - this.canAddUser(); - this.canInviteUser(); } componentWillUnmount() { From 2b9c447fe470f9e08ccd18d174ee04fca8fa77cb Mon Sep 17 00:00:00 2001 From: Prateek Jain Date: Thu, 30 Apr 2020 23:50:29 +0530 Subject: [PATCH 35/38] [FIX] Allow special chars in Filename (#2020) * fixed-filename-issue * improve Co-authored-by: Djorkaeff Alexandre Co-authored-by: Diego Mello --- app/lib/methods/sendFileMessage.js | 2 +- app/views/AttachmentView.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/lib/methods/sendFileMessage.js b/app/lib/methods/sendFileMessage.js index b5a85c4cc..041b1f40c 100644 --- a/app/lib/methods/sendFileMessage.js +++ b/app/lib/methods/sendFileMessage.js @@ -62,7 +62,7 @@ export function sendFileMessage(rid, fileInfo, tmid, server, user) { formData.append('file', { uri: fileInfo.path, type: fileInfo.type, - name: fileInfo.name || 'fileMessage' + name: encodeURI(fileInfo.name) || 'fileMessage' }); if (fileInfo.description) { diff --git a/app/views/AttachmentView.js b/app/views/AttachmentView.js index c94a8e84b..9f23833e3 100644 --- a/app/views/AttachmentView.js +++ b/app/views/AttachmentView.js @@ -35,7 +35,7 @@ class AttachmentView extends React.Component { const handleSave = navigation.getParam('handleSave', () => {}); const { title } = attachment; const options = { - title, + title: decodeURI(title), ...themedHeader(theme), headerRight: }; From 2ea6d34fd1b4c8b6178ab455d09e85e041ac61e1 Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Thu, 30 Apr 2020 15:54:27 -0300 Subject: [PATCH 36/38] [FIX] Recorded audio on Android doesn't play on iOS (#2073) * react-native-video -> expo-av * remove react-native-video * Add audio mode * update mocks * [FIX] Loading bigger than play/pause Co-authored-by: Diego Mello --- __mocks__/expo-av.js | 14 + .../__snapshots__/Storyshots.test.js.snap | 4 - app/containers/MessageBox/Recording.js | 3 +- app/containers/message/Audio.js | 135 +- ios/Podfile.lock | 14 +- .../SocketRocket/NSRunLoop+SRWebSocket.h | 1 + .../NSRunLoop+SRWebSocketPrivate.h | 1 + .../SocketRocket/NSURLRequest+SRWebSocket.h | 1 + .../NSURLRequest+SRWebSocketPrivate.h | 1 + .../Private/SocketRocket/SRConstants.h | 1 + .../SocketRocket/SRDelegateController.h | 1 + .../Headers/Private/SocketRocket/SRError.h | 1 + .../SocketRocket/SRHTTPConnectMessage.h | 1 + .../Headers/Private/SocketRocket/SRHash.h | 1 + .../Private/SocketRocket/SRIOConsumer.h | 1 + .../Private/SocketRocket/SRIOConsumerPool.h | 1 + ios/Pods/Headers/Private/SocketRocket/SRLog.h | 1 + .../Headers/Private/SocketRocket/SRMutex.h | 1 + .../SocketRocket/SRPinningSecurityPolicy.h | 1 + .../Private/SocketRocket/SRProxyConnect.h | 1 + .../Headers/Private/SocketRocket/SRRandom.h | 1 + .../Private/SocketRocket/SRRunLoopThread.h | 1 + .../Private/SocketRocket/SRSIMDHelpers.h | 1 + .../Private/SocketRocket/SRSecurityPolicy.h | 1 + .../Private/SocketRocket/SRURLUtilities.h | 1 + .../Private/SocketRocket/SRWebSocket.h | 1 + .../Private/SocketRocket/SocketRocket.h | 1 + .../Private/react-native-video/RCTVideo.h | 1 - .../react-native-video/RCTVideoManager.h | 1 - .../RCTVideoPlayerViewController.h | 1 - .../RCTVideoPlayerViewControllerDelegate.h | 1 - .../UIView+FindUIViewController.h | 1 - .../SocketRocket/NSRunLoop+SRWebSocket.h | 1 + .../SocketRocket/NSURLRequest+SRWebSocket.h | 1 + .../Public/SocketRocket/SRSecurityPolicy.h | 1 + .../Headers/Public/SocketRocket/SRWebSocket.h | 1 + .../Public/SocketRocket/SocketRocket.h | 1 + .../Public/react-native-video/RCTVideo.h | 1 - .../react-native-video/RCTVideoManager.h | 1 - .../RCTVideoPlayerViewController.h | 1 - .../RCTVideoPlayerViewControllerDelegate.h | 1 - .../UIView+FindUIViewController.h | 1 - ...actNativeKeyboardTrackingView.podspec.json | 24 + ios/Pods/Manifest.lock | 14 +- ios/Pods/Pods.xcodeproj/project.pbxproj | 16923 ++++++++-------- ...ods-RocketChatRN-acknowledgements.markdown | 58 +- .../Pods-RocketChatRN-acknowledgements.plist | 70 +- .../Pods-RocketChatRN.debug.xcconfig | 6 +- .../Pods-RocketChatRN.release.xcconfig | 6 +- ...hareRocketChatRN-acknowledgements.markdown | 58 +- ...s-ShareRocketChatRN-acknowledgements.plist | 70 +- .../Pods-ShareRocketChatRN.debug.xcconfig | 6 +- .../Pods-ShareRocketChatRN.release.xcconfig | 6 +- .../SocketRocket/SocketRocket-dummy.m | 5 + .../SocketRocket-prefix.pch} | 0 .../SocketRocket/SocketRocket.xcconfig | 11 + .../react-native-video-dummy.m | 5 - .../react-native-video.xcconfig | 11 - package.json | 1 - yarn.lock | 19 - 60 files changed, 8898 insertions(+), 8602 deletions(-) create mode 100644 __mocks__/expo-av.js create mode 120000 ios/Pods/Headers/Private/SocketRocket/NSRunLoop+SRWebSocket.h create mode 120000 ios/Pods/Headers/Private/SocketRocket/NSRunLoop+SRWebSocketPrivate.h create mode 120000 ios/Pods/Headers/Private/SocketRocket/NSURLRequest+SRWebSocket.h create mode 120000 ios/Pods/Headers/Private/SocketRocket/NSURLRequest+SRWebSocketPrivate.h create mode 120000 ios/Pods/Headers/Private/SocketRocket/SRConstants.h create mode 120000 ios/Pods/Headers/Private/SocketRocket/SRDelegateController.h create mode 120000 ios/Pods/Headers/Private/SocketRocket/SRError.h create mode 120000 ios/Pods/Headers/Private/SocketRocket/SRHTTPConnectMessage.h create mode 120000 ios/Pods/Headers/Private/SocketRocket/SRHash.h create mode 120000 ios/Pods/Headers/Private/SocketRocket/SRIOConsumer.h create mode 120000 ios/Pods/Headers/Private/SocketRocket/SRIOConsumerPool.h create mode 120000 ios/Pods/Headers/Private/SocketRocket/SRLog.h create mode 120000 ios/Pods/Headers/Private/SocketRocket/SRMutex.h create mode 120000 ios/Pods/Headers/Private/SocketRocket/SRPinningSecurityPolicy.h create mode 120000 ios/Pods/Headers/Private/SocketRocket/SRProxyConnect.h create mode 120000 ios/Pods/Headers/Private/SocketRocket/SRRandom.h create mode 120000 ios/Pods/Headers/Private/SocketRocket/SRRunLoopThread.h create mode 120000 ios/Pods/Headers/Private/SocketRocket/SRSIMDHelpers.h create mode 120000 ios/Pods/Headers/Private/SocketRocket/SRSecurityPolicy.h create mode 120000 ios/Pods/Headers/Private/SocketRocket/SRURLUtilities.h create mode 120000 ios/Pods/Headers/Private/SocketRocket/SRWebSocket.h create mode 120000 ios/Pods/Headers/Private/SocketRocket/SocketRocket.h delete mode 120000 ios/Pods/Headers/Private/react-native-video/RCTVideo.h delete mode 120000 ios/Pods/Headers/Private/react-native-video/RCTVideoManager.h delete mode 120000 ios/Pods/Headers/Private/react-native-video/RCTVideoPlayerViewController.h delete mode 120000 ios/Pods/Headers/Private/react-native-video/RCTVideoPlayerViewControllerDelegate.h delete mode 120000 ios/Pods/Headers/Private/react-native-video/UIView+FindUIViewController.h create mode 120000 ios/Pods/Headers/Public/SocketRocket/NSRunLoop+SRWebSocket.h create mode 120000 ios/Pods/Headers/Public/SocketRocket/NSURLRequest+SRWebSocket.h create mode 120000 ios/Pods/Headers/Public/SocketRocket/SRSecurityPolicy.h create mode 120000 ios/Pods/Headers/Public/SocketRocket/SRWebSocket.h create mode 120000 ios/Pods/Headers/Public/SocketRocket/SocketRocket.h delete mode 120000 ios/Pods/Headers/Public/react-native-video/RCTVideo.h delete mode 120000 ios/Pods/Headers/Public/react-native-video/RCTVideoManager.h delete mode 120000 ios/Pods/Headers/Public/react-native-video/RCTVideoPlayerViewController.h delete mode 120000 ios/Pods/Headers/Public/react-native-video/RCTVideoPlayerViewControllerDelegate.h delete mode 120000 ios/Pods/Headers/Public/react-native-video/UIView+FindUIViewController.h create mode 100644 ios/Pods/Local Podspecs/ReactNativeKeyboardTrackingView.podspec.json create mode 100644 ios/Pods/Target Support Files/SocketRocket/SocketRocket-dummy.m rename ios/Pods/Target Support Files/{react-native-video/react-native-video-prefix.pch => SocketRocket/SocketRocket-prefix.pch} (100%) create mode 100644 ios/Pods/Target Support Files/SocketRocket/SocketRocket.xcconfig delete mode 100644 ios/Pods/Target Support Files/react-native-video/react-native-video-dummy.m delete mode 100644 ios/Pods/Target Support Files/react-native-video/react-native-video.xcconfig diff --git a/__mocks__/expo-av.js b/__mocks__/expo-av.js new file mode 100644 index 000000000..e20feac67 --- /dev/null +++ b/__mocks__/expo-av.js @@ -0,0 +1,14 @@ +export class Sound { + loadAsync = () => {}; + + playAsync = () => {}; + + pauseAsync = () => {}; + + stopAsync = () => {}; + + setOnPlaybackStatusUpdate = () => {}; + + setPositionAsync = () => {}; +} +export const Audio = { Sound }; diff --git a/__tests__/__snapshots__/Storyshots.test.js.snap b/__tests__/__snapshots__/Storyshots.test.js.snap index 2fa6d1061..b9950e32d 100644 --- a/__tests__/__snapshots__/Storyshots.test.js.snap +++ b/__tests__/__snapshots__/Storyshots.test.js.snap @@ -16315,7 +16315,6 @@ exports[`Storyshots Message list message 1`] = ` ] } > - View - View - View - View { diff --git a/app/containers/message/Audio.js b/app/containers/message/Audio.js index 6ca5ce14c..83ac45ea7 100644 --- a/app/containers/message/Audio.js +++ b/app/containers/message/Audio.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import { View, StyleSheet, Text, Easing, Dimensions } from 'react-native'; -import Video from 'react-native-video'; +import { Audio } from 'expo-av'; import Slider from '@react-native-community/slider'; import moment from 'moment'; import equal from 'deep-equal'; @@ -15,6 +15,17 @@ import sharedStyles from '../../views/Styles'; import { themes } from '../../constants/colors'; import { isAndroid, isIOS } from '../../utils/deviceInfo'; import { withSplit } from '../../split'; +import ActivityIndicator from '../ActivityIndicator'; + +const mode = { + allowsRecordingIOS: false, + playsInSilentModeIOS: true, + staysActiveInBackground: false, + shouldDuckAndroid: true, + playThroughEarpieceAndroid: false, + interruptionModeIOS: Audio.INTERRUPTION_MODE_IOS_DO_NOT_MIX, + interruptionModeAndroid: Audio.INTERRUPTION_MODE_ANDROID_DO_NOT_MIX +}; const styles = StyleSheet.create({ audioContainer: { @@ -31,6 +42,9 @@ const styles = StyleSheet.create({ alignItems: 'center', backgroundColor: 'transparent' }, + audioLoading: { + marginHorizontal: 8 + }, slider: { flex: 1 }, @@ -51,25 +65,32 @@ const sliderAnimationConfig = { delay: 0 }; -const Button = React.memo(({ paused, onPress, theme }) => ( +const Button = React.memo(({ + loading, paused, onPress, theme +}) => ( - + { + loading + ? + : + } )); Button.propTypes = { + loading: PropTypes.bool, paused: PropTypes.bool, theme: PropTypes.string, onPress: PropTypes.func }; Button.displayName = 'MessageAudioButton'; -class Audio extends React.Component { +class MessageAudio extends React.Component { static propTypes = { file: PropTypes.object.isRequired, baseUrl: PropTypes.string.isRequired, @@ -83,16 +104,33 @@ class Audio extends React.Component { super(props); const { baseUrl, file, user } = props; this.state = { + loading: false, currentTime: 0, duration: 0, paused: true, uri: `${ baseUrl }${ file.audio_url }?rc_uid=${ user.id }&rc_token=${ user.token }` }; + + this.sound = new Audio.Sound(); + this.sound.setOnPlaybackStatusUpdate(this.onPlaybackStatusUpdate); + } + + async componentDidMount() { + const { uri } = this.state; + + this.setState({ loading: true }); + try { + await Audio.setAudioModeAsync(mode); + await this.sound.loadAsync({ uri }); + } catch { + // Do nothing + } + this.setState({ loading: false }); } shouldComponentUpdate(nextProps, nextState) { const { - currentTime, duration, paused, uri + currentTime, duration, paused, uri, loading } = this.state; const { file, split, theme } = this.props; if (nextProps.theme !== theme) { @@ -116,44 +154,87 @@ class Audio extends React.Component { if (nextProps.split !== split) { return true; } + if (nextState.loading !== loading) { + return true; + } return false; } + async componentWillUnmount() { + try { + await this.sound.stopAsync(); + } catch { + // Do nothing + } + } + + onPlaybackStatusUpdate = (status) => { + if (status) { + this.onLoad(status); + this.onProgress(status); + this.onEnd(status); + } + } + onLoad = (data) => { - this.setState({ duration: data.duration > 0 ? data.duration : 0 }); + const duration = data.durationMillis / 1000; + this.setState({ duration: duration > 0 ? duration : 0 }); } onProgress = (data) => { const { duration } = this.state; - if (data.currentTime <= duration) { - this.setState({ currentTime: data.currentTime }); + const currentTime = data.positionMillis / 1000; + if (currentTime <= duration) { + this.setState({ currentTime }); } } - onEnd = () => { - this.setState({ paused: true, currentTime: 0 }); - requestAnimationFrame(() => { - this.player.seek(0); - }); + onEnd = async(data) => { + if (data.didJustFinish) { + try { + await this.sound.stopAsync(); + this.setState({ paused: true, currentTime: 0 }); + } catch { + // do nothing + } + } } get duration() { - const { duration } = this.state; - return formatTime(duration); + const { currentTime, duration } = this.state; + return formatTime(currentTime || duration); } - setRef = ref => this.player = ref; - togglePlayPause = () => { const { paused } = this.state; - this.setState({ paused: !paused }); + this.setState({ paused: !paused }, this.playPause); } - onValueChange = value => this.setState({ currentTime: value }); + playPause = async() => { + const { paused } = this.state; + try { + if (paused) { + await this.sound.pauseAsync(); + } else { + await this.sound.playAsync(); + } + } catch { + // Do nothing + } + } + + onValueChange = async(value) => { + try { + this.setState({ currentTime: value }); + await this.sound.setPositionAsync(value * 1000); + } catch { + // Do nothing + } + } render() { const { - uri, paused, currentTime, duration + loading, paused, currentTime, duration } = this.state; const { user, baseUrl, file, getCustomEmoji, split, theme @@ -173,17 +254,7 @@ class Audio extends React.Component { split && sharedStyles.tabletContent ]} > -