From 96d0b1fcbc314f7fb9ed28fdf0444a288c8eb8d5 Mon Sep 17 00:00:00 2001 From: Diego Mello Date: Tue, 11 Sep 2018 13:32:52 -0300 Subject: [PATCH] [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 --- README.md | 42 +- __mocks__/fileMock.js | 1 + __mocks__/react-native-i18n.js | 7 + __mocks__/react-native-safari-view.js | 5 + __mocks__/react-native-video-controls.js | 1 + __mocks__/react-native-video.js | 1 + __tests__/RoomItem.js | 15 +- .../__snapshots__/Storyshots.test.js.snap | 16785 +++++++++++++++- android/app/build.gradle | 2 +- .../main/res/drawable-hdpi/add_reaction.png | Bin 0 -> 1023 bytes .../app/src/main/res/drawable-hdpi/pause.png | Bin 0 -> 1092 bytes .../app/src/main/res/drawable-hdpi/play.png | Bin 0 -> 1239 bytes .../src/main/res/drawable-hdpi/play_video.png | Bin 0 -> 1953 bytes .../app/src/main/res/drawable-hdpi/reply.png | Bin 0 -> 275 bytes .../main/res/drawable-mdpi/add_reaction.png | Bin 0 -> 630 bytes .../app/src/main/res/drawable-mdpi/pause.png | Bin 0 -> 687 bytes .../app/src/main/res/drawable-mdpi/play.png | Bin 0 -> 740 bytes .../src/main/res/drawable-mdpi/play_video.png | Bin 0 -> 1132 bytes .../app/src/main/res/drawable-mdpi/reply.png | Bin 0 -> 234 bytes .../main/res/drawable-xhdpi/add_reaction.png | Bin 0 -> 1350 bytes .../app/src/main/res/drawable-xhdpi/pause.png | Bin 0 -> 1445 bytes .../app/src/main/res/drawable-xhdpi/play.png | Bin 0 -> 1638 bytes .../main/res/drawable-xhdpi/play_video.png | Bin 0 -> 2809 bytes .../app/src/main/res/drawable-xhdpi/reply.png | Bin 0 -> 330 bytes .../main/res/drawable-xxhdpi/add_reaction.png | Bin 0 -> 1987 bytes .../src/main/res/drawable-xxhdpi/pause.png | Bin 0 -> 2181 bytes .../app/src/main/res/drawable-xxhdpi/play.png | Bin 0 -> 2485 bytes .../main/res/drawable-xxhdpi/play_video.png | Bin 0 -> 4656 bytes .../src/main/res/drawable-xxhdpi/reply.png | Bin 0 -> 436 bytes .../res/drawable-xxxhdpi/add_reaction.png | Bin 0 -> 2663 bytes .../src/main/res/drawable-xxxhdpi/pause.png | Bin 0 -> 3201 bytes .../src/main/res/drawable-xxxhdpi/play.png | Bin 0 -> 3718 bytes .../main/res/drawable-xxxhdpi/play_video.png | Bin 0 -> 6600 bytes .../src/main/res/drawable-xxxhdpi/reply.png | Bin 0 -> 523 bytes app/constants/settings.js | 4 + app/containers/Avatar.js | 6 +- app/containers/EmojiPicker/CustomEmoji.js | 4 - app/containers/EmojiPicker/EmojiCategory.js | 8 +- app/containers/EmojiPicker/index.js | 4 + app/containers/EmojiPicker/styles.js | 3 + app/containers/MessageBox/EmojiKeyboard.js | 15 +- app/containers/MessageBox/ReplyPreview.js | 27 +- app/containers/MessageBox/index.js | 54 +- app/containers/MessageBox/styles.js | 10 +- app/containers/Sidebar.js | 7 +- app/containers/message/Audio.js | 121 +- app/containers/message/Emoji.js | 16 +- app/containers/message/Image.js | 20 +- app/containers/message/Markdown.js | 64 +- app/containers/message/Message.js | 351 + app/containers/message/ReactionsModal.js | 23 +- app/containers/message/Reply.js | 64 +- app/containers/message/Url.js | 77 +- app/containers/message/User.js | 68 +- app/containers/message/Video.js | 49 +- app/containers/message/index.js | 357 +- app/containers/message/styles.js | 99 +- app/i18n/locales/en.js | 1 - app/lib/methods/canOpenRoom.js | 2 +- app/lib/methods/getRooms.js | 2 +- app/lib/methods/getSettings.js | 4 +- app/lib/rocketchat.js | 6 +- app/presentation/RoomItem.js | 10 +- app/presentation/UserItem.js | 5 +- app/sagas/rooms.js | 3 +- app/utils/touch/index.ios.js | 2 +- app/views/CreateChannelView.js | 8 +- app/views/MentionedMessagesView/index.js | 6 +- app/views/NewMessageView.js | 8 +- app/views/NewServerView.js | 8 +- app/views/OnboardingView/styles.js | 20 +- app/views/PinnedMessagesView/index.js | 5 +- app/views/ProfileView/index.js | 9 +- app/views/RoomActionsView/index.js | 5 +- app/views/RoomFilesView/index.js | 1 - app/views/RoomInfoView/index.js | 2 + app/views/RoomView/ReactionPicker.js | 7 +- app/views/RoomView/Separator.js | 47 +- app/views/RoomView/index.js | 8 +- app/views/RoomView/styles.js | 3 +- app/views/RoomsListView/Header/Header.ios.js | 3 +- app/views/RoomsListView/index.js | 25 +- app/views/SearchMessagesView/index.js | 4 +- app/views/SelectedUsersView.js | 4 + app/views/SnippetedMessagesView/index.js | 6 +- app/views/StarredMessagesView/index.js | 5 +- e2e/05-roomslist.spec.js | 2 +- e2e/06-createroom.spec.js | 5 +- e2e/07-room.spec.js | 22 +- e2e/08-roomactions.spec.js | 17 +- e2e/09-roominfo.spec.js | 2 + e2e/11-broadcast.spec.js | 10 +- e2e/data.js | 2 +- .../Icons/pause.imageset/Contents.json | 23 + .../Icons/pause.imageset/pause.png | Bin 0 -> 687 bytes .../Icons/pause.imageset/pause@2x.png | Bin 0 -> 1445 bytes .../Icons/pause.imageset/pause@3x.png | Bin 0 -> 2181 bytes .../Icons/play.imageset/Contents.json | 23 + .../Icons/play.imageset/play.png | Bin 0 -> 740 bytes .../Icons/play.imageset/play@2x.png | Bin 0 -> 1638 bytes .../Icons/play.imageset/play@3x.png | Bin 0 -> 2485 bytes .../Icons/play_video.imageset/Contents.json | 23 + .../play_video.imageset/play_video@1x.png | Bin 0 -> 1132 bytes .../play_video.imageset/play_video@2x.png | Bin 0 -> 2809 bytes .../play_video.imageset/play_video@3x.png | Bin 0 -> 4656 bytes .../Icons/reply.imageset/Contents.json | 23 + .../Icons/reply.imageset/reply_icon.png | Bin 0 -> 234 bytes .../Icons/reply.imageset/reply_icon@2x.png | Bin 0 -> 330 bytes .../Icons/reply.imageset/reply_icon@3x.png | Bin 0 -> 436 bytes .../add_reaction.imageset/Contents.json | 23 + .../add_reaction.imageset/add_reaction@1x.png | Bin 0 -> 630 bytes .../add_reaction.imageset/add_reaction@2x.png | Bin 0 -> 1350 bytes .../add_reaction.imageset/add_reaction@3x.png | Bin 0 -> 1987 bytes ios/RocketChatRN/Info.plist | 2 +- package.json | 10 +- storybook/index.js | 3 + storybook/stories/Avatar.js | 10 +- storybook/stories/Message.js | 428 + storybook/stories/StoriesSeparator.js | 21 + storybook/stories/index.js | 19 +- storybook/storybook.js | 25 +- 121 files changed, 18429 insertions(+), 793 deletions(-) create mode 100644 __mocks__/fileMock.js create mode 100644 __mocks__/react-native-i18n.js create mode 100644 __mocks__/react-native-safari-view.js create mode 100644 __mocks__/react-native-video-controls.js create mode 100644 __mocks__/react-native-video.js create mode 100644 android/app/src/main/res/drawable-hdpi/add_reaction.png create mode 100644 android/app/src/main/res/drawable-hdpi/pause.png create mode 100644 android/app/src/main/res/drawable-hdpi/play.png create mode 100644 android/app/src/main/res/drawable-hdpi/play_video.png create mode 100644 android/app/src/main/res/drawable-hdpi/reply.png create mode 100644 android/app/src/main/res/drawable-mdpi/add_reaction.png create mode 100644 android/app/src/main/res/drawable-mdpi/pause.png create mode 100644 android/app/src/main/res/drawable-mdpi/play.png create mode 100644 android/app/src/main/res/drawable-mdpi/play_video.png create mode 100644 android/app/src/main/res/drawable-mdpi/reply.png create mode 100644 android/app/src/main/res/drawable-xhdpi/add_reaction.png create mode 100644 android/app/src/main/res/drawable-xhdpi/pause.png create mode 100644 android/app/src/main/res/drawable-xhdpi/play.png create mode 100644 android/app/src/main/res/drawable-xhdpi/play_video.png create mode 100644 android/app/src/main/res/drawable-xhdpi/reply.png create mode 100644 android/app/src/main/res/drawable-xxhdpi/add_reaction.png create mode 100644 android/app/src/main/res/drawable-xxhdpi/pause.png create mode 100644 android/app/src/main/res/drawable-xxhdpi/play.png create mode 100644 android/app/src/main/res/drawable-xxhdpi/play_video.png create mode 100644 android/app/src/main/res/drawable-xxhdpi/reply.png create mode 100644 android/app/src/main/res/drawable-xxxhdpi/add_reaction.png create mode 100644 android/app/src/main/res/drawable-xxxhdpi/pause.png create mode 100644 android/app/src/main/res/drawable-xxxhdpi/play.png create mode 100644 android/app/src/main/res/drawable-xxxhdpi/play_video.png create mode 100644 android/app/src/main/res/drawable-xxxhdpi/reply.png create mode 100644 app/containers/message/Message.js create mode 100644 ios/RocketChatRN/Images.xcassets/Icons/pause.imageset/Contents.json create mode 100644 ios/RocketChatRN/Images.xcassets/Icons/pause.imageset/pause.png create mode 100644 ios/RocketChatRN/Images.xcassets/Icons/pause.imageset/pause@2x.png create mode 100644 ios/RocketChatRN/Images.xcassets/Icons/pause.imageset/pause@3x.png create mode 100644 ios/RocketChatRN/Images.xcassets/Icons/play.imageset/Contents.json create mode 100644 ios/RocketChatRN/Images.xcassets/Icons/play.imageset/play.png create mode 100644 ios/RocketChatRN/Images.xcassets/Icons/play.imageset/play@2x.png create mode 100644 ios/RocketChatRN/Images.xcassets/Icons/play.imageset/play@3x.png create mode 100644 ios/RocketChatRN/Images.xcassets/Icons/play_video.imageset/Contents.json create mode 100644 ios/RocketChatRN/Images.xcassets/Icons/play_video.imageset/play_video@1x.png create mode 100644 ios/RocketChatRN/Images.xcassets/Icons/play_video.imageset/play_video@2x.png create mode 100644 ios/RocketChatRN/Images.xcassets/Icons/play_video.imageset/play_video@3x.png create mode 100644 ios/RocketChatRN/Images.xcassets/Icons/reply.imageset/Contents.json create mode 100644 ios/RocketChatRN/Images.xcassets/Icons/reply.imageset/reply_icon.png create mode 100644 ios/RocketChatRN/Images.xcassets/Icons/reply.imageset/reply_icon@2x.png create mode 100644 ios/RocketChatRN/Images.xcassets/Icons/reply.imageset/reply_icon@3x.png create mode 100644 ios/RocketChatRN/Images.xcassets/add_reaction.imageset/Contents.json create mode 100644 ios/RocketChatRN/Images.xcassets/add_reaction.imageset/add_reaction@1x.png create mode 100644 ios/RocketChatRN/Images.xcassets/add_reaction.imageset/add_reaction@2x.png create mode 100644 ios/RocketChatRN/Images.xcassets/add_reaction.imageset/add_reaction@3x.png create mode 100644 storybook/index.js create mode 100644 storybook/stories/Message.js create mode 100644 storybook/stories/StoriesSeparator.js diff --git a/README.md b/README.md index 174994ae8..0ef048c2f 100644 --- a/README.md +++ b/README.md @@ -50,37 +50,35 @@ Readme will guide you on how to config. ### Current priorities -1) Onboarding ([#392][i392]) -2) Splash screen ([#399][i399]) -3) Add empty chat background ([#398][i398]) -4) Rooms list layout ([#395][i395]) -5) Create channel layout ([#401][i401]) +1) Open PDF and other file types ([#341][i341]) +2) [NEW] Commands ([#405][i405]) +3) Better message actions ([#329][i329]) +4) [NEW] Login/Register/Forgot Password layout ([#400][i400]) ### To do | Task | Status | |--------------------|-----| | [NEW] Reply Preview ([#311][i311]) | ✅ | | Image upload improvements ([#368][i368]) | ✅ | -| [NEW] Onboarding ([#392][i392]) | WIP | -| [NEW] Contextual bar layout ([#402][i402]) | ❌ | -| [NEW] Create channel layout ([#401][i401]) | ❌ | -| [NEW] Login/Register/Forgot Password layout ([#400][i400]) | ❌ | -| [NEW] Splash screen ([#399][i399]) | ❌ | -| [NEW] Add empty chat background ([#398][i398]) | ❌ | -| [NEW] Message layout ([#397][i397]) | ❌ | +| [NEW] Onboarding ([#392][i392]) | ✅ | +| [NEW] Create channel layout ([#401][i401]) | ✅ | +| [NEW] Splash screen ([#399][i399]) | ✅ | +| [NEW] Add empty chat background ([#398][i398]) | ✅ | +| [NEW] Message layout ([#397][i397]) | ✅ | +| [NEW] Rooms list layout ([#395][i395]) | ✅ | +| Add components to Storybook ([#38][i38]) | WIP | +| Open PDF and other file types ([#341][i341]) | WIP | +| Better message actions ([#329][i329]) | ❌ | | [NEW] Settings layout ([#396][i396]) | ❌ | -| [NEW] Rooms list layout ([#395][i395]) | ❌ | +| [NEW] Contextual bar layout ([#402][i402]) | ❌ | +| [NEW] Login/Register/Forgot Password layout ([#400][i400]) | ❌ | | [NEW] Commands ([#405][i405]) | ❌ | | [Android] Add Fastlane ([#404][i404]) | ❌ | -| [Android] Adaptive icons ([#403][i403]) | ❌ | | [NEW] Auto versioning app on Circle CI ([#393][i393]) | ❌ | | [Android] Group notifications by room ([#391][i391]) | ❌ | -| Open PDF and other file types ([#341][i341]) | ❌ | -| Better message actions ([#329][i329]) | ❌ | | Integrate project with code push ([#233][i233]) | ❌ | | Custom icons ([#210][i210]) | ❌ | | Share Extension ([#69][i69]) | ❌ | -| Add components to Storybook ([#38][i38]) | ❌ | | Upload files ([#2][i2]) | ❌ | [i2]: https://github.com/RocketChat/Rocket.Chat.ReactNative/issues/2 @@ -124,10 +122,10 @@ Readme will guide you on how to config. | Messages list: load more on scroll | ✅ | | Messages list: receive new messages via subscription | ✅ | | Subscriptions list | ✅ | -| Segmented subscriptions list: Favorites | ❌ | -| Segmented subscriptions list: Unreads | ❌ | -| Segmented subscriptions list: DMs | ❌ | -| Segmented subscriptions list: Channels | ❌ | +| Segmented subscriptions list: Favorites | ✅ | +| Segmented subscriptions list: Unreads | ✅ | +| Segmented subscriptions list: DMs | ✅ | +| Segmented subscriptions list: Channels | ✅ | | Subscriptions list: update user status via subscription | ✅ | | Numbers os messages unread in the Subscriptions list | ✅ | | Status change | ✅ | @@ -205,7 +203,7 @@ Readme will guide you on how to config. | Localized in Portuguese (pt-BR) | ❌ | | Localized in Russian | ✅ | | Localized in English | ✅ | -| Full name setting | ❌ | +| Full name setting | ✅ | | Read only rooms | ✅ | | Typing status | ✅ | | Create channel/group | ✅ | diff --git a/__mocks__/fileMock.js b/__mocks__/fileMock.js new file mode 100644 index 000000000..86059f362 --- /dev/null +++ b/__mocks__/fileMock.js @@ -0,0 +1 @@ +module.exports = 'test-file-stub'; diff --git a/__mocks__/react-native-i18n.js b/__mocks__/react-native-i18n.js new file mode 100644 index 000000000..ae8e97878 --- /dev/null +++ b/__mocks__/react-native-i18n.js @@ -0,0 +1,7 @@ +// @flow +/* eslint-disable */ +import I18nJs from 'i18n-js'; + +I18nJs.locale = 'en'; // a locale from your available translations +export const getLanguages = (): Promise => Promise.resolve(['en']); +export default I18nJs; \ No newline at end of file diff --git a/__mocks__/react-native-safari-view.js b/__mocks__/react-native-safari-view.js new file mode 100644 index 000000000..b1b73a38c --- /dev/null +++ b/__mocks__/react-native-safari-view.js @@ -0,0 +1,5 @@ +export default function() { + return { + show: () => {} + }; +} diff --git a/__mocks__/react-native-video-controls.js b/__mocks__/react-native-video-controls.js new file mode 100644 index 000000000..6b2ed22f8 --- /dev/null +++ b/__mocks__/react-native-video-controls.js @@ -0,0 +1 @@ +export default () => 'Video'; diff --git a/__mocks__/react-native-video.js b/__mocks__/react-native-video.js new file mode 100644 index 000000000..6b2ed22f8 --- /dev/null +++ b/__mocks__/react-native-video.js @@ -0,0 +1 @@ +export default () => 'Video'; diff --git a/__tests__/RoomItem.js b/__tests__/RoomItem.js index b6c422246..a2dfc92f3 100644 --- a/__tests__/RoomItem.js +++ b/__tests__/RoomItem.js @@ -13,29 +13,28 @@ import RoomItem from '../app/presentation/RoomItem'; import renderer from 'react-test-renderer'; const date = new Date(2017, 10, 10, 10); - -jest.mock('react-native-img-cache', () => { return { CachedImage: 'View' } }); +const onPress = () => {}; it('renders correctly', () => { - expect(renderer.create().toJSON()).toMatchSnapshot(); + expect(renderer.create().toJSON()).toMatchSnapshot(); }); it('render unread', () => { - expect(renderer.create().toJSON()).toMatchSnapshot(); + expect(renderer.create().toJSON()).toMatchSnapshot(); }); it('render unread +999', () => { - expect(renderer.create().toJSON()).toMatchSnapshot(); + expect(renderer.create().toJSON()).toMatchSnapshot(); }); it('render no icon', () => { - expect(renderer.create().toJSON()).toMatchSnapshot(); + expect(renderer.create().toJSON()).toMatchSnapshot(); }); it('render private group', () => { - expect(renderer.create( ).toJSON()).toMatchSnapshot(); + expect(renderer.create( ).toJSON()).toMatchSnapshot(); }); it('render channel', () => { - expect(renderer.create().toJSON()).toMatchSnapshot(); + expect(renderer.create().toJSON()).toMatchSnapshot(); }); diff --git a/__tests__/__snapshots__/Storyshots.test.js.snap b/__tests__/__snapshots__/Storyshots.test.js.snap index 2d8a2d067..2464e0f55 100644 --- a/__tests__/__snapshots__/Storyshots.test.js.snap +++ b/__tests__/__snapshots__/Storyshots.test.js.snap @@ -60,7 +60,7 @@ exports[`Storyshots Avatar avatar 1`] = ` source={ Object { "priority": "high", - "uri": "/avatar/test", + "uri": "baseUrl/avatar/test", } } style={ @@ -132,7 +132,7 @@ exports[`Storyshots Avatar avatar 1`] = ` source={ Object { "priority": "high", - "uri": "/avatar/aa", + "uri": "baseUrl/avatar/aa", } } style={ @@ -204,7 +204,7 @@ exports[`Storyshots Avatar avatar 1`] = ` source={ Object { "priority": "high", - "uri": "/avatar/bb", + "uri": "baseUrl/avatar/bb", } } style={ @@ -276,7 +276,7 @@ exports[`Storyshots Avatar avatar 1`] = ` source={ Object { "priority": "high", - "uri": "/avatar/test", + "uri": "baseUrl/avatar/test", } } style={ @@ -3017,3 +3017,16780 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = ` `; + +exports[`Storyshots Message list 1`] = ` + + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + + + + Message + + + + + + + + + + Simple + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum + + + + + + + + + + Long message + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + + + + … + + + + + + + + + + + + + + R + + + + + + + + + rocket.cat + + + 10:00 AM + + + + + + + Different user + + + + + + + + + + + + + + + + + This is the third message + + + + + + + + + + + + + + + + + This is the second message + + + + + + + + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + + + + This is the first message + + + + + + + + + + Grouped messages + + + + + + + + + + Message + + + + + + + + + + Without header + + + + + + + D + + + + + + + + + Diego Mello + + + @ + diego.mello + + + 10:00 AM + + + + + + + Message + + + + + + + + + + With alias + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + + + + Message + + + + (edited) + + + + + + + + + Edited + + + + + + + + + + + + + + + + diego.mello + + + 10:00 AM + + + + + + + Message + + + + + + + + + + Static avatar + + + + + + + D + + + + + + + + + Diego Mello + + + 10:00 AM + + + + + + + Message + + + + + + + + + + Full name + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + + + +   + rocket.cat +   + + + + + +   + diego.mello +   + + + + + +   + all +   + + + + + +   + here +   + + + + + +  # + general +   + + + + + + + + + + Mentions + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + + + + 👊🤙👏 + + + + + + + + + + Emojis + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + + + + + + + + + + + + + + + + + + + + Custom Emojis + + + + + + + D + + + + + + + + + diego.mello + + + 10 November 2017 + + + + + + + Testing + + + + + + + + + + Time format + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + + + + Reactions + + + + + + + + + 😂 + + + 3 + + + + + + + + 13 + + + + + + + 🤔 + + + 1 + + + + + + + + + + + + + Reactions + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + + + + Multiple Reactions + + + + + + + + + + 1 + + + + + + + + 1 + + + + + + + + 1 + + + + + + + ❤️ + + + 1 + + + + + + + 🐶 + + + 1 + + + + + + + 😀 + + + 1 + + + + + + + 😬 + + + 1 + + + + + + + 😁 + + + 1 + + + + + + + + + + + + + Multiple reactions + + + + + + + R + + + + + + + + + rocket.cat + + + 10:00 AM + + + + + + + Fourth message + + + + + + + + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + + + + Third message + + + + + + + + + + + + + + R + + + + + + + + + rocket.cat + + + 10:00 AM + + + + + + + Second message + + + + + + + + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + + + + First message + + + + + + + + + + Intercalated users + + + + + + + R + + + + + + + + + rocket.cat + + + 10:00 AM + + + + + + + Fourth message + + + + + + + + + + + Nov 10, 2017 + + + + unread messages + + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + + + + Third message + + + + + + + + + + + + unread messages + + + + + + + + + + + + Second message + + + + + + + + + + + + + + R + + + + + + + + + rocket.cat + + + 10:00 AM + + + + + + + Second message + + + + + + + + + + + + Nov 10, 2017 + + + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + + + + First message + + + + + + + + + + Date and Unread separators + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + + + + + + + + This is a description + + + + + + + + + + + + This is a title + + + This is a description + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + + + + + + + + This is a description + + + + + + + + + + + + This is a title + + + This is a description + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + With image + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + + + + + + + + This is a description + + + + + + + + + Video + + + + + + + + With video + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + Video + + + + + + + + + + + 00:00 + + + + + + + This is a description + + + + + + + + + + With audio + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + + + + + + + https://rocket.chat + + + Rocket.Chat - Free, Open Source, Enterprise Team Chat + + + Rocket.Chat is the leading open source team chat software solution. Free, unlimited and completely customizable with on-premises and SaaS cloud hosting. + + + + + + + + + https://google.com + + + Google + + + Search the world's information, including webpages, images, videos and more. Google has many special features to help you find exactly what you're looking for. + + + + + + + + + + URL + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + + + + Message + + + + + + + + + rocket.cat + + + 10:00 AM + + + + + + + Custom fields + + + + + + + + Field 1 + + + Value 1 + + + + + Field 2 + + + Value 2 + + + + + Field 3 + + + Value 3 + + + + + Field 4 + + + Value 4 + + + + + Field 5 + + + Value 5 + + + + + + + + + + + Custom fields + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + + + + Message + + + + + + + + + rocket.cat + + + 10:00 AM + + + + + + + Custom fields + + + + + + + + Field 1 + + + Value 1 + + + + + Field 2 + + + Value 2 + + + + + + + + + + rocket.cat + + + 10:00 AM + + + + + + + Custom fields 2 + + + + + + + + Field 1 + + + Value 1 + + + + + Field 2 + + + Value 2 + + + + + + + + + + + Two short custom fields + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + + + + Broadcasted message + + + + + + + + + Reply + + + + + + + + + Broadcast + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + + + + This message is inside an archived room + + + + + + + + + + Archived + + + + + +  + + + + + + + This message has error too + + + + + + + + + + + + +  + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + + + + This message has error + + + + + + + + + + Error + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + + + + Temp message + + + + + + + + + + Temp + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + + + + Message being edited + + + + + + + + + + Editing + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + Message removed + + + + + + + Removed + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + Has joined the channel + + + + + + + Joined + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + Room name changed to: New name by diego.mello + + + + + + + Room name changed + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + Message pinned + + + + + + rocket.cat + + + 10:00 AM + + + + + + + First message + + + + + + + + + + + + Message pinned + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + Has left the channel + + + + + + + Has left the channel + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + User rocket.cat removed by diego.mello + + + + + + + User removed + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + User rocket.cat added by diego.mello + + + + + + + User added + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + User rocket.cat muted by diego.mello + + + + + + + User muted + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + User rocket.cat unmuted by diego.mello + + + + + + + User unmuted + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + rocket.cat was set admin by diego.mello + + + + + + + Role added + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + rocket.cat is no longer admin by diego.mello + + + + + + + Role removed + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + Room description changed to: new description by diego.mello + + + + + + + Changed description + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + Room announcement changed to: new announcement by diego.mello + + + + + + + Changed announcement + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + Room topic changed to: new topic by diego.mello + + + + + + + Changed topic + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + Room type changed to: public by diego.mello + + + + + + + Changed type + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + + + + Message + + + + + + + + + + Custom style + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + + + + Italic with + + + + asterisks + + + + or + + + + underscores + + + + . Bold with + + + + asterisks + + + + or + + + + underscores + + + + . + + + + Strikethrough + + + + + + + + + + + Markdown emphasis + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + + + + H1 + + + + + + + H2 + + + + + + + H3 + + + + + + + H4 + + + + + + + H5 + + + + + + + H6 + + + + + + + + + + Markdown headers + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + + + + Support + + + + Google + + + + + + + + I\`m an inline-style link + + + + https://google.com + + + + + + + + + + Markdown links + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + + + + + + + + + + Markdown image + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + + + + Inline + + + code + + + has + + + back-ticks around + + + it. + + + + + Code block + + + + + + + + + Markdown code + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + + + + + Quote + + + + + + + + + + + Markdown quote + + + + + + + D + + + + + + + + + diego.mello + + + 10:00 AM + + + + + + + + + + First Header + + + + + + + Second Header + + + + + + + + + + + Content from cell 1 + + + + + + + Content from cell 2 + + + + + + + + + Content in the first column + + + + + + + Content in the second column + + + + + + + + + + + + + Markdown table + + + +`; diff --git a/android/app/build.gradle b/android/app/build.gradle index c0cbdd07f..f318e3dd4 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -102,7 +102,7 @@ android { minSdkVersion 19 targetSdkVersion 27 versionCode VERSIONCODE as Integer - versionName "1.1.1" + versionName "1.2" ndk { abiFilters "armeabi-v7a", "x86" } diff --git a/android/app/src/main/res/drawable-hdpi/add_reaction.png b/android/app/src/main/res/drawable-hdpi/add_reaction.png new file mode 100644 index 0000000000000000000000000000000000000000..ade95a3de6b354b23c34b5bde492ef2fd922dc2c GIT binary patch literal 1023 zcmV2+LbMjut_v_TxxV1BL5*L1R4 zg1DZDEA{#r7Z(=`{ze4&84WIfc`7wn5BE8?hGgBt!78KXj|T<64-u0JQSw!hb!H3w zT0vTz2GtVAQp~!ptS4q=P~TcW*6m`u@x0NJng2s6gfbd@1!|I%*HLuX0aW{FjW*TV ziEn@i2gFWmxTA`!$HisAjDL*)Yl(<)lc3?m(v)-ap$nDIlniA#P2%5*2{IJhPWl^q z-isYke+a)^smv(0&E@?&1SBFT5h%NBk#oj%!AQX8$j+g{W5WHSH4MJUrOw4;qLBr! zytCx6M9_lU@+Uj4yK!U_`nL4B7|;N%k!@KfYC`S>DJ&URU04j0JavMi1%|Gy|2se2 z|35qX0n}Z3ZX1Pp!Ha|p?ISAhca$ti#W0Z1rN+d`B*vJ_tZS`zzQ{R$a=($CeV=MN z@cd0oMBn6d)qM*5&AxQjKTH*b>0$3~ZL+VK#@ZZlJ;6s%XyAQO)c|PADrKh*auru2 zdj(Oy_gxO+&LQs#&lXAEPEpfT6m~>3gcXtXTRWiaY)NiOrvdS)RZ#V=aWN$hkv&Je zPU+XmdOn+jaxpf_9R?;^JDk6%^aCme=bh*OM)s)myN74{igV^F70-><))sg5s^k-n zdo&TOEEY>{aZYU}%+~3V_VF;ED(66l)-~YVVrQwJx$u#s1yivcbzO|sv82pix-8o0 zL$(LO{NsBM{Ez%_pKa`8j3ne(&JpV4VQz6Nn^>#FF&;EodoRuS2gSRq!`ZGu?Wbem zm9-&FGe6wO#y-YaonB!qO(D=1bI$4(9YN`A;XE3(n}8)bhy}{~?Wb(97u9?Z+dw6z zp66O8!!2N8=|hDrSc1Rk*lPi;F646^dn8_DM8=n9X~zGDz+ZI5@YIDPqMe8>^eOk- z($4y42VhP}L`Gz6s9c^*Xj{X}ldF!4AzUL{eN2>G;gE;Sut0LHWv& zlfL@5!0t&~-sqIG0fNSh$sbdL^+qI&3&_MFKRl$De|W?ZlU&}Uj&m_gk0d8zuDacZ tWP;Ar{K~PNPX^wwypL+jTjJ`;{{VNN+2Kh+KSTfk002ovPDHLkV1oF1@ACiv literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/pause.png b/android/app/src/main/res/drawable-hdpi/pause.png new file mode 100644 index 0000000000000000000000000000000000000000..bd701d4e4610c49e56abc1bd4792feeb26902e10 GIT binary patch literal 1092 zcmV-K1iSl*P)#kN+^O({>K&Z7IEUjF|dJ>oy|%sEwFgB>z*=3q-si`32H6qqyn$r&0d4o?*G1 z#@$yFovzlW1!6#JIw+t4`eDsX({hs&4)c?bccSw_83GJOv}Z)OB;3R`O>|ys9SJ&E zZhdA>3c!P?6TS8BHsh(3WF9j?3-=J95yxyLR*o~O-9SAm72JWPKpI1+re)OgzLB~to*(53mz zA&1T#b|~VcyZioI)8(g0n*AXQea3oPneLv9(AG`qhnjSW9!|RS_@yKQ7?ylT@owx@ zjHj{r2?~tyt{>e%-K~n+x1@i)T@7@$KXV5eAmmYQ>!3c`1vT)QO`0?`(Bl5Vpq-$8 zG~&GyUh~|t-27_oybjh#SWbm`S+*YX}T#i_1)yn8B-{tx1Sv_mXve2du%X%%PF#Rb8`Y;GhA57qf?i zHI0`8ok-?Cpxm>u@YRWU0cfXjnM2KunPmD5PqjR}w8S^?z6v@HvrmIv_kJm?I_JDRXJQk$!&rlM2l zijQFNg@=VR@~YCOY6mV3lkp45ykN`=4-1Z~(W#etysEOV$h+L22j^oOSKSk>2@UW} zjMvpSmxAE|SZj!>#*XL_W;If&c^v(se~eQohAoS|7WK5Ph-;|6Bd!ET+J3P$+M1En zf+$q74VGP{cz3)iUu<*Xkw?rMX$?x15q?(tHm<*tR&V~txAA{x;h>Cqu2RVW0000< KMNUMnLSTXg^AXYj literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/play.png b/android/app/src/main/res/drawable-hdpi/play.png new file mode 100644 index 0000000000000000000000000000000000000000..f42026fbf3f2b66c4bd2e3689a73c97177e8977f GIT binary patch literal 1239 zcmV;|1StE7P)CRYM(1rMuoi^R+uDB?L zf>Jd7p)RzgbR>&FrHUXTZUjNh*o~To2)anscGF+*2a}d)7gbV7CYgCNr{~4o9ld*|MJzBzO5x#ymT5VAZvMtyZ!c?A%Lfv6uqKF|+{z1+UT^#uT2;PwI# zTr@Cu?(cE@H;h;eGWoG1Y1~!T@LUX8zQT(`kM8N^%=XH$^h+s@`UgdQ5JJY5H?#J~eF9W)Q0QrHlQ2tq&efc#{4$j}=JgX^+H3Z8BmDBNeFm*m2|k{&;G>x;tXlTC zXlh6)%=a60T;}647_fkt&8^(P%B2wwjih0EEC(+=m5PS7xeB3NI1CQthnsy7Rt6t2 z;IlWf@Hu~mdLuL$tUtrhxGh3f*HSOAw$HzlgST1xS=05k{|@HmKUdx9{7?2VBWohO z^>P|!4(DKGM_7}gez8coh$d17dJOh3SvWD84kM4D<<^{V+4pQ3x^0K!Pdf9mO{;6Z zzlkA7e|^z{#d5$!m{+z2`)G)DGitnB|JULDZ>#YAm74Af@?2nOPND$C;`TJrszvb0 zj~0A59mRoz46QOhoXLo(Okc0Td!-7@-HAvB^O};Xii3ClKQ@I@6{fC*G6gpp^K!J8 zJ6EGJt0CA?UTtBDJN6J>LtPpXF1UYEXFa#?5`1^L5gGk()q)qtS72f)3fpzdmmHw* zs)LmqlN|O1&LHjoqQZW+65Nfs`Mi5LX(?Z*7)`R5ax?HA*;#L3zuVdJ>@WD{!kjW( zLCY0}13R);6-P*`rZVJ!qJv3##IuQ0mILxamx<*92pnP}RV)4Q0W(fQ&-_l=1*gck6v_|C=CJOox3 zv8ik!|2(2`EG|DT>&p5f$IFH_i+;A%v>qtW2kJfIdT^=hH?}IbMzG6YSc}9v=>lta zGLbj7t?<$on^&nd$yBMt&;8zw(?3AQZ&AD(zXw6N)pUFx-SPkc002ovPDHLkV1lP9 BWyAmg literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/play_video.png b/android/app/src/main/res/drawable-hdpi/play_video.png new file mode 100644 index 0000000000000000000000000000000000000000..5c5a9bb6d00bebd9bbf8447762539c53f6e06832 GIT binary patch literal 1953 zcmV;S2VVGzP)#A+K+lqS-G^+BVB z#77MVG2xPEuo2V;#dt~71VW6l5-tUT4@8JHD1xL36$KwkXvAnVD$vsHvfcInA7(eZ zGqd-(?#@Y0=l0Ea&iC7MX1y&if6It;xG zy$BtIo>lb>rl$gdKnznyBw)8yfSU!Ii=nO1W+-8mD}>tzJq$erpabPr=(_y@t{(ad z^e3ntLOZlq?>ZR8I)p|nfbNHmL!A)XrTqoP`tEpnINbvM8tNvYKP`^K$>#u^Y=G{C zx>@L7L%z1yz8y}5pzEL`P%jAmq`x6EV3mD#h9iw|qz5|R42Nv4;{@zIg|qp&a_rWW zvoip8VE=xo7Xh;A^t)ee2bW8dk|DzIW?0+>WyjddLjQNE?J21pMW-{2@hamJXje%V z-M!Oxxc7XqS3gBT1i(5N`4ZX&tyDRHhIInuXrT=(7@``1dr)yD159!w$o4`bvY2Bc zQ@9!c5+vKn_7)@sK~xXAT?N%xIfc5^cIRzT-gHJq?8fjcT&=PkX}vpF<8wj;z((xM zexTR8F}WDz+s6Bsa{w}HhdgUK10XMncqLNJ0124w?@@VhStnT`qU6g^uU?7h8d~NG zav%>wF-&Jr=UtAUp}aNk%QXUgL~$3=`n(oMwn*HHf}4bgakYt!9-TC>dUmdTMbak=NU zQJK4GR6aWvlSINYQ&v<=Zses%I>cv_EA5zmH4u|%EFu4nBxL=rsI~w!z!)xHTxGZ~rOxEs<%0DA^dQ!5jCY4(%ofnr}m5DpTDd{;LlLy}% zl^x&3B<}tcSGXn9xz$7#Wmk1^G$9-JL}lsLh@3pH3E8r1H?;zVTMd4FK6q+2wQ7?p zJAEN89UqLznx3fqJ#12?=2p{8evCwp4>V(Vo4M|(wK2ta{uq;o-Wru{M_rfVfWe4_HIOupL11;&m=^SQ1y)b@_SrXd>E0{Uqt0E4()VaW_S)_lG*N) z*HZk`Z)2kEE+xy@G*uu@x5=34W-dn(vT0vbmb?>@9|j#u@#&02&p$&s`$t@!{3s$X zd>)lQFWKI?oJxqUJu?>@y1o4|X?Z&$AAb{*n08OfQ#KixG$A0X z9}dZ?2ZEwpk6CYbI0^AK>up(Y;fXmx+1M76Tc)IL*jsNDK}d)kYvO5{achlqw}&q2KN_8NJ8 zSy=9EWXHl4qCn*P!mgJobpcuPXh@#BKPWY}o;UKMIm1Xi1!XtK`NS~r7teNO#k^Ws z-xijeCK?oQb``mu3c|@4?jHAHVX3qJ=&d)Q!_2epyav~#uGYyu@?#`Y4nti7aVk=G z?UIl@v(R;^tH4V8LvE6UcqnayW3x=%&iS>n?(wkP=)Tl7;-YX*jc_|VnE(l9+v$tPVf>y zqDk>ebrukb_1G{3O$W=umdOZ4g@up{VNFz8X3)Hfd5=v$Dh#2?VPXf(vy;E3iPw1& zARBg2<)t(-6^UFzH2NcD6)buGWFILDx*S5QoVN2;Q@sTatDI5jk|=d;9C8SLKs|BIB5t+=63c1LplVs**siO^bV@3bfB-KV8^n)>(B+-6|Jd z!wn;mr4WrFOpZc5dDok5Fi}pRu0?=&)u_&_5Lp-?8!_pJdVZ)0+f$nePHI{>aM zq>aTu#H|9^1FeS7x>)mF9Q-Q$@NFlQ1}a(DK7OI8;1B)gJtn5pLd6{X)DGRAzP^Iy z*)D#W$(})8I7V)UR+8{5eD(_nc0m90I7#}?4=9x^1)o^5S%3qL*yex9GaH~n*5mlW z4*4SJdMGc_y&&|H{_;|e{<}vIl?_n;>&9mMBmn7uXWI;rtOGC?Lj5nkn*kIcEBb#A zlznzC7BYa&!aj?kt9P+pJc`hP40%=c_~1wl|$ n-rpO9a)d9H<0~Ege=Pq4fO(X!ev>&L00000NkvXXu0mjf`@fmA literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-hdpi/reply.png b/android/app/src/main/res/drawable-hdpi/reply.png new file mode 100644 index 0000000000000000000000000000000000000000..ffb027e1db29fea4d2ed7752c85d63b16c821f26 GIT binary patch literal 275 zcmeAS@N?(olHy`uVBq!ia0vp^qChOf!3HF^2u;-kQY`6?zK#qG8~eHcB(eher#xL8 zLo5W76Bd~N`2T;utibD_vvCU&zd8J2?TBaG$aIvAnRg?5(u78Z4ICXaHH<_u8f*pn zr9A31jG7J!tfLgbztPk80kYo_B z-r`EYnI8(*6ZW(<&GG9y$inMt{DUEYS!3!0RtM8H4moUxT131M|_q@u~;$(>L Wc3N;(LTe7tR}7x6elF{r5}E+g_FbR= literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-mdpi/add_reaction.png b/android/app/src/main/res/drawable-mdpi/add_reaction.png new file mode 100644 index 0000000000000000000000000000000000000000..fd4ef8bdac91e33b066a27f14987abdbb1e52e5e GIT binary patch literal 630 zcmV-+0*U>JP)Ptp`f9nNf9{} z21I3wfRLTW7Df6<5e)?>f^>9gi1G(4uuXxbG>OFdqL8~`-o@)|EEkbiTJLsBx9^%98M0BE0P4eOG~eXH7=-es<;+{E$g&e{`Jerg)}N^^K?;LN_ec9wWW;QcOuz6SSH6@pLfp z`Fn|v(?I?4#>e(4jMh?JWR93`tDNdW-ge3;WkSg&i+nW~f~SoV@7n}}&g;caMHwyr zt^^mY-=HSAj%IA1Cy5R0KMe}otx3T$$ri&+Yzyw!$NY)+qrRE7ew=>V9hL*sr0IG@ z$-B$Z>+g6^UD&5fzxE~jJp6HL8BQANLE=+NUbw5=`P^$dLkE>7r4lti=YyVrcne}EOCN%mx` zn}^Jm8^JdsuB)RqRgz1M6>2NPRUMB9aV#6ykYR%l7+?`|5_^)$>@4y>k4-^abT#?g zS)YDGldW=4dzJ|<`^LM44H-80fB_aUh_#G*vxX5#h^u&*Iwl2oL{O9Nb!tdrNS2%B z%m3>qVlK-t^+2G^0=1c>^hSOuKvFf*w7s`1vPQ61D{?00kqi#+ZVWu Qwg3PC07*qoM6N<$f;Xxh-T(jq literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-mdpi/pause.png b/android/app/src/main/res/drawable-mdpi/pause.png new file mode 100644 index 0000000000000000000000000000000000000000..b13411a50e64b304e355df0b5cdeb3e6667c1ce3 GIT binary patch literal 687 zcmV;g0#N;lP)t%1^gCfG^>i(-h zWcB|+;Z;iT0blSL$LScbptZ(F)pK#f^Yoc{Wpk;@3YW~ZlK>-7w@ZG|+ zsvU8-r+B@i6T>{~_S^#F^fvbzKhC$O!~9{c=Ozj_aoX*xwpV7r>Ah4Wx_`say^5g= zxl<6dF@`zV^cOvFxSlF(lf$0BJ?NgUzsS?I$?!<5ZXDCIl|zg1cJ3n0-W{{;Kf3`v zSUmIUS{r@EJM$C8t6@eOA~`rvtiC?kJ{leEsEtMG@q+-71&vLEJq$)U1WeP)y`#kG z_O1CIn}&p+woGLToOZNYyhso+>S?MXLfe@DYm{4tlsTjtF2I;J4CqSQz>4|VfFmJ| z4FX3xbn<(*T~;aDj@mfexV9-X#3Y)o`ZcYYuj5A1J_^9CD~6hi|E(U-Q8S!Hk+@wl zl+)Al{ck}3{OGFgwvvH`U(3ZMn{+cPi?%*0G3)++$&P^hIp&G$WChGXCl*~lX${|w zeZco=ebbKaGnca% zWFbMI)keK>QHS~(X_}KMQ|%A4cg)B1nH85yp8GKfIK)6d;eLZNfp)`#`W@1GNfVvx zryGrl!98Mrrp|gVe+1l!`jcfUu)kcp9%_0)q^FaU?AlyaO!q5m<8S|^uaccwYxb89 z9*0_Q4i5^edKxxh3pSHDu?_>eQhzPw&7@+MHZ#AeJoRo#DJRyFn8!0Kwbi^q0Rx+` z-NrOU$K%$SVtYp?iup!#<^~wid%R!&p6yI+7R=SL32zqBZnoN7nW3ZC1~Af*fW!3^ zVUry8YrD4h)RCng{Wm>CK)t1G@m^_S{Cq1TStf@^R|@oX)uVe04i%kVqc%No5Lr-} zG-xwJbmn|TZh`5+;u+e0=+fm2W0o`HYQR+O+#4UUX!(g$_$JZ7agX%3k53QcIADr^1%RGY1$|`a^$*`6w_zO;xs(Q zdzwl99BEpAe@Iu?Q(wWDeOcTtE(L&RV=$Uly*O*xhkRn1e*wrIS9p z+Rxu11?5B97T|$}>5~Fov7Pv(8d9yP>G``R&960v0~IjA+!{D#B5G{{D9xEp$~44G zI8vHovOf!`u_ai*L{t-qnQTBc36g(Xc$mQwOc*!sqY$(Ff#McH{(yyE1B?oofebuB zeG~%Q5&MAsSb{q>vIiCjHkha9#?u7D?D4pJi$_i9V_V$~jQXkk!gMdf@UonL+WrDg WqZ(}B87U|L0000kQBCBc{FIY5BLhP% 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 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xhdpi/play.png b/android/app/src/main/res/drawable-xhdpi/play.png new file mode 100644 index 0000000000000000000000000000000000000000..c3880486555edab440f9c8bda94ae3710da2d7f1 GIT binary patch literal 1638 zcmV-s2ATPZP)Rx*eXBZo0XG~|w`j4*+uWN6tc<#T zPKeXe7wVXPLtM7&%QkSs(WOU~mN=~xZL;gk$@)UjH6c9*rjG}|v}0G=soc=L*r93K znNq_dX2gJ45R)B-oO*cMyDAW!Sv<#_Jy~bCnsq=h#6F+!{SEi<1}W2rY)t18()Y#kcev|raBc}^mt`!^4vS6 zhqbtRy`t$Xf;Tg*0XKF<_7v-_$09D*PJsz*hJ!U=jkHeVkv+2NCsnB2E9VX=` zCDrPSISw1PX%1{)L^B;&UzTxrrD9Wv=$q$*^ixlmM!SQw_pY^MvKg)e)tOCaG=Nvv zpd7G#-NfVfc&WK=1@ev>NrQ)ibnD$gA9clAXz}c0rT*7YwtHe@jzN?G5crn)r`UD+$*hgo(g4DLdW4`QK8H`|+`ns`e zZZaFL-y%8112p(dfEu=@XG7+e`CkF6#3FhACJJx4ce_VV^Ui%mNONYD_##kv*o9dL zcm*AP$VVgmG~ai(dua|<$;nh#Sh&u$zHPIl58DIu@v{MHy2<%82dm_%R~bwVQg7Ox zW)BT_1nH?=&OXY)%00aDVJp>T=}Uf2^WObFst!6A3s_4y{c#S&jwPh@yqyNcsvC_f zdg-$$%`Z9U5v-gz_&%$)I%l?UOXnsN)bn|irvBn3IR`hedfDU^w%O>Q-MmfxepRDa zzlhP-za;Xuk*y(Ez4-FZ2lr;H==QZ`PTv!waeD7;jF#i>c>}8#G6SA%x#wja%im2T z=#`-;P5RbSq7O#m z^!|vu>1zgtZls1;<*Hg{++3m1@+`DDrfv8_oF437qIZUi3%eS|I9OLE9;}uz#a3|f z%+GO}_;cmiFg2&q!IMjL=%Xn8b~XJ*6znV)1FMYs3>^zx(S^t#yj<_-xhFMUQb|qwFDMOJ+#{p6&~c5R1N&D^&C` zvm}2x1WO9Aeu5Ql_?TSLpd36Hpw=^UqygiLITUW(qI45%bCh<=9J{X4vydjH0mC-5 z5xn-(ZP!n^)JN=A`VPdG@{~3QT;I7c$U|wn`FuH-8R*o^K-IxaF<(5&aA-DE<(;%3D7z$q=)P1EwcjSPC>iqzdh87RLOSdN_h>jA;$G|mWYw- z=Dz9jVMTpqBUpm~4G*ZkaGE?R6O}Ds82Mib!~u-Qy9nZZ#m*T3TZ2UhM`n86bASpWb407*qoM6N<$f&+3O`Tzg` literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xhdpi/play_video.png b/android/app/src/main/res/drawable-xhdpi/play_video.png new file mode 100644 index 0000000000000000000000000000000000000000..a8958ac2655a0c18b05e4557935ceac04fea4e2c GIT binary patch literal 2809 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 LNkvXXu0mjf8v9a+ literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xhdpi/reply.png b/android/app/src/main/res/drawable-xhdpi/reply.png new file mode 100644 index 0000000000000000000000000000000000000000..b5d4a004362647f3470dfd0a0fe3aefc5b3cefb1 GIT binary patch literal 330 zcmV-Q0k!^#P)71Q{00004XF*Lt006O% z3;baP00032Nklpm*;$&NcGL7$c>^V})Z^pjG6d z@MKc65d%!uKs(_`eG1bAX-hs!tUpcbG>%YT8_Xjk=>EeXC(%uV1kWZqYwu&qilQy( zMgvs}C<_}nfS04|`+bb~JABcEAz{>lH cim~R|9jJo?*%p#mfB*mh07*qoM6N<$f|lZl3IG5A literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxhdpi/add_reaction.png b/android/app/src/main/res/drawable-xxhdpi/add_reaction.png new file mode 100644 index 0000000000000000000000000000000000000000..d76bb42958a0e6a6af180e5f7dbced4f99d2671c GIT binary patch literal 1987 zcmV;!2R!(RP)JG(zg=gx z-LKz%fBo9y=pFG(+TER*ot^n+cXoF6BjhH1=t9>kJyhDp1zD%$WRy(h4p8 zRty!nJ8P^lxp)>7*pSK?_d%JgRH{m!j(Fa-6&uJ_9x}PPH9ceuf^sXA7KDgKwS%>m z-{!zuM%tVe`voO05Fwg6pUKf=;28Zw#w%d$o&N7Y+yS`W2A)=+KGA6FHO9zE+~-1D zY*kM5Oc#wDD78%x(S5xP1H6`jmG9NX3u=ij!1~g|KDQiuhf)l!G+iu>fie#UPBcn? zr$l^9DESL`UnU}Q83*aa(^Rp(jIq92;m1L#+q?vXd3KR7_8Ez=6NPuXFM82*0v4!P zdWW$Y9K&I-(h|3DbdpfIXG=16B$uPyjSmSC>=#1$7Xj33VJ-LD@Y68vDO+2sLM-_M z0(=)XT8awsHLL+$DM~pNbRX-94Nv4~S>rknjlN9jC@5ydiXif($0$`bQIc}qJ-uNi>xh-EPSQ#rMfIOQ!@6V_p`ro zX(<+YsxaJr!46-@bXad8UlGASyDTVTD7LySLZoak$9mQf;Q#O%h)v_4I zelkqbDCi`5KMk}<8kWT%pncsH`@udH>bX}b>_CZMWQcYiaWNA-)&xM?f=UlI# zReEH=2yFh0pI6MliT$hUL8Vj-j~?kvY0yrH5ry1*?LbEzm4baP+W?C!z_95V)V4~G zjPfI~ub{wROOKq2c%FhiO9qctZwQl`M-<9ZRxhY{!4%#L=LJ*r?Uz!q`XN#00GvGP1XDAeplOi?G5lo8%#P#}0@dva|(am?Cra z?BL1QB}8+rqSKNMk-r;Mwn#GJ|rV_onPLPMY|$!#&SHuv8OrE9cg;V zz9D_q7 z1oh%qI~w-2$L#HePGrJ*hWm@7G{HjsBfRe}AU@qz~E`jD4`L zFM$mqWdWINAgt;#JCIVb2%}#*;DnfbqYLH$pkTZzzA*_umChKu@L1v?aW#)pUQlo> z;RKPYa0K@m_qwPOs{@oM4~MlzxUeXU!m(f|v6L;&%m2MY)e50bKvU z9wD|WhREoXVi^yRhZRhf^%rr>E+FD$Tabg-OmQ%kDM5-`fMbG((&g7oZoM=KtN&pi zZjxib^IoQnM)wrYOc zYNPex<*b%J+e}b+s{|g%%S%u>HppPnVg+QBvT8tg!%}Q~xa&voF`w%sqL0s%Z71Xg z7N^cFwktJV6@L&(E#8rH@ZeRhs0Bg$%rdDXShsebqM8%&QzrV3Nq zgl!B;l%{tX1H8<41G7zFpPV&IP9g0J+wD;ta{?#TRS zgQZfYdCKXSa6R`X6OTX!Y$jNx8rG#4g6o$O=Ri3-k$RzjL z#ow!QxcI}(SMF2NrR&}ghd`y^_i}zTepC+G!e5|b$OkP4)8o2c)ymip!z9jM1P|%h zeCyIvas~3hn_9J$(!Hr-NLXKU@^W2u^ep`@*Qtq7#|re6GD>#`v^qO*6tJcSTUk>& z1GIL?r{*n<9Bh!a&mltgYlRH=DL6wN>P^OTVZEOp|Imsl2K7xm^am`eUtozr07Mk9 z`R<;JmF#1*teEOt|Ktd6X!szk6Fu**h??Vt4_9lsaQCguz{3vYD*ccFMi>66-W0K8W&;L#* zot>GTotfRc-QBtKkeRt3=iKv~n{)5X-Z{fr3vHX;5?vExbA#pig+Y_?LC(xUCioh` z#Zu1r62Zh0?9pU8o}%L^xflFA<6=}WqhK&mNOz?Q%Lcj&C!XQ+tzsU(lnu$}h4D_Q zw9#PvE>noR3F_^HFxQwi@gl+h*5Le0lZmgM%4SdI^W1EV?C4T13FxbzFK%LG{v`F( zZPYbaMsIeE8l0Wwf*)pS@$R3m|kFuyZ_fb|3{@- zWuQ0g6S;{qrQL$@9pra=RT@#hY(CAIIJj(8cF#|{$hRxllz<)>Ds44Qwx0m^D`>Mq zk$l`R*v_%x?2$$*X(;GxcFzoy=gc>0fV;oZ4Q;AC&W@(Ljc5PZlNoE2-iCo*Jyd*{ zdhwxF^TTmL5ts?;-P=zO=RS@r!&$Fx&@|X}PZei|X*ThkQ*fso)9mEHl3Zqp2Ftm6 zY^n?Ny1ZC1Gd=SO`Qpv>G@|wE^5dD_%!4C&elBiXV}q9dcvgH)kk`dk-cI$XXBSf4 z{Jyw;+lXWAwJ*%xurMdSPYPr(BG)(wn_+t#W|4a|6wS|u}Eg?dnS3 z@%yVizeKSm5@@&!TvfWdS4L6NX=TZc{6%i$)+lZywCljYS0!R0O^Hd}1m>E832J{os?3nu%> zTUDpn1X2cjq}Cl|AZR)G&6+=U%5Aj`rqO$XIFafxZVVb616>Cm5NXJ@FAEsShiL&t ztAfU(&bEIF7hrh9v*?MXWL8D6FK9fpx1J|gsil*B34j^c`DOZo#xEl@%V@KQ_I~Cy zJ5BUk?7VtCgQ5J5Z+d2oK)3kMPhMkMBZW`*^=1a#zd?F>G=50ckn6c*qSsAmUqv%y3n%{*?CXNb-aA&NTi(h>yU*xB4}0R4G}}V* z`Y!XzIx{KQhbPKXp1ZD!b85jvcW-vUxs)O8R3z73G-*k|){QB)e_M}Jz32Ge^^9$} z%3!-b2>x+n__1#G_{|ljcw{|vQ=08OJj;%pT=3*IIsqLOEJ^Mgw(JVmLHF<5?F`lX z9rtvFQUQQh$klfK#gSJFvRyN*PP=?PdpFBP&{(ELSE6Yvh}Nw1{)<;LZ1sx8W_pSQ z<+%$-(dn)m^&Bka(zgp0FIqrr;i3wwr#wB=4PD&`C>oUKRuDy}yKby=2U7_et2*U^ z!&uUErD_Dg6l{?%|6u8C(^hp>YgH$v(@I&%)&`CB$(?9tE7)YSl|5Q60&j&@bzmE8 zwgz5juvXf4pp~s)61~L$#s=OQp<8a>Cr+)<&h~EuEng5HK)wcdgiAFGwFJPJT!-~0s#;aamJY@SUi(cp z2KCm1vF_38IWyU#o1jOlAOdh5Q<{WY0$>c+p+T$V4A(KGd$eN65O4Kp1QpSnQUVmd z;ygW<7NbhFXyFWu$#ob7%|a~!8G?u&c4*LQInxibqF^Al=Kt;HP_vP_Yh#EV5ZI6$zL8&F)h#1l~j05SI#K_mDc z-6x(^q${~%iK%2u1Z0m!ghLs8FS$sRSPrIk^hgO>YM}^+O0-oGO6!NKoMquTiYo!K) zMvNeY_6-uC^Jt(WMnUnEz$g$j3LyFw-Q^s>vEIA{z@}D&Fx09E8if!)nPwr!ajZ87 z0nU$EY#eD-4g&{6XB~uxq{xNe(YhNQ%~68kBNS8mwy-g!LxYBF9R$|udgLzD1%ZVM zIQ+Dcx*wr^EtSdpYlSsVMGn{<%11kKj=tXWGvX)Xsyfq?a15K{#Eu4=$e>XPL8=iy znFh!aoF`-BBd|GYfNq;jEYPS7H-f<+5wj7RUBK2_b7dQ<-##{I2*Zd=G2Y-tI(D87 z+xl{uEn#ODevpwCY1UCq2-5WjZ-VH=^wEAIad(8!zI5r1`sKG(8rc9_!rbwNwX0!0 z+Nn@~l*~!PIyP_33AC+7f3Dgl(d2z6e}Mge0E8+B$d1ot00000NkvXX Hu0mjf4#gSp literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxhdpi/play.png b/android/app/src/main/res/drawable-xxhdpi/play.png new file mode 100644 index 0000000000000000000000000000000000000000..2e60e189ac1ccc657a8e686cf3d1cc3ed543dc4e GIT binary patch literal 2485 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 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxhdpi/play_video.png b/android/app/src/main/res/drawable-xxhdpi/play_video.png new file mode 100644 index 0000000000000000000000000000000000000000..def52c709483c30ed4256b94de54dcab466a4f47 GIT binary patch literal 4656 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

b0BR4=-Lsta#w_l+^ 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 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxxhdpi/pause.png b/android/app/src/main/res/drawable-xxxhdpi/pause.png new file mode 100644 index 0000000000000000000000000000000000000000..81d47ece6aa4cd22bb17a4483a2d5fc9619c9136 GIT binary patch literal 3201 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 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxxhdpi/play_video.png b/android/app/src/main/res/drawable-xxxhdpi/play_video.png new file mode 100644 index 0000000000000000000000000000000000000000..41cc52ed688f5d7204a5a87876c3e1c57998f9c7 GIT binary patch literal 6600 zcmV;(88_yMP)|G&Mz+5g#RpL42=#CHVR+S+PR=^$tWbTD)Pv>&u@ z*0vA!yINY8wZ*PUL7TI-+&=_82tAOs-H-iU&_?KH()m zLC07+8rz}JGojT`Kjj1}+Y5aM`UdoMOLu^HA7NkO0RkeJOQ3>G#FAv1Wa$KKNv1B) zFiR_pBk5j(ZnKo6Ys0>zLIgyx3IGJDNT^xRDbRDFy`gcC!*F6d^f~BykZngCoC?AR z5zGPVAXHCezZgnV&4ltgDhaX&PHup%hi(GljwZorH+&SqN}y<6N6kUDzk<$&b}w;C z+2iHNLfUec`Tj$L!f)&6Aq~Zhw$+Qqka&fXkl8*o z6?Z~cgJ_9bO_CUbfmmE_v8n7;%h`)Rb@C~kc$2?k;fhs*av zrxtfzzk~>Z&9LRmAll9l+2o2TVPA;q$VrBSP|jL$rMSrD2)#fvv#nld+p!G;wZ!Gh zV>5!GVdesx??dZd#z@8ai@L1U7>G3((2!VM(jw_0blg*rq8xxNl}c$Z(~a@MX%$jv^n+3F*q^*59w7(lBAVn2dj zA6n#OSeOua5XSs1MzhepvLJK>1G%~ZEY1>M9;OzQEulx?7qF1Cj7?#(G*kowxq1Pd zr=gsRmk0r;2yhDjQjqM3(-XbQ9~y#zTm#@F-@V7zOiP47xd?Ef_e_v%f4K#?d0r?8 z267F9QyZZTZaSy35{p11Jf9Ady&W_HfzKj>T;l=4HfTf8V5t7sAi%z~&FWi$Iu$6v z0KgP@&y^Xxkt`7cZX&=wwZ-aVZkFq)tiVD<>%R-h)zgv1$}9w&A#fDgCnH>Z+1Y9C z7#3>ea;F_tO6Lf0N!6qvuE~5S7|6xh!WW?pP>B%m3xP&dG!Z28b#~F$ zYcPXl)h z5e($wJ+9ZFdRWq{)>FA|AiyW1$AV;@yneuw5E0}earxa|k;{!PpfbEffPM5atIxV# zk0%6!m3;ftbl0s_fkMC=1ZJRE_F31(^$-#N2{;YPHHNzGa=p1!poa+XdTcU6MLx9Y znz%|Zkc)5J<#m_dTj*L7sURN_*oV4!J?7dQgk1{}tr+%E7$|c2*dtVxs|c{~KI-Q6 zm}>-sVPA#nUGc8Aw+agY0rp|`Wmm+N5D|o z+I6B32tNWTm^cQb*v@iHtz-nd9~FvR<)E%}qJ#kZIQx28QWn85dR>j$rj}KsP7(sq zLtv`a=N((_I7GB2Hhzbi_;x6X5J(CF@59kyPA5Fd8NqHqMIu*Hx|RIQAi&33*!LZY zqY(_F7vs@)p;~X~2xeuD2?AUUJOrZ{Cq8V6(-CYDN)@?mL90wLM1XyNkrTgck6;+R zYEUqzDu+0!KzW5g%n)D%Hyoo_iygn5j9~LopvYwhRpp5@0^|U>U`uR`U>LoakE`WJ z*eX?-gh0Fzcnj`vwS8MDH|>sK^H7k;RSHf0o)iSg1#+UK*d4)MK}qM7EKM1NKynax z6(iWVQtp-&ram@Vm*9HH<6)aDQkwc&;R|<|`2oL!(8-C7( zTS*B7#@~L-eDHrAN3TMsj6JK`EWe`Gj5)Kj|7(TLR9eUp;7f7(V-(AKIZm;b=4;qQ zE}N}thg>Y`wf9b#xj$$&Uw`VjIh@xNHY-!MFd{&%6nu4IF@jwcMla%E6T`+;+mD+I z5H>#kpDm`X^uQMfx0B#QLC)lbhzJjR0u6?T-I9Qc8$O=3wEW?S;o|anb!P0KV*l&h zuux_AfB;{&eLBL#quF&8YSoL8LFCFt$;18E_qLkL5H{ZOWXk-Ze4ct}p^CPN0OyIx zoeolnV6!^p(1GU&AZjqH5iWAJ@v-d+8$Acyy9)BSQz%4y5A_f7&W8AvTuF#n2#wLW zIlcUfIy0`m(EqUAkcwBxdfXM z4Ih$YC6`~__VbjPeQ%TbO=D|v9FMN29XQl}4Tk@i+&={E9bMmovE1!zu+F@=a(s=s zb#|TUe`;sB^jm-k97f%Ja4nXOIkHDEUVn*P0k({ts-JurVdHm?nIHeE#hlQ9W(P9A z^N>U2Qd+VJHYt;+ZMYHmV^f>?_P?jh%J9=7T@lJxlp~K%gMOCiqaXs_+1TpTBZ4Y<%E(g^eD-TTYSfTuM)JV1k3If%!i$ zdqgXz;6$F|=OjldfIsz#F6MUJq&|13nz9sD9{$d_{Zu}_l4%8Alx6lktXD;Qjlgez z-)gSGuy|Gc%uv}hhAh;~kM zN(2i6dY|h2Q*)cSV{OVzzq`r&>TR*iC)hL9bRgL1Oscl=L*REGw3-F~(qz80DrNQ` z(V8otS~$(A%m_Brr%F{#fC#MpuNE^IVdD?Cw3y?12ane+k>*qtW)S&dy(TE%gD5Ej zfiTS?+BJVj|1RdAF0V5ed@A!l*6x|gXA=Sb3+qO7`FM)RWfQfyWPA6+RPoJzk4qQUi|RbXTgSpVNGX3EMY^MlPTCZ({^?RIP62sYU5QdM5G5IB}< zGb=Zw%(T0j%zy0EY@>^cC|5P0T|lVRh1&$gsLWDz6R{C1@u3D(!|T2){85okKzX6}CGWZ1a*ErpF`wpd?{ zU}Ykgl+$(}Y&F;ZxXFC+;b!yRA%%?&+g&4=L%Mz9 z&##>@&l9eC?Y#^}Ze@=#t_in;Bb0viksN)DGf)#>BX|@n(ZfP_3Y)qLYKTFxl zpRi16f^|)p({k4X1pW=LlY3>irt@>4?Wz$h2N4~XkH8Chs52M5^az%lsAC~e76L7L zfqout9KjSk=fR?cauAq0LQg&A;Fco6nsX9$CoPi9jNcy{*fMgCnhIXdIS@}lGEU> zcsd9RfW9@i)=VFzYpxQ2rU}Mxf=PrxNd&spR+$?wsxe=gQfs;@A}om)G8`gI2kqok zo@67y8Nz?WTd2K_NVwz zsj3J7fwNEVVs5{p&P+O6vx7duPfoQH>~$Y2R#iSBa7x!Ivl!vv^#})R#4VptZ?7iJ zsmur_g0nA(zOhlOZBzJ3hipA}`8@F;Nmd1bTL>GJk(@t@+}4HKtnJ3c3N`A*X0WCPd`^ zOHdJvNJLC7A6H|(F{jR)erm)FkFUApQd+VJwhbv?u+p`O00N)J_Y;?6cJOoQ50ys1 z;N+M{E~O=xV3~AnLyW+w2nYXRdaYSBN#S5fo2ekdcu{s3+B>91C*CZ?^=962kVEMS4jR}#f}!y+&(XFWX|wo)BwPrL9C$Ju9N(ZBjBvF~o;BOarA%r& z!K{Smuob~F=!9U~t9zAMGNaa9GqJ{W(JieIv`9%4$f0)0CD?lWva7#ej4!bCp4GN?U=c6>)*^cg3^!EyBp2Ym;>vI_T* zL)k@iAei;T25fK0&ZK>R5a`{b$}F8(YZgwZF&Mxk(L;dT=^%v&#vx7w>j0Ct2Mh|(kTn$|*e0YOgLY>IiMI%Rc2G5L7T2234pKPiEz+KsPR@`! z9VCxn_-}d?*J10B>n}Ux)PbuAoOVi;`5MB(1%IJ%&{bfAD{LLPlUscr!K@5VU@L;< zqUFMI7tFQK|6H}XWmcW(t#HrqIg=;F2(}hExf)nqAP=(q1m3GUa;*K{VtxiI zW$ale!@)6UDjX~dQZ#=cSIC(>DcI5&>WZF_SAr7E#IrkpdrTjMgWvspSF`4(u14gF zWrta7aVF2Xf&{a2t;)--gn|exn^SB0pPE0f&T#OWiM3|yE#1x42n!{#MW85G@_U7a z0VX=wBX&d2h%GEGI=1UTo4IG>ar69dPnZ*Uo^=X7_jBWgwPw`7q7b`SyNU`BfqkgE z9wXR^LN;{T`XJfuIO!XOPE?u@5CUlgmV;ck6~m$w!5VPlyU|1?#O-cF|S7xFN983AyOJqY;cJU=-ssVsAqS@>n7S5`w_{@N*al#z(nqi=z>Y zrCJp%v0Z~Q3W0bau*503=(gh#EQ1wBvS+bBHFK=35Qs4Xn?bH=<@i?#!G@zkekPL> z9}*!DR|GhrF$M(VEh@+2I7H0UU{!cm=2%-H5K{#1DwkZuqwEokCtDL9Z(_He#}XkB zGX!?SpOGM#qlt}d49XtCScp~e&DjNNUkJnqftxEK7jdX)1j_)4k?d*g&&eEXD+FSI z0N)gKX{CO+MX%ngo!Ncm(W=}mI#4}BCsBIUjl-aeAdg3f36XXm4Rgauz3xt#lQqa5;X+4 zn0GA5b-*pdT?r90##n~U$8o`zFlO>;D+EG_0Q>BGH_1gGT_qR`gn=($^G)tcgg}H4 zxXtRjuA1y>h?ud=x*lUJJ0p{(tq=$?0?)vjtlF@QYyl*4UHK%e{6;b$h zt^~n6zkKn9V00LxST}4oLeJ;1L!4g(B@qH{A;7SZBNzXX2PT0NjGlvJ z!?58Legjk@1S&v8+c7Rw z1f#(Kh)Y&vaikGg3+wp-yj@ZDBJu>wfDfY0 z#XgBvpGng;k_haE)g;!MNLrs`bR93Rq$R)dVh!FQmkLV1)HY6RG3Y&(7vITqw1 z+OZkI=uAd1nhnSP{m`kIG;KqTz-CzYWe{s;sI4r+xY&$f*}k)(pwp1XPbu+^za*Rp zux&W?J}r*qBIL0g!Ls`jMzbC`=DNnEP~AJr1}C_E-qTtMeE`JzC^$2`uQ~Pv%RmUC z)nR`T^cLt4sKkE+-bIxwppSr9iMUQq48bye2}G;GK10V_p(8Ts+Iot>TPXcb=xPwF z#nYNXR(RqFmcbuHqwn*eT;F(3CS6-s5qK4)-2r_H#A7BX;5gqWkv2i^1F877utbYGQ&#hXXbm{L4tgzA6Cwb?fpFsDVdz63R-=RSVx3h4 zE6}_kS~Ze6sx5?a2^MD}CHV+&29QgdRzcT+SfPBXINxmlQbe#4Sc7aN7fE&%bQZKb zG|9pRxa*-mgRTXsVm-}XX+w)(4iE&{dLlco(?~Qv06GYo1la>8H$X|OO(50LBslGc zk0MwFD1vaKa5~901$r*DH#81%7*1@5J_lV7LhXoyQ$hG3g1Lk`$i`)7BcYQloq+97 zXxNvdwZg`Cpf5qUS-JzHO60UU{C8DEFjwL1SeSMF#!-%6^rVi4l5}T6Ig#S0Z~|g4 zlw^7X`nshgldhuxh8H4&d4Xz)GC@49CgJs419UKS0JI;pZ`QUC_W50FF7cvvwYJ!# zAIE97wp?<=7j7Pc9)upq+V02xE@&fk4~UegRTS_!aQT0j24wuexDq)40000m98C literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxxhdpi/reply.png b/android/app/src/main/res/drawable-xxxhdpi/reply.png new file mode 100644 index 0000000000000000000000000000000000000000..2c38d2b2bc62cdb0015bf267989424f5f83050d1 GIT binary patch literal 523 zcmV+m0`&cfP)2Coyl=~QKX_L@V`zV%d%;7K1k{u z?vnNeT@DJe1V{Hr!hr-w%2G0CivN%h+29J;Yi~=n2HYKUX1xSdIL(}cg{x($WvOL3 z*%Q!rPT#r7R$Q&!v@AU<%eY9ZWRCthx>5LyHp4zaUk!hk<~y4|qqlJ!KUf2)QIp-Sce4JtI2LvZ5Yv`eL%3m@G z_MSK`lHz}~jCJLnW8)di=AZai`o<{N1hvT*1G{|-IyQ($Ua?j59<7ptfe@MH6{G+V z^8)%&LD(Ar%oq3wc~t@URte}MByh(Sfb!$SE-dgSlf-&7GN7RQ0@)bQ7s#;yeSjPr z&~?aG09}S`4bWA{RsmgvY#q=wNE_hqZ9)QWB0M-@o$VGPH;_fHWKT_=J<1y5*kZn1 zliC-7L`_L?*#6&XKZw76A~0phu;7Zr%OS&rD?u(5eQosw^aO^Uz&Da@fJ;hZSCRk# N002ovPDHLkV1mir<4OPk literal 0 HcmV?d00001 diff --git a/app/constants/settings.js b/app/constants/settings.js index 7206e0ecb..ec9916268 100644 --- a/app/constants/settings.js +++ b/app/constants/settings.js @@ -79,5 +79,9 @@ export default { }, Store_Last_Message: { type: 'valueAsBoolean' + }, + UI_Use_Real_Name: { + type: 'valueAsBoolean' } }; +export const settingsUpdatedAt = new Date('2018-09-10'); diff --git a/app/containers/Avatar.js b/app/containers/Avatar.js index cf357c2b2..b55466cd4 100644 --- a/app/containers/Avatar.js +++ b/app/containers/Avatar.js @@ -1,6 +1,5 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; import { StyleSheet, Text, View, ViewPropTypes } from 'react-native'; import FastImage from 'react-native-fast-image'; import avatarInitialsAndColor from '../utils/avatarInitialsAndColor'; @@ -19,13 +18,10 @@ const styles = StyleSheet.create({ } }); -@connect(state => ({ - baseUrl: state.settings.Site_Url || state.server ? state.server.server : '' -})) export default class Avatar extends React.PureComponent { static propTypes = { + baseUrl: PropTypes.string.isRequired, style: ViewPropTypes.style, - baseUrl: PropTypes.string, text: PropTypes.string, avatar: PropTypes.string, size: PropTypes.number, diff --git a/app/containers/EmojiPicker/CustomEmoji.js b/app/containers/EmojiPicker/CustomEmoji.js index 30f8670fd..7079d31e5 100644 --- a/app/containers/EmojiPicker/CustomEmoji.js +++ b/app/containers/EmojiPicker/CustomEmoji.js @@ -1,11 +1,7 @@ import React from 'react'; import { ViewPropTypes, Image } from 'react-native'; import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; -@connect(state => ({ - baseUrl: state.settings.Site_Url -})) export default class CustomEmoji extends React.Component { static propTypes = { baseUrl: PropTypes.string.isRequired, diff --git a/app/containers/EmojiPicker/EmojiCategory.js b/app/containers/EmojiPicker/EmojiCategory.js index cdef44435..bfd7ff94f 100644 --- a/app/containers/EmojiPicker/EmojiCategory.js +++ b/app/containers/EmojiPicker/EmojiCategory.js @@ -10,9 +10,9 @@ import scrollPersistTaps from '../../utils/scrollPersistTaps'; const emojisPerRow = Platform.OS === 'ios' ? 8 : 9; -const renderEmoji = (emoji, size) => { +const renderEmoji = (emoji, size, baseUrl) => { if (emoji.isCustom) { - return ; + return ; } return ( @@ -25,6 +25,7 @@ const renderEmoji = (emoji, size) => { @responsive export default class EmojiCategory extends React.Component { static propTypes = { + baseUrl: PropTypes.string.isRequired, emojis: PropTypes.any, window: PropTypes.any, onEmojiSelected: PropTypes.func, @@ -44,6 +45,7 @@ export default class EmojiCategory extends React.Component { } renderItem(emoji, size) { + const { baseUrl } = this.props; return ( this.props.onEmojiSelected(emoji)} testID={`reaction-picker-${ emoji.isCustom ? emoji.content : emoji }`} > - {renderEmoji(emoji, size)} + {renderEmoji(emoji, size, baseUrl)} ); } diff --git a/app/containers/EmojiPicker/index.js b/app/containers/EmojiPicker/index.js index ac30b7c37..93306e41a 100644 --- a/app/containers/EmojiPicker/index.js +++ b/app/containers/EmojiPicker/index.js @@ -19,6 +19,7 @@ const scrollProps = { export default class EmojiPicker extends Component { static propTypes = { + baseUrl: PropTypes.string.isRequired, onEmojiSelected: PropTypes.func, tabEmojiStyle: PropTypes.object, emojisPerRow: PropTypes.number, @@ -110,6 +111,7 @@ export default class EmojiPicker extends Component { style={styles.categoryContainer} size={this.props.emojisPerRow} width={this.props.width} + baseUrl={this.props.baseUrl} /> ); } @@ -123,12 +125,14 @@ export default class EmojiPicker extends Component { } contentProps={scrollProps} + style={styles.background} > { categories.tabs.map((tab, i) => ( {this.renderCategory(tab.category, i)} diff --git a/app/containers/EmojiPicker/styles.js b/app/containers/EmojiPicker/styles.js index 038d11b20..35cbd7e97 100644 --- a/app/containers/EmojiPicker/styles.js +++ b/app/containers/EmojiPicker/styles.js @@ -1,6 +1,9 @@ import { StyleSheet } from 'react-native'; export default StyleSheet.create({ + background: { + backgroundColor: '#fff' + }, container: { flex: 1 }, diff --git a/app/containers/MessageBox/EmojiKeyboard.js b/app/containers/MessageBox/EmojiKeyboard.js index ec60b34b8..9b5cb08e2 100644 --- a/app/containers/MessageBox/EmojiKeyboard.js +++ b/app/containers/MessageBox/EmojiKeyboard.js @@ -1,22 +1,25 @@ import React from 'react'; import { View } from 'react-native'; import { KeyboardRegistry } from 'react-native-keyboard-input'; -import { Provider } from 'react-redux'; + import store from '../../lib/createStore'; import EmojiPicker from '../EmojiPicker'; import styles from './styles'; export default class EmojiKeyboard extends React.PureComponent { + constructor(props) { + super(props); + const state = store.getState(); + this.baseUrl = state.settings.Site_Url || state.server ? state.server.server : ''; + } onEmojiSelected = (emoji) => { KeyboardRegistry.onItemSelected('EmojiKeyboard', { emoji }); } render() { return ( - - - this.onEmojiSelected(emoji)} /> - - + + this.onEmojiSelected(emoji)} baseUrl={this.baseUrl} /> + ); } } diff --git a/app/containers/MessageBox/ReplyPreview.js b/app/containers/MessageBox/ReplyPreview.js index 2463984ec..1b3f321ae 100644 --- a/app/containers/MessageBox/ReplyPreview.js +++ b/app/containers/MessageBox/ReplyPreview.js @@ -9,15 +9,17 @@ import Markdown from '../message/Markdown'; const styles = StyleSheet.create({ container: { - flexDirection: 'row' + flexDirection: 'row', + marginTop: 10, + backgroundColor: '#fff' }, messageContainer: { flex: 1, - marginHorizontal: 15, + marginHorizontal: 10, backgroundColor: '#F3F4F5', paddingHorizontal: 15, paddingVertical: 10, - borderRadius: 2 + borderRadius: 4 }, header: { flexDirection: 'row', @@ -35,18 +37,23 @@ const styles = StyleSheet.create({ marginLeft: 5 }, close: { - marginRight: 15 + marginRight: 10 } }); @connect(state => ({ - Message_TimeFormat: state.settings.Message_TimeFormat + Message_TimeFormat: state.settings.Message_TimeFormat, + customEmojis: state.customEmojis, + baseUrl: state.settings.Site_Url || state.server ? state.server.server : '' })) export default class ReplyPreview extends Component { static propTypes = { message: PropTypes.object.isRequired, Message_TimeFormat: PropTypes.string.isRequired, - close: PropTypes.func.isRequired + close: PropTypes.func.isRequired, + customEmojis: PropTypes.object.isRequired, + baseUrl: PropTypes.string.isRequired, + username: PropTypes.string.isRequired } close = () => { @@ -54,7 +61,9 @@ export default class ReplyPreview extends Component { } render() { - const { message, Message_TimeFormat } = this.props; + const { + message, Message_TimeFormat, customEmojis, baseUrl, username + } = this.props; const time = moment(message.ts).format(Message_TimeFormat); return ( @@ -63,9 +72,9 @@ export default class ReplyPreview extends Component { {message.u.username} {time} - + - + ); } diff --git a/app/containers/MessageBox/index.js b/app/containers/MessageBox/index.js index 63eb3bb12..3c520def0 100644 --- a/app/containers/MessageBox/index.js +++ b/app/containers/MessageBox/index.js @@ -530,6 +530,7 @@ export default class MessageBox extends React.PureComponent { text={item.username || item.name} size={30} type={item.username ? 'd' : 'c'} + baseUrl={this.props.baseUrl} />, { item.username || item.name } ] @@ -556,11 +557,13 @@ export default class MessageBox extends React.PureComponent { }; renderReplyPreview = () => { - const { replyMessage, replying, closeReply } = this.props; + const { + replyMessage, replying, closeReply, username + } = this.props; if (!replying) { return null; } - return ; + return ; }; renderFilesActions = () => { @@ -584,29 +587,30 @@ export default class MessageBox extends React.PureComponent { return ( [ this.renderMentions(), - this.renderReplyPreview(), - - {this.leftButtons} - this.component = component} - style={styles.textBoxInput} - returnKeyType='default' - keyboardType='twitter' - blurOnSubmit={false} - placeholder={I18n.t('New_Message')} - onChangeText={text => this.onChangeText(text)} - value={this.state.text} - underlineColorAndroid='transparent' - defaultValue='' - multiline - placeholderTextColor='#9EA2A8' - testID='messagebox-input' - /> - {this.rightButtons} + + {this.renderReplyPreview()} + + {this.leftButtons} + this.component = component} + style={styles.textBoxInput} + returnKeyType='default' + keyboardType='twitter' + blurOnSubmit={false} + placeholder={I18n.t('New_Message')} + onChangeText={text => this.onChangeText(text)} + value={this.state.text} + underlineColorAndroid='transparent' + defaultValue='' + multiline + placeholderTextColor='#9EA2A8' + testID='messagebox-input' + /> + {this.rightButtons} + ] ); diff --git a/app/containers/MessageBox/styles.js b/app/containers/MessageBox/styles.js index 8293f6e25..5fa1aea79 100644 --- a/app/containers/MessageBox/styles.js +++ b/app/containers/MessageBox/styles.js @@ -11,13 +11,17 @@ export default StyleSheet.create({ borderTopColor: '#D8D8D8', zIndex: 2 }, + composer: { + backgroundColor: '#fff', + flexDirection: 'column', + borderTopColor: '#e1e5e8', + borderTopWidth: 1 + }, textArea: { flexDirection: 'row', alignItems: 'center', flexGrow: 0, - backgroundColor: '#fff', - borderTopColor: '#ECECEC', - borderTopWidth: 1 + backgroundColor: '#fff' }, textBoxInput: { textAlignVertical: 'center', diff --git a/app/containers/Sidebar.js b/app/containers/Sidebar.js index 382939ae6..8a1bccb72 100644 --- a/app/containers/Sidebar.js +++ b/app/containers/Sidebar.js @@ -85,7 +85,8 @@ const keyExtractor = item => item.id; server: state.login.user && state.login.user.server, status: state.login.user && state.login.user.status, username: state.login.user && state.login.user.username - } + }, + baseUrl: state.settings.Site_Url || state.server ? state.server.server : '' }), dispatch => ({ selectServerRequest: server => dispatch(selectServerRequest(server)), logout: () => dispatch(logout()), @@ -93,6 +94,7 @@ const keyExtractor = item => item.id; })) export default class Sidebar extends Component { static propTypes = { + baseUrl: PropTypes.string, navigator: PropTypes.object, server: PropTypes.string.isRequired, selectServerRequest: PropTypes.func.isRequired, @@ -323,7 +325,7 @@ export default class Sidebar extends Component { ) render() { - const { user, server } = this.props; + const { user, server, baseUrl } = this.props; if (!user) { return null; } @@ -341,6 +343,7 @@ export default class Sidebar extends Component { text={user.username} size={30} style={styles.avatar} + baseUrl={baseUrl} /> diff --git a/app/containers/message/Audio.js b/app/containers/message/Audio.js index c809dee80..ecedd793c 100644 --- a/app/containers/message/Audio.js +++ b/app/containers/message/Audio.js @@ -1,74 +1,55 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { View, StyleSheet, TouchableOpacity, Text, Easing } from 'react-native'; +import { View, StyleSheet, TouchableOpacity, Text, Easing, Image } from 'react-native'; import Video from 'react-native-video'; -import Icon from 'react-native-vector-icons/MaterialIcons'; import Slider from 'react-native-slider'; -import { connect } from 'react-redux'; +import moment from 'moment'; + import Markdown from './Markdown'; const styles = StyleSheet.create({ audioContainer: { flex: 1, flexDirection: 'row', - justifyContent: 'center', alignItems: 'center', - height: 50, - margin: 5, - backgroundColor: '#eee', - borderRadius: 6 + height: 56, + backgroundColor: '#f7f8fa', + borderRadius: 4, + marginBottom: 10 }, playPauseButton: { - width: 50, + width: 56, alignItems: 'center', - backgroundColor: 'transparent', - borderRightColor: '#ccc', - borderRightWidth: 1 - }, - playPauseIcon: { - color: '#ccc', backgroundColor: 'transparent' }, - progressContainer: { + playPauseImage: { + width: 30, + height: 30 + }, + slider: { flex: 1, - justifyContent: 'center', - height: '100%', - marginHorizontal: 10 - }, - label: { - color: '#888', - fontSize: 10 - }, - currentTime: { - position: 'absolute', - left: 0, - bottom: 2 + marginRight: 10 }, duration: { - position: 'absolute', - right: 0, - bottom: 2 + marginRight: 16, + fontSize: 14, + fontWeight: '500', + color: '#54585e' + }, + thumbStyle: { + width: 12, + height: 12 } }); -const formatTime = (t = 0, duration = 0) => { - const time = Math.min( - Math.max(t, 0), - duration - ); - const formattedMinutes = Math.floor(time / 60).toFixed(0).padStart(2, 0); - const formattedSeconds = Math.floor(time % 60).toFixed(0).padStart(2, 0); - return `${ formattedMinutes }:${ formattedSeconds }`; -}; +const formatTime = seconds => moment.utc(seconds * 1000).format('mm:ss'); -@connect(state => ({ - baseUrl: state.settings.Site_Url || state.server ? state.server.server : '' -})) export default class Audio extends React.PureComponent { static propTypes = { file: PropTypes.object.isRequired, baseUrl: PropTypes.string.isRequired, - user: PropTypes.object.isRequired + user: PropTypes.object.isRequired, + customEmojis: PropTypes.object.isRequired } constructor(props) { @@ -90,7 +71,7 @@ export default class Audio extends React.PureComponent { } onProgress(data) { - if (data.currentTime < this.state.duration) { + if (data.currentTime <= this.state.duration) { this.setState({ currentTime: data.currentTime }); } } @@ -102,10 +83,6 @@ export default class Audio extends React.PureComponent { }); } - getCurrentTime() { - return formatTime(this.state.currentTime, this.state.duration); - } - getDuration() { return formatTime(this.state.duration); } @@ -116,7 +93,10 @@ export default class Audio extends React.PureComponent { render() { const { uri, paused } = this.state; - const { description } = this.props.file; + const { + user, baseUrl, customEmojis, file + } = this.props; + const { description } = file; return ( [ @@ -136,29 +116,30 @@ export default class Audio extends React.PureComponent { onPress={() => this.togglePlayPause()} > { - paused ? - : + paused ? + : + } - - {this.getCurrentTime()} - {this.getDuration()} - this.setState({ currentTime: value })} - /> - + this.setState({ currentTime: value })} + thumbStyle={styles.thumbStyle} + /> + {this.getDuration()} , - + ] ); } diff --git a/app/containers/message/Emoji.js b/app/containers/message/Emoji.js index 5f87f64e0..c26cba26d 100644 --- a/app/containers/message/Emoji.js +++ b/app/containers/message/Emoji.js @@ -2,28 +2,28 @@ import React from 'react'; import { Text, ViewPropTypes } from 'react-native'; import PropTypes from 'prop-types'; import { emojify } from 'react-emojione'; -import { connect } from 'react-redux'; import CustomEmoji from '../EmojiPicker/CustomEmoji'; -@connect(state => ({ - customEmojis: state.customEmojis -})) export default class Emoji extends React.PureComponent { static propTypes = { - content: PropTypes.string, + content: PropTypes.string.isRequired, + baseUrl: PropTypes.string.isRequired, standardEmojiStyle: Text.propTypes.style, customEmojiStyle: ViewPropTypes.style, - customEmojis: PropTypes.object.isRequired + customEmojis: PropTypes.oneOfType([ + PropTypes.array, + PropTypes.object + ]) }; render() { const { - content, standardEmojiStyle, customEmojiStyle, customEmojis + content, standardEmojiStyle, customEmojiStyle, customEmojis, baseUrl } = this.props; const parsedContent = content.replace(/^:|:$/g, ''); const emojiExtension = customEmojis[parsedContent]; if (emojiExtension) { const emoji = { extension: emojiExtension, content: parsedContent }; - return ; + return ; } return { emojify(`${ content }`, { output: 'unicode' }) }; } diff --git a/app/containers/message/Image.js b/app/containers/message/Image.js index f3b83b27b..d6ab72e7e 100644 --- a/app/containers/message/Image.js +++ b/app/containers/message/Image.js @@ -2,29 +2,30 @@ import PropTypes from 'prop-types'; import React from 'react'; import FastImage from 'react-native-fast-image'; import { TouchableOpacity } from 'react-native'; -import { connect } from 'react-redux'; import PhotoModal from './PhotoModal'; import Markdown from './Markdown'; import styles from './styles'; -@connect(state => ({ - baseUrl: state.settings.Site_Url || state.server ? state.server.server : '' -})) export default class extends React.PureComponent { static propTypes = { file: PropTypes.object.isRequired, baseUrl: PropTypes.string.isRequired, user: PropTypes.object.isRequired, - customEmojis: PropTypes.object + customEmojis: PropTypes.oneOfType([ + PropTypes.array, + PropTypes.object + ]) } state = { modalVisible: false }; getDescription() { - const { file, customEmojis } = this.props; + const { + file, customEmojis, baseUrl, user + } = this.props; if (file.description) { - return ; + return ; } } @@ -47,13 +48,14 @@ export default class extends React.PureComponent { {this.getDescription()} , this.setState({ modalVisible: false })} diff --git a/app/containers/message/Markdown.js b/app/containers/message/Markdown.js index da54d141c..10d00a4e2 100644 --- a/app/containers/message/Markdown.js +++ b/app/containers/message/Markdown.js @@ -1,8 +1,7 @@ import React from 'react'; -import { Text, Platform, Image } from 'react-native'; +import { Text, Image } from 'react-native'; import PropTypes from 'prop-types'; import { emojify } from 'react-emojione'; -import { connect } from 'react-redux'; import MarkdownRenderer, { PluginContainer } from 'react-native-markdown-renderer'; import MarkdownFlowdock from 'markdown-it-flowdock'; import styles from './styles'; @@ -16,16 +15,13 @@ const formatText = text => (match, url, title) => `[${ title }](${ url })` ); -@connect(state => ({ - customEmojis: state.customEmojis -})) export default class Markdown extends React.Component { shouldComponentUpdate(nextProps) { return nextProps.msg !== this.props.msg; } render() { const { - msg, customEmojis, style, rules + msg, customEmojis, style, rules, baseUrl, username, edited } = this.props; if (!msg) { return null; @@ -36,21 +32,38 @@ export default class Markdown extends React.Component { return ( ( - - {children} - - ) - }, - mention: node => ( - alert(`Username @${ node.content }`)} style={styles.mention}> - @{node.content} + paragraph: (node, children) => ( + + {children}{edited ? (edited) : null} ), + mention: (node) => { + const { content, key } = node; + let mentionStyle = styles.mention; + if (content === 'all' || content === 'here') { + mentionStyle = { + ...mentionStyle, + ...styles.mentionAll + }; + } else if (content === username) { + mentionStyle = { + ...mentionStyle, + ...styles.mentionLoggedUser + }; + } + return ( + alert(`Username ${ content }`)} + style={mentionStyle} + > +  {content}  + + ); + }, hashtag: node => ( alert(`Room #${ node.content }`)} style={styles.mention}> - #{node.content} +  #{node.content}  ), emoji: (node) => { @@ -59,7 +72,7 @@ export default class Markdown extends React.Component { const emojiExtension = customEmojis[content]; if (emojiExtension) { const emoji = { extension: emojiExtension, content }; - return ; + return ; } return :{content}:; } @@ -74,6 +87,11 @@ export default class Markdown extends React.Component { }} style={{ paragraph: styles.paragraph, + text: { + color: '#0C0D0F', + fontSize: 16, + letterSpacing: 0.1 + }, codeInline: { borderWidth: 1, borderColor: '#CCCCCC', @@ -81,6 +99,9 @@ export default class Markdown extends React.Component { padding: 2, borderRadius: 4 }, + link: { + color: '#1D74F5' + }, ...style }} plugins={[ @@ -95,7 +116,10 @@ export default class Markdown extends React.Component { Markdown.propTypes = { msg: PropTypes.string, - customEmojis: PropTypes.object, + username: PropTypes.string.isRequired, + baseUrl: PropTypes.string.isRequired, + customEmojis: PropTypes.object.isRequired, style: PropTypes.any, - rules: PropTypes.object + rules: PropTypes.object, + edited: PropTypes.bool }; diff --git a/app/containers/message/Message.js b/app/containers/message/Message.js new file mode 100644 index 000000000..665b97d78 --- /dev/null +++ b/app/containers/message/Message.js @@ -0,0 +1,351 @@ +import React, { PureComponent } from 'react'; +import PropTypes from 'prop-types'; +import { View, Text, TouchableOpacity, ViewPropTypes, Image as ImageRN } from 'react-native'; +import Icon from 'react-native-vector-icons/MaterialIcons'; +import moment from 'moment'; +import { KeyboardUtils } from 'react-native-keyboard-input'; + +import Image from './Image'; +import User from './User'; +import Avatar from '../Avatar'; +import Audio from './Audio'; +import Video from './Video'; +import Markdown from './Markdown'; +import Url from './Url'; +import Reply from './Reply'; +import ReactionsModal from './ReactionsModal'; +import Emoji from './Emoji'; +import styles from './styles'; +import Touch from '../../utils/touch'; +import I18n from '../../i18n'; +import messagesStatus from '../../constants/messagesStatus'; + +const SYSTEM_MESSAGES = [ + 'r', + 'au', + 'ru', + 'ul', + 'uj', + 'rm', + 'user-muted', + 'user-unmuted', + 'message_pinned', + 'subscription-role-added', + 'subscription-role-removed', + 'room_changed_description', + 'room_changed_announcement', + 'room_changed_topic', + 'room_changed_privacy' +]; + +const getInfoMessage = ({ + type, role, msg, user +}) => { + const { username } = user; + if (type === 'rm') { + return I18n.t('Message_removed'); + } else if (type === 'uj') { + return I18n.t('Has_joined_the_channel'); + } else if (type === 'r') { + return I18n.t('Room_name_changed', { name: msg, userBy: username }); + } else if (type === 'message_pinned') { + return I18n.t('Message_pinned'); + } else if (type === 'ul') { + return I18n.t('Has_left_the_channel'); + } else if (type === 'ru') { + return I18n.t('User_removed_by', { userRemoved: msg, userBy: username }); + } else if (type === 'au') { + return I18n.t('User_added_by', { userAdded: msg, userBy: username }); + } else if (type === 'user-muted') { + return I18n.t('User_muted_by', { userMuted: msg, userBy: username }); + } else if (type === 'user-unmuted') { + return I18n.t('User_unmuted_by', { userUnmuted: msg, userBy: username }); + } else if (type === 'subscription-role-added') { + return `${ msg } was set ${ role } by ${ username }`; + } else if (type === 'subscription-role-removed') { + return `${ msg } is no longer ${ role } by ${ username }`; + } else if (type === 'room_changed_description') { + return I18n.t('Room_changed_description', { description: msg, userBy: username }); + } else if (type === 'room_changed_announcement') { + return I18n.t('Room_changed_announcement', { announcement: msg, userBy: username }); + } else if (type === 'room_changed_topic') { + return I18n.t('Room_changed_topic', { topic: msg, userBy: username }); + } else if (type === 'room_changed_privacy') { + return I18n.t('Room_changed_privacy', { type: msg, userBy: username }); + } + return ''; +}; + +export default class Message extends PureComponent { + static propTypes = { + baseUrl: PropTypes.string.isRequired, + customEmojis: PropTypes.object.isRequired, + timeFormat: PropTypes.string.isRequired, + msg: PropTypes.string, + user: PropTypes.shape({ + id: PropTypes.string.isRequired, + username: PropTypes.string.isRequired, + token: PropTypes.string.isRequired + }), + author: PropTypes.shape({ + _id: PropTypes.string.isRequired, + username: PropTypes.string.isRequired, + name: PropTypes.string + }), + status: PropTypes.any, + reactions: PropTypes.any, + editing: PropTypes.bool, + style: ViewPropTypes.style, + archived: PropTypes.bool, + broadcast: PropTypes.bool, + reactionsModal: PropTypes.bool, + type: PropTypes.string, + header: PropTypes.bool, + avatar: PropTypes.string, + alias: PropTypes.string, + ts: PropTypes.instanceOf(Date), + edited: PropTypes.bool, + attachments: PropTypes.oneOfType([ + PropTypes.array, + PropTypes.object + ]), + urls: PropTypes.oneOfType([ + PropTypes.array, + PropTypes.object + ]), + useRealName: PropTypes.bool, + // methods + closeReactions: PropTypes.func, + onErrorPress: PropTypes.func, + onLongPress: PropTypes.func, + onReactionLongPress: PropTypes.func, + onReactionPress: PropTypes.func, + replyBroadcast: PropTypes.func, + toggleReactionPicker: PropTypes.func + } + + static defaultProps = { + archived: false, + broadcast: false, + attachments: [], + urls: [], + reactions: [], + onLongPress: () => {} + } + + onPress = () => { + KeyboardUtils.dismiss(); + } + + isInfoMessage() { + return SYSTEM_MESSAGES.includes(this.props.type); + } + + isOwn = () => this.props.author._id === this.props.user.id; + + isDeleted() { + return this.props.type === 'rm'; + } + + isTemp() { + return this.props.status === messagesStatus.TEMP || this.props.status === messagesStatus.ERROR; + } + + hasError() { + return this.props.status === messagesStatus.ERROR; + } + + renderAvatar = () => { + const { + header, avatar, author, baseUrl + } = this.props; + if (header) { + return ( + + ); + } + return null; + } + + renderUsername = () => { + const { + header, timeFormat, author, alias, ts, useRealName + } = this.props; + if (header) { + return ( + + ); + } + return null; + } + + renderContent() { + if (this.isInfoMessage()) { + return {getInfoMessage({ ...this.props })}; + } + const { + customEmojis, msg, baseUrl, user, edited + } = this.props; + return ; + } + + renderAttachment() { + const { attachments, timeFormat } = this.props; + + if (attachments.length === 0) { + return null; + } + + return attachments.map((file, index) => { + const { user, baseUrl, customEmojis } = this.props; + if (file.image_url) { + return ; + } + if (file.audio_url) { + return @@ -97,22 +98,22 @@ export default class ReactionsModal extends React.PureComponent { render() { const { - isVisible, onClose, reactions + isVisible, close, reactions } = this.props; return ( - + {I18n.t('Reactions')} diff --git a/app/containers/message/Reply.js b/app/containers/message/Reply.js index fd7654329..2516f9d53 100644 --- a/app/containers/message/Reply.js +++ b/app/containers/message/Reply.js @@ -1,39 +1,41 @@ import React from 'react'; -import { View, Text, TouchableOpacity, StyleSheet } from 'react-native'; +import { View, Text, StyleSheet } from 'react-native'; import PropTypes from 'prop-types'; import moment from 'moment'; import Markdown from './Markdown'; -import QuoteMark from './QuoteMark'; -import Avatar from '../Avatar'; import openLink from '../../utils/openLink'; - +import Touch from '../../utils/touch'; const styles = StyleSheet.create({ button: { flex: 1, flexDirection: 'row', alignItems: 'center', - marginTop: 2, + marginTop: 15, alignSelf: 'flex-end' }, attachmentContainer: { flex: 1, - flexDirection: 'column' + borderRadius: 4, + flexDirection: 'column', + backgroundColor: '#f3f4f5', + padding: 15 }, authorContainer: { flexDirection: 'row', alignItems: 'center' }, author: { - fontWeight: 'bold', - marginHorizontal: 5, - flex: 1 + color: '#1d74f5', + fontSize: 18, + fontWeight: '500', + marginRight: 10 }, time: { - fontSize: 10, + fontSize: 14, fontWeight: 'normal', - color: '#888', + color: '#9ea2a8', marginLeft: 5 }, fieldsContainer: { @@ -47,6 +49,9 @@ const styles = StyleSheet.create({ }, fieldTitle: { fontWeight: 'bold' + }, + marginTop: { + marginTop: 4 } }); @@ -58,23 +63,13 @@ const onPress = (attachment) => { openLink(attachment.title_link || attachment.author_link); }; -const Reply = ({ attachment, timeFormat }) => { +const Reply = ({ + attachment, timeFormat, baseUrl, customEmojis, user, index +}) => { if (!attachment) { return null; } - const renderAvatar = () => { - if (!attachment.author_icon && !attachment.author_name) { - return null; - } - return ( - - ); - }; - const renderAuthor = () => ( attachment.author_name ? {attachment.author_name} : null ); @@ -90,7 +85,6 @@ const Reply = ({ attachment, timeFormat }) => { } return ( - {renderAvatar()} {renderAuthor()} {renderTime()} @@ -98,7 +92,7 @@ const Reply = ({ attachment, timeFormat }) => { }; const renderText = () => ( - attachment.text ? : null + attachment.text ? : null ); const renderFields = () => { @@ -119,28 +113,26 @@ const Reply = ({ attachment, timeFormat }) => { }; return ( - onPress(attachment)} - style={styles.button} + style={[styles.button, index > 0 && styles.marginTop]} > - {renderTitle()} {renderText()} {renderFields()} - {attachment.attachments ? - attachment.attachments - .map(attach => ) - : null - } - + ); }; Reply.propTypes = { attachment: PropTypes.object.isRequired, - timeFormat: PropTypes.string.isRequired + timeFormat: PropTypes.string.isRequired, + baseUrl: PropTypes.string.isRequired, + customEmojis: PropTypes.object.isRequired, + user: PropTypes.object.isRequired, + index: PropTypes.number }; export default Reply; diff --git a/app/containers/message/Url.js b/app/containers/message/Url.js index 43dd2542e..730b065e0 100644 --- a/app/containers/message/Url.js +++ b/app/containers/message/Url.js @@ -1,67 +1,82 @@ import React from 'react'; -import { View, Text, TouchableOpacity, StyleSheet, Image } from 'react-native'; +import { View, Text, StyleSheet } from 'react-native'; import PropTypes from 'prop-types'; +import FastImage from 'react-native-fast-image'; -import QuoteMark from './QuoteMark'; import openLink from '../../utils/openLink'; +import Touch from '../../utils/touch'; const styles = StyleSheet.create({ button: { - flex: 1, - flexDirection: 'row', - alignItems: 'center', - marginVertical: 2 + marginTop: 10 }, - image: { - height: 80, - width: 80, - resizeMode: 'cover', - borderRadius: 6 + container: { + flex: 1, + flexDirection: 'column', + borderRadius: 4, + backgroundColor: '#F3F4F5' }, textContainer: { flex: 1, - height: '100%', flexDirection: 'column', - padding: 4, + padding: 15, justifyContent: 'flex-start', alignItems: 'flex-start' }, title: { - fontWeight: 'bold', - fontSize: 12 + fontWeight: '500', + color: '#1D74F5', + fontSize: 16, + marginTop: 5 }, description: { - fontSize: 12 + marginTop: 5, + fontSize: 16, + color: '#0C0D0F' + }, + url: { + fontSize: 15, + fontWeight: '500', + color: '#9EA2A8' + }, + marginTop: { + marginTop: 4 + }, + image: { + width: '100%', + height: 150, + borderTopLeftRadius: 4, + borderTopRightRadius: 4 } }); const onPress = (url) => { openLink(url); }; -const Url = ({ url }) => { +const Url = ({ url, index }) => { if (!url) { return null; } return ( - onPress(url.url)} style={styles.button}> - - {url.image ? - - : null - } - - {url.title} - {url.description} + onPress(url.url)} style={[styles.button, index > 0 && styles.marginTop]}> + + {/* + {url.image ? : null} + */} + {url.image ? : null} + + {url.url} + {url.title} + {url.description} + - + ); }; Url.propTypes = { - url: PropTypes.object.isRequired + url: PropTypes.object.isRequired, + index: PropTypes.number }; export default Url; diff --git a/app/containers/message/User.js b/app/containers/message/User.js index 8480f9b7d..2b988acc8 100644 --- a/app/containers/message/User.js +++ b/app/containers/message/User.js @@ -2,14 +2,13 @@ import React from 'react'; import PropTypes from 'prop-types'; import { View, Text, StyleSheet } from 'react-native'; import moment from 'moment'; -import Icon from 'react-native-vector-icons/FontAwesome'; -import Avatar from '../Avatar'; const styles = StyleSheet.create({ username: { - color: '#000', - fontWeight: '400', - fontSize: 14 + color: '#0C0D0F', + fontWeight: '600', + fontSize: 16, + lineHeight: 22 }, usernameView: { flexDirection: 'row', @@ -17,67 +16,50 @@ const styles = StyleSheet.create({ marginBottom: 2 }, alias: { - fontSize: 10, - color: '#888', - paddingLeft: 5 + fontSize: 14, + color: '#9EA2A8', + paddingLeft: 6, + lineHeight: 16 }, time: { - fontSize: 10, - color: '#888', - paddingLeft: 5, - fontWeight: '400' - }, - edited: { - marginLeft: 5, - flexDirection: 'row', - alignItems: 'center' + fontSize: 14, + color: '#9EA2A8', + paddingLeft: 10, + fontWeight: '300', + lineHeight: 16 } }); export default class User extends React.PureComponent { static propTypes = { - item: PropTypes.object.isRequired, - Message_TimeFormat: PropTypes.string.isRequired, + timeFormat: PropTypes.string.isRequired, + username: PropTypes.string, + alias: PropTypes.string, + ts: PropTypes.instanceOf(Date), + temp: PropTypes.bool, onPress: PropTypes.func } - renderEdited = (item) => { - if (!item.editedBy) { - return null; - } - return ( - - - - - ); - } - render() { - const { item } = this.props; + const { + username, alias, ts, temp + } = this.props; const extraStyle = {}; - if (item.temp) { + if (temp) { extraStyle.opacity = 0.3; } - const username = item.alias || item.u.username; - const aliasUsername = item.alias ? (@{item.u.username}) : null; - const time = moment(item.ts).format(this.props.Message_TimeFormat); + const aliasUsername = alias ? (@{username}) : null; + const time = moment(ts).format(this.props.timeFormat); return ( - {username} + {alias || username} {aliasUsername} {time} - {this.renderEdited(item)} ); } diff --git a/app/containers/message/Video.js b/app/containers/message/Video.js index 4476cc0c4..59be1c448 100644 --- a/app/containers/message/Video.js +++ b/app/containers/message/Video.js @@ -1,9 +1,8 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { StyleSheet, TouchableOpacity, Image, Platform } from 'react-native'; +import { StyleSheet, TouchableOpacity, Image, Platform, View } from 'react-native'; import Modal from 'react-native-modal'; import VideoPlayer from 'react-native-video-controls'; -import { connect } from 'react-redux'; import Markdown from './Markdown'; import openLink from '../../utils/openLink'; @@ -11,31 +10,31 @@ const SUPPORTED_TYPES = ['video/quicktime', 'video/mp4', ...(Platform.OS === 'io const isTypeSupported = type => SUPPORTED_TYPES.indexOf(type) !== -1; const styles = StyleSheet.create({ - container: { + button: { flex: 1, - height: 100, - margin: 5 + borderRadius: 4, + height: 150, + backgroundColor: '#1f2329', + marginBottom: 10, + alignItems: 'center', + justifyContent: 'center' }, modal: { margin: 0, backgroundColor: '#000' }, image: { - flex: 1, - width: null, - height: null, - resizeMode: 'contain' + width: 54, + height: 54 } }); -@connect(state => ({ - baseUrl: state.settings.Site_Url || state.server ? state.server.server : '' -})) export default class Video extends React.PureComponent { static propTypes = { file: PropTypes.object.isRequired, baseUrl: PropTypes.string.isRequired, - user: PropTypes.object.isRequired + user: PropTypes.object.isRequired, + customEmojis: PropTypes.object.isRequired } state = { isVisible: false }; @@ -62,19 +61,21 @@ export default class Video extends React.PureComponent { render() { const { isVisible } = this.state; const { description } = this.props.file; + const { baseUrl, user, customEmojis } = this.props; return ( [ - this.open()} - > - - - , + + this.open()} + > + + + + , { - if (t === 'rm') { - return I18n.t('Message_removed'); - } else if (t === 'uj') { - return I18n.t('Has_joined_the_channel'); - } else if (t === 'r') { - return I18n.t('Room_name_changed', { name: msg, userBy: u.username }); - } else if (t === 'message_pinned') { - return I18n.t('Message_pinned'); - } else if (t === 'ul') { - return I18n.t('Has_left_the_channel'); - } else if (t === 'ru') { - return I18n.t('User_removed_by', { userRemoved: msg, userBy: u.username }); - } else if (t === 'au') { - return I18n.t('User_added_by', { userAdded: msg, userBy: u.username }); - } else if (t === 'user-muted') { - return I18n.t('User_muted_by', { userMuted: msg, userBy: u.username }); - } else if (t === 'user-unmuted') { - return I18n.t('User_unmuted_by', { userUnmuted: msg, userBy: u.username }); - } else if (t === 'subscription-role-added') { - return `${ msg } was set ${ role } by ${ u.username }`; - } else if (t === 'subscription-role-removed') { - return `${ msg } is no longer ${ role } by ${ u.username }`; - } else if (t === 'room_changed_description') { - return I18n.t('Room_changed_description', { description: msg, userBy: u.username }); - } else if (t === 'room_changed_announcement') { - return I18n.t('Room_changed_announcement', { announcement: msg, userBy: u.username }); - } else if (t === 'room_changed_topic') { - return I18n.t('Room_changed_topic', { topic: msg, userBy: u.username }); - } else if (t === 'room_changed_privacy') { - return I18n.t('Room_changed_privacy', { type: msg, userBy: u.username }); - } - return ''; -}; +import Message from './Message'; +import { errorActionsShow, toggleReactionPicker, replyBroadcast } from '../../actions/messages'; @connect(state => ({ - message: state.messages.message, - editing: state.messages.editing, + baseUrl: state.settings.Site_Url || state.server ? state.server.server : '', customEmojis: state.customEmojis, + editing: state.messages.editing, + Message_GroupingPeriod: state.settings.Message_GroupingPeriod, Message_TimeFormat: state.settings.Message_TimeFormat, - Message_GroupingPeriod: state.settings.Message_GroupingPeriod + message: state.messages.message, + useRealName: state.settings.UI_Use_Real_Name }), dispatch => ({ - actionsShow: actionMessage => dispatch(actionsShow(actionMessage)), errorActionsShow: actionMessage => dispatch(errorActionsShow(actionMessage)), - toggleReactionPicker: message => dispatch(toggleReactionPicker(message)), - replyBroadcast: message => dispatch(replyBroadcast(message)) + replyBroadcast: message => dispatch(replyBroadcast(message)), + toggleReactionPicker: message => dispatch(toggleReactionPicker(message)) })) -export default class Message extends React.Component { +export default class MessageContainer extends React.Component { static propTypes = { - status: PropTypes.any, item: PropTypes.object.isRequired, reactions: PropTypes.any.isRequired, - Message_TimeFormat: PropTypes.string.isRequired, - Message_GroupingPeriod: PropTypes.number.isRequired, - customTimeFormat: PropTypes.string, - message: PropTypes.object.isRequired, user: PropTypes.shape({ id: PropTypes.string.isRequired, username: PropTypes.string.isRequired, token: PropTypes.string.isRequired }), - editing: PropTypes.bool, - errorActionsShow: PropTypes.func, - toggleReactionPicker: PropTypes.func, - replyBroadcast: PropTypes.func, - onReactionPress: PropTypes.func, + customTimeFormat: PropTypes.string, style: ViewPropTypes.style, - onLongPress: PropTypes.func, - _updatedAt: PropTypes.instanceOf(Date), + status: PropTypes.number, archived: PropTypes.bool, broadcast: PropTypes.bool, - previousItem: PropTypes.object + previousItem: PropTypes.object, + _updatedAt: PropTypes.instanceOf(Date), + // redux + baseUrl: PropTypes.string, + customEmojis: PropTypes.object, + editing: PropTypes.bool, + Message_GroupingPeriod: PropTypes.number, + Message_TimeFormat: PropTypes.string, + message: PropTypes.object, + useRealName: PropTypes.bool, + // methods - props + onLongPress: PropTypes.func, + onReactionPress: PropTypes.func, + // methods - redux + errorActionsShow: PropTypes.func, + replyBroadcast: PropTypes.func, + toggleReactionPicker: PropTypes.func } static defaultProps = { @@ -127,7 +63,7 @@ export default class Message extends React.Component { constructor(props) { super(props); this.state = { reactionsModal: false }; - this.onClose = this.onClose.bind(this); + this.closeReactions = this.closeReactions.bind(this); } shouldComponentUpdate(nextProps, nextState) { @@ -147,12 +83,12 @@ export default class Message extends React.Component { if (this.props.broadcast !== nextProps.broadcast) { return true; } + if (this.props.editing !== nextProps.editing) { + return true; + } return this.props._updatedAt.toGMTString() !== nextProps._updatedAt.toGMTString(); } - onPress = () => { - KeyboardUtils.dismiss(); - } onLongPress = () => { this.props.onLongPress(this.parseMessage()); @@ -165,10 +101,9 @@ export default class Message extends React.Component { onReactionPress = (emoji) => { this.props.onReactionPress(emoji, this.props.item._id); } - onClose() { - this.setState({ reactionsModal: false }); - } - onReactionLongPress() { + + + onReactionLongPress = () => { this.setState({ reactionsModal: true }); Vibration.vibrate(50); } @@ -178,29 +113,12 @@ export default class Message extends React.Component { return customTimeFormat || Message_TimeFormat; } - parseMessage = () => JSON.parse(JSON.stringify(this.props.item)); - - isInfoMessage() { - return SYSTEM_MESSAGES.includes(this.props.item.t); + closeReactions = () => { + this.setState({ reactionsModal: false }); } - isOwn = () => this.props.item.u && this.props.item.u._id === this.props.user.id; - - isDeleted() { - return this.props.item.t === 'rm'; - } - - isTemp() { - return this.props.item.status === messagesStatus.TEMP || this.props.item.status === messagesStatus.ERROR; - } - - hasError() { - return this.props.item.status === messagesStatus.ERROR; - } - - renderHeader = (username) => { + isHeader = () => { const { item, previousItem } = this.props; - if (previousItem && ( (previousItem.ts.toDateString() === item.ts.toDateString()) && (previousItem.u.username === item.u.username) && @@ -208,172 +126,61 @@ export default class Message extends React.Component { (previousItem.status === item.status) && (item.ts - previousItem.ts < this.props.Message_GroupingPeriod * 1000) )) { - return null; + return false; } - - return ( - - - - - ); + return true; } - renderContent() { - if (this.isInfoMessage()) { - return {getInfoMessage(this.props.item)}; - } - const { item } = this.props; - return ; + parseMessage = () => JSON.parse(JSON.stringify(this.props.item)); + + toggleReactionPicker = () => { + this.props.toggleReactionPicker(this.parseMessage()); } - renderAttachment() { - if (this.props.item.attachments.length === 0) { - return null; - } - - return this.props.item.attachments.map((file) => { - const { user } = this.props; - if (file.image_url) { - return ; - } - if (file.audio_url) { - return : null diff --git a/app/views/RoomView/Separator.js b/app/views/RoomView/Separator.js index efb5a1f42..c722809cb 100644 --- a/app/views/RoomView/Separator.js +++ b/app/views/RoomView/Separator.js @@ -9,51 +9,62 @@ const styles = StyleSheet.create({ flex: 1, flexDirection: 'row', alignItems: 'center', - marginVertical: 10 + marginBottom: 25, + marginTop: 15, + transform: [{ scaleY: -1 }] }, line: { - borderTopColor: '#eaeaea', - borderTopWidth: StyleSheet.hairlineWidth, + backgroundColor: '#9ea2a8', + height: 1, flex: 1 }, text: { - color: '#444444', - fontSize: 11, - paddingHorizontal: 10, - transform: [{ scaleY: -1 }] + color: '#9ea2a8', + fontSize: 14, + fontWeight: '600' }, unreadLine: { - borderTopColor: 'red' + backgroundColor: '#f5455c' }, unreadText: { - color: 'red' + color: '#f5455c' + }, + marginLeft: { + marginLeft: 10 + }, + marginRight: { + marginRight: 10 + }, + marginHorizontal: { + marginHorizontal: 10 } }); const DateSeparator = ({ ts, unread }) => { - const date = ts ? moment(ts).format('MMMM DD, YYYY') : null; + const date = ts ? moment(ts).format('MMM DD, YYYY') : null; if (ts && unread) { return ( - {date} - - {I18n.t('unread_messages')} + {date} + + {I18n.t('unread_messages')} ); } if (ts) { return ( - - {date} - + + {date} + ); } return ( - - {I18n.t('unread_messages')} + + {I18n.t('unread_messages')} + ); }; diff --git a/app/views/RoomView/index.js b/app/views/RoomView/index.js index b739e9389..f2d01a3e9 100644 --- a/app/views/RoomView/index.js +++ b/app/views/RoomView/index.js @@ -232,15 +232,15 @@ export default class RoomView extends LoggedView { ); @@ -273,7 +273,7 @@ export default class RoomView extends LoggedView { renderHeader = () => { if (!this.state.end) { - return {I18n.t('Loading_messages_ellipsis')}; + return ; } return null; } diff --git a/app/views/RoomView/styles.js b/app/views/RoomView/styles.js index ab37be0c4..aea3eff45 100644 --- a/app/views/RoomView/styles.js +++ b/app/views/RoomView/styles.js @@ -46,7 +46,8 @@ export default StyleSheet.create({ flexDirection: 'column' }, loading: { - flex: 1 + flex: 1, + marginVertical: 15 }, imageBackground: { width: '100%', diff --git a/app/views/RoomsListView/Header/Header.ios.js b/app/views/RoomsListView/Header/Header.ios.js index 4ae44bc11..34a7e3aab 100644 --- a/app/views/RoomsListView/Header/Header.ios.js +++ b/app/views/RoomsListView/Header/Header.ios.js @@ -7,7 +7,8 @@ import I18n from '../../../i18n'; const styles = StyleSheet.create({ container: { flex: 1, - alignItems: 'center' + alignItems: 'center', + justifyContent: 'center' }, button: { flexDirection: 'row' diff --git a/app/views/RoomsListView/index.js b/app/views/RoomsListView/index.js index 1df2dc90d..3978abd88 100644 --- a/app/views/RoomsListView/index.js +++ b/app/views/RoomsListView/index.js @@ -43,7 +43,7 @@ if (Platform.OS === 'android') { @connect(state => ({ userId: state.login.user && state.login.user.id, server: state.server.server, - Site_Url: state.settings.Site_Url, + baseUrl: state.settings.baseUrl || state.server ? state.server.server : '', searchText: state.rooms.searchText, loadingServer: state.server.loading, showServerDropdown: state.rooms.showServerDropdown, @@ -51,7 +51,8 @@ if (Platform.OS === 'android') { sortBy: state.sortPreferences.sortBy, groupByType: state.sortPreferences.groupByType, showFavorites: state.sortPreferences.showFavorites, - showUnread: state.sortPreferences.showUnread + showUnread: state.sortPreferences.showUnread, + useRealName: state.settings.UI_Use_Real_Name }), dispatch => ({ toggleSortDropdown: () => dispatch(toggleSortDropdown()) })) @@ -72,7 +73,7 @@ export default class RoomsListView extends LoggedView { static propTypes = { navigator: PropTypes.object, userId: PropTypes.string, - Site_Url: PropTypes.string, + baseUrl: PropTypes.string, server: PropTypes.string, searchText: PropTypes.string, loadingServer: PropTypes.bool, @@ -82,12 +83,14 @@ export default class RoomsListView extends LoggedView { groupByType: PropTypes.bool, showFavorites: PropTypes.bool, showUnread: PropTypes.bool, - toggleSortDropdown: PropTypes.func + toggleSortDropdown: PropTypes.func, + useRealName: PropTypes.bool } constructor(props) { super('RoomsListView', props); + this.data = []; this.state = { search: [], loading: true, @@ -396,18 +399,19 @@ export default class RoomsListView extends LoggedView { renderItem = ({ item }) => { const id = item.rid.replace(this.props.userId, '').trim(); + const { useRealName } = this.props; return ( this._onPressItem(item)} testID={`rooms-list-view-item-${ item.name }`} height={ROW_HEIGHT} @@ -417,6 +421,15 @@ export default class RoomsListView extends LoggedView { renderSeparator = () => ; renderSection = (data, header) => { + if (header === 'Unread' && !this.props.showUnread) { + return null; + } else if (header === 'Favorites' && !this.props.showFavorites) { + return null; + } else if (['Channels', 'Direct_Messages', 'Private_Groups', 'Livechat'].includes(header) && !this.props.groupByType) { + return null; + } else if (header === 'Chats' && this.props.groupByType) { + return null; + } if (data.length > 0) { return ( {}} onReactionPress={async(emoji) => { try { await RocketChat.setReaction(emoji, item._id); @@ -124,7 +122,7 @@ export default class SearchMessagesView extends LoggedView { placeholder={I18n.t('Search_Messages')} testID='search-message-view-input' /> - + ({ + baseUrl: state.settings.Site_Url || state.server ? state.server.server : '', users: state.selectedUsers.users, loading: state.selectedUsers.loading }), dispatch => ({ @@ -43,6 +44,7 @@ export default class SelectedUsersView extends LoggedView { navigator: PropTypes.object, rid: PropTypes.string, nextAction: PropTypes.string.isRequired, + baseUrl: PropTypes.string, addUser: PropTypes.func.isRequired, removeUser: PropTypes.func.isRequired, reset: PropTypes.func.isRequired, @@ -185,6 +187,7 @@ export default class SelectedUsersView extends LoggedView { username={item.name} onPress={() => this._onPressSelectedItem(item)} testID={`selected-user-${ item.name }`} + baseUrl={this.props.baseUrl} style={{ paddingRight: 15 }} /> ) @@ -211,6 +214,7 @@ export default class SelectedUsersView extends LoggedView { onPress={() => this._onPressItem(item._id, item)} testID={`select-users-view-item-${ item.name }`} icon={this.isChecked(username) ? 'check' : null} + baseUrl={this.props.baseUrl} style={style} /> ); diff --git a/app/views/SnippetedMessagesView/index.js b/app/views/SnippetedMessagesView/index.js index 7c4c897e2..442c5859f 100644 --- a/app/views/SnippetedMessagesView/index.js +++ b/app/views/SnippetedMessagesView/index.js @@ -17,8 +17,7 @@ import I18n from '../../i18n'; id: state.login.user && state.login.user.id, username: state.login.user && state.login.user.username, token: state.login.user && state.login.user.token - }, - baseUrl: state.settings.Site_Url || state.server ? state.server.server : '' + } }), dispatch => ({ openSnippetedMessages: (rid, limit) => dispatch(openSnippetedMessages(rid, limit)), closeSnippetedMessages: () => dispatch(closeSnippetedMessages()) @@ -30,7 +29,6 @@ export default class SnippetedMessagesView extends LoggedView { messages: PropTypes.array, ready: PropTypes.bool, user: PropTypes.object, - baseUrl: PropTypes.string, openSnippetedMessages: PropTypes.func, closeSnippetedMessages: PropTypes.func } @@ -87,9 +85,7 @@ export default class SnippetedMessagesView extends LoggedView { style={styles.message} reactions={item.reactions} user={this.props.user} - baseUrl={this.props.baseUrl} customTimeFormat='MMMM Do YYYY, h:mm:ss a' - onLongPress={() => {}} /> ); diff --git a/app/views/StarredMessagesView/index.js b/app/views/StarredMessagesView/index.js index 4e2c476b4..3fa214b8f 100644 --- a/app/views/StarredMessagesView/index.js +++ b/app/views/StarredMessagesView/index.js @@ -23,8 +23,7 @@ const options = [I18n.t('Unstar'), I18n.t('Cancel')]; id: state.login.user && state.login.user.id, username: state.login.user && state.login.user.username, token: state.login.user && state.login.user.token - }, - baseUrl: state.settings.Site_Url || state.server ? state.server.server : '' + } }), dispatch => ({ openStarredMessages: (rid, limit) => dispatch(openStarredMessages(rid, limit)), closeStarredMessages: () => dispatch(closeStarredMessages()), @@ -37,7 +36,6 @@ export default class StarredMessagesView extends LoggedView { messages: PropTypes.array, ready: PropTypes.bool, user: PropTypes.object, - baseUrl: PropTypes.string, openStarredMessages: PropTypes.func, closeStarredMessages: PropTypes.func, toggleStarRequest: PropTypes.func @@ -113,7 +111,6 @@ export default class StarredMessagesView extends LoggedView { style={styles.message} reactions={item.reactions} user={this.props.user} - baseUrl={this.props.baseUrl} customTimeFormat='MMMM Do YYYY, h:mm:ss a' onLongPress={this.onLongPress} /> diff --git a/e2e/05-roomslist.spec.js b/e2e/05-roomslist.spec.js index 309ebf87d..87537f9fb 100644 --- a/e2e/05-roomslist.spec.js +++ b/e2e/05-roomslist.spec.js @@ -16,7 +16,7 @@ describe('Rooms list screen', () => { // }); it('should have room item', async() => { - await expect(element(by.id('rooms-list-view-item-general'))).toExist(); + await expect(element(by.id('rooms-list-view-item-general')).atIndex(0)).toExist(); }); // Render - Header diff --git a/e2e/06-createroom.spec.js b/e2e/06-createroom.spec.js index dc056586b..897bfc16a 100644 --- a/e2e/06-createroom.spec.js +++ b/e2e/06-createroom.spec.js @@ -88,8 +88,8 @@ describe('Create room screen', () => { it('should navigate to create channel view', async() => { await element(by.id('selected-users-view-submit')).tap(); - await waitFor(element(by.id('create-channel-view'))).toBeVisible().withTimeout(5000); - await expect(element(by.id('create-channel-view'))).toBeVisible(); + await waitFor(element(by.id('create-channel-view'))).toExist().withTimeout(5000); + await expect(element(by.id('create-channel-view'))).toExist(); }); }) @@ -145,6 +145,7 @@ describe('Create room screen', () => { await expect(element(by.text(`private${ data.random }`))).toBeVisible(); await tapBack(2); await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(2000); + await element(by.id('rooms-list-view-search')).replaceText(`private${ data.random }`); await waitFor(element(by.id(`rooms-list-view-item-private${ data.random }`))).toBeVisible().withTimeout(60000); await expect(element(by.id(`rooms-list-view-item-private${ data.random }`))).toBeVisible(); }); diff --git a/e2e/07-room.spec.js b/e2e/07-room.spec.js index 69a726837..09cd43dab 100644 --- a/e2e/07-room.spec.js +++ b/e2e/07-room.spec.js @@ -9,10 +9,11 @@ async function mockMessage(message) { await element(by.id('messagebox-input')).tap(); await element(by.id('messagebox-input')).typeText(`${ data.random }${ message }`); await element(by.id('messagebox-send-message')).tap(); - await waitFor(element(by.text(`${ data.random }${ message }`))).toBeVisible().withTimeout(60000); + await waitFor(element(by.text(`${ data.random }${ message }`))).toExist().withTimeout(60000); }; async function navigateToRoom() { + await element(by.id('rooms-list-view-search')).replaceText(`private${ data.random }`); await waitFor(element(by.id(`rooms-list-view-item-private${ data.random }`))).toBeVisible().withTimeout(60000); await element(by.id(`rooms-list-view-item-private${ data.random }`)).tap(); await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(5000); @@ -92,8 +93,7 @@ describe('Room screen', () => { describe('Messagebox', async() => { it('should send message', async() => { await mockMessage('message'); - await waitFor(element(by.text(`${ data.random }message`))).toBeVisible().withTimeout(60000); - await expect(element(by.text(`${ data.random }message`))).toBeVisible(); + await expect(element(by.text(`${ data.random }message`))).toExist(); }); it('should show/hide emoji keyboard', async() => { @@ -139,9 +139,9 @@ describe('Room screen', () => { await element(by.id(`mention-item-${ data.user }`)).tap(); await expect(element(by.id('messagebox-input'))).toHaveText(`@${ data.user } `); await element(by.id('messagebox-input')).tap(); - await element(by.id('messagebox-input')).typeText('test'); + await element(by.id('messagebox-input')).typeText(`${ data.random }mention`); await element(by.id('messagebox-send-message')).tap(); - await waitFor(element(by.text(`@${ data.user } test`))).toBeVisible().withTimeout(60000); + await waitFor(element(by.text(`@${ data.user } ${ data.random }mention`))).toBeVisible().withTimeout(60000); }); it('should show and tap on room autocomplete', async() => { @@ -250,8 +250,8 @@ describe('Room screen', () => { await element(by.text('Edit')).tap(); await element(by.id('messagebox-input')).typeText('ed'); await element(by.id('messagebox-send-message')).tap(); - await waitFor(element(by.text(`${ data.random }edited`))).toBeVisible().withTimeout(60000); - await expect(element(by.text(`${ data.random }edited`))).toBeVisible(); + await waitFor(element(by.text(`${ data.random }edited (edited)`))).toBeVisible().withTimeout(60000); + await expect(element(by.text(`${ data.random }edited (edited)`))).toBeVisible(); }); it('should quote message', async() => { @@ -266,13 +266,15 @@ describe('Room screen', () => { }); it('should pin message', async() => { - await element(by.text(`${ data.random }edited`)).longPress(); + await waitFor(element(by.text(`${ data.random }edited (edited)`))).toBeVisible().whileElement(by.id('room-view-messages')).scroll(200, 'up'); + await element(by.text(`${ data.random }edited (edited)`)).longPress(); await waitFor(element(by.text('Message actions'))).toBeVisible().withTimeout(5000); await expect(element(by.text('Message actions'))).toBeVisible(); await element(by.text('Pin')).tap(); await waitFor(element(by.text('Message actions'))).toBeNotVisible().withTimeout(5000); - await waitFor(element(by.text(`${ data.random }edited`)).atIndex(1)).toBeVisible().withTimeout(60000); - await element(by.text(`${ data.random }edited`)).atIndex(0).longPress(); + await waitFor(element(by.text(`${ data.random }edited (edited)`))).toBeVisible().whileElement(by.id('room-view-messages')).scroll(200, 'up'); + await waitFor(element(by.text(`${ data.random }edited (edited)`)).atIndex(1)).toBeVisible().withTimeout(60000); + await element(by.text(`${ data.random }edited (edited)`)).atIndex(0).longPress(); await waitFor(element(by.text('Unpin'))).toBeVisible().withTimeout(2000); await expect(element(by.text('Unpin'))).toBeVisible(); await element(by.text('Cancel')).tap(); diff --git a/e2e/08-roomactions.spec.js b/e2e/08-roomactions.spec.js index a6b939e48..a15ca65e0 100644 --- a/e2e/08-roomactions.spec.js +++ b/e2e/08-roomactions.spec.js @@ -14,7 +14,7 @@ async function navigateToRoomActions(type) { } else { room = `private${ data.random }`; } - await waitFor(element(by.id(`rooms-list-view-item-${ room }`))).toBeVisible().withTimeout(2000); + await waitFor(element(by.id(`rooms-list-view-item-${ room }`))).toExist().withTimeout(2000); await element(by.id(`rooms-list-view-item-${ room }`)).tap(); await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(2000); await element(by.id('room-view-header-actions')).tap(); @@ -210,8 +210,9 @@ describe('Room actions screen', () => { it('should show mentioned messages', async() => { await element(by.id('room-actions-mentioned')).tap(); await waitFor(element(by.id('mentioned-messages-view'))).toExist().withTimeout(2000); - await waitFor(element(by.text(`@${ data.user } test`).withAncestor(by.id('mentioned-messages-view')))).toBeVisible().withTimeout(60000); - await expect(element(by.text(`@${ data.user } test`).withAncestor(by.id('mentioned-messages-view')))).toBeVisible(); + await expect(element(by.id('mentioned-messages-view'))).toExist(); + // await waitFor(element(by.text(` ${ data.random }mention`))).toBeVisible().withTimeout(60000); + // await expect(element(by.text(` ${ data.random }mention`))).toBeVisible(); await backToActions(); }); @@ -233,14 +234,14 @@ describe('Room actions screen', () => { await waitFor(element(by.id('room-actions-pinned'))).toBeVisible().whileElement(by.id('room-actions-list')).scroll(scrollDown, 'down'); await element(by.id('room-actions-pinned')).tap(); await waitFor(element(by.id('pinned-messages-view'))).toExist().withTimeout(2000); - await waitFor(element(by.text(`${ data.random }edited`).withAncestor(by.id('pinned-messages-view'))).atIndex(0)).toBeVisible().withTimeout(60000); - await expect(element(by.text(`${ data.random }edited`).withAncestor(by.id('pinned-messages-view')))).toBeVisible(); - await element(by.text(`${ data.random }edited`).withAncestor(by.id('pinned-messages-view'))).longPress(); + await waitFor(element(by.text(`${ data.random }edited (edited)`).withAncestor(by.id('pinned-messages-view'))).atIndex(0)).toBeVisible().withTimeout(60000); + await expect(element(by.text(`${ data.random }edited (edited)`).withAncestor(by.id('pinned-messages-view')))).toBeVisible(); + await element(by.text(`${ data.random }edited (edited)`).withAncestor(by.id('pinned-messages-view'))).longPress(); await waitFor(element(by.text('Unpin'))).toBeVisible().withTimeout(2000); await expect(element(by.text('Unpin'))).toBeVisible(); await element(by.text('Unpin')).tap(); - await waitFor(element(by.text(`${ data.random }edited`).withAncestor(by.id('pinned-messages-view'))).atIndex(0)).toBeNotVisible().withTimeout(60000); - await expect(element(by.text(`${ data.random }edited`).withAncestor(by.id('pinned-messages-view')))).toBeNotVisible(); + await waitFor(element(by.text(`${ data.random }edited (edited)`).withAncestor(by.id('pinned-messages-view'))).atIndex(0)).toBeNotVisible().withTimeout(60000); + await expect(element(by.text(`${ data.random }edited (edited)`).withAncestor(by.id('pinned-messages-view')))).toBeNotVisible(); await backToActions(); }); diff --git a/e2e/09-roominfo.spec.js b/e2e/09-roominfo.spec.js index 0638d0123..4d22f0d76 100644 --- a/e2e/09-roominfo.spec.js +++ b/e2e/09-roominfo.spec.js @@ -12,6 +12,7 @@ async function navigateToRoomInfo(type) { } else { room = `private${ data.random }`; } + await element(by.id('rooms-list-view-search')).replaceText(room); await waitFor(element(by.id(`rooms-list-view-item-${ room }`))).toBeVisible().withTimeout(2000); await element(by.id(`rooms-list-view-item-${ room }`)).tap(); await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(2000); @@ -310,6 +311,7 @@ describe('Room info screen', () => { await expect(element(by.text('Yes, delete it!'))).toBeVisible(); await element(by.text('Yes, delete it!')).tap(); await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(2000); + await element(by.id('rooms-list-view-search')).replaceText(''); await waitFor(element(by.id(`rooms-list-view-item-${ room }`))).toBeNotVisible().withTimeout(60000); await expect(element(by.id(`rooms-list-view-item-${ room }`))).toBeNotVisible(); }); diff --git a/e2e/11-broadcast.spec.js b/e2e/11-broadcast.spec.js index 582cb8935..de4383c4b 100644 --- a/e2e/11-broadcast.spec.js +++ b/e2e/11-broadcast.spec.js @@ -36,14 +36,14 @@ describe('Broadcast room', () => { await waitFor(element(by.id('room-actions-view'))).toBeVisible().withTimeout(2000); await tapBack(); await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(2000); - await tapBack(2); - await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(2000); - await waitFor(element(by.id(`rooms-list-view-item-broadcast${ data.random }`))).toExist().withTimeout(60000); - await expect(element(by.id(`rooms-list-view-item-broadcast${ data.random }`))).toExist(); + // await tapBack(2); + // await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(2000); + // await waitFor(element(by.id(`rooms-list-view-item-broadcast${ data.random }`))).toExist().withTimeout(60000); + // await expect(element(by.id(`rooms-list-view-item-broadcast${ data.random }`))).toExist(); }); it('should send message', async() => { - await element(by.id(`rooms-list-view-item-broadcast${ data.random }`)).tap(); + // await element(by.id(`rooms-list-view-item-broadcast${ data.random }`)).tap(); await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(5000); await element(by.id('messagebox-input')).tap(); await element(by.id('messagebox-input')).typeText(`${ data.random }message`); diff --git a/e2e/data.js b/e2e/data.js index 19257a80f..8cdd99e0e 100644 --- a/e2e/data.js +++ b/e2e/data.js @@ -2,7 +2,7 @@ const random = require('./helpers/random'); const value = random(20); const data = { server: 'https://stable.rocket.chat', - alternateServer: 'https://open.rocket.chat', + alternateServer: 'https://unstable.rocket.chat', user: `user${ value }`, password: `password${ value }`, alternateUser: 'detox', diff --git a/ios/RocketChatRN/Images.xcassets/Icons/pause.imageset/Contents.json b/ios/RocketChatRN/Images.xcassets/Icons/pause.imageset/Contents.json new file mode 100644 index 000000000..ecf2c0cd8 --- /dev/null +++ b/ios/RocketChatRN/Images.xcassets/Icons/pause.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "pause.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "pause@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "pause@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ios/RocketChatRN/Images.xcassets/Icons/pause.imageset/pause.png b/ios/RocketChatRN/Images.xcassets/Icons/pause.imageset/pause.png new file mode 100644 index 0000000000000000000000000000000000000000..b13411a50e64b304e355df0b5cdeb3e6667c1ce3 GIT binary patch literal 687 zcmV;g0#N;lP)t%1^gCfG^>i(-h zWcB|+;Z;iT0blSL$LScbptZ(F)pK#f^Yoc{Wpk;@3YW~ZlK>-7w@ZG|+ zsvU8-r+B@i6T>{~_S^#F^fvbzKhC$O!~9{c=Ozj_aoX*xwpV7r>Ah4Wx_`say^5g= zxl<6dF@`zV^cOvFxSlF(lf$0BJ?NgUzsS?I$?!<5ZXDCIl|zg1cJ3n0-W{{;Kf3`v zSUmIUS{r@EJM$C8t6@eOA~`rvtiC?kJ{leEsEtMG@q+-71&vLEJq$)U1WeP)y`#kG z_O1CIn}&p+woGLToOZNYyhso+>S?MXLfe@DYm{4tlsTjtF2I;J4CqSQz>4|VfFmJ| z4FX3xbn<(*T~;aDj@mfexV9-X#3Y)o`ZcYYuj5A1J_^9CD~6hi|E(U-Q8S!Hk+@wl zl+)Al{ck}3{OGFgwvvH`U(3ZMn{+cPi?%*0G3)++$&P^hIp&G$WChGXCl*~lX${|w zeZco=ebbKaGncadtH3tvoun5s)K=6Zr=q<7yeMmClG*7h-@j&hwx_20 zYd-oTsmpX%y{h+qUENjH)&JpaOzFs+s@}PK|0w6`2$OP3aX!Tv+pCz`%^BYfw{*No z$D4|=+gzzNCd8Uj{Mw#fJ65jE@%lJIqZme)o}N>Cw*G6JVw}B2txhYY%7e7dId4+E zRk|YIOgvKg`j0t&XOMPmbw&bw@O^o$lX9!^IrZjATccyo z<9ta>RA$yc;eRFdl^A&P{JqzdbeEK3k0y0CN_)=Pzg##c*Dvn;K1sVGiSguYeMU-o zC2Ls3j2I9LVoJggtA`IQsvXUZ`WG~PoKDhsTDAmnxxByn&W$ttew5Eh;6v}L$D6Ij zcQnPk5Y7V!?LA5 zE;OAbc$2By!w1eaj=4%+wbV(JRdyJA^LdBudu;n!Hd~4F_?zYEup? zm%8DwTmMM*?Qbq?x|RwFvm7pt-@H`$3Dvsqu9C^K3EQ!nFPab~G-3{2O&@b=9wX18te3-h}k^qEWG!yb{ zu&@hi%WNa+9Bg2Ood(w1G9%il@ZXkZAht4Fo>wod%(IF0OKh5vjN1=ddk-pB-NG7m z7zK7031YgiAn^mA25SjhsWeLuw7VGJSN4|JK?SSO`^MSFlS%|&71$(C#akYn5Uao! zfjq>LMhsvTG~Mq_!&x4DfK}jIPac9vBL=Wi54S&TrQtAZA7I^H;b$F9O8#+6Z>Hoc zb2nhcE&b2{gOz%i-Ol{drxXBKh5quMlEbXsfK@4u!@daW_7&oa?$!KSlbH^Qp@Bbq;Uq(Vbs8o1~F30jKUwbWP_5e%$DcX z4=eL*V*L`EW+Y<`3>_4tL9r@F82xzNzLDH=+k4Yyb?jH8%$9=Mve|~^fz8u;bvJ{d zwQ9Li@7;z~jw;LJMtsQ;$2^T!7Z@P>&(?pT^=2xXtEdY%s&ZORu52t+U-a7Rd0XOw zf9MrFD8CT0`B{2^*XJwCGO@1I8C~ zDBP%qG>r>$PO)p1o<*A22Mj1^Bj`nWwlIK3porb3?|@m)C~efEQTy(fG((;?^YeU8 zK$kZbcD)@GqqT=UW61fSaP!Xd{;Sn^6mwXdp}^2CLe5tNXblVLVT9f?6c|?u+Qsry zl^Sl9uq&5k8Dc|>Q94V+NVf5lmJcg7pBup%1ZWtb=Bs`3q#&w9z-Z*55{LsB!#yX3 zTc#^AT0tR(ps5FO2BpM3>~9D{Ht3+zdf~u}Kqi0k@I&Jm8ZStL#`!lM+Fo7ov{t77 zB4nL|dh00000NkvXXu0mjflby~w literal 0 HcmV?d00001 diff --git a/ios/RocketChatRN/Images.xcassets/Icons/pause.imageset/pause@3x.png b/ios/RocketChatRN/Images.xcassets/Icons/pause.imageset/pause@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..e2ba5b563e7bf0f7cb7945b0cd17b85d55e36eaf GIT binary patch literal 2181 zcmV;02zvL4P)lsaQCguz{3vYD*ccFMi>66-W0K8W&;L#* zot>GTotfRc-QBtKkeRt3=iKv~n{)5X-Z{fr3vHX;5?vExbA#pig+Y_?LC(xUCioh` z#Zu1r62Zh0?9pU8o}%L^xflFA<6=}WqhK&mNOz?Q%Lcj&C!XQ+tzsU(lnu$}h4D_Q zw9#PvE>noR3F_^HFxQwi@gl+h*5Le0lZmgM%4SdI^W1EV?C4T13FxbzFK%LG{v`F( zZPYbaMsIeE8l0Wwf*)pS@$R3m|kFuyZ_fb|3{@- zWuQ0g6S;{qrQL$@9pra=RT@#hY(CAIIJj(8cF#|{$hRxllz<)>Ds44Qwx0m^D`>Mq zk$l`R*v_%x?2$$*X(;GxcFzoy=gc>0fV;oZ4Q;AC&W@(Ljc5PZlNoE2-iCo*Jyd*{ zdhwxF^TTmL5ts?;-P=zO=RS@r!&$Fx&@|X}PZei|X*ThkQ*fso)9mEHl3Zqp2Ftm6 zY^n?Ny1ZC1Gd=SO`Qpv>G@|wE^5dD_%!4C&elBiXV}q9dcvgH)kk`dk-cI$XXBSf4 z{Jyw;+lXWAwJ*%xurMdSPYPr(BG)(wn_+t#W|4a|6wS|u}Eg?dnS3 z@%yVizeKSm5@@&!TvfWdS4L6NX=TZc{6%i$)+lZywCljYS0!R0O^Hd}1m>E832J{os?3nu%> zTUDpn1X2cjq}Cl|AZR)G&6+=U%5Aj`rqO$XIFafxZVVb616>Cm5NXJ@FAEsShiL&t ztAfU(&bEIF7hrh9v*?MXWL8D6FK9fpx1J|gsil*B34j^c`DOZo#xEl@%V@KQ_I~Cy zJ5BUk?7VtCgQ5J5Z+d2oK)3kMPhMkMBZW`*^=1a#zd?F>G=50ckn6c*qSsAmUqv%y3n%{*?CXNb-aA&NTi(h>yU*xB4}0R4G}}V* z`Y!XzIx{KQhbPKXp1ZD!b85jvcW-vUxs)O8R3z73G-*k|){QB)e_M}Jz32Ge^^9$} z%3!-b2>x+n__1#G_{|ljcw{|vQ=08OJj;%pT=3*IIsqLOEJ^Mgw(JVmLHF<5?F`lX z9rtvFQUQQh$klfK#gSJFvRyN*PP=?PdpFBP&{(ELSE6Yvh}Nw1{)<;LZ1sx8W_pSQ z<+%$-(dn)m^&Bka(zgp0FIqrr;i3wwr#wB=4PD&`C>oUKRuDy}yKby=2U7_et2*U^ z!&uUErD_Dg6l{?%|6u8C(^hp>YgH$v(@I&%)&`CB$(?9tE7)YSl|5Q60&j&@bzmE8 zwgz5juvXf4pp~s)61~L$#s=OQp<8a>Cr+)<&h~EuEng5HK)wcdgiAFGwFJPJT!-~0s#;aamJY@SUi(cp z2KCm1vF_38IWyU#o1jOlAOdh5Q<{WY0$>c+p+T$V4A(KGd$eN65O4Kp1QpSnQUVmd z;ygW<7NbhFXyFWu$#ob7%|a~!8G?u&c4*LQInxibqF^Al=Kt;HP_vP_Yh#EV5ZI6$zL8&F)h#1l~j05SI#K_mDc z-6x(^q${~%iK%2u1Z0m!ghLs8FS$sRSPrIk^hgO>YM}^+O0-oGO6!NKoMquTiYo!K) zMvNeY_6-uC^Jt(WMnUnEz$g$j3LyFw-Q^s>vEIA{z@}D&Fx09E8if!)nPwr!ajZ87 z0nU$EY#eD-4g&{6XB~uxq{xNe(YhNQ%~68kBNS8mwy-g!LxYBF9R$|udgLzD1%ZVM zIQ+Dcx*wr^EtSdpYlSsVMGn{<%11kKj=tXWGvX)Xsyfq?a15K{#Eu4=$e>XPL8=iy znFh!aoF`-BBd|GYfNq;jEYPS7H-f<+5wj7RUBK2_b7dQ<-##{I2*Zd=G2Y-tI(D87 z+xl{uEn#ODevpwCY1UCq2-5WjZ-VH=^wEAIad(8!zI5r1`sKG(8rc9_!rbwNwX0!0 z+Nn@~l*~!PIyP_33AC+7f3Dgl(d2z6e}Mge0E8+B$d1ot00000NkvXX Hu0mjf4#gSp literal 0 HcmV?d00001 diff --git a/ios/RocketChatRN/Images.xcassets/Icons/play.imageset/Contents.json b/ios/RocketChatRN/Images.xcassets/Icons/play.imageset/Contents.json new file mode 100644 index 000000000..db7ffa04f --- /dev/null +++ b/ios/RocketChatRN/Images.xcassets/Icons/play.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "play.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "play@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "play@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ios/RocketChatRN/Images.xcassets/Icons/play.imageset/play.png b/ios/RocketChatRN/Images.xcassets/Icons/play.imageset/play.png new file mode 100644 index 0000000000000000000000000000000000000000..b40c8f3cc4e66290ad63db5f4238e3a441e08ef1 GIT binary patch literal 740 zcmV% zWFbMI)keK>QHS~(X_}KMQ|%A4cg)B1nH85yp8GKfIK)6d;eLZNfp)`#`W@1GNfVvx zryGrl!98Mrrp|gVe+1l!`jcfUu)kcp9%_0)q^FaU?AlyaO!q5m<8S|^uaccwYxb89 z9*0_Q4i5^edKxxh3pSHDu?_>eQhzPw&7@+MHZ#AeJoRo#DJRyFn8!0Kwbi^q0Rx+` z-NrOU$K%$SVtYp?iup!#<^~wid%R!&p6yI+7R=SL32zqBZnoN7nW3ZC1~Af*fW!3^ zVUry8YrD4h)RCng{Wm>CK)t1G@m^_S{Cq1TStf@^R|@oX)uVe04i%kVqc%No5Lr-} zG-xwJbmn|TZh`5+;u+e0=+fm2W0o`HYQR+O+#4UUX!(g$_$JZ7agX%3k53QcIADr^1%RGY1$|`a^$*`6w_zO;xs(Q zdzwl99BEpAe@Iu?Q(wWDeOcTtE(L&RV=$Uly*O*xhkRn1e*wrIS9p z+Rxu11?5B97T|$}>5~Fov7Pv(8d9yP>G``R&960v0~IjA+!{D#B5G{{D9xEp$~44G zI8vHovOf!`u_ai*L{t-qnQTBc36g(Xc$mQwOc*!sqY$(Ff#McH{(yyE1B?oofebuB zeG~%Q5&MAsSb{q>vIiCjHkha9#?u7D?D4pJi$_i9V_V$~jQXkk!gMdf@UonL+WrDg WqZ(}B87U|L0000Rx*eXBZo0XG~|w`j4*+uWN6tc<#T zPKeXe7wVXPLtM7&%QkSs(WOU~mN=~xZL;gk$@)UjH6c9*rjG}|v}0G=soc=L*r93K znNq_dX2gJ45R)B-oO*cMyDAW!Sv<#_Jy~bCnsq=h#6F+!{SEi<1}W2rY)t18()Y#kcev|raBc}^mt`!^4vS6 zhqbtRy`t$Xf;Tg*0XKF<_7v-_$09D*PJsz*hJ!U=jkHeVkv+2NCsnB2E9VX=` zCDrPSISw1PX%1{)L^B;&UzTxrrD9Wv=$q$*^ixlmM!SQw_pY^MvKg)e)tOCaG=Nvv zpd7G#-NfVfc&WK=1@ev>NrQ)ibnD$gA9clAXz}c0rT*7YwtHe@jzN?G5crn)r`UD+$*hgo(g4DLdW4`QK8H`|+`ns`e zZZaFL-y%8112p(dfEu=@XG7+e`CkF6#3FhACJJx4ce_VV^Ui%mNONYD_##kv*o9dL zcm*AP$VVgmG~ai(dua|<$;nh#Sh&u$zHPIl58DIu@v{MHy2<%82dm_%R~bwVQg7Ox zW)BT_1nH?=&OXY)%00aDVJp>T=}Uf2^WObFst!6A3s_4y{c#S&jwPh@yqyNcsvC_f zdg-$$%`Z9U5v-gz_&%$)I%l?UOXnsN)bn|irvBn3IR`hedfDU^w%O>Q-MmfxepRDa zzlhP-za;Xuk*y(Ez4-FZ2lr;H==QZ`PTv!waeD7;jF#i>c>}8#G6SA%x#wja%im2T z=#`-;P5RbSq7O#m z^!|vu>1zgtZls1;<*Hg{++3m1@+`DDrfv8_oF437qIZUi3%eS|I9OLE9;}uz#a3|f z%+GO}_;cmiFg2&q!IMjL=%Xn8b~XJ*6znV)1FMYs3>^zx(S^t#yj<_-xhFMUQb|qwFDMOJ+#{p6&~c5R1N&D^&C` zvm}2x1WO9Aeu5Ql_?TSLpd36Hpw=^UqygiLITUW(qI45%bCh<=9J{X4vydjH0mC-5 z5xn-(ZP!n^)JN=A`VPdG@{~3QT;I7c$U|wn`FuH-8R*o^K-IxaF<(5&aA-DE<(;%3D7z$q=)P1EwcjSPC>iqzdh87RLOSdN_h>jA;$G|mWYw- z=Dz9jVMTpqBUpm~4G*ZkaGE?R6O}Ds82Mib!~u-Qy9nZZ#m*T3TZ2UhM`n86bASpWb407*qoM6N<$f&+3O`Tzg` literal 0 HcmV?d00001 diff --git a/ios/RocketChatRN/Images.xcassets/Icons/play.imageset/play@3x.png b/ios/RocketChatRN/Images.xcassets/Icons/play.imageset/play@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..2e60e189ac1ccc657a8e686cf3d1cc3ed543dc4e GIT binary patch literal 2485 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 literal 0 HcmV?d00001 diff --git a/ios/RocketChatRN/Images.xcassets/Icons/play_video.imageset/Contents.json b/ios/RocketChatRN/Images.xcassets/Icons/play_video.imageset/Contents.json new file mode 100644 index 000000000..fe5012b98 --- /dev/null +++ b/ios/RocketChatRN/Images.xcassets/Icons/play_video.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "play_video@1x.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "play_video@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "play_video@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ios/RocketChatRN/Images.xcassets/Icons/play_video.imageset/play_video@1x.png b/ios/RocketChatRN/Images.xcassets/Icons/play_video.imageset/play_video@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..83fc41316fd1f5b1582c34f1f63a06ceebb884af GIT binary patch literal 1132 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 LNkvXXu0mjf8v9a+ literal 0 HcmV?d00001 diff --git a/ios/RocketChatRN/Images.xcassets/Icons/play_video.imageset/play_video@3x.png b/ios/RocketChatRN/Images.xcassets/Icons/play_video.imageset/play_video@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..def52c709483c30ed4256b94de54dcab466a4f47 GIT binary patch literal 4656 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

b0BR4=-Lsta#w_l+^ zhn|RfAV5lf5rNNJla$mU&?=}Oq!UJLf|7XD^&lTlL|24V6cLRx3S!nFji-ZnjeCHm z{jp`bm%`iccR^b;-HI*0(8TnLl!_*z)r^Cnd^NM4nDsd3Vko6Obo)%BaM6&`!@7N@ m9fYQd2g2EYwJ++2TK)$XN*|ST7Ey`-000071Q{00004XF*Lt006O% z3;baP00032Nklpm*;$&NcGL7$c>^V})Z^pjG6d z@MKc65d%!uKs(_`eG1bAX-hs!tUpcbG>%YT8_Xjk=>EeXC(%uV1kWZqYwu&qilQy( zMgvs}C<_}nfS04|`+bb~JABcEAz{>lH cim~R|9jJo?*%p#mfB*mh07*qoM6N<$f|lZl3IG5A literal 0 HcmV?d00001 diff --git a/ios/RocketChatRN/Images.xcassets/Icons/reply.imageset/reply_icon@3x.png b/ios/RocketChatRN/Images.xcassets/Icons/reply.imageset/reply_icon@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..5ceef53aad17a5b20d371ad1c839559cbe8df0f0 GIT binary patch literal 436 zcmV;l0ZaagP)=q>9+Tw!+%P9HFSS~kJ-IXdkAZP4#l(6iv3DVXhJWEQ3YiD1Xl(h8-&ytei z+Symeu4E>-0?G1%UrO%Sg8a*=9V?YNZ@92LW?A-G4%(q4TdMZX^pOEQA&|tUr0LOG z&lxPIvatY|SDzE#N+Cj9!8BNd3LNA)ix2jm`UBpCoib#IPx0+PhbL>ez~VleSdB+c z0Jw7?UMnMMP=|%#$^reZfJ#9dmiYq*wD5vz!yW{x341W87Hklx25c~B)3AR6Z4%Z8 zT7H=XWFO-uIeqRI?1S0`r=8_K_o(Y(Mwg!Jy1v?dfyIq22x2_cY@P!+fsGr|NDgS< e#A*F+3j6@2vg%y4Fb~oI0000JP)Ptp`f9nNf9{} z21I3wfRLTW7Df6<5e)?>f^>9gi1G(4uuXxbG>OFdqL8~`-o@)|EEkbiTJLsBx9^%98M0BE0P4eOG~eXH7=-es<;+{E$g&e{`Jerg)}N^^K?;LN_ec9wWW;QcOuz6SSH6@pLfp z`Fn|v(?I?4#>e(4jMh?JWR93`tDNdW-ge3;WkSg&i+nW~f~SoV@7n}}&g;caMHwyr zt^^mY-=HSAj%IA1Cy5R0KMe}otx3T$$ri&+Yzyw!$NY)+qrRE7ew=>V9hL*sr0IG@ z$-B$Z>+g6^UD&5fzxE~jJp6HL8BQANLE=+NUbw5=`P^$dLkE>7r4lti=YyVrcne}EOCN%mx` zn}^Jm8^JdsuB)RqRgz1M6>2NPRUMB9aV#6ykYR%l7+?`|5_^)$>@4y>k4-^abT#?g zS)YDGldW=4dzJ|<`^LM44H-80fB_aUh_#G*vxX5#h^u&*Iwl2oL{O9Nb!tdrNS2%B z%m3>qVlK-t^+2G^0=1c>^hSOuKvFf*w7s`1vPQ61D{?00kqi#+ZVWu Qwg3PC07*qoM6N<$f;Xxh-T(jq literal 0 HcmV?d00001 diff --git a/ios/RocketChatRN/Images.xcassets/add_reaction.imageset/add_reaction@2x.png b/ios/RocketChatRN/Images.xcassets/add_reaction.imageset/add_reaction@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..1c2825de8e244fc283780da1d576be7cb4dbd5c0 GIT binary patch literal 1350 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 APPL CFBundleShortVersionString - 1.1.1 + 1.2 CFBundleSignature ???? CFBundleURLTypes diff --git a/package.json b/package.json index ffc2fed13..f0f2ca9a6 100644 --- a/package.json +++ b/package.json @@ -104,7 +104,12 @@ "react-test-renderer": "^16.4.2", "reactotron-react-native": "^2.0.0", "reactotron-redux": "^2.0.0", - "reactotron-redux-saga": "^2.0.0" + "reactotron-redux-saga": "^2.0.0", + "@storybook/react-native": "^3.4.10", + "@storybook/addon-actions": "^3.4.10", + "@storybook/addon-links": "^3.4.10", + "@storybook/addons": "^3.4.10", + "babel-runtime": "^6.26.0" }, "jest": { "testPathIgnorePatterns": [ @@ -114,7 +119,8 @@ "coverageDirectory": "./coverage/", "collectCoverage": true, "moduleNameMapper": { - ".+\\.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$": "identity-obj-proxy" + ".+\\.(css|styl|less|sass|scss)$": "identity-obj-proxy", + ".+\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "/__mocks__/fileMock.js" }, "transform": { "^.+\\.js$": "/node_modules/react-native/jest/preprocessor.js" diff --git a/storybook/index.js b/storybook/index.js new file mode 100644 index 000000000..f0513c5a8 --- /dev/null +++ b/storybook/index.js @@ -0,0 +1,3 @@ +import StorybookUI from './storybook'; + +export default StorybookUI; diff --git a/storybook/stories/Avatar.js b/storybook/stories/Avatar.js index 2f0e0de66..45f5c4d6c 100644 --- a/storybook/stories/Avatar.js +++ b/storybook/stories/Avatar.js @@ -7,15 +7,15 @@ import Avatar from '../../app/containers/Avatar'; const reducers = combineReducers({ settings: () => ({}) }); const store = createStore(reducers); - +const baseUrl = 'baseUrl'; export default ( - - - - + + + + ); diff --git a/storybook/stories/Message.js b/storybook/stories/Message.js new file mode 100644 index 000000000..4984e088f --- /dev/null +++ b/storybook/stories/Message.js @@ -0,0 +1,428 @@ +import React from 'react'; +import { ScrollView, StyleSheet } from 'react-native'; + +import MessageComponent from '../../app/containers/message/Message'; +import StoriesSeparator from './StoriesSeparator'; +import messagesStatus from '../../app/constants/messagesStatus'; +import MessageSeparator from '../../app/views/RoomView/Separator'; + +const styles = StyleSheet.create({ + separator: { + transform: [{ scaleY: -1 }], + marginBottom: 30, + marginTop: 0 + } +}); + +const user = { + id: 'y8bd77ptZswPj3EW8', + username: 'diego.mello', + token: '79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz' +}; +const author = { + _id: 'userid', + username: 'diego.mello' +}; +const baseUrl = 'https://open.rocket.chat'; +const customEmojis = { react_rocket: 'png', nyan_rocket: 'png', marioparty: 'gif' }; +const date = new Date(2017, 10, 10, 10); + +const Message = props => ( + +); + +// eslint-disable-next-line react/prop-types +const Separator = ({ title }) => ; + +export default ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {}} + /> + + + {}} + /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + alert('broadcast!')} /> + + + + + + alert('Error pressed')} header={false} /> + alert('Error pressed')} /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +); diff --git a/storybook/stories/StoriesSeparator.js b/storybook/stories/StoriesSeparator.js new file mode 100644 index 000000000..3ab4cea79 --- /dev/null +++ b/storybook/stories/StoriesSeparator.js @@ -0,0 +1,21 @@ +import React from 'react'; +import { Text, StyleSheet } from 'react-native'; +import PropTypes from 'prop-types'; + +const styles = StyleSheet.create({ + separator: { + marginTop: 30, + marginLeft: 10, + fontSize: 20, + fontWeight: '300' + } +}); + +const Separator = ({ title, style }) => {title}; + +Separator.propTypes = { + title: PropTypes.string.isRequired, + style: PropTypes.object +}; + +export default Separator; diff --git a/storybook/stories/index.js b/storybook/stories/index.js index 09631e178..6454659c7 100644 --- a/storybook/stories/index.js +++ b/storybook/stories/index.js @@ -7,28 +7,15 @@ import { createStore, combineReducers } from 'redux'; import { storiesOf } from '@storybook/react-native'; -// import { action } from '@storybook/addon-actions'; -// import { linkTo } from '@storybook/addon-links'; import DirectMessage from './Channels/DirectMessage'; import Avatar from './Avatar'; +import Message from './Message'; const reducers = combineReducers({ settings: () => ({}), login: () => ({ user: {} }), meteor: () => ({ connected: true }) }); const store = createStore(reducers); storiesOf('Avatar', module).addDecorator(story => {story()}).add('avatar', () => Avatar); storiesOf('Channel Cell', module).addDecorator(story => {story()}).add('Direct Messages', () => DirectMessage); - -// storiesOf('Welcome', module).add('to Storybook', () => ); - -// storiesOf('Button', module) -// .addDecorator(getStory => ( -// -// {getStory()} -// -// )) -// .add('with text', () => ( -// -// )) +storiesOf('Message', module) + .add('list', () => Message); diff --git a/storybook/storybook.js b/storybook/storybook.js index 841d13edd..fc8fdc828 100644 --- a/storybook/storybook.js +++ b/storybook/storybook.js @@ -1,4 +1,5 @@ -import { AppRegistry } from 'react-native'; +import React, { Component } from 'react'; +import { Navigation } from 'react-native-navigation'; import { getStorybookUI, configure } from '@storybook/react-native'; // import stories @@ -8,7 +9,23 @@ configure(() => { // This assumes that storybook is running on the same host as your RN packager, // to set manually use, e.g. host: 'localhost' option -const StorybookUI = getStorybookUI({ port: 7007, onDeviceUI: true }); -AppRegistry.registerComponent('RocketChatRN', () => StorybookUI); +const StorybookUIRoot = getStorybookUI({ port: 7007, onDeviceUI: true }); -export default StorybookUI; +// react-native hot module loader must take in a Class - https://github.com/facebook/react-native/issues/10991 +// https://github.com/storybooks/storybook/issues/2081 +// eslint-disable-next-line react/prefer-stateless-function +class StorybookUIHMRRoot extends Component { + render() { + return ; + } +} + +Navigation.registerComponent('storybook.UI', () => StorybookUIHMRRoot); +Navigation.startSingleScreenApp({ + screen: { + screen: 'storybook.UI', + title: 'Storybook' + } +}); + +export default StorybookUIHMRRoot;