Merge branch 'develop' into feat.new-audio-player

This commit is contained in:
Reinaldo Neto 2023-08-23 11:41:37 -03:00
commit fe18a1a3fa
201 changed files with 6037 additions and 4377 deletions

6
.buckconfig Normal file
View File

@ -0,0 +1,6 @@
[android]
target = Google Inc.:Google APIs:23
[maven_repositories]
central = https://repo1.maven.org/maven2

View File

@ -1,10 +1,6 @@
defaults: &defaults defaults: &defaults
working_directory: ~/repo working_directory: ~/repo
android-img: &android-img
docker:
- image: cimg/android:2023.04.1-node
orbs: orbs:
android: circleci/android@2.1.2 android: circleci/android@2.1.2
@ -58,13 +54,14 @@ save-gems-cache: &save-gems-cache
update-fastlane-ios: &update-fastlane-ios update-fastlane-ios: &update-fastlane-ios
name: Update Fastlane name: Update Fastlane
command: | command: |
echo "ruby-2.7.7" > ~/.ruby-version
bundle install bundle install
working_directory: ios working_directory: ios
update-fastlane-android: &update-fastlane-android update-fastlane-android: &update-fastlane-android
name: Update Fastlane name: Update Fastlane
command: | command: |
bundle config set --local deployment 'true' echo "ruby-2.7.7" > ~/.ruby-version
bundle install bundle install
working_directory: android working_directory: android
@ -114,10 +111,10 @@ commands:
name: Configure Gradle name: Configure Gradle
command: | command: |
echo -e "" > ./gradle.properties echo -e "" > ./gradle.properties
# echo -e "android.enableAapt2=false" >> ./gradle.properties
echo -e "android.useAndroidX=true" >> ./gradle.properties echo -e "android.useAndroidX=true" >> ./gradle.properties
echo -e "android.enableJetifier=true" >> ./gradle.properties echo -e "android.enableJetifier=true" >> ./gradle.properties
echo -e "newArchEnabled=false" >> ./gradle.properties echo -e "newArchEnabled=false" >> ./gradle.properties
echo -e "hermesEnabled=true" >> ./gradle.properties
echo -e "FLIPPER_VERSION=0.125.0" >> ./gradle.properties echo -e "FLIPPER_VERSION=0.125.0" >> ./gradle.properties
echo -e "VERSIONCODE=$CIRCLE_BUILD_NUM" >> ./gradle.properties echo -e "VERSIONCODE=$CIRCLE_BUILD_NUM" >> ./gradle.properties
@ -150,9 +147,7 @@ commands:
- run: - run:
name: Build App name: Build App
no_output_timeout: 40m
command: | command: |
sudo apt install -y libicu-dev
if [[ $CIRCLE_JOB == "android-build-official" ]]; then if [[ $CIRCLE_JOB == "android-build-official" ]]; then
./gradlew bundleOfficialPlayRelease ./gradlew bundleOfficialPlayRelease
fi fi
@ -172,16 +167,16 @@ commands:
--api-key=$BUGSNAG_KEY_OFFICIAL \ --api-key=$BUGSNAG_KEY_OFFICIAL \
--app-version-code=$CIRCLE_BUILD_NUM \ --app-version-code=$CIRCLE_BUILD_NUM \
--platform android \ --platform android \
--source-map=android/app/build/generated/sourcemaps/react/officialPlayRelease/index.android.bundle.map \ --source-map=android/app/build/generated/sourcemaps/react/officialPlay/release/app.bundle.map \
--bundle android/app/build/ASSETS/createBundleOfficialPlayReleaseJsAndAssets/index.android.bundle --bundle android/app/build/generated/assets/react/officialPlay/release/app.bundle
fi fi
if [[ $CIRCLE_JOB == "android-build-experimental" || "android-automatic-build-experimental" ]]; then if [[ $CIRCLE_JOB == "android-build-experimental" || "android-automatic-build-experimental" ]]; then
npx bugsnag-source-maps upload-react-native \ npx bugsnag-source-maps upload-react-native \
--api-key=$BUGSNAG_KEY \ --api-key=$BUGSNAG_KEY \
--app-version-code=$CIRCLE_BUILD_NUM \ --app-version-code=$CIRCLE_BUILD_NUM \
--platform android \ --platform android \
--source-map=android/app/build/generated/sourcemaps/react/experimentalPlayRelease/index.android.bundle.map \ --source-map=android/app/build/generated/sourcemaps/react/experimentalPlay/release/app.bundle.map \
--bundle android/app/build/ASSETS/createBundleExperimentalPlayReleaseJsAndAssets/index.android.bundle --bundle android/app/build/generated/assets/react/experimentalPlay/release/app.bundle
fi fi
- store_artifacts: - store_artifacts:
@ -389,45 +384,50 @@ jobs:
# Android builds # Android builds
android-build-experimental: android-build-experimental:
<<: *defaults <<: *defaults
<<: *android-img docker:
- image: cimg/android:2022.03.1-node
environment: environment:
<<: *android-env <<: *android-env
<<: *bash-env <<: *bash-env
resource_class: xlarge resource_class: large
steps: steps:
- android-build - android-build
# Android automatic builds # Android automatic builds
android-automatic-build-experimental: android-automatic-build-experimental:
<<: *defaults <<: *defaults
<<: *android-img docker:
- image: circleci/android:api-29-node
environment: environment:
<<: *android-env <<: *android-env
<<: *bash-env <<: *bash-env
resource_class: xlarge resource_class: large
steps: steps:
- android-build - android-build
android-build-official: android-build-official:
<<: *defaults <<: *defaults
<<: *android-img docker:
- image: cimg/android:2022.03.1-node
environment: environment:
<<: *android-env <<: *android-env
<<: *bash-env <<: *bash-env
resource_class: xlarge resource_class: large
steps: steps:
- android-build - android-build
android-internal-app-sharing-experimental: android-internal-app-sharing-experimental:
<<: *defaults <<: *defaults
<<: *android-img docker:
- image: cimg/android:2022.03.1-node
steps: steps:
- upload-to-internal-app-sharing - upload-to-internal-app-sharing
android-google-play-beta-experimental: android-google-play-beta-experimental:
<<: *defaults <<: *defaults
<<: *android-img docker:
- image: cimg/android:2022.03.1-node
steps: steps:
- upload-to-google-play-beta: - upload-to-google-play-beta:
@ -435,13 +435,15 @@ jobs:
android-google-play-production-experimental: android-google-play-production-experimental:
<<: *defaults <<: *defaults
<<: *android-img docker:
- image: cimg/android:2022.03.1-node
steps: steps:
- upload-to-google-play-production - upload-to-google-play-production
android-google-play-beta-official: android-google-play-beta-official:
<<: *defaults <<: *defaults
<<: *android-img docker:
- image: cimg/android:2022.03.1-node
steps: steps:
- upload-to-google-play-beta: - upload-to-google-play-beta:
@ -452,7 +454,7 @@ jobs:
executor: executor:
name: android/android-machine name: android/android-machine
resource-class: xlarge resource-class: xlarge
tag: 2023.04.1 tag: 2022.12.1
environment: environment:
<<: *android-env <<: *android-env
steps: steps:
@ -469,7 +471,6 @@ jobs:
echo -e "android.useAndroidX=true" >> ./gradle.properties echo -e "android.useAndroidX=true" >> ./gradle.properties
echo -e "android.enableJetifier=true" >> ./gradle.properties echo -e "android.enableJetifier=true" >> ./gradle.properties
echo -e "newArchEnabled=false" >> ./gradle.properties echo -e "newArchEnabled=false" >> ./gradle.properties
echo -e "hermesEnabled=true" >> ./gradle.properties
echo -e "FLIPPER_VERSION=0.125.0" >> ./gradle.properties echo -e "FLIPPER_VERSION=0.125.0" >> ./gradle.properties
echo -e "VERSIONCODE=$CIRCLE_BUILD_NUM" >> ./gradle.properties echo -e "VERSIONCODE=$CIRCLE_BUILD_NUM" >> ./gradle.properties
echo -e "APPLICATION_ID=chat.rocket.reactnative" >> ./gradle.properties echo -e "APPLICATION_ID=chat.rocket.reactnative" >> ./gradle.properties
@ -482,7 +483,6 @@ jobs:
working_directory: android working_directory: android
- run: - run:
name: Build Android name: Build Android
no_output_timeout: 20m
command: | command: |
export RUNNING_E2E_TESTS=true export RUNNING_E2E_TESTS=true
yarn e2e:android-build yarn e2e:android-build
@ -501,7 +501,7 @@ jobs:
executor: executor:
name: android/android-machine name: android/android-machine
resource-class: xlarge resource-class: xlarge
tag: 2023.04.1 tag: 2022.12.1
parallelism: 4 parallelism: 4
steps: steps:
- checkout - checkout
@ -522,10 +522,6 @@ jobs:
echo "hw.lcd.density = 440" >> ~/.android/avd/Pixel_API_31_AOSP.avd/config.ini 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.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 echo "hw.lcd.width = 1080" >> ~/.android/avd/Pixel_API_31_AOSP.avd/config.ini
- android/start-emulator:
avd-name: Pixel_API_31_AOSP
verbose: true
post-emulator-launch-assemble-command: ''
- run: - run:
name: Run Detox Tests name: Run Detox Tests
command: | command: |
@ -582,7 +578,6 @@ jobs:
brew install applesimutils brew install applesimutils
- run: - run:
name: Build name: Build
no_output_timeout: 20m
command: | command: |
/usr/libexec/PlistBuddy -c "Set :bugsnag:apiKey $BUGSNAG_KEY" ./ios/RocketChatRN/Info.plist /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 /usr/libexec/PlistBuddy -c "Set :bugsnag:apiKey $BUGSNAG_KEY" ./ios/ShareRocketChatRN/Info.plist

2
.env
View File

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

17
.gitignore vendored
View File

@ -24,7 +24,6 @@ project.xcworkspace
*.mobileprovision *.mobileprovision
ios/Pods/ ios/Pods/
/vendor/bundle/ /vendor/bundle/
ios/.xcode.env.local
# Android/IntelliJ # Android/IntelliJ
# #
@ -33,10 +32,6 @@ build/
.gradle .gradle
local.properties local.properties
*.iml *.iml
.cxx/
*.keystore
!debug.keystore
*.jks
# node.js # node.js
# #
@ -46,6 +41,12 @@ yarn-error.log
coverage/ coverage/
# BUCK
buck-out/
\.buckd/
*.keystore
*.jks
# fastlane # fastlane
# #
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
@ -62,10 +63,10 @@ coverage
artifacts artifacts
.vscode/ .vscode/
e2e/docker/rc_test_env/docker-compose.yml
e2e/docker/data/db
e2e/e2e_account.js
e2e/e2e_account.ts e2e/e2e_account.ts
junit.xml junit.xml
*.p8 *.p8
# Temporary files created by Metro to check the health of the file watcher
.metro-health-check*

View File

@ -1 +0,0 @@
18

1
.ruby-version Normal file
View File

@ -0,0 +1 @@
2.7.7

View File

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

View File

@ -4,8 +4,10 @@ export class MMKVLoader {
} }
setProcessingMode = jest.fn().mockImplementation(() => ({ setProcessingMode = jest.fn().mockImplementation(() => ({
withEncryption: jest.fn().mockImplementation(() => ({ setAccessibleIOS: jest.fn().mockImplementation(() => ({
initialize: jest.fn().mockImplementation(() => {}) withEncryption: jest.fn().mockImplementation(() => ({
initialize: jest.fn().mockImplementation(() => {})
}))
})) }))
})); }));
} }
@ -14,4 +16,8 @@ export const ProcessingModes = {
MULTI_PROCESS: '' MULTI_PROCESS: ''
}; };
export const IOSAccessibleStates = {
AFTER_FIRST_UNLOCK_THIS_DEVICE_ONLY: ''
};
export const create = jest.fn(); export const create = jest.fn();

View File

@ -26,7 +26,7 @@ exports[`Storyshots Avatar Room Avatar External Provider Url 1`] = `"{\\"type\\"
exports[`Storyshots Avatar Static 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"width\\":56,\\"height\\":56,\\"borderRadius\\":4},null],\\"testID\\":\\"avatar\\"},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"overflow\\":\\"hidden\\"},{\\"width\\":56,\\"height\\":56,\\"borderRadius\\":4}]},\\"children\\":[{\\"type\\":\\"FastImageView\\",\\"props\\":{\\"style\\":{\\"position\\":\\"absolute\\",\\"left\\":0,\\"right\\":0,\\"top\\":0,\\"bottom\\":0},\\"source\\":{\\"uri\\":\\"https://user-images.githubusercontent.com/29778115/89444446-14738480-d728-11ea-9412-75fd978d95fb.jpg\\",\\"headers\\":{\\"User-Agent\\":\\"RC Mobile; ios unknown; vunknown (unknown)\\"},\\"priority\\":\\"high\\"},\\"resizeMode\\":\\"cover\\"},\\"children\\":null}]}]}"`; exports[`Storyshots Avatar Static 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"width\\":56,\\"height\\":56,\\"borderRadius\\":4},null],\\"testID\\":\\"avatar\\"},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"overflow\\":\\"hidden\\"},{\\"width\\":56,\\"height\\":56,\\"borderRadius\\":4}]},\\"children\\":[{\\"type\\":\\"FastImageView\\",\\"props\\":{\\"style\\":{\\"position\\":\\"absolute\\",\\"left\\":0,\\"right\\":0,\\"top\\":0,\\"bottom\\":0},\\"source\\":{\\"uri\\":\\"https://user-images.githubusercontent.com/29778115/89444446-14738480-d728-11ea-9412-75fd978d95fb.jpg\\",\\"headers\\":{\\"User-Agent\\":\\"RC Mobile; ios unknown; vunknown (unknown)\\"},\\"priority\\":\\"high\\"},\\"resizeMode\\":\\"cover\\"},\\"children\\":null}]}]}"`;
exports[`Storyshots Avatar Touchable 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"width\\":56,\\"height\\":56,\\"borderRadius\\":4},null],\\"testID\\":\\"avatar\\"},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityState\\":{},\\"accessibilityValue\\":{},\\"focusable\\":true,\\"collapsable\\":false,\\"style\\":{\\"opacity\\":1}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"overflow\\":\\"hidden\\"},{\\"width\\":56,\\"height\\":56,\\"borderRadius\\":4}]},\\"children\\":[{\\"type\\":\\"FastImageView\\",\\"props\\":{\\"style\\":{\\"position\\":\\"absolute\\",\\"left\\":0,\\"right\\":0,\\"top\\":0,\\"bottom\\":0},\\"source\\":{\\"uri\\":\\"https://open.rocket.chat/avatar/Avatar?format=png&size=112\\",\\"headers\\":{\\"User-Agent\\":\\"RC Mobile; ios unknown; vunknown (unknown)\\"},\\"priority\\":\\"high\\"},\\"resizeMode\\":\\"cover\\"},\\"children\\":null}]}]}]}"`; exports[`Storyshots Avatar Touchable 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"width\\":56,\\"height\\":56,\\"borderRadius\\":4},null],\\"testID\\":\\"avatar\\"},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"focusable\\":true,\\"collapsable\\":false,\\"style\\":{\\"opacity\\":1}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"overflow\\":\\"hidden\\"},{\\"width\\":56,\\"height\\":56,\\"borderRadius\\":4}]},\\"children\\":[{\\"type\\":\\"FastImageView\\",\\"props\\":{\\"style\\":{\\"position\\":\\"absolute\\",\\"left\\":0,\\"right\\":0,\\"top\\":0,\\"bottom\\":0},\\"source\\":{\\"uri\\":\\"https://open.rocket.chat/avatar/Avatar?format=png&size=112\\",\\"headers\\":{\\"User-Agent\\":\\"RC Mobile; ios unknown; vunknown (unknown)\\"},\\"priority\\":\\"high\\"},\\"resizeMode\\":\\"cover\\"},\\"children\\":null}]}]}]}"`;
exports[`Storyshots Avatar With E Tag 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"width\\":56,\\"height\\":56,\\"borderRadius\\":4},null],\\"testID\\":\\"avatar\\"},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"overflow\\":\\"hidden\\"},{\\"width\\":56,\\"height\\":56,\\"borderRadius\\":4}]},\\"children\\":[{\\"type\\":\\"FastImageView\\",\\"props\\":{\\"style\\":{\\"position\\":\\"absolute\\",\\"left\\":0,\\"right\\":0,\\"top\\":0,\\"bottom\\":0},\\"source\\":{\\"uri\\":\\"https://open.rocket.chat/avatar/djorkaeff.alexandre?format=png&size=112&etag=5ag8KffJcZj9m5rCv\\",\\"headers\\":{\\"User-Agent\\":\\"RC Mobile; ios unknown; vunknown (unknown)\\"},\\"priority\\":\\"high\\"},\\"resizeMode\\":\\"cover\\"},\\"children\\":null}]}]}"`; exports[`Storyshots Avatar With E Tag 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"width\\":56,\\"height\\":56,\\"borderRadius\\":4},null],\\"testID\\":\\"avatar\\"},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"overflow\\":\\"hidden\\"},{\\"width\\":56,\\"height\\":56,\\"borderRadius\\":4}]},\\"children\\":[{\\"type\\":\\"FastImageView\\",\\"props\\":{\\"style\\":{\\"position\\":\\"absolute\\",\\"left\\":0,\\"right\\":0,\\"top\\":0,\\"bottom\\":0},\\"source\\":{\\"uri\\":\\"https://open.rocket.chat/avatar/djorkaeff.alexandre?format=png&size=112&etag=5ag8KffJcZj9m5rCv\\",\\"headers\\":{\\"User-Agent\\":\\"RC Mobile; ios unknown; vunknown (unknown)\\"},\\"priority\\":\\"high\\"},\\"resizeMode\\":\\"cover\\"},\\"children\\":null}]}]}"`;

View File

@ -1,13 +1,13 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Storyshots Button Custom Button 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityLabel\\":\\"Press me!\\",\\"accessibilityState\\":{\\"disabled\\":false},\\"accessibilityValue\\":{},\\"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 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},\\"accessibilityValue\\":{},\\"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 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},\\"accessibilityValue\\":{},\\"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 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},\\"accessibilityValue\\":{},\\"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 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},\\"accessibilityValue\\":{},\\"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 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},\\"accessibilityValue\\":{},\\"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!\\"]}]}"`; 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 // 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,\\"accessibilityValue\\":{},\\"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 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,\\"accessibilityValue\\":{},\\"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 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,\\"accessibilityValue\\":{},\\"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 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,\\"accessibilityValue\\":{},\\"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 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,\\"accessibilityValue\\":{},\\"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\\"]}]}]}]}]}"`; 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 // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Storyshots Login Services Separators 1`] = `"[{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityLabel\\":\\"More options\\",\\"accessibilityState\\":{\\"disabled\\":false},\\"accessibilityValue\\":{},\\"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},\\"accessibilityValue\\":{},\\"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 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\\":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\\"]}]}]}]"`; 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

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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,3 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Storyshots CollapsibleQuote Item 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"padding\\":10}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityState\\":{},\\"accessibilityValue\\":{},\\"testID\\":\\"collapsibleQuoteTouchable-Engineering (9 today)\\",\\"hitSlop\\":{\\"top\\":4,\\"right\\":4,\\"bottom\\":4,\\"left\\":4},\\"focusable\\":true,\\"collapsable\\":false,\\"style\\":{\\"flexDirection\\":\\"row\\",\\"alignItems\\":\\"center\\",\\"marginTop\\":6,\\"borderWidth\\":1,\\"borderRadius\\":4,\\"minHeight\\":40,\\"backgroundColor\\":\\"#f3f4f5\\",\\"borderLeftColor\\":\\"#CBCED1\\",\\"borderTopColor\\":\\"#e1e5e8\\",\\"borderRightColor\\":\\"#e1e5e8\\",\\"borderBottomColor\\":\\"#e1e5e8\\",\\"borderLeftWidth\\":2,\\"opacity\\":1}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flexDirection\\":\\"row\\"}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flex\\":1,\\"borderRadius\\":4,\\"padding\\":8}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flexDirection\\":\\"row\\"}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"fontSize\\":16,\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#6C727A\\"}]},\\"children\\":[\\"Engineering (9 today)\\"]}]}]},{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"width\\":20,\\"height\\":20,\\"right\\":8,\\"top\\":8,\\"justifyContent\\":\\"center\\",\\"alignItems\\":\\"center\\"}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":22,\\"color\\":\\"#6C727A\\"},null,{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]}]}]}]}]}"`; exports[`Storyshots CollapsibleQuote Item 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"padding\\":10}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"testID\\":\\"collapsibleQuoteTouchable-Engineering (9 today)\\",\\"hitSlop\\":{\\"top\\":4,\\"right\\":4,\\"bottom\\":4,\\"left\\":4},\\"focusable\\":true,\\"collapsable\\":false,\\"style\\":{\\"flexDirection\\":\\"row\\",\\"alignItems\\":\\"center\\",\\"marginTop\\":6,\\"borderWidth\\":1,\\"borderRadius\\":4,\\"minHeight\\":40,\\"backgroundColor\\":\\"#f3f4f5\\",\\"borderLeftColor\\":\\"#CBCED1\\",\\"borderTopColor\\":\\"#e1e5e8\\",\\"borderRightColor\\":\\"#e1e5e8\\",\\"borderBottomColor\\":\\"#e1e5e8\\",\\"borderLeftWidth\\":2,\\"opacity\\":1}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flexDirection\\":\\"row\\"}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flex\\":1,\\"borderRadius\\":4,\\"padding\\":8}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flexDirection\\":\\"row\\"}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"fontSize\\":16,\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#6C727A\\"}]},\\"children\\":[\\"Engineering (9 today)\\"]}]}]},{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"width\\":20,\\"height\\":20,\\"right\\":8,\\"top\\":8,\\"justifyContent\\":\\"center\\",\\"alignItems\\":\\"center\\"}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":22,\\"color\\":\\"#6C727A\\"},null,{\\"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

@ -1,27 +1,27 @@
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
CFPropertyList (3.0.6) CFPropertyList (3.0.5)
rexml rexml
addressable (2.8.4) addressable (2.8.0)
public_suffix (>= 2.0.2, < 6.0) public_suffix (>= 2.0.2, < 5.0)
artifactory (3.0.15) artifactory (3.0.15)
atomos (0.1.3) atomos (0.1.3)
aws-eventstream (1.2.0) aws-eventstream (1.2.0)
aws-partitions (1.750.0) aws-partitions (1.600.0)
aws-sdk-core (3.171.0) aws-sdk-core (3.131.2)
aws-eventstream (~> 1, >= 1.0.2) aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.651.0) aws-partitions (~> 1, >= 1.525.0)
aws-sigv4 (~> 1.5)
jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.63.0)
aws-sdk-core (~> 3, >= 3.165.0)
aws-sigv4 (~> 1.1) aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.121.0) jmespath (~> 1, >= 1.6.1)
aws-sdk-core (~> 3, >= 3.165.0) aws-sdk-kms (1.57.0)
aws-sdk-core (~> 3, >= 3.127.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.114.0)
aws-sdk-core (~> 3, >= 3.127.0)
aws-sdk-kms (~> 1) aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.4) aws-sigv4 (~> 1.4)
aws-sigv4 (1.5.2) aws-sigv4 (1.5.0)
aws-eventstream (~> 1, >= 1.0.2) aws-eventstream (~> 1, >= 1.0.2)
babosa (1.0.4) babosa (1.0.4)
claide (1.1.0) claide (1.1.0)
@ -34,10 +34,10 @@ GEM
rake (>= 12.0.0, < 14.0.0) rake (>= 12.0.0, < 14.0.0)
domain_name (0.5.20190701) domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0) unf (>= 0.0.5, < 1.0.0)
dotenv (2.8.1) dotenv (2.7.6)
emoji_regex (3.2.3) emoji_regex (3.2.3)
excon (0.99.0) excon (0.92.3)
faraday (1.10.3) faraday (1.10.0)
faraday-em_http (~> 1.0) faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0) faraday-em_synchrony (~> 1.0)
faraday-excon (~> 1.1) faraday-excon (~> 1.1)
@ -66,7 +66,7 @@ GEM
faraday_middleware (1.2.0) faraday_middleware (1.2.0)
faraday (~> 1.0) faraday (~> 1.0)
fastimage (2.2.6) fastimage (2.2.6)
fastlane (2.212.2) fastlane (2.206.2)
CFPropertyList (>= 2.3, < 4.0.0) CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.8, < 3.0.0) addressable (>= 2.8, < 3.0.0)
artifactory (~> 3.0) artifactory (~> 3.0)
@ -106,9 +106,9 @@ GEM
xcpretty (~> 0.3.0) xcpretty (~> 0.3.0)
xcpretty-travis-formatter (>= 0.0.3) xcpretty-travis-formatter (>= 0.0.3)
gh_inspector (1.1.3) gh_inspector (1.1.3)
google-apis-androidpublisher_v3 (0.39.0) google-apis-androidpublisher_v3 (0.22.0)
google-apis-core (>= 0.11.0, < 2.a) google-apis-core (>= 0.5, < 2.a)
google-apis-core (0.11.0) google-apis-core (0.6.0)
addressable (~> 2.5, >= 2.5.1) addressable (~> 2.5, >= 2.5.1)
googleauth (>= 0.16.2, < 2.a) googleauth (>= 0.16.2, < 2.a)
httpclient (>= 2.8.1, < 3.a) httpclient (>= 2.8.1, < 3.a)
@ -117,27 +117,27 @@ GEM
retriable (>= 2.0, < 4.a) retriable (>= 2.0, < 4.a)
rexml rexml
webrick webrick
google-apis-iamcredentials_v1 (0.17.0) google-apis-iamcredentials_v1 (0.12.0)
google-apis-core (>= 0.11.0, < 2.a) google-apis-core (>= 0.6, < 2.a)
google-apis-playcustomapp_v1 (0.13.0) google-apis-playcustomapp_v1 (0.9.0)
google-apis-core (>= 0.11.0, < 2.a) google-apis-core (>= 0.6, < 2.a)
google-apis-storage_v1 (0.19.0) google-apis-storage_v1 (0.15.0)
google-apis-core (>= 0.9.0, < 2.a) google-apis-core (>= 0.5, < 2.a)
google-cloud-core (1.6.0) google-cloud-core (1.6.0)
google-cloud-env (~> 1.0) google-cloud-env (~> 1.0)
google-cloud-errors (~> 1.0) google-cloud-errors (~> 1.0)
google-cloud-env (1.6.0) google-cloud-env (1.6.0)
faraday (>= 0.17.3, < 3.0) faraday (>= 0.17.3, < 3.0)
google-cloud-errors (1.3.1) google-cloud-errors (1.2.0)
google-cloud-storage (1.44.0) google-cloud-storage (1.36.2)
addressable (~> 2.8) addressable (~> 2.8)
digest-crc (~> 0.4) digest-crc (~> 0.4)
google-apis-iamcredentials_v1 (~> 0.1) google-apis-iamcredentials_v1 (~> 0.1)
google-apis-storage_v1 (~> 0.19.0) google-apis-storage_v1 (~> 0.1)
google-cloud-core (~> 1.6) google-cloud-core (~> 1.6)
googleauth (>= 0.16.2, < 2.a) googleauth (>= 0.16.2, < 2.a)
mini_mime (~> 1.0) mini_mime (~> 1.0)
googleauth (1.5.2) googleauth (1.2.0)
faraday (>= 0.17.3, < 3.a) faraday (>= 0.17.3, < 3.a)
jwt (>= 1.4, < 3.0) jwt (>= 1.4, < 3.0)
memoist (~> 0.16) memoist (~> 0.16)
@ -148,11 +148,11 @@ GEM
http-cookie (1.0.5) http-cookie (1.0.5)
domain_name (~> 0.5) domain_name (~> 0.5)
httpclient (2.8.3) httpclient (2.8.3)
jmespath (1.6.2) jmespath (1.6.1)
json (2.6.3) json (2.6.2)
jwt (2.7.0) jwt (2.4.1)
memoist (0.16.2) memoist (0.16.2)
mini_magick (4.12.0) mini_magick (4.11.0)
mini_mime (1.1.2) mini_mime (1.1.2)
multi_json (1.15.0) multi_json (1.15.0)
multipart-post (2.0.0) multipart-post (2.0.0)
@ -160,8 +160,8 @@ GEM
naturally (2.2.1) naturally (2.2.1)
optparse (0.1.1) optparse (0.1.1)
os (1.1.4) os (1.1.4)
plist (3.7.0) plist (3.6.0)
public_suffix (5.0.1) public_suffix (4.0.7)
rake (13.0.6) rake (13.0.6)
representable (3.2.0) representable (3.2.0)
declarative (< 0.1.0) declarative (< 0.1.0)
@ -178,7 +178,7 @@ GEM
faraday (>= 0.17.5, < 3.a) faraday (>= 0.17.5, < 3.a)
jwt (>= 1.5, < 3.0) jwt (>= 1.5, < 3.0)
multi_json (~> 1.10) multi_json (~> 1.10)
simctl (1.6.10) simctl (1.6.8)
CFPropertyList CFPropertyList
naturally naturally
terminal-notifier (2.0.0) terminal-notifier (2.0.0)
@ -193,9 +193,8 @@ GEM
unf (0.1.4) unf (0.1.4)
unf_ext unf_ext
unf_ext (0.0.8.2) unf_ext (0.0.8.2)
unf_ext (0.0.8.2-x64-mingw32)
unicode-display_width (1.8.0) unicode-display_width (1.8.0)
webrick (1.8.1) webrick (1.7.0)
word_wrap (1.0.0) word_wrap (1.0.0)
xcodeproj (1.22.0) xcodeproj (1.22.0)
CFPropertyList (>= 2.3.3, < 4.0) CFPropertyList (>= 2.3.3, < 4.0)
@ -217,4 +216,4 @@ DEPENDENCIES
fastlane fastlane
BUNDLED WITH BUNDLED WITH
2.4.10 2.3.11

55
android/app/_BUCK Normal file
View File

@ -0,0 +1,55 @@
# To learn about Buck see [Docs](https://buckbuild.com/).
# To run your application with Buck:
# - install Buck
# - `npm start` - to start the packager
# - `cd android`
# - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"`
# - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck
# - `buck install -r android/app` - compile, install and run application
#
load(":build_defs.bzl", "create_aar_targets", "create_jar_targets")
lib_deps = []
create_aar_targets(glob(["libs/*.aar"]))
create_jar_targets(glob(["libs/*.jar"]))
android_library(
name = "all-libs",
exported_deps = lib_deps,
)
android_library(
name = "app-code",
srcs = glob([
"src/main/java/**/*.java",
]),
deps = [
":all-libs",
":build_config",
":res",
],
)
android_build_config(
name = "build_config",
package = "chat.rocket.reactnative",
)
android_resource(
name = "res",
package = "chat.rocket.reactnative",
res = "src/main/res",
)
android_binary(
name = "app",
keystore = "//android/keystores:debug",
manifest = "src/main/AndroidManifest.xml",
package_type = "debug",
deps = [
":app-code",
],
)

View File

@ -3,7 +3,6 @@ def isFoss = taskRequests.contains("foss")
apply plugin: "com.android.application" apply plugin: "com.android.application"
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply plugin: "com.facebook.react"
if (!isFoss) { if (!isFoss) {
apply plugin: 'com.google.firebase.crashlytics' apply plugin: 'com.google.firebase.crashlytics'
@ -13,88 +12,126 @@ if (!isFoss) {
import com.android.build.OutputFile import com.android.build.OutputFile
/** /**
* This is the configuration block to customize your React Native Android app. * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
* By default you don't need to apply any configuration, just uncomment the lines you need. * and bundleReleaseJsAndAssets).
* These basically call `react-native bundle` with the correct arguments during the Android build
* cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
* bundle directly from the development server. Below you can see all the possible configurations
* and their defaults. If you decide to add a configuration block, make sure to add it before the
* `apply from: "../../node_modules/react-native/react.gradle"` line.
*
* project.ext.react = [
* // the name of the generated asset file containing your JS bundle
* bundleAssetName: "index.android.bundle",
*
* // the entry file for bundle generation. If none specified and
* // "index.android.js" exists, it will be used. Otherwise "index.tsx" is
* // default. Can be overridden with ENTRY_FILE environment variable.
* entryFile: "index.android.js",
*
* // https://facebook.github.io/react-native/docs/performance#enable-the-ram-format
* bundleCommand: "ram-bundle",
*
* // whether to bundle JS and assets in debug mode
* bundleInDebug: false,
*
* // whether to bundle JS and assets in release mode
* bundleInRelease: true,
*
* // whether to bundle JS and assets in another build variant (if configured).
* // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
* // The configuration property can be in the following formats
* // 'bundleIn${productFlavor}${buildType}'
* // 'bundleIn${buildType}'
* // bundleInFreeDebug: true,
* // bundleInPaidRelease: true,
* // bundleInBeta: true,
*
* // whether to disable dev mode in custom build variants (by default only disabled in release)
* // for example: to disable dev mode in the staging build type (if configured)
* devDisabledInStaging: true,
* // The configuration property can be in the following formats
* // 'devDisabledIn${productFlavor}${buildType}'
* // 'devDisabledIn${buildType}'
*
* // the root of your project, i.e. where "package.json" lives
* root: "../../",
*
* // where to put the JS bundle asset in debug mode
* jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
*
* // where to put the JS bundle asset in release mode
* jsBundleDirRelease: "$buildDir/intermediates/assets/release",
*
* // where to put drawable resources / React Native assets, e.g. the ones you use via
* // require('./image.png')), in debug mode
* resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
*
* // where to put drawable resources / React Native assets, e.g. the ones you use via
* // require('./image.png')), in release mode
* resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
*
* // by default the gradle tasks are skipped if none of the JS files or assets change; this means
* // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
* // date; if you have any other folders that you want to ignore for performance reasons (gradle
* // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
* // for example, you might want to remove it from here.
* inputExcludes: ["android/**", "ios/**"],
*
* // override which node gets called and with what additional arguments
* nodeExecutableAndArgs: ["node"],
*
* // supply additional arguments to the packager
* extraPackagerArgs: []
* ]
*/ */
react {
/* Folders */
// The root of your project, i.e. where "package.json" lives. Default is '..'
// root = file("../")
// The folder where the react-native NPM package is. Default is ../node_modules/react-native
// reactNativeDir = file("../node_modules/react-native")
// The folder where the react-native Codegen package is. Default is ../node_modules/react-native-codegen
// codegenDir = file("../node_modules/react-native-codegen")
// The cli.js file which is the React Native CLI entrypoint. Default is ../node_modules/react-native/cli.js
// cliFile = file("../node_modules/react-native/cli.js")
/* Variants */
// The list of variants to that are debuggable. For those we're going to
// skip the bundling of the JS bundle and the assets. By default is just 'debug'.
// If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants.
debuggableVariants = ["experimentalPlayDebug", "officialPlayDebug", "experimentalFossDebug", "officialFossDebug"]
/* Bundling */
// A list containing the node command and its flags. Default is just 'node'.
// nodeExecutableAndArgs = ["node"]
//
// The command to run when bundling. By default is 'bundle'
// bundleCommand = "ram-bundle"
//
// The path to the CLI configuration file. Default is empty.
// bundleConfig = file(../rn-cli.config.js)
//
// The name of the generated asset file containing your JS bundle
// bundleAssetName = "MyApplication.android.bundle"
//
// The entry file for bundle generation. Default is 'index.android.js' or 'index.js'
// entryFile = file("../js/MyApplication.android.js")
//
// A list of extra flags to pass to the 'bundle' commands.
// See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle
// extraPackagerArgs = []
/* Hermes Commands */
// The hermes compiler command to run. By default it is 'hermesc'
// hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc"
//
// The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map"
// hermesFlags = ["-O", "-output-source-map"]
}
project.ext.react = [
bundleAssetName: "app.bundle",
iconFontNames: [ 'custom.ttf' ],
enableHermes: true, // clean and rebuild if changing
]
// project.ext.react = [ apply from: "../../node_modules/react-native/react.gradle"
// bundleAssetName: "app.bundle",
// iconFontNames: [ 'custom.ttf' ],
// enableHermes: true, // clean and rebuild if changing
// ]
/** /**
* Set this to true to create four separate APKs instead of one, * Set this to true to create two separate APKs instead of one:
* one for each native architecture. This is useful if you don't * - An APK that only works on ARM devices
* use App Bundles (https://developer.android.com/guide/app-bundle/) * - An APK that only works on x86 devices
* and want to have separate APKs to upload to the Play Store. * The advantage is the size of the APK is reduced by about 4MB.
* Upload all the APKs to the Play Store and people will download
* the correct one based on the CPU architecture of their device.
*/ */
def enableSeparateBuildPerCPUArchitecture = false def enableSeparateBuildPerCPUArchitecture = false
/** /**
* Set this to true to Run Proguard on Release builds to minify the Java bytecode. * Run Proguard to shrink the Java bytecode in release builds.
*/ */
def enableProguardInReleaseBuilds = false def enableProguardInReleaseBuilds = false
/** /**
* The preferred build flavor of JavaScriptCore (JSC) * The preferred build flavor of JavaScriptCore.
* *
* For example, to use the international variant, you can use: * For example, to use the international variant, you can use:
* `def jscFlavor = 'org.webkit:android-jsc-intl:+'` * `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
* *
* The international variant includes ICU i18n library and necessary data * The international variant includes ICU i18n library and necessary data
* allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
* give correct results when using with locales other than en-US. Note that * give correct results when using with locales other than en-US. Note that
* this variant is about 6MiB larger per architecture than default. * this variant is about 6MiB larger per architecture than default.
*/ */
def jscFlavor = 'org.webkit:android-jsc:+' def jscFlavor = 'org.webkit:android-jsc:+'
/**
* Whether to enable the Hermes VM.
*
* This should be set on project.ext.react and mirrored here. If it is not set
* on project.ext.react, JavaScript will not be compiled to Hermes Bytecode
* and the benefits of using Hermes will therefore be sharply reduced.
*/
def enableHermes = project.ext.react.get("enableHermes", false);
/** /**
* Private function to get the list of Native Architectures you want to build. * Architectures to build native code for.
* This reads the value from reactNativeArchitectures in your gradle.properties
* file and works together with the --active-arch-only flag of react-native run-android.
*/ */
def reactNativeArchitectures() { def reactNativeArchitectures() {
def value = project.getProperties().get("reactNativeArchitectures") def value = project.getProperties().get("reactNativeArchitectures")
@ -105,8 +142,6 @@ android {
ndkVersion rootProject.ext.ndkVersion ndkVersion rootProject.ext.ndkVersion
compileSdkVersion rootProject.ext.compileSdkVersion compileSdkVersion rootProject.ext.compileSdkVersion
// Can't set this, since it causes issues to Official flavor
// namespace APPLICATION_ID
defaultConfig { defaultConfig {
applicationId APPLICATION_ID applicationId APPLICATION_ID
minSdkVersion rootProject.ext.minSdkVersion minSdkVersion rootProject.ext.minSdkVersion
@ -121,16 +156,78 @@ android {
resValue "string", "rn_config_reader_custom_package", "chat.rocket.reactnative" resValue "string", "rn_config_reader_custom_package", "chat.rocket.reactnative"
testBuildType System.getProperty('testBuildType', 'debug') testBuildType System.getProperty('testBuildType', 'debug')
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
}
splits { buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
abi { if (isNewArchitectureEnabled()) {
reset() // We configure the NDK build only if you decide to opt-in for the New Architecture.
enable enableSeparateBuildPerCPUArchitecture externalNativeBuild {
universalApk false // If true, also generate a universal APK ndkBuild {
include (*reactNativeArchitectures()) arguments "APP_PLATFORM=android-21",
"APP_STL=c++_shared",
"NDK_TOOLCHAIN_VERSION=clang",
"GENERATED_SRC_DIR=$buildDir/generated/source",
"PROJECT_BUILD_DIR=$buildDir",
"REACT_ANDROID_DIR=$rootDir/../node_modules/react-native/ReactAndroid",
"REACT_ANDROID_BUILD_DIR=$rootDir/../node_modules/react-native/ReactAndroid/build"
cFlags "-Wall", "-Werror", "-fexceptions", "-frtti", "-DWITH_INSPECTOR=1"
cppFlags "-std=c++17"
// Make sure this target name is the same you specify inside the
// src/main/jni/Android.mk file for the `LOCAL_MODULE` variable.
targets "rndiffapp_appmodules"
// Fix for windows limit on number of character in file paths and in command lines
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
arguments "NDK_APP_SHORT_COMMANDS=true"
}
}
}
if (!enableSeparateBuildPerCPUArchitecture) {
ndk {
abiFilters (*reactNativeArchitectures())
}
}
} }
} }
if (isNewArchitectureEnabled()) {
// We configure the NDK build only if you decide to opt-in for the New Architecture.
externalNativeBuild {
ndkBuild {
path "$projectDir/src/main/jni/Android.mk"
}
}
def reactAndroidProjectDir = project(':ReactAndroid').projectDir
def packageReactNdkDebugLibs = tasks.register("packageReactNdkDebugLibs", Copy) {
dependsOn(":ReactAndroid:packageReactNdkDebugLibsForBuck")
from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib")
into("$buildDir/react-ndk/exported")
}
def packageReactNdkReleaseLibs = tasks.register("packageReactNdkReleaseLibs", Copy) {
dependsOn(":ReactAndroid:packageReactNdkReleaseLibsForBuck")
from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib")
into("$buildDir/react-ndk/exported")
}
afterEvaluate {
// If you wish to add a custom TurboModule or component locally,
// you should uncomment this line.
// preBuild.dependsOn("generateCodegenArtifactsFromSchema")
preDebugBuild.dependsOn(packageReactNdkDebugLibs)
preReleaseBuild.dependsOn(packageReactNdkReleaseLibs)
// Due to a bug inside AGP, we have to explicitly set a dependency
// between configureNdkBuild* tasks and the preBuild tasks.
// This can be removed once this is solved: https://issuetracker.google.com/issues/207403732
configureNdkBuildRelease.dependsOn(preReleaseBuild)
configureNdkBuildDebug.dependsOn(preDebugBuild)
reactNativeArchitectures().each { architecture ->
tasks.findByName("configureNdkBuildDebug[${architecture}]")?.configure {
dependsOn("preDebugBuild")
}
tasks.findByName("configureNdkBuildRelease[${architecture}]")?.configure {
dependsOn("preReleaseBuild")
}
}
}
}
signingConfigs { signingConfigs {
release { release {
if (project.hasProperty('KEYSTORE')) { if (project.hasProperty('KEYSTORE')) {
@ -141,6 +238,14 @@ android {
} }
} }
} }
splits {
abi {
reset()
enable enableSeparateBuildPerCPUArchitecture
universalApk false // If true, also generate a universal APK
include (*reactNativeArchitectures())
}
}
buildTypes { buildTypes {
release { release {
minifyEnabled enableProguardInReleaseBuilds minifyEnabled enableProguardInReleaseBuilds
@ -157,6 +262,18 @@ android {
} }
} }
// packagingOptions {
// pickFirst '**/armeabi-v7a/libc++_shared.so'
// pickFirst '**/x86/libc++_shared.so'
// pickFirst '**/arm64-v8a/libc++_shared.so'
// pickFirst '**/x86_64/libc++_shared.so'
// }
// FIXME: Remove when we update RN
packagingOptions {
pickFirst '**/*.so'
}
// applicationVariants are e.g. debug, release // applicationVariants are e.g. debug, release
flavorDimensions "app", "type" flavorDimensions "app", "type"
@ -225,47 +342,74 @@ android {
} }
dependencies { dependencies {
// The version of react-native is set by the React Native Gradle Plugin
implementation("com.facebook.react:react-android")
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.0.0")
debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}")
debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
exclude group:'com.squareup.okhttp3', module:'okhttp'
}
debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}")
if (hermesEnabled.toBoolean()) {
implementation("com.facebook.react:hermes-android")
} else {
implementation jscFlavor
}
implementation project(':@react-native-community_viewpager') implementation project(':@react-native-community_viewpager')
implementation "androidx.core:core-splashscreen:1.0.0" implementation "androidx.core:core-splashscreen:1.0.0"
playImplementation project(':react-native-notifications') playImplementation project(':react-native-notifications')
playImplementation 'com.google.firebase:firebase-core:16.0.0' playImplementation 'com.google.firebase:firebase-core:16.0.0'
playImplementation project(':@react-native-firebase_app') playImplementation project(':@react-native-firebase_app')
playImplementation project(':@react-native-firebase_analytics') playImplementation project(':@react-native-firebase_analytics')
playImplementation project(':@react-native-firebase_crashlytics') playImplementation project(':@react-native-firebase_crashlytics')
implementation fileTree(dir: "libs", include: ["*.jar"])
//noinspection GradleDynamicVersion
implementation "com.facebook.react:react-native:+" // From node_modules
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
exclude group:'com.facebook.fbjni'
}
debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
exclude group:'com.facebook.flipper'
exclude group:'com.squareup.okhttp3', module:'okhttp'
}
debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") {
exclude group:'com.facebook.flipper'
}
if (enableHermes) {
def hermesPath = "../../node_modules/hermes-engine/android/";
debugImplementation files(hermesPath + "hermes-debug.aar")
releaseImplementation files(hermesPath + "hermes-release.aar")
} else {
implementation jscFlavor
}
implementation "com.google.code.gson:gson:2.8.9" implementation "com.google.code.gson:gson:2.8.9"
implementation "com.github.bumptech.glide:glide:4.9.0" implementation "com.github.bumptech.glide:glide:4.9.0"
annotationProcessor "com.github.bumptech.glide:compiler:4.9.0" annotationProcessor "com.github.bumptech.glide:compiler:4.9.0"
implementation "com.tencent:mmkv-static:1.2.10" implementation "com.tencent:mmkv-static:1.2.10"
androidTestImplementation('com.wix:detox:+') androidTestImplementation('com.wix:detox:+')
androidTestImplementation 'androidx.test:core:1.4.0'
implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'com.facebook.soloader:soloader:0.10.4' implementation 'com.facebook.soloader:soloader:0.10.4'
} }
if (isNewArchitectureEnabled()) {
// If new architecture is enabled, we let you build RN from source
// Otherwise we fallback to a prebuilt .aar bundled in the NPM package.
// This will be applied to all the imported transtitive dependency.
configurations.all {
resolutionStrategy.dependencySubstitution {
substitute(module("com.facebook.react:react-native"))
.using(project(":ReactAndroid")).because("On New Architecture we're building React Native from source")
}
}
}
// Run this once to be able to run the application with BUCK
// puts all compile dependencies into folder libs for BUCK to use
task copyDownloadableDepsToLibs(type: Copy) {
from configurations.implementation
into 'libs'
}
apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
if (!isFoss) { if (!isFoss) {
apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.gms.google-services'
} }
bugsnag { def isNewArchitectureEnabled() {
uploadReactNativeMappings = false // To opt-in for the New Architecture, you can either:
// - Set `newArchEnabled` to true inside the `gradle.properties` file
// - Invoke gradle with `-newArchEnabled=true`
// - Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true`
return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
} }

View File

@ -0,0 +1,19 @@
"""Helper definitions to glob .aar and .jar targets"""
def create_aar_targets(aarfiles):
for aarfile in aarfiles:
name = "aars__" + aarfile[aarfile.rindex("/") + 1:aarfile.rindex(".aar")]
lib_deps.append(":" + name)
android_prebuilt_aar(
name = name,
aar = aarfile,
)
def create_jar_targets(jarfiles):
for jarfile in jarfiles:
name = "jars__" + jarfile[jarfile.rindex("/") + 1:jarfile.rindex(".jar")]
lib_deps.append(":" + name)
prebuilt_jar(
name = name,
binary_jar = jarfile,
)

View File

@ -1,3 +1,9 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
* directory of this source tree.
*/
package chat.rocket.reactnative; package chat.rocket.reactnative;
import android.content.Context; import android.content.Context;
import com.facebook.flipper.android.AndroidFlipperClient; import com.facebook.flipper.android.AndroidFlipperClient;
@ -18,11 +24,6 @@ import com.facebook.react.bridge.ReactContext;
import com.facebook.react.modules.network.NetworkingModule; import com.facebook.react.modules.network.NetworkingModule;
import com.facebook.react.modules.network.CustomClientBuilder; import com.facebook.react.modules.network.CustomClientBuilder;
import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;
/**
* Class responsible of loading Flipper inside your React Native application. This is the debug
* flavor of it. Here you can add your own plugins and customize the Flipper setup.
*/
public class ReactNativeFlipper { public class ReactNativeFlipper {
public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) { public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
if (FlipperUtils.shouldEnableFlipper(context)) { if (FlipperUtils.shouldEnableFlipper(context)) {

View File

@ -0,0 +1,24 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="731.4286"
android:viewportHeight="731.4286">
<group android:translateX="109.71429"
android:translateY="109.71429">
<group>
<clip-path android:pathData="M0,0h512v512h-512z M 0,0"/>
<path
android:pathData="M404.999,208.068C396.342,194.624 384.207,182.722 368.953,172.683C339.479,153.318 300.753,142.65 259.908,142.65C246.261,142.65 232.816,143.837 219.765,146.187C211.667,138.391 202.2,131.378 192.173,125.836C154.971,107.29 122.187,114.196 105.623,120.152C100.181,122.11 98.502,128.993 102.527,133.146C114.209,145.202 133.536,169.029 128.785,190.696C110.315,209.551 100.3,232.287 100.3,255.959C100.3,280.083 110.315,302.818 128.785,321.674C133.536,343.341 114.209,367.18 102.527,379.236C98.514,383.377 100.181,390.259 105.623,392.217C122.187,398.174 154.971,405.092 192.185,386.545C202.212,381.004 211.679,373.991 219.777,366.195C232.828,368.544 246.273,369.731 259.92,369.731C300.777,369.731 339.503,359.075 368.965,339.71C384.219,329.671 396.354,317.782 405.011,304.325C414.657,289.35 419.539,273.225 419.539,256.422C419.527,239.169 414.645,223.055 404.999,208.068ZM258.241,341.787C240.58,341.787 223.742,339.508 208.392,335.391L197.174,346.177C191.077,352.039 183.932,357.343 176.478,361.52C166.606,366.349 156.853,368.995 147.207,369.79C147.755,368.806 148.255,367.809 148.791,366.812C160.032,346.165 163.069,327.607 157.889,311.148C139.502,296.707 128.475,278.22 128.475,258.083C128.475,211.865 186.576,174.392 258.241,174.392C329.905,174.392 388.018,211.865 388.018,258.083C388.018,304.314 329.917,341.787 258.241,341.787Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M196.162,238.837C185.6,238.837 177.038,247.333 177.038,257.811C177.038,268.288 185.6,276.784 196.162,276.784C206.725,276.784 215.287,268.288 215.287,257.811C215.287,247.333 206.725,238.837 196.162,238.837Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M257.717,238.837C247.154,238.837 238.592,247.333 238.592,257.811C238.592,268.288 247.154,276.784 257.717,276.784C268.279,276.784 276.842,268.288 276.842,257.811C276.842,247.333 268.279,238.837 257.717,238.837Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M319.282,238.837C308.72,238.837 300.158,247.333 300.158,257.811C300.158,268.288 308.72,276.784 319.282,276.784C329.845,276.784 338.407,268.288 338.407,257.811C338.407,247.333 329.845,238.837 319.282,238.837Z"
android:fillColor="#ffffff"/>
</group>
</group>
</vector>

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/> <background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/> <foreground android:drawable="@drawable/ic_launcher_foreground"/>
<monochrome android:drawable="@drawable/ic_launcher_monochrome"/>
</adaptive-icon> </adaptive-icon>

View File

@ -2,4 +2,5 @@
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/> <background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/> <foreground android:drawable="@drawable/ic_launcher_foreground"/>
<monochrome android:drawable="@drawable/ic_launcher_monochrome"/>
</adaptive-icon> </adaptive-icon>

View File

@ -6,10 +6,9 @@ import android.os.Bundle;
import com.facebook.react.ReactActivity; import com.facebook.react.ReactActivity;
import com.facebook.react.ReactActivityDelegate; import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint; import com.facebook.react.ReactRootView;
import com.facebook.react.defaults.DefaultReactActivityDelegate;
import com.zoontek.rnbootsplash.RNBootSplash; import com.zoontek.rnbootsplash.RNBootSplash;
import expo.modules.ReactActivityDelegateWrapper; import expo.modules.ReactActivityDelegateWrapper;
public class MainActivity extends ReactActivity { public class MainActivity extends ReactActivity {
@ -44,20 +43,26 @@ public class MainActivity extends ReactActivity {
this.sendBroadcast(intent); this.sendBroadcast(intent);
} }
/** /**
* Returns the instance of the {@link ReactActivityDelegate}. Here we use a util class {@link * Returns the instance of the {@link ReactActivityDelegate}. There the RootView is created and
* DefaultReactActivityDelegate} which allows you to easily enable Fabric and Concurrent React * you can specify the rendered you wish to use (Fabric or the older renderer).
* (aka React 18) with two boolean flags.
*/ */
@Override @Override
protected ReactActivityDelegate createReactActivityDelegate() { protected ReactActivityDelegate createReactActivityDelegate() {
return new DefaultReactActivityDelegate( return new ReactActivityDelegateWrapper(this, new MainActivityDelegate(this, getMainComponentName()));
this, }
getMainComponentName(),
public static class MainActivityDelegate extends ReactActivityDelegate {
public MainActivityDelegate(ReactActivity activity, String mainComponentName) {
super(activity, mainComponentName);
}
@Override
protected ReactRootView createRootView() {
ReactRootView reactRootView = new ReactRootView(getContext());
// If you opted-in for the New Architecture, we enable the Fabric Renderer. // If you opted-in for the New Architecture, we enable the Fabric Renderer.
DefaultNewArchitectureEntryPoint.getFabricEnabled(), // fabricEnabled reactRootView.setIsFabric(BuildConfig.IS_NEW_ARCHITECTURE_ENABLED);
// If you opted-in for the New Architecture, we enable Concurrent React (i.e. React 18). return reactRootView;
DefaultNewArchitectureEntryPoint.getConcurrentReactEnabled() // concurrentRootEnabled }
);
} }
} }

View File

@ -8,70 +8,115 @@ import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication; import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost; import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage; import com.facebook.react.ReactPackage;
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint; import com.facebook.react.config.ReactFeatureFlags;
import com.facebook.react.defaults.DefaultReactNativeHost; import com.facebook.react.ReactInstanceManager;
import com.facebook.soloader.SoLoader; import com.facebook.soloader.SoLoader;
import com.reactnativecommunity.viewpager.RNCViewPagerPackage; import com.reactnativecommunity.viewpager.RNCViewPagerPackage;
import com.facebook.react.bridge.JSIModulePackage; import com.facebook.react.bridge.JSIModulePackage;
import com.swmansion.reanimated.ReanimatedJSIModulePackage;
import android.content.Context; import android.content.Context;
import android.content.res.Configuration; import android.content.res.Configuration;
import expo.modules.ApplicationLifecycleDispatcher; import expo.modules.ApplicationLifecycleDispatcher;
import expo.modules.ReactNativeHostWrapper; import expo.modules.ReactNativeHostWrapper;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import chat.rocket.reactnative.newarchitecture.MainApplicationReactNativeHost;
import chat.rocket.reactnative.networking.SSLPinningPackage; import chat.rocket.reactnative.networking.SSLPinningPackage;
public class MainApplication extends Application implements ReactApplication { public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = private final ReactNativeHost mReactNativeHost = new ReactNativeHostWrapper(this, new ReactNativeHost(this) {
new DefaultReactNativeHost(this) { @Override
@Override public boolean getUseDeveloperSupport() {
public boolean getUseDeveloperSupport() { return BuildConfig.DEBUG;
return BuildConfig.DEBUG; }
}
@Override @Override
protected List<ReactPackage> getPackages() { protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable") @SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages(); List<ReactPackage> packages = new PackageList(this).getPackages();
packages.add(new RNCViewPagerPackage()); packages.add(new RNCViewPagerPackage());
packages.add(new SSLPinningPackage()); packages.add(new SSLPinningPackage());
List<ReactPackage> additionalModules = new AdditionalModules().getAdditionalModules(MainApplication.this); List<ReactPackage> additionalModules = new AdditionalModules().getAdditionalModules(MainApplication.this);
packages.addAll(additionalModules); packages.addAll(additionalModules);
return packages; return packages;
} }
@Override @Override
protected String getJSMainModuleName() { protected String getJSMainModuleName() {
return "index"; return "index";
} }
@Override @Override
protected boolean isNewArchEnabled() { protected JSIModulePackage getJSIModulePackage() {
return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; return new ReanimatedJSIModulePackage();
} }
@Override @Override
protected Boolean isHermesEnabled() { protected @Nullable String getBundleAssetName() {
return BuildConfig.IS_HERMES_ENABLED; return "app.bundle";
} }
}; });
private final ReactNativeHost mNewArchitectureNativeHost =
new ReactNativeHostWrapper(this, new MainApplicationReactNativeHost(this));
@Override @Override
public ReactNativeHost getReactNativeHost() { public ReactNativeHost getReactNativeHost() {
return mReactNativeHost; if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
return mNewArchitectureNativeHost;
} else {
return mReactNativeHost;
}
} }
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
// 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); SoLoader.init(this, /* native exopackage */ false);
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
// If you opted-in for the New Architecture, we load the native entry point for this app. ApplicationLifecycleDispatcher.onApplicationCreate(this);
DefaultNewArchitectureEntryPoint.load(); }
@Override
public void onConfigurationChanged(Configuration newConfig) {
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();
}
} }
ReactNativeFlipper.initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
} }
} }

View File

@ -0,0 +1,116 @@
package chat.rocket.reactnative.newarchitecture;
import android.app.Application;
import androidx.annotation.NonNull;
import com.facebook.react.PackageList;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.ReactPackageTurboModuleManagerDelegate;
import com.facebook.react.bridge.JSIModulePackage;
import com.facebook.react.bridge.JSIModuleProvider;
import com.facebook.react.bridge.JSIModuleSpec;
import com.facebook.react.bridge.JSIModuleType;
import com.facebook.react.bridge.JavaScriptContextHolder;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.UIManager;
import com.facebook.react.fabric.ComponentFactory;
import com.facebook.react.fabric.CoreComponentsRegistry;
import com.facebook.react.fabric.EmptyReactNativeConfig;
import com.facebook.react.fabric.FabricJSIModuleProvider;
import com.facebook.react.uimanager.ViewManagerRegistry;
import chat.rocket.reactnative.BuildConfig;
import chat.rocket.reactnative.newarchitecture.components.MainComponentsRegistry;
import chat.rocket.reactnative.newarchitecture.modules.MainApplicationTurboModuleManagerDelegate;
import java.util.ArrayList;
import java.util.List;
/**
* A {@link ReactNativeHost} that helps you load everything needed for the New Architecture, both
* TurboModule delegates and the Fabric Renderer.
*
* <p>Please note that this class is used ONLY if you opt-in for the New Architecture (see the
* `newArchEnabled` property). Is ignored otherwise.
*/
public class MainApplicationReactNativeHost extends ReactNativeHost {
public MainApplicationReactNativeHost(Application application) {
super(application);
}
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List<ReactPackage> getPackages() {
List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
// TurboModules must also be loaded here providing a valid TurboReactPackage implementation:
// packages.add(new TurboReactPackage() { ... });
// If you have custom Fabric Components, their ViewManagers should also be loaded here
// inside a ReactPackage.
return packages;
}
@Override
protected String getJSMainModuleName() {
return "index";
}
@NonNull
@Override
protected ReactPackageTurboModuleManagerDelegate.Builder
getReactPackageTurboModuleManagerDelegateBuilder() {
// Here we provide the ReactPackageTurboModuleManagerDelegate Builder. This is necessary
// for the new architecture and to use TurboModules correctly.
return new MainApplicationTurboModuleManagerDelegate.Builder();
}
@Override
protected JSIModulePackage getJSIModulePackage() {
return new JSIModulePackage() {
@Override
public List<JSIModuleSpec> getJSIModules(
final ReactApplicationContext reactApplicationContext,
final JavaScriptContextHolder jsContext) {
final List<JSIModuleSpec> specs = new ArrayList<>();
// Here we provide a new JSIModuleSpec that will be responsible of providing the
// custom Fabric Components.
specs.add(
new JSIModuleSpec() {
@Override
public JSIModuleType getJSIModuleType() {
return JSIModuleType.UIManager;
}
@Override
public JSIModuleProvider<UIManager> getJSIModuleProvider() {
final ComponentFactory componentFactory = new ComponentFactory();
CoreComponentsRegistry.register(componentFactory);
// Here we register a Components Registry.
// The one that is generated with the template contains no components
// and just provides you the one from React Native core.
MainComponentsRegistry.register(componentFactory);
final ReactInstanceManager reactInstanceManager = getReactInstanceManager();
ViewManagerRegistry viewManagerRegistry =
new ViewManagerRegistry(
reactInstanceManager.getOrCreateViewManagers(reactApplicationContext));
return new FabricJSIModuleProvider(
reactApplicationContext,
componentFactory,
new EmptyReactNativeConfig(),
viewManagerRegistry);
}
});
return specs;
}
};
}
}

View File

@ -0,0 +1,36 @@
package chat.rocket.reactnative.newarchitecture.components;
import com.facebook.jni.HybridData;
import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.react.fabric.ComponentFactory;
import com.facebook.soloader.SoLoader;
/**
* Class responsible to load the custom Fabric Components. This class has native methods and needs a
* corresponding C++ implementation/header file to work correctly (already placed inside the jni/
* folder for you).
*
* <p>Please note that this class is used ONLY if you opt-in for the New Architecture (see the
* `newArchEnabled` property). Is ignored otherwise.
*/
@DoNotStrip
public class MainComponentsRegistry {
static {
SoLoader.loadLibrary("fabricjni");
}
@DoNotStrip private final HybridData mHybridData;
@DoNotStrip
private native HybridData initHybrid(ComponentFactory componentFactory);
@DoNotStrip
private MainComponentsRegistry(ComponentFactory componentFactory) {
mHybridData = initHybrid(componentFactory);
}
@DoNotStrip
public static MainComponentsRegistry register(ComponentFactory componentFactory) {
return new MainComponentsRegistry(componentFactory);
}
}

View File

@ -0,0 +1,48 @@
package chat.rocket.reactnative.newarchitecture.modules;
import com.facebook.jni.HybridData;
import com.facebook.react.ReactPackage;
import com.facebook.react.ReactPackageTurboModuleManagerDelegate;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.soloader.SoLoader;
import java.util.List;
/**
* Class responsible to load the TurboModules. This class has native methods and needs a
* corresponding C++ implementation/header file to work correctly (already placed inside the jni/
* folder for you).
*
* <p>Please note that this class is used ONLY if you opt-in for the New Architecture (see the
* `newArchEnabled` property). Is ignored otherwise.
*/
public class MainApplicationTurboModuleManagerDelegate
extends ReactPackageTurboModuleManagerDelegate {
private static volatile boolean sIsSoLibraryLoaded;
protected MainApplicationTurboModuleManagerDelegate(
ReactApplicationContext reactApplicationContext, List<ReactPackage> packages) {
super(reactApplicationContext, packages);
}
protected native HybridData initHybrid();
native boolean canCreateTurboModule(String moduleName);
public static class Builder extends ReactPackageTurboModuleManagerDelegate.Builder {
protected MainApplicationTurboModuleManagerDelegate build(
ReactApplicationContext context, List<ReactPackage> packages) {
return new MainApplicationTurboModuleManagerDelegate(context, packages);
}
}
@Override
protected synchronized void maybeLoadOtherSoLibraries() {
if (!sIsSoLibraryLoaded) {
// If you change the name of your application .so file in the Android.mk file,
// make sure you update the name here as well.
SoLoader.loadLibrary("rocketchat_appmodules");
sIsSoLibraryLoaded = true;
}
}
}

View File

@ -0,0 +1,49 @@
THIS_DIR := $(call my-dir)
include $(REACT_ANDROID_DIR)/Android-prebuilt.mk
# If you wish to add a custom TurboModule or Fabric component in your app you
# will have to include the following autogenerated makefile.
# include $(GENERATED_SRC_DIR)/codegen/jni/Android.mk
include $(CLEAR_VARS)
LOCAL_PATH := $(THIS_DIR)
# You can customize the name of your application .so file here.
LOCAL_MODULE := rocketchat_appmodules
LOCAL_C_INCLUDES := $(LOCAL_PATH)
LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp)
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
# If you wish to add a custom TurboModule or Fabric component in your app you
# will have to uncomment those lines to include the generated source
# files from the codegen (placed in $(GENERATED_SRC_DIR)/codegen/jni)
#
# LOCAL_C_INCLUDES += $(GENERATED_SRC_DIR)/codegen/jni
# LOCAL_SRC_FILES += $(wildcard $(GENERATED_SRC_DIR)/codegen/jni/*.cpp)
# LOCAL_EXPORT_C_INCLUDES += $(GENERATED_SRC_DIR)/codegen/jni
# Here you should add any native library you wish to depend on.
LOCAL_SHARED_LIBRARIES := \
libfabricjni \
libfbjni \
libfolly_futures \
libfolly_json \
libglog \
libjsi \
libreact_codegen_rncore \
libreact_debug \
libreact_nativemodule_core \
libreact_render_componentregistry \
libreact_render_core \
libreact_render_debug \
libreact_render_graphics \
librrc_view \
libruntimeexecutor \
libturbomodulejsijni \
libyoga
LOCAL_CFLAGS := -DLOG_TAG=\"ReactNative\" -fexceptions -frtti -std=c++17 -Wall
include $(BUILD_SHARED_LIBRARY)

View File

