From f5b013f4e767e03e48a9b079369319f5bbe0466e Mon Sep 17 00:00:00 2001 From: Diego Mello Date: Mon, 15 Mar 2021 14:36:40 -0300 Subject: [PATCH] Merge 4.15.0 into master (#2984) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [FIX] MessagesView title not working (#2294) * Set title in header of room actions view items Signed-off-by: Ezequiel De Oliveira * Remove unneeded spaces Signed-off-by: Ezequiel De Oliveira * Set header title on constructor Signed-off-by: Ezequiel De Oliveira * Remove unused navigation options Signed-off-by: Ezequiel De Oliveira Co-authored-by: Diego Mello * [TESTS] Stabilise Room Actions test (#2333) * Stabilise Room Actions test * Fix Create Room test * Be more tolerant of slow starting apps in CI * Be more tolerant of slow running apps in CI * Switch visibility checks ti stabilise Room Create test in CI * Move slow simulator readiness waiting to initial navigateToX methods rather than repeatedly in tests without description of purpose * [CHORE] Update icon names (#2318) * [CHORE] Move Detox to Github Actions (#2340) * Initial workflow for iOS detox tests * Increase timeout * Parallelise tests and optimise when to build * Refine GH Actions logic * Improve Detox App caching * Upload failed test artifacts * Rate limiting aware data setup * Remove detox tests from Circle CI * Revert "Rate limiting aware data setup" This reverts commit d115604270f719de775018b9b06e89f2bfdc2dc7. Co-authored-by: Diego Mello * [NEW] Push notification data privacy (#2213) * [WIP] Notification Service * [WIP] Android push notification privacy * [WIP] Retry request when it fails (iOS) * [WIP] Override notification bundle * [CHORE] Remove unnecessary import * [WIP] Check notification Type (iOS) * [WIP] Change to notification endpoint * eof * fix unwrap conditional value * turn run request synchronous * fix bundle info * eof * remove extra tab * undo unnecessary change * remove not working code for a while * fix notification title * change endpoint and received/sent data * message-id-only working properly on android * notification privacy working on ios * invalidate circleCI yarn cache * Fix provisioning profiles * fix notification service version * fix unwrap nil * compatibility older servers android * show received notification when cant fetch content from server * undo some android changes * prevent group & reply fallback notifications * dont show more than one fallback notification by server Co-authored-by: Diego Mello * [IMPROVEMENT] Apply new mention colors (#2351) * New mention colors * Increase letterSpacing for mentions * Refactor * UnreadBadge * Add migration * [FIX] Missing icons (#2353) * [FIX] Long press gestures not working properly on Android (#2354) * [FIX] In-app notification showing while in a Jitsi call (#2345) * Hide in app notification when focused on JitsiMeetView * Hide notifications from different rooms Co-authored-by: Diego Mello * [CHORE] Only run Flipper in debug via MainApplication is debug (#2347) * Only run Flipper in debug via MainApplication is debug * ReactNativeFlipper package rename + gradle bump * [CHORE] Update Flipper to 0.51.0 (#2356) * Only run Flipper in debug via MainApplication is debug * ReactNativeFlipper package rename + gradle bump * Update Flipper to latest 0.51 for Android Co-authored-by: Diego Mello * [NEW] Log events from RoomsList, SideDrawer and Profile (#2190) * Create method to track user event to isolate the logic to improve future refactoring * Track Onboarding view * Track NewServer view * Refactor track method due to firebase already send the current screen * Track default login and all the oAuth options * Track default sign up in RegisterView * Change trackUserEvent signature and update all the files * Track the remaining login services * track add server, change server and search * Track SidebarView and refactor to use react-navigation * Track profile events and handle exceptions * Track create channel flux * Track send message to user via NewMessageView * Track create direct message flux * Handle failure of create channel and group in the saga * Track create discussion flux * Track navigate to directory and its actions * Track read, favorite and hide a channel, handling its errors * Track all channels sorting and grouping * Resolve requests to improve the importing logs and events * Remove unused events file * Leave a bugsnag breadcrumb when logging an event * Move all logEvent to the top of code block and log remaining fail events * Move all the non-logic-dependent logEvent to the top of code block * Improve the logging of sidebar events * Improve events from onboarding and newserver * Improve events from login and register view, and log enter with apple * Improve NewMessageView events * Improve CreateChannel events * Improve CreateDiscussion and SelectedUsers create group events * Improve RoomsList events and log trivial events * Improve ProfileView events * Remove single line function body for the sidebarNavigate * Navigate to Status and AdminPanel View using the defined sidebarNavigate method Co-authored-by: Diego Mello * [FIX] Add missing keys to push get payload (#2358) * [IMPROVEMENT] Add deep link to Jitsi calls (#2223) * [WIP] Jitsi Deep Links * [WIP] Add app links * save uniqueID servers database * add serverInfoKey of uniqueID * search server by call url * open jitsi deeplink poc * improve jitsi url * fix * improve comment * add missing android scheme * handle host not found * Allow app links to be matched on parseDeepLinking * Fix push notification of a call * Minor fix Co-authored-by: Diego Mello * [FIX] App hanging on splash screen when deep link params are wrong (#2359) * Add rule when there's no host on the deep link params * Add fallbackNavigation() * Fix insecure hosts * [FIX] More missing icons (#2360) * [NEW] Log events from Room, Settings and Edit status (#2206) * Create method to track user event to isolate the logic to improve future refactoring * Track Onboarding view * Track NewServer view * Refactor track method due to firebase already send the current screen * Track default login and all the oAuth options * Track default sign up in RegisterView * Change trackUserEvent signature and update all the files * Track the remaining login services * track add server, change server and search * Track SidebarView and refactor to use react-navigation * Track profile events and handle exceptions * Track create channel flux * Track send message to user via NewMessageView * Track create direct message flux * Handle failure of create channel and group in the saga * Track create discussion flux * Track navigate to directory and its actions * Track read, favorite and hide a channel, handling its errors * Track all channels sorting and grouping * Resolve requests to improve the importing logs and events * Remove unused events file * Remove unused events file * log proposed Room events * Log proposed Message actions events * Log EditStatus proposed events * Log Settings proposed events * Leave a bugsnag breadcrumb when logging an event * Move all logEvent to the top of code block and log remaining fail events * Move all the non-logic-dependent logEvent to the top of code block * Move all non-logic and non-data dependent logEvent to the top of code block * Improve the logging of sidebar events * Improve events from onboarding and newserver * Improve events from login and register view, and log enter with apple * Improve NewMessageView events * Improve CreateChannel events * Improve CreateDiscussion and SelectedUsers create group events * Improve RoomsList events and log trivial events * Improve ProfileView events * Remove single line function body for the sidebarNavigate * Improve SettingsView events * Log more events from ScreenLockConfigView * Navigate to Status and AdminPanel View using the defined sidebarNavigate method * Improve StatusView events * Improve RoomView events Co-authored-by: Diego Mello * [FIX] Vertically centralize RoomItem when `Store_Last_Message` is disabled (#2363) * Split RoomItem into container and component * Refactor RoomItem * Fix wrong status * Tests * Wrapper * [NEW] Omnichannel inquiry queue (#2352) * [WIP] Omnichannel queue * Request inquiry when login * Show take inquiry queued room * Queue List as a Screen * Poc using unread badge * Prevent navigation to empty list * Remove chat from queue when taked * Fix header status on omnichannel preview room * Fix room actions view to preview queued chat * Use isOmnichannelPreview and dont show actions when is preview * Filter queue chats taken by other people * Fix room info to omnichannel preview room * Handle show Queue * Reset inquiry store when change server * Improve queue logic * Disable swipe on RoomItem when is a Queue Item * Add unreadBadge style * Move unread badge to presentation folder * Cleanup inquiry reducers * Move take saga to rocketchat function * Remove comments * Add relevant comments * Subscribe to public stream if is livechat manager or doesnt have departments * Add pt-br and improve queue empty message * Fix take when dont have view-livechat-manager permission * Add missing events * Create selector for inquiry queue * Minor fixes Co-authored-by: Diego Mello * [CHORE] Wrap logEvent in a try/catch (#2361) Co-authored-by: Diego Mello * [FIX] Minor i18n issues (#2335) * Add new translations to ptBr Signed-off-by: Ezequiel De Oliveira * Fix update language in headers Signed-off-by: Ezequiel De Oliveira Co-authored-by: Diego Mello * [IMPROVEMENT] Use parsed EJSON info on load notification (#2370) * [NEW] Log remaining events (#2368) * Change NAVIGATE_TO for GO_TO to reduce event size * Log RA JitsiMeet events and join / terminate * Log more RoomView events * Log slash commands and handle fail * Log RoomActions events * Change from GO_TO to just GO * Log RoomInfoEdit events * Log InviteUsers and InviteUsersEdit events * Log AutoTranslate events * Log NotificationPreferences events * Log remaining routes from RoomActions * Log RoomAction toggle block user * Fix command event Co-authored-by: Diego Mello * [FIX] WorkspaceView not looking for the correct image path (#2376) Co-authored-by: Gabriel Henriques * [FIX] Android targeting wrong SDK version (#2375) * [FIX] Mentions crashing without username (#2374) * [FIX] Missing delete icon on MessageErrorActions (#2373) * [FIX] Quote not working on Group DM (#2372) * [DOCS] Add Whitelabel (#2379) * Update readme (#2381) * Update README.md (#2378) * Update README.md * Update README.md Co-authored-by: Diego Mello * [DOCS] Refactor Readme (#2382) * Refactoring * Detail docs * Contributing * Update CONTRIBUTING.md Co-authored-by: Djorkaeff Alexandre Co-authored-by: Djorkaeff Alexandre * Merge beta into master (#2388) * Sync develop on master (#275) * Create LICENSE * Sync master (#721) * Merge 1.13.0 into Master (#936) * fix last messages (#239) * fix last messages * Room actions (#231) * Layout * Empty starred list * Favorite room * Pinned messages * fix last messages * fix date on pinned messages * fix package * [NEW] OAuth (#241) * Layout * tmp * test iscordova * Webview redirecting * Open and Close login actions * Login services saved on redux * OAuth Github * Server regex fix * OAuth modal style * - Twitter login - Remove services from redux - Open login saga fix * - Facebook login - Fixed user agent - Reactions fix - Message url unique key fix * Google login * Email keyboard removed from messagebox * - Login buttons refactored - RoomList header * Layout improvements * Meteor login redirect_uri changed * fix * Random credentialToken state * [NEW] Room actions: Mentioned messages and Room Members (#242) * Mentioned messages * Starred and pinned actions debounce * Room members * Open room on member touch * [WIP] Improves (#245) * hotfix for ios * hotfix for ios * Update config.yml * Workaround for RN 0.54 on iOS (#246) * Update iOS to RN 0.54 (#248) * Update iOS to RN 0.54 * [WIP] Audio message functionality (#247) * [NEW] Add module react-native-audio * [WIP] Audio message basic UI * [NEW] Record audio message * Use cordova repository to get certificates * Icon 1024 * [NEW] Room actions: block user, snippet messages, room files and leave room (#250) * - Block user - Load room members async - fixed reactive change of room's read only flag * Snippet messages * - Room files - Dismiss Video component on back button press - Improvements on Image component * Improvement on Video component * Leave room * Missing message types * lint * Reactotron working (#249) * [NEW] Room info and Room info edit (#254) * - Block user - Load room members async - fixed reactive change of room's read only flag * Snippet messages * - Room files - Dismiss Video component on back button press - Improvements on Image component * Improvement on Video component * Leave room * Missing message types * lint * - Room info (read only) - Missing message types * Room info scroll * - Tap on room header opens room info - Layout tweaks * - Room info edit - iOS Toast fixed * - Style not implemented actions as disabled * Edit room permission * - Save all room settings in a single call - Implemented roomType and readOnly * - Allow reacting when room is read only * Message type added: room_changed_privacy * Erase room * Created TextInput and SwitchContainer components for reuse and readability * - hasPermission method * - Archive/Unarchive room - Set Join Code * Twitter keyboard type on iOS * Archived room * reactWhenReadOnly permission on message * Active users refactored * User roles * - Subscribe to roles (in order to get role description info: e.g. 'core-team' to 'Rocket.Chat Team') - Save roles to realm (for offline access) - Save roles to redux (and get data from realm on app init) * Lint * code style * password show/hide feature * fix show/hide password * password show/hide * Crashlytics (#258) * Fabric iOS * Fabric configured on iOS and Android * login tracked * more logs * fix reaction * CI fix * Bug fixes (#261) * Layout fixes * RoomsListView's SafeAreaView * Unhandled promise rejection fix * Prevent navigation from opening scenes twice * Create channel fixes * Create LICENSE * Beta (#265) * Fabric iOS * Fabric configured on iOS and Android * - react-native-fabric configured - login tracked * README updated * Run scripts from README updated * README scripts * get rooms and messages by rest * user status * more improves * more improves * send pong on timeout * fix some methods * more tests * rest messages * Room actions (#266) * Toggle notifications * Search messages * Invite users * Mute/Unmute users in room * rocket.cat messages * Room topic layout fixed * Starred messages loading onEndReached * Room actions onEndReached * Unnecessary login request * Login loading * Login services fixed * User presence layout * ïmproves on room actions view * Removed unnecessary data from SelectedUsersView * load few messages on open room, search message improve * fix loading messages forever * Removed state from search * Custom message time format * secureTextEntry layout * Reduce android app size * Roles subscription fix * Public routes navigation * fix reconnect * - New login/register, login, register * proguard * Login flux * App init/restore * Android layout fixes * Multiple meteor connection requests fixed * Nested attachments * Nested attachments * fix check status * New login layout (#269) * Public routes navigation * New login/register, login, register * Multiple meteor connection requests fixed * Nested attachments * Button component * TextInput android layout fixed * Register fixed * Thinner close modal button * Requests /me after login only one time * Static images moved * fix reconnect * fix ddp * fix custom emoji * New message layout (#273) * Grouping messages * Message layout * Users typing animation * Image attachment layout * Fabric and image fix (#284) * Fixed images not showing * Keyboard libs updated * Fabric fix and location removed (#286) * Proguard disabled * message with list + links fixed (#288) * Better image cache component (#292) * react-native-img-cache removed * Improve list render * Support inside markdown * Deep linking (#291) * deep linking * Basic deep link working * Deep link routing * Multiple servers working * Send user to the room * Avatar initials and room type icon (#298) * Deep linking fix and more (#294) * Fix - Any https link was deep linking to RocketChat * Keyboard dismiss after add new server * Room info bug fix * Opacity animation * Navigation when adding server fixed * Throttle for unnecessary render on receiving several messages * Search inputs without autocorrect and autocapitalize * Search messages fixed * Messagebox unnecessary render and spotlight fixed * react-native-keyboard-input updated * Lint * Tests updated * Update all dependencies (#299) * Update react-navigation to the latest version 🚀 (#293) * fix(package): update react-navigation to version 2.0.0 * Code updated to support breaking changes of react-navigation * Detox tests E2E (#283) * RoomsListView re-render (#304) @RocketChat/ReactNative - [x] Removed unnecessary re-renders on RoomsListView * [NEW] Broadcast channels (#301) * Broadcast channels * e2e tests * New markdown (#306) Our current markdown is causing a lot of issues on Android devices, since it wraps everything inside a Text component. On Android, Text doesn't support View as a child. This PR adds react-native-markdown-renderer, that uses View as wrapper and may be better. * Fixed audio recording issues (#310) * Fix for "java.lang.IllegalArgumentException: unexpected url" (#313) @RocketChat/ReactNative User was able to add an invalid instance of Rocket.Chat by pressing submit button instead of "Connect" button. * I18n (#312) * Unread and date separator layout improved (#319) @RocketChat/ReactNative - [x] Unread and date separator layout - [x] "Start of conversation"/"Loading messages" label ![screen shot 2018-05-30 at 18 10 43](https://user-images.githubusercontent.com/804994/40747867-0424964a-6435-11e8-9293-31cc43c110ab.png) ![screen shot 2018-05-30 at 18 09 05](https://user-images.githubusercontent.com/804994/40747868-04484784-6435-11e8-8c31-92e0776276f0.png) * [FIX] iOS Universal links (#318) * [NEW] Drawer (#322) * [FIX] invalid user muted value * Ddp fixes (#324) * [NEW] User Profile (#323) * Drawer layout * Drawer changes * Profile * Profile avatar * Set language * Tests * Custom fields * Readme updated * fix invalid user muted value * Fix for "Cannot add a child that doesn't have a YogaNode to a parent without a measure function! (Trying to add a 'RCTVirtualText' to a 'RCTView')" * Settings/Permissions improvements (#325) * Changed the way we read RocketChat settings since setting.type won't be returned from server anymore * Permissions * Unnecessary action sheet render * Update gradle and targetSdkVersion (#328) * Changed the way we read RocketChat settings since setting.type won't be returned from server anymore * Permissions * Unnecessary action sheet render * Update gradle * Switched testServer to use blob * RoomsListHeader search fixed * Runs loadMessagesForRoom only if room has at least 20 rows * - Logout if user's token expired - Removed update avatar logic - Profile dialog border on android * - Animations disabled - CircleCI set * Tests updated * "eventType argument is required" fix * Switch push notification lib (#346) @RocketChat/ReactNative Closes #342 * Allow x-instance-id and X-Instance-ID header (#354) @RocketChat/ReactNative Closes #137 Some server configurations may send x-instance-id header with different case. * Image upload improvements (#368) @RocketChat/ReactNative - [x] Crop image - [x] Type image description (like web) - [x] Show upload progress - [x] "Try again" in case of error - [x] Cancel upload while in progress - [x] [Android] Zoom on photos ![image](https://user-images.githubusercontent.com/804994/42526934-a12da304-844d-11e8-8668-f3d69369726a.png) ![image](https://user-images.githubusercontent.com/804994/42527829-297945fe-8450-11e8-9f0e-9e668dd33043.png) * [NEW] Room Loading(#372) @RocketChat/ReactNative * [FIX] Empty room name for livechat (#375) @RocketChat/ReactNative Closes #320 Closes #209 * [NEW] Reply preview (#374) * Updated to React Native 0.56 * Reply Preview * [FIX] Close websocket (#379) * Fixed a bug when closing websocket * removeListener fixed * [I18N] Russian translation (#381) [I18N] Russian translation file * [NEW] Icon (#383) @RocketChat/ReactNative ![image](https://user-images.githubusercontent.com/804994/43228416-d8af49d6-9037-11e8-8830-a1803932c7fd.png) * [FIX] Android 8 notifications (#382) @RocketChat/ReactNative Closes #380 * Added CocoaPods to manage react-native-image-crop-picker (#373) @RocketChat/ReactNative react-native-image-crop-picker raised an error when uploading to TestFlight. The lib highly recommends CocoaPods for production builds. * Added single-server to readme (#390) @RocketChat/ReactNative Closes #386 Closes #295 * Improve RoomsList render time (#384) @RocketChat/ReactNative - [x] Added FlatList.getItemLayout() to improve list render time - [x] Some texts were breaking lines at sidebar - [x] Removed onPress from links at RoomsListView - [x] Added eslint rule to prevent unused styles - [x] Fixed auto focus bug at CreateChannel and NewServer - [x] Fix change server bug - [x] Fixed a bug when resuming in ListServer - [x] I18n fixed - [x] Fixed a bug on actionsheet ref not being created - [x] Reply wasn't showing on Android - [x] Use Notification.Builder.setColor/getColor only after Android SDK 23 - [x] Listen to app state only when inside app - [x] Switched register push token position in order to improve login performance - [x] When deep link changes server, it doesn't refresh rooms list - [x] Added SafeAreaView in all views to improve iPhone X experience - [x] Subpath regex #388 * [NEW] Empty room background (#412) @RocketChat/ReactNative Closes #398 ![aug-09-2018 11-35-32](https://user-images.githubusercontent.com/804994/43906080-cbfadf92-9bc8-11e8-9ac9-44f43d3af023.gif) ![aug-09-2018 11-35-16](https://user-images.githubusercontent.com/804994/43906082-cc19411c-9bc8-11e8-9892-c65c86951a91.gif) ![image](https://user-images.githubusercontent.com/804994/43911366-ad830cd0-9bd5-11e8-8913-6a7e87a2206c.png) * Add roadmap (#406) @RocketChat/ReactNative Closes #45 * [NEW] Onboarding (#407) @RocketChat/ReactNative Closes #392 ![aug-07-2018 17-03-50](https://user-images.githubusercontent.com/804994/43799447-f62074dc-9a63-11e8-8aac-bf2c4c5a8a2b.gif) ![aug-07-2018 17-03-35](https://user-images.githubusercontent.com/804994/43799446-f5f84a70-9a63-11e8-8947-265113ae9bf4.gif) ![aug-07-2018 17-03-13](https://user-images.githubusercontent.com/804994/43799445-f5d70ee6-9a63-11e8-94a9-f49c7d69fbba.gif) * [NEW] Updated Logo on Splash screen (#409) @RocketChat/ReactNative Closes #399 ![aug-07-2018 17-39-44](https://user-images.githubusercontent.com/804994/43801415-739a0cca-9a69-11e8-8bec-d65f751e6a28.gif) ![aug-07-2018 17-31-12](https://user-images.githubusercontent.com/804994/43801416-73d19bd6-9a69-11e8-90ac-bbc7ddeed938.gif) * [FIX] Only single attachment rendered (#417) * [NEW] Rooms list layout (#413) * RoomsListView layout * Rooms list layout * Sort component * Header icons * Default header colors * Add server dropdown * Close sort dropdown if server dropdown will open * UserItem * Room type icon * Search working * Tests updated * Android layout * Using realm queries instead of array iterates * Animation duration * Fixed render bug * [NEW] Create channel layout (#420) * RoomsListView layout * Rooms list layout * Sort component * Header icons * Default header colors * Add server dropdown * Close sort dropdown if server dropdown will open * UserItem * Room type icon * Search working * Tests updated * Android layout * Using realm queries instead of array iterates * Animation duration * Fixed render bug * - NewMessageView - backButtonTitle always empty - SearchBox created * New create channel layout * Search refactored * loginSuccess dismiss modal * Tests working * [FIX] Open unsupported videos on browser (#422) * 1.1 * Sort/group rooms local only (#425) * Update android api from ci * Sort local only * [FIX] Missing current server (#427) * server.current removed * Increased area of touch on header * Hide search when sort dropdown is tapped * default server icon url * 1.1.1 * [NEW] Experimental Icon (#430) * [NEW] Message layout (#426) * message container/component * Separator component * Reply * Url * tests updated * Minor changes * Audio component * Broadcast button * Minor touches * Reply preview * Edited * Minor bug fixes * - Update roadmap - Bump version to 1.2 * Onboarding styles fix * [FIX] Drawer navigation won't refresh chats (#432) * Avoid errors on Audio/Image/Video (#443) * Bump version to 1.2.1 (#444) * Stop supporting Android 4.4 and lower (#447) * Several fixes for 1.2.1 (#448) * Fix user.roles * Better onLongPress handle on messages * Indicator position * Fix role undefined in system messages * Add baseUrl in case of file attachments * Join room fixed * RoomView params * Broadcast fixes * Add server layout changes * Use native images * Subscribe to not joined channels * Fix alerts without i18n * Tests updated * Bump version to 1.2.2 (#449) * [NEW] Use community JSC for Android (#450) * [NEW] Use community JSC for Android * Quick fix on unread chats * [NEW] Show app version (#454) * [NEW] Portuguese translation (#452) * [NEW] Portuguese translation * Remove servers from sidebar * Update dependencies (#431) * Update dependencies * Lint and test * Added react-native fork * rn 57 * Lint and tests updated * Update xcode on circleci * Use legacy build system * Update tests * Use inline requires (#459) * Update dependencies * Lint and test * Added react-native fork * rn 57 * Lint and tests updated * Update xcode on circleci * Use legacy build system * Update tests * Inline requires * Fix eslint and remove temp gradle * Unnecessary renders * Update isNotch and Readme * Tests updated * Bump version to 1.3.0 (#461) * Better touch handling on rooms list (#462) * Use react-native-gesture-handler at RoomItem * Fixed info message author * Edit message render improvement * Fix ws to http replace * Bump version to 1.3.1 (#463) * Composer layout tweaked (#464) * Composer layout tweaked * Fix localization error * Bump version to 1.3.2 * [FIX] Handle deleted messages (#466) * [FIX] Handle deleted messages * Fix rest error * Fix some connection issues * [FIX] Search rooms (#468) * Bump version to 1.3.3 (#469) * Connecting to DDP badge (#471) * Display custom fields on user info (#476) * Render custom fields on user info * renderCustomFields fix * Display custom fields in user info * Fix lint error * [FIX] DDP badge wasn't hiding on fast connections (#477) * Use Rocket.Chat JS SDK (#481) * JS SDK * API working * Multiple servers * Bump version to 1.4.0 (#482) * [FIX] 2FA and LDAP (#488) * [FIX] Unread rooms group order (#487) * Use grouping setting on temp messages (#486) * [FIX] Delete room error (#485) * Rename to Rocket.Chat Experimental (#483) * Update dependencies (#484) * Bump version to 1.4.0 (#482) * test * one more test * Fix build * Regression: Wait for unmount to delete database after logout (#489) * Bump version to 1.4.1 (#490) * Regression: Crash on Android search (#492) * Bump version to 1.4.2 (#493) * Update Rocket.Chat.js.SDK (#494) * Bump version to v1.4.3 (#495) * [FIX] OAuth (#496) * Smaller header icons inside the room (#499) * [FIX] Logout (#497) * [FIX] Logout * Removed realm instances on rooms list * Bump version to 1.4.4 (#498) * Update navigation library (#501) * v2 * Working on Android 0.57.3 * Drawer working * Removing v1 navigator * - Splash screen - Icons changed * Deeplink * Remove EventEmitter from CreateChannelView * Android search * Android notifications * OAuth * Fix search props * Lint and tests fixed * Fix android build * Improvements on iPhone X* usage * Fix detox * Fix android build * Room.f added to RoomView.shouldComponentUpdate * Animations on RoomsListView and RoomView * Fix topbar buttons on Android * Bump version to 1.5.0 (#503) * Check $FABRIC_KEY availability in CircleCI (#506) * Check $FABRIC_KEY in CircleCI * Remove config scripts * Check $FABRIC_KEY availability in CircleCI for iOS (#507) * [I18n] Add Simplified Chinese(zh-CN) locale (#505) * [FIX] iOS pop gesture not working properly (#509) * Check if lastMessage has an attachment and show "User sent an attachment" at RoomsList (#510) * [FIX] Messages not being loaded properly (#513) * Fetch avatar initials from server (#512) * Fix iOS pop gesture and open sidemenu gesture (#511) * Bump version to 1.5.1 (#516) * [NEW] Room header layout (#521) * Clear iOS notification on resume/open (#520) * [FIX] Flashing avatars on Android after #512 (#519) * [FIX] App connects to previous server instead of the recent added (#518) * [FIX] Room view header crashes when destructuring reducer (#523) * [FIX] Dismiss keyboard on room close (#530) * [FIX] Composer composer's send icon slowness (#528) * [WIP] New Authentication layout (#536) New Authentication layout * Regression: Resend messages with error (#532) * DDP Connection badge animation changed (#533) * [FIX] Upload buttons on Android (#541) * Bump version to 1.6.0 (#543) * I18n: Add missing translation of simplified Chinese (#539) * Update dependencies (#544) * AndroidManifest changes * Regression: Deep linking stopped working after react-native-navigation update (#549) * [FIX] Android stuck on splash screen after hardware back button is pressed (#550) * [FIX] Android stuck on splash screen after hardware button is pressed * Fix empty user at asyncstorage * Remove unused subscribe * [FIX] x-instance-id header prop is case insensitive (#551) * Bump version to 1.6.1 (#553) * [FIX] x-instance-id header prop is case insensitive * Use Rest API calls (#558) * Chats: Don't show group header if none of the filters is selected (#560) * [CHORE] Update Xcode image version on CircleCI (#561) * Bump version to 1.7.0 (#562) * [FIX] Load messages on notification tap (#564) * Use Rest API pt 2 (#568) * Room files * Pinned messages * Starred messages * Mentioned messages * Search messages * Bug fixes * Profile * Livechat * Block/unblock user * Erase room * Archive room * Remove unused method * Bug fix * [CHORE] Add hold step on CircleCI before TestFlight (#572) * [FIX] GET /info to check if it's a valid server instead of x-instance-id (#573) * Bump version to 1.7.1 (#574) * Unnecessary re-renders removed (#570) * shouldComponentUpdate * Rooms list shouldcomponentupdate * RoomView shouldComponentUpdate * Messagebox and Message shouldComponentUpdate * EmojiPicker shouldComponentUpdate * RoomActions shouldComponentUpdate * Room info shouldComponentUpdate * Update RNN * Use only one Flatlist if none group filter is selected * Update fix * shouldComponentUpdate * Bug fixes * ListView changes * Bug fix * render list bug fix * Changes on public channels * - RoomView saga leak removed - Join room e2e tests added * Rest versions * Method call versions * Min RocketChat version alert * Update dependencies (#587) * [FIX] Better message actions (#567) * [FIX] Back button press on message actions (#592) * Bump version to 1.8.0 (#595) * [FIX] LDAP login (#596) * Create class to manage navigation (#594) * Add Navigation class * Place Drawer.js logic inside of Navigation * Load less views at startup * [FIX] v1.8.0 (#599) * Downgrade react-native-fast-image * Update iOS permission usage descriptions * [FIX] Delete upload item * Update JS SDK version (#602) * Add Icons class (#611) Creates Icons class to manage when to load icons from native side or react-native-vector-icons. It also fixes `react-native run-android` #517 * Updating room indicator (#609) Shows "Updating..." when requesting rooms from Rest API. * [FIX] Load avatar on servers that prevent unauthenticated avatar access (#604) App would show an empty space on servers that require authentication on avatar access * [FIX] 2FA login in a server with LDAP enabled (#612) * [FIX] Start loop searching for rooms updates only when connection goes down and SDK has userId (#613) * Allow to create empty channel (#615) * [FIX] Reply title should break text (#616) * Bump version to 1.9.0 (#617) * [FIX] SDK issues (#621) * Remove listeners from room * Properly close connections on change server * Minor layout change on connecting badge * [CHORE] Add TestFlight invite and update Readme (#623) * [FIX] npm -> yarn dependencies migration (#622) * I18n: Add French (#629) * [FIX] Remove rooms listener (#630) * [CHORE] Update issue template (#638) * I18n: Add German (#641) * Bump version to 1.10.0 (#644) * [FIX] Prevent mass is typing dispatchs (#651) * [FIX] Handle database errors properly (#650) * [FIX] Change actions labels (#654) * [FIX] Room members filter (#655) * [FIX] uploadProgress is not a function (#656) * [FIX] Slow messagebox (#658) * Remove drawer (#653) * Remove drawer (layout needs to be changed in future releases, though) * Don't navigate outside on logout if there's other logged server * Update react-native-navigation * Message button (#660) * Remove touchable opacity when scrolling messages * Tap on disable messages closes keyboard * Unify vibration * Vibrate only on Android * [FIX] Fetch rooms date (#662) * [FIX] Select emoji error (#666) * Update Realm to 2.24 (#667) * Update React Native to 0.58.6 (#668) * [FIX] Fix some language issues in German language (#664) * New icons (#643) * New Icons * Remove unused assets * Change send icon * Layout tweaks * Refactor Status * Styles changed * User layout fix * Separator layout changes * Sidebar status layout fix * Fix Message.onLongPress issue * Fix code markdown Closes https://github.com/RocketChat/Rocket.Chat.ReactNative/issues/625 * Status lint * Fix tests * Navigation debounce * RoomActions icons * Space between components * Group text * Update tests * [CHORE] Remove .debug suffix on Android (#681) * [FIX] Fix null native Messagebox component object (#680) * Fix null native Messagebox component object * [iOS] Fix header alignment * Remove unused files * Switch to react-navigation (#687) * Update readme (#714) * Bump to 1.10.1 (#731) * [FIX] Deep linking between multiple logged servers (#730) * Fix handle invisible status (#692) * I18n: Add Portuguese (Portugal) (#722) * [FIX] Show ActivityIndicator in RoomMembersView (#686) * Bump version to 1.11.0 (#761) * Migrate from GCM to FCM (#760) * [NEW] Scrollable room name feature (#756) * [NEW] Scroll down floating button (#735) * [CHORE] Added Storybook documentation (#757) * Use FlatList in RoomView (#762) * [FIX] iOS requiring location permission (#768) * Room item layout (#771) * [NEW] Draft message per room (#772) * [FIX] Add Realm.safeAddListener (#785) * [CHORE] Remove tvOS target (#779) * [NEW] Discussions (#696) * Bump version to 1.12.0 (#804) * [NEW] Threads (#798) * RoomsListView improvements (#819) * [FIX] Giphy not showing (#810) * [FIX] Apply emojify on empty texts (#824) * Lock drawer when stack is not on root screen (#825) * Room item layout (#835) * [FIX] Threads (#838) Closes #826 Closes #827 Closes #828 Closes #829 Closes #830 Closes #831 Closes #832 Closes #833 * [FIX] Smaller thread title (#846) * [FIX] Smaller thread title * Remove markdown notation from thread title * On message press debounce * Align vertical thread title * [Regression] Search stopped working on Android after LastMessage refactor (#851) * Load legal pages from web (#849) * Update fetch permissions api (#850) * Update custom emojis endpoint (#852) * Update emoji endpoint * Use React.memo on Markdown * Support RC versions lower than 0.75.0 * Realm migration * Fetch roles from rest api (#853) * Fetch roles from rest api * Fix RoomInfoView role get * Remove roles from redux * Bump version to 1.13 (#857) * Active users improvements (#855) * Remove connection badge (#862) * Connecting indicator on RoomsListView header * Connecting indicator on RoomView header * Remove ConnectionBadge * Show updating on RoomView load messages * Update dependencies (#863) * Minor updates * Update jsc-android * Update react-native-modal * Minor updates * Update react-native-fast-image * Minor dev updates * Few major updates * Update react-native-keyboard-aware-scroll-view * Update pods * Update android-support * Update tests * Remove duplicated getRoleDescription function (#866) * [FIX] Load local URL image (#871) * [FIX] Toggle/follow thread icon (#867) * Tweaks on sequential threads messages layout (#858) * Tweaks on sequential threads messages * Update tests * Fix quote * Prevent from deleting thread start message when positioned inside the thread * Remove thread listener from RightButtons * Fix error on thread start parse * Stop parsing threads on render * Check replied thread only if necessary * Fix messages don't displaying * Fix threads e2e * RoomsListView.updateState slice * Stop fetching hidden messages on threads * Set initialNumToRender to 5 * [FIX] Check if room is mounted before setting state (#864) * Tweaks on sequential threads messages * Update tests * Fix quote * Prevent from deleting thread start message when positioned inside the thread * Remove thread listener from RightButtons * Fix error on thread start parse * Stop parsing threads on render * Check replied thread only if necessary * Fix messages don't displaying * Fix threads e2e * RoomsListView.updateState slice * Stop fetching hidden messages on threads * Check if RoomView is mounted before rendering * Refactor navigation events on RoomsListView * Fix lint * Fix listener * [FIX] Typing not getting cleared after popping a room (#873) * [CHORE] Remove e2e tests from CI (#875) * [FIX] Remove listeners on RoomView header unmount (#874) * [RELEASE] Merge beta into master (#1055) * Bump version to 1.16.0 (#1014) * [IMPROVEMENT] Share credentials with Rocket.Chat.iOS (#982) * :sparkles: Create user table * :sparkles: Introduce user table * :fire: Remove unused table * :heavy_plus_sign: Add userdefaults to storage data * :green_heart: Fix android build * :sparkles: Get credentials from iOS native client * :fire: Remove unused code * :rewind: Revert sign xcode * :bug: Fix first login-logout * :art: Use constants to UserDefaults Keys * :bug: Fix clear server-user-info on logout * :bug: Fix filter null value * :ambulance: Remove user object in logout * :sparkles: Fix get servers from native-client * :ambulance: Fix error on change server * [FIX] Don't run UserDefaults credentials on Android (#1015) * :bug: Fix native credentials (android) * Fix migration loop * [IMPROVEMENT] Hide frequently used emoji tab when empty (#792) * [IMPROVEMENT] Bigger emoji in emoji only messages (#793) * issue #725: bigger emoji in emoji only message * issue-725/add storybook for Message/Emoji * issue-725: update storybook/Message jest snapshot * comment storybook import * allow spaces and line breaks in emoji only message * merge develop * revert unnecessary spacing * [FIX] Empty message if contains only a link (#787) * Fix empty message if contains only a link * :bug: Fix empty space * [IMPROVEMENT] Refactor empty space regex on quote (#1017) * :art: Improve regex to empty space on quote * :art: Improve on regex to empty space on quote * [NEW] Custom fields on signup (#1013) * added custom feilds on registration * added flag as leftIcon and removed lable * added try and catch * typo * [CHORE] Renew provisioning profiles (#1020) * [NEW] Auto-translate (#1012) * Update realm * View original and translate working * Read AutoTranslate_Enabled setting * RocketChat.canAutoTranslate() * AutoTranslateView * Save language * Auto-translate switch * Translate message * [IMPROVEMENT] Use haptics rather than vibration (#1016) * Install expo-haptics * Use expo-haptics rather than RN's Vibration module * [IMPROVEMENT] Use Rest API for file upload (#1005) * removed rn-fetch-blob and use native XMLHttpRequest instead * removed unnessary changes * fix android bug * fix android bug * added tmid support * fix bug * fixed isssue with cacel model * fix problems with audio * done requested changes * fix bug with android * [CHORE] [CI] [TESTS] update detox to make ci pass (#1026) * feat: update detox to 12.11.3 to make CI pass * ci: comment all jobs but leave e2e-test job * commit to rerun IC e2e-test job * ci: uncomment all CI jobs * [NEW] Room swipe actions: mark as read/unread, hide, fav (#976) * added unread and fav feature * changed the layout * fix jest * done requested changes * added requested changes * [FIX] Android build (#1027) * [FIX] Android build * CircleCI error * [FIX] iOS share credentials build (#1028) * [FIX] iOS share credentials build * Use `hasMigration` as a string * [CI] Restore cache on CI (#1029) * feat: add fastlane save\restore cache config; comment not needed jobs; * install fastlane using 'bundle install' * install fastlane using 'sudo bundle install' * uncomment ios build commands * run set up google services in ios folder * add working_directory: ios to ios-build steps * remove 'cd ios' from Fastlane build step * add save\restore cache for npm modules * group save_cache steps * cache fastlane in ios-testflight job * uncomment previously commented jobs\steps * fix: add missing colon * use key for caching: node-modules-{{ checksum ".circleci/config.yml" }}-{{ checksum "yarn.lock" }} * add names for save\restore steps * ci: add `default` step with `working_directory: ~/repo` to ios-build job * return back caching npm: `node-v1-{{ checksum "package.json" }}-{{ arch }}` * fix: add missing curly braces * save\restore cache in e2e-test job; remove {{arch}} from cache names * add names to restore_cache steps in android-build job * add names to save_cache steps in android-build job * add names to all save\restore steps; change checksum package.json to yarn.lock * change `npm` to `NPM` in steps naming * remove {{ checksum circle ci }} from android-build job and fix naming of steps * [FIX] Rooms swipes (#1034) * Regression: on press style feedback * Action button styles * Fix animations * Styles changed * Update subscription without having to wait for socket * Calculate width on RoomsListView instead * [FIX] Decrease bigger emoji size to 30 (#1031) * [FIX] Append server URL on avatar if necessary (#1038) * Comment removeClippedSubviews * Comment width animation * Remove redux from RoomItem * Fix wrong re-render comparison * Remove listener * Raise minDeltaX * memo actions * Spring with native driver * Refactor functions * Fix props issues * Remove RoomItem.height * Long swipe * Refactor animations * this.rowTranslation -> this.transX * Moved state to this * Bump version to 1.16.1 (#1045) * [FIX] Set UserDefaults AppGroup on notification tap (#1047) * [FIX] Auto-translate messages as they arrive * Fix favorite button * [RELEASE] Merge beta into master (#1082) * Bump version to 1.16.0 (#1014) * [IMPROVEMENT] Share credentials with Rocket.Chat.iOS (#982) * :sparkles: Create user table * :sparkles: Introduce user table * :fire: Remove unused table * :heavy_plus_sign: Add userdefaults to storage data * :green_heart: Fix android build * :sparkles: Get credentials from iOS native client * :fire: Remove unused code * :rewind: Revert sign xcode * :bug: Fix first login-logout * :art: Use constants to UserDefaults Keys * :bug: Fix clear server-user-info on logout * :bug: Fix filter null value * :ambulance: Remove user object in logout * :sparkles: Fix get servers from native-client * :ambulance: Fix error on change server * [FIX] Don't run UserDefaults credentials on Android (#1015) * :bug: Fix native credentials (android) * Fix migration loop * [IMPROVEMENT] Hide frequently used emoji tab when empty (#792) * [IMPROVEMENT] Bigger emoji in emoji only messages (#793) * issue #725: bigger emoji in emoji only message * issue-725/add storybook for Message/Emoji * issue-725: update storybook/Message jest snapshot * comment storybook import * allow spaces and line breaks in emoji only message * merge develop * revert unnecessary spacing * [FIX] Empty message if contains only a link (#787) * Fix empty message if contains only a link * :bug: Fix empty space * [IMPROVEMENT] Refactor empty space regex on quote (#1017) * :art: Improve regex to empty space on quote * :art: Improve on regex to empty space on quote * [NEW] Custom fields on signup (#1013) * added custom feilds on registration * added flag as leftIcon and removed lable * added try and catch * typo * [CHORE] Renew provisioning profiles (#1020) * [NEW] Auto-translate (#1012) * Update realm * View original and translate working * Read AutoTranslate_Enabled setting * RocketChat.canAutoTranslate() * AutoTranslateView * Save language * Auto-translate switch * Translate message * [IMPROVEMENT] Use haptics rather than vibration (#1016) * Install expo-haptics * Use expo-haptics rather than RN's Vibration module * [IMPROVEMENT] Use Rest API for file upload (#1005) * removed rn-fetch-blob and use native XMLHttpRequest instead * removed unnessary changes * fix android bug * fix android bug * added tmid support * fix bug * fixed isssue with cacel model * fix problems with audio * done requested changes * fix bug with android * [CHORE] [CI] [TESTS] update detox to make ci pass (#1026) * feat: update detox to 12.11.3 to make CI pass * ci: comment all jobs but leave e2e-test job * commit to rerun IC e2e-test job * ci: uncomment all CI jobs * [NEW] Room swipe actions: mark as read/unread, hide, fav (#976) * added unread and fav feature * changed the layout * fix jest * done requested changes * added requested changes * [FIX] Android build (#1027) * [FIX] Android build * CircleCI error * [FIX] iOS share credentials build (#1028) * [FIX] iOS share credentials build * Use `hasMigration` as a string * [CI] Restore cache on CI (#1029) * feat: add fastlane save\restore cache config; comment not needed jobs; * install fastlane using 'bundle install' * install fastlane using 'sudo bundle install' * uncomment ios build commands * run set up google services in ios folder * add working_directory: ios to ios-build steps * remove 'cd ios' from Fastlane build step * add save\restore cache for npm modules * group save_cache steps * cache fastlane in ios-testflight job * uncomment previously commented jobs\steps * fix: add missing colon * use key for caching: node-modules-{{ checksum ".circleci/config.yml" }}-{{ checksum "yarn.lock" }} * add names for save\restore steps * ci: add `default` step with `working_directory: ~/repo` to ios-build job * return back caching npm: `node-v1-{{ checksum "package.json" }}-{{ arch }}` * fix: add missing curly braces * save\restore cache in e2e-test job; remove {{arch}} from cache names * add names to restore_cache steps in android-build job * add names to save_cache steps in android-build job * add names to all save\restore steps; change checksum package.json to yarn.lock * change `npm` to `NPM` in steps naming * remove {{ checksum circle ci }} from android-build job and fix naming of steps * [FIX] Rooms swipes (#1034) * Regression: on press style feedback * Action button styles * Fix animations * Styles changed * Update subscription without having to wait for socket * Calculate width on RoomsListView instead * [FIX] Decrease bigger emoji size to 30 (#1031) * [FIX] Append server URL on avatar if necessary (#1038) * Comment removeClippedSubviews * Comment width animation * Remove redux from RoomItem * Fix wrong re-render comparison * Remove listener * Raise minDeltaX * memo actions * Spring with native driver * Refactor functions * Fix props issues * Remove RoomItem.height * Long swipe * Refactor animations * this.rowTranslation -> this.transX * Moved state to this * Bump version to 1.16.1 (#1045) * [FIX] Set UserDefaults AppGroup on notification tap (#1047) * [FIX] Auto-translate messages as they arrive * Fix favorite button * [FIX] Swipe animations (#1044) * Comment removeClippedSubviews * Comment width animation * Remove redux from RoomItem * Fix wrong re-render comparison * Remove listener * Raise minDeltaX * memo actions * Spring with native driver * Refactor functions * Fix props issues * Remove RoomItem.height * Long swipe * Refactor animations * this.rowTranslation -> this.transX * Moved state to this * Fix favorite button * [FIX] Auto-translate messages as they arrive (#1049) * Comment removeClippedSubviews * Comment width animation * Remove redux from RoomItem * Fix wrong re-render comparison * Remove listener * Raise minDeltaX * memo actions * Spring with native driver * Refactor functions * Fix props issues * Remove RoomItem.height * Long swipe * Refactor animations * this.rowTranslation -> this.transX * Moved state to this * [FIX] Auto-translate messages as they arrive * [i18n] Add missing de translations (#1040) * [CHORE] Switch to react-native-localize (#1043) * Bump version to 1.17.0 (#1057) * Load views as needed (#1056) * [IMPROVEMENT] Change "resend" icon position (#1048) * [NEW] Video support (#801) * [NEW] File upload (#882) * [NEW] Share extension (#942) * [FIX] Share extension CI build (#1060) * Change bundleID * Provisioning * get provisioning profile * [IMPROVEMENT] Reusable toast (#1065) * [FIX] Moment locales (#1066) * [FIX] Share Extension issues (#1064) * [FIX] Empty white list enables all media types upload (#1077) * Merge branch 'master' into develop (#1079) * [FIX] Empty white list enables all media types upload (#1080) * Create utils to media (canUpload) * Fix variable name * [CHORE] Update README (#1081) * [RELEASE] Merge beta into master (#1088) * Bump version to 1.16.0 (#1014) * [IMPROVEMENT] Share credentials with Rocket.Chat.iOS (#982) * :sparkles: Create user table * :sparkles: Introduce user table * :fire: Remove unused table * :heavy_plus_sign: Add userdefaults to storage data * :green_heart: Fix android build * :sparkles: Get credentials from iOS native client * :fire: Remove unused code * :rewind: Revert sign xcode * :bug: Fix first login-logout * :art: Use constants to UserDefaults Keys * :bug: Fix clear server-user-info on logout * :bug: Fix filter null value * :ambulance: Remove user object in logout * :sparkles: Fix get servers from native-client * :ambulance: Fix error on change server * [FIX] Don't run UserDefaults credentials on Android (#1015) * :bug: Fix native credentials (android) * Fix migration loop * [IMPROVEMENT] Hide frequently used emoji tab when empty (#792) * [IMPROVEMENT] Bigger emoji in emoji only messages (#793) * issue #725: bigger emoji in emoji only message * issue-725/add storybook for Message/Emoji * issue-725: update storybook/Message jest snapshot * comment storybook import * allow spaces and line breaks in emoji only message * merge develop * revert unnecessary spacing * [FIX] Empty message if contains only a link (#787) * Fix empty message if contains only a link * :bug: Fix empty space * [IMPROVEMENT] Refactor empty space regex on quote (#1017) * :art: Improve regex to empty space on quote * :art: Improve on regex to empty space on quote * [NEW] Custom fields on signup (#1013) * added custom feilds on registration * added flag as leftIcon and removed lable * added try and catch * typo * [CHORE] Renew provisioning profiles (#1020) * [NEW] Auto-translate (#1012) * Update realm * View original and translate working * Read AutoTranslate_Enabled setting * RocketChat.canAutoTranslate() * AutoTranslateView * Save language * Auto-translate switch * Translate message * [IMPROVEMENT] Use haptics rather than vibration (#1016) * Install expo-haptics * Use expo-haptics rather than RN's Vibration module * [IMPROVEMENT] Use Rest API for file upload (#1005) * removed rn-fetch-blob and use native XMLHttpRequest instead * removed unnessary changes * fix android bug * fix android bug * added tmid support * fix bug * fixed isssue with cacel model * fix problems with audio * done requested changes * fix bug with android * [CHORE] [CI] [TESTS] update detox to make ci pass (#1026) * feat: update detox to 12.11.3 to make CI pass * ci: comment all jobs but leave e2e-test job * commit to rerun IC e2e-test job * ci: uncomment all CI jobs * [NEW] Room swipe actions: mark as read/unread, hide, fav (#976) * added unread and fav feature * changed the layout * fix jest * done requested changes * added requested changes * [FIX] Android build (#1027) * [FIX] Android build * CircleCI error * [FIX] iOS share credentials build (#1028) * [FIX] iOS share credentials build * Use `hasMigration` as a string * [CI] Restore cache on CI (#1029) * feat: add fastlane save\restore cache config; comment not needed jobs; * install fastlane using 'bundle install' * install fastlane using 'sudo bundle install' * uncomment ios build commands * run set up google services in ios folder * add working_directory: ios to ios-build steps * remove 'cd ios' from Fastlane build step * add save\restore cache for npm modules * group save_cache steps * cache fastlane in ios-testflight job * uncomment previously commented jobs\steps * fix: add missing colon * use key for caching: node-modules-{{ checksum ".circleci/config.yml" }}-{{ checksum "yarn.lock" }} * add names for save\restore steps * ci: add `default` step with `working_directory: ~/repo` to ios-build job * return back caching npm: `node-v1-{{ checksum "package.json" }}-{{ arch }}` * fix: add missing curly braces * save\restore cache in e2e-test job; remove {{arch}} from cache names * add names to restore_cache steps in android-build job * add names to save_cache steps in android-build job * add names to all save\restore steps; change checksum package.json to yarn.lock * change `npm` to `NPM` in steps naming * remove {{ checksum circle ci }} from android-build job and fix naming of steps * [FIX] Rooms swipes (#1034) * Regression: on press style feedback * Action button styles * Fix animations * Styles changed * Update subscription without having to wait for socket * Calculate width on RoomsListView instead * [FIX] Decrease bigger emoji size to 30 (#1031) * [FIX] Append server URL on avatar if necessary (#1038) * Comment removeClippedSubviews * Comment width animation * Remove redux from RoomItem * Fix wrong re-render comparison * Remove listener * Raise minDeltaX * memo actions * Spring with native driver * Refactor functions * Fix props issues * Remove RoomItem.height * Long swipe * Refactor animations * this.rowTranslation -> this.transX * Moved state to this * Bump version to 1.16.1 (#1045) * [FIX] Set UserDefaults AppGroup on notification tap (#1047) * [FIX] Auto-translate messages as they arrive * Fix favorite button * [FIX] Swipe animations (#1044) * Comment removeClippedSubviews * Comment width animation * Remove redux from RoomItem * Fix wrong re-render comparison * Remove listener * Raise minDeltaX * memo actions * Spring with native driver * Refactor functions * Fix props issues * Remove RoomItem.height * Long swipe * Refactor animations * this.rowTranslation -> this.transX * Moved state to this * Fix favorite button * [FIX] Auto-translate messages as they arrive (#1049) * Comment removeClippedSubviews * Comment width animation * Remove redux from RoomItem * Fix wrong re-render comparison * Remove listener * Raise minDeltaX * memo actions * Spring with native driver * Refactor functions * Fix props issues * Remove RoomItem.height * Long swipe * Refactor animations * this.rowTranslation -> this.transX * Moved state to this * [FIX] Auto-translate messages as they arrive * [i18n] Add missing de translations (#1040) * [CHORE] Switch to react-native-localize (#1043) * Bump version to 1.17.0 (#1057) * Load views as needed (#1056) * [IMPROVEMENT] Change "resend" icon position (#1048) * [NEW] Video support (#801) * [NEW] File upload (#882) * [NEW] Share extension (#942) * [FIX] Share extension CI build (#1060) * Change bundleID * Provisioning * get provisioning profile * [IMPROVEMENT] Reusable toast (#1065) * [FIX] Moment locales (#1066) * [FIX] Share Extension issues (#1064) * [FIX] Empty white list enables all media types upload (#1077) * Merge branch 'master' into develop (#1079) * [FIX] Empty white list enables all media types upload (#1080) * Create utils to media (canUpload) * Fix variable name * [CHORE] Update README (#1081) * [FIX] Media share type (#1086) * [RELEASE] Merge beta into master (#1142) * [RELEASE] Merge beta into master (#1174) * [RELEASE] Merge beta into master (#1282) * Merge beta into master (#1461) * Merge beta into master (#1637) * Merge beta into master (#1759) * Merge beta into master (#1897) * [FIX] Close SortDropdown on sort select (#1230) * [FIX] Cancel upload and check failed upload (#1232) * [FIX] Slash commands not cleaning is typing and not using state (#1233) * [FIX] Dispatch roomsRequest on app foreground event even if not connected (#1234) * [CHORE] Update react-native-jitsi-meet (#1235) * [FIX] Regex on run slash command (#1223) * Update React Native to 0.61.1 (#1236) * Update React Native to 0.61.1 * Update patch to SSL Pinning * Revert storybook * [CHORE] Update react-native-safe-area-view (#1219) * [FIX] Try/catch JSON.parse XHR response (#1238) * [FIX] Change messagebox icon immediate on change text (#1241) * [FIX] Update last open on message stream received (#1240) * [FIX] Remove animation from RoomsListView.willFocus (#1239) * [FIX] Delete message on thread (#1214) * [REGRESSION] Markdown text (#1242) * [FIX] Jest (#1243) * [FIX] Avatar shown when useRealName is activated (#1162) * Fix avatar when use real name * Wrong indentation * [DOCS] Add SECURITY.md (#1244) * [CHORE] Update react-native-reanimated to 1.3.0 (#1246) * [FIX] Run credentials migration only once (#1245) * [CHORE] Update react-native-jitsi-meet to 2.0.1 (#1249) * [FIX] Messagebox onChangeText issues (#1252) * Stop ongoing debounces on messagebox unmount * Immediately change send icon, but keep debouncing others * Make CustomEmoji stateless function * Fix mentions keyExtractor * [FIX] Room subscription issues (#1255) * [FIX] Reaction press (#1258) * [FIX] Channel avatars not showing after application unloads (#1264) * Revert react-native-safe-area-view (#1265) * [FIX] Remove console on production mode (#1268) * [FIX] Messages preview issues (#1257) * [FIX] Select user from native credentials (#1266) * [FIX] Some issues on preview message (#1271) * [FIX] Audio player track and thumb not rendering on Android (#1273) * [FIX] Record audio message throws exception when FileSystem.getInfoAsync is called (#1272) * [FIX] China shouldn't use CallKit (#1274) * [FIX] Watermelon batches (#1277) * Bump version to 1.20.1 (#1285) * [CHORE] Remove memoize-one (#1284) * [FIX] End Jitsi call on unmount (#1291) * [FIX] Allow self-signed certificates (#1310) * [FIX] Set User-Agent (#1318) * Set User-Agent Fetch & Websocket & XHR * Set User-Agent * Custom User Agent on fetch/websocket * Fix names * Use DeviceInfo * fix server with subpath (#1322) * [FIX] Server with https:\\ instead of https:// (#1320) * [FIX] Server dropdown not closing after changing stack (#1299) * [FIX] Invalid server version (#1319) * [IMPROVEMENT] Respect "Hide counter" preference (#1306) * [FIX] Pass isFocused as a function to Messagebox (#1309) * [CHORE] Remove icons folder (#1290) * [CHORE] Refactor RoomItem touchable (#1331) * [FIX] Unnecessary rerender on RoomItem when status is undefined (#1336) * [UPDATE DEPS] react-navigation and react-navigation-stack (#1337) * [FIX] Avatars not loading on share extension when Accounts_AvatarBlockUnauthenticatedAccess is enabled (#1339) * Bump version to 1.20.2 (#1340) * [FIX] Remove some unnecessary re-renders on Messagebox (#1341) * [REGRESSION] Use LayoutAnimation instead of Transition API (#1338) * [FIX] Remove setState from notifications view causing watermelon object to be updated outside an action (#1342) * [IMPROVEMENT] Save last message as message when subscription is updated (#1344) * [UPDATE DEPS] Update RN to 0.61.3 (#1345) * [DOCS] Update Readme (#1346) * [CHORE] Remove react-native-scrollable-tab-view fork (#1352) * [FIX] URL preview (#1360) * [REGRESSION] Decrease list view memory size (#1361) * [FIX] Paste (#1350) * [CHORE] Update gems (#1365) * Bump version to 1.20.3 (#1366) * [FIX] Use Ruby 2.4 on TestFlight upload (#1368) * [FIX] Parse Urls (#1371) * [FIX] Parse image URL only if it's not empty (#1372) * [FIX] Load messages issues (#1373) * Bump version to 1.21.0 (#1376) * [FIX] Crowd login (#1381) * [FIX] Clicking user avatar in thread previews crashes app (#1363) * [IMPROVEMENT] Error messages on connect (#1379) * [FIX] ProfileView input navigation error when custom fields aren't set (#1383) * [FIX] Batch server deletion on logout (#1382) * Bump app to 1.22.0 (#1387) * [FIX] Server Version (#1392) * Update patch and minor deps (#1386) * [FIX] Crash when open thread (#1395) * Bump version to 1.23.0 (#1394) * [I18N] Update ru.js (#1384) * [FIX] CAS building wrong URL (#1362) * [FIX] Delete messages (#1399) * [FIX] In-app notification showing wrong content on channels (#1400) * Bump version to 1.24.0 (#1404) * [FIX] Prevent server with whitespace (#1402) * [IMPROVEMENT] Keyboard and content type on login (#1403) * [FIX] Messages stop loading (#1410) * [NEW] Tablet support (#1300) * [IMPROVEMENT] Authentication via deep linking (#1418) * [IMPROVEMENT] Markdown performance when identifying emoji only content (#1422) * [FIX] BackHandler remove random failing on development (#1423) * Bump version to 1.25.0 (#1424) * [CHORE] Update CI Xcode Image (#1430) * [FIX] Rooms grouping not working properly (#1435) * [FIX] Take a video (#1437) * [NEW] Themes (#1298) * [FIX] Share extension doesn't reconnect to previous selected server on Android (#1429) * [FIX] Init local settings on notification tap (#1438) * Bump version to 1.26.0 (#1450) * [FIX] Emoji parser not working on Hermes (#1445) * [NEW] Enable Hermes (#1446) * [FIX] Automatic theme repeating (#1457) * [CHORE] Sync Experimental and Official app versions (#1458) * [DOCS] Update readme (#1459) * [FIX] Messages being sent but showing as temp status (#1469) * [FIX] Missing messages after reconnect (#1470) * [FIX] Few fixes on themes (#1477) * [I18N] Missing German translations (#1465) * Missing German translation * adding a missing space behind colon * added a missing space after colon * and another attempt to finally fix this – got confused by all the branches * some smaller fixes for the translation * better wording * fixed another typo * [FIX] Crash while displaying the attached image with http on file name (#1401) * [IMPROVEMENT] Tap app and server version to copy to clipboard (#1425) * [NEW] Reply notification (#1448) * [FIX] Incorrect background color login on iPad (#1480) * [FIX] Prevent multiple tap on send (Share Extension) (#1481) * [NEW] Image Viewer (#1479) * [DOCS] Update Readme (#1485) * [FIX] Jitsi with Hermes Enabled (#1523) * [FIX] Draft messages not working with themed Messagebox (#1525) * [FIX] Go to direct message from members list (#1519) * [FIX] Make SAML wait for idp token instead of creating it on client (#1527) * [FIX] Server Test Push Notification (#1508) Co-authored-by: Diego Mello * [CHORE] Update to new server response (#1509) * [FIX] Insert messages with blank users (#1529) * Bump version to 4.2.1 (#1530) * [FIX] Error when normalizing empty messages (#1532) * [REGRESSION] CAS (#1570) * Bump version to 4.2.2 (#1571) * [FIX] Add username block condition to prevent error (#1585) * Bump version to 4.2.3 * Bump version to 4.2.4 * Bump version to 4.3.0 (#1630) * [FIX] Channels doesn't load (#1586) * [FIX] Channels doesn't load * [FIX] Update roomsUpdatedAt when subscriptions.length is 0 * [FIX] Remove unnecessary changes * [FIX] Improve the code Co-authored-by: Diego Mello * [FIX] Make SAML to work on Rocket.Chat < 2.3.0 (#1629) * [NEW] Invite links (#1534) * [FIX] Set the http-agent to the form that Rocket.Chat requires for logging (#1482) Co-authored-by: Diego Mello * [FIX] "Following thread" and "Unfollowed Thread" is hardcoded and not translated (#1625) * [FIX] Disable reset button if form didn't changed (#1569) Co-authored-by: Diego Mello * [FIX] Header title of RoomInfoView (#1553) * [I18N] Gallery Permissions DE (#1542) * [FIX] Not allow to send messages to archived room (#1623) * [FIX] Profile fields automatically reset (#1502) * [FIX] Show attachment on ThreadMessagesView (#1493) * [NEW] Wordpress auth (#1633) * [CHORE] Add Start Packager script (#1639) * [CHORE] Update RN to 0.61.5 (#1638) * [CHORE] Update RN to 0.61.5 * [CHORE] Update react-native patch Co-authored-by: Djorkaeff Alexandre * Bump version to 4.3.1 (#1641) * [FIX] Change force logout rule (#1640) * Bump version to 4.4.0 (#1643) * [IMPROVEMENT] Use MessagingStyle on Android Notification (#1575) * [NEW] Request review (#1627) * [NEW] Pull to refresh RoomView (#1657) * [FIX] Unsubscribe from room (#1655) * [FIX] Server with subdirs (#1646) * [NEW] Clear cache (#1660) * [IMPROVEMENT] Memoize and batch subscriptions updates (#1642) * [FIX] Disallow empty sharing (#1664) * [REGRESSION] Use HTTPS links for sharing and markets protocol for review (#1663) * [FIX] In some cases, share extension doesn't load images (#1649) * [i18n] DE translations for new invite function and some minor fixes (#1631) * [FIX] Remove duplicate jetify step (#1628) minor: also remove 'cd' calls Co-authored-by: Diego Mello * [REGRESSION] Read messages (#1666) * [i18n] German translations missing (#1670) * [FIX] Notifications crash on older Android Versions (#1672) * [i18n] Added Dutch translation (#1676) * [NEW] Omnichannel Beta (#1674) * [NEW] Confirm logout/clear cache (#1688) * [I18N] Add es-ES language (#1495) * [NEW] UiKit Beta (#1497) * [IMPROVEMENT] Use reselect (#1696) * [FIX] Notification in Android API level less than 24 (#1692) * [IMPROVEMENT] Send tmid on slash commands and media (#1698) * [FIX] Unhandled action on UIKit (#1703) * [NEW] Pull to refresh RoomsList (#1701) * [IMPROVEMENT] Reset app when language is changed (#1702) * [FIX] Small fixes on UIKit (#1709) * [FIX] Spotlight (#1719) * [CHORE] Update react-native-image-crop-picker (#1712) * [FIX] Messages Overlapping (Android) and MessageBox Scroll (iOS) (#1720) * [REGRESSION] Remove @ and # from mention (#1721) * [NEW] Direct message from user info (#1516) * [FIX] Delete slash commands (#1723) * [IMPROVEMENT] Hold URL to copy (#1684) * [FIX] Different sourcemaps generation for Hermes (#1724) * [FIX] Different sourcemaps generation for Hermes * Upload sourcemaps after build * [REVERT] Show emoji keyboard on Android (#1738) * [FIX] Stop logging react-native-image-crop-picker (#1745) * [FIX] Prevent toast ref error (#1744) * [FIX] Prevent reaction map error (#1743) * [FIX] Add missing calls to user info (#1741) * [FIX] Catch room unsubscribe error (#1739) * [i18n] Missing German keys (#1735) * [FIX] Missing i18n on MessagesView title (#1733) * [FIX] UIKit Modal: Weird behavior on Android Tablet (#1742) * [i18n] Missing key on German (#1747) Co-authored-by: Diego Mello * [i18n] Add Italian (#1736) … * [CHORE] Improve ISSUE_TEMPLATE.md (#2390) * Bump version to 4.11.0 (#2392) * [i18n] Update fr.js (#2380) * Update fr.js * Update fr.js * Update fr.js * Update fr.js * Update fr.js * Update fr.js Co-authored-by: Diego Mello * [CHORE] Add to internal lane instead of alpha (#2400) * [CHORE] Remove Google Services files from repo (#2405) * Android * iOS * [FIX] Fix broken StatusView on tablet (#2407) Signed-off-by: Ezequiel De Oliveira * [FIX] REST for method calls not raising errors (#2408) * [FIX] REST for Method calls not raising erorrs * Remove unnecessary lint disable * [NEW] Encrypt user credentials and preferences (#2247) * install react-native-mmkv-storage * wip ios migration * change all js rn-user-defaults -> react-native-mmkv-storage * remove all rn-user-defaults native references (iOS) * android migration from rn-user-defaults to react-native-mmkv-storage * ios app group accessible mmkv * handle get errors * remove access of credentials from legacy native apps * remove data of user defaults * remove no longer necessary import * js mmkv encryption * run migration only once * reply from notification android * fix app group key access at native level ios * encrypt user credentials using a specific key * ios encrypt with random key * use a random key at the first encryption * encrypt migrated data on js land * remove unused function * reply notifications ios should be working * use fix instanceID * android ejson retrieve encrypted data * remove encryption migrated data for a while * encryption working between app and share extension * fix patch react-native-notifications * ssl pinning working using mmkv encrypted data * improve react-native-notifications * run encrypt migration data only once * fix build * fix patches magic string * fix mmkv id * mmkv -> userPreferences * fix instance id on android migration * cast our oldest sharedPreferences string into an object * revert log remove * create currentServer Rocket.Chat key * wrap mmkv api class * change the get logic * move userPreferences to lib * move encrypt migrated data to userPreferences class * check if the new object is new before insert * invalidate ci yarn cache * fix sort migration from android shared preferences * fix splashscreen forever * invalidate yarn cache * invalidate yarn cache * fix patch * Minor change * fix android notifications looking for wrong mmkv instance * Fix some issues on iOS mmkv native access * Remove unnecessary code * Fix notification reply and ssl pinning * WIP NotificationService use MMKV credentials * Add KeychainGroup * Notification idOnly get credentials from mmkv * Some fixes * Invalidate yarn cache * Pods * Use MMKVAppExtension on NotificationService Co-authored-by: Diego Mello * [IMPROVEMENT] Use font icons on login services (#2412) * Replace font * Use CustomIcon * Remove native assets * [FIX] SharedPreferences data migration (#2413) * [IMPROVEMENT] Move directory to header (#2414) * [FIX] Android crashing on receive a notification (#2415) * [NEW] User notification preferences (#2403) * Button to preferences view Signed-off-by: Ezequiel De Oliveira * Create screen to preferences and listItem to notifications Signed-off-by: Ezequiel De Oliveira * Refactoring NotificationPreferencesView Signed-off-by: Ezequiel De Oliveira * List notification preferences Signed-off-by: Ezequiel De Oliveira * Adding translations to labels Signed-off-by: Ezequiel De Oliveira * SetUserPreferences api call Signed-off-by: Ezequiel De Oliveira * Saving new user preference in API Signed-off-by: Ezequiel De Oliveira * Fix lint Signed-off-by: Ezequiel De Oliveira * Add in-app notification test Signed-off-by: Ezequiel De Oliveira * Fix in app mentions preference Signed-off-by: Ezequiel De Oliveira * Improve object in testInAppNotification Signed-off-by: Ezequiel De Oliveira * Removing improper options for NotificationpreferencesView Signed-off-by: Ezequiel De Oliveira * Adding API version Signed-off-by: Ezequiel De Oliveira * Use redux in UserNotificationPrefView Signed-off-by: Ezequiel De Oliveira * Remove in app test Signed-off-by: Ezequiel De Oliveira * Use components from another view Signed-off-by: Ezequiel De Oliveira * Removing verification for testing in-app notifications Signed-off-by: Ezequiel De Oliveira * Move to ProfileView Co-authored-by: Diego Mello * [IMPROVEMENT] Verify Enterprise status on Omnichannel (#2399) * Add enterpriseModules on Redux * Fetch enterprise modules and put on redux * hasLicense * Clear modules * Hide omnichannel rooms * Minor refactor * Hide omnichannel toggle * Check license on user status * Apply on search * lint * Look for 'livechat-enterprise' * One module is enough to enable the features * Unhide omnichannel rooms * Sort tweaks * Move omnichannel toggle to RoomsListView * Remove omnichannel toggle from SettingsView * Fix toggle * Ask to enable omnichannel * Lint * Fix issues found on review * [FIX] Change some icons (#2419) * [FIX] User Preferences (#2418) * [FIX] User Preferences * PreferencesView -> UserPreferencesView Co-authored-by: Diego Mello * [IMPROVEMENT] Customize Sign in with Apple button (#2420) * [Snyk] Security upgrade lodash from 4.17.19 to 4.17.20 (#2416) The following vulnerabilities are fixed with an upgrade: - https://snyk.io/vuln/SNYK-JS-LODASH-590103 Co-authored-by: Diego Mello * [NEW] Add to F-Droid (#2171) * create play and foss build * update package.json to generate each build * check1 * requested changes * initial commit * Update config.yml * minor changes * remove bugsnag from foss build * remove bugsnag tasks from foss job * fix stuck screen * fixes * update * fix lint * finalise :rocket: * requested changes * share app for fdroid * update * use negation for builds * requested change * update share app * fix issues due to latest sync * add extra line * fix lint * update * update * fix bugsnag issue * Update config.yml * Fix store url * Foss release instead of debug * Add hold for foss * Fix build * requested changes * update name and icons * update * fix * Revert "Bump version to 4.11.0 (#2392)" This reverts commit ea287980d96b181b90b8db35dfa77f600d12d517. * finalise Co-authored-by: Djorkaeff Alexandre Co-authored-by: Diego Mello * [FIX] Commit pods after #2171 (#2424) * [IMPROVEMENT] Add subscription and room events on the same batch queue (#2423) * [IMPROVEMENT] Add subscription and room events on the same batch queue * Send both params * Unused var * [IMPROVEMENT] Show "Chats in Progress" group (#2425) * [NEW] Logout from other logged in locations (#2386) * Logout from other logged in locations * Add UI feedback for the request result * Refactor request to use the proper REST API * Change backgroundColor * I18n Co-authored-by: Diego Mello * [FIX] App can't reopening a room in some cases (#2429) * [FIX] Logout from custom oauth (#2377) * New field in table of users Signed-off-by: Ezequiel De Oliveira * Saving when the user logged in with email and password Signed-off-by: Ezequiel De Oliveira * Saving login method info Signed-off-by: Ezequiel De Oliveira * Ask for the user to clear cookies Signed-off-by: Ezequiel De Oliveira * Fix lint Signed-off-by: Ezequiel De Oliveira * Removing loginMethod from redux and add I18n Signed-off-by: Ezequiel De Oliveira * Using async/await instead of then/catch Signed-off-by: Ezequiel De Oliveira * Fix lint Signed-off-by: Ezequiel De Oliveira * Pods * Added dismissText on showConfirmationAlert * Fix iOS * Rename function * I18n tweaks Co-authored-by: Diego Mello * [FIX] Wrong date and time shown in file section (#2409) * Adding missing prop to item object Signed-off-by: Ezequiel De Oliveira * Resolving the missing date in the files section in a more elegant way Signed-off-by: Ezequiel De Oliveira * Using ts attribute always inside of an item object Signed-off-by: Ezequiel De Oliveira Co-authored-by: Diego Mello * [FIX] Verify useRealName setting on files screen (#2427) Signed-off-by: Ezequiel De Oliveira Co-authored-by: Diego Mello * [FIX] Apply theme on Directory description (#2428) Signed-off-by: Ezequiel De Oliveira Co-authored-by: Diego Mello * [FIX] Wrong merge resolution after #2171 (#2431) * [FIX] Upload to internal looking for the wrong path after #2171 (#2432) * [FIX] Detox tests (#2433) * Spotlight issues * Fix room tests * Fix roomactions tests * [FIX] Crashlytics reportError not working after #2171 (#2436) * [FIX] Logout from custom oauth when using password (#2435) * [FIX] Logout from custom oauth when using password * Remove an useless const Co-authored-by: Diego Mello * [IMPROVEMENT] Move toggle and inquiry to Enterprise Edition license (#2426) * [IMPROVEMENT] Move toggle and inquiry to Enterprise * Move inquiry stream to ee * Emit inquiry subscribe * imports to ee last * Add readme to ee Co-authored-by: Djorkaeff Alexandre * [CHORE] App Group path as a iOS constant (#2439) * [FIX] Chrome debugging * Remove rn-fetch-blob * [CHORE] Use Rocket.Chat JS SDK's official repo (#2440) Co-authored-by: Diego Mello * [IMPROVEMENT] Disable HTTP for production on Android (#2357) * Only enable HTTP and user CAs on debug builds and * Allow User CAs in prod * Add config on debug * Add lint Co-authored-by: Diego Mello * [NEW] E2E Encryption (#2394) * Add E2EKey to Subscription Model * Install react-native-simple-crypto * Install bytebuffer * Add translations * CreateChannel Encrypted toggle * Request E2E_Enabled setting * Add some E2E API methods * POC E2E Encryption * Garbage remove * Remove keys cleaner * Android cast JWK -> PKCS1 * Initialize E2E when Login Success * Add some translations * Add e2e property to Message model * Send Encrypted messages * (iOS) PKCS1 -> JWK & e2e.setUserPublicAndPrivateKeys * (Android) PKCS1 -> JWK & e2e.setUserPublicAndPrivateKeys * Create an encrypted channel * Fix app crashing on RoomsList * Create room key * Set Room E2E Key (Android) * Edit room encrypted * Show encrypted icon on messages * logEvents * Decrypt pending subscriptions & messages * Handle user cancel e2e password entry * E2ESavePasswordView * Update Snapshot * Add encrypted props to message on Send * Thread messages encryption * E2E -> Encryption * Share Extension: Share encrypted text * (POC) Search messages on Encrypted room * Provide room key to new users * Request roomKey on stream-notify-room-users * Add e2eKeyId to Room Model * (WIP) E2E Encryption Screens * Remove encryption subscription file * Move E2E_Enable to Server Model * Encryption List Banner * Move Encryption init to Sagas * Show banner only when enabled * Use RocketChat/react-native-simple-crypto * Search on WM only when is an Encrypted channel * (WIP) Encryption Banner * Encryption banner * Patch -> Fork * Improve send encrypted message * Update simple-crypto * Not decrypt already decrypted messages * Add comments * Change eslint disable to inline * Improve code * Remove comment * Some fixes * (WIP) Encryption Screens * Improve sub find * Resend an encrypted message * Fix comment * Code improvements * Hide e2e buttons on features if it is not enabled * InApp notifications of a encrypted room * Encryption stop logic * Edit encrypted message * DB batch on decryptPending * Encryption ready client * Comments * Handle getRoomInstance errors * Multiple messages decrypt * Remove unnecessary try/catch * Fix decrypt all messages history * Just add a questionmark * Fix some subscriptions missing decrypt * Disable request key logic * Fix unicode emojis * Fix e2ekey request * roomId -> subscription * Decrypt subscription after merge * E2ERoom -> EncryptionRoom * Fix infinite loading * Handle import key errors * Handle request key errors * Move e2eRequestRoomKey to Rocket.Chat * WIP handshake when key should be requested * Add search messages explanation * Remove some TODO and update comments * Improvements * Dont show message hash to user * Handle key request & prevent multiple calls * Request E2EKey on decryptSubscription that doesn't exists on database yet * Insert decrypted subscription * Fix crash after login * Decrypt sub when receive the key * Decrypt pending messages of a room * Encrypted as a switch * Buffer to Base64 URI Safe * Add a relevant comment * Prevent import key without a privateKey * Prevent create a new instance when client is not ready * Update simple-crypto & remove replace trick * More comments * Remove useless comment * Remove useless try/catch * I18n all E2E screens * E2ESavePassword -> E2ESaveYourPassword * Prevent multiple views on message when is not encrypted * Fix encryption toggle not working sometimes * follow some suggestions * dont rotate icons * remove unnecessary condition * remove unreachable event * create channel comment * disable no-bitwise rule for entire file * loadKeys -> persistKeys * getMasterKey -> generateMasterKey * explicit difference between E2EKey & e2eKeyId * roomId -> rid * group columns * Remove server selector * missing log events * remove comment * use stored public key * update simple-crypto & remove base64-js patch * add some logs * remove unreachable condition * log errors * handle errors on provide key directly on subscription * Downgrade RocketChat/react-native-simple-crypto * improve get room instance * migration of older apps * check encrypted status before send a message * wait client ready * use our own base64-js * add more jest tests * explain return * remove unncessary stop * thrown error to caller * remove superfluous checks * use Encryption property * change ready state logic * ready -> establishing * encryption.room -> encryptionRoom * EncryptionRoom -> Room * add documentation * wait establishing before provide a room key * remove superfluous condition * improve error handling logic * fallback e2ekey set * remove no longer necessary check * remove e.g. * improve getRoomInstance * import from index * use batch * fix a comment * decrypt tmsg * dont show hash when message is encrypted * Fix detox * Apply suggestions from code review Co-authored-by: Diego Mello * [CHORE] Update run-ios and run-android scripts (#2450) * [IMPROVEMENT] Show errors on server enter (#2449) * Catching errors * [IMPROVEMENT] Show errors on server enter * "Not rc server" instead of "invalid or insecure url" msg * [NEW] Show server history (#2421) * Add dropdown Signed-off-by: Ezequiel De Oliveira * Adding new table to serverSchema Signed-off-by: Ezequiel De Oliveira * Saving if not exists Signed-off-by: Ezequiel De Oliveira * list of visited servers finished Signed-off-by: Ezequiel De Oliveira * Fix lint Signed-off-by: Ezequiel De Oliveira * Rename ServerLinks to ServersHistory * Refactor * Save username * Sort servers desc * ServerInput * Item * Refactor * Layout tweaks * Layout * query by text * Small refactor * Redirecting to login * Save username for oauth * Fix keyboard persist * Add tests * Unnecessary yield * Stop rendering FlatList logic when there's no servers on history * Dismiss keyboard and autocomplete when tapped outside server TextInput Co-authored-by: Diego Mello * [NEW] Toggle analytics events (#2422) * Create flow to toggle analytics events on memory * Persist toggle analytics events * Update crash report to contemplate analytics events * Minor tweaks Co-authored-by: Diego Mello * [FIX] Local database searches using non-latin characters (#2462) * [FIX] Local database searches using non-latin characters * Add tests * [FIX] Read receipt crashing in some cases (#2464) * [IMPROVEMENT] Add "Allow_Save_Media_to_Gallery" setting (#2459) * [IMPROVEMENT] Add "Allow_Save_Media_to_Gallery" setting * Default true for old servers * [FIX] Jitsi breaking changes (#2468) * [FIX] Jitsi breaking changes * Update yarn cache * Update WatermelonDB to 0.19.0 (#2469) * [FIX] Jitsi breaking changes * Update yarn cache * Update watermelon to 0.19 * [FIX] SanitizeLikeString util crashes for empty strings (#2471) * [i18n] Add Traditional Chinese (zh_TW) (#2465) * I18n: Add Traditional Chinese language file(zh_TW) * Minor fixes * I18n: Add missing translation and fix some weird words * fix escape char * Fix minor issues Co-authored-by: Diego Mello * [I18n] Improve Simplified Chinese (zh_CN) (#2466) * I18n: Improve Simplified Chinese(zh_CN) language file * I18n: Add missing translation Co-authored-by: Diego Mello * [CHORE] Simplify i18n files (#2472) * [FIX] Remove assets from share extension on iOS (#2473) * [CHORE] Change database location to Experimental Apps (#2483) * change database location of experimental apps * fix migration from older versions * [FIX] WatermelonDB caching Date as String (#2484) Co-authored-by: Diego Mello * [NEW] E2E Encryption push (Android) (#2481) * poc push encryption android * eof * format code * react-native-simple-crypto update * prevent find sub twice * remove storage and use ejson storage * invalidate yarn cache * Bump crypto and fix db path * Fix google-services path Co-authored-by: Diego Mello * [FIX] Language set by web client (#2488) Co-authored-by: Diego Mello * [i18n] Improve Chinese translation (zh-TW, zh-CN) (#2486) Co-authored-by: Diego Mello * [i18n] Add missing italian strings (#2487) fix some existing ones too * [NEW] E2E Encryption push (iOS) (#2463) * link pods to notification service * push encryption poc * decrypt room key poc * read user key from mmkv and cast into a pkcs * push decrypt poc (iOS) * expose needed watermelon methods * watermelon -> database * indent & simple-crypto update * string extensions * storage * toBase64 -> toData * remove a forced unwrap * remove unused import * database driver * improvement * folder structure & watermelon bridge * more improvement stuff * watermelon -> database * reuse database instance * improvement * database fix: bypass watermelon cache * some code improvements * encryption instances * start api stuff * network layer * improve notification service * improve folder structure * watermelon patch * retry fetch logic * rocketchat class * fix try to decrypt without a roomKey * fallback to original content that is translated * some fixes to rocketchat logic * merge develop * remove unnecessary extension * [CHORE] Improve reply notification code (iOS) * undo sign changes * remove mocked value * import direct from library * send message request * reply notification with encrypted message working properly * revert apple sign * fix api onerror * trick to display sender name on group notifications * revert data.host change * fix some multithread issues * use sendername sent by server * small improvement * Bump crypto lib * Update ios/NotificationService/NotificationService.swift * add experimental string * remove trailing slash * remove trailing slash on reply * fix decrypt messages Co-authored-by: Diego Mello * [REGRESSION] HTTP Basic Auth (#2490) * [FIX] Logout when install fresh Official and Experimental iOS app (#2493) * [FIX] Show images in iOS 14 (#2494) * [DOCS] Add Reactotron (#2498) * Update about the inspection tool for our app. Information about the Reactotron tool was missing in the contribution file. * Update CONTRIBUTING.md Co-authored-by: Diego Mello * [REGRESSION] SSL Pinning stopped working after #2449 (#2510) * [CHORE] Reset yarn cache (#2512) * [FIX] Fastlane iOS (#2513) * [IMPROVEMENT] Add F-Droid modules as AdditionalModules (#2530) * [IMPROVEMENT] Add F-Droid modules as AdditionalModules * Fix missing import * [CHORE] Use App Store Connect API Key (#2549) * [CHORE] Use App Store Connect API Key * Update bundle * rollback keychain * Remove keychain * Keychain is actually needed * Update gitignore * [FIX] Failing iOS build on fork PR (#2558) * Fix fastlane build for a fork PR * Change the iOS fastlane command to build_fork * [FIX] Avatar cache invalidation (#2311) * [WIP] Avatar cache invalidation * [WIP] Avatar container * [IMPROVEMENT] Avatar container * [CHORE] Improve code * Allow static image on Avatar * Fix avatar changing while change username (#1583) Co-authored-by: Prateek93a * Add default props to properly update on Sidebar and ProfileView * Fix subscribing on the wrong moment * Storyshots update * RoomItem using Avatar Component * use iife to unsubscribe from user * Use component on avatar container * RoomItem as a React.Component * Move servers models to servers folder * Avatar -> AvatarContainer * Users indexed fields * Initialize author and check if u is present * Not was found -> User not found (turn comments more relevant) * RoomItemInner -> Wrapper * Revert Avatar Touchable logic * Revert responsability of LeftButton on Tablet Mode * Prevent setState on constructor * Run avatarURL only when its not static * Add streams RC Version * Move entire add user logic to result.success * Reorder init on RoomItem * onPress as a class function * Fix roomItem using same username * Add avatar Stories * Fix pick an image from gallery on ProfileView * get avatar etag on select users of create discussion * invalidate ci cache * Fix migration * Fix sidebar avatar not updating Co-authored-by: Prateek93a Co-authored-by: Diego Mello * [NEW] Channel avatars (#2504) * [WIP] Avatar cache invalidation * [WIP] Avatar container * [IMPROVEMENT] Avatar container * [CHORE] Improve code * Allow static image on Avatar * Fix avatar changing while change username (#1583) Co-authored-by: Prateek93a * Add default props to properly update on Sidebar and ProfileView * Fix subscribing on the wrong moment * Storyshots update * RoomItem using Avatar Component * use iife to unsubscribe from user * Use component on avatar container * RoomItem as a React.Component * Move servers models to servers folder * Avatar -> AvatarContainer * Users indexed fields * Initialize author and check if u is present * Not was found -> User not found (turn comments more relevant) * RoomItemInner -> Wrapper * Revert Avatar Touchable logic * Revert responsability of LeftButton on Tablet Mode * Prevent setState on constructor * Run avatarURL only when its not static * Add streams RC Version * Move entire add user logic to result.success * Reorder init on RoomItem * onPress as a class function * Fix roomItem using same username * Add avatar Stories * Fix pick an image from gallery on ProfileView * Format Avatar URL to use RoomId. Co-authored-by: Ezequiel De Oliveira * edit room avatar * invalidate cache of room images * reinit avatar if something change * read avatar cache on search * room avatar changed system message * add avatar by rid test * update snapshot * etag cache on select channel * reset room avatar * increase caching to have a better image quality * fix lgtm warn * invalidate ci cache * get avatar etag on select users of create discussion * invalidate ci cache * Fix migration * Fix sidebar avatar not updating * Remove outdated comment * Tests Co-authored-by: Prateek93a Co-authored-by: Diego Mello Co-authored-by: Ezequiel De Oliveira * [IMPROVEMENT] List Component (#2506) * List.Item * section * Start removing theme as prop * Remove StatusBar theme prop * SafeAreaView theme prop * Minor fixes * List.Container * Add translateTitle and translateSubtitle props * Storybook * Show action indicator * Header * Info * Theme stories * FlatList * DisplayName * Fix settings * FlatList tweaks * ThemeView * Screen Lock Config * DefaultBrowserView * PickerView and User Prefs * Notification Prefs * StatusView * Auto Translate * InviteUsersEdit * Visitor * Minor fixes * Remove Separator * Remove iteminfo * Font scale * Legal * Jitsi and e2e * Block * search, star, etc * auto translate and notifications * RoomInfo * Refactor RoomActions * lint * Remove DisclosureIndicator * padding horizontal 12 * Detox * Tests * Address review comments * Fix vertical scroll Co-authored-by: Djorkaeff Alexandre * [FIX] App always sends auth for Avatar requests (#2517) * [FIX] Sending auth for Avatar requests when not necessary * fix storybook * Fix ShareListView not updating avatars Co-authored-by: Diego Mello * [FIX] iOS uploads always cropping as squares (#2516) Co-authored-by: Diego Mello * [IMPROVEMENT] Mentions layout without background (#2559) * [IMPROVEMENT] Mentions layout without background * Fix RoomItem * Fix tests * [IMPROVEMENT] Support badge number on header buttons (#2566) * Beginning header buttons refactor * Add HeaderButtons * item with title * Refactor * Remove lib * Refactor * Update snapshot * Refactor * Update tests * Lint * [NEW] Threads (#2567) * [IMPROVEMENT] Mentions layout without background * Fix RoomItem * Fix tests * Smaller messagebox * Messagebox colors tweak * Beginning header buttons refactor * Add HeaderButtons * item with title * Refactor * Remove lib * Refactor * Update snapshot * Send to channel on messagebox * Add tshow * Add showMessageInMainThread to login.user reducer * Filter threads on main channel based on user setting * Send tshow * Add tunread * Move unread colors logic away from UnreadBadge component so it can be used on other components * Export UnreadBadge on index * Add empty test * Refactor * Update tests * Lint * Thread unread user and group on RoomItem * Thread badge working * Started ThreadMessagesView.Item * Fix separator * Reactivity working * Lint * custom emojis aren't necessary * Basic filter layout * Filtering layout * Refactor * apply filter * DropdownItemHeader * default all * few fixes * No data found * Fixes list performance issues * Use locale on date formats * Fixed minor styles * Thread badge * Refactor getBadgeColor * Fix send to channel background color * starting search threads * Fix lint and tests * Bump to 4.12.0 just for testing :) * Search input layout * query * starting threads header * fix unnecessary tlm on tmid messages * Fix thread header * lint * Fix thread header on ShareView * Add e2e tests * Fix subscriptions sort * Update stories and minor fixes * Fix button sizes on Messagebox * Remove comment * Unnecessary conditional * Add showMessageInMainThread to user collection * Fix thread header * Fix thread messages not working on tablet * Reset Messagebox.tshow after sending a message * Allow to send to channel when replying to a thread from main channel * Unnecessary theme prop * Address comments * Remove re-render * Fix scroll indicator bug * Fix style * Minor i18n fix * Fix dropdown height * I18n ptbr * I18n * [IMPROVEMENT] Android push notification as a heads-up notification (#2507) Co-authored-by: Diego Mello * [IMPROVEMENT] Add `Change Encryption Password` and `Reset E2E Key` (#2542) * init * Basic tests passing * Add SecurityPrivacyView * List.Item * section * Start removing theme as prop * Remove StatusBar theme prop * SafeAreaView theme prop * Minor fixes * List.Container * Add translateTitle and translateSubtitle props * Storybook * Show action indicator * Header * Info * Theme stories * FlatList * DisplayName * Fix settings * FlatList tweaks * ThemeView * Screen Lock Config * DefaultBrowserView * PickerView and User Prefs * Notification Prefs * StatusView * Auto Translate * InviteUsersEdit * Visitor * Minor fixes * Remove Separator * Remove iteminfo * Font scale * Legal * Jitsi and e2e * Block * search, star, etc * auto translate and notifications * RoomInfo * Refactor RoomActions * lint * Remove DisclosureIndicator * padding horizontal 12 * Detox * Tests * SecurityPrivacy * E2E encryption sec view * stash * Reset own key * Reset key * Change password * Hide content * Small refactor * Fix tests * Tests passing * Change test order * add pt-br * Address review comments * tests * Missing i18n ptbr Co-authored-by: Djorkaeff Alexandre * [IMPROVEMENT] Branding update (#2580) * iOS native icons * Android native icons * Foss native icons * Experimental icon iOS * Experimental * Notification icon * Splash screen * Splash screen iOS * Blue notification text * Fix iOS Launch Screen Icon * Experimental and foss Co-authored-by: Diego Mello * [CHORE] Update Xcode to 12.1.0 (#2592) * [CHORE] Update Xcode to 12.1.0 * Remove alpha from Xcode App Store Icon * [IMPROVEMENT] Auto search when text changes in directory textfield (#2547) Co-authored-by: Djorkaeff Alexandre Co-authored-by: Diego Mello * [FIX] Rooms header overlapping right icons (#2503) takes into account long names on small screen which led to overlapping title and right buttons on the header bar * [IMPROVEMENT] Jitsi lean (#2534) * 2.10.2 * update jitsi sdk * use our own react-native-jitsi-meet * use own android jitsi sdk * remove jsc reference * use self-builded ios sdk * update react-native-jitsi-meet Co-authored-by: Diego Mello * [i18n] German word fix (#2598) Report in German means "The Report" not "to report". Therefor "Melden" ist better suited here. Co-authored-by: Diego Mello * [i18n] Improve Chinese translation (#2570) * [FIX] App crashing when notification is received/replied (Android) (#2602) Co-authored-by: Diego Mello * [FIX] Update react native CLI to support white labeling with XCode 12 (#2560) Co-authored-by: Diego Mello * [i18n] Add missing German strings (#2571) * adding missing German strings * resolving conflict Co-authored-by: Diego Mello * [REGRESSION] Avatars doesn't show up on older servers (< 3.6.0) (#2603) * [REGRESSION] Avatars doesn't show up on older servers (< 3.6.0) * fix: snapshots tests failing Co-authored-by: Diego Mello * [FIX] Missing locales in moment helper (#2562) * [i18n] Add missing Russian strings (#2555) * Added waiting for network string translate * [i18n] Add missing russian strings * Some E2E strings * [i18n] Add missing russian strings * Some grammatical changes and translate optimizations * Add english strings * Final translate Co-authored-by: Карлан Антон Андреевич Co-authored-by: Diego Mello * [FIX] 'Send to channel' when replying as a quote (#2606) Co-authored-by: Diego Mello * [FIX] Android notification on Dark Theme using Official main color (#2604) Co-authored-by: Diego Mello * [FIX] Storybook not able to import Avatar (#2607) * [FIX] Storybook not able to import Avatar * Fix lint * Mock Date.now * Fix RU translation * isLegacy -> serverVersion * Remove change avatar from room info edit for servers below 3.6 * Mock for storyshots only * lint Co-authored-by: Diego Mello * [BUG] App isn't showing message for PDF/file uploads (#2584) * Fixed the issue #2531 In app/containers/message/Reply.js added a View Contaier around the Attachment Touchable and Added a Markdown attribute with msg set to description of attachment to display the message if any. * Added the condition to check if File Description Exists Added an if statement to check if file description exists and if yes then add a markdown with value msg equal to the description. Also tested using 'yarn test -u' to add/update the tests. * Made the requested Changes Removed the condition to check for attachment description. Added the `markdown` inside the touchable and wrapped `attachmentContainer` and the `markdown` inside a `<>` component * Added file not showing message issue code in this branch * Fixed the mistake in return * fix * Add tests Co-authored-by: Diego Mello * [FIX] Header title positioning not changing according to the number of icons (#2608) * [DOCS] Update Android Supported versions (#2611) * [i18n] Improve Russian translation (#2609) Co-authored-by: Diego Mello * [FIX] User notification preferences throwing an error when select default Email option (#2615) Co-authored-by: Diego Mello * [FIX] MomentJS crashing on Spanish language (#2616) Co-authored-by: Diego Mello * [FIX] AllowBackup manifest attribute causing unexpected behaviour on login (#2617) * [FIX] Search messages crashing when show a thread message (#2618) Co-authored-by: Diego Mello * [FIX] F-Droid build for store (#2557) * [FIX] F-Droid build for store * Trying to make Override custom push notifications on play build only * Use play sourceSets * Change version code * Fix react-native-config-reader * [FIX] F-Droid build for store * Trying to make Override custom push notifications on play build only * Use play sourceSets * Change version code * Fix react-native-config-reader * Remove react-native-device-info Google dependencies / Use LIBRE_BUILD of react-native-jitsi-meet * Invalidate CI Cache * Set specific jitsi-meet-sdk * Specify 2.10.0-libre * jitsi-meet using an url based on play build * update react-native-jitsi-meet * react-native-device-info foss * undo some unnecessary changes * Fix notifications Co-authored-by: Djorkaeff Alexandre * Merge beta into master (#2621) * Sync develop on master (#275) * Create LICENSE * Sync master (#721) * Merge 1.13.0 into Master (#936) * fix last messages (#239) * fix last messages * Room actions (#231) * Layout * Empty starred list * Favorite room * Pinned messages * fix last messages * fix date on pinned messages * fix package * [NEW] OAuth (#241) * Layout * tmp * test iscordova * Webview redirecting * Open and Close login actions * Login services saved on redux * OAuth Github * Server regex fix * OAuth modal style * - Twitter login - Remove services from redux - Open login saga fix * - Facebook login - Fixed user agent - Reactions fix - Message url unique key fix * Google login * Email keyboard removed from messagebox * - Login buttons refactored - RoomList header * Layout improvements * Meteor login redirect_uri changed * fix * Random credentialToken state * [NEW] Room actions: Mentioned messages and Room Members (#242) * Mentioned messages * Starred and pinned actions debounce * Room members * Open room on member touch * [WIP] Improves (#245) * hotfix for ios * hotfix for ios * Update config.yml * Workaround for RN 0.54 on iOS (#246) * Update iOS to RN 0.54 (#248) * Update iOS to RN 0.54 * [WIP] Audio message functionality (#247) * [NEW] Add module react-native-audio * [WIP] Audio message basic UI * [NEW] Record audio message * Use cordova repository to get certificates * Icon 1024 * [NEW] Room actions: block user, snippet messages, room files and leave room (#250) * - Block user - Load room members async - fixed reactive change of room's read only flag * Snippet messages * - Room files - Dismiss Video component on back button press - Improvements on Image component * Improvement on Video component * Leave room * Missing message types * lint * Reactotron working (#249) * [NEW] Room info and Room info edit (#254) * - Block user - Load room members async - fixed reactive change of room's read only flag * Snippet messages * - Room files - Dismiss Video component on back button press - Improvements on Image component * Improvement on Video component * Leave room * Missing message types * lint * - Room info (read only) - Missing message types * Room info scroll * - Tap on room header opens room info - Layout tweaks * - Room info edit - iOS Toast fixed * - Style not implemented actions as disabled * Edit room permission * - Save all room settings in a single call - Implemented roomType and readOnly * - Allow reacting when room is read only * Message type added: room_changed_privacy * Erase room * Created TextInput and SwitchContainer components for reuse and readability * - hasPermission method * - Archive/Unarchive room - Set Join Code * Twitter keyboard type on iOS * Archived room * reactWhenReadOnly permission on message * Active users refactored * User roles * - Subscribe to roles (in order to get role description info: e.g. 'core-team' to 'Rocket.Chat Team') - Save roles to realm (for offline access) - Save roles to redux (and get data from realm on app init) * Lint * code style * password show/hide feature * fix show/hide password * password show/hide * Crashlytics (#258) * Fabric iOS * Fabric configured on iOS and Android * login tracked * more logs * fix reaction * CI fix * Bug fixes (#261) * Layout fixes * RoomsListView's SafeAreaView * Unhandled promise rejection fix * Prevent navigation from opening scenes twice * Create channel fixes * Create LICENSE * Beta (#265) * Fabric iOS * Fabric configured on iOS and Android * - react-native-fabric configured - login tracked * README updated * Run scripts from README updated * README scripts * get rooms and messages by rest * user status * more improves * more improves * send pong on timeout * fix some methods * more tests * rest messages * Room actions (#266) * Toggle notifications * Search messages * Invite users * Mute/Unmute users in room * rocket.cat messages * Room topic layout fixed * Starred messages loading onEndReached * Room actions onEndReached * Unnecessary login request * Login loading * Login services fixed * User presence layout * ïmproves on room actions view * Removed unnecessary data from SelectedUsersView * load few messages on open room, search message improve * fix loading messages forever * Removed state from search * Custom message time format * secureTextEntry layout * Reduce android app size * Roles subscription fix * Public routes navigation * fix reconnect * - New login/register, login, register * proguard * Login flux * App init/restore * Android layout fixes * Multiple meteor connection requests fixed * Nested attachments * Nested attachments * fix check status * New login layout (#269) * Public routes navigation * New login/register, login, register * Multiple meteor connection requests fixed * Nested attachments * Button component * TextInput android layout fixed * Register fixed * Thinner close modal button * Requests /me after login only one time * Static images moved * fix reconnect * fix ddp * fix custom emoji * New message layout (#273) * Grouping messages * Message layout * Users typing animation * Image attachment layout * Fabric and image fix (#284) * Fixed images not showing * Keyboard libs updated * Fabric fix and location removed (#286) * Proguard disabled * message with list + links fixed (#288) * Better image cache component (#292) * react-native-img-cache removed * Improve list render * Support inside markdown * Deep linking (#291) * deep linking * Basic deep link working * Deep link routing * Multiple servers working * Send user to the room * Avatar initials and room type icon (#298) * Deep linking fix and more (#294) * Fix - Any https link was deep linking to RocketChat * Keyboard dismiss after add new server * Room info bug fix * Opacity animation * Navigation when adding server fixed * Throttle for unnecessary render on receiving several messages * Search inputs without autocorrect and autocapitalize * Search messages fixed * Messagebox unnecessary render and spotlight fixed * react-native-keyboard-input updated * Lint * Tests updated * Update all dependencies (#299) * Update react-navigation to the latest version 🚀 (#293) * fix(package): update react-navigation to version 2.0.0 * Code updated to support breaking changes of react-navigation * Detox tests E2E (#283) * RoomsListView re-render (#304) @RocketChat/ReactNative - [x] Removed unnecessary re-renders on RoomsListView * [NEW] Broadcast channels (#301) * Broadcast channels * e2e tests * New markdown (#306) Our current markdown is causing a lot of issues on Android devices, since it wraps everything inside a Text component. On Android, Text doesn't support View as a child. This PR adds react-native-markdown-renderer, that uses View as wrapper and may be better. * Fixed audio recording issues (#310) * Fix for "java.lang.IllegalArgumentException: unexpected url" (#313) @RocketChat/ReactNative User was able to add an invalid instance of Rocket.Chat by pressing submit button instead of "Connect" button. * I18n (#312) * Unread and date separator layout improved (#319) @RocketChat/ReactNative - [x] Unread and date separator layout - [x] "Start of conversation"/"Loading messages" label ![screen shot 2018-05-30 at 18 10 43](https://user-images.githubusercontent.com/804994/40747867-0424964a-6435-11e8-9293-31cc43c110ab.png) ![screen shot 2018-05-30 at 18 09 05](https://user-images.githubusercontent.com/804994/40747868-04484784-6435-11e8-8c31-92e0776276f0.png) * [FIX] iOS Universal links (#318) * [NEW] Drawer (#322) * [FIX] invalid user muted value * Ddp fixes (#324) * [NEW] User Profile (#323) * Drawer layout * Drawer changes * Profile * Profile avatar * Set language * Tests * Custom fields * Readme updated * fix invalid user muted value * Fix for "Cannot add a child that doesn't have a YogaNode to a parent without a measure function! (Trying to add a 'RCTVirtualText' to a 'RCTView')" * Settings/Permissions improvements (#325) * Changed the way we read RocketChat settings since setting.type won't be returned from server anymore * Permissions * Unnecessary action sheet render * Update gradle and targetSdkVersion (#328) * Changed the way we read RocketChat settings since setting.type won't be returned from server anymore * Permissions * Unnecessary action sheet render * Update gradle * Switched testServer to use blob * RoomsListHeader search fixed * Runs loadMessagesForRoom only if room has at least 20 rows * - Logout if user's token expired - Removed update avatar logic - Profile dialog border on android * - Animations disabled - CircleCI set * Tests updated * "eventType argument is required" fix * Switch push notification lib (#346) @RocketChat/ReactNative Closes #342 * Allow x-instance-id and X-Instance-ID header (#354) @RocketChat/ReactNative Closes #137 Some server configurations may send x-instance-id header with different case. * Image upload improvements (#368) @RocketChat/ReactNative - [x] Crop image - [x] Type image description (like web) - [x] Show upload progress - [x] "Try again" in case of error - [x] Cancel upload while in progress - [x] [Android] Zoom on photos ![image](https://user-images.githubusercontent.com/804994/42526934-a12da304-844d-11e8-8668-f3d69369726a.png) ![image](https://user-images.githubusercontent.com/804994/42527829-297945fe-8450-11e8-9f0e-9e668dd33043.png) * [NEW] Room Loading(#372) @RocketChat/ReactNative * [FIX] Empty room name for livechat (#375) @RocketChat/ReactNative Closes #320 Closes #209 * [NEW] Reply preview (#374) * Updated to React Native 0.56 * Reply Preview * [FIX] Close websocket (#379) * Fixed a bug when closing websocket * removeListener fixed * [I18N] Russian translation (#381) [I18N] Russian translation file * [NEW] Icon (#383) @RocketChat/ReactNative ![image](https://user-images.githubusercontent.com/804994/43228416-d8af49d6-9037-11e8-8830-a1803932c7fd.png) * [FIX] Android 8 notifications (#382) @RocketChat/ReactNative Closes #380 * Added CocoaPods to manage react-native-image-crop-picker (#373) @RocketChat/ReactNative react-native-image-crop-picker raised an error when uploading to TestFlight. The lib highly recommends CocoaPods for production builds. * Added single-server to readme (#390) @RocketChat/ReactNative Closes #386 Closes #295 * Improve RoomsList render time (#384) @RocketChat/ReactNative - [x] Added FlatList.getItemLayout() to improve list render time - [x] Some texts were breaking lines at sidebar - [x] Removed onPress from links at RoomsListView - [x] Added eslint rule to prevent unused styles - [x] Fixed auto focus bug at CreateChannel and NewServer - [x] Fix change server bug - [x] Fixed a bug when resuming in ListServer - [x] I18n fixed - [x] Fixed a bug on actionsheet ref not being created - [x] Reply wasn't showing on Android - [x] Use Notification.Builder.setColor/getColor only after Android SDK 23 - [x] Listen to app state only when inside app - [x] Switched register push token position in order to improve login performance - [x] When deep link changes server, it doesn't refresh rooms list - [x] Added SafeAreaView in all views to improve iPhone X experience - [x] Subpath regex #388 * [NEW] Empty room background (#412) @RocketChat/ReactNative Closes #398 ![aug-09-2018 11-35-32](https://user-images.githubusercontent.com/804994/43906080-cbfadf92-9bc8-11e8-9ac9-44f43d3af023.gif) ![aug-09-2018 11-35-16](https://user-images.githubusercontent.com/804994/43906082-cc19411c-9bc8-11e8-9892-c65c86951a91.gif) ![image](https://user-images.githubusercontent.com/804994/43911366-ad830cd0-9bd5-11e8-8913-6a7e87a2206c.png) * Add roadmap (#406) @RocketChat/ReactNative Closes #45 * [NEW] Onboarding (#407) @RocketChat/ReactNative Closes #392 ![aug-07-2018 17-03-50](https://user-images.githubusercontent.com/804994/43799447-f62074dc-9a63-11e8-8aac-bf2c4c5a8a2b.gif) ![aug-07-2018 17-03-35](https://user-images.githubusercontent.com/804994/43799446-f5f84a70-9a63-11e8-8947-265113ae9bf4.gif) ![aug-07-2018 17-03-13](https://user-images.githubusercontent.com/804994/43799445-f5d70ee6-9a63-11e8-94a9-f49c7d69fbba.gif) * [NEW] Updated Logo on Splash screen (#409) @RocketChat/ReactNative Closes #399 ![aug-07-2018 17-39-44](https://user-images.githubusercontent.com/804994/43801415-739a0cca-9a69-11e8-8bec-d65f751e6a28.gif) ![aug-07-2018 17-31-12](https://user-images.githubusercontent.com/804994/43801416-73d19bd6-9a69-11e8-90ac-bbc7ddeed938.gif) * [FIX] Only single attachment rendered (#417) * [NEW] Rooms list layout (#413) * RoomsListView layout * Rooms list layout * Sort component * Header icons * Default header colors * Add server dropdown * Close sort dropdown if server dropdown will open * UserItem * Room type icon * Search working * Tests updated * Android layout * Using realm queries instead of array iterates * Animation duration * Fixed render bug * [NEW] Create channel layout (#420) * RoomsListView layout * Rooms list layout * Sort component * Header icons * Default header colors * Add server dropdown * Close sort dropdown if server dropdown will open * UserItem * Room type icon * Search working * Tests updated * Android layout * Using realm queries instead of array iterates * Animation duration * Fixed render bug * - NewMessageView - backButtonTitle always empty - SearchBox created * New create channel layout * Search refactored * loginSuccess dismiss modal * Tests working * [FIX] Open unsupported videos on browser (#422) * 1.1 * Sort/group rooms local only (#425) * Update android api from ci * Sort local only * [FIX] Missing current server (#427) * server.current removed * Increased area of touch on header * Hide search when sort dropdown is tapped * default server icon url * 1.1.1 * [NEW] Experimental Icon (#430) * [NEW] Message layout (#426) * message container/component * Separator component * Reply * Url * tests updated * Minor changes * Audio component * Broadcast button * Minor touches * Reply preview * Edited * Minor bug fixes * - Update roadmap - Bump version to 1.2 * Onboarding styles fix * [FIX] Drawer navigation won't refresh chats (#432) * Avoid errors on Audio/Image/Video (#443) * Bump version to 1.2.1 (#444) * Stop supporting Android 4.4 and lower (#447) * Several fixes for 1.2.1 (#448) * Fix user.roles * Better onLongPress handle on messages * Indicator position * Fix role undefined in system messages * Add baseUrl in case of file attachments * Join room fixed * RoomView params * Broadcast fixes * Add server layout changes * Use native images * Subscribe to not joined channels * Fix alerts without i18n * Tests updated * Bump version to 1.2.2 (#449) * [NEW] Use community JSC for Android (#450) * [NEW] Use community JSC for Android * Quick fix on unread chats * [NEW] Show app version (#454) * [NEW] Portuguese translation (#452) * [NEW] Portuguese translation * Remove servers from sidebar * Update dependencies (#431) * Update dependencies * Lint and test * Added react-native fork * rn 57 * Lint and tests updated * Update xcode on circleci * Use legacy build system * Update tests * Use inline requires (#459) * Update dependencies * Lint and test * Added react-native fork * rn 57 * Lint and tests updated * Update xcode on circleci * Use legacy build system * Update tests * Inline requires * Fix eslint and remove temp gradle * Unnecessary renders * Update isNotch and Readme * Tests updated * Bump version to 1.3.0 (#461) * Better touch handling on rooms list (#462) * Use react-native-gesture-handler at RoomItem * Fixed info message author * Edit message render improvement * Fix ws to http replace * Bump version to 1.3.1 (#463) * Composer layout tweaked (#464) * Composer layout tweaked * Fix localization error * Bump version to 1.3.2 * [FIX] Handle deleted messages (#466) * [FIX] Handle deleted messages * Fix rest error * Fix some connection issues * [FIX] Search rooms (#468) * Bump version to 1.3.3 (#469) * Connecting to DDP badge (#471) * Display custom fields on user info (#476) * Render custom fields on user info * renderCustomFields fix * Display custom fields in user info * Fix lint error * [FIX] DDP badge wasn't hiding on fast connections (#477) * Use Rocket.Chat JS SDK (#481) * JS SDK * API working * Multiple servers * Bump version to 1.4.0 (#482) * [FIX] 2FA and LDAP (#488) * [FIX] Unread rooms group order (#487) * Use grouping setting on temp messages (#486) * [FIX] Delete room error (#485) * Rename to Rocket.Chat Experimental (#483) * Update dependencies (#484) * Bump version to 1.4.0 (#482) * test * one more test * Fix build * Regression: Wait for unmount to delete database after logout (#489) * Bump version to 1.4.1 (#490) * Regression: Crash on Android search (#492) * Bump version to 1.4.2 (#493) * Update Rocket.Chat.js.SDK (#494) * Bump version to v1.4.3 (#495) * [FIX] OAuth (#496) * Smaller header icons inside the room (#499) * [FIX] Logout (#497) * [FIX] Logout * Removed realm instances on rooms list * Bump version to 1.4.4 (#498) * Update navigation library (#501) * v2 * Working on Android 0.57.3 * Drawer working * Removing v1 navigator * - Splash screen - Icons changed * Deeplink * Remove EventEmitter from CreateChannelView * Android search * Android notifications * OAuth * Fix search props * Lint and tests fixed * Fix android build * Improvements on iPhone X* usage * Fix detox * Fix android build * Room.f added to RoomView.shouldComponentUpdate * Animations on RoomsListView and RoomView * Fix topbar buttons on Android * Bump version to 1.5.0 (#503) * Check $FABRIC_KEY availability in CircleCI (#506) * Check $FABRIC_KEY in CircleCI * Remove config scripts * Check $FABRIC_KEY availability in CircleCI for iOS (#507) * [I18n] Add Simplified Chinese(zh-CN) locale (#505) * [FIX] iOS pop gesture not working properly (#509) * Check if lastMessage has an attachment and show "User sent an attachment" at RoomsList (#510) * [FIX] Messages not being loaded properly (#513) * Fetch avatar initials from server (#512) * Fix iOS pop gesture and open sidemenu gesture (#511) * Bump version to 1.5.1 (#516) * [NEW] Room header layout (#521) * Clear iOS notification on resume/open (#520) * [FIX] Flashing avatars on Android after #512 (#519) * [FIX] App connects to previous server instead of the recent added (#518) * [FIX] Room view header crashes when destructuring reducer (#523) * [FIX] Dismiss keyboard on room close (#530) * [FIX] Composer composer's send icon slowness (#528) * [WIP] New Authentication layout (#536) New Authentication layout * Regression: Resend messages with error (#532) * DDP Connection badge animation changed (#533) * [FIX] Upload buttons on Android (#541) * Bump version to 1.6.0 (#543) * I18n: Add missing translation of simplified Chinese (#539) * Update dependencies (#544) * AndroidManifest changes * Regression: Deep linking stopped working after react-native-navigation update (#549) * [FIX] Android stuck on splash screen after hardware back button is pressed (#550) * [FIX] Android stuck on splash screen after hardware button is pressed * Fix empty user at asyncstorage * Remove unused subscribe * [FIX] x-instance-id header prop is case insensitive (#551) * Bump version to 1.6.1 (#553) * [FIX] x-instance-id header prop is case insensitive * Use Rest API calls (#558) * Chats: Don't show group header if none of the filters is selected (#560) * [CHORE] Update Xcode image version on CircleCI (#561) * Bump version to 1.7.0 (#562) * [FIX] Load messages on notification tap (#564) * Use Rest API pt 2 (#568) * Room files * Pinned messages * Starred messages * Mentioned messages * Search messages * Bug fixes * Profile * Livechat * Block/unblock user * Erase room * Archive room * Remove unused method * Bug fix * [CHORE] Add hold step on CircleCI before TestFlight (#572) * [FIX] GET /info to check if it's a valid server instead of x-instance-id (#573) * Bump version to 1.7.1 (#574) * Unnecessary re-renders removed (#570) * shouldComponentUpdate * Rooms list shouldcomponentupdate * RoomView shouldComponentUpdate * Messagebox and Message shouldComponentUpdate * EmojiPicker shouldComponentUpdate * RoomActions shouldComponentUpdate * Room info shouldComponentUpdate * Update RNN * Use only one Flatlist if none group filter is selected * Update fix * shouldComponentUpdate * Bug fixes * ListView changes * Bug fix * render list bug fix * Changes on public channels * - RoomView saga leak removed - Join room e2e tests added * Rest versions * Method call versions * Min RocketChat version alert * Update dependencies (#587) * [FIX] Better message actions (#567) * [FIX] Back button press on message actions (#592) * Bump version to 1.8.0 (#595) * [FIX] LDAP login (#596) * Create class to manage navigation (#594) * Add Navigation class * Place Drawer.js logic inside of Navigation * Load less views at startup * [FIX] v1.8.0 (#599) * Downgrade react-native-fast-image * Update iOS permission usage descriptions * [FIX] Delete upload item * Update JS SDK version (#602) * Add Icons class (#611) Creates Icons class to manage when to load icons from native side or react-native-vector-icons. It also fixes `react-native run-android` #517 * Updating room indicator (#609) Shows "Updating..." when requesting rooms from Rest API. * [FIX] Load avatar on servers that prevent unauthenticated avatar access (#604) App would show an empty space on servers that require authentication on avatar access * [FIX] 2FA login in a server with LDAP enabled (#612) * [FIX] Start loop searching for rooms updates only when connection goes down and SDK has userId (#613) * Allow to create empty channel (#615) * [FIX] Reply title should break text (#616) * Bump version to 1.9.0 (#617) * [FIX] SDK issues (#621) * Remove listeners from room * Properly close connections on change server * Minor layout change on connecting badge * [CHORE] Add TestFlight invite and update Readme (#623) * [FIX] npm -> yarn dependencies migration (#622) * I18n: Add French (#629) * [FIX] Remove rooms listener (#630) * [CHORE] Update issue template (#638) * I18n: Add German (#641) * Bump version to 1.10.0 (#644) * [FIX] Prevent mass is typing dispatchs (#651) * [FIX] Handle database errors properly (#650) * [FIX] Change actions labels (#654) * [FIX] Room members filter (#655) * [FIX] uploadProgress is not a function (#656) * [FIX] Slow messagebox (#658) * Remove drawer (#653) * Remove drawer (layout needs to be changed in future releases, though) * Don't navigate outside on logout if there's other logged server * Update react-native-navigation * Message button (#660) * Remove touchable opacity when scrolling messages * Tap on disable messages closes keyboard * Unify vibration * Vibrate only on Android * [FIX] Fetch rooms date (#662) * [FIX] Select emoji error (#666) * Update Realm to 2.24 (#667) * Update React Native to 0.58.6 (#668) * [FIX] Fix some language issues in German language (#664) * New icons (#643) * New Icons * Remove unused assets * Change send icon * Layout tweaks * Refactor Status * Styles changed * User layout fix * Separator layout changes * Sidebar status layout fix * Fix Message.onLongPress issue * Fix code markdown Closes https://github.com/RocketChat/Rocket.Chat.ReactNative/issues/625 * Status lint * Fix tests * Navigation debounce * RoomActions icons * Space between components * Group text * Update tests * [CHORE] Remove .debug suffix on Android (#681) * [FIX] Fix null native Messagebox component object (#680) * Fix null native Messagebox component object * [iOS] Fix header alignment * Remove unused files * Switch to react-navigation (#687) * Update readme (#714) * Bump to 1.10.1 (#731) * [FIX] Deep linking between multiple logged servers (#730) * Fix handle invisible status (#692) * I18n: Add Portuguese (Portugal) (#722) * [FIX] Show ActivityIndicator in RoomMembersView (#686) * Bump version to 1.11.0 (#761) * Migrate from GCM to FCM (#760) * [NEW] Scrollable room name feature (#756) * [NEW] Scroll down floating button (#735) * [CHORE] Added Storybook documentation (#757) * Use FlatList in RoomView (#762) * [FIX] iOS requiring location permission (#768) * Room item layout (#771) * [NEW] Draft message per room (#772) * [FIX] Add Realm.safeAddListener (#785) * [CHORE] Remove tvOS target (#779) * [NEW] Discussions (#696) * Bump version to 1.12.0 (#804) * [NEW] Threads (#798) * RoomsListView improvements (#819) * [FIX] Giphy not showing (#810) * [FIX] Apply emojify on empty texts (#824) * Lock drawer when stack is not on root screen (#825) * Room item layout (#835) * [FIX] Threads (#838) Closes #826 Closes #827 Closes #828 Closes #829 Closes #830 Closes #831 Closes #832 Closes #833 * [FIX] Smaller thread title (#846) * [FIX] Smaller thread title * Remove markdown notation from thread title * On message press debounce * Align vertical thread title * [Regression] Search stopped working on Android after LastMessage refactor (#851) * Load legal pages from web (#849) * Update fetch permissions api (#850) * Update custom emojis endpoint (#852) * Update emoji endpoint * Use React.memo on Markdown * Support RC versions lower than 0.75.0 * Realm migration * Fetch roles from rest api (#853) * Fetch roles from rest api * Fix RoomInfoView role get * Remove roles from redux * Bump version to 1.13 (#857) * Active users improvements (#855) * Remove connection badge (#862) * Connecting indicator on RoomsListView header * Connecting indicator on RoomView header * Remove ConnectionBadge * Show updating on RoomView load messages * Update dependencies (#863) * Minor updates * Update jsc-android * Update react-native-modal * Minor updates * Update react-native-fast-image * Minor dev updates * Few major updates * Update react-native-keyboard-aware-scroll-view * Update pods * Update android-support * Update tests * Remove duplicated getRoleDescription function (#866) * [FIX] Load local URL image (#871) * [FIX] Toggle/follow thread icon (#867) * Tweaks on sequential threads messages layout (#858) * Tweaks on sequential threads messages * Update tests * Fix quote * Prevent from deleting thread start message when positioned inside the thread * Remove thread listener from RightButtons * Fix error on thread start parse * Stop parsing threads on render * Check replied thread only if necessary * Fix messages don't displaying * Fix threads e2e * RoomsListView.updateState slice * Stop fetching hidden messages on threads * Set initialNumToRender to 5 * [FIX] Check if room is mounted before setting state (#864) * Tweaks on sequential threads messages * Update tests * Fix quote * Prevent from deleting thread start message when positioned inside the thread * Remove thread listener from RightButtons * Fix error on thread start parse * Stop parsing threads on render * Check replied thread only if necessary * Fix messages don't displaying * Fix threads e2e * RoomsListView.updateState slice * Stop fetching hidden messages on threads * Check if RoomView is mounted before rendering * Refactor navigation events on RoomsListView * Fix lint * Fix listener * [FIX] Typing not getting cleared after popping a room (#873) * [CHORE] Remove e2e tests from CI (#875) * [FIX] Remove listeners on RoomView header unmount (#874) * [RELEASE] Merge beta into master (#1055) * Bump version to 1.16.0 (#1014) * [IMPROVEMENT] Share credentials with Rocket.Chat.iOS (#982) * :sparkles: Create user table * :sparkles: Introduce user table * :fire: Remove unused table * :heavy_plus_sign: Add userdefaults to storage data * :green_heart: Fix android build * :sparkles: Get credentials from iOS native client * :fire: Remove unused code * :rewind: Revert sign xcode * :bug: Fix first login-logout * :art: Use constants to UserDefaults Keys * :bug: Fix clear server-user-info on logout * :bug: Fix filter null value * :ambulance: Remove user object in logout * :sparkles: Fix get servers from native-client * :ambulance: Fix error on change server * [FIX] Don't run UserDefaults credentials on Android (#1015) * :bug: Fix native credentials (android) * Fix migration loop * [IMPROVEMENT] Hide frequently used emoji tab when empty (#792) * [IMPROVEMENT] Bigger emoji in emoji only messages (#793) * issue #725: bigger emoji in emoji only message * issue-725/add storybook for Message/Emoji * issue-725: update storybook/Message jest snapshot * comment storybook import * allow spaces and line breaks in emoji only message * merge develop * revert unnecessary spacing * [FIX] Empty message if contains only a link (#787) * Fix empty message if contains only a link * :bug: Fix empty space * [IMPROVEMENT] Refactor empty space regex on quote (#1017) * :art: Improve regex to empty space on quote * :art: Improve on regex to empty space on quote * [NEW] Custom fields on signup (#1013) * added custom feilds on registration * added flag as leftIcon and removed lable * added try and catch * typo * [CHORE] Renew provisioning profiles (#1020) * [NEW] Auto-translate (#1012) * Update realm * View original and translate working * Read AutoTranslate_Enabled setting * RocketChat.canAutoTranslate() * AutoTranslateView * Save language * Auto-translate switch * Translate message * [IMPROVEMENT] Use haptics rather than vibration (#1016) * Install expo-haptics * Use expo-haptics rather than RN's Vibration module * [IMPROVEMENT] Use Rest API for file upload (#1005) * removed rn-fetch-blob and use native XMLHttpRequest instead * removed unnessary changes * fix android bug * fix android bug * added tmid support * fix bug * fixed isssue with cacel model * fix problems with audio * done requested changes * fix bug with android * [CHORE] [CI] [TESTS] update detox to make ci pass (#1026) * feat: update detox to 12.11.3 to make CI pass * ci: comment all jobs but leave e2e-test job * commit to rerun IC e2e-test job * ci: uncomment all CI jobs * [NEW] Room swipe actions: mark as read/unread, hide, fav (#976) * added unread and fav feature * changed the layout * fix jest * done requested changes * added requested changes * [FIX] Android build (#1027) * [FIX] Android build * CircleCI error * [FIX] iOS share credentials build (#1028) * [FIX] iOS share credentials build * Use `hasMigration` as a string * [CI] Restore cache on CI (#1029) * feat: add fastlane save\restore cache config; comment not needed jobs; * install fastlane using 'bundle install' * install fastlane using 'sudo bundle install' * uncomment ios build commands * run set up google services in ios folder * add working_directory: ios to ios-build steps * remove 'cd ios' from Fastlane build step * add save\restore cache for npm modules * group save_cache steps * cache fastlane in ios-testflight job * uncomment previously commented jobs\steps * fix: add missing colon * use key for caching: node-modules-{{ checksum ".circleci/config.yml" }}-{{ checksum "yarn.lock" }} * add names for save\restore steps * ci: add `default` step with `working_directory: ~/repo` to ios-build job * return back caching npm: `node-v1-{{ checksum "package.json" }}-{{ arch }}` * fix: add missing curly braces * save\restore cache in e2e-test job; remove {{arch}} from cache names * add names to restore_cache steps in android-build job * add names to save_cache steps in android-build job * add names to all save\restore steps; change checksum package.json to yarn.lock * change `npm` to `NPM` in steps naming * remove {{ checksum circle ci }} from android-build job and fix naming of steps * [FIX] Rooms swipes (#1034) * Regression: on press style feedback * Action button styles * Fix animations * Styles changed * Update subscription without having to wait for socket * Calculate width on RoomsListView instead * [FIX] Decrease bigger emoji size to 30 (#1031) * [FIX] Append server URL on avatar if necessary (#1038) * Comment removeClippedSubviews * Comment width animation * Remove redux from RoomItem * Fix wrong re-render comparison * Remove listener * Raise minDeltaX * memo actions * Spring with native driver * Refactor functions * Fix props issues * Remove RoomItem.height * Long swipe * Refactor animations * this.rowTranslation -> this.transX * Moved state to this * Bump version to 1.16.1 (#1045) * [FIX] Set UserDefaults AppGroup on notification tap (#1047) * [FIX] Auto-translate messages as they arrive * Fix favorite button * [RELEASE] Merge beta into master (#1082) * Bump version to 1.16.0 (#1014) * [IMPROVEMENT] Share credentials with Rocket.Chat.iOS (#982) * :sparkles: Create user table * :sparkles: Introduce user table * :fire: Remove unused table * :heavy_plus_sign: Add userdefaults to storage data * :green_heart: Fix android build * :sparkles: Get credentials from iOS native client * :fire: Remove unused code * :rewind: Revert sign xcode * :bug: Fix first login-logout * :art: Use constants to UserDefaults Keys * :bug: Fix clear server-user-info on logout * :bug: Fix filter null value * :ambulance: Remove user object in logout * :sparkles: Fix get servers from native-client * :ambulance: Fix error on change server * [FIX] Don't run UserDefaults credentials on Android (#1015) * :bug: Fix native credentials (android) * Fix migration loop * [IMPROVEMENT] Hide frequently used emoji tab when empty (#792) * [IMPROVEMENT] Bigger emoji in emoji only messages (#793) * issue #725: bigger emoji in emoji only message * issue-725/add storybook for Message/Emoji * issue-725: update storybook/Message jest snapshot * comment storybook import * allow spaces and line breaks in emoji only message * merge develop * revert unnecessary spacing * [FIX] Empty message if contains only a link (#787) * Fix empty message if contains only a link * :bug: Fix empty space * [IMPROVEMENT] Refactor empty space regex on quote (#1017) * :art: Improve regex to empty space on quote * :art: Improve on regex to empty space on quote * [NEW] Custom fields on signup (#1013) * added custom feilds on registration * added flag as leftIcon and removed lable * added try and catch * typo * [CHORE] Renew provisioning profiles (#1020) * [NEW] Auto-translate (#1012) * Update realm * View original and translate working * Read AutoTranslate_Enabled setting * RocketChat.canAutoTranslate() * AutoTranslateView * Save language * Auto-translate switch * Translate message * [IMPROVEMENT] Use haptics rather than vibration (#1016) * Install expo-haptics * Use expo-haptics rather than RN's Vibration module * [IMPROVEMENT] Use Rest API for file upload (#1005) * removed rn-fetch-blob and use native XMLHttpRequest instead * removed unnessary changes * fix android bug * fix android bug * added tmid support * fix bug * fixed isssue with cacel model * fix problems with audio * done requested changes * fix bug with android * [CHORE] [CI] [TESTS] update detox to make ci pass (#1026) * feat: update detox to 12.11.3 to make CI pass * ci: comment all jobs but leave e2e-test job * commit to rerun IC e2e-test job * ci: uncomment all CI jobs * [NEW] Room swipe actions: mark as read/unread, hide, fav (#976) * added unread and fav feature * changed the layout * fix jest * done requested changes * added requested changes * [FIX] Android build (#1027) * [FIX] Android build * CircleCI error * [FIX] iOS share credentials build (#1028) * [FIX] iOS share credentials build * Use `hasMigration` as a string * [CI] Restore cache on CI (#1029) * feat: add fastlane save\restore cache config; comment not needed jobs; * install fastlane using 'bundle install' * install fastlane using 'sudo bundle install' * uncomment ios build commands * run set up google services in ios folder * add working_directory: ios to ios-build steps * remove 'cd ios' from Fastlane build step * add save\restore cache for npm modules * group save_cache steps * cache fastlane in ios-testflight job * uncomment previously commented jobs\steps * fix: add missing colon * use key for caching: node-modules-{{ checksum ".circleci/config.yml" }}-{{ checksum "yarn.lock" }} * add names for save\restore steps * ci: add `default` step with `working_directory: ~/repo` to ios-build job * return back caching npm: `node-v1-{{ checksum "package.json" }}-{{ arch }}` * fix: add missing curly braces * save\restore cache in e2e-test job; remove {{arch}} from cache names * add names to restore_cache steps in android-build job * add names to save_cache steps in android-build job * add names to all save\restore steps; change checksum package.json to yarn.lock * change `npm` to `NPM` in steps naming * remove {{ checksum circle ci }} from android-build job and fix naming of steps * [FIX] Rooms swipes (#1034) * Regression: on press style feedback * Action button styles * Fix animations * Styles changed * Update subscription without having to wait for socket * Calculate width on RoomsListView instead * [FIX] Decrease bigger emoji size to 30 (#1031) * [FIX] Append server URL on avatar if necessary (#1038) * Comment removeClippedSubviews * Comment width animation * Remove redux from RoomItem * Fix wrong re-render comparison * Remove listener * Raise minDeltaX * memo actions * Spring with native driver * Refactor functions * Fix props issues * Remove RoomItem.height * Long swipe * Refactor animations * this.rowTranslation -> this.transX * Moved state to this * Bump version to 1.16.1 (#1045) * [FIX] Set UserDefaults AppGroup on notification tap (#1047) * [FIX] Auto-translate messages as they arrive * Fix favorite button * [FIX] Swipe animations (#1044) * Comment removeClippedSubviews * Comment width animation * Remove redux from RoomItem * Fix wrong re-render comparison * Remove listener * Raise minDeltaX * memo actions * Spring with native driver * Refactor functions * Fix props issues * Remove RoomItem.height * Long swipe * Refactor animations * this.rowTranslation -> this.transX * Moved state to this * Fix favorite button * [FIX] Auto-translate messages as they arrive (#1049) * Comment removeClippedSubviews * Comment width animation * Remove redux from RoomItem * Fix wrong re-render comparison * Remove listener * Raise minDeltaX * memo actions * Spring with native driver * Refactor functions * Fix props issues * Remove RoomItem.height * Long swipe * Refactor animations * this.rowTranslation -> this.transX * Moved state to this * [FIX] Auto-translate messages as they arrive * [i18n] Add missing de translations (#1040) * [CHORE] Switch to react-native-localize (#1043) * Bump version to 1.17.0 (#1057) * Load views as needed (#1056) * [IMPROVEMENT] Change "resend" icon position (#1048) * [NEW] Video support (#801) * [NEW] File upload (#882) * [NEW] Share extension (#942) * [FIX] Share extension CI build (#1060) * Change bundleID * Provisioning * get provisioning profile * [IMPROVEMENT] Reusable toast (#1065) * [FIX] Moment locales (#1066) * [FIX] Share Extension issues (#1064) * [FIX] Empty white list enables all media types upload (#1077) * Merge branch 'master' into develop (#1079) * [FIX] Empty white list enables all media types upload (#1080) * Create utils to media (canUpload) * Fix variable name * [CHORE] Update README (#1081) * [RELEASE] Merge beta into master (#1088) * Bump version to 1.16.0 (#1014) * [IMPROVEMENT] Share credentials with Rocket.Chat.iOS (#982) * :sparkles: Create user table * :sparkles: Introduce user table * :fire: Remove unused table * :heavy_plus_sign: Add userdefaults to storage data * :green_heart: Fix android build * :sparkles: Get credentials from iOS native client * :fire: Remove unused code * :rewind: Revert sign xcode * :bug: Fix first login-logout * :art: Use constants to UserDefaults Keys * :bug: Fix clear server-user-info on logout * :bug: Fix filter null value * :ambulance: Remove user object in logout * :sparkles: Fix get servers from native-client * :ambulance: Fix error on change server * [FIX] Don't run UserDefaults credentials on Android (#1015) * :bug: Fix native credentials (android) * Fix migration loop * [IMPROVEMENT] Hide frequently used emoji tab when empty (#792) * [IMPROVEMENT] Bigger emoji in emoji only messages (#793) * issue #725: bigger emoji in emoji only message * issue-725/add storybook for Message/Emoji * issue-725: update storybook/Message jest snapshot * comment storybook import * allow spaces and line breaks in emoji only message * merge develop * revert unnecessary spacing * [FIX] Empty message if contains only a link (#787) * Fix empty message if contains only a link * :bug: Fix empty space * [IMPROVEMENT] Refactor empty space regex on quote (#1017) * :art: Improve regex to empty space on quote * :art: Improve on regex to empty space on quote * [NEW] Custom fields on signup (#1013) * added custom feilds on registration * added flag as leftIcon and removed lable * added try and catch * typo * [CHORE] Renew provisioning profiles (#1020) * [NEW] Auto-translate (#1012) * Update realm * View original and translate working * Read AutoTranslate_Enabled setting * RocketChat.canAutoTranslate() * AutoTranslateView * Save language * Auto-translate switch * Translate message * [IMPROVEMENT] Use haptics rather than vibration (#1016) * Install expo-haptics * Use expo-haptics rather than RN's Vibration module * [IMPROVEMENT] Use Rest API for file upload (#1005) * removed rn-fetch-blob and use native XMLHttpRequest instead * removed unnessary changes * fix android bug * fix android bug * added tmid support * fix bug * fixed isssue with cacel model * fix problems with audio * done requested changes * fix bug with android * [CHORE] [CI] [TESTS] update detox to make ci pass (#1026) * feat: update detox to 12.11.3 to make CI pass * ci: comment all jobs but leave e2e-test job * commit to rerun IC e2e-test job * ci: uncomment all CI jobs * [NEW] Room swipe actions: mark as read/unread, hide, fav (#976) * added unread and fav feature * changed the layout * fix jest * done requested changes * added requested changes * [FIX] Android build (#1027) * [FIX] Android build * CircleCI error * [FIX] iOS share credentials build (#1028) * [FIX] iOS share credentials build * Use `hasMigration` as a string * [CI] Restore cache on CI (#1029) * feat: add fastlane save\restore cache config; comment not needed jobs; * install fastlane using 'bundle install' * install fastlane using 'sudo bundle install' * uncomment ios build commands * run set up google services in ios folder * add working_directory: ios to ios-build steps * remove 'cd ios' from Fastlane build step * add save\restore cache for npm modules * group save_cache steps * cache fastlane in ios-testflight job * uncomment previously commented jobs\steps * fix: add missing colon * use key for caching: node-modules-{{ checksum ".circleci/config.yml" }}-{{ checksum "yarn.lock" }} * add names for save\restore steps * ci: add `default` step with `working_directory: ~/repo` to ios-build job * return back caching npm: `node-v1-{{ checksum "package.json" }}-{{ arch }}` * fix: add missing curly braces * save\restore cache in e2e-test job; remove {{arch}} from cache names * add names to restore_cache steps in android-build job * add names to save_cache steps in android-build job * add names to all save\restore steps; change checksum package.json to yarn.lock * change `npm` to `NPM` in steps naming * remove {{ checksum circle ci }} from android-build job and fix naming of steps * [FIX] Rooms swipes (#1034) * Regression: on press style feedback * Action button styles * Fix animations * Styles changed * Update subscription without having to wait for socket * Calculate width on RoomsListView instead * [FIX] Decrease bigger emoji size to 30 (#1031) * [FIX] Append server URL on avatar if necessary (#1038) * Comment removeClippedSubviews * Comment width animation * Remove redux from RoomItem * Fix wrong re-render comparison * Remove listener * Raise minDeltaX * memo actions * Spring with native driver * Refactor functions * Fix props issues * Remove RoomItem.height * Long swipe * Refactor animations * this.rowTranslation -> this.transX * Moved state to this * Bump version to 1.16.1 (#1045) * [FIX] Set UserDefaults AppGroup on notification tap (#1047) * [FIX] Auto-translate messages as they arrive * Fix favorite button * [FIX] Swipe animations (#1044) * Comment removeClippedSubviews * Comment width animation * Remove redux from RoomItem * Fix wrong re-render comparison * Remove listener * Raise minDeltaX * memo actions * Spring with native driver * Refactor functions * Fix props issues * Remove RoomItem.height * Long swipe * Refactor animations * this.rowTranslation -> this.transX * Moved state to this * Fix favorite button * [FIX] Auto-translate messages as they arrive (#1049) * Comment removeClippedSubviews * Comment width animation * Remove redux from RoomItem * Fix wrong re-render comparison * Remove listener * Raise minDeltaX * memo actions * Spring with native driver * Refactor functions * Fix props issues * Remove RoomItem.height * Long swipe * Refactor animations * this.rowTranslation -> this.transX * Moved state to this * [FIX] Auto-translate messages as they arrive * [i18n] Add missing de translations (#1040) * [CHORE] Switch to react-native-localize (#1043) * Bump version to 1.17.0 (#1057) * Load views as needed (#1056) * [IMPROVEMENT] Change "resend" icon position (#1048) * [NEW] Video support (#801) * [NEW] File upload (#882) * [NEW] Share extension (#942) * [FIX] Share extension CI build (#1060) * Change bundleID * Provisioning * get provisioning profile * [IMPROVEMENT] Reusable toast (#1065) * [FIX] Moment locales (#1066) * [FIX] Share Extension issues (#1064) * [FIX] Empty white list enables all media types upload (#1077) * Merge branch 'master' into develop (#1079) * [FIX] Empty white list enables all media types upload (#1080) * Create utils to media (canUpload) * Fix variable name * [CHORE] Update README (#1081) * [FIX] Media share type (#1086) * [RELEASE] Merge beta into master (#1142) * [RELEASE] Merge beta into master (#1174) * [RELEASE] Merge beta into master (#1282) * Merge beta into master (#1461) * Merge beta into master (#1637) * Merge beta into master (#1759) * Merge beta into master (#1897) * [FIX] Close SortDropdown on sort select (#1230) * [FIX] Cancel upload and check failed upload (#1232) * [FIX] Slash commands not cleaning is typing and not using state (#1233) * [FIX] Dispatch roomsRequest on app foreground event even if not connected (#1234) * [CHORE] Update react-native-jitsi-meet (#1235) * [FIX] Regex on run slash command (#1223) * Update React Native to 0.61.1 (#1236) * Update React Native to 0.61.1 * Update patch to SSL Pinning * Revert storybook * [CHORE] Update react-native-safe-area-view (#1219) * [FIX] Try/catch JSON.parse XHR response (#1238) * [FIX] Change messagebox icon immediate on change text (#1241) * [FIX] Update last open on message stream received (#1240) * [FIX] Remove animation from RoomsListView.willFocus (#1239) * [FIX] Delete message on thread (#1214) * [REGRESSION] Markdown text (#1242) * [FIX] Jest (#1243) * [FIX] Avatar shown when useRealName is activated (#1162) * Fix avatar when use real name * Wrong indentation * [DOCS] Add SECURITY.md (#1244) * [CHORE] Update react-native-reanimated to 1.3.0 (#1246) * [FIX] Run credentials migration only once (#1245) * [CHORE] Update react-native-jitsi-meet to 2.0.1 (#1249) * [FIX] Messagebox onChangeText issues (#1252) * Stop ongoing debounces on messagebox unmount * Immediately change send icon, but keep debouncing others * Make CustomEmoji stateless function * Fix mentions keyExtractor * [FIX] Room subscription issues (#1255) * [FIX] Reaction press (#1258) * [FIX] Channel avatars not showing after application unloads (#1264) * Revert react-native-safe-area-view (#1265) * [FIX] Remove console on production mode (#1268) * [FIX] Messages preview issues (#1257) * [FIX] Select user from native credentials (#1266) * [FIX] Some issues on preview message (#1271) * [FIX] Audio player track and thumb not rendering on Android (#1273) * [FIX] Record audio message throws exception when FileSystem.getInfoAsync is called (#1272) * [FIX] China shouldn't use CallKit (#1274) * [FIX] Watermelon batches (#1277) * Bump version to 1.20.1 (#1285) * [CHORE] Remove memoize-one (#1284) * [FIX] End Jitsi call on unmount (#1291) * [FIX] Allow self-signed certificates (#1310) * [FIX] Set User-Agent (#1318) * Set User-Agent Fetch & Websocket & XHR * Set User-Agent * Custom User Agent on fetch/websocket * Fix names * Use DeviceInfo * fix server with subpath (#1322) * [FIX] Server with https:\\ instead of https:// (#1320) * [FIX] Server dropdown not closing after changing stack (#1299) * [FIX] Invalid server version (#1319) * [IMPROVEMENT] Respect "Hide counter" preference (#1306) * [FIX] Pass isFocused as a function to Messagebox (#1309) * [CHORE] Remove icons folder (#1290) * [CHORE] Refactor RoomItem touchable (#1331) * [FIX] Unnecessary rerender on RoomItem when status is undefined (#1336) * [UPDATE DEPS] react-navigation and react-navigation-stack (#1337) * [FIX] Avatars not loading on share extension when Accounts_AvatarBlockUnauthenticatedAccess is enabled (#1339) * Bump version to 1.20.2 (#1340) * [FIX] Remove some unnecessary re-renders on Messagebox (#1341) * [REGRESSION] Use LayoutAnimation instead of Transition API (#1338) * [FIX] Remove setState from notifications view causing watermelon object to be updated outside an action (#1342) * [IMPROVEMENT] Save last message as message when subscription is updated (#1344) * [UPDATE DEPS] Update RN to 0.61.3 (#1345) * [DOCS] Update Readme (#1346) * [CHORE] Remove react-native-scrollable-tab-view fork (#1352) * [FIX] URL preview (#1360) * [REGRESSION] Decrease list view memory size (#1361) * [FIX] Paste (#1350) * [CHORE] Update gems (#1365) * Bump version to 1.20.3 (#1366) * [FIX] Use Ruby 2.4 on TestFlight upload (#1368) * [FIX] Parse Urls (#1371) * [FIX] Parse image URL only if it's not empty (#1372) * [FIX] Load messages issues (#1373) * Bump version to 1.21.0 (#1376) * [FIX] Crowd login (#1381) * [FIX] Clicking user avatar in thread previews crashes app (#1363) * [IMPROVEMENT] Error messages on connect (#1379) * [FIX] ProfileView input navigation error when custom fields aren't set (#1383) * [FIX] Batch server deletion on logout (#1382) * Bump app to 1.22.0 (#1387) * [FIX] Server Version (#1392) * Update patch and minor deps (#1386) * [FIX] Crash when open thread (#1395) * Bump version to 1.23.0 (#1394) * [I18N] Update ru.js (#1384) * [FIX] CAS building wrong URL (#1362) * [FIX] Delete messages (#1399) * [FIX] In-app notification showing wrong content on channels (#1400) * Bump version to 1.24.0 (#1404) * [FIX] Prevent server with whitespace (#1402) * [IMPROVEMENT] Keyboard and content type on login (#1403) * [FIX] Messages stop loading (#1410) * [NEW] Tablet support (#1300) * [IMPROVEMENT] Authentication via deep linking (#1418) * [IMPROVEMENT] Markdown performance when identifying emoji only content (#1422) * [FIX] BackHandler remove random failing on development (#1423) * Bump version to 1.25.0 (#1424) * [CHORE] Update CI Xcode Image (#1430) * [FIX] Rooms grouping not working properly (#1435) * [FIX] Take a video (#1437) * [NEW] Themes (#1298) * [FIX] Share extension doesn't reconnect to previous selected server on Android (#1429) * [FIX] Init local settings on notification tap (#1438) * Bump version to 1.26.0 (#1450) * [FIX] Emoji parser not working on Hermes (#1445) * [NEW] Enable Hermes (#1446) * [FIX] Automatic theme repeating (#1457) * [CHORE] Sync Experimental and Official app versions (#1458) * [DOCS] Update readme (#1459) * [FIX] Messages being sent but showing as temp status (#1469) * [FIX] Missing messages after reconnect (#1470) * [FIX] Few fixes on themes (#1477) * [I18N] Missing German translations (#1465) * Missing German translation * adding a missing space behind colon * added a missing space after colon * and another attempt to finally fix this – got confused by all the branches * some smaller fixes for the translation * better wording * fixed another typo * [FIX] Crash while displaying the attached image with http on file name (#1401) * [IMPROVEMENT] Tap app and server version to copy to clipboard (#1425) * [NEW] Reply notification (#1448) * [FIX] Incorrect background color login on iPad (#1480) * [FIX] Prevent multiple tap on send (Share Extension) (#1481) * [NEW] Image Viewer (#1479) * [DOCS] Update Readme (#1485) * [FIX] Jitsi with Hermes Enabled (#1523) * [FIX] Draft messages not working with themed Messagebox (#1525) * [FIX] Go to direct message from members list (#1519) * [FIX] Make SAML wait for idp token instead of creating it on client (#1527) * [FIX] Server Test Push Notification (#1508) Co-authored-by: Diego Mello * [CHORE] Update to new server response (#1509) * [FIX] Insert messages with blank users (#1529) * Bump version to 4.2.1 (#1530) * [FIX] Error when normalizing empty messages (#1532) * [REGRESSION] CAS (#1570) * Bump version to 4.2.2 (#1571) * [FIX] Add username block condition to prevent error (#1585) * Bump version to 4.2.3 * Bump version to 4.2.4 * Bump version to 4.3.0 (#1630) * [FIX] Channels doesn't load (#1586) * [FIX] Channels doesn't load * [FIX] Update roomsUpdatedAt when subscriptions.length is 0 * [FIX] Remove unnecessary changes * [FIX] Improve the code Co-authored-by: Diego Mello * [FIX] Make SAML to work on Rocket.Chat < 2.3.0 (#1629) * [NEW] Invite links (#1534) * [FIX] Set the http-agent to the form that Rocket.Chat requires for logging (#1482) Co-authored-by: Diego Mello * [FIX] "Following thread" and "Unfollowed Thread" is hardcoded and not translated (#1625) * [FIX] Disable reset button if form didn't changed (#1569) Co-authored-by: Diego Mello * [FIX] Header title of RoomInfoView (#1553) * [I18N] Gallery Permissions DE (#1542) * [FIX] Not allow to send messages to archived room (#1623) * [FIX] Profile fields automatically reset (#1502) * [FIX] Show attachment on ThreadMessagesView (#1493) * [NEW] Wordpress auth (#1633) * [CHORE] Add Start Packager script (#1639) * [CHORE] Update RN to 0.61.5 (#1638) * [CHORE] Update RN to 0.61.5 * [CHORE] Update react-native patch Co-authored-by: Djorkaeff Alexandre * Bump version to 4.3.1 (#1641) * [FIX] Change force logout rule (#1640) * Bump version to 4.4.0 (#1643) * [IMPROVEMENT] Use MessagingStyle on Android Notification (#1575) * [NEW] Request review (#1627) * [NEW] Pull to refresh RoomView (#1657) * [FIX] Unsubscribe from room (#1655) * [FIX] Server with subdirs (#1646) * [NEW] Clear cache (#1660) * [IMPROVEMENT] Memoize and batch subscriptions updates (#1642) * [FIX] Disallow empty sharing (#1664) * [REGRESSION] Use HTTPS links for sharing and markets protocol for review (#1663) * [FIX] In some cases, share extension doesn't load images (#1649) * [i18n] DE translations for new invite function and some minor fixes (#1631) * [FIX] Remove duplicate jetify step (#1628) minor: also remove 'cd' calls Co-authored-by: Diego Mello * [REGRESSION] Read messages (#1666) * [i18n] German translations missing (#1670) * [FIX] Notifications crash on older Android Versions (#1672) * [i18n] Added Dutch translation (#1676) * [NEW] Omnichannel Beta (#1674) * [NEW] Confirm logout/clear cache (#1688) * [I18N] Add es-ES language (#1495) * [NEW] UiKit Beta (#1497) * [IMPROVEMENT] Use reselect (#1696) * [FIX] Notification in Android API level less than 24 (#1692) * [IMPROVEMENT] Send tmid on slash commands and media (#1698) * [FIX] Unhandled action on UIKit (#1703) * [NEW] Pull to refresh RoomsList (#1701) * [IMPROVEMENT] Reset app when language is changed (#1702) * [FIX] Small fixes on UIKit (#1709) * [FIX] Spotlight (#1719) * [CHORE] Update react-native-image-crop-picker (#1712) * [FIX] Messages Overlapping (Android) and MessageBox Scroll (iOS) (#1720) * [REGRESSION] Remove @ and # from mention (#1721) * [NEW] Direct message from user info (#1516) * [FIX] Delete slash commands (#1723) * [IMPROVEMENT] Hold URL to copy (#1684) * [FIX] Different sourcemaps generation for Hermes (#1724) * [FIX] Different sourcemaps generation for Hermes * Upload sourcemaps after build * [REVERT] Show emoji keyboard on Android (#1738) * [FIX] Stop logging react-native-image-crop-picker (#1745) * [FIX] Prevent toast ref error (#1744) * [FIX] Prevent reaction map error (#1743) * [FIX] Add missing calls to user info (#1741) * [FIX] Catch room unsubscribe error (#1739) * [i18n] Missing German keys (#1735) * [FIX] Missing i18n on MessagesView title (#1733) * [FIX] UIKit Modal: Weird behavior on Android Tablet (#1742) * [i18n] Missing key on German (#1747) Co-authored-by: Diego Mello * [i18n] Add Italian (#1736) … * [FIX] Notification stream throwing an error when there isn't a message on payload (#2637) * [FIX] Threads not being updated and other related issues (#2636) * Fix parent title on thread header breaking lines * Fix https://github.com/RocketChat/Rocket.Chat.ReactNative/issues/2519 * Fix thread badge not being updated * [FIX] Minor room header issues (#2630) * Add hitSlop to RoomView header * Use 1 icon padding for threads header Co-authored-by: Djorkaeff Alexandre * [FIX] Whitelabel unable to find package name (#2626) * Fixes #2625 * Fixes #2614 * Apply resValue on defaultConfig and undo unnecessary changes Co-authored-by: Diego Mello * [i18n] Add missing German strings (#2619) Co-authored-by: Diego Mello * [FIX] Model columns misplaced (#2640) * [FIX] Connect a null server (#2639) Co-authored-by: Diego Mello * [FIX] Jitsi users unable to unmute (#2623) * [FIX] Jitsi users being muted always * fix: bundle is invalid * Update jitsi meet sdk with ui improvements * Update JitsiMeetSDK ios * Centralize toolbox android * Fix images on Jitsi Co-authored-by: Diego Mello * Bump version to 4.12.1 (#2641) * [FIX] Share extension and save image not working on Android 10 (#2651) * Bump version to 4.13.0 (#2657) * [FIX] Update Loading logo (#2658) * [NEW] Support client certificates for SSL (two-way authentication) (Android) (#2624) * wip: Android SSL Pinning * Use own SSLPinningModule * wip: Use Rocket.Chat own react-native * wip: Fresco Images using custom OkHttpClient * wip: react-native-webview onReceivedClientCertRequest * feat: Save Images of a SSL Pinning protected server * chore: SSLPinning package as a interface to iOS & Android implementations * chore: update glide * feat: load images under a client ssl certificate protected server * chore: remove patch * feat: Audio & Video under a SSL Client protected server * fix: Unpin certificate when change server * feat: Fast Image as a patch * chore: update fast-image * Fix merge Co-authored-by: Diego Mello * [NEW] Channel actions (#2644) * room roles * handle owner * endpoints * Leader and Moderator * Remove user from room * stash ignore * Add subscription.ignored column * ignore user * Fix icons * I18n * Minor i18n fixes * Direct Message and open action sheet after a normal tap * Fix icon * stash isIgnored * isManualUnignored message * Fix update * Ignored * Mute, moderator, leader, owner, remove from room * ignore * Tests * pt-BR * Update pods * Apply requested changes * Add RC version on requests * [NEW] Support RTL (#2656) * wip: RTL (iOS) * wip: RTL (Android) * wip: reload bundle when change between RTL languages * fix: Stack Animation on Android * fix: update snapshot * fix: Swipe Room Actions in RTL mode * fix: snapshots * Move isRTL to i18n * Fix styling * Update tests * Update pods Co-authored-by: Diego Mello * [FIX] Initial users' status is not fetched (#2664) * [FIX] Messages overlapping and emoji keyboard not opening (#2670) * Replace keyboard libs for react-native-ui-lib * Apply Jitsi branch * Require keyboard on bundle * Update ui-lib * chore: update deps Co-authored-by: Djorkaeff Alexandre * [CHORE] Force normalized params for 2FA (#2683) Co-authored-by: Diego Mello * [FIX] Thread message flickering while thread parent isn't found (#2676) Co-authored-by: Diego Mello * [FIX] Light theme not working on Android with Dark Theme set (#2675) Co-authored-by: Diego Mello * [FIX] App not prompting join code for password protected channels (#2514) * Adding joinCode parameter Co-authored-by: Vitor Leal Co-authored-by: Fernando Aguilar * Insert join code input Signed-off-by: Vitor.Leal * Add joinCode field on db Signed-off-by: Vitor.Leal * Add label i18 pt-br and en-us Signed-off-by: Vitor.Leal * Add insert join code text Signed-off-by: Vitor.Leal * Fix atribute name Signed-off-by: Vitor.Leal * Add join text Signed-off-by: Vitor.Leal Co-authored-by: Daniel Maike Co-authored-by: Fernando Aguilar * Fix attributes joinCode, joinCodeRequired and pass attribute param in navigation Signed-off-by: Daniel Maike Co-authored-by: Vitor Leal * Fixing attribute joinCodeRequired pass to goRoom Signed-off-by: Daniel Maike * Changed textinput style Signed-off-by: Daniel Maike Co-authored-by: Vitor Leal * Delete not necessary attribute Signed-off-by: Daniel Maike * Fixing input style Co-authored-by: Vitor Leal * Undo unncessary changes * use a join code modal * tests: e2e tests to join protected channel * fix: undo unnecessary change * tests: cancel join code * Remove some tests * Minor fixes Co-authored-by: Vitor Leal Co-authored-by: Fernando Aguilar Co-authored-by: Djorkaeff Alexandre Co-authored-by: youssef-md Co-authored-by: Diego Mello * [I18n] Add Arabic (#2537) * Arabic language setup * Added arabic translation * Arabic translation Proofreading Co-authored-by: Diego Mello * [I18N] Add missing zh_TW and zh_CN strings (#2680) * feat(i18n): add some missing strings and improve some translation * fix: add missing server version Co-authored-by: Diego Mello * [IMPROVEMENT] Add username on status messages (#2553) * 1689 - missing user name for status messages * 1689 - missing user name for status messages. Fixed broken e2e test "should pin message". * Minor tweak * Remove center style * Small refactor on User * Remove toLowerCase * Update tests Co-authored-by: Diego Mello * [FIX] Filenames are incorrect in non-latin alphabets on upload (#2671) * fix: filename on react-native-image-crop-picker * fix: use rn-fetch-blob to upload files * fix: FileUpload as a service * fix: cancel upload on iOS * fix: file upload from share extension Co-authored-by: Diego Mello * [IMPROVEMENT] Ease white labelling for Android (#2685) * improve white labelling for Android * Move application ID to gradle properties * Fix CI * Point foss sufix to main app * Use npx on android-whitelabel script Co-authored-by: Diego Mello * [FIX] Chats order (#2688) * Persist highest value on subscription.roomUpdatedAt * Update tests Co-authored-by: Djorkaeff Alexandre * [REGRESSION] Re-enable Jitsi Chat (#2687) * Fix main jitsi * Fix iOS * Clear build.gradle cache * Don't restore gradle * cache is back * Use master * Point to react-native-jitsi-meet#master * [CHORE] Build official apps on CI (#2701) * Duplicated target and changed Bridging Header * Display name * Unnecessary dumb swift file removed * Buildable name * Reorder Info.plist * Rename Official target's bundle id * Ignore .mobileprovision * Fix provisioning of official app * Starting signing * stash fastfile * starting official ci iOS * Uncomment Fastfile keychain * Fix CI config * allowProvisioningUpdates * Changing AppIcon and Splash Screen * Remove unnecessary folder inside of Images.xcassets * Reorder notificationservice and shareextension plists * Fix signing * Manual signing style for official * Split official signing * Update project provisioning * Use ENV as profile * Output match * Keys * TestFlight refactor * Setting up android * android-official-play-build job * Start removing unnecessary fastlane tasks on Android * Trying to refactor Android jobs * android-env * Remove foss build for now * Fork * Fix if conditions * Fix push * ios-build command * Rename Android builds * Upload dSYMs * Refactoring workflow * Reorder upload-to-testflight * upload-to-google-play-beta command * Fix ci * Fix android fork build * Fix keystore * Fix options on fastlane android * Fix keystore * Check isOfficial on iOS * Check isOfficial on db * Remove unused imports * Database names on Android * Tag fix * Minor fixes * Set IS_OFFICIAL on CI * Fix detox * follow review suggestions Co-authored-by: Djorkaeff Alexandre * [i18n] Update fr (#2697) Co-authored-by: Diego Mello * [i18n] Update fr (#2705) Typo Co-authored-by: Diego Mello * [FIX] Empty space on Messagebox (#2704) Co-authored-by: Diego Mello * [FIX] Yarn android scripts (#2716) * [CHORE] Rename Experimental iOS lane (#2717) * Move build_fork to the end * Rename release to build_experimental * [IMPROVEMENT] Use class variable instead of state for List's animated (#2718) * [FIX] Bottom sheet being hidden sometimes (#2722) * [IMPROVEMENT] Match background and text mention colors (#2723) * [FIX] App freezing if Markdown preview contains sequential empty spaces (#2726) * Remove sequential empty spaces from Markdown preview * Use Markdown preview on RepliedThread * [FIX] Official app without sharedUserId (#2734) * [CHORE] Update React Native to 0.63.4 (#2737) * Bump version to 4.13.1 (#2739) * [REGRESSION] Multiple uploads not working on iOS (#2738) * Update React Native to 0.63.4 * Fix multiple uploads not working on iOS * [FIX] Unable to save attachment on iOS (#2743) * Fix rn-fetch-blob's document dir without forward slash * Update camera roll * [FIX] Generate Jitsi access token when making a call (#2694) fixes: #2693 # Please enter the commit message for your changes. Lines starting Co-authored-by: Diego Mello * [FIX] Jitsi notification delay (#2668) Co-authored-by: Diego Mello * [FIX] Channels list not following the same sorting logic from web client (#2763) * [FIX] Pods lost on Official target (#2764) * [FIX] RoomItem using deprecated animated event signature (#2771) * [FIX] Server autocomplete text breaking line (#2774) * [FIX] ServerDropdown flashing bigger server icon (#2775) * [FIX] ServerDropdown flashing bigger server icon * Remove unused logo and update image path where needed * Minor tweak Co-authored-by: Diego Mello * [FIX] Rooms list not being updated on some cases (#2765) * Request subscriptions on RoomsListView.constructor * Removes opened rooms from last message persisting * Change server reducer * Prevent undefined ids causing query error * [FIX] Share Extension hitting memory limit on iOS (#2788) * [FIX] Disallow swipe to dismiss on share extension * Limit query to 20 and clean up props * Remove rn-extension-share branch pointer * Test new branch * Remove branch * [IMPROVEMENT] Threads layout tweaks (#2686) * improvement: Thread Details * fix: re-render Thread Messages Item * fix: update snapshots * improve: thread details component * fix: cast replies length * improvement: format date of threads * improvement: thread details styles * fix: wrap text * tests: update snapshot * improvement: use same date format for all dates * Icon size 24 * Remove date * Remove prop drill * Badge position * Badge container tweak * Fix inline style * Move ThreadDetails to containers * Update stories * Fix lint * Remove wrong prop Co-authored-by: Diego Mello * [CHORE] Remove some migrations (#2792) * Remove force rooms refresh * Remove MMKV migration * Bump version to 4.14.0 (#2797) * [FIX] Messagebox tracking lost on pop gesture navigation (#2799) * Use setTimeout instead of InteractionManager * Update tracking lib * [FIX] Back button closing activity when on root stack screen (#2804) * Make hardware back button to behave as home button on root screens * Remove unnecessary code * Remove handleBackPress from OnboardingView * Fix lint * [i18n] Add missing German strings (#2715) Co-authored-by: Diego Mello * [NEW] Encrypted Discussions (#2813) * I18n key fix * Add encrypted switch * Remove unused i18n keys * Add enabled to encryption reducer * Show encrypted option on CreateDiscussionView only when e2e encryption is properly set * Add localSearch and use it on search * Use encrypted from parent channel * Fix method calls as rest api with 2fa enabled * Fix logout after reset keys * Use encryption reducer instead of lib directly to check render * Check for room type logic to display encryption option on create discussion * Check toggle-room-e2e-encryption permission on RoomActionsView * Check for encryption status instead of setting on server * Fix * Disable switch instead of hide it * Fix spotlight for DMs * Fix server test * [FIX] Messagebox missing style for text color (#2786) * Changing auxilaryTintColor * Changed Placeholder color to BodyText color * added color prop * eslint changes * used array for styles Co-authored-by: Diego Mello * [I18N] Update arabic (#2696) * Update ar.js * Update ar.js Co-authored-by: Diego Mello * [FIX] Workspace input without i18n (#2689) * [FIX] Translation of strings in Login page * Strings are added for translation. fixes: #2620 * Add pt-BR Co-authored-by: Diego Mello * [FIX] Spotlight returning duplicated entries (#2805) * Update rocketchat.js * Updated search function * Minor improvements * Remove atIndex * Add remove logic to remove duplicate data from response Co-authored-by: Diego Mello * [CHORE] Refactor ServerItem (#2778) * Updated ServerDropdown and ServerItem * Added ServerItem stories * Update ServerDropdown.js * Updated ServerItem stories * Updated ServerItem stories and ServerItem component * Updated SelectServerView, ServerItem and ServerItem stories * Updated ServerItem stories * Updated ServerItem stories * Update tests Co-authored-by: Diego Mello * [DOCS] Updated Quick Start docs link in e2e/readme (#2802) Co-authored-by: Diego Mello * [I18N] Add Turkish (#2793) * Turkish language support added * Update tr.js Co-authored-by: Diego Mello * [FIX] Lint on #2793 (#2818) * [I18N] Add missing german strings (#2689) (#2820) * [I18N] Add missing italian strings (#2817) * [FIX] Server version becoming null on server change (#2821) * [FIX] Wrong styling on E2E encryption banner (#2767) * [FIX] Wrong styling on E2E encryption banner * [FIX] Wrong styling on E2E encryption banner * [FIX] Wrong styling on E2E encryption banner * [FIX] Wrong styling on E2E encryption banner (#2767) * Updated SortDropdown, ListHeader, ListItem and added stories for List.Item * Updated SortDropdown * Removed unused component * Updated List.Item and stories * Reverted unnecessary changes and updated ListItem stories * Fix minor indentation * Stop breaking Touch's default underlay color * Fix indentation * Remove falsy comparison from render * Fix left icon * Use List.Item on OmnichannelStatus * Add missing separator * Lint * Fix sort dropdown * Remove unnecessary styles * Fix detox Co-authored-by: Diego Mello * [FIX] App Store using Experimental's app id (#2826) * [FIX] Wrong username on push notifications (#2825) * [FIX] Share extension memory issues on iOS (#2845) * Remove unnecessary class prop * Stop rendering servers when there's only one * Map and alloc only necessary columns from query * Fetch servers count instead of all servers records * Fetch only needed servers * Separators * Remove renderContent * Minor fix * Refactor query * Smaller avatars in memory * Fix getItemLayout * Add topic * Load less pods * tests * Import only used functions from lodash * Fix pods * Import only used functions from semver * Fix media sharing * Update pods * Disables preview and thumb on iOS * Update expo-video-thumbnail * Unnecessary change * [FIX] Logout from other locations not prompting confirmation option (#2854) * Fixed logout toast bug for the iOS * Removing callToAction and replacing with confirmationText Co-authored-by: Diego Mello * Bump version to 4.14.1 (#2859) * [IMPROVEMENT] Check for focused rooms on in-app notifications (#2857) * Update InAppNotification and room reducer * Update InAppNotification This reverts commit 60330a1e04cfe8d2e5aa311f367083d831682c49. * Stop subscribing to threads * Remove ref * Fix prop-types Co-authored-by: Diego Mello * [FIX] Real name being ignored in SearchMessagesView (#2838) Co-authored-by: Gerzon Z Co-authored-by: Diego Mello * [CHORE] Remove unnecessary share reducer calls (#2861) * Remove unnecesary share reducer calls * Update Avatar Co-authored-by: Diego Mello * [FIX] Breadcrumbs exceeding characters limit (#2862) * [FIX] breadcrumbs exceeding * fix.breadcrumbs-exceeding-change-events Co-authored-by: Diego Mello * [FIX] App compressing videos on iOS (#2915) * Update index.js * Update index.js * [FIX] Real name setting ignored on reply preview (#2908) Co-authored-by: Diego Mello * [FIX] Reply component sending unused prop to Description (#2900) Co-authored-by: Diego Mello * [CHORE] BackdropOpacity based on themes (#2863) * Added backdropOpacity based on theme * Updated ActionSheet, ReactionsModal, ReactionPicker and Sidebar * Updated MultiSelect Co-authored-by: Diego Mello * [FIX] Webview not falling back to default auth challenge when no cert is provided (#2918) * [FIX] Android - fallback to default auth challenge handling when no cert is provided * If a certificate auth challenge is requested on Android the webview will hang if no certificate is loaded. To prevent this, fallback to default Android behavior and cancel the challenge with request.cancel() * No client certificate case defaults to super implementation * Update react-native-webview * Downgrade to previous dependency version Co-authored-by: Diego Mello Co-authored-by: Gerzon Z Co-authored-by: Jan Garaj * [FIX] Support Jitsi_URL_Room_Hash (#2905) * [FIX] Temp attachment files not being flushed after saved to gallery (#2871) * Update AttachmentView.js * Update AttachmentView.js * Update AttachmentView.js * Update AttachmentView.js Co-authored-by: Diego Mello * [CHORE] Update iOS profiles for Experimental app (#2933) * [IMPROVE] Deleted thread reply redirects to thread (#2840) Co-authored-by: Diego Mello * [FIX] Thread showing typing indicator from main room (#2869) * [FIX] Remove typing indicator from thread's header * remove unnecessary props and change usersTyping condition Co-authored-by: Diego Mello * [FIX] DM rooms show typing status from last group room (#2878) * [FIX] DM rooms show typing status from last group room * Undo changes * Check if current typing is from focused room before dispatching to redux Co-authored-by: Diego Mello * [FIX] Can't copy or edit media's description (#2885) * [FIX] Image descriptions issues * shorten the condition string * fix selectedMessage state Co-authored-by: Diego Mello * [FIX] RightButtonsContainer re-render check not returning default value (#2899) Co-authored-by: Diego Mello * [CHORE] Remove InteractionManager blocks (#2906) * [FIX] Remove InteractionManager blocks * Minor fix Co-authored-by: Diego Mello * [FIX] App not sending second argument for EventEmitter.removeListener on some places (#2909) Co-authored-by: Diego Mello * [FIX] Temp message ignoring real name (#2919) Co-authored-by: Diego Mello * [FIX] System message of e2e encryption is missing (#2888) * [FIX] System message of e2e encryption missing * add new encryption string * add to stories * Add pt-BR * Move stories Co-authored-by: Diego Mello * [CHORE] Add permissions to Redux (#2914) * [FIX] Add permissions to Redux store * add only permissions being used in the app * add clear permissions reducer * call RocketChat.hasPermission from reducer * add server version comparison on getPermissions * refactor hasPermission function * refactor hasPermission function * remove uncomment code * use Q.experimentalSortBy() * add coerce function * Change Rocketchat.hasPermission * Apply on isReadOnly * Apply to RoomInfoEditView * Apply to RoomInfoView and RoomInfoEditView * canAutoTranslate * Unnecessary clear permissions * Revert getUpdatedSince * Naming fix Co-authored-by: Diego Mello * [CHORE] Add hold step for ios and android build experimental (#2943) * [CHORE] Add hold step for ios-build-experimental and android-build-experimental * Android hold step * add ios hold step Co-authored-by: Diego Mello * [IMPROVEMENT] Remove lodash.isEqual (#2893) * Added dequal and react-fast-compare as substitutes to lodash.isEqual * Update ReplyPreview.js * Remove react-fast-compare * Removed deep-equal and upgrade babel-eslint dev dependency * Fix avatar * Fix Messagebox * Fix CreateDiscussionView * ModalBlockView * NewMessageView * ProfileView * RoomInfoEditView * ServerDropdown * Return local search as object instead of observable * SelectedUsersView Co-authored-by: Diego Mello * [I18N] Add missing Russian strings (#2946) * [i18n] Add missing Russian strings * Couple fixes * Fix Direct_message Translate Direct_message as already has been translated Co-authored-by: Diego Mello * [CHORE] Use shortcut syntax for get collections (#2932) Co-authored-by: Diego Mello * [FIX] Use List.Separator in all places (#2931) * [FIX] Use List.Separator in all places * add List.Separator * change List.Separator Co-authored-by: Diego Mello * [FIX] Limit new message list query size to 50 (#2947) * Limit query to 50 * Remove observable * [FIX] Support chats order for older versions of the server (#2934) * Update mergeSubscriptionsRooms.js * Update mergeSubscriptionsRooms.js * Update mergeSubscriptionsRooms.js * Minor refactor Co-authored-by: Diego Mello * [FIX] Reactions modal's backdrop color too light (#2949) Co-authored-by: Diego Mello * Bump version to 4.15.0 (#2950) * [FIX] Share extension not working correctly on Official app (#2963) * [FIX] Cannot read property 'some' of undefined on hasPermission (#2966) Co-authored-by: Diego Mello * [FIX] Deep linking and other connectivity issues (#2894) * Navigate from push notification only if necessary * Use JS SDK branch * Stop reconnecting if it's already connected * Fix RoomsListView forever loading after tapping push notification of another server * Execute fewer operations on app/index * Remove roomsRequest call from onForeground * Apply check and reopen * Stop opening in-app notification when the app is on backgorund * Connecting tweaks * Fix deep linking not working if the app is on background * Force reset yarn cache * Upgrade JS SDK * Remove listener on unmount * Fix resume on Android after back button is pressed * Fix local authentication resume * Fix back button android * Change JS SDK branch * [FIX] Messagebox's placeholder color is too bright (#2968) Co-authored-by: Ezequiel de Oliveira Co-authored-by: Dan Caseley Co-authored-by: Djorkaeff Alexandre Co-authored-by: Youssef Muhamad Co-authored-by: Graham Smith Co-authored-by: Gabriel Henriques Co-authored-by: Júlia Grala <30629556+juliagrala@users.noreply.github.com> Co-authored-by: Guilherme Gazzo Co-authored-by: Prateek Jain <44807945+Prateek93a@users.noreply.github.com> Co-authored-by: Lucas Siqueira Co-authored-by: Calebe Rios Co-authored-by: Pitstopper <18574776+Pitstopper@users.noreply.github.com> Co-authored-by: phriedrich Co-authored-by: Guilherme Siqueira Co-authored-by: Prateek Jain Co-authored-by: devyaniChoubey <52153085+devyaniChoubey@users.noreply.github.com> Co-authored-by: Bernard Seow Co-authored-by: Hiroki Ishiura Co-authored-by: Exordian Co-authored-by: Daanchaam Co-authored-by: Iván Álvarez Co-authored-by: Sarthak Pranesh <41206172+sarthakpranesh@users.noreply.github.com> Co-authored-by: Michele Pellegrini Co-authored-by: Tanmoy Bhowmik Co-authored-by: Hibikine Kage <14365761+hibikine@users.noreply.github.com> Co-authored-by: Neil Agarwal Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Govind Dixit Co-authored-by: Zhaubassarova Aruzhan <49000079+azhaubassar@users.noreply.github.com> Co-authored-by: Aroo Co-authored-by: Sarthak Pranesh Co-authored-by: Siddharth Padhi Co-authored-by: Bruno Dantas Co-authored-by: devyaniChoubey Co-authored-by: Heng Sok Co-authored-by: Snyk bot Co-authored-by: nixxou <45721836+nixxou@users.noreply.github.com> Co-authored-by: David-Tsui Co-authored-by: Vincenzo Esposito Co-authored-by: Rishabh Gupta <38923768+imrishabh18@users.noreply.github.com> Co-authored-by: Hendy Irawan Co-authored-by: Alexandru Naiman Co-authored-by: Dani Co-authored-by: Luis Co-authored-by: zaphod534 <32894570+zaphod534@users.noreply.github.com> Co-authored-by: ankar84 Co-authored-by: Карлан Антон Андреевич Co-authored-by: Saket Mahajan Co-authored-by: Rohit Verma <44283521+refactor-droidyy@users.noreply.github.com> Co-authored-by: Marco Jakobs Co-authored-by: Daniel Maike Co-authored-by: Vitor Leal Co-authored-by: Fernando Aguilar Co-authored-by: Abdullah Alhamoud <10301923+abalhamoud@users.noreply.github.com> Co-authored-by: Dave Koo Co-authored-by: Fazil Boudjelal Co-authored-by: Lucas Dousse Co-authored-by: Sumukha Hegde Co-authored-by: Gerzon Z Co-authored-by: Gerzon Z Co-authored-by: yash-rajpal <58601732+yash-rajpal@users.noreply.github.com> Co-authored-by: Hakan YILMAZ Co-authored-by: Arkadyuti Bandyopadhyay Co-authored-by: Anant Bhasin <38764067+aKn1ghtOut@users.noreply.github.com> Co-authored-by: Gung Wah <41157464+kresnaputra@users.noreply.github.com> Co-authored-by: Billy Newman Co-authored-by: Jan Garaj --- .circleci/config.yml | 16 +- .eslintrc.js | 8 +- .../__snapshots__/Storyshots.test.js.snap | 303 ++++++++++++++++++ android/app/build.gradle | 2 +- android/app/src/main/AndroidManifest.xml | 2 +- app/actions/actionsTypes.js | 2 + app/actions/permissions.js | 8 + app/constants/colors.js | 3 + app/constants/settings.js | 3 + app/containers/ActionSheet/ActionSheet.js | 2 +- app/containers/Avatar/index.js | 8 +- app/containers/EmojiPicker/index.js | 8 +- app/containers/InAppNotification/index.js | 29 +- app/containers/MessageActions/Header.js | 2 +- app/containers/MessageActions/index.js | 32 +- .../MessageBox/CommandsPreview/index.js | 4 +- app/containers/MessageBox/Mentions/index.js | 4 +- app/containers/MessageBox/ReplyPreview.js | 13 +- app/containers/MessageBox/index.js | 28 +- app/containers/MessageErrorActions.js | 4 +- app/containers/Toast.js | 4 +- app/containers/TwoFactor/index.js | 4 +- app/containers/UIKit/MultiSelect/index.js | 4 +- app/containers/UIKit/MultiSelect/styles.js | 4 - app/containers/message/Attachments.js | 4 +- app/containers/message/Audio.js | 4 +- app/containers/message/Content.js | 6 +- app/containers/message/Image.js | 4 +- app/containers/message/Message.js | 3 +- app/containers/message/Reply.js | 7 +- app/containers/message/Urls.js | 6 +- app/containers/message/Video.js | 4 +- app/containers/message/utils.js | 8 +- app/ee/omnichannel/views/QueueListView.js | 4 +- app/i18n/locales/en.js | 4 +- app/i18n/locales/pt-BR.js | 4 +- app/i18n/locales/ru.js | 28 +- app/index.js | 21 +- app/lib/encryption/encryption.js | 12 +- app/lib/encryption/room.js | 2 +- app/lib/methods/callJitsi.js | 22 +- app/lib/methods/canOpenRoom.js | 5 +- app/lib/methods/enterpriseModules.js | 4 +- app/lib/methods/getCustomEmojis.js | 45 ++- app/lib/methods/getPermissions.js | 74 ++++- app/lib/methods/getRoles.js | 63 ++-- app/lib/methods/getSettings.js | 6 +- app/lib/methods/getSlashCommands.js | 73 ++--- app/lib/methods/getUsersPresence.js | 2 +- .../methods/helpers/findSubscriptionsRooms.js | 2 +- .../helpers/mergeSubscriptionsRooms.js | 15 +- app/lib/methods/loadMissedMessages.js | 2 +- app/lib/methods/loadThreadMessages.js | 67 ++-- app/lib/methods/logout.js | 4 +- app/lib/methods/readMessages.js | 2 +- app/lib/methods/sendFileMessage.js | 2 +- app/lib/methods/sendMessage.js | 18 +- app/lib/methods/subscriptions/room.js | 16 +- app/lib/methods/subscriptions/rooms.js | 12 +- app/lib/methods/updateMessages.js | 8 +- app/lib/rocketchat.js | 100 +++--- app/presentation/RoomItem/LastMessage.js | 4 +- app/reducers/index.js | 4 +- app/reducers/permissions.js | 14 + app/sagas/createChannel.js | 6 +- app/sagas/createDiscussion.js | 8 +- app/sagas/deepLinking.js | 41 ++- app/sagas/encryption.js | 2 +- app/sagas/init.js | 2 +- app/sagas/login.js | 6 +- app/sagas/messages.js | 2 +- app/sagas/rooms.js | 8 +- app/sagas/selectServer.js | 7 +- app/sagas/state.js | 17 +- app/stacks/InsideStack.js | 32 +- app/utils/isReadOnly.js | 16 +- app/utils/localAuthentication.js | 10 +- app/utils/log/events.js | 36 +-- app/views/AttachmentView.js | 5 +- app/views/ChangePasscodeView.js | 4 +- app/views/CreateChannelView.js | 38 +-- app/views/CreateDiscussionView/SelectUsers.js | 2 +- app/views/CreateDiscussionView/index.js | 12 +- app/views/DirectoryView/Options.js | 8 +- app/views/DirectoryView/index.js | 8 +- app/views/LanguageView/index.js | 2 +- app/views/LoginView.js | 4 +- app/views/MessagesView/index.js | 4 +- app/views/ModalBlockView.js | 12 - app/views/NewMessageView.js | 50 +-- app/views/NewServerView/index.js | 6 +- app/views/ProfileView/index.js | 18 +- app/views/ReadReceiptView/index.js | 12 +- app/views/RoomActionsView/index.js | 82 +++-- app/views/RoomInfoEditView/index.js | 77 +++-- app/views/RoomInfoView/index.js | 17 +- app/views/RoomMembersView/index.js | 47 ++- app/views/RoomView/Header/Header.js | 2 +- app/views/RoomView/Header/RightButtons.js | 13 +- app/views/RoomView/Header/index.js | 4 +- app/views/RoomView/List.js | 10 +- app/views/RoomView/ReactionPicker.js | 10 +- app/views/RoomView/index.js | 41 ++- app/views/RoomsListView/ServerDropdown.js | 29 +- app/views/RoomsListView/SortDropdown/index.js | 8 +- app/views/RoomsListView/index.js | 35 +- app/views/ScreenLockConfigView.js | 2 +- app/views/ScreenLockedView.js | 4 +- app/views/SearchMessagesView/index.js | 15 +- app/views/SelectServerView.js | 2 +- app/views/SelectedUsersView.js | 38 +-- app/views/SettingsView/index.js | 2 +- app/views/ShareListView/index.js | 8 +- app/views/ShareView/Thumbs.js | 1 + app/views/ShareView/index.js | 6 +- app/views/SidebarView/index.js | 92 +++--- .../ThreadMessagesView/Dropdown/index.js | 2 +- app/views/ThreadMessagesView/index.js | 20 +- ios/NotificationService/Info.plist | 2 + ios/ReplyNotification.swift | 3 + ios/RocketChatRN-Bridging-Header.h | 2 + ios/RocketChatRN.xcodeproj/project.pbxproj | 18 +- ios/RocketChatRN/Info.plist | 2 +- ios/ShareRocketChatRN/Info.plist | 4 +- package.json | 10 +- patches/react-native-webview+10.3.2.patch | 6 +- storybook/stories/Message.js | 4 + yarn.lock | 177 +++------- 128 files changed, 1342 insertions(+), 1013 deletions(-) create mode 100644 app/actions/permissions.js create mode 100644 app/reducers/permissions.js diff --git a/.circleci/config.yml b/.circleci/config.yml index c2195c3b2..3e3a66b87 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -237,9 +237,13 @@ commands: if [[ $CIRCLE_JOB == "ios-build-official" ]]; then /usr/libexec/PlistBuddy -c "Set BugsnagAPIKey $BUGSNAG_KEY_OFFICIAL" ./RocketChatRN/Info.plist /usr/libexec/PlistBuddy -c "Set IS_OFFICIAL YES" ./RocketChatRN/Info.plist + /usr/libexec/PlistBuddy -c "Set IS_OFFICIAL YES" ./ShareRocketChatRN/Info.plist + /usr/libexec/PlistBuddy -c "Set IS_OFFICIAL YES" ./NotificationService/Info.plist else /usr/libexec/PlistBuddy -c "Set BugsnagAPIKey $BUGSNAG_KEY" ./RocketChatRN/Info.plist /usr/libexec/PlistBuddy -c "Set IS_OFFICIAL NO" ./RocketChatRN/Info.plist + /usr/libexec/PlistBuddy -c "Set IS_OFFICIAL NO" ./ShareRocketChatRN/Info.plist + /usr/libexec/PlistBuddy -c "Set IS_OFFICIAL NO" ./NotificationService/Info.plist fi if [[ $APP_STORE_CONNECT_API_KEY ]]; then @@ -416,9 +420,13 @@ workflows: - lint-testunit # iOS Experimental + - ios-hold-build-experimental: + type: approval + requires: + - lint-testunit - ios-build-experimental: requires: - - lint-testunit + - ios-hold-build-experimental - ios-hold-testflight-experimental: type: approval requires: @@ -444,9 +452,13 @@ workflows: - ios-hold-testflight-official # Android Experimental + - android-hold-build-experimental: + type: approval + requires: + - lint-testunit - android-build-experimental: requires: - - lint-testunit + - android-hold-build-experimental - android-hold-google-play-beta-experimental: type: approval requires: diff --git a/.eslintrc.js b/.eslintrc.js index 44e4eaf4c..add372a0b 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -6,7 +6,7 @@ module.exports = { } } }, - "parser": "babel-eslint", + "parser": "@babel/eslint-parser", "extends": "airbnb", "parserOptions": { "sourceType": "module", @@ -21,7 +21,8 @@ module.exports = { "react", "jsx-a11y", "import", - "react-native" + "react-native", + "@babel" ], "env": { "browser": true, @@ -148,7 +149,8 @@ module.exports = { "react/jsx-curly-newline": [0], "react/state-in-constructor": [0], "no-async-promise-executor": [0], - "max-classes-per-file": [0] + "max-classes-per-file": [0], + "no-multiple-empty-lines": [0] }, "globals": { "__DEV__": true diff --git a/__tests__/__snapshots__/Storyshots.test.js.snap b/__tests__/__snapshots__/Storyshots.test.js.snap index 17bfb4dd2..0eb72257c 100644 --- a/__tests__/__snapshots__/Storyshots.test.js.snap +++ b/__tests__/__snapshots__/Storyshots.test.js.snap @@ -44404,6 +44404,309 @@ exports[`Storyshots Message list message 1`] = ` + + Toggle e2e encryption + + + + + + + + + + + + + + + This room's encryption has been disabled by diego.mello + + + + + + + + + + + + + + + + + + + + This room's encryption has been enabled by diego.mello + + + + + + diff --git a/app/actions/actionsTypes.js b/app/actions/actionsTypes.js index 0d18c9445..1fd8679bc 100644 --- a/app/actions/actionsTypes.js +++ b/app/actions/actionsTypes.js @@ -70,3 +70,5 @@ export const SETTINGS = createRequestTypes('SETTINGS', ['CLEAR', 'ADD']); export const APP_STATE = createRequestTypes('APP_STATE', ['FOREGROUND', 'BACKGROUND']); export const ENTERPRISE_MODULES = createRequestTypes('ENTERPRISE_MODULES', ['CLEAR', 'SET']); export const ENCRYPTION = createRequestTypes('ENCRYPTION', ['INIT', 'STOP', 'DECODE_KEY', 'SET', 'SET_BANNER']); + +export const PERMISSIONS = createRequestTypes('PERMISSIONS', ['SET']); diff --git a/app/actions/permissions.js b/app/actions/permissions.js new file mode 100644 index 000000000..88179c34f --- /dev/null +++ b/app/actions/permissions.js @@ -0,0 +1,8 @@ +import * as types from './actionsTypes'; + +export function setPermissions(permissions) { + return { + type: types.PERMISSIONS.SET, + permissions + }; +} diff --git a/app/constants/colors.js b/app/constants/colors.js index b1fdcd7f3..f29f03d1d 100644 --- a/app/constants/colors.js +++ b/app/constants/colors.js @@ -63,6 +63,7 @@ export const themes = { passcodeDotFull: '#6C727A', previewBackground: '#1F2329', previewTintColor: '#ffffff', + backdropOpacity: 0.3, ...mentions }, dark: { @@ -109,6 +110,7 @@ export const themes = { passcodeDotFull: '#6C727A', previewBackground: '#030b1b', previewTintColor: '#ffffff', + backdropOpacity: 0.9, ...mentions }, black: { @@ -155,6 +157,7 @@ export const themes = { passcodeDotFull: '#6C727A', previewBackground: '#000000', previewTintColor: '#ffffff', + backdropOpacity: 0.9, ...mentions } }; diff --git a/app/constants/settings.js b/app/constants/settings.js index 359dff092..9f0df8865 100644 --- a/app/constants/settings.js +++ b/app/constants/settings.js @@ -101,6 +101,9 @@ export default { Jitsi_Enabled_TokenAuth: { type: 'valueAsBoolean' }, + Jitsi_URL_Room_Hash: { + type: 'valueAsBoolean' + }, Jitsi_URL_Room_Prefix: { type: 'valueAsString' }, diff --git a/app/containers/ActionSheet/ActionSheet.js b/app/containers/ActionSheet/ActionSheet.js index 81b3496ae..af98a75ce 100644 --- a/app/containers/ActionSheet/ActionSheet.js +++ b/app/containers/ActionSheet/ActionSheet.js @@ -147,7 +147,7 @@ const ActionSheet = React.memo(forwardRef(({ children, theme }, ref) => { const animatedPosition = React.useRef(new Value(0)); const opacity = interpolate(animatedPosition.current, { inputRange: [0, 1], - outputRange: [0, 0.7], + outputRange: [0, themes[theme].backdropOpacity], extrapolate: Extrapolate.CLAMP }); diff --git a/app/containers/Avatar/index.js b/app/containers/Avatar/index.js index 73314a17d..4d7c6d7a5 100644 --- a/app/containers/Avatar/index.js +++ b/app/containers/Avatar/index.js @@ -2,7 +2,6 @@ import React from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { Q } from '@nozbe/watermelondb'; -import isEqual from 'react-fast-compare'; import database from '../../lib/database'; import { getUserSelector } from '../../selectors/login'; @@ -34,7 +33,8 @@ class AvatarContainer extends React.Component { } componentDidUpdate(prevProps) { - if (!isEqual(prevProps, this.props)) { + const { text, type } = this.props; + if (prevProps.text !== text || prevProps.type !== type) { this.init(); } } @@ -52,8 +52,8 @@ class AvatarContainer extends React.Component { init = async() => { const db = database.active; - const usersCollection = db.collections.get('users'); - const subsCollection = db.collections.get('subscriptions'); + const usersCollection = db.get('users'); + const subsCollection = db.get('subscriptions'); let record; try { diff --git a/app/containers/EmojiPicker/index.js b/app/containers/EmojiPicker/index.js index 65a973715..89446c067 100644 --- a/app/containers/EmojiPicker/index.js +++ b/app/containers/EmojiPicker/index.js @@ -2,7 +2,7 @@ import React, { Component } from 'react'; import { View } from 'react-native'; import PropTypes from 'prop-types'; import ScrollableTabView from 'react-native-scrollable-tab-view'; -import equal from 'deep-equal'; +import { dequal } from 'dequal'; import { connect } from 'react-redux'; import orderBy from 'lodash/orderBy'; import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord'; @@ -67,7 +67,7 @@ class EmojiPicker extends Component { if (nextState.width !== width) { return true; } - if (!equal(nextState.frequentlyUsed, frequentlyUsed)) { + if (!dequal(nextState.frequentlyUsed, frequentlyUsed)) { return true; } return false; @@ -95,7 +95,7 @@ class EmojiPicker extends Component { // eslint-disable-next-line react/sort-comp _addFrequentlyUsed = protectedFunction(async(emoji) => { const db = database.active; - const freqEmojiCollection = db.collections.get('frequently_used_emojis'); + const freqEmojiCollection = db.get('frequently_used_emojis'); let freqEmojiRecord; try { freqEmojiRecord = await freqEmojiCollection.find(emoji.content); @@ -120,7 +120,7 @@ class EmojiPicker extends Component { updateFrequentlyUsed = async() => { const db = database.active; - const frequentlyUsedRecords = await db.collections.get('frequently_used_emojis').query().fetch(); + const frequentlyUsedRecords = await db.get('frequently_used_emojis').query().fetch(); let frequentlyUsed = orderBy(frequentlyUsedRecords, ['count'], ['desc']); frequentlyUsed = frequentlyUsed.map((item) => { if (item.isCustom) { diff --git a/app/containers/InAppNotification/index.js b/app/containers/InAppNotification/index.js index dd6573f33..7d22b127a 100644 --- a/app/containers/InAppNotification/index.js +++ b/app/containers/InAppNotification/index.js @@ -1,5 +1,8 @@ import React, { memo, useEffect } from 'react'; +import PropTypes from 'prop-types'; import { NotifierRoot, Notifier, Easing } from 'react-native-notifier'; +import { connect } from 'react-redux'; +import { dequal } from 'dequal'; import NotifierComponent from './NotifierComponent'; import EventEmitter from '../../utils/events'; @@ -8,13 +11,17 @@ import { getActiveRoute } from '../../utils/navigation'; export const INAPP_NOTIFICATION_EMITTER = 'NotificationInApp'; -const InAppNotification = memo(() => { +const InAppNotification = memo(({ rooms, appState }) => { const show = (notification) => { + if (appState !== 'foreground') { + return; + } + const { payload } = notification; const state = Navigation.navigationRef.current?.getRootState(); const route = getActiveRoute(state); if (payload.rid) { - if ((route?.name === 'RoomView' && route.params?.rid === payload.rid) || route?.name === 'JitsiMeetView') { + if (rooms.includes(payload.rid) || route?.name === 'JitsiMeetView') { return; } Notifier.showNotification({ @@ -28,13 +35,23 @@ const InAppNotification = memo(() => { }; useEffect(() => { - EventEmitter.addEventListener(INAPP_NOTIFICATION_EMITTER, show); + const listener = EventEmitter.addEventListener(INAPP_NOTIFICATION_EMITTER, show); return () => { - EventEmitter.removeListener(INAPP_NOTIFICATION_EMITTER); + EventEmitter.removeListener(INAPP_NOTIFICATION_EMITTER, listener); }; - }, []); + }, [rooms]); return ; +}, (prevProps, nextProps) => dequal(prevProps.rooms, nextProps.rooms)); + +const mapStateToProps = state => ({ + rooms: state.room.rooms, + appState: state.app.ready && state.app.foreground ? 'foreground' : 'background' }); -export default InAppNotification; +InAppNotification.propTypes = { + rooms: PropTypes.array, + appState: PropTypes.string +}; + +export default connect(mapStateToProps)(InAppNotification); diff --git a/app/containers/MessageActions/Header.js b/app/containers/MessageActions/Header.js index ab011e445..78aa9ae3d 100644 --- a/app/containers/MessageActions/Header.js +++ b/app/containers/MessageActions/Header.js @@ -96,7 +96,7 @@ const Header = React.memo(({ const setEmojis = async() => { try { const db = database.active; - const freqEmojiCollection = db.collections.get('frequently_used_emojis'); + const freqEmojiCollection = db.get('frequently_used_emojis'); let freqEmojis = await freqEmojiCollection.query().fetch(); const isLandscape = width > height; diff --git a/app/containers/MessageActions/index.js b/app/containers/MessageActions/index.js index 0ce32bb71..cf0ba6918 100644 --- a/app/containers/MessageActions/index.js +++ b/app/containers/MessageActions/index.js @@ -34,20 +34,24 @@ const MessageActions = React.memo(forwardRef(({ Message_AllowPinning, Message_AllowStarring, Message_Read_Receipt_Store_Users, - isMasterDetail + isMasterDetail, + editMessagePermission, + deleteMessagePermission, + forceDeleteMessagePermission, + pinMessagePermission }, ref) => { let permissions = {}; const { showActionSheet, hideActionSheet } = useActionSheet(); const getPermissions = async() => { try { - const permission = ['edit-message', 'delete-message', 'force-delete-message', 'pin-message']; + const permission = [editMessagePermission, deleteMessagePermission, forceDeleteMessagePermission, pinMessagePermission]; const result = await RocketChat.hasPermission(permission, room.rid); permissions = { - hasEditPermission: result[permission[0]], - hasDeletePermission: result[permission[1]], - hasForceDeletePermission: result[permission[2]], - hasPinPermission: result[permission[3]] + hasEditPermission: result[0], + hasDeletePermission: result[1], + hasForceDeletePermission: result[2], + hasPinPermission: result[3] }; } catch { // Do nothing @@ -141,7 +145,7 @@ const MessageActions = React.memo(forwardRef(({ const db = database.active; const result = await RocketChat.markAsUnread({ messageId }); if (result.success) { - const subCollection = db.collections.get('subscriptions'); + const subCollection = db.get('subscriptions'); const subRecord = await subCollection.find(rid); await db.action(async() => { try { @@ -171,7 +175,7 @@ const MessageActions = React.memo(forwardRef(({ const handleCopy = async(message) => { logEvent(events.ROOM_MSG_ACTION_COPY); - await Clipboard.setString(message.msg); + await Clipboard.setString(message?.attachments?.[0]?.description || message.msg); EventEmitter.emit(LISTENER, { message: I18n.t('Copied_to_clipboard') }); }; @@ -440,7 +444,11 @@ MessageActions.propTypes = { Message_AllowPinning: PropTypes.bool, Message_AllowStarring: PropTypes.bool, Message_Read_Receipt_Store_Users: PropTypes.bool, - server: PropTypes.string + server: PropTypes.string, + editMessagePermission: PropTypes.array, + deleteMessagePermission: PropTypes.array, + forceDeleteMessagePermission: PropTypes.array, + pinMessagePermission: PropTypes.array }; const mapStateToProps = state => ({ @@ -452,7 +460,11 @@ const mapStateToProps = state => ({ Message_AllowPinning: state.settings.Message_AllowPinning, Message_AllowStarring: state.settings.Message_AllowStarring, Message_Read_Receipt_Store_Users: state.settings.Message_Read_Receipt_Store_Users, - isMasterDetail: state.app.isMasterDetail + isMasterDetail: state.app.isMasterDetail, + editMessagePermission: state.permissions['edit-message'], + deleteMessagePermission: state.permissions['delete-message'], + forceDeleteMessagePermission: state.permissions['force-delete-message'], + pinMessagePermission: state.permissions['pin-message'] }); export default connect(mapStateToProps, null, null, { forwardRef: true })(MessageActions); diff --git a/app/containers/MessageBox/CommandsPreview/index.js b/app/containers/MessageBox/CommandsPreview/index.js index 1b6a27acd..1bb03ca8b 100644 --- a/app/containers/MessageBox/CommandsPreview/index.js +++ b/app/containers/MessageBox/CommandsPreview/index.js @@ -1,7 +1,7 @@ import React from 'react'; import { FlatList } from 'react-native'; import PropTypes from 'prop-types'; -import equal from 'deep-equal'; +import { dequal } from 'dequal'; import Item from './Item'; import styles from '../styles'; @@ -31,7 +31,7 @@ const CommandsPreview = React.memo(({ theme, commandPreview, showCommandPreview if (prevProps.showCommandPreview !== nextProps.showCommandPreview) { return false; } - if (!equal(prevProps.commandPreview, nextProps.commandPreview)) { + if (!dequal(prevProps.commandPreview, nextProps.commandPreview)) { return false; } return true; diff --git a/app/containers/MessageBox/Mentions/index.js b/app/containers/MessageBox/Mentions/index.js index 37c30c30b..fb845b2ad 100644 --- a/app/containers/MessageBox/Mentions/index.js +++ b/app/containers/MessageBox/Mentions/index.js @@ -1,7 +1,7 @@ import React from 'react'; import { FlatList, View } from 'react-native'; import PropTypes from 'prop-types'; -import equal from 'deep-equal'; +import { dequal } from 'dequal'; import styles from '../styles'; import MentionItem from './MentionItem'; @@ -30,7 +30,7 @@ const Mentions = React.memo(({ mentions, trackingType, theme }) => { if (prevProps.trackingType !== nextProps.trackingType) { return false; } - if (!equal(prevProps.mentions, nextProps.mentions)) { + if (!dequal(prevProps.mentions, nextProps.mentions)) { return false; } return true; diff --git a/app/containers/MessageBox/ReplyPreview.js b/app/containers/MessageBox/ReplyPreview.js index e1fcbcca7..eee81236d 100644 --- a/app/containers/MessageBox/ReplyPreview.js +++ b/app/containers/MessageBox/ReplyPreview.js @@ -3,7 +3,6 @@ import { View, Text, StyleSheet } from 'react-native'; import PropTypes from 'prop-types'; import moment from 'moment'; import { connect } from 'react-redux'; -import isEqual from 'lodash/isEqual'; import Markdown from '../markdown'; import { CustomIcon } from '../../lib/Icons'; @@ -43,7 +42,7 @@ const styles = StyleSheet.create({ }); const ReplyPreview = React.memo(({ - message, Message_TimeFormat, baseUrl, username, replying, getCustomEmoji, close, theme + message, Message_TimeFormat, baseUrl, username, replying, getCustomEmoji, close, theme, useRealName }) => { if (!replying) { return null; @@ -59,7 +58,7 @@ const ReplyPreview = React.memo(({ > - {message.u?.username} + {useRealName ? message.u?.name : message.u?.username} {time} ); -}, (prevProps, nextProps) => prevProps.replying === nextProps.replying && prevProps.theme === nextProps.theme && isEqual(prevProps.message, nextProps.message)); +}, (prevProps, nextProps) => prevProps.replying === nextProps.replying && prevProps.theme === nextProps.theme && prevProps.message.id === nextProps.message.id); ReplyPreview.propTypes = { replying: PropTypes.bool, @@ -85,12 +84,14 @@ ReplyPreview.propTypes = { baseUrl: PropTypes.string.isRequired, username: PropTypes.string.isRequired, getCustomEmoji: PropTypes.func, - theme: PropTypes.string + theme: PropTypes.string, + useRealName: PropTypes.bool }; const mapStateToProps = state => ({ Message_TimeFormat: state.settings.Message_TimeFormat, - baseUrl: state.server.server + baseUrl: state.server.server, + useRealName: state.settings.UI_Use_Real_Name }); export default connect(mapStateToProps)(ReplyPreview); diff --git a/app/containers/MessageBox/index.js b/app/containers/MessageBox/index.js index 12fad3f15..9a075e31a 100644 --- a/app/containers/MessageBox/index.js +++ b/app/containers/MessageBox/index.js @@ -6,7 +6,7 @@ import { import { connect } from 'react-redux'; import { KeyboardAccessoryView } from 'react-native-ui-lib/keyboard'; import ImagePicker from 'react-native-image-crop-picker'; -import equal from 'deep-equal'; +import { dequal } from 'dequal'; import DocumentPicker from 'react-native-document-picker'; import { Q } from '@nozbe/watermelondb'; import { TouchableWithoutFeedback } from 'react-native-gesture-handler'; @@ -63,6 +63,7 @@ const imagePickerConfig = { const libraryPickerConfig = { multiple: true, + compressVideoPreset: 'Passthrough', mediaType: 'any' }; @@ -189,8 +190,8 @@ class MessageBox extends Component { } = this.props; let msg; try { - const threadsCollection = db.collections.get('threads'); - const subsCollection = db.collections.get('subscriptions'); + const threadsCollection = db.get('threads'); + const subsCollection = db.get('subscriptions'); try { this.room = await subsCollection.find(rid); } catch (error) { @@ -270,7 +271,7 @@ class MessageBox extends Component { } = this.state; const { - roomType, replying, editing, isFocused, message, theme, children + roomType, replying, editing, isFocused, message, theme } = this.props; if (nextProps.theme !== theme) { return true; @@ -299,16 +300,13 @@ class MessageBox extends Component { if (nextState.tshow !== tshow) { return true; } - if (!equal(nextState.mentions, mentions)) { + if (!dequal(nextState.mentions, mentions)) { return true; } - if (!equal(nextState.commandPreview, commandPreview)) { + if (!dequal(nextState.commandPreview, commandPreview)) { return true; } - if (!equal(nextProps.message, message)) { - return true; - } - if (!equal(nextProps.children, children)) { + if (!dequal(nextProps.message?.id, message?.id)) { return true; } return false; @@ -366,7 +364,7 @@ class MessageBox extends Component { const slashCommand = text.match(/^\/([a-z0-9._-]+) (.+)/im); if (slashCommand) { const [, name, params] = slashCommand; - const commandsCollection = db.collections.get('slash_commands'); + const commandsCollection = db.get('slash_commands'); try { const command = await commandsCollection.find(name); if (command.providesPreview) { @@ -507,7 +505,7 @@ class MessageBox extends Component { getEmojis = debounce(async(keyword) => { const db = database.active; if (keyword) { - const customEmojisCollection = db.collections.get('custom_emojis'); + const customEmojisCollection = db.get('custom_emojis'); const likeString = sanitizeLikeString(keyword); let customEmojis = await customEmojisCollection.query( Q.where('name', Q.like(`${ likeString }%`)) @@ -521,7 +519,7 @@ class MessageBox extends Component { getSlashCommands = debounce(async(keyword) => { const db = database.active; - const commandsCollection = db.collections.get('slash_commands'); + const commandsCollection = db.get('slash_commands'); const likeString = sanitizeLikeString(keyword); const commands = await commandsCollection.query( Q.where('id', Q.like(`${ likeString }%`)) @@ -753,7 +751,7 @@ class MessageBox extends Component { // Slash command if (message[0] === MENTIONS_TRACKING_TYPE_COMMANDS) { const db = database.active; - const commandsCollection = db.collections.get('slash_commands'); + const commandsCollection = db.get('slash_commands'); const command = message.replace(/ .*/, '').slice(1); const likeString = sanitizeLikeString(command); const slashCommand = await commandsCollection.query( @@ -941,7 +939,7 @@ class MessageBox extends Component { keyboardType='twitter' blurOnSubmit={false} placeholder={I18n.t('New_Message')} - placeholderTextColor={themes[theme].auxiliaryTintColor} + placeholderTextColor={themes[theme].auxiliaryText} onChangeText={this.onChangeText} onSelectionChange={this.onSelectionChange} underlineColorAndroid='transparent' diff --git a/app/containers/MessageErrorActions.js b/app/containers/MessageErrorActions.js index c9975b0e3..e84a99048 100644 --- a/app/containers/MessageErrorActions.js +++ b/app/containers/MessageErrorActions.js @@ -19,8 +19,8 @@ const MessageErrorActions = forwardRef(({ tmid }, ref) => { try { const db = database.active; const deleteBatch = []; - const msgCollection = db.collections.get('messages'); - const threadCollection = db.collections.get('threads'); + const msgCollection = db.get('messages'); + const threadCollection = db.get('threads'); // Delete the object (it can be Message or ThreadMessage instance) deleteBatch.push(message.prepareDestroyPermanently()); diff --git a/app/containers/Toast.js b/app/containers/Toast.js index eed7cfd7c..4b982fb49 100644 --- a/app/containers/Toast.js +++ b/app/containers/Toast.js @@ -28,7 +28,7 @@ class Toast extends React.Component { } componentDidMount() { - EventEmitter.addEventListener(LISTENER, this.showToast); + this.listener = EventEmitter.addEventListener(LISTENER, this.showToast); } shouldComponentUpdate(nextProps) { @@ -40,7 +40,7 @@ class Toast extends React.Component { } componentWillUnmount() { - EventEmitter.removeListener(LISTENER); + EventEmitter.removeListener(LISTENER, this.listener); } getToastRef = toast => this.toast = toast; diff --git a/app/containers/TwoFactor/index.js b/app/containers/TwoFactor/index.js index c6ad5467a..deb5c25db 100644 --- a/app/containers/TwoFactor/index.js +++ b/app/containers/TwoFactor/index.js @@ -58,9 +58,9 @@ const TwoFactor = React.memo(({ theme, isMasterDetail }) => { const showTwoFactor = args => setData(args); useEffect(() => { - EventEmitter.addEventListener(TWO_FACTOR, showTwoFactor); + const listener = EventEmitter.addEventListener(TWO_FACTOR, showTwoFactor); - return () => EventEmitter.removeListener(TWO_FACTOR); + return () => EventEmitter.removeListener(TWO_FACTOR, listener); }, []); const onCancel = () => { diff --git a/app/containers/UIKit/MultiSelect/index.js b/app/containers/UIKit/MultiSelect/index.js index b88330e4e..246a44ec0 100644 --- a/app/containers/UIKit/MultiSelect/index.js +++ b/app/containers/UIKit/MultiSelect/index.js @@ -1,6 +1,6 @@ import React, { useState, useEffect } from 'react'; import { - View, Text, TouchableWithoutFeedback, Modal, KeyboardAvoidingView, Animated, Easing + View, Text, TouchableWithoutFeedback, Modal, KeyboardAvoidingView, Animated, Easing, StyleSheet } from 'react-native'; import PropTypes from 'prop-types'; import { BLOCK_CONTEXT } from '@rocket.chat/ui-kit'; @@ -172,7 +172,7 @@ export const MultiSelect = React.memo(({ > - + {showContent ? renderContent() : null} diff --git a/app/containers/UIKit/MultiSelect/styles.js b/app/containers/UIKit/MultiSelect/styles.js index f261932c3..8bc2c2124 100644 --- a/app/containers/UIKit/MultiSelect/styles.js +++ b/app/containers/UIKit/MultiSelect/styles.js @@ -8,10 +8,6 @@ export default StyleSheet.create({ alignItems: 'center', justifyContent: 'flex-end' }, - backdrop: { - ...StyleSheet.absoluteFill, - opacity: 0.3 - }, modal: { height: 300, width: '100%', diff --git a/app/containers/message/Attachments.js b/app/containers/message/Attachments.js index 3d4ff48b4..0d068e9fd 100644 --- a/app/containers/message/Attachments.js +++ b/app/containers/message/Attachments.js @@ -1,5 +1,5 @@ import React from 'react'; -import isEqual from 'lodash/isEqual'; +import { dequal } from 'dequal'; import PropTypes from 'prop-types'; import Image from './Image'; @@ -28,7 +28,7 @@ const Attachments = React.memo(({ // eslint-disable-next-line react/no-array-index-key return ; }); -}, (prevProps, nextProps) => isEqual(prevProps.attachments, nextProps.attachments) && prevProps.theme === nextProps.theme); +}, (prevProps, nextProps) => dequal(prevProps.attachments, nextProps.attachments) && prevProps.theme === nextProps.theme); Attachments.propTypes = { attachments: PropTypes.array, diff --git a/app/containers/message/Audio.js b/app/containers/message/Audio.js index fad195890..e22dff408 100644 --- a/app/containers/message/Audio.js +++ b/app/containers/message/Audio.js @@ -6,7 +6,7 @@ import { import { Audio } from 'expo-av'; import Slider from '@react-native-community/slider'; import moment from 'moment'; -import equal from 'deep-equal'; +import { dequal } from 'dequal'; import { activateKeepAwake, deactivateKeepAwake } from 'expo-keep-awake'; import Touchable from './Touchable'; @@ -150,7 +150,7 @@ class MessageAudio extends React.Component { if (nextState.paused !== paused) { return true; } - if (!equal(nextProps.file, file)) { + if (!dequal(nextProps.file, file)) { return true; } if (nextState.loading !== loading) { diff --git a/app/containers/message/Content.js b/app/containers/message/Content.js index c963fed5c..2f29bf4ac 100644 --- a/app/containers/message/Content.js +++ b/app/containers/message/Content.js @@ -1,7 +1,7 @@ import React, { useContext } from 'react'; import { Text, View } from 'react-native'; import PropTypes from 'prop-types'; -import equal from 'deep-equal'; +import { dequal } from 'dequal'; import I18n from '../../i18n'; import styles from './styles'; @@ -108,10 +108,10 @@ const Content = React.memo((props) => { if (prevProps.isIgnored !== nextProps.isIgnored) { return false; } - if (!equal(prevProps.mentions, nextProps.mentions)) { + if (!dequal(prevProps.mentions, nextProps.mentions)) { return false; } - if (!equal(prevProps.channels, nextProps.channels)) { + if (!dequal(prevProps.channels, nextProps.channels)) { return false; } return true; diff --git a/app/containers/message/Image.js b/app/containers/message/Image.js index 1471b449e..6f466b3b3 100644 --- a/app/containers/message/Image.js +++ b/app/containers/message/Image.js @@ -2,7 +2,7 @@ import React, { useContext } from 'react'; import { View } from 'react-native'; import PropTypes from 'prop-types'; import FastImage from '@rocket.chat/react-native-fast-image'; -import equal from 'deep-equal'; +import { dequal } from 'dequal'; import { createImageProgress } from 'react-native-image-progress'; import * as Progress from 'react-native-progress'; @@ -66,7 +66,7 @@ const ImageContainer = React.memo(({ ); -}, (prevProps, nextProps) => equal(prevProps.file, nextProps.file) && prevProps.theme === nextProps.theme); +}, (prevProps, nextProps) => dequal(prevProps.file, nextProps.file) && prevProps.theme === nextProps.theme); ImageContainer.propTypes = { file: PropTypes.object, diff --git a/app/containers/message/Message.js b/app/containers/message/Message.js index bb59dbee0..104244740 100644 --- a/app/containers/message/Message.js +++ b/app/containers/message/Message.js @@ -119,7 +119,7 @@ const MessageTouchable = React.memo((props) => { @@ -132,6 +132,7 @@ MessageTouchable.displayName = 'MessageTouchable'; MessageTouchable.propTypes = { hasError: PropTypes.bool, isInfo: PropTypes.bool, + isThreadReply: PropTypes.bool, isTemp: PropTypes.bool, archived: PropTypes.bool }; diff --git a/app/containers/message/Reply.js b/app/containers/message/Reply.js index fba4c0fbd..88c748baa 100644 --- a/app/containers/message/Reply.js +++ b/app/containers/message/Reply.js @@ -2,7 +2,7 @@ import React, { useContext } from 'react'; import { View, Text, StyleSheet } from 'react-native'; import PropTypes from 'prop-types'; import moment from 'moment'; -import isEqual from 'deep-equal'; +import { dequal } from 'dequal'; import Touchable from './Touchable'; import Markdown from '../markdown'; @@ -125,7 +125,7 @@ const Fields = React.memo(({ attachment, theme }) => { ))} ); -}, (prevProps, nextProps) => isEqual(prevProps.attachment.fields, nextProps.attachment.fields) && prevProps.theme === nextProps.theme); +}, (prevProps, nextProps) => dequal(prevProps.attachment.fields, nextProps.attachment.fields) && prevProps.theme === nextProps.theme); const Reply = React.memo(({ attachment, timeFormat, index, getCustomEmoji, theme @@ -172,7 +172,6 @@ const Reply = React.memo(({ /> @@ -188,7 +187,7 @@ const Reply = React.memo(({ /> ); -}, (prevProps, nextProps) => isEqual(prevProps.attachment, nextProps.attachment) && prevProps.theme === nextProps.theme); +}, (prevProps, nextProps) => dequal(prevProps.attachment, nextProps.attachment) && prevProps.theme === nextProps.theme); Reply.propTypes = { attachment: PropTypes.object, diff --git a/app/containers/message/Urls.js b/app/containers/message/Urls.js index 946433d43..742b2f478 100644 --- a/app/containers/message/Urls.js +++ b/app/containers/message/Urls.js @@ -4,7 +4,7 @@ import { } from 'react-native'; import PropTypes from 'prop-types'; import FastImage from '@rocket.chat/react-native-fast-image'; -import isEqual from 'lodash/isEqual'; +import { dequal } from 'dequal'; import Touchable from './Touchable'; import openLink from '../../utils/openLink'; @@ -112,7 +112,7 @@ const Url = React.memo(({ url, index, theme }) => { ); -}, (oldProps, newProps) => isEqual(oldProps.url, newProps.url) && oldProps.theme === newProps.theme); +}, (oldProps, newProps) => dequal(oldProps.url, newProps.url) && oldProps.theme === newProps.theme); const Urls = React.memo(({ urls, theme }) => { if (!urls || urls.length === 0) { @@ -122,7 +122,7 @@ const Urls = React.memo(({ urls, theme }) => { return urls.map((url, index) => ( )); -}, (oldProps, newProps) => isEqual(oldProps.urls, newProps.urls) && oldProps.theme === newProps.theme); +}, (oldProps, newProps) => dequal(oldProps.urls, newProps.urls) && oldProps.theme === newProps.theme); UrlImage.propTypes = { image: PropTypes.string diff --git a/app/containers/message/Video.js b/app/containers/message/Video.js index 2e9ef6c2a..fed0c67f2 100644 --- a/app/containers/message/Video.js +++ b/app/containers/message/Video.js @@ -1,7 +1,7 @@ import React, { useContext } from 'react'; import PropTypes from 'prop-types'; import { StyleSheet } from 'react-native'; -import isEqual from 'deep-equal'; +import { dequal } from 'dequal'; import Touchable from './Touchable'; import Markdown from '../markdown'; @@ -57,7 +57,7 @@ const Video = React.memo(({ ); -}, (prevProps, nextProps) => isEqual(prevProps.file, nextProps.file) && prevProps.theme === nextProps.theme); +}, (prevProps, nextProps) => dequal(prevProps.file, nextProps.file) && prevProps.theme === nextProps.theme); Video.propTypes = { file: PropTypes.object, diff --git a/app/containers/message/utils.js b/app/containers/message/utils.js index 325d3d764..22f4d90ca 100644 --- a/app/containers/message/utils.js +++ b/app/containers/message/utils.js @@ -37,7 +37,9 @@ export const SYSTEM_MESSAGES = [ 'room_changed_privacy', 'room_changed_avatar', 'message_snippeted', - 'thread-created' + 'thread-created', + 'room_e2e_enabled', + 'room_e2e_disabled' ]; export const SYSTEM_MESSAGE_TYPES = { @@ -100,6 +102,10 @@ export const getInfoMessage = ({ return I18n.t('Room_changed_avatar', { userBy: username }); } else if (type === 'message_snippeted') { return I18n.t('Created_snippet'); + } else if (type === 'room_e2e_disabled') { + return I18n.t('This_room_encryption_has_been_disabled_by__username_', { username }); + } else if (type === 'room_e2e_enabled') { + return I18n.t('This_room_encryption_has_been_enabled_by__username_', { username }); } return ''; }; diff --git a/app/ee/omnichannel/views/QueueListView.js b/app/ee/omnichannel/views/QueueListView.js index 34a307699..a261d481e 100644 --- a/app/ee/omnichannel/views/QueueListView.js +++ b/app/ee/omnichannel/views/QueueListView.js @@ -2,7 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { FlatList } from 'react-native'; import { connect } from 'react-redux'; -import isEqual from 'react-fast-compare'; +import { dequal } from 'dequal'; import I18n from '../../../i18n'; import RoomItem, { ROW_HEIGHT } from '../../../presentation/RoomItem'; @@ -56,7 +56,7 @@ class QueueListView extends React.Component { shouldComponentUpdate(nextProps) { const { queued } = this.props; - if (!isEqual(nextProps.queued, queued)) { + if (!dequal(nextProps.queued, queued)) { return true; } diff --git a/app/i18n/locales/en.js b/app/i18n/locales/en.js index c35da810b..02adcb460 100644 --- a/app/i18n/locales/en.js +++ b/app/i18n/locales/en.js @@ -704,5 +704,7 @@ export default { Direct_message: 'Direct message', Message_Ignored: 'Message ignored. Tap to display it.', Enter_workspace_URL: 'Enter workspace URL', - Workspace_URL_Example: 'Ex. your-company.rocket.chat' + Workspace_URL_Example: 'Ex. your-company.rocket.chat', + This_room_encryption_has_been_enabled_by__username_: 'This room\'s encryption has been enabled by {{username}}', + This_room_encryption_has_been_disabled_by__username_: 'This room\'s encryption has been disabled by {{username}}' }; diff --git a/app/i18n/locales/pt-BR.js b/app/i18n/locales/pt-BR.js index 3819a3b3b..e3dc8e106 100644 --- a/app/i18n/locales/pt-BR.js +++ b/app/i18n/locales/pt-BR.js @@ -651,5 +651,7 @@ export default { Direct_message: 'Mensagem direta', Message_Ignored: 'Mensagem ignorada. Toque para mostrar.', Enter_workspace_URL: 'Digite a URL da sua workspace', - Workspace_URL_Example: 'Ex. sua-empresa.rocket.chat' + Workspace_URL_Example: 'Ex. sua-empresa.rocket.chat', + This_room_encryption_has_been_enabled_by__username_: 'A criptografia para essa sala foi habilitada por {{username}}', + This_room_encryption_has_been_disabled_by__username_: 'A criptografia para essa sala foi desabilitada por {{username}}' }; diff --git a/app/i18n/locales/ru.js b/app/i18n/locales/ru.js index 4d37232bf..fcbcd5e47 100644 --- a/app/i18n/locales/ru.js +++ b/app/i18n/locales/ru.js @@ -678,5 +678,31 @@ export default { No_threads: 'Тредов нет', No_threads_following: 'Нет тредов, за которыми вы следите', No_threads_unread: 'Непрочитанных тредов нет', - Messagebox_Send_to_channel: 'Отправить в чат' + Messagebox_Send_to_channel: 'Отправить в чат', + Set_as_leader: 'Назначить лидером', + Set_as_moderator: 'Назначить модератором', + Set_as_owner: 'Назначить владельцем', + Remove_as_leader: 'Удалить из лидеров', + Remove_as_moderator: 'Удалить из модераторов', + Remove_as_owner: 'Удалить из владельцев', + Remove_from_room: 'Удалить из чата', + Ignore: 'Игнориновать', + Unignore: 'Прекратить игнорировать', + User_has_been_ignored: 'Пользователь теперь игнорируется', + User_has_been_unignored: 'Пользователь больше не игнорируется', + User_has_been_removed_from_s: 'Пользователь удален из {{s}}', + User__username__is_now_a_leader_of__room_name_: 'Пользователь {{username}} больше не лидер в чате {{room_name}}', + User__username__is_now_a_moderator_of__room_name_: 'Пользователь {{username}} больше не модератор в чате {{room_name}}', + User__username__is_now_a_owner_of__room_name_: 'Пользователь {{username}} больше не владелец в чате {{room_name}}', + User__username__removed_from__room_name__leaders: 'Пользователь {{username}} удален из {{room_name}} лидеров', + User__username__removed_from__room_name__moderators: 'Пользователь {{username}} удален из {{room_name}} модераторов', + User__username__removed_from__room_name__owners: 'Пользователь {{username}} удален из {{room_name}} владельцев', + The_user_will_be_removed_from_s: 'Пользователь будет удален из {{s}}', + Yes_remove_user: 'Да, удалить пользователя!', + Direct_message: 'Личное сообщение', + Message_Ignored: 'Сообщение игнорируется. Тапните по нему, чтобы отобразить его.', + Enter_workspace_URL: 'Введите URL вашего рабочего пространства', + Workspace_URL_Example: 'Например, your-company.rocket.chat', + This_room_encryption_has_been_enabled_by__username_: 'Шифрование для этого чата включено {{username}}', + This_room_encryption_has_been_disabled_by__username_: 'Шифрование для этого чата выключено {{username}}' }; diff --git a/app/index.js b/app/index.js index 8bf338dad..048323a5b 100644 --- a/app/index.js +++ b/app/index.js @@ -112,16 +112,25 @@ export default class Root extends React.Component { init = async() => { UserPreferences.getMapAsync(THEME_PREFERENCES_KEY).then(this.setTheme); - const [notification, deepLinking] = await Promise.all([initializePushNotifications(), Linking.getInitialURL()]); - const parsedDeepLinkingURL = parseDeepLinking(deepLinking); store.dispatch(appInitLocalSettings()); + + // Open app from push notification + const notification = await initializePushNotifications(); if (notification) { onNotification(notification); - } else if (parsedDeepLinkingURL) { - store.dispatch(deepLinkingOpen(parsedDeepLinkingURL)); - } else { - store.dispatch(appInit()); + return; } + + // Open app from deep linking + const deepLinking = await Linking.getInitialURL(); + const parsedDeepLinkingURL = parseDeepLinking(deepLinking); + if (parsedDeepLinkingURL) { + store.dispatch(deepLinkingOpen(parsedDeepLinkingURL)); + return; + } + + // Open app from app icon + store.dispatch(appInit()); } getMasterDetail = (width) => { diff --git a/app/lib/encryption/encryption.js b/app/lib/encryption/encryption.js index 972f2c588..e4a7f2c14 100644 --- a/app/lib/encryption/encryption.js +++ b/app/lib/encryption/encryption.js @@ -229,9 +229,9 @@ class Encryption { decryptPendingMessages = async(roomId) => { const db = database.active; - const messagesCollection = db.collections.get('messages'); - const threadsCollection = db.collections.get('threads'); - const threadMessagesCollection = db.collections.get('thread_messages'); + const messagesCollection = db.get('messages'); + const threadsCollection = db.get('threads'); + const threadMessagesCollection = db.get('thread_messages'); // e2e status is null or 'pending' and message type is 'e2e' const whereClause = [ @@ -286,7 +286,7 @@ class Encryption { // after initialize the encryption client decryptPendingSubscriptions = async() => { const db = database.active; - const subCollection = db.collections.get('subscriptions'); + const subCollection = db.get('subscriptions'); try { // Find all rooms that can have a lastMessage encrypted // If we select only encrypted rooms we can miss some room that changed their encrypted status @@ -347,7 +347,7 @@ class Encryption { const { rid } = subscription; const db = database.active; - const subCollection = db.collections.get('subscriptions'); + const subCollection = db.get('subscriptions'); let subRecord; try { @@ -400,7 +400,7 @@ class Encryption { encryptMessage = async(message) => { const { rid } = message; const db = database.active; - const subCollection = db.collections.get('subscriptions'); + const subCollection = db.get('subscriptions'); try { // Find the subscription diff --git a/app/lib/encryption/room.js b/app/lib/encryption/room.js index 835bd9ab5..0aa1b932e 100644 --- a/app/lib/encryption/room.js +++ b/app/lib/encryption/room.js @@ -49,7 +49,7 @@ export default class EncryptionRoom { } const db = database.active; - const subCollection = db.collections.get('subscriptions'); + const subCollection = db.get('subscriptions'); try { // Find the subscription const subscription = await subCollection.find(this.roomId); diff --git a/app/lib/methods/callJitsi.js b/app/lib/methods/callJitsi.js index 7410ed8bd..7275ef812 100644 --- a/app/lib/methods/callJitsi.js +++ b/app/lib/methods/callJitsi.js @@ -2,7 +2,7 @@ import reduxStore from '../createStore'; import Navigation from '../Navigation'; import { logEvent, events } from '../../utils/log'; -async function jitsiURL({ rid }) { +async function jitsiURL({ room }) { const { settings } = reduxStore.getState(); const { Jitsi_Enabled } = settings; @@ -11,31 +11,37 @@ async function jitsiURL({ rid }) { } const { - Jitsi_Domain, Jitsi_URL_Room_Prefix, Jitsi_SSL, Jitsi_Enabled_TokenAuth, uniqueID + Jitsi_Domain, Jitsi_URL_Room_Prefix, Jitsi_SSL, Jitsi_Enabled_TokenAuth, uniqueID, Jitsi_URL_Room_Hash } = settings; const domain = `${ Jitsi_Domain }/`; const prefix = Jitsi_URL_Room_Prefix; - const uniqueIdentifier = uniqueID || 'undefined'; const protocol = Jitsi_SSL ? 'https://' : 'http://'; let queryString = ''; if (Jitsi_Enabled_TokenAuth) { try { - const accessToken = await this.methodCallWrapper('jitsi:generateAccessToken', rid); + const accessToken = await this.methodCallWrapper('jitsi:generateAccessToken', room?.rid); queryString = `?jwt=${ accessToken }`; } catch { logEvent(events.RA_JITSI_F); } } - return `${ protocol }${ domain }${ prefix }${ uniqueIdentifier }${ rid }${ queryString }`; + let rname; + if (Jitsi_URL_Room_Hash) { + rname = uniqueID + room?.rid; + } else { + rname = encodeURIComponent(room.t === 'd' ? room?.usernames?.join?.(' x ') : room?.name); + } + + return `${ protocol }${ domain }${ prefix }${ rname }${ queryString }`; } -async function callJitsi(rid, onlyAudio = false) { +async function callJitsi(room, onlyAudio = false) { logEvent(onlyAudio ? events.RA_JITSI_AUDIO : events.RA_JITSI_VIDEO); - const url = await jitsiURL.call(this, { rid }); - Navigation.navigate('JitsiMeetView', { url, onlyAudio, rid }); + const url = await jitsiURL.call(this, { room }); + Navigation.navigate('JitsiMeetView', { url, onlyAudio, rid: room?.rid }); } export default callJitsi; diff --git a/app/lib/methods/canOpenRoom.js b/app/lib/methods/canOpenRoom.js index b85728727..c233899b8 100644 --- a/app/lib/methods/canOpenRoom.js +++ b/app/lib/methods/canOpenRoom.js @@ -57,7 +57,7 @@ async function open({ type, rid, name }) { export default async function canOpenRoom({ rid, path, isCall }) { try { const db = database.active; - const subsCollection = db.collections.get('subscriptions'); + const subsCollection = db.get('subscriptions'); if (isCall && !rid) { // Extract rid from a Jitsi URL @@ -75,7 +75,8 @@ export default async function canOpenRoom({ rid, path, isCall }) { name: room.name, fname: room.fname, prid: room.prid, - uids: room.uids + uids: room.uids, + usernames: room.usernames }; } catch (e) { // Do nothing diff --git a/app/lib/methods/enterpriseModules.js b/app/lib/methods/enterpriseModules.js index 5cb68e7a9..35c6672d2 100644 --- a/app/lib/methods/enterpriseModules.js +++ b/app/lib/methods/enterpriseModules.js @@ -13,7 +13,7 @@ export async function setEnterpriseModules() { try { const { server: serverId } = reduxStore.getState().server; const serversDB = database.servers; - const serversCollection = serversDB.collections.get('servers'); + const serversCollection = serversDB.get('servers'); let server; try { server = await serversCollection.find(serverId); @@ -39,7 +39,7 @@ export function getEnterpriseModules() { const enterpriseModules = await this.methodCallWrapper('license:getModules'); if (enterpriseModules) { const serversDB = database.servers; - const serversCollection = serversDB.collections.get('servers'); + const serversCollection = serversDB.get('servers'); const server = await serversCollection.find(serverId); await serversDB.action(async() => { await server.update((s) => { diff --git a/app/lib/methods/getCustomEmojis.js b/app/lib/methods/getCustomEmojis.js index 0037168df..31108fb62 100644 --- a/app/lib/methods/getCustomEmojis.js +++ b/app/lib/methods/getCustomEmojis.js @@ -1,4 +1,3 @@ -import { InteractionManager } from 'react-native'; import lt from 'semver/functions/lt'; import orderBy from 'lodash/orderBy'; import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord'; @@ -21,7 +20,7 @@ const updateEmojis = async({ update = [], remove = [], allRecords }) => { return; } const db = database.active; - const emojisCollection = db.collections.get('custom_emojis'); + const emojisCollection = db.get('custom_emojis'); let emojisToCreate = []; let emojisToUpdate = []; let emojisToDelete = []; @@ -63,7 +62,7 @@ const updateEmojis = async({ update = [], remove = [], allRecords }) => { export async function setCustomEmojis() { const db = database.active; - const emojisCollection = db.collections.get('custom_emojis'); + const emojisCollection = db.get('custom_emojis'); const allEmojis = await emojisCollection.query().fetch(); const parsed = allEmojis.reduce((ret, item) => { ret[item.name] = { @@ -86,7 +85,7 @@ export function getCustomEmojis() { try { const serverVersion = reduxStore.getState().server.version; const db = database.active; - const emojisCollection = db.collections.get('custom_emojis'); + const emojisCollection = db.get('custom_emojis'); const allRecords = await emojisCollection.query().fetch(); const updatedSince = await getUpdatedSince(allRecords); @@ -95,18 +94,16 @@ export function getCustomEmojis() { // RC 0.61.0 const result = await this.sdk.get('emoji-custom'); - InteractionManager.runAfterInteractions(async() => { - let { emojis } = result; - emojis = emojis.filter(emoji => !updatedSince || emoji._updatedAt > updatedSince); - const changedEmojis = await updateEmojis({ update: emojis, allRecords }); + let { emojis } = result; + emojis = emojis.filter(emoji => !updatedSince || emoji._updatedAt > updatedSince); + const changedEmojis = await updateEmojis({ update: emojis, allRecords }); - // `setCustomEmojis` is fired on selectServer - // We run it again only if emojis were changed - if (changedEmojis) { - setCustomEmojis(); - } - return resolve(); - }); + // `setCustomEmojis` is fired on selectServer + // We run it again only if emojis were changed + if (changedEmojis) { + setCustomEmojis(); + } + return resolve(); } else { const params = {}; if (updatedSince) { @@ -120,17 +117,15 @@ export function getCustomEmojis() { return resolve(); } - InteractionManager.runAfterInteractions(async() => { - const { emojis } = result; - const { update, remove } = emojis; - const changedEmojis = await updateEmojis({ update, remove, allRecords }); + const { emojis } = result; + const { update, remove } = emojis; + const changedEmojis = await updateEmojis({ update, remove, allRecords }); - // `setCustomEmojis` is fired on selectServer - // We run it again only if emojis were changed - if (changedEmojis) { - setCustomEmojis(); - } - }); + // `setCustomEmojis` is fired on selectServer + // We run it again only if emojis were changed + if (changedEmojis) { + setCustomEmojis(); + } } } catch (e) { log(e); diff --git a/app/lib/methods/getPermissions.js b/app/lib/methods/getPermissions.js index 249441582..15ee221b8 100644 --- a/app/lib/methods/getPermissions.js +++ b/app/lib/methods/getPermissions.js @@ -1,12 +1,55 @@ -import { InteractionManager } from 'react-native'; import lt from 'semver/functions/lt'; import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord'; +import { Q } from '@nozbe/watermelondb'; +import coerce from 'semver/functions/coerce'; import orderBy from 'lodash/orderBy'; import database from '../database'; import log from '../../utils/log'; import reduxStore from '../createStore'; import protectedFunction from './helpers/protectedFunction'; +import { setPermissions as setPermissionsAction } from '../../actions/permissions'; + +const PERMISSIONS = [ + 'add-user-to-any-c-room', + 'add-user-to-any-p-room', + 'add-user-to-joined-room', + 'archive-room', + 'auto-translate', + 'create-invite-links', + 'delete-c', + 'delete-message', + 'delete-p', + 'edit-message', + 'edit-room', + 'force-delete-message', + 'mute-user', + 'pin-message', + 'post-readonly', + 'remove-user', + 'set-leader', + 'set-moderator', + 'set-owner', + 'set-react-when-readonly', + 'set-readonly', + 'toggle-room-e2e-encryption', + 'transfer-livechat-guest', + 'unarchive-room', + 'view-broadcast-member-list', + 'view-privileged-setting', + 'view-room-administration', + 'view-statistics', + 'view-user-administration' +]; + +export async function setPermissions() { + const db = database.active; + const permissionsCollection = db.collections.get('permissions'); + const allPermissions = await permissionsCollection.query(Q.where('id', Q.oneOf(PERMISSIONS))).fetch(); + const parsed = allPermissions.reduce((acc, item) => ({ ...acc, [item.id]: item.roles }), {}); + + reduxStore.dispatch(setPermissionsAction(parsed)); +} const getUpdatedSince = (allRecords) => { try { @@ -26,7 +69,7 @@ const updatePermissions = async({ update = [], remove = [], allRecords }) => { return; } const db = database.active; - const permissionsCollection = db.collections.get('permissions'); + const permissionsCollection = db.get('permissions'); // filter permissions let permissionsToCreate = []; @@ -65,33 +108,35 @@ const updatePermissions = async({ update = [], remove = [], allRecords }) => { await db.action(async() => { await db.batch(...batch); }); + return true; } catch (e) { log(e); } }; -export default function() { +export function getPermissions() { return new Promise(async(resolve) => { try { const serverVersion = reduxStore.getState().server.version; const db = database.active; - const permissionsCollection = db.collections.get('permissions'); + const permissionsCollection = db.get('permissions'); const allRecords = await permissionsCollection.query().fetch(); // if server version is lower than 0.73.0, fetches from old api - if (serverVersion && lt(serverVersion, '0.73.0')) { + if (serverVersion && lt(coerce(serverVersion), '0.73.0')) { // RC 0.66.0 const result = await this.sdk.get('permissions.list'); if (!result.success) { return resolve(); } - InteractionManager.runAfterInteractions(async() => { - await updatePermissions({ update: result.permissions, allRecords }); - return resolve(); - }); + const changePermissions = await updatePermissions({ update: result.permissions, allRecords }); + if (changePermissions) { + setPermissions(); + } + return resolve(); } else { const params = {}; - const updatedSince = await getUpdatedSince(allRecords); + const updatedSince = getUpdatedSince(allRecords); if (updatedSince) { params.updatedSince = updatedSince; } @@ -102,10 +147,11 @@ export default function() { return resolve(); } - InteractionManager.runAfterInteractions(async() => { - await updatePermissions({ update: result.update, remove: result.delete, allRecords }); - return resolve(); - }); + const changePermissions = await updatePermissions({ update: result.update, remove: result.delete, allRecords }); + if (changePermissions) { + setPermissions(); + } + return resolve(); } } catch (e) { log(e); diff --git a/app/lib/methods/getRoles.js b/app/lib/methods/getRoles.js index 3856d64f4..df22d382b 100644 --- a/app/lib/methods/getRoles.js +++ b/app/lib/methods/getRoles.js @@ -1,4 +1,3 @@ -import { InteractionManager } from 'react-native'; import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord'; import database from '../database'; @@ -19,43 +18,41 @@ export default function() { const { roles } = result; if (roles && roles.length) { - InteractionManager.runAfterInteractions(async() => { - await db.action(async() => { - const rolesCollections = db.collections.get('roles'); - const allRolesRecords = await rolesCollections.query().fetch(); + await db.action(async() => { + const rolesCollections = db.get('roles'); + const allRolesRecords = await rolesCollections.query().fetch(); - // filter roles - let rolesToCreate = roles.filter(i1 => !allRolesRecords.find(i2 => i1._id === i2.id)); - let rolesToUpdate = allRolesRecords.filter(i1 => roles.find(i2 => i1.id === i2._id)); + // filter roles + let rolesToCreate = roles.filter(i1 => !allRolesRecords.find(i2 => i1._id === i2.id)); + let rolesToUpdate = allRolesRecords.filter(i1 => roles.find(i2 => i1.id === i2._id)); - // Create - rolesToCreate = rolesToCreate.map(role => rolesCollections.prepareCreate(protectedFunction((r) => { - r._raw = sanitizedRaw({ id: role._id }, rolesCollections.schema); - Object.assign(r, role); - }))); + // Create + rolesToCreate = rolesToCreate.map(role => rolesCollections.prepareCreate(protectedFunction((r) => { + r._raw = sanitizedRaw({ id: role._id }, rolesCollections.schema); + Object.assign(r, role); + }))); - // Update - rolesToUpdate = rolesToUpdate.map((role) => { - const newRole = roles.find(r => r._id === role.id); - return role.prepareUpdate(protectedFunction((r) => { - Object.assign(r, newRole); - })); - }); - - const allRecords = [ - ...rolesToCreate, - ...rolesToUpdate - ]; - - try { - await db.batch(...allRecords); - } catch (e) { - log(e); - } - return allRecords.length; + // Update + rolesToUpdate = rolesToUpdate.map((role) => { + const newRole = roles.find(r => r._id === role.id); + return role.prepareUpdate(protectedFunction((r) => { + Object.assign(r, newRole); + })); }); - return resolve(); + + const allRecords = [ + ...rolesToCreate, + ...rolesToUpdate + ]; + + try { + await db.batch(...allRecords); + } catch (e) { + log(e); + } + return allRecords.length; }); + return resolve(); } } catch (e) { log(e); diff --git a/app/lib/methods/getSettings.js b/app/lib/methods/getSettings.js index f433f4a9a..6935631ef 100644 --- a/app/lib/methods/getSettings.js +++ b/app/lib/methods/getSettings.js @@ -44,7 +44,7 @@ const loginSettings = [ const serverInfoUpdate = async(serverInfo, iconSetting) => { const serversDB = database.servers; const serverId = reduxStore.getState().server.server; - const serversCollection = serversDB.collections.get('servers'); + const serversCollection = serversDB.get('servers'); const server = await serversCollection.find(serverId); let info = serverInfo.reduce((allSettings, setting) => { @@ -118,7 +118,7 @@ export async function getLoginSettings({ server }) { export async function setSettings() { const db = database.active; - const settingsCollection = db.collections.get('settings'); + const settingsCollection = db.get('settings'); const settingsRecords = await settingsCollection.query().fetch(); const parsed = Object.values(settingsRecords).map(item => ({ _id: item.id, @@ -157,7 +157,7 @@ export default async function() { } await db.action(async() => { - const settingsCollection = db.collections.get('settings'); + const settingsCollection = db.get('settings'); const allSettingsRecords = await settingsCollection .query(Q.where('id', Q.oneOf(filteredSettingsIds))) .fetch(); diff --git a/app/lib/methods/getSlashCommands.js b/app/lib/methods/getSlashCommands.js index 729e8b4a9..c37e077f4 100644 --- a/app/lib/methods/getSlashCommands.js +++ b/app/lib/methods/getSlashCommands.js @@ -1,4 +1,3 @@ -import { InteractionManager } from 'react-native'; import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord'; import database from '../database'; @@ -20,47 +19,45 @@ export default function() { const { commands } = result; if (commands && commands.length) { - InteractionManager.runAfterInteractions(async() => { - await db.action(async() => { - const slashCommandsCollection = db.collections.get('slash_commands'); - const allSlashCommandsRecords = await slashCommandsCollection.query().fetch(); + await db.action(async() => { + const slashCommandsCollection = db.get('slash_commands'); + const allSlashCommandsRecords = await slashCommandsCollection.query().fetch(); - // filter slash commands - let slashCommandsToCreate = commands.filter(i1 => !allSlashCommandsRecords.find(i2 => i1.command === i2.id)); - let slashCommandsToUpdate = allSlashCommandsRecords.filter(i1 => commands.find(i2 => i1.id === i2.command)); - let slashCommandsToDelete = allSlashCommandsRecords - .filter(i1 => !slashCommandsToCreate.find(i2 => i2.command === i1.id) && !slashCommandsToUpdate.find(i2 => i2.id === i1.id)); + // filter slash commands + let slashCommandsToCreate = commands.filter(i1 => !allSlashCommandsRecords.find(i2 => i1.command === i2.id)); + let slashCommandsToUpdate = allSlashCommandsRecords.filter(i1 => commands.find(i2 => i1.id === i2.command)); + let slashCommandsToDelete = allSlashCommandsRecords + .filter(i1 => !slashCommandsToCreate.find(i2 => i2.command === i1.id) && !slashCommandsToUpdate.find(i2 => i2.id === i1.id)); - // Create - slashCommandsToCreate = slashCommandsToCreate.map(command => slashCommandsCollection.prepareCreate(protectedFunction((s) => { - s._raw = sanitizedRaw({ id: command.command }, slashCommandsCollection.schema); - Object.assign(s, command); - }))); + // Create + slashCommandsToCreate = slashCommandsToCreate.map(command => slashCommandsCollection.prepareCreate(protectedFunction((s) => { + s._raw = sanitizedRaw({ id: command.command }, slashCommandsCollection.schema); + Object.assign(s, command); + }))); - // Update - slashCommandsToUpdate = slashCommandsToUpdate.map((command) => { - const newCommand = commands.find(s => s.command === command.id); - return command.prepareUpdate(protectedFunction((s) => { - Object.assign(s, newCommand); - })); - }); - - // Delete - slashCommandsToDelete = slashCommandsToDelete.map(command => command.prepareDestroyPermanently()); - - const allRecords = [ - ...slashCommandsToCreate, - ...slashCommandsToUpdate, - ...slashCommandsToDelete - ]; - - try { - await db.batch(...allRecords); - } catch (e) { - log(e); - } - return allRecords.length; + // Update + slashCommandsToUpdate = slashCommandsToUpdate.map((command) => { + const newCommand = commands.find(s => s.command === command.id); + return command.prepareUpdate(protectedFunction((s) => { + Object.assign(s, newCommand); + })); }); + + // Delete + slashCommandsToDelete = slashCommandsToDelete.map(command => command.prepareDestroyPermanently()); + + const allRecords = [ + ...slashCommandsToCreate, + ...slashCommandsToUpdate, + ...slashCommandsToDelete + ]; + + try { + await db.batch(...allRecords); + } catch (e) { + log(e); + } + return allRecords.length; }); } } catch (e) { diff --git a/app/lib/methods/getUsersPresence.js b/app/lib/methods/getUsersPresence.js index 68d9b1eaa..83e5ce815 100644 --- a/app/lib/methods/getUsersPresence.js +++ b/app/lib/methods/getUsersPresence.js @@ -72,7 +72,7 @@ export default async function getUsersPresence() { ids = []; const db = database.active; - const userCollection = db.collections.get('users'); + const userCollection = db.get('users'); users.forEach(async(user) => { try { const userRecord = await userCollection.find(user._id); diff --git a/app/lib/methods/helpers/findSubscriptionsRooms.js b/app/lib/methods/helpers/findSubscriptionsRooms.js index f1714932d..a64a88940 100644 --- a/app/lib/methods/helpers/findSubscriptionsRooms.js +++ b/app/lib/methods/helpers/findSubscriptionsRooms.js @@ -5,7 +5,7 @@ import database from '../../database'; export default async(subscriptions = [], rooms = []) => { try { const db = database.active; - const subCollection = db.collections.get('subscriptions'); + const subCollection = db.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(); diff --git a/app/lib/methods/helpers/mergeSubscriptionsRooms.js b/app/lib/methods/helpers/mergeSubscriptionsRooms.js index 1bc3f18b2..1e5afa3b2 100644 --- a/app/lib/methods/helpers/mergeSubscriptionsRooms.js +++ b/app/lib/methods/helpers/mergeSubscriptionsRooms.js @@ -1,11 +1,14 @@ import EJSON from 'ejson'; +import { lt, coerce } from 'semver'; import normalizeMessage from './normalizeMessage'; import findSubscriptionsRooms from './findSubscriptionsRooms'; import { Encryption } from '../../encryption'; +import reduxStore from '../../createStore'; // TODO: delete and update export const merge = (subscription, room) => { + const serverVersion = reduxStore.getState().server.version; subscription = EJSON.fromJSONValue(subscription); room = EJSON.fromJSONValue(room); @@ -25,9 +28,15 @@ export const merge = (subscription, room) => { subscription.usernames = room.usernames; subscription.uids = room.uids; } - // https://github.com/RocketChat/Rocket.Chat/blob/develop/app/ui-sidenav/client/roomList.js#L180 - const lastRoomUpdate = room.lm || subscription.ts || subscription._updatedAt; - subscription.roomUpdatedAt = subscription.lr ? Math.max(new Date(subscription.lr), new Date(lastRoomUpdate)) : lastRoomUpdate; + if (serverVersion && lt(coerce(serverVersion), '3.7.0')) { + const updatedAt = room?._updatedAt ? new Date(room._updatedAt) : null; + const lastMessageTs = subscription?.lastMessage?.ts ? new Date(subscription.lastMessage.ts) : null; + subscription.roomUpdatedAt = Math.max(updatedAt, lastMessageTs); + } else { + // https://github.com/RocketChat/Rocket.Chat/blob/develop/app/ui-sidenav/client/roomList.js#L180 + const lastRoomUpdate = room.lm || subscription.ts || subscription._updatedAt; + subscription.roomUpdatedAt = subscription.lr ? Math.max(new Date(subscription.lr), new Date(lastRoomUpdate)) : lastRoomUpdate; + } subscription.ro = room.ro; subscription.broadcast = room.broadcast; subscription.encrypted = room.encrypted; diff --git a/app/lib/methods/loadMissedMessages.js b/app/lib/methods/loadMissedMessages.js index 82c2e1bda..d1acaf0b4 100644 --- a/app/lib/methods/loadMissedMessages.js +++ b/app/lib/methods/loadMissedMessages.js @@ -5,7 +5,7 @@ import updateMessages from './updateMessages'; const getLastUpdate = async(rid) => { try { const db = database.active; - const subsCollection = db.collections.get('subscriptions'); + const subsCollection = db.get('subscriptions'); const sub = await subsCollection.find(rid); return sub.lastOpen.toISOString(); } catch (e) { diff --git a/app/lib/methods/loadThreadMessages.js b/app/lib/methods/loadThreadMessages.js index 4dc8a05fd..de6f244c6 100644 --- a/app/lib/methods/loadThreadMessages.js +++ b/app/lib/methods/loadThreadMessages.js @@ -1,4 +1,3 @@ -import { InteractionManager } from 'react-native'; import { Q } from '@nozbe/watermelondb'; import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord'; @@ -30,44 +29,42 @@ export default function loadThreadMessages({ tmid, rid, offset = 0 }) { let data = await load.call(this, { tmid, offset }); if (data && data.length) { - InteractionManager.runAfterInteractions(async() => { - try { - data = data.map(m => buildMessage(m)); - data = await Encryption.decryptMessages(data); - const db = database.active; - const threadMessagesCollection = db.collections.get('thread_messages'); - const allThreadMessagesRecords = await threadMessagesCollection.query(Q.where('rid', tmid)).fetch(); - let threadMessagesToCreate = data.filter(i1 => !allThreadMessagesRecords.find(i2 => i1._id === i2.id)); - let threadMessagesToUpdate = allThreadMessagesRecords.filter(i1 => data.find(i2 => i1.id === i2._id)); + try { + data = data.map(m => buildMessage(m)); + data = await Encryption.decryptMessages(data); + const db = database.active; + const threadMessagesCollection = db.get('thread_messages'); + const allThreadMessagesRecords = await threadMessagesCollection.query(Q.where('rid', tmid)).fetch(); + let threadMessagesToCreate = data.filter(i1 => !allThreadMessagesRecords.find(i2 => i1._id === i2.id)); + let threadMessagesToUpdate = allThreadMessagesRecords.filter(i1 => data.find(i2 => i1.id === i2._id)); - threadMessagesToCreate = threadMessagesToCreate.map(threadMessage => threadMessagesCollection.prepareCreate(protectedFunction((tm) => { - tm._raw = sanitizedRaw({ id: threadMessage._id }, threadMessagesCollection.schema); - Object.assign(tm, threadMessage); - tm.subscription.id = rid; + threadMessagesToCreate = threadMessagesToCreate.map(threadMessage => threadMessagesCollection.prepareCreate(protectedFunction((tm) => { + tm._raw = sanitizedRaw({ id: threadMessage._id }, threadMessagesCollection.schema); + Object.assign(tm, threadMessage); + tm.subscription.id = rid; + tm.rid = threadMessage.tmid; + delete threadMessage.tmid; + }))); + + threadMessagesToUpdate = threadMessagesToUpdate.map((threadMessage) => { + const newThreadMessage = data.find(t => t._id === threadMessage.id); + return threadMessage.prepareUpdate(protectedFunction((tm) => { + Object.assign(tm, newThreadMessage); tm.rid = threadMessage.tmid; delete threadMessage.tmid; - }))); + })); + }); - threadMessagesToUpdate = threadMessagesToUpdate.map((threadMessage) => { - const newThreadMessage = data.find(t => t._id === threadMessage.id); - return threadMessage.prepareUpdate(protectedFunction((tm) => { - Object.assign(tm, newThreadMessage); - tm.rid = threadMessage.tmid; - delete threadMessage.tmid; - })); - }); - - await db.action(async() => { - await db.batch( - ...threadMessagesToCreate, - ...threadMessagesToUpdate - ); - }); - } catch (e) { - log(e); - } - return resolve(data); - }); + await db.action(async() => { + await db.batch( + ...threadMessagesToCreate, + ...threadMessagesToUpdate + ); + }); + } catch (e) { + log(e); + } + return resolve(data); } else { return resolve([]); } diff --git a/app/lib/methods/logout.js b/app/lib/methods/logout.js index 0a1923de0..bb6950835 100644 --- a/app/lib/methods/logout.js +++ b/app/lib/methods/logout.js @@ -42,12 +42,12 @@ async function removeServerData({ server }) { const serversDB = database.servers; const userId = await UserPreferences.getStringAsync(`${ RocketChat.TOKEN_KEY }-${ server }`); - const usersCollection = serversDB.collections.get('users'); + const usersCollection = serversDB.get('users'); if (userId) { const userRecord = await usersCollection.find(userId); batch.push(userRecord.prepareDestroyPermanently()); } - const serverCollection = serversDB.collections.get('servers'); + const serverCollection = serversDB.get('servers'); const serverRecord = await serverCollection.find(server); batch.push(serverRecord.prepareDestroyPermanently()); diff --git a/app/lib/methods/readMessages.js b/app/lib/methods/readMessages.js index e813a68b4..137612648 100644 --- a/app/lib/methods/readMessages.js +++ b/app/lib/methods/readMessages.js @@ -4,7 +4,7 @@ import log from '../../utils/log'; export default async function readMessages(rid, ls, updateLastOpen = false) { try { const db = database.active; - const subscription = await db.collections.get('subscriptions').find(rid); + const subscription = await db.get('subscriptions').find(rid); // RC 0.61.0 await this.sdk.post('subscriptions.read', { rid }); diff --git a/app/lib/methods/sendFileMessage.js b/app/lib/methods/sendFileMessage.js index 923da1723..435e377cb 100644 --- a/app/lib/methods/sendFileMessage.js +++ b/app/lib/methods/sendFileMessage.js @@ -40,7 +40,7 @@ export function sendFileMessage(rid, fileInfo, tmid, server, user) { fileInfo.rid = rid; const db = database.active; - const uploadsCollection = db.collections.get('uploads'); + const uploadsCollection = db.get('uploads'); let uploadRecord; try { uploadRecord = await uploadsCollection.find(fileInfo.path); diff --git a/app/lib/methods/sendMessage.js b/app/lib/methods/sendMessage.js index a9a86ae60..9b1bc6d10 100644 --- a/app/lib/methods/sendMessage.js +++ b/app/lib/methods/sendMessage.js @@ -9,8 +9,8 @@ import { E2E_MESSAGE_TYPE, E2E_STATUS } from '../encryption/constants'; const changeMessageStatus = async(id, tmid, status, message) => { const db = database.active; - const msgCollection = db.collections.get('messages'); - const threadMessagesCollection = db.collections.get('thread_messages'); + const msgCollection = db.get('messages'); + const threadMessagesCollection = db.get('thread_messages'); const successBatch = []; const messageRecord = await msgCollection.find(id); successBatch.push( @@ -89,10 +89,10 @@ export async function resendMessage(message, tmid) { export default async function(rid, msg, tmid, user, tshow) { try { const db = database.active; - const subsCollection = db.collections.get('subscriptions'); - const msgCollection = db.collections.get('messages'); - const threadCollection = db.collections.get('threads'); - const threadMessagesCollection = db.collections.get('thread_messages'); + const subsCollection = db.get('subscriptions'); + const msgCollection = db.get('messages'); + const threadCollection = db.get('threads'); + const threadMessagesCollection = db.get('thread_messages'); const messageId = random(17); const batch = []; @@ -151,7 +151,8 @@ export default async function(rid, msg, tmid, user, tshow) { tm.status = messagesStatus.TEMP; tm.u = { _id: user.id || '1', - username: user.username + username: user.username, + name: user.name }; tm.t = message.t; if (message.t === E2E_MESSAGE_TYPE) { @@ -175,7 +176,8 @@ export default async function(rid, msg, tmid, user, tshow) { m.status = messagesStatus.TEMP; m.u = { _id: user.id || '1', - username: user.username + username: user.username, + name: user.name }; if (tmid && tMessageRecord) { m.tmid = tmid; diff --git a/app/lib/methods/subscriptions/room.js b/app/lib/methods/subscriptions/room.js index 71ac3dfee..885c2469a 100644 --- a/app/lib/methods/subscriptions/room.js +++ b/app/lib/methods/subscriptions/room.js @@ -90,6 +90,10 @@ export default class RoomSubscription { if (ev === 'typing') { const { user } = reduxStore.getState().login; const { UI_Use_Real_Name } = reduxStore.getState().settings; + const { rooms } = reduxStore.getState().room; + if (rooms[0] !== _rid) { + return; + } const [name, typing] = ddpMessage.fields.args; const key = UI_Use_Real_Name ? 'name' : 'username'; if (name !== user[key]) { @@ -105,9 +109,9 @@ export default class RoomSubscription { try { const { _id } = ddpMessage.fields.args[0]; const db = database.active; - const msgCollection = db.collections.get('messages'); - const threadsCollection = db.collections.get('threads'); - const threadMessagesCollection = db.collections.get('thread_messages'); + const msgCollection = db.get('messages'); + const threadsCollection = db.get('threads'); + const threadMessagesCollection = db.get('thread_messages'); let deleteMessage; let deleteThread; let deleteThreadMessage; @@ -159,9 +163,9 @@ export default class RoomSubscription { } const db = database.active; - const msgCollection = db.collections.get('messages'); - const threadsCollection = db.collections.get('threads'); - const threadMessagesCollection = db.collections.get('thread_messages'); + const msgCollection = db.get('messages'); + const threadsCollection = db.get('threads'); + const threadMessagesCollection = db.get('thread_messages'); // Decrypt the message if necessary message = await Encryption.decryptMessage(message); diff --git a/app/lib/methods/subscriptions/rooms.js b/app/lib/methods/subscriptions/rooms.js index 42918da13..b79e422a6 100644 --- a/app/lib/methods/subscriptions/rooms.js +++ b/app/lib/methods/subscriptions/rooms.js @@ -32,8 +32,8 @@ const WINDOW_TIME = 500; const createOrUpdateSubscription = async(subscription, room) => { try { const db = database.active; - const subCollection = db.collections.get('subscriptions'); - const roomsCollection = db.collections.get('rooms'); + const subCollection = db.get('subscriptions'); + const roomsCollection = db.get('rooms'); if (!subscription) { try { @@ -185,7 +185,7 @@ const createOrUpdateSubscription = async(subscription, room) => { const { rooms } = store.getState().room; if (tmp.lastMessage && !rooms.includes(tmp.rid)) { const lastMessage = buildMessage(tmp.lastMessage); - const messagesCollection = db.collections.get('messages'); + const messagesCollection = db.get('messages'); let messageRecord; try { messageRecord = await messagesCollection.find(lastMessage._id); @@ -281,7 +281,7 @@ export default function subscribeRooms() { if (/subscriptions/.test(ev)) { if (type === 'removed') { try { - const subCollection = db.collections.get('subscriptions'); + const subCollection = db.get('subscriptions'); const sub = await subCollection.find(data.rid); const messages = await sub.messages.fetch(); const threads = await sub.threads.fetch(); @@ -335,7 +335,7 @@ export default function subscribeRooms() { } }; try { - const msgCollection = db.collections.get('messages'); + const msgCollection = db.get('messages'); await db.action(async() => { await msgCollection.create(protectedFunction((m) => { m._raw = sanitizedRaw({ id: message._id }, msgCollection.schema); @@ -407,7 +407,7 @@ export default function subscribeRooms() { }; connectedListener = this.sdk.onStreamData('connected', handleConnection); - disconnectedListener = this.sdk.onStreamData('close', handleConnection); + // disconnectedListener = this.sdk.onStreamData('close', handleConnection); streamListener = this.sdk.onStreamData('stream-notify-user', handleStreamMessageReceived); try { diff --git a/app/lib/methods/updateMessages.js b/app/lib/methods/updateMessages.js index 0dc63e9ba..5f0db0f66 100644 --- a/app/lib/methods/updateMessages.js +++ b/app/lib/methods/updateMessages.js @@ -16,7 +16,7 @@ export default function updateMessages({ rid, update = [], remove = [] }) { return db.action(async() => { // Decrypt these messages update = await Encryption.decryptMessages(update); - const subCollection = db.collections.get('subscriptions'); + const subCollection = db.get('subscriptions'); let sub; try { sub = await subCollection.find(rid); @@ -26,9 +26,9 @@ export default function updateMessages({ rid, update = [], remove = [] }) { } const messagesIds = [...update.map(m => m._id), ...remove.map(m => m._id)]; - const msgCollection = db.collections.get('messages'); - const threadCollection = db.collections.get('threads'); - const threadMessagesCollection = db.collections.get('thread_messages'); + const msgCollection = db.get('messages'); + const threadCollection = db.get('threads'); + const threadMessagesCollection = db.get('thread_messages'); const allMessagesRecords = await msgCollection .query(Q.where('rid', rid), Q.where('id', Q.oneOf(messagesIds))) .fetch(); diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index 4f9952b80..693c5eb78 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -32,7 +32,7 @@ import readMessages from './methods/readMessages'; import getSettings, { getLoginSettings, setSettings } from './methods/getSettings'; import getRooms from './methods/getRooms'; -import getPermissions from './methods/getPermissions'; +import { setPermissions, getPermissions } from './methods/getPermissions'; import { getCustomEmojis, setCustomEmojis } from './methods/getCustomEmojis'; import { getEnterpriseModules, setEnterpriseModules, hasLicense, isOmnichannelModuleAvailable @@ -70,7 +70,6 @@ const CERTIFICATE_KEY = 'RC_CERTIFICATE_KEY'; export const THEME_PREFERENCES_KEY = 'RC_THEME_PREFERENCES_KEY'; export const CRASH_REPORT_KEY = 'RC_CRASH_REPORT_KEY'; export const ANALYTICS_EVENTS_KEY = 'RC_ANALYTICS_EVENTS_KEY'; -const returnAnArray = obj => obj || []; const MIN_ROCKETCHAT_VERSION = '0.70.0'; const STATUSES = ['offline', 'online', 'away', 'busy']; @@ -178,9 +177,16 @@ const RocketChat = { } this.controller = new AbortController(); }, + checkAndReopen() { + return this?.sdk?.checkAndReopen(); + }, connect({ server, user, logoutOnError = false }) { return new Promise((resolve) => { - if (!this.sdk || this.sdk.client.host !== server) { + if (this?.sdk?.client?.host === server) { + return resolve(); + } else { + this.sdk?.disconnect?.(); + this.sdk = null; database.setActiveDB(server); } reduxStore.dispatch(connectRequest()); @@ -209,11 +215,6 @@ const RocketChat = { EventEmitter.emit('INQUIRY_UNSUBSCRIBE'); - if (this.sdk) { - this.sdk.disconnect(); - this.sdk = null; - } - if (this.code) { this.code = null; } @@ -241,6 +242,10 @@ const RocketChat = { sdkConnect(); + this.connectedListener = this.sdk.onStreamData('connecting', () => { + reduxStore.dispatch(connectRequest()); + }); + this.connectedListener = this.sdk.onStreamData('connected', () => { reduxStore.dispatch(connectSuccess()); }); @@ -276,7 +281,7 @@ const RocketChat = { } else if (/updateAvatar/.test(eventName)) { const { username, etag } = ddpMessage.fields.args[0]; const db = database.active; - const userCollection = db.collections.get('users'); + const userCollection = db.get('users'); try { const [userRecord] = await userCollection.query(Q.where('username', Q.eq(username))).fetch(); await db.action(async() => { @@ -290,7 +295,7 @@ const RocketChat = { } else if (/Users:NameChanged/.test(eventName)) { const userNameChanged = ddpMessage.fields.args[0]; const db = database.active; - const userCollection = db.collections.get('users'); + const userCollection = db.get('users'); try { const userRecord = await userCollection.find(userNameChanged._id); await db.action(async() => { @@ -334,7 +339,7 @@ const RocketChat = { // set Server const currentServer = { server }; const serversDB = database.servers; - const serversCollection = serversDB.collections.get('servers'); + const serversCollection = serversDB.get('servers'); try { const serverRecord = await serversCollection.find(server); currentServer.version = serverRecord.version; @@ -349,7 +354,7 @@ const RocketChat = { // set Settings const settings = ['Accounts_AvatarBlockUnauthenticatedAccess']; const db = database.active; - const settingsCollection = db.collections.get('settings'); + const settingsCollection = db.get('settings'); const settingsRecords = await settingsCollection.query(Q.where('id', Q.oneOf(settings))).fetch(); const parsed = Object.values(settingsRecords).map(item => ({ _id: item.id, @@ -363,7 +368,7 @@ const RocketChat = { // set User info const userId = await UserPreferences.getStringAsync(`${ RocketChat.TOKEN_KEY }-${ server }`); - const userCollections = serversDB.collections.get('users'); + const userCollections = serversDB.get('users'); let user = null; if (userId) { const userRecord = await userCollections.find(userId); @@ -545,7 +550,7 @@ const RocketChat = { try { const serversDB = database.servers; await serversDB.action(async() => { - const serverCollection = serversDB.collections.get('servers'); + const serverCollection = serversDB.get('servers'); const serverRecord = await serverCollection.find(server); await serverRecord.update((s) => { s.roomsUpdatedAt = null; @@ -605,7 +610,7 @@ const RocketChat = { } const db = database.active; const likeString = sanitizeLikeString(searchText); - let data = await db.collections.get('subscriptions').query( + let data = await db.get('subscriptions').query( Q.or( Q.where('name', Q.like(`%${ likeString }%`)), Q.where('fname', Q.like(`%${ likeString }%`)) @@ -621,19 +626,15 @@ 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, - avatarETag: sub.avatarETag, - t: sub.t, - encrypted: sub.encrypted - }; - } - return sub; - }); + data = data.map(sub => ({ + rid: sub.rid, + name: sub.name, + fname: sub.fname, + avatarETag: sub.avatarETag, + t: sub.t, + encrypted: sub.encrypted, + lastMessage: sub.lastMessage + })); return data; }, @@ -740,6 +741,7 @@ const RocketChat = { getLoginSettings, setSettings, getPermissions, + setPermissions, getCustomEmojis, setCustomEmojis, getEnterpriseModules, @@ -796,7 +798,7 @@ const RocketChat = { async getRoom(rid) { try { const db = database.active; - const room = await db.collections.get('subscriptions').find(rid); + const room = await db.get('subscriptions').find(rid); return Promise.resolve(room); } catch (error) { return Promise.reject(new Error('Room not found')); @@ -1172,10 +1174,13 @@ const RocketChat = { // RC 0.65.0 return this.sdk.get(`${ this.roomTypeToApiType(type) }.roles`, { roomId }); }, + /** + * Permissions: array of permissions' roles from redux. Example: [['owner', 'admin'], ['leader']] + * Returns an array of boolean for each permission from permissions arg + */ async hasPermission(permissions, rid) { const db = database.active; - const subsCollection = db.collections.get('subscriptions'); - const permissionsCollection = db.collections.get('permissions'); + const subsCollection = db.get('subscriptions'); let roomRoles = []; try { // get the room from database @@ -1184,31 +1189,16 @@ const RocketChat = { roomRoles = room.roles || []; } catch (error) { console.log('hasPermission -> Room not found'); - return permissions.reduce((result, permission) => { - result[permission] = false; - return result; - }, {}); + return permissions.map(() => false); } - // 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 = (shareUser?.roles || loginUser?.roles) || []; - // merge both roles const mergedRoles = [...new Set([...roomRoles, ...userRoles])]; - - // return permissions in object format - // e.g. { 'edit-room': true, 'set-readonly': false } - return permissions.reduce((result, permission) => { - result[permission] = false; - const permissionFound = permissionsFiltered.find(p => p.id === permission); - if (permissionFound) { - result[permission] = returnAnArray(permissionFound.roles).some(r => mergedRoles.includes(r)); - } - return result; - }, {}); + return permissions.map(permission => permission?.some(r => mergedRoles.includes(r) ?? false)); } catch (e) { log(e); } @@ -1438,17 +1428,15 @@ const RocketChat = { query, count, offset, sort }); }, - async canAutoTranslate() { - const db = database.active; + canAutoTranslate() { try { - const AutoTranslate_Enabled = reduxStore.getState().settings && reduxStore.getState().settings.AutoTranslate_Enabled; + const { AutoTranslate_Enabled } = reduxStore.getState().settings; if (!AutoTranslate_Enabled) { return false; } - const permissionsCollection = db.collections.get('permissions'); - const autoTranslatePermission = await permissionsCollection.find('auto-translate'); - const userRoles = (reduxStore.getState().login.user && reduxStore.getState().login.user.roles) || []; - return autoTranslatePermission.roles.some(role => userRoles.includes(role)); + const autoTranslatePermission = reduxStore.getState().permissions['auto-translate']; + const userRoles = (reduxStore.getState().login?.user?.roles) ?? []; + return autoTranslatePermission?.some(role => userRoles.includes(role)); } catch (e) { log(e); return false; diff --git a/app/presentation/RoomItem/LastMessage.js b/app/presentation/RoomItem/LastMessage.js index b29cb6cd1..25fc2c08d 100644 --- a/app/presentation/RoomItem/LastMessage.js +++ b/app/presentation/RoomItem/LastMessage.js @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import isEqual from 'lodash/isEqual'; +import { dequal } from 'dequal'; import I18n from '../../i18n'; import styles from './styles'; @@ -45,7 +45,7 @@ const formatMsg = ({ return `${ prefix }${ lastMessage.msg }`; }; -const arePropsEqual = (oldProps, newProps) => isEqual(oldProps, newProps); +const arePropsEqual = (oldProps, newProps) => dequal(oldProps, newProps); const LastMessage = React.memo(({ lastMessage, type, showLastMessage, username, alert, useRealName, theme diff --git a/app/reducers/index.js b/app/reducers/index.js index 6211ccb6f..dfee5f3eb 100644 --- a/app/reducers/index.js +++ b/app/reducers/index.js @@ -18,6 +18,7 @@ import inviteLinks from './inviteLinks'; import createDiscussion from './createDiscussion'; import enterpriseModules from './enterpriseModules'; import encryption from './encryption'; +import permissions from './permissions'; import inquiry from '../ee/omnichannel/reducers/inquiry'; @@ -41,5 +42,6 @@ export default combineReducers({ createDiscussion, inquiry, enterpriseModules, - encryption + encryption, + permissions }); diff --git a/app/reducers/permissions.js b/app/reducers/permissions.js new file mode 100644 index 000000000..1b3a14ec2 --- /dev/null +++ b/app/reducers/permissions.js @@ -0,0 +1,14 @@ +import { PERMISSIONS } from '../actions/actionsTypes'; + +const initialState = { + permissions: {} +}; + +export default function permissions(state = initialState, action) { + switch (action.type) { + case PERMISSIONS.SET: + return action.permissions; + default: + return state; + } +} diff --git a/app/sagas/createChannel.js b/app/sagas/createChannel.js index ca4bcb9fe..613aedec2 100644 --- a/app/sagas/createChannel.js +++ b/app/sagas/createChannel.js @@ -42,7 +42,7 @@ const handleRequest = function* handleRequest({ data }) { broadcast, encrypted } = data; - logEvent(events.CREATE_CHANNEL_CREATE, { + logEvent(events.CR_CREATE, { type: type ? 'private' : 'public', readOnly, broadcast, @@ -53,7 +53,7 @@ const handleRequest = function* handleRequest({ data }) { try { const db = database.active; - const subCollection = db.collections.get('subscriptions'); + const subCollection = db.get('subscriptions'); yield db.action(async() => { await subCollection.create((s) => { s._raw = sanitizedRaw({ id: sub.rid }, subCollection.schema); @@ -66,7 +66,7 @@ const handleRequest = function* handleRequest({ data }) { yield put(createChannelSuccess(sub)); } catch (err) { - logEvent(events[data.group ? 'SELECTED_USERS_CREATE_GROUP_F' : 'CREATE_CHANNEL_CREATE_F']); + logEvent(events[data.group ? 'SELECTED_USERS_CREATE_GROUP_F' : 'CR_CREATE_F']); yield put(createChannelFailure(err)); } }; diff --git a/app/sagas/createDiscussion.js b/app/sagas/createDiscussion.js index a185e6671..746ab1583 100644 --- a/app/sagas/createDiscussion.js +++ b/app/sagas/createDiscussion.js @@ -14,7 +14,7 @@ const create = function* create(data) { }; const handleRequest = function* handleRequest({ data }) { - logEvent(events.CREATE_DISCUSSION_CREATE); + logEvent(events.CD_CREATE); try { const auth = yield select(state => state.login.isAuthenticated); if (!auth) { @@ -27,7 +27,7 @@ const handleRequest = function* handleRequest({ data }) { try { const db = database.active; - const subCollection = db.collections.get('subscriptions'); + const subCollection = db.get('subscriptions'); yield db.action(async() => { await subCollection.create((s) => { s._raw = sanitizedRaw({ id: sub.rid }, subCollection.schema); @@ -39,11 +39,11 @@ const handleRequest = function* handleRequest({ data }) { } yield put(createDiscussionSuccess(sub)); } else { - logEvent(events.CREATE_DISCUSSION_CREATE_F); + logEvent(events.CD_CREATE_F); yield put(createDiscussionFailure(result)); } } catch (err) { - logEvent(events.CREATE_DISCUSSION_CREATE_F); + logEvent(events.CD_CREATE_F); yield put(createDiscussionFailure(err)); } }; diff --git a/app/sagas/deepLinking.js b/app/sagas/deepLinking.js index caf2a46f9..21e0695fb 100644 --- a/app/sagas/deepLinking.js +++ b/app/sagas/deepLinking.js @@ -31,6 +31,14 @@ const handleInviteLink = function* handleInviteLink({ params, requireLogin = fal } }; +const popToRoot = function popToRoot({ isMasterDetail }) { + if (isMasterDetail) { + Navigation.navigate('DrawerNavigator'); + } else { + Navigation.navigate('RoomsListView'); + } +}; + const navigate = function* navigate({ params }) { yield put(appStart({ root: ROOT_INSIDE })); if (params.path) { @@ -38,22 +46,31 @@ const navigate = function* navigate({ params }) { if (type !== 'invite') { const room = yield RocketChat.canOpenRoom(params); if (room) { - const isMasterDetail = yield select(state => state.app.isMasterDetail); - if (isMasterDetail) { - Navigation.navigate('DrawerNavigator'); - } else { - Navigation.navigate('RoomsListView'); - } const item = { name, t: roomTypes[type], roomUserId: RocketChat.getUidDirectMessage(room), ...room }; - yield goRoom({ item, isMasterDetail }); + + const isMasterDetail = yield select(state => state.app.isMasterDetail); + const focusedRooms = yield select(state => state.room.rooms); + + if (focusedRooms.includes(room.rid)) { + // if there's one room on the list or last room is the one + if (focusedRooms.length === 1 || focusedRooms[0] === room.rid) { + yield goRoom({ item, isMasterDetail }); + } else { + popToRoot({ isMasterDetail }); + yield goRoom({ item, isMasterDetail }); + } + } else { + popToRoot({ isMasterDetail }); + yield goRoom({ item, isMasterDetail }); + } if (params.isCall) { - RocketChat.callJitsi(item.rid); + RocketChat.callJitsi(item); } } } else { @@ -72,7 +89,7 @@ const fallbackNavigation = function* fallbackNavigation() { const handleOpen = function* handleOpen({ params }) { const serversDB = database.servers; - const serversCollection = serversDB.collections.get('servers'); + const serversCollection = serversDB.get('servers'); let { host } = params; if (params.isCall && !host) { @@ -121,10 +138,10 @@ const handleOpen = function* handleOpen({ params }) { } else { // search if deep link's server already exists try { - const servers = yield serversCollection.find(host); - if (servers && user) { + const hostServerRecord = yield serversCollection.find(host); + if (hostServerRecord && user) { yield localAuthenticate(host); - yield put(selectServerRequest(host)); + yield put(selectServerRequest(host, hostServerRecord.version, true, true)); yield take(types.LOGIN.SUCCESS); yield navigate({ params }); return; diff --git a/app/sagas/encryption.js b/app/sagas/encryption.js index f28c77834..395923a43 100644 --- a/app/sagas/encryption.js +++ b/app/sagas/encryption.js @@ -30,7 +30,7 @@ const handleEncryptionInit = function* handleEncryptionInit() { // Fetch server info to check E2E enable const serversDB = database.servers; - const serversCollection = serversDB.collections.get('servers'); + const serversCollection = serversDB.get('servers'); let serverInfo; try { serverInfo = yield serversCollection.find(server); diff --git a/app/sagas/init.js b/app/sagas/init.js index 5c0cb7286..03a6c5a78 100644 --- a/app/sagas/init.js +++ b/app/sagas/init.js @@ -38,7 +38,7 @@ const restore = function* restore() { yield put(appStart({ root: ROOT_OUTSIDE })); } else { const serversDB = database.servers; - const serverCollections = serversDB.collections.get('servers'); + const serverCollections = serversDB.get('servers'); let serverObj; try { diff --git a/app/sagas/login.js b/app/sagas/login.js index cf487eed4..b5c267263 100644 --- a/app/sagas/login.js +++ b/app/sagas/login.js @@ -57,7 +57,7 @@ const handleLoginRequest = function* handleLoginRequest({ credentials, logoutOnE // Saves username on server history const serversDB = database.servers; - const serversHistoryCollection = serversDB.collections.get('servers_history'); + const serversHistoryCollection = serversDB.get('servers_history'); yield serversDB.action(async() => { try { const serversHistory = await serversHistoryCollection.query(Q.where('url', server)).fetch(); @@ -145,7 +145,7 @@ const handleLoginSuccess = function* handleLoginSuccess({ user }) { moment.locale(toMomentLocale(user.language)); const serversDB = database.servers; - const usersCollection = serversDB.collections.get('users'); + const usersCollection = serversDB.get('users'); const u = { token: user.token, username: user.username, @@ -222,7 +222,7 @@ const handleLogout = function* handleLogout({ forcedByServer }) { } else { const serversDB = database.servers; // all servers - const serversCollection = serversDB.collections.get('servers'); + const serversCollection = serversDB.get('servers'); const servers = yield serversCollection.query().fetch(); // see if there're other logged in servers and selects first one diff --git a/app/sagas/messages.js b/app/sagas/messages.js index 2879b2b64..2674be42e 100644 --- a/app/sagas/messages.js +++ b/app/sagas/messages.js @@ -12,7 +12,7 @@ const handleReplyBroadcast = function* handleReplyBroadcast({ message }) { try { const db = database.active; const { username } = message.u; - const subsCollection = db.collections.get('subscriptions'); + const subsCollection = db.get('subscriptions'); const subscriptions = yield subsCollection.query(Q.where('name', username)).fetch(); const isMasterDetail = yield select(state => state.app.isMasterDetail); diff --git a/app/sagas/rooms.js b/app/sagas/rooms.js index 94670ea1f..f963a2948 100644 --- a/app/sagas/rooms.js +++ b/app/sagas/rooms.js @@ -15,7 +15,7 @@ import protectedFunction from '../lib/methods/helpers/protectedFunction'; const updateRooms = function* updateRooms({ server, newRoomsUpdatedAt }) { const serversDB = database.servers; - const serversCollection = serversDB.collections.get('servers'); + const serversCollection = serversDB.get('servers'); try { const serverRecord = yield serversCollection.find(server); @@ -39,7 +39,7 @@ const handleRoomsRequest = function* handleRoomsRequest({ params }) { if (params.allData) { yield put(roomsRefresh()); } else { - const serversCollection = serversDB.collections.get('servers'); + const serversCollection = serversDB.get('servers'); try { const serverRecord = yield serversCollection.find(server); ({ roomsUpdatedAt } = serverRecord); @@ -51,8 +51,8 @@ const handleRoomsRequest = function* handleRoomsRequest({ params }) { const { subscriptions } = yield mergeSubscriptionsRooms(subscriptionsResult, roomsResult); const db = database.active; - const subCollection = db.collections.get('subscriptions'); - const messagesCollection = db.collections.get('messages'); + const subCollection = db.get('subscriptions'); + const messagesCollection = db.get('messages'); const subsIds = subscriptions.map(sub => sub.rid).concat(roomsResult.remove.map(room => room._id)); if (subsIds.length) { diff --git a/app/sagas/selectServer.js b/app/sagas/selectServer.js index 87fb47549..d367274a3 100644 --- a/app/sagas/selectServer.js +++ b/app/sagas/selectServer.js @@ -46,7 +46,7 @@ const getServerInfo = function* getServerInfo({ server, raiseError = true }) { } const serversDB = database.servers; - const serversCollection = serversDB.collections.get('servers'); + const serversCollection = serversDB.get('servers'); yield serversDB.action(async() => { try { const serverRecord = await serversCollection.find(server); @@ -78,7 +78,7 @@ const handleSelectServer = function* handleSelectServer({ server, version, fetch const serversDB = database.servers; yield UserPreferences.setStringAsync(RocketChat.CURRENT_SERVER, server); const userId = yield UserPreferences.getStringAsync(`${ RocketChat.TOKEN_KEY }-${ server }`); - const userCollections = serversDB.collections.get('users'); + const userCollections = serversDB.get('users'); let user = null; if (userId) { try { @@ -124,6 +124,7 @@ const handleSelectServer = function* handleSelectServer({ server, version, fetch // and block the selectServerSuccess raising multiples errors RocketChat.setSettings(); RocketChat.setCustomEmojis(); + RocketChat.setPermissions(); RocketChat.setEnterpriseModules(); let serverInfo; @@ -151,7 +152,7 @@ const handleServerRequest = function* handleServerRequest({ server, username, fr const serverInfo = yield getServerInfo({ server }); const serversDB = database.servers; - const serversHistoryCollection = serversDB.collections.get('servers_history'); + const serversHistoryCollection = serversDB.get('servers_history'); if (serverInfo) { yield RocketChat.getLoginServices(server); diff --git a/app/sagas/state.js b/app/sagas/state.js index 8b072c0a9..5b86af2ef 100644 --- a/app/sagas/state.js +++ b/app/sagas/state.js @@ -12,13 +12,14 @@ const appHasComeBackToForeground = function* appHasComeBackToForeground() { if (appRoot === ROOT_OUTSIDE) { return; } - const auth = yield select(state => state.login.isAuthenticated); - if (!auth) { + const login = yield select(state => state.login); + const server = yield select(state => state.server); + if (!login.isAuthenticated || login.isFetching || server.connecting || server.loading || server.changingServer) { return; } try { - const server = yield select(state => state.server.server); - yield localAuthenticate(server); + yield localAuthenticate(server.server); + RocketChat.checkAndReopen(); setBadgeCount(); return yield RocketChat.setUserPresenceOnline(); } catch (e) { @@ -31,14 +32,6 @@ const appHasComeBackToBackground = function* appHasComeBackToBackground() { if (appRoot === ROOT_OUTSIDE) { return; } - const auth = yield select(state => state.login.isAuthenticated); - if (!auth) { - return; - } - const localAuthenticated = yield select(state => state.login.isLocalAuthenticated); - if (!localAuthenticated) { - return; - } try { const server = yield select(state => state.server.server); yield saveLastLocalAuthenticationSession(server); diff --git a/app/stacks/InsideStack.js b/app/stacks/InsideStack.js index 75d01708e..a0af96177 100644 --- a/app/stacks/InsideStack.js +++ b/app/stacks/InsideStack.js @@ -31,6 +31,7 @@ import PickerView from '../views/PickerView'; import ThreadMessagesView from '../views/ThreadMessagesView'; import MarkdownTableView from '../views/MarkdownTableView'; import ReadReceiptsView from '../views/ReadReceiptView'; +import { themes } from '../constants/colors'; // Profile Stack import ProfileView from '../views/ProfileView'; @@ -280,19 +281,24 @@ const AdminPanelStackNavigator = () => { // DrawerNavigator const Drawer = createDrawerNavigator(); -const DrawerNavigator = () => ( - } - drawerPosition={I18nManager.isRTL ? 'right' : 'left'} - screenOptions={{ swipeEnabled: false }} - drawerType='back' - > - - - - - -); +const DrawerNavigator = () => { + const { theme } = React.useContext(ThemeContext); + + return ( + } + drawerPosition={I18nManager.isRTL ? 'right' : 'left'} + screenOptions={{ swipeEnabled: false }} + drawerType='back' + overlayColor={`rgba(0,0,0,${ themes[theme].backdropOpacity })`} + > + + + + + + ); +}; // NewMessageStackNavigator const NewMessageStack = createStackNavigator(); diff --git a/app/utils/isReadOnly.js b/app/utils/isReadOnly.js index 7d35a2836..f6f1937f6 100644 --- a/app/utils/isReadOnly.js +++ b/app/utils/isReadOnly.js @@ -1,13 +1,11 @@ import RocketChat from '../lib/rocketchat'; +import reduxStore from '../lib/createStore'; -const canPost = async({ rid }) => { - try { - const permission = await RocketChat.hasPermission(['post-readonly'], rid); - return permission && permission['post-readonly']; - } catch { - // do nothing - } - return false; +const canPostReadOnly = async({ rid }) => { + // TODO: this is not reactive. If this permission changes, the component won't be updated + const postReadOnlyPermission = reduxStore.getState().permissions['post-readonly']; + const permission = await RocketChat.hasPermission([postReadOnlyPermission], rid); + return permission[0]; }; const isMuted = (room, user) => room && room.muted && room.muted.find && !!room.muted.find(m => m === user.username); @@ -20,7 +18,7 @@ export const isReadOnly = async(room, user) => { return true; } if (room?.ro) { - const allowPost = await canPost(room); + const allowPost = await canPostReadOnly(room); if (allowPost) { return false; } diff --git a/app/utils/localAuthentication.js b/app/utils/localAuthentication.js index 2eb9c7d29..6e6d40dfb 100644 --- a/app/utils/localAuthentication.js +++ b/app/utils/localAuthentication.js @@ -17,7 +17,7 @@ import { setLocalAuthenticated } from '../actions/login'; export const saveLastLocalAuthenticationSession = async(server, serverRecord) => { const serversDB = database.servers; - const serversCollection = serversDB.collections.get('servers'); + const serversCollection = serversDB.get('servers'); await serversDB.action(async() => { try { if (!serverRecord) { @@ -91,7 +91,7 @@ export const checkHasPasscode = async({ force = true, serverRecord }) => { export const localAuthenticate = async(server) => { const serversDB = database.servers; - const serversCollection = serversDB.collections.get('servers'); + const serversCollection = serversDB.get('servers'); let serverRecord; try { @@ -102,9 +102,6 @@ export const localAuthenticate = async(server) => { // if screen lock is enabled if (serverRecord?.autoLock) { - // set isLocalAuthenticated to false - store.dispatch(setLocalAuthenticated(false)); - // Make sure splash screen has been hidden RNBootSplash.hide(); @@ -118,6 +115,9 @@ export const localAuthenticate = async(server) => { // if last authenticated session is older than configured auto lock time, authentication is required if (diffToLastSession >= serverRecord?.autoLockTime) { + // set isLocalAuthenticated to false + store.dispatch(setLocalAuthenticated(false)); + let hasBiometry = false; // if biometry is enabled on the app diff --git a/app/utils/log/events.js b/app/utils/log/events.js index 4895ad8f2..2e1e8f9a4 100644 --- a/app/utils/log/events.js +++ b/app/utils/log/events.js @@ -5,9 +5,8 @@ export default { ONBOARD_CREATE_NEW_WORKSPACE_F: 'onboard_create_new_workspace_f', // NEW SERVER VIEW - NEWSERVER_CONNECT_TO_WORKSPACE: 'newserver_connect_to_workspace', - NEWSERVER_CONNECT_TO_WORKSPACE_F: 'newserver_connect_to_workspace_f', - NEWSERVER_JOIN_OPEN_WORKSPACE: 'newserver_join_open_workspace', + NS_CONNECT_TO_WORKSPACE: 'ns_connect_to_workspace', + NS_JOIN_OPEN_WORKSPACE: 'ns_join_open_workspace', // LOGIN VIEW LOGIN_DEFAULT_LOGIN: 'login_default_login', @@ -99,20 +98,20 @@ export default { SELECTED_USERS_CREATE_GROUP_F: 'selected_users_create_group_f', // CREATE CHANNEL VIEW - CREATE_CHANNEL_CREATE: 'create_channel_create', - CREATE_CHANNEL_CREATE_F: 'create_channel_create_f', - CREATE_CHANNEL_TOGGLE_TYPE: 'create_channel_toggle_type', - CREATE_CHANNEL_TOGGLE_READ_ONLY: 'create_channel_toggle_read_only', - CREATE_CHANNEL_TOGGLE_BROADCAST: 'create_channel_toggle_broadcast', - CREATE_CHANNEL_TOGGLE_ENCRYPTED: 'create_channel_toggle_encrypted', - CREATE_CHANNEL_REMOVE_USER: 'create_channel_remove_user', + CR_CREATE: 'cr_create', + CR_CREATE_F: 'cr_create_f', + CR_TOGGLE_TYPE: 'cr_toggle_type', + CR_TOGGLE_READ_ONLY: 'cr_toggle_read_only', + CR_TOGGLE_BROADCAST: 'cr_toggle_broadcast', + CR_TOGGLE_ENCRYPTED: 'cr_toggle_encrypted', + CR_REMOVE_USER: 'cr_remove_user', // CREATE DISCUSSION VIEW - CREATE_DISCUSSION_CREATE: 'create_discussion_create', - CREATE_DISCUSSION_CREATE_F: 'create_discussion_create_f', - CREATE_DISCUSSION_SELECT_CHANNEL: 'create_discussion_select_channel', - CREATE_DISCUSSION_SELECT_USERS: 'create_discussion_select_users', - CREATE_DISCUSSION_TOGGLE_ENCRY: 'create_discussion_toggle_encry', + CD_CREATE: 'cd_create', + CD_CREATE_F: 'cd_create_f', + CD_SELECT_CHANNEL: 'cd_select_channel', + CD_SELECT_USERS: 'cd_select_users', + CD_TOGGLE_ENCRY: 'cd_toggle_encry', // PROFILE VIEW PROFILE_PICK_AVATAR: 'profile_pick_avatar', @@ -122,8 +121,9 @@ export default { PROFILE_SAVE_AVATAR_F: 'profile_save_avatar_f', PROFILE_SAVE_CHANGES: 'profile_save_changes', PROFILE_SAVE_CHANGES_F: 'profile_save_changes_f', - PROFILE_LOGOUT_OTHER_LOCATIONS: 'profile_logout_other_locations', - PROFILE_LOGOUT_OTHER_LOCATIONS_F: 'profile_logout_other_locations_f', + // PROFILE LOGOUT + PL_OTHER_LOCATIONS: 'pl_other_locations', + PL_OTHER_LOCATIONS_F: 'pl_other_locations_f', // SETTINGS VIEW SE_CONTACT_US: 'se_contact_us', @@ -297,8 +297,6 @@ export default { NP_AUDIONOTIFICATIONS_F: 'np_audio_notifications_f', NP_AUDIONOTIFICATIONVALUE: 'np_audio_notification_value', NP_AUDIONOTIFICATIONVALUE_F: 'np_audio_notification_value_f', - NP_DESKTOPNOTIFICATIONDURATION: 'np_desktopnotificationduration', - NP_DESKTOPNOTIFICATIONDURATION_F: 'np_desktopnotificationduration_f', NP_EMAILNOTIFICATIONS: 'np_email_notifications', NP_EMAILNOTIFICATIONS_F: 'np_email_notifications_f', diff --git a/app/views/AttachmentView.js b/app/views/AttachmentView.js index 3f4adfec7..c07ed71b9 100644 --- a/app/views/AttachmentView.js +++ b/app/views/AttachmentView.js @@ -121,8 +121,9 @@ class AttachmentView extends React.Component { const extension = image_url ? `.${ mime.extension(image_type) || 'jpg' }` : `.${ mime.extension(video_type) || 'mp4' }`; const documentDir = `${ RNFetchBlob.fs.dirs.DocumentDir }/`; const path = `${ documentDir + SHA256(url) + extension }`; - const file = await RNFetchBlob.config({ path }).fetch('GET', mediaAttachment).then(res => res.path()); - await CameraRoll.save(file, { album: 'Rocket.Chat' }); + const file = await RNFetchBlob.config({ path }).fetch('GET', mediaAttachment); + await CameraRoll.save(path, { album: 'Rocket.Chat' }); + await file.flush(); EventEmitter.emit(LISTENER, { message: I18n.t('saved_to_gallery') }); } catch (e) { EventEmitter.emit(LISTENER, { message: I18n.t(image_url ? 'error-save-image' : 'error-save-video') }); diff --git a/app/views/ChangePasscodeView.js b/app/views/ChangePasscodeView.js index 308e2d782..535ba71d4 100644 --- a/app/views/ChangePasscodeView.js +++ b/app/views/ChangePasscodeView.js @@ -63,12 +63,12 @@ const ChangePasscodeView = React.memo(({ theme }) => { if (!isTablet) { Orientation.lockToPortrait(); } - EventEmitter.addEventListener(CHANGE_PASSCODE_EMITTER, showChangePasscode); + const listener = EventEmitter.addEventListener(CHANGE_PASSCODE_EMITTER, showChangePasscode); return (() => { if (!isTablet) { Orientation.unlockAllOrientations(); } - EventEmitter.removeListener(CHANGE_PASSCODE_EMITTER); + EventEmitter.removeListener(CHANGE_PASSCODE_EMITTER, listener); }); }, []); diff --git a/app/views/CreateChannelView.js b/app/views/CreateChannelView.js index 70982094d..9d1e450ff 100644 --- a/app/views/CreateChannelView.js +++ b/app/views/CreateChannelView.js @@ -4,7 +4,8 @@ import PropTypes from 'prop-types'; import { View, Text, Switch, ScrollView, StyleSheet, FlatList } from 'react-native'; -import equal from 'deep-equal'; +import { dequal } from 'dequal'; +import * as List from '../containers/List'; import TextInput from '../presentation/TextInput'; import Loading from '../containers/Loading'; @@ -31,12 +32,6 @@ const styles = StyleSheet.create({ list: { width: '100%' }, - separator: { - marginLeft: 60 - }, - formSeparator: { - marginLeft: 15 - }, input: { height: 54, paddingHorizontal: 18, @@ -133,7 +128,7 @@ class CreateChannelView extends React.Component { if (nextProps.encryptionEnabled !== encryptionEnabled) { return true; } - if (!equal(nextProps.users, users)) { + if (!dequal(nextProps.users, users)) { return true; } return false; @@ -177,7 +172,7 @@ class CreateChannelView extends React.Component { } removeUser = (user) => { - logEvent(events.CREATE_CHANNEL_REMOVE_USER); + logEvent(events.CR_REMOVE_USER); const { removeUser } = this.props; removeUser(user); } @@ -207,7 +202,7 @@ class CreateChannelView extends React.Component { value: type, label: 'Private_Channel', onValueChange: (value) => { - logEvent(events.CREATE_CHANNEL_TOGGLE_TYPE); + logEvent(events.CR_TOGGLE_TYPE); // If we set the channel as public, encrypted status should be false this.setState(({ encrypted }) => ({ type: value, encrypted: value && encrypted })); } @@ -221,7 +216,7 @@ class CreateChannelView extends React.Component { value: readOnly, label: 'Read_Only_Channel', onValueChange: (value) => { - logEvent(events.CREATE_CHANNEL_TOGGLE_READ_ONLY); + logEvent(events.CR_TOGGLE_READ_ONLY); this.setState({ readOnly: value }); }, disabled: broadcast @@ -241,7 +236,7 @@ class CreateChannelView extends React.Component { value: encrypted, label: 'Encrypted', onValueChange: (value) => { - logEvent(events.CREATE_CHANNEL_TOGGLE_ENCRYPTED); + logEvent(events.CR_TOGGLE_ENCRYPTED); this.setState({ encrypted: value }); }, disabled: !type @@ -255,7 +250,7 @@ class CreateChannelView extends React.Component { value: broadcast, label: 'Broadcast_Channel', onValueChange: (value) => { - logEvent(events.CREATE_CHANNEL_TOGGLE_BROADCAST); + logEvent(events.CR_TOGGLE_BROADCAST); this.setState({ broadcast: value, readOnly: value ? true : readOnly @@ -264,13 +259,6 @@ class CreateChannelView extends React.Component { }); } - renderSeparator = () => - - renderFormSeparator = () => { - const { theme } = this.props; - return ; - } - renderItem = ({ item }) => { const { baseUrl, user, theme } = this.props; @@ -305,7 +293,7 @@ class CreateChannelView extends React.Component { } ]} renderItem={this.renderItem} - ItemSeparatorComponent={this.renderSeparator} + ItemSeparatorComponent={List.Separator} enableEmptySections keyboardShouldPersistTaps='always' /> @@ -341,13 +329,13 @@ class CreateChannelView extends React.Component { theme={theme} underlineColorAndroid='transparent' /> - {this.renderFormSeparator()} + {this.renderType()} - {this.renderFormSeparator()} + {this.renderReadOnly()} - {this.renderFormSeparator()} + {this.renderEncrypted()} - {this.renderFormSeparator()} + {this.renderBroadcast()} diff --git a/app/views/CreateDiscussionView/SelectUsers.js b/app/views/CreateDiscussionView/SelectUsers.js index a88773ab0..8500ee15c 100644 --- a/app/views/CreateDiscussionView/SelectUsers.js +++ b/app/views/CreateDiscussionView/SelectUsers.js @@ -22,7 +22,7 @@ const SelectUsers = ({ const getUsers = debounce(async(keyword = '') => { try { const db = database.active; - const usersCollection = db.collections.get('users'); + const usersCollection = db.get('users'); const res = await RocketChat.search({ text: keyword, filterRooms: false }); let items = [...users.filter(u => selected.includes(u.name)), ...res.filter(r => !users.find(u => u.name === r.name))]; const records = await usersCollection.query(Q.where('username', Q.oneOf(items.map(u => u.name)))).fetch(); diff --git a/app/views/CreateDiscussionView/index.js b/app/views/CreateDiscussionView/index.js index 43329f102..2970ba016 100644 --- a/app/views/CreateDiscussionView/index.js +++ b/app/views/CreateDiscussionView/index.js @@ -2,7 +2,6 @@ import React from 'react'; import { connect } from 'react-redux'; import PropTypes from 'prop-types'; import { ScrollView, Text, Switch } from 'react-native'; -import isEqual from 'lodash/isEqual'; import Loading from '../../containers/Loading'; import KeyboardView from '../../presentation/KeyboardView'; @@ -63,11 +62,12 @@ class CreateChannelView extends React.Component { } componentDidUpdate(prevProps, prevState) { + const { channel, name } = this.state; const { loading, failure, error, result, isMasterDetail } = this.props; - if (!isEqual(this.state, prevState)) { + if (channel?.rid !== prevState.channel?.rid || name !== prevState.name) { this.setHeader(); } @@ -136,17 +136,17 @@ class CreateChannelView extends React.Component { }; selectChannel = ({ value }) => { - logEvent(events.CREATE_DISCUSSION_SELECT_CHANNEL); + logEvent(events.CD_SELECT_CHANNEL); this.setState({ channel: value, encrypted: value?.encrypted }); } selectUsers = ({ value }) => { - logEvent(events.CREATE_DISCUSSION_SELECT_USERS); + logEvent(events.CD_SELECT_USERS); this.setState({ users: value }); } onEncryptedChange = (value) => { - logEvent(events.CREATE_DISCUSSION_TOGGLE_ENCRY); + logEvent(events.CD_TOGGLE_ENCRY); this.setState({ encrypted: value }); } @@ -222,7 +222,7 @@ const mapStateToProps = state => ({ loading: state.createDiscussion.isFetching, result: state.createDiscussion.result, blockUnauthenticatedAccess: state.settings.Accounts_AvatarBlockUnauthenticatedAccess ?? true, - serverVersion: state.share.server.version || state.server.version, + serverVersion: state.server.version, isMasterDetail: state.app.isMasterDetail, encryptionEnabled: state.encryption.enabled }); diff --git a/app/views/DirectoryView/Options.js b/app/views/DirectoryView/Options.js index ab69b11f4..ad8de1da1 100644 --- a/app/views/DirectoryView/Options.js +++ b/app/views/DirectoryView/Options.js @@ -84,13 +84,13 @@ export default class DirectoryOptions extends PureComponent { inputRange: [0, 1], outputRange: [-326, 0] }); - const backdropOpacity = this.animatedValue.interpolate({ - inputRange: [0, 1], - outputRange: [0, 0.3] - }); const { globalUsers, toggleWorkspace, isFederationEnabled, theme } = this.props; + const backdropOpacity = this.animatedValue.interpolate({ + inputRange: [0, 1], + outputRange: [0, themes[theme].backdropOpacity] + }); return ( <> diff --git a/app/views/DirectoryView/index.js b/app/views/DirectoryView/index.js index 8be78712d..afb1214f3 100644 --- a/app/views/DirectoryView/index.js +++ b/app/views/DirectoryView/index.js @@ -4,6 +4,7 @@ import { View, FlatList, Text } from 'react-native'; import { connect } from 'react-redux'; +import * as List from '../../containers/List'; import Touch from '../../utils/touch'; import RocketChat from '../../lib/rocketchat'; @@ -182,11 +183,6 @@ class DirectoryView extends React.Component { ); } - renderSeparator = () => { - const { theme } = this.props; - return ; - } - renderItem = ({ item, index }) => { const { data, type } = this.state; const { baseUrl, user, theme } = this.props; @@ -251,7 +247,7 @@ class DirectoryView extends React.Component { keyExtractor={item => item._id} ListHeaderComponent={this.renderHeader} renderItem={this.renderItem} - ItemSeparatorComponent={this.renderSeparator} + ItemSeparatorComponent={List.Separator} keyboardShouldPersistTaps='always' ListFooterComponent={loading ? : null} onEndReached={() => this.load({})} diff --git a/app/views/LanguageView/index.js b/app/views/LanguageView/index.js index 435762d21..b2e6e1079 100644 --- a/app/views/LanguageView/index.js +++ b/app/views/LanguageView/index.js @@ -94,7 +94,7 @@ class LanguageView extends React.Component { setUser({ language: params.language }); const serversDB = database.servers; - const usersCollection = serversDB.collections.get('users'); + const usersCollection = serversDB.get('users'); await serversDB.action(async() => { try { const userRecord = await usersCollection.find(user.id); diff --git a/app/views/LoginView.js b/app/views/LoginView.js index bdffd103b..8e9791d36 100644 --- a/app/views/LoginView.js +++ b/app/views/LoginView.js @@ -4,7 +4,7 @@ import { Text, View, StyleSheet, Keyboard, Alert } from 'react-native'; import { connect } from 'react-redux'; -import equal from 'deep-equal'; +import { dequal } from 'dequal'; import sharedStyles from './Styles'; import Button from '../containers/Button'; @@ -82,7 +82,7 @@ class LoginView extends React.Component { UNSAFE_componentWillReceiveProps(nextProps) { const { error } = this.props; - if (nextProps.failure && !equal(error, nextProps.error)) { + if (nextProps.failure && !dequal(error, nextProps.error)) { Alert.alert(I18n.t('Oops'), I18n.t('Login_error')); } } diff --git a/app/views/MessagesView/index.js b/app/views/MessagesView/index.js index 678d28f29..fc840b2d6 100644 --- a/app/views/MessagesView/index.js +++ b/app/views/MessagesView/index.js @@ -2,7 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { FlatList, View, Text } from 'react-native'; import { connect } from 'react-redux'; -import equal from 'deep-equal'; +import { dequal } from 'dequal'; import styles from './styles'; import Message from '../../containers/message'; @@ -57,7 +57,7 @@ class MessagesView extends React.Component { if (nextState.loading !== loading) { return true; } - if (!equal(nextState.messages, messages)) { + if (!dequal(nextState.messages, messages)) { return true; } if (fileLoading !== nextState.fileLoading) { diff --git a/app/views/ModalBlockView.js b/app/views/ModalBlockView.js index 2d72fa339..85eee8492 100644 --- a/app/views/ModalBlockView.js +++ b/app/views/ModalBlockView.js @@ -1,7 +1,6 @@ import React from 'react'; import { StyleSheet, View } from 'react-native'; import PropTypes from 'prop-types'; -import isEqual from 'lodash/isEqual'; import { connect } from 'react-redux'; import { KeyboardAwareScrollView } from '@codler/react-native-keyboard-aware-scroll-view'; @@ -94,17 +93,6 @@ class ModalBlockView extends React.Component { EventEmitter.addEventListener(viewId, this.handleUpdate); } - shouldComponentUpdate(nextProps, nextState) { - if (!isEqual(nextProps, this.props)) { - return true; - } - if (!isEqual(nextState, this.state)) { - return true; - } - - return false; - } - componentDidUpdate(prevProps) { const { navigation, route } = this.props; const oldData = prevProps.route.params?.data ?? {}; diff --git a/app/views/NewMessageView.js b/app/views/NewMessageView.js index be47513bc..7e2aa2323 100644 --- a/app/views/NewMessageView.js +++ b/app/views/NewMessageView.js @@ -4,9 +4,8 @@ import { View, StyleSheet, FlatList, Text } from 'react-native'; import { connect } from 'react-redux'; -import equal from 'deep-equal'; -import orderBy from 'lodash/orderBy'; import { Q } from '@nozbe/watermelondb'; +import * as List from '../containers/List'; import Touch from '../utils/touch'; import database from '../lib/database'; @@ -27,10 +26,9 @@ import { createChannelRequest } from '../actions/createChannel'; import { goRoom } from '../utils/goRoom'; import SafeAreaView from '../containers/SafeAreaView'; +const QUERY_SIZE = 50; + const styles = StyleSheet.create({ - separator: { - marginLeft: 60 - }, button: { height: 46, flexDirection: 'row', @@ -77,40 +75,20 @@ class NewMessageView extends React.Component { }; } - shouldComponentUpdate(nextProps, nextState) { - const { search, chats } = this.state; - const { theme } = this.props; - if (nextProps.theme !== theme) { - return true; - } - if (!equal(nextState.search, search)) { - return true; - } - if (!equal(nextState.chats, chats)) { - return true; - } - return false; - } - - componentWillUnmount() { - if (this.querySubscription && this.querySubscription.unsubscribe) { - this.querySubscription.unsubscribe(); - } - } - // eslint-disable-next-line react/sort-comp init = async() => { try { const db = database.active; - const observable = await db.collections + const chats = await db.collections .get('subscriptions') - .query(Q.where('t', 'd')) - .observeWithColumns(['room_updated_at']); + .query( + Q.where('t', 'd'), + Q.experimentalTake(QUERY_SIZE), + Q.experimentalSortBy('room_updated_at', Q.desc) + ) + .fetch(); - this.querySubscription = observable.subscribe((data) => { - const chats = orderBy(data, ['roomUpdatedAt'], ['desc']); - this.setState({ chats }); - }); + this.setState({ chats }); } catch (e) { log(e); } @@ -211,10 +189,6 @@ class NewMessageView extends React.Component { ); } - renderSeparator = () => { - const { theme } = this.props; - return ; - } renderItem = ({ item, index }) => { const { search, chats } = this.state; @@ -254,7 +228,7 @@ class NewMessageView extends React.Component { keyExtractor={item => item._id} ListHeaderComponent={this.renderHeader} renderItem={this.renderItem} - ItemSeparatorComponent={this.renderSeparator} + ItemSeparatorComponent={List.Separator} contentContainerStyle={{ backgroundColor: themes[theme].backgroundColor }} keyboardShouldPersistTaps='always' /> diff --git a/app/views/NewServerView/index.js b/app/views/NewServerView/index.js index 192468ed3..27422dec8 100644 --- a/app/views/NewServerView/index.js +++ b/app/views/NewServerView/index.js @@ -132,7 +132,7 @@ class NewServerView extends React.Component { queryServerHistory = async(text) => { const db = database.servers; try { - const serversHistoryCollection = db.collections.get('servers_history'); + const serversHistoryCollection = db.get('servers_history'); let whereClause = [ Q.where('username', Q.notEq(null)), Q.experimentalSortBy('updated_at', Q.desc), @@ -174,7 +174,7 @@ class NewServerView extends React.Component { } submit = async({ fromServerHistory = false, username }) => { - logEvent(events.NEWSERVER_CONNECT_TO_WORKSPACE); + logEvent(events.NS_CONNECT_TO_WORKSPACE); const { text, certificate } = this.state; const { connectServer } = this.props; @@ -199,7 +199,7 @@ class NewServerView extends React.Component { } connectOpen = () => { - logEvent(events.NEWSERVER_JOIN_OPEN_WORKSPACE); + logEvent(events.NS_JOIN_OPEN_WORKSPACE); this.setState({ connectingOpen: true }); const { connectServer } = this.props; connectServer('https://open.rocket.chat'); diff --git a/app/views/ProfileView/index.js b/app/views/ProfileView/index.js index f4faeec1c..7e97422df 100644 --- a/app/views/ProfileView/index.js +++ b/app/views/ProfileView/index.js @@ -6,7 +6,7 @@ import prompt from 'react-native-prompt-android'; import SHA256 from 'js-sha256'; import ImagePicker from 'react-native-image-crop-picker'; import RNPickerSelect from 'react-native-picker-select'; -import isEqual from 'lodash/isEqual'; +import { dequal } from 'dequal'; import omit from 'lodash/omit'; import Touch from '../../utils/touch'; @@ -91,21 +91,11 @@ class ProfileView extends React.Component { * it's resetting the avatar right after * select some image from gallery. */ - if (!isEqual(omit(user, ['status']), omit(nextProps.user, ['status']))) { + if (!dequal(omit(user, ['status']), omit(nextProps.user, ['status']))) { this.init(nextProps.user); } } - shouldComponentUpdate(nextProps, nextState) { - if (!isEqual(nextState, this.state)) { - return true; - } - if (!isEqual(nextProps, this.props)) { - return true; - } - return false; - } - setAvatar = (avatar) => { const { Accounts_AllowUserAvatarChange } = this.props; @@ -434,7 +424,7 @@ class ProfileView extends React.Component { } logoutOtherLocations = () => { - logEvent(events.PROFILE_LOGOUT_OTHER_LOCATIONS); + logEvent(events.PL_OTHER_LOCATIONS); showConfirmationAlert({ message: I18n.t('You_will_be_logged_out_from_other_locations'), confirmationText: I18n.t('Logout'), @@ -443,7 +433,7 @@ class ProfileView extends React.Component { await RocketChat.logoutOtherLocations(); EventEmitter.emit(LISTENER, { message: I18n.t('Logged_out_of_other_clients_successfully') }); } catch { - logEvent(events.PROFILE_LOGOUT_OTHER_LOCATIONS_F); + logEvent(events.PL_OTHER_LOCATIONS_F); EventEmitter.emit(LISTENER, { message: I18n.t('Logout_failed') }); } } diff --git a/app/views/ReadReceiptView/index.js b/app/views/ReadReceiptView/index.js index b7456c77a..f41d7c873 100644 --- a/app/views/ReadReceiptView/index.js +++ b/app/views/ReadReceiptView/index.js @@ -1,9 +1,10 @@ import React from 'react'; import PropTypes from 'prop-types'; import { FlatList, View, Text } from 'react-native'; -import equal from 'deep-equal'; +import { dequal } from 'dequal'; import moment from 'moment'; import { connect } from 'react-redux'; +import * as List from '../../containers/List'; import Avatar from '../../containers/Avatar'; import styles from './styles'; @@ -55,7 +56,7 @@ class ReadReceiptView extends React.Component { if (nextState.loading !== loading) { return true; } - if (!equal(nextState.receipts, receipts)) { + if (!dequal(nextState.receipts, receipts)) { return true; } return false; @@ -121,11 +122,6 @@ class ReadReceiptView extends React.Component { ); } - renderSeparator = () => { - const { theme } = this.props; - return ; - } - render() { const { receipts, loading } = this.state; const { theme } = this.props; @@ -143,7 +139,7 @@ class ReadReceiptView extends React.Component { { const { room, joined } = this.state; + const { addUserToJoinedRoomPermission, addUserToAnyCRoomPermission, addUserToAnyPRoomPermission } = this.props; const { rid, t } = room; - let canAdd = false; + let canAddUser = false; const userInRoom = joined; - const permissions = await RocketChat.hasPermission(['add-user-to-joined-room', 'add-user-to-any-c-room', 'add-user-to-any-p-room'], rid); + const permissions = await RocketChat.hasPermission([addUserToJoinedRoomPermission, addUserToAnyCRoomPermission, addUserToAnyPRoomPermission], rid); - if (permissions) { - if (userInRoom && permissions['add-user-to-joined-room']) { - canAdd = true; - } - if (t === 'c' && permissions['add-user-to-any-c-room']) { - canAdd = true; - } - if (t === 'p' && permissions['add-user-to-any-p-room']) { - canAdd = true; - } + if (userInRoom && permissions[0]) { + canAddUser = true; } - this.setState({ canAddUser: canAdd }); + if (t === 'c' && permissions[1]) { + canAddUser = true; + } + if (t === 'p' && permissions[2]) { + canAddUser = true; + } + this.setState({ canAddUser }); } canInviteUser = async() => { const { room } = this.state; + const { createInviteLinksPermission } = this.props; const { rid } = room; - const permissions = await RocketChat.hasPermission(['create-invite-links'], rid); + const permissions = await RocketChat.hasPermission([createInviteLinksPermission], rid); - const canInviteUser = permissions && permissions['create-invite-links']; + const canInviteUser = permissions[0]; this.setState({ canInviteUser }); } canEdit = async() => { const { room } = this.state; + const { editRoomPermission } = this.props; const { rid } = room; - const permissions = await RocketChat.hasPermission(['edit-room'], rid); + const permissions = await RocketChat.hasPermission([editRoomPermission], rid); - const canEdit = permissions && permissions['edit-room']; + const canEdit = permissions[0]; this.setState({ canEdit }); } canToggleEncryption = async() => { const { room } = this.state; + const { toggleRoomE2EEncryptionPermission } = this.props; const { rid } = room; - const permissions = await RocketChat.hasPermission(['toggle-room-e2e-encryption'], rid); + const permissions = await RocketChat.hasPermission([toggleRoomE2EEncryptionPermission], rid); - const canToggleEncryption = permissions && permissions['toggle-room-e2e-encryption']; + const canToggleEncryption = permissions[0]; this.setState({ canToggleEncryption }); } canViewMembers = async() => { const { room } = this.state; + const { viewBroadcastMemberListPermission } = this.props; const { rid, t, broadcast } = room; if (broadcast) { - const viewBroadcastMemberListPermission = 'view-broadcast-member-list'; const permissions = await RocketChat.hasPermission([viewBroadcastMemberListPermission], rid); - if (!permissions[viewBroadcastMemberListPermission]) { + if (!permissions[0]) { return false; } } @@ -226,16 +236,10 @@ class RoomActionsView extends React.Component { canForwardGuest = async() => { const { room } = this.state; + const { transferLivechatGuestPermission } = this.props; const { rid } = room; - let result = true; - - const transferLivechatGuest = 'transfer-livechat-guest'; - const permissions = await RocketChat.hasPermission([transferLivechatGuest], rid); - if (!permissions[transferLivechatGuest]) { - result = false; - } - - this.setState({ canForwardGuest: result }); + const permissions = await RocketChat.hasPermission([transferLivechatGuestPermission], rid); + this.setState({ canForwardGuest: permissions[0] }); } canReturnQueue = async() => { @@ -482,7 +486,7 @@ class RoomActionsView extends React.Component { RocketChat.callJitsi(room?.rid, true)} + onPress={() => RocketChat.callJitsi(room, true)} testID='room-actions-voice' left={() => } showActionIndicator @@ -490,7 +494,7 @@ class RoomActionsView extends React.Component { RocketChat.callJitsi(room?.rid)} + onPress={() => RocketChat.callJitsi(room)} testID='room-actions-video' left={() => } showActionIndicator @@ -866,7 +870,15 @@ class RoomActionsView extends React.Component { const mapStateToProps = state => ({ jitsiEnabled: state.settings.Jitsi_Enabled || false, encryptionEnabled: state.encryption.enabled, - serverVersion: state.server.version + serverVersion: state.server.version, + addUserToJoinedRoomPermission: state.permissions['add-user-to-joined-room'], + addUserToAnyCRoomPermission: state.permissions['add-user-to-any-c-room'], + addUserToAnyPRoomPermission: state.permissions['add-user-to-any-p-room'], + createInviteLinksPermission: state.permissions['create-invite-links'], + editRoomPermission: state.permissions['edit-room'], + toggleRoomE2EEncryptionPermission: state.permissions['toggle-room-e2e-encryption'], + viewBroadcastMemberListPermission: state.permissions['view-broadcast-member-list'], + transferLivechatGuestPermission: state.permissions['transfer-livechat-guest'] }); const mapDispatchToProps = dispatch => ({ diff --git a/app/views/RoomInfoEditView/index.js b/app/views/RoomInfoEditView/index.js index 58664c6f2..04472c82e 100644 --- a/app/views/RoomInfoEditView/index.js +++ b/app/views/RoomInfoEditView/index.js @@ -4,15 +4,13 @@ import { Text, View, ScrollView, TouchableOpacity, Keyboard, Alert } from 'react-native'; import { connect } from 'react-redux'; -import equal from 'deep-equal'; import { BLOCK_CONTEXT } from '@rocket.chat/ui-kit'; import ImagePicker from 'react-native-image-crop-picker'; -import isEqual from 'lodash/isEqual'; +import { dequal } from 'dequal'; import isEmpty from 'lodash/isEmpty'; import lt from 'semver/functions/lt'; import coerce from 'semver/functions/coerce'; - import database from '../../lib/database'; import { deleteRoom as deleteRoomAction } from '../../actions/room'; import KeyboardView from '../../presentation/KeyboardView'; @@ -44,14 +42,6 @@ const PERMISSION_ARCHIVE = 'archive-room'; const PERMISSION_UNARCHIVE = 'unarchive-room'; const PERMISSION_DELETE_C = 'delete-c'; const PERMISSION_DELETE_P = 'delete-p'; -const PERMISSIONS_ARRAY = [ - PERMISSION_SET_READONLY, - PERMISSION_SET_REACT_WHEN_READONLY, - PERMISSION_ARCHIVE, - PERMISSION_UNARCHIVE, - PERMISSION_DELETE_C, - PERMISSION_DELETE_P -]; class RoomInfoEditView extends React.Component { static navigationOptions = () => ({ @@ -63,7 +53,13 @@ class RoomInfoEditView extends React.Component { deleteRoom: PropTypes.func, serverVersion: PropTypes.string, encryptionEnabled: PropTypes.bool, - theme: PropTypes.string + theme: PropTypes.string, + setReadOnlyPermission: PropTypes.array, + setReactWhenReadOnlyPermission: PropTypes.array, + archiveRoomPermission: PropTypes.array, + unarchiveRoomPermission: PropTypes.array, + deleteCPermission: PropTypes.array, + deletePPermission: PropTypes.array }; constructor(props) { @@ -90,16 +86,6 @@ class RoomInfoEditView extends React.Component { this.loadRoom(); } - shouldComponentUpdate(nextProps, nextState) { - if (!equal(nextState, this.state)) { - return true; - } - if (!equal(nextProps, this.props)) { - return true; - } - return false; - } - componentWillUnmount() { if (this.querySubscription && this.querySubscription.unsubscribe) { this.querySubscription.unsubscribe(); @@ -108,14 +94,22 @@ class RoomInfoEditView extends React.Component { // eslint-disable-next-line react/sort-comp loadRoom = async() => { - const { route } = this.props; + const { + route, + setReadOnlyPermission, + setReactWhenReadOnlyPermission, + archiveRoomPermission, + unarchiveRoomPermission, + deleteCPermission, + deletePPermission + } = this.props; const rid = route.params?.rid; if (!rid) { return; } try { const db = database.active; - const sub = await db.collections.get('subscriptions').find(rid); + const sub = await db.get('subscriptions').find(rid); const observable = sub.observe(); this.querySubscription = observable.subscribe((data) => { @@ -123,8 +117,25 @@ class RoomInfoEditView extends React.Component { this.init(this.room); }); - const permissions = await RocketChat.hasPermission(PERMISSIONS_ARRAY, rid); - this.setState({ permissions }); + const result = await RocketChat.hasPermission([ + setReadOnlyPermission, + setReactWhenReadOnlyPermission, + archiveRoomPermission, + unarchiveRoomPermission, + deleteCPermission, + deletePPermission + ], rid); + + this.setState({ + permissions: { + [PERMISSION_SET_READONLY]: result[0], + [PERMISSION_SET_REACT_WHEN_READONLY]: result[1], + [PERMISSION_ARCHIVE]: result[2], + [PERMISSION_UNARCHIVE]: result[3], + [PERMISSION_DELETE_C]: result[4], + [PERMISSION_DELETE_P]: result[5] + } + }); } catch (e) { log(e); } @@ -179,7 +190,7 @@ class RoomInfoEditView extends React.Component { && room.t === 'p' === t && room.ro === ro && room.reactWhenReadOnly === reactWhenReadOnly - && isEqual(room.sysMes, systemMessages) + && dequal(room.sysMes, systemMessages) && enableSysMes === (room.sysMes && room.sysMes.length > 0) && room.encrypted === encrypted && isEmpty(avatar) @@ -239,7 +250,7 @@ class RoomInfoEditView extends React.Component { params.reactWhenReadOnly = reactWhenReadOnly; } - if (!isEqual(room.sysMes, systemMessages)) { + if (!dequal(room.sysMes, systemMessages)) { params.systemMessages = systemMessages; } @@ -666,8 +677,14 @@ class RoomInfoEditView extends React.Component { } const mapStateToProps = state => ({ - serverVersion: state.share.server.version || state.server.version, - encryptionEnabled: state.encryption.enabled + serverVersion: state.server.version, + encryptionEnabled: state.encryption.enabled, + setReadOnlyPermission: state.permissions[PERMISSION_SET_READONLY], + setReactWhenReadOnlyPermission: state.permissions[PERMISSION_SET_REACT_WHEN_READONLY], + archiveRoomPermission: state.permissions[PERMISSION_ARCHIVE], + unarchiveRoomPermission: state.permissions[PERMISSION_UNARCHIVE], + deleteCPermission: state.permissions[PERMISSION_DELETE_C], + deletePPermission: state.permissions[PERMISSION_DELETE_P] }); const mapDispatchToProps = dispatch => ({ diff --git a/app/views/RoomInfoView/index.js b/app/views/RoomInfoView/index.js index fd61e0eae..a18476d34 100644 --- a/app/views/RoomInfoView/index.js +++ b/app/views/RoomInfoView/index.js @@ -31,7 +31,6 @@ import SafeAreaView from '../../containers/SafeAreaView'; import { goRoom } from '../../utils/goRoom'; import Navigation from '../../lib/Navigation'; -const PERMISSION_EDIT_ROOM = 'edit-room'; const getRoomTitle = (room, type, name, username, statusText, theme) => (type === 'd' ? ( <> @@ -55,7 +54,8 @@ class RoomInfoView extends React.Component { rooms: PropTypes.array, theme: PropTypes.string, isMasterDetail: PropTypes.bool, - jitsiEnabled: PropTypes.bool + jitsiEnabled: PropTypes.bool, + editRoomPermission: PropTypes.array } constructor(props) { @@ -136,7 +136,7 @@ class RoomInfoView extends React.Component { getRoleDescription = async(id) => { const db = database.active; try { - const rolesCollection = db.collections.get('roles'); + const rolesCollection = db.get('roles'); const role = await rolesCollection.find(id); if (role) { return role.description; @@ -193,7 +193,7 @@ class RoomInfoView extends React.Component { loadRoom = async() => { const { room: roomState } = this.state; - const { route } = this.props; + const { route, editRoomPermission } = this.props; let room = route.params?.room; if (room && room.observe) { this.roomObservable = room.observe(); @@ -213,8 +213,8 @@ class RoomInfoView extends React.Component { } } - const permissions = await RocketChat.hasPermission([PERMISSION_EDIT_ROOM], room.rid); - if (permissions[PERMISSION_EDIT_ROOM] && !room.prid) { + const permissions = await RocketChat.hasPermission([editRoomPermission], room.rid); + if (permissions[0] && !room.prid) { this.setState({ showEdit: true }, () => this.setHeader()); } } @@ -276,7 +276,7 @@ class RoomInfoView extends React.Component { videoCall = () => { const { room } = this.state; - RocketChat.callJitsi(room.rid); + RocketChat.callJitsi(room); } renderAvatar = (room, roomUser) => { @@ -369,7 +369,8 @@ class RoomInfoView extends React.Component { const mapStateToProps = state => ({ rooms: state.room.rooms, isMasterDetail: state.app.isMasterDetail, - jitsiEnabled: state.settings.Jitsi_Enabled || false + jitsiEnabled: state.settings.Jitsi_Enabled || false, + editRoomPermission: state.permissions['edit-room'] }); export default connect(mapStateToProps)(withTheme(RoomInfoView)); diff --git a/app/views/RoomMembersView/index.js b/app/views/RoomMembersView/index.js index 269814669..4caa03381 100644 --- a/app/views/RoomMembersView/index.js +++ b/app/views/RoomMembersView/index.js @@ -1,8 +1,9 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { FlatList, View } from 'react-native'; +import { FlatList } from 'react-native'; import { connect } from 'react-redux'; import { Q } from '@nozbe/watermelondb'; +import * as List from '../../containers/List'; import styles from './styles'; import UserItem from '../../presentation/UserItem'; @@ -28,6 +29,12 @@ import { goRoom } from '../../utils/goRoom'; const PAGE_SIZE = 25; +const PERMISSION_MUTE_USER = 'mute-user'; +const PERMISSION_SET_LEADER = 'set-leader'; +const PERMISSION_SET_OWNER = 'set-owner'; +const PERMISSION_SET_MODERATOR = 'set-moderator'; +const PERMISSION_REMOVE_USER = 'remove-user'; + class RoomMembersView extends React.Component { static propTypes = { navigation: PropTypes.object, @@ -43,7 +50,12 @@ class RoomMembersView extends React.Component { showActionSheet: PropTypes.func, theme: PropTypes.string, isMasterDetail: PropTypes.bool, - useRealName: PropTypes.bool + useRealName: PropTypes.bool, + muteUserPermission: PropTypes.array, + setLeaderPermission: PropTypes.array, + setOwnerPermission: PropTypes.array, + setModeratorPermission: PropTypes.array, + removeUserPermission: PropTypes.array } constructor(props) { @@ -81,7 +93,20 @@ class RoomMembersView extends React.Component { this.fetchMembers(); const { room } = this.state; - this.permissions = await RocketChat.hasPermission(['mute-user', 'set-leader', 'set-owner', 'set-moderator', 'remove-user'], room.rid); + const { + muteUserPermission, setLeaderPermission, setOwnerPermission, setModeratorPermission, removeUserPermission + } = this.props; + const result = await RocketChat.hasPermission([ + muteUserPermission, setLeaderPermission, setOwnerPermission, setModeratorPermission, removeUserPermission + ], room.rid); + + this.permissions = { + [PERMISSION_MUTE_USER]: result[0], + [PERMISSION_SET_LEADER]: result[1], + [PERMISSION_SET_OWNER]: result[2], + [PERMISSION_SET_MODERATOR]: result[3], + [PERMISSION_REMOVE_USER]: result[4] + }; const hasSinglePermission = Object.values(this.permissions).some(p => !!p); if (hasSinglePermission) { @@ -122,7 +147,7 @@ class RoomMembersView extends React.Component { navToDirectMessage = async(item) => { try { const db = database.active; - const subsCollection = db.collections.get('subscriptions'); + const subsCollection = db.get('subscriptions'); const query = await subsCollection.query(Q.where('name', item.username)).fetch(); if (query.length) { const [room] = query; @@ -395,11 +420,6 @@ class RoomMembersView extends React.Component { this.onSearchChangeText(text)} testID='room-members-view-search' /> ) - renderSeparator = () => { - const { theme } = this.props; - return ; - } - renderItem = ({ item }) => { const { baseUrl, user, theme } = this.props; @@ -429,7 +449,7 @@ class RoomMembersView extends React.Component { renderItem={this.renderItem} style={[styles.list, { backgroundColor: themes[theme].backgroundColor }]} keyExtractor={item => item._id} - ItemSeparatorComponent={this.renderSeparator} + ItemSeparatorComponent={List.Separator} ListHeaderComponent={this.renderSearchBar} ListFooterComponent={() => { if (isLoading) { @@ -452,7 +472,12 @@ const mapStateToProps = state => ({ baseUrl: state.server.server, user: getUserSelector(state), isMasterDetail: state.app.isMasterDetail, - useRealName: state.settings.UI_Use_Real_Name + useRealName: state.settings.UI_Use_Real_Name, + muteUserPermission: state.permissions[PERMISSION_MUTE_USER], + setLeaderPermission: state.permissions[PERMISSION_SET_LEADER], + setOwnerPermission: state.permissions[PERMISSION_SET_OWNER], + setModeratorPermission: state.permissions[PERMISSION_SET_MODERATOR], + removeUserPermission: state.permissions[PERMISSION_REMOVE_USER] }); export default connect(mapStateToProps)(withActionSheet(withTheme(RoomMembersView))); diff --git a/app/views/RoomView/Header/Header.js b/app/views/RoomView/Header/Header.js index 637d57c58..410ca1bf5 100644 --- a/app/views/RoomView/Header/Header.js +++ b/app/views/RoomView/Header/Header.js @@ -168,7 +168,7 @@ const Header = React.memo(({ theme={theme} /> - + ); }); diff --git a/app/views/RoomView/Header/RightButtons.js b/app/views/RoomView/Header/RightButtons.js index 6580351c8..37939b1e3 100644 --- a/app/views/RoomView/Header/RightButtons.js +++ b/app/views/RoomView/Header/RightButtons.js @@ -1,7 +1,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; -import isEqual from 'react-fast-compare'; +import { dequal } from 'dequal'; import * as HeaderButton from '../../../containers/HeaderButton'; import database from '../../../lib/database'; @@ -35,7 +35,7 @@ class RightButtonsContainer extends Component { const db = database.active; if (tmid) { try { - const threadRecord = await db.collections.get('messages').find(tmid); + const threadRecord = await db.get('messages').find(tmid); this.observeThread(threadRecord); } catch (e) { console.log('Can\'t find message to observe.'); @@ -43,7 +43,7 @@ class RightButtonsContainer extends Component { } if (rid) { try { - const subCollection = db.collections.get('subscriptions'); + const subCollection = db.get('subscriptions'); const subRecord = await subCollection.find(rid); this.observeSubscription(subRecord); } catch (e) { @@ -59,15 +59,16 @@ class RightButtonsContainer extends Component { if (nextState.isFollowingThread !== isFollowingThread) { return true; } - if (!isEqual(nextState.tunread, tunread)) { + if (!dequal(nextState.tunread, tunread)) { return true; } - if (!isEqual(nextState.tunreadUser, tunreadUser)) { + if (!dequal(nextState.tunreadUser, tunreadUser)) { return true; } - if (!isEqual(nextState.tunreadGroup, tunreadGroup)) { + if (!dequal(nextState.tunreadGroup, tunreadGroup)) { return true; } + return false; } componentWillUnmount() { diff --git a/app/views/RoomView/Header/index.js b/app/views/RoomView/Header/index.js index 33663bbe4..05a5f2e12 100644 --- a/app/views/RoomView/Header/index.js +++ b/app/views/RoomView/Header/index.js @@ -1,7 +1,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; -import equal from 'deep-equal'; +import { dequal } from 'dequal'; import Header from './Header'; import LeftButtons from './LeftButtons'; @@ -65,7 +65,7 @@ class RoomHeaderView extends Component { if (nextProps.height !== height) { return true; } - if (!equal(nextProps.usersTyping, usersTyping)) { + if (!dequal(nextProps.usersTyping, usersTyping)) { return true; } if (nextProps.goRoomActionsView !== goRoomActionsView) { diff --git a/app/views/RoomView/List.js b/app/views/RoomView/List.js index 4db965d97..41d424fa3 100644 --- a/app/views/RoomView/List.js +++ b/app/views/RoomView/List.js @@ -3,7 +3,7 @@ import { FlatList, RefreshControl } from 'react-native'; import PropTypes from 'prop-types'; import { Q } from '@nozbe/watermelondb'; import moment from 'moment'; -import isEqual from 'lodash/isEqual'; +import { dequal } from 'dequal'; import styles from './styles'; import database from '../../lib/database'; @@ -89,13 +89,13 @@ class List extends React.Component { if (refreshing !== nextState.refreshing) { return true; } - if (!isEqual(hideSystemMessages, nextProps.hideSystemMessages)) { + if (!dequal(hideSystemMessages, nextProps.hideSystemMessages)) { return true; } - if (!isEqual(tunread, nextProps.tunread)) { + if (!dequal(tunread, nextProps.tunread)) { return true; } - if (!isEqual(ignored, nextProps.ignored)) { + if (!dequal(ignored, nextProps.ignored)) { return true; } return false; @@ -103,7 +103,7 @@ class List extends React.Component { componentDidUpdate(prevProps) { const { hideSystemMessages } = this.props; - if (!isEqual(hideSystemMessages, prevProps.hideSystemMessages)) { + if (!dequal(hideSystemMessages, prevProps.hideSystemMessages)) { this.reload(); } } diff --git a/app/views/RoomView/ReactionPicker.js b/app/views/RoomView/ReactionPicker.js index 556d18256..9e9c470f8 100644 --- a/app/views/RoomView/ReactionPicker.js +++ b/app/views/RoomView/ReactionPicker.js @@ -7,6 +7,8 @@ import Modal from 'react-native-modal'; import EmojiPicker from '../../containers/EmojiPicker'; import styles from './styles'; import { isAndroid } from '../../utils/deviceInfo'; +import { themes } from '../../constants/colors'; +import { withTheme } from '../../theme'; const margin = isAndroid ? 40 : 20; const maxSize = 400; @@ -20,7 +22,8 @@ class ReactionPicker extends React.Component { reactionClose: PropTypes.func, onEmojiSelected: PropTypes.func, width: PropTypes.number, - height: PropTypes.number + height: PropTypes.number, + theme: PropTypes.string }; shouldComponentUpdate(nextProps) { @@ -38,7 +41,7 @@ class ReactionPicker extends React.Component { render() { const { - width, height, show, baseUrl, reactionClose, isMasterDetail + width, height, show, baseUrl, reactionClose, isMasterDetail, theme } = this.props; let widthStyle = width - margin; @@ -58,6 +61,7 @@ class ReactionPicker extends React.Component { onBackButtonPress={reactionClose} animationIn='fadeIn' animationOut='fadeOut' + backdropOpacity={themes[theme].backdropOpacity} > ({ isMasterDetail: state.app.isMasterDetail }); -export default connect(mapStateToProps)(ReactionPicker); +export default connect(mapStateToProps)(withTheme(ReactionPicker)); diff --git a/app/views/RoomView/index.js b/app/views/RoomView/index.js index 38a39d979..2ee84ae25 100644 --- a/app/views/RoomView/index.js +++ b/app/views/RoomView/index.js @@ -7,7 +7,7 @@ import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord'; import moment from 'moment'; import * as Haptics from 'expo-haptics'; import { Q } from '@nozbe/watermelondb'; -import isEqual from 'lodash/isEqual'; +import { dequal } from 'dequal'; import { withSafeAreaInsets } from 'react-native-safe-area-context'; import Touch from '../../utils/touch'; @@ -155,7 +155,9 @@ class RoomView extends React.Component { this.list = React.createRef(); this.joinCode = React.createRef(); this.mounted = false; - if (this.rid) { + + // we don't need to subscribe to threads + if (this.rid && !this.tmid) { this.sub = new RoomClass(this.rid); } console.timeEnd(`${ this.constructor.name } init`); @@ -168,7 +170,7 @@ class RoomView extends React.Component { const { isAuthenticated } = this.props; this.setHeader(); if (this.rid) { - this.sub.subscribe(); + this.sub?.subscribe?.(); if (isAuthenticated) { this.init(); } else { @@ -203,10 +205,10 @@ class RoomView extends React.Component { if (stateUpdated) { return true; } - if (!isEqual(nextProps.insets, insets)) { + if (!dequal(nextProps.insets, insets)) { return true; } - return roomAttrsUpdate.some(key => !isEqual(nextState.roomUpdate[key], roomUpdate[key])); + return roomAttrsUpdate.some(key => !dequal(nextState.roomUpdate[key], roomUpdate[key])); } componentDidUpdate(prevProps, prevState) { @@ -227,7 +229,7 @@ class RoomView extends React.Component { } // If it's a livechat room if (this.t === 'l') { - if (!isEqual(prevState.roomUpdate.visitor, roomUpdate.visitor)) { + if (!dequal(prevState.roomUpdate.visitor, roomUpdate.visitor)) { this.setHeader(); } } @@ -249,7 +251,7 @@ class RoomView extends React.Component { let obj; if (this.tmid) { try { - const threadsCollection = db.collections.get('threads'); + const threadsCollection = db.get('threads'); obj = await threadsCollection.find(this.tmid); } catch (e) { // Do nothing @@ -398,7 +400,7 @@ class RoomView extends React.Component { const db = database.active; try { - const subCollection = db.collections.get('subscriptions'); + const subCollection = db.get('subscriptions'); const sub = await subCollection.find(this.rid); const { room } = await RocketChat.getRoomInfo(this.rid); @@ -434,10 +436,7 @@ class RoomView extends React.Component { } } - // We run `canAutoTranslate` again in order to refetch auto translate permission - // in case of a missing connection or poor connection on room open - const canAutoTranslate = await RocketChat.canAutoTranslate(); - + const canAutoTranslate = RocketChat.canAutoTranslate(); const member = await this.getRoomMember(); this.setState({ canAutoTranslate, member, loading: false }); @@ -476,7 +475,7 @@ class RoomView extends React.Component { findAndObserveRoom = async(rid) => { try { const db = database.active; - const subCollection = await db.collections.get('subscriptions'); + const subCollection = await db.get('subscriptions'); const room = await subCollection.find(rid); this.setState({ room }); if (!this.tmid) { @@ -531,7 +530,14 @@ class RoomView extends React.Component { } onEditInit = (message) => { - this.setState({ selectedMessage: message, editing: true }); + const newMessage = { + id: message.id, + subscription: { + id: message.subscription.id + }, + msg: message?.attachments?.[0]?.description || message.msg + }; + this.setState({ selectedMessage: newMessage, editing: true }); } onEditCancel = () => { @@ -744,8 +750,8 @@ class RoomView extends React.Component { fetchThreadName = async(tmid, messageId) => { try { const db = database.active; - const threadCollection = db.collections.get('threads'); - const messageCollection = db.collections.get('messages'); + const threadCollection = db.get('threads'); + const messageCollection = db.get('messages'); const messageRecord = await messageCollection.find(messageId); let threadRecord; try { @@ -815,7 +821,7 @@ class RoomView extends React.Component { if (jitsiTimeout < Date.now()) { showErrorAlert(I18n.t('Call_already_ended')); } else { - RocketChat.callJitsi(this.rid); + RocketChat.callJitsi(room); } }; @@ -1082,6 +1088,7 @@ class RoomView extends React.Component { reactionClose={this.onReactionClose} width={width} height={height} + theme={theme} /> { - const { theme } = this.props; - return ; - } - renderServer = ({ item }) => { const { server, theme } = this.props; @@ -225,7 +202,7 @@ class ServerDropdown extends Component { }); const backdropOpacity = this.animatedValue.interpolate({ inputRange: [0, 1], - outputRange: [0, 0.6] + outputRange: [0, themes[theme].backdropOpacity] }); return ( <> @@ -266,7 +243,7 @@ class ServerDropdown extends Component { data={servers} keyExtractor={item => item.id} renderItem={this.renderServer} - ItemSeparatorComponent={this.renderSeparator} + ItemSeparatorComponent={List.Separator} keyboardShouldPersistTaps='always' /> diff --git a/app/views/RoomsListView/SortDropdown/index.js b/app/views/RoomsListView/SortDropdown/index.js index cb85edcd5..06a398a82 100644 --- a/app/views/RoomsListView/SortDropdown/index.js +++ b/app/views/RoomsListView/SortDropdown/index.js @@ -124,13 +124,13 @@ class Sort extends PureComponent { inputRange: [0, 1], outputRange: [-326, heightDestination] }); - const backdropOpacity = this.animatedValue.interpolate({ - inputRange: [0, 1], - outputRange: [0, 0.3] - }); const { sortBy, groupByType, showFavorites, showUnread, theme } = this.props; + const backdropOpacity = this.animatedValue.interpolate({ + inputRange: [0, 1], + outputRange: [0, themes[theme].backdropOpacity] + }); return ( <> diff --git a/app/views/RoomsListView/index.js b/app/views/RoomsListView/index.js index 6ec23f29c..996847c91 100644 --- a/app/views/RoomsListView/index.js +++ b/app/views/RoomsListView/index.js @@ -9,7 +9,7 @@ import { RefreshControl } from 'react-native'; import { connect } from 'react-redux'; -import isEqual from 'react-fast-compare'; +import { dequal } from 'dequal'; import Orientation from 'react-native-orientation-locker'; import { Q } from '@nozbe/watermelondb'; import { withSafeAreaInsets } from 'react-native-safe-area-context'; @@ -89,7 +89,6 @@ const shouldUpdateProps = [ 'showUnread', 'useRealName', 'StoreLastMessage', - 'appState', 'theme', 'isMasterDetail', 'refreshing', @@ -126,7 +125,6 @@ class RoomsListView extends React.Component { showUnread: PropTypes.bool, refreshing: PropTypes.bool, StoreLastMessage: PropTypes.bool, - appState: PropTypes.string, theme: PropTypes.string, toggleSortDropdown: PropTypes.func, openSearchHeader: PropTypes.func, @@ -135,7 +133,6 @@ class RoomsListView extends React.Component { roomsRequest: PropTypes.func, closeServerDropdown: PropTypes.func, useRealName: PropTypes.bool, - connected: PropTypes.bool, isMasterDetail: PropTypes.bool, rooms: PropTypes.array, width: PropTypes.number, @@ -222,7 +219,7 @@ class RoomsListView extends React.Component { } // Compare changes only once - const chatsNotEqual = !isEqual(nextState.chatsUpdate, chatsUpdate); + const chatsNotEqual = !dequal(nextState.chatsUpdate, chatsUpdate); // If they aren't equal, set to update if focused if (chatsNotEqual) { @@ -253,13 +250,13 @@ class RoomsListView extends React.Component { if (nextProps.width !== width) { return true; } - if (!isEqual(nextState.search, search)) { + if (!dequal(nextState.search, search)) { return true; } - if (!isEqual(nextProps.rooms, rooms)) { + if (!dequal(nextProps.rooms, rooms)) { return true; } - if (!isEqual(nextProps.insets, insets)) { + if (!dequal(nextProps.insets, insets)) { return true; } // If it's focused and there are changes, update @@ -276,9 +273,6 @@ class RoomsListView extends React.Component { groupByType, showFavorites, showUnread, - appState, - connected, - roomsRequest, rooms, isMasterDetail, insets @@ -294,15 +288,9 @@ class RoomsListView extends React.Component { ) ) { this.getSubscriptions(); - } else if ( - appState === 'foreground' - && appState !== prevProps.appState - && connected - ) { - roomsRequest(); } // Update current item in case of another action triggers an update on rooms reducer - if (isMasterDetail && item?.rid !== rooms[0] && !isEqual(rooms, prevProps.rooms)) { + if (isMasterDetail && item?.rid !== rooms[0] && !dequal(rooms, prevProps.rooms)) { // eslint-disable-next-line react/no-did-update-set-state this.setState({ item: { rid: rooms[0] } }); } @@ -319,6 +307,9 @@ class RoomsListView extends React.Component { if (this.unsubscribeBlur) { this.unsubscribeBlur(); } + if (this.backHandler && this.backHandler.remove) { + this.backHandler.remove(); + } if (isTablet) { EventEmitter.removeListener(KEY_COMMAND, this.handleCommands); } @@ -620,7 +611,7 @@ class RoomsListView extends React.Component { const db = database.active; const result = await RocketChat.toggleFavorite(rid, !favorite); if (result.success) { - const subCollection = db.collections.get('subscriptions'); + const subCollection = db.get('subscriptions'); await db.action(async() => { try { const subRecord = await subCollection.find(rid); @@ -644,7 +635,7 @@ class RoomsListView extends React.Component { const db = database.active; const result = await RocketChat.toggleRead(isRead, rid); if (result.success) { - const subCollection = db.collections.get('subscriptions'); + const subCollection = db.get('subscriptions'); await db.action(async() => { try { const subRecord = await subCollection.find(rid); @@ -668,7 +659,7 @@ class RoomsListView extends React.Component { const db = database.active; const result = await RocketChat.hideRoom(rid, type); if (result.success) { - const subCollection = db.collections.get('subscriptions'); + const subCollection = db.get('subscriptions'); await db.action(async() => { try { const subRecord = await subCollection.find(rid); @@ -1018,7 +1009,6 @@ const mapStateToProps = state => ({ isMasterDetail: state.app.isMasterDetail, server: state.server.server, changingServer: state.server.changingServer, - connected: state.server.connected, searchText: state.rooms.searchText, loadingServer: state.server.loading, showServerDropdown: state.rooms.showServerDropdown, @@ -1029,7 +1019,6 @@ const mapStateToProps = state => ({ showFavorites: state.sortPreferences.showFavorites, showUnread: state.sortPreferences.showUnread, useRealName: state.settings.UI_Use_Real_Name, - appState: state.app.ready && state.app.foreground ? 'foreground' : 'background', StoreLastMessage: state.settings.Store_Last_Message, rooms: state.room.rooms, queueSize: getInquiryQueueSelector(state).length, diff --git a/app/views/ScreenLockConfigView.js b/app/views/ScreenLockConfigView.js index bf0f6a15c..294a854a6 100644 --- a/app/views/ScreenLockConfigView.js +++ b/app/views/ScreenLockConfigView.js @@ -71,7 +71,7 @@ class ScreenLockConfigView extends React.Component { init = async() => { const { server } = this.props; const serversDB = database.servers; - const serversCollection = serversDB.collections.get('servers'); + const serversCollection = serversDB.get('servers'); try { this.serverRecord = await serversCollection.find(server); this.setState({ diff --git a/app/views/ScreenLockedView.js b/app/views/ScreenLockedView.js index 883584056..2b036779c 100644 --- a/app/views/ScreenLockedView.js +++ b/app/views/ScreenLockedView.js @@ -31,12 +31,12 @@ const ScreenLockedView = ({ theme }) => { if (!isTablet) { Orientation.lockToPortrait(); } - EventEmitter.addEventListener(LOCAL_AUTHENTICATE_EMITTER, showScreenLock); + const listener = EventEmitter.addEventListener(LOCAL_AUTHENTICATE_EMITTER, showScreenLock); return (() => { if (!isTablet) { Orientation.unlockAllOrientations(); } - EventEmitter.removeListener(LOCAL_AUTHENTICATE_EMITTER); + EventEmitter.removeListener(LOCAL_AUTHENTICATE_EMITTER, listener); }); }, []); diff --git a/app/views/SearchMessagesView/index.js b/app/views/SearchMessagesView/index.js index 18380e55f..e11a5b83d 100644 --- a/app/views/SearchMessagesView/index.js +++ b/app/views/SearchMessagesView/index.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import { View, FlatList, Text } from 'react-native'; import { Q } from '@nozbe/watermelondb'; import { connect } from 'react-redux'; -import equal from 'deep-equal'; +import { dequal } from 'dequal'; import RCTextInput from '../../containers/TextInput'; import ActivityIndicator from '../../containers/ActivityIndicator'; @@ -42,7 +42,8 @@ class SearchMessagesView extends React.Component { user: PropTypes.object, baseUrl: PropTypes.string, customEmojis: PropTypes.object, - theme: PropTypes.string + theme: PropTypes.string, + useRealName: PropTypes.bool } constructor(props) { @@ -68,7 +69,7 @@ class SearchMessagesView extends React.Component { if (nextState.searchText !== searchText) { return true; } - if (!equal(nextState.messages, messages)) { + if (!dequal(nextState.messages, messages)) { return true; } return false; @@ -83,7 +84,7 @@ class SearchMessagesView extends React.Component { // If it's a encrypted, room we'll search only on the local stored messages if (this.encrypted) { const db = database.active; - const messagesCollection = db.collections.get('messages'); + const messagesCollection = db.get('messages'); const likeString = sanitizeLikeString(searchText); return messagesCollection .query( @@ -143,7 +144,9 @@ class SearchMessagesView extends React.Component { } renderItem = ({ item }) => { - const { user, baseUrl, theme } = this.props; + const { + user, baseUrl, theme, useRealName + } = this.props; return ( {}} getCustomEmoji={this.getCustomEmoji} navToRoomInfo={this.navToRoomInfo} + useRealName={useRealName} theme={theme} /> ); @@ -206,6 +210,7 @@ class SearchMessagesView extends React.Component { const mapStateToProps = state => ({ baseUrl: state.server.server, user: getUserSelector(state), + useRealName: state.settings.UI_Use_Real_Name, customEmojis: state.customEmojis }); diff --git a/app/views/SelectServerView.js b/app/views/SelectServerView.js index e04c05247..b3345c820 100644 --- a/app/views/SelectServerView.js +++ b/app/views/SelectServerView.js @@ -29,7 +29,7 @@ class SelectServerView extends React.Component { async componentDidMount() { const serversDB = database.servers; - const serversCollection = serversDB.collections.get('servers'); + const serversCollection = serversDB.get('servers'); const servers = await serversCollection.query(Q.where('rooms_updated_at', Q.notEq(null))).fetch(); this.setState({ servers }); } diff --git a/app/views/SelectedUsersView.js b/app/views/SelectedUsersView.js index 666cee3d1..f9d14e169 100644 --- a/app/views/SelectedUsersView.js +++ b/app/views/SelectedUsersView.js @@ -1,10 +1,10 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { View, StyleSheet, FlatList } from 'react-native'; +import { View, FlatList } from 'react-native'; import { connect } from 'react-redux'; -import equal from 'deep-equal'; import orderBy from 'lodash/orderBy'; import { Q } from '@nozbe/watermelondb'; +import * as List from '../containers/List'; import database from '../lib/database'; import RocketChat from '../lib/rocketchat'; @@ -28,12 +28,6 @@ import { import { showErrorAlert } from '../utils/info'; import SafeAreaView from '../containers/SafeAreaView'; -const styles = StyleSheet.create({ - separator: { - marginLeft: 60 - } -}); - class SelectedUsersView extends React.Component { static propTypes = { baseUrl: PropTypes.string, @@ -70,27 +64,6 @@ class SelectedUsersView extends React.Component { this.setHeader(props.route.params?.showButton); } - shouldComponentUpdate(nextProps, nextState) { - const { search, chats } = this.state; - const { users, loading, theme } = this.props; - if (nextProps.theme !== theme) { - return true; - } - if (nextProps.loading !== loading) { - return true; - } - if (!equal(nextProps.users, users)) { - return true; - } - if (!equal(nextState.search, search)) { - return true; - } - if (!equal(nextState.chats, chats)) { - return true; - } - return false; - } - componentDidUpdate(prevProps) { if (this.isGroupChat()) { const { users } = this.props; @@ -247,11 +220,6 @@ class SelectedUsersView extends React.Component { ); } - renderSeparator = () => { - const { theme } = this.props; - return ; - } - renderItem = ({ item, index }) => { const { search, chats } = this.state; const { baseUrl, user, theme } = this.props; @@ -297,7 +265,7 @@ class SelectedUsersView extends React.Component { extraData={this.props} keyExtractor={item => item._id} renderItem={this.renderItem} - ItemSeparatorComponent={this.renderSeparator} + ItemSeparatorComponent={List.Separator} ListHeaderComponent={this.renderHeader} contentContainerStyle={{ backgroundColor: themes[theme].backgroundColor }} enableEmptySections diff --git a/app/views/SettingsView/index.js b/app/views/SettingsView/index.js index bc11da7b7..b67c7f1ea 100644 --- a/app/views/SettingsView/index.js +++ b/app/views/SettingsView/index.js @@ -62,7 +62,7 @@ class SettingsView extends React.Component { checkCookiesAndLogout = async() => { const { logout, user } = this.props; const db = database.servers; - const usersCollection = db.collections.get('users'); + const usersCollection = db.get('users'); try { const userRecord = await usersCollection.find(user.id); if (!userRecord.loginEmailPassword) { diff --git a/app/views/ShareListView/index.js b/app/views/ShareListView/index.js index aa8cf7f6d..38f3aff72 100644 --- a/app/views/ShareListView/index.js +++ b/app/views/ShareListView/index.js @@ -7,7 +7,7 @@ import ShareExtension from 'rn-extensions-share'; import * as FileSystem from 'expo-file-system'; import { connect } from 'react-redux'; import * as mime from 'react-native-mime-types'; -import isEqual from 'react-fast-compare'; +import { dequal } from 'dequal'; import { Q } from '@nozbe/watermelondb'; import database from '../../lib/database'; @@ -118,7 +118,7 @@ class ShareListView extends React.Component { const { searchResults } = this.state; if (nextState.searching) { - if (!isEqual(nextState.searchResults, searchResults)) { + if (!dequal(nextState.searchResults, searchResults)) { return true; } } @@ -206,7 +206,7 @@ class ShareListView extends React.Component { ) ); } - const data = await db.collections.get('subscriptions').query(...defaultWhereClause).fetch(); + const data = await db.get('subscriptions').query(...defaultWhereClause).fetch(); return data.map(item => ({ rid: item.rid, t: item.t, @@ -226,7 +226,7 @@ class ShareListView extends React.Component { if (server) { const chats = await this.query(); - const serversCollection = serversDB.collections.get('servers'); + const serversCollection = serversDB.get('servers'); const serversCount = await serversCollection.query(Q.where('rooms_updated_at', Q.notEq(null))).fetchCount(); let serverInfo = {}; try { diff --git a/app/views/ShareView/Thumbs.js b/app/views/ShareView/Thumbs.js index 0ce0d7373..26bc54fb4 100644 --- a/app/views/ShareView/Thumbs.js +++ b/app/views/ShareView/Thumbs.js @@ -179,6 +179,7 @@ const Thumbs = React.memo(({ /> ); } + return null; }); Thumbs.propTypes = { attachments: PropTypes.array, diff --git a/app/views/ShareView/index.js b/app/views/ShareView/index.js index 03ea45724..765860036 100644 --- a/app/views/ShareView/index.js +++ b/app/views/ShareView/index.js @@ -95,7 +95,7 @@ class ShareView extends Component { getServerInfo = async() => { const { server } = this.props; const serversDB = database.servers; - const serversCollection = serversDB.collections.get('servers'); + const serversCollection = serversDB.get('servers'); try { this.serverInfo = await serversCollection.find(server); } catch (error) { @@ -235,7 +235,9 @@ class ShareView extends Component { newSelected = attachments[selectedIndex - 1] || {}; } } - this.setState({ attachments: attachments.filter(att => att.path !== item.path), selected: newSelected ?? selected }); + this.setState({ attachments: attachments.filter(att => att.path !== item.path), selected: newSelected ?? selected }, () => { + this.messagebox?.current?.forceUpdate?.(); + }); } onChangeText = (text) => { diff --git a/app/views/SidebarView/index.js b/app/views/SidebarView/index.js index 9dd63b8dc..a14b178cd 100644 --- a/app/views/SidebarView/index.js +++ b/app/views/SidebarView/index.js @@ -4,19 +4,16 @@ import { ScrollView, Text, View, TouchableWithoutFeedback } from 'react-native'; import { connect } from 'react-redux'; -import { Q } from '@nozbe/watermelondb'; -import isEqual from 'react-fast-compare'; - +import { dequal } from 'dequal'; import Avatar from '../../containers/Avatar'; import Status from '../../containers/Status/Status'; -import log, { logEvent, events } from '../../utils/log'; +import { logEvent, events } from '../../utils/log'; import I18n from '../../i18n'; import scrollPersistTaps from '../../utils/scrollPersistTaps'; import { CustomIcon } from '../../lib/Icons'; import styles from './styles'; import SidebarItem from './SidebarItem'; import { themes } from '../../constants/colors'; -import database from '../../lib/database'; import { withTheme } from '../../theme'; import { getUserSelector } from '../../selectors/login'; import SafeAreaView from '../../containers/SafeAreaView'; @@ -27,13 +24,6 @@ Separator.propTypes = { theme: PropTypes.string }; -const permissions = [ - 'view-statistics', - 'view-room-administration', - 'view-user-administration', - 'view-privileged-setting' -]; - class Sidebar extends Component { static propTypes = { baseUrl: PropTypes.string, @@ -45,32 +35,24 @@ class Sidebar extends Component { loadingServer: PropTypes.bool, useRealName: PropTypes.bool, allowStatusMessage: PropTypes.bool, - isMasterDetail: PropTypes.bool + isMasterDetail: PropTypes.bool, + viewStatisticsPermission: PropTypes.object, + viewRoomAdministrationPermission: PropTypes.object, + viewUserAdministrationPermission: PropTypes.object, + viewPrivilegedSettingPermission: PropTypes.object } constructor(props) { super(props); this.state = { - showStatus: false, - isAdmin: false + showStatus: false }; } - componentDidMount() { - this.setIsAdmin(); - } - - UNSAFE_componentWillReceiveProps(nextProps) { - const { loadingServer } = this.props; - if (loadingServer && nextProps.loadingServer !== loadingServer) { - this.setIsAdmin(); - } - } - shouldComponentUpdate(nextProps, nextState) { const { showStatus, isAdmin } = this.state; const { - Site_Name, user, baseUrl, state, isMasterDetail, useRealName, theme + Site_Name, user, baseUrl, state, isMasterDetail, useRealName, theme, viewStatisticsPermission, viewRoomAdministrationPermission, viewUserAdministrationPermission, viewPrivilegedSettingPermission } = this.props; // Drawer navigation state if (state?.index !== nextProps.state?.index) { @@ -91,7 +73,7 @@ class Sidebar extends Component { if (nextProps.theme !== theme) { return true; } - if (!isEqual(nextProps.user, user)) { + if (!dequal(nextProps.user, user)) { return true; } if (nextProps.isMasterDetail !== isMasterDetail) { @@ -103,25 +85,42 @@ class Sidebar extends Component { if (nextState.isAdmin !== isAdmin) { return true; } + if (!dequal(nextProps.viewStatisticsPermission, viewStatisticsPermission)) { + return true; + } + if (!dequal(nextProps.viewRoomAdministrationPermission, viewRoomAdministrationPermission)) { + return true; + } + if (!dequal(nextProps.viewUserAdministrationPermission, viewUserAdministrationPermission)) { + return true; + } + if (!dequal(nextProps.viewPrivilegedSettingPermission, viewPrivilegedSettingPermission)) { + return true; + } return false; } - async setIsAdmin() { - const db = database.active; - const { user } = this.props; + + getIsAdmin() { + const { + user, viewStatisticsPermission, viewRoomAdministrationPermission, viewUserAdministrationPermission, viewPrivilegedSettingPermission + } = this.props; const { roles } = user; - try { - if (roles) { - const permissionsCollection = db.collections.get('permissions'); - const permissionsFiltered = await permissionsCollection.query(Q.where('id', Q.oneOf(permissions))).fetch(); - const isAdmin = permissionsFiltered.reduce((result, permission) => ( - result || permission.roles.some(r => roles.indexOf(r) !== -1)), - false); - this.setState({ isAdmin }); - } - } catch (e) { - log(e); + const allPermissions = [viewStatisticsPermission, viewRoomAdministrationPermission, viewUserAdministrationPermission, viewPrivilegedSettingPermission]; + let isAdmin = false; + + if (roles) { + isAdmin = allPermissions.reduce((result, permission) => { + if (permission) { + return ( + result || permission.some(r => roles.indexOf(r) !== -1) + ); + } + return result; + }, + false); } + return isAdmin; } sidebarNavigate = (route) => { @@ -143,9 +142,8 @@ class Sidebar extends Component { } renderAdmin = () => { - const { isAdmin } = this.state; const { theme, isMasterDetail } = this.props; - if (!isAdmin) { + if (!this.getIsAdmin()) { return null; } const routeName = isMasterDetail ? 'AdminPanelView' : 'AdminPanelStackNavigator'; @@ -275,7 +273,11 @@ const mapStateToProps = state => ({ loadingServer: state.server.loading, useRealName: state.settings.UI_Use_Real_Name, allowStatusMessage: state.settings.Accounts_AllowUserStatusMessageChange, - isMasterDetail: state.app.isMasterDetail + isMasterDetail: state.app.isMasterDetail, + viewStatisticsPermission: state.permissions['view-statistics'], + viewRoomAdministrationPermission: state.permissions['view-room-administration'], + viewUserAdministrationPermission: state.permissions['view-user-administration'], + viewPrivilegedSettingPermission: state.permissions['view-privileged-setting'] }); export default connect(mapStateToProps)(withTheme(Sidebar)); diff --git a/app/views/ThreadMessagesView/Dropdown/index.js b/app/views/ThreadMessagesView/Dropdown/index.js index 49533e4be..fdf1acba7 100644 --- a/app/views/ThreadMessagesView/Dropdown/index.js +++ b/app/views/ThreadMessagesView/Dropdown/index.js @@ -68,7 +68,7 @@ class Dropdown extends React.Component { }); const backdropOpacity = this.animatedValue.interpolate({ inputRange: [0, 1], - outputRange: [0, 0.3] + outputRange: [0, themes[theme].backdropOpacity] }); return ( <> diff --git a/app/views/ThreadMessagesView/index.js b/app/views/ThreadMessagesView/index.js index d75328a99..417c10328 100644 --- a/app/views/ThreadMessagesView/index.js +++ b/app/views/ThreadMessagesView/index.js @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { FlatList, InteractionManager } from 'react-native'; +import { FlatList } from 'react-native'; import { connect } from 'react-redux'; import { Q } from '@nozbe/watermelondb'; import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord'; @@ -73,9 +73,7 @@ class ThreadMessagesView extends React.Component { componentDidMount() { this.mounted = true; - this.mountInteraction = InteractionManager.runAfterInteractions(() => { - this.init(); - }); + this.init(); } componentDidUpdate(prevProps) { @@ -89,12 +87,6 @@ class ThreadMessagesView extends React.Component { componentWillUnmount() { console.countReset(`${ this.constructor.name }.render calls`); - if (this.mountInteraction && this.mountInteraction.cancel) { - this.mountInteraction.cancel(); - } - if (this.syncInteraction && this.syncInteraction.cancel) { - this.syncInteraction.cancel(); - } if (this.subSubscription && this.subSubscription.unsubscribe) { this.subSubscription.unsubscribe(); } @@ -249,7 +241,7 @@ class ThreadMessagesView extends React.Component { try { const db = database.active; - const threadsCollection = db.collections.get('threads'); + const threadsCollection = db.get('threads'); const allThreadsRecords = await subscription.threads.fetch(); let threadsToCreate = []; let threadsToUpdate = []; @@ -330,10 +322,8 @@ class ThreadMessagesView extends React.Component { rid: this.rid, updatedSince: updatedSince.toISOString() }); if (result.success && result.threads) { - this.syncInteraction = InteractionManager.runAfterInteractions(() => { - const { update, remove } = result.threads; - this.updateThreads({ update, remove, lastThreadSync: updatedSince }); - }); + const { update, remove } = result.threads; + this.updateThreads({ update, remove, lastThreadSync: updatedSince }); } this.setState({ loading: false diff --git a/ios/NotificationService/Info.plist b/ios/NotificationService/Info.plist index d2f1244d4..9d9595029 100644 --- a/ios/NotificationService/Info.plist +++ b/ios/NotificationService/Info.plist @@ -4,6 +4,8 @@ AppGroup group.ios.chat.rocket + IS_OFFICIAL + CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName diff --git a/ios/ReplyNotification.swift b/ios/ReplyNotification.swift index 87b8cc439..771a1056d 100644 --- a/ios/ReplyNotification.swift +++ b/ios/ReplyNotification.swift @@ -48,6 +48,9 @@ class ReplyNotification: RNNotificationEventHandler { } } } + } else { + let body = RNNotificationParser.parseNotificationResponse(response) + RNEventEmitter.sendEvent(RNNotificationOpened, body: body) } } } diff --git a/ios/RocketChatRN-Bridging-Header.h b/ios/RocketChatRN-Bridging-Header.h index 0c1ed67a4..142bd0845 100644 --- a/ios/RocketChatRN-Bridging-Header.h +++ b/ios/RocketChatRN-Bridging-Header.h @@ -7,6 +7,8 @@ #import #import #import +#import +#import #import #import #import diff --git a/ios/RocketChatRN.xcodeproj/project.pbxproj b/ios/RocketChatRN.xcodeproj/project.pbxproj index 4d8a2f561..af7653b82 100644 --- a/ios/RocketChatRN.xcodeproj/project.pbxproj +++ b/ios/RocketChatRN.xcodeproj/project.pbxproj @@ -1477,7 +1477,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = chat.rocket.reactnative; PRODUCT_NAME = "Rocket.Chat Experimental"; - PROVISIONING_PROFILE_SPECIFIER = "match Development chat.rocket.reactnative"; + PROVISIONING_PROFILE_SPECIFIER = "match Development chat.rocket.reactnative 1614015157"; SWIFT_OBJC_BRIDGING_HEADER = "RocketChatRN-Bridging-Header.h"; SWIFT_OBJC_INTERFACE_HEADER_NAME = "RocketChatRN-Swift.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -1582,7 +1582,7 @@ "$(inherited)", "$(SRCROOT)/../node_modules/rn-extensions-share/ios/**", "$(SRCROOT)/../node_modules/react-native-firebase/ios/RNFirebase/**", - "$PODS_CONFIGURATION_BUILD_DIR/Firebase", + $PODS_CONFIGURATION_BUILD_DIR/Firebase, ); INFOPLIST_FILE = ShareRocketChatRN/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 11.0; @@ -1599,7 +1599,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = chat.rocket.reactnative.ShareExtension; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "match Development chat.rocket.reactnative.ShareExtension"; + PROVISIONING_PROFILE_SPECIFIER = "match Development chat.rocket.reactnative.ShareExtension 1614015146"; SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -1648,7 +1648,7 @@ "$(inherited)", "$(SRCROOT)/../node_modules/rn-extensions-share/ios/**", "$(SRCROOT)/../node_modules/react-native-firebase/ios/RNFirebase/**", - "$PODS_CONFIGURATION_BUILD_DIR/Firebase", + $PODS_CONFIGURATION_BUILD_DIR/Firebase, ); INFOPLIST_FILE = ShareRocketChatRN/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 11.0; @@ -1664,7 +1664,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = chat.rocket.reactnative.ShareExtension; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "chat.rocket.reactnative.ShareExtension AppStore"; + PROVISIONING_PROFILE_SPECIFIER = "match AppStore chat.rocket.reactnative.ShareExtension"; SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -1691,12 +1691,12 @@ INFOPLIST_FILE = NotificationService/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 4.14.1; + MARKETING_VERSION = 4.15.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = chat.rocket.reactnative.NotificationService; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "match Development chat.rocket.reactnative.NotificationService"; + PROVISIONING_PROFILE_SPECIFIER = "match Development chat.rocket.reactnative.NotificationService 1614015134"; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OBJC_BRIDGING_HEADER = "NotificationService/NotificationService-Bridging-Header.h"; @@ -1728,11 +1728,11 @@ INFOPLIST_FILE = NotificationService/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 4.14.1; + MARKETING_VERSION = 4.15.0; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = chat.rocket.reactnative.NotificationService; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "chat.rocket.reactnative.NotificationService AppStore"; + PROVISIONING_PROFILE_SPECIFIER = "match AppStore chat.rocket.reactnative.NotificationService"; SKIP_INSTALL = YES; SWIFT_OBJC_BRIDGING_HEADER = "NotificationService/NotificationService-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-O"; diff --git a/ios/RocketChatRN/Info.plist b/ios/RocketChatRN/Info.plist index b6b497f45..ada5fc6c0 100644 --- a/ios/RocketChatRN/Info.plist +++ b/ios/RocketChatRN/Info.plist @@ -23,7 +23,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 4.14.1 + 4.15.0 CFBundleSignature ???? CFBundleURLTypes diff --git a/ios/ShareRocketChatRN/Info.plist b/ios/ShareRocketChatRN/Info.plist index 77e3c4e75..d545207a6 100644 --- a/ios/ShareRocketChatRN/Info.plist +++ b/ios/ShareRocketChatRN/Info.plist @@ -4,6 +4,8 @@ AppGroup group.ios.chat.rocket + IS_OFFICIAL + CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName @@ -19,7 +21,7 @@ CFBundlePackageType XPC! CFBundleShortVersionString - 4.14.1 + 4.15.0 CFBundleVersion 1 KeychainGroup diff --git a/package.json b/package.json index 71bfdbc1e..901e70955 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rocket-chat-reactnative", - "version": "0.0.1", + "version": "4.15.0", "private": true, "scripts": { "start": "react-native start", @@ -50,7 +50,7 @@ "bytebuffer": "^5.0.1", "commonmark": "git+https://github.com/RocketChat/commonmark.js.git", "commonmark-react-renderer": "git+https://github.com/RocketChat/commonmark-react-renderer.git", - "deep-equal": "2.0.3", + "dequal": "^2.0.2", "ejson": "2.2.0", "eslint-config-airbnb": "^18.1.0", "expo-apple-authentication": "^2.2.1", @@ -70,7 +70,6 @@ "pretty-bytes": "^5.3.0", "prop-types": "15.7.2", "react": "16.13.1", - "react-fast-compare": "^3.2.0", "react-native": "RocketChat/react-native#0.63.4", "react-native-animatable": "^1.3.3", "react-native-appearance": "0.3.4", @@ -121,7 +120,7 @@ "reselect": "4.0.0", "rn-extensions-share": "RocketChat/rn-extensions-share", "rn-fetch-blob": "0.12.0", - "rn-root-view": "^1.0.3", + "rn-root-view": "1.0.3", "semver": "7.3.2", "ua-parser-js": "^0.7.21", "url-parse": "^1.4.7", @@ -130,6 +129,8 @@ }, "devDependencies": { "@babel/core": "^7.8.4", + "@babel/eslint-parser": "^7.13.4", + "@babel/eslint-plugin": "^7.13.0", "@babel/plugin-proposal-decorators": "^7.8.3", "@babel/runtime": "^7.8.4", "@storybook/addon-storyshots": "5.3.19", @@ -137,7 +138,6 @@ "@types/react-native": "^0.62.7", "axios": "^0.19.2", "babel-core": "^6.26.3", - "babel-eslint": "^9.0.0", "babel-jest": "^25.1.0", "babel-plugin-transform-remove-console": "^6.9.4", "babel-runtime": "^6.26.0", diff --git a/patches/react-native-webview+10.3.2.patch b/patches/react-native-webview+10.3.2.patch index 68412ee27..08b0e9721 100644 --- a/patches/react-native-webview+10.3.2.patch +++ b/patches/react-native-webview+10.3.2.patch @@ -1,5 +1,5 @@ diff --git a/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java b/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java -index ab869cf..2aa7a9e 100644 +index ab869cf..08ce7ce 100644 --- a/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java +++ b/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java @@ -84,6 +84,12 @@ import java.util.Map; @@ -44,7 +44,7 @@ index ab869cf..2aa7a9e 100644 } @Override -@@ -742,12 +754,54 @@ public class RNCWebViewManager extends SimpleViewManager { +@@ -742,12 +754,56 @@ public class RNCWebViewManager extends SimpleViewManager { protected static class RNCWebViewClient extends WebViewClient { @@ -93,6 +93,8 @@ index ab869cf..2aa7a9e 100644 + } + }; + task.execute(); ++ } else { ++ super.onReceivedClientCertRequest(view, request); + } + } + diff --git a/storybook/stories/Message.js b/storybook/stories/Message.js index e2f67a469..7e8e06646 100644 --- a/storybook/stories/Message.js +++ b/storybook/stories/Message.js @@ -821,6 +821,10 @@ export default ({ theme }) => { + + + + diff --git a/yarn.lock b/yarn.lock index 4a577acf4..633d519bd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -76,6 +76,22 @@ semver "^5.4.1" source-map "^0.5.0" +"@babel/eslint-parser@^7.13.4": + version "7.13.4" + resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.13.4.tgz#dd9df3c70f44d2fb5a6519e8e10ca06c67dca43a" + integrity sha512-WfFEd89SzqmtYox8crTLJuEXyJolZY6Uu6iJpJmw4aMu50zHbYnxzxwuVkCt2cWygw+gLkUPTtAuox7eSnrL8g== + dependencies: + eslint-scope "5.1.0" + eslint-visitor-keys "^1.3.0" + semver "7.0.0" + +"@babel/eslint-plugin@^7.13.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@babel/eslint-plugin/-/eslint-plugin-7.13.0.tgz#e6d99efcd6b8551adf479e382a47218726179b1b" + integrity sha512-YGwCLc/u/uc3bU+q/fvgRQ62+TkxuyVvdmybK6ElzE49vODp+RnRe16eJzMM7EwvcRPQfQvcOSuGmzfcbZE2+w== + dependencies: + eslint-rule-composer "^0.3.0" + "@babel/generator@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.10.4.tgz#e49eeed9fe114b62fa5b181856a43a5e32f5f243" @@ -2258,7 +2274,7 @@ "@rocket.chat/sdk@RocketChat/Rocket.Chat.js.SDK#mobile": version "1.0.0-mobile" - resolved "https://codeload.github.com/RocketChat/Rocket.Chat.js.SDK/tar.gz/0a97c818e60670d7660868ea107b96e5ebb631af" + resolved "https://codeload.github.com/RocketChat/Rocket.Chat.js.SDK/tar.gz/0241e2fc0c29827c51655f2d46d96e7a7720d2b6" dependencies: js-sha256 "^0.9.0" lru-cache "^4.1.1" @@ -3457,11 +3473,6 @@ array-equal@^1.0.0: resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" integrity sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM= -array-filter@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-1.0.0.tgz#baf79e62e6ef4c2a4c0b831232daffec251f9d83" - integrity sha1-uveeYubvTCpMC4MSMtr/7CUfnYM= - array-filter@~0.0.0: version "0.0.1" resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-0.0.1.tgz#7da8cf2e26628ed732803581fd21f67cacd2eeec" @@ -3649,13 +3660,6 @@ autoprefixer@^9.7.2: postcss "^7.0.30" postcss-value-parser "^4.1.0" -available-typed-arrays@^1.0.0, available-typed-arrays@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.2.tgz#6b098ca9d8039079ee3f77f7b783c4480ba513f5" - integrity sha512-XWX3OX8Onv97LMk/ftVyBibpGwY5a8SmuxZPzeOxqmuEqUCOM9ZE+uIaD1VNJ5QnvU2UQusvmKbuM1FR8QWGfQ== - dependencies: - array-filter "^1.0.0" - aws-sign2@~0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" @@ -3717,18 +3721,6 @@ babel-core@^6.0.0, babel-core@^6.26.0, babel-core@^6.26.3: slash "^1.0.0" source-map "^0.5.7" -babel-eslint@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-9.0.0.tgz#7d9445f81ed9f60aff38115f838970df9f2b6220" - integrity sha512-itv1MwE3TMbY0QtNfeL7wzak1mV47Uy+n6HtSOO4Xd7rvmO+tsGQSgyOEEgo6Y2vHZKZphaoelNeSVj4vkLA1g== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/parser" "^7.0.0" - "@babel/traverse" "^7.0.0" - "@babel/types" "^7.0.0" - eslint-scope "3.7.1" - eslint-visitor-keys "^1.0.0" - babel-generator@^6.18.0, babel-generator@^6.26.0: version "6.26.1" resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" @@ -5741,26 +5733,6 @@ deep-assign@^3.0.0: dependencies: is-obj "^1.0.0" -deep-equal@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-2.0.3.tgz#cad1c15277ad78a5c01c49c2dee0f54de8a6a7b0" - integrity sha512-Spqdl4H+ky45I9ByyJtXteOm9CaIrPmnIPmOhrkKGNYWeDgCvJ8jNYVCTjChxW4FqGuZnLHADc8EKRMX6+CgvA== - dependencies: - es-abstract "^1.17.5" - es-get-iterator "^1.1.0" - is-arguments "^1.0.4" - is-date-object "^1.0.2" - is-regex "^1.0.5" - isarray "^2.0.5" - object-is "^1.1.2" - object-keys "^1.1.1" - object.assign "^4.1.0" - regexp.prototype.flags "^1.3.0" - side-channel "^1.0.2" - which-boxed-primitive "^1.0.1" - which-collection "^1.0.1" - which-typed-array "^1.1.2" - deep-equal@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a" @@ -5871,6 +5843,11 @@ dequal@^1.0.0: resolved "https://registry.yarnpkg.com/dequal/-/dequal-1.0.0.tgz#41c6065e70de738541c82cdbedea5292277a017e" integrity sha512-/Nd1EQbQbI9UbSHrMiKZjFLrXSnU328iQdZKPQf78XQI6C+gutkFUeoHpG5J08Ioa6HeRbRNFpSIclh1xyG0mw== +dequal@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.2.tgz#85ca22025e3a87e65ef75a7a437b35284a7e319d" + integrity sha512-q9K8BlJVxK7hQYqa6XISGmBZbtQQWVXSrRrWreHC94rMt1QL/Impruc+7p2CYSYuVIUr+YCt6hjrs1kkdJRTug== + des.js@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" @@ -6309,7 +6286,7 @@ es-array-method-boxes-properly@^1.0.0: resolved "https://registry.yarnpkg.com/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e" integrity sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA== -es-get-iterator@^1.0.2, es-get-iterator@^1.1.0: +es-get-iterator@^1.0.2: version "1.1.0" resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.0.tgz#bb98ad9d6d63b31aacdc8f89d5d0ee57bcb5b4c8" integrity sha512-UfrmHuWQlNMTs35e1ypnvikg6jCz3SK8v8ImvmDsh36fCVUR1MqoFDiyn0/k52C8NqO3YsO8Oe0azeesNuqSsQ== @@ -6484,10 +6461,15 @@ eslint-plugin-react@7.20.3: resolve "^1.17.0" string.prototype.matchall "^4.0.2" -eslint-scope@3.7.1: - version "3.7.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" - integrity sha1-PWPD7f2gLgbgGkUq2IyqzHzctug= +eslint-rule-composer@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz#79320c927b0c5c0d3d3d2b76c8b4a488f25bbaf9" + integrity sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg== + +eslint-scope@5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.0.tgz#d0f971dfe59c69e0cada684b23d49dbf82600ce5" + integrity sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w== dependencies: esrecurse "^4.1.0" estraverse "^4.1.1" @@ -6515,11 +6497,16 @@ eslint-utils@^1.4.3: dependencies: eslint-visitor-keys "^1.1.0" -eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: +eslint-visitor-keys@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== +eslint-visitor-keys@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" + integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== + eslint@6.8.0: version "6.8.0" resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.8.0.tgz#62262d6729739f9275723824302fb227c8c93ffb" @@ -7344,11 +7331,6 @@ for-own@^1.0.0: dependencies: for-in "^1.0.1" -foreach@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" - integrity sha1-C+4AUBiusmDQo6865ljdATbsG5k= - forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" @@ -8458,11 +8440,6 @@ is-arrayish@^0.3.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== -is-bigint@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.0.tgz#73da8c33208d00f130e9b5e15d23eac9215601c4" - integrity sha512-t5mGUXC/xRheCK431ylNiSkGGpBp8bHENBcENTkDT6ppwPzEVxNGZRvgvmOEfbWkFhA7D2GEuE2mmQTr78sl2g== - is-binary-path@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" @@ -8477,11 +8454,6 @@ is-binary-path@~2.1.0: dependencies: binary-extensions "^2.0.0" -is-boolean-object@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.0.1.tgz#10edc0900dd127697a92f6f9807c7617d68ac48e" - integrity sha512-TqZuVwa/sppcrhUCAYkGBk7w0yxfQQnxq28fjkO53tnK9FQXmdwz2JS5+GjsWQ6RByES1K40nI+yDic5c9/aAQ== - is-buffer@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" @@ -8525,7 +8497,7 @@ is-data-descriptor@^1.0.0: dependencies: kind-of "^6.0.0" -is-date-object@^1.0.1, is-date-object@^1.0.2: +is-date-object@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== @@ -8665,11 +8637,6 @@ is-map@^2.0.1: resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.1.tgz#520dafc4307bb8ebc33b813de5ce7c9400d644a1" integrity sha512-T/S49scO8plUiAOA2DBTBG3JHpn1yiw0kRp6dgiZ0v2/6twi5eiB0rHtHFH9ZIrvlWc6+4O+m4zg5+Z833aXgw== -is-number-object@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.4.tgz#36ac95e741cf18b283fc1ddf5e83da798e3ec197" - integrity sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw== - is-number@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" @@ -8767,16 +8734,6 @@ is-symbol@^1.0.2, is-symbol@^1.0.3: dependencies: has-symbols "^1.0.1" -is-typed-array@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.3.tgz#a4ff5a5e672e1a55f99c7f54e59597af5c1df04d" - integrity sha512-BSYUBOK/HJibQ30wWkWold5txYwMUXQct9YHAQJr8fSwvZoiglcqB0pd7vEN23+Tsi9IUEjztdOSzl4qLVYGTQ== - dependencies: - available-typed-arrays "^1.0.0" - es-abstract "^1.17.4" - foreach "^2.0.5" - has-symbols "^1.0.1" - is-typedarray@^1.0.0, is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" @@ -8787,16 +8744,6 @@ is-utf8@^0.2.0: resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= -is-weakmap@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.1.tgz#5008b59bdc43b698201d18f62b37b2ca243e8cf2" - integrity sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA== - -is-weakset@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.1.tgz#e9a0af88dbd751589f5e50d80f4c98b780884f83" - integrity sha512-pi4vhbhVHGLxohUw7PhGsueT4vRGFoXhP7+RGN0jKIv9+8PWYCQTqtADngrxOm2g46hoH0+g8uZZBzMrvVGDmw== - is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" @@ -11522,7 +11469,7 @@ object-inspect@^1.7.0: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67" integrity sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw== -object-is@^1.0.1, object-is@^1.1.2: +object-is@^1.0.1: version "1.1.2" resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.2.tgz#c5d2e87ff9e119f78b7a088441519e2eec1573b6" integrity sha512-5lHCz+0uufF6wZ7CRFWJN3hp8Jqblpgve06U5CMQ3f//6iDjPr2PEo9MWCjEssDsa+UZEL4PkFpr+BMop6aKzQ== @@ -12786,11 +12733,6 @@ react-fast-compare@^3.0.1: resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.1.1.tgz#0becf31e3812fa70dc231e259f40d892d4767900" integrity sha512-SCsAORWK59BvauR2L1BTdjQbJcSGJJz03U0awektk2hshLKrITDDFTlgGCqIZpTDlPC/NFlZee6xTMzXPVLiHw== -react-fast-compare@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb" - integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA== - react-focus-lock@^2.1.0: version "2.3.1" resolved "https://registry.yarnpkg.com/react-focus-lock/-/react-focus-lock-2.3.1.tgz#9d5d85899773609c7eefa4fc54fff6a0f5f2fc47" @@ -13189,7 +13131,7 @@ react-native-windows@^0.62.0-0: uuid "^3.3.2" xml-parser "^1.2.1" -react-native@RocketChat/react-native#0.63.4, react-native@^0.63.1: +react-native@RocketChat/react-native#0.63.4: version "0.63.4" resolved "https://codeload.github.com/RocketChat/react-native/tar.gz/616299bbc01eeb56cb7d5b52e543051e1ad2d136" dependencies: @@ -13832,8 +13774,6 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: rn-extensions-share@RocketChat/rn-extensions-share: version "2.4.1" resolved "https://codeload.github.com/RocketChat/rn-extensions-share/tar.gz/4d7c0e4c2f300e4fb116af7b7cc0dbbc8169150c" - dependencies: - react-native "^0.63.1" rn-fetch-blob@0.12.0: version "0.12.0" @@ -13848,7 +13788,7 @@ rn-host-detect@1.2.0: resolved "https://registry.yarnpkg.com/rn-host-detect/-/rn-host-detect-1.2.0.tgz#8b0396fc05631ec60c1cb8789e5070cdb04d0da0" integrity sha512-btNg5kzHcjZZ7t7mvvV/4wNJ9e3MPgrWivkRgWURzXL0JJ0pwWlU4zrbmdlz3HHzHOxhBhHB4D+/dbMFfu4/4A== -rn-root-view@^1.0.3: +rn-root-view@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/rn-root-view/-/rn-root-view-1.0.3.tgz#a2cddc717278cb2175fb29b7c006e407b7f0d0e2" integrity sha512-BIKm8hY5q8+pxK9B5ugYjqutoI9xn2JfxIZKWoaFmAl1bOIM4oXjwFQrRM1e6lFgzz99MN6Mf2dK3Alsywnvvw== @@ -15995,44 +15935,11 @@ whatwg-url@^7.0.0: tr46 "^1.0.1" webidl-conversions "^4.0.2" -which-boxed-primitive@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.1.tgz#cbe8f838ebe91ba2471bb69e9edbda67ab5a5ec1" - integrity sha512-7BT4TwISdDGBgaemWU0N0OU7FeAEJ9Oo2P1PHRm/FCWoEi2VLWC9b6xvxAA3C/NMpxg3HXVgi0sMmGbNUbNepQ== - dependencies: - is-bigint "^1.0.0" - is-boolean-object "^1.0.0" - is-number-object "^1.0.3" - is-string "^1.0.4" - is-symbol "^1.0.2" - -which-collection@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.1.tgz#70eab71ebbbd2aefaf32f917082fc62cdcb70906" - integrity sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A== - dependencies: - is-map "^2.0.1" - is-set "^2.0.1" - is-weakmap "^2.0.1" - is-weakset "^2.0.1" - which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= -which-typed-array@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.2.tgz#e5f98e56bda93e3dac196b01d47c1156679c00b2" - integrity sha512-KT6okrd1tE6JdZAy3o2VhMoYPh3+J6EMZLyrxBQsZflI1QCZIxMrIYLkosd8Twf+YfknVIHmYQPgJt238p8dnQ== - dependencies: - available-typed-arrays "^1.0.2" - es-abstract "^1.17.5" - foreach "^2.0.5" - function-bind "^1.1.1" - has-symbols "^1.0.1" - is-typed-array "^1.1.3" - which@1.3.1, which@^1.2.12, which@^1.2.9, which@^1.3.0, which@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"