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

View File

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

View File

@ -2780,7 +2780,7 @@ exports[`Storyshots Message list 1`] = `
"backgroundColor": "transparent", "backgroundColor": "transparent",
"color": "#2F343D", "color": "#2F343D",
"fontFamily": "System", "fontFamily": "System",
"fontSize": 16, "fontSize": 30,
"fontWeight": "400", "fontWeight": "400",
} }
} }
@ -2796,6 +2796,210 @@ exports[`Storyshots Message list 1`] = `
</View> </View>
</View> </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 <Text
style={ style={
Array [ Array [
@ -2984,7 +3188,7 @@ exports[`Storyshots Message list 1`] = `
"backgroundColor": "transparent", "backgroundColor": "transparent",
"color": "#2F343D", "color": "#2F343D",
"fontFamily": "System", "fontFamily": "System",
"fontSize": 16, "fontSize": 30,
"fontWeight": "400", "fontWeight": "400",
} }
} }
@ -2997,8 +3201,8 @@ exports[`Storyshots Message list 1`] = `
} }
style={ style={
Object { Object {
"height": 20, "height": 30,
"width": 20, "width": 30,
} }
} }
/> />
@ -3013,8 +3217,8 @@ exports[`Storyshots Message list 1`] = `
} }
style={ style={
Object { Object {
"height": 20, "height": 30,
"width": 20, "width": 30,
} }
} }
/> />
@ -3027,6 +3231,654 @@ exports[`Storyshots Message list 1`] = `
"uri": "https://open.rocket.chat/emoji-custom/marioparty.gif", "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={ style={
Object { Object {
"height": 20, "height": 20,
@ -3034,6 +3886,9 @@ exports[`Storyshots Message list 1`] = `
} }
} }
/> />
<Text>
🤙🤙
</Text>
</Text> </Text>
</Text> </Text>
</View> </View>

View File

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

View File

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

View File

@ -9,6 +9,7 @@ public class BasePackageList {
return Arrays.<Package>asList( return Arrays.<Package>asList(
new expo.modules.constants.ConstantsPackage(), new expo.modules.constants.ConstantsPackage(),
new expo.modules.filesystem.FileSystemPackage(), new expo.modules.filesystem.FileSystemPackage(),
new expo.modules.haptics.HapticsPackage(),
new expo.modules.permissions.PermissionsPackage(), new expo.modules.permissions.PermissionsPackage(),
new expo.modules.webbrowser.WebBrowserPackage() 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') project(':react-native-device-info').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-device-info/android')
include ':react-native-gesture-handler' include ':react-native-gesture-handler'
project(':react-native-gesture-handler').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-gesture-handler/android') 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' 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') project(':react-native-image-crop-picker').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-image-crop-picker/android')
include ':react-native-i18n' 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_DANGER = '#f5455c';
export const COLOR_SUCCESS = '#2de0a5'; 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_TITLE = isIOS ? COLOR_TITLE : COLOR_WHITE;
export const HEADER_BACK = isIOS ? COLOR_PRIMARY : COLOR_WHITE; export const HEADER_BACK = isIOS ? COLOR_PRIMARY : COLOR_WHITE;
export const HEADER_TINT = 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: { API_Gitlab_URL: {
type: 'valueAsString' 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 { View } from 'react-native';
import FastImage from 'react-native-fast-image'; 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(({ const Avatar = React.memo(({
text, size, baseUrl, borderRadius, style, avatar, type, children, userId, token 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 }`; 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 = ( const image = (
<FastImage <FastImage

View File

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

View File

@ -4,6 +4,8 @@ import { Alert, Clipboard, Share } from 'react-native';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import ActionSheet from 'react-native-action-sheet'; import ActionSheet from 'react-native-action-sheet';
import moment from 'moment'; import moment from 'moment';
import * as Haptics from 'expo-haptics';
import { import {
actionsHide as actionsHideAction, actionsHide as actionsHideAction,
deleteRequest as deleteRequestAction, deleteRequest as deleteRequestAction,
@ -13,11 +15,12 @@ import {
toggleReactionPicker as toggleReactionPickerAction, toggleReactionPicker as toggleReactionPickerAction,
toggleStarRequest as toggleStarRequestAction toggleStarRequest as toggleStarRequestAction
} from '../actions/messages'; } from '../actions/messages';
import { vibrate } from '../utils/vibration';
import RocketChat from '../lib/rocketchat'; import RocketChat from '../lib/rocketchat';
import database from '../lib/realm';
import I18n from '../i18n'; import I18n from '../i18n';
import log from '../utils/log'; import log from '../utils/log';
import Navigation from '../lib/Navigation'; import Navigation from '../lib/Navigation';
import { getMessageTranslation } from './message/utils';
@connect( @connect(
state => ({ state => ({
@ -46,7 +49,7 @@ export default class MessageActions extends React.Component {
room: PropTypes.object.isRequired, room: PropTypes.object.isRequired,
actionMessage: PropTypes.object, actionMessage: PropTypes.object,
toast: PropTypes.element, toast: PropTypes.element,
// user: PropTypes.object.isRequired, user: PropTypes.object,
deleteRequest: PropTypes.func.isRequired, deleteRequest: PropTypes.func.isRequired,
editInit: PropTypes.func.isRequired, editInit: PropTypes.func.isRequired,
toggleStarRequest: 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; 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 // Report
this.options.push(I18n.t('Report')); this.options.push(I18n.t('Report'));
this.REPORT_INDEX = this.options.length - 1; this.REPORT_INDEX = this.options.length - 1;
@ -138,7 +147,7 @@ export default class MessageActions extends React.Component {
} }
setTimeout(() => { setTimeout(() => {
this.showActionSheet(); 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) => { handleActionPress = (actionIndex) => {
if (actionIndex) { if (actionIndex) {
switch (actionIndex) { switch (actionIndex) {
@ -365,6 +391,9 @@ export default class MessageActions extends React.Component {
case this.READ_RECEIPT_INDEX: case this.READ_RECEIPT_INDEX:
this.handleReadReceipt(); this.handleReadReceipt();
break; break;
case this.TOGGLE_TRANSLATION_INDEX:
this.handleToggleTranslation();
break;
default: default:
break; break;
} }

View File

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

View File

@ -20,6 +20,33 @@ const formatText = text => text.replace(
(match, url, title) => `[${ title }](${ url })` (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(({ const Markdown = React.memo(({
msg, style, rules, baseUrl, username, isEdited, numberOfLines, mentions, channels, getCustomEmoji, useMarkdown = true msg, style, rules, baseUrl, username, isEdited, numberOfLines, mentions, channels, getCustomEmoji, useMarkdown = true
}) => { }) => {
@ -30,7 +57,7 @@ const Markdown = React.memo(({
if (m) { if (m) {
m = emojify(m, { output: 'unicode' }); m = emojify(m, { output: 'unicode' });
} }
m = m.replace(/^\[([^\]]*)\]\(([^)]*)\)/, '').trim(); m = m.replace(/^\[([^\]]*)\]\(([^)]*)\)\s/, '').trim();
if (numberOfLines > 0) { if (numberOfLines > 0) {
m = m.replace(/[\n]+/g, '\n').trim(); m = m.replace(/[\n]+/g, '\n').trim();
} }
@ -39,6 +66,8 @@ const Markdown = React.memo(({
return <Text style={styles.text} numberOfLines={numberOfLines}>{m}</Text>; return <Text style={styles.text} numberOfLines={numberOfLines}>{m}</Text>;
} }
const isMessageContainsOnlyEmoji = isOnlyEmoji(m) && emojiCount(m) <= 3;
return ( return (
<MarkdownRenderer <MarkdownRenderer
rules={{ rules={{
@ -87,7 +116,14 @@ const Markdown = React.memo(({
const { content } = node.children[0]; const { content } = node.children[0];
const emoji = getCustomEmoji && getCustomEmoji(content); const emoji = getCustomEmoji && getCustomEmoji(content);
if (emoji) { 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>; return <Text key={node.key}>:{content}:</Text>;
} }
@ -102,7 +138,7 @@ const Markdown = React.memo(({
}} }}
style={{ style={{
paragraph: styles.paragraph, paragraph: styles.paragraph,
text: styles.text, text: isMessageContainsOnlyEmoji ? styles.textBig : styles.text,
codeInline: styles.codeInline, codeInline: styles.codeInline,
codeBlock: styles.codeBlock, codeBlock: styles.codeBlock,
link: styles.link, link: styles.link,

View File

@ -4,7 +4,7 @@ import { KeyboardUtils } from 'react-native-keyboard-input';
import Message from './Message'; import Message from './Message';
import debounce from '../../utils/debounce'; import debounce from '../../utils/debounce';
import { SYSTEM_MESSAGES, getCustomEmoji } from './utils'; import { SYSTEM_MESSAGES, getCustomEmoji, getMessageTranslation } from './utils';
import messagesStatus from '../../constants/messagesStatus'; import messagesStatus from '../../constants/messagesStatus';
export default class MessageContainer extends React.Component { export default class MessageContainer extends React.Component {
@ -27,6 +27,8 @@ export default class MessageContainer extends React.Component {
isReadReceiptEnabled: PropTypes.bool, isReadReceiptEnabled: PropTypes.bool,
useRealName: PropTypes.bool, useRealName: PropTypes.bool,
useMarkdown: PropTypes.bool, useMarkdown: PropTypes.bool,
autoTranslateRoom: PropTypes.bool,
autoTranslateLanguage: PropTypes.string,
status: PropTypes.number, status: PropTypes.number,
onLongPress: PropTypes.func, onLongPress: PropTypes.func,
onReactionPress: PropTypes.func, onReactionPress: PropTypes.func,
@ -49,12 +51,15 @@ export default class MessageContainer extends React.Component {
shouldComponentUpdate(nextProps) { shouldComponentUpdate(nextProps) {
const { const {
status, item, _updatedAt status, item, _updatedAt, autoTranslateRoom
} = this.props; } = this.props;
if (status !== nextProps.status) { if (status !== nextProps.status) {
return true; return true;
} }
if (autoTranslateRoom !== nextProps.autoTranslateRoom) {
return true;
}
if (item.tmsg !== nextProps.item.tmsg) { if (item.tmsg !== nextProps.item.tmsg) {
return true; return true;
} }
@ -191,16 +196,23 @@ export default class MessageContainer extends React.Component {
render() { render() {
const { 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; } = this.props;
const { 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; } = 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 ( return (
<Message <Message
id={_id} id={_id}
msg={msg} msg={message}
author={u} author={u}
ts={ts} ts={ts}
type={t} type={t}

View File

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

View File

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

View File

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

View File

@ -36,6 +36,10 @@ export default (msg) => {
if (!Array.isArray(msg.reactions)) { if (!Array.isArray(msg.reactions)) {
msg.reactions = Object.keys(msg.reactions).map(key => ({ _id: `${ msg._id }${ key }`, emoji: key, usernames: msg.reactions[key].usernames })); 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.urls = msg.urls ? parseUrls(msg.urls) : [];
msg._updatedAt = new Date(); msg._updatedAt = new Date();
// loadHistory returns msg.starred as object // loadHistory returns msg.starred as object

View File

@ -1,111 +1,129 @@
import RNFetchBlob from 'rn-fetch-blob';
import reduxStore from '../createStore'; import reduxStore from '../createStore';
import database from '../realm'; import database from '../realm';
import log from '../../utils/log'; import log from '../../utils/log';
const promises = {}; const uploadQueue = {};
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);
}
export function isUploadActive(path) { export function isUploadActive(path) {
return !!promises[path]; return !!uploadQueue[path];
} }
export async function cancelUpload(path) { export function cancelUpload(path) {
if (promises[path]) { if (uploadQueue[path]) {
await promises[path].cancel(); uploadQueue[path].abort();
}
}
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;
database.write(() => { database.write(() => {
try { const upload = database.objects('uploads').filtered('path = $0', path);
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);
try { try {
database.delete(upload); database.delete(upload);
} catch (e) { } catch (e) {
log('err_send_file_message_delete_upload', e); log('err_send_file_message_delete_upload', e);
} }
}); });
} catch (e) { delete uploadQueue[path];
database.write(() => {
fileInfo.error = true;
try {
database.create('uploads', fileInfo, true);
} catch (err) {
log('err_send_file_message_create_upload_3', err);
}
});
} }
} }
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(); // Realm.clearTestState();
// AsyncStorage.clear(); // 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 = { const serversSchema = {
name: 'servers', name: 'servers',
primaryKey: 'id', primaryKey: 'id',
@ -82,7 +96,9 @@ const subscriptionSchema = {
broadcast: { type: 'bool', optional: true }, broadcast: { type: 'bool', optional: true },
prid: { type: 'string', optional: true }, prid: { type: 'string', optional: true },
draftMessage: { 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 = { const messagesEditedBySchema = {
name: 'messagesEditedBy', name: 'messagesEditedBy',
primaryKey: '_id', primaryKey: '_id',
@ -198,7 +224,9 @@ const messagesSchema = {
replies: 'string[]', replies: 'string[]',
mentions: { type: 'list', objectType: 'users' }, mentions: { type: 'list', objectType: 'users' },
channels: { type: 'list', objectType: 'rooms' }, 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 }, tcount: { type: 'int', optional: true },
tlm: { type: 'date', optional: true }, tlm: { type: 'date', optional: true },
replies: 'string[]', 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?' draftMessage: 'string?'
} }
}; };
@ -258,7 +291,13 @@ const threadMessagesSchema = {
starred: { type: 'bool', optional: true }, starred: { type: 'bool', optional: true },
editedBy: 'messagesEditedBy', editedBy: 'messagesEditedBy',
reactions: { type: 'list', objectType: 'messagesReactions' }, 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, messagesReactionsSchema,
rolesSchema, rolesSchema,
uploadsSchema, uploadsSchema,
slashCommandSchema slashCommandSchema,
messagesTranslationsSchema
]; ];
const inMemorySchema = [usersTypingSchema, activeUsersSchema]; const inMemorySchema = [usersTypingSchema, activeUsersSchema];
@ -370,11 +410,12 @@ class DB {
serversDB: new Realm({ serversDB: new Realm({
path: 'default.realm', path: 'default.realm',
schema: [ schema: [
userSchema,
serversSchema serversSchema
], ],
schemaVersion: 8, schemaVersion: 9,
migration: (oldRealm, newRealm) => { migration: (oldRealm, newRealm) => {
if (oldRealm.schemaVersion >= 1 && newRealm.schemaVersion <= 8) { if (oldRealm.schemaVersion >= 1 && newRealm.schemaVersion <= 9) {
const newServers = newRealm.objects('servers'); const newServers = newRealm.objects('servers');
// eslint-disable-next-line no-plusplus // eslint-disable-next-line no-plusplus
@ -429,9 +470,9 @@ class DB {
return this.databases.activeDB = new Realm({ return this.databases.activeDB = new Realm({
path: `${ path }.realm`, path: `${ path }.realm`,
schema, schema,
schemaVersion: 12, schemaVersion: 13,
migration: (oldRealm, newRealm) => { migration: (oldRealm, newRealm) => {
if (oldRealm.schemaVersion >= 3 && newRealm.schemaVersion <= 11) { if (oldRealm.schemaVersion >= 3 && newRealm.schemaVersion <= 13) {
const newSubs = newRealm.objects('subscriptions'); const newSubs = newRealm.objects('subscriptions');
newRealm.delete(newSubs); newRealm.delete(newSubs);
const newMessages = newRealm.objects('messages'); const newMessages = newRealm.objects('messages');

View File

@ -1,6 +1,7 @@
import { AsyncStorage, InteractionManager } from 'react-native'; import { AsyncStorage, InteractionManager } from 'react-native';
import semver from 'semver'; import semver from 'semver';
import { Rocketchat as RocketchatClient } from '@rocket.chat/sdk'; import { Rocketchat as RocketchatClient } from '@rocket.chat/sdk';
import RNUserDefaults from 'rn-user-defaults';
import reduxStore from './createStore'; import reduxStore from './createStore';
import defaultSettings from '../constants/settings'; import defaultSettings from '../constants/settings';
@ -36,6 +37,7 @@ import sendMessage, { getMessage, sendMessageCall } from './methods/sendMessage'
import { sendFileMessage, cancelUpload, isUploadActive } from './methods/sendFileMessage'; import { sendFileMessage, cancelUpload, isUploadActive } from './methods/sendFileMessage';
import { getDeviceToken } from '../notifications/push'; import { getDeviceToken } from '../notifications/push';
import { SERVERS, SERVER_URL } from '../constants/userDefaults';
const TOKEN_KEY = 'reactnativemeteor_usertoken'; const TOKEN_KEY = 'reactnativemeteor_usertoken';
const SORT_PREFS_KEY = 'RC_SORT_PREFS_KEY'; const SORT_PREFS_KEY = 'RC_SORT_PREFS_KEY';
@ -58,9 +60,9 @@ const RocketChat = {
}, },
async getUserToken() { async getUserToken() {
try { try {
return await AsyncStorage.getItem(TOKEN_KEY); return await RNUserDefaults.get(TOKEN_KEY);
} catch (error) { } catch (error) {
console.warn(`AsyncStorage error: ${ error.message }`); console.warn(`RNUserDefaults error: ${ error.message }`);
} }
}, },
async getServerInfo(server) { async getServerInfo(server) {
@ -321,10 +323,26 @@ const RocketChat = {
} }
this.sdk = null; 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([ Promise.all([
AsyncStorage.removeItem('currentServer'), RNUserDefaults.clear('currentServer'),
AsyncStorage.removeItem(TOKEN_KEY), RNUserDefaults.clear(TOKEN_KEY),
AsyncStorage.removeItem(`${ TOKEN_KEY }-${ server }`) RNUserDefaults.clear(`${ TOKEN_KEY }-${ server }`)
]).catch(error => console.log(error)); ]).catch(error => console.log(error));
try { try {
@ -564,6 +582,12 @@ const RocketChat = {
// RC 0.64.0 // RC 0.64.0
return this.sdk.post('rooms.favorite', { roomId, favorite }); 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) { getRoomMembers(rid, allUsers, skip = 0, limit = 10) {
// RC 0.42.0 // RC 0.42.0
return this.sdk.methodCall('getUsersOfRoom', rid, allUsers, { skip, limit }); return this.sdk.methodCall('getUsersOfRoom', rid, allUsers, { skip, limit });
@ -622,6 +646,9 @@ const RocketChat = {
// RC 0.48.0 // RC 0.48.0
return this.sdk.post(`${ this.roomTypeToApiType(t) }.unarchive`, { roomId }); return this.sdk.post(`${ this.roomTypeToApiType(t) }.unarchive`, { roomId });
}, },
hideRoom(roomId, t) {
return this.sdk.post(`${ this.roomTypeToApiType(t) }.close`, { roomId });
},
saveRoomSettings(rid, params) { saveRoomSettings(rid, params) {
// RC 0.55.0 // RC 0.55.0
return this.sdk.methodCall('saveRoomSettings', rid, params); return this.sdk.methodCall('saveRoomSettings', rid, params);
@ -863,6 +890,31 @@ const RocketChat = {
return this.sdk.get('directory', { return this.sdk.get('directory', {
query, count, offset, sort 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 React from 'react';
import moment from 'moment'; import moment from 'moment';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { View, Text } from 'react-native'; import { View, Text, Animated } from 'react-native';
import { connect } from 'react-redux'; import { RectButton, PanGestureHandler, State } from 'react-native-gesture-handler';
import { RectButton } from 'react-native-gesture-handler';
import Avatar from '../../containers/Avatar'; import Avatar from '../../containers/Avatar';
import I18n from '../../i18n'; 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 UnreadBadge from './UnreadBadge';
import TypeIcon from './TypeIcon'; import TypeIcon from './TypeIcon';
import LastMessage from './LastMessage'; import LastMessage from './LastMessage';
import { LeftActions, RightActions } from './Actions';
export { ROW_HEIGHT }; export { ROW_HEIGHT };
const attrs = ['name', 'unread', 'userMentions', 'showLastMessage', 'alert', 'type']; const attrs = ['name', 'unread', 'userMentions', 'showLastMessage', 'alert', 'type', 'width', 'isRead', 'favorite'];
@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
}))
export default class RoomItem extends React.Component { export default class RoomItem extends React.Component {
static propTypes = { static propTypes = {
type: PropTypes.string.isRequired, type: PropTypes.string.isRequired,
@ -39,7 +37,13 @@ export default class RoomItem extends React.Component {
token: PropTypes.string, token: PropTypes.string,
avatarSize: PropTypes.number, avatarSize: PropTypes.number,
testID: PropTypes.string, 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 = { static defaultProps = {
@ -50,6 +54,19 @@ export default class RoomItem extends React.Component {
// eslint-disable-next-line no-useless-constructor // eslint-disable-next-line no-useless-constructor
constructor(props) { constructor(props) {
super(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) { shouldComponentUpdate(nextProps) {
@ -60,13 +77,132 @@ export default class RoomItem extends React.Component {
if (oldlastMessage && newLastmessage && oldlastMessage.ts !== newLastmessage.ts) { if (oldlastMessage && newLastmessage && oldlastMessage.ts !== newLastmessage.ts) {
return true; return true;
} }
if (_updatedAt && nextProps._updatedAt && nextProps._updatedAt !== _updatedAt) { if (_updatedAt && nextProps._updatedAt && nextProps._updatedAt.toISOString() !== _updatedAt.toISOString()) {
return true; return true;
} }
// eslint-disable-next-line react/destructuring-assignment // eslint-disable-next-line react/destructuring-assignment
return attrs.some(key => nextProps[key] !== this.props[key]); 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, { formatDate = date => moment(date).calendar(null, {
lastDay: `[${ I18n.t('Yesterday') }]`, lastDay: `[${ I18n.t('Yesterday') }]`,
sameDay: 'h:mm A', sameDay: 'h:mm A',
@ -76,7 +212,7 @@ export default class RoomItem extends React.Component {
render() { render() {
const { 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; } = this.props;
const date = this.formatDate(_updatedAt); const date = this.formatDate(_updatedAt);
@ -97,30 +233,60 @@ export default class RoomItem extends React.Component {
} }
return ( return (
<RectButton <PanGestureHandler
onPress={onPress} minDeltaX={20}
activeOpacity={0.8} onGestureEvent={this._onGestureEvent}
underlayColor='#e1e5e8' onHandlerStateChange={this._onHandlerStateChange}
testID={testID}
> >
<View <Animated.View>
style={[styles.container, height && { height }]} <LeftActions
accessibilityLabel={accessibilityLabel} transX={this.transX}
> isRead={isRead}
<Avatar text={name} size={avatarSize} type={type} baseUrl={baseUrl} style={styles.avatar} userId={userId} token={token} /> width={width}
<View style={styles.centerContainer}> onToggleReadPress={this.onToggleReadPress}
<View style={styles.titleContainer}> />
<TypeIcon type={type} id={id} prid={prid} /> <RightActions
<Text style={[styles.title, alert && styles.alert]} ellipsizeMode='tail' numberOfLines={1}>{ name }</Text> transX={this.transX}
{_updatedAt ? <Text style={[styles.date, alert && styles.updateAlert]} ellipsizeMode='tail' numberOfLines={1}>{ date }</Text> : null} favorite={favorite}
</View> width={width}
<View style={styles.row}> toggleFav={this.toggleFav}
<LastMessage lastMessage={lastMessage} type={type} showLastMessage={showLastMessage} username={username} alert={alert} /> onHidePress={this.onHidePress}
<UnreadBadge unread={unread} userMentions={userMentions} type={type} /> />
</View> <Animated.View
</View> style={
</View> {
</RectButton> 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'; } from '../../constants/colors';
export const ROW_HEIGHT = 75 * PixelRatio.getFontScale(); 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({ export default StyleSheet.create({
container: { container: {
flexDirection: 'row', flexDirection: 'row',
alignItems: 'center', alignItems: 'center',
marginLeft: 14, paddingLeft: 14,
height: ROW_HEIGHT height: ROW_HEIGHT
}, },
button: {
backgroundColor: COLOR_WHITE
},
centerContainer: { centerContainer: {
flex: 1, flex: 1,
paddingVertical: 10, paddingVertical: 10,
@ -93,5 +99,42 @@ export default StyleSheet.create({
}, },
avatar: { avatar: {
marginRight: 10 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 { delay } from 'redux-saga';
import { import {
takeLatest, take, select, put, all takeLatest, take, select, put, all
} from 'redux-saga/effects'; } from 'redux-saga/effects';
import RNUserDefaults from 'rn-user-defaults';
import Navigation from '../lib/Navigation'; import Navigation from '../lib/Navigation';
import * as types from '../actions/actionsTypes'; import * as types from '../actions/actionsTypes';
@ -11,6 +11,7 @@ import database from '../lib/realm';
import RocketChat from '../lib/rocketchat'; import RocketChat from '../lib/rocketchat';
import EventEmitter from '../utils/events'; import EventEmitter from '../utils/events';
import { appStart } from '../actions'; import { appStart } from '../actions';
import { isIOS } from '../utils/deviceInfo';
const roomTypes = { const roomTypes = {
channel: 'c', direct: 'd', group: 'p' channel: 'c', direct: 'd', group: 'p'
@ -33,6 +34,10 @@ const handleOpen = function* handleOpen({ params }) {
return; return;
} }
if (isIOS) {
yield RNUserDefaults.setName('group.ios.chat.rocket');
}
let { host } = params; let { host } = params;
if (!/^(http|https)/.test(host)) { if (!/^(http|https)/.test(host)) {
host = `https://${ params.host }`; host = `https://${ params.host }`;
@ -43,8 +48,8 @@ const handleOpen = function* handleOpen({ params }) {
} }
const [server, user] = yield all([ const [server, user] = yield all([
AsyncStorage.getItem('currentServer'), RNUserDefaults.get('currentServer'),
AsyncStorage.getItem(`${ RocketChat.TOKEN_KEY }-${ host }`) RNUserDefaults.get(`${ RocketChat.TOKEN_KEY }-${ host }`)
]); ]);
// TODO: needs better test // TODO: needs better test

View File

@ -1,6 +1,7 @@
import { AsyncStorage } from 'react-native'; import { AsyncStorage } from 'react-native';
import { put, takeLatest, all } from 'redux-saga/effects'; import { put, takeLatest, all } from 'redux-saga/effects';
import SplashScreen from 'react-native-splash-screen'; import SplashScreen from 'react-native-splash-screen';
import RNUserDefaults from 'rn-user-defaults';
import * as actions from '../actions'; import * as actions from '../actions';
import { selectServerRequest } from '../actions/server'; import { selectServerRequest } from '../actions/server';
@ -11,14 +12,54 @@ import RocketChat from '../lib/rocketchat';
import log from '../utils/log'; import log from '../utils/log';
import Navigation from '../lib/Navigation'; import Navigation from '../lib/Navigation';
import database from '../lib/realm'; 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() { const restore = function* restore() {
try { try {
const { token, server } = yield all({ let hasMigration;
token: AsyncStorage.getItem(RocketChat.TOKEN_KEY), if (isIOS) {
server: AsyncStorage.getItem('currentServer') 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(); const sortPreferences = yield RocketChat.getSortPreferences();
yield put(setAllPreferences(sortPreferences)); yield put(setAllPreferences(sortPreferences));
@ -27,8 +68,8 @@ const restore = function* restore() {
if (!token || !server) { if (!token || !server) {
yield all([ yield all([
AsyncStorage.removeItem(RocketChat.TOKEN_KEY), RNUserDefaults.clear(RocketChat.TOKEN_KEY),
AsyncStorage.removeItem('currentServer') RNUserDefaults.clear('currentServer')
]); ]);
yield put(actions.appStart('outside')); yield put(actions.appStart('outside'));
} else if (server) { } else if (server) {

View File

@ -1,7 +1,7 @@
import { AsyncStorage } from 'react-native';
import { import {
put, call, takeLatest, select, take, fork, cancel put, call, takeLatest, select, take, fork, cancel
} from 'redux-saga/effects'; } from 'redux-saga/effects';
import RNUserDefaults from 'rn-user-defaults';
import * as types from '../actions/actionsTypes'; import * as types from '../actions/actionsTypes';
import { appStart } from '../actions'; import { appStart } from '../actions';
@ -60,7 +60,7 @@ const fetchUserPresence = function* fetchUserPresence() {
const handleLoginSuccess = function* handleLoginSuccess({ user }) { const handleLoginSuccess = function* handleLoginSuccess({ user }) {
try { try {
const adding = yield select(state => state.server.adding); 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); const server = yield select(getServer);
yield put(roomsRequest()); yield put(roomsRequest());
@ -72,7 +72,17 @@ const handleLoginSuccess = function* handleLoginSuccess({ user }) {
yield fork(fetchUserPresence); yield fork(fetchUserPresence);
I18n.locale = user.language; 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)); yield put(setUser(user));
EventEmitter.emit('connected'); EventEmitter.emit('connected');
@ -105,7 +115,7 @@ const handleLogout = function* handleLogout() {
// see if there's other logged in servers and selects first one // see if there's other logged in servers and selects first one
if (servers.length > 0) { if (servers.length > 0) {
const newServer = servers[0].id; 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) { if (token) {
return yield put(selectServerRequest(newServer)); return yield put(selectServerRequest(newServer));
} }

View File

@ -1,7 +1,8 @@
import { import {
put, take, takeLatest, fork, cancel, race put, take, takeLatest, fork, cancel, race
} from 'redux-saga/effects'; } 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 Navigation from '../lib/Navigation';
import { SERVER } from '../actions/actionsTypes'; import { SERVER } from '../actions/actionsTypes';
@ -14,6 +15,7 @@ import RocketChat from '../lib/rocketchat';
import database from '../lib/realm'; import database from '../lib/realm';
import log from '../utils/log'; import log from '../utils/log';
import I18n from '../i18n'; import I18n from '../i18n';
import { SERVERS, TOKEN, SERVER_URL } from '../constants/userDefaults';
const getServerInfo = function* getServerInfo({ server, raiseError = true }) { const getServerInfo = function* getServerInfo({ server, raiseError = true }) {
try { try {
@ -38,13 +40,21 @@ const getServerInfo = function* getServerInfo({ server, raiseError = true }) {
const handleSelectServer = function* handleSelectServer({ server, version, fetchVersion }) { const handleSelectServer = function* handleSelectServer({ server, version, fetchVersion }) {
try { try {
yield AsyncStorage.setItem('currentServer', server); const { serversDB } = database.databases;
const userStringified = yield AsyncStorage.getItem(`${ RocketChat.TOKEN_KEY }-${ server }`);
if (userStringified) { yield RNUserDefaults.set('currentServer', server);
const user = JSON.parse(userStringified); const userId = yield RNUserDefaults.get(`${ RocketChat.TOKEN_KEY }-${ server }`);
yield RocketChat.connect({ server, user }); const user = userId && serversDB.objectForPrimaryKey('user', userId);
yield put(setUser(user));
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')); yield put(actions.appStart('inside'));
} else { } else {
yield RocketChat.connect({ server }); 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 I18n from '../i18n';
import UserItem from '../presentation/UserItem'; import UserItem from '../presentation/UserItem';
import { showErrorAlert } from '../utils/info'; import { showErrorAlert } from '../utils/info';
import { isAndroid } from '../utils/deviceInfo';
import { CustomHeaderButtons, Item } from '../containers/HeaderButton'; import { CustomHeaderButtons, Item } from '../containers/HeaderButton';
import StatusBar from '../containers/StatusBar'; 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({ const styles = StyleSheet.create({
container: { container: {
@ -245,8 +244,7 @@ export default class CreateChannelView extends React.Component {
value={value} value={value}
onValueChange={onValueChange} onValueChange={onValueChange}
testID={`create-channel-${ id }`} testID={`create-channel-${ id }`}
onTintColor='#2de0a5' trackColor={SWITCH_TRACK_COLOR}
tintColor={isAndroid ? '#f5455c' : null}
disabled={disabled} disabled={disabled}
/> />
</View> </View>

View File

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

View File

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

View File

@ -5,6 +5,8 @@ import {
} from 'react-native'; } from 'react-native';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { SafeAreaView } from 'react-navigation'; import { SafeAreaView } from 'react-navigation';
import RNPickerSelect from 'react-native-picker-select';
import equal from 'deep-equal';
import TextInput from '../containers/TextInput'; import TextInput from '../containers/TextInput';
import Button from '../containers/Button'; import Button from '../containers/Button';
@ -17,10 +19,13 @@ import { loginRequest as loginRequestAction } from '../actions/login';
import isValidEmail from '../utils/isValidEmail'; import isValidEmail from '../utils/isValidEmail';
import { LegalButton } from '../containers/HeaderButton'; import { LegalButton } from '../containers/HeaderButton';
import StatusBar from '../containers/StatusBar'; import StatusBar from '../containers/StatusBar';
import log from '../utils/log';
const shouldUpdateState = ['name', 'email', 'password', 'username', 'saving']; const shouldUpdateState = ['name', 'email', 'password', 'username', 'saving'];
@connect(null, dispatch => ({ @connect(state => ({
Accounts_CustomFields: state.settings.Accounts_CustomFields
}), dispatch => ({
loginRequest: params => dispatch(loginRequestAction(params)) loginRequest: params => dispatch(loginRequestAction(params))
})) }))
export default class RegisterView extends React.Component { export default class RegisterView extends React.Component {
@ -35,15 +40,34 @@ export default class RegisterView extends React.Component {
static propTypes = { static propTypes = {
navigation: PropTypes.object, navigation: PropTypes.object,
loginRequest: PropTypes.func, loginRequest: PropTypes.func,
Site_Name: PropTypes.string Site_Name: PropTypes.string,
Accounts_CustomFields: PropTypes.string
} }
state = { constructor(props) {
name: '', super(props);
email: '', const customFields = {};
password: '', this.parsedCustomFields = {};
username: '', if (props.Accounts_CustomFields) {
saving: false 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() { componentDidMount() {
@ -53,6 +77,10 @@ export default class RegisterView extends React.Component {
} }
shouldComponentUpdate(nextProps, nextState) { shouldComponentUpdate(nextProps, nextState) {
const { customFields } = this.state;
if (!equal(nextState.customFields, customFields)) {
return true;
}
// eslint-disable-next-line react/destructuring-assignment // eslint-disable-next-line react/destructuring-assignment
return shouldUpdateState.some(key => nextState[key] !== this.state[key]); return shouldUpdateState.some(key => nextState[key] !== this.state[key]);
} }
@ -77,9 +105,15 @@ export default class RegisterView extends React.Component {
valid = () => { valid = () => {
const { const {
name, email, password, username name, email, password, username, customFields
} = this.state; } = 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() => { submit = async() => {
@ -90,13 +124,13 @@ export default class RegisterView extends React.Component {
Keyboard.dismiss(); Keyboard.dismiss();
const { const {
name, email, password, username name, email, password, username, customFields
} = this.state; } = this.state;
const { loginRequest } = this.props; const { loginRequest } = this.props;
try { try {
await RocketChat.register({ await RocketChat.register({
name, email, pass: password, username name, email, pass: password, username, ...customFields
}); });
await loginRequest({ user: email, password }); await loginRequest({ user: email, password });
} catch (e) { } catch (e) {
@ -105,6 +139,64 @@ export default class RegisterView extends React.Component {
this.setState({ saving: false }); 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() { render() {
const { saving } = this.state; const { saving } = this.state;
return ( return (
@ -153,6 +245,8 @@ export default class RegisterView extends React.Component {
containerStyle={sharedStyles.inputLastChild} containerStyle={sharedStyles.inputLastChild}
/> />
{this.renderCustomFields()}
<Button <Button
title={I18n.t('Register')} title={I18n.t('Register')}
type='primary' type='primary'

View File

@ -60,7 +60,8 @@ export default class RoomActionsView extends React.Component {
membersCount: 0, membersCount: 0,
member: {}, member: {},
joined: this.rooms.length > 0, 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') { } else if (room.t === 'd') {
this.updateRoomMember(); this.updateRoomMember();
} }
const canAutoTranslate = RocketChat.canAutoTranslate();
this.setState({ canAutoTranslate });
safeAddListener(this.rooms, this.updateRoom); safeAddListener(this.rooms, this.updateRoom);
} }
@ -169,7 +174,7 @@ export default class RoomActionsView extends React.Component {
get sections() { get sections() {
const { const {
room, membersCount, canViewMembers, joined room, membersCount, canViewMembers, joined, canAutoTranslate
} = this.state; } = this.state;
const { const {
rid, t, blocker, notifications rid, t, blocker, notifications
@ -255,6 +260,16 @@ export default class RoomActionsView extends React.Component {
renderItem: this.renderItem 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') { if (t === 'd') {
sections.push({ sections.push({
data: [ data: [

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -152,7 +152,7 @@ export default class Sidebar extends Component {
const permissionsFiltered = database.objects('permissions') const permissionsFiltered = database.objects('permissions')
.filter(permission => permissions.includes(permission._id)); .filter(permission => permissions.includes(permission._id));
return permissionsFiltered.reduce((result, permission) => ( return permissionsFiltered.reduce((result, permission) => (
result || permission.roles.some(r => roles.includes(r))), result || permission.roles.some(r => roles.indexOf(r) !== -1)),
false); false);
} }
return 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): - EXFileSystem (5.0.1):
- UMCore - UMCore
- UMFileSystemInterface - UMFileSystemInterface
- EXHaptics (5.0.1):
- UMCore
- EXPermissions (5.0.1): - EXPermissions (5.0.1):
- UMCore - UMCore
- UMPermissionsInterface - UMPermissionsInterface
@ -171,6 +173,7 @@ DEPENDENCIES:
- EXAppLoaderProvider (from `../node_modules/expo-app-loader-provider/ios`) - EXAppLoaderProvider (from `../node_modules/expo-app-loader-provider/ios`)
- EXConstants (from `../node_modules/expo-constants/ios`) - EXConstants (from `../node_modules/expo-constants/ios`)
- EXFileSystem (from `../node_modules/expo-file-system/ios`) - EXFileSystem (from `../node_modules/expo-file-system/ios`)
- EXHaptics (from `../node_modules/expo-haptics/ios`)
- EXPermissions (from `../node_modules/expo-permissions/ios`) - EXPermissions (from `../node_modules/expo-permissions/ios`)
- EXWebBrowser (from `../node_modules/expo-web-browser/ios`) - EXWebBrowser (from `../node_modules/expo-web-browser/ios`)
- Fabric (~> 1.9.0) - Fabric (~> 1.9.0)
@ -243,6 +246,9 @@ EXTERNAL SOURCES:
EXFileSystem: EXFileSystem:
:path: !ruby/object:Pathname :path: !ruby/object:Pathname
path: "../node_modules/expo-file-system/ios" path: "../node_modules/expo-file-system/ios"
EXHaptics:
:path: !ruby/object:Pathname
path: "../node_modules/expo-haptics/ios"
EXPermissions: EXPermissions:
:path: !ruby/object:Pathname :path: !ruby/object:Pathname
path: "../node_modules/expo-permissions/ios" path: "../node_modules/expo-permissions/ios"
@ -313,6 +319,7 @@ SPEC CHECKSUMS:
EXAppLoaderProvider: 8f2c04a0a8d9be91f7c37c2b8824077ee5d4bc01 EXAppLoaderProvider: 8f2c04a0a8d9be91f7c37c2b8824077ee5d4bc01
EXConstants: 9fe56eec8bf0a3ee9beb8f3381fa91340a5b1e57 EXConstants: 9fe56eec8bf0a3ee9beb8f3381fa91340a5b1e57
EXFileSystem: 96624bd4b93a0684335c421a6567a92b25bd7ddb EXFileSystem: 96624bd4b93a0684335c421a6567a92b25bd7ddb
EXHaptics: 6d594612afa321bfc8e167bdfb0b47f940f8f537
EXPermissions: 8e05008ed4fc8c9be6c17ea95301fc3f3f005a7b EXPermissions: 8e05008ed4fc8c9be6c17ea95301fc3f3f005a7b
EXWebBrowser: e03894b4583bb726e5ea05d01b341ba00134c2b5 EXWebBrowser: e03894b4583bb726e5ea05d01b341ba00134c2b5
Fabric: f988e33c97f08930a413e08123064d2e5f68d655 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): - EXFileSystem (5.0.1):
- UMCore - UMCore
- UMFileSystemInterface - UMFileSystemInterface
- EXHaptics (5.0.1):
- UMCore
- EXPermissions (5.0.1): - EXPermissions (5.0.1):
- UMCore - UMCore
- UMPermissionsInterface - UMPermissionsInterface
@ -171,6 +173,7 @@ DEPENDENCIES:
- EXAppLoaderProvider (from `../node_modules/expo-app-loader-provider/ios`) - EXAppLoaderProvider (from `../node_modules/expo-app-loader-provider/ios`)
- EXConstants (from `../node_modules/expo-constants/ios`) - EXConstants (from `../node_modules/expo-constants/ios`)
- EXFileSystem (from `../node_modules/expo-file-system/ios`) - EXFileSystem (from `../node_modules/expo-file-system/ios`)
- EXHaptics (from `../node_modules/expo-haptics/ios`)
- EXPermissions (from `../node_modules/expo-permissions/ios`) - EXPermissions (from `../node_modules/expo-permissions/ios`)
- EXWebBrowser (from `../node_modules/expo-web-browser/ios`) - EXWebBrowser (from `../node_modules/expo-web-browser/ios`)
- Fabric (~> 1.9.0) - Fabric (~> 1.9.0)
@ -243,6 +246,9 @@ EXTERNAL SOURCES:
EXFileSystem: EXFileSystem:
:path: !ruby/object:Pathname :path: !ruby/object:Pathname
path: "../node_modules/expo-file-system/ios" path: "../node_modules/expo-file-system/ios"
EXHaptics:
:path: !ruby/object:Pathname
path: "../node_modules/expo-haptics/ios"
EXPermissions: EXPermissions:
:path: !ruby/object:Pathname :path: !ruby/object:Pathname
path: "../node_modules/expo-permissions/ios" path: "../node_modules/expo-permissions/ios"
@ -313,6 +319,7 @@ SPEC CHECKSUMS:
EXAppLoaderProvider: 8f2c04a0a8d9be91f7c37c2b8824077ee5d4bc01 EXAppLoaderProvider: 8f2c04a0a8d9be91f7c37c2b8824077ee5d4bc01
EXConstants: 9fe56eec8bf0a3ee9beb8f3381fa91340a5b1e57 EXConstants: 9fe56eec8bf0a3ee9beb8f3381fa91340a5b1e57
EXFileSystem: 96624bd4b93a0684335c421a6567a92b25bd7ddb EXFileSystem: 96624bd4b93a0684335c421a6567a92b25bd7ddb
EXHaptics: 6d594612afa321bfc8e167bdfb0b47f940f8f537
EXPermissions: 8e05008ed4fc8c9be6c17ea95301fc3f3f005a7b EXPermissions: 8e05008ed4fc8c9be6c17ea95301fc3f3f005a7b
EXWebBrowser: e03894b4583bb726e5ea05d01b341ba00134c2b5 EXWebBrowser: e03894b4583bb726e5ea05d01b341ba00134c2b5
Fabric: f988e33c97f08930a413e08123064d2e5f68d655 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" 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 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 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}/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" 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"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" 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_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 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" 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 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 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}/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" 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"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" 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_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_PODFILE_DIR_PATH = ${SRCROOT}/. PODS_PODFILE_DIR_PATH = ${SRCROOT}/.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

114
yarn.lock
View File

@ -49,6 +49,26 @@
semver "^5.4.1" semver "^5.4.1"
source-map "^0.5.0" 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": "@babel/generator@^7.0.0", "@babel/generator@^7.2.2":
version "7.3.0" version "7.3.0"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.3.0.tgz#f663838cd7b542366de3aa608a657b8ccb2a99eb" 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" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.4.4.tgz#5977129431b8fe33471730d255ce8654ae1250b6"
integrity sha512-5pCS4mOsL+ANsFZGdvNLybx4wtqAZJ0MJjMHxvzI3bvIsz6sQvzW8XX92EYIkiPtIvcfG3Aj+Ir5VNyjnZhP7w== 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": "@babel/plugin-external-helpers@^7.0.0":
version "7.2.0" version "7.2.0"
resolved "https://registry.yarnpkg.com/@babel/plugin-external-helpers/-/plugin-external-helpers-7.2.0.tgz#7f4cb7dee651cd380d2034847d914288467a6be4" 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" globals "^11.1.0"
lodash "^4.17.11" 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": "@babel/types@^7.0.0", "@babel/types@^7.2.0", "@babel/types@^7.2.2", "@babel/types@^7.3.0":
version "7.3.0" version "7.3.0"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.3.0.tgz#61dc0b336a93badc02bf5f69c4cd8e1353f2ffc0" 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" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= 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: base64-js@^1.0.2, base64-js@^1.1.2, base64-js@^1.2.3:
version "1.3.0" version "1.3.0"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" 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" readable-stream "^2.3.5"
safe-buffer "^5.1.1" 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" version "3.5.3"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.3.tgz#7d01c6f9616c9a51ab0f8c549a79dfe6ec33efa7" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.3.tgz#7d01c6f9616c9a51ab0f8c549a79dfe6ec33efa7"
integrity sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw== integrity sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==
@ -4906,16 +4946,18 @@ detect-port@^1.2.3:
address "^1.0.1" address "^1.0.1"
debug "^2.6.0" debug "^2.6.0"
detox@12.8.0: detox@12.11.3:
version "12.8.0" version "12.11.3"
resolved "https://registry.yarnpkg.com/detox/-/detox-12.8.0.tgz#68cf92ff02fcdb896f05c67b2b40a8c94d09b24b" resolved "https://registry.yarnpkg.com/detox/-/detox-12.11.3.tgz#510de28c47f2542a8bc4ddab4ceaa7859e1db7e9"
integrity sha512-mDe4HcrfUePokhgv6gZADzqqgE6BxYnHXNm4qi5WrwgPJJQMjTLeJOsD7Z6t02SoK5G5Uvq3rx9Z7eI+Xgb3iQ== integrity sha512-Ds1x6VLWjUsIR6FDXORan7NxRlugI4RCCpH5n3L++UIBuMvSicaWSKcmU0rCYCFUeluKDofx+QBgnEryNxRUSg==
dependencies: dependencies:
"@babel/core" "^7.4.5"
bunyan "^1.8.12" bunyan "^1.8.12"
bunyan-debug-stream "^1.1.0" bunyan-debug-stream "^1.1.0"
chalk "^2.4.2" chalk "^2.4.2"
child-process-promise "^2.2.0" child-process-promise "^2.2.0"
fs-extra "^4.0.2" fs-extra "^4.0.2"
funpermaproxy "^1.0.1"
get-port "^2.1.0" get-port "^2.1.0"
ini "^1.3.4" ini "^1.3.4"
lodash "^4.17.5" lodash "^4.17.5"
@ -4926,7 +4968,7 @@ detox@12.8.0:
tail "^2.0.0" tail "^2.0.0"
telnet-client "0.15.3" telnet-client "0.15.3"
tempfile "^2.0.0" tempfile "^2.0.0"
ws "^1.1.1" ws "^3.3.1"
yargs "^13.0.0" yargs "^13.0.0"
yargs-parser "^13.0.0" yargs-parser "^13.0.0"
@ -5749,6 +5791,11 @@ expo-file-system@~5.0.0:
dependencies: dependencies:
uuid-js "^0.7.5" 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: expo-permissions@~5.0.0:
version "5.0.1" version "5.0.1"
resolved "https://registry.yarnpkg.com/expo-permissions/-/expo-permissions-5.0.1.tgz#cc6af49a37ea3ab73e780a8a19f22b7662379941" 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" resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= 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: fuse.js@^3.0.1, fuse.js@^3.3.0:
version "3.3.0" version "3.3.0"
resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-3.3.0.tgz#1e4fe172a60687230fb54a5cb247eb96e2e7e885" 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" resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab"
integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs= 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: glob@7.1.2:
version "7.1.2" version "7.1.2"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" 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" resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= 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" version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
@ -9834,11 +9874,16 @@ mv@~2:
ncp "~2.0.0" ncp "~2.0.0"
rimraf "~2.4.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" version "2.12.1"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.12.1.tgz#7b1aa193e9aa86057e3c7bbd0ac448e770925552" resolved "https://registry.yarnpkg.com/nan/-/nan-2.12.1.tgz#7b1aa193e9aa86057e3c7bbd0ac448e770925552"
integrity sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw== 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: nanomatch@^1.2.9:
version "1.2.13" version "1.2.13"
resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" 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" hash-base "^3.0.0"
inherits "^2.0.1" inherits "^2.0.1"
rn-fetch-blob@^0.10.15: rn-user-defaults@^1.3.4:
version "0.10.15" version "1.3.4"
resolved "https://registry.yarnpkg.com/rn-fetch-blob/-/rn-fetch-blob-0.10.15.tgz#3526860c1c57e0bf4c09bdbe409c919264afffba" resolved "https://registry.yarnpkg.com/rn-user-defaults/-/rn-user-defaults-1.3.4.tgz#1fbdd1bf29d9f853918dca5219e45db54d19fe37"
integrity sha512-/m/gurTaPAvR3J843uehHhznj5k89x7XClyO5ejmbspNLNQ4ByF+kZs80wiiKGWntj+Wqo0jJu1goArXEfc0kA== integrity sha512-CnzZbq3Q1VQUr6wKl9Z48eKmOzu+6dMcl2wN0ty+sBnpUyIqFvv3CMzYzb26v1qK8z7q/PcMr75shFHcrJH9WA==
dependencies:
base-64 "0.1.0"
glob "7.0.6"
rsvp@^3.3.3: rsvp@^3.3.3:
version "3.6.2" version "3.6.2"
@ -14781,7 +14823,7 @@ write@^0.2.1:
dependencies: dependencies:
mkdirp "^0.5.1" 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" version "1.1.5"
resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.5.tgz#cbd9e6e75e09fc5d2c90015f21f0c40875e0dd51" resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.5.tgz#cbd9e6e75e09fc5d2c90015f21f0c40875e0dd51"
integrity sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w== integrity sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w==
@ -14907,9 +14949,9 @@ yargs-parser@^13.0.0:
decamelize "^1.2.0" decamelize "^1.2.0"
yargs-parser@^13.1.0: yargs-parser@^13.1.0:
version "13.1.0" version "13.1.1"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.0.tgz#7016b6dd03e28e1418a510e258be4bff5a31138f" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0"
integrity sha512-Yq+32PrijHRri0vVKQEm+ys8mbqWjLiwQkMFNXEENutzLPP0bE4Lcd4iA3OQY5HF+GD3xXxf0MEHb8E4/SA3AA== integrity sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==
dependencies: dependencies:
camelcase "^5.0.0" camelcase "^5.0.0"
decamelize "^1.2.0" decamelize "^1.2.0"