Compare commits

...

88 Commits

Author SHA1 Message Date
Gleidson Daniel Silva 4dfc9c70f3
[FIX] Keyboard not showing all emojis or showing cut emojis (#4919)
* fix the logic based on window width and make the keyboard dynamic

* fix var naming and math

* fix alignment of emojis

* add comment

* wip
2023-03-09 17:17:20 -03:00
Piyush Gupta 513e8ee636
[FIX] Increase border radius on MessageAvatar as small (#4837)
* fixed border radius of 4 on avatar

* fixed lint

* Update tests

---------

Co-authored-by: Diego Mello <diegolmello@gmail.com>
2023-03-08 15:34:39 -03:00
Mister-H aa57237004
[FIX] Order of quoted message done according to desktop version (#4739)
Co-authored-by: Diego Mello <diegolmello@gmail.com>
2023-03-08 11:20:01 -03:00
Diego Mello 58391964cb
[FIX] Message not rendering E2EE data if md exists (#4951) 2023-03-07 10:57:57 -03:00
Diego Mello 412f62eb2a
Chore: Update Detox to 20.1.2 (#4866) 2023-03-07 09:28:51 -03:00
Reinaldo Neto 4526b7f871
[FIX] UGC Rules Text align (#4934) 2023-03-02 16:04:52 -03:00
Diego Mello 27efa89dac
Bump version to 4.37.0 (#4938) 2023-03-02 13:22:40 -03:00
Gleidson Daniel Silva 3fbb7b5720
[IMPROVE] Brings the operation of the video call closer to the web (#4883)
* rename CallAgainActionSheet to StartACallActionSheet

* remove useVideoConf and use videoConfJoin directly

* consider phone on calls

* fix text shrink

* fix mic audio

* change the behavior of call icon on header and RoomInfo

* update types

* update types and variables names

* revert old type

* fix issue on old servers

* rename to a correct naming

* fix translation

* revamp call icon

* add error handling to videoconf capabilities

* lint

* fix role logic

* change const name

* rename comp

* remove commented code

* fix types and apply correct logic

* fix naming

* correct the import

* update icon size

* create timer function for videoConf bellow 5.0

* add subscription to useVideoConf hook

---------

Co-authored-by: Diego Mello <diegolmello@gmail.com>
2023-03-01 15:26:56 -03:00
Reinaldo Neto 4d5ff8aba1
[FIX] Omnichannel's icon svg fallback when the link returns an error (#4916)
* [FIX] Omnichannel's icon svg fallback when the link returns an error

* add activity indicator

* switch between activity indicator to custom icon

* reuse the same component as const
2023-02-27 17:31:28 -03:00
Reinaldo Neto 4336f0db40
[FIX] "Allow Reaction" does not work properly on "Read Only" rooms (#4864)
* [FIX] "Allow Reaction" does not work properly on "Read Only" rooms

* fix the handle of message box

---------

Co-authored-by: Gleidson Daniel Silva <gleidson10daniel@hotmail.com>
2023-02-24 11:37:56 -03:00
Gleidson Daniel Silva 4686d4f6f8
[FIX] Text color and fit content of TaskList (#4906)
* fix regression on plain text

* update stories

* fix where to add the color

* fit content taskList

---------

Co-authored-by: Reinaldo Neto <reinaldonetof@hotmail.com>
2023-02-16 10:07:19 -03:00
Gleidson Daniel Silva 58f28fb488
[FIX] Remove some permissions and keep only basic Bluetooth permission on Android (#4912) 2023-02-15 14:19:44 -03:00
lingohub[bot] 6bb4adaecd
Language update from LingoHub 🤖 on 2023-02-14Z (#4911)
* Language update from LingoHub 🤖

Project Name: Rocket.Chat.ReactNative
Project Link: https://translate.lingohub.com/rocketchat/dashboard/rocket-dot-chat-dot-reactnative
User: Diego Mello

Easy language translations with LingoHub 🚀

* Language update from LingoHub 🤖

Project Name: Rocket.Chat.ReactNative
Project Link: https://translate.lingohub.com/rocketchat/dashboard/rocket-dot-chat-dot-reactnative
User: Diego Mello

Easy language translations with LingoHub 🚀

---------

Co-authored-by: Diego Mello <diego.mello@rocket.chat>
2023-02-14 18:00:41 -03:00
Diego Mello 197616b94c
Chore: Remove deprecated typing stream (#4888) 2023-02-14 15:49:16 -03:00
Diego Mello edd0333be1
Chore: Update React Native to 0.68.6 (#4881) 2023-02-14 12:06:37 -03:00
Diego Mello 8c47187f70
[NEW] Presence Cap (#4900) 2023-02-14 10:47:56 -03:00
Gleidson Daniel Silva c4a2ce20c6
Regression: Adds idempotent prop to delete audio (#4862) 2023-02-06 16:07:23 -03:00
Reinaldo Neto 68f6eb40de
Chore: Hooks app/views/InviteUsersEditView (#4670)
* Chore: Hooks app/views/InviteUsersEditView

* minor tweak

* switch value name
2023-02-02 18:41:32 -03:00
Diego Mello 59c76d3956
Bump version to 4.36.0 (#4884) 2023-02-02 16:51:16 -03:00
Reinaldo Neto 9396b08ead
[FIX] Quote rendering with leading empty space on mobile only (#4778)
* [FIX] Quote rendering with leading empty space on mobile only

* update the message storyshot

* compareServerVersion to connection string

* fix time

* fix lint

* update to servers greater or equal than 6.0

* refactor tests

* minor tweak

---------

Co-authored-by: GleidsonDaniel <gleidson10daniel@hotmail.com>
2023-02-02 00:17:09 -03:00
Reinaldo Neto a927746d7f
[FIX] Show read receipts when it isn't read yet (#4865)
* [FIX] Show read receipts when it isn't read yet

* minor tweak
2023-02-02 00:10:27 -03:00
Reinaldo Neto 21e4818af7
[FIX] Team icons on Share View and searching on RoomsListView (#4833)
* [FIX] Team icons on Share View

* fix the teams when searching
2023-02-02 00:04:17 -03:00
Diego Mello 4de7c83e80
Bump version to 4.35.1 (#4871) 2023-01-30 15:10:09 -03:00
Gleidson Daniel Silva 18cc16beb7
Regression: Add token to Jitsi call on iOS (#4863)
* add token to jitsi builder

* fix room

* fix room and remove flags

* fix video prop
2023-01-30 13:56:39 -03:00
Reinaldo Neto 3cd1a5f0a6
[FIX] Add users shouldn't have Skip option (#4828) 2023-01-25 15:28:03 -03:00
lingohub[bot] 1abff18e75
Language update from LingoHub 🤖 (#4859)
Project Name: Rocket.Chat.ReactNative
Project Link: https://translate.lingohub.com/rocketchat/dashboard/rocket-dot-chat-dot-reactnative
User: Diego Mello

Easy language translations with LingoHub 🚀

Co-authored-by: Diego Mello <diego.mello@rocket.chat>
2023-01-24 16:01:29 -03:00
Diego Mello 26c8931563
Bump version to 4.36.0 (#4854) 2023-01-24 13:25:13 -03:00
Gleidson Daniel Silva 192a6b055a
Regression: Fix RoomItem's loading status (#4835) 2023-01-24 10:03:48 -03:00
Diego Mello 7363d9d742
[FIX] Official CI build (#4850) 2023-01-24 09:50:17 -03:00
Umang Patel 21f64b08e5
Docs: Fix Rocket.Chat server guide URL (#4848) 2023-01-23 13:50:30 -03:00
Gleidson Daniel Silva 38511d2f2d
[IMPROVE] Migrate from react-native-jitsi-meet to lib react-native-jitsimeet-custom (#4823)
Co-authored-by: Diego Mello <diegolmello@gmail.com>
2023-01-20 13:55:53 -03:00
Reinaldo Neto 593d12b129
[FIX] Add User Generated Content link on login (#4827)
* [FIX] Add User Generated Content link on login

* minor tweak
2023-01-20 11:42:18 -03:00
Diego Mello ad3bfa830c
Chore: Rotate CI secrets (#4797) 2023-01-18 19:15:22 -03:00
Diego Mello af70849b5e
[FIX] Point to correct RN fork commit (#4832) 2023-01-18 14:55:54 -03:00
Diego Mello 91831c8f33
[FIX] Unwanted clear keychain and request challenges (#4826) 2023-01-18 13:43:26 -03:00
Diego Mello 447a2b9344
Regression: App not fetching messages properly after #4801 (#4819) 2023-01-16 13:43:27 -03:00
Gleidson Daniel Silva fbb05fa0d3
Regression: Add bluetooth permissions for Jitsi (#4796)
* add blt permissions

* Update AndroidManifest.xml

* add blt permissions

* remove wrong permission
2023-01-16 10:17:52 -03:00
Gleidson Daniel Silva 41b54d6d87
[FIX] Audio names not being handled properly (#4685) 2023-01-14 07:07:25 -03:00
Diego Mello 5387d31a68
[FIX] Messages not loading on some edge cases (#4801) 2023-01-13 16:32:52 -03:00
Diego Mello a1580811ed
[IMPROVE] E2EE improvements (#4763) 2023-01-12 10:32:33 -03:00
Reinaldo Neto 3a1b06b86c
[FIX] Not Login with SSO after upgrade to version 5.4.0 and 5.4.1 (#4783)
* [FIX] Not Login with SSO after upgrade to version 5.4.0 and 5.4.1

* minor tweak
2023-01-10 20:17:14 -03:00
Reinaldo Neto 9525ef25d8
[FIX] Modal freezing app after return from the background (#4795) 2023-01-09 15:32:16 -03:00
Gleidson Daniel Silva d208373b3a
Regression: Prevent screen from sleeping on Jitsi on Android (#4791) 2023-01-09 10:29:58 -03:00
Reinaldo Neto 24ad69346a
[FIX] Opening search field after server list does not hide server list (#4792)
* [FIX] Opening search field after server list does not hide server list

* minor tweak
2023-01-06 12:36:23 -03:00
Reinaldo Neto 8102bef1d0
[FIX] Quote message and reply with image (#4715)
* send msg with attachment

* send quote inside image

* minor tweak

* remove msg from return

* fix the lint and prettier

* fix visual bug for iOS

* fixing the message box input
2023-01-05 15:23:11 -03:00
Reinaldo Neto b6b5e7294f
[FIX] Member list filters for All by default (#4757)
Co-authored-by: Gleidson Daniel Silva <gleidson10daniel@hotmail.com>
2023-01-04 11:36:51 -03:00
Diego Mello 73557038a2
[FIX] Flipper on Android (#4771) 2022-12-21 17:35:45 -03:00
Diego Mello 4174aef4f8
Chore: Upgrade react-native-device-info to 10.3.0 (#4770) 2022-12-21 15:47:42 -03:00
dependabot[bot] 67f41a712c
Chore: Bump loader-utils from 1.4.1 to 1.4.2 (#4687)
Bumps [loader-utils](https://github.com/webpack/loader-utils) from 1.4.1 to 1.4.2.
- [Release notes](https://github.com/webpack/loader-utils/releases)
- [Changelog](https://github.com/webpack/loader-utils/blob/v1.4.2/CHANGELOG.md)
- [Commits](https://github.com/webpack/loader-utils/compare/v1.4.1...v1.4.2)

---
updated-dependencies:
- dependency-name: loader-utils
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Diego Mello <diegolmello@gmail.com>
2022-12-21 14:39:09 -03:00
dependabot[bot] c13e0af110
Chore: Bump underscore from 1.10.2 to 1.13.6 (#4764)
Bumps [underscore](https://github.com/jashkenas/underscore) from 1.10.2 to 1.13.6.
- [Release notes](https://github.com/jashkenas/underscore/releases)
- [Commits](https://github.com/jashkenas/underscore/compare/1.10.2...1.13.6)

---
updated-dependencies:
- dependency-name: underscore
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Diego Mello <diegolmello@gmail.com>
2022-12-21 14:38:36 -03:00
dependabot[bot] d10a77ba3d
Bump minimist from 1.2.5 to 1.2.7 (#4616)
Bumps [minimist](https://github.com/minimistjs/minimist) from 1.2.5 to 1.2.7.
- [Release notes](https://github.com/minimistjs/minimist/releases)
- [Changelog](https://github.com/minimistjs/minimist/blob/main/CHANGELOG.md)
- [Commits](https://github.com/minimistjs/minimist/compare/v1.2.5...v1.2.7)

---
updated-dependencies:
- dependency-name: minimist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Diego Mello <diegolmello@gmail.com>
2022-12-21 14:38:18 -03:00
Reinaldo Neto 68066d487f
[FIX] Try again to resend a file on a thread (#4756) 2022-12-21 14:34:48 -03:00
Reinaldo Neto 0b5dab3ddf
[FIX] Notification preferences menu shows nothing (#4703) 2022-12-21 13:15:30 -03:00
Reinaldo Neto 23f716c280
[FIX] Disappear push notifications when open the app (#4718)
* [FIX] Disappear push notifications when open the app

* minor tweak

* test badgeCount

* refactor remove notification to remove notification and badge
2022-12-21 13:07:17 -03:00
Diego Mello 4b1f1d9074
Chore: Select different provisioning profile for Experimental app (#4752) 2022-12-14 18:58:05 -03:00
Diego Mello 09cdb3e7a4
Bump version to 4.35.0 (#4751) 2022-12-14 16:23:28 -03:00
lingohub[bot] 46c18fb20d
Language update from LingoHub 🤖 on 2022-12-14Z (#4748)
* Language update from LingoHub 🤖

Project Name: Rocket.Chat.ReactNative
Project Link: https://translate.lingohub.com/rocketchat/dashboard/rocket-dot-chat-dot-reactnative
User: Diego Mello

Easy language translations with LingoHub 🚀

* Add sv and fi

* Add missing locales to util

* Reorder languages

Co-authored-by: Diego Mello <diego.mello@rocket.chat>
Co-authored-by: Diego Mello <diegolmello@gmail.com>
2022-12-14 12:59:30 -03:00
Diego Mello 0290d8e0a9
[FIX] Emoji picker not opening in some cases (#4735) 2022-12-08 15:38:16 -03:00
Gleidson Daniel Silva a2722f07b0
[FIX] Can't upload the same file on two rooms at the same time (#4528)
* update style to match other spaces

* fix sending the same file in different rooms and add the limit for sending the same file

* remove when error happens and cant finish the upload

* use the same variable as rocket.chat

* minor tweak upload path and removed _raw

* change from 2 to 4

Co-authored-by: Reinaldo Neto <reinaldonetof@hotmail.com>
Co-authored-by: Reinaldo Neto <47038980+reinaldonetof@users.noreply.github.com>
2022-12-05 13:31:44 -03:00
Reinaldo Neto 00661174a3
[FIX] Bottom View color when using iPad (#4643)
* [FIX] Bottom View color when using iPAD

* [FIX] Bottom View color when using iPAD

* tweak on path to react-native-ui-lib in package.json
2022-12-05 12:19:57 -03:00
Reinaldo Neto cbd9b27cf7
[FIX] Cannot read property 'fetch' of undefined on ThreadMessagesView (#4557)
* [FIX] Cannot read property 'fetch' of undefined on ThreadMessagesView

* added e2e test

* change from _raw to _id

* test thread messages view with a thread created
2022-12-02 14:06:14 -03:00
Diego Mello 87a3f85feb
Bump version to 4.34.0 (#4724) 2022-12-02 11:09:24 -03:00
Gleidson Daniel Silva a8b3a3b7de
[IMPROVE] Disable Jitsi native module on Android (#4708)
* temp: disable jitsi on android

* update props and subscription

* add open intent

* add request permissions

* disable react-native-jitsi-meet on android and separate implementations

* fix ios

* fix import alias

* revert android manifest indentation

* add catch to method

* return comment

* remove is iOS

* fix queries

* remove unused data

* webview audio

* fix android permissions

* fix audio android

* change how to open jitsi app

* remove loading

* update close logic
2022-12-01 14:20:22 -03:00
Reinaldo Neto 057ca8afac
Regression: The Unordered and Ordered List text color to bodyText (#4717)
* Regression: The Unordered and Ordered List text color to bodyText

* update storyshot
2022-11-30 15:35:17 -03:00
Gleidson Daniel Silva 92ae597b76
[FIX] videoconf skeleton border color and height (#4716) 2022-11-29 17:18:53 -03:00
Reinaldo Neto 7def88a7e2
Regression: Avatar and Username for Allowed Reactions and for Message Removed (#4714) 2022-11-29 12:12:35 -03:00
Reinaldo Neto aa26f7251e
[FIX] Remove nested room navigation (#4702)
* reset from room to room

* jump from room to room it's fine

* threads ipad

* fix ts roomslistview

* remove params

* fix the ipad highlight

* jump to a message from a thread to main room

* the reset within the goRoom

* create channel

* changes in canned response

* fix discussion navigation

* navigation newmessageview to users

* fix go room from room info view

* inappnotification, deeplinking, room.js

* change from room.rooms to room.subscribed

* minor tweak jumptomessage

* fix add existing channel to team and fixing test 02 of teams

* keep the same behavior after add existing channel

* keep the same behavior after add existing channel

* clean cosole

* changes requested about the name

* inapp redux to hooks

* added a comment to addexistingchanneltoteam

* minor tweak jumptomessage

* refactor goRoom to add the param popToRoot, also refactor the navigate in deeplinking too

* refactor other places that exist goRoom

* fix the didUpdate

* added in app notification test

* clean js

* minor tweak test
2022-11-25 10:21:56 -03:00
Gleidson Daniel Silva 21ee25e818
[FIX] Check videoConf type (#4707)
* add videoconf check

* update message type
2022-11-24 14:24:20 -03:00
Gleidson Daniel Silva 362df65bbe
[NEW] Video conf message block (#4619)
* create skeleton loading

* add phone-in icon

* fix avatar style props

* fix ios icon

* add new types

* add Rocket.Chat definitions

* fix block re-render

* create VideoConferenceBlock

* better composition

* fix call originator

* add pt-br translations

* create useSnaps hook

* update colors

* init action sheet

* fix to go back when the call ends

* create CallAgainActionSheet

* update pods

* bump lib react-native-skeleton-placeholder

* update hook location

* remove loading prop

* move files to components

* update border radius

* add verify on message options

* update icons

* apply patch
2022-11-24 08:37:08 -03:00
Diego Mello 61dc320a68
Chore: Update react-native-mmkv-storage to 0.8.0 (#4695) 2022-11-21 16:16:53 -03:00
Diego Mello 62c2d876eb
[IMPROVE] Standardize padding of E2E screens (#4701) 2022-11-21 16:10:38 -03:00
Diego Mello 44f062f9b9
Bump react-native-notifications to 4.3.3 (#4692) 2022-11-16 18:09:46 -03:00
GitStart 438b69b371
[FIX] Playing multiple voice messages at the same time (#4662)
Co-authored-by: gitstart <gitstart@users.noreply.github.com>
Co-authored-by: Debojyoti Singha <20729878+debojyoti452@users.noreply.github.com>
Co-authored-by: Diego Mello <diegolmello@gmail.com>
2022-11-16 10:40:45 -03:00
Diego Mello 988c6931ec
Chore: Bump patches (#4679) 2022-11-16 10:26:37 -03:00
Reinaldo Neto b0ea5e31f8
[FIX] Auto-translate feature wasn't working (#4678) 2022-11-11 16:51:57 -03:00
dependabot[bot] 82c922fa4d
Chore: Bump moment from 2.29.3 to 2.29.4 (#4347)
Bumps [moment](https://github.com/moment/moment) from 2.29.3 to 2.29.4.
- [Release notes](https://github.com/moment/moment/releases)
- [Changelog](https://github.com/moment/moment/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/moment/moment/compare/2.29.3...2.29.4)

---
updated-dependencies:
- dependency-name: moment
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-11 16:20:02 -03:00
dependabot[bot] 9b48ce0264
Chore(deps): Bump simple-plist from 1.1.1 to 1.3.1 (#4263)
Bumps [simple-plist](https://github.com/wollardj/simple-plist) from 1.1.1 to 1.3.1.
- [Release notes](https://github.com/wollardj/simple-plist/releases)
- [Commits](https://github.com/wollardj/simple-plist/compare/v1.1.1...v1.3.1)

---
updated-dependencies:
- dependency-name: simple-plist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-11 15:27:50 -03:00
dependabot[bot] 994892abb2
Chore: Bump loader-utils from 1.4.0 to 1.4.1 (#4660)
Bumps [loader-utils](https://github.com/webpack/loader-utils) from 1.4.0 to 1.4.1.
- [Release notes](https://github.com/webpack/loader-utils/releases)
- [Changelog](https://github.com/webpack/loader-utils/blob/v1.4.1/CHANGELOG.md)
- [Commits](https://github.com/webpack/loader-utils/compare/v1.4.0...v1.4.1)

---
updated-dependencies:
- dependency-name: loader-utils
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-11 15:16:59 -03:00
Reinaldo Neto 251cc9843b
[IMPROVE] Add delete-own-message permission (#4663) 2022-11-11 14:28:41 -03:00
Diego Mello 316bc80876
[IMPROVE] Add missing borders styles changes (#4675) 2022-11-11 13:04:57 -03:00
Diego Mello 94f0981b49
Regression: Remove users already in local database (#4673) 2022-11-10 16:59:27 -03:00
Diego Mello 05a04f7f29
[IMPROVE] Sync message actions order with web app (#4672) 2022-11-10 16:48:52 -03:00
Reinaldo Neto cd9924361e
[FIX] Non primitive dependency on useSubscriptionRoles (#4618)
* [FIX] Non primitive dependency on useSubscriptionRoles

* removed sort

* Remove JSON.parse and order by array

Co-authored-by: Diego Mello <diegolmello@gmail.com>
2022-11-10 13:36:24 -03:00
Reinaldo Neto 440e745901
[IMPROVE] Border radius and width on inputs (#4659)
* [IMPROVE] Border radius to 4 on FormTextInput

* change border width

* Remove border radius from StatusView input

Co-authored-by: Diego Mello <diegolmello@gmail.com>
2022-11-10 13:35:59 -03:00
Reinaldo Neto 612405cfae
[IMPROVE] Increase border radius on all buttons (#4657)
* border radius complete

* increase to chip

* Apply in missing places

* tweak slash command and update test

Co-authored-by: Diego Mello <diegolmello@gmail.com>
2022-11-10 13:22:02 -03:00
Diego Mello 6b6bb1df08
Chore: Reduce the frequency of dependabot runs to weekly basis (#4656) 2022-11-10 13:15:56 -03:00
Reinaldo Neto 640d83c9df
[FIX] The TS in data_setup and add expect in room and ignoreuser spec (#4658) 2022-11-09 13:41:39 -03:00
Reinaldo Neto a5e538c13f
[NEW] Emphasis Elements (italic, strike and bold) in Message Parser Components (#4621)
* [NEW] Emphasis Elements (italic, strike and bold) in Message Parser Components

* update storyshot

* minor tweak and remove of isLink

* Add theme provider to new md stories

* Cleanup

* Update tests

Co-authored-by: Diego Mello <diegolmello@gmail.com>
2022-11-07 13:42:42 -03:00
326 changed files with 9520 additions and 8287 deletions

View File

@ -1,9 +1,12 @@
defaults: &defaults
working_directory: ~/repo
orbs:
android: circleci/android@2.1.2
macos: &macos
macos:
xcode: "13.3.0"
xcode: "14.2.0"
resource_class: large
bash-env: &bash-env
@ -51,14 +54,14 @@ save-gems-cache: &save-gems-cache
update-fastlane-ios: &update-fastlane-ios
name: Update Fastlane
command: |
echo "ruby-2.6.4" > ~/.ruby-version
echo "ruby-2.7.7" > ~/.ruby-version
bundle install
working_directory: ios
update-fastlane-android: &update-fastlane-android
name: Update Fastlane
command: |
echo "ruby-2.6.4" > ~/.ruby-version
echo "ruby-2.7.7" > ~/.ruby-version
bundle install
working_directory: android
@ -118,26 +121,26 @@ commands:
if [[ $CIRCLE_JOB == "android-build-official" ]]; then
echo -e "APPLICATION_ID=chat.rocket.android" >> ./gradle.properties
echo -e "BugsnagAPIKey=$BUGSNAG_KEY_OFFICIAL" >> ./gradle.properties
echo $CHAT_ROCKET_ANDROID_STORE_FILE_BASE64_JKS | base64 --decode > ./app/$KEYSTORE_OFFICIAL
echo $KEYSTORE_OFFICIAL_BASE64 | base64 --decode > ./app/$KEYSTORE_OFFICIAL
echo -e "KEYSTORE=$KEYSTORE_OFFICIAL" >> ./gradle.properties
echo -e "KEYSTORE_PASSWORD=$CHAT_ROCKET_ANDROID_STORE_PASSWORD" >> ./gradle.properties
echo -e "KEY_ALIAS=$CHAT_ROCKET_ANDROID_KEY_ALIAS" >> ./gradle.properties
echo -e "KEY_PASSWORD=$CHAT_ROCKET_ANDROID_KEY_PASSWORD" >> ./gradle.properties
echo -e "KEYSTORE_PASSWORD=$KEYSTORE_OFFICIAL_PASSWORD" >> ./gradle.properties
echo -e "KEY_ALIAS=$KEYSTORE_OFFICIAL_ALIAS" >> ./gradle.properties
echo -e "KEY_PASSWORD=$KEYSTORE_OFFICIAL_PASSWORD" >> ./gradle.properties
else
echo -e "APPLICATION_ID=chat.rocket.reactnative" >> ./gradle.properties
echo -e "BugsnagAPIKey=$BUGSNAG_KEY" >> ./gradle.properties
echo $KEYSTORE_BASE64 | base64 --decode > ./app/$KEYSTORE
echo -e "KEYSTORE=$KEYSTORE" >> ./gradle.properties
echo -e "KEYSTORE_PASSWORD=$KEYSTORE_PASSWORD" >> ./gradle.properties
echo -e "KEY_ALIAS=$KEY_ALIAS" >> ./gradle.properties
echo -e "KEY_PASSWORD=$KEYSTORE_PASSWORD" >> ./gradle.properties
echo $KEYSTORE_EXPERIMENTAL_BASE64 | base64 --decode > ./app/$KEYSTORE_EXPERIMENTAL
echo -e "KEYSTORE=$KEYSTORE_EXPERIMENTAL" >> ./gradle.properties
echo -e "KEYSTORE_PASSWORD=$KEYSTORE_EXPERIMENTAL_PASSWORD" >> ./gradle.properties
echo -e "KEY_ALIAS=$KEYSTORE_EXPERIMENTAL_ALIAS" >> ./gradle.properties
echo -e "KEY_PASSWORD=$KEYSTORE_EXPERIMENTAL_PASSWORD" >> ./gradle.properties
fi
working_directory: android
- run:
name: Set Google Services
command: |
if [[ $KEYSTORE ]]; then
if [[ $GOOGLE_SERVICES_ANDROID ]]; then
echo $GOOGLE_SERVICES_ANDROID | base64 --decode > google-services.json
fi
working_directory: android/app
@ -151,7 +154,7 @@ commands:
if [[ $CIRCLE_JOB == "android-build-experimental" || "android-automatic-build-experimental" ]]; then
./gradlew bundleExperimentalPlayRelease
fi
if [[ ! $KEYSTORE ]]; then
if [[ ! $GOOGLE_SERVICES_ANDROID ]]; then
./gradlew assembleExperimentalPlayDebug
fi
working_directory: android
@ -200,8 +203,12 @@ commands:
- run:
name: Set Google Services
command: |
if [[ $KEYSTORE ]]; then
echo $GOOGLE_SERVICES_IOS | base64 --decode > GoogleService-Info.plist
if [[ $APP_STORE_CONNECT_API_KEY_BASE64 ]]; then
if [[ $CIRCLE_JOB == "ios-build-official" ]]; then
echo $GOOGLE_SERVICES_IOS | base64 --decode > GoogleService-Info.plist
else
echo $GOOGLE_SERVICES_IOS_EXPERIMENTAL | base64 --decode > GoogleService-Info.plist
fi
fi
working_directory: ios
- run:
@ -223,12 +230,12 @@ commands:
/usr/libexec/PlistBuddy -c "Set IS_OFFICIAL NO" ./NotificationService/Info.plist
fi
if [[ $APP_STORE_CONNECT_API_BASE64 ]]; then
echo $APP_STORE_CONNECT_API_BASE64 | base64 --decode > ./fastlane/app_store_connect_api_key.p8
if [[ $APP_STORE_CONNECT_API_KEY_BASE64 ]]; then
echo $APP_STORE_CONNECT_API_KEY_BASE64 | base64 --decode > ./fastlane/app_store_connect_api_key.p8
if [[ $CIRCLE_JOB == "ios-build-official" ]]; then
bundle exec fastlane ios build_official
else
if [[ $KEYSTORE ]]; then
if [[ $APP_STORE_CONNECT_API_KEY_BASE64 ]]; then
bundle exec fastlane ios build_experimental
else
bundle exec fastlane ios build_fork
@ -318,11 +325,19 @@ commands:
- run:
name: Fastlane Tesflight Upload
command: |
echo $APP_STORE_CONNECT_API_BASE64 | base64 --decode > ./fastlane/app_store_connect_api_key.p8
echo $APP_STORE_CONNECT_API_KEY_BASE64 | base64 --decode > ./fastlane/app_store_connect_api_key.p8
bundle exec fastlane ios beta official:<< parameters.official >>
working_directory: ios
- save_cache: *save-gems-cache
create-e2e-account-file:
description: "Create e2e account file"
steps:
- run:
command: |
echo $E2E_ACCOUNT | base64 --decode > ./e2e_account.ts
working_directory: e2e
version: 2.1
# EXECUTORS
@ -434,6 +449,94 @@ jobs:
- upload-to-google-play-beta:
official: true
e2e-build-android:
<<: *defaults
executor:
name: android/android-machine
resource-class: xlarge
tag: 2022.12.1
environment:
<<: *android-env
steps:
- checkout
- restore_cache: *restore-npm-cache-linux
- run: *install-npm-modules
- save_cache: *save-npm-cache-linux
- restore_cache: *restore-gradle-cache
- run:
name: Configure Gradle
command: |
echo -e "" > ./gradle.properties
# echo -e "android.enableAapt2=false" >> ./gradle.properties
echo -e "android.useAndroidX=true" >> ./gradle.properties
echo -e "android.enableJetifier=true" >> ./gradle.properties
echo -e "newArchEnabled=false" >> ./gradle.properties
echo -e "FLIPPER_VERSION=0.125.0" >> ./gradle.properties
echo -e "VERSIONCODE=$CIRCLE_BUILD_NUM" >> ./gradle.properties
echo -e "APPLICATION_ID=chat.rocket.reactnative" >> ./gradle.properties
echo -e "BugsnagAPIKey=$BUGSNAG_KEY" >> ./gradle.properties
echo $KEYSTORE_EXPERIMENTAL_BASE64 | base64 --decode > ./app/$KEYSTORE_EXPERIMENTAL
echo -e "KEYSTORE=$KEYSTORE_EXPERIMENTAL" >> ./gradle.properties
echo -e "KEYSTORE_PASSWORD=$KEYSTORE_EXPERIMENTAL_PASSWORD" >> ./gradle.properties
echo -e "KEY_ALIAS=$KEYSTORE_EXPERIMENTAL_ALIAS" >> ./gradle.properties
echo -e "KEY_PASSWORD=$KEYSTORE_EXPERIMENTAL_PASSWORD" >> ./gradle.properties
working_directory: android
- run:
name: Build Android
command: |
echo "RUNNING_E2E_TESTS=true" > ./.env
yarn e2e:android-build
- save_cache: *save-gradle-cache
- store_artifacts:
path: android/app/build/outputs/apk/experimentalPlay/release/app-experimental-play-release.apk
- store_artifacts:
path: android/app/build/outputs/apk/androidTest/experimentalPlay/release/app-experimental-play-release-androidTest.apk
- persist_to_workspace:
root: /home/circleci/repo
paths:
- android/app/build/outputs/apk/
e2e-test-android:
<<: *defaults
executor:
name: android/android-machine
resource-class: xlarge
tag: 2022.12.1
parallelism: 4
steps:
- checkout
- attach_workspace:
at: /home/circleci/repo
- restore_cache: *restore-npm-cache-linux
- run: *install-npm-modules
- save_cache: *save-npm-cache-linux
- run: mkdir ~/junit
- create-e2e-account-file
- android/create-avd:
avd-name: Pixel_API_31_AOSP
install: true
system-image: system-images;android-31;default;x86_64
- run:
name: Setup emulator
command: |
echo "hw.lcd.density = 440" >> ~/.android/avd/Pixel_API_31_AOSP.avd/config.ini
echo "hw.lcd.height = 2280" >> ~/.android/avd/Pixel_API_31_AOSP.avd/config.ini
echo "hw.lcd.width = 1080" >> ~/.android/avd/Pixel_API_31_AOSP.avd/config.ini
- run:
name: Run Detox Tests
command: |
TEST=$(circleci tests glob "e2e/tests/**/*.ts" | circleci tests split --split-by=timings)
yarn e2e:android-test $TEST
- store_artifacts:
path: artifacts
- run:
command: cp junit.xml ~/junit/
when: always
- store_test_results:
path: ~/junit
- store_artifacts:
path: ~/junit
# iOS builds
ios-build-experimental:
executor: mac-env
@ -457,11 +560,89 @@ jobs:
- upload-to-testflight:
official: true
e2e-build-ios:
executor: mac-env
steps:
- checkout
- restore_cache: *restore-gems-cache
- restore_cache: *restore-npm-cache-mac
- run: *install-npm-modules
- run: *update-fastlane-ios
- save_cache: *save-npm-cache-mac
- save_cache: *save-gems-cache
- manage-pods
- run:
name: Configure Detox
command: |
brew tap wix/brew
brew install applesimutils
- run:
name: Build
command: |
/usr/libexec/PlistBuddy -c "Set :bugsnag:apiKey $BUGSNAG_KEY" ./ios/RocketChatRN/Info.plist
/usr/libexec/PlistBuddy -c "Set :bugsnag:apiKey $BUGSNAG_KEY" ./ios/ShareRocketChatRN/Info.plist
yarn detox clean-framework-cache && yarn detox build-framework-cache
echo "RUNNING_E2E_TESTS=true" > ./.env
yarn e2e:ios-build
- persist_to_workspace:
root: /Users/distiller/project
paths:
- ios/build/Build/Products/Release-iphonesimulator/Rocket.Chat Experimental.app
e2e-test-ios:
executor: mac-env
parallelism: 5
steps:
- checkout
- attach_workspace:
at: /Users/distiller/project
- restore_cache: *restore-npm-cache-mac
- run: *install-npm-modules
- save_cache: *save-npm-cache-mac
- run: mkdir ~/junit
- run:
name: Configure Detox
command: |
brew tap wix/brew
brew install applesimutils
yarn detox clean-framework-cache && yarn detox build-framework-cache
- create-e2e-account-file
- run:
name: Run tests
command: |
TEST=$(circleci tests glob "e2e/tests/**/*.ts" | circleci tests split --split-by=timings)
yarn e2e:ios-test $TEST
- store_artifacts:
path: artifacts
- run:
command: cp junit.xml ~/junit/
when: always
- store_test_results:
path: ~/junit
- store_artifacts:
path: ~/junit
workflows:
build-and-test:
jobs:
- lint-testunit
# E2E tests
- e2e-hold:
type: approval
- e2e-build-ios:
requires:
- e2e-hold
- e2e-test-ios:
requires:
- e2e-build-ios
- e2e-build-android:
requires:
- e2e-hold
- e2e-test-android:
requires:
- e2e-build-android
# iOS Experimental
- ios-hold-build-experimental:
type: approval

91
.detoxrc.js Normal file
View File

@ -0,0 +1,91 @@
/** @type {Detox.DetoxConfig} */
module.exports = {
testRunner: {
args: {
$0: 'jest',
config: 'e2e/jest.config.js'
},
retries: process.env.CI ? 3 : 0
},
artifacts: {
plugins: {
screenshot: 'failing',
video: 'failing',
uiHierarchy: 'enabled'
}
},
apps: {
'ios.debug': {
type: 'ios.app',
binaryPath: 'ios/build/Build/Products/Debug-iphonesimulator/Rocket.Chat Experimental.app',
build:
'xcodebuild -workspace ios/RocketChatRN.xcworkspace -scheme RocketChatRN -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build'
},
'ios.release': {
type: 'ios.app',
binaryPath: 'ios/build/Build/Products/Release-iphonesimulator/Rocket.Chat Experimental.app',
build:
'xcodebuild -workspace ios/RocketChatRN.xcworkspace -scheme RocketChatRN -configuration Release -sdk iphonesimulator -derivedDataPath ios/build'
},
'android.debug': {
type: 'android.apk',
binaryPath: 'android/app/build/outputs/apk/experimentalPlay/debug/app-experimental-play-debug.apk',
build:
'cd android ; ./gradlew assembleExperimentalPlayDebug assembleExperimentalPlayDebugAndroidTest -DtestBuildType=debug ; cd -',
reversePorts: [8081]
},
'android.release': {
type: 'android.apk',
binaryPath: 'android/app/build/outputs/apk/experimentalPlay/release/app-experimental-play-release.apk',
build:
'cd android ; ./gradlew assembleExperimentalPlayRelease assembleExperimentalPlayReleaseAndroidTest -DtestBuildType=release ; cd -'
}
},
devices: {
simulator: {
type: 'ios.simulator',
device: {
type: 'iPhone 14'
}
},
attached: {
type: 'android.attached',
device: {
adbName: '.*'
}
},
emulator: {
type: 'android.emulator',
device: {
avdName: 'Pixel_API_31_AOSP'
},
headless: process.env.CI ? true : false
}
},
configurations: {
'ios.sim.debug': {
device: 'simulator',
app: 'ios.debug'
},
'ios.sim.release': {
device: 'simulator',
app: 'ios.release'
},
'android.att.debug': {
device: 'attached',
app: 'android.debug'
},
'android.att.release': {
device: 'attached',
app: 'android.release'
},
'android.emu.debug': {
device: 'emulator',
app: 'android.debug'
},
'android.emu.release': {
device: 'emulator',
app: 'android.release'
}
}
};

2
.env Normal file
View File

@ -0,0 +1,2 @@
# DON'T COMMIT THIS FILE
RUNNING_E2E_TESTS=

View File

@ -2,7 +2,7 @@ module.exports = {
settings: {
'import/resolver': {
node: {
extensions: ['.ts', '.tsx', '.js', '.ios.js', '.android.js', '.native.js']
extensions: ['.ts', '.tsx', '.js', '.ios.js', '.android.js', '.native.js', '.ios.tsx', '.android.tsx']
}
}
},
@ -240,19 +240,8 @@ module.exports = {
},
{
files: ['e2e/**'],
globals: {
by: true,
detox: true,
device: true,
element: true,
waitFor: true
},
rules: {
'import/no-extraneous-dependencies': 0,
'no-await-in-loop': 0,
'no-restricted-syntax': 0,
// TODO: remove this rule when update Detox to 20 and test if the namespace Detox is available
'no-undef': 1
'no-await-in-loop': 0
}
}
]

View File

@ -3,5 +3,5 @@ updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "daily"
interval: "weekly"
open-pull-requests-limit: 25

1
.gitignore vendored
View File

@ -67,5 +67,6 @@ e2e/docker/rc_test_env/docker-compose.yml
e2e/docker/data/db
e2e/e2e_account.js
e2e/e2e_account.ts
junit.xml
*.p8

View File

@ -1 +1 @@
2.7.4
2.7.7

View File

@ -1,4 +1,4 @@
source 'https://rubygems.org'
# You may use http://rbenv.org/ or https://rvm.io/ to install and use this version
ruby '2.7.4'
ruby '2.7.7'
gem 'cocoapods', '~> 1.11', '>= 1.11.2'

View File

@ -1,13 +1,13 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Storyshots Button Custom Button 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityLabel\\":\\"Press me!\\",\\"accessibilityState\\":{\\"disabled\\":false},\\"testID\\":\\"testButton\\",\\"focusable\\":true,\\"collapsable\\":false,\\"style\\":{\\"paddingHorizontal\\":14,\\"justifyContent\\":\\"center\\",\\"height\\":48,\\"borderRadius\\":2,\\"marginBottom\\":12,\\"backgroundColor\\":\\"purple\\",\\"padding\\":10,\\"opacity\\":1}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"textAlign\\":\\"center\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"yellow\\",\\"fontSize\\":18},[{\\"textAlign\\":\\"left\\"}]],\\"accessibilityLabel\\":\\"Press me!\\"},\\"children\\":[\\"Press me!\\"]}]}"`;
exports[`Storyshots Button Custom Button 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityLabel\\":\\"Press me!\\",\\"accessibilityState\\":{\\"disabled\\":false},\\"testID\\":\\"testButton\\",\\"focusable\\":true,\\"collapsable\\":false,\\"style\\":{\\"paddingHorizontal\\":14,\\"justifyContent\\":\\"center\\",\\"height\\":48,\\"borderRadius\\":4,\\"marginBottom\\":12,\\"backgroundColor\\":\\"purple\\",\\"padding\\":10,\\"opacity\\":1}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"textAlign\\":\\"center\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"yellow\\",\\"fontSize\\":18},[{\\"textAlign\\":\\"left\\"}]],\\"accessibilityLabel\\":\\"Press me!\\"},\\"children\\":[\\"Press me!\\"]}]}"`;
exports[`Storyshots Button Disabled Button 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityLabel\\":\\"Press me!\\",\\"accessibilityState\\":{\\"disabled\\":true},\\"testID\\":\\"testButton\\",\\"focusable\\":true,\\"collapsable\\":false,\\"style\\":{\\"paddingHorizontal\\":14,\\"justifyContent\\":\\"center\\",\\"height\\":48,\\"borderRadius\\":2,\\"marginBottom\\":12,\\"backgroundColor\\":\\"#1d74f5\\",\\"opacity\\":0.3}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"textAlign\\":\\"center\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#ffffff\\",\\"fontSize\\":16},null],\\"accessibilityLabel\\":\\"Press me!\\"},\\"children\\":[\\"Press me!\\"]}]}"`;
exports[`Storyshots Button Disabled Button 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityLabel\\":\\"Press me!\\",\\"accessibilityState\\":{\\"disabled\\":true},\\"testID\\":\\"testButton\\",\\"focusable\\":true,\\"collapsable\\":false,\\"style\\":{\\"paddingHorizontal\\":14,\\"justifyContent\\":\\"center\\",\\"height\\":48,\\"borderRadius\\":4,\\"marginBottom\\":12,\\"backgroundColor\\":\\"#1d74f5\\",\\"opacity\\":0.3}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"textAlign\\":\\"center\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#ffffff\\",\\"fontSize\\":16},null],\\"accessibilityLabel\\":\\"Press me!\\"},\\"children\\":[\\"Press me!\\"]}]}"`;
exports[`Storyshots Button Disabled Loading Button 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityLabel\\":\\"Press me!\\",\\"accessibilityState\\":{\\"disabled\\":true},\\"testID\\":\\"testButton\\",\\"focusable\\":true,\\"collapsable\\":false,\\"style\\":{\\"paddingHorizontal\\":14,\\"justifyContent\\":\\"center\\",\\"height\\":48,\\"borderRadius\\":2,\\"marginBottom\\":12,\\"backgroundColor\\":\\"#1d74f5\\",\\"opacity\\":0.3}},\\"children\\":[{\\"type\\":\\"ActivityIndicator\\",\\"props\\":{\\"style\\":[{\\"padding\\":16,\\"flex\\":1},null],\\"color\\":\\"#ffffff\\"},\\"children\\":null}]}"`;
exports[`Storyshots Button Disabled Loading Button 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityLabel\\":\\"Press me!\\",\\"accessibilityState\\":{\\"disabled\\":true},\\"testID\\":\\"testButton\\",\\"focusable\\":true,\\"collapsable\\":false,\\"style\\":{\\"paddingHorizontal\\":14,\\"justifyContent\\":\\"center\\",\\"height\\":48,\\"borderRadius\\":4,\\"marginBottom\\":12,\\"backgroundColor\\":\\"#1d74f5\\",\\"opacity\\":0.3}},\\"children\\":[{\\"type\\":\\"ActivityIndicator\\",\\"props\\":{\\"style\\":[{\\"padding\\":16,\\"flex\\":1},null],\\"color\\":\\"#ffffff\\"},\\"children\\":null}]}"`;
exports[`Storyshots Button Loading Button 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityLabel\\":\\"Press me!\\",\\"accessibilityState\\":{\\"disabled\\":true},\\"testID\\":\\"testButton\\",\\"focusable\\":true,\\"collapsable\\":false,\\"style\\":{\\"paddingHorizontal\\":14,\\"justifyContent\\":\\"center\\",\\"height\\":48,\\"borderRadius\\":2,\\"marginBottom\\":12,\\"backgroundColor\\":\\"#1d74f5\\",\\"opacity\\":1}},\\"children\\":[{\\"type\\":\\"ActivityIndicator\\",\\"props\\":{\\"style\\":[{\\"padding\\":16,\\"flex\\":1},null],\\"color\\":\\"#ffffff\\"},\\"children\\":null}]}"`;
exports[`Storyshots Button Loading Button 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityLabel\\":\\"Press me!\\",\\"accessibilityState\\":{\\"disabled\\":true},\\"testID\\":\\"testButton\\",\\"focusable\\":true,\\"collapsable\\":false,\\"style\\":{\\"paddingHorizontal\\":14,\\"justifyContent\\":\\"center\\",\\"height\\":48,\\"borderRadius\\":4,\\"marginBottom\\":12,\\"backgroundColor\\":\\"#1d74f5\\",\\"opacity\\":1}},\\"children\\":[{\\"type\\":\\"ActivityIndicator\\",\\"props\\":{\\"style\\":[{\\"padding\\":16,\\"flex\\":1},null],\\"color\\":\\"#ffffff\\"},\\"children\\":null}]}"`;
exports[`Storyshots Button Primary Button 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityLabel\\":\\"Press me!\\",\\"accessibilityState\\":{\\"disabled\\":false},\\"testID\\":\\"testButton\\",\\"focusable\\":true,\\"collapsable\\":false,\\"style\\":{\\"paddingHorizontal\\":14,\\"justifyContent\\":\\"center\\",\\"height\\":48,\\"borderRadius\\":2,\\"marginBottom\\":12,\\"backgroundColor\\":\\"#1d74f5\\",\\"opacity\\":1}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"textAlign\\":\\"center\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#ffffff\\",\\"fontSize\\":16},null],\\"accessibilityLabel\\":\\"Press me!\\"},\\"children\\":[\\"Press me!\\"]}]}"`;
exports[`Storyshots Button Primary Button 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityLabel\\":\\"Press me!\\",\\"accessibilityState\\":{\\"disabled\\":false},\\"testID\\":\\"testButton\\",\\"focusable\\":true,\\"collapsable\\":false,\\"style\\":{\\"paddingHorizontal\\":14,\\"justifyContent\\":\\"center\\",\\"height\\":48,\\"borderRadius\\":4,\\"marginBottom\\":12,\\"backgroundColor\\":\\"#1d74f5\\",\\"opacity\\":1}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"textAlign\\":\\"center\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#ffffff\\",\\"fontSize\\":16},null],\\"accessibilityLabel\\":\\"Press me!\\"},\\"children\\":[\\"Press me!\\"]}]}"`;
exports[`Storyshots Button Secondary Button 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityLabel\\":\\"Press me!\\",\\"accessibilityState\\":{\\"disabled\\":false},\\"testID\\":\\"testButton\\",\\"focusable\\":true,\\"collapsable\\":false,\\"style\\":{\\"paddingHorizontal\\":14,\\"justifyContent\\":\\"center\\",\\"height\\":48,\\"borderRadius\\":2,\\"marginBottom\\":12,\\"backgroundColor\\":\\"#ffffff\\",\\"opacity\\":1}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"textAlign\\":\\"center\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#2f343d\\",\\"fontSize\\":16},null],\\"accessibilityLabel\\":\\"Press me!\\"},\\"children\\":[\\"Press me!\\"]}]}"`;
exports[`Storyshots Button Secondary Button 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityLabel\\":\\"Press me!\\",\\"accessibilityState\\":{\\"disabled\\":false},\\"testID\\":\\"testButton\\",\\"focusable\\":true,\\"collapsable\\":false,\\"style\\":{\\"paddingHorizontal\\":14,\\"justifyContent\\":\\"center\\",\\"height\\":48,\\"borderRadius\\":4,\\"marginBottom\\":12,\\"backgroundColor\\":\\"#ffffff\\",\\"opacity\\":1}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"textAlign\\":\\"center\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#2f343d\\",\\"fontSize\\":16},null],\\"accessibilityLabel\\":\\"Press me!\\"},\\"children\\":[\\"Press me!\\"]}]}"`;

View File

@ -1,11 +1,11 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Storyshots Chip Chip Text 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flex\\":1,\\"alignItems\\":\\"flex-start\\",\\"padding\\":16}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityState\\":{\\"disabled\\":false},\\"focusable\\":true,\\"style\\":[{\\"paddingHorizontal\\":8,\\"marginRight\\":8,\\"borderRadius\\":2,\\"justifyContent\\":\\"center\\",\\"maxWidth\\":192},{\\"backgroundColor\\":\\"#efeff4\\"},null],\\"collapsable\\":false},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flexDirection\\":\\"row\\",\\"alignItems\\":\\"center\\"}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"width\\":28,\\"height\\":28,\\"borderRadius\\":4},{\\"marginRight\\":8,\\"marginVertical\\":8}],\\"testID\\":\\"avatar\\"},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"overflow\\":\\"hidden\\"},{\\"width\\":28,\\"height\\":28,\\"borderRadius\\":4}]},\\"children\\":[{\\"type\\":\\"FastImageView\\",\\"props\\":{\\"style\\":{\\"position\\":\\"absolute\\",\\"left\\":0,\\"right\\":0,\\"top\\":0,\\"bottom\\":0},\\"source\\":{\\"uri\\":\\"https://open.rocket.chat/avatar/rocket.cat?format=png&size=56\\",\\"headers\\":{\\"User-Agent\\":\\"RC Mobile; ios unknown; vunknown (unknown)\\"},\\"priority\\":\\"high\\"},\\"resizeMode\\":\\"cover\\"},\\"children\\":null}]}]},{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"marginRight\\":8,\\"maxWidth\\":120}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"fontSize\\":16,\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#2f343d\\"}],\\"numberOfLines\\":1},\\"children\\":[\\"Rocket.Cat\\"]}]},{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":16,\\"color\\":\\"#6C727A\\"},null,{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]}]}]}]}"`;
exports[`Storyshots Chip Chip Text 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flex\\":1,\\"alignItems\\":\\"flex-start\\",\\"padding\\":16}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityState\\":{\\"disabled\\":false},\\"focusable\\":true,\\"style\\":[{\\"paddingHorizontal\\":8,\\"marginRight\\":8,\\"borderRadius\\":4,\\"justifyContent\\":\\"center\\",\\"maxWidth\\":192},{\\"backgroundColor\\":\\"#efeff4\\"},null],\\"collapsable\\":false},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flexDirection\\":\\"row\\",\\"alignItems\\":\\"center\\"}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"width\\":28,\\"height\\":28,\\"borderRadius\\":4},{\\"marginRight\\":8,\\"marginVertical\\":8}],\\"testID\\":\\"avatar\\"},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"overflow\\":\\"hidden\\"},{\\"width\\":28,\\"height\\":28,\\"borderRadius\\":4}]},\\"children\\":[{\\"type\\":\\"FastImageView\\",\\"props\\":{\\"style\\":{\\"position\\":\\"absolute\\",\\"left\\":0,\\"right\\":0,\\"top\\":0,\\"bottom\\":0},\\"source\\":{\\"uri\\":\\"https://open.rocket.chat/avatar/rocket.cat?format=png&size=56\\",\\"headers\\":{\\"User-Agent\\":\\"RC Mobile; ios unknown; vunknown (unknown)\\"},\\"priority\\":\\"high\\"},\\"resizeMode\\":\\"cover\\"},\\"children\\":null}]}]},{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"marginRight\\":8,\\"maxWidth\\":120}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"fontSize\\":16,\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#2f343d\\"}],\\"numberOfLines\\":1},\\"children\\":[\\"Rocket.Cat\\"]}]},{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":16,\\"color\\":\\"#6C727A\\"},null,{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]}]}]}]}"`;
exports[`Storyshots Chip Chip With Short Text 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flex\\":1,\\"alignItems\\":\\"flex-start\\",\\"padding\\":16}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityState\\":{\\"disabled\\":false},\\"focusable\\":true,\\"style\\":[{\\"paddingHorizontal\\":8,\\"marginRight\\":8,\\"borderRadius\\":2,\\"justifyContent\\":\\"center\\",\\"maxWidth\\":192},{\\"backgroundColor\\":\\"#efeff4\\"},null],\\"collapsable\\":false},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flexDirection\\":\\"row\\",\\"alignItems\\":\\"center\\"}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"width\\":28,\\"height\\":28,\\"borderRadius\\":4},{\\"marginRight\\":8,\\"marginVertical\\":8}],\\"testID\\":\\"avatar\\"},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"overflow\\":\\"hidden\\"},{\\"width\\":28,\\"height\\":28,\\"borderRadius\\":4}]},\\"children\\":[{\\"type\\":\\"FastImageView\\",\\"props\\":{\\"style\\":{\\"position\\":\\"absolute\\",\\"left\\":0,\\"right\\":0,\\"top\\":0,\\"bottom\\":0},\\"source\\":{\\"uri\\":\\"https://open.rocket.chat/avatar/rocket.cat?format=png&size=56\\",\\"headers\\":{\\"User-Agent\\":\\"RC Mobile; ios unknown; vunknown (unknown)\\"},\\"priority\\":\\"high\\"},\\"resizeMode\\":\\"cover\\"},\\"children\\":null}]}]},{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"marginRight\\":8,\\"maxWidth\\":120}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"fontSize\\":16,\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#2f343d\\"}],\\"numberOfLines\\":1},\\"children\\":[\\"Short\\"]}]},{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":16,\\"color\\":\\"#6C727A\\"},null,{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]}]}]}]}"`;
exports[`Storyshots Chip Chip With Short Text 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flex\\":1,\\"alignItems\\":\\"flex-start\\",\\"padding\\":16}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityState\\":{\\"disabled\\":false},\\"focusable\\":true,\\"style\\":[{\\"paddingHorizontal\\":8,\\"marginRight\\":8,\\"borderRadius\\":4,\\"justifyContent\\":\\"center\\",\\"maxWidth\\":192},{\\"backgroundColor\\":\\"#efeff4\\"},null],\\"collapsable\\":false},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flexDirection\\":\\"row\\",\\"alignItems\\":\\"center\\"}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"width\\":28,\\"height\\":28,\\"borderRadius\\":4},{\\"marginRight\\":8,\\"marginVertical\\":8}],\\"testID\\":\\"avatar\\"},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"overflow\\":\\"hidden\\"},{\\"width\\":28,\\"height\\":28,\\"borderRadius\\":4}]},\\"children\\":[{\\"type\\":\\"FastImageView\\",\\"props\\":{\\"style\\":{\\"position\\":\\"absolute\\",\\"left\\":0,\\"right\\":0,\\"top\\":0,\\"bottom\\":0},\\"source\\":{\\"uri\\":\\"https://open.rocket.chat/avatar/rocket.cat?format=png&size=56\\",\\"headers\\":{\\"User-Agent\\":\\"RC Mobile; ios unknown; vunknown (unknown)\\"},\\"priority\\":\\"high\\"},\\"resizeMode\\":\\"cover\\"},\\"children\\":null}]}]},{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"marginRight\\":8,\\"maxWidth\\":120}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"fontSize\\":16,\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#2f343d\\"}],\\"numberOfLines\\":1},\\"children\\":[\\"Short\\"]}]},{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":16,\\"color\\":\\"#6C727A\\"},null,{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]}]}]}]}"`;
exports[`Storyshots Chip Chip Without Avatar 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flex\\":1,\\"alignItems\\":\\"flex-start\\",\\"padding\\":16}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityState\\":{\\"disabled\\":false},\\"focusable\\":true,\\"style\\":[{\\"paddingHorizontal\\":8,\\"marginRight\\":8,\\"borderRadius\\":2,\\"justifyContent\\":\\"center\\",\\"maxWidth\\":192},{\\"backgroundColor\\":\\"#efeff4\\"},null],\\"collapsable\\":false},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flexDirection\\":\\"row\\",\\"alignItems\\":\\"center\\"}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"marginRight\\":8,\\"maxWidth\\":120}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"fontSize\\":16,\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#2f343d\\"}],\\"numberOfLines\\":1},\\"children\\":[\\"Without Avatar\\"]}]},{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":16,\\"color\\":\\"#6C727A\\"},null,{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]}]}]}]}"`;
exports[`Storyshots Chip Chip Without Avatar 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flex\\":1,\\"alignItems\\":\\"flex-start\\",\\"padding\\":16}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityState\\":{\\"disabled\\":false},\\"focusable\\":true,\\"style\\":[{\\"paddingHorizontal\\":8,\\"marginRight\\":8,\\"borderRadius\\":4,\\"justifyContent\\":\\"center\\",\\"maxWidth\\":192},{\\"backgroundColor\\":\\"#efeff4\\"},null],\\"collapsable\\":false},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flexDirection\\":\\"row\\",\\"alignItems\\":\\"center\\"}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"marginRight\\":8,\\"maxWidth\\":120}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"fontSize\\":16,\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#2f343d\\"}],\\"numberOfLines\\":1},\\"children\\":[\\"Without Avatar\\"]}]},{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":16,\\"color\\":\\"#6C727A\\"},null,{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]}]}]}]}"`;
exports[`Storyshots Chip Chip Without Avatar And Icon 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flex\\":1,\\"alignItems\\":\\"flex-start\\",\\"padding\\":16}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityState\\":{\\"disabled\\":true},\\"focusable\\":true,\\"style\\":[{\\"paddingHorizontal\\":8,\\"marginRight\\":8,\\"borderRadius\\":2,\\"justifyContent\\":\\"center\\",\\"maxWidth\\":192},{\\"backgroundColor\\":\\"#efeff4\\"},null],\\"collapsable\\":false},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flexDirection\\":\\"row\\",\\"alignItems\\":\\"center\\"}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"marginRight\\":8,\\"maxWidth\\":120}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"fontSize\\":16,\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#2f343d\\"}],\\"numberOfLines\\":1},\\"children\\":[\\"Without Avatar and Icon\\"]}]}]}]}]}"`;
exports[`Storyshots Chip Chip Without Avatar And Icon 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flex\\":1,\\"alignItems\\":\\"flex-start\\",\\"padding\\":16}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityState\\":{\\"disabled\\":true},\\"focusable\\":true,\\"style\\":[{\\"paddingHorizontal\\":8,\\"marginRight\\":8,\\"borderRadius\\":4,\\"justifyContent\\":\\"center\\",\\"maxWidth\\":192},{\\"backgroundColor\\":\\"#efeff4\\"},null],\\"collapsable\\":false},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flexDirection\\":\\"row\\",\\"alignItems\\":\\"center\\"}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"marginRight\\":8,\\"maxWidth\\":120}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"fontSize\\":16,\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#2f343d\\"}],\\"numberOfLines\\":1},\\"children\\":[\\"Without Avatar and Icon\\"]}]}]}]}]}"`;
exports[`Storyshots Chip Chip Without Icon 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flex\\":1,\\"alignItems\\":\\"flex-start\\",\\"padding\\":16}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityState\\":{\\"disabled\\":true},\\"focusable\\":true,\\"style\\":[{\\"paddingHorizontal\\":8,\\"marginRight\\":8,\\"borderRadius\\":2,\\"justifyContent\\":\\"center\\",\\"maxWidth\\":192},{\\"backgroundColor\\":\\"#efeff4\\"},null],\\"collapsable\\":false},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flexDirection\\":\\"row\\",\\"alignItems\\":\\"center\\"}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"width\\":28,\\"height\\":28,\\"borderRadius\\":4},{\\"marginRight\\":8,\\"marginVertical\\":8}],\\"testID\\":\\"avatar\\"},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"overflow\\":\\"hidden\\"},{\\"width\\":28,\\"height\\":28,\\"borderRadius\\":4}]},\\"children\\":[{\\"type\\":\\"FastImageView\\",\\"props\\":{\\"style\\":{\\"position\\":\\"absolute\\",\\"left\\":0,\\"right\\":0,\\"top\\":0,\\"bottom\\":0},\\"source\\":{\\"uri\\":\\"https://open.rocket.chat/avatar/rocket.cat?format=png&size=56\\",\\"headers\\":{\\"User-Agent\\":\\"RC Mobile; ios unknown; vunknown (unknown)\\"},\\"priority\\":\\"high\\"},\\"resizeMode\\":\\"cover\\"},\\"children\\":null}]}]},{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"marginRight\\":8,\\"maxWidth\\":120}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"fontSize\\":16,\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#2f343d\\"}],\\"numberOfLines\\":1},\\"children\\":[\\"Without Icon\\"]}]}]}]}]}"`;
exports[`Storyshots Chip Chip Without Icon 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flex\\":1,\\"alignItems\\":\\"flex-start\\",\\"padding\\":16}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityState\\":{\\"disabled\\":true},\\"focusable\\":true,\\"style\\":[{\\"paddingHorizontal\\":8,\\"marginRight\\":8,\\"borderRadius\\":4,\\"justifyContent\\":\\"center\\",\\"maxWidth\\":192},{\\"backgroundColor\\":\\"#efeff4\\"},null],\\"collapsable\\":false},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flexDirection\\":\\"row\\",\\"alignItems\\":\\"center\\"}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"width\\":28,\\"height\\":28,\\"borderRadius\\":4},{\\"marginRight\\":8,\\"marginVertical\\":8}],\\"testID\\":\\"avatar\\"},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"overflow\\":\\"hidden\\"},{\\"width\\":28,\\"height\\":28,\\"borderRadius\\":4}]},\\"children\\":[{\\"type\\":\\"FastImageView\\",\\"props\\":{\\"style\\":{\\"position\\":\\"absolute\\",\\"left\\":0,\\"right\\":0,\\"top\\":0,\\"bottom\\":0},\\"source\\":{\\"uri\\":\\"https://open.rocket.chat/avatar/rocket.cat?format=png&size=56\\",\\"headers\\":{\\"User-Agent\\":\\"RC Mobile; ios unknown; vunknown (unknown)\\"},\\"priority\\":\\"high\\"},\\"resizeMode\\":\\"cover\\"},\\"children\\":null}]}]},{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"marginRight\\":8,\\"maxWidth\\":120}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"fontSize\\":16,\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#2f343d\\"}],\\"numberOfLines\\":1},\\"children\\":[\\"Without Icon\\"]}]}]}]}]}"`;

View File

@ -1,5 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Storyshots Login Services Separators 1`] = `"[{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityLabel\\":\\"More options\\",\\"accessibilityState\\":{\\"disabled\\":false},\\"focusable\\":true,\\"collapsable\\":false,\\"style\\":{\\"paddingHorizontal\\":14,\\"justifyContent\\":\\"center\\",\\"height\\":48,\\"borderRadius\\":2,\\"marginBottom\\":0,\\"backgroundColor\\":\\"#ffffff\\",\\"opacity\\":1}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"textAlign\\":\\"center\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#1d74f5\\",\\"fontSize\\":16},null],\\"accessibilityLabel\\":\\"More options\\"},\\"children\\":[\\"More options\\"]}]},{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flexDirection\\":\\"row\\",\\"alignItems\\":\\"center\\",\\"marginVertical\\":24}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"height\\":1,\\"flex\\":1},{\\"backgroundColor\\":\\"#e1e5e8\\"}]},\\"children\\":null},{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"fontSize\\":14,\\"marginLeft\\":14,\\"marginRight\\":14,\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#9ca2a8\\"}]},\\"children\\":[\\"OR\\"]},{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"height\\":1,\\"flex\\":1},{\\"backgroundColor\\":\\"#e1e5e8\\"}]},\\"children\\":null}]},{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityLabel\\":\\"Less options\\",\\"accessibilityState\\":{\\"disabled\\":false},\\"focusable\\":true,\\"collapsable\\":false,\\"style\\":{\\"paddingHorizontal\\":14,\\"justifyContent\\":\\"center\\",\\"height\\":48,\\"borderRadius\\":2,\\"marginBottom\\":0,\\"backgroundColor\\":\\"#ffffff\\",\\"opacity\\":1}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"textAlign\\":\\"center\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#1d74f5\\",\\"fontSize\\":16},null],\\"accessibilityLabel\\":\\"Less options\\"},\\"children\\":[\\"Less options\\"]}]},{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flexDirection\\":\\"row\\",\\"alignItems\\":\\"center\\",\\"marginVertical\\":24}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"height\\":1,\\"flex\\":1},{\\"backgroundColor\\":\\"#e1e5e8\\"}]},\\"children\\":null},{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"fontSize\\":14,\\"marginLeft\\":14,\\"marginRight\\":14,\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#9ca2a8\\"}]},\\"children\\":[\\"OR\\"]},{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"height\\":1,\\"flex\\":1},{\\"backgroundColor\\":\\"#e1e5e8\\"}]},\\"children\\":null}]}]"`;
exports[`Storyshots Login Services Separators 1`] = `"[{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityLabel\\":\\"More options\\",\\"accessibilityState\\":{\\"disabled\\":false},\\"focusable\\":true,\\"collapsable\\":false,\\"style\\":{\\"paddingHorizontal\\":14,\\"justifyContent\\":\\"center\\",\\"height\\":48,\\"borderRadius\\":4,\\"marginBottom\\":0,\\"backgroundColor\\":\\"#ffffff\\",\\"opacity\\":1}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"textAlign\\":\\"center\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#1d74f5\\",\\"fontSize\\":16},null],\\"accessibilityLabel\\":\\"More options\\"},\\"children\\":[\\"More options\\"]}]},{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flexDirection\\":\\"row\\",\\"alignItems\\":\\"center\\",\\"marginVertical\\":24}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"height\\":1,\\"flex\\":1},{\\"backgroundColor\\":\\"#e1e5e8\\"}]},\\"children\\":null},{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"fontSize\\":14,\\"marginLeft\\":14,\\"marginRight\\":14,\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#9ca2a8\\"}]},\\"children\\":[\\"OR\\"]},{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"height\\":1,\\"flex\\":1},{\\"backgroundColor\\":\\"#e1e5e8\\"}]},\\"children\\":null}]},{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityLabel\\":\\"Less options\\",\\"accessibilityState\\":{\\"disabled\\":false},\\"focusable\\":true,\\"collapsable\\":false,\\"style\\":{\\"paddingHorizontal\\":14,\\"justifyContent\\":\\"center\\",\\"height\\":48,\\"borderRadius\\":4,\\"marginBottom\\":0,\\"backgroundColor\\":\\"#ffffff\\",\\"opacity\\":1}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"textAlign\\":\\"center\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#1d74f5\\",\\"fontSize\\":16},null],\\"accessibilityLabel\\":\\"Less options\\"},\\"children\\":[\\"Less options\\"]}]},{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flexDirection\\":\\"row\\",\\"alignItems\\":\\"center\\",\\"marginVertical\\":24}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"height\\":1,\\"flex\\":1},{\\"backgroundColor\\":\\"#e1e5e8\\"}]},\\"children\\":null},{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"fontSize\\":14,\\"marginLeft\\":14,\\"marginRight\\":14,\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#9ca2a8\\"}]},\\"children\\":[\\"OR\\"]},{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"height\\":1,\\"flex\\":1},{\\"backgroundColor\\":\\"#e1e5e8\\"}]},\\"children\\":null}]}]"`;
exports[`Storyshots Login Services Service List 1`] = `"[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"borderRadius\\":2,\\"width\\":\\"100%\\",\\"height\\":48,\\"flexDirection\\":\\"row\\",\\"alignItems\\":\\"center\\",\\"justifyContent\\":\\"center\\",\\"paddingHorizontal\\":15}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":24,\\"color\\":\\"#0d0e12\\"},{\\"position\\":\\"absolute\\",\\"left\\":15,\\"top\\":12,\\"width\\":24,\\"height\\":24},{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]},{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"400\\",\\"fontSize\\":16},{\\"color\\":\\"#0d0e12\\"}]},\\"children\\":[\\"Continue with\\",\\" \\",{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":{\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"600\\"}},\\"children\\":[\\"github\\"]}]}]},{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"borderRadius\\":2,\\"width\\":\\"100%\\",\\"height\\":48,\\"flexDirection\\":\\"row\\",\\"alignItems\\":\\"center\\",\\"justifyContent\\":\\"center\\",\\"paddingHorizontal\\":15}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":24,\\"color\\":\\"#0d0e12\\"},{\\"position\\":\\"absolute\\",\\"left\\":15,\\"top\\":12,\\"width\\":24,\\"height\\":24},{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]},{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"400\\",\\"fontSize\\":16},{\\"color\\":\\"#0d0e12\\"}]},\\"children\\":[\\"Continue with\\",\\" \\",{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":{\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"600\\"}},\\"children\\":[\\"gitlab\\"]}]}]},{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"borderRadius\\":2,\\"width\\":\\"100%\\",\\"height\\":48,\\"flexDirection\\":\\"row\\",\\"alignItems\\":\\"center\\",\\"justifyContent\\":\\"center\\",\\"paddingHorizontal\\":15}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":24,\\"color\\":\\"#0d0e12\\"},{\\"position\\":\\"absolute\\",\\"left\\":15,\\"top\\":12,\\"width\\":24,\\"height\\":24},{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]},{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"400\\",\\"fontSize\\":16},{\\"color\\":\\"#0d0e12\\"}]},\\"children\\":[\\"Continue with\\",\\" \\",{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":{\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"600\\"}},\\"children\\":[\\"google\\"]}]}]},{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"borderRadius\\":2,\\"width\\":\\"100%\\",\\"height\\":48,\\"flexDirection\\":\\"row\\",\\"alignItems\\":\\"center\\",\\"justifyContent\\":\\"center\\",\\"paddingHorizontal\\":15}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":24,\\"color\\":\\"#0d0e12\\"},{\\"position\\":\\"absolute\\",\\"left\\":15,\\"top\\":12,\\"width\\":24,\\"height\\":24},{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]},{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"400\\",\\"fontSize\\":16},{\\"color\\":\\"#0d0e12\\"}]},\\"children\\":[\\"Continue with\\",\\" \\",{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":{\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"600\\"}},\\"children\\":[\\"apple\\"]}]}]}]"`;
exports[`Storyshots Login Services Service List 1`] = `"[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"borderRadius\\":4,\\"width\\":\\"100%\\",\\"height\\":48,\\"flexDirection\\":\\"row\\",\\"alignItems\\":\\"center\\",\\"justifyContent\\":\\"center\\",\\"paddingHorizontal\\":15}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":24,\\"color\\":\\"#0d0e12\\"},{\\"position\\":\\"absolute\\",\\"left\\":15,\\"top\\":12,\\"width\\":24,\\"height\\":24},{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]},{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"400\\",\\"fontSize\\":16},{\\"color\\":\\"#0d0e12\\"}]},\\"children\\":[\\"Continue with\\",\\" \\",{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":{\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"600\\"}},\\"children\\":[\\"github\\"]}]}]},{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"borderRadius\\":4,\\"width\\":\\"100%\\",\\"height\\":48,\\"flexDirection\\":\\"row\\",\\"alignItems\\":\\"center\\",\\"justifyContent\\":\\"center\\",\\"paddingHorizontal\\":15}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":24,\\"color\\":\\"#0d0e12\\"},{\\"position\\":\\"absolute\\",\\"left\\":15,\\"top\\":12,\\"width\\":24,\\"height\\":24},{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]},{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"400\\",\\"fontSize\\":16},{\\"color\\":\\"#0d0e12\\"}]},\\"children\\":[\\"Continue with\\",\\" \\",{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":{\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"600\\"}},\\"children\\":[\\"gitlab\\"]}]}]},{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"borderRadius\\":4,\\"width\\":\\"100%\\",\\"height\\":48,\\"flexDirection\\":\\"row\\",\\"alignItems\\":\\"center\\",\\"justifyContent\\":\\"center\\",\\"paddingHorizontal\\":15}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":24,\\"color\\":\\"#0d0e12\\"},{\\"position\\":\\"absolute\\",\\"left\\":15,\\"top\\":12,\\"width\\":24,\\"height\\":24},{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]},{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"400\\",\\"fontSize\\":16},{\\"color\\":\\"#0d0e12\\"}]},\\"children\\":[\\"Continue with\\",\\" \\",{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":{\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"600\\"}},\\"children\\":[\\"google\\"]}]}]},{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"borderRadius\\":4,\\"width\\":\\"100%\\",\\"height\\":48,\\"flexDirection\\":\\"row\\",\\"alignItems\\":\\"center\\",\\"justifyContent\\":\\"center\\",\\"paddingHorizontal\\":15}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":24,\\"color\\":\\"#0d0e12\\"},{\\"position\\":\\"absolute\\",\\"left\\":15,\\"top\\":12,\\"width\\":24,\\"height\\":24},{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]},{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"400\\",\\"fontSize\\":16},{\\"color\\":\\"#0d0e12\\"}]},\\"children\\":[\\"Continue with\\",\\" \\",{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":{\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"600\\"}},\\"children\\":[\\"apple\\"]}]}]}]"`;

File diff suppressed because one or more lines are too long

View File

@ -1,3 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Storyshots SearchBox Basic 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"testID\\":\\"searchbox\\",\\"style\\":{\\"backgroundColor\\":\\"#ffffff\\"}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"marginBottom\\":10},{\\"margin\\":16,\\"marginBottom\\":16}]},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"position\\":\\"relative\\",\\"justifyContent\\":\\"center\\"}},\\"children\\":[{\\"type\\":\\"TextInput\\",\\"props\\":{\\"style\\":[{\\"color\\":\\"#0d0e12\\"},[{\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"400\\",\\"height\\":48,\\"fontSize\\":16,\\"paddingHorizontal\\":16,\\"paddingVertical\\":10,\\"borderWidth\\":2,\\"borderRadius\\":2},null,{\\"paddingRight\\":45},{\\"backgroundColor\\":\\"#ffffff\\",\\"borderColor\\":\\"#cbcbcc\\",\\"color\\":\\"#0d0e12\\"},null,null],{\\"textAlign\\":\\"auto\\"}],\\"placeholderTextColor\\":\\"#9ca2a8\\",\\"keyboardAppearance\\":\\"light\\",\\"autoCorrect\\":false,\\"autoCapitalize\\":\\"none\\",\\"underlineColorAndroid\\":\\"transparent\\",\\"accessibilityLabel\\":\\"Search\\",\\"placeholder\\":\\"Search\\",\\"value\\":\\"\\",\\"blurOnSubmit\\":true,\\"returnKeyType\\":\\"search\\"},\\"children\\":null},{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":20,\\"color\\":\\"#2f343d\\"},[{\\"position\\":\\"absolute\\"},{\\"right\\":12}],{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]}]}]}]}"`;
exports[`Storyshots SearchBox Basic 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"testID\\":\\"searchbox\\",\\"style\\":{\\"backgroundColor\\":\\"#ffffff\\"}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"marginBottom\\":10},{\\"margin\\":16,\\"marginBottom\\":16}]},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"position\\":\\"relative\\",\\"justifyContent\\":\\"center\\"}},\\"children\\":[{\\"type\\":\\"TextInput\\",\\"props\\":{\\"style\\":[{\\"color\\":\\"#0d0e12\\"},[{\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"400\\",\\"height\\":48,\\"fontSize\\":16,\\"paddingHorizontal\\":16,\\"paddingVertical\\":10,\\"borderWidth\\":1,\\"borderRadius\\":4},null,{\\"paddingRight\\":45},{\\"backgroundColor\\":\\"#ffffff\\",\\"borderColor\\":\\"#cbcbcc\\",\\"color\\":\\"#0d0e12\\"},null,null],{\\"textAlign\\":\\"auto\\"}],\\"placeholderTextColor\\":\\"#9ca2a8\\",\\"keyboardAppearance\\":\\"light\\",\\"autoCorrect\\":false,\\"autoCapitalize\\":\\"none\\",\\"underlineColorAndroid\\":\\"transparent\\",\\"accessibilityLabel\\":\\"Search\\",\\"placeholder\\":\\"Search\\",\\"value\\":\\"\\",\\"blurOnSubmit\\":true,\\"returnKeyType\\":\\"search\\"},\\"children\\":null},{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":20,\\"color\\":\\"#2f343d\\"},[{\\"position\\":\\"absolute\\"},{\\"right\\":12}],{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]}]}]}]}"`;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -147,7 +147,7 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode VERSIONCODE as Integer
versionName "4.33.0"
versionName "4.37.0"
vectorDrawables.useSupportLibrary = true
if (!isFoss) {
manifestPlaceholders = [BugsnagAPIKey: BugsnagAPIKey as String]
@ -250,6 +250,7 @@ android {
release {
minifyEnabled enableProguardInReleaseBuilds
setProguardFiles([getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'])
proguardFile "${rootProject.projectDir}/../node_modules/detox/android/detox/proguard-rules-app.pro"
signingConfig signingConfigs.release
if (!isFoss) {
firebaseCrashlytics {
@ -268,6 +269,11 @@ android {
// pickFirst '**/x86_64/libc++_shared.so'
// }
// FIXME: Remove when we update RN
packagingOptions {
pickFirst '**/*.so'
}
// applicationVariants are e.g. debug, release
flavorDimensions "app", "type"
@ -280,10 +286,6 @@ android {
dimension = "app"
buildConfigField "boolean", "IS_OFFICIAL", "false"
}
e2e {
dimension = "app"
buildConfigField "boolean", "IS_OFFICIAL", "false"
}
foss {
dimension = "type"
buildConfigField "boolean", "FDROID_BUILD", "true"
@ -311,16 +313,6 @@ android {
java.srcDirs = ['src/main/java', 'src/play/java']
manifest.srcFile 'src/play/AndroidManifest.xml'
}
e2ePlayDebug {
java.srcDirs = ['src/main/java', 'src/play/java']
res.srcDirs = ['src/experimental/res']
manifest.srcFile 'src/play/AndroidManifest.xml'
}
e2ePlayRelease {
java.srcDirs = ['src/main/java', 'src/play/java']
res.srcDirs = ['src/experimental/res']
manifest.srcFile 'src/play/AndroidManifest.xml'
}
}
applicationVariants.all { variant ->
@ -357,9 +349,6 @@ dependencies {
playImplementation project(':@react-native-firebase_app')
playImplementation project(':@react-native-firebase_analytics')
playImplementation project(':@react-native-firebase_crashlytics')
implementation(project(':react-native-jitsi-meet')) { // https://github.com/skrafft/react-native-jitsi-meet#side-note
exclude group: 'com.facebook.react',module:'react-native-svg'
}
implementation fileTree(dir: "libs", include: ["*.jar"])
//noinspection GradleDynamicVersion
@ -388,8 +377,9 @@ dependencies {
implementation "com.github.bumptech.glide:glide:4.9.0"
annotationProcessor "com.github.bumptech.glide:compiler:4.9.0"
implementation "com.tencent:mmkv-static:1.2.10"
androidTestImplementation('com.wix:detox:+') { transitive = true }
androidTestImplementation 'junit:junit:4.12'
androidTestImplementation('com.wix:detox:+')
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'com.facebook.soloader:soloader:0.10.4'
}
if (isNewArchitectureEnabled()) {

View File

@ -18,7 +18,7 @@ public class DetoxTest {
@Rule
// Replace 'MainActivity' with the value of android:name entry in
// <activity> in AndroidManifest.xml
public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>(MainActivity.class, false, false);
public ActivityTestRule<chat.rocket.reactnative.MainActivity> mActivityRule = new ActivityTestRule<>(chat.rocket.reactnative.MainActivity.class, false, false);
@Test
public void runDetoxTests() {

View File

@ -1,25 +0,0 @@
package chat.rocket.reactnative;
import android.content.Context;
import com.facebook.react.ReactInstanceManager;
public class MainDebugApplication extends MainApplication {
@Override
public void onCreate() {
super.onCreate();
initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
}
/**
* Loads Flipper in React Native templates. Call this in the onCreate method with something like
* initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
*
* @param context
* @param reactInstanceManager
*/
private static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
ReactNativeFlipper.initializeFlipper(context, reactInstanceManager);
}
}

View File

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config xmlns:tools="http://schemas.android.com/tools">
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<certificates src="system" />
<certificates src="user"
tools:ignore="AcceptsUserCertificates" />
</trust-anchors>
</base-config>
</network-security-config>

View File

@ -5,6 +5,15 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.VIDEO_CAPTURE" />
<uses-permission android:name="android.permission.AUDIO_CAPTURE" />
<!-- permissions related to jitsi call -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<application
android:name="chat.rocket.reactnative.MainApplication"
android:allowBackup="false"
@ -14,6 +23,7 @@
android:requestLegacyExternalStorage="true"
android:supportsRtl="true"
android:theme="@style/BootTheme"
android:hardwareAccelerated="true"
tools:replace="android:allowBackup">
<activity
android:name="chat.rocket.reactnative.MainActivity"
@ -69,5 +79,10 @@
</intent-filter>
</activity>
</application>
<queries>
<package android:name="org.jitsi.meet" />
<intent>
<action android:name="android.intent.action.SEND" />
</intent>
</queries>
</manifest>

View File

@ -9,13 +9,16 @@ import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.config.ReactFeatureFlags;
import com.facebook.react.ReactInstanceManager;
import com.facebook.soloader.SoLoader;
import com.reactnativecommunity.viewpager.RNCViewPagerPackage;
import com.facebook.react.bridge.JSIModulePackage;
import com.swmansion.reanimated.ReanimatedJSIModulePackage;
import android.content.Context;
import android.content.res.Configuration;
import expo.modules.ApplicationLifecycleDispatcher;
import expo.modules.ReactNativeHostWrapper;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.List;
@ -76,6 +79,7 @@ public class MainApplication extends Application implements ReactApplication {
// If you opted-in for the New Architecture, we enable the TurboModule system
ReactFeatureFlags.useTurboModules = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
SoLoader.init(this, /* native exopackage */ false);
initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
ApplicationLifecycleDispatcher.onApplicationCreate(this);
}
@ -84,4 +88,35 @@ public class MainApplication extends Application implements ReactApplication {
super.onConfigurationChanged(newConfig);
ApplicationLifecycleDispatcher.onConfigurationChanged(this, newConfig);
}
/**
* Loads Flipper in React Native templates. Call this in the onCreate method with something like
* initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
*
* @param context
* @param reactInstanceManager
*/
private static void initializeFlipper(
Context context, ReactInstanceManager reactInstanceManager) {
if (BuildConfig.DEBUG) {
try {
/*
We use reflection here to pick up the class that initializes Flipper,
since Flipper library is not available in release mode
*/
Class<?> aClass = Class.forName("chat.rocket.reactnative.ReactNativeFlipper");
aClass
.getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
.invoke(null, context, reactInstanceManager);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}

View File

@ -7,4 +7,8 @@
tools:ignore="AcceptsUserCertificates" />
</trust-anchors>
</base-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">10.0.2.2</domain>
<domain includeSubdomains="true">localhost</domain>
</domain-config>
</network-security-config>

View File

@ -1,9 +1,5 @@
import org.apache.tools.ant.taskdefs.condition.Os
def safeExtGet(prop, fallback) {
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
}
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
def taskRequests = getGradle().getStartParameter().getTaskRequests().toString().toLowerCase()
@ -26,8 +22,6 @@ buildscript {
kotlinVersion = '1.6.10'
supportLibVersion = "28.0.0"
libre_build = !(isPlay.toBoolean())
jitsi_url = "https://github.com/RocketChat/jitsi-maven-repository/raw/master/releases"
jitsi_version = "3.7.0"
}
repositories {
@ -68,9 +62,6 @@ allprojects {
url "$rootDir/../node_modules/detox/Detox-android"
}
maven {
url jitsi_url
}
mavenCentral {
content {
excludeGroup "com.facebook.react"
@ -80,5 +71,38 @@ allprojects {
google()
maven { url 'https://maven.google.com' }
maven { url 'https://www.jitpack.io' }
// https://stackoverflow.com/a/74333788/5447468
// TODO: remove once we update RN
exclusiveContent {
// We get React Native's Android binaries exclusively through npm,
// from a local Maven repo inside node_modules/react-native/.
// (The use of exclusiveContent prevents looking elsewhere like Maven Central
// and potentially getting a wrong version.)
filter {
includeGroup "com.facebook.react"
}
forRepository {
maven {
// NOTE: if you are in a monorepo, you may have "$rootDir/../../../node_modules/react-native/android"
url "$rootDir/../node_modules/react-native/android"
}
}
}
}
}
subprojects { subproject ->
afterEvaluate {
if (!project.name.equalsIgnoreCase("app") && project.hasProperty("android")) {
android {
compileSdkVersion 31
buildToolsVersion "31.0.0"
defaultConfig {
minSdkVersion 23
targetSdkVersion 31
}
}
}
}
}

View File

@ -23,7 +23,7 @@ android.useAndroidX=true
android.enableJetifier=true
# Version of flipper SDK to use with React Native
FLIPPER_VERSION=0.125.0
FLIPPER_VERSION=0.175.0
# Use this property to specify which architecture you want to build.
# You can also override it from the CLI using

View File

@ -28,7 +28,9 @@ export const ROOM = createRequestTypes('ROOM', [
'DELETE',
'REMOVED',
'FORWARD',
'USER_TYPING'
'USER_TYPING',
'HISTORY_REQUEST',
'HISTORY_FINISHED'
]);
export const INQUIRY = createRequestTypes('INQUIRY', [
...defaultTypes,
@ -38,7 +40,14 @@ export const INQUIRY = createRequestTypes('INQUIRY', [
'QUEUE_UPDATE',
'QUEUE_REMOVE'
]);
export const APP = createRequestTypes('APP', ['START', 'READY', 'INIT', 'INIT_LOCAL_SETTINGS', 'SET_MASTER_DETAIL']);
export const APP = createRequestTypes('APP', [
'START',
'READY',
'INIT',
'INIT_LOCAL_SETTINGS',
'SET_MASTER_DETAIL',
'SET_NOTIFICATION_PRESENCE_CAP'
]);
export const MESSAGES = createRequestTypes('MESSAGES', ['REPLY_BROADCAST']);
export const CREATE_CHANNEL = createRequestTypes('CREATE_CHANNEL', [...defaultTypes]);
export const CREATE_DISCUSSION = createRequestTypes('CREATE_DISCUSSION', [...defaultTypes]);

View File

@ -12,7 +12,11 @@ interface ISetMasterDetail extends Action {
isMasterDetail: boolean;
}
export type TActionApp = IAppStart & ISetMasterDetail;
interface ISetNotificationPresenceCap extends Action {
show: boolean;
}
export type TActionApp = IAppStart & ISetMasterDetail & ISetNotificationPresenceCap;
interface Params {
root: RootEnum;
@ -51,3 +55,10 @@ export function setMasterDetail(isMasterDetail: boolean): ISetMasterDetail {
isMasterDetail
};
}
export function setNotificationPresenceCap(show: boolean): ISetNotificationPresenceCap {
return {
type: APP.SET_NOTIFICATION_PRESENCE_CAP,
show
};
}

View File

@ -1,6 +1,6 @@
import { Action } from 'redux';
import { ERoomType } from '../definitions/ERoomType';
import { ERoomType, RoomType } from '../definitions';
import { ROOM } from './actionsTypes';
// TYPE RETURN RELATED
@ -44,7 +44,24 @@ interface IUserTyping extends Action {
status: boolean;
}
export type TActionsRoom = TSubscribeRoom & TUnsubscribeRoom & ILeaveRoom & IDeleteRoom & IForwardRoom & IUserTyping;
export interface IRoomHistoryRequest extends Action {
rid: string;
t: RoomType;
loaderId: string;
}
export interface IRoomHistoryFinished extends Action {
loaderId: string;
}
export type TActionsRoom = TSubscribeRoom &
TUnsubscribeRoom &
ILeaveRoom &
IDeleteRoom &
IForwardRoom &
IUserTyping &
IRoomHistoryRequest &
IRoomHistoryFinished;
export function subscribeRoom(rid: string): TSubscribeRoom {
return {
@ -99,3 +116,19 @@ export function userTyping(rid: string, status = true): IUserTyping {
status
};
}
export function roomHistoryRequest({ rid, t, loaderId }: { rid: string; t: RoomType; loaderId: string }): IRoomHistoryRequest {
return {
type: ROOM.HISTORY_REQUEST,
rid,
t,
loaderId
};
}
export function roomHistoryFinished({ loaderId }: { loaderId: string }): IRoomHistoryFinished {
return {
type: ROOM.HISTORY_FINISHED,
loaderId
};
}

View File

@ -122,7 +122,6 @@ const ActionSheetContentWithInputAndSubmit = ({
}}
testID={testID}
secureTextEntry={secureTextEntry}
inputStyle={{ borderWidth: 2 }}
bottomSheet={isIOS}
/>
) : null}

View File

@ -52,7 +52,7 @@ export default StyleSheet.create({
paddingHorizontal: 14,
justifyContent: 'center',
height: ITEM_HEIGHT,
borderRadius: 2,
borderRadius: 4,
marginBottom: 12
},
text: {

View File

@ -1,10 +1,11 @@
import React from 'react';
import { ViewStyle } from 'react-native';
import { TGetCustomEmoji } from '../../definitions/IEmoji';
export interface IAvatar {
server?: string;
style?: any;
style?: ViewStyle;
text?: string;
avatar?: string;
emoji?: string;

View File

@ -22,7 +22,7 @@ const styles = StyleSheet.create({
paddingHorizontal: 14,
justifyContent: 'center',
height: 48,
borderRadius: 2,
borderRadius: 4,
marginBottom: 12
},
text: {

View File

@ -10,7 +10,7 @@ const styles = StyleSheet.create({
pressable: {
paddingHorizontal: 8,
marginRight: 8,
borderRadius: 2,
borderRadius: 4,
justifyContent: 'center',
maxWidth: 192
},

View File

@ -1,7 +1,10 @@
export const mappedIcons = {
'lamp-bulb': 59812,
'status-disabled': 59837,
'lamp-bulb': 59836,
'phone-in': 59835,
'basketball': 59776,
'percentage': 59777,
'glasses': 59812,
'burger': 59813,
'leaf': 59814,
'airplane': 59815,

File diff suppressed because one or more lines are too long

View File

@ -1,34 +1,31 @@
import React from 'react';
import { useWindowDimensions } from 'react-native';
import { FlatList } from 'react-native-gesture-handler';
import { EMOJI_BUTTON_SIZE } from './styles';
import scrollPersistTaps from '../../lib/methods/helpers/scrollPersistTaps';
import { IEmoji } from '../../definitions/IEmoji';
import scrollPersistTaps from '../../lib/methods/helpers/scrollPersistTaps';
import { PressableEmoji } from './PressableEmoji';
import { EMOJI_BUTTON_SIZE } from './styles';
interface IEmojiCategoryProps {
emojis: IEmoji[];
onEmojiSelected: (emoji: IEmoji) => void;
tabLabel?: string; // needed for react-native-scrollable-tab-view only
parentWidth: number;
}
const EmojiCategory = ({ onEmojiSelected, emojis }: IEmojiCategoryProps): React.ReactElement | null => {
const { width } = useWindowDimensions();
const numColumns = Math.trunc(width / EMOJI_BUTTON_SIZE);
const marginHorizontal = (width % EMOJI_BUTTON_SIZE) / 2;
const renderItem = ({ item }: { item: IEmoji }) => <PressableEmoji emoji={item} onPress={onEmojiSelected} />;
if (!width) {
const EmojiCategory = ({ onEmojiSelected, emojis, parentWidth }: IEmojiCategoryProps): React.ReactElement | null => {
if (!parentWidth) {
return null;
}
const numColumns = Math.trunc(parentWidth / EMOJI_BUTTON_SIZE);
const marginHorizontal = (parentWidth % EMOJI_BUTTON_SIZE) / 2;
const renderItem = ({ item }: { item: IEmoji }) => <PressableEmoji emoji={item} onPress={onEmojiSelected} />;
return (
<FlatList
// needed to update the numColumns when the width changes
key={`emoji-category-${width}`}
key={`emoji-category-${parentWidth}`}
keyExtractor={item => (typeof item === 'string' ? item : item.name)}
data={emojis}
renderItem={renderItem}

View File

@ -1,4 +1,4 @@
import React from 'react';
import React, { useState } from 'react';
import { View } from 'react-native';
import ScrollableTabView from 'react-native-scrollable-tab-view';
@ -20,6 +20,8 @@ const EmojiPicker = ({
searchedEmojis = []
}: IEmojiPickerProps): React.ReactElement | null => {
const { colors } = useTheme();
const [parentWidth, setParentWidth] = useState(0);
const { frequentlyUsed, loaded } = useFrequentlyUsedEmoji();
const allCustomEmojis: ICustomEmojis = useAppSelector(
@ -50,7 +52,14 @@ const EmojiPicker = ({
if (!emojis.length) {
return null;
}
return <EmojiCategory emojis={emojis} onEmojiSelected={(emoji: IEmoji) => handleEmojiSelect(emoji)} tabLabel={label} />;
return (
<EmojiCategory
parentWidth={parentWidth}
emojis={emojis}
onEmojiSelected={(emoji: IEmoji) => handleEmojiSelect(emoji)}
tabLabel={label}
/>
);
};
if (!loaded) {
@ -58,9 +67,13 @@ const EmojiPicker = ({
}
return (
<View style={styles.emojiPickerContainer}>
<View style={styles.emojiPickerContainer} onLayout={e => setParentWidth(e.nativeEvent.layout.width)}>
{searching ? (
<EmojiCategory emojis={searchedEmojis} onEmojiSelected={(emoji: IEmoji) => handleEmojiSelect(emoji)} />
<EmojiCategory
emojis={searchedEmojis}
onEmojiSelected={(emoji: IEmoji) => handleEmojiSelect(emoji)}
parentWidth={parentWidth}
/>
) : (
<ScrollableTabView
renderTabBar={() => <TabBar />}

View File

@ -1,6 +1,7 @@
import React from 'react';
import { StyleSheet } from 'react-native';
import { StyleSheet, View } from 'react-native';
import { STATUS_COLORS } from '../../lib/constants';
import UnreadBadge from '../UnreadBadge';
const styles = StyleSheet.create({
@ -15,6 +16,8 @@ const styles = StyleSheet.create({
}
});
export const Badge = ({ ...props }): React.ReactElement => <UnreadBadge {...props} style={styles.badgeContainer} small />;
export const BadgeUnread = ({ ...props }): React.ReactElement => <UnreadBadge {...props} style={styles.badgeContainer} small />;
export default Badge;
export const BadgeWarn = (): React.ReactElement => (
<View style={[styles.badgeContainer, { width: 10, height: 10, backgroundColor: STATUS_COLORS.disabled }]} />
);

View File

@ -1,4 +1,5 @@
import React from 'react';
import { View } from 'react-native';
import { Header, HeaderBackground } from '@react-navigation/elements';
import { NavigationContainer } from '@react-navigation/native';
import { SafeAreaProvider } from 'react-native-safe-area-context';
@ -103,9 +104,10 @@ export const Badge = () => (
<HeaderExample
left={() => (
<HeaderButton.Container left>
<HeaderButton.Item iconName='threads' badge={() => <HeaderButton.Badge tunread={[1]} />} />
<HeaderButton.Item iconName='threads' badge={() => <HeaderButton.Badge tunread={[1]} tunreadUser={[1]} />} />
<HeaderButton.Item iconName='threads' badge={() => <HeaderButton.Badge tunread={[1]} tunreadGroup={[1]} />} />
<HeaderButton.Item iconName='threads' badge={() => <HeaderButton.BadgeUnread tunread={[1]} />} />
<HeaderButton.Item iconName='threads' badge={() => <HeaderButton.BadgeUnread tunread={[1]} tunreadUser={[1]} />} />
<HeaderButton.Item iconName='threads' badge={() => <HeaderButton.BadgeUnread tunread={[1]} tunreadGroup={[1]} />} />
<HeaderButton.Drawer badge={() => <HeaderButton.BadgeWarn />} />
</HeaderButton.Container>
)}
/>
@ -114,20 +116,23 @@ export const Badge = () => (
const ThemeStory = ({ theme }: { theme: TSupportedThemes }) => (
<ThemeContext.Provider value={{ theme, colors: colors[theme] }}>
<HeaderExample
left={() => (
<HeaderButton.Container left>
<HeaderButton.Item iconName='threads' />
</HeaderButton.Container>
)}
right={() => (
<HeaderButton.Container>
<HeaderButton.Item title='Threads' />
<HeaderButton.Item iconName='threads' badge={() => <HeaderButton.Badge tunread={[1]} />} />
</HeaderButton.Container>
)}
colors={colors[theme]}
/>
<View style={{ flexDirection: 'column' }}>
<HeaderExample
left={() => (
<HeaderButton.Container left>
<HeaderButton.Drawer badge={() => <HeaderButton.BadgeWarn />} />
<HeaderButton.Item iconName='threads' />
</HeaderButton.Container>
)}
right={() => (
<HeaderButton.Container>
<HeaderButton.Item title='Threads' />
<HeaderButton.Item iconName='threads' badge={() => <HeaderButton.BadgeUnread tunread={[1]} />} />
</HeaderButton.Container>
)}
colors={colors[theme]}
/>
</View>
</ThemeContext.Provider>
);

View File

@ -1,4 +1,4 @@
export { default as Container } from './HeaderButtonContainer';
export { default as Item } from './HeaderButtonItem';
export { default as Badge } from './HeaderButtonItemBadge';
export * from './HeaderButtonItemBadge';
export * from './Common';

View File

@ -12,7 +12,6 @@ import { themes } from '../../lib/constants';
import { useTheme } from '../../theme';
import { ROW_HEIGHT } from '../RoomItem';
import { goRoom } from '../../lib/methods/helpers/goRoom';
import Navigation from '../../lib/navigation/appNavigation';
import { useOrientation } from '../../dimensions';
import { IApplicationState, ISubscription, SubscriptionType } from '../../definitions';
@ -98,12 +97,7 @@ const NotifierComponent = React.memo(({ notification, isMasterDetail }: INotifie
prid
};
if (isMasterDetail) {
Navigation.navigate('DrawerNavigator');
} else {
Navigation.navigate('RoomsListView');
}
goRoom({ item, isMasterDetail, jumpToMessageId: _id });
goRoom({ item, isMasterDetail, jumpToMessageId: _id, popToRoot: true });
hideNotification();
};
@ -124,6 +118,7 @@ const NotifierComponent = React.memo(({ notification, isMasterDetail }: INotifie
onPress={onPress}
hitSlop={BUTTON_HIT_SLOP}
background={Touchable.SelectableBackgroundBorderless()}
testID={`in-app-notification-${text}`}
>
<>
<Avatar text={avatar} size={AVATAR_SIZE} type={type} rid={rid} style={styles.avatar} />

View File

@ -1,56 +1,50 @@
import React, { memo, useEffect } from 'react';
import { Easing, Notifier, NotifierRoot } from 'react-native-notifier';
import { connect } from 'react-redux';
import { dequal } from 'dequal';
import NotifierComponent, { INotifierComponent } from './NotifierComponent';
import EventEmitter from '../../lib/methods/helpers/events';
import Navigation from '../../lib/navigation/appNavigation';
import { getActiveRoute } from '../../lib/methods/helpers/navigation';
import { IApplicationState } from '../../definitions';
import { IRoom } from '../../reducers/room';
import { useAppSelector } from '../../lib/hooks';
export const INAPP_NOTIFICATION_EMITTER = 'NotificationInApp';
const InAppNotification = memo(
({ rooms, appState }: { rooms: IRoom['rooms']; appState: string }) => {
const show = (notification: INotifierComponent['notification']) => {
if (appState !== 'foreground') {
const InAppNotification = memo(() => {
const { appState, subscribedRoom } = useAppSelector(state => ({
subscribedRoom: state.room.subscribedRoom,
appState: state.app.ready && state.app.foreground ? 'foreground' : 'background'
}));
const show = (notification: INotifierComponent['notification']) => {
if (appState !== 'foreground') {
return;
}
const { payload } = notification;
const state = Navigation.navigationRef.current?.getRootState();
const route = getActiveRoute(state);
if (payload.rid) {
if (payload.rid === subscribedRoom || route?.name === 'JitsiMeetView') {
return;
}
const { payload } = notification;
const state = Navigation.navigationRef.current?.getRootState();
const route = getActiveRoute(state);
if (payload.rid) {
if (rooms.includes(payload.rid) || route?.name === 'JitsiMeetView') {
return;
Notifier.showNotification({
showEasing: Easing.inOut(Easing.quad),
Component: NotifierComponent,
componentProps: {
notification
}
Notifier.showNotification({
showEasing: Easing.inOut(Easing.quad),
Component: NotifierComponent,
componentProps: {
notification
}
});
}
});
}
};
useEffect(() => {
const listener = EventEmitter.addEventListener(INAPP_NOTIFICATION_EMITTER, show);
return () => {
EventEmitter.removeListener(INAPP_NOTIFICATION_EMITTER, listener);
};
}, [subscribedRoom, appState]);
useEffect(() => {
const listener = EventEmitter.addEventListener(INAPP_NOTIFICATION_EMITTER, show);
return () => {
EventEmitter.removeListener(INAPP_NOTIFICATION_EMITTER, listener);
};
}, [rooms]);
return <NotifierRoot />;
},
(prevProps, nextProps) => dequal(prevProps.rooms, nextProps.rooms)
);
const mapStateToProps = (state: IApplicationState) => ({
rooms: state.room.rooms,
appState: state.app.ready && state.app.foreground ? 'foreground' : 'background'
return <NotifierRoot />;
});
export default connect(mapStateToProps)(InAppNotification);
export default InAppNotification;

View File

@ -4,7 +4,7 @@ import sharedStyles from '../../views/Styles';
export const BUTTON_HEIGHT = 48;
export const SERVICE_HEIGHT = 58;
export const BORDER_RADIUS = 2;
export const BORDER_RADIUS = 4;
export const SERVICES_COLLAPSED_HEIGHT = 174;
export default StyleSheet.create({

View File

@ -14,12 +14,12 @@ import { IEmoji, TAnyMessageModel } from '../../definitions';
import Touch from '../Touch';
export interface IHeader {
handleReaction: (emoji: IEmoji, message: TAnyMessageModel) => void;
handleReaction: (emoji: IEmoji | null, message: TAnyMessageModel) => void;
message: TAnyMessageModel;
isMasterDetail: boolean;
}
type TOnReaction = ({ emoji }: { emoji: IEmoji }) => void;
type TOnReaction = ({ emoji }: { emoji?: IEmoji }) => void;
interface THeaderItem {
item: IEmoji;
@ -94,8 +94,10 @@ const Header = React.memo(({ handleReaction, message, isMasterDetail }: IHeader)
const quantity = Math.trunc(size / (ITEM_SIZE + ITEM_MARGIN * 2) - 1);
const onReaction: TOnReaction = ({ emoji }) => {
handleReaction(emoji, message);
addFrequentlyUsed(emoji);
handleReaction(emoji || null, message);
if (emoji) {
addFrequentlyUsed(emoji);
}
};
const renderItem = ({ item }: { item: IEmoji }) => <HeaderItem item={item} onReaction={onReaction} theme={theme} />;

View File

@ -40,6 +40,7 @@ export interface IMessageActionsProps {
editMessagePermission?: string[];
deleteMessagePermission?: string[];
forceDeleteMessagePermission?: string[];
deleteOwnMessagePermission?: string[];
pinMessagePermission?: string[];
createDirectMessagePermission?: string[];
}
@ -71,6 +72,7 @@ const MessageActions = React.memo(
editMessagePermission,
deleteMessagePermission,
forceDeleteMessagePermission,
deleteOwnMessagePermission,
pinMessagePermission,
createDirectMessagePermission
},
@ -80,19 +82,27 @@ const MessageActions = React.memo(
hasEditPermission: false,
hasDeletePermission: false,
hasForceDeletePermission: false,
hasPinPermission: false
hasPinPermission: false,
hasDeleteOwnPermission: false
};
const { showActionSheet, hideActionSheet } = useActionSheet();
const getPermissions = async () => {
try {
const permission = [editMessagePermission, deleteMessagePermission, forceDeleteMessagePermission, pinMessagePermission];
const permission = [
editMessagePermission,
deleteMessagePermission,
forceDeleteMessagePermission,
pinMessagePermission,
deleteOwnMessagePermission
];
const result = await hasPermission(permission, room.rid);
permissions = {
hasEditPermission: result[0],
hasDeletePermission: result[1],
hasForceDeletePermission: result[2],
hasPinPermission: result[3]
hasPinPermission: result[3],
hasDeleteOwnPermission: result[4]
};
} catch {
// Do nothing
@ -134,7 +144,7 @@ const MessageActions = React.memo(
if (tmid === message.id) {
return false;
}
const deleteOwn = isOwn(message);
const deleteOwn = isOwn(message) && permissions.hasDeleteOwnPermission;
if (!(permissions.hasDeletePermission || (Message_AllowDeleting && deleteOwn) || permissions.hasForceDeletePermission)) {
return false;
}
@ -275,10 +285,10 @@ const MessageActions = React.memo(
}
};
const handleReaction: IHeader['handleReaction'] = (shortname, message) => {
const handleReaction: IHeader['handleReaction'] = (emoji, message) => {
logEvent(events.ROOM_MSG_ACTION_REACTION);
if (shortname) {
onReactionPress(shortname, message.id);
if (emoji) {
onReactionPress(emoji, message.id);
} else {
setTimeout(() => reactionInit(message), ACTION_SHEET_ANIMATION_DURATION);
}
@ -342,21 +352,11 @@ const MessageActions = React.memo(
};
const getOptions = (message: TAnyMessageModel) => {
let options: TActionSheetOptionsItem[] = [];
// Reply
if (!isReadOnly && !tmid) {
options = [
{
title: I18n.t('Reply_in_Thread'),
icon: 'threads',
onPress: () => handleReply(message)
}
];
}
const options: TActionSheetOptionsItem[] = [];
const videoConfBlock = message.t === 'videoconf';
// Quote
if (!isReadOnly) {
if (!isReadOnly && !videoConfBlock) {
options.push({
title: I18n.t('Quote'),
icon: 'quote',
@ -364,8 +364,17 @@ const MessageActions = React.memo(
});
}
// Reply
if (!isReadOnly && !tmid) {
options.push({
title: I18n.t('Reply_in_Thread'),
icon: 'threads',
onPress: () => handleReply(message)
});
}
// Reply in DM
if (room.t !== 'd' && room.t !== 'l' && createDirectMessagePermission) {
if (room.t !== 'd' && room.t !== 'l' && createDirectMessagePermission && !videoConfBlock) {
options.push({
title: I18n.t('Reply_in_direct_message'),
icon: 'arrow-back',
@ -373,22 +382,6 @@ const MessageActions = React.memo(
});
}
// Edit
if (allowEdit(message)) {
options.push({
title: I18n.t('Edit'),
icon: 'edit',
onPress: () => handleEdit(message)
});
}
// Permalink
options.push({
title: I18n.t('Permalink'),
icon: 'link',
onPress: () => handlePermalink(message)
});
// Create Discussion
options.push({
title: I18n.t('Start_a_Discussion'),
@ -396,21 +389,21 @@ const MessageActions = React.memo(
onPress: () => handleCreateDiscussion(message)
});
// Mark as unread
if (message.u && message.u._id !== user.id) {
options.push({
title: I18n.t('Mark_unread'),
icon: 'flag',
onPress: () => handleUnread(message)
});
}
// Permalink
options.push({
title: I18n.t('Get_link'),
icon: 'link',
onPress: () => handlePermalink(message)
});
// Copy
options.push({
title: I18n.t('Copy'),
icon: 'copy',
onPress: () => handleCopy(message)
});
if (!videoConfBlock) {
options.push({
title: I18n.t('Copy'),
icon: 'copy',
onPress: () => handleCopy(message)
});
}
// Share
options.push({
@ -419,8 +412,26 @@ const MessageActions = React.memo(
onPress: () => handleShare(message)
});
// Edit
if (allowEdit(message) && !videoConfBlock) {
options.push({
title: I18n.t('Edit'),
icon: 'edit',
onPress: () => handleEdit(message)
});
}
// Pin
if (Message_AllowPinning && permissions?.hasPinPermission && !videoConfBlock) {
options.push({
title: I18n.t(message.pinned ? 'Unpin' : 'Pin'),
icon: 'pin',
onPress: () => handlePin(message)
});
}
// Star
if (Message_AllowStarring) {
if (Message_AllowStarring && !videoConfBlock) {
options.push({
title: I18n.t(message.starred ? 'Unstar' : 'Star'),
icon: message.starred ? 'star-filled' : 'star',
@ -428,12 +439,12 @@ const MessageActions = React.memo(
});
}
// Pin
if (Message_AllowPinning && permissions?.hasPinPermission) {
// Mark as unread
if (message.u && message.u._id !== user.id) {
options.push({
title: I18n.t(message.pinned ? 'Unpin' : 'Pin'),
icon: 'pin',
onPress: () => handlePin(message)
title: I18n.t('Mark_unread'),
icon: 'flag',
onPress: () => handleUnread(message)
});
}
@ -507,6 +518,7 @@ const mapStateToProps = (state: IApplicationState) => ({
isMasterDetail: state.app.isMasterDetail,
editMessagePermission: state.permissions['edit-message'],
deleteMessagePermission: state.permissions['delete-message'],
deleteOwnMessagePermission: state.permissions['delete-own-message'],
forceDeleteMessagePermission: state.permissions['force-delete-message'],
pinMessagePermission: state.permissions['pin-message'],
createDirectMessagePermission: state.permissions['create-d']

View File

@ -37,7 +37,7 @@ const styles = StyleSheet.create({
height: 32,
justifyContent: 'center',
alignItems: 'center',
borderRadius: 10
borderRadius: 4
},
emptyContainer: {
flex: 1,

View File

@ -1,5 +1,5 @@
import React, { useContext } from 'react';
import { Text, TouchableOpacity } from 'react-native';
import { Text, TouchableOpacity, View } from 'react-native';
import { themes } from '../../../lib/constants';
import { IEmoji } from '../../../definitions/IEmoji';
@ -37,7 +37,9 @@ const MentionItemContent = React.memo(({ trackingType, item }: IMessageBoxMentio
case MENTIONS_TRACKING_TYPE_COMMANDS:
return (
<>
<Text style={[styles.slash, { backgroundColor: themes[theme].borderColor, color: themes[theme].tintColor }]}>/</Text>
<View style={[styles.slash, { backgroundColor: themes[theme].borderColor }]}>
<Text style={{ color: themes[theme].tintColor }}>/</Text>
</View>
<Text style={[styles.mentionText, { color: themes[theme].titleText }]}>{item.id}</Text>
</>
);

View File

@ -237,7 +237,7 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
async componentDidMount() {
const db = database.active;
const { rid, tmid, navigation, sharing, usedCannedResponse, isMasterDetail } = this.props;
const { rid, tmid, navigation, sharing, usedCannedResponse } = this.props;
let msg;
try {
const threadsCollection = db.get('threads');
@ -272,7 +272,7 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
EventEmiter.addEventListener(KEY_COMMAND, this.handleCommands);
}
if (isMasterDetail && usedCannedResponse) {
if (usedCannedResponse) {
this.onChangeText(usedCannedResponse);
}
@ -302,7 +302,7 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
if (usedCannedResponse !== nextProps.usedCannedResponse) {
this.onChangeText(nextProps.usedCannedResponse ?? '');
}
if (sharing) {
if (sharing && !replying) {
this.setInput(nextProps.message.msg ?? '');
return;
}
@ -857,14 +857,21 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
};
openShareView = (attachments: any) => {
const { message, replyCancel, replyWithMention } = this.props;
const { message, replyCancel, replyWithMention, replying } = this.props;
// Start a thread with an attachment
let value: TThreadModel | IMessage = this.thread;
if (replyWithMention) {
value = message;
replyCancel();
}
Navigation.navigate('ShareView', { room: this.room, thread: value, attachments });
Navigation.navigate('ShareView', {
room: this.room,
thread: value,
attachments,
replying,
replyingMessage: message,
closeReply: replyCancel
});
};
createDiscussion = () => {
@ -1042,16 +1049,7 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
// Legacy reply or quote (quote is a reply without mention)
} else {
const { user, roomType } = this.props;
const permalink = await this.getPermalink(replyingMessage);
let msg = `[ ](${permalink}) `;
// if original message wasn't sent by current user and neither from a direct room
if (user.username !== replyingMessage?.u?.username && roomType !== 'd' && replyWithMention) {
msg += `@${replyingMessage?.u?.username} `;
}
msg = `${msg} ${message}`;
const msg = await this.formatReplyMessage(replyingMessage, message);
onSubmit(msg);
}
replyCancel();
@ -1063,6 +1061,20 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
}
};
formatReplyMessage = async (replyingMessage: IMessage, message = '') => {
const { user, roomType, replyWithMention, serverVersion } = this.props;
const permalink = await this.getPermalink(replyingMessage);
let msg = `[ ](${permalink}) `;
// if original message wasn't sent by current user and neither from a direct room
if (user.username !== replyingMessage?.u?.username && roomType !== 'd' && replyWithMention) {
msg += `@${replyingMessage?.u?.username} `;
}
const connectionString = compareServerVersion(serverVersion, 'lowerThan', '5.0.0') ? ' ' : '\n';
return `${msg}${connectionString}${message}`;
};
updateMentions = (keyword: any, type: string) => {
if (type === MENTIONS_TRACKING_TYPE_USERS) {
this.getUsers(keyword);

View File

@ -113,7 +113,7 @@ export default StyleSheet.create({
padding: 5,
paddingHorizontal: 12,
marginHorizontal: 10,
borderRadius: 2
borderRadius: 4
},
commandPreviewImage: {
justifyContent: 'center',

View File

@ -46,6 +46,7 @@ const RoomHeaderContainer = React.memo(
const connecting = useSelector((state: IApplicationState) => state.meteor.connecting || state.server.loading);
const usersTyping = useSelector((state: IApplicationState) => state.usersTyping, shallowEqual);
const connected = useSelector((state: IApplicationState) => state.meteor.connected);
const presenceDisabled = useSelector((state: IApplicationState) => state.settings.Presence_broadcast_disabled);
const activeUser = useSelector(
(state: IApplicationState) => (roomUserId ? state.activeUsers?.[roomUserId] : undefined),
shallowEqual
@ -61,9 +62,13 @@ const RoomHeaderContainer = React.memo(
if (connected) {
if ((type === 'd' || (tmid && roomUserId)) && activeUser) {
const { status: statusActiveUser, statusText: statusTextActiveUser } = activeUser;
status = statusActiveUser;
statusText = statusTextActiveUser;
if (presenceDisabled) {
status = 'disabled';
} else {
const { status: statusActiveUser, statusText: statusTextActiveUser } = activeUser;
status = statusActiveUser;
statusText = statusTextActiveUser;
}
} else if (type === 'l' && visitor?.status) {
const { status: statusVisitor } = visitor;
status = statusVisitor;

View File

@ -65,6 +65,7 @@ export const UserStatus = () => (
<RoomItem status='busy' />
<RoomItem status='offline' />
<RoomItem status='loading' />
<RoomItem status='disabled' />
<RoomItem status='wrong' />
</>
);

View File

@ -2,13 +2,13 @@ import React, { useEffect, useReducer, useRef } from 'react';
import { Subscription } from 'rxjs';
import I18n from '../../i18n';
import { useAppSelector } from '../../lib/hooks';
import { getUserPresence } from '../../lib/methods';
import { isGroupChat } from '../../lib/methods/helpers';
import { formatDate } from '../../lib/methods/helpers/room';
import { IRoomItemContainerProps } from './interfaces';
import RoomItem from './RoomItem';
import { ROW_HEIGHT, ROW_HEIGHT_CONDENSED } from './styles';
import { useUserStatus } from './useUserStatus';
export { ROW_HEIGHT, ROW_HEIGHT_CONDENSED };
@ -42,11 +42,11 @@ const RoomItemContainer = React.memo(
const isRead = getIsRead(item);
const date = item.roomUpdatedAt && formatDate(item.roomUpdatedAt);
const alert = item.alert || item.tunread?.length;
const connected = useAppSelector(state => state.meteor.connected);
const userStatus = useAppSelector(state => state.activeUsers[id || '']?.status);
const [_, forceUpdate] = useReducer(x => x + 1, 1);
const roomSubscription = useRef<Subscription | null>(null);
const { connected, status } = useUserStatus(item.t, item?.visitor?.status, id);
useEffect(() => {
const init = () => {
if (item?.observe) {
@ -85,8 +85,6 @@ const RoomItemContainer = React.memo(
accessibilityLabel = `, ${I18n.t('last_message')} ${date}`;
}
const status = item.t === 'l' ? item.visitor?.status || item.v?.status : userStatus;
return (
<RoomItem
name={name}

View File

@ -0,0 +1,30 @@
import { TUserStatus } from '../../definitions';
import { useAppSelector } from '../../lib/hooks';
import { RoomTypes } from '../../lib/methods';
export const useUserStatus = (
type: RoomTypes,
liveChatStatus?: TUserStatus,
id?: string
): { connected: boolean; status: TUserStatus } => {
const connected = useAppSelector(state => state.meteor.connected);
const presenceDisabled = useAppSelector(state => state.settings.Presence_broadcast_disabled);
const userStatus = useAppSelector(state => state.activeUsers[id || '']?.status);
let status = 'loading';
if (connected) {
if (type === 'd') {
if (presenceDisabled) {
status = 'disabled';
} else {
status = userStatus || 'loading';
}
} else if (type === 'l' && liveChatStatus) {
status = liveChatStatus;
}
}
return {
connected,
status: status as TUserStatus
};
};

View File

@ -1,4 +1,4 @@
import React from 'react';
import React, { useState } from 'react';
import { StyleProp, ViewStyle } from 'react-native';
import { SvgUri } from 'react-native-svg';
@ -29,22 +29,12 @@ interface IOmnichannelRoomIconProps {
}
export const OmnichannelRoomIcon = ({ size, style, sourceType, status }: IOmnichannelRoomIconProps) => {
const [loading, setLoading] = useState(true);
const [svgError, setSvgError] = useState(false);
const baseUrl = useAppSelector(state => state.server?.server);
const connected = useAppSelector(state => state.meteor?.connected);
if (sourceType?.type === OmnichannelSourceType.APP && sourceType.id && sourceType.sidebarIcon && connected) {
return (
<SvgUri
height={size}
width={size}
color={STATUS_COLORS[status || 'offline']}
uri={`${baseUrl}/api/apps/public/${sourceType.id}/get-sidebar-icon?icon=${sourceType.sidebarIcon}`}
style={style}
/>
);
}
return (
const customIcon = (
<CustomIcon
name={iconMap[sourceType?.type || 'other']}
size={size}
@ -52,4 +42,23 @@ export const OmnichannelRoomIcon = ({ size, style, sourceType, status }: IOmnich
color={STATUS_COLORS[status || 'offline']}
/>
);
if (!svgError && sourceType?.type === OmnichannelSourceType.APP && sourceType.id && sourceType.sidebarIcon && connected) {
return (
<>
<SvgUri
height={size}
width={size}
color={STATUS_COLORS[status || 'offline']}
uri={`${baseUrl}/api/apps/public/${sourceType.id}/get-sidebar-icon?icon=${sourceType.sidebarIcon}`}
style={style}
onError={() => setSvgError(true)}
onLoad={() => setLoading(false)}
/>
{loading ? customIcon : null}
</>
);
}
return customIcon;
};

View File

@ -6,9 +6,15 @@ import { IStatus } from './definition';
import { useAppSelector } from '../../lib/hooks';
const StatusContainer = ({ id, style, size = 32, ...props }: Omit<IStatus, 'status'>): React.ReactElement => {
const status = useAppSelector(state =>
state.meteor.connected ? state.activeUsers[id] && state.activeUsers[id].status : 'loading'
) as TUserStatus;
const status = useAppSelector(state => {
if (state.settings.Presence_broadcast_disabled) {
return 'disabled';
}
if (state.meteor.connected) {
return state.activeUsers[id] && state.activeUsers[id].status;
}
return 'loading';
}) as TUserStatus;
return <Status size={size} style={style} status={status} {...props} />;
};

View File

@ -28,8 +28,8 @@ const styles = StyleSheet.create({
fontSize: 16,
paddingHorizontal: 16,
paddingVertical: 10,
borderWidth: 2,
borderRadius: 2
borderWidth: 1,
borderRadius: 4
},
inputIconLeft: {
paddingLeft: 45

View File

@ -19,8 +19,8 @@ const styles = StyleSheet.create({
input: {
height: 48,
paddingLeft: 16,
borderWidth: 2,
borderRadius: 2,
borderWidth: 1,
borderRadius: 4,
alignItems: 'center',
flexDirection: 'row'
},

View File

@ -22,11 +22,11 @@ const Input = ({ children, onPress, loading, inputStyle, placeholder, disabled,
return (
<Touchable
onPress={onPress}
style={[{ backgroundColor: colors.backgroundColor }, inputStyle]}
style={[{ backgroundColor: colors.backgroundColor }, styles.inputBorder, inputStyle]}
background={Touchable.Ripple(colors.bannerBackground)}
disabled={disabled}
>
<View style={[styles.input, { borderColor: colors.separatorColor }, innerInputStyle]}>
<View style={[styles.input, styles.inputBorder, { borderColor: colors.separatorColor }, innerInputStyle]}>
{placeholder ? <Text style={[styles.pickerText, { color: colors.auxiliaryText }]}>{placeholder}</Text> : children}
{loading ? (
<ActivityIndicator style={styles.icon} />

View File

@ -31,12 +31,14 @@ export default StyleSheet.create({
flexDirection: 'row',
flex: 1
},
inputBorder: {
borderRadius: 4
},
input: {
minHeight: 48,
paddingHorizontal: 8,
paddingBottom: 0,
borderWidth: 2,
borderRadius: 2,
borderWidth: 1,
alignItems: 'center',
flexDirection: 'row'
},

View File

@ -19,8 +19,8 @@ const styles = StyleSheet.create({
viewContainer: {
marginBottom: 16,
paddingHorizontal: 16,
borderWidth: 2,
borderRadius: 2,
borderWidth: 1,
borderRadius: 4,
justifyContent: 'center'
},
pickerText: {

View File

@ -0,0 +1,27 @@
import React from 'react';
import { Text, View } from 'react-native';
import i18n from '../../../../i18n';
import useStyle from './styles';
import AvatarContainer from '../../../Avatar';
const MAX_USERS = 3;
export type TCallUsers = { _id: string; username: string; name: string; avatarETag: string }[];
export const CallParticipants = ({ users }: { users: TCallUsers }): React.ReactElement => {
const style = useStyle();
return (
<>
{users.map(({ username }, index) =>
index < MAX_USERS ? <AvatarContainer style={{ marginRight: 4 }} key={index} size={28} text={username} /> : null
)}
{users.length > MAX_USERS ? (
<View style={style.plusUsers}>
<Text style={style.plusUsersText}>{users.length > 9 ? '+9' : `+${users.length}`}</Text>
</View>
) : null}
<Text style={style.joined}>{i18n.t('Joined')}</Text>
</>
);
};

View File

@ -0,0 +1,81 @@
import React, { useEffect, useState } from 'react';
import { Text, View } from 'react-native';
import Touchable from 'react-native-platform-touchable';
import i18n from '../../../../i18n';
import { getSubscriptionByRoomId } from '../../../../lib/database/services/Subscription';
import { useAppSelector } from '../../../../lib/hooks';
import { getRoomAvatar, getUidDirectMessage } from '../../../../lib/methods/helpers';
import { useTheme } from '../../../../theme';
import { useActionSheet } from '../../../ActionSheet';
import AvatarContainer from '../../../Avatar';
import Button from '../../../Button';
import { CustomIcon } from '../../../CustomIcon';
import { BUTTON_HIT_SLOP } from '../../../message/utils';
import StatusContainer from '../../../Status';
import useStyle from './styles';
export default function StartACallActionSheet({ rid, initCall }: { rid: string; initCall: Function }): React.ReactElement {
const style = useStyle();
const { colors } = useTheme();
const [user, setUser] = useState({ username: '', avatar: '', uid: '' });
const [mic, setMic] = useState(true);
const [cam, setCam] = useState(false);
const username = useAppSelector(state => state.login.user.username);
const { hideActionSheet } = useActionSheet();
useEffect(() => {
(async () => {
const room = await getSubscriptionByRoomId(rid);
const uid = (await getUidDirectMessage(room)) as string;
const avt = getRoomAvatar(room);
setUser({ uid, username: room?.name || '', avatar: avt });
})();
}, [rid]);
const handleColor = (enabled: boolean) => (enabled ? colors.conferenceCallEnabledIcon : colors.conferenceCallDisabledIcon);
return (
<View style={style.actionSheetContainer}>
<View style={style.actionSheetHeader}>
<Text style={style.actionSheetHeaderTitle}>{i18n.t('Start_a_call')}</Text>
<View style={style.actionSheetHeaderButtons}>
<Touchable
onPress={() => setCam(!cam)}
style={[style.iconCallContainer, cam && style.enabledBackground, { marginRight: 6 }]}
hitSlop={BUTTON_HIT_SLOP}
>
<CustomIcon name={cam ? 'camera' : 'camera-disabled'} size={20} color={handleColor(cam)} />
</Touchable>
<Touchable
onPress={() => setMic(!mic)}
style={[style.iconCallContainer, mic && style.enabledBackground]}
hitSlop={BUTTON_HIT_SLOP}
>
<CustomIcon name={mic ? 'microphone' : 'microphone-disabled'} size={20} color={handleColor(mic)} />
</Touchable>
</View>
</View>
<View style={style.actionSheetUsernameContainer}>
<AvatarContainer text={user.avatar} size={36} />
<StatusContainer size={16} id={user.uid} style={{ marginLeft: 8, marginRight: 6 }} />
<Text style={style.actionSheetUsername} numberOfLines={1}>
{user.username}
</Text>
</View>
<View style={style.actionSheetPhotoContainer}>
<AvatarContainer size={62} text={username} />
</View>
<Button
onPress={() => {
hideActionSheet();
setTimeout(() => {
initCall({ cam, mic });
}, 100);
}}
title={i18n.t('Call')}
/>
</View>
);
}

View File

@ -0,0 +1,55 @@
import React from 'react';
import { View, Text } from 'react-native';
import i18n from '../../../../i18n';
import { useTheme } from '../../../../theme';
import { CustomIcon, TIconsName } from '../../../CustomIcon';
import useStyle from './styles';
type VideoConfMessageIconProps = {
variant: 'ended' | 'incoming' | 'outgoing';
children: React.ReactElement | React.ReactElement[];
};
export const VideoConferenceBaseContainer = ({ variant, children }: VideoConfMessageIconProps): React.ReactElement => {
const { colors } = useTheme();
const style = useStyle();
const iconStyle: { [key: string]: { icon: TIconsName; color: string; backgroundColor: string; label: string } } = {
ended: {
icon: 'phone-end',
color: colors.conferenceCallEndedPhoneIcon,
backgroundColor: colors.conferenceCallEndedPhoneBackground,
label: i18n.t('Call_ended')
},
incoming: {
icon: 'phone-in',
color: colors.conferenceCallIncomingPhoneIcon,
backgroundColor: colors.conferenceCallIncomingPhoneBackground,
label: i18n.t('Calling')
},
outgoing: {
icon: 'phone',
color: colors.conferenceCallOngoingPhoneIcon,
backgroundColor: colors.conferenceCallOngoingPhoneBackground,
label: i18n.t('Call_ongoing')
}
};
return (
<View style={style.container}>
<View style={style.callInfoContainer}>
<View
style={{
...style.iconContainer,
backgroundColor: iconStyle[variant].backgroundColor
}}
>
<CustomIcon name={iconStyle[variant].icon} size={variant === 'incoming' ? 16 : 24} color={iconStyle[variant].color} />
</View>
<Text style={style.infoContainerText}>{iconStyle[variant].label}</Text>
</View>
<View style={style.callToActionContainer}>{children}</View>
</View>
);
};

View File

@ -0,0 +1,23 @@
import React from 'react';
import { Text } from 'react-native';
import Touchable from 'react-native-platform-touchable';
import i18n from '../../../../i18n';
import { videoConfJoin } from '../../../../lib/methods/videoConf';
import useStyle from './styles';
import { VideoConferenceBaseContainer } from './VideoConferenceBaseContainer';
const VideoConferenceDirect = React.memo(({ blockId }: { blockId: string }) => {
const style = useStyle();
return (
<VideoConferenceBaseContainer variant='incoming'>
<Touchable style={style.callToActionButton} onPress={() => videoConfJoin(blockId)}>
<Text style={style.callToActionButtonText}>{i18n.t('Join')}</Text>
</Touchable>
<Text style={style.callBack}>{i18n.t('Waiting_for_answer')}</Text>
</VideoConferenceBaseContainer>
);
});
export default VideoConferenceDirect;

View File

@ -0,0 +1,53 @@
import React from 'react';
import { Text } from 'react-native';
import Touchable from 'react-native-platform-touchable';
import { IUser } from '../../../../definitions';
import { VideoConferenceType } from '../../../../definitions/IVideoConference';
import i18n from '../../../../i18n';
import { useAppSelector } from '../../../../lib/hooks';
import { useVideoConf } from '../../../../lib/hooks/useVideoConf';
import { CallParticipants, TCallUsers } from './CallParticipants';
import useStyle from './styles';
import { VideoConferenceBaseContainer } from './VideoConferenceBaseContainer';
export default function VideoConferenceEnded({
users,
type,
createdBy,
rid
}: {
users: TCallUsers;
type: VideoConferenceType;
createdBy: Pick<IUser, '_id' | 'username' | 'name'>;
rid: string;
}): React.ReactElement {
const style = useStyle();
const username = useAppSelector(state => state.login.user.username);
const { showInitCallActionSheet } = useVideoConf(rid);
const onlyAuthorOnCall = users.length === 1 && users.some(user => user.username === createdBy.username);
return (
<VideoConferenceBaseContainer variant='ended'>
{type === 'direct' ? (
<>
<Touchable style={style.callToActionCallBack} onPress={showInitCallActionSheet}>
<Text style={style.callToActionCallBackText}>
{createdBy.username === username ? i18n.t('Call_back') : i18n.t('Call_again')}
</Text>
</Touchable>
<Text style={style.callBack}>{i18n.t('Call_was_not_answered')}</Text>
</>
) : (
<>
{users.length && !onlyAuthorOnCall ? (
<CallParticipants users={users} />
) : (
<Text style={style.notAnswered}>{i18n.t('Call_was_not_answered')}</Text>
)}
</>
)}
</VideoConferenceBaseContainer>
);
}

View File

@ -0,0 +1,22 @@
import React from 'react';
import { Text } from 'react-native';
import Touchable from 'react-native-platform-touchable';
import i18n from '../../../../i18n';
import { videoConfJoin } from '../../../../lib/methods/videoConf';
import { CallParticipants, TCallUsers } from './CallParticipants';
import useStyle from './styles';
import { VideoConferenceBaseContainer } from './VideoConferenceBaseContainer';
export default function VideoConferenceOutgoing({ users, blockId }: { users: TCallUsers; blockId: string }): React.ReactElement {
const style = useStyle();
return (
<VideoConferenceBaseContainer variant='outgoing'>
<Touchable style={style.callToActionButton} onPress={() => videoConfJoin(blockId)}>
<Text style={style.callToActionButtonText}>{i18n.t('Join')}</Text>
</Touchable>
<CallParticipants users={users} />
</VideoConferenceBaseContainer>
);
}

View File

@ -0,0 +1,28 @@
import React from 'react';
import SkeletonPlaceholder from 'react-native-skeleton-placeholder';
import { useTheme } from '../../../../theme';
export default function VideoConferenceSkeletonLoading(): React.ReactElement {
const { colors } = useTheme();
return (
<SkeletonPlaceholder backgroundColor={colors.conferenceCallBackground}>
<SkeletonPlaceholder.Item borderWidth={1} borderColor={colors.conferenceCallBorder} borderRadius={4} marginTop={8}>
<SkeletonPlaceholder.Item alignItems={'center'} flexDirection='row' marginTop={16} marginLeft={16}>
<SkeletonPlaceholder.Item width={28} height={26} />
<SkeletonPlaceholder.Item width={75} height={16} marginLeft={8} borderRadius={0} />
</SkeletonPlaceholder.Item>
<SkeletonPlaceholder.Item
width={'100%'}
height={48}
marginTop={16}
borderBottomLeftRadius={4}
borderBottomRightRadius={4}
borderTopLeftRadius={0}
borderTopRightRadius={0}
/>
</SkeletonPlaceholder.Item>
</SkeletonPlaceholder>
);
}

View File

@ -0,0 +1,127 @@
import { StyleSheet } from 'react-native';
import { useTheme } from '../../../../theme';
import sharedStyles from '../../../../views/Styles';
export default function useStyle() {
const { colors } = useTheme();
return StyleSheet.create({
container: { height: 108, flex: 1, borderWidth: 1, borderRadius: 4, marginTop: 8, borderColor: colors.conferenceCallBorder },
callInfoContainer: { flex: 1, alignItems: 'center', paddingLeft: 16, flexDirection: 'row' },
infoContainerText: {
fontSize: 12,
marginLeft: 8,
...sharedStyles.textBold,
color: colors.auxiliaryTintColor
},
iconContainer: {
width: 28,
height: 28,
alignItems: 'center',
justifyContent: 'center',
borderRadius: 4
},
callToActionContainer: {
height: 48,
backgroundColor: colors.conferenceCallBackground,
flexDirection: 'row',
alignItems: 'center',
paddingLeft: 16
},
callToActionButtonText: {
fontSize: 12,
...sharedStyles.textSemibold,
color: colors.buttonText
},
callToActionCallBackText: {
fontSize: 12,
...sharedStyles.textSemibold,
color: colors.conferenceCallCallBackText
},
callToActionButton: {
backgroundColor: colors.tintColor,
minWidth: 50,
alignItems: 'center',
justifyContent: 'center',
height: 32,
borderRadius: 4,
marginRight: 8,
paddingHorizontal: 8
},
joined: {
fontSize: 12,
...sharedStyles.textRegular,
color: colors.passcodeSecondary,
marginLeft: 8
},
plusUsers: {
width: 28,
height: 28,
backgroundColor: colors.conferenceCallPlusUsersButton,
borderRadius: 4,
alignItems: 'center',
justifyContent: 'center'
},
plusUsersText: {
fontSize: 14,
...sharedStyles.textSemibold,
color: colors.conferenceCallPlusUsersText,
alignSelf: 'center'
},
callBack: {
fontSize: 12,
...sharedStyles.textRegular,
color: colors.passcodeSecondary
},
callToActionCallBack: {
backgroundColor: colors.conferenceCallPlusUsersButton,
minWidth: 50,
alignItems: 'center',
justifyContent: 'center',
height: 32,
borderRadius: 4,
marginRight: 8,
paddingHorizontal: 8
},
notAnswered: {
fontSize: 12,
...sharedStyles.textRegular,
color: colors.passcodeSecondary
},
actionSheetContainer: {
paddingHorizontal: 24,
flex: 1
},
actionSheetHeaderTitle: {
fontSize: 14,
...sharedStyles.textBold,
color: colors.passcodePrimary
},
actionSheetUsername: {
fontSize: 16,
...sharedStyles.textBold,
color: colors.passcodePrimary,
flexShrink: 1
},
enabledBackground: {
backgroundColor: colors.conferenceCallEnabledIconBackground
},
iconCallContainer: {
padding: 6,
borderRadius: 4
},
actionSheetHeader: { flexDirection: 'row', alignItems: 'center' },
actionSheetHeaderButtons: { flex: 1, alignItems: 'center', flexDirection: 'row', justifyContent: 'flex-end' },
actionSheetUsernameContainer: { flexDirection: 'row', paddingTop: 8, alignItems: 'center' },
actionSheetPhotoContainer: {
height: 220,
width: 148,
backgroundColor: colors.conferenceCallPhotoBackground,
borderRadius: 8,
margin: 24,
alignSelf: 'center',
justifyContent: 'center',
alignItems: 'center'
}
});
}

View File

@ -0,0 +1,23 @@
import React from 'react';
import { useEndpointData } from '../../../lib/hooks/useEndpointData';
import VideoConferenceDirect from './components/VideoConferenceDirect';
import VideoConferenceEnded from './components/VideoConferenceEnded';
import VideoConferenceOutgoing from './components/VideoConferenceOutgoing';
import VideoConferenceSkeletonLoading from './components/VideoConferenceSkeletonLoading';
export default function VideoConferenceBlock({ callId, blockId }: { callId: string; blockId: string }): React.ReactElement {
const { result } = useEndpointData('video-conference.info', { callId });
if (result?.success) {
const { users, type, status, createdBy, rid } = result;
if ('endedAt' in result) return <VideoConferenceEnded createdBy={createdBy} rid={rid} type={type} users={users} />;
if (type === 'direct' && status === 0) return <VideoConferenceDirect blockId={blockId} />;
return <VideoConferenceOutgoing blockId={blockId} users={users} />;
}
return <VideoConferenceSkeletonLoading />;
}

View File

@ -29,6 +29,7 @@ import { DatePicker } from './DatePicker';
import { Overflow } from './Overflow';
import { ThemeContext } from '../../theme';
import { IActions, IButton, IElement, IInputIndex, IParser, ISection } from './interfaces';
import VideoConferenceBlock from './VideoConferenceBlock';
const styles = StyleSheet.create({
input: {
@ -149,6 +150,10 @@ class MessageParser extends UiKitParserMessage<React.ReactElement> {
const [{ loading, value }, action] = useBlockContext(element, context);
return <MultiSelect {...element} value={value} onChange={action} context={context} loading={loading} />;
}
video_conf(element: IElement & { callId: string }) {
return <VideoConferenceBlock callId={element.callId} blockId={element.blockId!} />;
}
}
// plain_text and mrkdwn functions are created in MessageParser and the ModalParser's constructor use the same functions

View File

@ -1,11 +1,9 @@
/* eslint-disable no-shadow */
import React, { useContext, useState } from 'react';
import { BlockContext } from '@rocket.chat/ui-kit';
import React, { useContext, useState } from 'react';
import { IText } from './interfaces';
import { videoConfJoin } from '../../lib/methods/videoConf';
import { TActionSheetOptionsItem, useActionSheet } from '../ActionSheet';
import i18n from '../../i18n';
import { IText } from './interfaces';
export const textParser = ([{ text }]: IText[]) => text;
@ -42,7 +40,6 @@ export const useBlockContext = ({ blockId, actionId, appId, initialValue }: IUse
const { action, appId: appIdFromContext, viewId, state, language, errors, values = {} } = useContext(KitContext);
const { value = initialValue } = values[actionId] || {};
const [loading, setLoading] = useState(false);
const { showActionSheet } = useActionSheet();
const error = errors && actionId && errors[actionId];
@ -60,20 +57,7 @@ export const useBlockContext = ({ blockId, actionId, appId, initialValue }: IUse
try {
if (appId === 'videoconf-core' && blockId) {
setLoading(false);
const options: TActionSheetOptionsItem[] = [
{
title: i18n.t('Video_call'),
icon: 'camera',
onPress: () => videoConfJoin(blockId, true)
},
{
title: i18n.t('Voice_call'),
icon: 'microphone',
onPress: () => videoConfJoin(blockId, false)
}
];
showActionSheet({ options });
return;
return videoConfJoin(blockId);
}
await action({
blockId,

View File

@ -0,0 +1,64 @@
import React from 'react';
import { View, StyleSheet, Text, ViewStyle } from 'react-native';
import sharedStyles from '../views/Styles';
import { useTheme } from '../theme';
import openLink from '../lib/methods/helpers/openLink';
import { useAppSelector } from '../lib/hooks';
import I18n from '../i18n';
const styles = StyleSheet.create({
bottomContainer: {
flexDirection: 'column',
alignItems: 'center',
marginBottom: 32,
marginHorizontal: 30
},
bottomContainerText: {
...sharedStyles.textRegular,
fontSize: 13,
textAlign: 'center'
},
bottomContainerTextBold: {
...sharedStyles.textSemibold,
fontSize: 13,
textAlign: 'center'
}
});
const UGCRules = ({ styleContainer }: { styleContainer?: ViewStyle }) => {
const { colors, theme } = useTheme();
const { server } = useAppSelector(state => ({
server: state.server.server
}));
const openContract = (route: string) => {
if (!server) {
return;
}
openLink(`${server}/${route}`, theme);
};
return (
<View style={[styles.bottomContainer, styleContainer]}>
<Text style={[styles.bottomContainerText, { color: colors.auxiliaryText }]}>
{`${I18n.t('Onboarding_agree_terms')}\n`}
<Text
style={[styles.bottomContainerTextBold, { color: colors.actionTintColor }]}
onPress={() => openContract('terms-of-service')}
>
{I18n.t('Terms_of_Service')}
</Text>{' '}
{I18n.t('and')}
<Text
style={[styles.bottomContainerTextBold, { color: colors.actionTintColor }]}
onPress={() => openContract('privacy-policy')}
>
{' '}
{I18n.t('Privacy_Policy')}
</Text>
</Text>
</View>
);
};
export default UGCRules;

View File

@ -1,14 +1,11 @@
import React from 'react';
import { StyleProp, Text, TextStyle } from 'react-native';
import { useNavigation } from '@react-navigation/native';
import { StackNavigationProp } from '@react-navigation/stack';
import { themes } from '../../lib/constants';
import { useTheme } from '../../theme';
import { IUserChannel } from './interfaces';
import styles from './styles';
import { getSubscriptionByRoomId } from '../../lib/database/services/Subscription';
import { ChatsStackParamList } from '../../stacks/types';
import { useAppSelector } from '../../lib/hooks';
import { goRoom } from '../../lib/methods/helpers/goRoom';
@ -22,7 +19,6 @@ interface IHashtag {
const Hashtag = React.memo(({ hashtag, channels, navToRoomInfo, style = [] }: IHashtag) => {
const { theme } = useTheme();
const isMasterDetail = useAppSelector(state => state.app.isMasterDetail);
const navigation = useNavigation<StackNavigationProp<ChatsStackParamList, 'RoomView'>>();
const handlePress = async () => {
const index = channels?.findIndex(channel => channel.name === hashtag);
@ -33,7 +29,7 @@ const Hashtag = React.memo(({ hashtag, channels, navToRoomInfo, style = [] }: IH
};
const room = navParam.rid && (await getSubscriptionByRoomId(navParam.rid));
if (room) {
goRoom({ item: room, isMasterDetail, navigationMethod: isMasterDetail ? navigation.replace : navigation.push });
goRoom({ item: room, isMasterDetail });
} else {
navToRoomInfo(navParam);
}

View File

@ -45,6 +45,7 @@ interface IMarkdownProps {
testID?: string;
style?: StyleProp<TextStyle>[];
onLinkPress?: TOnLinkPress;
isTranslated?: boolean;
}
type TLiteral = {
@ -93,9 +94,7 @@ class Markdown extends PureComponent<IMarkdownProps, any> {
constructor(props: IMarkdownProps) {
super(props);
if (!this.isNewMarkdown) {
this.renderer = this.createRenderer();
}
this.renderer = this.createRenderer();
}
createRenderer = () =>
@ -310,13 +309,24 @@ class Markdown extends PureComponent<IMarkdownProps, any> {
};
render() {
const { msg, md, mentions, channels, navToRoomInfo, useRealName, username = '', getCustomEmoji, onLinkPress } = this.props;
const {
msg,
md,
mentions,
channels,
navToRoomInfo,
useRealName,
username = '',
getCustomEmoji,
onLinkPress,
isTranslated
} = this.props;
if (!msg) {
return null;
}
if (this.isNewMarkdown) {
if (this.isNewMarkdown && !isTranslated) {
return (
<NewMarkdown
username={username}

View File

@ -18,13 +18,29 @@ import MarkdownContext from './MarkdownContext';
interface IParagraphProps {
value: ParagraphProps['value'];
forceTrim?: boolean;
}
const Inline = ({ value }: IParagraphProps): React.ReactElement | null => {
const Inline = ({ value, forceTrim }: IParagraphProps): React.ReactElement | null => {
const { useRealName, username, navToRoomInfo, mentions, channels } = useContext(MarkdownContext);
return (
<Text style={styles.inline}>
{value.map(block => {
{value.map((block, index) => {
// We are forcing trim when is a `[ ](https://https://open.rocket.chat/) plain_text`
// to clean the empty spaces
if (forceTrim) {
if (index === 0 && block.type === 'LINK') {
block.value.label.value =
// Need to update the @rocket.chat/message-parser to understand that the label can be a Markup | Markup[]
// https://github.com/RocketChat/fuselage/blob/461ecf661d9ff4a46390957c915e4352fa942a7c/packages/message-parser/src/definitions.ts#L141
// @ts-ignore
block.value?.label?.value?.toString().trimLeft() || block?.value?.label?.[0]?.value?.toString().trimLeft();
}
if (index === 1 && block.type !== 'LINK') {
block.value = block.value?.toString().trimLeft();
}
}
switch (block.type) {
case 'IMAGE':
return <Image value={block.value} />;

View File

@ -41,18 +41,21 @@ const Link = ({ value }: ILinkProps) => {
return (
<Text onPress={handlePress} onLongPress={onLongPress} style={[styles.link, { color: themes[theme].actionTintColor }]}>
{(block => {
switch (block.type) {
case 'PLAIN_TEXT':
return block.value;
case 'STRIKE':
return <Strike value={block.value} />;
case 'ITALIC':
return <Italic value={block.value} />;
case 'BOLD':
return <Bold value={block.value} />;
default:
return null;
}
const blockArray = Array.isArray(block) ? block : [block];
return blockArray.map(blockInArray => {
switch (blockInArray.type) {
case 'PLAIN_TEXT':
return blockInArray.value;
case 'STRIKE':
return <Strike value={blockInArray.value} />;
case 'ITALIC':
return <Italic value={blockInArray.value} />;
case 'BOLD':
return <Bold value={blockInArray.value} />;
default:
return null;
}
});
})(label)}
</Text>
);

View File

@ -3,22 +3,25 @@ import { StyleSheet, View } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import NewMarkdownComponent from '.';
import { themes } from '../../../lib/constants';
import { colors, themes } from '../../../lib/constants';
import { longText } from '../../../../.storybook/utils';
import { ThemeContext } from '../../../theme';
const theme = 'light';
export default {
title: 'NewMarkdown',
decorators: [
(Story: any) => (
<NavigationContainer>
<Story />
<ThemeContext.Provider value={{ theme, colors: colors[theme] }}>
<Story />
</ThemeContext.Provider>
</NavigationContainer>
)
]
};
const theme = 'light';
const styles = StyleSheet.create({
container: {
marginHorizontal: 15,
@ -378,27 +381,6 @@ export const BlockQuote = () => (
</View>
);
const rocketChatLink = [
{
type: 'PARAGRAPH',
value: [
{
type: 'LINK',
value: {
src: {
type: 'PLAIN_TEXT',
value: 'https://rocket.chat'
},
label: {
type: 'PLAIN_TEXT',
value: 'https://rocket.chat'
}
}
}
]
}
];
const markdownLink = [
{
type: 'PARAGRAPH',
@ -420,10 +402,72 @@ const markdownLink = [
}
];
const markdownLinkWithEmphasis = [
{
type: 'PARAGRAPH',
value: [
{
type: 'LINK',
value: {
src: {
type: 'PLAIN_TEXT',
value: 'https://rocket.chat/'
},
label: [
{
type: 'PLAIN_TEXT',
value: 'Normal Link - '
},
{
type: 'BOLD',
value: [
{
type: 'PLAIN_TEXT',
value: 'Bold'
}
]
},
{
type: 'PLAIN_TEXT',
value: ' '
},
{
type: 'STRIKE',
value: [
{
type: 'PLAIN_TEXT',
value: 'strike'
}
]
},
{
type: 'PLAIN_TEXT',
value: ' and '
},
{
type: 'ITALIC',
value: [
{
type: 'PLAIN_TEXT',
value: 'Italic'
}
]
},
{
type: 'PLAIN_TEXT',
value: ' Styles'
}
]
}
}
]
}
];
export const Links = () => (
<View style={styles.container}>
<NewMarkdown tokens={rocketChatLink} />
<NewMarkdown tokens={markdownLink} />
<NewMarkdown tokens={markdownLinkWithEmphasis} />
</View>
);
@ -740,3 +784,128 @@ export const InlineKatex = () => (
<NewMarkdown tokens={inlineKatex} />
</View>
);
const messageQuote = {
/**
# Hello head 1
[ ](https://google.com)
*/
headAndLink: [
{ type: 'HEADING', level: 1, value: [{ type: 'PLAIN_TEXT', value: 'Hello head 1' }] },
{ type: 'LINE_BREAK' },
{
type: 'PARAGRAPH',
value: [
{
type: 'LINK',
value: { src: { type: 'PLAIN_TEXT', value: 'https://google.com' }, label: { type: 'PLAIN_TEXT', value: ' ' } }
}
]
}
],
/**
# Head 1 as the first line then line break and after paragraph
bla bla bla bla bla bla
bla bla bla bla bla bla
[ ](https://google.com)
*/
headTextAndLink: [
{
type: 'HEADING',
level: 1,
value: [{ type: 'PLAIN_TEXT', value: 'Head 1 as the first line then line break and after paragraph' }]
},
{ type: 'LINE_BREAK' },
{ type: 'PARAGRAPH', value: [{ type: 'PLAIN_TEXT', value: 'bla bla bla bla bla bla ' }] },
{ type: 'PARAGRAPH', value: [{ type: 'PLAIN_TEXT', value: 'bla bla bla bla bla bla ' }] },
{
type: 'PARAGRAPH',
value: [
{
type: 'LINK',
value: { src: { type: 'PLAIN_TEXT', value: 'https://google.com' }, label: { type: 'PLAIN_TEXT', value: ' ' } }
}
]
}
],
/**
[ ](permalink from message)\n# Head 1 after a forced line break
asdas asd asd asd
*/
headTextAndQuote: [
{
type: 'PARAGRAPH',
value: [
{
type: 'LINK',
value: {
src: { type: 'PLAIN_TEXT', value: 'https://open.rocket.chat/direct/subaru123?msg=QB42gWcaO6BgqtLTo' },
label: { type: 'PLAIN_TEXT', value: ' ' }
}
},
{ type: 'PLAIN_TEXT', value: ' ' }
]
},
{ type: 'HEADING', level: 1, value: [{ type: 'PLAIN_TEXT', value: 'Head 1 after a forced line break' }] },
{ type: 'LINE_BREAK' },
{ type: 'PARAGRAPH', value: [{ type: 'PLAIN_TEXT', value: 'Description' }] }
],
/**
[ ](https://google.com) *There is a link before this bold separated by single space*
*/
linkAndBoldText: [
{
type: 'PARAGRAPH',
value: [
{
type: 'LINK',
value: { src: { type: 'PLAIN_TEXT', value: 'https://google.com' }, label: { type: 'PLAIN_TEXT', value: ' ' } }
},
{ type: 'PLAIN_TEXT', value: ' ' },
{ type: 'BOLD', value: [{ type: 'PLAIN_TEXT', value: 'There is a link before this bold separated by single space' }] }
]
}
],
simpleQuote: [
{
type: 'PARAGRAPH',
value: [
{
type: 'LINK',
value: {
src: {
type: 'PLAIN_TEXT',
value: 'https://open.rocket.chat/group/quoteeee9798789?msg=ZZp6t2dCRX4TqExht'
},
// format of label for servers greater or equal than 6.0
label: [
{
type: 'PLAIN_TEXT',
value: ' '
}
]
}
}
]
},
{
type: 'PARAGRAPH',
value: [
{
type: 'PLAIN_TEXT',
value: 'Quoting a message wrote before'
}
]
}
]
};
export const MessageQuote = () => (
<View style={styles.container}>
<NewMarkdown tokens={messageQuote.headAndLink} />
<NewMarkdown tokens={messageQuote.headTextAndLink} />
<NewMarkdown tokens={messageQuote.headTextAndQuote} />
<NewMarkdown tokens={messageQuote.linkAndBoldText} />
<NewMarkdown tokens={messageQuote.simpleQuote} />
</View>
);

View File

@ -17,7 +17,9 @@ const OrderedList = ({ value }: IOrderedListProps): React.ReactElement => {
{value.map(item => (
<View style={styles.row} key={item.number?.toString()}>
<Text style={[styles.text, { color: colors.bodyText }]}>{item.number}. </Text>
<Inline value={item.value} />
<Text style={{ color: colors.bodyText }}>
<Inline value={item.value} />
</Text>
</View>
))}
</View>

View File

@ -12,10 +12,28 @@ interface IParagraphProps {
}
const Paragraph = ({ value }: IParagraphProps) => {
let forceTrim = false;
const { theme } = useTheme();
if (
value?.[0]?.type === 'LINK' &&
// Need to update the @rocket.chat/message-parser to understand that the label can be a Markup | Markup[]
// https://github.com/RocketChat/fuselage/blob/461ecf661d9ff4a46390957c915e4352fa942a7c/packages/message-parser/src/definitions.ts#L141
// @ts-ignore
(value?.[0]?.value?.label?.value?.toString().trim() === '' || value?.[0]?.value?.label?.[0]?.value?.toString().trim() === '')
) {
// We are returning null when we receive a message like this: `[ ](https://open.rocket.chat/)\nplain_text`
// to avoid render a line empty above the the message
if (value.length === 1) {
return null;
}
if (value.length === 2 && value?.[1]?.type === 'PLAIN_TEXT' && value?.[1]?.value?.toString().trim() === '') {
return null;
}
forceTrim = true;
}
return (
<Text style={[styles.text, { color: themes[theme].bodyText }]}>
<Inline value={value} />
<Inline value={value} forceTrim={forceTrim} />
</Text>
);
};

View File

@ -3,20 +3,15 @@ import { Text } from 'react-native';
import { Plain as PlainProps } from '@rocket.chat/message-parser';
import styles from '../styles';
import { useTheme } from '../../../theme';
import { themes } from '../../../lib/constants';
interface IPlainProps {
value: PlainProps['value'];
}
const Plain = ({ value }: IPlainProps) => {
const { theme } = useTheme();
return (
<Text accessibilityLabel={value} style={[styles.plainText, { color: themes[theme].bodyText }]}>
{value}
</Text>
);
};
const Plain = ({ value }: IPlainProps): React.ReactElement => (
<Text accessibilityLabel={value} style={styles.plainText}>
{value}
</Text>
);
export default Plain;

View File

@ -4,7 +4,6 @@ import { Tasks as TasksProps } from '@rocket.chat/message-parser';
import Inline from './Inline';
import styles from '../styles';
import { themes } from '../../../lib/constants';
import { useTheme } from '../../../theme';
interface ITasksProps {
@ -12,13 +11,15 @@ interface ITasksProps {
}
const TaskList = ({ value = [] }: ITasksProps) => {
const { theme } = useTheme();
const { colors } = useTheme();
return (
<View>
{value.map(item => (
<View style={styles.row}>
<Text style={[styles.text, { color: themes[theme].bodyText }]}>{item.status ? '- [x] ' : '- [ ] '}</Text>
<Inline value={item.value} />
<Text style={[styles.text, { color: colors.bodyText }]}>{item.status ? '- [x] ' : '- [ ] '}</Text>
<Text style={[styles.inline, { color: colors.bodyText }]}>
<Inline value={item.value} />
</Text>
</View>
))}
</View>

View File

@ -18,7 +18,9 @@ const UnorderedList = ({ value }: IUnorderedListProps) => {
{value.map(item => (
<View style={styles.row}>
<Text style={[styles.text, { color: themes[theme].bodyText }]}>- </Text>
<Inline value={item.value} />
<Text style={{ color: themes[theme].bodyText }}>
<Inline value={item.value} />
</Text>
</View>
))}
</View>

View File

@ -20,6 +20,8 @@ import { TGetCustomEmoji } from '../../definitions/IEmoji';
import { IAttachment } from '../../definitions';
import { TSupportedThemes } from '../../theme';
import { downloadAudioFile } from '../../lib/methods/audioFile';
import EventEmitter from '../../lib/methods/helpers/events';
import { PAUSE_AUDIO } from './constants';
interface IButton {
loading: boolean;
@ -128,6 +130,11 @@ class MessageAudio extends React.Component<IMessageAudioProps, IMessageAudioStat
this.sound.setOnPlaybackStatusUpdate(this.onPlaybackStatusUpdate);
}
pauseSound = () => {
EventEmitter.removeListener(PAUSE_AUDIO, this.pauseSound);
this.togglePlayPause();
};
async componentDidMount() {
const { file, messageId } = this.props;
const { baseUrl, user } = this.context;
@ -183,6 +190,7 @@ class MessageAudio extends React.Component<IMessageAudioProps, IMessageAudioStat
}
async componentWillUnmount() {
EventEmitter.removeListener(PAUSE_AUDIO, this.pauseSound);
try {
await this.sound.stopAsync();
} catch {
@ -221,6 +229,7 @@ class MessageAudio extends React.Component<IMessageAudioProps, IMessageAudioStat
try {
await this.sound.stopAsync();
this.setState({ paused: true, currentTime: 0 });
EventEmitter.removeListener(PAUSE_AUDIO, this.pauseSound);
} catch {
// do nothing
}
@ -243,7 +252,10 @@ class MessageAudio extends React.Component<IMessageAudioProps, IMessageAudioStat
try {
if (paused) {
await this.sound.pauseAsync();
EventEmitter.removeListener(PAUSE_AUDIO, this.pauseSound);
} else {
EventEmitter.emit(PAUSE_AUDIO);
EventEmitter.addEventListener(PAUSE_AUDIO, this.pauseSound);
await Audio.setAudioModeAsync(mode);
await this.sound.playAsync();
}

View File

@ -1,4 +1,4 @@
import React from 'react';
import React, { useRef } from 'react';
import { messageBlockWithContext } from '../UIKit/MessageBlock';
import { IMessageBlocks } from './interfaces';
@ -6,25 +6,29 @@ import { IMessageBlocks } from './interfaces';
const Blocks = React.memo(({ blocks, id: mid, rid, blockAction }: IMessageBlocks) => {
if (blocks && blocks.length > 0) {
const appId = blocks[0]?.appId || '';
return React.createElement(
messageBlockWithContext({
action: async ({ actionId, value, blockId }: { actionId: string; value: string; blockId: string }) => {
if (blockAction) {
await blockAction({
actionId,
appId,
value,
blockId,
rid,
mid
});
}
},
appId,
rid
}),
{ blocks }
// eslint-disable-next-line react-hooks/rules-of-hooks
const comp = useRef(
React.createElement(
messageBlockWithContext({
action: async ({ actionId, value, blockId }: { actionId: string; value: string; blockId: string }) => {
if (blockAction) {
await blockAction({
actionId,
appId,
value,
blockId,
rid,
mid
});
}
},
appId,
rid
}),
{ blocks }
)
);
return comp.current;
}
return null;
});

View File

@ -10,12 +10,12 @@ import { themes } from '../../lib/constants';
import { IMessageCallButton } from './interfaces';
import { useTheme } from '../../theme';
const CallButton = React.memo(({ callJitsi }: IMessageCallButton) => {
const CallButton = React.memo(({ handleEnterCall }: IMessageCallButton) => {
const { theme } = useTheme();
return (
<View style={styles.buttonContainer}>
<Touchable
onPress={callJitsi}
onPress={handleEnterCall}
background={Touchable.Ripple(themes[theme].bannerBackground)}
style={[styles.button, { backgroundColor: themes[theme].tintColor }]}
hitSlop={BUTTON_HIT_SLOP}

View File

@ -1,14 +1,20 @@
import React from 'react';
import { themes } from '../../../../lib/constants';
import { CustomIcon } from '../../../CustomIcon';
import styles from '../../styles';
import { useTheme } from '../../../../theme';
const ReadReceipt = React.memo(({ isReadReceiptEnabled, unread }: { isReadReceiptEnabled?: boolean; unread?: boolean }) => {
const { theme } = useTheme();
if (isReadReceiptEnabled && !unread && unread !== null) {
return <CustomIcon name='check' color={themes[theme].tintColor} size={16} style={styles.rightIcons} />;
const { colors } = useTheme();
if (isReadReceiptEnabled) {
return (
<CustomIcon
name='check'
color={!unread && unread !== null ? colors.tintColor : colors.auxiliaryTintColor}
size={16}
style={styles.rightIcons}
/>
);
}
return null;
});

View File

@ -53,7 +53,7 @@ const Content = React.memo(
content = (
<Markdown
msg={props.msg}
md={props.md}
md={props.type !== 'e2e' ? props.md : undefined}
getCustomEmoji={props.getCustomEmoji}
enableMessageParser={user.enableMessageParserEarlyAdoption}
username={user.username}
@ -64,6 +64,7 @@ const Content = React.memo(
useRealName={props.useRealName}
theme={theme}
onLinkPress={onLinkPress}
isTranslated={props.isTranslated}
/>
);
}

View File

@ -18,7 +18,7 @@ const MessageAvatar = React.memo(({ isHeader, avatar, author, small, navToRoomIn
style={small ? styles.avatarSmall : styles.avatar}
text={avatar ? '' : author.username}
size={small ? 20 : 36}
borderRadius={small ? 2 : 4}
borderRadius={4}
onPress={author._id === user.id ? undefined : () => navToRoomInfo(navParam)}
getCustomEmoji={getCustomEmoji}
avatar={avatar}

View File

@ -247,6 +247,8 @@ const Reply = React.memo(
>
<View style={styles.attachmentContainer}>
<Title attachment={attachment} timeFormat={timeFormat} theme={theme} />
<Description attachment={attachment} getCustomEmoji={getCustomEmoji} theme={theme} />
<UrlImage image={attachment.thumb_url} />
<Attachments
attachments={attachment.attachments}
getCustomEmoji={getCustomEmoji}
@ -255,8 +257,6 @@ const Reply = React.memo(
isReply
id={messageId}
/>
<UrlImage image={attachment.thumb_url} />
<Description attachment={attachment} getCustomEmoji={getCustomEmoji} theme={theme} />
<Fields attachment={attachment} getCustomEmoji={getCustomEmoji} theme={theme} />
{loading ? (
<View style={[styles.backdrop]}>

View File

@ -1,2 +1,3 @@
export const DISCUSSION = 'discussion';
export const THREAD = 'thread';
export const PAUSE_AUDIO = 'pause_audio';

View File

@ -50,7 +50,7 @@ interface IMessageContainerProps {
showAttachment: (file: IAttachment) => void;
onReactionLongPress?: (item: TAnyMessageModel) => void;
navToRoomInfo: (navParam: IRoomInfoParam) => void;
callJitsi?: () => void;
handleEnterCall?: () => void;
blockAction?: (params: { actionId: string; appId: string; value: string; blockId: string; rid: string; mid: string }) => void;
onAnswerButtonPress?: (message: string, tmid?: string, tshow?: boolean) => void;
threadBadgeColor?: string;
@ -69,7 +69,6 @@ class MessageContainer extends React.Component<IMessageContainerProps, IMessageC
static defaultProps = {
getCustomEmoji: () => null,
onLongPress: () => {},
callJitsi: () => {},
blockAction: () => {},
archived: false,
broadcast: false,
@ -233,7 +232,9 @@ class MessageContainer extends React.Component<IMessageContainerProps, IMessageC
!(previousItem.groupable === false || item.groupable === false || broadcast === true) &&
// @ts-ignore TODO: IMessage vs IMessageFromServer non-sense
item.ts - previousItem.ts < Message_GroupingPeriod * 1000 &&
previousItem.tmid === item.tmid
previousItem.tmid === item.tmid &&
item.t !== 'rm' &&
previousItem.t !== 'rm'
) {
return false;
}
@ -270,7 +271,7 @@ class MessageContainer extends React.Component<IMessageContainerProps, IMessageC
get isInfo(): string | boolean {
const { item } = this.props;
if (['e2e', 'discussion-created', 'jitsi_call_started'].includes(item.t)) {
if (['e2e', 'discussion-created', 'jitsi_call_started', 'videoconf'].includes(item.t)) {
return false;
}
return item.t;
@ -336,7 +337,7 @@ class MessageContainer extends React.Component<IMessageContainerProps, IMessageC
navToRoomInfo,
getCustomEmoji,
isThreadRoom,
callJitsi,
handleEnterCall,
blockAction,
rid,
threadBadgeColor,
@ -376,10 +377,13 @@ class MessageContainer extends React.Component<IMessageContainerProps, IMessageC
} = item;
let message = msg;
let isTranslated = false;
// "autoTranslateRoom" and "autoTranslateLanguage" are properties from the subscription
// "autoTranslateMessage" is a toggle between "View Original" and "Translate" state
if (autoTranslateRoom && autoTranslateMessage && autoTranslateLanguage) {
message = getMessageTranslation(item, autoTranslateLanguage) || message;
const messageTranslated = getMessageTranslation(item, autoTranslateLanguage);
isTranslated = !!messageTranslated;
message = messageTranslated || message;
}
return (
@ -451,10 +455,11 @@ class MessageContainer extends React.Component<IMessageContainerProps, IMessageC
showAttachment={showAttachment}
getCustomEmoji={getCustomEmoji}
navToRoomInfo={navToRoomInfo}
callJitsi={callJitsi}
handleEnterCall={handleEnterCall}
blockAction={blockAction}
highlighted={highlighted}
comment={comment}
isTranslated={isTranslated}
/>
</MessageContext.Provider>
);

View File

@ -40,7 +40,7 @@ export interface IMessageBroadcast {
}
export interface IMessageCallButton {
callJitsi?: () => void;
handleEnterCall?: () => void;
}
export interface IMessageContent {
@ -63,6 +63,7 @@ export interface IMessageContent {
comment?: string;
hasError: boolean;
isHeader: boolean;
isTranslated: boolean;
}
export interface IMessageEmoji {

View File

@ -41,13 +41,13 @@ export default StyleSheet.create({
reactionButton: {
marginRight: 8,
marginBottom: 8,
borderRadius: 2
borderRadius: 4
},
reactionContainer: {
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
borderRadius: 2,
borderRadius: 4,
borderWidth: 1,
height: 28,
minWidth: 46.3
@ -85,7 +85,7 @@ export default StyleSheet.create({
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
borderRadius: 2
borderRadius: 4
},
buttonIcon: {
marginRight: 8

View File

@ -65,6 +65,7 @@ const messagesWithAuthorName: MessageTypesValues[] = [
'room_changed_avatar',
'room_e2e_disabled',
'room_e2e_enabled',
'room-allowed-reacting',
'room-disallowed-reacting',
'room-set-read-only',
'room-removed-read-only',

View File

@ -8,7 +8,15 @@ import { TThreadMessageModel } from './IThreadMessage';
import { TThreadModel } from './IThread';
import { IUrl, IUrlFromServer } from './IUrl';
export type MessageType = 'jitsi_call_started' | 'discussion-created' | 'e2e' | 'load_more' | 'rm' | 'uj' | MessageTypeLoad | MessageTypesValues;
export type MessageType =
| 'jitsi_call_started'
| 'discussion-created'
| 'e2e'
| 'load_more'
| 'rm'
| 'uj'
| MessageTypeLoad
| MessageTypesValues;
export interface IUserMessage {
_id: string;
@ -222,6 +230,7 @@ export type MessageTypesValues =
| 'room-allowed-reacting'
| 'room-disallowed-reacting'
| 'command'
| 'videoconf'
| LivechatMessageTypes
| TeamMessageTypes
| VoipMessageTypesValues

View File

@ -91,6 +91,7 @@ export interface ISubscription {
livechatData?: any;
tags?: string[];
E2EKey?: string;
E2ESuggestedKey?: string;
encrypted?: boolean;
e2eKeyId?: string;
avatarETag?: string;
@ -145,6 +146,7 @@ export interface IServerSubscription extends IRocketChatRecord {
onHold?: boolean;
encrypted?: boolean;
E2EKey?: string;
E2ESuggestedKey?: string;
unreadAlert?: 'default' | 'all' | 'mentions' | 'nothing';
fname?: unknown;

View File

@ -5,6 +5,7 @@ export interface IUpload {
rid?: string;
path: string;
name?: string;
tmid?: string;
description?: string;
size: number;
type?: string;
@ -12,6 +13,7 @@ export interface IUpload {
progress?: number;
error?: boolean;
subscription?: { id: string };
msg?: string;
}
export type TUploadModel = IUpload & Model;

View File

@ -0,0 +1,109 @@
import type { AtLeast } from './utils';
import type { IRocketChatRecord } from './IRocketChatRecord';
import type { IRoom } from './IRoom';
import type { IUser } from './IUser';
import type { IMessage } from './IMessage';
export declare enum VideoConferenceStatus {
CALLING = 0,
STARTED = 1,
EXPIRED = 2,
ENDED = 3,
DECLINED = 4
}
export declare type DirectCallInstructions = {
type: 'direct';
calleeId: IUser['_id'];
callId: string;
};
export declare type ConferenceInstructions = {
type: 'videoconference';
callId: string;
rid: IRoom['_id'];
};
export declare type LivechatInstructions = {
type: 'livechat';
callId: string;
};
export declare type VideoConferenceType =
| DirectCallInstructions['type']
| ConferenceInstructions['type']
| LivechatInstructions['type'];
export interface IVideoConferenceUser extends Pick<Required<IUser>, '_id' | 'username' | 'name' | 'avatarETag'> {
ts: Date;
}
export interface IVideoConference extends IRocketChatRecord {
type: VideoConferenceType;
rid: string;
users: IVideoConferenceUser[];
status: VideoConferenceStatus;
messages: {
started?: IMessage['_id'];
ended?: IMessage['_id'];
};
url?: string;
createdBy: Pick<Required<IUser>, '_id' | 'username' | 'name'>;
createdAt: Date;
endedBy?: Pick<Required<IUser>, '_id' | 'username' | 'name'>;
endedAt?: Date;
providerName: string;
providerData?: Record<string, any>;
ringing?: boolean;
}
export interface IDirectVideoConference extends IVideoConference {
type: 'direct';
}
export interface IGroupVideoConference extends IVideoConference {
type: 'videoconference';
anonymousUsers: number;
title: string;
}
export interface ILivechatVideoConference extends IVideoConference {
type: 'livechat';
}
export declare type VideoConference = IDirectVideoConference | IGroupVideoConference | ILivechatVideoConference;
export declare type VideoConferenceInstructions = DirectCallInstructions | ConferenceInstructions | LivechatInstructions;
export declare const isDirectVideoConference: (call: VideoConference | undefined | null) => call is IDirectVideoConference;
export declare const isGroupVideoConference: (call: VideoConference | undefined | null) => call is IGroupVideoConference;
export declare const isLivechatVideoConference: (call: VideoConference | undefined | null) => call is ILivechatVideoConference;
declare type GroupVideoConferenceCreateData = Omit<IGroupVideoConference, 'createdBy'> & {
createdBy: IUser['_id'];
};
declare type DirectVideoConferenceCreateData = Omit<IDirectVideoConference, 'createdBy'> & {
createdBy: IUser['_id'];
};
declare type LivechatVideoConferenceCreateData = Omit<ILivechatVideoConference, 'createdBy'> & {
createdBy: IUser['_id'];
};
export declare type VideoConferenceCreateData = AtLeast<
DirectVideoConferenceCreateData | GroupVideoConferenceCreateData | LivechatVideoConferenceCreateData,
'createdBy' | 'type' | 'rid' | 'providerName' | 'providerData'
>;
export type VideoConferenceCapabilities = {
mic?: boolean;
cam?: boolean;
title?: boolean;
};
export type VideoConfStartProps = { roomId: string; title?: string; allowRinging?: boolean };
export type VideoConfJoinProps = {
callId: string;
state?: {
mic?: boolean;
cam?: boolean;
};
};
export type VideoConfCancelProps = {
callId: string;
};
export type VideoConfListProps = {
roomId: string;
count?: number;
offset?: number;
};
export type VideoConfInfoProps = { callId: string };

Some files were not shown because too many files have changed in this diff Show More