Merge 4.15.0 into master (#2984)
* [FIX] MessagesView title not working (#2294) * Set title in header of room actions view items Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * Remove unneeded spaces Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * Set header title on constructor Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * Remove unused navigation options Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> Co-authored-by: Diego Mello <diegolmello@gmail.com> * [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 commitd115604270
. Co-authored-by: Diego Mello <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [CHORE] Wrap logEvent in a try/catch (#2361) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Minor i18n issues (#2335) * Add new translations to ptBr Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * Fix update language in headers Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> Co-authored-by: Diego Mello <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [FIX] WorkspaceView not looking for the correct image path (#2376) Co-authored-by: Gabriel Henriques <gabriel.henriques@rocket.chat> * [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 <diegolmello@gmail.com> * [DOCS] Refactor Readme (#2382) * Refactoring * Detail docs * Contributing * Update CONTRIBUTING.md Co-authored-by: Djorkaeff Alexandre <djorkaeff.unb@gmail.com> Co-authored-by: Djorkaeff Alexandre <djorkaeff.unb@gmail.com> * 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 <http://link/Text> 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) <!-- INSTRUCTION: Keep the line below to notify all core developers about this new PR --> @RocketChat/ReactNative <!-- INSTRUCTION: Inform the issue number that this PR closes, or remove the line below --> <!-- INSTRUCTION: Tell us more about your PR with screen shots if you can --> - [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) <!-- INSTRUCTION: Keep the line below to notify all core developers about this new PR --> @RocketChat/ReactNative <!-- INSTRUCTION: Inform the issue number that this PR closes, or remove the line below --> User was able to add an invalid instance of Rocket.Chat by pressing submit button instead of "Connect" button. <!-- INSTRUCTION: Tell us more about your PR with screen shots if you can --> * I18n (#312) * Unread and date separator layout improved (#319) <!-- INSTRUCTION: Keep the line below to notify all core developers about this new PR --> @RocketChat/ReactNative <!-- INSTRUCTION: Inform the issue number that this PR closes, or remove the line below --> - [x] Unread and date separator layout - [x] "Start of conversation"/"Loading messages" label   <!-- INSTRUCTION: Tell us more about your PR with screen shots if you can --> * [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) <!-- INSTRUCTION: Keep the line below to notify all core developers about this new PR --> @RocketChat/ReactNative <!-- INSTRUCTION: Inform the issue number that this PR closes, or remove the line below --> Closes #342 <!-- INSTRUCTION: Tell us more about your PR with screen shots if you can --> * Allow x-instance-id and X-Instance-ID header (#354) <!-- INSTRUCTION: Keep the line below to notify all core developers about this new PR --> @RocketChat/ReactNative <!-- INSTRUCTION: Inform the issue number that this PR closes, or remove the line below --> Closes #137 <!-- INSTRUCTION: Tell us more about your PR with screen shots if you can --> Some server configurations may send x-instance-id header with different case. * Image upload improvements (#368) <!-- INSTRUCTION: Keep the line below to notify all core developers about this new PR --> @RocketChat/ReactNative <!-- INSTRUCTION: Inform the issue number that this PR closes, or remove the line below --> - [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 <!-- INSTRUCTION: Tell us more about your PR with screen shots if you can -->   * [NEW] Room Loading(#372) <!-- INSTRUCTION: Keep the line below to notify all core developers about this new PR --> @RocketChat/ReactNative <!-- INSTRUCTION: Inform the issue number that this PR closes, or remove the line below --> <!-- INSTRUCTION: Tell us more about your PR with screen shots if you can --> * [FIX] Empty room name for livechat (#375) <!-- INSTRUCTION: Keep the line below to notify all core developers about this new PR --> @RocketChat/ReactNative <!-- INSTRUCTION: Inform the issue number that this PR closes, or remove the line below --> Closes #320 Closes #209 <!-- INSTRUCTION: Tell us more about your PR with screen shots if you can --> * [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) <!-- INSTRUCTION: Keep the line below to notify all core developers about this new PR --> @RocketChat/ReactNative <!-- INSTRUCTION: Inform the issue number that this PR closes, or remove the line below --> <!-- INSTRUCTION: Tell us more about your PR with screen shots if you can -->  * [FIX] Android 8 notifications (#382) <!-- INSTRUCTION: Keep the line below to notify all core developers about this new PR --> @RocketChat/ReactNative <!-- INSTRUCTION: Inform the issue number that this PR closes, or remove the line below --> Closes #380 <!-- INSTRUCTION: Tell us more about your PR with screen shots if you can --> * Added CocoaPods to manage react-native-image-crop-picker (#373) <!-- INSTRUCTION: Keep the line below to notify all core developers about this new PR --> @RocketChat/ReactNative <!-- INSTRUCTION: Inform the issue number that this PR closes, or remove the line below --> <!-- INSTRUCTION: Tell us more about your PR with screen shots if you can --> 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) <!-- INSTRUCTION: Keep the line below to notify all core developers about this new PR --> @RocketChat/ReactNative <!-- INSTRUCTION: Inform the issue number that this PR closes, or remove the line below --> Closes #386 Closes #295 <!-- INSTRUCTION: Tell us more about your PR with screen shots if you can --> * Improve RoomsList render time (#384) <!-- INSTRUCTION: Keep the line below to notify all core developers about this new PR --> @RocketChat/ReactNative <!-- INSTRUCTION: Inform the issue number that this PR closes, or remove the line below --> <!-- INSTRUCTION: Tell us more about your PR with screen shots if you can --> - [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) <!-- INSTRUCTION: Keep the line below to notify all core developers about this new PR --> @RocketChat/ReactNative <!-- INSTRUCTION: Inform the issue number that this PR closes, or remove the line below --> Closes #398 <!-- INSTRUCTION: Tell us more about your PR with screen shots if you can -->    * Add roadmap (#406) <!-- INSTRUCTION: Keep the line below to notify all core developers about this new PR --> @RocketChat/ReactNative <!-- INSTRUCTION: Inform the issue number that this PR closes, or remove the line below --> Closes #45 <!-- INSTRUCTION: Tell us more about your PR with screen shots if you can --> * [NEW] Onboarding (#407) <!-- INSTRUCTION: Keep the line below to notify all core developers about this new PR --> @RocketChat/ReactNative <!-- INSTRUCTION: Inform the issue number that this PR closes, or remove the line below --> Closes #392 <!-- INSTRUCTION: Tell us more about your PR with screen shots if you can -->    * [NEW] Updated Logo on Splash screen (#409) <!-- INSTRUCTION: Keep the line below to notify all core developers about this new PR --> @RocketChat/ReactNative <!-- INSTRUCTION: Inform the issue number that this PR closes, or remove the line below --> Closes #399 <!-- INSTRUCTION: Tell us more about your PR with screen shots if you can -->   * [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) * ✨ Create user table * ✨ Introduce user table * 🔥 Remove unused table * ➕ Add userdefaults to storage data * 💚 Fix android build * ✨ Get credentials from iOS native client * 🔥 Remove unused code * ⏪ Revert sign xcode * 🐛 Fix first login-logout * 🎨 Use constants to UserDefaults Keys * 🐛 Fix clear server-user-info on logout * 🐛 Fix filter null value * 🚑 Remove user object in logout * ✨ Fix get servers from native-client * 🚑 Fix error on change server * [FIX] Don't run UserDefaults credentials on Android (#1015) * 🐛 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 * 🐛 Fix empty space * [IMPROVEMENT] Refactor empty space regex on quote (#1017) * 🎨 Improve regex to empty space on quote * 🎨 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) * ✨ Create user table * ✨ Introduce user table * 🔥 Remove unused table * ➕ Add userdefaults to storage data * 💚 Fix android build * ✨ Get credentials from iOS native client * 🔥 Remove unused code * ⏪ Revert sign xcode * 🐛 Fix first login-logout * 🎨 Use constants to UserDefaults Keys * 🐛 Fix clear server-user-info on logout * 🐛 Fix filter null value * 🚑 Remove user object in logout * ✨ Fix get servers from native-client * 🚑 Fix error on change server * [FIX] Don't run UserDefaults credentials on Android (#1015) * 🐛 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 * 🐛 Fix empty space * [IMPROVEMENT] Refactor empty space regex on quote (#1017) * 🎨 Improve regex to empty space on quote * 🎨 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) * ✨ Create user table * ✨ Introduce user table * 🔥 Remove unused table * ➕ Add userdefaults to storage data * 💚 Fix android build * ✨ Get credentials from iOS native client * 🔥 Remove unused code * ⏪ Revert sign xcode * 🐛 Fix first login-logout * 🎨 Use constants to UserDefaults Keys * 🐛 Fix clear server-user-info on logout * 🐛 Fix filter null value * 🚑 Remove user object in logout * ✨ Fix get servers from native-client * 🚑 Fix error on change server * [FIX] Don't run UserDefaults credentials on Android (#1015) * 🐛 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 * 🐛 Fix empty space * [IMPROVEMENT] Refactor empty space regex on quote (#1017) * 🎨 Improve regex to empty space on quote * 🎨 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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <djorkaeff.unb@gmail.com> * 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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <ezequiel1de1oliveira@gmail.com> * [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 <diegolmello@gmail.com> * [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 <ezequiel1de1oliveira@gmail.com> * Create screen to preferences and listItem to notifications Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * Refactoring NotificationPreferencesView Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * List notification preferences Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * Adding translations to labels Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * SetUserPreferences api call Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * Saving new user preference in API Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * Fix lint Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * Add in-app notification test Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * Fix in app mentions preference Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * Improve object in testInAppNotification Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * Removing improper options for NotificationpreferencesView Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * Adding API version Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * Use redux in UserNotificationPrefView Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * Remove in app test Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * Use components from another view Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * Removing verification for testing in-app notifications Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * Move to ProfileView Co-authored-by: Diego Mello <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 🚀 * 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 commitea287980d9
. * finalise Co-authored-by: Djorkaeff Alexandre <djorkaeff.unb@gmail.com> Co-authored-by: Diego Mello <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <ezequiel1de1oliveira@gmail.com> * Saving when the user logged in with email and password Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * Saving login method info Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * Ask for the user to clear cookies Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * Fix lint Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * Removing loginMethod from redux and add I18n Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * Using async/await instead of then/catch Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * Fix lint Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * Pods * Added dismissText on showConfirmationAlert * Fix iOS * Rename function * I18n tweaks Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Wrong date and time shown in file section (#2409) * Adding missing prop to item object Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * Resolving the missing date in the files section in a more elegant way Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * Using ts attribute always inside of an item object Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Verify useRealName setting on files screen (#2427) Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Apply theme on Directory description (#2428) Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> Co-authored-by: Diego Mello <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <djorkaeff.unb@gmail.com> * [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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <ezequiel1de1oliveira@gmail.com> * Adding new table to serverSchema Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * Saving if not exists Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * list of visited servers finished Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * Fix lint Signed-off-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * 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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [I18n] Improve Simplified Chinese (zh_CN) (#2466) * I18n: Improve Simplified Chinese(zh_CN) language file * I18n: Add missing translation Co-authored-by: Diego Mello <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [FIX] Language set by web client (#2488) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [i18n] Improve Chinese translation (zh-TW, zh-CN) (#2486) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <prateek93a@gmail.com> * 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 <prateek93a@gmail.com> Co-authored-by: Diego Mello <diegolmello@gmail.com> * [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 <prateek93a@gmail.com> * 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 <ezequiel1de1oliveira@gmail.com> * 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 <prateek93a@gmail.com> Co-authored-by: Diego Mello <diegolmello@gmail.com> Co-authored-by: Ezequiel De Oliveira <ezequiel1de1oliveira@gmail.com> * [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 <djorkaeff.unb@gmail.com> * [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 <diegolmello@gmail.com> * [FIX] iOS uploads always cropping as squares (#2516) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <djorkaeff.unb@gmail.com> * [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 <diegolmello@gmail.com> * [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 <djorkaeff.unb@gmail.com> Co-authored-by: Diego Mello <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [i18n] Improve Chinese translation (#2570) * [FIX] App crashing when notification is received/replied (Android) (#2602) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Update react native CLI to support white labeling with XCode 12 (#2560) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [i18n] Add missing German strings (#2571) * adding missing German strings * resolving conflict Co-authored-by: Diego Mello <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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: Карлан Антон Андреевич <KarlanAA@global.bcs> Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] 'Send to channel' when replying as a quote (#2606) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Android notification on Dark Theme using Official main color (#2604) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [FIX] User notification preferences throwing an error when select default Email option (#2615) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] MomentJS crashing on Spanish language (#2616) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <djorkaeff.unb@gmail.com> * 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 <http://link/Text> 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) <!-- INSTRUCTION: Keep the line below to notify all core developers about this new PR --> @RocketChat/ReactNative <!-- INSTRUCTION: Inform the issue number that this PR closes, or remove the line below --> <!-- INSTRUCTION: Tell us more about your PR with screen shots if you can --> - [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) <!-- INSTRUCTION: Keep the line below to notify all core developers about this new PR --> @RocketChat/ReactNative <!-- INSTRUCTION: Inform the issue number that this PR closes, or remove the line below --> User was able to add an invalid instance of Rocket.Chat by pressing submit button instead of "Connect" button. <!-- INSTRUCTION: Tell us more about your PR with screen shots if you can --> * I18n (#312) * Unread and date separator layout improved (#319) <!-- INSTRUCTION: Keep the line below to notify all core developers about this new PR --> @RocketChat/ReactNative <!-- INSTRUCTION: Inform the issue number that this PR closes, or remove the line below --> - [x] Unread and date separator layout - [x] "Start of conversation"/"Loading messages" label   <!-- INSTRUCTION: Tell us more about your PR with screen shots if you can --> * [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) <!-- INSTRUCTION: Keep the line below to notify all core developers about this new PR --> @RocketChat/ReactNative <!-- INSTRUCTION: Inform the issue number that this PR closes, or remove the line below --> Closes #342 <!-- INSTRUCTION: Tell us more about your PR with screen shots if you can --> * Allow x-instance-id and X-Instance-ID header (#354) <!-- INSTRUCTION: Keep the line below to notify all core developers about this new PR --> @RocketChat/ReactNative <!-- INSTRUCTION: Inform the issue number that this PR closes, or remove the line below --> Closes #137 <!-- INSTRUCTION: Tell us more about your PR with screen shots if you can --> Some server configurations may send x-instance-id header with different case. * Image upload improvements (#368) <!-- INSTRUCTION: Keep the line below to notify all core developers about this new PR --> @RocketChat/ReactNative <!-- INSTRUCTION: Inform the issue number that this PR closes, or remove the line below --> - [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 <!-- INSTRUCTION: Tell us more about your PR with screen shots if you can -->   * [NEW] Room Loading(#372) <!-- INSTRUCTION: Keep the line below to notify all core developers about this new PR --> @RocketChat/ReactNative <!-- INSTRUCTION: Inform the issue number that this PR closes, or remove the line below --> <!-- INSTRUCTION: Tell us more about your PR with screen shots if you can --> * [FIX] Empty room name for livechat (#375) <!-- INSTRUCTION: Keep the line below to notify all core developers about this new PR --> @RocketChat/ReactNative <!-- INSTRUCTION: Inform the issue number that this PR closes, or remove the line below --> Closes #320 Closes #209 <!-- INSTRUCTION: Tell us more about your PR with screen shots if you can --> * [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) <!-- INSTRUCTION: Keep the line below to notify all core developers about this new PR --> @RocketChat/ReactNative <!-- INSTRUCTION: Inform the issue number that this PR closes, or remove the line below --> <!-- INSTRUCTION: Tell us more about your PR with screen shots if you can -->  * [FIX] Android 8 notifications (#382) <!-- INSTRUCTION: Keep the line below to notify all core developers about this new PR --> @RocketChat/ReactNative <!-- INSTRUCTION: Inform the issue number that this PR closes, or remove the line below --> Closes #380 <!-- INSTRUCTION: Tell us more about your PR with screen shots if you can --> * Added CocoaPods to manage react-native-image-crop-picker (#373) <!-- INSTRUCTION: Keep the line below to notify all core developers about this new PR --> @RocketChat/ReactNative <!-- INSTRUCTION: Inform the issue number that this PR closes, or remove the line below --> <!-- INSTRUCTION: Tell us more about your PR with screen shots if you can --> 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) <!-- INSTRUCTION: Keep the line below to notify all core developers about this new PR --> @RocketChat/ReactNative <!-- INSTRUCTION: Inform the issue number that this PR closes, or remove the line below --> Closes #386 Closes #295 <!-- INSTRUCTION: Tell us more about your PR with screen shots if you can --> * Improve RoomsList render time (#384) <!-- INSTRUCTION: Keep the line below to notify all core developers about this new PR --> @RocketChat/ReactNative <!-- INSTRUCTION: Inform the issue number that this PR closes, or remove the line below --> <!-- INSTRUCTION: Tell us more about your PR with screen shots if you can --> - [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) <!-- INSTRUCTION: Keep the line below to notify all core developers about this new PR --> @RocketChat/ReactNative <!-- INSTRUCTION: Inform the issue number that this PR closes, or remove the line below --> Closes #398 <!-- INSTRUCTION: Tell us more about your PR with screen shots if you can -->    * Add roadmap (#406) <!-- INSTRUCTION: Keep the line below to notify all core developers about this new PR --> @RocketChat/ReactNative <!-- INSTRUCTION: Inform the issue number that this PR closes, or remove the line below --> Closes #45 <!-- INSTRUCTION: Tell us more about your PR with screen shots if you can --> * [NEW] Onboarding (#407) <!-- INSTRUCTION: Keep the line below to notify all core developers about this new PR --> @RocketChat/ReactNative <!-- INSTRUCTION: Inform the issue number that this PR closes, or remove the line below --> Closes #392 <!-- INSTRUCTION: Tell us more about your PR with screen shots if you can -->    * [NEW] Updated Logo on Splash screen (#409) <!-- INSTRUCTION: Keep the line below to notify all core developers about this new PR --> @RocketChat/ReactNative <!-- INSTRUCTION: Inform the issue number that this PR closes, or remove the line below --> Closes #399 <!-- INSTRUCTION: Tell us more about your PR with screen shots if you can -->   * [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) * ✨ Create user table * ✨ Introduce user table * 🔥 Remove unused table * ➕ Add userdefaults to storage data * 💚 Fix android build * ✨ Get credentials from iOS native client * 🔥 Remove unused code * ⏪ Revert sign xcode * 🐛 Fix first login-logout * 🎨 Use constants to UserDefaults Keys * 🐛 Fix clear server-user-info on logout * 🐛 Fix filter null value * 🚑 Remove user object in logout * ✨ Fix get servers from native-client * 🚑 Fix error on change server * [FIX] Don't run UserDefaults credentials on Android (#1015) * 🐛 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 * 🐛 Fix empty space * [IMPROVEMENT] Refactor empty space regex on quote (#1017) * 🎨 Improve regex to empty space on quote * 🎨 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) * ✨ Create user table * ✨ Introduce user table * 🔥 Remove unused table * ➕ Add userdefaults to storage data * 💚 Fix android build * ✨ Get credentials from iOS native client * 🔥 Remove unused code * ⏪ Revert sign xcode * 🐛 Fix first login-logout * 🎨 Use constants to UserDefaults Keys * 🐛 Fix clear server-user-info on logout * 🐛 Fix filter null value * 🚑 Remove user object in logout * ✨ Fix get servers from native-client * 🚑 Fix error on change server * [FIX] Don't run UserDefaults credentials on Android (#1015) * 🐛 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 * 🐛 Fix empty space * [IMPROVEMENT] Refactor empty space regex on quote (#1017) * 🎨 Improve regex to empty space on quote * 🎨 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) * ✨ Create user table * ✨ Introduce user table * 🔥 Remove unused table * ➕ Add userdefaults to storage data * 💚 Fix android build * ✨ Get credentials from iOS native client * 🔥 Remove unused code * ⏪ Revert sign xcode * 🐛 Fix first login-logout * 🎨 Use constants to UserDefaults Keys * 🐛 Fix clear server-user-info on logout * 🐛 Fix filter null value * 🚑 Remove user object in logout * ✨ Fix get servers from native-client * 🚑 Fix error on change server * [FIX] Don't run UserDefaults credentials on Android (#1015) * 🐛 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 * 🐛 Fix empty space * [IMPROVEMENT] Refactor empty space regex on quote (#1017) * 🎨 Improve regex to empty space on quote * 🎨 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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <djorkaeff.unb@gmail.com> * 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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <djorkaeff.unb@gmail.com> * [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 <diegolmello@gmail.com> * [i18n] Add missing German strings (#2619) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Model columns misplaced (#2640) * [FIX] Connect a null server (#2639) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * 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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <djorkaeff.unb@gmail.com> * [CHORE] Force normalized params for 2FA (#2683) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Thread message flickering while thread parent isn't found (#2676) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Light theme not working on Android with Dark Theme set (#2675) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] App not prompting join code for password protected channels (#2514) * Adding joinCode parameter Co-authored-by: Vitor Leal <vitor_leal2201@hotmail.com> Co-authored-by: Fernando Aguilar <fernando.aguilar@hotmail.com.br> * Insert join code input Signed-off-by: Vitor.Leal <vitor_leal2201@hotmail.com> * Add joinCode field on db Signed-off-by: Vitor.Leal <vitor_leal2201@hotmail.com> * Add label i18 pt-br and en-us Signed-off-by: Vitor.Leal <vitor_leal2201@hotmail.com> * Add insert join code text Signed-off-by: Vitor.Leal <vitor_leal2201@hotmail.com> * Fix atribute name Signed-off-by: Vitor.Leal <vitor_leal2201@hotmail.com> * Add join text Signed-off-by: Vitor.Leal <vitor_leal2201@hotmail.com> Co-authored-by: Daniel Maike <danmke@hotmail.com> Co-authored-by: Fernando Aguilar <fernando.aguilar@hotmail.com.br> * Fix attributes joinCode, joinCodeRequired and pass attribute param in navigation Signed-off-by: Daniel Maike <danmke@hotmail.com> Co-authored-by: Vitor Leal <vitor_leal2201@hotmail.com> * Fixing attribute joinCodeRequired pass to goRoom Signed-off-by: Daniel Maike <danmke@hotmail.com> * Changed textinput style Signed-off-by: Daniel Maike <danmke@hotmail.com> Co-authored-by: Vitor Leal <vitor_leal2201@hotmail.com> * Delete not necessary attribute Signed-off-by: Daniel Maike <danmke@hotmail.com> * Fixing input style Co-authored-by: Vitor Leal <vitor_leal2201@hotmail.com> * 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 <vitor_leal2201@hotmail.com> Co-authored-by: Fernando Aguilar <fernando.aguilar@hotmail.com.br> Co-authored-by: Djorkaeff Alexandre <djorkaeff.unb@gmail.com> Co-authored-by: youssef-md <emaildeyoussefmuhamad@gmail.com> Co-authored-by: Diego Mello <diegolmello@gmail.com> * [I18n] Add Arabic (#2537) * Arabic language setup * Added arabic translation * Arabic translation Proofreading Co-authored-by: Diego Mello <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [FIX] Chats order (#2688) * Persist highest value on subscription.roomUpdatedAt * Update tests Co-authored-by: Djorkaeff Alexandre <djorkaeff.unb@gmail.com> * [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 <djorkaeff.unb@gmail.com> * [i18n] Update fr (#2697) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [i18n] Update fr (#2705) Typo Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Empty space on Messagebox (#2704) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [FIX] Jitsi notification delay (#2668) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [I18N] Update arabic (#2696) * Update ar.js * Update ar.js Co-authored-by: Diego Mello <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [DOCS] Updated Quick Start docs link in e2e/readme (#2802) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [I18N] Add Turkish (#2793) * Turkish language support added * Update tr.js Co-authored-by: Diego Mello <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * 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 commit60330a1e04
. * Stop subscribing to threads * Remove ref * Fix prop-types Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Real name being ignored in SearchMessagesView (#2838) Co-authored-by: Gerzon Z <gerzonc@icloud.com> Co-authored-by: Diego Mello <diegolmello@gmail.com> * [CHORE] Remove unnecessary share reducer calls (#2861) * Remove unnecesary share reducer calls * Update Avatar Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Breadcrumbs exceeding characters limit (#2862) * [FIX] breadcrumbs exceeding * fix.breadcrumbs-exceeding-change-events Co-authored-by: Diego Mello <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [FIX] Reply component sending unused prop to Description (#2900) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [CHORE] BackdropOpacity based on themes (#2863) * Added backdropOpacity based on theme * Updated ActionSheet, ReactionsModal, ReactionPicker and Sidebar * Updated MultiSelect Co-authored-by: Diego Mello <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> Co-authored-by: Gerzon Z <gerzonc@icloud.com> Co-authored-by: Jan Garaj <jan.garaj@gmail.com> * [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 <diegolmello@gmail.com> * [CHORE] Update iOS profiles for Experimental app (#2933) * [IMPROVE] Deleted thread reply redirects to thread (#2840) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [FIX] RightButtonsContainer re-render check not returning default value (#2899) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [CHORE] Remove InteractionManager blocks (#2906) * [FIX] Remove InteractionManager blocks * Minor fix Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] App not sending second argument for EventEmitter.removeListener on some places (#2909) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [FIX] Temp message ignoring real name (#2919) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [CHORE] Use shortcut syntax for get collections (#2932) Co-authored-by: Diego Mello <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [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 <diegolmello@gmail.com> * [FIX] Reactions modal's backdrop color too light (#2949) Co-authored-by: Diego Mello <diegolmello@gmail.com> * 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 <diegolmello@gmail.com> * [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 <ezequiel1de1oliveira@gmail.com> Co-authored-by: Dan Caseley <dan@caseley.me.uk> Co-authored-by: Djorkaeff Alexandre <djorkaeff.unb@gmail.com> Co-authored-by: Youssef Muhamad <emaildeyoussefmuhamad@gmail.com> Co-authored-by: Graham Smith <graham@wiseman-designs.com> Co-authored-by: Gabriel Henriques <gabriel.henriques@rocket.chat> Co-authored-by: Júlia Grala <30629556+juliagrala@users.noreply.github.com> Co-authored-by: Guilherme Gazzo <guilhermegazzo@gmail.com> Co-authored-by: Prateek Jain <44807945+Prateek93a@users.noreply.github.com> Co-authored-by: Lucas Siqueira <lucassiqzro@gmail.com> Co-authored-by: Calebe Rios <calebersmendes@gmail.com> Co-authored-by: Pitstopper <18574776+Pitstopper@users.noreply.github.com> Co-authored-by: phriedrich <info@phriedrich.de> Co-authored-by: Guilherme Siqueira <guilhersiqueira@gmail.com> Co-authored-by: Prateek Jain <prateek93a@gmail.com> Co-authored-by: devyaniChoubey <52153085+devyaniChoubey@users.noreply.github.com> Co-authored-by: Bernard Seow <ssbing99@gmail.com> Co-authored-by: Hiroki Ishiura <ishiura@ja2.so-net.ne.jp> Co-authored-by: Exordian <jakob.englisch@gmail.com> Co-authored-by: Daanchaam <daanhendriks97@gmail.com> Co-authored-by: Iván Álvarez <ialvarezpereira@gmail.com> Co-authored-by: Sarthak Pranesh <41206172+sarthakpranesh@users.noreply.github.com> Co-authored-by: Michele Pellegrini <pellettiero@users.noreply.github.com> Co-authored-by: Tanmoy Bhowmik <tanmoy.openroot@gmail.com> Co-authored-by: Hibikine Kage <14365761+hibikine@users.noreply.github.com> Co-authored-by: Neil Agarwal <neil@neilagarwal.me> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Govind Dixit <GOVINDDIXIT93@GMAIL.COM> Co-authored-by: Zhaubassarova Aruzhan <49000079+azhaubassar@users.noreply.github.com> Co-authored-by: Aroo <azhaubassar@gmail.com> Co-authored-by: Sarthak Pranesh <sarthak.pranesh2018@vitstudent.ac.in> Co-authored-by: Siddharth Padhi <padhisiddharth31@gmail.com> Co-authored-by: Bruno Dantas <oliveiradantas96@gmail.com> Co-authored-by: devyaniChoubey <devyanichoubey16@gmail.com> Co-authored-by: Heng Sok <sokheng@idatahub.com> Co-authored-by: Snyk bot <snyk-bot@snyk.io> Co-authored-by: nixxou <45721836+nixxou@users.noreply.github.com> Co-authored-by: David-Tsui <st880221@gmail.com> Co-authored-by: Vincenzo Esposito <aenon.esposito@gmail.com> Co-authored-by: Rishabh Gupta <38923768+imrishabh18@users.noreply.github.com> Co-authored-by: Hendy Irawan <hendy@hendyirawan.com> Co-authored-by: Alexandru Naiman <alex.naiman.4@gmail.com> Co-authored-by: Dani <assgex@gmail.com> Co-authored-by: Luis <ljcp28ljcp@gmail.com> Co-authored-by: zaphod534 <32894570+zaphod534@users.noreply.github.com> Co-authored-by: ankar84 <ankar84@gmail.com> Co-authored-by: Карлан Антон Андреевич <KarlanAA@global.bcs> Co-authored-by: Saket Mahajan <saketmahajan99@gmail.com> Co-authored-by: Rohit Verma <44283521+refactor-droidyy@users.noreply.github.com> Co-authored-by: Marco Jakobs <mj@jacotec.de> Co-authored-by: Daniel Maike <danmke@hotmail.com> Co-authored-by: Vitor Leal <vitor_leal2201@hotmail.com> Co-authored-by: Fernando Aguilar <fernando.aguilar@hotmail.com.br> Co-authored-by: Abdullah Alhamoud <10301923+abalhamoud@users.noreply.github.com> Co-authored-by: Dave Koo <dkoo761@gmail.com> Co-authored-by: Fazil Boudjelal <fazildiablou@hotmail.fr> Co-authored-by: Lucas Dousse <Cormoran96@users.noreply.github.com> Co-authored-by: Sumukha Hegde <SUMUKHA214@GMAIL.COM> Co-authored-by: Gerzon Z <gerzonzcanario@gmail.com> Co-authored-by: Gerzon Z <gerzonc@icloud.com> Co-authored-by: yash-rajpal <58601732+yash-rajpal@users.noreply.github.com> Co-authored-by: Hakan YILMAZ <mukerrem.yilmaz@hotmail.com> Co-authored-by: Arkadyuti Bandyopadhyay <bandyopadhyayarkadyuti@gmail.com> 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 <newmanw10@gmail.com> Co-authored-by: Jan Garaj <jan.garaj@gmail.com>
This commit is contained in:
parent
197b78e8f0
commit
f5b013f4e7
|
@ -237,9 +237,13 @@ commands:
|
||||||
if [[ $CIRCLE_JOB == "ios-build-official" ]]; then
|
if [[ $CIRCLE_JOB == "ios-build-official" ]]; then
|
||||||
/usr/libexec/PlistBuddy -c "Set BugsnagAPIKey $BUGSNAG_KEY_OFFICIAL" ./RocketChatRN/Info.plist
|
/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" ./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
|
else
|
||||||
/usr/libexec/PlistBuddy -c "Set BugsnagAPIKey $BUGSNAG_KEY" ./RocketChatRN/Info.plist
|
/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" ./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
|
fi
|
||||||
|
|
||||||
if [[ $APP_STORE_CONNECT_API_KEY ]]; then
|
if [[ $APP_STORE_CONNECT_API_KEY ]]; then
|
||||||
|
@ -416,9 +420,13 @@ workflows:
|
||||||
- lint-testunit
|
- lint-testunit
|
||||||
|
|
||||||
# iOS Experimental
|
# iOS Experimental
|
||||||
|
- ios-hold-build-experimental:
|
||||||
|
type: approval
|
||||||
|
requires:
|
||||||
|
- lint-testunit
|
||||||
- ios-build-experimental:
|
- ios-build-experimental:
|
||||||
requires:
|
requires:
|
||||||
- lint-testunit
|
- ios-hold-build-experimental
|
||||||
- ios-hold-testflight-experimental:
|
- ios-hold-testflight-experimental:
|
||||||
type: approval
|
type: approval
|
||||||
requires:
|
requires:
|
||||||
|
@ -444,9 +452,13 @@ workflows:
|
||||||
- ios-hold-testflight-official
|
- ios-hold-testflight-official
|
||||||
|
|
||||||
# Android Experimental
|
# Android Experimental
|
||||||
|
- android-hold-build-experimental:
|
||||||
|
type: approval
|
||||||
|
requires:
|
||||||
|
- lint-testunit
|
||||||
- android-build-experimental:
|
- android-build-experimental:
|
||||||
requires:
|
requires:
|
||||||
- lint-testunit
|
- android-hold-build-experimental
|
||||||
- android-hold-google-play-beta-experimental:
|
- android-hold-google-play-beta-experimental:
|
||||||
type: approval
|
type: approval
|
||||||
requires:
|
requires:
|
||||||
|
|
|
@ -6,7 +6,7 @@ module.exports = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"parser": "babel-eslint",
|
"parser": "@babel/eslint-parser",
|
||||||
"extends": "airbnb",
|
"extends": "airbnb",
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
"sourceType": "module",
|
"sourceType": "module",
|
||||||
|
@ -21,7 +21,8 @@ module.exports = {
|
||||||
"react",
|
"react",
|
||||||
"jsx-a11y",
|
"jsx-a11y",
|
||||||
"import",
|
"import",
|
||||||
"react-native"
|
"react-native",
|
||||||
|
"@babel"
|
||||||
],
|
],
|
||||||
"env": {
|
"env": {
|
||||||
"browser": true,
|
"browser": true,
|
||||||
|
@ -148,7 +149,8 @@ module.exports = {
|
||||||
"react/jsx-curly-newline": [0],
|
"react/jsx-curly-newline": [0],
|
||||||
"react/state-in-constructor": [0],
|
"react/state-in-constructor": [0],
|
||||||
"no-async-promise-executor": [0],
|
"no-async-promise-executor": [0],
|
||||||
"max-classes-per-file": [0]
|
"max-classes-per-file": [0],
|
||||||
|
"no-multiple-empty-lines": [0]
|
||||||
},
|
},
|
||||||
"globals": {
|
"globals": {
|
||||||
"__DEV__": true
|
"__DEV__": true
|
||||||
|
|
|
@ -44404,6 +44404,309 @@ exports[`Storyshots Message list message 1`] = `
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
<Text
|
||||||
|
style={
|
||||||
|
Array [
|
||||||
|
Object {
|
||||||
|
"fontSize": 20,
|
||||||
|
"fontWeight": "300",
|
||||||
|
"marginLeft": 10,
|
||||||
|
"marginVertical": 30,
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"color": "#0d0e12",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"marginBottom": 0,
|
||||||
|
"marginTop": 30,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Toggle e2e encryption
|
||||||
|
</Text>
|
||||||
|
<View
|
||||||
|
accessible={true}
|
||||||
|
focusable={true}
|
||||||
|
onClick={[Function]}
|
||||||
|
onResponderGrant={[Function]}
|
||||||
|
onResponderMove={[Function]}
|
||||||
|
onResponderRelease={[Function]}
|
||||||
|
onResponderTerminate={[Function]}
|
||||||
|
onResponderTerminationRequest={[Function]}
|
||||||
|
onStartShouldSetResponder={[Function]}
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"opacity": 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<View>
|
||||||
|
<View
|
||||||
|
style={
|
||||||
|
Array [
|
||||||
|
Object {
|
||||||
|
"flexDirection": "column",
|
||||||
|
"paddingHorizontal": 14,
|
||||||
|
"paddingVertical": 4,
|
||||||
|
"width": "100%",
|
||||||
|
},
|
||||||
|
undefined,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<View
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"flexDirection": "row",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<View
|
||||||
|
style={
|
||||||
|
Array [
|
||||||
|
Object {
|
||||||
|
"borderRadius": 2,
|
||||||
|
"height": 20,
|
||||||
|
"width": 20,
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"marginLeft": 16,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<View
|
||||||
|
accessible={true}
|
||||||
|
focusable={true}
|
||||||
|
onClick={[Function]}
|
||||||
|
onResponderGrant={[Function]}
|
||||||
|
onResponderMove={[Function]}
|
||||||
|
onResponderRelease={[Function]}
|
||||||
|
onResponderTerminate={[Function]}
|
||||||
|
onResponderTerminationRequest={[Function]}
|
||||||
|
onStartShouldSetResponder={[Function]}
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"opacity": 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<View
|
||||||
|
style={
|
||||||
|
Array [
|
||||||
|
Object {
|
||||||
|
"overflow": "hidden",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"borderRadius": 2,
|
||||||
|
"height": 20,
|
||||||
|
"width": 20,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<FastImageView
|
||||||
|
resizeMode="cover"
|
||||||
|
source={
|
||||||
|
Object {
|
||||||
|
"headers": undefined,
|
||||||
|
"priority": "high",
|
||||||
|
"uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=20",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"bottom": 0,
|
||||||
|
"left": 0,
|
||||||
|
"position": "absolute",
|
||||||
|
"right": 0,
|
||||||
|
"top": 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<View
|
||||||
|
style={
|
||||||
|
Array [
|
||||||
|
Object {
|
||||||
|
"flex": 1,
|
||||||
|
"marginLeft": 46,
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"marginLeft": 10,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Text
|
||||||
|
accessibilityLabel="This room's encryption has been disabled by diego.mello"
|
||||||
|
style={
|
||||||
|
Array [
|
||||||
|
Object {
|
||||||
|
"backgroundColor": "transparent",
|
||||||
|
"fontFamily": "System",
|
||||||
|
"fontSize": 16,
|
||||||
|
"fontStyle": "italic",
|
||||||
|
"fontWeight": "400",
|
||||||
|
"textAlign": "left",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"color": "#9ca2a8",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
>
|
||||||
|
This room's encryption has been disabled by diego.mello
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<View
|
||||||
|
accessible={true}
|
||||||
|
focusable={true}
|
||||||
|
onClick={[Function]}
|
||||||
|
onResponderGrant={[Function]}
|
||||||
|
onResponderMove={[Function]}
|
||||||
|
onResponderRelease={[Function]}
|
||||||
|
onResponderTerminate={[Function]}
|
||||||
|
onResponderTerminationRequest={[Function]}
|
||||||
|
onStartShouldSetResponder={[Function]}
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"opacity": 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<View>
|
||||||
|
<View
|
||||||
|
style={
|
||||||
|
Array [
|
||||||
|
Object {
|
||||||
|
"flexDirection": "column",
|
||||||
|
"paddingHorizontal": 14,
|
||||||
|
"paddingVertical": 4,
|
||||||
|
"width": "100%",
|
||||||
|
},
|
||||||
|
undefined,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<View
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"flexDirection": "row",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<View
|
||||||
|
style={
|
||||||
|
Array [
|
||||||
|
Object {
|
||||||
|
"borderRadius": 2,
|
||||||
|
"height": 20,
|
||||||
|
"width": 20,
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"marginLeft": 16,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<View
|
||||||
|
accessible={true}
|
||||||
|
focusable={true}
|
||||||
|
onClick={[Function]}
|
||||||
|
onResponderGrant={[Function]}
|
||||||
|
onResponderMove={[Function]}
|
||||||
|
onResponderRelease={[Function]}
|
||||||
|
onResponderTerminate={[Function]}
|
||||||
|
onResponderTerminationRequest={[Function]}
|
||||||
|
onStartShouldSetResponder={[Function]}
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"opacity": 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<View
|
||||||
|
style={
|
||||||
|
Array [
|
||||||
|
Object {
|
||||||
|
"overflow": "hidden",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"borderRadius": 2,
|
||||||
|
"height": 20,
|
||||||
|
"width": 20,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<FastImageView
|
||||||
|
resizeMode="cover"
|
||||||
|
source={
|
||||||
|
Object {
|
||||||
|
"headers": undefined,
|
||||||
|
"priority": "high",
|
||||||
|
"uri": "https://open.rocket.chat/avatar/diego.mello?format=png&size=20",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"bottom": 0,
|
||||||
|
"left": 0,
|
||||||
|
"position": "absolute",
|
||||||
|
"right": 0,
|
||||||
|
"top": 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<View
|
||||||
|
style={
|
||||||
|
Array [
|
||||||
|
Object {
|
||||||
|
"flex": 1,
|
||||||
|
"marginLeft": 46,
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"marginLeft": 10,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Text
|
||||||
|
accessibilityLabel="This room's encryption has been enabled by diego.mello"
|
||||||
|
style={
|
||||||
|
Array [
|
||||||
|
Object {
|
||||||
|
"backgroundColor": "transparent",
|
||||||
|
"fontFamily": "System",
|
||||||
|
"fontSize": 16,
|
||||||
|
"fontStyle": "italic",
|
||||||
|
"fontWeight": "400",
|
||||||
|
"textAlign": "left",
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"color": "#9ca2a8",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
>
|
||||||
|
This room's encryption has been enabled by diego.mello
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
<Text
|
<Text
|
||||||
style={
|
style={
|
||||||
Array [
|
Array [
|
||||||
|
|
|
@ -144,7 +144,7 @@ android {
|
||||||
minSdkVersion rootProject.ext.minSdkVersion
|
minSdkVersion rootProject.ext.minSdkVersion
|
||||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||||
versionCode VERSIONCODE as Integer
|
versionCode VERSIONCODE as Integer
|
||||||
versionName "4.14.1"
|
versionName "4.15.0"
|
||||||
vectorDrawables.useSupportLibrary = true
|
vectorDrawables.useSupportLibrary = true
|
||||||
if (!isFoss) {
|
if (!isFoss) {
|
||||||
manifestPlaceholders = [BugsnagAPIKey: BugsnagAPIKey as String]
|
manifestPlaceholders = [BugsnagAPIKey: BugsnagAPIKey as String]
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
|
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTask"
|
||||||
android:windowSoftInputMode="adjustResize">
|
android:windowSoftInputMode="adjustResize">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
|
<action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
|
||||||
|
|
|
@ -70,3 +70,5 @@ export const SETTINGS = createRequestTypes('SETTINGS', ['CLEAR', 'ADD']);
|
||||||
export const APP_STATE = createRequestTypes('APP_STATE', ['FOREGROUND', 'BACKGROUND']);
|
export const APP_STATE = createRequestTypes('APP_STATE', ['FOREGROUND', 'BACKGROUND']);
|
||||||
export const ENTERPRISE_MODULES = createRequestTypes('ENTERPRISE_MODULES', ['CLEAR', 'SET']);
|
export const ENTERPRISE_MODULES = createRequestTypes('ENTERPRISE_MODULES', ['CLEAR', 'SET']);
|
||||||
export const ENCRYPTION = createRequestTypes('ENCRYPTION', ['INIT', 'STOP', 'DECODE_KEY', 'SET', 'SET_BANNER']);
|
export const ENCRYPTION = createRequestTypes('ENCRYPTION', ['INIT', 'STOP', 'DECODE_KEY', 'SET', 'SET_BANNER']);
|
||||||
|
|
||||||
|
export const PERMISSIONS = createRequestTypes('PERMISSIONS', ['SET']);
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
import * as types from './actionsTypes';
|
||||||
|
|
||||||
|
export function setPermissions(permissions) {
|
||||||
|
return {
|
||||||
|
type: types.PERMISSIONS.SET,
|
||||||
|
permissions
|
||||||
|
};
|
||||||
|
}
|
|
@ -63,6 +63,7 @@ export const themes = {
|
||||||
passcodeDotFull: '#6C727A',
|
passcodeDotFull: '#6C727A',
|
||||||
previewBackground: '#1F2329',
|
previewBackground: '#1F2329',
|
||||||
previewTintColor: '#ffffff',
|
previewTintColor: '#ffffff',
|
||||||
|
backdropOpacity: 0.3,
|
||||||
...mentions
|
...mentions
|
||||||
},
|
},
|
||||||
dark: {
|
dark: {
|
||||||
|
@ -109,6 +110,7 @@ export const themes = {
|
||||||
passcodeDotFull: '#6C727A',
|
passcodeDotFull: '#6C727A',
|
||||||
previewBackground: '#030b1b',
|
previewBackground: '#030b1b',
|
||||||
previewTintColor: '#ffffff',
|
previewTintColor: '#ffffff',
|
||||||
|
backdropOpacity: 0.9,
|
||||||
...mentions
|
...mentions
|
||||||
},
|
},
|
||||||
black: {
|
black: {
|
||||||
|
@ -155,6 +157,7 @@ export const themes = {
|
||||||
passcodeDotFull: '#6C727A',
|
passcodeDotFull: '#6C727A',
|
||||||
previewBackground: '#000000',
|
previewBackground: '#000000',
|
||||||
previewTintColor: '#ffffff',
|
previewTintColor: '#ffffff',
|
||||||
|
backdropOpacity: 0.9,
|
||||||
...mentions
|
...mentions
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -101,6 +101,9 @@ export default {
|
||||||
Jitsi_Enabled_TokenAuth: {
|
Jitsi_Enabled_TokenAuth: {
|
||||||
type: 'valueAsBoolean'
|
type: 'valueAsBoolean'
|
||||||
},
|
},
|
||||||
|
Jitsi_URL_Room_Hash: {
|
||||||
|
type: 'valueAsBoolean'
|
||||||
|
},
|
||||||
Jitsi_URL_Room_Prefix: {
|
Jitsi_URL_Room_Prefix: {
|
||||||
type: 'valueAsString'
|
type: 'valueAsString'
|
||||||
},
|
},
|
||||||
|
|
|
@ -147,7 +147,7 @@ const ActionSheet = React.memo(forwardRef(({ children, theme }, ref) => {
|
||||||
const animatedPosition = React.useRef(new Value(0));
|
const animatedPosition = React.useRef(new Value(0));
|
||||||
const opacity = interpolate(animatedPosition.current, {
|
const opacity = interpolate(animatedPosition.current, {
|
||||||
inputRange: [0, 1],
|
inputRange: [0, 1],
|
||||||
outputRange: [0, 0.7],
|
outputRange: [0, themes[theme].backdropOpacity],
|
||||||
extrapolate: Extrapolate.CLAMP
|
extrapolate: Extrapolate.CLAMP
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { Q } from '@nozbe/watermelondb';
|
import { Q } from '@nozbe/watermelondb';
|
||||||
import isEqual from 'react-fast-compare';
|
|
||||||
|
|
||||||
import database from '../../lib/database';
|
import database from '../../lib/database';
|
||||||
import { getUserSelector } from '../../selectors/login';
|
import { getUserSelector } from '../../selectors/login';
|
||||||
|
@ -34,7 +33,8 @@ class AvatarContainer extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
if (!isEqual(prevProps, this.props)) {
|
const { text, type } = this.props;
|
||||||
|
if (prevProps.text !== text || prevProps.type !== type) {
|
||||||
this.init();
|
this.init();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,8 +52,8 @@ class AvatarContainer extends React.Component {
|
||||||
|
|
||||||
init = async() => {
|
init = async() => {
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const usersCollection = db.collections.get('users');
|
const usersCollection = db.get('users');
|
||||||
const subsCollection = db.collections.get('subscriptions');
|
const subsCollection = db.get('subscriptions');
|
||||||
|
|
||||||
let record;
|
let record;
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React, { Component } from 'react';
|
||||||
import { View } from 'react-native';
|
import { View } from 'react-native';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import ScrollableTabView from 'react-native-scrollable-tab-view';
|
import ScrollableTabView from 'react-native-scrollable-tab-view';
|
||||||
import equal from 'deep-equal';
|
import { dequal } from 'dequal';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import orderBy from 'lodash/orderBy';
|
import orderBy from 'lodash/orderBy';
|
||||||
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
|
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
|
||||||
|
@ -67,7 +67,7 @@ class EmojiPicker extends Component {
|
||||||
if (nextState.width !== width) {
|
if (nextState.width !== width) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!equal(nextState.frequentlyUsed, frequentlyUsed)) {
|
if (!dequal(nextState.frequentlyUsed, frequentlyUsed)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -95,7 +95,7 @@ class EmojiPicker extends Component {
|
||||||
// eslint-disable-next-line react/sort-comp
|
// eslint-disable-next-line react/sort-comp
|
||||||
_addFrequentlyUsed = protectedFunction(async(emoji) => {
|
_addFrequentlyUsed = protectedFunction(async(emoji) => {
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const freqEmojiCollection = db.collections.get('frequently_used_emojis');
|
const freqEmojiCollection = db.get('frequently_used_emojis');
|
||||||
let freqEmojiRecord;
|
let freqEmojiRecord;
|
||||||
try {
|
try {
|
||||||
freqEmojiRecord = await freqEmojiCollection.find(emoji.content);
|
freqEmojiRecord = await freqEmojiCollection.find(emoji.content);
|
||||||
|
@ -120,7 +120,7 @@ class EmojiPicker extends Component {
|
||||||
|
|
||||||
updateFrequentlyUsed = async() => {
|
updateFrequentlyUsed = async() => {
|
||||||
const db = database.active;
|
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']);
|
let frequentlyUsed = orderBy(frequentlyUsedRecords, ['count'], ['desc']);
|
||||||
frequentlyUsed = frequentlyUsed.map((item) => {
|
frequentlyUsed = frequentlyUsed.map((item) => {
|
||||||
if (item.isCustom) {
|
if (item.isCustom) {
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
import React, { memo, useEffect } from 'react';
|
import React, { memo, useEffect } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
import { NotifierRoot, Notifier, Easing } from 'react-native-notifier';
|
import { NotifierRoot, Notifier, Easing } from 'react-native-notifier';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { dequal } from 'dequal';
|
||||||
|
|
||||||
import NotifierComponent from './NotifierComponent';
|
import NotifierComponent from './NotifierComponent';
|
||||||
import EventEmitter from '../../utils/events';
|
import EventEmitter from '../../utils/events';
|
||||||
|
@ -8,13 +11,17 @@ import { getActiveRoute } from '../../utils/navigation';
|
||||||
|
|
||||||
export const INAPP_NOTIFICATION_EMITTER = 'NotificationInApp';
|
export const INAPP_NOTIFICATION_EMITTER = 'NotificationInApp';
|
||||||
|
|
||||||
const InAppNotification = memo(() => {
|
const InAppNotification = memo(({ rooms, appState }) => {
|
||||||
const show = (notification) => {
|
const show = (notification) => {
|
||||||
|
if (appState !== 'foreground') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const { payload } = notification;
|
const { payload } = notification;
|
||||||
const state = Navigation.navigationRef.current?.getRootState();
|
const state = Navigation.navigationRef.current?.getRootState();
|
||||||
const route = getActiveRoute(state);
|
const route = getActiveRoute(state);
|
||||||
if (payload.rid) {
|
if (payload.rid) {
|
||||||
if ((route?.name === 'RoomView' && route.params?.rid === payload.rid) || route?.name === 'JitsiMeetView') {
|
if (rooms.includes(payload.rid) || route?.name === 'JitsiMeetView') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Notifier.showNotification({
|
Notifier.showNotification({
|
||||||
|
@ -28,13 +35,23 @@ const InAppNotification = memo(() => {
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
EventEmitter.addEventListener(INAPP_NOTIFICATION_EMITTER, show);
|
const listener = EventEmitter.addEventListener(INAPP_NOTIFICATION_EMITTER, show);
|
||||||
return () => {
|
return () => {
|
||||||
EventEmitter.removeListener(INAPP_NOTIFICATION_EMITTER);
|
EventEmitter.removeListener(INAPP_NOTIFICATION_EMITTER, listener);
|
||||||
};
|
};
|
||||||
}, []);
|
}, [rooms]);
|
||||||
|
|
||||||
return <NotifierRoot />;
|
return <NotifierRoot />;
|
||||||
|
}, (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);
|
||||||
|
|
|
@ -96,7 +96,7 @@ const Header = React.memo(({
|
||||||
const setEmojis = async() => {
|
const setEmojis = async() => {
|
||||||
try {
|
try {
|
||||||
const db = database.active;
|
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();
|
let freqEmojis = await freqEmojiCollection.query().fetch();
|
||||||
|
|
||||||
const isLandscape = width > height;
|
const isLandscape = width > height;
|
||||||
|
|
|
@ -34,20 +34,24 @@ const MessageActions = React.memo(forwardRef(({
|
||||||
Message_AllowPinning,
|
Message_AllowPinning,
|
||||||
Message_AllowStarring,
|
Message_AllowStarring,
|
||||||
Message_Read_Receipt_Store_Users,
|
Message_Read_Receipt_Store_Users,
|
||||||
isMasterDetail
|
isMasterDetail,
|
||||||
|
editMessagePermission,
|
||||||
|
deleteMessagePermission,
|
||||||
|
forceDeleteMessagePermission,
|
||||||
|
pinMessagePermission
|
||||||
}, ref) => {
|
}, ref) => {
|
||||||
let permissions = {};
|
let permissions = {};
|
||||||
const { showActionSheet, hideActionSheet } = useActionSheet();
|
const { showActionSheet, hideActionSheet } = useActionSheet();
|
||||||
|
|
||||||
const getPermissions = async() => {
|
const getPermissions = async() => {
|
||||||
try {
|
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);
|
const result = await RocketChat.hasPermission(permission, room.rid);
|
||||||
permissions = {
|
permissions = {
|
||||||
hasEditPermission: result[permission[0]],
|
hasEditPermission: result[0],
|
||||||
hasDeletePermission: result[permission[1]],
|
hasDeletePermission: result[1],
|
||||||
hasForceDeletePermission: result[permission[2]],
|
hasForceDeletePermission: result[2],
|
||||||
hasPinPermission: result[permission[3]]
|
hasPinPermission: result[3]
|
||||||
};
|
};
|
||||||
} catch {
|
} catch {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
|
@ -141,7 +145,7 @@ const MessageActions = React.memo(forwardRef(({
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const result = await RocketChat.markAsUnread({ messageId });
|
const result = await RocketChat.markAsUnread({ messageId });
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
const subCollection = db.collections.get('subscriptions');
|
const subCollection = db.get('subscriptions');
|
||||||
const subRecord = await subCollection.find(rid);
|
const subRecord = await subCollection.find(rid);
|
||||||
await db.action(async() => {
|
await db.action(async() => {
|
||||||
try {
|
try {
|
||||||
|
@ -171,7 +175,7 @@ const MessageActions = React.memo(forwardRef(({
|
||||||
|
|
||||||
const handleCopy = async(message) => {
|
const handleCopy = async(message) => {
|
||||||
logEvent(events.ROOM_MSG_ACTION_COPY);
|
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') });
|
EventEmitter.emit(LISTENER, { message: I18n.t('Copied_to_clipboard') });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -440,7 +444,11 @@ MessageActions.propTypes = {
|
||||||
Message_AllowPinning: PropTypes.bool,
|
Message_AllowPinning: PropTypes.bool,
|
||||||
Message_AllowStarring: PropTypes.bool,
|
Message_AllowStarring: PropTypes.bool,
|
||||||
Message_Read_Receipt_Store_Users: 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 => ({
|
const mapStateToProps = state => ({
|
||||||
|
@ -452,7 +460,11 @@ const mapStateToProps = state => ({
|
||||||
Message_AllowPinning: state.settings.Message_AllowPinning,
|
Message_AllowPinning: state.settings.Message_AllowPinning,
|
||||||
Message_AllowStarring: state.settings.Message_AllowStarring,
|
Message_AllowStarring: state.settings.Message_AllowStarring,
|
||||||
Message_Read_Receipt_Store_Users: state.settings.Message_Read_Receipt_Store_Users,
|
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);
|
export default connect(mapStateToProps, null, null, { forwardRef: true })(MessageActions);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { FlatList } from 'react-native';
|
import { FlatList } from 'react-native';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import equal from 'deep-equal';
|
import { dequal } from 'dequal';
|
||||||
|
|
||||||
import Item from './Item';
|
import Item from './Item';
|
||||||
import styles from '../styles';
|
import styles from '../styles';
|
||||||
|
@ -31,7 +31,7 @@ const CommandsPreview = React.memo(({ theme, commandPreview, showCommandPreview
|
||||||
if (prevProps.showCommandPreview !== nextProps.showCommandPreview) {
|
if (prevProps.showCommandPreview !== nextProps.showCommandPreview) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!equal(prevProps.commandPreview, nextProps.commandPreview)) {
|
if (!dequal(prevProps.commandPreview, nextProps.commandPreview)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { FlatList, View } from 'react-native';
|
import { FlatList, View } from 'react-native';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import equal from 'deep-equal';
|
import { dequal } from 'dequal';
|
||||||
|
|
||||||
import styles from '../styles';
|
import styles from '../styles';
|
||||||
import MentionItem from './MentionItem';
|
import MentionItem from './MentionItem';
|
||||||
|
@ -30,7 +30,7 @@ const Mentions = React.memo(({ mentions, trackingType, theme }) => {
|
||||||
if (prevProps.trackingType !== nextProps.trackingType) {
|
if (prevProps.trackingType !== nextProps.trackingType) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!equal(prevProps.mentions, nextProps.mentions)) {
|
if (!dequal(prevProps.mentions, nextProps.mentions)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -3,7 +3,6 @@ import { View, Text, StyleSheet } from 'react-native';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import isEqual from 'lodash/isEqual';
|
|
||||||
|
|
||||||
import Markdown from '../markdown';
|
import Markdown from '../markdown';
|
||||||
import { CustomIcon } from '../../lib/Icons';
|
import { CustomIcon } from '../../lib/Icons';
|
||||||
|
@ -43,7 +42,7 @@ const styles = StyleSheet.create({
|
||||||
});
|
});
|
||||||
|
|
||||||
const ReplyPreview = React.memo(({
|
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) {
|
if (!replying) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -59,7 +58,7 @@ const ReplyPreview = React.memo(({
|
||||||
>
|
>
|
||||||
<View style={[styles.messageContainer, { backgroundColor: themes[theme].chatComponentBackground }]}>
|
<View style={[styles.messageContainer, { backgroundColor: themes[theme].chatComponentBackground }]}>
|
||||||
<View style={styles.header}>
|
<View style={styles.header}>
|
||||||
<Text style={[styles.username, { color: themes[theme].tintColor }]}>{message.u?.username}</Text>
|
<Text style={[styles.username, { color: themes[theme].tintColor }]}>{useRealName ? message.u?.name : message.u?.username}</Text>
|
||||||
<Text style={[styles.time, { color: themes[theme].auxiliaryText }]}>{time}</Text>
|
<Text style={[styles.time, { color: themes[theme].auxiliaryText }]}>{time}</Text>
|
||||||
</View>
|
</View>
|
||||||
<Markdown
|
<Markdown
|
||||||
|
@ -75,7 +74,7 @@ const ReplyPreview = React.memo(({
|
||||||
<CustomIcon name='close' color={themes[theme].auxiliaryText} size={20} style={styles.close} onPress={close} />
|
<CustomIcon name='close' color={themes[theme].auxiliaryText} size={20} style={styles.close} onPress={close} />
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}, (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 = {
|
ReplyPreview.propTypes = {
|
||||||
replying: PropTypes.bool,
|
replying: PropTypes.bool,
|
||||||
|
@ -85,12 +84,14 @@ ReplyPreview.propTypes = {
|
||||||
baseUrl: PropTypes.string.isRequired,
|
baseUrl: PropTypes.string.isRequired,
|
||||||
username: PropTypes.string.isRequired,
|
username: PropTypes.string.isRequired,
|
||||||
getCustomEmoji: PropTypes.func,
|
getCustomEmoji: PropTypes.func,
|
||||||
theme: PropTypes.string
|
theme: PropTypes.string,
|
||||||
|
useRealName: PropTypes.bool
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
Message_TimeFormat: state.settings.Message_TimeFormat,
|
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);
|
export default connect(mapStateToProps)(ReplyPreview);
|
||||||
|
|
|
@ -6,7 +6,7 @@ import {
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { KeyboardAccessoryView } from 'react-native-ui-lib/keyboard';
|
import { KeyboardAccessoryView } from 'react-native-ui-lib/keyboard';
|
||||||
import ImagePicker from 'react-native-image-crop-picker';
|
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 DocumentPicker from 'react-native-document-picker';
|
||||||
import { Q } from '@nozbe/watermelondb';
|
import { Q } from '@nozbe/watermelondb';
|
||||||
import { TouchableWithoutFeedback } from 'react-native-gesture-handler';
|
import { TouchableWithoutFeedback } from 'react-native-gesture-handler';
|
||||||
|
@ -63,6 +63,7 @@ const imagePickerConfig = {
|
||||||
|
|
||||||
const libraryPickerConfig = {
|
const libraryPickerConfig = {
|
||||||
multiple: true,
|
multiple: true,
|
||||||
|
compressVideoPreset: 'Passthrough',
|
||||||
mediaType: 'any'
|
mediaType: 'any'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -189,8 +190,8 @@ class MessageBox extends Component {
|
||||||
} = this.props;
|
} = this.props;
|
||||||
let msg;
|
let msg;
|
||||||
try {
|
try {
|
||||||
const threadsCollection = db.collections.get('threads');
|
const threadsCollection = db.get('threads');
|
||||||
const subsCollection = db.collections.get('subscriptions');
|
const subsCollection = db.get('subscriptions');
|
||||||
try {
|
try {
|
||||||
this.room = await subsCollection.find(rid);
|
this.room = await subsCollection.find(rid);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -270,7 +271,7 @@ class MessageBox extends Component {
|
||||||
} = this.state;
|
} = this.state;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
roomType, replying, editing, isFocused, message, theme, children
|
roomType, replying, editing, isFocused, message, theme
|
||||||
} = this.props;
|
} = this.props;
|
||||||
if (nextProps.theme !== theme) {
|
if (nextProps.theme !== theme) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -299,16 +300,13 @@ class MessageBox extends Component {
|
||||||
if (nextState.tshow !== tshow) {
|
if (nextState.tshow !== tshow) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!equal(nextState.mentions, mentions)) {
|
if (!dequal(nextState.mentions, mentions)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!equal(nextState.commandPreview, commandPreview)) {
|
if (!dequal(nextState.commandPreview, commandPreview)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!equal(nextProps.message, message)) {
|
if (!dequal(nextProps.message?.id, message?.id)) {
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!equal(nextProps.children, children)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -366,7 +364,7 @@ class MessageBox extends Component {
|
||||||
const slashCommand = text.match(/^\/([a-z0-9._-]+) (.+)/im);
|
const slashCommand = text.match(/^\/([a-z0-9._-]+) (.+)/im);
|
||||||
if (slashCommand) {
|
if (slashCommand) {
|
||||||
const [, name, params] = slashCommand;
|
const [, name, params] = slashCommand;
|
||||||
const commandsCollection = db.collections.get('slash_commands');
|
const commandsCollection = db.get('slash_commands');
|
||||||
try {
|
try {
|
||||||
const command = await commandsCollection.find(name);
|
const command = await commandsCollection.find(name);
|
||||||
if (command.providesPreview) {
|
if (command.providesPreview) {
|
||||||
|
@ -507,7 +505,7 @@ class MessageBox extends Component {
|
||||||
getEmojis = debounce(async(keyword) => {
|
getEmojis = debounce(async(keyword) => {
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
if (keyword) {
|
if (keyword) {
|
||||||
const customEmojisCollection = db.collections.get('custom_emojis');
|
const customEmojisCollection = db.get('custom_emojis');
|
||||||
const likeString = sanitizeLikeString(keyword);
|
const likeString = sanitizeLikeString(keyword);
|
||||||
let customEmojis = await customEmojisCollection.query(
|
let customEmojis = await customEmojisCollection.query(
|
||||||
Q.where('name', Q.like(`${ likeString }%`))
|
Q.where('name', Q.like(`${ likeString }%`))
|
||||||
|
@ -521,7 +519,7 @@ class MessageBox extends Component {
|
||||||
|
|
||||||
getSlashCommands = debounce(async(keyword) => {
|
getSlashCommands = debounce(async(keyword) => {
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const commandsCollection = db.collections.get('slash_commands');
|
const commandsCollection = db.get('slash_commands');
|
||||||
const likeString = sanitizeLikeString(keyword);
|
const likeString = sanitizeLikeString(keyword);
|
||||||
const commands = await commandsCollection.query(
|
const commands = await commandsCollection.query(
|
||||||
Q.where('id', Q.like(`${ likeString }%`))
|
Q.where('id', Q.like(`${ likeString }%`))
|
||||||
|
@ -753,7 +751,7 @@ class MessageBox extends Component {
|
||||||
// Slash command
|
// Slash command
|
||||||
if (message[0] === MENTIONS_TRACKING_TYPE_COMMANDS) {
|
if (message[0] === MENTIONS_TRACKING_TYPE_COMMANDS) {
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const commandsCollection = db.collections.get('slash_commands');
|
const commandsCollection = db.get('slash_commands');
|
||||||
const command = message.replace(/ .*/, '').slice(1);
|
const command = message.replace(/ .*/, '').slice(1);
|
||||||
const likeString = sanitizeLikeString(command);
|
const likeString = sanitizeLikeString(command);
|
||||||
const slashCommand = await commandsCollection.query(
|
const slashCommand = await commandsCollection.query(
|
||||||
|
@ -941,7 +939,7 @@ class MessageBox extends Component {
|
||||||
keyboardType='twitter'
|
keyboardType='twitter'
|
||||||
blurOnSubmit={false}
|
blurOnSubmit={false}
|
||||||
placeholder={I18n.t('New_Message')}
|
placeholder={I18n.t('New_Message')}
|
||||||
placeholderTextColor={themes[theme].auxiliaryTintColor}
|
placeholderTextColor={themes[theme].auxiliaryText}
|
||||||
onChangeText={this.onChangeText}
|
onChangeText={this.onChangeText}
|
||||||
onSelectionChange={this.onSelectionChange}
|
onSelectionChange={this.onSelectionChange}
|
||||||
underlineColorAndroid='transparent'
|
underlineColorAndroid='transparent'
|
||||||
|
|
|
@ -19,8 +19,8 @@ const MessageErrorActions = forwardRef(({ tmid }, ref) => {
|
||||||
try {
|
try {
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const deleteBatch = [];
|
const deleteBatch = [];
|
||||||
const msgCollection = db.collections.get('messages');
|
const msgCollection = db.get('messages');
|
||||||
const threadCollection = db.collections.get('threads');
|
const threadCollection = db.get('threads');
|
||||||
|
|
||||||
// Delete the object (it can be Message or ThreadMessage instance)
|
// Delete the object (it can be Message or ThreadMessage instance)
|
||||||
deleteBatch.push(message.prepareDestroyPermanently());
|
deleteBatch.push(message.prepareDestroyPermanently());
|
||||||
|
|
|
@ -28,7 +28,7 @@ class Toast extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
EventEmitter.addEventListener(LISTENER, this.showToast);
|
this.listener = EventEmitter.addEventListener(LISTENER, this.showToast);
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps) {
|
shouldComponentUpdate(nextProps) {
|
||||||
|
@ -40,7 +40,7 @@ class Toast extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
EventEmitter.removeListener(LISTENER);
|
EventEmitter.removeListener(LISTENER, this.listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
getToastRef = toast => this.toast = toast;
|
getToastRef = toast => this.toast = toast;
|
||||||
|
|
|
@ -58,9 +58,9 @@ const TwoFactor = React.memo(({ theme, isMasterDetail }) => {
|
||||||
const showTwoFactor = args => setData(args);
|
const showTwoFactor = args => setData(args);
|
||||||
|
|
||||||
useEffect(() => {
|
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 = () => {
|
const onCancel = () => {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import {
|
import {
|
||||||
View, Text, TouchableWithoutFeedback, Modal, KeyboardAvoidingView, Animated, Easing
|
View, Text, TouchableWithoutFeedback, Modal, KeyboardAvoidingView, Animated, Easing, StyleSheet
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { BLOCK_CONTEXT } from '@rocket.chat/ui-kit';
|
import { BLOCK_CONTEXT } from '@rocket.chat/ui-kit';
|
||||||
|
@ -172,7 +172,7 @@ export const MultiSelect = React.memo(({
|
||||||
>
|
>
|
||||||
<TouchableWithoutFeedback onPress={onHide}>
|
<TouchableWithoutFeedback onPress={onHide}>
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<View style={[styles.backdrop, { backgroundColor: themes[theme].backdropColor }]} />
|
<View style={{ ...StyleSheet.absoluteFill, opacity: themes[theme].backdropOpacity, backgroundColor: themes[theme].backdropColor }} />
|
||||||
<KeyboardAvoidingView style={styles.keyboardView} behavior={behavior}>
|
<KeyboardAvoidingView style={styles.keyboardView} behavior={behavior}>
|
||||||
<Animated.View style={[styles.animatedContent, { transform: [{ translateY }] }]}>
|
<Animated.View style={[styles.animatedContent, { transform: [{ translateY }] }]}>
|
||||||
{showContent ? renderContent() : null}
|
{showContent ? renderContent() : null}
|
||||||
|
|
|
@ -8,10 +8,6 @@ export default StyleSheet.create({
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'flex-end'
|
justifyContent: 'flex-end'
|
||||||
},
|
},
|
||||||
backdrop: {
|
|
||||||
...StyleSheet.absoluteFill,
|
|
||||||
opacity: 0.3
|
|
||||||
},
|
|
||||||
modal: {
|
modal: {
|
||||||
height: 300,
|
height: 300,
|
||||||
width: '100%',
|
width: '100%',
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import isEqual from 'lodash/isEqual';
|
import { dequal } from 'dequal';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import Image from './Image';
|
import Image from './Image';
|
||||||
|
@ -28,7 +28,7 @@ const Attachments = React.memo(({
|
||||||
// eslint-disable-next-line react/no-array-index-key
|
// eslint-disable-next-line react/no-array-index-key
|
||||||
return <Reply key={index} index={index} attachment={file} timeFormat={timeFormat} getCustomEmoji={getCustomEmoji} theme={theme} />;
|
return <Reply key={index} index={index} attachment={file} timeFormat={timeFormat} getCustomEmoji={getCustomEmoji} theme={theme} />;
|
||||||
});
|
});
|
||||||
}, (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 = {
|
||||||
attachments: PropTypes.array,
|
attachments: PropTypes.array,
|
||||||
|
|
|
@ -6,7 +6,7 @@ import {
|
||||||
import { Audio } from 'expo-av';
|
import { Audio } from 'expo-av';
|
||||||
import Slider from '@react-native-community/slider';
|
import Slider from '@react-native-community/slider';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import equal from 'deep-equal';
|
import { dequal } from 'dequal';
|
||||||
import { activateKeepAwake, deactivateKeepAwake } from 'expo-keep-awake';
|
import { activateKeepAwake, deactivateKeepAwake } from 'expo-keep-awake';
|
||||||
|
|
||||||
import Touchable from './Touchable';
|
import Touchable from './Touchable';
|
||||||
|
@ -150,7 +150,7 @@ class MessageAudio extends React.Component {
|
||||||
if (nextState.paused !== paused) {
|
if (nextState.paused !== paused) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!equal(nextProps.file, file)) {
|
if (!dequal(nextProps.file, file)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (nextState.loading !== loading) {
|
if (nextState.loading !== loading) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
import { Text, View } from 'react-native';
|
import { Text, View } from 'react-native';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import equal from 'deep-equal';
|
import { dequal } from 'dequal';
|
||||||
|
|
||||||
import I18n from '../../i18n';
|
import I18n from '../../i18n';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
|
@ -108,10 +108,10 @@ const Content = React.memo((props) => {
|
||||||
if (prevProps.isIgnored !== nextProps.isIgnored) {
|
if (prevProps.isIgnored !== nextProps.isIgnored) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!equal(prevProps.mentions, nextProps.mentions)) {
|
if (!dequal(prevProps.mentions, nextProps.mentions)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!equal(prevProps.channels, nextProps.channels)) {
|
if (!dequal(prevProps.channels, nextProps.channels)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React, { useContext } from 'react';
|
||||||
import { View } from 'react-native';
|
import { View } from 'react-native';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import FastImage from '@rocket.chat/react-native-fast-image';
|
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 { createImageProgress } from 'react-native-image-progress';
|
||||||
import * as Progress from 'react-native-progress';
|
import * as Progress from 'react-native-progress';
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ const ImageContainer = React.memo(({
|
||||||
<MessageImage img={img} theme={theme} />
|
<MessageImage img={img} theme={theme} />
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
}, (prevProps, nextProps) => equal(prevProps.file, nextProps.file) && prevProps.theme === nextProps.theme);
|
}, (prevProps, nextProps) => dequal(prevProps.file, nextProps.file) && prevProps.theme === nextProps.theme);
|
||||||
|
|
||||||
ImageContainer.propTypes = {
|
ImageContainer.propTypes = {
|
||||||
file: PropTypes.object,
|
file: PropTypes.object,
|
||||||
|
|
|
@ -119,7 +119,7 @@ const MessageTouchable = React.memo((props) => {
|
||||||
<Touchable
|
<Touchable
|
||||||
onLongPress={onLongPress}
|
onLongPress={onLongPress}
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
disabled={props.isInfo || props.archived || props.isTemp}
|
disabled={(props.isInfo && !props.isThreadReply) || props.archived || props.isTemp}
|
||||||
>
|
>
|
||||||
<View>
|
<View>
|
||||||
<Message {...props} />
|
<Message {...props} />
|
||||||
|
@ -132,6 +132,7 @@ MessageTouchable.displayName = 'MessageTouchable';
|
||||||
MessageTouchable.propTypes = {
|
MessageTouchable.propTypes = {
|
||||||
hasError: PropTypes.bool,
|
hasError: PropTypes.bool,
|
||||||
isInfo: PropTypes.bool,
|
isInfo: PropTypes.bool,
|
||||||
|
isThreadReply: PropTypes.bool,
|
||||||
isTemp: PropTypes.bool,
|
isTemp: PropTypes.bool,
|
||||||
archived: PropTypes.bool
|
archived: PropTypes.bool
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React, { useContext } from 'react';
|
||||||
import { View, Text, StyleSheet } from 'react-native';
|
import { View, Text, StyleSheet } from 'react-native';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import isEqual from 'deep-equal';
|
import { dequal } from 'dequal';
|
||||||
|
|
||||||
import Touchable from './Touchable';
|
import Touchable from './Touchable';
|
||||||
import Markdown from '../markdown';
|
import Markdown from '../markdown';
|
||||||
|
@ -125,7 +125,7 @@ const Fields = React.memo(({ attachment, theme }) => {
|
||||||
))}
|
))}
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}, (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(({
|
const Reply = React.memo(({
|
||||||
attachment, timeFormat, index, getCustomEmoji, theme
|
attachment, timeFormat, index, getCustomEmoji, theme
|
||||||
|
@ -172,7 +172,6 @@ const Reply = React.memo(({
|
||||||
/>
|
/>
|
||||||
<Description
|
<Description
|
||||||
attachment={attachment}
|
attachment={attachment}
|
||||||
timeFormat={timeFormat}
|
|
||||||
getCustomEmoji={getCustomEmoji}
|
getCustomEmoji={getCustomEmoji}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
/>
|
/>
|
||||||
|
@ -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 = {
|
Reply.propTypes = {
|
||||||
attachment: PropTypes.object,
|
attachment: PropTypes.object,
|
||||||
|
|
|
@ -4,7 +4,7 @@ import {
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import FastImage from '@rocket.chat/react-native-fast-image';
|
import FastImage from '@rocket.chat/react-native-fast-image';
|
||||||
import isEqual from 'lodash/isEqual';
|
import { dequal } from 'dequal';
|
||||||
|
|
||||||
import Touchable from './Touchable';
|
import Touchable from './Touchable';
|
||||||
import openLink from '../../utils/openLink';
|
import openLink from '../../utils/openLink';
|
||||||
|
@ -112,7 +112,7 @@ const Url = React.memo(({ url, index, theme }) => {
|
||||||
</>
|
</>
|
||||||
</Touchable>
|
</Touchable>
|
||||||
);
|
);
|
||||||
}, (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 }) => {
|
const Urls = React.memo(({ urls, theme }) => {
|
||||||
if (!urls || urls.length === 0) {
|
if (!urls || urls.length === 0) {
|
||||||
|
@ -122,7 +122,7 @@ const Urls = React.memo(({ urls, theme }) => {
|
||||||
return urls.map((url, index) => (
|
return urls.map((url, index) => (
|
||||||
<Url url={url} key={url.url} index={index} theme={theme} />
|
<Url url={url} key={url.url} index={index} theme={theme} />
|
||||||
));
|
));
|
||||||
}, (oldProps, newProps) => isEqual(oldProps.urls, newProps.urls) && oldProps.theme === newProps.theme);
|
}, (oldProps, newProps) => dequal(oldProps.urls, newProps.urls) && oldProps.theme === newProps.theme);
|
||||||
|
|
||||||
UrlImage.propTypes = {
|
UrlImage.propTypes = {
|
||||||
image: PropTypes.string
|
image: PropTypes.string
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { StyleSheet } from 'react-native';
|
import { StyleSheet } from 'react-native';
|
||||||
import isEqual from 'deep-equal';
|
import { dequal } from 'dequal';
|
||||||
|
|
||||||
import Touchable from './Touchable';
|
import Touchable from './Touchable';
|
||||||
import Markdown from '../markdown';
|
import Markdown from '../markdown';
|
||||||
|
@ -57,7 +57,7 @@ const Video = React.memo(({
|
||||||
<Markdown msg={file.description} baseUrl={baseUrl} username={user.username} getCustomEmoji={getCustomEmoji} theme={theme} />
|
<Markdown msg={file.description} baseUrl={baseUrl} username={user.username} getCustomEmoji={getCustomEmoji} theme={theme} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}, (prevProps, nextProps) => isEqual(prevProps.file, nextProps.file) && prevProps.theme === nextProps.theme);
|
}, (prevProps, nextProps) => dequal(prevProps.file, nextProps.file) && prevProps.theme === nextProps.theme);
|
||||||
|
|
||||||
Video.propTypes = {
|
Video.propTypes = {
|
||||||
file: PropTypes.object,
|
file: PropTypes.object,
|
||||||
|
|
|
@ -37,7 +37,9 @@ export const SYSTEM_MESSAGES = [
|
||||||
'room_changed_privacy',
|
'room_changed_privacy',
|
||||||
'room_changed_avatar',
|
'room_changed_avatar',
|
||||||
'message_snippeted',
|
'message_snippeted',
|
||||||
'thread-created'
|
'thread-created',
|
||||||
|
'room_e2e_enabled',
|
||||||
|
'room_e2e_disabled'
|
||||||
];
|
];
|
||||||
|
|
||||||
export const SYSTEM_MESSAGE_TYPES = {
|
export const SYSTEM_MESSAGE_TYPES = {
|
||||||
|
@ -100,6 +102,10 @@ export const getInfoMessage = ({
|
||||||
return I18n.t('Room_changed_avatar', { userBy: username });
|
return I18n.t('Room_changed_avatar', { userBy: username });
|
||||||
} else if (type === 'message_snippeted') {
|
} else if (type === 'message_snippeted') {
|
||||||
return I18n.t('Created_snippet');
|
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 '';
|
return '';
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { FlatList } from 'react-native';
|
import { FlatList } from 'react-native';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import isEqual from 'react-fast-compare';
|
import { dequal } from 'dequal';
|
||||||
|
|
||||||
import I18n from '../../../i18n';
|
import I18n from '../../../i18n';
|
||||||
import RoomItem, { ROW_HEIGHT } from '../../../presentation/RoomItem';
|
import RoomItem, { ROW_HEIGHT } from '../../../presentation/RoomItem';
|
||||||
|
@ -56,7 +56,7 @@ class QueueListView extends React.Component {
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps) {
|
shouldComponentUpdate(nextProps) {
|
||||||
const { queued } = this.props;
|
const { queued } = this.props;
|
||||||
if (!isEqual(nextProps.queued, queued)) {
|
if (!dequal(nextProps.queued, queued)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -704,5 +704,7 @@ export default {
|
||||||
Direct_message: 'Direct message',
|
Direct_message: 'Direct message',
|
||||||
Message_Ignored: 'Message ignored. Tap to display it.',
|
Message_Ignored: 'Message ignored. Tap to display it.',
|
||||||
Enter_workspace_URL: 'Enter workspace URL',
|
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}}'
|
||||||
};
|
};
|
||||||
|
|
|
@ -651,5 +651,7 @@ export default {
|
||||||
Direct_message: 'Mensagem direta',
|
Direct_message: 'Mensagem direta',
|
||||||
Message_Ignored: 'Mensagem ignorada. Toque para mostrar.',
|
Message_Ignored: 'Mensagem ignorada. Toque para mostrar.',
|
||||||
Enter_workspace_URL: 'Digite a URL da sua workspace',
|
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}}'
|
||||||
};
|
};
|
||||||
|
|
|
@ -678,5 +678,31 @@ export default {
|
||||||
No_threads: 'Тредов нет',
|
No_threads: 'Тредов нет',
|
||||||
No_threads_following: 'Нет тредов, за которыми вы следите',
|
No_threads_following: 'Нет тредов, за которыми вы следите',
|
||||||
No_threads_unread: 'Непрочитанных тредов нет',
|
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}}'
|
||||||
};
|
};
|
||||||
|
|
21
app/index.js
21
app/index.js
|
@ -112,16 +112,25 @@ export default class Root extends React.Component {
|
||||||
|
|
||||||
init = async() => {
|
init = async() => {
|
||||||
UserPreferences.getMapAsync(THEME_PREFERENCES_KEY).then(this.setTheme);
|
UserPreferences.getMapAsync(THEME_PREFERENCES_KEY).then(this.setTheme);
|
||||||
const [notification, deepLinking] = await Promise.all([initializePushNotifications(), Linking.getInitialURL()]);
|
|
||||||
const parsedDeepLinkingURL = parseDeepLinking(deepLinking);
|
|
||||||
store.dispatch(appInitLocalSettings());
|
store.dispatch(appInitLocalSettings());
|
||||||
|
|
||||||
|
// Open app from push notification
|
||||||
|
const notification = await initializePushNotifications();
|
||||||
if (notification) {
|
if (notification) {
|
||||||
onNotification(notification);
|
onNotification(notification);
|
||||||
} else if (parsedDeepLinkingURL) {
|
return;
|
||||||
store.dispatch(deepLinkingOpen(parsedDeepLinkingURL));
|
|
||||||
} else {
|
|
||||||
store.dispatch(appInit());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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) => {
|
getMasterDetail = (width) => {
|
||||||
|
|
|
@ -229,9 +229,9 @@ class Encryption {
|
||||||
decryptPendingMessages = async(roomId) => {
|
decryptPendingMessages = async(roomId) => {
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
|
|
||||||
const messagesCollection = db.collections.get('messages');
|
const messagesCollection = db.get('messages');
|
||||||
const threadsCollection = db.collections.get('threads');
|
const threadsCollection = db.get('threads');
|
||||||
const threadMessagesCollection = db.collections.get('thread_messages');
|
const threadMessagesCollection = db.get('thread_messages');
|
||||||
|
|
||||||
// e2e status is null or 'pending' and message type is 'e2e'
|
// e2e status is null or 'pending' and message type is 'e2e'
|
||||||
const whereClause = [
|
const whereClause = [
|
||||||
|
@ -286,7 +286,7 @@ class Encryption {
|
||||||
// after initialize the encryption client
|
// after initialize the encryption client
|
||||||
decryptPendingSubscriptions = async() => {
|
decryptPendingSubscriptions = async() => {
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const subCollection = db.collections.get('subscriptions');
|
const subCollection = db.get('subscriptions');
|
||||||
try {
|
try {
|
||||||
// Find all rooms that can have a lastMessage encrypted
|
// 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
|
// 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 { rid } = subscription;
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const subCollection = db.collections.get('subscriptions');
|
const subCollection = db.get('subscriptions');
|
||||||
|
|
||||||
let subRecord;
|
let subRecord;
|
||||||
try {
|
try {
|
||||||
|
@ -400,7 +400,7 @@ class Encryption {
|
||||||
encryptMessage = async(message) => {
|
encryptMessage = async(message) => {
|
||||||
const { rid } = message;
|
const { rid } = message;
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const subCollection = db.collections.get('subscriptions');
|
const subCollection = db.get('subscriptions');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Find the subscription
|
// Find the subscription
|
||||||
|
|
|
@ -49,7 +49,7 @@ export default class EncryptionRoom {
|
||||||
}
|
}
|
||||||
|
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const subCollection = db.collections.get('subscriptions');
|
const subCollection = db.get('subscriptions');
|
||||||
try {
|
try {
|
||||||
// Find the subscription
|
// Find the subscription
|
||||||
const subscription = await subCollection.find(this.roomId);
|
const subscription = await subCollection.find(this.roomId);
|
||||||
|
|
|
@ -2,7 +2,7 @@ import reduxStore from '../createStore';
|
||||||
import Navigation from '../Navigation';
|
import Navigation from '../Navigation';
|
||||||
import { logEvent, events } from '../../utils/log';
|
import { logEvent, events } from '../../utils/log';
|
||||||
|
|
||||||
async function jitsiURL({ rid }) {
|
async function jitsiURL({ room }) {
|
||||||
const { settings } = reduxStore.getState();
|
const { settings } = reduxStore.getState();
|
||||||
const { Jitsi_Enabled } = settings;
|
const { Jitsi_Enabled } = settings;
|
||||||
|
|
||||||
|
@ -11,31 +11,37 @@ async function jitsiURL({ rid }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const {
|
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;
|
} = settings;
|
||||||
|
|
||||||
const domain = `${ Jitsi_Domain }/`;
|
const domain = `${ Jitsi_Domain }/`;
|
||||||
const prefix = Jitsi_URL_Room_Prefix;
|
const prefix = Jitsi_URL_Room_Prefix;
|
||||||
const uniqueIdentifier = uniqueID || 'undefined';
|
|
||||||
const protocol = Jitsi_SSL ? 'https://' : 'http://';
|
const protocol = Jitsi_SSL ? 'https://' : 'http://';
|
||||||
|
|
||||||
let queryString = '';
|
let queryString = '';
|
||||||
if (Jitsi_Enabled_TokenAuth) {
|
if (Jitsi_Enabled_TokenAuth) {
|
||||||
try {
|
try {
|
||||||
const accessToken = await this.methodCallWrapper('jitsi:generateAccessToken', rid);
|
const accessToken = await this.methodCallWrapper('jitsi:generateAccessToken', room?.rid);
|
||||||
queryString = `?jwt=${ accessToken }`;
|
queryString = `?jwt=${ accessToken }`;
|
||||||
} catch {
|
} catch {
|
||||||
logEvent(events.RA_JITSI_F);
|
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);
|
logEvent(onlyAudio ? events.RA_JITSI_AUDIO : events.RA_JITSI_VIDEO);
|
||||||
const url = await jitsiURL.call(this, { rid });
|
const url = await jitsiURL.call(this, { room });
|
||||||
Navigation.navigate('JitsiMeetView', { url, onlyAudio, rid });
|
Navigation.navigate('JitsiMeetView', { url, onlyAudio, rid: room?.rid });
|
||||||
}
|
}
|
||||||
|
|
||||||
export default callJitsi;
|
export default callJitsi;
|
||||||
|
|
|
@ -57,7 +57,7 @@ async function open({ type, rid, name }) {
|
||||||
export default async function canOpenRoom({ rid, path, isCall }) {
|
export default async function canOpenRoom({ rid, path, isCall }) {
|
||||||
try {
|
try {
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const subsCollection = db.collections.get('subscriptions');
|
const subsCollection = db.get('subscriptions');
|
||||||
|
|
||||||
if (isCall && !rid) {
|
if (isCall && !rid) {
|
||||||
// Extract rid from a Jitsi URL
|
// Extract rid from a Jitsi URL
|
||||||
|
@ -75,7 +75,8 @@ export default async function canOpenRoom({ rid, path, isCall }) {
|
||||||
name: room.name,
|
name: room.name,
|
||||||
fname: room.fname,
|
fname: room.fname,
|
||||||
prid: room.prid,
|
prid: room.prid,
|
||||||
uids: room.uids
|
uids: room.uids,
|
||||||
|
usernames: room.usernames
|
||||||
};
|
};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
|
|
|
@ -13,7 +13,7 @@ export async function setEnterpriseModules() {
|
||||||
try {
|
try {
|
||||||
const { server: serverId } = reduxStore.getState().server;
|
const { server: serverId } = reduxStore.getState().server;
|
||||||
const serversDB = database.servers;
|
const serversDB = database.servers;
|
||||||
const serversCollection = serversDB.collections.get('servers');
|
const serversCollection = serversDB.get('servers');
|
||||||
let server;
|
let server;
|
||||||
try {
|
try {
|
||||||
server = await serversCollection.find(serverId);
|
server = await serversCollection.find(serverId);
|
||||||
|
@ -39,7 +39,7 @@ export function getEnterpriseModules() {
|
||||||
const enterpriseModules = await this.methodCallWrapper('license:getModules');
|
const enterpriseModules = await this.methodCallWrapper('license:getModules');
|
||||||
if (enterpriseModules) {
|
if (enterpriseModules) {
|
||||||
const serversDB = database.servers;
|
const serversDB = database.servers;
|
||||||
const serversCollection = serversDB.collections.get('servers');
|
const serversCollection = serversDB.get('servers');
|
||||||
const server = await serversCollection.find(serverId);
|
const server = await serversCollection.find(serverId);
|
||||||
await serversDB.action(async() => {
|
await serversDB.action(async() => {
|
||||||
await server.update((s) => {
|
await server.update((s) => {
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import { InteractionManager } from 'react-native';
|
|
||||||
import lt from 'semver/functions/lt';
|
import lt from 'semver/functions/lt';
|
||||||
import orderBy from 'lodash/orderBy';
|
import orderBy from 'lodash/orderBy';
|
||||||
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
|
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
|
||||||
|
@ -21,7 +20,7 @@ const updateEmojis = async({ update = [], remove = [], allRecords }) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const emojisCollection = db.collections.get('custom_emojis');
|
const emojisCollection = db.get('custom_emojis');
|
||||||
let emojisToCreate = [];
|
let emojisToCreate = [];
|
||||||
let emojisToUpdate = [];
|
let emojisToUpdate = [];
|
||||||
let emojisToDelete = [];
|
let emojisToDelete = [];
|
||||||
|
@ -63,7 +62,7 @@ const updateEmojis = async({ update = [], remove = [], allRecords }) => {
|
||||||
|
|
||||||
export async function setCustomEmojis() {
|
export async function setCustomEmojis() {
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const emojisCollection = db.collections.get('custom_emojis');
|
const emojisCollection = db.get('custom_emojis');
|
||||||
const allEmojis = await emojisCollection.query().fetch();
|
const allEmojis = await emojisCollection.query().fetch();
|
||||||
const parsed = allEmojis.reduce((ret, item) => {
|
const parsed = allEmojis.reduce((ret, item) => {
|
||||||
ret[item.name] = {
|
ret[item.name] = {
|
||||||
|
@ -86,7 +85,7 @@ export function getCustomEmojis() {
|
||||||
try {
|
try {
|
||||||
const serverVersion = reduxStore.getState().server.version;
|
const serverVersion = reduxStore.getState().server.version;
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const emojisCollection = db.collections.get('custom_emojis');
|
const emojisCollection = db.get('custom_emojis');
|
||||||
const allRecords = await emojisCollection.query().fetch();
|
const allRecords = await emojisCollection.query().fetch();
|
||||||
const updatedSince = await getUpdatedSince(allRecords);
|
const updatedSince = await getUpdatedSince(allRecords);
|
||||||
|
|
||||||
|
@ -95,18 +94,16 @@ export function getCustomEmojis() {
|
||||||
// RC 0.61.0
|
// RC 0.61.0
|
||||||
const result = await this.sdk.get('emoji-custom');
|
const result = await this.sdk.get('emoji-custom');
|
||||||
|
|
||||||
InteractionManager.runAfterInteractions(async() => {
|
let { emojis } = result;
|
||||||
let { emojis } = result;
|
emojis = emojis.filter(emoji => !updatedSince || emoji._updatedAt > updatedSince);
|
||||||
emojis = emojis.filter(emoji => !updatedSince || emoji._updatedAt > updatedSince);
|
const changedEmojis = await updateEmojis({ update: emojis, allRecords });
|
||||||
const changedEmojis = await updateEmojis({ update: emojis, allRecords });
|
|
||||||
|
|
||||||
// `setCustomEmojis` is fired on selectServer
|
// `setCustomEmojis` is fired on selectServer
|
||||||
// We run it again only if emojis were changed
|
// We run it again only if emojis were changed
|
||||||
if (changedEmojis) {
|
if (changedEmojis) {
|
||||||
setCustomEmojis();
|
setCustomEmojis();
|
||||||
}
|
}
|
||||||
return resolve();
|
return resolve();
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
const params = {};
|
const params = {};
|
||||||
if (updatedSince) {
|
if (updatedSince) {
|
||||||
|
@ -120,17 +117,15 @@ export function getCustomEmojis() {
|
||||||
return resolve();
|
return resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
InteractionManager.runAfterInteractions(async() => {
|
const { emojis } = result;
|
||||||
const { emojis } = result;
|
const { update, remove } = emojis;
|
||||||
const { update, remove } = emojis;
|
const changedEmojis = await updateEmojis({ update, remove, allRecords });
|
||||||
const changedEmojis = await updateEmojis({ update, remove, allRecords });
|
|
||||||
|
|
||||||
// `setCustomEmojis` is fired on selectServer
|
// `setCustomEmojis` is fired on selectServer
|
||||||
// We run it again only if emojis were changed
|
// We run it again only if emojis were changed
|
||||||
if (changedEmojis) {
|
if (changedEmojis) {
|
||||||
setCustomEmojis();
|
setCustomEmojis();
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log(e);
|
log(e);
|
||||||
|
|
|
@ -1,12 +1,55 @@
|
||||||
import { InteractionManager } from 'react-native';
|
|
||||||
import lt from 'semver/functions/lt';
|
import lt from 'semver/functions/lt';
|
||||||
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
|
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
|
||||||
|
import { Q } from '@nozbe/watermelondb';
|
||||||
|
import coerce from 'semver/functions/coerce';
|
||||||
import orderBy from 'lodash/orderBy';
|
import orderBy from 'lodash/orderBy';
|
||||||
|
|
||||||
import database from '../database';
|
import database from '../database';
|
||||||
import log from '../../utils/log';
|
import log from '../../utils/log';
|
||||||
import reduxStore from '../createStore';
|
import reduxStore from '../createStore';
|
||||||
import protectedFunction from './helpers/protectedFunction';
|
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) => {
|
const getUpdatedSince = (allRecords) => {
|
||||||
try {
|
try {
|
||||||
|
@ -26,7 +69,7 @@ const updatePermissions = async({ update = [], remove = [], allRecords }) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const permissionsCollection = db.collections.get('permissions');
|
const permissionsCollection = db.get('permissions');
|
||||||
|
|
||||||
// filter permissions
|
// filter permissions
|
||||||
let permissionsToCreate = [];
|
let permissionsToCreate = [];
|
||||||
|
@ -65,33 +108,35 @@ const updatePermissions = async({ update = [], remove = [], allRecords }) => {
|
||||||
await db.action(async() => {
|
await db.action(async() => {
|
||||||
await db.batch(...batch);
|
await db.batch(...batch);
|
||||||
});
|
});
|
||||||
|
return true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log(e);
|
log(e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function() {
|
export function getPermissions() {
|
||||||
return new Promise(async(resolve) => {
|
return new Promise(async(resolve) => {
|
||||||
try {
|
try {
|
||||||
const serverVersion = reduxStore.getState().server.version;
|
const serverVersion = reduxStore.getState().server.version;
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const permissionsCollection = db.collections.get('permissions');
|
const permissionsCollection = db.get('permissions');
|
||||||
const allRecords = await permissionsCollection.query().fetch();
|
const allRecords = await permissionsCollection.query().fetch();
|
||||||
|
|
||||||
// if server version is lower than 0.73.0, fetches from old api
|
// 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
|
// RC 0.66.0
|
||||||
const result = await this.sdk.get('permissions.list');
|
const result = await this.sdk.get('permissions.list');
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
return resolve();
|
return resolve();
|
||||||
}
|
}
|
||||||
InteractionManager.runAfterInteractions(async() => {
|
const changePermissions = await updatePermissions({ update: result.permissions, allRecords });
|
||||||
await updatePermissions({ update: result.permissions, allRecords });
|
if (changePermissions) {
|
||||||
return resolve();
|
setPermissions();
|
||||||
});
|
}
|
||||||
|
return resolve();
|
||||||
} else {
|
} else {
|
||||||
const params = {};
|
const params = {};
|
||||||
const updatedSince = await getUpdatedSince(allRecords);
|
const updatedSince = getUpdatedSince(allRecords);
|
||||||
if (updatedSince) {
|
if (updatedSince) {
|
||||||
params.updatedSince = updatedSince;
|
params.updatedSince = updatedSince;
|
||||||
}
|
}
|
||||||
|
@ -102,10 +147,11 @@ export default function() {
|
||||||
return resolve();
|
return resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
InteractionManager.runAfterInteractions(async() => {
|
const changePermissions = await updatePermissions({ update: result.update, remove: result.delete, allRecords });
|
||||||
await updatePermissions({ update: result.update, remove: result.delete, allRecords });
|
if (changePermissions) {
|
||||||
return resolve();
|
setPermissions();
|
||||||
});
|
}
|
||||||
|
return resolve();
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log(e);
|
log(e);
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import { InteractionManager } from 'react-native';
|
|
||||||
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
|
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
|
||||||
|
|
||||||
import database from '../database';
|
import database from '../database';
|
||||||
|
@ -19,43 +18,41 @@ export default function() {
|
||||||
const { roles } = result;
|
const { roles } = result;
|
||||||
|
|
||||||
if (roles && roles.length) {
|
if (roles && roles.length) {
|
||||||
InteractionManager.runAfterInteractions(async() => {
|
await db.action(async() => {
|
||||||
await db.action(async() => {
|
const rolesCollections = db.get('roles');
|
||||||
const rolesCollections = db.collections.get('roles');
|
const allRolesRecords = await rolesCollections.query().fetch();
|
||||||
const allRolesRecords = await rolesCollections.query().fetch();
|
|
||||||
|
|
||||||
// filter roles
|
// filter roles
|
||||||
let rolesToCreate = roles.filter(i1 => !allRolesRecords.find(i2 => i1._id === i2.id));
|
let rolesToCreate = roles.filter(i1 => !allRolesRecords.find(i2 => i1._id === i2.id));
|
||||||
let rolesToUpdate = allRolesRecords.filter(i1 => roles.find(i2 => i1.id === i2._id));
|
let rolesToUpdate = allRolesRecords.filter(i1 => roles.find(i2 => i1.id === i2._id));
|
||||||
|
|
||||||
// Create
|
// Create
|
||||||
rolesToCreate = rolesToCreate.map(role => rolesCollections.prepareCreate(protectedFunction((r) => {
|
rolesToCreate = rolesToCreate.map(role => rolesCollections.prepareCreate(protectedFunction((r) => {
|
||||||
r._raw = sanitizedRaw({ id: role._id }, rolesCollections.schema);
|
r._raw = sanitizedRaw({ id: role._id }, rolesCollections.schema);
|
||||||
Object.assign(r, role);
|
Object.assign(r, role);
|
||||||
})));
|
})));
|
||||||
|
|
||||||
// Update
|
// Update
|
||||||
rolesToUpdate = rolesToUpdate.map((role) => {
|
rolesToUpdate = rolesToUpdate.map((role) => {
|
||||||
const newRole = roles.find(r => r._id === role.id);
|
const newRole = roles.find(r => r._id === role.id);
|
||||||
return role.prepareUpdate(protectedFunction((r) => {
|
return role.prepareUpdate(protectedFunction((r) => {
|
||||||
Object.assign(r, newRole);
|
Object.assign(r, newRole);
|
||||||
}));
|
}));
|
||||||
});
|
|
||||||
|
|
||||||
const allRecords = [
|
|
||||||
...rolesToCreate,
|
|
||||||
...rolesToUpdate
|
|
||||||
];
|
|
||||||
|
|
||||||
try {
|
|
||||||
await db.batch(...allRecords);
|
|
||||||
} catch (e) {
|
|
||||||
log(e);
|
|
||||||
}
|
|
||||||
return allRecords.length;
|
|
||||||
});
|
});
|
||||||
return resolve();
|
|
||||||
|
const allRecords = [
|
||||||
|
...rolesToCreate,
|
||||||
|
...rolesToUpdate
|
||||||
|
];
|
||||||
|
|
||||||
|
try {
|
||||||
|
await db.batch(...allRecords);
|
||||||
|
} catch (e) {
|
||||||
|
log(e);
|
||||||
|
}
|
||||||
|
return allRecords.length;
|
||||||
});
|
});
|
||||||
|
return resolve();
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log(e);
|
log(e);
|
||||||
|
|
|
@ -44,7 +44,7 @@ const loginSettings = [
|
||||||
const serverInfoUpdate = async(serverInfo, iconSetting) => {
|
const serverInfoUpdate = async(serverInfo, iconSetting) => {
|
||||||
const serversDB = database.servers;
|
const serversDB = database.servers;
|
||||||
const serverId = reduxStore.getState().server.server;
|
const serverId = reduxStore.getState().server.server;
|
||||||
const serversCollection = serversDB.collections.get('servers');
|
const serversCollection = serversDB.get('servers');
|
||||||
const server = await serversCollection.find(serverId);
|
const server = await serversCollection.find(serverId);
|
||||||
|
|
||||||
let info = serverInfo.reduce((allSettings, setting) => {
|
let info = serverInfo.reduce((allSettings, setting) => {
|
||||||
|
@ -118,7 +118,7 @@ export async function getLoginSettings({ server }) {
|
||||||
|
|
||||||
export async function setSettings() {
|
export async function setSettings() {
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const settingsCollection = db.collections.get('settings');
|
const settingsCollection = db.get('settings');
|
||||||
const settingsRecords = await settingsCollection.query().fetch();
|
const settingsRecords = await settingsCollection.query().fetch();
|
||||||
const parsed = Object.values(settingsRecords).map(item => ({
|
const parsed = Object.values(settingsRecords).map(item => ({
|
||||||
_id: item.id,
|
_id: item.id,
|
||||||
|
@ -157,7 +157,7 @@ export default async function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
await db.action(async() => {
|
await db.action(async() => {
|
||||||
const settingsCollection = db.collections.get('settings');
|
const settingsCollection = db.get('settings');
|
||||||
const allSettingsRecords = await settingsCollection
|
const allSettingsRecords = await settingsCollection
|
||||||
.query(Q.where('id', Q.oneOf(filteredSettingsIds)))
|
.query(Q.where('id', Q.oneOf(filteredSettingsIds)))
|
||||||
.fetch();
|
.fetch();
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import { InteractionManager } from 'react-native';
|
|
||||||
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
|
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
|
||||||
|
|
||||||
import database from '../database';
|
import database from '../database';
|
||||||
|
@ -20,47 +19,45 @@ export default function() {
|
||||||
const { commands } = result;
|
const { commands } = result;
|
||||||
|
|
||||||
if (commands && commands.length) {
|
if (commands && commands.length) {
|
||||||
InteractionManager.runAfterInteractions(async() => {
|
await db.action(async() => {
|
||||||
await db.action(async() => {
|
const slashCommandsCollection = db.get('slash_commands');
|
||||||
const slashCommandsCollection = db.collections.get('slash_commands');
|
const allSlashCommandsRecords = await slashCommandsCollection.query().fetch();
|
||||||
const allSlashCommandsRecords = await slashCommandsCollection.query().fetch();
|
|
||||||
|
|
||||||
// filter slash commands
|
// filter slash commands
|
||||||
let slashCommandsToCreate = commands.filter(i1 => !allSlashCommandsRecords.find(i2 => i1.command === i2.id));
|
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 slashCommandsToUpdate = allSlashCommandsRecords.filter(i1 => commands.find(i2 => i1.id === i2.command));
|
||||||
let slashCommandsToDelete = allSlashCommandsRecords
|
let slashCommandsToDelete = allSlashCommandsRecords
|
||||||
.filter(i1 => !slashCommandsToCreate.find(i2 => i2.command === i1.id) && !slashCommandsToUpdate.find(i2 => i2.id === i1.id));
|
.filter(i1 => !slashCommandsToCreate.find(i2 => i2.command === i1.id) && !slashCommandsToUpdate.find(i2 => i2.id === i1.id));
|
||||||
|
|
||||||
// Create
|
// Create
|
||||||
slashCommandsToCreate = slashCommandsToCreate.map(command => slashCommandsCollection.prepareCreate(protectedFunction((s) => {
|
slashCommandsToCreate = slashCommandsToCreate.map(command => slashCommandsCollection.prepareCreate(protectedFunction((s) => {
|
||||||
s._raw = sanitizedRaw({ id: command.command }, slashCommandsCollection.schema);
|
s._raw = sanitizedRaw({ id: command.command }, slashCommandsCollection.schema);
|
||||||
Object.assign(s, command);
|
Object.assign(s, command);
|
||||||
})));
|
})));
|
||||||
|
|
||||||
// Update
|
// Update
|
||||||
slashCommandsToUpdate = slashCommandsToUpdate.map((command) => {
|
slashCommandsToUpdate = slashCommandsToUpdate.map((command) => {
|
||||||
const newCommand = commands.find(s => s.command === command.id);
|
const newCommand = commands.find(s => s.command === command.id);
|
||||||
return command.prepareUpdate(protectedFunction((s) => {
|
return command.prepareUpdate(protectedFunction((s) => {
|
||||||
Object.assign(s, newCommand);
|
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;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 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) {
|
} catch (e) {
|
||||||
|
|
|
@ -72,7 +72,7 @@ export default async function getUsersPresence() {
|
||||||
ids = [];
|
ids = [];
|
||||||
|
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const userCollection = db.collections.get('users');
|
const userCollection = db.get('users');
|
||||||
users.forEach(async(user) => {
|
users.forEach(async(user) => {
|
||||||
try {
|
try {
|
||||||
const userRecord = await userCollection.find(user._id);
|
const userRecord = await userCollection.find(user._id);
|
||||||
|
|
|
@ -5,7 +5,7 @@ import database from '../../database';
|
||||||
export default async(subscriptions = [], rooms = []) => {
|
export default async(subscriptions = [], rooms = []) => {
|
||||||
try {
|
try {
|
||||||
const db = database.active;
|
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);
|
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();
|
let existingSubs = await subCollection.query(Q.where('rid', Q.oneOf(roomIds))).fetch();
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import EJSON from 'ejson';
|
import EJSON from 'ejson';
|
||||||
|
import { lt, coerce } from 'semver';
|
||||||
|
|
||||||
import normalizeMessage from './normalizeMessage';
|
import normalizeMessage from './normalizeMessage';
|
||||||
import findSubscriptionsRooms from './findSubscriptionsRooms';
|
import findSubscriptionsRooms from './findSubscriptionsRooms';
|
||||||
import { Encryption } from '../../encryption';
|
import { Encryption } from '../../encryption';
|
||||||
|
import reduxStore from '../../createStore';
|
||||||
// TODO: delete and update
|
// TODO: delete and update
|
||||||
|
|
||||||
export const merge = (subscription, room) => {
|
export const merge = (subscription, room) => {
|
||||||
|
const serverVersion = reduxStore.getState().server.version;
|
||||||
subscription = EJSON.fromJSONValue(subscription);
|
subscription = EJSON.fromJSONValue(subscription);
|
||||||
room = EJSON.fromJSONValue(room);
|
room = EJSON.fromJSONValue(room);
|
||||||
|
|
||||||
|
@ -25,9 +28,15 @@ export const merge = (subscription, room) => {
|
||||||
subscription.usernames = room.usernames;
|
subscription.usernames = room.usernames;
|
||||||
subscription.uids = room.uids;
|
subscription.uids = room.uids;
|
||||||
}
|
}
|
||||||
// https://github.com/RocketChat/Rocket.Chat/blob/develop/app/ui-sidenav/client/roomList.js#L180
|
if (serverVersion && lt(coerce(serverVersion), '3.7.0')) {
|
||||||
const lastRoomUpdate = room.lm || subscription.ts || subscription._updatedAt;
|
const updatedAt = room?._updatedAt ? new Date(room._updatedAt) : null;
|
||||||
subscription.roomUpdatedAt = subscription.lr ? Math.max(new Date(subscription.lr), new Date(lastRoomUpdate)) : lastRoomUpdate;
|
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.ro = room.ro;
|
||||||
subscription.broadcast = room.broadcast;
|
subscription.broadcast = room.broadcast;
|
||||||
subscription.encrypted = room.encrypted;
|
subscription.encrypted = room.encrypted;
|
||||||
|
|
|
@ -5,7 +5,7 @@ import updateMessages from './updateMessages';
|
||||||
const getLastUpdate = async(rid) => {
|
const getLastUpdate = async(rid) => {
|
||||||
try {
|
try {
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const subsCollection = db.collections.get('subscriptions');
|
const subsCollection = db.get('subscriptions');
|
||||||
const sub = await subsCollection.find(rid);
|
const sub = await subsCollection.find(rid);
|
||||||
return sub.lastOpen.toISOString();
|
return sub.lastOpen.toISOString();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import { InteractionManager } from 'react-native';
|
|
||||||
import { Q } from '@nozbe/watermelondb';
|
import { Q } from '@nozbe/watermelondb';
|
||||||
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
|
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 });
|
let data = await load.call(this, { tmid, offset });
|
||||||
|
|
||||||
if (data && data.length) {
|
if (data && data.length) {
|
||||||
InteractionManager.runAfterInteractions(async() => {
|
try {
|
||||||
try {
|
data = data.map(m => buildMessage(m));
|
||||||
data = data.map(m => buildMessage(m));
|
data = await Encryption.decryptMessages(data);
|
||||||
data = await Encryption.decryptMessages(data);
|
const db = database.active;
|
||||||
const db = database.active;
|
const threadMessagesCollection = db.get('thread_messages');
|
||||||
const threadMessagesCollection = db.collections.get('thread_messages');
|
const allThreadMessagesRecords = await threadMessagesCollection.query(Q.where('rid', tmid)).fetch();
|
||||||
const allThreadMessagesRecords = await threadMessagesCollection.query(Q.where('rid', tmid)).fetch();
|
let threadMessagesToCreate = data.filter(i1 => !allThreadMessagesRecords.find(i2 => i1._id === i2.id));
|
||||||
let threadMessagesToCreate = data.filter(i1 => !allThreadMessagesRecords.find(i2 => i1._id === i2.id));
|
let threadMessagesToUpdate = allThreadMessagesRecords.filter(i1 => data.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) => {
|
threadMessagesToCreate = threadMessagesToCreate.map(threadMessage => threadMessagesCollection.prepareCreate(protectedFunction((tm) => {
|
||||||
tm._raw = sanitizedRaw({ id: threadMessage._id }, threadMessagesCollection.schema);
|
tm._raw = sanitizedRaw({ id: threadMessage._id }, threadMessagesCollection.schema);
|
||||||
Object.assign(tm, threadMessage);
|
Object.assign(tm, threadMessage);
|
||||||
tm.subscription.id = rid;
|
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;
|
tm.rid = threadMessage.tmid;
|
||||||
delete threadMessage.tmid;
|
delete threadMessage.tmid;
|
||||||
})));
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
threadMessagesToUpdate = threadMessagesToUpdate.map((threadMessage) => {
|
await db.action(async() => {
|
||||||
const newThreadMessage = data.find(t => t._id === threadMessage.id);
|
await db.batch(
|
||||||
return threadMessage.prepareUpdate(protectedFunction((tm) => {
|
...threadMessagesToCreate,
|
||||||
Object.assign(tm, newThreadMessage);
|
...threadMessagesToUpdate
|
||||||
tm.rid = threadMessage.tmid;
|
);
|
||||||
delete threadMessage.tmid;
|
});
|
||||||
}));
|
} catch (e) {
|
||||||
});
|
log(e);
|
||||||
|
}
|
||||||
await db.action(async() => {
|
return resolve(data);
|
||||||
await db.batch(
|
|
||||||
...threadMessagesToCreate,
|
|
||||||
...threadMessagesToUpdate
|
|
||||||
);
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
log(e);
|
|
||||||
}
|
|
||||||
return resolve(data);
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
return resolve([]);
|
return resolve([]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,12 +42,12 @@ async function removeServerData({ server }) {
|
||||||
const serversDB = database.servers;
|
const serversDB = database.servers;
|
||||||
const userId = await UserPreferences.getStringAsync(`${ RocketChat.TOKEN_KEY }-${ server }`);
|
const userId = await UserPreferences.getStringAsync(`${ RocketChat.TOKEN_KEY }-${ server }`);
|
||||||
|
|
||||||
const usersCollection = serversDB.collections.get('users');
|
const usersCollection = serversDB.get('users');
|
||||||
if (userId) {
|
if (userId) {
|
||||||
const userRecord = await usersCollection.find(userId);
|
const userRecord = await usersCollection.find(userId);
|
||||||
batch.push(userRecord.prepareDestroyPermanently());
|
batch.push(userRecord.prepareDestroyPermanently());
|
||||||
}
|
}
|
||||||
const serverCollection = serversDB.collections.get('servers');
|
const serverCollection = serversDB.get('servers');
|
||||||
const serverRecord = await serverCollection.find(server);
|
const serverRecord = await serverCollection.find(server);
|
||||||
batch.push(serverRecord.prepareDestroyPermanently());
|
batch.push(serverRecord.prepareDestroyPermanently());
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import log from '../../utils/log';
|
||||||
export default async function readMessages(rid, ls, updateLastOpen = false) {
|
export default async function readMessages(rid, ls, updateLastOpen = false) {
|
||||||
try {
|
try {
|
||||||
const db = database.active;
|
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
|
// RC 0.61.0
|
||||||
await this.sdk.post('subscriptions.read', { rid });
|
await this.sdk.post('subscriptions.read', { rid });
|
||||||
|
|
|
@ -40,7 +40,7 @@ export function sendFileMessage(rid, fileInfo, tmid, server, user) {
|
||||||
fileInfo.rid = rid;
|
fileInfo.rid = rid;
|
||||||
|
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const uploadsCollection = db.collections.get('uploads');
|
const uploadsCollection = db.get('uploads');
|
||||||
let uploadRecord;
|
let uploadRecord;
|
||||||
try {
|
try {
|
||||||
uploadRecord = await uploadsCollection.find(fileInfo.path);
|
uploadRecord = await uploadsCollection.find(fileInfo.path);
|
||||||
|
|
|
@ -9,8 +9,8 @@ import { E2E_MESSAGE_TYPE, E2E_STATUS } from '../encryption/constants';
|
||||||
|
|
||||||
const changeMessageStatus = async(id, tmid, status, message) => {
|
const changeMessageStatus = async(id, tmid, status, message) => {
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const msgCollection = db.collections.get('messages');
|
const msgCollection = db.get('messages');
|
||||||
const threadMessagesCollection = db.collections.get('thread_messages');
|
const threadMessagesCollection = db.get('thread_messages');
|
||||||
const successBatch = [];
|
const successBatch = [];
|
||||||
const messageRecord = await msgCollection.find(id);
|
const messageRecord = await msgCollection.find(id);
|
||||||
successBatch.push(
|
successBatch.push(
|
||||||
|
@ -89,10 +89,10 @@ export async function resendMessage(message, tmid) {
|
||||||
export default async function(rid, msg, tmid, user, tshow) {
|
export default async function(rid, msg, tmid, user, tshow) {
|
||||||
try {
|
try {
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const subsCollection = db.collections.get('subscriptions');
|
const subsCollection = db.get('subscriptions');
|
||||||
const msgCollection = db.collections.get('messages');
|
const msgCollection = db.get('messages');
|
||||||
const threadCollection = db.collections.get('threads');
|
const threadCollection = db.get('threads');
|
||||||
const threadMessagesCollection = db.collections.get('thread_messages');
|
const threadMessagesCollection = db.get('thread_messages');
|
||||||
const messageId = random(17);
|
const messageId = random(17);
|
||||||
const batch = [];
|
const batch = [];
|
||||||
|
|
||||||
|
@ -151,7 +151,8 @@ export default async function(rid, msg, tmid, user, tshow) {
|
||||||
tm.status = messagesStatus.TEMP;
|
tm.status = messagesStatus.TEMP;
|
||||||
tm.u = {
|
tm.u = {
|
||||||
_id: user.id || '1',
|
_id: user.id || '1',
|
||||||
username: user.username
|
username: user.username,
|
||||||
|
name: user.name
|
||||||
};
|
};
|
||||||
tm.t = message.t;
|
tm.t = message.t;
|
||||||
if (message.t === E2E_MESSAGE_TYPE) {
|
if (message.t === E2E_MESSAGE_TYPE) {
|
||||||
|
@ -175,7 +176,8 @@ export default async function(rid, msg, tmid, user, tshow) {
|
||||||
m.status = messagesStatus.TEMP;
|
m.status = messagesStatus.TEMP;
|
||||||
m.u = {
|
m.u = {
|
||||||
_id: user.id || '1',
|
_id: user.id || '1',
|
||||||
username: user.username
|
username: user.username,
|
||||||
|
name: user.name
|
||||||
};
|
};
|
||||||
if (tmid && tMessageRecord) {
|
if (tmid && tMessageRecord) {
|
||||||
m.tmid = tmid;
|
m.tmid = tmid;
|
||||||
|
|
|
@ -90,6 +90,10 @@ export default class RoomSubscription {
|
||||||
if (ev === 'typing') {
|
if (ev === 'typing') {
|
||||||
const { user } = reduxStore.getState().login;
|
const { user } = reduxStore.getState().login;
|
||||||
const { UI_Use_Real_Name } = reduxStore.getState().settings;
|
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 [name, typing] = ddpMessage.fields.args;
|
||||||
const key = UI_Use_Real_Name ? 'name' : 'username';
|
const key = UI_Use_Real_Name ? 'name' : 'username';
|
||||||
if (name !== user[key]) {
|
if (name !== user[key]) {
|
||||||
|
@ -105,9 +109,9 @@ export default class RoomSubscription {
|
||||||
try {
|
try {
|
||||||
const { _id } = ddpMessage.fields.args[0];
|
const { _id } = ddpMessage.fields.args[0];
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const msgCollection = db.collections.get('messages');
|
const msgCollection = db.get('messages');
|
||||||
const threadsCollection = db.collections.get('threads');
|
const threadsCollection = db.get('threads');
|
||||||
const threadMessagesCollection = db.collections.get('thread_messages');
|
const threadMessagesCollection = db.get('thread_messages');
|
||||||
let deleteMessage;
|
let deleteMessage;
|
||||||
let deleteThread;
|
let deleteThread;
|
||||||
let deleteThreadMessage;
|
let deleteThreadMessage;
|
||||||
|
@ -159,9 +163,9 @@ export default class RoomSubscription {
|
||||||
}
|
}
|
||||||
|
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const msgCollection = db.collections.get('messages');
|
const msgCollection = db.get('messages');
|
||||||
const threadsCollection = db.collections.get('threads');
|
const threadsCollection = db.get('threads');
|
||||||
const threadMessagesCollection = db.collections.get('thread_messages');
|
const threadMessagesCollection = db.get('thread_messages');
|
||||||
|
|
||||||
// Decrypt the message if necessary
|
// Decrypt the message if necessary
|
||||||
message = await Encryption.decryptMessage(message);
|
message = await Encryption.decryptMessage(message);
|
||||||
|
|
|
@ -32,8 +32,8 @@ const WINDOW_TIME = 500;
|
||||||
const createOrUpdateSubscription = async(subscription, room) => {
|
const createOrUpdateSubscription = async(subscription, room) => {
|
||||||
try {
|
try {
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const subCollection = db.collections.get('subscriptions');
|
const subCollection = db.get('subscriptions');
|
||||||
const roomsCollection = db.collections.get('rooms');
|
const roomsCollection = db.get('rooms');
|
||||||
|
|
||||||
if (!subscription) {
|
if (!subscription) {
|
||||||
try {
|
try {
|
||||||
|
@ -185,7 +185,7 @@ const createOrUpdateSubscription = async(subscription, room) => {
|
||||||
const { rooms } = store.getState().room;
|
const { rooms } = store.getState().room;
|
||||||
if (tmp.lastMessage && !rooms.includes(tmp.rid)) {
|
if (tmp.lastMessage && !rooms.includes(tmp.rid)) {
|
||||||
const lastMessage = buildMessage(tmp.lastMessage);
|
const lastMessage = buildMessage(tmp.lastMessage);
|
||||||
const messagesCollection = db.collections.get('messages');
|
const messagesCollection = db.get('messages');
|
||||||
let messageRecord;
|
let messageRecord;
|
||||||
try {
|
try {
|
||||||
messageRecord = await messagesCollection.find(lastMessage._id);
|
messageRecord = await messagesCollection.find(lastMessage._id);
|
||||||
|
@ -281,7 +281,7 @@ export default function subscribeRooms() {
|
||||||
if (/subscriptions/.test(ev)) {
|
if (/subscriptions/.test(ev)) {
|
||||||
if (type === 'removed') {
|
if (type === 'removed') {
|
||||||
try {
|
try {
|
||||||
const subCollection = db.collections.get('subscriptions');
|
const subCollection = db.get('subscriptions');
|
||||||
const sub = await subCollection.find(data.rid);
|
const sub = await subCollection.find(data.rid);
|
||||||
const messages = await sub.messages.fetch();
|
const messages = await sub.messages.fetch();
|
||||||
const threads = await sub.threads.fetch();
|
const threads = await sub.threads.fetch();
|
||||||
|
@ -335,7 +335,7 @@ export default function subscribeRooms() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
const msgCollection = db.collections.get('messages');
|
const msgCollection = db.get('messages');
|
||||||
await db.action(async() => {
|
await db.action(async() => {
|
||||||
await msgCollection.create(protectedFunction((m) => {
|
await msgCollection.create(protectedFunction((m) => {
|
||||||
m._raw = sanitizedRaw({ id: message._id }, msgCollection.schema);
|
m._raw = sanitizedRaw({ id: message._id }, msgCollection.schema);
|
||||||
|
@ -407,7 +407,7 @@ export default function subscribeRooms() {
|
||||||
};
|
};
|
||||||
|
|
||||||
connectedListener = this.sdk.onStreamData('connected', handleConnection);
|
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);
|
streamListener = this.sdk.onStreamData('stream-notify-user', handleStreamMessageReceived);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -16,7 +16,7 @@ export default function updateMessages({ rid, update = [], remove = [] }) {
|
||||||
return db.action(async() => {
|
return db.action(async() => {
|
||||||
// Decrypt these messages
|
// Decrypt these messages
|
||||||
update = await Encryption.decryptMessages(update);
|
update = await Encryption.decryptMessages(update);
|
||||||
const subCollection = db.collections.get('subscriptions');
|
const subCollection = db.get('subscriptions');
|
||||||
let sub;
|
let sub;
|
||||||
try {
|
try {
|
||||||
sub = await subCollection.find(rid);
|
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 messagesIds = [...update.map(m => m._id), ...remove.map(m => m._id)];
|
||||||
const msgCollection = db.collections.get('messages');
|
const msgCollection = db.get('messages');
|
||||||
const threadCollection = db.collections.get('threads');
|
const threadCollection = db.get('threads');
|
||||||
const threadMessagesCollection = db.collections.get('thread_messages');
|
const threadMessagesCollection = db.get('thread_messages');
|
||||||
const allMessagesRecords = await msgCollection
|
const allMessagesRecords = await msgCollection
|
||||||
.query(Q.where('rid', rid), Q.where('id', Q.oneOf(messagesIds)))
|
.query(Q.where('rid', rid), Q.where('id', Q.oneOf(messagesIds)))
|
||||||
.fetch();
|
.fetch();
|
||||||
|
|
|
@ -32,7 +32,7 @@ import readMessages from './methods/readMessages';
|
||||||
import getSettings, { getLoginSettings, setSettings } from './methods/getSettings';
|
import getSettings, { getLoginSettings, setSettings } from './methods/getSettings';
|
||||||
|
|
||||||
import getRooms from './methods/getRooms';
|
import getRooms from './methods/getRooms';
|
||||||
import getPermissions from './methods/getPermissions';
|
import { setPermissions, getPermissions } from './methods/getPermissions';
|
||||||
import { getCustomEmojis, setCustomEmojis } from './methods/getCustomEmojis';
|
import { getCustomEmojis, setCustomEmojis } from './methods/getCustomEmojis';
|
||||||
import {
|
import {
|
||||||
getEnterpriseModules, setEnterpriseModules, hasLicense, isOmnichannelModuleAvailable
|
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 THEME_PREFERENCES_KEY = 'RC_THEME_PREFERENCES_KEY';
|
||||||
export const CRASH_REPORT_KEY = 'RC_CRASH_REPORT_KEY';
|
export const CRASH_REPORT_KEY = 'RC_CRASH_REPORT_KEY';
|
||||||
export const ANALYTICS_EVENTS_KEY = 'RC_ANALYTICS_EVENTS_KEY';
|
export const ANALYTICS_EVENTS_KEY = 'RC_ANALYTICS_EVENTS_KEY';
|
||||||
const returnAnArray = obj => obj || [];
|
|
||||||
const MIN_ROCKETCHAT_VERSION = '0.70.0';
|
const MIN_ROCKETCHAT_VERSION = '0.70.0';
|
||||||
|
|
||||||
const STATUSES = ['offline', 'online', 'away', 'busy'];
|
const STATUSES = ['offline', 'online', 'away', 'busy'];
|
||||||
|
@ -178,9 +177,16 @@ const RocketChat = {
|
||||||
}
|
}
|
||||||
this.controller = new AbortController();
|
this.controller = new AbortController();
|
||||||
},
|
},
|
||||||
|
checkAndReopen() {
|
||||||
|
return this?.sdk?.checkAndReopen();
|
||||||
|
},
|
||||||
connect({ server, user, logoutOnError = false }) {
|
connect({ server, user, logoutOnError = false }) {
|
||||||
return new Promise((resolve) => {
|
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);
|
database.setActiveDB(server);
|
||||||
}
|
}
|
||||||
reduxStore.dispatch(connectRequest());
|
reduxStore.dispatch(connectRequest());
|
||||||
|
@ -209,11 +215,6 @@ const RocketChat = {
|
||||||
|
|
||||||
EventEmitter.emit('INQUIRY_UNSUBSCRIBE');
|
EventEmitter.emit('INQUIRY_UNSUBSCRIBE');
|
||||||
|
|
||||||
if (this.sdk) {
|
|
||||||
this.sdk.disconnect();
|
|
||||||
this.sdk = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.code) {
|
if (this.code) {
|
||||||
this.code = null;
|
this.code = null;
|
||||||
}
|
}
|
||||||
|
@ -241,6 +242,10 @@ const RocketChat = {
|
||||||
|
|
||||||
sdkConnect();
|
sdkConnect();
|
||||||
|
|
||||||
|
this.connectedListener = this.sdk.onStreamData('connecting', () => {
|
||||||
|
reduxStore.dispatch(connectRequest());
|
||||||
|
});
|
||||||
|
|
||||||
this.connectedListener = this.sdk.onStreamData('connected', () => {
|
this.connectedListener = this.sdk.onStreamData('connected', () => {
|
||||||
reduxStore.dispatch(connectSuccess());
|
reduxStore.dispatch(connectSuccess());
|
||||||
});
|
});
|
||||||
|
@ -276,7 +281,7 @@ const RocketChat = {
|
||||||
} else if (/updateAvatar/.test(eventName)) {
|
} else if (/updateAvatar/.test(eventName)) {
|
||||||
const { username, etag } = ddpMessage.fields.args[0];
|
const { username, etag } = ddpMessage.fields.args[0];
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const userCollection = db.collections.get('users');
|
const userCollection = db.get('users');
|
||||||
try {
|
try {
|
||||||
const [userRecord] = await userCollection.query(Q.where('username', Q.eq(username))).fetch();
|
const [userRecord] = await userCollection.query(Q.where('username', Q.eq(username))).fetch();
|
||||||
await db.action(async() => {
|
await db.action(async() => {
|
||||||
|
@ -290,7 +295,7 @@ const RocketChat = {
|
||||||
} else if (/Users:NameChanged/.test(eventName)) {
|
} else if (/Users:NameChanged/.test(eventName)) {
|
||||||
const userNameChanged = ddpMessage.fields.args[0];
|
const userNameChanged = ddpMessage.fields.args[0];
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const userCollection = db.collections.get('users');
|
const userCollection = db.get('users');
|
||||||
try {
|
try {
|
||||||
const userRecord = await userCollection.find(userNameChanged._id);
|
const userRecord = await userCollection.find(userNameChanged._id);
|
||||||
await db.action(async() => {
|
await db.action(async() => {
|
||||||
|
@ -334,7 +339,7 @@ const RocketChat = {
|
||||||
// set Server
|
// set Server
|
||||||
const currentServer = { server };
|
const currentServer = { server };
|
||||||
const serversDB = database.servers;
|
const serversDB = database.servers;
|
||||||
const serversCollection = serversDB.collections.get('servers');
|
const serversCollection = serversDB.get('servers');
|
||||||
try {
|
try {
|
||||||
const serverRecord = await serversCollection.find(server);
|
const serverRecord = await serversCollection.find(server);
|
||||||
currentServer.version = serverRecord.version;
|
currentServer.version = serverRecord.version;
|
||||||
|
@ -349,7 +354,7 @@ const RocketChat = {
|
||||||
// set Settings
|
// set Settings
|
||||||
const settings = ['Accounts_AvatarBlockUnauthenticatedAccess'];
|
const settings = ['Accounts_AvatarBlockUnauthenticatedAccess'];
|
||||||
const db = database.active;
|
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 settingsRecords = await settingsCollection.query(Q.where('id', Q.oneOf(settings))).fetch();
|
||||||
const parsed = Object.values(settingsRecords).map(item => ({
|
const parsed = Object.values(settingsRecords).map(item => ({
|
||||||
_id: item.id,
|
_id: item.id,
|
||||||
|
@ -363,7 +368,7 @@ const RocketChat = {
|
||||||
|
|
||||||
// set User info
|
// set User info
|
||||||
const userId = await UserPreferences.getStringAsync(`${ RocketChat.TOKEN_KEY }-${ server }`);
|
const userId = await UserPreferences.getStringAsync(`${ RocketChat.TOKEN_KEY }-${ server }`);
|
||||||
const userCollections = serversDB.collections.get('users');
|
const userCollections = serversDB.get('users');
|
||||||
let user = null;
|
let user = null;
|
||||||
if (userId) {
|
if (userId) {
|
||||||
const userRecord = await userCollections.find(userId);
|
const userRecord = await userCollections.find(userId);
|
||||||
|
@ -545,7 +550,7 @@ const RocketChat = {
|
||||||
try {
|
try {
|
||||||
const serversDB = database.servers;
|
const serversDB = database.servers;
|
||||||
await serversDB.action(async() => {
|
await serversDB.action(async() => {
|
||||||
const serverCollection = serversDB.collections.get('servers');
|
const serverCollection = serversDB.get('servers');
|
||||||
const serverRecord = await serverCollection.find(server);
|
const serverRecord = await serverCollection.find(server);
|
||||||
await serverRecord.update((s) => {
|
await serverRecord.update((s) => {
|
||||||
s.roomsUpdatedAt = null;
|
s.roomsUpdatedAt = null;
|
||||||
|
@ -605,7 +610,7 @@ const RocketChat = {
|
||||||
}
|
}
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const likeString = sanitizeLikeString(searchText);
|
const likeString = sanitizeLikeString(searchText);
|
||||||
let data = await db.collections.get('subscriptions').query(
|
let data = await db.get('subscriptions').query(
|
||||||
Q.or(
|
Q.or(
|
||||||
Q.where('name', Q.like(`%${ likeString }%`)),
|
Q.where('name', Q.like(`%${ likeString }%`)),
|
||||||
Q.where('fname', Q.like(`%${ likeString }%`))
|
Q.where('fname', Q.like(`%${ likeString }%`))
|
||||||
|
@ -621,19 +626,15 @@ const RocketChat = {
|
||||||
|
|
||||||
data = data.slice(0, 7);
|
data = data.slice(0, 7);
|
||||||
|
|
||||||
data = data.map((sub) => {
|
data = data.map(sub => ({
|
||||||
if (sub.t !== 'd') {
|
rid: sub.rid,
|
||||||
return {
|
name: sub.name,
|
||||||
rid: sub.rid,
|
fname: sub.fname,
|
||||||
name: sub.name,
|
avatarETag: sub.avatarETag,
|
||||||
fname: sub.fname,
|
t: sub.t,
|
||||||
avatarETag: sub.avatarETag,
|
encrypted: sub.encrypted,
|
||||||
t: sub.t,
|
lastMessage: sub.lastMessage
|
||||||
encrypted: sub.encrypted
|
}));
|
||||||
};
|
|
||||||
}
|
|
||||||
return sub;
|
|
||||||
});
|
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
|
@ -740,6 +741,7 @@ const RocketChat = {
|
||||||
getLoginSettings,
|
getLoginSettings,
|
||||||
setSettings,
|
setSettings,
|
||||||
getPermissions,
|
getPermissions,
|
||||||
|
setPermissions,
|
||||||
getCustomEmojis,
|
getCustomEmojis,
|
||||||
setCustomEmojis,
|
setCustomEmojis,
|
||||||
getEnterpriseModules,
|
getEnterpriseModules,
|
||||||
|
@ -796,7 +798,7 @@ const RocketChat = {
|
||||||
async getRoom(rid) {
|
async getRoom(rid) {
|
||||||
try {
|
try {
|
||||||
const db = database.active;
|
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);
|
return Promise.resolve(room);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return Promise.reject(new Error('Room not found'));
|
return Promise.reject(new Error('Room not found'));
|
||||||
|
@ -1172,10 +1174,13 @@ const RocketChat = {
|
||||||
// RC 0.65.0
|
// RC 0.65.0
|
||||||
return this.sdk.get(`${ this.roomTypeToApiType(type) }.roles`, { roomId });
|
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) {
|
async hasPermission(permissions, rid) {
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const subsCollection = db.collections.get('subscriptions');
|
const subsCollection = db.get('subscriptions');
|
||||||
const permissionsCollection = db.collections.get('permissions');
|
|
||||||
let roomRoles = [];
|
let roomRoles = [];
|
||||||
try {
|
try {
|
||||||
// get the room from database
|
// get the room from database
|
||||||
|
@ -1184,31 +1189,16 @@ const RocketChat = {
|
||||||
roomRoles = room.roles || [];
|
roomRoles = room.roles || [];
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('hasPermission -> Room not found');
|
console.log('hasPermission -> Room not found');
|
||||||
return permissions.reduce((result, permission) => {
|
return permissions.map(() => false);
|
||||||
result[permission] = false;
|
|
||||||
return result;
|
|
||||||
}, {});
|
|
||||||
}
|
}
|
||||||
// get permissions from database
|
|
||||||
try {
|
try {
|
||||||
const permissionsFiltered = await permissionsCollection.query(Q.where('id', Q.oneOf(permissions))).fetch();
|
|
||||||
const shareUser = reduxStore.getState().share.user;
|
const shareUser = reduxStore.getState().share.user;
|
||||||
const loginUser = reduxStore.getState().login.user;
|
const loginUser = reduxStore.getState().login.user;
|
||||||
// get user roles on the server from redux
|
// get user roles on the server from redux
|
||||||
const userRoles = (shareUser?.roles || loginUser?.roles) || [];
|
const userRoles = (shareUser?.roles || loginUser?.roles) || [];
|
||||||
// merge both roles
|
|
||||||
const mergedRoles = [...new Set([...roomRoles, ...userRoles])];
|
const mergedRoles = [...new Set([...roomRoles, ...userRoles])];
|
||||||
|
return permissions.map(permission => permission?.some(r => mergedRoles.includes(r) ?? false));
|
||||||
// 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;
|
|
||||||
}, {});
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log(e);
|
log(e);
|
||||||
}
|
}
|
||||||
|
@ -1438,17 +1428,15 @@ const RocketChat = {
|
||||||
query, count, offset, sort
|
query, count, offset, sort
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
async canAutoTranslate() {
|
canAutoTranslate() {
|
||||||
const db = database.active;
|
|
||||||
try {
|
try {
|
||||||
const AutoTranslate_Enabled = reduxStore.getState().settings && reduxStore.getState().settings.AutoTranslate_Enabled;
|
const { AutoTranslate_Enabled } = reduxStore.getState().settings;
|
||||||
if (!AutoTranslate_Enabled) {
|
if (!AutoTranslate_Enabled) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const permissionsCollection = db.collections.get('permissions');
|
const autoTranslatePermission = reduxStore.getState().permissions['auto-translate'];
|
||||||
const autoTranslatePermission = await permissionsCollection.find('auto-translate');
|
const userRoles = (reduxStore.getState().login?.user?.roles) ?? [];
|
||||||
const userRoles = (reduxStore.getState().login.user && reduxStore.getState().login.user.roles) || [];
|
return autoTranslatePermission?.some(role => userRoles.includes(role));
|
||||||
return autoTranslatePermission.roles.some(role => userRoles.includes(role));
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log(e);
|
log(e);
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import isEqual from 'lodash/isEqual';
|
import { dequal } from 'dequal';
|
||||||
|
|
||||||
import I18n from '../../i18n';
|
import I18n from '../../i18n';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
|
@ -45,7 +45,7 @@ const formatMsg = ({
|
||||||
return `${ prefix }${ lastMessage.msg }`;
|
return `${ prefix }${ lastMessage.msg }`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const arePropsEqual = (oldProps, newProps) => isEqual(oldProps, newProps);
|
const arePropsEqual = (oldProps, newProps) => dequal(oldProps, newProps);
|
||||||
|
|
||||||
const LastMessage = React.memo(({
|
const LastMessage = React.memo(({
|
||||||
lastMessage, type, showLastMessage, username, alert, useRealName, theme
|
lastMessage, type, showLastMessage, username, alert, useRealName, theme
|
||||||
|
|
|
@ -18,6 +18,7 @@ import inviteLinks from './inviteLinks';
|
||||||
import createDiscussion from './createDiscussion';
|
import createDiscussion from './createDiscussion';
|
||||||
import enterpriseModules from './enterpriseModules';
|
import enterpriseModules from './enterpriseModules';
|
||||||
import encryption from './encryption';
|
import encryption from './encryption';
|
||||||
|
import permissions from './permissions';
|
||||||
|
|
||||||
import inquiry from '../ee/omnichannel/reducers/inquiry';
|
import inquiry from '../ee/omnichannel/reducers/inquiry';
|
||||||
|
|
||||||
|
@ -41,5 +42,6 @@ export default combineReducers({
|
||||||
createDiscussion,
|
createDiscussion,
|
||||||
inquiry,
|
inquiry,
|
||||||
enterpriseModules,
|
enterpriseModules,
|
||||||
encryption
|
encryption,
|
||||||
|
permissions
|
||||||
});
|
});
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -42,7 +42,7 @@ const handleRequest = function* handleRequest({ data }) {
|
||||||
broadcast,
|
broadcast,
|
||||||
encrypted
|
encrypted
|
||||||
} = data;
|
} = data;
|
||||||
logEvent(events.CREATE_CHANNEL_CREATE, {
|
logEvent(events.CR_CREATE, {
|
||||||
type: type ? 'private' : 'public',
|
type: type ? 'private' : 'public',
|
||||||
readOnly,
|
readOnly,
|
||||||
broadcast,
|
broadcast,
|
||||||
|
@ -53,7 +53,7 @@ const handleRequest = function* handleRequest({ data }) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const subCollection = db.collections.get('subscriptions');
|
const subCollection = db.get('subscriptions');
|
||||||
yield db.action(async() => {
|
yield db.action(async() => {
|
||||||
await subCollection.create((s) => {
|
await subCollection.create((s) => {
|
||||||
s._raw = sanitizedRaw({ id: sub.rid }, subCollection.schema);
|
s._raw = sanitizedRaw({ id: sub.rid }, subCollection.schema);
|
||||||
|
@ -66,7 +66,7 @@ const handleRequest = function* handleRequest({ data }) {
|
||||||
|
|
||||||
yield put(createChannelSuccess(sub));
|
yield put(createChannelSuccess(sub));
|
||||||
} catch (err) {
|
} 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));
|
yield put(createChannelFailure(err));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,7 +14,7 @@ const create = function* create(data) {
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRequest = function* handleRequest({ data }) {
|
const handleRequest = function* handleRequest({ data }) {
|
||||||
logEvent(events.CREATE_DISCUSSION_CREATE);
|
logEvent(events.CD_CREATE);
|
||||||
try {
|
try {
|
||||||
const auth = yield select(state => state.login.isAuthenticated);
|
const auth = yield select(state => state.login.isAuthenticated);
|
||||||
if (!auth) {
|
if (!auth) {
|
||||||
|
@ -27,7 +27,7 @@ const handleRequest = function* handleRequest({ data }) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const subCollection = db.collections.get('subscriptions');
|
const subCollection = db.get('subscriptions');
|
||||||
yield db.action(async() => {
|
yield db.action(async() => {
|
||||||
await subCollection.create((s) => {
|
await subCollection.create((s) => {
|
||||||
s._raw = sanitizedRaw({ id: sub.rid }, subCollection.schema);
|
s._raw = sanitizedRaw({ id: sub.rid }, subCollection.schema);
|
||||||
|
@ -39,11 +39,11 @@ const handleRequest = function* handleRequest({ data }) {
|
||||||
}
|
}
|
||||||
yield put(createDiscussionSuccess(sub));
|
yield put(createDiscussionSuccess(sub));
|
||||||
} else {
|
} else {
|
||||||
logEvent(events.CREATE_DISCUSSION_CREATE_F);
|
logEvent(events.CD_CREATE_F);
|
||||||
yield put(createDiscussionFailure(result));
|
yield put(createDiscussionFailure(result));
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logEvent(events.CREATE_DISCUSSION_CREATE_F);
|
logEvent(events.CD_CREATE_F);
|
||||||
yield put(createDiscussionFailure(err));
|
yield put(createDiscussionFailure(err));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -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 }) {
|
const navigate = function* navigate({ params }) {
|
||||||
yield put(appStart({ root: ROOT_INSIDE }));
|
yield put(appStart({ root: ROOT_INSIDE }));
|
||||||
if (params.path) {
|
if (params.path) {
|
||||||
|
@ -38,22 +46,31 @@ const navigate = function* navigate({ params }) {
|
||||||
if (type !== 'invite') {
|
if (type !== 'invite') {
|
||||||
const room = yield RocketChat.canOpenRoom(params);
|
const room = yield RocketChat.canOpenRoom(params);
|
||||||
if (room) {
|
if (room) {
|
||||||
const isMasterDetail = yield select(state => state.app.isMasterDetail);
|
|
||||||
if (isMasterDetail) {
|
|
||||||
Navigation.navigate('DrawerNavigator');
|
|
||||||
} else {
|
|
||||||
Navigation.navigate('RoomsListView');
|
|
||||||
}
|
|
||||||
const item = {
|
const item = {
|
||||||
name,
|
name,
|
||||||
t: roomTypes[type],
|
t: roomTypes[type],
|
||||||
roomUserId: RocketChat.getUidDirectMessage(room),
|
roomUserId: RocketChat.getUidDirectMessage(room),
|
||||||
...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) {
|
if (params.isCall) {
|
||||||
RocketChat.callJitsi(item.rid);
|
RocketChat.callJitsi(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -72,7 +89,7 @@ const fallbackNavigation = function* fallbackNavigation() {
|
||||||
|
|
||||||
const handleOpen = function* handleOpen({ params }) {
|
const handleOpen = function* handleOpen({ params }) {
|
||||||
const serversDB = database.servers;
|
const serversDB = database.servers;
|
||||||
const serversCollection = serversDB.collections.get('servers');
|
const serversCollection = serversDB.get('servers');
|
||||||
|
|
||||||
let { host } = params;
|
let { host } = params;
|
||||||
if (params.isCall && !host) {
|
if (params.isCall && !host) {
|
||||||
|
@ -121,10 +138,10 @@ const handleOpen = function* handleOpen({ params }) {
|
||||||
} else {
|
} else {
|
||||||
// search if deep link's server already exists
|
// search if deep link's server already exists
|
||||||
try {
|
try {
|
||||||
const servers = yield serversCollection.find(host);
|
const hostServerRecord = yield serversCollection.find(host);
|
||||||
if (servers && user) {
|
if (hostServerRecord && user) {
|
||||||
yield localAuthenticate(host);
|
yield localAuthenticate(host);
|
||||||
yield put(selectServerRequest(host));
|
yield put(selectServerRequest(host, hostServerRecord.version, true, true));
|
||||||
yield take(types.LOGIN.SUCCESS);
|
yield take(types.LOGIN.SUCCESS);
|
||||||
yield navigate({ params });
|
yield navigate({ params });
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -30,7 +30,7 @@ const handleEncryptionInit = function* handleEncryptionInit() {
|
||||||
|
|
||||||
// Fetch server info to check E2E enable
|
// Fetch server info to check E2E enable
|
||||||
const serversDB = database.servers;
|
const serversDB = database.servers;
|
||||||
const serversCollection = serversDB.collections.get('servers');
|
const serversCollection = serversDB.get('servers');
|
||||||
let serverInfo;
|
let serverInfo;
|
||||||
try {
|
try {
|
||||||
serverInfo = yield serversCollection.find(server);
|
serverInfo = yield serversCollection.find(server);
|
||||||
|
|
|
@ -38,7 +38,7 @@ const restore = function* restore() {
|
||||||
yield put(appStart({ root: ROOT_OUTSIDE }));
|
yield put(appStart({ root: ROOT_OUTSIDE }));
|
||||||
} else {
|
} else {
|
||||||
const serversDB = database.servers;
|
const serversDB = database.servers;
|
||||||
const serverCollections = serversDB.collections.get('servers');
|
const serverCollections = serversDB.get('servers');
|
||||||
|
|
||||||
let serverObj;
|
let serverObj;
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -57,7 +57,7 @@ const handleLoginRequest = function* handleLoginRequest({ credentials, logoutOnE
|
||||||
|
|
||||||
// Saves username on server history
|
// Saves username on server history
|
||||||
const serversDB = database.servers;
|
const serversDB = database.servers;
|
||||||
const serversHistoryCollection = serversDB.collections.get('servers_history');
|
const serversHistoryCollection = serversDB.get('servers_history');
|
||||||
yield serversDB.action(async() => {
|
yield serversDB.action(async() => {
|
||||||
try {
|
try {
|
||||||
const serversHistory = await serversHistoryCollection.query(Q.where('url', server)).fetch();
|
const serversHistory = await serversHistoryCollection.query(Q.where('url', server)).fetch();
|
||||||
|
@ -145,7 +145,7 @@ const handleLoginSuccess = function* handleLoginSuccess({ user }) {
|
||||||
moment.locale(toMomentLocale(user.language));
|
moment.locale(toMomentLocale(user.language));
|
||||||
|
|
||||||
const serversDB = database.servers;
|
const serversDB = database.servers;
|
||||||
const usersCollection = serversDB.collections.get('users');
|
const usersCollection = serversDB.get('users');
|
||||||
const u = {
|
const u = {
|
||||||
token: user.token,
|
token: user.token,
|
||||||
username: user.username,
|
username: user.username,
|
||||||
|
@ -222,7 +222,7 @@ const handleLogout = function* handleLogout({ forcedByServer }) {
|
||||||
} else {
|
} else {
|
||||||
const serversDB = database.servers;
|
const serversDB = database.servers;
|
||||||
// all servers
|
// all servers
|
||||||
const serversCollection = serversDB.collections.get('servers');
|
const serversCollection = serversDB.get('servers');
|
||||||
const servers = yield serversCollection.query().fetch();
|
const servers = yield serversCollection.query().fetch();
|
||||||
|
|
||||||
// see if there're other logged in servers and selects first one
|
// see if there're other logged in servers and selects first one
|
||||||
|
|
|
@ -12,7 +12,7 @@ const handleReplyBroadcast = function* handleReplyBroadcast({ message }) {
|
||||||
try {
|
try {
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const { username } = message.u;
|
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 subscriptions = yield subsCollection.query(Q.where('name', username)).fetch();
|
||||||
|
|
||||||
const isMasterDetail = yield select(state => state.app.isMasterDetail);
|
const isMasterDetail = yield select(state => state.app.isMasterDetail);
|
||||||
|
|
|
@ -15,7 +15,7 @@ import protectedFunction from '../lib/methods/helpers/protectedFunction';
|
||||||
|
|
||||||
const updateRooms = function* updateRooms({ server, newRoomsUpdatedAt }) {
|
const updateRooms = function* updateRooms({ server, newRoomsUpdatedAt }) {
|
||||||
const serversDB = database.servers;
|
const serversDB = database.servers;
|
||||||
const serversCollection = serversDB.collections.get('servers');
|
const serversCollection = serversDB.get('servers');
|
||||||
try {
|
try {
|
||||||
const serverRecord = yield serversCollection.find(server);
|
const serverRecord = yield serversCollection.find(server);
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ const handleRoomsRequest = function* handleRoomsRequest({ params }) {
|
||||||
if (params.allData) {
|
if (params.allData) {
|
||||||
yield put(roomsRefresh());
|
yield put(roomsRefresh());
|
||||||
} else {
|
} else {
|
||||||
const serversCollection = serversDB.collections.get('servers');
|
const serversCollection = serversDB.get('servers');
|
||||||
try {
|
try {
|
||||||
const serverRecord = yield serversCollection.find(server);
|
const serverRecord = yield serversCollection.find(server);
|
||||||
({ roomsUpdatedAt } = serverRecord);
|
({ roomsUpdatedAt } = serverRecord);
|
||||||
|
@ -51,8 +51,8 @@ const handleRoomsRequest = function* handleRoomsRequest({ params }) {
|
||||||
const { subscriptions } = yield mergeSubscriptionsRooms(subscriptionsResult, roomsResult);
|
const { subscriptions } = yield mergeSubscriptionsRooms(subscriptionsResult, roomsResult);
|
||||||
|
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const subCollection = db.collections.get('subscriptions');
|
const subCollection = db.get('subscriptions');
|
||||||
const messagesCollection = db.collections.get('messages');
|
const messagesCollection = db.get('messages');
|
||||||
|
|
||||||
const subsIds = subscriptions.map(sub => sub.rid).concat(roomsResult.remove.map(room => room._id));
|
const subsIds = subscriptions.map(sub => sub.rid).concat(roomsResult.remove.map(room => room._id));
|
||||||
if (subsIds.length) {
|
if (subsIds.length) {
|
||||||
|
|
|
@ -46,7 +46,7 @@ const getServerInfo = function* getServerInfo({ server, raiseError = true }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const serversDB = database.servers;
|
const serversDB = database.servers;
|
||||||
const serversCollection = serversDB.collections.get('servers');
|
const serversCollection = serversDB.get('servers');
|
||||||
yield serversDB.action(async() => {
|
yield serversDB.action(async() => {
|
||||||
try {
|
try {
|
||||||
const serverRecord = await serversCollection.find(server);
|
const serverRecord = await serversCollection.find(server);
|
||||||
|
@ -78,7 +78,7 @@ const handleSelectServer = function* handleSelectServer({ server, version, fetch
|
||||||
const serversDB = database.servers;
|
const serversDB = database.servers;
|
||||||
yield UserPreferences.setStringAsync(RocketChat.CURRENT_SERVER, server);
|
yield UserPreferences.setStringAsync(RocketChat.CURRENT_SERVER, server);
|
||||||
const userId = yield UserPreferences.getStringAsync(`${ RocketChat.TOKEN_KEY }-${ server }`);
|
const userId = yield UserPreferences.getStringAsync(`${ RocketChat.TOKEN_KEY }-${ server }`);
|
||||||
const userCollections = serversDB.collections.get('users');
|
const userCollections = serversDB.get('users');
|
||||||
let user = null;
|
let user = null;
|
||||||
if (userId) {
|
if (userId) {
|
||||||
try {
|
try {
|
||||||
|
@ -124,6 +124,7 @@ const handleSelectServer = function* handleSelectServer({ server, version, fetch
|
||||||
// and block the selectServerSuccess raising multiples errors
|
// and block the selectServerSuccess raising multiples errors
|
||||||
RocketChat.setSettings();
|
RocketChat.setSettings();
|
||||||
RocketChat.setCustomEmojis();
|
RocketChat.setCustomEmojis();
|
||||||
|
RocketChat.setPermissions();
|
||||||
RocketChat.setEnterpriseModules();
|
RocketChat.setEnterpriseModules();
|
||||||
|
|
||||||
let serverInfo;
|
let serverInfo;
|
||||||
|
@ -151,7 +152,7 @@ const handleServerRequest = function* handleServerRequest({ server, username, fr
|
||||||
|
|
||||||
const serverInfo = yield getServerInfo({ server });
|
const serverInfo = yield getServerInfo({ server });
|
||||||
const serversDB = database.servers;
|
const serversDB = database.servers;
|
||||||
const serversHistoryCollection = serversDB.collections.get('servers_history');
|
const serversHistoryCollection = serversDB.get('servers_history');
|
||||||
|
|
||||||
if (serverInfo) {
|
if (serverInfo) {
|
||||||
yield RocketChat.getLoginServices(server);
|
yield RocketChat.getLoginServices(server);
|
||||||
|
|
|
@ -12,13 +12,14 @@ const appHasComeBackToForeground = function* appHasComeBackToForeground() {
|
||||||
if (appRoot === ROOT_OUTSIDE) {
|
if (appRoot === ROOT_OUTSIDE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auth = yield select(state => state.login.isAuthenticated);
|
const login = yield select(state => state.login);
|
||||||
if (!auth) {
|
const server = yield select(state => state.server);
|
||||||
|
if (!login.isAuthenticated || login.isFetching || server.connecting || server.loading || server.changingServer) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const server = yield select(state => state.server.server);
|
yield localAuthenticate(server.server);
|
||||||
yield localAuthenticate(server);
|
RocketChat.checkAndReopen();
|
||||||
setBadgeCount();
|
setBadgeCount();
|
||||||
return yield RocketChat.setUserPresenceOnline();
|
return yield RocketChat.setUserPresenceOnline();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -31,14 +32,6 @@ const appHasComeBackToBackground = function* appHasComeBackToBackground() {
|
||||||
if (appRoot === ROOT_OUTSIDE) {
|
if (appRoot === ROOT_OUTSIDE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auth = yield select(state => state.login.isAuthenticated);
|
|
||||||
if (!auth) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const localAuthenticated = yield select(state => state.login.isLocalAuthenticated);
|
|
||||||
if (!localAuthenticated) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
const server = yield select(state => state.server.server);
|
const server = yield select(state => state.server.server);
|
||||||
yield saveLastLocalAuthenticationSession(server);
|
yield saveLastLocalAuthenticationSession(server);
|
||||||
|
|
|
@ -31,6 +31,7 @@ import PickerView from '../views/PickerView';
|
||||||
import ThreadMessagesView from '../views/ThreadMessagesView';
|
import ThreadMessagesView from '../views/ThreadMessagesView';
|
||||||
import MarkdownTableView from '../views/MarkdownTableView';
|
import MarkdownTableView from '../views/MarkdownTableView';
|
||||||
import ReadReceiptsView from '../views/ReadReceiptView';
|
import ReadReceiptsView from '../views/ReadReceiptView';
|
||||||
|
import { themes } from '../constants/colors';
|
||||||
|
|
||||||
// Profile Stack
|
// Profile Stack
|
||||||
import ProfileView from '../views/ProfileView';
|
import ProfileView from '../views/ProfileView';
|
||||||
|
@ -280,19 +281,24 @@ const AdminPanelStackNavigator = () => {
|
||||||
|
|
||||||
// DrawerNavigator
|
// DrawerNavigator
|
||||||
const Drawer = createDrawerNavigator();
|
const Drawer = createDrawerNavigator();
|
||||||
const DrawerNavigator = () => (
|
const DrawerNavigator = () => {
|
||||||
<Drawer.Navigator
|
const { theme } = React.useContext(ThemeContext);
|
||||||
drawerContent={({ navigation, state }) => <Sidebar navigation={navigation} state={state} />}
|
|
||||||
drawerPosition={I18nManager.isRTL ? 'right' : 'left'}
|
return (
|
||||||
screenOptions={{ swipeEnabled: false }}
|
<Drawer.Navigator
|
||||||
drawerType='back'
|
drawerContent={({ navigation, state }) => <Sidebar navigation={navigation} state={state} />}
|
||||||
>
|
drawerPosition={I18nManager.isRTL ? 'right' : 'left'}
|
||||||
<Drawer.Screen name='ChatsStackNavigator' component={ChatsStackNavigator} />
|
screenOptions={{ swipeEnabled: false }}
|
||||||
<Drawer.Screen name='ProfileStackNavigator' component={ProfileStackNavigator} />
|
drawerType='back'
|
||||||
<Drawer.Screen name='SettingsStackNavigator' component={SettingsStackNavigator} />
|
overlayColor={`rgba(0,0,0,${ themes[theme].backdropOpacity })`}
|
||||||
<Drawer.Screen name='AdminPanelStackNavigator' component={AdminPanelStackNavigator} />
|
>
|
||||||
</Drawer.Navigator>
|
<Drawer.Screen name='ChatsStackNavigator' component={ChatsStackNavigator} />
|
||||||
);
|
<Drawer.Screen name='ProfileStackNavigator' component={ProfileStackNavigator} />
|
||||||
|
<Drawer.Screen name='SettingsStackNavigator' component={SettingsStackNavigator} />
|
||||||
|
<Drawer.Screen name='AdminPanelStackNavigator' component={AdminPanelStackNavigator} />
|
||||||
|
</Drawer.Navigator>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
// NewMessageStackNavigator
|
// NewMessageStackNavigator
|
||||||
const NewMessageStack = createStackNavigator();
|
const NewMessageStack = createStackNavigator();
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
import RocketChat from '../lib/rocketchat';
|
import RocketChat from '../lib/rocketchat';
|
||||||
|
import reduxStore from '../lib/createStore';
|
||||||
|
|
||||||
const canPost = async({ rid }) => {
|
const canPostReadOnly = async({ rid }) => {
|
||||||
try {
|
// TODO: this is not reactive. If this permission changes, the component won't be updated
|
||||||
const permission = await RocketChat.hasPermission(['post-readonly'], rid);
|
const postReadOnlyPermission = reduxStore.getState().permissions['post-readonly'];
|
||||||
return permission && permission['post-readonly'];
|
const permission = await RocketChat.hasPermission([postReadOnlyPermission], rid);
|
||||||
} catch {
|
return permission[0];
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const isMuted = (room, user) => room && room.muted && room.muted.find && !!room.muted.find(m => m === user.username);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
if (room?.ro) {
|
if (room?.ro) {
|
||||||
const allowPost = await canPost(room);
|
const allowPost = await canPostReadOnly(room);
|
||||||
if (allowPost) {
|
if (allowPost) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ import { setLocalAuthenticated } from '../actions/login';
|
||||||
|
|
||||||
export const saveLastLocalAuthenticationSession = async(server, serverRecord) => {
|
export const saveLastLocalAuthenticationSession = async(server, serverRecord) => {
|
||||||
const serversDB = database.servers;
|
const serversDB = database.servers;
|
||||||
const serversCollection = serversDB.collections.get('servers');
|
const serversCollection = serversDB.get('servers');
|
||||||
await serversDB.action(async() => {
|
await serversDB.action(async() => {
|
||||||
try {
|
try {
|
||||||
if (!serverRecord) {
|
if (!serverRecord) {
|
||||||
|
@ -91,7 +91,7 @@ export const checkHasPasscode = async({ force = true, serverRecord }) => {
|
||||||
|
|
||||||
export const localAuthenticate = async(server) => {
|
export const localAuthenticate = async(server) => {
|
||||||
const serversDB = database.servers;
|
const serversDB = database.servers;
|
||||||
const serversCollection = serversDB.collections.get('servers');
|
const serversCollection = serversDB.get('servers');
|
||||||
|
|
||||||
let serverRecord;
|
let serverRecord;
|
||||||
try {
|
try {
|
||||||
|
@ -102,9 +102,6 @@ export const localAuthenticate = async(server) => {
|
||||||
|
|
||||||
// if screen lock is enabled
|
// if screen lock is enabled
|
||||||
if (serverRecord?.autoLock) {
|
if (serverRecord?.autoLock) {
|
||||||
// set isLocalAuthenticated to false
|
|
||||||
store.dispatch(setLocalAuthenticated(false));
|
|
||||||
|
|
||||||
// Make sure splash screen has been hidden
|
// Make sure splash screen has been hidden
|
||||||
RNBootSplash.hide();
|
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 last authenticated session is older than configured auto lock time, authentication is required
|
||||||
if (diffToLastSession >= serverRecord?.autoLockTime) {
|
if (diffToLastSession >= serverRecord?.autoLockTime) {
|
||||||
|
// set isLocalAuthenticated to false
|
||||||
|
store.dispatch(setLocalAuthenticated(false));
|
||||||
|
|
||||||
let hasBiometry = false;
|
let hasBiometry = false;
|
||||||
|
|
||||||
// if biometry is enabled on the app
|
// if biometry is enabled on the app
|
||||||
|
|
|
@ -5,9 +5,8 @@ export default {
|
||||||
ONBOARD_CREATE_NEW_WORKSPACE_F: 'onboard_create_new_workspace_f',
|
ONBOARD_CREATE_NEW_WORKSPACE_F: 'onboard_create_new_workspace_f',
|
||||||
|
|
||||||
// NEW SERVER VIEW
|
// NEW SERVER VIEW
|
||||||
NEWSERVER_CONNECT_TO_WORKSPACE: 'newserver_connect_to_workspace',
|
NS_CONNECT_TO_WORKSPACE: 'ns_connect_to_workspace',
|
||||||
NEWSERVER_CONNECT_TO_WORKSPACE_F: 'newserver_connect_to_workspace_f',
|
NS_JOIN_OPEN_WORKSPACE: 'ns_join_open_workspace',
|
||||||
NEWSERVER_JOIN_OPEN_WORKSPACE: 'newserver_join_open_workspace',
|
|
||||||
|
|
||||||
// LOGIN VIEW
|
// LOGIN VIEW
|
||||||
LOGIN_DEFAULT_LOGIN: 'login_default_login',
|
LOGIN_DEFAULT_LOGIN: 'login_default_login',
|
||||||
|
@ -99,20 +98,20 @@ export default {
|
||||||
SELECTED_USERS_CREATE_GROUP_F: 'selected_users_create_group_f',
|
SELECTED_USERS_CREATE_GROUP_F: 'selected_users_create_group_f',
|
||||||
|
|
||||||
// CREATE CHANNEL VIEW
|
// CREATE CHANNEL VIEW
|
||||||
CREATE_CHANNEL_CREATE: 'create_channel_create',
|
CR_CREATE: 'cr_create',
|
||||||
CREATE_CHANNEL_CREATE_F: 'create_channel_create_f',
|
CR_CREATE_F: 'cr_create_f',
|
||||||
CREATE_CHANNEL_TOGGLE_TYPE: 'create_channel_toggle_type',
|
CR_TOGGLE_TYPE: 'cr_toggle_type',
|
||||||
CREATE_CHANNEL_TOGGLE_READ_ONLY: 'create_channel_toggle_read_only',
|
CR_TOGGLE_READ_ONLY: 'cr_toggle_read_only',
|
||||||
CREATE_CHANNEL_TOGGLE_BROADCAST: 'create_channel_toggle_broadcast',
|
CR_TOGGLE_BROADCAST: 'cr_toggle_broadcast',
|
||||||
CREATE_CHANNEL_TOGGLE_ENCRYPTED: 'create_channel_toggle_encrypted',
|
CR_TOGGLE_ENCRYPTED: 'cr_toggle_encrypted',
|
||||||
CREATE_CHANNEL_REMOVE_USER: 'create_channel_remove_user',
|
CR_REMOVE_USER: 'cr_remove_user',
|
||||||
|
|
||||||
// CREATE DISCUSSION VIEW
|
// CREATE DISCUSSION VIEW
|
||||||
CREATE_DISCUSSION_CREATE: 'create_discussion_create',
|
CD_CREATE: 'cd_create',
|
||||||
CREATE_DISCUSSION_CREATE_F: 'create_discussion_create_f',
|
CD_CREATE_F: 'cd_create_f',
|
||||||
CREATE_DISCUSSION_SELECT_CHANNEL: 'create_discussion_select_channel',
|
CD_SELECT_CHANNEL: 'cd_select_channel',
|
||||||
CREATE_DISCUSSION_SELECT_USERS: 'create_discussion_select_users',
|
CD_SELECT_USERS: 'cd_select_users',
|
||||||
CREATE_DISCUSSION_TOGGLE_ENCRY: 'create_discussion_toggle_encry',
|
CD_TOGGLE_ENCRY: 'cd_toggle_encry',
|
||||||
|
|
||||||
// PROFILE VIEW
|
// PROFILE VIEW
|
||||||
PROFILE_PICK_AVATAR: 'profile_pick_avatar',
|
PROFILE_PICK_AVATAR: 'profile_pick_avatar',
|
||||||
|
@ -122,8 +121,9 @@ export default {
|
||||||
PROFILE_SAVE_AVATAR_F: 'profile_save_avatar_f',
|
PROFILE_SAVE_AVATAR_F: 'profile_save_avatar_f',
|
||||||
PROFILE_SAVE_CHANGES: 'profile_save_changes',
|
PROFILE_SAVE_CHANGES: 'profile_save_changes',
|
||||||
PROFILE_SAVE_CHANGES_F: 'profile_save_changes_f',
|
PROFILE_SAVE_CHANGES_F: 'profile_save_changes_f',
|
||||||
PROFILE_LOGOUT_OTHER_LOCATIONS: 'profile_logout_other_locations',
|
// PROFILE LOGOUT
|
||||||
PROFILE_LOGOUT_OTHER_LOCATIONS_F: 'profile_logout_other_locations_f',
|
PL_OTHER_LOCATIONS: 'pl_other_locations',
|
||||||
|
PL_OTHER_LOCATIONS_F: 'pl_other_locations_f',
|
||||||
|
|
||||||
// SETTINGS VIEW
|
// SETTINGS VIEW
|
||||||
SE_CONTACT_US: 'se_contact_us',
|
SE_CONTACT_US: 'se_contact_us',
|
||||||
|
@ -297,8 +297,6 @@ export default {
|
||||||
NP_AUDIONOTIFICATIONS_F: 'np_audio_notifications_f',
|
NP_AUDIONOTIFICATIONS_F: 'np_audio_notifications_f',
|
||||||
NP_AUDIONOTIFICATIONVALUE: 'np_audio_notification_value',
|
NP_AUDIONOTIFICATIONVALUE: 'np_audio_notification_value',
|
||||||
NP_AUDIONOTIFICATIONVALUE_F: 'np_audio_notification_value_f',
|
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: 'np_email_notifications',
|
||||||
NP_EMAILNOTIFICATIONS_F: 'np_email_notifications_f',
|
NP_EMAILNOTIFICATIONS_F: 'np_email_notifications_f',
|
||||||
|
|
||||||
|
|
|
@ -121,8 +121,9 @@ class AttachmentView extends React.Component {
|
||||||
const extension = image_url ? `.${ mime.extension(image_type) || 'jpg' }` : `.${ mime.extension(video_type) || 'mp4' }`;
|
const extension = image_url ? `.${ mime.extension(image_type) || 'jpg' }` : `.${ mime.extension(video_type) || 'mp4' }`;
|
||||||
const documentDir = `${ RNFetchBlob.fs.dirs.DocumentDir }/`;
|
const documentDir = `${ RNFetchBlob.fs.dirs.DocumentDir }/`;
|
||||||
const path = `${ documentDir + SHA256(url) + extension }`;
|
const path = `${ documentDir + SHA256(url) + extension }`;
|
||||||
const file = await RNFetchBlob.config({ path }).fetch('GET', mediaAttachment).then(res => res.path());
|
const file = await RNFetchBlob.config({ path }).fetch('GET', mediaAttachment);
|
||||||
await CameraRoll.save(file, { album: 'Rocket.Chat' });
|
await CameraRoll.save(path, { album: 'Rocket.Chat' });
|
||||||
|
await file.flush();
|
||||||
EventEmitter.emit(LISTENER, { message: I18n.t('saved_to_gallery') });
|
EventEmitter.emit(LISTENER, { message: I18n.t('saved_to_gallery') });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
EventEmitter.emit(LISTENER, { message: I18n.t(image_url ? 'error-save-image' : 'error-save-video') });
|
EventEmitter.emit(LISTENER, { message: I18n.t(image_url ? 'error-save-image' : 'error-save-video') });
|
||||||
|
|
|
@ -63,12 +63,12 @@ const ChangePasscodeView = React.memo(({ theme }) => {
|
||||||
if (!isTablet) {
|
if (!isTablet) {
|
||||||
Orientation.lockToPortrait();
|
Orientation.lockToPortrait();
|
||||||
}
|
}
|
||||||
EventEmitter.addEventListener(CHANGE_PASSCODE_EMITTER, showChangePasscode);
|
const listener = EventEmitter.addEventListener(CHANGE_PASSCODE_EMITTER, showChangePasscode);
|
||||||
return (() => {
|
return (() => {
|
||||||
if (!isTablet) {
|
if (!isTablet) {
|
||||||
Orientation.unlockAllOrientations();
|
Orientation.unlockAllOrientations();
|
||||||
}
|
}
|
||||||
EventEmitter.removeListener(CHANGE_PASSCODE_EMITTER);
|
EventEmitter.removeListener(CHANGE_PASSCODE_EMITTER, listener);
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,8 @@ import PropTypes from 'prop-types';
|
||||||
import {
|
import {
|
||||||
View, Text, Switch, ScrollView, StyleSheet, FlatList
|
View, Text, Switch, ScrollView, StyleSheet, FlatList
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import equal from 'deep-equal';
|
import { dequal } from 'dequal';
|
||||||
|
import * as List from '../containers/List';
|
||||||
|
|
||||||
import TextInput from '../presentation/TextInput';
|
import TextInput from '../presentation/TextInput';
|
||||||
import Loading from '../containers/Loading';
|
import Loading from '../containers/Loading';
|
||||||
|
@ -31,12 +32,6 @@ const styles = StyleSheet.create({
|
||||||
list: {
|
list: {
|
||||||
width: '100%'
|
width: '100%'
|
||||||
},
|
},
|
||||||
separator: {
|
|
||||||
marginLeft: 60
|
|
||||||
},
|
|
||||||
formSeparator: {
|
|
||||||
marginLeft: 15
|
|
||||||
},
|
|
||||||
input: {
|
input: {
|
||||||
height: 54,
|
height: 54,
|
||||||
paddingHorizontal: 18,
|
paddingHorizontal: 18,
|
||||||
|
@ -133,7 +128,7 @@ class CreateChannelView extends React.Component {
|
||||||
if (nextProps.encryptionEnabled !== encryptionEnabled) {
|
if (nextProps.encryptionEnabled !== encryptionEnabled) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!equal(nextProps.users, users)) {
|
if (!dequal(nextProps.users, users)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -177,7 +172,7 @@ class CreateChannelView extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
removeUser = (user) => {
|
removeUser = (user) => {
|
||||||
logEvent(events.CREATE_CHANNEL_REMOVE_USER);
|
logEvent(events.CR_REMOVE_USER);
|
||||||
const { removeUser } = this.props;
|
const { removeUser } = this.props;
|
||||||
removeUser(user);
|
removeUser(user);
|
||||||
}
|
}
|
||||||
|
@ -207,7 +202,7 @@ class CreateChannelView extends React.Component {
|
||||||
value: type,
|
value: type,
|
||||||
label: 'Private_Channel',
|
label: 'Private_Channel',
|
||||||
onValueChange: (value) => {
|
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
|
// If we set the channel as public, encrypted status should be false
|
||||||
this.setState(({ encrypted }) => ({ type: value, encrypted: value && encrypted }));
|
this.setState(({ encrypted }) => ({ type: value, encrypted: value && encrypted }));
|
||||||
}
|
}
|
||||||
|
@ -221,7 +216,7 @@ class CreateChannelView extends React.Component {
|
||||||
value: readOnly,
|
value: readOnly,
|
||||||
label: 'Read_Only_Channel',
|
label: 'Read_Only_Channel',
|
||||||
onValueChange: (value) => {
|
onValueChange: (value) => {
|
||||||
logEvent(events.CREATE_CHANNEL_TOGGLE_READ_ONLY);
|
logEvent(events.CR_TOGGLE_READ_ONLY);
|
||||||
this.setState({ readOnly: value });
|
this.setState({ readOnly: value });
|
||||||
},
|
},
|
||||||
disabled: broadcast
|
disabled: broadcast
|
||||||
|
@ -241,7 +236,7 @@ class CreateChannelView extends React.Component {
|
||||||
value: encrypted,
|
value: encrypted,
|
||||||
label: 'Encrypted',
|
label: 'Encrypted',
|
||||||
onValueChange: (value) => {
|
onValueChange: (value) => {
|
||||||
logEvent(events.CREATE_CHANNEL_TOGGLE_ENCRYPTED);
|
logEvent(events.CR_TOGGLE_ENCRYPTED);
|
||||||
this.setState({ encrypted: value });
|
this.setState({ encrypted: value });
|
||||||
},
|
},
|
||||||
disabled: !type
|
disabled: !type
|
||||||
|
@ -255,7 +250,7 @@ class CreateChannelView extends React.Component {
|
||||||
value: broadcast,
|
value: broadcast,
|
||||||
label: 'Broadcast_Channel',
|
label: 'Broadcast_Channel',
|
||||||
onValueChange: (value) => {
|
onValueChange: (value) => {
|
||||||
logEvent(events.CREATE_CHANNEL_TOGGLE_BROADCAST);
|
logEvent(events.CR_TOGGLE_BROADCAST);
|
||||||
this.setState({
|
this.setState({
|
||||||
broadcast: value,
|
broadcast: value,
|
||||||
readOnly: value ? true : readOnly
|
readOnly: value ? true : readOnly
|
||||||
|
@ -264,13 +259,6 @@ class CreateChannelView extends React.Component {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
renderSeparator = () => <View style={[sharedStyles.separator, styles.separator]} />
|
|
||||||
|
|
||||||
renderFormSeparator = () => {
|
|
||||||
const { theme } = this.props;
|
|
||||||
return <View style={[sharedStyles.separator, styles.formSeparator, { backgroundColor: themes[theme].separatorColor }]} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
renderItem = ({ item }) => {
|
renderItem = ({ item }) => {
|
||||||
const { baseUrl, user, theme } = this.props;
|
const { baseUrl, user, theme } = this.props;
|
||||||
|
|
||||||
|
@ -305,7 +293,7 @@ class CreateChannelView extends React.Component {
|
||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
renderItem={this.renderItem}
|
renderItem={this.renderItem}
|
||||||
ItemSeparatorComponent={this.renderSeparator}
|
ItemSeparatorComponent={List.Separator}
|
||||||
enableEmptySections
|
enableEmptySections
|
||||||
keyboardShouldPersistTaps='always'
|
keyboardShouldPersistTaps='always'
|
||||||
/>
|
/>
|
||||||
|
@ -341,13 +329,13 @@ class CreateChannelView extends React.Component {
|
||||||
theme={theme}
|
theme={theme}
|
||||||
underlineColorAndroid='transparent'
|
underlineColorAndroid='transparent'
|
||||||
/>
|
/>
|
||||||
{this.renderFormSeparator()}
|
<List.Separator />
|
||||||
{this.renderType()}
|
{this.renderType()}
|
||||||
{this.renderFormSeparator()}
|
<List.Separator />
|
||||||
{this.renderReadOnly()}
|
{this.renderReadOnly()}
|
||||||
{this.renderFormSeparator()}
|
<List.Separator />
|
||||||
{this.renderEncrypted()}
|
{this.renderEncrypted()}
|
||||||
{this.renderFormSeparator()}
|
<List.Separator />
|
||||||
{this.renderBroadcast()}
|
{this.renderBroadcast()}
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.invitedHeader}>
|
<View style={styles.invitedHeader}>
|
||||||
|
|
|
@ -22,7 +22,7 @@ const SelectUsers = ({
|
||||||
const getUsers = debounce(async(keyword = '') => {
|
const getUsers = debounce(async(keyword = '') => {
|
||||||
try {
|
try {
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const usersCollection = db.collections.get('users');
|
const usersCollection = db.get('users');
|
||||||
const res = await RocketChat.search({ text: keyword, filterRooms: false });
|
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))];
|
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();
|
const records = await usersCollection.query(Q.where('username', Q.oneOf(items.map(u => u.name)))).fetch();
|
||||||
|
|
|
@ -2,7 +2,6 @@ import React from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { ScrollView, Text, Switch } from 'react-native';
|
import { ScrollView, Text, Switch } from 'react-native';
|
||||||
import isEqual from 'lodash/isEqual';
|
|
||||||
|
|
||||||
import Loading from '../../containers/Loading';
|
import Loading from '../../containers/Loading';
|
||||||
import KeyboardView from '../../presentation/KeyboardView';
|
import KeyboardView from '../../presentation/KeyboardView';
|
||||||
|
@ -63,11 +62,12 @@ class CreateChannelView extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps, prevState) {
|
componentDidUpdate(prevProps, prevState) {
|
||||||
|
const { channel, name } = this.state;
|
||||||
const {
|
const {
|
||||||
loading, failure, error, result, isMasterDetail
|
loading, failure, error, result, isMasterDetail
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
if (!isEqual(this.state, prevState)) {
|
if (channel?.rid !== prevState.channel?.rid || name !== prevState.name) {
|
||||||
this.setHeader();
|
this.setHeader();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,17 +136,17 @@ class CreateChannelView extends React.Component {
|
||||||
};
|
};
|
||||||
|
|
||||||
selectChannel = ({ value }) => {
|
selectChannel = ({ value }) => {
|
||||||
logEvent(events.CREATE_DISCUSSION_SELECT_CHANNEL);
|
logEvent(events.CD_SELECT_CHANNEL);
|
||||||
this.setState({ channel: value, encrypted: value?.encrypted });
|
this.setState({ channel: value, encrypted: value?.encrypted });
|
||||||
}
|
}
|
||||||
|
|
||||||
selectUsers = ({ value }) => {
|
selectUsers = ({ value }) => {
|
||||||
logEvent(events.CREATE_DISCUSSION_SELECT_USERS);
|
logEvent(events.CD_SELECT_USERS);
|
||||||
this.setState({ users: value });
|
this.setState({ users: value });
|
||||||
}
|
}
|
||||||
|
|
||||||
onEncryptedChange = (value) => {
|
onEncryptedChange = (value) => {
|
||||||
logEvent(events.CREATE_DISCUSSION_TOGGLE_ENCRY);
|
logEvent(events.CD_TOGGLE_ENCRY);
|
||||||
this.setState({ encrypted: value });
|
this.setState({ encrypted: value });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,7 +222,7 @@ const mapStateToProps = state => ({
|
||||||
loading: state.createDiscussion.isFetching,
|
loading: state.createDiscussion.isFetching,
|
||||||
result: state.createDiscussion.result,
|
result: state.createDiscussion.result,
|
||||||
blockUnauthenticatedAccess: state.settings.Accounts_AvatarBlockUnauthenticatedAccess ?? true,
|
blockUnauthenticatedAccess: state.settings.Accounts_AvatarBlockUnauthenticatedAccess ?? true,
|
||||||
serverVersion: state.share.server.version || state.server.version,
|
serverVersion: state.server.version,
|
||||||
isMasterDetail: state.app.isMasterDetail,
|
isMasterDetail: state.app.isMasterDetail,
|
||||||
encryptionEnabled: state.encryption.enabled
|
encryptionEnabled: state.encryption.enabled
|
||||||
});
|
});
|
||||||
|
|
|
@ -84,13 +84,13 @@ export default class DirectoryOptions extends PureComponent {
|
||||||
inputRange: [0, 1],
|
inputRange: [0, 1],
|
||||||
outputRange: [-326, 0]
|
outputRange: [-326, 0]
|
||||||
});
|
});
|
||||||
const backdropOpacity = this.animatedValue.interpolate({
|
|
||||||
inputRange: [0, 1],
|
|
||||||
outputRange: [0, 0.3]
|
|
||||||
});
|
|
||||||
const {
|
const {
|
||||||
globalUsers, toggleWorkspace, isFederationEnabled, theme
|
globalUsers, toggleWorkspace, isFederationEnabled, theme
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
const backdropOpacity = this.animatedValue.interpolate({
|
||||||
|
inputRange: [0, 1],
|
||||||
|
outputRange: [0, themes[theme].backdropOpacity]
|
||||||
|
});
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TouchableWithoutFeedback onPress={this.close}>
|
<TouchableWithoutFeedback onPress={this.close}>
|
||||||
|
|
|
@ -4,6 +4,7 @@ import {
|
||||||
View, FlatList, Text
|
View, FlatList, Text
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
import * as List from '../../containers/List';
|
||||||
|
|
||||||
import Touch from '../../utils/touch';
|
import Touch from '../../utils/touch';
|
||||||
import RocketChat from '../../lib/rocketchat';
|
import RocketChat from '../../lib/rocketchat';
|
||||||
|
@ -182,11 +183,6 @@ class DirectoryView extends React.Component {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderSeparator = () => {
|
|
||||||
const { theme } = this.props;
|
|
||||||
return <View style={[sharedStyles.separator, styles.separator, { backgroundColor: themes[theme].separatorColor }]} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
renderItem = ({ item, index }) => {
|
renderItem = ({ item, index }) => {
|
||||||
const { data, type } = this.state;
|
const { data, type } = this.state;
|
||||||
const { baseUrl, user, theme } = this.props;
|
const { baseUrl, user, theme } = this.props;
|
||||||
|
@ -251,7 +247,7 @@ class DirectoryView extends React.Component {
|
||||||
keyExtractor={item => item._id}
|
keyExtractor={item => item._id}
|
||||||
ListHeaderComponent={this.renderHeader}
|
ListHeaderComponent={this.renderHeader}
|
||||||
renderItem={this.renderItem}
|
renderItem={this.renderItem}
|
||||||
ItemSeparatorComponent={this.renderSeparator}
|
ItemSeparatorComponent={List.Separator}
|
||||||
keyboardShouldPersistTaps='always'
|
keyboardShouldPersistTaps='always'
|
||||||
ListFooterComponent={loading ? <ActivityIndicator theme={theme} /> : null}
|
ListFooterComponent={loading ? <ActivityIndicator theme={theme} /> : null}
|
||||||
onEndReached={() => this.load({})}
|
onEndReached={() => this.load({})}
|
||||||
|
|
|
@ -94,7 +94,7 @@ class LanguageView extends React.Component {
|
||||||
setUser({ language: params.language });
|
setUser({ language: params.language });
|
||||||
|
|
||||||
const serversDB = database.servers;
|
const serversDB = database.servers;
|
||||||
const usersCollection = serversDB.collections.get('users');
|
const usersCollection = serversDB.get('users');
|
||||||
await serversDB.action(async() => {
|
await serversDB.action(async() => {
|
||||||
try {
|
try {
|
||||||
const userRecord = await usersCollection.find(user.id);
|
const userRecord = await usersCollection.find(user.id);
|
||||||
|
|
|
@ -4,7 +4,7 @@ import {
|
||||||
Text, View, StyleSheet, Keyboard, Alert
|
Text, View, StyleSheet, Keyboard, Alert
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import equal from 'deep-equal';
|
import { dequal } from 'dequal';
|
||||||
|
|
||||||
import sharedStyles from './Styles';
|
import sharedStyles from './Styles';
|
||||||
import Button from '../containers/Button';
|
import Button from '../containers/Button';
|
||||||
|
@ -82,7 +82,7 @@ class LoginView extends React.Component {
|
||||||
|
|
||||||
UNSAFE_componentWillReceiveProps(nextProps) {
|
UNSAFE_componentWillReceiveProps(nextProps) {
|
||||||
const { error } = this.props;
|
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'));
|
Alert.alert(I18n.t('Oops'), I18n.t('Login_error'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { FlatList, View, Text } from 'react-native';
|
import { FlatList, View, Text } from 'react-native';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import equal from 'deep-equal';
|
import { dequal } from 'dequal';
|
||||||
|
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
import Message from '../../containers/message';
|
import Message from '../../containers/message';
|
||||||
|
@ -57,7 +57,7 @@ class MessagesView extends React.Component {
|
||||||
if (nextState.loading !== loading) {
|
if (nextState.loading !== loading) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!equal(nextState.messages, messages)) {
|
if (!dequal(nextState.messages, messages)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (fileLoading !== nextState.fileLoading) {
|
if (fileLoading !== nextState.fileLoading) {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { StyleSheet, View } from 'react-native';
|
import { StyleSheet, View } from 'react-native';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import isEqual from 'lodash/isEqual';
|
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { KeyboardAwareScrollView } from '@codler/react-native-keyboard-aware-scroll-view';
|
import { KeyboardAwareScrollView } from '@codler/react-native-keyboard-aware-scroll-view';
|
||||||
|
|
||||||
|
@ -94,17 +93,6 @@ class ModalBlockView extends React.Component {
|
||||||
EventEmitter.addEventListener(viewId, this.handleUpdate);
|
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) {
|
componentDidUpdate(prevProps) {
|
||||||
const { navigation, route } = this.props;
|
const { navigation, route } = this.props;
|
||||||
const oldData = prevProps.route.params?.data ?? {};
|
const oldData = prevProps.route.params?.data ?? {};
|
||||||
|
|
|
@ -4,9 +4,8 @@ import {
|
||||||
View, StyleSheet, FlatList, Text
|
View, StyleSheet, FlatList, Text
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import equal from 'deep-equal';
|
|
||||||
import orderBy from 'lodash/orderBy';
|
|
||||||
import { Q } from '@nozbe/watermelondb';
|
import { Q } from '@nozbe/watermelondb';
|
||||||
|
import * as List from '../containers/List';
|
||||||
|
|
||||||
import Touch from '../utils/touch';
|
import Touch from '../utils/touch';
|
||||||
import database from '../lib/database';
|
import database from '../lib/database';
|
||||||
|
@ -27,10 +26,9 @@ import { createChannelRequest } from '../actions/createChannel';
|
||||||
import { goRoom } from '../utils/goRoom';
|
import { goRoom } from '../utils/goRoom';
|
||||||
import SafeAreaView from '../containers/SafeAreaView';
|
import SafeAreaView from '../containers/SafeAreaView';
|
||||||
|
|
||||||
|
const QUERY_SIZE = 50;
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
separator: {
|
|
||||||
marginLeft: 60
|
|
||||||
},
|
|
||||||
button: {
|
button: {
|
||||||
height: 46,
|
height: 46,
|
||||||
flexDirection: 'row',
|
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
|
// eslint-disable-next-line react/sort-comp
|
||||||
init = async() => {
|
init = async() => {
|
||||||
try {
|
try {
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const observable = await db.collections
|
const chats = await db.collections
|
||||||
.get('subscriptions')
|
.get('subscriptions')
|
||||||
.query(Q.where('t', 'd'))
|
.query(
|
||||||
.observeWithColumns(['room_updated_at']);
|
Q.where('t', 'd'),
|
||||||
|
Q.experimentalTake(QUERY_SIZE),
|
||||||
|
Q.experimentalSortBy('room_updated_at', Q.desc)
|
||||||
|
)
|
||||||
|
.fetch();
|
||||||
|
|
||||||
this.querySubscription = observable.subscribe((data) => {
|
this.setState({ chats });
|
||||||
const chats = orderBy(data, ['roomUpdatedAt'], ['desc']);
|
|
||||||
this.setState({ chats });
|
|
||||||
});
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log(e);
|
log(e);
|
||||||
}
|
}
|
||||||
|
@ -211,10 +189,6 @@ class NewMessageView extends React.Component {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderSeparator = () => {
|
|
||||||
const { theme } = this.props;
|
|
||||||
return <View style={[sharedStyles.separator, styles.separator, { backgroundColor: themes[theme].separatorColor }]} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
renderItem = ({ item, index }) => {
|
renderItem = ({ item, index }) => {
|
||||||
const { search, chats } = this.state;
|
const { search, chats } = this.state;
|
||||||
|
@ -254,7 +228,7 @@ class NewMessageView extends React.Component {
|
||||||
keyExtractor={item => item._id}
|
keyExtractor={item => item._id}
|
||||||
ListHeaderComponent={this.renderHeader}
|
ListHeaderComponent={this.renderHeader}
|
||||||
renderItem={this.renderItem}
|
renderItem={this.renderItem}
|
||||||
ItemSeparatorComponent={this.renderSeparator}
|
ItemSeparatorComponent={List.Separator}
|
||||||
contentContainerStyle={{ backgroundColor: themes[theme].backgroundColor }}
|
contentContainerStyle={{ backgroundColor: themes[theme].backgroundColor }}
|
||||||
keyboardShouldPersistTaps='always'
|
keyboardShouldPersistTaps='always'
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -132,7 +132,7 @@ class NewServerView extends React.Component {
|
||||||
queryServerHistory = async(text) => {
|
queryServerHistory = async(text) => {
|
||||||
const db = database.servers;
|
const db = database.servers;
|
||||||
try {
|
try {
|
||||||
const serversHistoryCollection = db.collections.get('servers_history');
|
const serversHistoryCollection = db.get('servers_history');
|
||||||
let whereClause = [
|
let whereClause = [
|
||||||
Q.where('username', Q.notEq(null)),
|
Q.where('username', Q.notEq(null)),
|
||||||
Q.experimentalSortBy('updated_at', Q.desc),
|
Q.experimentalSortBy('updated_at', Q.desc),
|
||||||
|
@ -174,7 +174,7 @@ class NewServerView extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
submit = async({ fromServerHistory = false, username }) => {
|
submit = async({ fromServerHistory = false, username }) => {
|
||||||
logEvent(events.NEWSERVER_CONNECT_TO_WORKSPACE);
|
logEvent(events.NS_CONNECT_TO_WORKSPACE);
|
||||||
const { text, certificate } = this.state;
|
const { text, certificate } = this.state;
|
||||||
const { connectServer } = this.props;
|
const { connectServer } = this.props;
|
||||||
|
|
||||||
|
@ -199,7 +199,7 @@ class NewServerView extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
connectOpen = () => {
|
connectOpen = () => {
|
||||||
logEvent(events.NEWSERVER_JOIN_OPEN_WORKSPACE);
|
logEvent(events.NS_JOIN_OPEN_WORKSPACE);
|
||||||
this.setState({ connectingOpen: true });
|
this.setState({ connectingOpen: true });
|
||||||
const { connectServer } = this.props;
|
const { connectServer } = this.props;
|
||||||
connectServer('https://open.rocket.chat');
|
connectServer('https://open.rocket.chat');
|
||||||
|
|
|
@ -6,7 +6,7 @@ import prompt from 'react-native-prompt-android';
|
||||||
import SHA256 from 'js-sha256';
|
import SHA256 from 'js-sha256';
|
||||||
import ImagePicker from 'react-native-image-crop-picker';
|
import ImagePicker from 'react-native-image-crop-picker';
|
||||||
import RNPickerSelect from 'react-native-picker-select';
|
import RNPickerSelect from 'react-native-picker-select';
|
||||||
import isEqual from 'lodash/isEqual';
|
import { dequal } from 'dequal';
|
||||||
import omit from 'lodash/omit';
|
import omit from 'lodash/omit';
|
||||||
|
|
||||||
import Touch from '../../utils/touch';
|
import Touch from '../../utils/touch';
|
||||||
|
@ -91,21 +91,11 @@ class ProfileView extends React.Component {
|
||||||
* it's resetting the avatar right after
|
* it's resetting the avatar right after
|
||||||
* select some image from gallery.
|
* 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);
|
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) => {
|
setAvatar = (avatar) => {
|
||||||
const { Accounts_AllowUserAvatarChange } = this.props;
|
const { Accounts_AllowUserAvatarChange } = this.props;
|
||||||
|
|
||||||
|
@ -434,7 +424,7 @@ class ProfileView extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
logoutOtherLocations = () => {
|
logoutOtherLocations = () => {
|
||||||
logEvent(events.PROFILE_LOGOUT_OTHER_LOCATIONS);
|
logEvent(events.PL_OTHER_LOCATIONS);
|
||||||
showConfirmationAlert({
|
showConfirmationAlert({
|
||||||
message: I18n.t('You_will_be_logged_out_from_other_locations'),
|
message: I18n.t('You_will_be_logged_out_from_other_locations'),
|
||||||
confirmationText: I18n.t('Logout'),
|
confirmationText: I18n.t('Logout'),
|
||||||
|
@ -443,7 +433,7 @@ class ProfileView extends React.Component {
|
||||||
await RocketChat.logoutOtherLocations();
|
await RocketChat.logoutOtherLocations();
|
||||||
EventEmitter.emit(LISTENER, { message: I18n.t('Logged_out_of_other_clients_successfully') });
|
EventEmitter.emit(LISTENER, { message: I18n.t('Logged_out_of_other_clients_successfully') });
|
||||||
} catch {
|
} catch {
|
||||||
logEvent(events.PROFILE_LOGOUT_OTHER_LOCATIONS_F);
|
logEvent(events.PL_OTHER_LOCATIONS_F);
|
||||||
EventEmitter.emit(LISTENER, { message: I18n.t('Logout_failed') });
|
EventEmitter.emit(LISTENER, { message: I18n.t('Logout_failed') });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { FlatList, View, Text } from 'react-native';
|
import { FlatList, View, Text } from 'react-native';
|
||||||
import equal from 'deep-equal';
|
import { dequal } from 'dequal';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
import * as List from '../../containers/List';
|
||||||
|
|
||||||
import Avatar from '../../containers/Avatar';
|
import Avatar from '../../containers/Avatar';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
|
@ -55,7 +56,7 @@ class ReadReceiptView extends React.Component {
|
||||||
if (nextState.loading !== loading) {
|
if (nextState.loading !== loading) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!equal(nextState.receipts, receipts)) {
|
if (!dequal(nextState.receipts, receipts)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -121,11 +122,6 @@ class ReadReceiptView extends React.Component {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderSeparator = () => {
|
|
||||||
const { theme } = this.props;
|
|
||||||
return <View style={[styles.separator, { backgroundColor: themes[theme].separatorColor }]} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { receipts, loading } = this.state;
|
const { receipts, loading } = this.state;
|
||||||
const { theme } = this.props;
|
const { theme } = this.props;
|
||||||
|
@ -143,7 +139,7 @@ class ReadReceiptView extends React.Component {
|
||||||
<FlatList
|
<FlatList
|
||||||
data={receipts}
|
data={receipts}
|
||||||
renderItem={this.renderItem}
|
renderItem={this.renderItem}
|
||||||
ItemSeparatorComponent={this.renderSeparator}
|
ItemSeparatorComponent={List.Separator}
|
||||||
style={[
|
style={[
|
||||||
styles.list,
|
styles.list,
|
||||||
{
|
{
|
||||||
|
|
|
@ -53,7 +53,15 @@ class RoomActionsView extends React.Component {
|
||||||
closeRoom: PropTypes.func,
|
closeRoom: PropTypes.func,
|
||||||
theme: PropTypes.string,
|
theme: PropTypes.string,
|
||||||
fontScale: PropTypes.number,
|
fontScale: PropTypes.number,
|
||||||
serverVersion: PropTypes.string
|
serverVersion: PropTypes.string,
|
||||||
|
addUserToJoinedRoomPermission: PropTypes.array,
|
||||||
|
addUserToAnyCRoomPermission: PropTypes.array,
|
||||||
|
addUserToAnyPRoomPermission: PropTypes.array,
|
||||||
|
createInviteLinksPermission: PropTypes.array,
|
||||||
|
editRoomPermission: PropTypes.array,
|
||||||
|
toggleRoomE2EEncryptionPermission: PropTypes.array,
|
||||||
|
viewBroadcastMemberListPermission: PropTypes.array,
|
||||||
|
transferLivechatGuestPermission: PropTypes.array
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -118,7 +126,7 @@ class RoomActionsView extends React.Component {
|
||||||
this.updateRoomMember();
|
this.updateRoomMember();
|
||||||
}
|
}
|
||||||
|
|
||||||
const canAutoTranslate = await RocketChat.canAutoTranslate();
|
const canAutoTranslate = RocketChat.canAutoTranslate();
|
||||||
this.setState({ canAutoTranslate });
|
this.setState({ canAutoTranslate });
|
||||||
|
|
||||||
this.canAddUser();
|
this.canAddUser();
|
||||||
|
@ -159,60 +167,62 @@ class RoomActionsView extends React.Component {
|
||||||
|
|
||||||
canAddUser = async() => {
|
canAddUser = async() => {
|
||||||
const { room, joined } = this.state;
|
const { room, joined } = this.state;
|
||||||
|
const { addUserToJoinedRoomPermission, addUserToAnyCRoomPermission, addUserToAnyPRoomPermission } = this.props;
|
||||||
const { rid, t } = room;
|
const { rid, t } = room;
|
||||||
let canAdd = false;
|
let canAddUser = false;
|
||||||
|
|
||||||
const userInRoom = joined;
|
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[0]) {
|
||||||
if (userInRoom && permissions['add-user-to-joined-room']) {
|
canAddUser = true;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
this.setState({ canAddUser: canAdd });
|
if (t === 'c' && permissions[1]) {
|
||||||
|
canAddUser = true;
|
||||||
|
}
|
||||||
|
if (t === 'p' && permissions[2]) {
|
||||||
|
canAddUser = true;
|
||||||
|
}
|
||||||
|
this.setState({ canAddUser });
|
||||||
}
|
}
|
||||||
|
|
||||||
canInviteUser = async() => {
|
canInviteUser = async() => {
|
||||||
const { room } = this.state;
|
const { room } = this.state;
|
||||||
|
const { createInviteLinksPermission } = this.props;
|
||||||
const { rid } = room;
|
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 });
|
this.setState({ canInviteUser });
|
||||||
}
|
}
|
||||||
|
|
||||||
canEdit = async() => {
|
canEdit = async() => {
|
||||||
const { room } = this.state;
|
const { room } = this.state;
|
||||||
|
const { editRoomPermission } = this.props;
|
||||||
const { rid } = room;
|
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 });
|
this.setState({ canEdit });
|
||||||
}
|
}
|
||||||
|
|
||||||
canToggleEncryption = async() => {
|
canToggleEncryption = async() => {
|
||||||
const { room } = this.state;
|
const { room } = this.state;
|
||||||
|
const { toggleRoomE2EEncryptionPermission } = this.props;
|
||||||
const { rid } = room;
|
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 });
|
this.setState({ canToggleEncryption });
|
||||||
}
|
}
|
||||||
|
|
||||||
canViewMembers = async() => {
|
canViewMembers = async() => {
|
||||||
const { room } = this.state;
|
const { room } = this.state;
|
||||||
|
const { viewBroadcastMemberListPermission } = this.props;
|
||||||
const { rid, t, broadcast } = room;
|
const { rid, t, broadcast } = room;
|
||||||
if (broadcast) {
|
if (broadcast) {
|
||||||
const viewBroadcastMemberListPermission = 'view-broadcast-member-list';
|
|
||||||
const permissions = await RocketChat.hasPermission([viewBroadcastMemberListPermission], rid);
|
const permissions = await RocketChat.hasPermission([viewBroadcastMemberListPermission], rid);
|
||||||
if (!permissions[viewBroadcastMemberListPermission]) {
|
if (!permissions[0]) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -226,16 +236,10 @@ class RoomActionsView extends React.Component {
|
||||||
|
|
||||||
canForwardGuest = async() => {
|
canForwardGuest = async() => {
|
||||||
const { room } = this.state;
|
const { room } = this.state;
|
||||||
|
const { transferLivechatGuestPermission } = this.props;
|
||||||
const { rid } = room;
|
const { rid } = room;
|
||||||
let result = true;
|
const permissions = await RocketChat.hasPermission([transferLivechatGuestPermission], rid);
|
||||||
|
this.setState({ canForwardGuest: permissions[0] });
|
||||||
const transferLivechatGuest = 'transfer-livechat-guest';
|
|
||||||
const permissions = await RocketChat.hasPermission([transferLivechatGuest], rid);
|
|
||||||
if (!permissions[transferLivechatGuest]) {
|
|
||||||
result = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({ canForwardGuest: result });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
canReturnQueue = async() => {
|
canReturnQueue = async() => {
|
||||||
|
@ -482,7 +486,7 @@ class RoomActionsView extends React.Component {
|
||||||
<List.Separator />
|
<List.Separator />
|
||||||
<List.Item
|
<List.Item
|
||||||
title='Voice_call'
|
title='Voice_call'
|
||||||
onPress={() => RocketChat.callJitsi(room?.rid, true)}
|
onPress={() => RocketChat.callJitsi(room, true)}
|
||||||
testID='room-actions-voice'
|
testID='room-actions-voice'
|
||||||
left={() => <List.Icon name='phone' />}
|
left={() => <List.Icon name='phone' />}
|
||||||
showActionIndicator
|
showActionIndicator
|
||||||
|
@ -490,7 +494,7 @@ class RoomActionsView extends React.Component {
|
||||||
<List.Separator />
|
<List.Separator />
|
||||||
<List.Item
|
<List.Item
|
||||||
title='Video_call'
|
title='Video_call'
|
||||||
onPress={() => RocketChat.callJitsi(room?.rid)}
|
onPress={() => RocketChat.callJitsi(room)}
|
||||||
testID='room-actions-video'
|
testID='room-actions-video'
|
||||||
left={() => <List.Icon name='camera' />}
|
left={() => <List.Icon name='camera' />}
|
||||||
showActionIndicator
|
showActionIndicator
|
||||||
|
@ -866,7 +870,15 @@ class RoomActionsView extends React.Component {
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
jitsiEnabled: state.settings.Jitsi_Enabled || false,
|
jitsiEnabled: state.settings.Jitsi_Enabled || false,
|
||||||
encryptionEnabled: state.encryption.enabled,
|
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 => ({
|
const mapDispatchToProps = dispatch => ({
|
||||||
|
|
|
@ -4,15 +4,13 @@ import {
|
||||||
Text, View, ScrollView, TouchableOpacity, Keyboard, Alert
|
Text, View, ScrollView, TouchableOpacity, Keyboard, Alert
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import equal from 'deep-equal';
|
|
||||||
import { BLOCK_CONTEXT } from '@rocket.chat/ui-kit';
|
import { BLOCK_CONTEXT } from '@rocket.chat/ui-kit';
|
||||||
import ImagePicker from 'react-native-image-crop-picker';
|
import ImagePicker from 'react-native-image-crop-picker';
|
||||||
import isEqual from 'lodash/isEqual';
|
import { dequal } from 'dequal';
|
||||||
import isEmpty from 'lodash/isEmpty';
|
import isEmpty from 'lodash/isEmpty';
|
||||||
import lt from 'semver/functions/lt';
|
import lt from 'semver/functions/lt';
|
||||||
import coerce from 'semver/functions/coerce';
|
import coerce from 'semver/functions/coerce';
|
||||||
|
|
||||||
|
|
||||||
import database from '../../lib/database';
|
import database from '../../lib/database';
|
||||||
import { deleteRoom as deleteRoomAction } from '../../actions/room';
|
import { deleteRoom as deleteRoomAction } from '../../actions/room';
|
||||||
import KeyboardView from '../../presentation/KeyboardView';
|
import KeyboardView from '../../presentation/KeyboardView';
|
||||||
|
@ -44,14 +42,6 @@ const PERMISSION_ARCHIVE = 'archive-room';
|
||||||
const PERMISSION_UNARCHIVE = 'unarchive-room';
|
const PERMISSION_UNARCHIVE = 'unarchive-room';
|
||||||
const PERMISSION_DELETE_C = 'delete-c';
|
const PERMISSION_DELETE_C = 'delete-c';
|
||||||
const PERMISSION_DELETE_P = 'delete-p';
|
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 {
|
class RoomInfoEditView extends React.Component {
|
||||||
static navigationOptions = () => ({
|
static navigationOptions = () => ({
|
||||||
|
@ -63,7 +53,13 @@ class RoomInfoEditView extends React.Component {
|
||||||
deleteRoom: PropTypes.func,
|
deleteRoom: PropTypes.func,
|
||||||
serverVersion: PropTypes.string,
|
serverVersion: PropTypes.string,
|
||||||
encryptionEnabled: PropTypes.bool,
|
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) {
|
constructor(props) {
|
||||||
|
@ -90,16 +86,6 @@ class RoomInfoEditView extends React.Component {
|
||||||
this.loadRoom();
|
this.loadRoom();
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps, nextState) {
|
|
||||||
if (!equal(nextState, this.state)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!equal(nextProps, this.props)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
if (this.querySubscription && this.querySubscription.unsubscribe) {
|
if (this.querySubscription && this.querySubscription.unsubscribe) {
|
||||||
this.querySubscription.unsubscribe();
|
this.querySubscription.unsubscribe();
|
||||||
|
@ -108,14 +94,22 @@ class RoomInfoEditView extends React.Component {
|
||||||
|
|
||||||
// eslint-disable-next-line react/sort-comp
|
// eslint-disable-next-line react/sort-comp
|
||||||
loadRoom = async() => {
|
loadRoom = async() => {
|
||||||
const { route } = this.props;
|
const {
|
||||||
|
route,
|
||||||
|
setReadOnlyPermission,
|
||||||
|
setReactWhenReadOnlyPermission,
|
||||||
|
archiveRoomPermission,
|
||||||
|
unarchiveRoomPermission,
|
||||||
|
deleteCPermission,
|
||||||
|
deletePPermission
|
||||||
|
} = this.props;
|
||||||
const rid = route.params?.rid;
|
const rid = route.params?.rid;
|
||||||
if (!rid) {
|
if (!rid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const db = database.active;
|
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();
|
const observable = sub.observe();
|
||||||
|
|
||||||
this.querySubscription = observable.subscribe((data) => {
|
this.querySubscription = observable.subscribe((data) => {
|
||||||
|
@ -123,8 +117,25 @@ class RoomInfoEditView extends React.Component {
|
||||||
this.init(this.room);
|
this.init(this.room);
|
||||||
});
|
});
|
||||||
|
|
||||||
const permissions = await RocketChat.hasPermission(PERMISSIONS_ARRAY, rid);
|
const result = await RocketChat.hasPermission([
|
||||||
this.setState({ permissions });
|
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) {
|
} catch (e) {
|
||||||
log(e);
|
log(e);
|
||||||
}
|
}
|
||||||
|
@ -179,7 +190,7 @@ class RoomInfoEditView extends React.Component {
|
||||||
&& room.t === 'p' === t
|
&& room.t === 'p' === t
|
||||||
&& room.ro === ro
|
&& room.ro === ro
|
||||||
&& room.reactWhenReadOnly === reactWhenReadOnly
|
&& room.reactWhenReadOnly === reactWhenReadOnly
|
||||||
&& isEqual(room.sysMes, systemMessages)
|
&& dequal(room.sysMes, systemMessages)
|
||||||
&& enableSysMes === (room.sysMes && room.sysMes.length > 0)
|
&& enableSysMes === (room.sysMes && room.sysMes.length > 0)
|
||||||
&& room.encrypted === encrypted
|
&& room.encrypted === encrypted
|
||||||
&& isEmpty(avatar)
|
&& isEmpty(avatar)
|
||||||
|
@ -239,7 +250,7 @@ class RoomInfoEditView extends React.Component {
|
||||||
params.reactWhenReadOnly = reactWhenReadOnly;
|
params.reactWhenReadOnly = reactWhenReadOnly;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isEqual(room.sysMes, systemMessages)) {
|
if (!dequal(room.sysMes, systemMessages)) {
|
||||||
params.systemMessages = systemMessages;
|
params.systemMessages = systemMessages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -666,8 +677,14 @@ class RoomInfoEditView extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
serverVersion: state.share.server.version || state.server.version,
|
serverVersion: state.server.version,
|
||||||
encryptionEnabled: state.encryption.enabled
|
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 => ({
|
const mapDispatchToProps = dispatch => ({
|
||||||
|
|
|
@ -31,7 +31,6 @@ import SafeAreaView from '../../containers/SafeAreaView';
|
||||||
import { goRoom } from '../../utils/goRoom';
|
import { goRoom } from '../../utils/goRoom';
|
||||||
import Navigation from '../../lib/Navigation';
|
import Navigation from '../../lib/Navigation';
|
||||||
|
|
||||||
const PERMISSION_EDIT_ROOM = 'edit-room';
|
|
||||||
const getRoomTitle = (room, type, name, username, statusText, theme) => (type === 'd'
|
const getRoomTitle = (room, type, name, username, statusText, theme) => (type === 'd'
|
||||||
? (
|
? (
|
||||||
<>
|
<>
|
||||||
|
@ -55,7 +54,8 @@ class RoomInfoView extends React.Component {
|
||||||
rooms: PropTypes.array,
|
rooms: PropTypes.array,
|
||||||
theme: PropTypes.string,
|
theme: PropTypes.string,
|
||||||
isMasterDetail: PropTypes.bool,
|
isMasterDetail: PropTypes.bool,
|
||||||
jitsiEnabled: PropTypes.bool
|
jitsiEnabled: PropTypes.bool,
|
||||||
|
editRoomPermission: PropTypes.array
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -136,7 +136,7 @@ class RoomInfoView extends React.Component {
|
||||||
getRoleDescription = async(id) => {
|
getRoleDescription = async(id) => {
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
try {
|
try {
|
||||||
const rolesCollection = db.collections.get('roles');
|
const rolesCollection = db.get('roles');
|
||||||
const role = await rolesCollection.find(id);
|
const role = await rolesCollection.find(id);
|
||||||
if (role) {
|
if (role) {
|
||||||
return role.description;
|
return role.description;
|
||||||
|
@ -193,7 +193,7 @@ class RoomInfoView extends React.Component {
|
||||||
|
|
||||||
loadRoom = async() => {
|
loadRoom = async() => {
|
||||||
const { room: roomState } = this.state;
|
const { room: roomState } = this.state;
|
||||||
const { route } = this.props;
|
const { route, editRoomPermission } = this.props;
|
||||||
let room = route.params?.room;
|
let room = route.params?.room;
|
||||||
if (room && room.observe) {
|
if (room && room.observe) {
|
||||||
this.roomObservable = 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);
|
const permissions = await RocketChat.hasPermission([editRoomPermission], room.rid);
|
||||||
if (permissions[PERMISSION_EDIT_ROOM] && !room.prid) {
|
if (permissions[0] && !room.prid) {
|
||||||
this.setState({ showEdit: true }, () => this.setHeader());
|
this.setState({ showEdit: true }, () => this.setHeader());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -276,7 +276,7 @@ class RoomInfoView extends React.Component {
|
||||||
|
|
||||||
videoCall = () => {
|
videoCall = () => {
|
||||||
const { room } = this.state;
|
const { room } = this.state;
|
||||||
RocketChat.callJitsi(room.rid);
|
RocketChat.callJitsi(room);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderAvatar = (room, roomUser) => {
|
renderAvatar = (room, roomUser) => {
|
||||||
|
@ -369,7 +369,8 @@ class RoomInfoView extends React.Component {
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
rooms: state.room.rooms,
|
rooms: state.room.rooms,
|
||||||
isMasterDetail: state.app.isMasterDetail,
|
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));
|
export default connect(mapStateToProps)(withTheme(RoomInfoView));
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { FlatList, View } from 'react-native';
|
import { FlatList } from 'react-native';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { Q } from '@nozbe/watermelondb';
|
import { Q } from '@nozbe/watermelondb';
|
||||||
|
import * as List from '../../containers/List';
|
||||||
|
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
import UserItem from '../../presentation/UserItem';
|
import UserItem from '../../presentation/UserItem';
|
||||||
|
@ -28,6 +29,12 @@ import { goRoom } from '../../utils/goRoom';
|
||||||
|
|
||||||
const PAGE_SIZE = 25;
|
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 {
|
class RoomMembersView extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
navigation: PropTypes.object,
|
navigation: PropTypes.object,
|
||||||
|
@ -43,7 +50,12 @@ class RoomMembersView extends React.Component {
|
||||||
showActionSheet: PropTypes.func,
|
showActionSheet: PropTypes.func,
|
||||||
theme: PropTypes.string,
|
theme: PropTypes.string,
|
||||||
isMasterDetail: PropTypes.bool,
|
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) {
|
constructor(props) {
|
||||||
|
@ -81,7 +93,20 @@ class RoomMembersView extends React.Component {
|
||||||
this.fetchMembers();
|
this.fetchMembers();
|
||||||
|
|
||||||
const { room } = this.state;
|
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);
|
const hasSinglePermission = Object.values(this.permissions).some(p => !!p);
|
||||||
if (hasSinglePermission) {
|
if (hasSinglePermission) {
|
||||||
|
@ -122,7 +147,7 @@ class RoomMembersView extends React.Component {
|
||||||
navToDirectMessage = async(item) => {
|
navToDirectMessage = async(item) => {
|
||||||
try {
|
try {
|
||||||
const db = database.active;
|
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();
|
const query = await subsCollection.query(Q.where('name', item.username)).fetch();
|
||||||
if (query.length) {
|
if (query.length) {
|
||||||
const [room] = query;
|
const [room] = query;
|
||||||
|
@ -395,11 +420,6 @@ class RoomMembersView extends React.Component {
|
||||||
<SearchBox onChangeText={text => this.onSearchChangeText(text)} testID='room-members-view-search' />
|
<SearchBox onChangeText={text => this.onSearchChangeText(text)} testID='room-members-view-search' />
|
||||||
)
|
)
|
||||||
|
|
||||||
renderSeparator = () => {
|
|
||||||
const { theme } = this.props;
|
|
||||||
return <View style={[styles.separator, { backgroundColor: themes[theme].separatorColor }]} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
renderItem = ({ item }) => {
|
renderItem = ({ item }) => {
|
||||||
const { baseUrl, user, theme } = this.props;
|
const { baseUrl, user, theme } = this.props;
|
||||||
|
|
||||||
|
@ -429,7 +449,7 @@ class RoomMembersView extends React.Component {
|
||||||
renderItem={this.renderItem}
|
renderItem={this.renderItem}
|
||||||
style={[styles.list, { backgroundColor: themes[theme].backgroundColor }]}
|
style={[styles.list, { backgroundColor: themes[theme].backgroundColor }]}
|
||||||
keyExtractor={item => item._id}
|
keyExtractor={item => item._id}
|
||||||
ItemSeparatorComponent={this.renderSeparator}
|
ItemSeparatorComponent={List.Separator}
|
||||||
ListHeaderComponent={this.renderSearchBar}
|
ListHeaderComponent={this.renderSearchBar}
|
||||||
ListFooterComponent={() => {
|
ListFooterComponent={() => {
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
|
@ -452,7 +472,12 @@ const mapStateToProps = state => ({
|
||||||
baseUrl: state.server.server,
|
baseUrl: state.server.server,
|
||||||
user: getUserSelector(state),
|
user: getUserSelector(state),
|
||||||
isMasterDetail: state.app.isMasterDetail,
|
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)));
|
export default connect(mapStateToProps)(withActionSheet(withTheme(RoomMembersView)));
|
||||||
|
|
|
@ -168,7 +168,7 @@ const Header = React.memo(({
|
||||||
theme={theme}
|
theme={theme}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
<SubTitle usersTyping={usersTyping} subtitle={subtitle} theme={theme} renderFunc={renderFunc} />
|
<SubTitle usersTyping={tmid ? [] : usersTyping} subtitle={subtitle} theme={theme} renderFunc={renderFunc} />
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import isEqual from 'react-fast-compare';
|
import { dequal } from 'dequal';
|
||||||
|
|
||||||
import * as HeaderButton from '../../../containers/HeaderButton';
|
import * as HeaderButton from '../../../containers/HeaderButton';
|
||||||
import database from '../../../lib/database';
|
import database from '../../../lib/database';
|
||||||
|
@ -35,7 +35,7 @@ class RightButtonsContainer extends Component {
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
if (tmid) {
|
if (tmid) {
|
||||||
try {
|
try {
|
||||||
const threadRecord = await db.collections.get('messages').find(tmid);
|
const threadRecord = await db.get('messages').find(tmid);
|
||||||
this.observeThread(threadRecord);
|
this.observeThread(threadRecord);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log('Can\'t find message to observe.');
|
console.log('Can\'t find message to observe.');
|
||||||
|
@ -43,7 +43,7 @@ class RightButtonsContainer extends Component {
|
||||||
}
|
}
|
||||||
if (rid) {
|
if (rid) {
|
||||||
try {
|
try {
|
||||||
const subCollection = db.collections.get('subscriptions');
|
const subCollection = db.get('subscriptions');
|
||||||
const subRecord = await subCollection.find(rid);
|
const subRecord = await subCollection.find(rid);
|
||||||
this.observeSubscription(subRecord);
|
this.observeSubscription(subRecord);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -59,15 +59,16 @@ class RightButtonsContainer extends Component {
|
||||||
if (nextState.isFollowingThread !== isFollowingThread) {
|
if (nextState.isFollowingThread !== isFollowingThread) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!isEqual(nextState.tunread, tunread)) {
|
if (!dequal(nextState.tunread, tunread)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!isEqual(nextState.tunreadUser, tunreadUser)) {
|
if (!dequal(nextState.tunreadUser, tunreadUser)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!isEqual(nextState.tunreadGroup, tunreadGroup)) {
|
if (!dequal(nextState.tunreadGroup, tunreadGroup)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import equal from 'deep-equal';
|
import { dequal } from 'dequal';
|
||||||
|
|
||||||
import Header from './Header';
|
import Header from './Header';
|
||||||
import LeftButtons from './LeftButtons';
|
import LeftButtons from './LeftButtons';
|
||||||
|
@ -65,7 +65,7 @@ class RoomHeaderView extends Component {
|
||||||
if (nextProps.height !== height) {
|
if (nextProps.height !== height) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!equal(nextProps.usersTyping, usersTyping)) {
|
if (!dequal(nextProps.usersTyping, usersTyping)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (nextProps.goRoomActionsView !== goRoomActionsView) {
|
if (nextProps.goRoomActionsView !== goRoomActionsView) {
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue