[RELEASE] Merge beta into master (#1055)

* Bump version to 1.16.0 (#1014)

* [IMPROVEMENT] Share credentials with Rocket.Chat.iOS (#982)

*  Create user table

*  Introduce user table

* 🔥 Remove unused table

*  Add userdefaults to storage data

* 💚 Fix android build

*  Get credentials from iOS native client

* 🔥 Remove unused code

*  Revert sign xcode

* 🐛 Fix first login-logout

* 🎨 Use constants to UserDefaults Keys

* 🐛 Fix clear server-user-info on logout

* 🐛 Fix filter null value

* 🚑 Remove user object in logout

*  Fix get servers from native-client

* 🚑 Fix error on change server

* [FIX] Don't run UserDefaults credentials on Android (#1015)

* 🐛 Fix native credentials (android)

* Fix migration loop

* [IMPROVEMENT] Hide frequently used emoji tab when empty (#792)

* [IMPROVEMENT] Bigger emoji in emoji only messages (#793)

* issue #725: bigger emoji in emoji only message

* issue-725/add storybook for Message/Emoji

* issue-725: update storybook/Message jest snapshot

* comment storybook import

* allow spaces and line breaks in emoji only message

* merge develop

* revert unnecessary spacing

* [FIX] Empty message if contains only a link (#787)

* Fix empty message if contains only a link

* 🐛 Fix empty space

* [IMPROVEMENT] Refactor empty space regex on quote (#1017)

* 🎨 Improve regex to empty space on quote

* 🎨 Improve on regex to empty space on quote

* [NEW] Custom fields on signup (#1013)

* added custom feilds on registration

* added flag as leftIcon and removed lable

* added try and catch

* typo

* [CHORE] Renew provisioning profiles (#1020)

* [NEW] Auto-translate (#1012)

* Update realm

* View original and translate working

* Read AutoTranslate_Enabled setting

* RocketChat.canAutoTranslate()

* AutoTranslateView

* Save language

* Auto-translate switch

* Translate message

* [IMPROVEMENT] Use haptics rather than vibration (#1016)

* Install expo-haptics

* Use expo-haptics rather than RN's Vibration module

* [IMPROVEMENT] Use Rest API for file upload (#1005)

* removed rn-fetch-blob and use native XMLHttpRequest instead

* removed unnessary changes

* fix android bug

* fix android bug

* added tmid support

* fix bug

* fixed isssue with cacel model

* fix problems with audio

* done requested changes

* fix bug with android

* [CHORE] [CI] [TESTS] update detox to make ci pass (#1026)

* feat: update detox to 12.11.3 to make CI pass

* ci: comment all jobs but leave e2e-test job

* commit to rerun IC e2e-test job

* ci: uncomment all CI jobs

* [NEW] Room swipe actions: mark as read/unread, hide, fav (#976)

* added unread and fav feature

* changed the layout

* fix jest

* done requested changes

* added requested changes

* [FIX] Android build (#1027)

* [FIX] Android build

* CircleCI error

* [FIX] iOS share credentials build (#1028)

* [FIX] iOS share credentials build

* Use `hasMigration` as a string

* [CI] Restore cache on CI (#1029)

* feat: add fastlane save\restore cache config; comment not needed jobs;

* install fastlane using 'bundle install'

* install fastlane using 'sudo bundle install'

* uncomment ios build commands

* run set up google services in ios folder

* add working_directory: ios to ios-build steps

* remove 'cd ios' from Fastlane build step

* add save\restore cache for npm modules

* group save_cache steps

* cache fastlane in ios-testflight job

* uncomment previously commented jobs\steps

* fix: add missing colon

* use key for caching: node-modules-{{ checksum ".circleci/config.yml" }}-{{ checksum "yarn.lock" }}

* add names for save\restore steps

* ci: add `default` step with `working_directory: ~/repo` to ios-build job

* return back caching npm: `node-v1-{{ checksum "package.json" }}-{{ arch }}`

* fix: add missing curly braces

* save\restore cache in e2e-test job; remove {{arch}} from cache names

* add names to restore_cache steps in android-build job

* add names to save_cache steps in android-build job

* add names to all save\restore steps; change checksum package.json to yarn.lock

* change `npm` to `NPM` in steps naming

* remove {{ checksum circle ci }} from android-build job and fix naming of steps

* [FIX] Rooms swipes (#1034)

* Regression: on press style feedback

* Action button styles

* Fix animations

* Styles changed

* Update subscription without having to wait for socket

* Calculate width on RoomsListView instead

* [FIX] Decrease bigger emoji size to 30 (#1031)

* [FIX] Append server URL on avatar if necessary (#1038)

* Comment removeClippedSubviews

* Comment width animation

* Remove redux from RoomItem

* Fix wrong re-render comparison

* Remove listener

* Raise minDeltaX

* memo actions

* Spring with native driver

* Refactor functions

* Fix props issues

* Remove RoomItem.height

* Long swipe

* Refactor animations

* this.rowTranslation -> this.transX

* Moved state to this

* Bump version to 1.16.1 (#1045)

* [FIX] Set UserDefaults AppGroup on notification tap (#1047)

* [FIX] Auto-translate messages as they arrive

* Fix favorite button
This commit is contained in:
Diego Mello 2019-07-15 14:24:48 -03:00 committed by GitHub
parent adaa977c65
commit 8ea6f1647e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
66 changed files with 6659 additions and 4315 deletions

View File

@ -15,7 +15,8 @@ jobs:
- checkout
- restore_cache:
key: node-modules-{{ checksum ".circleci/config.yml" }}-{{ checksum "yarn.lock" }}
name: Restore NPM cache
key: node-modules-{{ checksum "yarn.lock" }}
- run:
name: Install NPM modules
@ -38,7 +39,8 @@ jobs:
yarn codecov
- save_cache:
key: node-modules-{{ checksum ".circleci/config.yml" }}-{{ checksum "yarn.lock" }}
key: node-modules-{{ checksum "yarn.lock" }}
name: Save NPM cache
paths:
- ./node_modules
@ -52,6 +54,10 @@ jobs:
steps:
- checkout
- restore_cache:
name: Restore NPM cache
key: node-v1-mac-{{ checksum "yarn.lock" }}
- run:
name: Install Node 8
command: |
@ -84,6 +90,12 @@ jobs:
command: |
detox test --configuration ios.sim.release --cleanup
- save_cache:
name: Save NPM cache
key: node-v1-mac-{{ checksum "yarn.lock" }}
paths:
- node_modules
- store_artifacts:
path: /tmp/screenshots
@ -103,7 +115,8 @@ jobs:
- checkout
- restore_cache:
key: node-modules-{{ checksum ".circleci/config.yml" }}-{{ checksum "yarn.lock" }}
name: Restore NPM cache
key: node-modules-{{ checksum "yarn.lock" }}
- run:
name: Install NPM modules
@ -111,7 +124,8 @@ jobs:
yarn
- restore_cache:
key: android-{{ checksum ".circleci/config.yml" }}-{{ checksum "android/build.gradle" }}-{{ checksum "android/app/build.gradle" }}
name: Restore gradle cache
key: android-{{ checksum "android/build.gradle" }}-{{ checksum "android/app/build.gradle" }}
- run:
name: Configure Gradle
@ -155,12 +169,14 @@ jobs:
path: /tmp/build/outputs
- save_cache:
key: node-modules-{{ checksum ".circleci/config.yml" }}-{{ checksum "yarn.lock" }}
name: Save NPM cache
key: node-modules-{{ checksum "yarn.lock" }}
paths:
- ./node_modules
- save_cache:
key: android-{{ checksum ".circleci/config.yml" }}-{{ checksum "android/build.gradle" }}-{{ checksum "android/app/build.gradle" }}
name: Save gradle cache
key: android-{{ checksum "android/build.gradle" }}-{{ checksum "android/app/build.gradle" }}
paths:
- ~/.gradle
@ -174,6 +190,14 @@ jobs:
steps:
- checkout
- restore_cache:
name: Restore gems cache
key: bundle-v1-{{ checksum "ios/Gemfile.lock" }}
- restore_cache:
name: Restore NPM cache
key: node-v1-mac-{{ checksum "yarn.lock" }}
- run:
name: Install Node 8
command: |
@ -183,38 +207,49 @@ jobs:
set +e
nvm install 8
- run:
name: Update Fastlane
command: |
brew update
brew install ruby
sudo gem install fastlane
- run:
name: Install NPM modules
command: |
yarn
- run:
name: Update Fastlane
command: |
sudo bundle install
working_directory: ios
- run:
name: Set Google Services
command: |
cd ios
cp GoogleService-Info.prod.plist GoogleService-Info.plist
working_directory: ios
- run:
name: Fastlane Build
no_output_timeout: 1200
command: |
cd ios
agvtool new-version -all $CIRCLE_BUILD_NUM
if [[ $MATCH_KEYCHAIN_NAME ]]; then
fastlane ios release
bundle exec fastlane ios release
else
export MATCH_KEYCHAIN_NAME="temp"
export MATCH_KEYCHAIN_PASSWORD="temp"
fastlane ios build
bundle exec fastlane ios build
fi
working_directory: ios
- save_cache:
name: Save NPM cache
key: node-v1-mac-{{ checksum "yarn.lock" }}
paths:
- node_modules
- save_cache:
name: Save gems cache
key: bundle-v1-{{ checksum "ios/Gemfile.lock" }}
paths:
- vendor/bundle
- store_artifacts:
path: ios/RocketChatRN.ipa
@ -235,18 +270,27 @@ jobs:
- attach_workspace:
at: ios
- restore_cache:
name: Restore gems cache
key: bundle-v1-{{ checksum "ios/Gemfile.lock" }}
- run:
name: Update Fastlane
command: |
brew update
brew install ruby
sudo gem install fastlane
sudo bundle install
working_directory: ios
- run:
name: Fastlane Tesflight Upload
command: |
cd ios
fastlane pilot upload --ipa ios/RocketChatRN.ipa --changelog "$(sh ../.circleci/changelog.sh)"
bundle exec fastlane pilot upload --ipa ios/RocketChatRN.ipa --changelog "$(sh ../.circleci/changelog.sh)"
working_directory: ios
- save_cache:
name: Save gems cache
key: bundle-v1-{{ checksum "ios/Gemfile.lock" }}
paths:
- vendor/bundle
workflows:
version: 2

View File

@ -2,3 +2,4 @@ export const RectButton = () => 'View';
export const State = () => 'View';
export const LongPressGestureHandler = () => 'View';
export const BorderlessButton = () => 'View';
export const PanGestureHandler = () => 'View';

View File

@ -2780,7 +2780,7 @@ exports[`Storyshots Message list 1`] = `
"backgroundColor": "transparent",
"color": "#2F343D",
"fontFamily": "System",
"fontSize": 16,
"fontSize": 30,
"fontWeight": "400",
}
}
@ -2796,6 +2796,210 @@ exports[`Storyshots Message list 1`] = `
</View>
</View>
</View>
<Text
style={
Array [
Object {
"fontSize": 20,
"fontWeight": "300",
"marginLeft": 10,
"marginTop": 30,
},
Object {
"marginBottom": 0,
"marginTop": 30,
},
]
}
>
Single Emoji
</Text>
<View
accessible={true}
isTVSelectable={true}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
style={
Object {
"opacity": 1,
}
}
>
<View>
<View
style={
Array [
Object {
"flexDirection": "column",
"paddingHorizontal": 14,
"paddingVertical": 4,
"width": "100%",
},
undefined,
undefined,
]
}
>
<View
style={
Object {
"flexDirection": "row",
}
}
>
<View
style={
Array [
Object {
"borderRadius": 4,
"height": 36,
"width": 36,
},
Object {
"marginTop": 4,
},
]
}
>
<View
style={
Array [
Object {
"overflow": "hidden",
},
Object {
"borderRadius": 4,
"height": 36,
"width": 36,
},
]
}
>
<FastImageView
resizeMode="cover"
source={
Object {
"priority": "high",
"uri": "https://open.rocket.chat/avatar/diego.mello?format=png&width=50&height=50&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8",
}
}
style={
Object {
"bottom": 0,
"left": 0,
"position": "absolute",
"right": 0,
"top": 0,
}
}
/>
</View>
</View>
<View
style={
Array [
Object {
"flex": 1,
"marginLeft": 46,
},
Object {
"marginLeft": 10,
},
]
}
>
<View
style={
Object {
"alignItems": "center",
"flex": 1,
"flexDirection": "row",
}
}
>
<View
style={
Object {
"alignItems": "center",
"flex": 1,
"flexDirection": "row",
}
}
>
<Text
numberOfLines={1}
style={
Object {
"backgroundColor": "transparent",
"color": "#2F343D",
"fontFamily": "System",
"fontSize": 16,
"fontWeight": "500",
"lineHeight": 22,
}
}
>
diego.mello
</Text>
</View>
<Text
style={
Object {
"backgroundColor": "transparent",
"color": "#9ca2a8",
"fontFamily": "System",
"fontSize": 12,
"fontWeight": "300",
"lineHeight": 22,
"paddingLeft": 10,
}
}
>
10:00 AM
</Text>
</View>
<View
style={Object {}}
>
<Text
numberOfLines={0}
style={
Object {
"alignItems": "flex-start",
"flexDirection": "row",
"flexWrap": "wrap",
"justifyContent": "flex-start",
"marginBottom": 0,
"marginTop": 0,
}
}
>
<Text
style={
Object {
"backgroundColor": "transparent",
"color": "#2F343D",
"fontFamily": "System",
"fontSize": 30,
"fontWeight": "400",
}
}
>
<Text>
👏
</Text>
</Text>
</Text>
</View>
</View>
</View>
</View>
</View>
</View>
<Text
style={
Array [
@ -2984,7 +3188,7 @@ exports[`Storyshots Message list 1`] = `
"backgroundColor": "transparent",
"color": "#2F343D",
"fontFamily": "System",
"fontSize": 16,
"fontSize": 30,
"fontWeight": "400",
}
}
@ -2997,8 +3201,8 @@ exports[`Storyshots Message list 1`] = `
}
style={
Object {
"height": 20,
"width": 20,
"height": 30,
"width": 30,
}
}
/>
@ -3013,8 +3217,8 @@ exports[`Storyshots Message list 1`] = `
}
style={
Object {
"height": 20,
"width": 20,
"height": 30,
"width": 30,
}
}
/>
@ -3027,6 +3231,654 @@ exports[`Storyshots Message list 1`] = `
"uri": "https://open.rocket.chat/emoji-custom/marioparty.gif",
}
}
style={
Object {
"height": 30,
"width": 30,
}
}
/>
</Text>
</Text>
</View>
</View>
</View>
</View>
</View>
</View>
<Text
style={
Array [
Object {
"fontSize": 20,
"fontWeight": "300",
"marginLeft": 10,
"marginTop": 30,
},
Object {
"marginBottom": 0,
"marginTop": 30,
},
]
}
>
Single Custom Emojis
</Text>
<View
accessible={true}
isTVSelectable={true}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
style={
Object {
"opacity": 1,
}
}
>
<View>
<View
style={
Array [
Object {
"flexDirection": "column",
"paddingHorizontal": 14,
"paddingVertical": 4,
"width": "100%",
},
undefined,
undefined,
]
}
>
<View
style={
Object {
"flexDirection": "row",
}
}
>
<View
style={
Array [
Object {
"borderRadius": 4,
"height": 36,
"width": 36,
},
Object {
"marginTop": 4,
},
]
}
>
<View
style={
Array [
Object {
"overflow": "hidden",
},
Object {
"borderRadius": 4,
"height": 36,
"width": 36,
},
]
}
>
<FastImageView
resizeMode="cover"
source={
Object {
"priority": "high",
"uri": "https://open.rocket.chat/avatar/diego.mello?format=png&width=50&height=50&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8",
}
}
style={
Object {
"bottom": 0,
"left": 0,
"position": "absolute",
"right": 0,
"top": 0,
}
}
/>
</View>
</View>
<View
style={
Array [
Object {
"flex": 1,
"marginLeft": 46,
},
Object {
"marginLeft": 10,
},
]
}
>
<View
style={
Object {
"alignItems": "center",
"flex": 1,
"flexDirection": "row",
}
}
>
<View
style={
Object {
"alignItems": "center",
"flex": 1,
"flexDirection": "row",
}
}
>
<Text
numberOfLines={1}
style={
Object {
"backgroundColor": "transparent",
"color": "#2F343D",
"fontFamily": "System",
"fontSize": 16,
"fontWeight": "500",
"lineHeight": 22,
}
}
>
diego.mello
</Text>
</View>
<Text
style={
Object {
"backgroundColor": "transparent",
"color": "#9ca2a8",
"fontFamily": "System",
"fontSize": 12,
"fontWeight": "300",
"lineHeight": 22,
"paddingLeft": 10,
}
}
>
10:00 AM
</Text>
</View>
<View
style={Object {}}
>
<Text
numberOfLines={0}
style={
Object {
"alignItems": "flex-start",
"flexDirection": "row",
"flexWrap": "wrap",
"justifyContent": "flex-start",
"marginBottom": 0,
"marginTop": 0,
}
}
>
<Text
style={
Object {
"backgroundColor": "transparent",
"color": "#2F343D",
"fontFamily": "System",
"fontSize": 30,
"fontWeight": "400",
}
}
>
<Image
source={
Object {
"uri": "https://open.rocket.chat/emoji-custom/react_rocket.png",
}
}
style={
Object {
"height": 30,
"width": 30,
}
}
/>
</Text>
</Text>
</View>
</View>
</View>
</View>
</View>
</View>
<Text
style={
Array [
Object {
"fontSize": 20,
"fontWeight": "300",
"marginLeft": 10,
"marginTop": 30,
},
Object {
"marginBottom": 0,
"marginTop": 30,
},
]
}
>
Normal Emoji + Custom Emojis
</Text>
<View
accessible={true}
isTVSelectable={true}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
style={
Object {
"opacity": 1,
}
}
>
<View>
<View
style={
Array [
Object {
"flexDirection": "column",
"paddingHorizontal": 14,
"paddingVertical": 4,
"width": "100%",
},
undefined,
undefined,
]
}
>
<View
style={
Object {
"flexDirection": "row",
}
}
>
<View
style={
Array [
Object {
"borderRadius": 4,
"height": 36,
"width": 36,
},
Object {
"marginTop": 4,
},
]
}
>
<View
style={
Array [
Object {
"overflow": "hidden",
},
Object {
"borderRadius": 4,
"height": 36,
"width": 36,
},
]
}
>
<FastImageView
resizeMode="cover"
source={
Object {
"priority": "high",
"uri": "https://open.rocket.chat/avatar/diego.mello?format=png&width=50&height=50&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8",
}
}
style={
Object {
"bottom": 0,
"left": 0,
"position": "absolute",
"right": 0,
"top": 0,
}
}
/>
</View>
</View>
<View
style={
Array [
Object {
"flex": 1,
"marginLeft": 46,
},
Object {
"marginLeft": 10,
},
]
}
>
<View
style={
Object {
"alignItems": "center",
"flex": 1,
"flexDirection": "row",
}
}
>
<View
style={
Object {
"alignItems": "center",
"flex": 1,
"flexDirection": "row",
}
}
>
<Text
numberOfLines={1}
style={
Object {
"backgroundColor": "transparent",
"color": "#2F343D",
"fontFamily": "System",
"fontSize": 16,
"fontWeight": "500",
"lineHeight": 22,
}
}
>
diego.mello
</Text>
</View>
<Text
style={
Object {
"backgroundColor": "transparent",
"color": "#9ca2a8",
"fontFamily": "System",
"fontSize": 12,
"fontWeight": "300",
"lineHeight": 22,
"paddingLeft": 10,
}
}
>
10:00 AM
</Text>
</View>
<View
style={Object {}}
>
<Text
numberOfLines={0}
style={
Object {
"alignItems": "flex-start",
"flexDirection": "row",
"flexWrap": "wrap",
"justifyContent": "flex-start",
"marginBottom": 0,
"marginTop": 0,
}
}
>
<Text
style={
Object {
"backgroundColor": "transparent",
"color": "#2F343D",
"fontFamily": "System",
"fontSize": 30,
"fontWeight": "400",
}
}
>
<Text>
🤙
</Text>
<Image
source={
Object {
"uri": "https://open.rocket.chat/emoji-custom/react_rocket.png",
}
}
style={
Object {
"height": 30,
"width": 30,
}
}
/>
</Text>
</Text>
</View>
</View>
</View>
</View>
</View>
</View>
<Text
style={
Array [
Object {
"fontSize": 20,
"fontWeight": "300",
"marginLeft": 10,
"marginTop": 30,
},
Object {
"marginBottom": 0,
"marginTop": 30,
},
]
}
>
Four emoji
</Text>
<View
accessible={true}
isTVSelectable={true}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
style={
Object {
"opacity": 1,
}
}
>
<View>
<View
style={
Array [
Object {
"flexDirection": "column",
"paddingHorizontal": 14,
"paddingVertical": 4,
"width": "100%",
},
undefined,
undefined,
]
}
>
<View
style={
Object {
"flexDirection": "row",
}
}
>
<View
style={
Array [
Object {
"borderRadius": 4,
"height": 36,
"width": 36,
},
Object {
"marginTop": 4,
},
]
}
>
<View
style={
Array [
Object {
"overflow": "hidden",
},
Object {
"borderRadius": 4,
"height": 36,
"width": 36,
},
]
}
>
<FastImageView
resizeMode="cover"
source={
Object {
"priority": "high",
"uri": "https://open.rocket.chat/avatar/diego.mello?format=png&width=50&height=50&rc_token=79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz&rc_uid=y8bd77ptZswPj3EW8",
}
}
style={
Object {
"bottom": 0,
"left": 0,
"position": "absolute",
"right": 0,
"top": 0,
}
}
/>
</View>
</View>
<View
style={
Array [
Object {
"flex": 1,
"marginLeft": 46,
},
Object {
"marginLeft": 10,
},
]
}
>
<View
style={
Object {
"alignItems": "center",
"flex": 1,
"flexDirection": "row",
}
}
>
<View
style={
Object {
"alignItems": "center",
"flex": 1,
"flexDirection": "row",
}
}
>
<Text
numberOfLines={1}
style={
Object {
"backgroundColor": "transparent",
"color": "#2F343D",
"fontFamily": "System",
"fontSize": 16,
"fontWeight": "500",
"lineHeight": 22,
}
}
>
diego.mello
</Text>
</View>
<Text
style={
Object {
"backgroundColor": "transparent",
"color": "#9ca2a8",
"fontFamily": "System",
"fontSize": 12,
"fontWeight": "300",
"lineHeight": 22,
"paddingLeft": 10,
}
}
>
10:00 AM
</Text>
</View>
<View
style={Object {}}
>
<Text
numberOfLines={0}
style={
Object {
"alignItems": "flex-start",
"flexDirection": "row",
"flexWrap": "wrap",
"justifyContent": "flex-start",
"marginBottom": 0,
"marginTop": 0,
}
}
>
<Text
style={
Object {
"backgroundColor": "transparent",
"color": "#2F343D",
"fontFamily": "System",
"fontSize": 16,
"fontWeight": "400",
}
}
>
<Text>
🤙
</Text>
<Image
source={
Object {
"uri": "https://open.rocket.chat/emoji-custom/react_rocket.png",
}
}
style={
Object {
"height": 20,
@ -3034,6 +3886,9 @@ exports[`Storyshots Message list 1`] = `
}
}
/>
<Text>
🤙🤙
</Text>
</Text>
</Text>
</View>

View File

@ -110,7 +110,7 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode VERSIONCODE as Integer
versionName "1.15.1"
versionName "1.16.1"
vectorDrawables.useSupportLibrary = true
}
@ -190,7 +190,6 @@ dependencies {
implementation project(":reactnativekeyboardinput")
implementation project(':react-native-video')
implementation project(':react-native-vector-icons')
implementation project(':rn-fetch-blob')
implementation project(':react-native-fast-image')
implementation project(':realm')
implementation project(':reactnativenotifications')

View File

@ -17,7 +17,6 @@ import com.facebook.soloader.SoLoader;
import com.AlexanderZaytsev.RNI18n.RNI18nPackage;
import com.reactnative.ivpusic.imagepicker.PickerPackage;
import com.RNFetchBlob.RNFetchBlobPackage;
import com.brentvatne.react.ReactVideoPackage;
import com.dylanvann.fastimage.FastImageViewPackage;
import com.oblador.vectoricons.VectorIconsPackage;
@ -74,7 +73,6 @@ public class MainApplication extends Application implements ReactApplication, IN
new RNDeviceInfo(),
new PickerPackage(),
new VectorIconsPackage(),
new RNFetchBlobPackage(),
new RealmReactPackage(),
new ReactVideoPackage(),
new ReactNativeAudioPackage(),

View File

@ -9,6 +9,7 @@ public class BasePackageList {
return Arrays.<Package>asList(
new expo.modules.constants.ConstantsPackage(),
new expo.modules.filesystem.FileSystemPackage(),
new expo.modules.haptics.HapticsPackage(),
new expo.modules.permissions.PermissionsPackage(),
new expo.modules.webbrowser.WebBrowserPackage()
);

View File

@ -18,8 +18,6 @@ include ':react-native-device-info'
project(':react-native-device-info').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-device-info/android')
include ':react-native-gesture-handler'
project(':react-native-gesture-handler').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-gesture-handler/android')
include ':rn-fetch-blob'
project(':rn-fetch-blob').projectDir = new File(rootProject.projectDir, '../node_modules/rn-fetch-blob/android')
include ':react-native-image-crop-picker'
project(':react-native-image-crop-picker').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-image-crop-picker/android')
include ':react-native-i18n'

View File

@ -1,4 +1,4 @@
import { isIOS } from '../utils/deviceInfo';
import { isIOS, isAndroid } from '../utils/deviceInfo';
export const COLOR_DANGER = '#f5455c';
export const COLOR_SUCCESS = '#2de0a5';
@ -25,3 +25,8 @@ export const HEADER_BACKGROUND = isIOS ? '#f8f8f8' : '#2F343D';
export const HEADER_TITLE = isIOS ? COLOR_TITLE : COLOR_WHITE;
export const HEADER_BACK = isIOS ? COLOR_PRIMARY : COLOR_WHITE;
export const HEADER_TINT = isIOS ? COLOR_PRIMARY : COLOR_WHITE;
export const SWITCH_TRACK_COLOR = {
false: isAndroid ? COLOR_DANGER : null,
true: COLOR_SUCCESS
};

View File

@ -70,5 +70,8 @@ export default {
},
API_Gitlab_URL: {
type: 'valueAsString'
},
AutoTranslate_Enabled: {
type: 'valueAsBoolean'
}
};

View File

@ -0,0 +1,6 @@
export const SERVERS = 'kServers';
export const TOKEN = 'kAuthToken';
export const USER_ID = 'kUserId';
export const SERVER_URL = 'kAuthServerURL';
export const SERVER_NAME = 'kServerName';
export const SERVER_ICON = 'kServerIconURL';

View File

@ -3,6 +3,10 @@ import PropTypes from 'prop-types';
import { View } from 'react-native';
import FastImage from 'react-native-fast-image';
const formatUrl = (url, baseUrl, uriSize, avatarAuthURLFragment) => (
`${ baseUrl }${ url }?format=png&width=${ uriSize }&height=${ uriSize }${ avatarAuthURLFragment }`
);
const Avatar = React.memo(({
text, size, baseUrl, borderRadius, style, avatar, type, children, userId, token
}) => {
@ -26,7 +30,14 @@ const Avatar = React.memo(({
avatarAuthURLFragment = `&rc_token=${ token }&rc_uid=${ userId }`;
}
const uri = avatar || `${ baseUrl }/avatar/${ room }?format=png&width=${ uriSize }&height=${ uriSize }${ avatarAuthURLFragment }`;
let uri;
if (avatar) {
uri = avatar.includes('http') ? avatar : formatUrl(avatar, baseUrl, uriSize, avatarAuthURLFragment);
} else {
uri = formatUrl(`/avatar/${ room }`, baseUrl, uriSize, avatarAuthURLFragment);
}
const image = (
<FastImage

View File

@ -141,7 +141,7 @@ export default class EmojiPicker extends Component {
}
render() {
const { show } = this.state;
const { show, frequentlyUsed } = this.state;
const { tabEmojiStyle } = this.props;
if (!show) {
@ -155,15 +155,17 @@ export default class EmojiPicker extends Component {
>
{
categories.tabs.map((tab, i) => (
<ScrollView
key={tab.category}
tabLabel={tab.tabLabel}
style={styles.background}
{...scrollProps}
>
{this.renderCategory(tab.category, i)}
</ScrollView>
))
(i === 0 && frequentlyUsed.length === 0) ? null // when no frequentlyUsed don't show the tab
: (
<ScrollView
key={tab.category}
tabLabel={tab.tabLabel}
style={styles.background}
{...scrollProps}
>
{this.renderCategory(tab.category, i)}
</ScrollView>
)))
}
</ScrollableTabView>
);

View File

@ -4,6 +4,8 @@ import { Alert, Clipboard, Share } from 'react-native';
import { connect } from 'react-redux';
import ActionSheet from 'react-native-action-sheet';
import moment from 'moment';
import * as Haptics from 'expo-haptics';
import {
actionsHide as actionsHideAction,
deleteRequest as deleteRequestAction,
@ -13,11 +15,12 @@ import {
toggleReactionPicker as toggleReactionPickerAction,
toggleStarRequest as toggleStarRequestAction
} from '../actions/messages';
import { vibrate } from '../utils/vibration';
import RocketChat from '../lib/rocketchat';
import database from '../lib/realm';
import I18n from '../i18n';
import log from '../utils/log';
import Navigation from '../lib/Navigation';
import { getMessageTranslation } from './message/utils';
@connect(
state => ({
@ -46,7 +49,7 @@ export default class MessageActions extends React.Component {
room: PropTypes.object.isRequired,
actionMessage: PropTypes.object,
toast: PropTypes.element,
// user: PropTypes.object.isRequired,
user: PropTypes.object,
deleteRequest: PropTypes.func.isRequired,
editInit: PropTypes.func.isRequired,
toggleStarRequest: PropTypes.func.isRequired,
@ -127,6 +130,12 @@ export default class MessageActions extends React.Component {
this.READ_RECEIPT_INDEX = this.options.length - 1;
}
// Toggle Auto-translate
if (props.room.autoTranslate && props.actionMessage.u && props.actionMessage.u._id !== props.user.id) {
this.options.push(I18n.t(props.actionMessage.autoTranslate ? 'View_Original' : 'Translate'));
this.TOGGLE_TRANSLATION_INDEX = this.options.length - 1;
}
// Report
this.options.push(I18n.t('Report'));
this.REPORT_INDEX = this.options.length - 1;
@ -138,7 +147,7 @@ export default class MessageActions extends React.Component {
}
setTimeout(() => {
this.showActionSheet();
vibrate();
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
});
}
@ -326,6 +335,23 @@ export default class MessageActions extends React.Component {
}
}
handleToggleTranslation = async() => {
const { actionMessage, room } = this.props;
try {
const message = database.objectForPrimaryKey('messages', actionMessage._id);
database.write(() => {
message.autoTranslate = !message.autoTranslate;
message._updatedAt = new Date();
});
const translatedMessage = getMessageTranslation(message, room.autoTranslateLanguage);
if (!translatedMessage) {
await RocketChat.translateMessage(actionMessage, room.autoTranslateLanguage);
}
} catch (err) {
log('err_toggle_translation', err);
}
}
handleActionPress = (actionIndex) => {
if (actionIndex) {
switch (actionIndex) {
@ -365,6 +391,9 @@ export default class MessageActions extends React.Component {
case this.READ_RECEIPT_INDEX:
this.handleReadReceipt();
break;
case this.TOGGLE_TRANSLATION_INDEX:
this.handleToggleTranslation();
break;
default:
break;
}

View File

@ -44,13 +44,14 @@ export default class extends React.PureComponent {
this.recordingCanceled = false;
this.recording = true;
this.name = `${ Date.now() }.aac`;
this.state = {
currentTime: '00:00'
};
}
componentDidMount() {
const audioPath = `${ AudioUtils.CachesDirectoryPath }/${ Date.now() }.aac`;
const audioPath = `${ AudioUtils.CachesDirectoryPath }/${ this.name }`;
AudioRecorder.prepareRecordingAtPath(audioPath, {
SampleRate: 22050,
@ -84,12 +85,14 @@ export default class extends React.PureComponent {
if (!didSucceed) {
return onFinish && onFinish(didSucceed);
}
const path = filePath.startsWith('file://') ? filePath.split('file://')[1] : filePath;
if (isAndroid) {
filePath = filePath.startsWith('file://') ? filePath : `file://${ filePath }`;
}
const fileInfo = {
name: this.name,
type: 'audio/aac',
store: 'Uploads',
path
path: filePath
};
return onFinish && onFinish(fileInfo);
}

View File

@ -20,6 +20,33 @@ const formatText = text => text.replace(
(match, url, title) => `[${ title }](${ url })`
);
const emojiRanges = [
'\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff]', // unicode emoji from https://www.regextester.com/106421
':.{1,40}:', // custom emoji
' |\n' // allow spaces and line breaks
].join('|');
const removeAllEmoji = str => str.replace(new RegExp(emojiRanges, 'g'), '');
const isOnlyEmoji = str => !removeAllEmoji(str).length;
const removeOneEmoji = str => str.replace(new RegExp(emojiRanges), '');
const emojiCount = (str) => {
let oldLength = 0;
let counter = 0;
while (oldLength !== str.length) {
oldLength = str.length;
str = removeOneEmoji(str);
if (oldLength !== str.length) {
counter += 1;
}
}
return counter;
};
const Markdown = React.memo(({
msg, style, rules, baseUrl, username, isEdited, numberOfLines, mentions, channels, getCustomEmoji, useMarkdown = true
}) => {
@ -30,7 +57,7 @@ const Markdown = React.memo(({
if (m) {
m = emojify(m, { output: 'unicode' });
}
m = m.replace(/^\[([^\]]*)\]\(([^)]*)\)/, '').trim();
m = m.replace(/^\[([^\]]*)\]\(([^)]*)\)\s/, '').trim();
if (numberOfLines > 0) {
m = m.replace(/[\n]+/g, '\n').trim();
}
@ -39,6 +66,8 @@ const Markdown = React.memo(({
return <Text style={styles.text} numberOfLines={numberOfLines}>{m}</Text>;
}
const isMessageContainsOnlyEmoji = isOnlyEmoji(m) && emojiCount(m) <= 3;
return (
<MarkdownRenderer
rules={{
@ -87,7 +116,14 @@ const Markdown = React.memo(({
const { content } = node.children[0];
const emoji = getCustomEmoji && getCustomEmoji(content);
if (emoji) {
return <CustomEmoji key={node.key} baseUrl={baseUrl} style={styles.customEmoji} emoji={emoji} />;
return (
<CustomEmoji
key={node.key}
baseUrl={baseUrl}
style={isMessageContainsOnlyEmoji ? styles.customEmojiBig : styles.customEmoji}
emoji={emoji}
/>
);
}
return <Text key={node.key}>:{content}:</Text>;
}
@ -102,7 +138,7 @@ const Markdown = React.memo(({
}}
style={{
paragraph: styles.paragraph,
text: styles.text,
text: isMessageContainsOnlyEmoji ? styles.textBig : styles.text,
codeInline: styles.codeInline,
codeBlock: styles.codeBlock,
link: styles.link,

View File

@ -4,7 +4,7 @@ import { KeyboardUtils } from 'react-native-keyboard-input';
import Message from './Message';
import debounce from '../../utils/debounce';
import { SYSTEM_MESSAGES, getCustomEmoji } from './utils';
import { SYSTEM_MESSAGES, getCustomEmoji, getMessageTranslation } from './utils';
import messagesStatus from '../../constants/messagesStatus';
export default class MessageContainer extends React.Component {
@ -27,6 +27,8 @@ export default class MessageContainer extends React.Component {
isReadReceiptEnabled: PropTypes.bool,
useRealName: PropTypes.bool,
useMarkdown: PropTypes.bool,
autoTranslateRoom: PropTypes.bool,
autoTranslateLanguage: PropTypes.string,
status: PropTypes.number,
onLongPress: PropTypes.func,
onReactionPress: PropTypes.func,
@ -49,12 +51,15 @@ export default class MessageContainer extends React.Component {
shouldComponentUpdate(nextProps) {
const {
status, item, _updatedAt
status, item, _updatedAt, autoTranslateRoom
} = this.props;
if (status !== nextProps.status) {
return true;
}
if (autoTranslateRoom !== nextProps.autoTranslateRoom) {
return true;
}
if (item.tmsg !== nextProps.item.tmsg) {
return true;
}
@ -191,16 +196,23 @@ export default class MessageContainer extends React.Component {
render() {
const {
item, user, style, archived, baseUrl, useRealName, broadcast, fetchThreadName, customThreadTimeFormat, onOpenFileModal, timeFormat, useMarkdown, isReadReceiptEnabled
item, user, style, archived, baseUrl, useRealName, broadcast, fetchThreadName, customThreadTimeFormat, onOpenFileModal, timeFormat, useMarkdown, isReadReceiptEnabled, autoTranslateRoom, autoTranslateLanguage
} = this.props;
const {
_id, msg, ts, attachments, urls, reactions, t, avatar, u, alias, editedBy, role, drid, dcount, dlm, tmid, tcount, tlm, tmsg, mentions, channels, unread
_id, msg, ts, attachments, urls, reactions, t, avatar, u, alias, editedBy, role, drid, dcount, dlm, tmid, tcount, tlm, tmsg, mentions, channels, unread, autoTranslate: autoTranslateMessage
} = item;
let message = msg;
// "autoTranslateRoom" and "autoTranslateLanguage" are properties from the subscription
// "autoTranslateMessage" is a toggle between "View Original" and "Translate" state
if (autoTranslateRoom && autoTranslateMessage) {
message = getMessageTranslation(item, autoTranslateLanguage) || message;
}
return (
<Message
id={_id}
msg={msg}
msg={message}
author={u}
ts={ts}
type={t}

View File

@ -39,6 +39,11 @@ export default StyleSheet.create({
...sharedStyles.textColorNormal,
...sharedStyles.textRegular
},
textBig: {
fontSize: 30,
...sharedStyles.textColorNormal,
...sharedStyles.textRegular
},
textInfo: {
fontStyle: 'italic',
fontSize: 16,
@ -49,6 +54,10 @@ export default StyleSheet.create({
width: 20,
height: 20
},
customEmojiBig: {
width: 30,
height: 30
},
temp: { opacity: 0.3 },
marginTop: {
marginTop: 6

View File

@ -114,3 +114,15 @@ export const getCustomEmoji = (content) => {
});
return findByAlias;
};
export const getMessageTranslation = (message, autoTranslateLanguage) => {
if (!autoTranslateLanguage) {
return null;
}
const { translations } = message;
if (translations) {
const translation = translations.find(trans => trans.language === autoTranslateLanguage);
return translation && translation.value;
}
return null;
};

View File

@ -99,6 +99,7 @@ export default {
Are_you_sure_question_mark: 'Are you sure?',
Are_you_sure_you_want_to_leave_the_room: 'Are you sure you want to leave the room {{room}}?',
Authenticating: 'Authenticating',
Auto_Translate: 'Auto-Translate',
Avatar_changed_successfully: 'Avatar changed successfully!',
Avatar_Url: 'Avatar URL',
Away: 'Away',
@ -155,11 +156,13 @@ export default {
Email_or_password_field_is_empty: 'Email or password field is empty',
Email: 'Email',
email: 'e-mail',
Enable_Auto_Translate: 'Enable Auto-Translate',
Enable_markdown: 'Enable markdown',
Enable_notifications: 'Enable notifications',
Everyone_can_access_this_channel: 'Everyone can access this channel',
erasing_room: 'erasing room',
Error_uploading: 'Error uploading',
Favorite: 'Favorite',
Favorites: 'Favorites',
Files: 'Files',
File_description: 'File description',
@ -173,6 +176,7 @@ export default {
Forgot_Password: 'Forgot Password',
Group_by_favorites: 'Group favorites',
Group_by_type: 'Group by type',
Hide: 'Hide',
Has_joined_the_channel: 'Has joined the channel',
Has_joined_the_conversation: 'Has joined the conversation',
Has_left_the_channel: 'Has left the channel',
@ -266,6 +270,7 @@ export default {
Reactions_are_disabled: 'Reactions are disabled',
Reactions_are_enabled: 'Reactions are enabled',
Reactions: 'Reactions',
Read: 'Read',
Read_Only_Channel: 'Read Only Channel',
Read_Only: 'Read Only',
Read_Receipt: 'Read Receipt',
@ -343,12 +348,14 @@ export default {
Timezone: 'Timezone',
topic: 'topic',
Topic: 'Topic',
Translate: 'Translate',
Try_again: 'Try again',
Two_Factor_Authentication: 'Two-factor Authentication',
Type_the_channel_name_here: 'Type the channel name here',
unarchive: 'unarchive',
UNARCHIVE: 'UNARCHIVE',
Unblock_user: 'Unblock user',
Unfavorite: 'Unfavorite',
Unfollowed_thread: 'Unfollowed thread',
Unmute: 'Unmute',
unmuted: 'unmuted',
@ -374,6 +381,7 @@ export default {
Username_or_email: 'Username or email',
Validating: 'Validating',
Video_call: 'Video call',
View_Original: 'View Original',
Voice_call: 'Voice call',
Welcome: 'Welcome',
Welcome_to_RocketChat: 'Welcome to Rocket.Chat',

View File

@ -33,6 +33,7 @@ import SearchMessagesView from './views/SearchMessagesView';
import ReadReceiptsView from './views/ReadReceiptView';
import ThreadMessagesView from './views/ThreadMessagesView';
import MessagesView from './views/MessagesView';
import AutoTranslateView from './views/AutoTranslateView';
import SelectedUsersView from './views/SelectedUsersView';
import CreateChannelView from './views/CreateChannelView';
import LegalView from './views/LegalView';
@ -116,6 +117,7 @@ const ChatsStack = createStackNavigator({
SelectedUsersView,
ThreadMessagesView,
MessagesView,
AutoTranslateView,
ReadReceiptsView,
DirectoryView
}, {

View File

@ -36,6 +36,10 @@ export default (msg) => {
if (!Array.isArray(msg.reactions)) {
msg.reactions = Object.keys(msg.reactions).map(key => ({ _id: `${ msg._id }${ key }`, emoji: key, usernames: msg.reactions[key].usernames }));
}
if (msg.translations && Object.keys(msg.translations).length) {
msg.translations = Object.keys(msg.translations).map(key => ({ _id: `${ msg._id }${ key }`, language: key, value: msg.translations[key] }));
msg.autoTranslate = true;
}
msg.urls = msg.urls ? parseUrls(msg.urls) : [];
msg._updatedAt = new Date();
// loadHistory returns msg.starred as object

View File

@ -1,111 +1,129 @@
import RNFetchBlob from 'rn-fetch-blob';
import reduxStore from '../createStore';
import database from '../realm';
import log from '../../utils/log';
const promises = {};
function _ufsCreate(fileInfo) {
return this.sdk.methodCall('ufsCreate', fileInfo);
}
function _ufsComplete(fileId, store, token) {
return this.sdk.methodCall('ufsComplete', fileId, store, token);
}
function _sendFileMessage(rid, data, msg = {}) {
// RC 0.22.0
return this.sdk.methodCall('sendFileMessage', rid, null, data, msg);
}
const uploadQueue = {};
export function isUploadActive(path) {
return !!promises[path];
return !!uploadQueue[path];
}
export async function cancelUpload(path) {
if (promises[path]) {
await promises[path].cancel();
}
}
export async function sendFileMessage(rid, fileInfo, tmid) {
try {
const data = await RNFetchBlob.wrap(fileInfo.path);
if (!fileInfo.size) {
const fileStat = await RNFetchBlob.fs.stat(fileInfo.path);
fileInfo.size = fileStat.size;
fileInfo.name = fileStat.filename;
}
const { FileUpload_MaxFileSize } = reduxStore.getState().settings;
// -1 maxFileSize means there is no limit
if (FileUpload_MaxFileSize > -1 && fileInfo.size > FileUpload_MaxFileSize) {
return Promise.reject({ error: 'error-file-too-large' }); // eslint-disable-line
}
fileInfo.rid = rid;
export function cancelUpload(path) {
if (uploadQueue[path]) {
uploadQueue[path].abort();
database.write(() => {
try {
database.create('uploads', fileInfo, true);
} catch (e) {
return log('err_send_file_message_create_upload_1', e);
}
});
const result = await _ufsCreate.call(this, fileInfo);
promises[fileInfo.path] = RNFetchBlob.fetch('POST', result.url, {
'Content-Type': 'octet-stream'
}, data);
// Workaround for https://github.com/joltup/rn-fetch-blob/issues/96
setTimeout(() => {
if (promises[fileInfo.path] && promises[fileInfo.path].uploadProgress) {
promises[fileInfo.path].uploadProgress((loaded, total) => {
database.write(() => {
fileInfo.progress = Math.floor((loaded / total) * 100);
try {
database.create('uploads', fileInfo, true);
} catch (e) {
return log('err_send_file_message_create_upload_2', e);
}
});
});
}
});
await promises[fileInfo.path];
const completeResult = await _ufsComplete.call(this, result.fileId, fileInfo.store, result.token);
await _sendFileMessage.call(this, completeResult.rid, {
_id: completeResult._id,
type: completeResult.type,
size: completeResult.size,
name: completeResult.name,
description: completeResult.description,
url: completeResult.path
}, {
tmid
});
database.write(() => {
const upload = database.objects('uploads').filtered('path = $0', fileInfo.path);
const upload = database.objects('uploads').filtered('path = $0', path);
try {
database.delete(upload);
} catch (e) {
log('err_send_file_message_delete_upload', e);
}
});
} catch (e) {
database.write(() => {
fileInfo.error = true;
try {
database.create('uploads', fileInfo, true);
} catch (err) {
log('err_send_file_message_create_upload_3', err);
}
});
delete uploadQueue[path];
}
}
export function sendFileMessage(rid, fileInfo, tmid) {
return new Promise((resolve, reject) => {
try {
const { FileUpload_MaxFileSize, Site_Url } = reduxStore.getState().settings;
const { id, token } = reduxStore.getState().login.user;
// -1 maxFileSize means there is no limit
if (FileUpload_MaxFileSize > -1 && fileInfo.size > FileUpload_MaxFileSize) {
return reject({ error: 'error-file-too-large' }); // eslint-disable-line
}
const uploadUrl = `${ Site_Url }/api/v1/rooms.upload/${ rid }`;
const xhr = new XMLHttpRequest();
const formData = new FormData();
fileInfo.rid = rid;
database.write(() => {
try {
database.create('uploads', fileInfo, true);
} catch (e) {
return log('err_send_file_message_create_upload_1', e);
}
});
uploadQueue[fileInfo.path] = xhr;
xhr.open('POST', uploadUrl);
formData.append('file', {
uri: fileInfo.path,
type: fileInfo.type,
name: fileInfo.name || 'fileMessage'
});
if (fileInfo.description) {
formData.append('description', fileInfo.description);
}
if (tmid) {
formData.append('tmid', tmid);
}
xhr.setRequestHeader('X-Auth-Token', token);
xhr.setRequestHeader('X-User-Id', id);
xhr.upload.onprogress = ({ total, loaded }) => {
database.write(() => {
fileInfo.progress = Math.floor((loaded / total) * 100);
try {
database.create('uploads', fileInfo, true);
} catch (e) {
return log('err_send_file_message_create_upload_2', e);
}
});
};
xhr.onload = () => {
if (xhr.status >= 200 && xhr.status < 400) { // If response is all good...
database.write(() => {
const upload = database.objects('uploads').filtered('path = $0', fileInfo.path);
try {
database.delete(upload);
const response = JSON.parse(xhr.response);
resolve(response);
} catch (e) {
reject(e);
log('err_send_file_message_delete_upload', e);
}
});
} else {
database.write(() => {
fileInfo.error = true;
try {
database.create('uploads', fileInfo, true);
const response = JSON.parse(xhr.response);
reject(response);
} catch (err) {
reject(err);
log('err_send_file_message_create_upload_3', err);
}
});
}
};
xhr.onerror = (e) => {
database.write(() => {
fileInfo.error = true;
try {
database.create('uploads', fileInfo, true);
reject(e);
} catch (err) {
reject(err);
log('err_send_file_message_create_upload_3', err);
}
});
};
xhr.send(formData);
} catch (err) {
log('err_send_file_message_create_upload_4', err);
}
});
}

View File

@ -4,6 +4,20 @@ import Realm from 'realm';
// Realm.clearTestState();
// AsyncStorage.clear();
const userSchema = {
name: 'user',
primaryKey: 'id',
properties: {
id: 'string',
token: { type: 'string', optional: true },
username: { type: 'string', optional: true },
name: { type: 'string', optional: true },
language: { type: 'string', optional: true },
status: { type: 'string', optional: true },
roles: { type: 'string[]', optional: true }
}
};
const serversSchema = {
name: 'servers',
primaryKey: 'id',
@ -82,7 +96,9 @@ const subscriptionSchema = {
broadcast: { type: 'bool', optional: true },
prid: { type: 'string', optional: true },
draftMessage: { type: 'string', optional: true },
lastThreadSync: 'date?'
lastThreadSync: 'date?',
autoTranslate: 'bool?',
autoTranslateLanguage: 'string?'
}
};
@ -157,6 +173,16 @@ const messagesReactionsSchema = {
}
};
const messagesTranslationsSchema = {
name: 'messagesTranslations',
primaryKey: '_id',
properties: {
_id: 'string',
language: 'string',
value: 'string'
}
};
const messagesEditedBySchema = {
name: 'messagesEditedBy',
primaryKey: '_id',
@ -198,7 +224,9 @@ const messagesSchema = {
replies: 'string[]',
mentions: { type: 'list', objectType: 'users' },
channels: { type: 'list', objectType: 'rooms' },
unread: { type: 'bool', optional: true }
unread: { type: 'bool', optional: true },
autoTranslate: { type: 'bool', default: false },
translations: { type: 'list', objectType: 'messagesTranslations' }
}
};
@ -232,6 +260,11 @@ const threadsSchema = {
tcount: { type: 'int', optional: true },
tlm: { type: 'date', optional: true },
replies: 'string[]',
mentions: { type: 'list', objectType: 'users' },
channels: { type: 'list', objectType: 'rooms' },
unread: { type: 'bool', optional: true },
autoTranslate: { type: 'bool', default: false },
translations: { type: 'list', objectType: 'messagesTranslations' },
draftMessage: 'string?'
}
};
@ -258,7 +291,13 @@ const threadMessagesSchema = {
starred: { type: 'bool', optional: true },
editedBy: 'messagesEditedBy',
reactions: { type: 'list', objectType: 'messagesReactions' },
role: { type: 'string', optional: true }
role: { type: 'string', optional: true },
replies: 'string[]',
mentions: { type: 'list', objectType: 'users' },
channels: { type: 'list', objectType: 'rooms' },
unread: { type: 'bool', optional: true },
autoTranslate: { type: 'bool', default: false },
translations: { type: 'list', objectType: 'messagesTranslations' }
}
};
@ -360,7 +399,8 @@ const schema = [
messagesReactionsSchema,
rolesSchema,
uploadsSchema,
slashCommandSchema
slashCommandSchema,
messagesTranslationsSchema
];
const inMemorySchema = [usersTypingSchema, activeUsersSchema];
@ -370,11 +410,12 @@ class DB {
serversDB: new Realm({
path: 'default.realm',
schema: [
userSchema,
serversSchema
],
schemaVersion: 8,
schemaVersion: 9,
migration: (oldRealm, newRealm) => {
if (oldRealm.schemaVersion >= 1 && newRealm.schemaVersion <= 8) {
if (oldRealm.schemaVersion >= 1 && newRealm.schemaVersion <= 9) {
const newServers = newRealm.objects('servers');
// eslint-disable-next-line no-plusplus
@ -429,9 +470,9 @@ class DB {
return this.databases.activeDB = new Realm({
path: `${ path }.realm`,
schema,
schemaVersion: 12,
schemaVersion: 13,
migration: (oldRealm, newRealm) => {
if (oldRealm.schemaVersion >= 3 && newRealm.schemaVersion <= 11) {
if (oldRealm.schemaVersion >= 3 && newRealm.schemaVersion <= 13) {
const newSubs = newRealm.objects('subscriptions');
newRealm.delete(newSubs);
const newMessages = newRealm.objects('messages');

View File

@ -1,6 +1,7 @@
import { AsyncStorage, InteractionManager } from 'react-native';
import semver from 'semver';
import { Rocketchat as RocketchatClient } from '@rocket.chat/sdk';
import RNUserDefaults from 'rn-user-defaults';
import reduxStore from './createStore';
import defaultSettings from '../constants/settings';
@ -36,6 +37,7 @@ import sendMessage, { getMessage, sendMessageCall } from './methods/sendMessage'
import { sendFileMessage, cancelUpload, isUploadActive } from './methods/sendFileMessage';
import { getDeviceToken } from '../notifications/push';
import { SERVERS, SERVER_URL } from '../constants/userDefaults';
const TOKEN_KEY = 'reactnativemeteor_usertoken';
const SORT_PREFS_KEY = 'RC_SORT_PREFS_KEY';
@ -58,9 +60,9 @@ const RocketChat = {
},
async getUserToken() {
try {
return await AsyncStorage.getItem(TOKEN_KEY);
return await RNUserDefaults.get(TOKEN_KEY);
} catch (error) {
console.warn(`AsyncStorage error: ${ error.message }`);
console.warn(`RNUserDefaults error: ${ error.message }`);
}
},
async getServerInfo(server) {
@ -321,10 +323,26 @@ const RocketChat = {
}
this.sdk = null;
try {
const servers = await RNUserDefaults.objectForKey(SERVERS);
await RNUserDefaults.setObjectForKey(SERVERS, servers && servers.filter(srv => srv[SERVER_URL] !== server));
} catch (error) {
console.log('logout_rn_user_defaults', error);
}
const { serversDB } = database.databases;
const userId = await RNUserDefaults.get(`${ TOKEN_KEY }-${ server }`);
serversDB.write(() => {
const user = serversDB.objectForPrimaryKey('user', userId);
serversDB.delete(user);
});
Promise.all([
AsyncStorage.removeItem('currentServer'),
AsyncStorage.removeItem(TOKEN_KEY),
AsyncStorage.removeItem(`${ TOKEN_KEY }-${ server }`)
RNUserDefaults.clear('currentServer'),
RNUserDefaults.clear(TOKEN_KEY),
RNUserDefaults.clear(`${ TOKEN_KEY }-${ server }`)
]).catch(error => console.log(error));
try {
@ -564,6 +582,12 @@ const RocketChat = {
// RC 0.64.0
return this.sdk.post('rooms.favorite', { roomId, favorite });
},
toggleRead(read, roomId) {
if (read) {
return this.sdk.post('subscriptions.unread', { roomId });
}
return this.sdk.post('subscriptions.read', { rid: roomId });
},
getRoomMembers(rid, allUsers, skip = 0, limit = 10) {
// RC 0.42.0
return this.sdk.methodCall('getUsersOfRoom', rid, allUsers, { skip, limit });
@ -622,6 +646,9 @@ const RocketChat = {
// RC 0.48.0
return this.sdk.post(`${ this.roomTypeToApiType(t) }.unarchive`, { roomId });
},
hideRoom(roomId, t) {
return this.sdk.post(`${ this.roomTypeToApiType(t) }.close`, { roomId });
},
saveRoomSettings(rid, params) {
// RC 0.55.0
return this.sdk.methodCall('saveRoomSettings', rid, params);
@ -863,6 +890,31 @@ const RocketChat = {
return this.sdk.get('directory', {
query, count, offset, sort
});
},
canAutoTranslate() {
try {
const AutoTranslate_Enabled = reduxStore.getState().settings && reduxStore.getState().settings.AutoTranslate_Enabled;
if (!AutoTranslate_Enabled) {
return false;
}
const autoTranslatePermission = database.objectForPrimaryKey('permissions', 'auto-translate');
const userRoles = (reduxStore.getState().login.user && reduxStore.getState().login.user.roles) || [];
return autoTranslatePermission.roles.some(role => userRoles.includes(role));
} catch (error) {
log('err_can_auto_translate', error);
return false;
}
},
saveAutoTranslate({
rid, field, value, options
}) {
return this.sdk.methodCall('autoTranslate.saveSettings', rid, field, value, options);
},
getSupportedLanguagesAutoTranslate() {
return this.sdk.methodCall('autoTranslate.getSupportedLanguages', 'en');
},
translateMessage(message, targetLanguage) {
return this.sdk.methodCall('autoTranslate.translateMessage', message, targetLanguage);
}
};

View File

@ -0,0 +1,129 @@
import React from 'react';
import { Animated, View, Text } from 'react-native';
import { RectButton } from 'react-native-gesture-handler';
import PropTypes from 'prop-types';
import I18n from '../../i18n';
import styles, { ACTION_WIDTH, LONG_SWIPE } from './styles';
import { CustomIcon } from '../../lib/Icons';
export const LeftActions = React.memo(({
transX, isRead, width, onToggleReadPress
}) => {
const translateX = transX.interpolate({
inputRange: [0, ACTION_WIDTH],
outputRange: [-ACTION_WIDTH, 0]
});
const translateXIcon = transX.interpolate({
inputRange: [0, ACTION_WIDTH, LONG_SWIPE - 2, LONG_SWIPE],
outputRange: [0, 0, -LONG_SWIPE + ACTION_WIDTH + 2, 0],
extrapolate: 'clamp'
});
return (
<View
style={styles.actionsContainer}
pointerEvents='box-none'
>
<Animated.View
style={[
styles.actionLeftButtonContainer,
{
right: width - ACTION_WIDTH,
width,
transform: [{ translateX }]
}
]}
>
<Animated.View
style={[
styles.actionLeftButtonContainer,
{
right: 0,
transform: [{ translateX: translateXIcon }]
}
]}
>
<RectButton style={styles.actionButton} onPress={onToggleReadPress}>
<React.Fragment>
<CustomIcon size={20} name={isRead ? 'flag' : 'check'} color='white' />
<Text style={styles.actionText}>{I18n.t(isRead ? 'Unread' : 'Read')}</Text>
</React.Fragment>
</RectButton>
</Animated.View>
</Animated.View>
</View>
);
});
export const RightActions = React.memo(({
transX, favorite, width, toggleFav, onHidePress
}) => {
const translateXFav = transX.interpolate({
inputRange: [-width / 2, -ACTION_WIDTH * 2, 0],
outputRange: [width / 2, width - ACTION_WIDTH * 2, width]
});
const translateXHide = transX.interpolate({
inputRange: [-width, -LONG_SWIPE, -ACTION_WIDTH * 2, 0],
outputRange: [0, width - LONG_SWIPE, width - ACTION_WIDTH, width]
});
return (
<View
style={{
position: 'absolute',
left: 0,
right: 0,
height: 75,
flexDirection: 'row'
}}
pointerEvents='box-none'
>
<Animated.View
style={[
styles.actionRightButtonContainer,
{
width,
transform: [{ translateX: translateXFav }]
}
]}
>
<RectButton style={[styles.actionButton, { backgroundColor: '#ffbb00' }]} onPress={toggleFav}>
<React.Fragment>
<CustomIcon size={20} name={favorite ? 'Star-filled' : 'star'} color='white' />
<Text style={styles.actionText}>{I18n.t(favorite ? 'Unfavorite' : 'Favorite')}</Text>
</React.Fragment>
</RectButton>
</Animated.View>
<Animated.View
style={[
styles.actionRightButtonContainer,
{
width,
transform: [{ translateX: translateXHide }]
}
]}
>
<RectButton style={[styles.actionButton, { backgroundColor: '#54585e' }]} onPress={onHidePress}>
<React.Fragment>
<CustomIcon size={20} name='eye-off' color='white' />
<Text style={styles.actionText}>{I18n.t('Hide')}</Text>
</React.Fragment>
</RectButton>
</Animated.View>
</View>
);
});
LeftActions.propTypes = {
transX: PropTypes.object,
isRead: PropTypes.bool,
width: PropTypes.number,
onToggleReadPress: PropTypes.func
};
RightActions.propTypes = {
transX: PropTypes.object,
favorite: PropTypes.bool,
width: PropTypes.number,
toggleFav: PropTypes.func,
onHidePress: PropTypes.func
};

View File

@ -1,25 +1,23 @@
import React from 'react';
import moment from 'moment';
import PropTypes from 'prop-types';
import { View, Text } from 'react-native';
import { connect } from 'react-redux';
import { RectButton } from 'react-native-gesture-handler';
import { View, Text, Animated } from 'react-native';
import { RectButton, PanGestureHandler, State } from 'react-native-gesture-handler';
import Avatar from '../../containers/Avatar';
import I18n from '../../i18n';
import styles, { ROW_HEIGHT } from './styles';
import styles, {
ROW_HEIGHT, ACTION_WIDTH, SMALL_SWIPE, LONG_SWIPE
} from './styles';
import UnreadBadge from './UnreadBadge';
import TypeIcon from './TypeIcon';
import LastMessage from './LastMessage';
import { LeftActions, RightActions } from './Actions';
export { ROW_HEIGHT };
const attrs = ['name', 'unread', 'userMentions', 'showLastMessage', 'alert', 'type'];
@connect(state => ({
userId: state.login.user && state.login.user.id,
username: state.login.user && state.login.user.username,
token: state.login.user && state.login.user.token
}))
const attrs = ['name', 'unread', 'userMentions', 'showLastMessage', 'alert', 'type', 'width', 'isRead', 'favorite'];
export default class RoomItem extends React.Component {
static propTypes = {
type: PropTypes.string.isRequired,
@ -39,7 +37,13 @@ export default class RoomItem extends React.Component {
token: PropTypes.string,
avatarSize: PropTypes.number,
testID: PropTypes.string,
height: PropTypes.number
width: PropTypes.number,
favorite: PropTypes.bool,
isRead: PropTypes.bool,
rid: PropTypes.string,
toggleFav: PropTypes.func,
toggleRead: PropTypes.func,
hideChannel: PropTypes.func
}
static defaultProps = {
@ -50,6 +54,19 @@ export default class RoomItem extends React.Component {
// eslint-disable-next-line no-useless-constructor
constructor(props) {
super(props);
this.dragX = new Animated.Value(0);
this.rowOffSet = new Animated.Value(0);
this.transX = Animated.add(
this.rowOffSet,
this.dragX
);
this.state = {
rowState: 0 // 0: closed, 1: right opened, -1: left opened
};
this._onGestureEvent = Animated.event(
[{ nativeEvent: { translationX: this.dragX } }]
);
this._value = 0;
}
shouldComponentUpdate(nextProps) {
@ -60,13 +77,132 @@ export default class RoomItem extends React.Component {
if (oldlastMessage && newLastmessage && oldlastMessage.ts !== newLastmessage.ts) {
return true;
}
if (_updatedAt && nextProps._updatedAt && nextProps._updatedAt !== _updatedAt) {
if (_updatedAt && nextProps._updatedAt && nextProps._updatedAt.toISOString() !== _updatedAt.toISOString()) {
return true;
}
// eslint-disable-next-line react/destructuring-assignment
return attrs.some(key => nextProps[key] !== this.props[key]);
}
_onHandlerStateChange = ({ nativeEvent }) => {
if (nativeEvent.oldState === State.ACTIVE) {
this._handleRelease(nativeEvent);
}
};
_handleRelease = (nativeEvent) => {
const { translationX } = nativeEvent;
const { rowState } = this.state;
this._value = this._value + translationX;
let toValue = 0;
if (rowState === 0) { // if no option is opened
if (translationX > 0 && translationX < LONG_SWIPE) {
toValue = ACTION_WIDTH; // open left option if he swipe right but not enough to trigger action
this.setState({ rowState: -1 });
} else if (translationX >= LONG_SWIPE) {
toValue = 0;
this.toggleRead();
} else if (translationX < 0 && translationX > -LONG_SWIPE) {
toValue = -2 * ACTION_WIDTH; // open right option if he swipe left
this.setState({ rowState: 1 });
} else if (translationX <= -LONG_SWIPE) {
toValue = 0;
this.setState({ rowState: 0 });
this.hideChannel();
} else {
toValue = 0;
}
}
if (rowState === -1) { // if left option is opened
if (this._value < SMALL_SWIPE) {
toValue = 0;
this.setState({ rowState: 0 });
} else if (this._value > LONG_SWIPE) {
toValue = 0;
this.setState({ rowState: 0 });
this.toggleRead();
} else {
toValue = ACTION_WIDTH;
}
}
if (rowState === 1) { // if right option is opened
if (this._value > -2 * SMALL_SWIPE) {
toValue = 0;
this.setState({ rowState: 0 });
} else if (this._value < -LONG_SWIPE) {
toValue = 0;
this.setState({ rowState: 0 });
this.hideChannel();
} else {
toValue = -2 * ACTION_WIDTH;
}
}
this._animateRow(toValue);
}
_animateRow = (toValue) => {
this.rowOffSet.setValue(this._value);
this._value = toValue;
this.dragX.setValue(0);
Animated.spring(this.rowOffSet, {
toValue,
bounciness: 0,
useNativeDriver: true
}).start();
}
close = () => {
this.setState({ rowState: 0 });
this._animateRow(0);
}
toggleFav = () => {
const { toggleFav, rid, favorite } = this.props;
if (toggleFav) {
toggleFav(rid, favorite);
}
this.close();
}
toggleRead = () => {
const { toggleRead, rid, isRead } = this.props;
if (toggleRead) {
toggleRead(rid, isRead);
}
}
hideChannel = () => {
const { hideChannel, rid, type } = this.props;
if (hideChannel) {
hideChannel(rid, type);
}
}
onToggleReadPress = () => {
this.toggleRead();
this.close();
}
onHidePress = () => {
this.hideChannel();
this.close();
}
onPress = () => {
const { rowState } = this.state;
if (rowState !== 0) {
this.close();
return;
}
const { onPress } = this.props;
if (onPress) {
onPress();
}
}
formatDate = date => moment(date).calendar(null, {
lastDay: `[${ I18n.t('Yesterday') }]`,
sameDay: 'h:mm A',
@ -76,7 +212,7 @@ export default class RoomItem extends React.Component {
render() {
const {
unread, userMentions, name, _updatedAt, alert, testID, height, type, avatarSize, baseUrl, userId, username, token, onPress, id, prid, showLastMessage, lastMessage
unread, userMentions, name, _updatedAt, alert, testID, type, avatarSize, baseUrl, userId, username, token, id, prid, showLastMessage, lastMessage, isRead, width, favorite
} = this.props;
const date = this.formatDate(_updatedAt);
@ -97,30 +233,60 @@ export default class RoomItem extends React.Component {
}
return (
<RectButton
onPress={onPress}
activeOpacity={0.8}
underlayColor='#e1e5e8'
testID={testID}
<PanGestureHandler
minDeltaX={20}
onGestureEvent={this._onGestureEvent}
onHandlerStateChange={this._onHandlerStateChange}
>
<View
style={[styles.container, height && { height }]}
accessibilityLabel={accessibilityLabel}
>
<Avatar text={name} size={avatarSize} type={type} baseUrl={baseUrl} style={styles.avatar} userId={userId} token={token} />
<View style={styles.centerContainer}>
<View style={styles.titleContainer}>
<TypeIcon type={type} id={id} prid={prid} />
<Text style={[styles.title, alert && styles.alert]} ellipsizeMode='tail' numberOfLines={1}>{ name }</Text>
{_updatedAt ? <Text style={[styles.date, alert && styles.updateAlert]} ellipsizeMode='tail' numberOfLines={1}>{ date }</Text> : null}
</View>
<View style={styles.row}>
<LastMessage lastMessage={lastMessage} type={type} showLastMessage={showLastMessage} username={username} alert={alert} />
<UnreadBadge unread={unread} userMentions={userMentions} type={type} />
</View>
</View>
</View>
</RectButton>
<Animated.View>
<LeftActions
transX={this.transX}
isRead={isRead}
width={width}
onToggleReadPress={this.onToggleReadPress}
/>
<RightActions
transX={this.transX}
favorite={favorite}
width={width}
toggleFav={this.toggleFav}
onHidePress={this.onHidePress}
/>
<Animated.View
style={
{
transform: [{ translateX: this.transX }]
}
}
>
<RectButton
onPress={this.onPress}
activeOpacity={0.8}
underlayColor='#e1e5e8'
testID={testID}
style={styles.button}
>
<View
style={styles.container}
accessibilityLabel={accessibilityLabel}
>
<Avatar text={name} size={avatarSize} type={type} baseUrl={baseUrl} style={styles.avatar} userId={userId} token={token} />
<View style={styles.centerContainer}>
<View style={styles.titleContainer}>
<TypeIcon type={type} id={id} prid={prid} />
<Text style={[styles.title, alert && styles.alert]} ellipsizeMode='tail' numberOfLines={1}>{ name }</Text>
{_updatedAt ? <Text style={[styles.date, alert && styles.updateAlert]} ellipsizeMode='tail' numberOfLines={1}>{ date }</Text> : null}
</View>
<View style={styles.row}>
<LastMessage lastMessage={lastMessage} type={type} showLastMessage={showLastMessage} username={username} alert={alert} />
<UnreadBadge unread={unread} userMentions={userMentions} type={type} />
</View>
</View>
</View>
</RectButton>
</Animated.View>
</Animated.View>
</PanGestureHandler>
);
}
}

View File

@ -6,14 +6,20 @@ import {
} from '../../constants/colors';
export const ROW_HEIGHT = 75 * PixelRatio.getFontScale();
export const ACTION_WIDTH = 80;
export const SMALL_SWIPE = ACTION_WIDTH / 2;
export const LONG_SWIPE = ACTION_WIDTH * 3;
export default StyleSheet.create({
container: {
flexDirection: 'row',
alignItems: 'center',
marginLeft: 14,
paddingLeft: 14,
height: ROW_HEIGHT
},
button: {
backgroundColor: COLOR_WHITE
},
centerContainer: {
flex: 1,
paddingVertical: 10,
@ -93,5 +99,42 @@ export default StyleSheet.create({
},
avatar: {
marginRight: 10
},
upperContainer: {
overflow: 'hidden'
},
actionsContainer: {
position: 'absolute',
left: 0,
right: 0,
height: ROW_HEIGHT
},
actionText: {
color: COLOR_WHITE,
fontSize: 15,
backgroundColor: 'transparent',
justifyContent: 'center',
marginTop: 4,
...sharedStyles.textSemibold
},
actionLeftButtonContainer: {
position: 'absolute',
height: ROW_HEIGHT,
backgroundColor: COLOR_PRIMARY,
justifyContent: 'center',
top: 0
},
actionRightButtonContainer: {
position: 'absolute',
height: ROW_HEIGHT,
justifyContent: 'center',
top: 0,
backgroundColor: '#54585e'
},
actionButton: {
width: ACTION_WIDTH,
height: '100%',
alignItems: 'center',
justifyContent: 'center'
}
});

View File

@ -1,8 +1,8 @@
import { AsyncStorage } from 'react-native';
import { delay } from 'redux-saga';
import {
takeLatest, take, select, put, all
} from 'redux-saga/effects';
import RNUserDefaults from 'rn-user-defaults';
import Navigation from '../lib/Navigation';
import * as types from '../actions/actionsTypes';
@ -11,6 +11,7 @@ import database from '../lib/realm';
import RocketChat from '../lib/rocketchat';
import EventEmitter from '../utils/events';
import { appStart } from '../actions';
import { isIOS } from '../utils/deviceInfo';
const roomTypes = {
channel: 'c', direct: 'd', group: 'p'
@ -33,6 +34,10 @@ const handleOpen = function* handleOpen({ params }) {
return;
}
if (isIOS) {
yield RNUserDefaults.setName('group.ios.chat.rocket');
}
let { host } = params;
if (!/^(http|https)/.test(host)) {
host = `https://${ params.host }`;
@ -43,8 +48,8 @@ const handleOpen = function* handleOpen({ params }) {
}
const [server, user] = yield all([
AsyncStorage.getItem('currentServer'),
AsyncStorage.getItem(`${ RocketChat.TOKEN_KEY }-${ host }`)
RNUserDefaults.get('currentServer'),
RNUserDefaults.get(`${ RocketChat.TOKEN_KEY }-${ host }`)
]);
// TODO: needs better test

View File

@ -1,6 +1,7 @@
import { AsyncStorage } from 'react-native';
import { put, takeLatest, all } from 'redux-saga/effects';
import SplashScreen from 'react-native-splash-screen';
import RNUserDefaults from 'rn-user-defaults';
import * as actions from '../actions';
import { selectServerRequest } from '../actions/server';
@ -11,14 +12,54 @@ import RocketChat from '../lib/rocketchat';
import log from '../utils/log';
import Navigation from '../lib/Navigation';
import database from '../lib/realm';
import {
SERVERS, SERVER_ICON, SERVER_NAME, SERVER_URL, TOKEN, USER_ID
} from '../constants/userDefaults';
import { isIOS } from '../utils/deviceInfo';
const restore = function* restore() {
try {
const { token, server } = yield all({
token: AsyncStorage.getItem(RocketChat.TOKEN_KEY),
server: AsyncStorage.getItem('currentServer')
let hasMigration;
if (isIOS) {
yield RNUserDefaults.setName('group.ios.chat.rocket');
hasMigration = yield AsyncStorage.getItem('hasMigration');
}
let { token, server } = yield all({
token: RNUserDefaults.get(RocketChat.TOKEN_KEY),
server: RNUserDefaults.get('currentServer')
});
// get native credentials
if (isIOS && !hasMigration) {
const { serversDB } = database.databases;
const servers = yield RNUserDefaults.objectForKey(SERVERS);
if (servers) {
serversDB.write(() => {
servers.forEach(async(serverItem) => {
const serverInfo = {
id: serverItem[SERVER_URL],
name: serverItem[SERVER_NAME],
iconURL: serverItem[SERVER_ICON]
};
try {
serversDB.create('servers', serverInfo, true);
await RNUserDefaults.set(`${ RocketChat.TOKEN_KEY }-${ serverInfo.id }`, serverItem[USER_ID]);
} catch (e) {
log('err_create_servers', e);
}
});
});
yield AsyncStorage.setItem('hasMigration', '1');
}
// if not have current
if (servers && servers.length !== 0 && (!token || !server)) {
server = servers[0][SERVER_URL];
token = servers[0][TOKEN];
}
}
const sortPreferences = yield RocketChat.getSortPreferences();
yield put(setAllPreferences(sortPreferences));
@ -27,8 +68,8 @@ const restore = function* restore() {
if (!token || !server) {
yield all([
AsyncStorage.removeItem(RocketChat.TOKEN_KEY),
AsyncStorage.removeItem('currentServer')
RNUserDefaults.clear(RocketChat.TOKEN_KEY),
RNUserDefaults.clear('currentServer')
]);
yield put(actions.appStart('outside'));
} else if (server) {

View File

@ -1,7 +1,7 @@
import { AsyncStorage } from 'react-native';
import {
put, call, takeLatest, select, take, fork, cancel
} from 'redux-saga/effects';
import RNUserDefaults from 'rn-user-defaults';
import * as types from '../actions/actionsTypes';
import { appStart } from '../actions';
@ -60,7 +60,7 @@ const fetchUserPresence = function* fetchUserPresence() {
const handleLoginSuccess = function* handleLoginSuccess({ user }) {
try {
const adding = yield select(state => state.server.adding);
yield AsyncStorage.setItem(RocketChat.TOKEN_KEY, user.token);
yield RNUserDefaults.set(RocketChat.TOKEN_KEY, user.token);
const server = yield select(getServer);
yield put(roomsRequest());
@ -72,7 +72,17 @@ const handleLoginSuccess = function* handleLoginSuccess({ user }) {
yield fork(fetchUserPresence);
I18n.locale = user.language;
yield AsyncStorage.setItem(`${ RocketChat.TOKEN_KEY }-${ server }`, JSON.stringify(user));
const { serversDB } = database.databases;
serversDB.write(() => {
try {
serversDB.create('user', user, true);
} catch (e) {
log('err_set_user_token', e);
}
});
yield RNUserDefaults.set(`${ RocketChat.TOKEN_KEY }-${ server }`, user.id);
yield put(setUser(user));
EventEmitter.emit('connected');
@ -105,7 +115,7 @@ const handleLogout = function* handleLogout() {
// see if there's other logged in servers and selects first one
if (servers.length > 0) {
const newServer = servers[0].id;
const token = yield AsyncStorage.getItem(`${ RocketChat.TOKEN_KEY }-${ newServer }`);
const token = yield RNUserDefaults.get(`${ RocketChat.TOKEN_KEY }-${ newServer }`);
if (token) {
return yield put(selectServerRequest(newServer));
}

View File

@ -1,7 +1,8 @@
import {
put, take, takeLatest, fork, cancel, race
} from 'redux-saga/effects';
import { AsyncStorage, Alert } from 'react-native';
import { Alert } from 'react-native';
import RNUserDefaults from 'rn-user-defaults';
import Navigation from '../lib/Navigation';
import { SERVER } from '../actions/actionsTypes';
@ -14,6 +15,7 @@ import RocketChat from '../lib/rocketchat';
import database from '../lib/realm';
import log from '../utils/log';
import I18n from '../i18n';
import { SERVERS, TOKEN, SERVER_URL } from '../constants/userDefaults';
const getServerInfo = function* getServerInfo({ server, raiseError = true }) {
try {
@ -38,13 +40,21 @@ const getServerInfo = function* getServerInfo({ server, raiseError = true }) {
const handleSelectServer = function* handleSelectServer({ server, version, fetchVersion }) {
try {
yield AsyncStorage.setItem('currentServer', server);
const userStringified = yield AsyncStorage.getItem(`${ RocketChat.TOKEN_KEY }-${ server }`);
const { serversDB } = database.databases;
if (userStringified) {
const user = JSON.parse(userStringified);
yield RocketChat.connect({ server, user });
yield put(setUser(user));
yield RNUserDefaults.set('currentServer', server);
const userId = yield RNUserDefaults.get(`${ RocketChat.TOKEN_KEY }-${ server }`);
const user = userId && serversDB.objectForPrimaryKey('user', userId);
const servers = yield RNUserDefaults.objectForKey(SERVERS);
const userCredentials = servers && servers.find(srv => srv[SERVER_URL] === server);
const userLogin = userCredentials && {
token: userCredentials[TOKEN]
};
if (user || userLogin) {
yield RocketChat.connect({ server, user: user || userLogin });
yield put(setUser(user || userLogin));
yield put(actions.appStart('inside'));
} else {
yield RocketChat.connect({ server });

View File

@ -1,11 +0,0 @@
import { Vibration } from 'react-native';
import { isAndroid } from './deviceInfo';
const vibrate = () => {
if (isAndroid) {
Vibration.vibrate(30);
}
};
export { vibrate };

View File

@ -0,0 +1,156 @@
import React from 'react';
import PropTypes from 'prop-types';
import {
FlatList, Switch, View, StyleSheet
} from 'react-native';
import { SafeAreaView, ScrollView } from 'react-navigation';
import RocketChat from '../../lib/rocketchat';
import I18n from '../../i18n';
// import log from '../../utils/log';
import StatusBar from '../../containers/StatusBar';
import { CustomIcon } from '../../lib/Icons';
import sharedStyles from '../Styles';
import ListItem from '../../containers/ListItem';
import Separator from '../../containers/Separator';
import {
SWITCH_TRACK_COLOR, COLOR_BACKGROUND_CONTAINER, COLOR_WHITE, COLOR_SEPARATOR
} from '../../constants/colors';
import scrollPersistTaps from '../../utils/scrollPersistTaps';
import database from '../../lib/realm';
const styles = StyleSheet.create({
contentContainerStyle: {
borderColor: COLOR_SEPARATOR,
borderTopWidth: StyleSheet.hairlineWidth,
borderBottomWidth: StyleSheet.hairlineWidth,
backgroundColor: COLOR_WHITE,
marginTop: 10,
paddingBottom: 30
},
sectionSeparator: {
...sharedStyles.separatorVertical,
backgroundColor: COLOR_BACKGROUND_CONTAINER,
height: 10
}
});
const SectionSeparator = React.memo(() => <View style={styles.sectionSeparator} />);
export default class AutoTranslateView extends React.Component {
static navigationOptions = () => ({
title: I18n.t('Auto_Translate')
})
static propTypes = {
navigation: PropTypes.object
}
constructor(props) {
super(props);
this.rid = props.navigation.getParam('rid');
this.rooms = database.objects('subscriptions').filtered('rid = $0', this.rid);
this.state = {
languages: [],
selectedLanguage: this.rooms[0].autoTranslateLanguage,
enableAutoTranslate: this.rooms[0].autoTranslate
};
}
async componentDidMount() {
try {
const languages = await RocketChat.getSupportedLanguagesAutoTranslate();
this.setState({ languages });
} catch (error) {
console.log(error);
}
}
toggleAutoTranslate = async() => {
const { enableAutoTranslate } = this.state;
try {
await RocketChat.saveAutoTranslate({
rid: this.rid,
field: 'autoTranslate',
value: enableAutoTranslate ? '0' : '1',
options: { defaultLanguage: 'en' }
});
this.setState({ enableAutoTranslate: !enableAutoTranslate });
} catch (error) {
console.log(error);
}
}
saveAutoTranslateLanguage = async(language) => {
try {
await RocketChat.saveAutoTranslate({
rid: this.rid,
field: 'autoTranslateLanguage',
value: language
});
this.setState({ selectedLanguage: language });
} catch (error) {
console.log(error);
}
}
renderSeparator = () => <Separator />
renderIcon = () => <CustomIcon name='check' size={20} style={sharedStyles.colorPrimary} />
renderSwitch = () => {
const { enableAutoTranslate } = this.state;
return (
<Switch
value={enableAutoTranslate}
trackColor={SWITCH_TRACK_COLOR}
onValueChange={this.toggleAutoTranslate}
/>
);
}
renderItem = ({ item }) => {
const { selectedLanguage } = this.state;
const { language, name } = item;
const isSelected = selectedLanguage === language;
return (
<ListItem
title={name || language}
onPress={() => this.saveAutoTranslateLanguage(language)}
testID={`auto-translate-view-${ language }`}
right={isSelected ? this.renderIcon : null}
/>
);
}
render() {
const { languages } = this.state;
return (
<SafeAreaView style={sharedStyles.listSafeArea} testID='auto-translate-view' forceInset={{ bottom: 'never' }}>
<StatusBar />
<ScrollView
{...scrollPersistTaps}
contentContainerStyle={styles.contentContainerStyle}
testID='auto-translate-view-list'
>
<ListItem
title={I18n.t('Enable_Auto_Translate')}
testID='auto-translate-view-switch'
right={() => this.renderSwitch()}
/>
<SectionSeparator />
<FlatList
data={languages}
extraData={this.state}
keyExtractor={item => item.language}
renderItem={this.renderItem}
ItemSeparatorComponent={this.renderSeparator}
/>
</ScrollView>
</SafeAreaView>
);
}
}
console.disableYellowBox = true;

View File

@ -16,10 +16,9 @@ import scrollPersistTaps from '../utils/scrollPersistTaps';
import I18n from '../i18n';
import UserItem from '../presentation/UserItem';
import { showErrorAlert } from '../utils/info';
import { isAndroid } from '../utils/deviceInfo';
import { CustomHeaderButtons, Item } from '../containers/HeaderButton';
import StatusBar from '../containers/StatusBar';
import { COLOR_TEXT_DESCRIPTION, COLOR_WHITE } from '../constants/colors';
import { COLOR_TEXT_DESCRIPTION, COLOR_WHITE, SWITCH_TRACK_COLOR } from '../constants/colors';
const styles = StyleSheet.create({
container: {
@ -245,8 +244,7 @@ export default class CreateChannelView extends React.Component {
value={value}
onValueChange={onValueChange}
testID={`create-channel-${ id }`}
onTintColor='#2de0a5'
tintColor={isAndroid ? '#f5455c' : null}
trackColor={SWITCH_TRACK_COLOR}
disabled={disabled}
/>
</View>

View File

@ -9,6 +9,7 @@ import styles from './styles';
import { CustomIcon } from '../../lib/Icons';
import Check from '../../containers/Check';
import I18n from '../../i18n';
import { SWITCH_TRACK_COLOR } from '../../constants/colors';
const ANIMATION_DURATION = 200;
const ANIMATION_PROPS = {
@ -109,7 +110,7 @@ export default class DirectoryOptions extends PureComponent {
<Text style={styles.dropdownItemText}>{I18n.t('Search_global_users')}</Text>
<Text style={styles.dropdownItemDescription}>{I18n.t('Search_global_users_description')}</Text>
</View>
<Switch value={globalUsers} onValueChange={toggleWorkspace} />
<Switch value={globalUsers} onValueChange={toggleWorkspace} trackColor={SWITCH_TRACK_COLOR} />
</View>
</React.Fragment>
)

View File

@ -46,7 +46,6 @@ const LANGUAGES = [
}), dispatch => ({
setUser: params => dispatch(setUserAction(params))
}))
/** @extends React.Component */
export default class LanguageView extends React.Component {
static navigationOptions = () => ({
title: I18n.t('Change_Language')

View File

@ -5,6 +5,8 @@ import {
} from 'react-native';
import { connect } from 'react-redux';
import { SafeAreaView } from 'react-navigation';
import RNPickerSelect from 'react-native-picker-select';
import equal from 'deep-equal';
import TextInput from '../containers/TextInput';
import Button from '../containers/Button';
@ -17,10 +19,13 @@ import { loginRequest as loginRequestAction } from '../actions/login';
import isValidEmail from '../utils/isValidEmail';
import { LegalButton } from '../containers/HeaderButton';
import StatusBar from '../containers/StatusBar';
import log from '../utils/log';
const shouldUpdateState = ['name', 'email', 'password', 'username', 'saving'];
@connect(null, dispatch => ({
@connect(state => ({
Accounts_CustomFields: state.settings.Accounts_CustomFields
}), dispatch => ({
loginRequest: params => dispatch(loginRequestAction(params))
}))
export default class RegisterView extends React.Component {
@ -35,15 +40,34 @@ export default class RegisterView extends React.Component {
static propTypes = {
navigation: PropTypes.object,
loginRequest: PropTypes.func,
Site_Name: PropTypes.string
Site_Name: PropTypes.string,
Accounts_CustomFields: PropTypes.string
}
state = {
name: '',
email: '',
password: '',
username: '',
saving: false
constructor(props) {
super(props);
const customFields = {};
this.parsedCustomFields = {};
if (props.Accounts_CustomFields) {
try {
this.parsedCustomFields = JSON.parse(props.Accounts_CustomFields);
} catch (e) {
log('err_parsing_account_custom_fields', e);
}
}
Object.keys(this.parsedCustomFields).forEach((key) => {
if (this.parsedCustomFields[key].defaultValue) {
customFields[key] = this.parsedCustomFields[key].defaultValue;
}
});
this.state = {
name: '',
email: '',
password: '',
username: '',
saving: false,
customFields
};
}
componentDidMount() {
@ -53,6 +77,10 @@ export default class RegisterView extends React.Component {
}
shouldComponentUpdate(nextProps, nextState) {
const { customFields } = this.state;
if (!equal(nextState.customFields, customFields)) {
return true;
}
// eslint-disable-next-line react/destructuring-assignment
return shouldUpdateState.some(key => nextState[key] !== this.state[key]);
}
@ -77,9 +105,15 @@ export default class RegisterView extends React.Component {
valid = () => {
const {
name, email, password, username
name, email, password, username, customFields
} = this.state;
return name.trim() && email.trim() && password.trim() && username.trim() && isValidEmail(email);
let requiredCheck = true;
Object.keys(this.parsedCustomFields).forEach((key) => {
if (this.parsedCustomFields[key].required) {
requiredCheck = requiredCheck && customFields[key] && Boolean(customFields[key].trim());
}
});
return name.trim() && email.trim() && password.trim() && username.trim() && isValidEmail(email) && requiredCheck;
}
submit = async() => {
@ -90,13 +124,13 @@ export default class RegisterView extends React.Component {
Keyboard.dismiss();
const {
name, email, password, username
name, email, password, username, customFields
} = this.state;
const { loginRequest } = this.props;
try {
await RocketChat.register({
name, email, pass: password, username
name, email, pass: password, username, ...customFields
});
await loginRequest({ user: email, password });
} catch (e) {
@ -105,6 +139,64 @@ export default class RegisterView extends React.Component {
this.setState({ saving: false });
}
renderCustomFields = () => {
const { customFields } = this.state;
const { Accounts_CustomFields } = this.props;
if (!Accounts_CustomFields) {
return null;
}
try {
return Object.keys(this.parsedCustomFields).map((key, index, array) => {
if (this.parsedCustomFields[key].type === 'select') {
const options = this.parsedCustomFields[key].options.map(option => ({ label: option, value: option }));
return (
<RNPickerSelect
key={key}
items={options}
onValueChange={(value) => {
const newValue = {};
newValue[key] = value;
this.setState({ customFields: { ...customFields, ...newValue } });
}}
value={customFields[key]}
>
<TextInput
inputRef={(e) => { this[key] = e; }}
placeholder={key}
value={customFields[key]}
iconLeft='flag'
testID='register-view-custom-picker'
/>
</RNPickerSelect>
);
}
return (
<TextInput
inputRef={(e) => { this[key] = e; }}
key={key}
placeholder={key}
value={customFields[key]}
iconLeft='flag'
onChangeText={(value) => {
const newValue = {};
newValue[key] = value;
this.setState({ customFields: { ...customFields, ...newValue } });
}}
onSubmitEditing={() => {
if (array.length - 1 > index) {
return this[array[index + 1]].focus();
}
this.avatarUrl.focus();
}}
/>
);
});
} catch (error) {
return null;
}
}
render() {
const { saving } = this.state;
return (
@ -153,6 +245,8 @@ export default class RegisterView extends React.Component {
containerStyle={sharedStyles.inputLastChild}
/>
{this.renderCustomFields()}
<Button
title={I18n.t('Register')}
type='primary'

View File

@ -60,7 +60,8 @@ export default class RoomActionsView extends React.Component {
membersCount: 0,
member: {},
joined: this.rooms.length > 0,
canViewMembers: false
canViewMembers: false,
canAutoTranslate: false
};
}
@ -89,6 +90,10 @@ export default class RoomActionsView extends React.Component {
} else if (room.t === 'd') {
this.updateRoomMember();
}
const canAutoTranslate = RocketChat.canAutoTranslate();
this.setState({ canAutoTranslate });
safeAddListener(this.rooms, this.updateRoom);
}
@ -169,7 +174,7 @@ export default class RoomActionsView extends React.Component {
get sections() {
const {
room, membersCount, canViewMembers, joined
room, membersCount, canViewMembers, joined, canAutoTranslate
} = this.state;
const {
rid, t, blocker, notifications
@ -255,6 +260,16 @@ export default class RoomActionsView extends React.Component {
renderItem: this.renderItem
}];
if (canAutoTranslate) {
sections[2].data.push({
icon: 'language',
name: I18n.t('Auto_Translate'),
route: 'AutoTranslateView',
params: { rid },
testID: 'room-actions-auto-translate'
});
}
if (t === 'd') {
sections.push({
data: [

View File

@ -4,6 +4,7 @@ import PropTypes from 'prop-types';
import styles from './styles';
import sharedStyles from '../Styles';
import { SWITCH_TRACK_COLOR } from '../../constants/colors';
export default class SwitchContainer extends React.PureComponent {
static propTypes = {
@ -33,6 +34,7 @@ export default class SwitchContainer extends React.PureComponent {
onValueChange={onValueChange}
value={value}
disabled={disabled}
trackColor={SWITCH_TRACK_COLOR}
testID={testID}
/>
<View style={styles.switchLabelContainer}>

View File

@ -5,6 +5,7 @@ import ActionSheet from 'react-native-action-sheet';
import { connect } from 'react-redux';
import { SafeAreaView } from 'react-navigation';
import equal from 'deep-equal';
import * as Haptics from 'expo-haptics';
import styles from './styles';
import UserItem from '../../presentation/UserItem';
@ -13,7 +14,6 @@ import RocketChat from '../../lib/rocketchat';
import database, { safeAddListener } from '../../lib/realm';
import { Toast } from '../../utils/info';
import log from '../../utils/log';
import { vibrate } from '../../utils/vibration';
import I18n from '../../i18n';
import SearchBox from '../../containers/SearchBox';
import protectedFunction from '../../lib/methods/helpers/protectedFunction';
@ -164,7 +164,7 @@ export default class RoomMembersView extends React.Component {
this.actionSheetOptions.push(I18n.t('Mute'));
}
this.setState({ userLongPressed: user });
vibrate();
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
this.showActionSheet();
}

View File

@ -9,6 +9,7 @@ import { SafeAreaView } from 'react-navigation';
import equal from 'deep-equal';
import moment from 'moment';
import EJSON from 'ejson';
import * as Haptics from 'expo-haptics';
import {
toggleReactionPicker as toggleReactionPickerAction,
@ -39,7 +40,6 @@ import { COLOR_WHITE } from '../../constants/colors';
import debounce from '../../utils/debounce';
import buildMessage from '../../lib/methods/helpers/buildMessage';
import FileModal from '../../containers/FileModal';
import { vibrate } from '../../utils/vibration';
import ReactionsModal from '../../containers/ReactionsModal';
import { Toast } from '../../utils/info';
@ -138,6 +138,7 @@ export default class RoomView extends React.Component {
this.t = props.navigation.getParam('t');
this.tmid = props.navigation.getParam('tmid');
this.rooms = database.objects('subscriptions').filtered('rid = $0', this.rid);
const canAutoTranslate = RocketChat.canAutoTranslate();
this.state = {
joined: this.rooms.length > 0,
room: this.rooms[0] || { rid: this.rid, t: this.t },
@ -145,7 +146,8 @@ export default class RoomView extends React.Component {
photoModalVisible: false,
reactionsModalVisible: false,
selectedAttachment: {},
selectedMessage: {}
selectedMessage: {},
canAutoTranslate
};
this.beginAnimating = false;
this.beginAnimatingTimeout = setTimeout(() => this.beginAnimating = true, 300);
@ -180,7 +182,7 @@ export default class RoomView extends React.Component {
shouldComponentUpdate(nextProps, nextState) {
const {
room, joined, lastOpen, photoModalVisible, reactionsModalVisible
room, joined, lastOpen, photoModalVisible, reactionsModalVisible, canAutoTranslate
} = this.state;
const { showActions, showErrorActions, appState } = this.props;
@ -202,6 +204,8 @@ export default class RoomView extends React.Component {
return true;
} else if (joined !== nextState.joined) {
return true;
} else if (canAutoTranslate !== nextState.canAutoTranslate) {
return true;
} else if (showActions !== nextProps.showActions) {
return true;
} else if (showErrorActions !== nextProps.showErrorActions) {
@ -298,6 +302,11 @@ export default class RoomView extends React.Component {
this.sub = await RocketChat.subscribeRoom(room);
}
}
// We run `canAutoTranslate` again in order to refetch auto translate permission
// in case of a missing connection or poor connection on room open
const canAutoTranslate = RocketChat.canAutoTranslate();
this.setState({ canAutoTranslate });
});
} catch (e) {
log('err_room_init', e);
@ -332,7 +341,7 @@ export default class RoomView extends React.Component {
onReactionLongPress = (message) => {
this.setState({ selectedMessage: message, reactionsModalVisible: true });
vibrate();
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
}
onCloseReactionsModal = () => {
@ -500,7 +509,7 @@ export default class RoomView extends React.Component {
}
renderItem = (item, previousItem) => {
const { room, lastOpen } = this.state;
const { room, lastOpen, canAutoTranslate } = this.state;
const {
user, Message_GroupingPeriod, Message_TimeFormat, useRealName, baseUrl, useMarkdown, Message_Read_Receipt_Enabled
} = this.props;
@ -545,6 +554,8 @@ export default class RoomView extends React.Component {
useRealName={useRealName}
useMarkdown={useMarkdown}
isReadReceiptEnabled={Message_Read_Receipt_Enabled}
autoTranslateRoom={canAutoTranslate && room.autoTranslate}
autoTranslateLanguage={room.autoTranslateLanguage}
/>
);

View File

@ -1,11 +1,12 @@
import React, { Component } from 'react';
import {
View, Text, Animated, Easing, TouchableWithoutFeedback, TouchableOpacity, FlatList, Image, AsyncStorage
View, Text, Animated, Easing, TouchableWithoutFeedback, TouchableOpacity, FlatList, Image
} from 'react-native';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import equal from 'deep-equal';
import { withNavigation } from 'react-navigation';
import RNUserDefaults from 'rn-user-defaults';
import { toggleServerDropdown as toggleServerDropdownAction } from '../../actions/rooms';
import { selectServerRequest as selectServerRequestAction } from '../../actions/server';
@ -124,8 +125,8 @@ class ServerDropdown extends Component {
this.close();
if (currentServer !== server) {
const token = await AsyncStorage.getItem(`${ RocketChat.TOKEN_KEY }-${ server }`);
if (!token) {
const userId = await RNUserDefaults.get(`${ RocketChat.TOKEN_KEY }-${ server }`);
if (!userId) {
appStart();
this.newServerTimeout = setTimeout(() => {
EventEmitter.emit('NewServer', { server });

View File

@ -1,7 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import {
View, FlatList, BackHandler, ActivityIndicator, Text, ScrollView, Keyboard, LayoutAnimation, InteractionManager
View, FlatList, BackHandler, ActivityIndicator, Text, ScrollView, Keyboard, LayoutAnimation, InteractionManager, Dimensions
} from 'react-native';
import { connect } from 'react-redux';
import { isEqual } from 'lodash';
@ -39,6 +39,9 @@ const keyExtractor = item => item.rid;
@connect(state => ({
userId: state.login.user && state.login.user.id,
username: state.login.user && state.login.user.username,
token: state.login.user && state.login.user.token,
isAuthenticated: state.login.isAuthenticated,
server: state.server.server,
baseUrl: state.settings.baseUrl || state.server ? state.server.server : '',
searchText: state.rooms.searchText,
@ -94,6 +97,8 @@ export default class RoomsListView extends React.Component {
static propTypes = {
navigation: PropTypes.object,
userId: PropTypes.string,
username: PropTypes.string,
token: PropTypes.string,
baseUrl: PropTypes.string,
server: PropTypes.string,
searchText: PropTypes.string,
@ -111,7 +116,8 @@ export default class RoomsListView extends React.Component {
openSearchHeader: PropTypes.func,
closeSearchHeader: PropTypes.func,
appStart: PropTypes.func,
roomsRequest: PropTypes.func
roomsRequest: PropTypes.func,
isAuthenticated: PropTypes.bool
}
constructor(props) {
@ -119,6 +125,7 @@ export default class RoomsListView extends React.Component {
console.time(`${ this.constructor.name } init`);
console.time(`${ this.constructor.name } mount`);
const { width } = Dimensions.get('window');
this.data = [];
this.state = {
searching: false,
@ -131,7 +138,8 @@ export default class RoomsListView extends React.Component {
channels: [],
privateGroup: [],
direct: [],
livechat: []
livechat: [],
width
};
Orientation.unlockAllOrientations();
this.didFocusListener = props.navigation.addListener('didFocus', () => BackHandler.addEventListener('hardwareBackPress', this.handleBackPress));
@ -146,6 +154,7 @@ export default class RoomsListView extends React.Component {
initSearchingAndroid: this.initSearchingAndroid,
cancelSearchingAndroid: this.cancelSearchingAndroid
});
Dimensions.addEventListener('change', this.onDimensionsChange);
console.timeEnd(`${ this.constructor.name } mount`);
}
@ -170,7 +179,7 @@ export default class RoomsListView extends React.Component {
return true;
}
const { loading, searching } = this.state;
const { loading, searching, width } = this.state;
if (nextState.loading !== loading) {
return true;
}
@ -178,6 +187,10 @@ export default class RoomsListView extends React.Component {
return true;
}
if (nextState.width !== width) {
return true;
}
const { search } = this.state;
if (!isEqual(nextState.search, search)) {
return true;
@ -187,7 +200,7 @@ export default class RoomsListView extends React.Component {
componentDidUpdate(prevProps) {
const {
sortBy, groupByType, showFavorites, showUnread, appState, roomsRequest
sortBy, groupByType, showFavorites, showUnread, appState, roomsRequest, isAuthenticated
} = this.props;
if (!(
@ -197,7 +210,7 @@ export default class RoomsListView extends React.Component {
&& (prevProps.showUnread === showUnread)
)) {
this.getSubscriptions();
} else if (appState === 'foreground' && appState !== prevProps.appState) {
} else if (appState === 'foreground' && appState !== prevProps.appState && isAuthenticated) {
roomsRequest();
}
}
@ -218,9 +231,12 @@ export default class RoomsListView extends React.Component {
if (this.willBlurListener && this.willBlurListener.remove) {
this.willBlurListener.remove();
}
Dimensions.removeEventListener('change', this.onDimensionsChange);
console.countReset(`${ this.constructor.name }.render calls`);
}
onDimensionsChange = ({ window: { width } }) => this.setState({ width })
// eslint-disable-next-line react/sort-comp
internalSetState = (...args) => {
const { navigation } = this.props;
@ -381,6 +397,52 @@ export default class RoomsListView extends React.Component {
}, 100);
}
toggleFav = async(rid, favorite) => {
try {
const result = await RocketChat.toggleFavorite(rid, !favorite);
if (result.success) {
database.write(() => {
const sub = database.objects('subscriptions').filtered('rid == $0', rid)[0];
if (sub) {
sub.f = !favorite;
}
});
}
} catch (e) {
log('error_toggle_favorite', e);
}
}
toggleRead = async(rid, isRead) => {
try {
const result = await RocketChat.toggleRead(isRead, rid);
if (result.success) {
database.write(() => {
const sub = database.objects('subscriptions').filtered('rid == $0', rid)[0];
if (sub) {
sub.alert = isRead;
}
});
}
} catch (e) {
log('error_toggle_read', e);
}
}
hideChannel = async(rid, type) => {
try {
const result = await RocketChat.hideRoom(rid, type);
if (result.success) {
database.write(() => {
const sub = database.objects('subscriptions').filtered('rid == $0', rid)[0];
database.delete(sub);
});
}
} catch (e) {
log('error_hide_channel', e);
}
}
goDirectory = () => {
const { navigation } = this.props;
navigation.navigate('DirectoryView');
@ -402,9 +464,16 @@ export default class RoomsListView extends React.Component {
);
}
getIsRead = (item) => {
let isUnread = (item.archived !== true && item.open === true); // item is not archived and not opened
isUnread = isUnread && (item.unread > 0 || item.alert === true); // either its unread count > 0 or its alert
return !isUnread;
}
renderItem = ({ item }) => {
const { width } = this.state;
const {
userId, baseUrl, StoreLastMessage
userId, username, token, baseUrl, StoreLastMessage
} = this.props;
const id = item.rid.replace(userId, '').trim();
@ -414,19 +483,27 @@ export default class RoomsListView extends React.Component {
alert={item.alert}
unread={item.unread}
userMentions={item.userMentions}
isRead={this.getIsRead(item)}
favorite={item.f}
lastMessage={item.lastMessage ? JSON.parse(JSON.stringify(item.lastMessage)) : null}
name={this.getRoomTitle(item)}
_updatedAt={item.roomUpdatedAt}
key={item._id}
id={id}
userId={userId}
username={username}
token={token}
rid={item.rid}
type={item.t}
baseUrl={baseUrl}
prid={item.prid}
showLastMessage={StoreLastMessage}
onPress={() => this._onPressItem(item)}
testID={`rooms-list-view-item-${ item.name }`}
height={ROW_HEIGHT}
width={width}
toggleFav={this.toggleFav}
toggleRead={this.toggleRead}
hideChannel={this.hideChannel}
/>
);
}
@ -528,7 +605,7 @@ export default class RoomsListView extends React.Component {
renderItem={this.renderItem}
ListHeaderComponent={this.renderListHeader}
getItemLayout={getItemLayout}
removeClippedSubviews
// removeClippedSubviews
keyboardShouldPersistTaps='always'
initialNumToRender={9}
windowSize={9}

View File

@ -6,7 +6,7 @@ import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { toggleMarkdown as toggleMarkdownAction } from '../../actions/markdown';
import { COLOR_DANGER, COLOR_SUCCESS } from '../../constants/colors';
import { SWITCH_TRACK_COLOR } from '../../constants/colors';
import { DrawerButton } from '../../containers/HeaderButton';
import StatusBar from '../../containers/StatusBar';
import ListItem from '../../containers/ListItem';
@ -14,7 +14,7 @@ import { DisclosureImage } from '../../containers/DisclosureIndicator';
import Separator from '../../containers/Separator';
import I18n from '../../i18n';
import { MARKDOWN_KEY } from '../../lib/rocketchat';
import { getReadableVersion, getDeviceModel, isAndroid } from '../../utils/deviceInfo';
import { getReadableVersion, getDeviceModel } from '../../utils/deviceInfo';
import openLink from '../../utils/openLink';
import scrollPersistTaps from '../../utils/scrollPersistTaps';
import { showErrorAlert } from '../../utils/info';
@ -23,10 +23,6 @@ import sharedStyles from '../Styles';
const LICENSE_LINK = 'https://github.com/RocketChat/Rocket.Chat.ReactNative/blob/develop/LICENSE';
const SectionSeparator = React.memo(() => <View style={styles.sectionSeparatorBorder} />);
const SWITCH_TRACK_COLOR = {
false: isAndroid ? COLOR_DANGER : null,
true: COLOR_SUCCESS
};
@connect(state => ({
server: state.server,

View File

@ -152,7 +152,7 @@ export default class Sidebar extends Component {
const permissionsFiltered = database.objects('permissions')
.filter(permission => permissions.includes(permission._id));
return permissionsFiltered.reduce((result, permission) => (
result || permission.roles.some(r => roles.includes(r))),
result || permission.roles.some(r => roles.indexOf(r) !== -1)),
false);
}
return false;

2
ios/Gemfile Normal file
View File

@ -0,0 +1,2 @@
source "https://rubygems.org"
gem 'fastlane'

159
ios/Gemfile.lock Normal file
View File

@ -0,0 +1,159 @@
GEM
remote: https://rubygems.org/
specs:
CFPropertyList (3.0.0)
addressable (2.6.0)
public_suffix (>= 2.0.2, < 4.0)
atomos (0.1.3)
babosa (1.0.2)
claide (1.0.2)
colored (1.2)
colored2 (3.1.2)
commander-fastlane (4.4.6)
highline (~> 1.7.2)
declarative (0.0.10)
declarative-option (0.1.0)
digest-crc (0.4.1)
domain_name (0.5.20180417)
unf (>= 0.0.5, < 1.0.0)
dotenv (2.7.4)
emoji_regex (1.0.1)
excon (0.64.0)
faraday (0.15.4)
multipart-post (>= 1.2, < 3)
faraday-cookie_jar (0.0.6)
faraday (>= 0.7.4)
http-cookie (~> 1.0.0)
faraday_middleware (0.13.1)
faraday (>= 0.7.4, < 1.0)
fastimage (2.1.5)
fastlane (2.126.0)
CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.3, < 3.0.0)
babosa (>= 1.0.2, < 2.0.0)
bundler (>= 1.12.0, < 3.0.0)
colored
commander-fastlane (>= 4.4.6, < 5.0.0)
dotenv (>= 2.1.1, < 3.0.0)
emoji_regex (>= 0.1, < 2.0)
excon (>= 0.45.0, < 1.0.0)
faraday (~> 0.9)
faraday-cookie_jar (~> 0.0.6)
faraday_middleware (~> 0.9)
fastimage (>= 2.1.0, < 3.0.0)
gh_inspector (>= 1.1.2, < 2.0.0)
google-api-client (>= 0.21.2, < 0.24.0)
google-cloud-storage (>= 1.15.0, < 2.0.0)
highline (>= 1.7.2, < 2.0.0)
json (< 3.0.0)
jwt (~> 2.1.0)
mini_magick (~> 4.5.1)
multi_xml (~> 0.5)
multipart-post (~> 2.0.0)
plist (>= 3.1.0, < 4.0.0)
public_suffix (~> 2.0.0)
rubyzip (>= 1.2.2, < 2.0.0)
security (= 0.1.3)
simctl (~> 1.6.3)
slack-notifier (>= 2.0.0, < 3.0.0)
terminal-notifier (>= 2.0.0, < 3.0.0)
terminal-table (>= 1.4.5, < 2.0.0)
tty-screen (>= 0.6.3, < 1.0.0)
tty-spinner (>= 0.8.0, < 1.0.0)
word_wrap (~> 1.0.0)
xcodeproj (>= 1.8.1, < 2.0.0)
xcpretty (~> 0.3.0)
xcpretty-travis-formatter (>= 0.0.3)
gh_inspector (1.1.3)
google-api-client (0.23.9)
addressable (~> 2.5, >= 2.5.1)
googleauth (>= 0.5, < 0.7.0)
httpclient (>= 2.8.1, < 3.0)
mime-types (~> 3.0)
representable (~> 3.0)
retriable (>= 2.0, < 4.0)
signet (~> 0.9)
google-cloud-core (1.3.0)
google-cloud-env (~> 1.0)
google-cloud-env (1.2.0)
faraday (~> 0.11)
google-cloud-storage (1.16.0)
digest-crc (~> 0.4)
google-api-client (~> 0.23)
google-cloud-core (~> 1.2)
googleauth (>= 0.6.2, < 0.10.0)
googleauth (0.6.7)
faraday (~> 0.12)
jwt (>= 1.4, < 3.0)
memoist (~> 0.16)
multi_json (~> 1.11)
os (>= 0.9, < 2.0)
signet (~> 0.7)
highline (1.7.10)
http-cookie (1.0.3)
domain_name (~> 0.5)
httpclient (2.8.3)
json (2.2.0)
jwt (2.1.0)
memoist (0.16.0)
mime-types (3.2.2)
mime-types-data (~> 3.2015)
mime-types-data (3.2019.0331)
mini_magick (4.5.1)
multi_json (1.13.1)
multi_xml (0.6.0)
multipart-post (2.0.0)
nanaimo (0.2.6)
naturally (2.2.0)
os (1.0.1)
plist (3.5.0)
public_suffix (2.0.5)
representable (3.0.4)
declarative (< 0.1.0)
declarative-option (< 0.2.0)
uber (< 0.2.0)
retriable (3.1.2)
rouge (2.0.7)
rubyzip (1.2.3)
security (0.1.3)
signet (0.11.0)
addressable (~> 2.3)
faraday (~> 0.9)
jwt (>= 1.5, < 3.0)
multi_json (~> 1.10)
simctl (1.6.5)
CFPropertyList
naturally
slack-notifier (2.3.2)
terminal-notifier (2.0.0)
terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1)
tty-cursor (0.7.0)
tty-screen (0.7.0)
tty-spinner (0.9.1)
tty-cursor (~> 0.7)
uber (0.1.0)
unf (0.1.4)
unf_ext
unf_ext (0.0.7.6)
unicode-display_width (1.6.0)
word_wrap (1.0.0)
xcodeproj (1.10.0)
CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0)
colored2 (~> 3.1)
nanaimo (~> 0.2.6)
xcpretty (0.3.0)
rouge (~> 2.0.7)
xcpretty-travis-formatter (1.0.0)
xcpretty (~> 0.2, >= 0.0.7)
PLATFORMS
ruby
DEPENDENCIES
fastlane
BUNDLED WITH
2.0.2

View File

@ -10,6 +10,8 @@ PODS:
- EXFileSystem (5.0.1):
- UMCore
- UMFileSystemInterface
- EXHaptics (5.0.1):
- UMCore
- EXPermissions (5.0.1):
- UMCore
- UMPermissionsInterface
@ -171,6 +173,7 @@ DEPENDENCIES:
- EXAppLoaderProvider (from `../node_modules/expo-app-loader-provider/ios`)
- EXConstants (from `../node_modules/expo-constants/ios`)
- EXFileSystem (from `../node_modules/expo-file-system/ios`)
- EXHaptics (from `../node_modules/expo-haptics/ios`)
- EXPermissions (from `../node_modules/expo-permissions/ios`)
- EXWebBrowser (from `../node_modules/expo-web-browser/ios`)
- Fabric (~> 1.9.0)
@ -243,6 +246,9 @@ EXTERNAL SOURCES:
EXFileSystem:
:path: !ruby/object:Pathname
path: "../node_modules/expo-file-system/ios"
EXHaptics:
:path: !ruby/object:Pathname
path: "../node_modules/expo-haptics/ios"
EXPermissions:
:path: !ruby/object:Pathname
path: "../node_modules/expo-permissions/ios"
@ -313,6 +319,7 @@ SPEC CHECKSUMS:
EXAppLoaderProvider: 8f2c04a0a8d9be91f7c37c2b8824077ee5d4bc01
EXConstants: 9fe56eec8bf0a3ee9beb8f3381fa91340a5b1e57
EXFileSystem: 96624bd4b93a0684335c421a6567a92b25bd7ddb
EXHaptics: 6d594612afa321bfc8e167bdfb0b47f940f8f537
EXPermissions: 8e05008ed4fc8c9be6c17ea95301fc3f3f005a7b
EXWebBrowser: e03894b4583bb726e5ea05d01b341ba00134c2b5
Fabric: f988e33c97f08930a413e08123064d2e5f68d655

View File

@ -0,0 +1 @@
../../../../../node_modules/expo-haptics/ios/EXHaptics/EXHapticsModule.h

View File

@ -0,0 +1 @@
../../../../../node_modules/expo-haptics/ios/EXHaptics/EXHapticsModule.h

View File

@ -0,0 +1,23 @@
{
"name": "EXHaptics",
"version": "5.0.1",
"summary": "Provides access to the system's haptics engine on iOS and vibration effects on Android.",
"description": "Provides access to the system's haptics engine on iOS and vibration effects on Android.",
"license": "MIT",
"authors": "650 Industries, Inc.",
"homepage": "https://docs.expo.io/versions/latest/sdk/haptics/",
"platforms": {
"ios": "10.0"
},
"source": {
"git": "https://github.com/expo/expo.git"
},
"source_files": "EXHaptics/**/*.{h,m}",
"preserve_paths": "EXHaptics/**/*.{h,m}",
"requires_arc": true,
"dependencies": {
"UMCore": [
]
}
}

View File

@ -10,6 +10,8 @@ PODS:
- EXFileSystem (5.0.1):
- UMCore
- UMFileSystemInterface
- EXHaptics (5.0.1):
- UMCore
- EXPermissions (5.0.1):
- UMCore
- UMPermissionsInterface
@ -171,6 +173,7 @@ DEPENDENCIES:
- EXAppLoaderProvider (from `../node_modules/expo-app-loader-provider/ios`)
- EXConstants (from `../node_modules/expo-constants/ios`)
- EXFileSystem (from `../node_modules/expo-file-system/ios`)
- EXHaptics (from `../node_modules/expo-haptics/ios`)
- EXPermissions (from `../node_modules/expo-permissions/ios`)
- EXWebBrowser (from `../node_modules/expo-web-browser/ios`)
- Fabric (~> 1.9.0)
@ -243,6 +246,9 @@ EXTERNAL SOURCES:
EXFileSystem:
:path: !ruby/object:Pathname
path: "../node_modules/expo-file-system/ios"
EXHaptics:
:path: !ruby/object:Pathname
path: "../node_modules/expo-haptics/ios"
EXPermissions:
:path: !ruby/object:Pathname
path: "../node_modules/expo-permissions/ios"
@ -313,6 +319,7 @@ SPEC CHECKSUMS:
EXAppLoaderProvider: 8f2c04a0a8d9be91f7c37c2b8824077ee5d4bc01
EXConstants: 9fe56eec8bf0a3ee9beb8f3381fa91340a5b1e57
EXFileSystem: 96624bd4b93a0684335c421a6567a92b25bd7ddb
EXHaptics: 6d594612afa321bfc8e167bdfb0b47f940f8f537
EXPermissions: 8e05008ed4fc8c9be6c17ea95301fc3f3f005a7b
EXWebBrowser: e03894b4583bb726e5ea05d01b341ba00134c2b5
Fabric: f988e33c97f08930a413e08123064d2e5f68d655

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,5 @@
#import <Foundation/Foundation.h>
@interface PodsDummy_EXHaptics : NSObject
@end
@implementation PodsDummy_EXHaptics
@end

View File

@ -0,0 +1,12 @@
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#else
#ifndef FOUNDATION_EXPORT
#if defined(__cplusplus)
#define FOUNDATION_EXPORT extern "C"
#else
#define FOUNDATION_EXPORT extern
#endif
#endif
#endif

View File

@ -0,0 +1,9 @@
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/EXHaptics
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/EXHaptics" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/EXHaptics" "${PODS_ROOT}/Headers/Public/UMCore"
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_ROOT = ${SRCROOT}
PODS_TARGET_SRCROOT = ${PODS_ROOT}/../../node_modules/expo-haptics/ios
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
SKIP_INSTALL = YES

View File

@ -1,8 +1,8 @@
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Crashlytics/iOS" "${PODS_ROOT}/Fabric/iOS" "${PODS_ROOT}/FirebaseABTesting/Frameworks" "${PODS_ROOT}/FirebaseAnalytics/Frameworks" "${PODS_ROOT}/FirebasePerformance/Frameworks" "${PODS_ROOT}/FirebaseRemoteConfig/Frameworks" "${PODS_ROOT}/GoogleAppMeasurement/Frameworks"
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 $(inherited) GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1 $(inherited) PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1 PB_ENABLE_MALLOC=1
HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/DoubleConversion" "${PODS_ROOT}/Headers/Public/EXAppLoaderProvider" "${PODS_ROOT}/Headers/Public/EXConstants" "${PODS_ROOT}/Headers/Public/EXFileSystem" "${PODS_ROOT}/Headers/Public/EXPermissions" "${PODS_ROOT}/Headers/Public/EXWebBrowser" "${PODS_ROOT}/Headers/Public/Firebase" "${PODS_ROOT}/Headers/Public/FirebaseCore" "${PODS_ROOT}/Headers/Public/FirebaseInstanceID" "${PODS_ROOT}/Headers/Public/GTMSessionFetcher" "${PODS_ROOT}/Headers/Public/GoogleToolboxForMac" "${PODS_ROOT}/Headers/Public/GoogleUtilities" "${PODS_ROOT}/Headers/Public/Protobuf" "${PODS_ROOT}/Headers/Public/QBImagePickerController" "${PODS_ROOT}/Headers/Public/RNDeviceInfo" "${PODS_ROOT}/Headers/Public/RNImageCropPicker" "${PODS_ROOT}/Headers/Public/RNScreens" "${PODS_ROOT}/Headers/Public/RSKImageCropper" "${PODS_ROOT}/Headers/Public/React" "${PODS_ROOT}/Headers/Public/UMBarCodeScannerInterface" "${PODS_ROOT}/Headers/Public/UMCameraInterface" "${PODS_ROOT}/Headers/Public/UMConstantsInterface" "${PODS_ROOT}/Headers/Public/UMCore" "${PODS_ROOT}/Headers/Public/UMFaceDetectorInterface" "${PODS_ROOT}/Headers/Public/UMFileSystemInterface" "${PODS_ROOT}/Headers/Public/UMFontInterface" "${PODS_ROOT}/Headers/Public/UMImageLoaderInterface" "${PODS_ROOT}/Headers/Public/UMPermissionsInterface" "${PODS_ROOT}/Headers/Public/UMReactNativeAdapter" "${PODS_ROOT}/Headers/Public/UMSensorsInterface" "${PODS_ROOT}/Headers/Public/UMTaskManagerInterface" "${PODS_ROOT}/Headers/Public/glog" "${PODS_ROOT}/Headers/Public/nanopb" "${PODS_ROOT}/Headers/Public/react-native-orientation-locker" "${PODS_ROOT}/Headers/Public/react-native-splash-screen" "${PODS_ROOT}/Headers/Public/react-native-webview" "${PODS_ROOT}/Headers/Public/yoga" $(inherited) ${PODS_ROOT}/Firebase/CoreOnly/Sources
LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/DoubleConversion" "${PODS_CONFIGURATION_BUILD_DIR}/EXAppLoaderProvider" "${PODS_CONFIGURATION_BUILD_DIR}/EXConstants" "${PODS_CONFIGURATION_BUILD_DIR}/EXFileSystem" "${PODS_CONFIGURATION_BUILD_DIR}/EXPermissions" "${PODS_CONFIGURATION_BUILD_DIR}/EXWebBrowser" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstanceID" "${PODS_CONFIGURATION_BUILD_DIR}/Folly" "${PODS_CONFIGURATION_BUILD_DIR}/GTMSessionFetcher" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleToolboxForMac" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/Protobuf" "${PODS_CONFIGURATION_BUILD_DIR}/QBImagePickerController" "${PODS_CONFIGURATION_BUILD_DIR}/RNDeviceInfo" "${PODS_CONFIGURATION_BUILD_DIR}/RNImageCropPicker" "${PODS_CONFIGURATION_BUILD_DIR}/RNScreens" "${PODS_CONFIGURATION_BUILD_DIR}/RSKImageCropper" "${PODS_CONFIGURATION_BUILD_DIR}/React" "${PODS_CONFIGURATION_BUILD_DIR}/UMCore" "${PODS_CONFIGURATION_BUILD_DIR}/UMReactNativeAdapter" "${PODS_CONFIGURATION_BUILD_DIR}/glog" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" "${PODS_CONFIGURATION_BUILD_DIR}/react-native-orientation-locker" "${PODS_CONFIGURATION_BUILD_DIR}/react-native-splash-screen" "${PODS_CONFIGURATION_BUILD_DIR}/react-native-webview" "${PODS_CONFIGURATION_BUILD_DIR}/yoga" "${PODS_ROOT}/GoogleIDFASupport/Libraries"
OTHER_LDFLAGS = $(inherited) -ObjC -l"AdIdAccessLibrary" -l"DoubleConversion" -l"EXAppLoaderProvider" -l"EXConstants" -l"EXFileSystem" -l"EXPermissions" -l"EXWebBrowser" -l"FirebaseCore" -l"FirebaseInstanceID" -l"Folly" -l"GTMSessionFetcher" -l"GoogleToolboxForMac" -l"GoogleUtilities" -l"Protobuf" -l"QBImagePickerController" -l"RNDeviceInfo" -l"RNImageCropPicker" -l"RNScreens" -l"RSKImageCropper" -l"React" -l"UMCore" -l"UMReactNativeAdapter" -l"c++" -l"glog" -l"nanopb" -l"react-native-orientation-locker" -l"react-native-splash-screen" -l"react-native-webview" -l"sqlite3" -l"stdc++" -l"yoga" -l"z" -framework "AdSupport" -framework "CoreTelephony" -framework "Crashlytics" -framework "FIRAnalyticsConnector" -framework "Fabric" -framework "FirebaseABTesting" -framework "FirebaseAnalytics" -framework "FirebaseCoreDiagnostics" -framework "FirebasePerformance" -framework "FirebaseRemoteConfig" -framework "Foundation" -framework "GoogleAppMeasurement" -framework "JavaScriptCore" -framework "Photos" -framework "QuartzCore" -framework "Security" -framework "StoreKit" -framework "SystemConfiguration" -framework "UIKit"
HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/DoubleConversion" "${PODS_ROOT}/Headers/Public/EXAppLoaderProvider" "${PODS_ROOT}/Headers/Public/EXConstants" "${PODS_ROOT}/Headers/Public/EXFileSystem" "${PODS_ROOT}/Headers/Public/EXHaptics" "${PODS_ROOT}/Headers/Public/EXPermissions" "${PODS_ROOT}/Headers/Public/EXWebBrowser" "${PODS_ROOT}/Headers/Public/Firebase" "${PODS_ROOT}/Headers/Public/FirebaseCore" "${PODS_ROOT}/Headers/Public/FirebaseInstanceID" "${PODS_ROOT}/Headers/Public/GTMSessionFetcher" "${PODS_ROOT}/Headers/Public/GoogleToolboxForMac" "${PODS_ROOT}/Headers/Public/GoogleUtilities" "${PODS_ROOT}/Headers/Public/Protobuf" "${PODS_ROOT}/Headers/Public/QBImagePickerController" "${PODS_ROOT}/Headers/Public/RNDeviceInfo" "${PODS_ROOT}/Headers/Public/RNImageCropPicker" "${PODS_ROOT}/Headers/Public/RNScreens" "${PODS_ROOT}/Headers/Public/RSKImageCropper" "${PODS_ROOT}/Headers/Public/React" "${PODS_ROOT}/Headers/Public/UMBarCodeScannerInterface" "${PODS_ROOT}/Headers/Public/UMCameraInterface" "${PODS_ROOT}/Headers/Public/UMConstantsInterface" "${PODS_ROOT}/Headers/Public/UMCore" "${PODS_ROOT}/Headers/Public/UMFaceDetectorInterface" "${PODS_ROOT}/Headers/Public/UMFileSystemInterface" "${PODS_ROOT}/Headers/Public/UMFontInterface" "${PODS_ROOT}/Headers/Public/UMImageLoaderInterface" "${PODS_ROOT}/Headers/Public/UMPermissionsInterface" "${PODS_ROOT}/Headers/Public/UMReactNativeAdapter" "${PODS_ROOT}/Headers/Public/UMSensorsInterface" "${PODS_ROOT}/Headers/Public/UMTaskManagerInterface" "${PODS_ROOT}/Headers/Public/glog" "${PODS_ROOT}/Headers/Public/nanopb" "${PODS_ROOT}/Headers/Public/react-native-orientation-locker" "${PODS_ROOT}/Headers/Public/react-native-splash-screen" "${PODS_ROOT}/Headers/Public/react-native-webview" "${PODS_ROOT}/Headers/Public/yoga" $(inherited) ${PODS_ROOT}/Firebase/CoreOnly/Sources
LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/DoubleConversion" "${PODS_CONFIGURATION_BUILD_DIR}/EXAppLoaderProvider" "${PODS_CONFIGURATION_BUILD_DIR}/EXConstants" "${PODS_CONFIGURATION_BUILD_DIR}/EXFileSystem" "${PODS_CONFIGURATION_BUILD_DIR}/EXHaptics" "${PODS_CONFIGURATION_BUILD_DIR}/EXPermissions" "${PODS_CONFIGURATION_BUILD_DIR}/EXWebBrowser" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstanceID" "${PODS_CONFIGURATION_BUILD_DIR}/Folly" "${PODS_CONFIGURATION_BUILD_DIR}/GTMSessionFetcher" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleToolboxForMac" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/Protobuf" "${PODS_CONFIGURATION_BUILD_DIR}/QBImagePickerController" "${PODS_CONFIGURATION_BUILD_DIR}/RNDeviceInfo" "${PODS_CONFIGURATION_BUILD_DIR}/RNImageCropPicker" "${PODS_CONFIGURATION_BUILD_DIR}/RNScreens" "${PODS_CONFIGURATION_BUILD_DIR}/RSKImageCropper" "${PODS_CONFIGURATION_BUILD_DIR}/React" "${PODS_CONFIGURATION_BUILD_DIR}/UMCore" "${PODS_CONFIGURATION_BUILD_DIR}/UMReactNativeAdapter" "${PODS_CONFIGURATION_BUILD_DIR}/glog" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" "${PODS_CONFIGURATION_BUILD_DIR}/react-native-orientation-locker" "${PODS_CONFIGURATION_BUILD_DIR}/react-native-splash-screen" "${PODS_CONFIGURATION_BUILD_DIR}/react-native-webview" "${PODS_CONFIGURATION_BUILD_DIR}/yoga" "${PODS_ROOT}/GoogleIDFASupport/Libraries"
OTHER_LDFLAGS = $(inherited) -ObjC -l"AdIdAccessLibrary" -l"DoubleConversion" -l"EXAppLoaderProvider" -l"EXConstants" -l"EXFileSystem" -l"EXHaptics" -l"EXPermissions" -l"EXWebBrowser" -l"FirebaseCore" -l"FirebaseInstanceID" -l"Folly" -l"GTMSessionFetcher" -l"GoogleToolboxForMac" -l"GoogleUtilities" -l"Protobuf" -l"QBImagePickerController" -l"RNDeviceInfo" -l"RNImageCropPicker" -l"RNScreens" -l"RSKImageCropper" -l"React" -l"UMCore" -l"UMReactNativeAdapter" -l"c++" -l"glog" -l"nanopb" -l"react-native-orientation-locker" -l"react-native-splash-screen" -l"react-native-webview" -l"sqlite3" -l"stdc++" -l"yoga" -l"z" -framework "AdSupport" -framework "CoreTelephony" -framework "Crashlytics" -framework "FIRAnalyticsConnector" -framework "Fabric" -framework "FirebaseABTesting" -framework "FirebaseAnalytics" -framework "FirebaseCoreDiagnostics" -framework "FirebasePerformance" -framework "FirebaseRemoteConfig" -framework "Foundation" -framework "GoogleAppMeasurement" -framework "JavaScriptCore" -framework "Photos" -framework "QuartzCore" -framework "Security" -framework "StoreKit" -framework "SystemConfiguration" -framework "UIKit"
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.

View File

@ -1,8 +1,8 @@
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Crashlytics/iOS" "${PODS_ROOT}/Fabric/iOS" "${PODS_ROOT}/FirebaseABTesting/Frameworks" "${PODS_ROOT}/FirebaseAnalytics/Frameworks" "${PODS_ROOT}/FirebasePerformance/Frameworks" "${PODS_ROOT}/FirebaseRemoteConfig/Frameworks" "${PODS_ROOT}/GoogleAppMeasurement/Frameworks"
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 $(inherited) GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1 $(inherited) PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1 PB_ENABLE_MALLOC=1
HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/DoubleConversion" "${PODS_ROOT}/Headers/Public/EXAppLoaderProvider" "${PODS_ROOT}/Headers/Public/EXConstants" "${PODS_ROOT}/Headers/Public/EXFileSystem" "${PODS_ROOT}/Headers/Public/EXPermissions" "${PODS_ROOT}/Headers/Public/EXWebBrowser" "${PODS_ROOT}/Headers/Public/Firebase" "${PODS_ROOT}/Headers/Public/FirebaseCore" "${PODS_ROOT}/Headers/Public/FirebaseInstanceID" "${PODS_ROOT}/Headers/Public/GTMSessionFetcher" "${PODS_ROOT}/Headers/Public/GoogleToolboxForMac" "${PODS_ROOT}/Headers/Public/GoogleUtilities" "${PODS_ROOT}/Headers/Public/Protobuf" "${PODS_ROOT}/Headers/Public/QBImagePickerController" "${PODS_ROOT}/Headers/Public/RNDeviceInfo" "${PODS_ROOT}/Headers/Public/RNImageCropPicker" "${PODS_ROOT}/Headers/Public/RNScreens" "${PODS_ROOT}/Headers/Public/RSKImageCropper" "${PODS_ROOT}/Headers/Public/React" "${PODS_ROOT}/Headers/Public/UMBarCodeScannerInterface" "${PODS_ROOT}/Headers/Public/UMCameraInterface" "${PODS_ROOT}/Headers/Public/UMConstantsInterface" "${PODS_ROOT}/Headers/Public/UMCore" "${PODS_ROOT}/Headers/Public/UMFaceDetectorInterface" "${PODS_ROOT}/Headers/Public/UMFileSystemInterface" "${PODS_ROOT}/Headers/Public/UMFontInterface" "${PODS_ROOT}/Headers/Public/UMImageLoaderInterface" "${PODS_ROOT}/Headers/Public/UMPermissionsInterface" "${PODS_ROOT}/Headers/Public/UMReactNativeAdapter" "${PODS_ROOT}/Headers/Public/UMSensorsInterface" "${PODS_ROOT}/Headers/Public/UMTaskManagerInterface" "${PODS_ROOT}/Headers/Public/glog" "${PODS_ROOT}/Headers/Public/nanopb" "${PODS_ROOT}/Headers/Public/react-native-orientation-locker" "${PODS_ROOT}/Headers/Public/react-native-splash-screen" "${PODS_ROOT}/Headers/Public/react-native-webview" "${PODS_ROOT}/Headers/Public/yoga" $(inherited) ${PODS_ROOT}/Firebase/CoreOnly/Sources
LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/DoubleConversion" "${PODS_CONFIGURATION_BUILD_DIR}/EXAppLoaderProvider" "${PODS_CONFIGURATION_BUILD_DIR}/EXConstants" "${PODS_CONFIGURATION_BUILD_DIR}/EXFileSystem" "${PODS_CONFIGURATION_BUILD_DIR}/EXPermissions" "${PODS_CONFIGURATION_BUILD_DIR}/EXWebBrowser" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstanceID" "${PODS_CONFIGURATION_BUILD_DIR}/Folly" "${PODS_CONFIGURATION_BUILD_DIR}/GTMSessionFetcher" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleToolboxForMac" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/Protobuf" "${PODS_CONFIGURATION_BUILD_DIR}/QBImagePickerController" "${PODS_CONFIGURATION_BUILD_DIR}/RNDeviceInfo" "${PODS_CONFIGURATION_BUILD_DIR}/RNImageCropPicker" "${PODS_CONFIGURATION_BUILD_DIR}/RNScreens" "${PODS_CONFIGURATION_BUILD_DIR}/RSKImageCropper" "${PODS_CONFIGURATION_BUILD_DIR}/React" "${PODS_CONFIGURATION_BUILD_DIR}/UMCore" "${PODS_CONFIGURATION_BUILD_DIR}/UMReactNativeAdapter" "${PODS_CONFIGURATION_BUILD_DIR}/glog" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" "${PODS_CONFIGURATION_BUILD_DIR}/react-native-orientation-locker" "${PODS_CONFIGURATION_BUILD_DIR}/react-native-splash-screen" "${PODS_CONFIGURATION_BUILD_DIR}/react-native-webview" "${PODS_CONFIGURATION_BUILD_DIR}/yoga" "${PODS_ROOT}/GoogleIDFASupport/Libraries"
OTHER_LDFLAGS = $(inherited) -ObjC -l"AdIdAccessLibrary" -l"DoubleConversion" -l"EXAppLoaderProvider" -l"EXConstants" -l"EXFileSystem" -l"EXPermissions" -l"EXWebBrowser" -l"FirebaseCore" -l"FirebaseInstanceID" -l"Folly" -l"GTMSessionFetcher" -l"GoogleToolboxForMac" -l"GoogleUtilities" -l"Protobuf" -l"QBImagePickerController" -l"RNDeviceInfo" -l"RNImageCropPicker" -l"RNScreens" -l"RSKImageCropper" -l"React" -l"UMCore" -l"UMReactNativeAdapter" -l"c++" -l"glog" -l"nanopb" -l"react-native-orientation-locker" -l"react-native-splash-screen" -l"react-native-webview" -l"sqlite3" -l"stdc++" -l"yoga" -l"z" -framework "AdSupport" -framework "CoreTelephony" -framework "Crashlytics" -framework "FIRAnalyticsConnector" -framework "Fabric" -framework "FirebaseABTesting" -framework "FirebaseAnalytics" -framework "FirebaseCoreDiagnostics" -framework "FirebasePerformance" -framework "FirebaseRemoteConfig" -framework "Foundation" -framework "GoogleAppMeasurement" -framework "JavaScriptCore" -framework "Photos" -framework "QuartzCore" -framework "Security" -framework "StoreKit" -framework "SystemConfiguration" -framework "UIKit"
HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/DoubleConversion" "${PODS_ROOT}/Headers/Public/EXAppLoaderProvider" "${PODS_ROOT}/Headers/Public/EXConstants" "${PODS_ROOT}/Headers/Public/EXFileSystem" "${PODS_ROOT}/Headers/Public/EXHaptics" "${PODS_ROOT}/Headers/Public/EXPermissions" "${PODS_ROOT}/Headers/Public/EXWebBrowser" "${PODS_ROOT}/Headers/Public/Firebase" "${PODS_ROOT}/Headers/Public/FirebaseCore" "${PODS_ROOT}/Headers/Public/FirebaseInstanceID" "${PODS_ROOT}/Headers/Public/GTMSessionFetcher" "${PODS_ROOT}/Headers/Public/GoogleToolboxForMac" "${PODS_ROOT}/Headers/Public/GoogleUtilities" "${PODS_ROOT}/Headers/Public/Protobuf" "${PODS_ROOT}/Headers/Public/QBImagePickerController" "${PODS_ROOT}/Headers/Public/RNDeviceInfo" "${PODS_ROOT}/Headers/Public/RNImageCropPicker" "${PODS_ROOT}/Headers/Public/RNScreens" "${PODS_ROOT}/Headers/Public/RSKImageCropper" "${PODS_ROOT}/Headers/Public/React" "${PODS_ROOT}/Headers/Public/UMBarCodeScannerInterface" "${PODS_ROOT}/Headers/Public/UMCameraInterface" "${PODS_ROOT}/Headers/Public/UMConstantsInterface" "${PODS_ROOT}/Headers/Public/UMCore" "${PODS_ROOT}/Headers/Public/UMFaceDetectorInterface" "${PODS_ROOT}/Headers/Public/UMFileSystemInterface" "${PODS_ROOT}/Headers/Public/UMFontInterface" "${PODS_ROOT}/Headers/Public/UMImageLoaderInterface" "${PODS_ROOT}/Headers/Public/UMPermissionsInterface" "${PODS_ROOT}/Headers/Public/UMReactNativeAdapter" "${PODS_ROOT}/Headers/Public/UMSensorsInterface" "${PODS_ROOT}/Headers/Public/UMTaskManagerInterface" "${PODS_ROOT}/Headers/Public/glog" "${PODS_ROOT}/Headers/Public/nanopb" "${PODS_ROOT}/Headers/Public/react-native-orientation-locker" "${PODS_ROOT}/Headers/Public/react-native-splash-screen" "${PODS_ROOT}/Headers/Public/react-native-webview" "${PODS_ROOT}/Headers/Public/yoga" $(inherited) ${PODS_ROOT}/Firebase/CoreOnly/Sources
LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/DoubleConversion" "${PODS_CONFIGURATION_BUILD_DIR}/EXAppLoaderProvider" "${PODS_CONFIGURATION_BUILD_DIR}/EXConstants" "${PODS_CONFIGURATION_BUILD_DIR}/EXFileSystem" "${PODS_CONFIGURATION_BUILD_DIR}/EXHaptics" "${PODS_CONFIGURATION_BUILD_DIR}/EXPermissions" "${PODS_CONFIGURATION_BUILD_DIR}/EXWebBrowser" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstanceID" "${PODS_CONFIGURATION_BUILD_DIR}/Folly" "${PODS_CONFIGURATION_BUILD_DIR}/GTMSessionFetcher" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleToolboxForMac" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/Protobuf" "${PODS_CONFIGURATION_BUILD_DIR}/QBImagePickerController" "${PODS_CONFIGURATION_BUILD_DIR}/RNDeviceInfo" "${PODS_CONFIGURATION_BUILD_DIR}/RNImageCropPicker" "${PODS_CONFIGURATION_BUILD_DIR}/RNScreens" "${PODS_CONFIGURATION_BUILD_DIR}/RSKImageCropper" "${PODS_CONFIGURATION_BUILD_DIR}/React" "${PODS_CONFIGURATION_BUILD_DIR}/UMCore" "${PODS_CONFIGURATION_BUILD_DIR}/UMReactNativeAdapter" "${PODS_CONFIGURATION_BUILD_DIR}/glog" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" "${PODS_CONFIGURATION_BUILD_DIR}/react-native-orientation-locker" "${PODS_CONFIGURATION_BUILD_DIR}/react-native-splash-screen" "${PODS_CONFIGURATION_BUILD_DIR}/react-native-webview" "${PODS_CONFIGURATION_BUILD_DIR}/yoga" "${PODS_ROOT}/GoogleIDFASupport/Libraries"
OTHER_LDFLAGS = $(inherited) -ObjC -l"AdIdAccessLibrary" -l"DoubleConversion" -l"EXAppLoaderProvider" -l"EXConstants" -l"EXFileSystem" -l"EXHaptics" -l"EXPermissions" -l"EXWebBrowser" -l"FirebaseCore" -l"FirebaseInstanceID" -l"Folly" -l"GTMSessionFetcher" -l"GoogleToolboxForMac" -l"GoogleUtilities" -l"Protobuf" -l"QBImagePickerController" -l"RNDeviceInfo" -l"RNImageCropPicker" -l"RNScreens" -l"RSKImageCropper" -l"React" -l"UMCore" -l"UMReactNativeAdapter" -l"c++" -l"glog" -l"nanopb" -l"react-native-orientation-locker" -l"react-native-splash-screen" -l"react-native-webview" -l"sqlite3" -l"stdc++" -l"yoga" -l"z" -framework "AdSupport" -framework "CoreTelephony" -framework "Crashlytics" -framework "FIRAnalyticsConnector" -framework "Fabric" -framework "FirebaseABTesting" -framework "FirebaseAnalytics" -framework "FirebaseCoreDiagnostics" -framework "FirebasePerformance" -framework "FirebaseRemoteConfig" -framework "Foundation" -framework "GoogleAppMeasurement" -framework "JavaScriptCore" -framework "Photos" -framework "QuartzCore" -framework "Security" -framework "StoreKit" -framework "SystemConfiguration" -framework "UIKit"
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.

View File

@ -20,6 +20,7 @@
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; };
1E02221122B2F76B00001862 /* libRNUserDefaults.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1E02220D22B2F76400001862 /* libRNUserDefaults.a */; };
24A2AEF2383D44B586D31C01 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 06BB44DD4855498082A744AD /* libz.tbd */; };
38CEA0ED468E49CFABCD82FD /* libRNFirebase.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A36F9982B71E4662AA8DEB77 /* libRNFirebase.a */; };
50046CB6BDA69B9232CF66D9 /* libPods-RocketChatRN.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C235DC7B31A4D1578EDEF219 /* libPods-RocketChatRN.a */; };
@ -37,7 +38,6 @@
B88F586F1FBF57F600B352B8 /* libRCTPushNotification.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B88F58461FBF55E200B352B8 /* libRCTPushNotification.a */; };
B8971BB2202A093B0000D245 /* libKeyboardTrackingView.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B8971BB1202A091D0000D245 /* libKeyboardTrackingView.a */; };
BAB7DC22804246F3923A1833 /* libFastImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FD2E2837F110483CA29EE0D4 /* libFastImage.a */; };
BED2B77AA660460E8BC9F8E0 /* libRNFetchBlob.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 6533FB90166345D29F1B91C0 /* libRNFetchBlob.a */; };
EF736EF520A64AE8820E684A /* libRealmReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DF26CC845883492D8AC8869B /* libRealmReact.a */; };
F5BF54DC78E1411B8343933B /* libRNI18n.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 921481B47B50490CA761932E /* libRNI18n.a */; };
/* End PBXBuildFile section */
@ -99,6 +99,13 @@
remoteGlobalIDString = 83CBBA2E1A601D0E00E9B192;
remoteInfo = React;
};
1E02220C22B2F76400001862 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 1E0221D522B2F76300001862 /* RNUserDefaults.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 134814201AA4EA6300B7C361;
remoteInfo = RNUserDefaults;
};
3DAD3E831DF850E9000B6D8A /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */;
@ -274,13 +281,6 @@
remoteGlobalIDString = 641E28441F0EEC8500443AF6;
remoteInfo = "RCTVideo-tvOS";
};
7A8C915220F39A8000C8F5EE /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 0B82BCC462E84F308C5B5CD1 /* RNFetchBlob.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = A15C300E1CD25C330074CB35;
remoteInfo = RNFetchBlob;
};
7A8DEB5120ED0BDE00C5DCE4 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 7A8DEB1B20ED0BDE00C5DCE4 /* RNNotifications.xcodeproj */;
@ -437,7 +437,6 @@
00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = "../node_modules/react-native/Libraries/Network/RCTNetwork.xcodeproj"; sourceTree = "<group>"; };
00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVibration.xcodeproj; path = "../node_modules/react-native/Libraries/Vibration/RCTVibration.xcodeproj"; sourceTree = "<group>"; };
06BB44DD4855498082A744AD /* libz.tbd */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
0B82BCC462E84F308C5B5CD1 /* RNFetchBlob.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNFetchBlob.xcodeproj; path = "../node_modules/rn-fetch-blob/ios/RNFetchBlob.xcodeproj"; sourceTree = "<group>"; };
1132AD7934954A958E143199 /* RNFirebase.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNFirebase.xcodeproj; path = "../node_modules/react-native-firebase/ios/RNFirebase.xcodeproj"; sourceTree = "<group>"; };
1142E3442BA94B19BCF52814 /* libRNAudio.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNAudio.a; sourceTree = "<group>"; };
139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = "../node_modules/react-native/Libraries/Settings/RCTSettings.xcodeproj"; sourceTree = "<group>"; };
@ -452,6 +451,7 @@
1845C223DA364898A8400573 /* FastImage.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = FastImage.xcodeproj; path = "../node_modules/react-native-fast-image/ios/FastImage.xcodeproj"; sourceTree = "<group>"; };
1A34D902CC074FF1BCC7DB48 /* libimageCropPicker.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libimageCropPicker.a; sourceTree = "<group>"; };
1D3BB00B9ABF44EA9BD71318 /* libSafariViewManager.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libSafariViewManager.a; sourceTree = "<group>"; };
1E0221D522B2F76300001862 /* RNUserDefaults.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RNUserDefaults.xcodeproj; path = "../node_modules/rn-user-defaults/ios/RNUserDefaults.xcodeproj"; sourceTree = "<group>"; };
20CE3E407E0D4D9E8C9885F2 /* libRCTVideo.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRCTVideo.a; sourceTree = "<group>"; };
22A8B76C8EBA443BB97CE82D /* RNVectorIcons.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNVectorIcons.xcodeproj; path = "../node_modules/react-native-vector-icons/RNVectorIcons.xcodeproj"; sourceTree = "<group>"; };
22D3971EAF2E4660B4FAB3DD /* RNI18n.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNI18n.xcodeproj; path = "../node_modules/react-native-i18n/ios/RNI18n.xcodeproj"; sourceTree = "<group>"; };
@ -461,7 +461,6 @@
5A8684E7C27E426C9206E980 /* RealmReact.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RealmReact.xcodeproj; path = "../node_modules/realm/react-native/ios/RealmReact.xcodeproj"; sourceTree = "<group>"; };
5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAnimation.xcodeproj; path = "../node_modules/react-native/Libraries/NativeAnimation/RCTAnimation.xcodeproj"; sourceTree = "<group>"; };
60B2A6A31FC4588700BD58E5 /* RocketChatRN.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = RocketChatRN.entitlements; path = RocketChatRN/RocketChatRN.entitlements; sourceTree = "<group>"; };
6533FB90166345D29F1B91C0 /* libRNFetchBlob.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNFetchBlob.a; sourceTree = "<group>"; };
66D6B1D0567051BE541450C9 /* Pods-RocketChatRN.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RocketChatRN.release.xcconfig"; path = "Pods/Target Support Files/Pods-RocketChatRN/Pods-RocketChatRN.release.xcconfig"; sourceTree = "<group>"; };
78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = "<group>"; };
7A006F13229C83B600803143 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
@ -492,6 +491,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
1E02221122B2F76B00001862 /* libRNUserDefaults.a in Frameworks */,
7ACD4897222860DE00442C55 /* JavaScriptCore.framework in Frameworks */,
7A8DEB5A20ED0BEC00C5DCE4 /* libRNNotifications.a in Frameworks */,
B8971BB2202A093B0000D245 /* libKeyboardTrackingView.a in Frameworks */,
@ -511,7 +511,6 @@
EF736EF520A64AE8820E684A /* libRealmReact.a in Frameworks */,
0C6E2DE448364EA896869ADF /* libc++.tbd in Frameworks */,
24A2AEF2383D44B586D31C01 /* libz.tbd in Frameworks */,
BED2B77AA660460E8BC9F8E0 /* libRNFetchBlob.a in Frameworks */,
77C35F50C01C43668188886C /* libRNVectorIcons.a in Frameworks */,
8ECBD927DDAC4987B98E102E /* libRCTVideo.a in Frameworks */,
74815BBCB91147C08C8F7B3D /* libRNAudio.a in Frameworks */,
@ -626,6 +625,14 @@
name = Products;
sourceTree = "<group>";
};
1E0221D622B2F76300001862 /* Products */ = {
isa = PBXGroup;
children = (
1E02220D22B2F76400001862 /* libRNUserDefaults.a */,
);
name = Products;
sourceTree = "<group>";
};
22CA7F59107E0C79C2506C7C /* Pods */ = {
isa = PBXGroup;
children = (
@ -695,14 +702,6 @@
name = Products;
sourceTree = "<group>";
};
7A8C912120F39A8000C8F5EE /* Products */ = {
isa = PBXGroup;
children = (
7A8C915320F39A8000C8F5EE /* libRNFetchBlob.a */,
);
name = Products;
sourceTree = "<group>";
};
7A8DEB1C20ED0BDE00C5DCE4 /* Products */ = {
isa = PBXGroup;
children = (
@ -731,6 +730,7 @@
832341AE1AAA6A7D00B99B32 /* Libraries */ = {
isa = PBXGroup;
children = (
1E0221D522B2F76300001862 /* RNUserDefaults.xcodeproj */,
7A8DEB1B20ED0BDE00C5DCE4 /* RNNotifications.xcodeproj */,
B8971BAC202A091D0000D245 /* KeyboardTrackingView.xcodeproj */,
7A430E1620238C01008F55BC /* RCTCustomInputController.xcodeproj */,
@ -752,7 +752,6 @@
C21010507E5B4B37BA0E4C9D /* RNAudio.xcodeproj */,
1845C223DA364898A8400573 /* FastImage.xcodeproj */,
22D3971EAF2E4660B4FAB3DD /* RNI18n.xcodeproj */,
0B82BCC462E84F308C5B5CD1 /* RNFetchBlob.xcodeproj */,
B1A58A7ACB0E4453A44AEC38 /* RNGestureHandler.xcodeproj */,
1132AD7934954A958E143199 /* RNFirebase.xcodeproj */,
);
@ -829,7 +828,6 @@
children = (
DF26CC845883492D8AC8869B /* libRealmReact.a */,
BAAE4B947F5D44959F0A9D5A /* libRNZeroconf.a */,
6533FB90166345D29F1B91C0 /* libRNFetchBlob.a */,
5A0EEFAF8AB14F5B9E796CDD /* libRNVectorIcons.a */,
DA50CE47374C4C35BE6D9D58 /* libRNSVG.a */,
3B696712EE2345A59F007A88 /* libRNImagePicker.a */,
@ -904,6 +902,9 @@
DevelopmentTeam = S6UPZG7ZR3;
ProvisioningStyle = Manual;
SystemCapabilities = {
com.apple.ApplicationGroups.iOS = {
enabled = 1;
};
com.apple.Push = {
enabled = 1;
};
@ -996,10 +997,6 @@
ProductGroup = A9A6C941204DD556006B7D9D /* Products */;
ProjectRef = C21010507E5B4B37BA0E4C9D /* RNAudio.xcodeproj */;
},
{
ProductGroup = 7A8C912120F39A8000C8F5EE /* Products */;
ProjectRef = 0B82BCC462E84F308C5B5CD1 /* RNFetchBlob.xcodeproj */;
},
{
ProductGroup = 7AB8E714229C6145006B474A /* Products */;
ProjectRef = 1132AD7934954A958E143199 /* RNFirebase.xcodeproj */;
@ -1016,6 +1013,10 @@
ProductGroup = 7A8DEB1C20ED0BDE00C5DCE4 /* Products */;
ProjectRef = 7A8DEB1B20ED0BDE00C5DCE4 /* RNNotifications.xcodeproj */;
},
{
ProductGroup = 1E0221D622B2F76300001862 /* Products */;
ProjectRef = 1E0221D522B2F76300001862 /* RNUserDefaults.xcodeproj */;
},
{
ProductGroup = B8E79A8A1F3CCC6C005B464F /* Products */;
ProjectRef = 22A8B76C8EBA443BB97CE82D /* RNVectorIcons.xcodeproj */;
@ -1085,6 +1086,13 @@
remoteRef = 146834031AC3E56700842450 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
1E02220D22B2F76400001862 /* libRNUserDefaults.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libRNUserDefaults.a;
remoteRef = 1E02220C22B2F76400001862 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
3DAD3E841DF850E9000B6D8A /* libRCTImage-tvOS.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
@ -1260,13 +1268,6 @@
remoteRef = 7A7F5C9A1FCC982500024129 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
7A8C915320F39A8000C8F5EE /* libRNFetchBlob.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libRNFetchBlob.a;
remoteRef = 7A8C915220F39A8000C8F5EE /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
7A8DEB5220ED0BDE00C5DCE4 /* libRNNotifications.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
@ -1531,16 +1532,12 @@
"$(SRCROOT)/../node_modules/react-native-fast-image/ios/FastImage/**",
"$(SRCROOT)/../node_modules/react-native-i18n/ios",
"$(SRCROOT)/../node_modules/react-native-notifications/RNNotifications",
"$(SRCROOT)/../node_modules/rn-fetch-blob/ios/**",
"$(SRCROOT)/../node_modules/react-native-gesture-handler/ios/**",
"$(SRCROOT)/../node_modules/react-native-firebase/ios/RNFirebase/**",
);
INFOPLIST_FILE = RocketChatRN/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/RocketChatRN\"",
);
LIBRARY_SEARCH_PATHS = "$(inherited)";
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@ -1548,7 +1545,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = chat.rocket.reactnative;
PRODUCT_NAME = RocketChatRN;
PROVISIONING_PROFILE_SPECIFIER = "match Development chat.rocket.reactnative";
PROVISIONING_PROFILE_SPECIFIER = "Development chat.rocket.reactnative";
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
@ -1560,7 +1557,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
CODE_SIGN_ENTITLEMENTS = RocketChatRN/RocketChatRN.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_IDENTITY = "iPhone Distribution";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 100;
@ -1582,16 +1579,12 @@
"$(SRCROOT)/../node_modules/react-native-fast-image/ios/FastImage/**",
"$(SRCROOT)/../node_modules/react-native-i18n/ios",
"$(SRCROOT)/../node_modules/react-native-notifications/RNNotifications",
"$(SRCROOT)/../node_modules/rn-fetch-blob/ios/**",
"$(SRCROOT)/../node_modules/react-native-gesture-handler/ios/**",
"$(SRCROOT)/../node_modules/react-native-firebase/ios/RNFirebase/**",
);
INFOPLIST_FILE = RocketChatRN/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/RocketChatRN\"",
);
LIBRARY_SEARCH_PATHS = "$(inherited)";
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@ -1599,7 +1592,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = chat.rocket.reactnative;
PRODUCT_NAME = RocketChatRN;
PROVISIONING_PROFILE_SPECIFIER = "match AppStore chat.rocket.reactnative 1552925104";
PROVISIONING_PROFILE_SPECIFIER = "match AppStore chat.rocket.reactnative";
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;

View File

@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.15.1</string>
<string>1.16.1</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>

View File

@ -8,5 +8,9 @@
<array>
<string>applinks:go.rocket.chat</string>
</array>
<key>com.apple.security.application-groups</key>
<array>
<string>group.ios.chat.rocket</string>
</array>
</dict>
</plist>

View File

@ -20,6 +20,7 @@ platform :ios do
# ENV["SLACK_URL"] = "https://hooks.slack.com/services/..."
# cocoapods
# carthage
setup_circle_ci
create_keychain(
name: ENV["MATCH_KEYCHAIN_NAME"],
password: ENV["MATCH_KEYCHAIN_PASSWORD"],

View File

@ -23,6 +23,7 @@
"@rocket.chat/sdk": "1.0.0-alpha.28",
"deep-equal": "^1.0.1",
"ejson": "^2.1.2",
"expo-haptics": "^5.0.1",
"expo-web-browser": "^5.0.3",
"js-base64": "^2.5.1",
"js-sha256": "^0.9.0",
@ -77,7 +78,7 @@
"redux-immutable-state-invariant": "^2.1.0",
"redux-saga": "^0.16.2",
"remove-markdown": "^0.3.0",
"rn-fetch-blob": "^0.10.15",
"rn-user-defaults": "^1.3.4",
"semver": "6.0.0",
"snyk": "^1.156.0",
"strip-ansi": "5.2.0"
@ -97,7 +98,7 @@
"babel-plugin-transform-remove-console": "^6.9.4",
"babel-runtime": "^6.26.0",
"codecov": "3.3.0",
"detox": "12.8.0",
"detox": "12.11.3",
"eslint": "^5.6.0",
"eslint-config-airbnb": "^17.1.0",
"eslint-plugin-import": "^2.14.0",

View File

@ -128,9 +128,21 @@ export default (
<Separator title='Emojis' />
<Message msg='👊🤙👏' />
<Separator title='Single Emoji' />
<Message msg='👏' />
<Separator title='Custom Emojis' />
<Message msg=':react_rocket: :nyan_rocket: :marioparty:' />
<Separator title='Single Custom Emojis' />
<Message msg=':react_rocket:' />
<Separator title='Normal Emoji + Custom Emojis' />
<Message msg='🤙:react_rocket:' />
<Separator title='Four emoji' />
<Message msg='🤙:react_rocket:🤙🤙' />
<Separator title='Time format' />
<Message msg='Testing' timeFormat='DD MMMM YYYY' />

View File

@ -1,5 +1,5 @@
import React from 'react';
import { ScrollView } from 'react-native';
import { ScrollView, Dimensions } from 'react-native';
// import moment from 'moment';
import RoomItemComponent from '../../app/presentation/RoomItem';
@ -7,6 +7,7 @@ import StoriesSeparator from './StoriesSeparator';
const date = '2017-10-10T10:00:00Z';
const baseUrl = 'https://open.rocket.chat';
const { width } = Dimensions.get('window');
const RoomItem = props => (
<RoomItemComponent
@ -14,6 +15,7 @@ const RoomItem = props => (
name='rocket.cat'
_updatedAt={date}
baseUrl={baseUrl}
width={width}
{...props}
/>
);

114
yarn.lock
View File

@ -49,6 +49,26 @@
semver "^5.4.1"
source-map "^0.5.0"
"@babel/core@^7.4.5":
version "7.4.5"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.4.5.tgz#081f97e8ffca65a9b4b0fdc7e274e703f000c06a"
integrity sha512-OvjIh6aqXtlsA8ujtGKfC7LYWksYSX8yQcM8Ay3LuvVeQ63lcOKgoZWVqcpFwkd29aYU9rVx7jxhfhiEDV9MZA==
dependencies:
"@babel/code-frame" "^7.0.0"
"@babel/generator" "^7.4.4"
"@babel/helpers" "^7.4.4"
"@babel/parser" "^7.4.5"
"@babel/template" "^7.4.4"
"@babel/traverse" "^7.4.5"
"@babel/types" "^7.4.4"
convert-source-map "^1.1.0"
debug "^4.1.0"
json5 "^2.1.0"
lodash "^4.17.11"
resolve "^1.3.2"
semver "^5.4.1"
source-map "^0.5.0"
"@babel/generator@^7.0.0", "@babel/generator@^7.2.2":
version "7.3.0"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.3.0.tgz#f663838cd7b542366de3aa608a657b8ccb2a99eb"
@ -289,6 +309,11 @@
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.4.4.tgz#5977129431b8fe33471730d255ce8654ae1250b6"
integrity sha512-5pCS4mOsL+ANsFZGdvNLybx4wtqAZJ0MJjMHxvzI3bvIsz6sQvzW8XX92EYIkiPtIvcfG3Aj+Ir5VNyjnZhP7w==
"@babel/parser@^7.4.5":
version "7.4.5"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.4.5.tgz#04af8d5d5a2b044a2a1bffacc1e5e6673544e872"
integrity sha512-9mUqkL1FF5T7f0WDFfAoDdiMVPWsdD1gZYzSnaXsxUCUqzuch/8of9G3VUSNiZmMBoRxT3neyVsqeiL/ZPcjew==
"@babel/plugin-external-helpers@^7.0.0":
version "7.2.0"
resolved "https://registry.yarnpkg.com/@babel/plugin-external-helpers/-/plugin-external-helpers-7.2.0.tgz#7f4cb7dee651cd380d2034847d914288467a6be4"
@ -887,6 +912,21 @@
globals "^11.1.0"
lodash "^4.17.11"
"@babel/traverse@^7.4.5":
version "7.4.5"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.4.5.tgz#4e92d1728fd2f1897dafdd321efbff92156c3216"
integrity sha512-Vc+qjynwkjRmIFGxy0KYoPj4FdVDxLej89kMHFsWScq999uX+pwcX4v9mWRjW0KcAYTPAuVQl2LKP1wEVLsp+A==
dependencies:
"@babel/code-frame" "^7.0.0"
"@babel/generator" "^7.4.4"
"@babel/helper-function-name" "^7.1.0"
"@babel/helper-split-export-declaration" "^7.4.4"
"@babel/parser" "^7.4.5"
"@babel/types" "^7.4.4"
debug "^4.1.0"
globals "^11.1.0"
lodash "^4.17.11"
"@babel/types@^7.0.0", "@babel/types@^7.2.0", "@babel/types@^7.2.2", "@babel/types@^7.3.0":
version "7.3.0"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.3.0.tgz#61dc0b336a93badc02bf5f69c4cd8e1353f2ffc0"
@ -3469,11 +3509,6 @@ balanced-match@^1.0.0:
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
base-64@0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/base-64/-/base-64-0.1.0.tgz#780a99c84e7d600260361511c4877613bf24f6bb"
integrity sha1-eAqZyE59YAJgNhURxId2E78k9rs=
base64-js@^1.0.2, base64-js@^1.1.2, base64-js@^1.2.3:
version "1.3.0"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3"
@ -3539,7 +3574,12 @@ bl@^1.0.0, bl@^1.2.1:
readable-stream "^2.3.5"
safe-buffer "^5.1.1"
bluebird@3.5.x, bluebird@^3.3.5, bluebird@^3.5.3:
bluebird@3.5.x:
version "3.5.5"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.5.tgz#a8d0afd73251effbbd5fe384a77d73003c17a71f"
integrity sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==
bluebird@^3.3.5, bluebird@^3.5.3:
version "3.5.3"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.3.tgz#7d01c6f9616c9a51ab0f8c549a79dfe6ec33efa7"
integrity sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==
@ -4906,16 +4946,18 @@ detect-port@^1.2.3:
address "^1.0.1"
debug "^2.6.0"
detox@12.8.0:
version "12.8.0"
resolved "https://registry.yarnpkg.com/detox/-/detox-12.8.0.tgz#68cf92ff02fcdb896f05c67b2b40a8c94d09b24b"
integrity sha512-mDe4HcrfUePokhgv6gZADzqqgE6BxYnHXNm4qi5WrwgPJJQMjTLeJOsD7Z6t02SoK5G5Uvq3rx9Z7eI+Xgb3iQ==
detox@12.11.3:
version "12.11.3"
resolved "https://registry.yarnpkg.com/detox/-/detox-12.11.3.tgz#510de28c47f2542a8bc4ddab4ceaa7859e1db7e9"
integrity sha512-Ds1x6VLWjUsIR6FDXORan7NxRlugI4RCCpH5n3L++UIBuMvSicaWSKcmU0rCYCFUeluKDofx+QBgnEryNxRUSg==
dependencies:
"@babel/core" "^7.4.5"
bunyan "^1.8.12"
bunyan-debug-stream "^1.1.0"
chalk "^2.4.2"
child-process-promise "^2.2.0"
fs-extra "^4.0.2"
funpermaproxy "^1.0.1"
get-port "^2.1.0"
ini "^1.3.4"
lodash "^4.17.5"
@ -4926,7 +4968,7 @@ detox@12.8.0:
tail "^2.0.0"
telnet-client "0.15.3"
tempfile "^2.0.0"
ws "^1.1.1"
ws "^3.3.1"
yargs "^13.0.0"
yargs-parser "^13.0.0"
@ -5749,6 +5791,11 @@ expo-file-system@~5.0.0:
dependencies:
uuid-js "^0.7.5"
expo-haptics@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/expo-haptics/-/expo-haptics-5.0.1.tgz#60b67bc613522ddd1ad5e4d701412771fe333c40"
integrity sha512-+ULs5ZNJXT81PILX+Dpp1l9AvcfZZUazg9wX7Dho//ZIaWncPpd5kkiqZpgBlIJNmr7W0rjGcaD8SqVXgesnKg==
expo-permissions@~5.0.0:
version "5.0.1"
resolved "https://registry.yarnpkg.com/expo-permissions/-/expo-permissions-5.0.1.tgz#cc6af49a37ea3ab73e780a8a19f22b7662379941"
@ -6356,6 +6403,11 @@ functional-red-black-tree@^1.0.1:
resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
funpermaproxy@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/funpermaproxy/-/funpermaproxy-1.0.1.tgz#4650e69b7c334d9717c06beba9b339cc08ac3335"
integrity sha512-9pEzs5vnNtR7ZGihly98w/mQ7blsvl68Wj30ZCDAXy7qDN4CWLLjdfjtH/P2m6whsnaJkw15hysCNHMXue+wdA==
fuse.js@^3.0.1, fuse.js@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-3.3.0.tgz#1e4fe172a60687230fb54a5cb247eb96e2e7e885"
@ -6496,18 +6548,6 @@ glob-to-regexp@^0.3.0:
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab"
integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=
glob@7.0.6:
version "7.0.6"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.0.6.tgz#211bafaf49e525b8cd93260d14ab136152b3f57a"
integrity sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.0.2"
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@7.1.2:
version "7.1.2"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
@ -9637,7 +9677,7 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1:
resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=
"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4:
"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.3, minimatch@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
@ -9834,11 +9874,16 @@ mv@~2:
ncp "~2.0.0"
rimraf "~2.4.0"
nan@^2.0.9, nan@^2.10.0, nan@^2.12.1, nan@^2.9.2:
nan@^2.0.9, nan@^2.12.1, nan@^2.9.2:
version "2.12.1"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.12.1.tgz#7b1aa193e9aa86057e3c7bbd0ac448e770925552"
integrity sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==
nan@^2.10.0:
version "2.14.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
nanomatch@^1.2.9:
version "1.2.13"
resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
@ -12542,13 +12587,10 @@ ripemd160@^2.0.0, ripemd160@^2.0.1:
hash-base "^3.0.0"
inherits "^2.0.1"
rn-fetch-blob@^0.10.15:
version "0.10.15"
resolved "https://registry.yarnpkg.com/rn-fetch-blob/-/rn-fetch-blob-0.10.15.tgz#3526860c1c57e0bf4c09bdbe409c919264afffba"
integrity sha512-/m/gurTaPAvR3J843uehHhznj5k89x7XClyO5ejmbspNLNQ4ByF+kZs80wiiKGWntj+Wqo0jJu1goArXEfc0kA==
dependencies:
base-64 "0.1.0"
glob "7.0.6"
rn-user-defaults@^1.3.4:
version "1.3.4"
resolved "https://registry.yarnpkg.com/rn-user-defaults/-/rn-user-defaults-1.3.4.tgz#1fbdd1bf29d9f853918dca5219e45db54d19fe37"
integrity sha512-CnzZbq3Q1VQUr6wKl9Z48eKmOzu+6dMcl2wN0ty+sBnpUyIqFvv3CMzYzb26v1qK8z7q/PcMr75shFHcrJH9WA==
rsvp@^3.3.3:
version "3.6.2"
@ -14781,7 +14823,7 @@ write@^0.2.1:
dependencies:
mkdirp "^0.5.1"
ws@^1.1.0, ws@^1.1.1, ws@^1.1.5:
ws@^1.1.0, ws@^1.1.5:
version "1.1.5"
resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.5.tgz#cbd9e6e75e09fc5d2c90015f21f0c40875e0dd51"
integrity sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w==
@ -14907,9 +14949,9 @@ yargs-parser@^13.0.0:
decamelize "^1.2.0"
yargs-parser@^13.1.0:
version "13.1.0"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.0.tgz#7016b6dd03e28e1418a510e258be4bff5a31138f"
integrity sha512-Yq+32PrijHRri0vVKQEm+ys8mbqWjLiwQkMFNXEENutzLPP0bE4Lcd4iA3OQY5HF+GD3xXxf0MEHb8E4/SA3AA==
version "13.1.1"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0"
integrity sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==
dependencies:
camelcase "^5.0.0"
decamelize "^1.2.0"