@ -0,0 +1,24 @@
#include "MainApplicationModuleProvider.h"
#include <rncore.h>
namespace facebook {
namespace react {
std::shared_ptr<TurboModule> MainApplicationModuleProvider(
const std::string moduleName,
const JavaTurboModule::InitParams &params) {
// Here you can provide your own module provider for TurboModules coming from
// either your application or from external libraries. The approach to follow
// is similar to the following (for a library called `samplelibrary`:
//
// auto module = samplelibrary_ModuleProvider(moduleName, params);
// if (module != nullptr) {
// return module;
// }
// return rncore_ModuleProvider(moduleName, params);
return rncore_ModuleProvider(moduleName, params);
}
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,16 @@
#pragma once
#include <memory>
#include <string>
#include <ReactCommon/JavaTurboModule.h>
namespace facebook {
namespace react {
std::shared_ptr<TurboModule> MainApplicationModuleProvider(
const std::string moduleName,
const JavaTurboModule::InitParams &params);
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,45 @@
#include "MainApplicationTurboModuleManagerDelegate.h"
#include "MainApplicationModuleProvider.h"
namespace facebook {
namespace react {
jni::local_ref<MainApplicationTurboModuleManagerDelegate::jhybriddata>
MainApplicationTurboModuleManagerDelegate::initHybrid(
jni::alias_ref<jhybridobject>) {
return makeCxxInstance();
}
void MainApplicationTurboModuleManagerDelegate::registerNatives() {
registerHybrid({
makeNativeMethod(
"initHybrid", MainApplicationTurboModuleManagerDelegate::initHybrid),
makeNativeMethod(
"canCreateTurboModule",
MainApplicationTurboModuleManagerDelegate::canCreateTurboModule),
});
}
std::shared_ptr<TurboModule>
MainApplicationTurboModuleManagerDelegate::getTurboModule(
const std::string name,
const std::shared_ptr<CallInvoker> jsInvoker) {
// Not implemented yet: provide pure-C++ NativeModules here.
return nullptr;
}
std::shared_ptr<TurboModule>
MainApplicationTurboModuleManagerDelegate::getTurboModule(
const std::string name,
const JavaTurboModule::InitParams &params) {
return MainApplicationModuleProvider(name, params);
}
bool MainApplicationTurboModuleManagerDelegate::canCreateTurboModule(
std::string name) {
return getTurboModule(name, nullptr) != nullptr ||
getTurboModule(name, {.moduleName = name}) != nullptr;
}
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,38 @@
#include <memory>
#include <string>
#include <ReactCommon/TurboModuleManagerDelegate.h>
#include <fbjni/fbjni.h>
namespace facebook {
namespace react {
class MainApplicationTurboModuleManagerDelegate
: public jni::HybridClass<
MainApplicationTurboModuleManagerDelegate,
TurboModuleManagerDelegate> {
public:
// Adapt it to the package you used for your Java class.
static constexpr auto kJavaDescriptor =
"Lchat/rocket/reactnative/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate;";
static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jhybridobject>);
static void registerNatives();
std::shared_ptr<TurboModule> getTurboModule(
const std::string name,
const std::shared_ptr<CallInvoker> jsInvoker) override;
std::shared_ptr<TurboModule> getTurboModule(
const std::string name,
const JavaTurboModule::InitParams &params) override;
/**
* Test-only method. Allows user to verify whether a TurboModule can be
* created by instances of this class.
*/
bool canCreateTurboModule(std::string name);
};
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,61 @@
#include "MainComponentsRegistry.h"
#include <CoreComponentsRegistry.h>
#include <fbjni/fbjni.h>
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
#include <react/renderer/components/rncore/ComponentDescriptors.h>
namespace facebook {
namespace react {
MainComponentsRegistry::MainComponentsRegistry(ComponentFactory *delegate) {}
std::shared_ptr<ComponentDescriptorProviderRegistry const>
MainComponentsRegistry::sharedProviderRegistry() {
auto providerRegistry = CoreComponentsRegistry::sharedProviderRegistry();
// Custom Fabric Components go here. You can register custom
// components coming from your App or from 3rd party libraries here.
//
// providerRegistry->add(concreteComponentDescriptorProvider<
// AocViewerComponentDescriptor>());
return providerRegistry;
}
jni::local_ref<MainComponentsRegistry::jhybriddata>
MainComponentsRegistry::initHybrid(
jni::alias_ref<jclass>,
ComponentFactory *delegate) {
auto instance = makeCxxInstance(delegate);
auto buildRegistryFunction =
[](EventDispatcher::Weak const &eventDispatcher,
ContextContainer::Shared const &contextContainer)
-> ComponentDescriptorRegistry::Shared {
auto registry = MainComponentsRegistry::sharedProviderRegistry()
->createComponentDescriptorRegistry(
{eventDispatcher, contextContainer});
auto mutableRegistry =
std::const_pointer_cast<ComponentDescriptorRegistry>(registry);
mutableRegistry->setFallbackComponentDescriptor(
std::make_shared<UnimplementedNativeViewComponentDescriptor>(
ComponentDescriptorParameters{
eventDispatcher, contextContainer, nullptr}));
return registry;
};
delegate->buildRegistryFunction = buildRegistryFunction;
return instance;
}
void MainComponentsRegistry::registerNatives() {
registerHybrid({
makeNativeMethod("initHybrid", MainComponentsRegistry::initHybrid),
});
}
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,32 @@
#pragma once
#include <ComponentFactory.h>
#include <fbjni/fbjni.h>
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
#include <react/renderer/componentregistry/ComponentDescriptorRegistry.h>
namespace facebook {
namespace react {
class MainComponentsRegistry
: public facebook::jni::HybridClass<MainComponentsRegistry> {
public:
// Adapt it to the package you used for your Java class.
constexpr static auto kJavaDescriptor =
"Lchat/rocket/reactnative/newarchitecture/components/MainComponentsRegistry;";
static void registerNatives();
MainComponentsRegistry(ComponentFactory *delegate);
private:
static std::shared_ptr<ComponentDescriptorProviderRegistry const>
sharedProviderRegistry();
static jni::local_ref<jhybriddata> initHybrid(
jni::alias_ref<jclass>,
ComponentFactory *delegate);
};
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,11 @@
#include <fbjni/fbjni.h>
#include "MainApplicationTurboModuleManagerDelegate.h"
#include "MainComponentsRegistry.h"
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {
return facebook::jni::initialize(vm, [] {
facebook::react::MainApplicationTurboModuleManagerDelegate::
registerNatives();
facebook::react::MainComponentsRegistry::registerNatives();
});
}

View File

@ -0,0 +1,24 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="731.4286"
android:viewportHeight="731.4286">
<group android:translateX="109.71429"
android:translateY="109.71429">
<group>
<clip-path android:pathData="M0,0h512v512h-512z M 0,0"/>
<path
android:pathData="M404.999,208.068C396.342,194.624 384.207,182.722 368.953,172.683C339.479,153.318 300.753,142.65 259.908,142.65C246.261,142.65 232.816,143.837 219.765,146.187C211.667,138.391 202.2,131.378 192.173,125.836C154.971,107.29 122.187,114.196 105.623,120.152C100.181,122.11 98.502,128.993 102.527,133.146C114.209,145.202 133.536,169.029 128.785,190.696C110.315,209.551 100.3,232.287 100.3,255.959C100.3,280.083 110.315,302.818 128.785,321.674C133.536,343.341 114.209,367.18 102.527,379.236C98.514,383.377 100.181,390.259 105.623,392.217C122.187,398.174 154.971,405.092 192.185,386.545C202.212,381.004 211.679,373.991 219.777,366.195C232.828,368.544 246.273,369.731 259.92,369.731C300.777,369.731 339.503,359.075 368.965,339.71C384.219,329.671 396.354,317.782 405.011,304.325C414.657,289.35 419.539,273.225 419.539,256.422C419.527,239.169 414.645,223.055 404.999,208.068ZM258.241,341.787C240.58,341.787 223.742,339.508 208.392,335.391L197.174,346.177C191.077,352.039 183.932,357.343 176.478,361.52C166.606,366.349 156.853,368.995 147.207,369.79C147.755,368.806 148.255,367.809 148.791,366.812C160.032,346.165 163.069,327.607 157.889,311.148C139.502,296.707 128.475,278.22 128.475,258.083C128.475,211.865 186.576,174.392 258.241,174.392C329.905,174.392 388.018,211.865 388.018,258.083C388.018,304.314 329.917,341.787 258.241,341.787Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M196.162,238.837C185.6,238.837 177.038,247.333 177.038,257.811C177.038,268.288 185.6,276.784 196.162,276.784C206.725,276.784 215.287,268.288 215.287,257.811C215.287,247.333 206.725,238.837 196.162,238.837Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M257.717,238.837C247.154,238.837 238.592,247.333 238.592,257.811C238.592,268.288 247.154,276.784 257.717,276.784C268.279,276.784 276.842,268.288 276.842,257.811C276.842,247.333 268.279,238.837 257.717,238.837Z"
android:fillColor="#ffffff"/>
<path
android:pathData="M319.282,238.837C308.72,238.837 300.158,247.333 300.158,257.811C300.158,268.288 308.72,276.784 319.282,276.784C329.845,276.784 338.407,268.288 338.407,257.811C338.407,247.333 329.845,238.837 319.282,238.837Z"
android:fillColor="#ffffff"/>
</group>
</group>
</vector>

View File

@ -2,4 +2,5 @@
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/> <background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/> <foreground android:drawable="@drawable/ic_launcher_foreground"/>
<monochrome android:drawable="@drawable/ic_launcher_monochrome"/>
</adaptive-icon> </adaptive-icon>

View File

@ -2,4 +2,5 @@
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/> <background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/> <foreground android:drawable="@drawable/ic_launcher_foreground"/>
<monochrome android:drawable="@drawable/ic_launcher_monochrome"/>
</adaptive-icon> </adaptive-icon>

View File

@ -34,6 +34,8 @@ public class Ejson {
String senderName; String senderName;
String msg; String msg;
String tmid;
private MMKV mmkv; private MMKV mmkv;
private String TOKEN_KEY = "reactnativemeteor_usertoken-"; private String TOKEN_KEY = "reactnativemeteor_usertoken-";

View File

@ -1,7 +1,6 @@
package chat.rocket.reactnative; package chat.rocket.reactnative;
import android.database.Cursor; import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.util.Base64; import android.util.Base64;
import android.util.Log; import android.util.Log;
@ -81,7 +80,7 @@ class Encryption {
dbName += "-experimental"; dbName += "-experimental";
} }
dbName += ".db"; dbName += ".db";
Database database = new Database(dbName, reactContext, SQLiteDatabase.CREATE_IF_NECESSARY); Database database = new Database(dbName, reactContext);
String[] query = {ejson.rid}; String[] query = {ejson.rid};
Cursor cursor = database.rawQuery("select * from subscriptions where id == ? limit 1", query); Cursor cursor = database.rawQuery("select * from subscriptions where id == ? limit 1", query);

View File

@ -123,7 +123,9 @@ public class ReplyBroadcast extends BroadcastReceiver {
if (msg != message) { if (msg != message) {
msgMap.put("t", "e2e"); msgMap.put("t", "e2e");
} }
msgMap.put("tmid", null); if(ejson.tmid != null) {
msgMap.put("tmid", ejson.tmid);
}
Map m = new HashMap(); Map m = new HashMap();
m.put("message", msgMap); m.put("message", msgMap);

View File

@ -1,12 +0,0 @@
package chat.rocket.reactnative;
import android.content.Context;
import com.facebook.react.ReactInstanceManager;
/**
* Class responsible of loading Flipper inside your React Native application. This is the release
* flavor of it so it's empty as we don't want to load Flipper.
*/
public class ReactNativeFlipper {
public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
// Do nothing as we don't want to initialize Flipper on Release.
}
}

View File

@ -1,10 +1,11 @@
import org.apache.tools.ant.taskdefs.condition.Os
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript { buildscript {
def taskRequests = getGradle().getStartParameter().getTaskRequests().toString().toLowerCase() def taskRequests = getGradle().getStartParameter().getTaskRequests().toString().toLowerCase()
def isPlay = !taskRequests.contains("foss") def isPlay = !taskRequests.contains("foss")
ext { ext {
// TODO: target 33
buildToolsVersion = "33.0.0" buildToolsVersion = "33.0.0"
minSdkVersion = 23 minSdkVersion = 23
compileSdkVersion = 33 compileSdkVersion = 33
@ -38,20 +39,75 @@ buildscript {
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.0' classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.0'
classpath 'com.bugsnag:bugsnag-android-gradle-plugin:7.+' classpath 'com.bugsnag:bugsnag-android-gradle-plugin:7.+'
} }
classpath("com.android.tools.build:gradle:7.3.1") classpath("com.android.tools.build:gradle:7.0.4")
classpath("com.facebook.react:react-native-gradle-plugin") classpath("com.facebook.react:react-native-gradle-plugin")
classpath("de.undercouch:gradle-download-task:4.1.2")
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
} }
} }
allprojects { allprojects {
repositories { repositories {
mavenLocal()
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url("$rootDir/../node_modules/react-native/android")
}
maven {
// Android JSC is installed from npm
url("$rootDir/../node_modules/jsc-android/dist")
}
maven { maven {
url "$rootDir/../node_modules/detox/Detox-android" url "$rootDir/../node_modules/detox/Detox-android"
} }
maven { maven {
// expo-camera bundles a custom com.google.android:cameraview // expo-camera bundles a custom com.google.android:cameraview
url "$rootDir/../node_modules/expo-camera/android/maven" url "$rootDir/../node_modules/expo-camera/android/maven"
} }
mavenCentral {
content {
excludeGroup "com.facebook.react"
}
}
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

@ -37,10 +37,6 @@ reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
# are providing them. # are providing them.
newArchEnabled=false newArchEnabled=false
# Use this property to enable or disable the Hermes JS engine.
# If set to false, you will be using JSC instead.
hermesEnabled=true
# Application ID # Application ID
APPLICATION_ID=chat.rocket.reactnative APPLICATION_ID=chat.rocket.reactnative

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View File

@ -11,13 +11,9 @@ apply from: file("../node_modules/@react-native-community/cli-platform-android/n
include ':app' include ':app'
includeBuild('../node_modules/react-native-gradle-plugin') includeBuild('../node_modules/react-native-gradle-plugin')
includeBuild('../node_modules/react-native') { if (settings.hasProperty("newArchEnabled") && settings.newArchEnabled == "true") {
dependencySubstitution { include(":ReactAndroid")
substitute(module("com.facebook.react:react-android")).using(project(":ReactAndroid")) project(":ReactAndroid").projectDir = file('../node_modules/react-native/ReactAndroid')
substitute(module("com.facebook.react:react-native")).using(project(":ReactAndroid"))
substitute(module("com.facebook.react:hermes-android")).using(project(":ReactAndroid:hermes-engine"))
substitute(module("com.facebook.react:hermes-engine")).using(project(":ReactAndroid:hermes-engine"))
}
} }
apply from: new File(["node", "--print", "require.resolve('expo/package.json')"].execute(null, rootDir).text.trim(), "../scripts/autolinking.gradle") apply from: new File(["node", "--print", "require.resolve('expo/package.json')"].execute(null, rootDir).text.trim(), "../scripts/autolinking.gradle")

View File

@ -3,15 +3,17 @@ import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack'; import { createStackNavigator } from '@react-navigation/stack';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { SetUsernameStackParamList, StackParamList } from './definitions/navigationTypes';
import Navigation from './lib/navigation/appNavigation'; import Navigation from './lib/navigation/appNavigation';
import { defaultHeader, getActiveRouteName, navigationTheme } from './lib/methods/helpers/navigation'; import { defaultHeader, getActiveRouteName, navigationTheme } from './lib/methods/helpers/navigation';
import { RootEnum } from './definitions'; import { RootEnum } from './definitions';
// Stacks
import AuthLoadingView from './views/AuthLoadingView'; import AuthLoadingView from './views/AuthLoadingView';
// SetUsername Stack
import SetUsernameView from './views/SetUsernameView'; import SetUsernameView from './views/SetUsernameView';
import OutsideStack from './stacks/OutsideStack'; import OutsideStack from './stacks/OutsideStack';
import InsideStack from './stacks/InsideStack'; import InsideStack from './stacks/InsideStack';
import MasterDetailStack from './stacks/MasterDetailStack'; import MasterDetailStack from './stacks/MasterDetailStack';
import { SetUsernameStackParamList, StackParamList } from './stacks/types';
import { ThemeContext } from './theme'; import { ThemeContext } from './theme';
import { setCurrentScreen } from './lib/methods/helpers/log'; import { setCurrentScreen } from './lib/methods/helpers/log';

View File

@ -85,6 +85,7 @@ export const ENCRYPTION = createRequestTypes('ENCRYPTION', ['INIT', 'STOP', 'DEC
export const PERMISSIONS = createRequestTypes('PERMISSIONS', ['SET', 'UPDATE']); export const PERMISSIONS = createRequestTypes('PERMISSIONS', ['SET', 'UPDATE']);
export const ROLES = createRequestTypes('ROLES', ['SET', 'UPDATE', 'REMOVE']); export const ROLES = createRequestTypes('ROLES', ['SET', 'UPDATE', 'REMOVE']);
export const USERS_ROLES = createRequestTypes('USERS_ROLES', ['SET']);
export const VIDEO_CONF = createRequestTypes('VIDEO_CONF', [ export const VIDEO_CONF = createRequestTypes('VIDEO_CONF', [
'HANDLE_INCOMING_WEBSOCKET_MESSAGES', 'HANDLE_INCOMING_WEBSOCKET_MESSAGES',
'SET', 'SET',

13
app/actions/usersRoles.ts Normal file
View File

@ -0,0 +1,13 @@
import { Action } from 'redux';
import { TUsersRoles } from '../reducers/usersRoles';
import { USERS_ROLES } from './actionsTypes';
export type TActionUsersRoles = Action & { usersRoles: TUsersRoles };
export function setUsersRoles(usersRoles: TUsersRoles): Action & { usersRoles: TUsersRoles } {
return {
type: USERS_ROLES.SET,
usersRoles
};
}

201
app/commands.ts Normal file
View File

@ -0,0 +1,201 @@
/* eslint-disable no-bitwise */
import { NativeSyntheticEvent } from 'react-native';
import KeyCommands, { constants, KeyCommand } from 'react-native-keycommands';
import I18n from './i18n';
const KEY_TYPING = '\t';
const KEY_PREFERENCES = 'p';
const KEY_SEARCH = 'f';
const KEY_PREVIOUS_ROOM = '[';
const KEY_NEXT_ROOM = ']';
const KEY_NEW_ROOM = __DEV__ ? 'e' : 'n';
const KEY_ROOM_ACTIONS = __DEV__ ? 'b' : 'i';
const KEY_UPLOAD = 'u';
const KEY_REPLY = ';';
const KEY_SERVER_SELECTION = __DEV__ ? 'o' : '`';
const KEY_ADD_SERVER = __DEV__ ? 'l' : 'n';
const KEY_SEND_MESSAGE = '\r';
const KEY_SELECT = '123456789';
const keyCommands = [
{
// Focus messageBox
input: KEY_TYPING,
modifierFlags: 0,
discoverabilityTitle: I18n.t('Type_message')
},
{
// Send message on textInput to current room
input: KEY_SEND_MESSAGE,
modifierFlags: 0,
discoverabilityTitle: I18n.t('Send')
},
{
// Open Preferences Modal
input: KEY_PREFERENCES,
modifierFlags: constants.keyModifierCommand,
discoverabilityTitle: I18n.t('Preferences')
},
{
// Focus Room Search
input: KEY_SEARCH,
modifierFlags: constants.keyModifierCommand | constants.keyModifierAlternate,
discoverabilityTitle: I18n.t('Room_search')
},
{
// Select a room by order using 1-9
input: '1...9',
modifierFlags: constants.keyModifierCommand,
discoverabilityTitle: I18n.t('Room_selection')
},
{
// Change room to next on Rooms List
input: KEY_NEXT_ROOM,
modifierFlags: constants.keyModifierCommand,
discoverabilityTitle: I18n.t('Next_room')
},
{
// Change room to previous on Rooms List
input: KEY_PREVIOUS_ROOM,
modifierFlags: constants.keyModifierCommand,
discoverabilityTitle: I18n.t('Previous_room')
},
{
// Open New Room Modal
input: KEY_NEW_ROOM,
modifierFlags: constants.keyModifierCommand,
discoverabilityTitle: I18n.t('New_room')
},
{
// Open Room Actions
input: KEY_ROOM_ACTIONS,
modifierFlags: constants.keyModifierCommand,
discoverabilityTitle: I18n.t('Room_actions')
},
{
// Upload a file to room
input: KEY_UPLOAD,
modifierFlags: constants.keyModifierCommand,
discoverabilityTitle: I18n.t('Upload_room')
},
{
// Search Messages on current room
input: KEY_SEARCH,
modifierFlags: constants.keyModifierCommand,
discoverabilityTitle: I18n.t('Search_messages')
},
{
// Scroll messages on current room
input: '↑ ↓',
modifierFlags: constants.keyModifierAlternate,
discoverabilityTitle: I18n.t('Scroll_messages')
},
{
// Scroll up messages on current room
input: constants.keyInputUpArrow,
modifierFlags: constants.keyModifierAlternate
},
{
// Scroll down messages on current room
input: constants.keyInputDownArrow,
modifierFlags: constants.keyModifierAlternate
},
{
// Reply latest message with Quote
input: KEY_REPLY,
modifierFlags: constants.keyModifierCommand,
discoverabilityTitle: I18n.t('Reply_latest')
},
{
// Open server dropdown
input: KEY_SERVER_SELECTION,
modifierFlags: constants.keyModifierCommand | constants.keyModifierAlternate,
discoverabilityTitle: I18n.t('Server_selection')
},
{
// Select a server by order using 1-9
input: '1...9',
modifierFlags: constants.keyModifierCommand | constants.keyModifierAlternate,
discoverabilityTitle: I18n.t('Server_selection_numbers')
},
{
// Navigate to add new server
input: KEY_ADD_SERVER,
modifierFlags: constants.keyModifierCommand | constants.keyModifierAlternate,
discoverabilityTitle: I18n.t('Add_server')
},
// Refers to select rooms on list
...[1, 2, 3, 4, 5, 6, 7, 8, 9].map(value => ({
input: `${value}`,
modifierFlags: constants.keyModifierCommand
})),
// Refers to select servers on list
...[1, 2, 3, 4, 5, 6, 7, 8, 9].map(value => ({
input: `${value}`,
modifierFlags: constants.keyModifierCommand | constants.keyModifierAlternate
}))
];
export const setKeyCommands = (): void => KeyCommands.setKeyCommands(keyCommands);
export const deleteKeyCommands = (): void => KeyCommands.deleteKeyCommands(keyCommands);
export const KEY_COMMAND = 'KEY_COMMAND';
export interface IKeyCommandEvent extends NativeSyntheticEvent<typeof KeyCommand> {
input: number & string;
modifierFlags: string | number;
}
export const commandHandle = (event: IKeyCommandEvent, key: string | string[], flags: string[] = []): boolean => {
const { input, modifierFlags } = event;
let _flags = 0;
if (flags.includes('command') && flags.includes('alternate')) {
_flags = constants.keyModifierCommand | constants.keyModifierAlternate;
} else if (flags.includes('command')) {
_flags = constants.keyModifierCommand;
} else if (flags.includes('alternate')) {
_flags = constants.keyModifierAlternate;
}
return key.includes(input) && modifierFlags === _flags;
};
export const handleCommandTyping = (event: IKeyCommandEvent): boolean => commandHandle(event, KEY_TYPING);
export const handleCommandSubmit = (event: IKeyCommandEvent): boolean => commandHandle(event, KEY_SEND_MESSAGE);
export const handleCommandShowUpload = (event: IKeyCommandEvent): boolean => commandHandle(event, KEY_UPLOAD, ['command']);
export const handleCommandScroll = (event: IKeyCommandEvent): boolean =>
commandHandle(event, [constants.keyInputUpArrow, constants.keyInputDownArrow], ['alternate']);
export const handleCommandRoomActions = (event: IKeyCommandEvent): boolean => commandHandle(event, KEY_ROOM_ACTIONS, ['command']);
export const handleCommandSearchMessages = (event: IKeyCommandEvent): boolean => commandHandle(event, KEY_SEARCH, ['command']);
export const handleCommandReplyLatest = (event: IKeyCommandEvent): boolean => commandHandle(event, KEY_REPLY, ['command']);
export const handleCommandSelectServer = (event: IKeyCommandEvent): boolean =>
commandHandle(event, KEY_SELECT, ['command', 'alternate']);
export const handleCommandShowPreferences = (event: IKeyCommandEvent): boolean =>
commandHandle(event, KEY_PREFERENCES, ['command']);
export const handleCommandSearching = (event: IKeyCommandEvent): boolean =>
commandHandle(event, KEY_SEARCH, ['command', 'alternate']);
export const handleCommandSelectRoom = (event: IKeyCommandEvent): boolean => commandHandle(event, KEY_SELECT, ['command']);
export const handleCommandPreviousRoom = (event: IKeyCommandEvent): boolean =>
commandHandle(event, KEY_PREVIOUS_ROOM, ['command']);
export const handleCommandNextRoom = (event: IKeyCommandEvent): boolean => commandHandle(event, KEY_NEXT_ROOM, ['command']);
export const handleCommandShowNewMessage = (event: IKeyCommandEvent): boolean => commandHandle(event, KEY_NEW_ROOM, ['command']);
export const handleCommandAddNewServer = (event: IKeyCommandEvent): boolean =>
commandHandle(event, KEY_ADD_SERVER, ['command', 'alternate']);
export const handleCommandOpenServerDropdown = (event: IKeyCommandEvent): boolean =>
commandHandle(event, KEY_SERVER_SELECTION, ['command', 'alternate']);

View File

@ -4,7 +4,7 @@ import React, { forwardRef, isValidElement, useEffect, useImperativeHandle, useR
import { Keyboard } from 'react-native'; import { Keyboard } from 'react-native';
import { Easing } from 'react-native-reanimated'; import { Easing } from 'react-native-reanimated';
import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { useSafeAreaInsets } from 'react-native-safe-area-context';
import BottomSheet, { BottomSheetBackdrop, BottomSheetBackdropProps } from '@gorhom/bottom-sheet'; import BottomSheet, { BottomSheetBackdrop } from '@gorhom/bottom-sheet';
import { useDimensions, useOrientation } from '../../dimensions'; import { useDimensions, useOrientation } from '../../dimensions';
import { useTheme } from '../../theme'; import { useTheme } from '../../theme';
@ -107,7 +107,7 @@ const ActionSheet = React.memo(
}; };
const renderBackdrop = useCallback( const renderBackdrop = useCallback(
(props: BottomSheetBackdropProps) => ( props => (
<BottomSheetBackdrop <BottomSheetBackdrop
{...props} {...props}
appearsOnIndex={0} appearsOnIndex={0}

View File

@ -75,7 +75,6 @@ const EmojiPicker = ({
parentWidth={parentWidth} parentWidth={parentWidth}
/> />
) : ( ) : (
// @ts-ignore
<ScrollableTabView <ScrollableTabView
renderTabBar={() => <TabBar />} renderTabBar={() => <TabBar />}
contentProps={{ contentProps={{

View File

@ -13,6 +13,7 @@ export interface IHeaderButtonItem extends Omit<ICustomIcon, 'name' | 'size' | '
testID?: string; testID?: string;
badge?(): void; badge?(): void;
color?: string; color?: string;
disabled?: boolean;
} }
export const BUTTON_HIT_SLOP = { export const BUTTON_HIT_SLOP = {

View File

@ -21,4 +21,4 @@ export function ImageComponent({
Component = FastImage; Component = FastImage;
} }
return Component; return Component;
}; }

View File

@ -322,7 +322,7 @@ const MessageActions = React.memo(
const db = database.active; const db = database.active;
await db.write(async () => { await db.write(async () => {
await message.update(m => { await message.update(m => {
m.autoTranslate = !m.autoTranslate; m.autoTranslate = m.autoTranslate !== null ? !m.autoTranslate : false;
m._updatedAt = new Date(); m._updatedAt = new Date();
}); });
}); });
@ -479,7 +479,7 @@ const MessageActions = React.memo(
// Toggle Auto-translate // Toggle Auto-translate
if (room.autoTranslate && message.u && message.u._id !== user.id) { if (room.autoTranslate && message.u && message.u._id !== user.id) {
options.push({ options.push({
title: I18n.t(message.autoTranslate ? 'View_Original' : 'Translate'), title: I18n.t(message.autoTranslate !== false ? 'View_Original' : 'Translate'),
icon: 'language', icon: 'language',
onPress: () => handleToggleTranslation(message) onPress: () => handleToggleTranslation(message)
}); });

View File

@ -31,7 +31,7 @@ const MentionItemContent = React.memo(({ trackingType, item }: IMessageBoxMentio
return ( return (
<> <>
<MentionEmoji item={item} /> <MentionEmoji item={item} />
<Text style={[styles.mentionText, { color: themes[theme].titleText }]}>:{item.name ?? item}:</Text> <Text style={[styles.mentionText, { color: themes[theme].titleText }]}>:{item.name || item}:</Text>
</> </>
); );
case MENTIONS_TRACKING_TYPE_COMMANDS: case MENTIONS_TRACKING_TYPE_COMMANDS:
@ -57,7 +57,7 @@ const MentionItemContent = React.memo(({ trackingType, item }: IMessageBoxMentio
return ( return (
<> <>
<Avatar style={styles.avatar} text={item.username || item.name} size={30} type={item.t} /> <Avatar style={styles.avatar} text={item.username || item.name} size={30} type={item.t} />
<Text style={[styles.mentionText, { color: themes[theme].titleText }]}>{item.username ?? item.name ?? item}</Text> <Text style={[styles.mentionText, { color: themes[theme].titleText }]}>{item.username || item.name || item}</Text>
</> </>
); );
} }

View File

@ -24,19 +24,19 @@ const RECORDING_EXTENSION = '.m4a';
const RECORDING_SETTINGS = { const RECORDING_SETTINGS = {
android: { android: {
extension: RECORDING_EXTENSION, extension: RECORDING_EXTENSION,
outputFormat: Audio.AndroidOutputFormat.MPEG_4, outputFormat: Audio.RECORDING_OPTION_ANDROID_OUTPUT_FORMAT_MPEG_4,
audioEncoder: Audio.AndroidAudioEncoder.AAC, audioEncoder: Audio.RECORDING_OPTION_ANDROID_AUDIO_ENCODER_AAC,
sampleRate: Audio.RecordingOptionsPresets.LOW_QUALITY.android.sampleRate, sampleRate: Audio.RECORDING_OPTIONS_PRESET_LOW_QUALITY.android.sampleRate,
numberOfChannels: Audio.RecordingOptionsPresets.LOW_QUALITY.android.numberOfChannels, numberOfChannels: Audio.RECORDING_OPTIONS_PRESET_LOW_QUALITY.android.numberOfChannels,
bitRate: Audio.RecordingOptionsPresets.LOW_QUALITY.android.bitRate bitRate: Audio.RECORDING_OPTIONS_PRESET_LOW_QUALITY.android.bitRate
}, },
ios: { ios: {
extension: RECORDING_EXTENSION, extension: RECORDING_EXTENSION,
audioQuality: Audio.IOSAudioQuality.MIN, audioQuality: Audio.RECORDING_OPTION_IOS_AUDIO_QUALITY_MIN,
sampleRate: Audio.RecordingOptionsPresets.LOW_QUALITY.ios.sampleRate, sampleRate: Audio.RECORDING_OPTIONS_PRESET_LOW_QUALITY.ios.sampleRate,
numberOfChannels: Audio.RecordingOptionsPresets.LOW_QUALITY.ios.numberOfChannels, numberOfChannels: Audio.RECORDING_OPTIONS_PRESET_LOW_QUALITY.ios.numberOfChannels,
bitRate: Audio.RecordingOptionsPresets.LOW_QUALITY.ios.bitRate, bitRate: Audio.RECORDING_OPTIONS_PRESET_LOW_QUALITY.ios.bitRate,
outputFormat: Audio.IOSOutputFormat.MPEG4AAC outputFormat: Audio.RECORDING_OPTION_IOS_OUTPUT_FORMAT_MPEG4AAC
}, },
web: {} web: {}
}; };

View File

@ -1,5 +1,5 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { Alert, NativeModules, Text, View, BackHandler } from 'react-native'; import { Alert, Keyboard, NativeModules, Text, View, BackHandler } from 'react-native';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { KeyboardAccessoryView } from 'react-native-ui-lib/keyboard'; import { KeyboardAccessoryView } from 'react-native-ui-lib/keyboard';
import ImagePicker, { Image, ImageOrVideo, Options } from 'react-native-image-crop-picker'; import ImagePicker, { Image, ImageOrVideo, Options } from 'react-native-image-crop-picker';
@ -21,6 +21,8 @@ import { themes, emojis } from '../../lib/constants';
import LeftButtons from './LeftButtons'; import LeftButtons from './LeftButtons';
import RightButtons from './RightButtons'; import RightButtons from './RightButtons';
import { canUploadFile } from '../../lib/methods/helpers/media'; import { canUploadFile } from '../../lib/methods/helpers/media';
import EventEmiter from '../../lib/methods/helpers/events';
import { KEY_COMMAND, handleCommandShowUpload, handleCommandSubmit, handleCommandTyping } from '../../commands';
import getMentionRegexp from './getMentionRegexp'; import getMentionRegexp from './getMentionRegexp';
import Mentions from './Mentions'; import Mentions from './Mentions';
import MessageboxContext from './Context'; import MessageboxContext from './Context';
@ -138,6 +140,8 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
private selection: { start: number; end: number }; private selection: { start: number; end: number };
private focused: boolean;
private imagePickerConfig: Options; private imagePickerConfig: Options;
private libraryPickerConfig: Options; private libraryPickerConfig: Options;
@ -188,6 +192,7 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
}; };
this.text = ''; this.text = '';
this.selection = { start: 0, end: 0 }; this.selection = { start: 0, end: 0 };
this.focused = false;
const libPickerLabels = { const libPickerLabels = {
cropperChooseText: I18n.t('Choose'), cropperChooseText: I18n.t('Choose'),
@ -263,6 +268,10 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
this.setShowSend(true); this.setShowSend(true);
} }
if (isTablet) {
EventEmiter.addEventListener(KEY_COMMAND, this.handleCommands);
}
if (usedCannedResponse) { if (usedCannedResponse) {
this.onChangeText(usedCannedResponse); this.onChangeText(usedCannedResponse);
} }
@ -437,6 +446,9 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
if (this.unsubscribeBlur) { if (this.unsubscribeBlur) {
this.unsubscribeBlur(); this.unsubscribeBlur();
} }
if (isTablet) {
EventEmiter.removeListener(KEY_COMMAND, this.handleCommands);
}
BackHandler.removeEventListener('hardwareBackPress', this.handleBackPress); BackHandler.removeEventListener('hardwareBackPress', this.handleBackPress);
} }
@ -966,7 +978,7 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
const { showEmojiKeyboard } = this.state; const { showEmojiKeyboard } = this.state;
this.closeEmoji(); this.closeEmoji();
setTimeout(() => action && action(params), showEmojiKeyboard && isIOS ? TIMEOUT_CLOSE_EMOJI : undefined); setTimeout(() => action && action(params), showEmojiKeyboard && isIOS ? TIMEOUT_CLOSE_EMOJI : null);
}; };
submit = async () => { submit = async () => {
@ -1101,6 +1113,21 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
}); });
}; };
handleCommands = ({ event }: { event: any }) => {
if (handleCommandTyping(event)) {
if (this.focused) {
Keyboard.dismiss();
} else {
this.component.focus();
}
this.focused = !this.focused;
} else if (handleCommandSubmit(event)) {
this.submit();
} else if (handleCommandShowUpload(event)) {
this.showMessageBoxActions();
}
};
onPressSendToChannel = () => this.setState(({ tshow }) => ({ tshow: !tshow })); onPressSendToChannel = () => this.setState(({ tshow }) => ({ tshow: !tshow }));
renderSendToChannel = () => { renderSendToChannel = () => {

View File

@ -21,7 +21,6 @@ const ReactionsList = ({ reactions, getCustomEmoji }: IReactionsListProps): Reac
const allTabLabel = { emoji: I18n.t('All'), usernames: [], names: [], _id: 'All' }; const allTabLabel = { emoji: I18n.t('All'), usernames: [], names: [], _id: 'All' };
return ( return (
<View style={styles.container} testID='reactionsList'> <View style={styles.container} testID='reactionsList'>
{/* @ts-ignore */}
<ScrollableTabView renderTabBar={() => <ReactionsTabBar getCustomEmoji={getCustomEmoji} />}> <ScrollableTabView renderTabBar={() => <ReactionsTabBar getCustomEmoji={getCustomEmoji} />}>
<AllTab tabLabel={allTabLabel} reactions={sortedReactions} getCustomEmoji={getCustomEmoji} /> <AllTab tabLabel={allTabLabel} reactions={sortedReactions} getCustomEmoji={getCustomEmoji} />
{sortedReactions?.map(reaction => ( {sortedReactions?.map(reaction => (

View File

@ -17,7 +17,7 @@ const SearchBox = ({ onChangeText, onSubmitEditing, testID }: TextInputProps): J
const { colors } = useTheme(); const { colors } = useTheme();
const internalOnChangeText = useCallback((value: string) => { const internalOnChangeText = useCallback(value => {
setText(value); setText(value);
onChangeText?.(value); onChangeText?.(value);
}, []); }, []);

View File

@ -1,8 +1,7 @@
import React, { useEffect } from 'react'; import React from 'react';
import { StatusBar as StatusBarRN } from 'react-native'; import { StatusBar as StatusBarRN } from 'react-native';
import { useTheme } from '../theme'; import { useTheme } from '../theme';
import { isAndroid } from '../lib/methods/helpers';
const supportedStyles = { const supportedStyles = {
'light-content': 'light-content', 'light-content': 'light-content',
@ -14,23 +13,15 @@ interface IStatusBar {
backgroundColor?: string; backgroundColor?: string;
} }
const StatusBar = React.memo(({ barStyle, backgroundColor }: IStatusBar) => { const StatusBar = ({ barStyle, backgroundColor }: IStatusBar) => {
const { theme, colors } = useTheme(); const { theme, colors } = useTheme();
if (!barStyle) {
useEffect(() => { barStyle = 'light-content';
if (!barStyle) { if (theme === 'light') {
barStyle = 'light-content'; barStyle = 'dark-content';
if (theme === 'light') {
barStyle = 'dark-content';
}
} }
if (isAndroid) { }
StatusBarRN.setBackgroundColor(backgroundColor ?? colors.headerBackground); return <StatusBarRN backgroundColor={backgroundColor ?? colors.headerBackground} barStyle={barStyle} animated />;
} };
StatusBarRN.setBarStyle(barStyle, true);
}, [theme, barStyle, backgroundColor]);
return <StatusBarRN />;
});
export default StatusBar; export default StatusBar;

View File

@ -46,7 +46,6 @@ const Toast = (): React.ReactElement => {
ref={getToastRef} ref={getToastRef}
// @ts-ignore // @ts-ignore
position='center' position='center'
// @ts-ignore
style={[styles.toast, { backgroundColor: colors.toastBackground }]} style={[styles.toast, { backgroundColor: colors.toastBackground }]}
textStyle={[styles.text, { color: colors.buttonText }]} textStyle={[styles.text, { color: colors.buttonText }]}
opacity={0.9} opacity={0.9}

View File

@ -93,7 +93,6 @@ export const DatePicker = ({ element, language, action, context, loading, value,
mode='date' mode='date'
display={isAndroid ? 'default' : 'inline'} display={isAndroid ? 'default' : 'inline'}
value={currentDate} value={currentDate}
// @ts-ignore
onChange={onChange} onChange={onChange}
textColor={themes[theme].titleText} textColor={themes[theme].titleText}
/> />

View File

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import { Text, View } from 'react-native'; import { Text, View } from 'react-native';
import Touchable, { PlatformTouchableProps } from 'react-native-platform-touchable'; import Touchable from 'react-native-platform-touchable';
import { CustomIcon } from '../../CustomIcon'; import { CustomIcon } from '../../CustomIcon';
import ActivityIndicator from '../../ActivityIndicator'; import ActivityIndicator from '../../ActivityIndicator';
@ -9,9 +9,9 @@ import { useTheme } from '../../../theme';
interface IInput { interface IInput {
children?: JSX.Element; children?: JSX.Element;
onPress: PlatformTouchableProps['onPress']; onPress: () => void;
inputStyle?: object; inputStyle?: object;
disabled?: PlatformTouchableProps['disabled']; disabled?: boolean | null;
placeholder?: string; placeholder?: string;
loading?: boolean; loading?: boolean;
innerInputStyle?: object; innerInputStyle?: object;

View File

@ -36,7 +36,7 @@ interface IMultiSelect {
onClose?: () => void; onClose?: () => void;
inputStyle?: TextStyle; inputStyle?: TextStyle;
value?: any[]; value?: any[];
disabled?: boolean; disabled?: boolean | null;
innerInputStyle?: object; innerInputStyle?: object;
} }

View File

@ -71,7 +71,6 @@ export const Select = ({ options = [], placeholder, onChange, loading, disabled,
); );
return ( return (
// @ts-ignore lib types issues. We need to fork it and maintain or find another lib
<RNPickerSelect <RNPickerSelect
items={items} items={items}
placeholder={placeholderObject} placeholder={placeholderObject}
@ -88,6 +87,8 @@ export const Select = ({ options = [], placeholder, onChange, loading, disabled,
}} }}
Icon={Icon} Icon={Icon}
textInputProps={{ textInputProps={{
// style property was Omitted in lib, but can be used normally
// @ts-ignore
style: { ...styles.pickerText, color: selected ? themes[theme].titleText : themes[theme].auxiliaryText } style: { ...styles.pickerText, color: selected ? themes[theme].titleText : themes[theme].auxiliaryText }
}} }}
/> />

View File

@ -7,7 +7,7 @@ import { CustomIcon, TIconsName } from '../../../CustomIcon';
import useStyle from './styles'; import useStyle from './styles';
type VideoConfMessageIconProps = { type VideoConfMessageIconProps = {
variant: 'ended' | 'incoming' | 'outgoing'; variant: 'ended' | 'incoming' | 'outgoing' | 'issue';
children: React.ReactElement | React.ReactElement[]; children: React.ReactElement | React.ReactElement[];
}; };
@ -33,6 +33,12 @@ export const VideoConferenceBaseContainer = ({ variant, children }: VideoConfMes
color: colors.conferenceCallOngoingPhoneIcon, color: colors.conferenceCallOngoingPhoneIcon,
backgroundColor: colors.conferenceCallOngoingPhoneBackground, backgroundColor: colors.conferenceCallOngoingPhoneBackground,
label: i18n.t('Call_ongoing') label: i18n.t('Call_ongoing')
},
issue: {
icon: 'phone-issue',
color: colors.statusFontOnWarning,
backgroundColor: colors.statusBackgroundWarning,
label: i18n.t('Call_issue')
} }
}; };
@ -45,7 +51,7 @@ export const VideoConferenceBaseContainer = ({ variant, children }: VideoConfMes
backgroundColor: iconStyle[variant].backgroundColor backgroundColor: iconStyle[variant].backgroundColor
}} }}
> >
<CustomIcon name={iconStyle[variant].icon} size={variant === 'incoming' ? 16 : 24} color={iconStyle[variant].color} /> <CustomIcon name={iconStyle[variant].icon} size={24} color={iconStyle[variant].color} />
</View> </View>
<Text style={style.infoContainerText}>{iconStyle[variant].label}</Text> <Text style={style.infoContainerText}>{iconStyle[variant].label}</Text>
</View> </View>

View File

@ -0,0 +1,18 @@
import React from 'react';
import { Text } from 'react-native';
import i18n from '../../../../i18n';
import useStyle from './styles';
import { VideoConferenceBaseContainer } from './VideoConferenceBaseContainer';
const VideoConferenceIssue = React.memo(() => {
const style = useStyle();
return (
<VideoConferenceBaseContainer variant='issue'>
<Text style={style.callBack}>{i18n.t('Waiting_for_server_connection')}</Text>
</VideoConferenceBaseContainer>
);
});
export default VideoConferenceIssue;

View File

@ -5,9 +5,10 @@ import VideoConferenceDirect from './components/VideoConferenceDirect';
import VideoConferenceEnded from './components/VideoConferenceEnded'; import VideoConferenceEnded from './components/VideoConferenceEnded';
import VideoConferenceOutgoing from './components/VideoConferenceOutgoing'; import VideoConferenceOutgoing from './components/VideoConferenceOutgoing';
import VideoConferenceSkeletonLoading from './components/VideoConferenceSkeletonLoading'; import VideoConferenceSkeletonLoading from './components/VideoConferenceSkeletonLoading';
import VideoConferenceIssue from './components/VideoConferenceIssue';
export default function VideoConferenceBlock({ callId, blockId }: { callId: string; blockId: string }): React.ReactElement { export default function VideoConferenceBlock({ callId, blockId }: { callId: string; blockId: string }): React.ReactElement {
const { result } = useEndpointData('video-conference.info', { callId }); const { result, error } = useEndpointData('video-conference.info', { callId });
if (result?.success) { if (result?.success) {
const { users, type, status, createdBy, rid } = result; const { users, type, status, createdBy, rid } = result;
@ -19,5 +20,7 @@ export default function VideoConferenceBlock({ callId, blockId }: { callId: stri
return <VideoConferenceOutgoing blockId={blockId} users={users} />; return <VideoConferenceOutgoing blockId={blockId} users={users} />;
} }
if (result?.error || error) return <VideoConferenceIssue />;
return <VideoConferenceSkeletonLoading />; return <VideoConferenceSkeletonLoading />;
} }

View File

@ -2,8 +2,10 @@ import React from 'react';
import { KaTeX as KaTeXProps } from '@rocket.chat/message-parser'; import { KaTeX as KaTeXProps } from '@rocket.chat/message-parser';
// eslint-disable-next-line import/no-unresolved // eslint-disable-next-line import/no-unresolved
import MathView, { MathText } from 'react-native-math-view'; import MathView, { MathText } from 'react-native-math-view';
import Katex from 'react-native-katex';
import { useTheme } from '../../../theme'; import { useTheme } from '../../../theme';
import { DEFAULT_MESSAGE_HEIGHT } from '../../message/utils';
interface IKaTeXProps { interface IKaTeXProps {
value: KaTeXProps['value']; value: KaTeXProps['value'];
@ -11,7 +13,13 @@ interface IKaTeXProps {
export const KaTeX = ({ value }: IKaTeXProps): React.ReactElement | null => { export const KaTeX = ({ value }: IKaTeXProps): React.ReactElement | null => {
const { colors } = useTheme(); const { colors } = useTheme();
return <MathView math={value} style={{ color: colors.bodyText }} />; return (
<MathView
math={value}
style={{ color: colors.bodyText }}
renderError={() => <Katex expression={value} style={{ flex: 1, height: DEFAULT_MESSAGE_HEIGHT }} />}
/>
);
}; };
export const InlineKaTeX = ({ value }: IKaTeXProps): React.ReactElement | null => { export const InlineKaTeX = ({ value }: IKaTeXProps): React.ReactElement | null => {

View File

@ -8,8 +8,11 @@ export const previewFormatText = (msg: string) => {
let m = formatText(msg); let m = formatText(msg);
m = formatHyperlink(m); m = formatHyperlink(m);
m = shortnameToUnicode(m); m = shortnameToUnicode(m);
// Removes sequential empty spaces before to use removeMarkdown,
// because with some edge cases the library takes a long time to finish the process
m = m.replace(/\s+/g, ' ');
m = removeMarkdown(m); m = removeMarkdown(m);
// Removes sequential empty spaces // Removes sequential empty spaces to remove leading empty space on quotes at the rooms list view
m = m.replace(/\s+/g, ' '); m = m.replace(/\s+/g, ' ');
m = m.replace(/\n+/g, ' '); m = m.replace(/\n+/g, ' ');
return m; return m;

View File

@ -12,6 +12,7 @@ import { IAttachment, TGetCustomEmoji } from '../../definitions';
import CollapsibleQuote from './Components/CollapsibleQuote'; import CollapsibleQuote from './Components/CollapsibleQuote';
import openLink from '../../lib/methods/helpers/openLink'; import openLink from '../../lib/methods/helpers/openLink';
import Markdown from '../markdown'; import Markdown from '../markdown';
import { getMessageFromAttachment } from './utils';
export type TElement = { export type TElement = {
type: string; type: string;
@ -54,11 +55,14 @@ const AttachedActions = ({ attachment, getCustomEmoji }: { attachment: IAttachme
const Attachments: React.FC<IMessageAttachments> = React.memo( const Attachments: React.FC<IMessageAttachments> = React.memo(
({ attachments, timeFormat, showAttachment, style, getCustomEmoji, isReply, author }: IMessageAttachments) => { ({ attachments, timeFormat, showAttachment, style, getCustomEmoji, isReply, author }: IMessageAttachments) => {
const { translateLanguage } = useContext(MessageContext);
if (!attachments || attachments.length === 0) { if (!attachments || attachments.length === 0) {
return null; return null;
} }
const attachmentsElements = attachments.map((file: IAttachment, index: number) => { const attachmentsElements = attachments.map((file: IAttachment, index: number) => {
const msg = getMessageFromAttachment(file, translateLanguage);
if (file && file.image_url) { if (file && file.image_url) {
return ( return (
<Image <Image
@ -69,6 +73,7 @@ const Attachments: React.FC<IMessageAttachments> = React.memo(
style={style} style={style}
isReply={isReply} isReply={isReply}
author={author} author={author}
msg={msg}
/> />
); );
} }
@ -82,6 +87,7 @@ const Attachments: React.FC<IMessageAttachments> = React.memo(
isReply={isReply} isReply={isReply}
style={style} style={style}
author={author} author={author}
msg={msg}
/> />
); );
} }
@ -95,6 +101,7 @@ const Attachments: React.FC<IMessageAttachments> = React.memo(
getCustomEmoji={getCustomEmoji} getCustomEmoji={getCustomEmoji}
style={style} style={style}
isReply={isReply} isReply={isReply}
msg={msg}
/> />
); );
} }
@ -108,7 +115,9 @@ const Attachments: React.FC<IMessageAttachments> = React.memo(
); );
} }
return <Reply key={index} index={index} attachment={file} timeFormat={timeFormat} getCustomEmoji={getCustomEmoji} />; return (
<Reply key={index} index={index} attachment={file} timeFormat={timeFormat} getCustomEmoji={getCustomEmoji} msg={msg} />
);
}); });
return <>{attachmentsElements}</>; return <>{attachmentsElements}</>;
}, },

View File

@ -1,7 +1,7 @@
import React, { useContext, useEffect, useRef, useState } from 'react'; import React, { useContext, useEffect, useRef, useState } from 'react';
import { StyleProp, TextStyle, View } from 'react-native'; import { StyleProp, TextStyle, View } from 'react-native';
import { AVPlaybackStatus } from 'expo-av'; import { AVPlaybackStatus } from 'expo-av';
import { activateKeepAwakeAsync, deactivateKeepAwake } from 'expo-keep-awake'; import { activateKeepAwake, deactivateKeepAwake } from 'expo-keep-awake';
import { useSharedValue } from 'react-native-reanimated'; import { useSharedValue } from 'react-native-reanimated';
import Markdown from '../../../markdown'; import Markdown from '../../../markdown';
@ -23,9 +23,10 @@ interface IMessageAudioProps {
style?: StyleProp<TextStyle>[]; style?: StyleProp<TextStyle>[];
getCustomEmoji: TGetCustomEmoji; getCustomEmoji: TGetCustomEmoji;
author?: IUserMessage; author?: IUserMessage;
msg?: string;
} }
const MessageAudio = ({ file, getCustomEmoji, author, isReply, style }: IMessageAudioProps) => { const MessageAudio = ({ file, getCustomEmoji, author, isReply, style, msg }: IMessageAudioProps) => {
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [paused, setPaused] = useState(true); const [paused, setPaused] = useState(true);
const [cached, setCached] = useState(false); const [cached, setCached] = useState(false);
@ -195,7 +196,7 @@ const MessageAudio = ({ file, getCustomEmoji, author, isReply, style }: IMessage
if (paused) { if (paused) {
deactivateKeepAwake(); deactivateKeepAwake();
} else { } else {
activateKeepAwakeAsync(); activateKeepAwake();
} }
}, [paused]); }, [paused]);
@ -204,13 +205,12 @@ const MessageAudio = ({ file, getCustomEmoji, author, isReply, style }: IMessage
} }
return ( return (
<> <>
<Markdown msg={file.description} style={[isReply && style]} username={user.username} getCustomEmoji={getCustomEmoji} /> <Markdown msg={msg} style={[isReply && style]} username={user.username} getCustomEmoji={getCustomEmoji} />
<View <View
style={[ style={[
styles.audioContainer, styles.audioContainer,
{ backgroundColor: colors.audioComponentBackground, borderColor: colors.audioBorderColor } { backgroundColor: colors.audioComponentBackground, borderColor: colors.audioBorderColor }
]} ]}>
>
<PlayButton disabled={isReply} loading={loading} paused={paused} cached={cached} onPress={onPress} /> <PlayButton disabled={isReply} loading={loading} paused={paused} cached={cached} onPress={onPress} />
<Slider currentTime={currentTime} duration={duration} loaded={!isReply && cached} onChangeTime={setPosition} /> <Slider currentTime={currentTime} duration={duration} loaded={!isReply && cached} onChangeTime={setPosition} />
<AudioRate onChange={onChangeRate} loaded={!isReply && cached} rate={rate} /> <AudioRate onChange={onChangeRate} loaded={!isReply && cached} rate={rate} />

View File

@ -1,19 +1,18 @@
import React, { useContext, useEffect, useState } from 'react'; import React, { useContext, useEffect, useState } from 'react';
import { StyleProp, TextStyle, View } from 'react-native'; import { StyleProp, TextStyle, View } from 'react-native';
import FastImage from 'react-native-fast-image'; import FastImage from 'react-native-fast-image';
import { dequal } from 'dequal';
import Touchable from './Touchable';
import Markdown from '../markdown';
import styles from './styles';
import MessageContext from './Context';
import { TGetCustomEmoji } from '../../definitions/IEmoji';
import { IAttachment, IUserMessage } from '../../definitions'; import { IAttachment, IUserMessage } from '../../definitions';
import { useTheme } from '../../theme'; import { TGetCustomEmoji } from '../../definitions/IEmoji';
import { formatAttachmentUrl } from '../../lib/methods/helpers/formatAttachmentUrl';
import { cancelDownload, downloadMediaFile, isDownloadActive, getMediaCache } from '../../lib/methods/handleMediaDownload';
import { fetchAutoDownloadEnabled } from '../../lib/methods/autoDownloadPreference'; import { fetchAutoDownloadEnabled } from '../../lib/methods/autoDownloadPreference';
import { cancelDownload, downloadMediaFile, getMediaCache, isDownloadActive } from '../../lib/methods/handleMediaDownload';
import { formatAttachmentUrl } from '../../lib/methods/helpers/formatAttachmentUrl';
import { useTheme } from '../../theme';
import Markdown from '../markdown';
import BlurComponent from './Components/BlurComponent'; import BlurComponent from './Components/BlurComponent';
import MessageContext from './Context';
import Touchable from './Touchable';
import styles from './styles';
interface IMessageButton { interface IMessageButton {
children: React.ReactElement; children: React.ReactElement;
@ -29,6 +28,7 @@ interface IMessageImage {
isReply?: boolean; isReply?: boolean;
getCustomEmoji?: TGetCustomEmoji; getCustomEmoji?: TGetCustomEmoji;
author?: IUserMessage; author?: IUserMessage;
msg?: string;
} }
const Button = React.memo(({ children, onPress, disabled }: IMessageButton) => { const Button = React.memo(({ children, onPress, disabled }: IMessageButton) => {
@ -61,124 +61,124 @@ export const MessageImage = React.memo(({ imgUri, cached, loading }: { imgUri: s
); );
}); });
const ImageContainer = React.memo( const ImageContainer = ({
({ file, imageUrl, showAttachment, getCustomEmoji, style, isReply, author }: IMessageImage) => { file,
const [imageCached, setImageCached] = useState(file); imageUrl,
const [cached, setCached] = useState(false); showAttachment,
const [loading, setLoading] = useState(true); getCustomEmoji,
const { theme } = useTheme(); style,
const { baseUrl, user } = useContext(MessageContext); isReply,
const getUrl = (link?: string) => imageUrl || formatAttachmentUrl(link, user.id, user.token, baseUrl); author,
const img = getUrl(file.image_url); msg
// The param file.title_link is the one that point to image with best quality, however we still need to test the imageUrl }: IMessageImage): React.ReactElement | null => {
// And we cannot be certain whether the file.title_link actually exists. const [imageCached, setImageCached] = useState(file);
const imgUrlToCache = getUrl(imageCached.title_link || imageCached.image_url); const [cached, setCached] = useState(false);
const [loading, setLoading] = useState(true);
const { theme } = useTheme();
const { baseUrl, user } = useContext(MessageContext);
const getUrl = (link?: string) => imageUrl || formatAttachmentUrl(link, user.id, user.token, baseUrl);
const img = getUrl(file.image_url);
// The param file.title_link is the one that point to image with best quality, however we still need to test the imageUrl
// And we cannot be certain whether the file.title_link actually exists.
const imgUrlToCache = getUrl(imageCached.title_link || imageCached.image_url);
useEffect(() => { useEffect(() => {
const handleCache = async () => { const handleCache = async () => {
if (img) { if (img) {
const cachedImageResult = await getMediaCache({ const cachedImageResult = await getMediaCache({
type: 'image',
mimeType: imageCached.image_type,
urlToCache: imgUrlToCache
});
if (cachedImageResult?.exists) {
setImageCached(prev => ({
...prev,
title_link: cachedImageResult?.uri
}));
setLoading(false);
setCached(true);
return;
}
if (isReply) {
setLoading(false);
return;
}
if (isDownloadActive(imgUrlToCache)) {
return;
}
setLoading(false);
await handleAutoDownload();
}
};
handleCache();
}, []);
if (!img) {
return null;
}
const handleAutoDownload = async () => {
const isCurrentUserAuthor = author?._id === user.id;
const isAutoDownloadEnabled = fetchAutoDownloadEnabled('imagesPreferenceDownload');
if (isAutoDownloadEnabled || isCurrentUserAuthor) {
await handleDownload();
}
};
const handleDownload = async () => {
try {
setLoading(true);
const imageUri = await downloadMediaFile({
downloadUrl: imgUrlToCache,
type: 'image', type: 'image',
mimeType: imageCached.image_type mimeType: imageCached.image_type,
urlToCache: imgUrlToCache
}); });
setImageCached(prev => ({ if (cachedImageResult?.exists) {
...prev, setImageCached(prev => ({
title_link: imageUri ...prev,
})); title_link: cachedImageResult?.uri
setCached(true); }));
} catch (e) { setLoading(false);
setCached(false); setCached(true);
} finally { return;
}
if (isReply) {
setLoading(false);
return;
}
if (isDownloadActive(imgUrlToCache)) {
return;
}
setLoading(false); setLoading(false);
await handleAutoDownload();
} }
}; };
handleCache();
}, []);
const onPress = () => { if (!img) {
if (loading && isDownloadActive(imgUrlToCache)) { return null;
cancelDownload(imgUrlToCache); }
setLoading(false);
setCached(false);
return;
}
if (!cached && !loading) {
handleDownload();
return;
}
if (!showAttachment) {
return;
}
showAttachment(imageCached);
};
if (imageCached.description) { const handleAutoDownload = async () => {
return ( const isCurrentUserAuthor = author?._id === user.id;
<View> const isAutoDownloadEnabled = fetchAutoDownloadEnabled('imagesPreferenceDownload');
<Markdown if (isAutoDownloadEnabled || isCurrentUserAuthor) {
msg={imageCached.description} await handleDownload();
style={[isReply && style]}
username={user.username}
getCustomEmoji={getCustomEmoji}
theme={theme}
/>
<Button disabled={isReply} onPress={onPress}>
<MessageImage imgUri={img} cached={cached} loading={loading} />
</Button>
</View>
);
} }
};
const handleDownload = async () => {
try {
setLoading(true);
const imageUri = await downloadMediaFile({
downloadUrl: imgUrlToCache,
type: 'image',
mimeType: imageCached.image_type
});
setImageCached(prev => ({
...prev,
title_link: imageUri
}));
setCached(true);
} catch (e) {
setCached(false);
} finally {
setLoading(false);
}
};
const onPress = () => {
if (loading && isDownloadActive(imgUrlToCache)) {
cancelDownload(imgUrlToCache);
setLoading(false);
setCached(false);
return;
}
if (!cached && !loading) {
handleDownload();
return;
}
if (!showAttachment) {
return;
}
showAttachment(imageCached);
};
if (msg) {
return ( return (
<Button disabled={isReply} onPress={onPress}> <View>
<MessageImage imgUri={img} cached={cached} loading={loading} /> <Markdown msg={msg} style={[isReply && style]} username={user.username} getCustomEmoji={getCustomEmoji} theme={theme} />
</Button> <Button disabled={isReply} onPress={onPress}>
<MessageImage imgUri={img} cached={cached} loading={loading} />
</Button>
</View>
); );
}, }
(prevProps, nextProps) => dequal(prevProps.file, nextProps.file)
); return (
<Button disabled={isReply} onPress={onPress}>
<MessageImage imgUri={img} cached={cached} loading={loading} />
</Button>
);
};
ImageContainer.displayName = 'MessageImageContainer'; ImageContainer.displayName = 'MessageImageContainer';
MessageImage.displayName = 'MessageImage'; MessageImage.displayName = 'MessageImage';

View File

@ -91,6 +91,7 @@ interface IMessageReply {
timeFormat?: string; timeFormat?: string;
index: number; index: number;
getCustomEmoji: TGetCustomEmoji; getCustomEmoji: TGetCustomEmoji;
msg?: string;
} }
const Title = React.memo( const Title = React.memo(
@ -197,7 +198,7 @@ const Fields = React.memo(
); );
const Reply = React.memo( const Reply = React.memo(
({ attachment, timeFormat, index, getCustomEmoji }: IMessageReply) => { ({ attachment, timeFormat, index, getCustomEmoji, msg }: IMessageReply) => {
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const { theme } = useTheme(); const { theme } = useTheme();
const { baseUrl, user, jumpToMessage } = useContext(MessageContext); const { baseUrl, user, jumpToMessage } = useContext(MessageContext);
@ -238,7 +239,7 @@ const Reply = React.memo(
style={[ style={[
styles.button, styles.button,
index > 0 && styles.marginTop, index > 0 && styles.marginTop,
attachment.description && styles.marginBottom, msg && styles.marginBottom,
{ {
borderColor borderColor
} }
@ -271,7 +272,7 @@ const Reply = React.memo(
) : null} ) : null}
</View> </View>
</Touchable> </Touchable>
<Markdown msg={attachment.description} username={user.username} getCustomEmoji={getCustomEmoji} theme={theme} /> <Markdown msg={msg} username={user.username} getCustomEmoji={getCustomEmoji} theme={theme} />
</> </>
); );
}, },

View File

@ -14,6 +14,7 @@ import EventEmitter from '../../lib/methods/helpers/events';
import I18n from '../../i18n'; import I18n from '../../i18n';
import MessageContext from './Context'; import MessageContext from './Context';
import { IUrl } from '../../definitions'; import { IUrl } from '../../definitions';
import { DEFAULT_MESSAGE_HEIGHT } from './utils';
const styles = StyleSheet.create({ const styles = StyleSheet.create({
button: { button: {
@ -45,7 +46,7 @@ const styles = StyleSheet.create({
}, },
image: { image: {
width: '100%', width: '100%',
height: 150, height: DEFAULT_MESSAGE_HEIGHT,
borderTopLeftRadius: 4, borderTopLeftRadius: 4,
borderTopRightRadius: 4 borderTopRightRadius: 4
}, },

View File

@ -1,26 +1,26 @@
import React, { useContext, useEffect, useState } from 'react'; import React, { useContext, useEffect, useState } from 'react';
import { StyleProp, StyleSheet, TextStyle, View, Text } from 'react-native'; import { StyleProp, StyleSheet, Text, TextStyle, View } from 'react-native';
import { dequal } from 'dequal';
import FastImage from 'react-native-fast-image'; import FastImage from 'react-native-fast-image';
import messageStyles from './styles';
import Touchable from './Touchable';
import Markdown from '../markdown';
import { isIOS } from '../../lib/methods/helpers';
import { themes } from '../../lib/constants';
import MessageContext from './Context';
import { fileDownload } from './helpers/fileDownload';
import EventEmitter from '../../lib/methods/helpers/events';
import { LISTENER } from '../Toast';
import I18n from '../../i18n';
import { IAttachment } from '../../definitions/IAttachment'; import { IAttachment } from '../../definitions/IAttachment';
import { TGetCustomEmoji } from '../../definitions/IEmoji'; import { TGetCustomEmoji } from '../../definitions/IEmoji';
import { useTheme } from '../../theme'; import I18n from '../../i18n';
import { formatAttachmentUrl } from '../../lib/methods/helpers/formatAttachmentUrl'; import { themes } from '../../lib/constants';
import { cancelDownload, downloadMediaFile, isDownloadActive, getMediaCache } from '../../lib/methods/handleMediaDownload';
import { fetchAutoDownloadEnabled } from '../../lib/methods/autoDownloadPreference'; import { fetchAutoDownloadEnabled } from '../../lib/methods/autoDownloadPreference';
import { cancelDownload, downloadMediaFile, getMediaCache, isDownloadActive } from '../../lib/methods/handleMediaDownload';
import { isIOS } from '../../lib/methods/helpers';
import EventEmitter from '../../lib/methods/helpers/events';
import { formatAttachmentUrl } from '../../lib/methods/helpers/formatAttachmentUrl';
import { useTheme } from '../../theme';
import sharedStyles from '../../views/Styles'; import sharedStyles from '../../views/Styles';
import { LISTENER } from '../Toast';
import Markdown from '../markdown';
import BlurComponent from './Components/BlurComponent'; import BlurComponent from './Components/BlurComponent';
import MessageContext from './Context';
import Touchable from './Touchable';
import { fileDownload } from './helpers/fileDownload';
import messageStyles from './styles';
import { DEFAULT_MESSAGE_HEIGHT } from './utils';
const SUPPORTED_TYPES = ['video/quicktime', 'video/mp4', ...(isIOS ? [] : ['video/3gp', 'video/mkv'])]; const SUPPORTED_TYPES = ['video/quicktime', 'video/mp4', ...(isIOS ? [] : ['video/3gp', 'video/mkv'])];
const isTypeSupported = (type: string) => SUPPORTED_TYPES.indexOf(type) !== -1; const isTypeSupported = (type: string) => SUPPORTED_TYPES.indexOf(type) !== -1;
@ -29,7 +29,7 @@ const styles = StyleSheet.create({
button: { button: {
flex: 1, flex: 1,
borderRadius: 4, borderRadius: 4,
height: 150, height: DEFAULT_MESSAGE_HEIGHT,
marginBottom: 6, marginBottom: 6,
alignItems: 'center', alignItems: 'center',
justifyContent: 'center' justifyContent: 'center'
@ -56,6 +56,7 @@ interface IMessageVideo {
getCustomEmoji: TGetCustomEmoji; getCustomEmoji: TGetCustomEmoji;
style?: StyleProp<TextStyle>[]; style?: StyleProp<TextStyle>[];
isReply?: boolean; isReply?: boolean;
msg?: string;
} }
const CancelIndicator = () => { const CancelIndicator = () => {
@ -81,139 +82,130 @@ const Thumbnail = ({ loading, thumbnailUrl, cached }: { loading: boolean; thumbn
</> </>
); );
const Video = React.memo( const Video = ({ file, showAttachment, getCustomEmoji, style, isReply, msg }: IMessageVideo): React.ReactElement | null => {
({ file, showAttachment, getCustomEmoji, style, isReply }: IMessageVideo) => { const [videoCached, setVideoCached] = useState(file);
const [videoCached, setVideoCached] = useState(file); const [loading, setLoading] = useState(true);
const [loading, setLoading] = useState(true); const [cached, setCached] = useState(false);
const [cached, setCached] = useState(false); const { baseUrl, user } = useContext(MessageContext);
const { baseUrl, user } = useContext(MessageContext); const { theme } = useTheme();
const { theme } = useTheme(); const video = formatAttachmentUrl(file.video_url, user.id, user.token, baseUrl);
const video = formatAttachmentUrl(file.video_url, user.id, user.token, baseUrl);
useEffect(() => { useEffect(() => {
const handleVideoSearchAndDownload = async () => { const handleVideoSearchAndDownload = async () => {
if (video) { if (video) {
const cachedVideoResult = await getMediaCache({ const cachedVideoResult = await getMediaCache({
type: 'video',
mimeType: file.video_type,
urlToCache: video
});
const downloadActive = isDownloadActive(video);
if (cachedVideoResult?.exists) {
setVideoCached(prev => ({
...prev,
video_url: cachedVideoResult?.uri
}));
setLoading(false);
setCached(true);
if (downloadActive) {
cancelDownload(video);
}
return;
}
if (isReply) {
setLoading(false);
return;
}
await handleAutoDownload();
}
};
handleVideoSearchAndDownload();
}, []);
if (!baseUrl) {
return null;
}
const handleAutoDownload = async () => {
const isAutoDownloadEnabled = fetchAutoDownloadEnabled('videoPreferenceDownload');
if (isAutoDownloadEnabled && file.video_type && isTypeSupported(file.video_type)) {
await handleDownload();
return;
}
setLoading(false);
};
const handleDownload = async () => {
setLoading(true);
try {
const videoUri = await downloadMediaFile({
downloadUrl: video,
type: 'video', type: 'video',
mimeType: file.video_type mimeType: file.video_type,
urlToCache: video
}); });
setVideoCached(prev => ({ const downloadActive = isDownloadActive(video);
...prev, if (cachedVideoResult?.exists) {
video_url: videoUri setVideoCached(prev => ({
})); ...prev,
setCached(true); video_url: cachedVideoResult?.uri
} catch { }));
setCached(false); setLoading(false);
} finally { setCached(true);
setLoading(false); if (downloadActive) {
cancelDownload(video);
}
return;
}
if (isReply) {
setLoading(false);
return;
}
await handleAutoDownload();
} }
}; };
handleVideoSearchAndDownload();
}, []);
const onPress = async () => { if (!baseUrl) {
if (file.video_type && cached && isTypeSupported(file.video_type) && showAttachment) { return null;
showAttachment(videoCached); }
return;
}
if (!loading && !cached && file.video_type && isTypeSupported(file.video_type)) {
handleDownload();
return;
}
if (loading && !cached) {
handleCancelDownload();
return;
}
if (!isIOS && file.video_url) {
await downloadVideoToGallery(video);
return;
}
EventEmitter.emit(LISTENER, { message: I18n.t('Unsupported_format') });
};
const handleCancelDownload = () => { const handleAutoDownload = async () => {
if (loading) { const isAutoDownloadEnabled = fetchAutoDownloadEnabled('videoPreferenceDownload');
cancelDownload(video); if (isAutoDownloadEnabled && file.video_type && isTypeSupported(file.video_type)) {
setLoading(false); await handleDownload();
} return;
}; }
setLoading(false);
};
const downloadVideoToGallery = async (uri: string) => { const handleDownload = async () => {
setLoading(true); setLoading(true);
const fileDownloaded = await fileDownload(uri, file); try {
const videoUri = await downloadMediaFile({
downloadUrl: video,
type: 'video',
mimeType: file.video_type
});
setVideoCached(prev => ({
...prev,
video_url: videoUri
}));
setCached(true);
} catch {
setCached(false);
} finally {
setLoading(false); setLoading(false);
}
};
if (fileDownloaded) { const onPress = async () => {
EventEmitter.emit(LISTENER, { message: I18n.t('saved_to_gallery') }); if (file.video_type && cached && isTypeSupported(file.video_type) && showAttachment) {
return; showAttachment(videoCached);
} return;
EventEmitter.emit(LISTENER, { message: I18n.t('error-save-video') }); }
}; if (!loading && !cached && file.video_type && isTypeSupported(file.video_type)) {
handleDownload();
return;
}
if (loading && !cached) {
handleCancelDownload();
return;
}
if (!isIOS && file.video_url) {
await downloadVideoToGallery(video);
return;
}
EventEmitter.emit(LISTENER, { message: I18n.t('Unsupported_format') });
};
return ( const handleCancelDownload = () => {
<> if (loading) {
<Markdown cancelDownload(video);
msg={file.description} setLoading(false);
username={user.username} }
getCustomEmoji={getCustomEmoji} };
style={[isReply && style]}
theme={theme} const downloadVideoToGallery = async (uri: string) => {
/> setLoading(true);
<Touchable const fileDownloaded = await fileDownload(uri, file);
disabled={isReply} setLoading(false);
onPress={onPress}
style={[styles.button, messageStyles.mustWrapBlur, { backgroundColor: themes[theme].videoBackground }]} if (fileDownloaded) {
background={Touchable.Ripple(themes[theme].bannerBackground)} EventEmitter.emit(LISTENER, { message: I18n.t('saved_to_gallery') });
> return;
<Thumbnail loading={loading} cached={cached} /> }
</Touchable> EventEmitter.emit(LISTENER, { message: I18n.t('error-save-video') });
</> };
);
}, return (
(prevProps, nextProps) => dequal(prevProps.file, nextProps.file) <>
); <Markdown msg={msg} username={user.username} getCustomEmoji={getCustomEmoji} style={[isReply && style]} theme={theme} />
<Touchable
disabled={isReply}
onPress={onPress}
style={[styles.button, messageStyles.mustWrapBlur, { backgroundColor: themes[theme].videoBackground }]}
background={Touchable.Ripple(themes[theme].bannerBackground)}
>
<Thumbnail loading={loading} cached={cached} />
</Touchable>
</>
);
};
export default Video; export default Video;

View File

@ -95,7 +95,8 @@ class MessageContainer extends React.Component<IMessageContainerProps, IMessageC
shouldComponentUpdate(nextProps: IMessageContainerProps, nextState: IMessageContainerState) { shouldComponentUpdate(nextProps: IMessageContainerProps, nextState: IMessageContainerState) {
const { isManualUnignored } = this.state; const { isManualUnignored } = this.state;
const { threadBadgeColor, isIgnored, highlighted, previousItem } = this.props; const { threadBadgeColor, isIgnored, highlighted, previousItem, autoTranslateRoom, autoTranslateLanguage } = this.props;
if (nextProps.highlighted !== highlighted) { if (nextProps.highlighted !== highlighted) {
return true; return true;
} }
@ -111,6 +112,12 @@ class MessageContainer extends React.Component<IMessageContainerProps, IMessageC
if (nextProps.previousItem?._id !== previousItem?._id) { if (nextProps.previousItem?._id !== previousItem?._id) {
return true; return true;
} }
if (nextProps.autoTranslateRoom !== autoTranslateRoom) {
return true;
}
if (nextProps.autoTranslateRoom !== autoTranslateRoom || nextProps.autoTranslateLanguage !== autoTranslateLanguage) {
return true;
}
return false; return false;
} }
@ -382,14 +389,17 @@ class MessageContainer extends React.Component<IMessageContainerProps, IMessageC
let message = msg; let message = msg;
let isTranslated = false; let isTranslated = false;
const otherUserMessage = u.username !== user.username;
// "autoTranslateRoom" and "autoTranslateLanguage" are properties from the subscription // "autoTranslateRoom" and "autoTranslateLanguage" are properties from the subscription
// "autoTranslateMessage" is a toggle between "View Original" and "Translate" state // "autoTranslateMessage" is a toggle between "View Original" and "Translate" state
if (autoTranslateRoom && autoTranslateMessage && autoTranslateLanguage) { if (autoTranslateRoom && autoTranslateMessage && autoTranslateLanguage && otherUserMessage) {
const messageTranslated = getMessageTranslation(item, autoTranslateLanguage); const messageTranslated = getMessageTranslation(item, autoTranslateLanguage);
isTranslated = !!messageTranslated; isTranslated = !!messageTranslated;
message = messageTranslated || message; message = messageTranslated || message;
} }
const canTranslateMessage = autoTranslateRoom && autoTranslateLanguage && autoTranslateMessage !== false && otherUserMessage;
return ( return (
<MessageContext.Provider <MessageContext.Provider
value={{ value={{
@ -409,7 +419,8 @@ class MessageContainer extends React.Component<IMessageContainerProps, IMessageC
jumpToMessage, jumpToMessage,
threadBadgeColor, threadBadgeColor,
toggleFollowThread, toggleFollowThread,
replies replies,
translateLanguage: canTranslateMessage ? autoTranslateLanguage : undefined
}} }}
> >
{/* @ts-ignore*/} {/* @ts-ignore*/}

View File

@ -1,8 +1,11 @@
/* eslint-disable complexity */ /* eslint-disable complexity */
import { IAttachment } from '../../definitions';
import { MessageTypesValues, TMessageModel } from '../../definitions/IMessage'; import { MessageTypesValues, TMessageModel } from '../../definitions/IMessage';
import I18n from '../../i18n'; import I18n from '../../i18n';
import { DISCUSSION } from './constants'; import { DISCUSSION } from './constants';
export const DEFAULT_MESSAGE_HEIGHT = 150;
export const formatMessageCount = (count?: number, type?: string): string | null => { export const formatMessageCount = (count?: number, type?: string): string | null => {
const discussion = type === DISCUSSION; const discussion = type === DISCUSSION;
let text = discussion ? I18n.t('No_messages_yet') : null; let text = discussion ? I18n.t('No_messages_yet') : null;
@ -194,3 +197,14 @@ export const getMessageTranslation = (message: TMessageModel, autoTranslateLangu
} }
return null; return null;
}; };
export const getMessageFromAttachment = (attachment: IAttachment, translateLanguage?: string): string | undefined => {
let msg = attachment.description;
if (translateLanguage) {
const translatedMessage = attachment.translations?.[translateLanguage];
if (translatedMessage) {
msg = translatedMessage;
}
}
return msg;
};

View File

@ -1,4 +1,5 @@
import { IUser } from './IUser'; import { IUser } from './IUser';
import { IAttachmentTranslations } from './IMessage';
export interface IAttachment { export interface IAttachment {
ts?: string | Date; ts?: string | Date;
@ -29,6 +30,7 @@ export interface IAttachment {
thumb_url?: string; thumb_url?: string;
collapsed?: boolean; collapsed?: boolean;
audio_type?: string; audio_type?: string;
translations?: IAttachmentTranslations;
} }
export interface IServerAttachment { export interface IServerAttachment {

View File

@ -0,0 +1,6 @@
export interface ICommand {
event: {
input: string;
modifierFlags: number;
};
}

View File

@ -41,7 +41,7 @@ export interface IEditedBy {
export type TOnLinkPress = (link: string) => void; export type TOnLinkPress = (link: string) => void;
export interface ITranslations { export interface IMessageTranslations {
_id: string; _id: string;
language: string; language: string;
value: string; value: string;
@ -136,7 +136,7 @@ export interface IMessage extends IMessageFromServer {
replies?: string[]; replies?: string[];
unread?: boolean; unread?: boolean;
autoTranslate?: boolean; autoTranslate?: boolean;
translations?: ITranslations[]; translations?: IMessageTranslations[];
tmsg?: string; tmsg?: string;
blocks?: any; blocks?: any;
e2e?: E2EType; e2e?: E2EType;
@ -243,3 +243,7 @@ export type MessageTypesValues =
| 'message_pinned' | 'message_pinned'
| 'message_snippeted' | 'message_snippeted'
| 'jitsi_call_started'; | 'jitsi_call_started';
export interface IAttachmentTranslations {
[k: string]: string;
}

View File

@ -40,6 +40,6 @@ export interface IBaseScreen<T extends Record<string, object | undefined>, S ext
dispatch: Dispatch; dispatch: Dispatch;
isMasterDetail: boolean; isMasterDetail: boolean;
// TODO: remove after migrating all Class components // TODO: remove after migrating all Class components
theme?: TSupportedThemes; theme: TSupportedThemes;
colors: TColors; colors: TColors;
} }

View File

@ -1,5 +1,12 @@
import { NavigatorScreenParams } from '@react-navigation/core';
import { StackNavigationOptions } from '@react-navigation/stack'; import { StackNavigationOptions } from '@react-navigation/stack';
import { TSubscriptionModel } from './ISubscription';
import { TServerModel } from './IServer';
import { IAttachment } from './IAttachment';
import { MasterDetailInsideStackParamList } from '../stacks/MasterDetailStack/types';
import { OutsideParamList, InsideStackParamList } from '../stacks/types';
interface INavigationProps { interface INavigationProps {
route?: any; route?: any;
navigation?: any; navigation?: any;
@ -9,3 +16,41 @@ interface INavigationProps {
export type TNavigationOptions = { export type TNavigationOptions = {
navigationOptions?(props: INavigationProps): StackNavigationOptions; navigationOptions?(props: INavigationProps): StackNavigationOptions;
}; };
export type SetUsernameStackParamList = {
SetUsernameView: {
title: string;
};
};
export type StackParamList = {
AuthLoading: undefined;
OutsideStack: NavigatorScreenParams<OutsideParamList>;
InsideStack: NavigatorScreenParams<InsideStackParamList>;
MasterDetailStack: NavigatorScreenParams<MasterDetailInsideStackParamList>;
SetUsernameStack: NavigatorScreenParams<SetUsernameStackParamList>;
};
export type ShareInsideStackParamList = {
ShareListView: undefined;
ShareView: {
attachments: IAttachment[];
isShareView?: boolean;
isShareExtension: boolean;
serverInfo: TServerModel;
text: string;
room: TSubscriptionModel;
thread?: any; // TODO: Change
};
SelectServerView: undefined;
};
export type ShareOutsideStackParamList = {
WithoutServersView: undefined;
};
export type ShareAppStackParamList = {
AuthLoading?: undefined;
OutsideStack?: NavigatorScreenParams<ShareOutsideStackParamList>;
InsideStack?: NavigatorScreenParams<ShareInsideStackParamList>;
};

View File

@ -36,6 +36,8 @@ import { IInquiry } from '../../ee/omnichannel/reducers/inquiry';
import { IPermissionsState } from '../../reducers/permissions'; import { IPermissionsState } from '../../reducers/permissions';
import { IEnterpriseModules } from '../../reducers/enterpriseModules'; import { IEnterpriseModules } from '../../reducers/enterpriseModules';
import { IVideoConf } from '../../reducers/videoConf'; import { IVideoConf } from '../../reducers/videoConf';
import { TActionUsersRoles } from '../../actions/usersRoles';
import { TUsersRoles } from '../../reducers/usersRoles';
export interface IApplicationState { export interface IApplicationState {
settings: TSettingsState; settings: TSettingsState;
@ -60,6 +62,7 @@ export interface IApplicationState {
permissions: IPermissionsState; permissions: IPermissionsState;
roles: IRoles; roles: IRoles;
videoConf: IVideoConf; videoConf: IVideoConf;
usersRoles: TUsersRoles;
} }
export type TApplicationActions = TActionActiveUsers & export type TApplicationActions = TActionActiveUsers &
@ -79,4 +82,5 @@ export type TApplicationActions = TActionActiveUsers &
TActionInquiry & TActionInquiry &
TActionPermissions & TActionPermissions &
TActionEnterpriseModules & TActionEnterpriseModules &
TActionVideoConf; TActionVideoConf &
TActionUsersRoles;

View File

@ -6,6 +6,7 @@ declare module 'react-native-image-progress';
declare module 'react-native-ui-lib/keyboard'; declare module 'react-native-ui-lib/keyboard';
declare module '@rocket.chat/sdk'; declare module '@rocket.chat/sdk';
declare module 'react-native-config-reader'; declare module 'react-native-config-reader';
declare module 'react-native-keycommands';
declare module 'react-native-mime-types'; declare module 'react-native-mime-types';
declare module 'react-native-restart'; declare module 'react-native-restart';
declare module 'rn-root-view'; declare module 'rn-root-view';

View File

@ -689,12 +689,14 @@
"Also_send_thread_message_to_channel_behavior": "Also send thread message to channel", "Also_send_thread_message_to_channel_behavior": "Also send thread message to channel",
"Accounts_Default_User_Preferences_alsoSendThreadToChannel_Description": "Allow users to select the 'Also send to channel' behavior", "Accounts_Default_User_Preferences_alsoSendThreadToChannel_Description": "Allow users to select the 'Also send to channel' behavior",
"Waiting_for_answer": "Waiting for answer", "Waiting_for_answer": "Waiting for answer",
"Waiting_for_server_connection": "Waiting for server connection",
"Call_ended": "Call ended", "Call_ended": "Call ended",
"Call_was_not_answered": "Call was not answered", "Call_was_not_answered": "Call was not answered",
"Call_rejected": "Call rejected", "Call_rejected": "Call rejected",
"Call_back": "Call Back", "Call_back": "Call Back",
"Call_again": "Call Again", "Call_again": "Call Again",
"Call_ongoing": "Call Ongoing", "Call_ongoing": "Call Ongoing",
"Call_issue": "Call issue",
"Joined": "Joined", "Joined": "Joined",
"Calling": "Calling", "Calling": "Calling",
"Start_a_call": "Start a call", "Start_a_call": "Start a call",

View File

@ -689,11 +689,13 @@
"Also_send_thread_message_to_channel_behavior": "Também enviar mensagem do tópico para o canal", "Also_send_thread_message_to_channel_behavior": "Também enviar mensagem do tópico para o canal",
"Accounts_Default_User_Preferences_alsoSendThreadToChannel_Description": "Permitir que os usuários selecionem o comportamento Também enviar para o canal", "Accounts_Default_User_Preferences_alsoSendThreadToChannel_Description": "Permitir que os usuários selecionem o comportamento Também enviar para o canal",
"Waiting_for_answer": "Esperando por resposta", "Waiting_for_answer": "Esperando por resposta",
"Waiting_for_server_connection": "Aguardando conexão com o servidor",
"Call_ended": "Chamada finalizada", "Call_ended": "Chamada finalizada",
"Call_was_not_answered": "A chamada não foi atendida", "Call_was_not_answered": "A chamada não foi atendida",
"Call_back": "Ligue de volta", "Call_back": "Ligue de volta",
"Call_again": "Ligue novamente", "Call_again": "Ligue novamente",
"Call_ongoing": "Chamada em andamento", "Call_ongoing": "Chamada em andamento",
"Call_issue": "Chamada com problemas",
"Joined": "Ingressou", "Joined": "Ingressou",
"Calling": "Chamando", "Calling": "Chamando",
"Start_a_call": "Inicie uma chamada", "Start_a_call": "Inicie uma chamada",

View File

@ -1,5 +1,6 @@
import React from 'react'; import React from 'react';
import { Dimensions, Linking, EmitterSubscription } from 'react-native'; import { Dimensions, Linking } from 'react-native';
import { KeyCommandsEmitter } from 'react-native-keycommands';
import { initialWindowMetrics, SafeAreaProvider } from 'react-native-safe-area-context'; import { initialWindowMetrics, SafeAreaProvider } from 'react-native-safe-area-context';
import RNScreens from 'react-native-screens'; import RNScreens from 'react-native-screens';
import { Provider } from 'react-redux'; import { Provider } from 'react-redux';
@ -8,11 +9,13 @@ import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { appInit, appInitLocalSettings, setMasterDetail as setMasterDetailAction } from './actions/app'; import { appInit, appInitLocalSettings, setMasterDetail as setMasterDetailAction } from './actions/app';
import { deepLinkingOpen } from './actions/deepLinking'; import { deepLinkingOpen } from './actions/deepLinking';
import AppContainer from './AppContainer'; import AppContainer from './AppContainer';
import { KEY_COMMAND } from './commands';
import { ActionSheetProvider } from './containers/ActionSheet'; import { ActionSheetProvider } from './containers/ActionSheet';
import InAppNotification from './containers/InAppNotification'; import InAppNotification from './containers/InAppNotification';
import Toast from './containers/Toast'; import Toast from './containers/Toast';
import TwoFactor from './containers/TwoFactor'; import TwoFactor from './containers/TwoFactor';
import Loading from './containers/Loading'; import Loading from './containers/Loading';
import { ICommand } from './definitions/ICommand';
import { IThemePreference } from './definitions/ITheme'; import { IThemePreference } from './definitions/ITheme';
import { DimensionsContext } from './dimensions'; import { DimensionsContext } from './dimensions';
import { colors, isFDroidBuild, MIN_WIDTH_MASTER_DETAIL_LAYOUT, themes } from './lib/constants'; import { colors, isFDroidBuild, MIN_WIDTH_MASTER_DETAIL_LAYOUT, themes } from './lib/constants';
@ -23,6 +26,7 @@ import store from './lib/store';
import { initStore } from './lib/store/auxStore'; import { initStore } from './lib/store/auxStore';
import { ThemeContext, TSupportedThemes } from './theme'; import { ThemeContext, TSupportedThemes } from './theme';
import { debounce, isTablet } from './lib/methods/helpers'; import { debounce, isTablet } from './lib/methods/helpers';
import EventEmitter from './lib/methods/helpers/events';
import { toggleAnalyticsEventsReport, toggleCrashErrorsReport } from './lib/methods/helpers/log'; import { toggleAnalyticsEventsReport, toggleCrashErrorsReport } from './lib/methods/helpers/log';
import { import {
getTheme, getTheme,
@ -79,7 +83,8 @@ const parseDeepLinking = (url: string) => {
export default class Root extends React.Component<{}, IState> { export default class Root extends React.Component<{}, IState> {
private listenerTimeout!: any; private listenerTimeout!: any;
private dimensionsListener?: EmitterSubscription;
private onKeyCommands: any;
constructor(props: any) { constructor(props: any) {
super(props); super(props);
@ -101,7 +106,6 @@ export default class Root extends React.Component<{}, IState> {
this.initTablet(); this.initTablet();
} }
setNativeTheme(theme); setNativeTheme(theme);
subscribeTheme(theme, this.state.theme, this.setTheme);
} }
componentDidMount() { componentDidMount() {
@ -113,16 +117,18 @@ export default class Root extends React.Component<{}, IState> {
} }
}); });
}, 5000); }, 5000);
this.dimensionsListener = Dimensions.addEventListener('change', this.onDimensionsChange); Dimensions.addEventListener('change', this.onDimensionsChange);
} }
componentWillUnmount() { componentWillUnmount() {
clearTimeout(this.listenerTimeout); clearTimeout(this.listenerTimeout);
if (this.dimensionsListener) { Dimensions.removeEventListener('change', this.onDimensionsChange);
this.dimensionsListener.remove();
}
unsubscribeTheme(); unsubscribeTheme();
if (this.onKeyCommands && this.onKeyCommands.remove) {
this.onKeyCommands.remove();
}
} }
init = async () => { init = async () => {
@ -175,9 +181,9 @@ export default class Root extends React.Component<{}, IState> {
this.setState( this.setState(
prevState => newThemeState(prevState, newTheme as IThemePreference), prevState => newThemeState(prevState, newTheme as IThemePreference),
() => { () => {
const { themePreferences, theme } = this.state; const { themePreferences } = this.state;
// subscribe to Appearance changes // subscribe to Appearance changes
subscribeTheme(themePreferences, theme, this.setTheme); subscribeTheme(themePreferences, this.setTheme);
} }
); );
}; };
@ -189,6 +195,9 @@ export default class Root extends React.Component<{}, IState> {
initTablet = () => { initTablet = () => {
const { width } = this.state; const { width } = this.state;
this.setMasterDetail(width); this.setMasterDetail(width);
this.onKeyCommands = KeyCommandsEmitter.addListener('onKeyCommand', (command: ICommand) => {
EventEmitter.emit(KEY_COMMAND, { event: command });
});
}; };
initCrashReport = () => { initCrashReport = () => {

View File

@ -99,6 +99,8 @@ export const colors = {
gray300: '#5f656e', gray300: '#5f656e',
gray100: '#CBCED1', gray100: '#CBCED1',
n900: '#1F2329', n900: '#1F2329',
statusBackgroundWarning: '#FFECAD',
statusFontOnWarning: '#B88D00',
overlayColor: '#1F2329B2', overlayColor: '#1F2329B2',
audioPlayerPrimary: '#156FF5', audioPlayerPrimary: '#156FF5',
audioPlayerSecondary: '#CBCED1', audioPlayerSecondary: '#CBCED1',
@ -183,6 +185,8 @@ export const colors = {
gray300: '#5f656e', gray300: '#5f656e',
gray100: '#CBCED1', gray100: '#CBCED1',
n900: '#FFFFFF', n900: '#FFFFFF',
statusBackgroundWarning: '#FFECAD',
statusFontOnWarning: '#B88D00',
overlayColor: '#1F2329B2', overlayColor: '#1F2329B2',
audioPlayerPrimary: '#3976D1', audioPlayerPrimary: '#3976D1',
audioPlayerSecondary: '#404754', audioPlayerSecondary: '#404754',
@ -267,6 +271,8 @@ export const colors = {
gray300: '#5f656e', gray300: '#5f656e',
gray100: '#CBCED1', gray100: '#CBCED1',
n900: '#FFFFFF', n900: '#FFFFFF',
statusBackgroundWarning: '#FFECAD',
statusFontOnWarning: '#B88D00',
overlayColor: '#1F2329B2', overlayColor: '#1F2329B2',
audioPlayerPrimary: '#3976D1', audioPlayerPrimary: '#3976D1',
audioPlayerSecondary: '#404754', audioPlayerSecondary: '#404754',

View File

@ -1,4 +1,31 @@
// 🚨🚨 48 settings after login. Pay attention not to reach 50 as that's the limit per request. // DEPRECATED: This settings are deprecated and will be removed in the LTS only support
const deprecatedSettings = {
Jitsi_Enable_Teams: {
type: 'valueAsBoolean'
},
Jitsi_Enable_Channels: {
type: 'valuesAsBoolean'
},
Jitsi_Enabled: {
type: 'valueAsBoolean'
},
Jitsi_SSL: {
type: 'valueAsBoolean'
},
Jitsi_Domain: {
type: 'valueAsString'
},
Jitsi_Enabled_TokenAuth: {
type: 'valueAsBoolean'
},
Jitsi_URL_Room_Hash: {
type: 'valueAsBoolean'
},
Jitsi_URL_Room_Prefix: {
type: 'valueAsString'
}
};
export const defaultSettings = { export const defaultSettings = {
Accounts_AllowEmailChange: { Accounts_AllowEmailChange: {
type: 'valueAsBoolean' type: 'valueAsBoolean'
@ -90,24 +117,6 @@ export const defaultSettings = {
Livechat_request_comment_when_closing_conversation: { Livechat_request_comment_when_closing_conversation: {
type: 'valueAsBoolean' type: 'valueAsBoolean'
}, },
Jitsi_Enabled: {
type: 'valueAsBoolean'
},
Jitsi_SSL: {
type: 'valueAsBoolean'
},
Jitsi_Domain: {
type: 'valueAsString'
},
Jitsi_Enabled_TokenAuth: {
type: 'valueAsBoolean'
},
Jitsi_URL_Room_Hash: {
type: 'valueAsBoolean'
},
Jitsi_URL_Room_Prefix: {
type: 'valueAsString'
},
Message_AllowDeleting: { Message_AllowDeleting: {
type: 'valueAsBoolean' type: 'valueAsBoolean'
}, },
@ -198,12 +207,6 @@ export const defaultSettings = {
Accounts_AllowInvisibleStatusOption: { Accounts_AllowInvisibleStatusOption: {
type: 'valueAsString' type: 'valueAsString'
}, },
Jitsi_Enable_Teams: {
type: 'valueAsBoolean'
},
Jitsi_Enable_Channels: {
type: 'valuesAsBoolean'
},
Canned_Responses_Enable: { Canned_Responses_Enable: {
type: 'valueAsBoolean' type: 'valueAsBoolean'
}, },
@ -236,5 +239,9 @@ export const defaultSettings = {
}, },
Presence_broadcast_disabled: { Presence_broadcast_disabled: {
type: 'valueAsBoolean' type: 'valueAsBoolean'
} },
Omnichannel_call_provider: {
type: 'valueAsBoolean'
},
...deprecatedSettings
} as const; } as const;

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