From 96bfe1910ecf68f7439c6557ff2d094d5ccac94d Mon Sep 17 00:00:00 2001 From: Diego Mello Date: Wed, 18 Mar 2020 18:26:17 -0300 Subject: [PATCH] Merge beta into master (#1897) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [FIX] Close SortDropdown on sort select (#1230) * [FIX] Cancel upload and check failed upload (#1232) * [FIX] Slash commands not cleaning is typing and not using state (#1233) * [FIX] Dispatch roomsRequest on app foreground event even if not connected (#1234) * [CHORE] Update react-native-jitsi-meet (#1235) * [FIX] Regex on run slash command (#1223) * Update React Native to 0.61.1 (#1236) * Update React Native to 0.61.1 * Update patch to SSL Pinning * Revert storybook * [CHORE] Update react-native-safe-area-view (#1219) * [FIX] Try/catch JSON.parse XHR response (#1238) * [FIX] Change messagebox icon immediate on change text (#1241) * [FIX] Update last open on message stream received (#1240) * [FIX] Remove animation from RoomsListView.willFocus (#1239) * [FIX] Delete message on thread (#1214) * [REGRESSION] Markdown text (#1242) * [FIX] Jest (#1243) * [FIX] Avatar shown when useRealName is activated (#1162) * Fix avatar when use real name * Wrong indentation * [DOCS] Add SECURITY.md (#1244) * [CHORE] Update react-native-reanimated to 1.3.0 (#1246) * [FIX] Run credentials migration only once (#1245) * [CHORE] Update react-native-jitsi-meet to 2.0.1 (#1249) * [FIX] Messagebox onChangeText issues (#1252) * Stop ongoing debounces on messagebox unmount * Immediately change send icon, but keep debouncing others * Make CustomEmoji stateless function * Fix mentions keyExtractor * [FIX] Room subscription issues (#1255) * [FIX] Reaction press (#1258) * [FIX] Channel avatars not showing after application unloads (#1264) * Revert react-native-safe-area-view (#1265) * [FIX] Remove console on production mode (#1268) * [FIX] Messages preview issues (#1257) * [FIX] Select user from native credentials (#1266) * [FIX] Some issues on preview message (#1271) * [FIX] Audio player track and thumb not rendering on Android (#1273) * [FIX] Record audio message throws exception when FileSystem.getInfoAsync is called (#1272) * [FIX] China shouldn't use CallKit (#1274) * [FIX] Watermelon batches (#1277) * Bump version to 1.20.1 (#1285) * [CHORE] Remove memoize-one (#1284) * [FIX] End Jitsi call on unmount (#1291) * [FIX] Allow self-signed certificates (#1310) * [FIX] Set User-Agent (#1318) * Set User-Agent Fetch & Websocket & XHR * Set User-Agent * Custom User Agent on fetch/websocket * Fix names * Use DeviceInfo * fix server with subpath (#1322) * [FIX] Server with https:\\ instead of https:// (#1320) * [FIX] Server dropdown not closing after changing stack (#1299) * [FIX] Invalid server version (#1319) * [IMPROVEMENT] Respect "Hide counter" preference (#1306) * [FIX] Pass isFocused as a function to Messagebox (#1309) * [CHORE] Remove icons folder (#1290) * [CHORE] Refactor RoomItem touchable (#1331) * [FIX] Unnecessary rerender on RoomItem when status is undefined (#1336) * [UPDATE DEPS] react-navigation and react-navigation-stack (#1337) * [FIX] Avatars not loading on share extension when Accounts_AvatarBlockUnauthenticatedAccess is enabled (#1339) * Bump version to 1.20.2 (#1340) * [FIX] Remove some unnecessary re-renders on Messagebox (#1341) * [REGRESSION] Use LayoutAnimation instead of Transition API (#1338) * [FIX] Remove setState from notifications view causing watermelon object to be updated outside an action (#1342) * [IMPROVEMENT] Save last message as message when subscription is updated (#1344) * [UPDATE DEPS] Update RN to 0.61.3 (#1345) * [DOCS] Update Readme (#1346) * [CHORE] Remove react-native-scrollable-tab-view fork (#1352) * [FIX] URL preview (#1360) * [REGRESSION] Decrease list view memory size (#1361) * [FIX] Paste (#1350) * [CHORE] Update gems (#1365) * Bump version to 1.20.3 (#1366) * [FIX] Use Ruby 2.4 on TestFlight upload (#1368) * [FIX] Parse Urls (#1371) * [FIX] Parse image URL only if it's not empty (#1372) * [FIX] Load messages issues (#1373) * Bump version to 1.21.0 (#1376) * [FIX] Crowd login (#1381) * [FIX] Clicking user avatar in thread previews crashes app (#1363) * [IMPROVEMENT] Error messages on connect (#1379) * [FIX] ProfileView input navigation error when custom fields aren't set (#1383) * [FIX] Batch server deletion on logout (#1382) * Bump app to 1.22.0 (#1387) * [FIX] Server Version (#1392) * Update patch and minor deps (#1386) * [FIX] Crash when open thread (#1395) * Bump version to 1.23.0 (#1394) * [I18N] Update ru.js (#1384) * [FIX] CAS building wrong URL (#1362) * [FIX] Delete messages (#1399) * [FIX] In-app notification showing wrong content on channels (#1400) * Bump version to 1.24.0 (#1404) * [FIX] Prevent server with whitespace (#1402) * [IMPROVEMENT] Keyboard and content type on login (#1403) * [FIX] Messages stop loading (#1410) * [NEW] Tablet support (#1300) * [IMPROVEMENT] Authentication via deep linking (#1418) * [IMPROVEMENT] Markdown performance when identifying emoji only content (#1422) * [FIX] BackHandler remove random failing on development (#1423) * Bump version to 1.25.0 (#1424) * [CHORE] Update CI Xcode Image (#1430) * [FIX] Rooms grouping not working properly (#1435) * [FIX] Take a video (#1437) * [NEW] Themes (#1298) * [FIX] Share extension doesn't reconnect to previous selected server on Android (#1429) * [FIX] Init local settings on notification tap (#1438) * Bump version to 1.26.0 (#1450) * [FIX] Emoji parser not working on Hermes (#1445) * [NEW] Enable Hermes (#1446) * [FIX] Automatic theme repeating (#1457) * [CHORE] Sync Experimental and Official app versions (#1458) * [DOCS] Update readme (#1459) * [FIX] Messages being sent but showing as temp status (#1469) * [FIX] Missing messages after reconnect (#1470) * [FIX] Few fixes on themes (#1477) * [I18N] Missing German translations (#1465) * Missing German translation * adding a missing space behind colon * added a missing space after colon * and another attempt to finally fix this – got confused by all the branches * some smaller fixes for the translation * better wording * fixed another typo * [FIX] Crash while displaying the attached image with http on file name (#1401) * [IMPROVEMENT] Tap app and server version to copy to clipboard (#1425) * [NEW] Reply notification (#1448) * [FIX] Incorrect background color login on iPad (#1480) * [FIX] Prevent multiple tap on send (Share Extension) (#1481) * [NEW] Image Viewer (#1479) * [DOCS] Update Readme (#1485) * [FIX] Jitsi with Hermes Enabled (#1523) * [FIX] Draft messages not working with themed Messagebox (#1525) * [FIX] Go to direct message from members list (#1519) * [FIX] Make SAML wait for idp token instead of creating it on client (#1527) * [FIX] Server Test Push Notification (#1508) Co-authored-by: Diego Mello * [CHORE] Update to new server response (#1509) * [FIX] Insert messages with blank users (#1529) * Bump version to 4.2.1 (#1530) * [FIX] Error when normalizing empty messages (#1532) * [REGRESSION] CAS (#1570) * Bump version to 4.2.2 (#1571) * [FIX] Add username block condition to prevent error (#1585) * Bump version to 4.2.3 * Bump version to 4.2.4 * Bump version to 4.3.0 (#1630) * [FIX] Channels doesn't load (#1586) * [FIX] Channels doesn't load * [FIX] Update roomsUpdatedAt when subscriptions.length is 0 * [FIX] Remove unnecessary changes * [FIX] Improve the code Co-authored-by: Diego Mello * [FIX] Make SAML to work on Rocket.Chat < 2.3.0 (#1629) * [NEW] Invite links (#1534) * [FIX] Set the http-agent to the form that Rocket.Chat requires for logging (#1482) Co-authored-by: Diego Mello * [FIX] "Following thread" and "Unfollowed Thread" is hardcoded and not translated (#1625) * [FIX] Disable reset button if form didn't changed (#1569) Co-authored-by: Diego Mello * [FIX] Header title of RoomInfoView (#1553) * [I18N] Gallery Permissions DE (#1542) * [FIX] Not allow to send messages to archived room (#1623) * [FIX] Profile fields automatically reset (#1502) * [FIX] Show attachment on ThreadMessagesView (#1493) * [NEW] Wordpress auth (#1633) * [CHORE] Add Start Packager script (#1639) * [CHORE] Update RN to 0.61.5 (#1638) * [CHORE] Update RN to 0.61.5 * [CHORE] Update react-native patch Co-authored-by: Djorkaeff Alexandre * Bump version to 4.3.1 (#1641) * [FIX] Change force logout rule (#1640) * Bump version to 4.4.0 (#1643) * [IMPROVEMENT] Use MessagingStyle on Android Notification (#1575) * [NEW] Request review (#1627) * [NEW] Pull to refresh RoomView (#1657) * [FIX] Unsubscribe from room (#1655) * [FIX] Server with subdirs (#1646) * [NEW] Clear cache (#1660) * [IMPROVEMENT] Memoize and batch subscriptions updates (#1642) * [FIX] Disallow empty sharing (#1664) * [REGRESSION] Use HTTPS links for sharing and markets protocol for review (#1663) * [FIX] In some cases, share extension doesn't load images (#1649) * [i18n] DE translations for new invite function and some minor fixes (#1631) * [FIX] Remove duplicate jetify step (#1628) minor: also remove 'cd' calls Co-authored-by: Diego Mello * [REGRESSION] Read messages (#1666) * [i18n] German translations missing (#1670) * [FIX] Notifications crash on older Android Versions (#1672) * [i18n] Added Dutch translation (#1676) * [NEW] Omnichannel Beta (#1674) * [NEW] Confirm logout/clear cache (#1688) * [I18N] Add es-ES language (#1495) * [NEW] UiKit Beta (#1497) * [IMPROVEMENT] Use reselect (#1696) * [FIX] Notification in Android API level less than 24 (#1692) * [IMPROVEMENT] Send tmid on slash commands and media (#1698) * [FIX] Unhandled action on UIKit (#1703) * [NEW] Pull to refresh RoomsList (#1701) * [IMPROVEMENT] Reset app when language is changed (#1702) * [FIX] Small fixes on UIKit (#1709) * [FIX] Spotlight (#1719) * [CHORE] Update react-native-image-crop-picker (#1712) * [FIX] Messages Overlapping (Android) and MessageBox Scroll (iOS) (#1720) * [REGRESSION] Remove @ and # from mention (#1721) * [NEW] Direct message from user info (#1516) * [FIX] Delete slash commands (#1723) * [IMPROVEMENT] Hold URL to copy (#1684) * [FIX] Different sourcemaps generation for Hermes (#1724) * [FIX] Different sourcemaps generation for Hermes * Upload sourcemaps after build * [REVERT] Show emoji keyboard on Android (#1738) * [FIX] Stop logging react-native-image-crop-picker (#1745) * [FIX] Prevent toast ref error (#1744) * [FIX] Prevent reaction map error (#1743) * [FIX] Add missing calls to user info (#1741) * [FIX] Catch room unsubscribe error (#1739) * [i18n] Missing German keys (#1735) * [FIX] Missing i18n on MessagesView title (#1733) * [FIX] UIKit Modal: Weird behavior on Android Tablet (#1742) * [i18n] Missing key on German (#1747) Co-authored-by: Diego Mello * [i18n] Add Italian (#1736) * [CHORE] Memory leaks investigation (#1675) * [IMPROVEMENT] Alert verify email when enabled (#1725) * [NEW] Jitsi JWT added to URL (#1746) * [FIX] UIKit submit when connection lost (#1748) * Bump version to 4.5.0 (#1761) * [NEW] Default browser (#1752) Co-authored-by: Diego Mello * [FIX] HTTP Basic Auth (#1753) Co-authored-by: Diego Mello * [IMPROVEMENT] Honor profile fields edit settings (#1687) Co-authored-by: Diego Mello * [IMPROVEMENT] Room announcements (#1726) Co-authored-by: Diego Mello * [IMPROVEMENT] Honor Register/Login settings (#1727) Co-authored-by: Diego Mello * [IMPROVEMENT] Make links clickable on Room Info (#1730) Co-authored-by: Diego Mello * [NEW] Hide system messages (#1755) Co-authored-by: Diego Mello * [IMPROVEMENT] Honor "Message_AudioRecorderEnabled" (#1764) Co-authored-by: Diego Mello * [i18n] Missing de keys (#1765) Co-authored-by: Diego Mello * [FIX] Redirect user to SetUsernameView (#1728) Co-authored-by: Diego Mello * [FIX] Join Room (#1769) Co-authored-by: Diego Mello * [FIX] Accept all media types using * (#1770) Co-authored-by: Diego Mello * [FIX] Use RealName when necessary (#1758) Co-authored-by: Diego Mello * [FIX] Markdown Line Break (#1783) * [IMPROVEMENT] Remove useMarkdown (#1774) Co-authored-by: Diego Mello * [IMPROVEMENT] Open browser rather than webview on Create Workspace (#1788) Co-authored-by: Diego Mello * [IMPROVEMENT] Markdown perf (#1796) * [FIX] Stop video when modal is closed (#1787) Co-authored-by: Diego Mello * [FIX] Hide reply notification action when there are missing data (#1771) Co-authored-by: Diego Mello * [i18n] Added Japanese translation (#1781) Co-authored-by: Diego Mello * [FIX] Reset password error message (#1772) Co-authored-by: Diego Mello * [FIX] Close tablet modal (#1773) Co-authored-by: Diego Mello * [FIX] Setting not present (#1775) Co-authored-by: Diego Mello * [FIX] Thread header (#1776) Co-authored-by: Diego Mello * [FIX] Keyboard tracking loses input ref (#1784) Co-authored-by: Diego Mello * [NEW] Mark message as unread (#1785) Co-authored-by: Djorkaeff Alexandre * [IMPROVEMENT] Log server version (#1786) Co-authored-by: Diego Mello * [IMPROVEMENT] Add loading message on long running tasks (#1798) Co-authored-by: Diego Mello * [CHORE] Switch Apple account on Fastlane (#1810) * [FIX] Watermelon throwing "Cannot update a record with pending updates" (#1754) * [FIX] Detox tests (#1790) * [CHORE] Use markdown preview on RoomView Header (#1807) Co-authored-by: Diego Mello * [FIX] LoginSignup blink services (#1809) Co-authored-by: Diego Mello * [IMPROVEMENT] Request user presence on demand (#1813) Co-authored-by: Diego Mello * [FIX] Remove all invited users when create a channel (#1814) Co-authored-by: Diego Mello * [FIX] Pop from room which you have been removed (#1819) Co-authored-by: Diego Mello * [FIX] Room Info styles (#1820) Co-authored-by: Diego Mello * [i18n] Add missing German keys (#1800) Co-authored-by: Diego Mello * [FIX] Empty mentions for @all and @here when real name is enabled (#1822) Co-authored-by: Diego Mello * [TESTS] Markdown added to Storybook (#1812) Co-authored-by: Diego Mello * [REGRESSION] Room View header title (#1827) Co-authored-by: Diego Mello * [FIX] Storybook snapshots (#1831) Co-authored-by: Djorkaeff Alexandre * [FIX] Mentions (#1829) Co-authored-by: Diego Mello * [FIX] Thread message not found (#1830) Co-authored-by: Diego Mello * [FIX] Separate delete and remove channel (#1832) * Rename to delete room * Separate delete and remove channel * handleRemoved -> handleRoomRemoved * [FIX] Navigate to RoomsList & Handle tablet case Co-authored-by: Djorkaeff Alexandre * [NEW] Filter system messages per room (#1815) Co-authored-by: Djorkaeff Alexandre Co-authored-by: Diego Mello * [FIX] e2e tests (#1838) * [FIX] Consecutive clear cache calls freezing app (#1851) * Bump version to 4.5.1 (#1853) * [FIX][iOS] Ignore silent mode on audio player (#1862) * [IMPROVEMENT] Create App Group property on Info.plist (#1858) Co-authored-by: Diego Mello Co-authored-by: Prateek Jain <44807945+Prateek93a@users.noreply.github.com> Co-authored-by: Djorkaeff Alexandre Co-authored-by: Lucas Siqueira Co-authored-by: Calebe Rios Co-authored-by: Pitstopper <18574776+Pitstopper@users.noreply.github.com> Co-authored-by: phriedrich Co-authored-by: Guilherme Siqueira Co-authored-by: Prateek Jain Co-authored-by: devyaniChoubey <52153085+devyaniChoubey@users.noreply.github.com> Co-authored-by: Bernard Seow Co-authored-by: Hiroki Ishiura Co-authored-by: Exordian Co-authored-by: Daanchaam Co-authored-by: Youssef Muhamad Co-authored-by: Iván Álvarez Co-authored-by: Sarthak Pranesh <41206172+sarthakpranesh@users.noreply.github.com> Co-authored-by: Michele Pellegrini Co-authored-by: Tanmoy Bhowmik Co-authored-by: Hibikine Kage <14365761+hibikine@users.noreply.github.com> --- .circleci/config.yml | 72 +- README.md | 2 +- __mocks__/rn-user-defaults.js | 4 + .../__snapshots__/Storyshots.test.js.snap | 4727 ++++++++++++++--- android/app/build.gradle | 2 +- .../reactnative/CustomPushNotification.java | 4 +- .../java/chat/rocket/reactnative/Ejson.java | 2 +- app/actions/actionsTypes.js | 3 +- app/actions/index.js | 11 +- app/actions/markdown.js | 8 - app/actions/room.js | 10 +- app/constants/settings.js | 35 +- app/constants/types.js | 1 - app/containers/Avatar.js | 2 + app/containers/MessageActions.js | 33 + app/containers/MessageBox/Mentions/index.js | 21 +- app/containers/MessageBox/ReplyPreview.js | 5 +- .../MessageBox/RightButtons.android.js | 18 +- app/containers/MessageBox/RightButtons.ios.js | 10 +- app/containers/MessageBox/index.js | 22 +- app/containers/UIKit/MultiSelect/Chips.js | 2 +- app/containers/UIKit/MultiSelect/index.js | 6 + app/containers/UIKit/MultiSelect/styles.js | 4 +- app/containers/markdown/AtMention.js | 17 +- app/containers/markdown/Hashtag.js | 7 +- app/containers/markdown/Link.js | 15 +- app/containers/markdown/index.js | 96 +- app/containers/markdown/mergeTextNodes.js | 27 + app/containers/message/Attachments.js | 11 +- app/containers/message/Audio.js | 6 +- app/containers/message/Broadcast.js | 1 + app/containers/message/Content.js | 35 +- app/containers/message/Image.js | 5 +- app/containers/message/Reply.js | 8 +- app/containers/message/Video.js | 5 +- app/containers/message/index.js | 4 +- app/i18n/index.js | 4 +- app/i18n/locales/de.js | 19 +- app/i18n/locales/en.js | 36 +- app/i18n/locales/es-ES.js | 6 +- app/i18n/locales/fr.js | 5 +- app/i18n/locales/it.js | 6 +- app/i18n/locales/ja.js | 542 ++ app/i18n/locales/nl.js | 6 +- app/i18n/locales/pt-BR.js | 36 +- app/i18n/locales/pt-PT.js | 5 +- app/i18n/locales/ru.js | 6 +- app/i18n/locales/zh-CN.js | 5 +- app/index.js | 8 +- app/lib/database/model/Setting.js | 6 +- app/lib/database/model/Subscription.js | 2 + app/lib/database/model/migrations.js | 22 + app/lib/database/schema/app.js | 6 +- app/lib/methods/actions.js | 1 + app/lib/methods/getSettings.js | 16 +- app/lib/methods/getUsersPresence.js | 72 + .../helpers/mergeSubscriptionsRooms.js | 1 + app/lib/methods/sendFileMessage.js | 7 +- app/lib/methods/sendMessage.js | 23 +- app/lib/methods/subscriptions/room.js | 163 +- app/lib/methods/subscriptions/rooms.js | 18 +- app/lib/methods/updateMessages.js | 12 + app/lib/rocketchat.js | 71 +- app/presentation/RoomItem/LastMessage.js | 18 +- app/presentation/RoomItem/index.js | 18 +- app/presentation/UserItem.js | 4 +- app/reducers/index.js | 4 +- app/reducers/markdown.js | 17 - app/reducers/reducers.js | 5 - app/reducers/room.js | 24 + app/sagas/createChannel.js | 20 +- app/sagas/init.js | 10 +- app/sagas/login.js | 32 +- app/sagas/room.js | 19 +- app/sagas/selectServer.js | 20 +- app/share.js | 5 +- app/tablet.js | 11 + app/utils/fetch.js | 22 +- app/utils/layoutAnimation.js | 15 +- app/utils/log.js | 16 +- app/utils/media.js | 2 +- app/utils/messageTypes.js | 42 + app/utils/openLink.js | 62 +- app/views/AttachmentView.js | 15 + app/views/AuthLoadingView.js | 40 +- app/views/CreateChannelView.js | 6 +- app/views/DefaultBrowserView.js | 191 + app/views/ForgotPasswordView.js | 2 +- app/views/LanguageView/index.js | 34 +- app/views/LoginSignupView.js | 88 +- app/views/LoginView.js | 39 +- app/views/NewServerView.js | 26 +- .../NotificationPreferencesView/index.js | 1 - app/views/OnboardingView/index.js | 12 +- app/views/ProfileView/index.js | 122 +- app/views/ProfileView/styles.js | 16 +- app/views/RegisterView.js | 12 +- app/views/RoomInfoEditView/SwitchContainer.js | 87 +- app/views/RoomInfoEditView/index.js | 87 +- app/views/RoomInfoEditView/styles.js | 9 + app/views/RoomInfoView/index.js | 55 +- app/views/RoomView/Header/Header.js | 42 +- app/views/RoomView/List.js | 30 +- app/views/RoomView/index.js | 108 +- app/views/RoomView/styles.js | 20 + app/views/RoomsListView/index.js | 6 + app/views/SetUsernameView.js | 4 +- app/views/SettingsView/index.js | 70 +- app/views/SidebarView/index.js | 13 +- e2e/00-onboarding.spec.js | 20 +- e2e/01-welcome.spec.js | 11 +- e2e/02-legal.spec.js | 9 - e2e/03-forgotpassword.spec.js | 9 - e2e/04-createuser.spec.js | 18 +- e2e/05-login.spec.js | 13 +- e2e/06-roomslist.spec.js | 38 +- e2e/07-createroom.spec.js | 60 +- e2e/08-room.spec.js | 145 +- e2e/09-roomactions.spec.js | 219 +- e2e/10-roominfo.spec.js | 172 +- e2e/11-changeserver.spec.js | 44 +- e2e/12-broadcast.spec.js | 94 +- e2e/13-profile.spec.js | 50 +- e2e/14-setting.spec.js | 54 +- e2e/15-joinpublicroom.spec.js | 83 +- e2e/helpers/app.js | 14 +- e2e/helpers/screenshot.js | 23 - ios/Podfile.lock | 8 +- .../RNUserDefaults.podspec.json | 2 +- .../react-native-keyboard-input.podspec.json | 4 +- ios/Pods/Manifest.lock | 8 +- ios/RocketChatRN/Info.plist | 13 +- ios/ShareRocketChatRN/Info.plist | 4 +- ios/fastlane/Appfile | 2 +- ios/fastlane/README.md | 26 +- ios/fastlane/report.xml | 19 +- package.json | 11 +- patches/react-native+0.61.5.patch | 35 +- ...> react-native-keyboard-input+5.4.1.patch} | 20 +- ...-native-keyboard-tracking-view+5.6.1.patch | 67 +- .../react-native-notifications+2.0.6.patch | 17 +- storybook/stories/Markdown.js | 279 + storybook/stories/index.js | 3 + yarn.lock | 69 +- 144 files changed, 7263 insertions(+), 2246 deletions(-) create mode 100644 __mocks__/rn-user-defaults.js delete mode 100644 app/actions/markdown.js create mode 100644 app/containers/markdown/mergeTextNodes.js create mode 100644 app/i18n/locales/ja.js create mode 100644 app/lib/methods/getUsersPresence.js delete mode 100644 app/reducers/markdown.js create mode 100644 app/reducers/room.js create mode 100644 app/utils/messageTypes.js create mode 100644 app/views/DefaultBrowserView.js delete mode 100644 e2e/helpers/screenshot.js rename patches/{react-native-keyboard-input+5.3.1.patch => react-native-keyboard-input+5.4.1.patch} (91%) create mode 100644 storybook/stories/Markdown.js diff --git a/.circleci/config.yml b/.circleci/config.yml index 0c563f034..579d126df 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -44,7 +44,7 @@ jobs: paths: - ./node_modules - e2e-test: + e2e-build: macos: xcode: "11.2.1" @@ -80,11 +80,73 @@ jobs: yarn global add detox-cli yarn + - run: + name: Rebuild Detox framework cache + command: | + detox clean-framework-cache + detox build-framework-cache + - run: name: Build command: | detox build --configuration ios.sim.release + - persist_to_workspace: + root: . + paths: + - ios/build/Build/Products/Release-iphonesimulator/RocketChatRN.app + + - save_cache: + name: Save NPM cache + key: node-v1-mac-{{ checksum "yarn.lock" }} + paths: + - node_modules + + e2e-test: + macos: + xcode: "11.2.1" + + environment: + BASH_ENV: "~/.nvm/nvm.sh" + + steps: + - checkout + + - attach_workspace: + at: . + + - restore_cache: + name: Restore NPM cache + key: node-v1-mac-{{ checksum "yarn.lock" }} + + - run: + name: Install Node 8 + command: | + curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.6/install.sh | bash + source ~/.nvm/nvm.sh + # https://github.com/creationix/nvm/issues/1394 + set +e + nvm install 8 + + - run: + name: Install appleSimUtils + command: | + brew update + brew tap wix/brew + brew install wix/brew/applesimutils + + - run: + name: Install NPM modules + command: | + yarn global add detox-cli + yarn + + - run: + name: Rebuild Detox framework cache + command: | + detox clean-framework-cache + detox build-framework-cache + - run: name: Test command: | @@ -96,9 +158,6 @@ jobs: paths: - node_modules - - store_artifacts: - path: /tmp/screenshots - android-build: <<: *defaults docker: @@ -359,9 +418,12 @@ workflows: type: approval requires: - lint-testunit - - e2e-test: + - e2e-build: requires: - e2e-hold + - e2e-test: + requires: + - e2e-build - ios-build: requires: diff --git a/README.md b/README.md index c55fa7c96..392aa0700 100644 --- a/README.md +++ b/README.md @@ -104,7 +104,7 @@ Readme will guide you on how to config. | Report message | ✅ | | Theming | ✅ | | Settings -> Review the App | ✅ | -| Settings -> Default Browser | ❌ | +| Settings -> Default Browser | ✅ | | Admin panel | ✅ | | Reply message from notification | ✅ | | Unread counter banner on message list | ✅ | diff --git a/__mocks__/rn-user-defaults.js b/__mocks__/rn-user-defaults.js new file mode 100644 index 000000000..71f26ca30 --- /dev/null +++ b/__mocks__/rn-user-defaults.js @@ -0,0 +1,4 @@ +export default { + set: () => '', + get: () => '' +}; diff --git a/__tests__/__snapshots__/Storyshots.test.js.snap b/__tests__/__snapshots__/Storyshots.test.js.snap index ed7afaf9e..758bf7345 100644 --- a/__tests__/__snapshots__/Storyshots.test.js.snap +++ b/__tests__/__snapshots__/Storyshots.test.js.snap @@ -1,5 +1,3638 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`Storyshots Markdown list Markdown 1`] = ` + + + + Short Text + + + + + This is Rocket.Chat + + + + + Long Text + + + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. + + + + + Line Break Text + + + + + a + + + + + + + b + + + + + + + c + + + + + + + + + + + d + + + + + + + + + + + + + + + e + + + + + Edited + + + + + This is edited + + + ( + edited + ) + + + + + Preview + + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. + + + a b c d e + + + @rocket.cat @name1 @all @here @unknown #general #unknown + + + Testing: 😃 👍 :marioparty: + + + + Mentions + + + + + rocket.cat + + + + + + name1 + + + + + + all + + + + + + here + + + + + + @unknown + + + + + Mentions with Real Name + + + + + Rocket Cat + + + + + + Name + + + + + + all + + + + + + here + + + + + + @unknown + + + + + Hashtag + + + + + test-channel + + + + + + #unknown + + + + + Emoji + + + + + Unicode: 😃😇👍 + + + + + Shortnames: + + + 😂 + + + 👍 + + + + + Custom emojis: + + + + + + + + + + + + + + + + + + + + 😃 + + + 👍 + + + + + + + + + + + Block Quote + + + + + + + + This is block quote + + + + + + + this is a normal line + + + + + Links + + + + + + Markdown link + + + + : + + + [description](url) + + + + + + Formatted Link + + + + : + + + <url|description> + + + + + Image + + + + + + + + Headers + + + + + Header 1 + + + + + Header 2 + + + + + Header 3 + + + + + Header 4 + + + + + Header 5 + + + + + Header 6 + + + + + Inline Code + + + + + This is + + + inline code + + + + + Code Block + + + + + Inline + + + code + + + has + + + back-ticks around + + + it. + + + + Code block + + + + + Lists + + + + + + • + + + + + + Open Source + + + + + + + + • + + + + + + Rocket.Chat + + + + + + ◦ + + + + + + nodejs + + + + + + + + ◦ + + + + + + ReactNative + + + + + + + + + Numbered Lists + + + + + + 1. + + + + + + Open Source + + + + + + + + 2. + + + + + + Rocket.Chat + + + + + + + Emphasis + + + + + Strong emphasis, aka bold, with + + + asterisks + + + or + + + underscores + + + + + Table + + + + + + + + + + + First Header + + + + + + + Second Header + + + + + + + + + Content from cell 1 + + + + + + + Content from cell 2 + + + + + + + + + Content in the first column + + + + + + + Content in the second column + + + + + + + + + Click to see full table + + + + + +`; + exports[`Storyshots Message list message 1`] = ` - I - - - 'm fine - - - ! + I'm fine! @@ -13158,6 +16831,7 @@ exports[`Storyshots Message list message 1`] = ` } > - I - - - 'm fine - - - ! + I'm fine! @@ -13550,6 +17174,7 @@ exports[`Storyshots Message list message 1`] = ` } > - I - - - 'm fine - - - ! + I'm fine! @@ -13970,6 +17545,7 @@ exports[`Storyshots Message list message 1`] = ` } > - I - - - 'm fine - - - ! + I'm fine! @@ -14141,6 +17665,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { + "headers": Object {}, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&width=50&height=50&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -14242,6 +17767,7 @@ exports[`Storyshots Message list message 1`] = ` } > - I - - - 'm fine - - - ! + I'm fine! @@ -14410,6 +17884,7 @@ exports[`Storyshots Message list message 1`] = ` } > - I - - - 'm fine - - - ! + I'm fine! @@ -14625,6 +18048,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { + "headers": Object {}, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&width=50&height=50&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -14726,6 +18150,7 @@ exports[`Storyshots Message list message 1`] = ` } > - - I - - - 'm fine - - - ! - + I'm fine! @@ -15615,6 +19002,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { + "headers": Object {}, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&width=50&height=50&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -15647,64 +19035,23 @@ exports[`Storyshots Message list message 1`] = ` > - - I - - - 'm fine - - - ! - + I'm fine! @@ -15887,6 +19234,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { + "headers": Object {}, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&width=50&height=50&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -15919,64 +19267,23 @@ exports[`Storyshots Message list message 1`] = ` > - - I - - - 'm fine - - - ! - + I'm fine! @@ -16159,6 +19466,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { + "headers": Object {}, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&width=50&height=50&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -16191,64 +19499,23 @@ exports[`Storyshots Message list message 1`] = ` > - - I - - - 'm fine - - - ! - + I'm fine! @@ -16431,6 +19698,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { + "headers": Object {}, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&width=50&height=50&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -16463,32 +19731,23 @@ exports[`Storyshots Message list message 1`] = ` > - - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. - + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. @@ -16671,6 +19930,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { + "headers": Object {}, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&width=50&height=50&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -16703,32 +19963,23 @@ exports[`Storyshots Message list message 1`] = ` > - - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. - + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. @@ -16911,6 +20162,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { + "headers": Object {}, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&width=50&height=50&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -17074,6 +20326,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { + "headers": Object {}, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&width=50&height=50&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -17175,6 +20428,7 @@ exports[`Storyshots Message list message 1`] = ` } > - - I - - - 'm fine - - - ! - + I'm fine! @@ -17583,6 +20797,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { + "headers": Object {}, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&width=50&height=50&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -17615,32 +20830,23 @@ exports[`Storyshots Message list message 1`] = ` > - - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. - + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. @@ -17740,6 +20946,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { + "headers": Object {}, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&width=50&height=50&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -17991,6 +21198,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { + "headers": Object {}, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&width=50&height=50&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -18023,64 +21231,23 @@ exports[`Storyshots Message list message 1`] = ` > - - I - - - 'm fine - - - ! - + I'm fine! @@ -18180,6 +21347,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { + "headers": Object {}, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&width=50&height=50&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -18212,48 +21380,23 @@ exports[`Storyshots Message list message 1`] = ` > - - Cool - - - ! - + Cool! @@ -18353,6 +21496,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { + "headers": Object {}, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&width=50&height=50&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -18385,32 +21529,23 @@ exports[`Storyshots Message list message 1`] = ` > - - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. - + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. @@ -18510,6 +21645,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { + "headers": Object {}, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&width=50&height=50&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -18673,6 +21809,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { + "headers": Object {}, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&width=50&height=50&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -18988,6 +22125,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { + "headers": Object {}, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&width=50&height=50&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -19305,6 +22443,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { + "headers": Object {}, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&width=50&height=50&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -19622,6 +22761,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { + "headers": Object {}, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&width=50&height=50&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -19961,6 +23101,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { + "headers": Object {}, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&width=50&height=50&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -20321,6 +23462,7 @@ exports[`Storyshots Message list message 1`] = ` resizeMode="cover" source={ Object { + "headers": Object {}, "priority": "high", "uri": "https://open.rocket.chat/avatar/diego.mello?format=png&width=50&height=50&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8", } @@ -20422,6 +23564,7 @@ exports[`Storyshots Message list message 1`] = ` } > - I - - - \` - - - m an inline-style link + I\`m an inline-style link ( @@ -45,6 +46,7 @@ const Avatar = React.memo(({ style={avatarStyle} source={{ uri, + headers: RocketChatSettings.customHeaders, priority: FastImage.priority.high }} /> diff --git a/app/containers/MessageActions.js b/app/containers/MessageActions.js index ab3677fce..79f75c7c4 100644 --- a/app/containers/MessageActions.js +++ b/app/containers/MessageActions.js @@ -63,6 +63,12 @@ class MessageActions extends React.Component { this.EDIT_INDEX = this.options.length - 1; } + // Mark as unread + if (message.u && message.u._id !== user.id) { + this.options.push(I18n.t('Mark_unread')); + this.UNREAD_INDEX = this.options.length - 1; + } + // Permalink this.options.push(I18n.t('Permalink')); this.PERMALINK_INDEX = this.options.length - 1; @@ -243,6 +249,30 @@ class MessageActions extends React.Component { editInit(message); } + handleUnread = async() => { + const { message, room } = this.props; + const { id: messageId, ts } = message; + const { rid } = room; + try { + const db = database.active; + const result = await RocketChat.markAsUnread({ messageId }); + if (result.success) { + const subCollection = db.collections.get('subscriptions'); + const subRecord = await subCollection.find(rid); + await db.action(async() => { + try { + await subRecord.update(sub => sub.lastOpen = ts); + } catch { + // do nothing + } + }); + Navigation.navigate('RoomsListView'); + } + } catch (e) { + log(e); + } + } + handleCopy = async() => { const { message } = this.props; await Clipboard.setString(message.msg); @@ -349,6 +379,9 @@ class MessageActions extends React.Component { case this.EDIT_INDEX: this.handleEdit(); break; + case this.UNREAD_INDEX: + this.handleUnread(); + break; case this.PERMALINK_INDEX: this.handlePermalink(); break; diff --git a/app/containers/MessageBox/Mentions/index.js b/app/containers/MessageBox/Mentions/index.js index 8b3649a2a..37c30c30b 100644 --- a/app/containers/MessageBox/Mentions/index.js +++ b/app/containers/MessageBox/Mentions/index.js @@ -1,5 +1,5 @@ import React from 'react'; -import { FlatList } from 'react-native'; +import { FlatList, View } from 'react-native'; import PropTypes from 'prop-types'; import equal from 'deep-equal'; @@ -12,15 +12,16 @@ const Mentions = React.memo(({ mentions, trackingType, theme }) => { return null; } return ( - } - keyExtractor={item => item.id || item.username || item.command || item} - keyboardShouldPersistTaps='always' - /> + + } + keyExtractor={item => item.id || item.username || item.command || item} + keyboardShouldPersistTaps='always' + /> + ); }, (prevProps, nextProps) => { if (prevProps.theme !== nextProps.theme) { diff --git a/app/containers/MessageBox/ReplyPreview.js b/app/containers/MessageBox/ReplyPreview.js index 54d872ebd..a755598be 100644 --- a/app/containers/MessageBox/ReplyPreview.js +++ b/app/containers/MessageBox/ReplyPreview.js @@ -42,7 +42,7 @@ const styles = StyleSheet.create({ }); const ReplyPreview = React.memo(({ - message, Message_TimeFormat, baseUrl, username, useMarkdown, replying, getCustomEmoji, close, theme + message, Message_TimeFormat, baseUrl, username, replying, getCustomEmoji, close, theme }) => { if (!replying) { return null; @@ -67,7 +67,6 @@ const ReplyPreview = React.memo(({ username={username} getCustomEmoji={getCustomEmoji} numberOfLines={1} - useMarkdown={useMarkdown} preview theme={theme} /> @@ -79,7 +78,6 @@ const ReplyPreview = React.memo(({ ReplyPreview.propTypes = { replying: PropTypes.bool, - useMarkdown: PropTypes.bool, message: PropTypes.object.isRequired, Message_TimeFormat: PropTypes.string.isRequired, close: PropTypes.func.isRequired, @@ -90,7 +88,6 @@ ReplyPreview.propTypes = { }; const mapStateToProps = state => ({ - useMarkdown: state.markdown.useMarkdown, Message_TimeFormat: state.settings.Message_TimeFormat, baseUrl: state.server.server }); diff --git a/app/containers/MessageBox/RightButtons.android.js b/app/containers/MessageBox/RightButtons.android.js index 716d9a258..f05c1ede8 100644 --- a/app/containers/MessageBox/RightButtons.android.js +++ b/app/containers/MessageBox/RightButtons.android.js @@ -4,17 +4,20 @@ import PropTypes from 'prop-types'; import { SendButton, AudioButton, FileButton } from './buttons'; const RightButtons = React.memo(({ - theme, showSend, submit, recordAudioMessage, showFileActions + theme, showSend, submit, recordAudioMessage, recordAudioMessageEnabled, showFileActions }) => { if (showSend) { return ; } - return ( - <> - - - - ); + if (recordAudioMessageEnabled) { + return ( + <> + + + + ); + } + return ; }); RightButtons.propTypes = { @@ -22,6 +25,7 @@ RightButtons.propTypes = { showSend: PropTypes.bool, submit: PropTypes.func.isRequired, recordAudioMessage: PropTypes.func.isRequired, + recordAudioMessageEnabled: PropTypes.bool, showFileActions: PropTypes.func.isRequired }; diff --git a/app/containers/MessageBox/RightButtons.ios.js b/app/containers/MessageBox/RightButtons.ios.js index d0b16da90..62fbca5ee 100644 --- a/app/containers/MessageBox/RightButtons.ios.js +++ b/app/containers/MessageBox/RightButtons.ios.js @@ -4,19 +4,23 @@ import PropTypes from 'prop-types'; import { SendButton, AudioButton } from './buttons'; const RightButtons = React.memo(({ - theme, showSend, submit, recordAudioMessage + theme, showSend, submit, recordAudioMessage, recordAudioMessageEnabled }) => { if (showSend) { return ; } - return ; + if (recordAudioMessageEnabled) { + return ; + } + return null; }); RightButtons.propTypes = { theme: PropTypes.string, showSend: PropTypes.bool, submit: PropTypes.func.isRequired, - recordAudioMessage: PropTypes.func.isRequired + recordAudioMessage: PropTypes.func.isRequired, + recordAudioMessageEnabled: PropTypes.bool }; export default RightButtons; diff --git a/app/containers/MessageBox/index.js b/app/containers/MessageBox/index.js index 2c5f49686..14decbbf9 100644 --- a/app/containers/MessageBox/index.js +++ b/app/containers/MessageBox/index.js @@ -85,13 +85,15 @@ class MessageBox extends Component { replyWithMention: PropTypes.bool, FileUpload_MediaTypeWhiteList: PropTypes.string, FileUpload_MaxFileSize: PropTypes.number, + Message_AudioRecorderEnabled: PropTypes.bool, getCustomEmoji: PropTypes.func, editCancel: PropTypes.func.isRequired, editRequest: PropTypes.func.isRequired, onSubmit: PropTypes.func.isRequired, typing: PropTypes.func, theme: PropTypes.string, - replyCancel: PropTypes.func + replyCancel: PropTypes.func, + navigation: PropTypes.object } constructor(props) { @@ -139,7 +141,7 @@ class MessageBox extends Component { async componentDidMount() { const db = database.active; - const { rid, tmid } = this.props; + const { rid, tmid, navigation } = this.props; let msg; try { const threadsCollection = db.collections.get('threads'); @@ -177,6 +179,12 @@ class MessageBox extends Component { if (isTablet) { EventEmiter.addEventListener(KEY_COMMAND, this.handleCommands); } + + this.didFocusListener = navigation.addListener('didFocus', () => { + if (this.tracking && this.tracking.resetTracking) { + this.tracking.resetTracking(); + } + }); } componentWillReceiveProps(nextProps) { @@ -257,6 +265,9 @@ class MessageBox extends Component { if (this.getSlashCommands && this.getSlashCommands.stop) { this.getSlashCommands.stop(); } + if (this.didFocusListener && this.didFocusListener.remove) { + this.didFocusListener.remove(); + } if (isTablet) { EventEmiter.removeListener(KEY_COMMAND, this.handleCommands); } @@ -781,7 +792,7 @@ class MessageBox extends Component { recording, showEmojiKeyboard, showSend, mentions, trackingType, commandPreview, showCommandPreview } = this.state; const { - editing, message, replying, replyCancel, user, getCustomEmoji, theme + editing, message, replying, replyCancel, user, getCustomEmoji, theme, Message_AudioRecorderEnabled } = this.props; const isAndroidTablet = isTablet && isAndroid ? { @@ -842,6 +853,7 @@ class MessageBox extends Component { showSend={showSend} submit={this.submit} recordAudioMessage={this.recordAudioMessage} + recordAudioMessageEnabled={Message_AudioRecorderEnabled} showFileActions={this.showFileActions} /> @@ -864,6 +876,7 @@ class MessageBox extends Component { }} > this.tracking = ref} renderContent={this.renderContent} kbInputRef={this.component} kbComponent={showEmojiKeyboard ? 'EmojiKeyboard' : null} @@ -891,7 +904,8 @@ const mapStateToProps = state => ({ threadsEnabled: state.settings.Threads_enabled, user: getUserSelector(state), FileUpload_MediaTypeWhiteList: state.settings.FileUpload_MediaTypeWhiteList, - FileUpload_MaxFileSize: state.settings.FileUpload_MaxFileSize + FileUpload_MaxFileSize: state.settings.FileUpload_MaxFileSize, + Message_AudioRecorderEnabled: state.settings.Message_AudioRecorderEnabled }); const dispatchToProps = ({ diff --git a/app/containers/UIKit/MultiSelect/Chips.js b/app/containers/UIKit/MultiSelect/Chips.js index 330a04d8f..dae9c797e 100644 --- a/app/containers/UIKit/MultiSelect/Chips.js +++ b/app/containers/UIKit/MultiSelect/Chips.js @@ -20,7 +20,7 @@ const Chip = ({ item, onSelect, theme }) => ( > <> {item.imageUrl ? : null} - {textParser([item.text])} + {textParser([item.text])} diff --git a/app/containers/UIKit/MultiSelect/index.js b/app/containers/UIKit/MultiSelect/index.js index 47e6141b4..553e92c61 100644 --- a/app/containers/UIKit/MultiSelect/index.js +++ b/app/containers/UIKit/MultiSelect/index.js @@ -41,6 +41,12 @@ export const MultiSelect = React.memo(({ const [currentValue, setCurrentValue] = useState(''); const [showContent, setShowContent] = useState(false); + useEffect(() => { + if (values) { + select(values); + } + }, [values]); + useEffect(() => { setOpen(showContent); }, [showContent]); diff --git a/app/containers/UIKit/MultiSelect/styles.js b/app/containers/UIKit/MultiSelect/styles.js index f0034364a..bac42a168 100644 --- a/app/containers/UIKit/MultiSelect/styles.js +++ b/app/containers/UIKit/MultiSelect/styles.js @@ -34,6 +34,7 @@ export default StyleSheet.create({ }, item: { height: 48, + maxWidth: '85%', alignItems: 'center', flexDirection: 'row' }, @@ -59,7 +60,7 @@ export default StyleSheet.create({ chips: { flexDirection: 'row', flexWrap: 'wrap', - marginRight: 16 + marginRight: 50 }, chip: { flexDirection: 'row', @@ -72,6 +73,7 @@ export default StyleSheet.create({ }, chipText: { paddingHorizontal: 8, + flexShrink: 1, ...sharedStyles.textMedium, fontSize: 14 }, diff --git a/app/containers/markdown/AtMention.js b/app/containers/markdown/AtMention.js index 8980777e4..513dd8805 100644 --- a/app/containers/markdown/AtMention.js +++ b/app/containers/markdown/AtMention.js @@ -7,7 +7,7 @@ import { themes } from '../../constants/colors'; import styles from './styles'; const AtMention = React.memo(({ - mention, mentions, username, navToRoomInfo, preview, style = [], theme + mention, mentions, username, navToRoomInfo, style = [], useRealName, theme }) => { let mentionStyle = { ...styles.mention, color: themes[theme].buttonText }; if (mention === 'all' || mention === 'here') { @@ -27,22 +27,23 @@ const AtMention = React.memo(({ }; } + const user = mentions && mentions.length && mentions.find(m => m.username === mention); + const handlePress = () => { - const index = mentions.findIndex(m => m.username === mention); const navParam = { t: 'd', - rid: mentions[index]._id + rid: user && user._id }; navToRoomInfo(navParam); }; - if (mentions && mentions.length && mentions.findIndex(m => m.username === mention) !== -1) { + if (user) { return ( - {mention} + {useRealName && user.name ? user.name : user.username} ); } @@ -59,7 +60,7 @@ AtMention.propTypes = { username: PropTypes.string, navToRoomInfo: PropTypes.func, style: PropTypes.array, - preview: PropTypes.bool, + useRealName: PropTypes.bool, theme: PropTypes.string, mentions: PropTypes.oneOfType([PropTypes.array, PropTypes.object]) }; diff --git a/app/containers/markdown/Hashtag.js b/app/containers/markdown/Hashtag.js index 594192cad..655d3a737 100644 --- a/app/containers/markdown/Hashtag.js +++ b/app/containers/markdown/Hashtag.js @@ -7,7 +7,7 @@ import { themes } from '../../constants/colors'; import styles from './styles'; const Hashtag = React.memo(({ - hashtag, channels, navToRoomInfo, preview, style = [], theme + hashtag, channels, navToRoomInfo, style = [], theme }) => { const handlePress = () => { const index = channels.findIndex(channel => channel.name === hashtag); @@ -21,8 +21,8 @@ const Hashtag = React.memo(({ if (channels && channels.length && channels.findIndex(channel => channel.name === hashtag) !== -1) { return ( {hashtag} @@ -39,7 +39,6 @@ Hashtag.propTypes = { hashtag: PropTypes.string, navToRoomInfo: PropTypes.func, style: PropTypes.array, - preview: PropTypes.bool, theme: PropTypes.string, channels: PropTypes.oneOfType([PropTypes.array, PropTypes.object]) }; diff --git a/app/containers/markdown/Link.js b/app/containers/markdown/Link.js index c974a0f25..1c1577110 100644 --- a/app/containers/markdown/Link.js +++ b/app/containers/markdown/Link.js @@ -10,7 +10,7 @@ import EventEmitter from '../../utils/events'; import I18n from '../../i18n'; const Link = React.memo(({ - children, link, preview, theme + children, link, theme }) => { const handlePress = () => { if (!link) { @@ -28,13 +28,9 @@ const Link = React.memo(({ // if you have a [](https://rocket.chat) render https://rocket.chat return ( { childLength !== 0 ? children : link } @@ -44,8 +40,7 @@ const Link = React.memo(({ Link.propTypes = { children: PropTypes.node, link: PropTypes.string, - theme: PropTypes.string, - preview: PropTypes.bool + theme: PropTypes.string }; export default Link; diff --git a/app/containers/markdown/index.js b/app/containers/markdown/index.js index 40af9e171..990b2fc66 100644 --- a/app/containers/markdown/index.js +++ b/app/containers/markdown/index.js @@ -3,6 +3,7 @@ import { Text, Image } from 'react-native'; import { Parser, Node } from 'commonmark'; import Renderer from 'commonmark-react-renderer'; import PropTypes from 'prop-types'; +import removeMarkdown from 'remove-markdown'; import shortnameToUnicode from '../../utils/shortnameToUnicode'; import I18n from '../../i18n'; @@ -18,6 +19,7 @@ import MarkdownEmoji from './Emoji'; import MarkdownTable from './Table'; import MarkdownTableRow from './TableRow'; import MarkdownTableCell from './TableCell'; +import mergeTextNodes from './mergeTextNodes'; import styles from './styles'; @@ -71,22 +73,23 @@ class Markdown extends PureComponent { tmid: PropTypes.string, isEdited: PropTypes.bool, numberOfLines: PropTypes.number, - useMarkdown: PropTypes.bool, customEmojis: PropTypes.bool, + useRealName: PropTypes.bool, channels: PropTypes.oneOfType([PropTypes.array, PropTypes.object]), mentions: PropTypes.oneOfType([PropTypes.array, PropTypes.object]), navToRoomInfo: PropTypes.func, preview: PropTypes.bool, theme: PropTypes.string, + testID: PropTypes.string, style: PropTypes.array }; constructor(props) { super(props); - this.renderer = this.createRenderer(props.preview); + this.renderer = this.createRenderer(); } - createRenderer = (preview = false) => new Renderer({ + createRenderer = () => new Renderer({ renderers: { text: this.renderText, @@ -119,7 +122,7 @@ class Markdown extends PureComponent { table_row: this.renderTableRow, table_cell: this.renderTableCell, - editedIndicator: preview ? () => null : this.renderEditedIndicator + editedIndicator: this.renderEditedIndicator }, renderParagraphsInLists: true }); @@ -141,19 +144,16 @@ class Markdown extends PureComponent { renderText = ({ context, literal }) => { const { - numberOfLines, preview, style = [] + numberOfLines, style = [] } = this.props; const defaultStyle = [ - this.isMessageContainsOnlyEmoji && !preview ? styles.textBig : {}, + this.isMessageContainsOnlyEmoji ? styles.textBig : {}, ...context.map(type => styles[type]) ]; return ( {literal} @@ -162,18 +162,16 @@ class Markdown extends PureComponent { } renderCodeInline = ({ literal }) => { - const { preview, theme, style = [] } = this.props; + const { theme, style = [] } = this.props; return ( @@ -183,18 +181,16 @@ class Markdown extends PureComponent { }; renderCodeBlock = ({ literal }) => { - const { preview, theme, style = [] } = this.props; + const { theme, style = [] } = this.props; return ( @@ -221,11 +217,10 @@ class Markdown extends PureComponent { }; renderLink = ({ children, href }) => { - const { preview, theme } = this.props; + const { theme } = this.props; return ( {children} @@ -235,14 +230,13 @@ class Markdown extends PureComponent { renderHashtag = ({ hashtag }) => { const { - channels, navToRoomInfo, style, preview, theme + channels, navToRoomInfo, style, theme } = this.props; return ( @@ -251,15 +245,15 @@ class Markdown extends PureComponent { renderAtMention = ({ mentionName }) => { const { - username, mentions, navToRoomInfo, preview, style, theme + username, mentions, navToRoomInfo, useRealName, style, theme } = this.props; return ( @@ -268,13 +262,13 @@ class Markdown extends PureComponent { renderEmoji = ({ emojiName, literal }) => { const { - getCustomEmoji, baseUrl, customEmojis = true, preview, style, theme + getCustomEmoji, baseUrl, customEmojis = true, style, theme } = this.props; return ( { - const { preview, theme } = this.props; - if (preview) { - return children; - } + const { theme } = this.props; return ( {children} @@ -367,7 +358,7 @@ class Markdown extends PureComponent { render() { const { - msg, useMarkdown = true, numberOfLines, preview = false, theme + msg, numberOfLines, preview = false, theme, style = [], testID } = this.props; if (!msg) { @@ -379,23 +370,22 @@ class Markdown extends PureComponent { // Ex: '[ ](https://open.rocket.chat/group/test?msg=abcdef) Test' // Return: 'Test' m = m.replace(/^\[([\s]]*)\]\(([^)]*)\)\s/, '').trim(); - m = shortnameToUnicode(m); if (preview) { - m = m.split('\n').reduce((lines, line) => `${ lines } ${ line }`, ''); - const ast = parser.parse(m); - return this.renderer.render(ast); + m = m.replace(/\n+/g, ' '); + m = shortnameToUnicode(m); + m = removeMarkdown(m); + return ( + + {m} + + ); } - if (!useMarkdown && !preview) { - return {m}; - } - - const ast = parser.parse(m); + let ast = parser.parse(m); + ast = mergeTextNodes(ast); this.isMessageContainsOnlyEmoji = isOnlyEmoji(m) && emojiCount(m) <= 3; - this.editedMessage(ast); - return this.renderer.render(ast); } } diff --git a/app/containers/markdown/mergeTextNodes.js b/app/containers/markdown/mergeTextNodes.js new file mode 100644 index 000000000..768395236 --- /dev/null +++ b/app/containers/markdown/mergeTextNodes.js @@ -0,0 +1,27 @@ +// TODO: should we add this to our commonmark fork instead? +// we loop through nodes and try to merge all texts +export default function mergeTextNodes(ast) { + // https://github.com/commonmark/commonmark.js/blob/master/lib/node.js#L268 + const walker = ast.walker(); + let event; + // eslint-disable-next-line no-cond-assign + while (event = walker.next()) { + const { entering, node } = event; + const { type } = node; + if (entering && type === 'text') { + while (node._next && node._next.type === 'text') { + const next = node._next; + node.literal += next.literal; + node._next = next._next; + if (node._next) { + node._next._prev = node; + } + if (node._parent._lastChild === next) { + node._parent._lastChild = node; + } + } + walker.resumeAt(node, false); + } + } + return ast; +} diff --git a/app/containers/message/Attachments.js b/app/containers/message/Attachments.js index dc1f06847..cf3f6106c 100644 --- a/app/containers/message/Attachments.js +++ b/app/containers/message/Attachments.js @@ -8,7 +8,7 @@ import Video from './Video'; import Reply from './Reply'; const Attachments = React.memo(({ - attachments, timeFormat, user, baseUrl, useMarkdown, showAttachment, getCustomEmoji, theme + attachments, timeFormat, user, baseUrl, showAttachment, getCustomEmoji, theme }) => { if (!attachments || attachments.length === 0) { return null; @@ -16,17 +16,17 @@ const Attachments = React.memo(({ return attachments.map((file, index) => { if (file.image_url) { - return ; + return ; } if (file.audio_url) { - return