[RELEASE] Merge beta into master (#1082)

* 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

* [FIX] Swipe animations (#1044)

* 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

* Fix favorite button

* [FIX] Auto-translate messages as they arrive (#1049)

* 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

* [FIX] Auto-translate messages as they arrive

* [i18n] Add missing de translations (#1040)

* [CHORE] Switch to react-native-localize (#1043)

* Bump version to 1.17.0 (#1057)

* Load views as needed (#1056)

* [IMPROVEMENT] Change "resend" icon position (#1048)

* [NEW] Video support (#801)

* [NEW] File upload (#882)

* [NEW] Share extension (#942)

* [FIX] Share extension CI build (#1060)

* Change bundleID

* Provisioning

* get provisioning profile

* [IMPROVEMENT] Reusable toast (#1065)

* [FIX] Moment locales (#1066)

* [FIX] Share Extension issues (#1064)

* [FIX] Empty white list enables all media types upload (#1077)

* Merge branch 'master' into develop (#1079)

* [FIX] Empty white list enables all media types upload (#1080)

* Create utils to media (canUpload)

* Fix variable name

* [CHORE] Update README (#1081)
This commit is contained in:
Diego Mello 2019-07-29 17:44:39 -03:00 committed by GitHub
parent 8ea6f1647e
commit 2d58a8b983
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
131 changed files with 15148 additions and 7495 deletions

View File

@ -1,13 +1,11 @@
# Rocket.Chat React Native Mobile # Rocket.Chat React Native Mobile
[![Greenkeeper badge](https://badges.greenkeeper.io/RocketChat/Rocket.Chat.ReactNative.svg)](https://greenkeeper.io/)
[![Build Status](https://img.shields.io/travis/RocketChat/Rocket.Chat.ReactNative/master.svg)](https://travis-ci.org/RocketChat/Rocket.Chat.ReactNative)
[![Project Dependencies](https://david-dm.org/RocketChat/Rocket.Chat.ReactNative.svg)](https://david-dm.org/RocketChat/Rocket.Chat.ReactNative) [![Project Dependencies](https://david-dm.org/RocketChat/Rocket.Chat.ReactNative.svg)](https://david-dm.org/RocketChat/Rocket.Chat.ReactNative)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/bb15e2392a71473ea59d3f634f35c54e)](https://www.codacy.com/app/RocketChat/Rocket.Chat.ReactNative?utm_source=github.com&utm_medium=referral&utm_content=RocketChat/Rocket.Chat.ReactNative&utm_campaign=badger) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/bb15e2392a71473ea59d3f634f35c54e)](https://www.codacy.com/app/RocketChat/Rocket.Chat.ReactNative?utm_source=github.com&utm_medium=referral&utm_content=RocketChat/Rocket.Chat.ReactNative&utm_campaign=badger)
[![codecov](https://codecov.io/gh/RocketChat/Rocket.Chat.ReactNative/branch/master/graph/badge.svg)](https://codecov.io/gh/RocketChat/Rocket.Chat.ReactNative) [![codecov](https://codecov.io/gh/RocketChat/Rocket.Chat.ReactNative/branch/master/graph/badge.svg)](https://codecov.io/gh/RocketChat/Rocket.Chat.ReactNative)
[![CodeFactor](https://www.codefactor.io/repository/github/rocketchat/rocket.chat.reactnative/badge)](https://www.codefactor.io/repository/github/rocketchat/rocket.chat.reactnative) [![CodeFactor](https://www.codefactor.io/repository/github/rocketchat/rocket.chat.reactnative/badge)](https://www.codefactor.io/repository/github/rocketchat/rocket.chat.reactnative)
**Supported Server Versions:** 0.66.0+ **Supported Server Versions:** 0.70.0+
## Download ## Download
<a href="https://play.google.com/store/apps/details?id=chat.rocket.reactnative"> <a href="https://play.google.com/store/apps/details?id=chat.rocket.reactnative">
@ -59,55 +57,53 @@ If you don't need multiple servers, there is a branch `single-server` just for t
Readme will guide you on how to config. Readme will guide you on how to config.
## Current priorities ## Current priorities
1) [NEW] Jitsi integration ([#711][i711]) 1) Jitsi integration
2) [NEW] Federation ([#706][i706]) 2) Notification Preferences
3) [NEW] Record video ([#712][i712]) 3) Two-way authentication
4) [NEW] Slash Commands ([#405][i405]) 4) Authentication via SAML
5) [NEW] Share extension ([#391][i391]) 5) Authentication via Custom OAuth
6) Authentication via CAS
[i711]: https://github.com/RocketChat/Rocket.Chat.ReactNative/issues/711 7) Bugsnag
[i706]: https://github.com/RocketChat/Rocket.Chat.ReactNative/issues/706 8) Optional Analytics
[i707]: https://github.com/RocketChat/Rocket.Chat.ReactNative/issues/707 9) Typescript
[i712]: https://github.com/RocketChat/Rocket.Chat.ReactNative/issues/712 10) Prettier
[i708]: https://github.com/RocketChat/Rocket.Chat.ReactNative/issues/708
[i391]: https://github.com/RocketChat/Rocket.Chat.ReactNative/issues/391
[i405]: https://github.com/RocketChat/Rocket.Chat.ReactNative/issues/405
## Features ## Features
| Feature | Status | | Feature | Status |
|--------------------------------------------------------------- |-------- | |--------------------------------------------------------------- |-------- |
| Jitsi Integration | ❌ | | Jitsi Integration | ❌ |
| Federation (Directory) | ❌ | | Federation (Directory) | ✅ |
| Discussions | ❌ |
| Threads | ✅ | | Threads | ✅ |
| Record Audio | ✅ | | Record Audio | ✅ |
| Record Video | | | Record Video | |
| Commands | | | Commands | |
| Draft message per room | ✅ | | Draft message per room | ✅ |
| Share Extension | | | Share Extension | |
| Notifications Preferences | ✅ | | Notifications Preferences | ✅ |
| Edited status | ✅ | | Edited status | ✅ |
| Upload video | | | Upload video | |
| Grouped messages | ✅ | | Grouped messages | ✅ |
| Mark room as read | | | Mark room as read | |
| Mark room as unread | | | Mark room as unread | |
| Tablet Support | ❌ | | Tablet Support | ❌ |
| Read receipt | | | Read receipt | |
| Broadbast Channel | ✅ | | Broadbast Channel | ✅ |
| Authentication via SAML | ❌ | | Authentication via SAML | ❌ |
| Authentication via CAS | ❌ | | Authentication via CAS | ❌ |
| Custom Fields on Signup | | | Custom Fields on Signup | |
| Report message | | | Report message | |
| Theming | ❌ | | Theming | ❌ |
| Settings -> Review the App | ❌ | | Settings -> Review the App | ❌ |
| Settings -> Default Browser | ❌ | | Settings -> Default Browser | ❌ |
| Admin panel | ✅ | | Admin panel | ✅ |
| Reply message from notification | ❌ | | Reply message from notification | ❌ |
| Unread counter banner on message list | ✅ | | Unread counter banner on message list | ✅ |
| E2E | ❌ | | E2E Encryption | ❌ |
| Join a Protected Room | ❌ | | Join a Protected Room | ❌ |
| Optional Analytics | ❌ | | Optional Analytics | ❌ |
| Settings -> About us | ❌ | | Settings -> About us | ❌ |
| Settings -> Contact us | | | Settings -> Contact us | |
| Settings -> Update App Icon | ❌ | | Settings -> Update App Icon | ❌ |
| Settings -> Share | ❌ | | Settings -> Share | ❌ |
| Accessibility (Medium) | ❌ | | Accessibility (Medium) | ❌ |

2
__mocks__/react-native-localize.js vendored Normal file
View File

@ -0,0 +1,2 @@
export const initialConstants = null;
export const findBestAvailableLanguage = () => null;

3
__mocks__/react-native-realm-path.js vendored Normal file
View File

@ -0,0 +1,3 @@
export default {
realmPath: ''
};

File diff suppressed because it is too large Load Diff

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.16.1" versionName "1.17.0"
vectorDrawables.useSupportLibrary = true vectorDrawables.useSupportLibrary = true
} }
@ -174,6 +174,9 @@ android {
dependencies { dependencies {
addUnimodulesDependencies() addUnimodulesDependencies()
implementation "org.webkit:android-jsc:r241213" implementation "org.webkit:android-jsc:r241213"
implementation project(':rn-extensions-share')
implementation project(':rn-fetch-blob')
implementation project(':react-native-document-picker')
implementation project(':react-native-firebase') implementation project(':react-native-firebase')
implementation project(':react-native-webview') implementation project(':react-native-webview')
implementation project(':react-native-orientation-locker') implementation project(':react-native-orientation-locker')
@ -185,7 +188,7 @@ dependencies {
}) })
implementation project(':react-native-gesture-handler') implementation project(':react-native-gesture-handler')
implementation project(':react-native-image-crop-picker') implementation project(':react-native-image-crop-picker')
implementation project(':react-native-i18n') implementation project(':react-native-localize')
implementation project(':react-native-audio') implementation project(':react-native-audio')
implementation project(":reactnativekeyboardinput") implementation project(":reactnativekeyboardinput")
implementation project(':react-native-video') implementation project(':react-native-video')

View File

@ -5,8 +5,10 @@
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
<uses-permission-sdk-23 android:name="android.permission.VIBRATE"/> <uses-permission-sdk-23 android:name="android.permission.VIBRATE"/>
<application <application
@ -25,6 +27,7 @@
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
<action android:name="android.intent.action.DOWNLOAD_COMPLETE"/>
</intent-filter> </intent-filter>
<intent-filter android:label="@string/app_name"> <intent-filter android:label="@string/app_name">
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
@ -36,6 +39,19 @@
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" /> <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
<activity
android:noHistory="true"
android:name=".share.ShareActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:label="@string/share_extension_name"
android:screenOrientation="portrait"
android:theme="@style/AppTheme" >
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="*/*" />
</intent-filter>
</activity>
</application> </application>
</manifest> </manifest>

View File

@ -3,6 +3,7 @@ package chat.rocket.reactnative;
import android.app.Application; import android.app.Application;
import com.facebook.react.ReactApplication; import com.facebook.react.ReactApplication;
import io.github.elyx0.reactnativedocumentpicker.DocumentPickerPackage;
import io.invertase.firebase.RNFirebasePackage; import io.invertase.firebase.RNFirebasePackage;
import io.invertase.firebase.fabric.crashlytics.RNFirebaseCrashlyticsPackage; import io.invertase.firebase.fabric.crashlytics.RNFirebaseCrashlyticsPackage;
import io.invertase.firebase.analytics.RNFirebaseAnalyticsPackage; import io.invertase.firebase.analytics.RNFirebaseAnalyticsPackage;
@ -15,7 +16,7 @@ import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage; import com.facebook.react.shell.MainReactPackage;
import com.facebook.soloader.SoLoader; import com.facebook.soloader.SoLoader;
import com.AlexanderZaytsev.RNI18n.RNI18nPackage; import com.reactcommunity.rnlocalize.RNLocalizePackage;
import com.reactnative.ivpusic.imagepicker.PickerPackage; import com.reactnative.ivpusic.imagepicker.PickerPackage;
import com.brentvatne.react.ReactVideoPackage; import com.brentvatne.react.ReactVideoPackage;
import com.dylanvann.fastimage.FastImageViewPackage; import com.dylanvann.fastimage.FastImageViewPackage;
@ -33,6 +34,8 @@ import com.learnium.RNDeviceInfo.RNDeviceInfo;
import com.actionsheet.ActionSheetPackage; import com.actionsheet.ActionSheetPackage;
import io.realm.react.RealmReactPackage; import io.realm.react.RealmReactPackage;
import com.swmansion.rnscreens.RNScreensPackage; import com.swmansion.rnscreens.RNScreensPackage;
import chat.rocket.SharePackage;
import com.RNFetchBlob.RNFetchBlobPackage;
import chat.rocket.reactnative.generated.BasePackageList; import chat.rocket.reactnative.generated.BasePackageList;
@ -60,6 +63,7 @@ public class MainApplication extends Application implements ReactApplication, IN
protected List<ReactPackage> getPackages() { protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList( return Arrays.<ReactPackage>asList(
new MainReactPackage(), new MainReactPackage(),
new DocumentPickerPackage(),
new RNFirebasePackage(), new RNFirebasePackage(),
new RNFirebaseCrashlyticsPackage(), new RNFirebaseCrashlyticsPackage(),
new RNFirebaseAnalyticsPackage(), new RNFirebaseAnalyticsPackage(),
@ -67,6 +71,8 @@ public class MainApplication extends Application implements ReactApplication, IN
new RNCWebViewPackage(), new RNCWebViewPackage(),
new OrientationPackage(), new OrientationPackage(),
new SplashScreenReactPackage(), new SplashScreenReactPackage(),
new SharePackage(),
new RNFetchBlobPackage(),
new RNGestureHandlerPackage(), new RNGestureHandlerPackage(),
new RNScreensPackage(), new RNScreensPackage(),
new ActionSheetPackage(), new ActionSheetPackage(),
@ -78,7 +84,7 @@ public class MainApplication extends Application implements ReactApplication, IN
new ReactNativeAudioPackage(), new ReactNativeAudioPackage(),
new KeyboardInputPackage(MainApplication.this), new KeyboardInputPackage(MainApplication.this),
new FastImageViewPackage(), new FastImageViewPackage(),
new RNI18nPackage(), new RNLocalizePackage(),
new RNNotificationsPackage(MainApplication.this), new RNNotificationsPackage(MainApplication.this),
new ModuleRegistryAdapter(mModuleRegistryProvider) new ModuleRegistryAdapter(mModuleRegistryProvider)
); );

View File

@ -0,0 +1,23 @@
package chat.rocket.reactnative.share;
import com.facebook.react.ReactActivity;
import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.ReactRootView;
import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView;
public class ShareActivity extends ReactActivity {
@Override
protected String getMainComponentName() {
return "ShareRocketChatRN";
}
@Override
protected ReactActivityDelegate createReactActivityDelegate() {
return new ReactActivityDelegate(this, getMainComponentName()) {
@Override
protected ReactRootView createRootView() {
return new RNGestureHandlerEnabledRootView(ShareActivity.this);
}
};
}
}

View File

@ -0,0 +1,38 @@
package chat.rocket.reactnative.share;
import chat.rocket.reactnative.BuildConfig;
import chat.rocket.SharePackage;
import android.app.Application;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactPackage;
import java.util.Arrays;
import java.util.List;
public class ShareApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new SharePackage()
);
}
};
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
}

View File

@ -1,5 +1,5 @@
<resources> <resources>
<string name="app_name">Rocket.Chat Experimental</string> <string name="app_name">Rocket.Chat Experimental</string>
<string name="share_extension_name">Rocket.Chat Experimental</string>
<string name="no_browser_found">No Browser Found</string> <string name="no_browser_found">No Browser Found</string>
</resources> </resources>

View File

@ -2,4 +2,19 @@
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:colorEdgeEffect">#aaaaaa</item> <item name="android:colorEdgeEffect">#aaaaaa</item>
</style> </style>
<style name="Share.Window" parent="android:Theme">
<item name="android:windowEnterAnimation">@null</item>
<item name="android:windowExitAnimation">@null</item>
</style>
<style name="Theme.Share.Transparent" parent="android:Theme">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">@color/primary_dark</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsFloating">true</item>
<item name="android:backgroundDimEnabled">true</item>
<item name="android:windowAnimationStyle">@style/Share.Window</item>
</style>
</resources> </resources>

View File

@ -2,6 +2,8 @@ apply from: '../node_modules/react-native-unimodules/gradle.groovy'
includeUnimodulesProjects() includeUnimodulesProjects()
rootProject.name = 'RocketChatRN' rootProject.name = 'RocketChatRN'
include ':react-native-document-picker'
project(':react-native-document-picker').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-document-picker/android')
include ':react-native-firebase' include ':react-native-firebase'
project(':react-native-firebase').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-firebase/android') project(':react-native-firebase').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-firebase/android')
include ':react-native-webview' include ':react-native-webview'
@ -20,8 +22,8 @@ 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 ':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-localize'
project(':react-native-i18n').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-i18n/android') project(':react-native-localize').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-localize/android')
include ':react-native-fast-image' include ':react-native-fast-image'
project(':react-native-fast-image').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-fast-image/android') project(':react-native-fast-image').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-fast-image/android')
include ':react-native-audio' include ':react-native-audio'
@ -36,4 +38,8 @@ include ':realm'
project(':realm').projectDir = new File(rootProject.projectDir, '../node_modules/realm/android') project(':realm').projectDir = new File(rootProject.projectDir, '../node_modules/realm/android')
include ':reactnativenotifications' include ':reactnativenotifications'
project(':reactnativenotifications').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-notifications/android') project(':reactnativenotifications').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-notifications/android')
include ':app' include ':rn-fetch-blob'
project(':rn-fetch-blob').projectDir = new File(rootProject.projectDir, '../node_modules/rn-fetch-blob/android')
include ':app', ':rn-extensions-share'
project(':rn-extensions-share').projectDir = new File(rootProject.projectDir, '../node_modules/rn-extensions-share/android')

View File

@ -1,4 +1,5 @@
{ {
"name": "RocketChatRN", "name": "RocketChatRN",
"share": "ShareRocketChatRN",
"displayName": "RocketChatRN" "displayName": "RocketChatRN"
} }

View File

@ -14,6 +14,11 @@ export const LOGIN = createRequestTypes('LOGIN', [
'SET_SERVICES', 'SET_SERVICES',
'SET_PREFERENCE' 'SET_PREFERENCE'
]); ]);
export const SHARE = createRequestTypes('SHARE', [
'SELECT_SERVER',
'SET_USER',
'SET_SERVER_INFO'
]);
export const USER = createRequestTypes('USER', ['SET']); export const USER = createRequestTypes('USER', ['SET']);
export const ROOMS = createRequestTypes('ROOMS', [ export const ROOMS = createRequestTypes('ROOMS', [
...defaultTypes, ...defaultTypes,

15
app/actions/share.js Normal file
View File

@ -0,0 +1,15 @@
import { SHARE } from './actionsTypes';
export function shareSelectServer(server) {
return {
type: SHARE.SELECT_SERVER,
server
};
}
export function shareSetUser(user) {
return {
type: SHARE.SET_USER,
user
};
}

View File

@ -68,6 +68,12 @@ export default {
Threads_enabled: { Threads_enabled: {
type: null type: null
}, },
FileUpload_MediaTypeWhiteList: {
type: 'valueAsString'
},
FileUpload_MaxFileSize: {
type: 'valueAsNumber'
},
API_Gitlab_URL: { API_Gitlab_URL: {
type: 'valueAsString' type: 'valueAsString'
}, },

View File

@ -5,6 +5,7 @@ import HeaderButtons, { HeaderButton, Item } from 'react-navigation-header-butto
import { CustomIcon } from '../lib/Icons'; import { CustomIcon } from '../lib/Icons';
import { isIOS } from '../utils/deviceInfo'; import { isIOS } from '../utils/deviceInfo';
import { COLOR_PRIMARY, COLOR_WHITE } from '../constants/colors'; import { COLOR_PRIMARY, COLOR_WHITE } from '../constants/colors';
import I18n from '../i18n';
const color = isIOS ? COLOR_PRIMARY : COLOR_WHITE; const color = isIOS ? COLOR_PRIMARY : COLOR_WHITE;
export const headerIconSize = 23; export const headerIconSize = 23;
@ -32,6 +33,15 @@ export const CloseModalButton = React.memo(({ navigation, testID }) => (
</CustomHeaderButtons> </CustomHeaderButtons>
)); ));
export const CloseShareExtensionButton = React.memo(({ onPress, testID }) => (
<CustomHeaderButtons left>
{isIOS
? <Item title={I18n.t('Cancel')} onPress={onPress} testID={testID} />
: <Item title='close' iconName='cross' onPress={onPress} testID={testID} />
}
</CustomHeaderButtons>
));
export const MoreButton = React.memo(({ onPress, testID }) => ( export const MoreButton = React.memo(({ onPress, testID }) => (
<CustomHeaderButtons> <CustomHeaderButtons>
<Item title='more' iconName='menu' onPress={onPress} testID={testID} /> <Item title='more' iconName='menu' onPress={onPress} testID={testID} />
@ -50,6 +60,10 @@ CloseModalButton.propTypes = {
navigation: PropTypes.object.isRequired, navigation: PropTypes.object.isRequired,
testID: PropTypes.string.isRequired testID: PropTypes.string.isRequired
}; };
CloseShareExtensionButton.propTypes = {
onPress: PropTypes.func.isRequired,
testID: PropTypes.string.isRequired
};
MoreButton.propTypes = { MoreButton.propTypes = {
onPress: PropTypes.func.isRequired, onPress: PropTypes.func.isRequired,
testID: PropTypes.string.isRequired testID: PropTypes.string.isRequired

View File

@ -21,6 +21,8 @@ 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'; import { getMessageTranslation } from './message/utils';
import { LISTENER } from './Toast';
import EventEmitter from '../utils/events';
@connect( @connect(
state => ({ state => ({
@ -48,7 +50,6 @@ export default class MessageActions extends React.Component {
actionsHide: PropTypes.func.isRequired, actionsHide: PropTypes.func.isRequired,
room: PropTypes.object.isRequired, room: PropTypes.object.isRequired,
actionMessage: PropTypes.object, actionMessage: PropTypes.object,
toast: PropTypes.element,
user: PropTypes.object, user: PropTypes.object,
deleteRequest: PropTypes.func.isRequired, deleteRequest: PropTypes.func.isRequired,
editInit: PropTypes.func.isRequired, editInit: PropTypes.func.isRequired,
@ -275,9 +276,9 @@ export default class MessageActions extends React.Component {
} }
handleCopy = async() => { handleCopy = async() => {
const { actionMessage, toast } = this.props; const { actionMessage } = this.props;
await Clipboard.setString(actionMessage.msg); await Clipboard.setString(actionMessage.msg);
toast.show(I18n.t('Copied_to_clipboard')); EventEmitter.emit(LISTENER, { message: I18n.t('Copied_to_clipboard') });
} }
handleShare = async() => { handleShare = async() => {
@ -294,10 +295,10 @@ export default class MessageActions extends React.Component {
} }
handlePermalink = async() => { handlePermalink = async() => {
const { actionMessage, toast } = this.props; const { actionMessage } = this.props;
const permalink = await this.getPermalink(actionMessage); const permalink = await this.getPermalink(actionMessage);
Clipboard.setString(permalink); Clipboard.setString(permalink);
toast.show(I18n.t('Permalink_copied_to_clipboard')); EventEmitter.emit(LISTENER, { message: I18n.t('Permalink_copied_to_clipboard') });
} }
handlePin = () => { handlePin = () => {

View File

@ -2,6 +2,7 @@ import React, { Component } from 'react';
import { import {
View, Text, StyleSheet, Image, ScrollView, TouchableHighlight View, Text, StyleSheet, Image, ScrollView, TouchableHighlight
} from 'react-native'; } from 'react-native';
import { connect } from 'react-redux';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import Modal from 'react-native-modal'; import Modal from 'react-native-modal';
import { responsive } from 'react-native-responsive-ui'; import { responsive } from 'react-native-responsive-ui';
@ -12,7 +13,11 @@ import Button from '../Button';
import I18n from '../../i18n'; import I18n from '../../i18n';
import sharedStyles from '../../views/Styles'; import sharedStyles from '../../views/Styles';
import { isIOS } from '../../utils/deviceInfo'; import { isIOS } from '../../utils/deviceInfo';
import { COLOR_PRIMARY, COLOR_BACKGROUND_CONTAINER, COLOR_WHITE } from '../../constants/colors'; import { canUploadFile } from '../../utils/media';
import {
COLOR_PRIMARY, COLOR_BACKGROUND_CONTAINER, COLOR_WHITE, COLOR_DANGER
} from '../../constants/colors';
import { CustomIcon } from '../../lib/Icons';
const cancelButtonColor = COLOR_BACKGROUND_CONTAINER; const cancelButtonColor = COLOR_BACKGROUND_CONTAINER;
@ -63,18 +68,56 @@ const styles = StyleSheet.create({
androidButtonText: { androidButtonText: {
fontSize: 18, fontSize: 18,
textAlign: 'center' textAlign: 'center'
},
fileIcon: {
color: COLOR_PRIMARY,
margin: 20,
flex: 1,
textAlign: 'center'
},
errorIcon: {
color: COLOR_DANGER
},
fileMime: {
...sharedStyles.textColorTitle,
...sharedStyles.textBold,
textAlign: 'center',
fontSize: 20,
marginBottom: 20
},
errorContainer: {
margin: 20,
flex: 1,
textAlign: 'center',
justifyContent: 'center',
alignItems: 'center'
},
video: {
flex: 1,
borderRadius: 4,
height: 150,
backgroundColor: '#1f2329',
marginBottom: 6,
alignItems: 'center',
justifyContent: 'center'
} }
}); });
@responsive @responsive
@connect(state => ({
FileUpload_MediaTypeWhiteList: state.settings.FileUpload_MediaTypeWhiteList,
FileUpload_MaxFileSize: state.settings.FileUpload_MaxFileSize
}))
export default class UploadModal extends Component { export default class UploadModal extends Component {
static propTypes = { static propTypes = {
isVisible: PropTypes.bool, isVisible: PropTypes.bool,
file: PropTypes.object, file: PropTypes.object,
close: PropTypes.func, close: PropTypes.func,
submit: PropTypes.func, submit: PropTypes.func,
window: PropTypes.object window: PropTypes.object,
FileUpload_MediaTypeWhiteList: PropTypes.string,
FileUpload_MaxFileSize: PropTypes.number
} }
state = { state = {
@ -116,12 +159,79 @@ export default class UploadModal extends Component {
return false; return false;
} }
canUploadFile = () => {
const { FileUpload_MediaTypeWhiteList, FileUpload_MaxFileSize, file } = this.props;
if (!(file && file.path)) {
return true;
}
if (file.size > FileUpload_MaxFileSize) {
return false;
}
// if white list is empty, all media types are enabled
if (!FileUpload_MediaTypeWhiteList) {
return true;
}
const allowedMime = FileUpload_MediaTypeWhiteList.split(',');
if (allowedMime.includes(file.mime)) {
return true;
}
const wildCardGlob = '/*';
const wildCards = allowedMime.filter(item => item.indexOf(wildCardGlob) > 0);
if (wildCards.includes(file.mime.replace(/(\/.*)$/, wildCardGlob))) {
return true;
}
return false;
}
submit = () => { submit = () => {
const { file, submit } = this.props; const { file, submit } = this.props;
const { name, description } = this.state; const { name, description } = this.state;
submit({ ...file, name, description }); submit({ ...file, name, description });
} }
renderError = () => {
const { file, FileUpload_MaxFileSize, close } = this.props;
const { window: { width } } = this.props;
const errorMessage = (FileUpload_MaxFileSize < file.size)
? 'error-file-too-large'
: 'error-invalid-file-type';
return (
<View style={[styles.container, { width: width - 32 }]}>
<View style={styles.titleContainer}>
<Text style={styles.title}>{I18n.t(errorMessage)}</Text>
</View>
<View style={styles.errorContainer}>
<CustomIcon name='circle-cross' size={120} style={styles.errorIcon} />
</View>
<Text style={styles.fileMime}>{ file.mime }</Text>
<View style={styles.buttonContainer}>
{
(isIOS)
? (
<Button
title={I18n.t('Cancel')}
type='secondary'
backgroundColor={cancelButtonColor}
style={styles.button}
onPress={close}
/>
)
: (
<TouchableHighlight
onPress={close}
style={[styles.androidButton, { backgroundColor: cancelButtonColor }]}
underlayColor={cancelButtonColor}
activeOpacity={0.5}
>
<Text style={[styles.androidButtonText, { ...sharedStyles.textBold, color: COLOR_PRIMARY }]}>{I18n.t('Cancel')}</Text>
</TouchableHighlight>
)
}
</View>
</View>
);
}
renderButtons = () => { renderButtons = () => {
const { close } = this.props; const { close } = this.props;
if (isIOS) { if (isIOS) {
@ -166,9 +276,27 @@ export default class UploadModal extends Component {
); );
} }
renderPreview() {
const { file } = this.props;
if (file.mime && file.mime.match(/image/)) {
return (<Image source={{ isStatic: true, uri: file.path }} style={styles.image} />);
}
if (file.mime && file.mime.match(/video/)) {
return (
<View style={styles.video}>
<CustomIcon name='play' size={72} color={COLOR_WHITE} />
</View>
);
}
return (<CustomIcon name='file-generic' size={72} style={styles.fileIcon} />);
}
render() { render() {
const { window: { width }, isVisible, close } = this.props; const {
const { name, description, file } = this.state; window: { width }, isVisible, close, file, FileUpload_MediaTypeWhiteList, FileUpload_MaxFileSize
} = this.props;
const { name, description } = this.state;
const showError = !canUploadFile(file, { FileUpload_MediaTypeWhiteList, FileUpload_MaxFileSize });
return ( return (
<Modal <Modal
isVisible={isVisible} isVisible={isVisible}
@ -181,13 +309,15 @@ export default class UploadModal extends Component {
hideModalContentWhileAnimating hideModalContentWhileAnimating
avoidKeyboard avoidKeyboard
> >
{(showError) ? this.renderError()
: (
<View style={[styles.container, { width: width - 32 }]}> <View style={[styles.container, { width: width - 32 }]}>
<View style={styles.titleContainer}> <View style={styles.titleContainer}>
<Text style={styles.title}>{I18n.t('Upload_file_question_mark')}</Text> <Text style={styles.title}>{I18n.t('Upload_file_question_mark')}</Text>
</View> </View>
<ScrollView style={styles.scrollView}> <ScrollView style={styles.scrollView}>
<Image source={{ isStatic: true, uri: file.path }} style={styles.image} /> {this.renderPreview()}
<TextInput <TextInput
placeholder={I18n.t('File_name')} placeholder={I18n.t('File_name')}
value={name} value={name}
@ -201,6 +331,7 @@ export default class UploadModal extends Component {
</ScrollView> </ScrollView>
{this.renderButtons()} {this.renderButtons()}
</View> </View>
)}
</Modal> </Modal>
); );
} }

View File

@ -8,6 +8,7 @@ import { emojify } from 'react-emojione';
import { KeyboardAccessoryView } from 'react-native-keyboard-input'; import { KeyboardAccessoryView } from 'react-native-keyboard-input';
import ImagePicker from 'react-native-image-crop-picker'; import ImagePicker from 'react-native-image-crop-picker';
import equal from 'deep-equal'; import equal from 'deep-equal';
import DocumentPicker from 'react-native-document-picker';
import ActionSheet from 'react-native-action-sheet'; import ActionSheet from 'react-native-action-sheet';
import { userTyping as userTypingAction } from '../../actions/room'; import { userTyping as userTypingAction } from '../../actions/room';
@ -46,21 +47,22 @@ const onlyUnique = function onlyUnique(value, index, self) {
const imagePickerConfig = { const imagePickerConfig = {
cropping: true, cropping: true,
compressImageQuality: 0.8, compressImageQuality: 0.8,
avoidEmptySpaceAroundImage: false, avoidEmptySpaceAroundImage: false
cropperChooseText: I18n.t('Choose'), };
cropperCancelText: I18n.t('Cancel')
const libraryPickerConfig = {
mediaType: 'any'
};
const videoPickerConfig = {
mediaType: 'video'
}; };
const fileOptions = [I18n.t('Cancel')];
const FILE_CANCEL_INDEX = 0; const FILE_CANCEL_INDEX = 0;
// Photo
fileOptions.push(I18n.t('Take_a_photo'));
const FILE_PHOTO_INDEX = 1; const FILE_PHOTO_INDEX = 1;
const FILE_VIDEO_INDEX = 2;
// Library const FILE_LIBRARY_INDEX = 3;
fileOptions.push(I18n.t('Choose_from_library')); const FILE_DOCUMENT_INDEX = 4;
const FILE_LIBRARY_INDEX = 2;
class MessageBox extends Component { class MessageBox extends Component {
static propTypes = { static propTypes = {
@ -107,6 +109,30 @@ class MessageBox extends Component {
this.customEmojis = []; this.customEmojis = [];
this.onEmojiSelected = this.onEmojiSelected.bind(this); this.onEmojiSelected = this.onEmojiSelected.bind(this);
this.text = ''; this.text = '';
this.fileOptions = [
I18n.t('Cancel'),
I18n.t('Take_a_photo'),
I18n.t('Take_a_video'),
I18n.t('Choose_from_library'),
I18n.t('Choose_file')
];
const libPickerLabels = {
cropperChooseText: I18n.t('Choose'),
cropperCancelText: I18n.t('Cancel'),
loadingLabelText: I18n.t('Processing')
};
this.imagePickerConfig = {
...imagePickerConfig,
...libPickerLabels
};
this.libraryPickerConfig = {
...libraryPickerConfig,
...libPickerLabels
};
this.videoPickerConfig = {
...videoPickerConfig,
...libPickerLabels
};
} }
componentDidMount() { componentDidMount() {
@ -462,9 +488,10 @@ class MessageBox extends Component {
this.setShowSend(false); this.setShowSend(false);
} }
sendImageMessage = async(file) => { sendMediaMessage = async(file) => {
const { rid, tmid } = this.props; const {
rid, tmid, baseUrl: server, user
} = this.props;
this.setState({ file: { isVisible: false } }); this.setState({ file: { isVisible: false } });
const fileInfo = { const fileInfo = {
name: file.name, name: file.name,
@ -475,37 +502,65 @@ class MessageBox extends Component {
path: file.path path: file.path
}; };
try { try {
await RocketChat.sendFileMessage(rid, fileInfo, tmid); await RocketChat.sendFileMessage(rid, fileInfo, tmid, server, user);
} catch (e) { } catch (e) {
log('err_send_image', e); log('err_send_media_message', e);
} }
} }
takePhoto = async() => { takePhoto = async() => {
try { try {
const image = await ImagePicker.openCamera(imagePickerConfig); const image = await ImagePicker.openCamera(this.imagePickerConfig);
this.showUploadModal(image); this.showUploadModal(image);
} catch (e) { } catch (e) {
log('err_take_photo', e); log('err_take_photo', e);
} }
} }
takeVideo = async() => {
try {
const video = await ImagePicker.openCamera(this.videoPickerConfig);
this.showUploadModal(video);
} catch (e) {
log('err_take_video', e);
}
}
chooseFromLibrary = async() => { chooseFromLibrary = async() => {
try { try {
const image = await ImagePicker.openPicker(imagePickerConfig); const image = await ImagePicker.openPicker(this.libraryPickerConfig);
this.showUploadModal(image); this.showUploadModal(image);
} catch (e) { } catch (e) {
log('err_choose_from_library', e); log('err_choose_from_library', e);
} }
} }
chooseFile = async() => {
try {
const res = await DocumentPicker.pick({
type: [DocumentPicker.types.allFiles]
});
this.showUploadModal({
filename: res.name,
size: res.size,
mime: res.type,
path: res.uri
});
} catch (error) {
if (!DocumentPicker.isCancel(error)) {
log('chooseFile', error);
}
}
}
showUploadModal = (file) => { showUploadModal = (file) => {
this.setState({ file: { ...file, isVisible: true } }); this.setState({ file: { ...file, isVisible: true } });
} }
showFileActions = () => { showFileActions = () => {
ActionSheet.showActionSheetWithOptions({ ActionSheet.showActionSheetWithOptions({
options: fileOptions, options: this.fileOptions,
cancelButtonIndex: FILE_CANCEL_INDEX cancelButtonIndex: FILE_CANCEL_INDEX
}, (actionIndex) => { }, (actionIndex) => {
this.handleFileActionPress(actionIndex); this.handleFileActionPress(actionIndex);
@ -517,9 +572,15 @@ class MessageBox extends Component {
case FILE_PHOTO_INDEX: case FILE_PHOTO_INDEX:
this.takePhoto(); this.takePhoto();
break; break;
case FILE_VIDEO_INDEX:
this.takeVideo();
break;
case FILE_LIBRARY_INDEX: case FILE_LIBRARY_INDEX:
this.chooseFromLibrary(); this.chooseFromLibrary();
break; break;
case FILE_DOCUMENT_INDEX:
this.chooseFile();
break;
default: default:
break; break;
} }
@ -543,14 +604,16 @@ class MessageBox extends Component {
} }
finishAudioMessage = async(fileInfo) => { finishAudioMessage = async(fileInfo) => {
const { rid, tmid } = this.props; const {
rid, tmid, baseUrl: server, user
} = this.props;
this.setState({ this.setState({
recording: false recording: false
}); });
if (fileInfo) { if (fileInfo) {
try { try {
await RocketChat.sendFileMessage(rid, fileInfo, tmid); await RocketChat.sendFileMessage(rid, fileInfo, tmid, server, user);
} catch (e) { } catch (e) {
if (e && e.error === 'error-file-too-large') { if (e && e.error === 'error-file-too-large') {
return Alert.alert(I18n.t(e.error)); return Alert.alert(I18n.t(e.error));
@ -895,7 +958,7 @@ class MessageBox extends Component {
isVisible={(file && file.isVisible)} isVisible={(file && file.isVisible)}
file={file} file={file}
close={() => this.setState({ file: {} })} close={() => this.setState({ file: {} })}
submit={this.sendImageMessage} submit={this.sendMediaMessage}
/> />
</React.Fragment> </React.Fragment>
); );

View File

@ -7,8 +7,12 @@ import { COLOR_TEXT_DESCRIPTION } from '../constants/colors';
const styles = StyleSheet.create({ const styles = StyleSheet.create({
style: { style: {
marginRight: 7, marginRight: 7,
marginTop: 3, marginTop: 3
tintColor: COLOR_TEXT_DESCRIPTION, },
imageColor: {
tintColor: COLOR_TEXT_DESCRIPTION
},
iconColor: {
color: COLOR_TEXT_DESCRIPTION color: COLOR_TEXT_DESCRIPTION
}, },
discussion: { discussion: {
@ -23,13 +27,15 @@ const RoomTypeIcon = React.memo(({ type, size, style }) => {
if (type === 'discussion') { if (type === 'discussion') {
// FIXME: These are temporary only. We should have all room icons on <Customicon />, but our design team is still working on this. // FIXME: These are temporary only. We should have all room icons on <Customicon />, but our design team is still working on this.
return <CustomIcon name='chat' size={13} style={[styles.style, styles.discussion]} />; return <CustomIcon name='chat' size={13} style={[styles.style, styles.iconColor, styles.discussion]} />;
} }
if (type === 'c') { if (type === 'c') {
return <Image source={{ uri: 'hashtag' }} style={[styles.style, style, { width: size, height: size }]} />; return <Image source={{ uri: 'hashtag' }} style={[styles.style, styles.imageColor, style, { width: size, height: size }]} />;
} if (type === 'd') {
return <CustomIcon name='at' size={13} style={[styles.style, styles.iconColor, styles.discussion]} />;
} }
return <Image source={{ uri: 'lock' }} style={[styles.style, style, { width: size, height: size }]} />; return <Image source={{ uri: 'lock' }} style={[styles.style, styles.imageColor, style, { width: size, height: size }]} />;
}); });
RoomTypeIcon.propTypes = { RoomTypeIcon.propTypes = {

View File

@ -1,6 +1,9 @@
import React from 'react'; import React from 'react';
import { View, StyleSheet, TextInput } from 'react-native'; import {
View, StyleSheet, TextInput, Text
} from 'react-native';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import Touchable from 'react-native-platform-touchable';
import I18n from '../i18n'; import I18n from '../i18n';
import { isIOS } from '../utils/deviceInfo'; import { isIOS } from '../utils/deviceInfo';
@ -9,7 +12,10 @@ import sharedStyles from '../views/Styles';
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {
backgroundColor: isIOS ? '#F7F8FA' : '#54585E' backgroundColor: isIOS ? '#F7F8FA' : '#54585E',
flexDirection: 'row',
alignItems: 'center',
flex: 1
}, },
searchBox: { searchBox: {
alignItems: 'center', alignItems: 'center',
@ -21,7 +27,8 @@ const styles = StyleSheet.create({
height: 36, height: 36,
margin: 16, margin: 16,
marginVertical: 10, marginVertical: 10,
paddingHorizontal: 10 paddingHorizontal: 10,
flex: 1
}, },
input: { input: {
color: '#8E8E93', color: '#8E8E93',
@ -31,10 +38,26 @@ const styles = StyleSheet.create({
paddingTop: 0, paddingTop: 0,
paddingBottom: 0, paddingBottom: 0,
...sharedStyles.textRegular ...sharedStyles.textRegular
},
cancel: {
marginRight: 10
},
cancelText: {
...sharedStyles.textRegular,
...sharedStyles.textColorHeaderBack,
fontSize: 17
} }
}); });
const SearchBox = ({ onChangeText, onSubmitEditing, testID }) => ( const CancelButton = onCancelPress => (
<Touchable onPress={onCancelPress} style={styles.cancel}>
<Text style={styles.cancelText}>{I18n.t('Cancel')}</Text>
</Touchable>
);
const SearchBox = ({
onChangeText, onSubmitEditing, testID, hasCancel, onCancelPress, ...props
}) => (
<View style={styles.container}> <View style={styles.container}>
<View style={styles.searchBox}> <View style={styles.searchBox}>
<CustomIcon name='magnifier' size={14} color='#8E8E93' /> <CustomIcon name='magnifier' size={14} color='#8E8E93' />
@ -50,14 +73,18 @@ const SearchBox = ({ onChangeText, onSubmitEditing, testID }) => (
underlineColorAndroid='transparent' underlineColorAndroid='transparent'
onChangeText={onChangeText} onChangeText={onChangeText}
onSubmitEditing={onSubmitEditing} onSubmitEditing={onSubmitEditing}
{...props}
/> />
</View> </View>
{ hasCancel ? CancelButton(onCancelPress) : null }
</View> </View>
); );
SearchBox.propTypes = { SearchBox.propTypes = {
onChangeText: PropTypes.func.isRequired, onChangeText: PropTypes.func.isRequired,
onSubmitEditing: PropTypes.func, onSubmitEditing: PropTypes.func,
hasCancel: PropTypes.bool,
onCancelPress: PropTypes.func,
testID: PropTypes.string testID: PropTypes.string
}; };

53
app/containers/Toast.js Normal file
View File

@ -0,0 +1,53 @@
import React from 'react';
import { StyleSheet } from 'react-native';
import EasyToast from 'react-native-easy-toast';
import { COLOR_TOAST, COLOR_WHITE } from '../constants/colors';
import sharedStyles from '../views/Styles';
import EventEmitter from '../utils/events';
const styles = StyleSheet.create({
toast: {
backgroundColor: COLOR_TOAST,
maxWidth: 300,
padding: 10
},
text: {
...sharedStyles.textRegular,
color: COLOR_WHITE,
fontSize: 14,
textAlign: 'center'
}
});
export const LISTENER = 'Toast';
export default class Toast extends React.Component {
componentDidMount() {
EventEmitter.addEventListener(LISTENER, this.showToast);
}
shouldComponentUpdate() {
return false;
}
componentWillUnmount() {
EventEmitter.removeListener(LISTENER);
}
showToast = ({ message }) => {
this.toast.show(message, 1000);
}
render() {
return (
<EasyToast
ref={toast => this.toast = toast}
position='center'
style={styles.toast}
textStyle={styles.text}
opacity={0.9}
/>
);
}
}

View File

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import { Text } from 'react-native'; import { Text, View } from 'react-native';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import I18n from '../../i18n'; import I18n from '../../i18n';
@ -12,11 +12,12 @@ const Content = React.memo((props) => {
return <Text style={styles.textInfo}>{getInfoMessage({ ...props })}</Text>; return <Text style={styles.textInfo}>{getInfoMessage({ ...props })}</Text>;
} }
if (props.tmid && !props.msg) { let content = null;
return <Text style={styles.text}>{I18n.t('Sent_an_attachment')}</Text>;
}
return ( if (props.tmid && !props.msg) {
content = <Text style={styles.text}>{I18n.t('Sent_an_attachment')}</Text>;
} else {
content = (
<Markdown <Markdown
msg={props.msg} msg={props.msg}
baseUrl={props.baseUrl} baseUrl={props.baseUrl}
@ -29,9 +30,17 @@ const Content = React.memo((props) => {
useMarkdown={props.useMarkdown} useMarkdown={props.useMarkdown}
/> />
); );
}, (prevProps, nextProps) => prevProps.msg === nextProps.msg); }
return (
<View style={props.isTemp && styles.temp}>
{content}
</View>
);
}, (prevProps, nextProps) => prevProps.isTemp === nextProps.isTemp && prevProps.msg === nextProps.msg);
Content.propTypes = { Content.propTypes = {
isTemp: PropTypes.bool,
isInfo: PropTypes.bool, isInfo: PropTypes.bool,
isEdited: PropTypes.bool, isEdited: PropTypes.bool,
useMarkdown: PropTypes.bool, useMarkdown: PropTypes.bool,

View File

@ -4,7 +4,6 @@ import { View } from 'react-native';
import Touchable from 'react-native-platform-touchable'; import Touchable from 'react-native-platform-touchable';
import User from './User'; import User from './User';
import MessageError from './MessageError';
import styles from './styles'; import styles from './styles';
import sharedStyles from '../../views/Styles'; import sharedStyles from '../../views/Styles';
import RepliedThread from './RepliedThread'; import RepliedThread from './RepliedThread';
@ -45,7 +44,7 @@ const Message = React.memo((props) => {
if (props.isThreadReply || props.isThreadSequential || props.isInfo) { if (props.isThreadReply || props.isThreadSequential || props.isInfo) {
const thread = props.isThreadReply ? <RepliedThread isTemp={props.isTemp} {...props} /> : null; const thread = props.isThreadReply ? <RepliedThread isTemp={props.isTemp} {...props} /> : null;
return ( return (
<View style={[styles.container, props.style, props.isTemp && styles.temp]}> <View style={[styles.container, props.style]}>
{thread} {thread}
<View style={[styles.flex, sharedStyles.alignItemsCenter]}> <View style={[styles.flex, sharedStyles.alignItemsCenter]}>
<MessageAvatar small {...props} /> <MessageAvatar small {...props} />
@ -62,7 +61,7 @@ const Message = React.memo((props) => {
); );
} }
return ( return (
<View style={[styles.container, props.style, props.isTemp && styles.temp]}> <View style={[styles.container, props.style]}>
<View style={styles.flex}> <View style={styles.flex}>
<MessageAvatar {...props} /> <MessageAvatar {...props} />
<View <View
@ -86,8 +85,7 @@ Message.displayName = 'Message';
const MessageTouchable = React.memo((props) => { const MessageTouchable = React.memo((props) => {
if (props.hasError) { if (props.hasError) {
return ( return (
<View style={styles.root}> <View>
<MessageError {...props} />
<Message {...props} /> <Message {...props} />
</View> </View>
); );

View File

@ -5,14 +5,15 @@ import PropTypes from 'prop-types';
import { CustomIcon } from '../../lib/Icons'; import { CustomIcon } from '../../lib/Icons';
import { COLOR_DANGER } from '../../constants/colors'; import { COLOR_DANGER } from '../../constants/colors';
import styles from './styles'; import styles from './styles';
import { BUTTON_HIT_SLOP } from './utils';
const MessageError = React.memo(({ hasError, onErrorPress }) => { const MessageError = React.memo(({ hasError, onErrorPress }) => {
if (!hasError) { if (!hasError) {
return null; return null;
} }
return ( return (
<Touchable onPress={onErrorPress} style={styles.errorButton}> <Touchable onPress={onErrorPress} style={styles.errorButton} hitSlop={BUTTON_HIT_SLOP}>
<CustomIcon name='circle-cross' color={COLOR_DANGER} size={20} /> <CustomIcon name='warning' color={COLOR_DANGER} size={18} />
</Touchable> </Touchable>
); );
}, (prevProps, nextProps) => prevProps.hasError === nextProps.hasError); }, (prevProps, nextProps) => prevProps.hasError === nextProps.hasError);

View File

@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
import { View, Text, StyleSheet } from 'react-native'; import { View, Text, StyleSheet } from 'react-native';
import moment from 'moment'; import moment from 'moment';
import MessageError from './MessageError';
import sharedStyles from '../../views/Styles'; import sharedStyles from '../../views/Styles';
import messageStyles from './styles'; import messageStyles from './styles';
@ -31,9 +32,9 @@ const styles = StyleSheet.create({
}); });
const User = React.memo(({ const User = React.memo(({
isHeader, useRealName, author, alias, ts, timeFormat isHeader, useRealName, author, alias, ts, timeFormat, hasError, ...props
}) => { }) => {
if (isHeader) { if (isHeader || hasError) {
const username = (useRealName && author.name) || author.username; const username = (useRealName && author.name) || author.username;
const aliasUsername = alias ? (<Text style={styles.alias}> @{username}</Text>) : null; const aliasUsername = alias ? (<Text style={styles.alias}> @{username}</Text>) : null;
const time = moment(ts).format(timeFormat); const time = moment(ts).format(timeFormat);
@ -47,6 +48,7 @@ const User = React.memo(({
</Text> </Text>
</View> </View>
<Text style={messageStyles.time}>{time}</Text> <Text style={messageStyles.time}>{time}</Text>
{ hasError && <MessageError hasError={hasError} {...props} /> }
</View> </View>
); );
} }
@ -55,6 +57,7 @@ const User = React.memo(({
User.propTypes = { User.propTypes = {
isHeader: PropTypes.bool, isHeader: PropTypes.bool,
hasError: PropTypes.bool,
useRealName: PropTypes.bool, useRealName: PropTypes.bool,
author: PropTypes.object, author: PropTypes.object,
alias: PropTypes.string, alias: PropTypes.string,

View File

@ -128,6 +128,9 @@ export default class MessageContainer extends React.Component {
const { const {
item, previousItem, broadcast, Message_GroupingPeriod item, previousItem, broadcast, Message_GroupingPeriod
} = this.props; } = this.props;
if (this.hasError || (previousItem && previousItem.status === messagesStatus.ERROR)) {
return true;
}
if (previousItem && ( if (previousItem && (
(previousItem.ts.toDateString() === item.ts.toDateString()) (previousItem.ts.toDateString() === item.ts.toDateString())
&& (previousItem.u.username === item.u.username) && (previousItem.u.username === item.u.username)

View File

@ -114,7 +114,7 @@ export default StyleSheet.create({
color: COLOR_PRIMARY color: COLOR_PRIMARY
}, },
errorButton: { errorButton: {
paddingHorizontal: 15, paddingLeft: 10,
paddingVertical: 5 paddingVertical: 5
}, },
buttonContainer: { buttonContainer: {

View File

@ -1,4 +1,7 @@
import I18n from 'react-native-i18n'; import i18n from 'i18n-js';
import { I18nManager } from 'react-native';
import * as RNLocalize from 'react-native-localize';
import en from './locales/en'; import en from './locales/en';
import ru from './locales/ru'; import ru from './locales/ru';
import fr from './locales/fr'; import fr from './locales/fr';
@ -7,11 +10,22 @@ import ptBR from './locales/pt-BR';
import zhCN from './locales/zh-CN'; import zhCN from './locales/zh-CN';
import ptPT from './locales/pt-PT'; import ptPT from './locales/pt-PT';
I18n.fallbacks = true; i18n.translations = {
I18n.defaultLocale = 'en'; en,
ru,
I18n.translations = { 'pt-BR': ptBR,
en, ru, 'pt-BR': ptBR, 'zh-CN': zhCN, fr, de, 'pt-PT': ptPT 'zh-CN': zhCN,
fr,
de,
'pt-PT': ptPT
}; };
i18n.fallbacks = true;
export default I18n; const defaultLanguage = { languageTag: 'en', isRTL: false };
const availableLanguages = Object.keys(i18n.translations);
const { languageTag, isRTL } = RNLocalize.findBestAvailableLanguage(availableLanguages) || defaultLanguage;
I18nManager.forceRTL(isRTL);
i18n.locale = languageTag;
export default i18n;

View File

@ -99,6 +99,7 @@ export default {
Are_you_sure_question_mark: 'Sind Sie sicher?', Are_you_sure_question_mark: 'Sind Sie sicher?',
Are_you_sure_you_want_to_leave_the_room: 'Möchten Sie den Raum wirklich verlassen {{room}}?', Are_you_sure_you_want_to_leave_the_room: 'Möchten Sie den Raum wirklich verlassen {{room}}?',
Authenticating: 'Authentifizierung', Authenticating: 'Authentifizierung',
Auto_Translate: 'Automatische Übersetzung',
Avatar_changed_successfully: 'Avatar erfolgreich geändert!', Avatar_changed_successfully: 'Avatar erfolgreich geändert!',
Avatar_Url: 'Avatar-URL', Avatar_Url: 'Avatar-URL',
Away: 'Abwesend', Away: 'Abwesend',
@ -155,11 +156,13 @@ export default {
Email_or_password_field_is_empty: 'Das E-Mail- oder Passwortfeld ist leer', Email_or_password_field_is_empty: 'Das E-Mail- oder Passwortfeld ist leer',
Email: 'Email', Email: 'Email',
email: 'Email', email: 'Email',
Enable_Auto_Translate: 'Automatische Übersetzung aktivieren',
Enable_markdown: 'Markdown aktivieren', Enable_markdown: 'Markdown aktivieren',
Enable_notifications: 'Benachrichtigungen aktivieren', Enable_notifications: 'Benachrichtigungen aktivieren',
Everyone_can_access_this_channel: 'Jeder kann auf diesen Kanal zugreifen', Everyone_can_access_this_channel: 'Jeder kann auf diesen Kanal zugreifen',
erasing_room: 'lösche Raum', erasing_room: 'lösche Raum',
Error_uploading: 'Fehler beim Hochladen', Error_uploading: 'Fehler beim Hochladen',
Favorite: 'Favorisieren',
Favorites: 'Favoriten', Favorites: 'Favoriten',
Files: 'Dateien', Files: 'Dateien',
File_description: 'Dateibeschreibung', File_description: 'Dateibeschreibung',
@ -173,6 +176,7 @@ export default {
Forgot_Password: 'Passwort vergessen', Forgot_Password: 'Passwort vergessen',
Group_by_favorites: 'Nach Favoriten gruppieren', Group_by_favorites: 'Nach Favoriten gruppieren',
Group_by_type: 'Gruppieren nach Typ', Group_by_type: 'Gruppieren nach Typ',
Hide: 'Ausblenden',
Has_joined_the_channel: 'Ist dem Kanal beigetreten', Has_joined_the_channel: 'Ist dem Kanal beigetreten',
Has_joined_the_conversation: 'Hat sich dem Gespräch angeschlossen', Has_joined_the_conversation: 'Hat sich dem Gespräch angeschlossen',
Has_left_the_channel: 'Hat den Kanal verlassen', Has_left_the_channel: 'Hat den Kanal verlassen',
@ -266,6 +270,7 @@ export default {
Reactions_are_disabled: 'Reaktionen sind deaktiviert', Reactions_are_disabled: 'Reaktionen sind deaktiviert',
Reactions_are_enabled: 'Reaktionen sind aktiviert', Reactions_are_enabled: 'Reaktionen sind aktiviert',
Reactions: 'Reaktionen', Reactions: 'Reaktionen',
Read: 'Gelesen',
Read_Only_Channel: 'Nur-Lese-Kanal', Read_Only_Channel: 'Nur-Lese-Kanal',
Read_Only: 'Schreibgeschützt', Read_Only: 'Schreibgeschützt',
Read_Receipt: 'Lesebestätigung', Read_Receipt: 'Lesebestätigung',
@ -343,12 +348,14 @@ export default {
Timezone: 'Zeitzone', Timezone: 'Zeitzone',
topic: 'Thema', topic: 'Thema',
Topic: 'Thema', Topic: 'Thema',
Translate: 'Übersetzen',
Try_again: 'Versuchen Sie es nochmal', Try_again: 'Versuchen Sie es nochmal',
Two_Factor_Authentication: 'Zwei-Faktor-Authentifizierung', Two_Factor_Authentication: 'Zwei-Faktor-Authentifizierung',
Type_the_channel_name_here: 'Geben Sie hier den Kanalnamen ein', Type_the_channel_name_here: 'Geben Sie hier den Kanalnamen ein',
unarchive: 'wiederherstellen', unarchive: 'wiederherstellen',
UNARCHIVE: 'WIEDERHERSTELLEN', UNARCHIVE: 'WIEDERHERSTELLEN',
Unblock_user: 'Nutzer entblockieren', Unblock_user: 'Nutzer entblockieren',
Unfavorite: 'Nicht mehr favorisieren',
Unfollowed_thread: 'Thread nicht mehr folgen', Unfollowed_thread: 'Thread nicht mehr folgen',
Unmute: 'Stummschaltung aufheben', Unmute: 'Stummschaltung aufheben',
unmuted: 'Stummschaltung aufgehoben', unmuted: 'Stummschaltung aufgehoben',
@ -374,6 +381,7 @@ export default {
Username_or_email: 'Benutzername oder E-Mail-Adresse', Username_or_email: 'Benutzername oder E-Mail-Adresse',
Validating: 'Validierung', Validating: 'Validierung',
Video_call: 'Videoanruf', Video_call: 'Videoanruf',
View_Original: 'Original anzeigen',
Voice_call: 'Sprachanruf', Voice_call: 'Sprachanruf',
Welcome: 'Herzlich willkommen', Welcome: 'Herzlich willkommen',
Welcome_to_RocketChat: 'Willkommen bei Rocket.Chat', Welcome_to_RocketChat: 'Willkommen bei Rocket.Chat',

View File

@ -103,6 +103,7 @@ export default {
Avatar_changed_successfully: 'Avatar changed successfully!', Avatar_changed_successfully: 'Avatar changed successfully!',
Avatar_Url: 'Avatar URL', Avatar_Url: 'Avatar URL',
Away: 'Away', Away: 'Away',
Back: 'Back',
Block_user: 'Block user', Block_user: 'Block user',
Broadcast_channel_Description: 'Only authorized users can write new messages, but the other users will be able to reply', Broadcast_channel_Description: 'Only authorized users can write new messages, but the other users will be able to reply',
Broadcast_Channel: 'Broadcast Channel', Broadcast_Channel: 'Broadcast Channel',
@ -120,6 +121,7 @@ export default {
Close_emoji_selector: 'Close emoji selector', Close_emoji_selector: 'Close emoji selector',
Choose: 'Choose', Choose: 'Choose',
Choose_from_library: 'Choose from library', Choose_from_library: 'Choose from library',
Choose_file: 'Choose file',
Code: 'Code', Code: 'Code',
Collaborative: 'Collaborative', Collaborative: 'Collaborative',
Confirm: 'Confirm', Confirm: 'Confirm',
@ -262,6 +264,7 @@ export default {
Private_Channel: 'Private Channel', Private_Channel: 'Private Channel',
Private_Groups: 'Private Groups', Private_Groups: 'Private Groups',
Private: 'Private', Private: 'Private',
Processing: 'Processing...',
Profile_saved_successfully: 'Profile saved successfully!', Profile_saved_successfully: 'Profile saved successfully!',
Profile: 'Profile', Profile: 'Profile',
Public_Channel: 'Public Channel', Public_Channel: 'Public Channel',
@ -308,11 +311,13 @@ export default {
Search_global_users: 'Search for global users', Search_global_users: 'Search for global users',
Search_global_users_description: 'If you turn-on, you can search for any user from others companies or servers.', Search_global_users_description: 'If you turn-on, you can search for any user from others companies or servers.',
Select_Avatar: 'Select Avatar', Select_Avatar: 'Select Avatar',
Select_Server: 'Select Server',
Select_Users: 'Select Users', Select_Users: 'Select Users',
Send: 'Send', Send: 'Send',
Send_audio_message: 'Send audio message', Send_audio_message: 'Send audio message',
Send_crash_report: 'Send crash report', Send_crash_report: 'Send crash report',
Send_message: 'Send message', Send_message: 'Send message',
Send_to: 'Send to...',
Sent_an_attachment: 'Sent an attachment', Sent_an_attachment: 'Sent an attachment',
Server: 'Server', Server: 'Server',
Servers: 'Servers', Servers: 'Servers',
@ -335,6 +340,7 @@ export default {
Started_discussion: 'Started a discussion:', Started_discussion: 'Started a discussion:',
Submit: 'Submit', Submit: 'Submit',
Take_a_photo: 'Take a photo', Take_a_photo: 'Take a photo',
Take_a_video: 'Take a video',
tap_to_change_status: 'tap to change status', tap_to_change_status: 'tap to change status',
Tap_to_view_servers_list: 'Tap to view servers list', Tap_to_view_servers_list: 'Tap to view servers list',
Terms_of_Service: ' Terms of Service ', Terms_of_Service: ' Terms of Service ',
@ -346,6 +352,7 @@ export default {
Thread: 'Thread', Thread: 'Thread',
Threads: 'Threads', Threads: 'Threads',
Timezone: 'Timezone', Timezone: 'Timezone',
To: 'To',
topic: 'topic', topic: 'topic',
Topic: 'Topic', Topic: 'Topic',
Translate: 'Translate', Translate: 'Translate',
@ -386,6 +393,7 @@ export default {
Welcome: 'Welcome', Welcome: 'Welcome',
Welcome_to_RocketChat: 'Welcome to Rocket.Chat', Welcome_to_RocketChat: 'Welcome to Rocket.Chat',
Whats_your_2fa: 'What\'s your 2FA code?', Whats_your_2fa: 'What\'s your 2FA code?',
Without_Servers: 'Without Servers',
Yes_action_it: 'Yes, {{action}} it!', Yes_action_it: 'Yes, {{action}} it!',
Yesterday: 'Yesterday', Yesterday: 'Yesterday',
You_are_in_preview_mode: 'You are in preview mode', You_are_in_preview_mode: 'You are in preview mode',
@ -395,6 +403,7 @@ export default {
you_were_mentioned: 'you were mentioned', you_were_mentioned: 'you were mentioned',
you: 'you', you: 'you',
You: 'You', You: 'You',
You_need_to_access_at_least_one_RocketChat_server_to_share_something: 'You need to access at least one Rocket.Chat server to share something.',
Version_no: 'Version: {{version}}', Version_no: 'Version: {{version}}',
You_will_not_be_able_to_recover_this_message: 'You will not be able to recover this message!', You_will_not_be_able_to_recover_this_message: 'You will not be able to recover this message!',
Change_Language: 'Change Language', Change_Language: 'Change Language',

View File

@ -108,6 +108,7 @@ export default {
Avatar_changed_successfully: 'Avatar alterado com sucesso!', Avatar_changed_successfully: 'Avatar alterado com sucesso!',
Avatar_Url: 'Avatar URL', Avatar_Url: 'Avatar URL',
Away: 'Ausente', Away: 'Ausente',
Back: 'Voltar',
Block_user: 'Bloquear usuário', Block_user: 'Bloquear usuário',
Broadcast_channel_Description: 'Somente usuários autorizados podem escrever novas mensagens, mas os outros usuários poderão responder', Broadcast_channel_Description: 'Somente usuários autorizados podem escrever novas mensagens, mas os outros usuários poderão responder',
Broadcast_Channel: 'Canal de Transmissão', Broadcast_Channel: 'Canal de Transmissão',
@ -125,6 +126,7 @@ export default {
Close_emoji_selector: 'Fechar seletor de emojis', Close_emoji_selector: 'Fechar seletor de emojis',
Choose: 'Escolher', Choose: 'Escolher',
Choose_from_library: 'Escolha da biblioteca', Choose_from_library: 'Escolha da biblioteca',
Choose_file: 'Enviar arquivo',
Code: 'Código', Code: 'Código',
Collaborative: 'Colaborativo', Collaborative: 'Colaborativo',
Confirm: 'Confirmar', Confirm: 'Confirmar',
@ -255,6 +257,7 @@ export default {
Private_Channel: 'Canal Privado', Private_Channel: 'Canal Privado',
Private_Groups: 'Grupo Privado', Private_Groups: 'Grupo Privado',
Private: 'Privado', Private: 'Privado',
Processing: 'Processando...',
Profile_saved_successfully: 'Perfil salvo com sucesso!', Profile_saved_successfully: 'Perfil salvo com sucesso!',
Profile: 'Perfil', Profile: 'Perfil',
Public_Channel: 'Canal Público', Public_Channel: 'Canal Público',
@ -299,10 +302,12 @@ export default {
Search_global_users: 'Busca por usuários globais', Search_global_users: 'Busca por usuários globais',
Search_global_users_description: 'Caso ativado, busca por usuários de outras empresas ou servidores.', Search_global_users_description: 'Caso ativado, busca por usuários de outras empresas ou servidores.',
Select_Avatar: 'Selecionar Avatar', Select_Avatar: 'Selecionar Avatar',
Select_Server: 'Selecionar Servidor',
Select_Users: 'Selecionar Usuários', Select_Users: 'Selecionar Usuários',
Send: 'Enviar', Send: 'Enviar',
Send_audio_message: 'Enviar mensagem de áudio', Send_audio_message: 'Enviar mensagem de áudio',
Send_message: 'Enviar mensagem', Send_message: 'Enviar mensagem',
Send_to: 'Enviar para...',
Sent_an_attachment: 'Enviou um anexo', Sent_an_attachment: 'Enviou um anexo',
Server: 'Servidor', Server: 'Servidor',
Set_username_subtitle: 'O usuário é utilizado para permitir que você seja mencionado em mensagens', Set_username_subtitle: 'O usuário é utilizado para permitir que você seja mencionado em mensagens',
@ -322,6 +327,7 @@ export default {
Started_discussion: 'Iniciou uma discussão:', Started_discussion: 'Iniciou uma discussão:',
Submit: 'Enviar', Submit: 'Enviar',
Take_a_photo: 'Tirar uma foto', Take_a_photo: 'Tirar uma foto',
Take_a_video: 'Gravar um vídeo',
Terms_of_Service: ' Termos de Serviço ', Terms_of_Service: ' Termos de Serviço ',
The_URL_is_invalid: 'A URL fornecida é inválida ou não acessível. Por favor tente novamente, mas com uma url diferente.', The_URL_is_invalid: 'A URL fornecida é inválida ou não acessível. Por favor tente novamente, mas com uma url diferente.',
There_was_an_error_while_action: 'Aconteceu um erro {{action}}!', There_was_an_error_while_action: 'Aconteceu um erro {{action}}!',
@ -330,6 +336,7 @@ export default {
Thread: 'Tópico', Thread: 'Tópico',
Threads: 'Tópicos', Threads: 'Tópicos',
Timezone: 'Fuso horário', Timezone: 'Fuso horário',
To: 'Para',
topic: 'tópico', topic: 'tópico',
Topic: 'Tópico', Topic: 'Tópico',
Try_again: 'Tentar novamente', Try_again: 'Tentar novamente',
@ -366,6 +373,7 @@ export default {
Welcome: 'Bem vindo', Welcome: 'Bem vindo',
Welcome_to_RocketChat: 'Bem vindo ao Rocket.Chat', Welcome_to_RocketChat: 'Bem vindo ao Rocket.Chat',
Whats_your_2fa: 'Qual seu código de autenticação?', Whats_your_2fa: 'Qual seu código de autenticação?',
Without_Servers: 'Sem Servidores',
Yes_action_it: 'Sim, {{action}}!', Yes_action_it: 'Sim, {{action}}!',
Yesterday: 'Ontem', Yesterday: 'Ontem',
You_are_in_preview_mode: 'Está é uma prévia do canal', You_are_in_preview_mode: 'Está é uma prévia do canal',
@ -375,5 +383,6 @@ export default {
you_were_mentioned: 'você foi mencionado', you_were_mentioned: 'você foi mencionado',
you: 'você', you: 'você',
You: 'Você', You: 'Você',
You_need_to_access_at_least_one_RocketChat_server_to_share_something: 'Você precisa acessar ao menos um servidor Rocket.Chat para compartilhar.',
You_will_not_be_able_to_recover_this_message: 'Você não será capaz de recuperar essa mensagem!' You_will_not_be_able_to_recover_this_message: 'Você não será capaz de recuperar essa mensagem!'
}; };

View File

@ -5,47 +5,18 @@ import {
import { Provider } from 'react-redux'; import { Provider } from 'react-redux';
import { useScreens } from 'react-native-screens'; // eslint-disable-line import/no-unresolved import { useScreens } from 'react-native-screens'; // eslint-disable-line import/no-unresolved
import { Linking } from 'react-native'; import { Linking } from 'react-native';
import firebase from 'react-native-firebase';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { appInit } from './actions'; import { appInit } from './actions';
import { deepLinkingOpen } from './actions/deepLinking'; import { deepLinkingOpen } from './actions/deepLinking';
import OnboardingView from './views/OnboardingView';
import NewServerView from './views/NewServerView';
import LoginSignupView from './views/LoginSignupView';
import AuthLoadingView from './views/AuthLoadingView';
import RoomsListView from './views/RoomsListView';
import RoomView from './views/RoomView';
import NewMessageView from './views/NewMessageView';
import DirectoryView from './views/DirectoryView';
import LoginView from './views/LoginView';
import Navigation from './lib/Navigation'; import Navigation from './lib/Navigation';
import Sidebar from './views/SidebarView'; import Sidebar from './views/SidebarView';
import ProfileView from './views/ProfileView';
import SettingsView from './views/SettingsView';
import LanguageView from './views/LanguageView';
import AdminPanelView from './views/AdminPanelView';
import RoomActionsView from './views/RoomActionsView';
import RoomInfoView from './views/RoomInfoView';
import RoomInfoEditView from './views/RoomInfoEditView';
import RoomMembersView from './views/RoomMembersView';
import SearchMessagesView from './views/SearchMessagesView';
import ReadReceiptsView from './views/ReadReceiptView';
import ThreadMessagesView from './views/ThreadMessagesView';
import MessagesView from './views/MessagesView';
import AutoTranslateView from './views/AutoTranslateView';
import SelectedUsersView from './views/SelectedUsersView';
import CreateChannelView from './views/CreateChannelView';
import LegalView from './views/LegalView';
import ForgotPasswordView from './views/ForgotPasswordView';
import RegisterView from './views/RegisterView';
import OAuthView from './views/OAuthView';
import SetUsernameView from './views/SetUsernameView';
import { HEADER_BACKGROUND, HEADER_TITLE, HEADER_BACK } from './constants/colors';
import parseQuery from './lib/methods/helpers/parseQuery'; import parseQuery from './lib/methods/helpers/parseQuery';
import { initializePushNotifications, onNotification } from './notifications/push'; import { initializePushNotifications, onNotification } from './notifications/push';
import store from './lib/createStore'; import store from './lib/createStore';
import NotificationBadge from './notifications/inApp'; import NotificationBadge from './notifications/inApp';
import { defaultHeader, onNavigationStateChange } from './utils/navigation';
import Toast from './containers/Toast';
useScreens(); useScreens();
@ -63,35 +34,38 @@ const parseDeepLinking = (url) => {
return null; return null;
}; };
const defaultHeader = {
headerStyle: {
backgroundColor: HEADER_BACKGROUND
},
headerTitleStyle: {
color: HEADER_TITLE
},
headerBackTitle: null,
headerTintColor: HEADER_BACK
};
// Outside // Outside
const OutsideStack = createStackNavigator({ const OutsideStack = createStackNavigator({
OnboardingView: { OnboardingView: {
screen: OnboardingView, getScreen: () => require('./views/OnboardingView').default,
header: null header: null
}, },
NewServerView, NewServerView: {
LoginSignupView, getScreen: () => require('./views/NewServerView').default
LoginView, },
ForgotPasswordView, LoginSignupView: {
RegisterView, getScreen: () => require('./views/LoginSignupView').default
LegalView },
LoginView: {
getScreen: () => require('./views/LoginView').default
},
ForgotPasswordView: {
getScreen: () => require('./views/ForgotPasswordView').default
},
RegisterView: {
getScreen: () => require('./views/RegisterView').default
},
LegalView: {
getScreen: () => require('./views/LegalView').default
}
}, { }, {
defaultNavigationOptions: defaultHeader defaultNavigationOptions: defaultHeader
}); });
const OAuthStack = createStackNavigator({ const OAuthStack = createStackNavigator({
OAuthView OAuthView: {
getScreen: () => require('./views/OAuthView').default
}
}, { }, {
defaultNavigationOptions: defaultHeader defaultNavigationOptions: defaultHeader
}); });
@ -107,19 +81,45 @@ const OutsideStackModal = createStackNavigator({
// Inside // Inside
const ChatsStack = createStackNavigator({ const ChatsStack = createStackNavigator({
RoomsListView, RoomsListView: {
RoomView, getScreen: () => require('./views/RoomsListView').default
RoomActionsView, },
RoomInfoView, RoomView: {
RoomInfoEditView, getScreen: () => require('./views/RoomView').default
RoomMembersView, },
SearchMessagesView, RoomActionsView: {
SelectedUsersView, getScreen: () => require('./views/RoomActionsView').default
ThreadMessagesView, },
MessagesView, RoomInfoView: {
AutoTranslateView, getScreen: () => require('./views/RoomInfoView').default
ReadReceiptsView, },
DirectoryView RoomInfoEditView: {
getScreen: () => require('./views/RoomInfoEditView').default
},
RoomMembersView: {
getScreen: () => require('./views/RoomMembersView').default
},
SearchMessagesView: {
getScreen: () => require('./views/SearchMessagesView').default
},
SelectedUsersView: {
getScreen: () => require('./views/SelectedUsersView').default
},
ThreadMessagesView: {
getScreen: () => require('./views/ThreadMessagesView').default
},
MessagesView: {
getScreen: () => require('./views/MessagesView').default
},
AutoTranslateView: {
getScreen: () => require('./views/AutoTranslateView').default
},
ReadReceiptsView: {
getScreen: () => require('./views/ReadReceiptView').default
},
DirectoryView: {
getScreen: () => require('./views/DirectoryView').default
}
}, { }, {
defaultNavigationOptions: defaultHeader defaultNavigationOptions: defaultHeader
}); });
@ -135,7 +135,9 @@ ChatsStack.navigationOptions = ({ navigation }) => {
}; };
const ProfileStack = createStackNavigator({ const ProfileStack = createStackNavigator({
ProfileView ProfileView: {
getScreen: () => require('./views/ProfileView').default
}
}, { }, {
defaultNavigationOptions: defaultHeader defaultNavigationOptions: defaultHeader
}); });
@ -151,14 +153,20 @@ ProfileStack.navigationOptions = ({ navigation }) => {
}; };
const SettingsStack = createStackNavigator({ const SettingsStack = createStackNavigator({
SettingsView, SettingsView: {
LanguageView getScreen: () => require('./views/SettingsView').default
},
LanguageView: {
getScreen: () => require('./views/LanguageView').default
}
}, { }, {
defaultNavigationOptions: defaultHeader defaultNavigationOptions: defaultHeader
}); });
const AdminPanelStack = createStackNavigator({ const AdminPanelStack = createStackNavigator({
AdminPanelView AdminPanelView: {
getScreen: () => require('./views/AdminPanelView').default
}
}, { }, {
defaultNavigationOptions: defaultHeader defaultNavigationOptions: defaultHeader
}); });
@ -183,9 +191,15 @@ const ChatsDrawer = createDrawerNavigator({
}); });
const NewMessageStack = createStackNavigator({ const NewMessageStack = createStackNavigator({
NewMessageView, NewMessageView: {
SelectedUsersViewCreateChannel: SelectedUsersView, getScreen: () => require('./views/NewMessageView').default
CreateChannelView },
SelectedUsersViewCreateChannel: {
getScreen: () => require('./views/SelectedUsersView').default
},
CreateChannelView: {
getScreen: () => require('./views/CreateChannelView').default
}
}, { }, {
defaultNavigationOptions: defaultHeader defaultNavigationOptions: defaultHeader
}); });
@ -200,7 +214,9 @@ const InsideStackModal = createStackNavigator({
}); });
const SetUsernameStack = createStackNavigator({ const SetUsernameStack = createStackNavigator({
SetUsernameView SetUsernameView: {
getScreen: () => require('./views/SetUsernameView').default
}
}); });
class CustomInsideStack extends React.Component { class CustomInsideStack extends React.Component {
@ -216,6 +232,7 @@ class CustomInsideStack extends React.Component {
<React.Fragment> <React.Fragment>
<InsideStackModal navigation={navigation} /> <InsideStackModal navigation={navigation} />
<NotificationBadge navigation={navigation} /> <NotificationBadge navigation={navigation} />
<Toast />
</React.Fragment> </React.Fragment>
); );
} }
@ -225,7 +242,9 @@ const App = createAppContainer(createSwitchNavigator(
{ {
OutsideStack: OutsideStackModal, OutsideStack: OutsideStackModal,
InsideStack: CustomInsideStack, InsideStack: CustomInsideStack,
AuthLoading: AuthLoadingView, AuthLoading: {
getScreen: () => require('./views/AuthLoadingView').default
},
SetUsernameStack SetUsernameStack
}, },
{ {
@ -233,28 +252,6 @@ const App = createAppContainer(createSwitchNavigator(
} }
)); ));
// gets the current screen from navigation state
const getActiveRouteName = (navigationState) => {
if (!navigationState) {
return null;
}
const route = navigationState.routes[navigationState.index];
// dive into nested navigators
if (route.routes) {
return getActiveRouteName(route);
}
return route.routeName;
};
const onNavigationStateChange = (prevState, currentState) => {
const currentScreen = getActiveRouteName(currentState);
const prevScreen = getActiveRouteName(prevState);
if (prevScreen !== currentScreen) {
firebase.analytics().setCurrentScreen(currentScreen);
}
};
export default class Root extends React.Component { export default class Root extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);

View File

@ -0,0 +1,21 @@
import { NavigationActions } from 'react-navigation';
let _shareNavigator;
function setTopLevelNavigator(navigatorRef) {
_shareNavigator = navigatorRef;
}
function navigate(routeName, params) {
_shareNavigator.dispatch(
NavigationActions.navigate({
routeName,
params
})
);
}
export default {
navigate,
setTopLevelNavigator
};

View File

@ -40,6 +40,15 @@ export default async function() {
if (setting._id === 'Site_Name') { if (setting._id === 'Site_Name') {
updateServer.call(this, { name: setting.valueAsString }); updateServer.call(this, { name: setting.valueAsString });
} }
if (setting._id === 'UI_Use_Real_Name') {
updateServer.call(this, { useRealName: setting.valueAsBoolean });
}
if (setting._id === 'FileUpload_MediaTypeWhiteList') {
updateServer.call(this, { FileUpload_MediaTypeWhiteList: setting.valueAsString });
}
if (setting._id === 'FileUpload_MaxFileSize') {
updateServer.call(this, { FileUpload_MaxFileSize: setting.valueAsNumber });
}
}) })
) )
); );

View File

@ -1,4 +1,3 @@
import reduxStore from '../createStore';
import database from '../realm'; import database from '../realm';
import log from '../../utils/log'; import log from '../../utils/log';
@ -23,11 +22,12 @@ export function cancelUpload(path) {
} }
} }
export function sendFileMessage(rid, fileInfo, tmid) { export function sendFileMessage(rid, fileInfo, tmid, server, user) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
try { try {
const { FileUpload_MaxFileSize, Site_Url } = reduxStore.getState().settings; const { serversDB } = database.databases;
const { id, token } = reduxStore.getState().login.user; const { FileUpload_MaxFileSize, id: Site_Url } = serversDB.objectForPrimaryKey('servers', server);
const { id, token } = user;
// -1 maxFileSize means there is no limit // -1 maxFileSize means there is no limit
if (FileUpload_MaxFileSize > -1 && fileInfo.size > FileUpload_MaxFileSize) { if (FileUpload_MaxFileSize > -1 && fileInfo.size > FileUpload_MaxFileSize) {

View File

@ -1,12 +1,12 @@
import messagesStatus from '../../constants/messagesStatus'; import messagesStatus from '../../constants/messagesStatus';
import buildMessage from './helpers/buildMessage'; import buildMessage from './helpers/buildMessage';
import database from '../realm'; import database from '../realm';
import reduxStore from '../createStore';
import log from '../../utils/log'; import log from '../../utils/log';
import random from '../../utils/random'; import random from '../../utils/random';
export const getMessage = (rid, msg = '', tmid) => { export const getMessage = (rid, msg = '', tmid, user) => {
const _id = random(17); const _id = random(17);
const { id, username } = user;
const message = { const message = {
_id, _id,
rid, rid,
@ -16,8 +16,8 @@ export const getMessage = (rid, msg = '', tmid) => {
_updatedAt: new Date(), _updatedAt: new Date(),
status: messagesStatus.TEMP, status: messagesStatus.TEMP,
u: { u: {
_id: reduxStore.getState().login.user.id || '1', _id: id || '1',
username: reduxStore.getState().login.user.username username
} }
}; };
try { try {
@ -43,9 +43,9 @@ export async function sendMessageCall(message) {
return data; return data;
} }
export default async function(rid, msg, tmid) { export default async function(rid, msg, tmid, user) {
try { try {
const message = getMessage(rid, msg, tmid); const message = getMessage(rid, msg, tmid, user);
const [room] = database.objects('subscriptions').filtered('rid == $0', rid); const [room] = database.objects('subscriptions').filtered('rid == $0', rid);
if (room) { if (room) {

View File

@ -1,4 +1,5 @@
import Realm from 'realm'; import Realm from 'realm';
import RNRealmPath from 'react-native-realm-path';
// import { AsyncStorage } from 'react-native'; // import { AsyncStorage } from 'react-native';
// Realm.clearTestState(); // Realm.clearTestState();
@ -25,6 +26,9 @@ const serversSchema = {
id: 'string', id: 'string',
name: { type: 'string', optional: true }, name: { type: 'string', optional: true },
iconURL: { type: 'string', optional: true }, iconURL: { type: 'string', optional: true },
useRealName: { type: 'bool', optional: true },
FileUpload_MediaTypeWhiteList: { type: 'string', optional: true },
FileUpload_MaxFileSize: { type: 'int', optional: true },
roomsUpdatedAt: { type: 'date', optional: true }, roomsUpdatedAt: { type: 'date', optional: true },
version: 'string?' version: 'string?'
} }
@ -408,12 +412,12 @@ const inMemorySchema = [usersTypingSchema, activeUsersSchema];
class DB { class DB {
databases = { databases = {
serversDB: new Realm({ serversDB: new Realm({
path: 'default.realm', path: `${ RNRealmPath.realmPath }default.realm`,
schema: [ schema: [
userSchema, userSchema,
serversSchema serversSchema
], ],
schemaVersion: 9, schemaVersion: 10,
migration: (oldRealm, newRealm) => { migration: (oldRealm, newRealm) => {
if (oldRealm.schemaVersion >= 1 && newRealm.schemaVersion <= 9) { if (oldRealm.schemaVersion >= 1 && newRealm.schemaVersion <= 9) {
const newServers = newRealm.objects('servers'); const newServers = newRealm.objects('servers');
@ -426,7 +430,7 @@ class DB {
} }
}), }),
inMemoryDB: new Realm({ inMemoryDB: new Realm({
path: 'memory.realm', path: `${ RNRealmPath.realmPath }memory.realm`,
schema: inMemorySchema, schema: inMemorySchema,
schemaVersion: 2, schemaVersion: 2,
inMemory: true inMemory: true
@ -468,7 +472,7 @@ class DB {
setActiveDB(database = '') { setActiveDB(database = '') {
const path = database.replace(/(^\w+:|^)\/\//, ''); const path = database.replace(/(^\w+:|^)\/\//, '');
return this.databases.activeDB = new Realm({ return this.databases.activeDB = new Realm({
path: `${ path }.realm`, path: `${ RNRealmPath.realmPath }${ path }.realm`,
schema, schema,
schemaVersion: 13, schemaVersion: 13,
migration: (oldRealm, newRealm) => { migration: (oldRealm, newRealm) => {

View File

@ -14,6 +14,9 @@ import {
setUser, setLoginServices, loginRequest, loginFailure, logout setUser, setLoginServices, loginRequest, loginFailure, logout
} from '../actions/login'; } from '../actions/login';
import { disconnect, connectSuccess, connectRequest } from '../actions/connect'; import { disconnect, connectSuccess, connectRequest } from '../actions/connect';
import {
shareSelectServer, shareSetUser
} from '../actions/share';
import subscribeRooms from './methods/subscriptions/rooms'; import subscribeRooms from './methods/subscriptions/rooms';
import subscribeRoom from './methods/subscriptions/room'; import subscribeRoom from './methods/subscriptions/room';
@ -217,6 +220,35 @@ const RocketChat = {
}); });
}, },
async shareExtensionInit(server) {
database.setActiveDB(server);
if (this.sdk) {
this.sdk.disconnect();
this.sdk = null;
}
// Use useSsl: false only if server url starts with http://
const useSsl = !/http:\/\//.test(server);
this.sdk = new RocketchatClient({ host: server, protocol: 'ddp', useSsl });
// set Server
const { serversDB } = database.databases;
reduxStore.dispatch(shareSelectServer(server));
// set User info
const userId = await RNUserDefaults.get(`${ RocketChat.TOKEN_KEY }-${ server }`);
const user = userId && serversDB.objectForPrimaryKey('user', userId);
reduxStore.dispatch(shareSetUser({
id: user.id,
token: user.token,
username: user.username
}));
await RocketChat.login({ resume: user.token });
},
register(credentials) { register(credentials) {
// RC 0.50.0 // RC 0.50.0
return this.sdk.post('users.register', credentials, false); return this.sdk.post('users.register', credentials, false);
@ -730,14 +762,14 @@ const RocketChat = {
return JSON.parse(useMarkdown); return JSON.parse(useMarkdown);
}, },
async getSortPreferences() { async getSortPreferences() {
const prefs = await AsyncStorage.getItem(SORT_PREFS_KEY); const prefs = await RNUserDefaults.objectForKey(SORT_PREFS_KEY);
return JSON.parse(prefs); return prefs;
}, },
async saveSortPreference(param) { async saveSortPreference(param) {
try { try {
let prefs = await RocketChat.getSortPreferences(); let prefs = await RocketChat.getSortPreferences();
prefs = { ...prefs, ...param }; prefs = { ...prefs, ...param };
return await AsyncStorage.setItem(SORT_PREFS_KEY, JSON.stringify(prefs)); return await RNUserDefaults.setObjectForKey(SORT_PREFS_KEY, prefs);
} catch (error) { } catch (error) {
console.warn(error); console.warn(error);
} }

View File

@ -5,7 +5,9 @@ import PropTypes from 'prop-types';
import Avatar from '../../containers/Avatar'; import Avatar from '../../containers/Avatar';
import Touch from '../../utils/touch'; import Touch from '../../utils/touch';
import RoomTypeIcon from '../../containers/RoomTypeIcon'; import RoomTypeIcon from '../../containers/RoomTypeIcon';
import styles from './styles'; import styles, { ROW_HEIGHT } from './styles';
export { ROW_HEIGHT };
const DirectoryItemLabel = React.memo(({ text }) => { const DirectoryItemLabel = React.memo(({ text }) => {
if (!text) { if (!text) {
@ -30,10 +32,10 @@ const DirectoryItem = ({
/> />
<View style={styles.directoryItemTextContainer}> <View style={styles.directoryItemTextContainer}>
<View style={styles.directoryItemTextTitle}> <View style={styles.directoryItemTextTitle}>
<RoomTypeIcon type='c' /> <RoomTypeIcon type={type} />
<Text style={styles.directoryItemName} numberOfLines={1}>{title}</Text> <Text style={styles.directoryItemName} numberOfLines={1}>{title}</Text>
</View> </View>
<Text style={styles.directoryItemUsername} numberOfLines={1}>{description}</Text> { description ? <Text style={styles.directoryItemUsername} numberOfLines={1}>{description}</Text> : null }
</View> </View>
<DirectoryItemLabel text={rightLabel} /> <DirectoryItemLabel text={rightLabel} />
</View> </View>

View File

@ -0,0 +1,49 @@
import { StyleSheet } from 'react-native';
import { COLOR_WHITE } from '../../constants/colors';
import sharedStyles from '../../views/Styles';
export const ROW_HEIGHT = 54;
export default StyleSheet.create({
directoryItemButton: {
height: ROW_HEIGHT,
backgroundColor: COLOR_WHITE
},
directoryItemContainer: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
paddingHorizontal: 15
},
directoryItemAvatar: {
marginRight: 12
},
directoryItemTextTitle: {
flexDirection: 'row',
alignItems: 'center'
},
directoryItemTextContainer: {
flex: 1,
flexDirection: 'column',
justifyContent: 'center'
},
directoryItemName: {
flex: 1,
fontSize: 17,
...sharedStyles.textMedium,
...sharedStyles.textColorNormal
},
directoryItemUsername: {
fontSize: 14,
...sharedStyles.textRegular,
...sharedStyles.textColorDescription
},
directoryItemLabel: {
fontSize: 14,
paddingLeft: 10,
...sharedStyles.textRegular,
...sharedStyles.textColorDescription
}
});

View File

@ -1,5 +1,4 @@
import React from 'react'; import React from 'react';
import moment from 'moment';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { View, Text, Animated } from 'react-native'; import { View, Text, Animated } from 'react-native';
import { RectButton, PanGestureHandler, State } from 'react-native-gesture-handler'; import { RectButton, PanGestureHandler, State } from 'react-native-gesture-handler';
@ -12,6 +11,7 @@ import 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 { capitalize, formatDate } from '../../utils/room';
import { LeftActions, RightActions } from './Actions'; import { LeftActions, RightActions } from './Actions';
export { ROW_HEIGHT }; export { ROW_HEIGHT };
@ -203,19 +203,12 @@ export default class RoomItem extends React.Component {
} }
} }
formatDate = date => moment(date).calendar(null, {
lastDay: `[${ I18n.t('Yesterday') }]`,
sameDay: 'h:mm A',
lastWeek: 'dddd',
sameElse: 'MMM D'
})
render() { render() {
const { const {
unread, userMentions, name, _updatedAt, alert, testID, type, avatarSize, baseUrl, userId, username, token, id, prid, showLastMessage, lastMessage, isRead, width, favorite 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 = formatDate(_updatedAt);
let accessibilityLabel = name; let accessibilityLabel = name;
if (unread === 1) { if (unread === 1) {
@ -275,7 +268,7 @@ export default class RoomItem extends React.Component {
<View style={styles.titleContainer}> <View style={styles.titleContainer}>
<TypeIcon type={type} id={id} prid={prid} /> <TypeIcon type={type} id={id} prid={prid} />
<Text style={[styles.title, alert && styles.alert]} ellipsizeMode='tail' numberOfLines={1}>{ name }</Text> <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} {_updatedAt ? <Text style={[styles.date, alert && styles.updateAlert]} ellipsizeMode='tail' numberOfLines={1}>{ capitalize(date) }</Text> : null}
</View> </View>
<View style={styles.row}> <View style={styles.row}>
<LastMessage lastMessage={lastMessage} type={type} showLastMessage={showLastMessage} username={username} alert={alert} /> <LastMessage lastMessage={lastMessage} type={type} showLastMessage={showLastMessage} username={username} alert={alert} />

View File

@ -0,0 +1,53 @@
import React from 'react';
import PropTypes from 'prop-types';
import { View, Text } from 'react-native';
import FastImage from 'react-native-fast-image';
import { RectButton } from 'react-native-gesture-handler';
import log from '../../utils/log';
import Check from '../../containers/Check';
import styles, { ROW_HEIGHT } from './styles';
export { ROW_HEIGHT };
const ServerItem = React.memo(({
server, item, onPress, hasCheck
}) => (
<RectButton onPress={onPress} style={styles.serverItem} testID={`rooms-list-header-server-${ item.id }`}>
<View style={styles.serverItemContainer}>
{item.iconURL
? (
<FastImage
source={{
uri: item.iconURL,
priority: FastImage.priority.high
}}
defaultSource={{ uri: 'logo' }}
style={styles.serverIcon}
onError={() => log('err_loading_server_icon')}
/>
)
: (
<FastImage
source={{ uri: 'logo' }}
style={styles.serverIcon}
/>
)
}
<View style={styles.serverTextContainer}>
<Text style={styles.serverName}>{item.name || item.id}</Text>
<Text style={styles.serverUrl}>{item.id}</Text>
</View>
{item.id === server && hasCheck ? <Check /> : null}
</View>
</RectButton>
));
ServerItem.propTypes = {
onPress: PropTypes.func.isRequired,
item: PropTypes.object.isRequired,
hasCheck: PropTypes.bool,
server: PropTypes.string
};
export default ServerItem;

View File

@ -0,0 +1,39 @@
import { StyleSheet } from 'react-native';
import sharedStyles from '../../views/Styles';
import { COLOR_WHITE } from '../../constants/colors';
export const ROW_HEIGHT = 56;
export default StyleSheet.create({
serverItem: {
height: ROW_HEIGHT,
backgroundColor: COLOR_WHITE,
justifyContent: 'center'
},
serverItemContainer: {
flexDirection: 'row',
alignItems: 'center'
},
serverIcon: {
width: 44,
height: 44,
marginHorizontal: 15,
borderRadius: 4
},
serverTextContainer: {
flex: 1,
flexDirection: 'column',
justifyContent: 'center'
},
serverName: {
fontSize: 18,
...sharedStyles.textColorNormal,
...sharedStyles.textSemibold
},
serverUrl: {
fontSize: 15,
...sharedStyles.textColorDescription,
...sharedStyles.textRegular
}
});

View File

@ -11,6 +11,7 @@ import app from './app';
import sortPreferences from './sortPreferences'; import sortPreferences from './sortPreferences';
import notification from './notification'; import notification from './notification';
import markdown from './markdown'; import markdown from './markdown';
import share from './share';
export default combineReducers({ export default combineReducers({
settings, settings,
@ -24,5 +25,6 @@ export default combineReducers({
rooms, rooms,
sortPreferences, sortPreferences,
notification, notification,
markdown markdown,
share
}); });

23
app/reducers/share.js Normal file
View File

@ -0,0 +1,23 @@
import { SHARE } from '../actions/actionsTypes';
const initialState = {
user: {},
server: ''
};
export default function share(state = initialState, action) {
switch (action.type) {
case SHARE.SELECT_SERVER:
return {
...state,
server: action.server
};
case SHARE.SET_USER:
return {
...state,
user: action.user
};
default:
return state;
}
}

View File

@ -2,12 +2,15 @@ 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 RNUserDefaults from 'rn-user-defaults';
import moment from 'moment';
import 'moment/min/locales';
import * as types from '../actions/actionsTypes'; import * as types from '../actions/actionsTypes';
import { appStart } from '../actions'; import { appStart } from '../actions';
import { serverFinishAdd, selectServerRequest } from '../actions/server'; import { serverFinishAdd, selectServerRequest } from '../actions/server';
import { loginFailure, loginSuccess, setUser } from '../actions/login'; import { loginFailure, loginSuccess, setUser } from '../actions/login';
import { roomsRequest } from '../actions/rooms'; import { roomsRequest } from '../actions/rooms';
import { toMomentLocale } from '../utils/moment';
import RocketChat from '../lib/rocketchat'; import RocketChat from '../lib/rocketchat';
import log from '../utils/log'; import log from '../utils/log';
import I18n from '../i18n'; import I18n from '../i18n';
@ -72,6 +75,7 @@ const handleLoginSuccess = function* handleLoginSuccess({ user }) {
yield fork(fetchUserPresence); yield fork(fetchUserPresence);
I18n.locale = user.language; I18n.locale = user.language;
moment.locale(toMomentLocale(user.language));
const { serversDB } = database.databases; const { serversDB } = database.databases;
serversDB.write(() => { serversDB.write(() => {
@ -132,6 +136,7 @@ const handleLogout = function* handleLogout() {
const handleSetUser = function handleSetUser({ user }) { const handleSetUser = function handleSetUser({ user }) {
if (user && user.language) { if (user && user.language) {
I18n.locale = user.language; I18n.locale = user.language;
moment.locale(toMomentLocale(user.language));
} }
}; };

98
app/share.js Normal file
View File

@ -0,0 +1,98 @@
import React from 'react';
import { View } from 'react-native';
import { createAppContainer, createStackNavigator, createSwitchNavigator } from 'react-navigation';
import { Provider } from 'react-redux';
import RNUserDefaults from 'rn-user-defaults';
import Navigation from './lib/ShareNavigation';
import store from './lib/createStore';
import sharedStyles from './views/Styles';
import { isNotch, isIOS } from './utils/deviceInfo';
import { defaultHeader, onNavigationStateChange } from './utils/navigation';
import RocketChat from './lib/rocketchat';
const InsideNavigator = createStackNavigator({
ShareListView: {
getScreen: () => require('./views/ShareListView').default
},
ShareView: {
getScreen: () => require('./views/ShareView').default
},
SelectServerView: {
getScreen: () => require('./views/SelectServerView').default
}
}, {
initialRouteName: 'ShareListView',
defaultNavigationOptions: defaultHeader
});
const OutsideNavigator = createStackNavigator({
WithoutServersView: {
getScreen: () => require('./views/WithoutServersView').default
}
}, {
initialRouteName: 'WithoutServersView',
defaultNavigationOptions: defaultHeader
});
const AppContainer = createAppContainer(createSwitchNavigator({
OutsideStack: OutsideNavigator,
InsideStack: InsideNavigator,
AuthLoading: {
getScreen: () => require('./views/AuthLoadingView').default
}
},
{
initialRouteName: 'AuthLoading'
}));
class Root extends React.Component {
constructor(props) {
super(props);
this.state = {
isLandscape: false
};
this.init();
}
init = async() => {
if (isIOS) {
await RNUserDefaults.setName('group.ios.chat.rocket');
}
const currentServer = await RNUserDefaults.get('currentServer');
const token = await RNUserDefaults.get(RocketChat.TOKEN_KEY);
if (currentServer && token) {
await Navigation.navigate('InsideStack');
await RocketChat.shareExtensionInit(currentServer);
} else {
await Navigation.navigate('OutsideStack');
}
}
handleLayout = (event) => {
const { width, height } = event.nativeEvent.layout;
this.setState({ isLandscape: width > height });
}
render() {
const { isLandscape } = this.state;
return (
<View
style={[sharedStyles.container, isLandscape && isNotch ? sharedStyles.notchLandscapeContainer : {}]}
onLayout={this.handleLayout}
>
<Provider store={store}>
<AppContainer
ref={(navigatorRef) => {
Navigation.setTopLevelNavigator(navigatorRef);
}}
onNavigationStateChange={onNavigationStateChange}
/>
</Provider>
</View>
);
}
}
export default Root;

View File

@ -1,32 +1,3 @@
import React from 'react'; import { Alert } from 'react-native';
import { Alert, StyleSheet } from 'react-native';
import EasyToast from 'react-native-easy-toast';
import { COLOR_TOAST, COLOR_WHITE } from '../constants/colors';
import { isNotch } from './deviceInfo';
import sharedStyles from '../views/Styles';
const styles = StyleSheet.create({
toast: {
backgroundColor: COLOR_TOAST
},
text: {
...sharedStyles.textRegular,
color: COLOR_WHITE,
fontSize: 14
}
});
const positionValue = isNotch ? 230 : 200;
export const Toast = React.forwardRef((props, ref) => (
<EasyToast
{...props}
ref={ref}
positionValue={positionValue}
style={styles.toast}
textStyle={styles.text}
opacity={0.8}
/>
));
export const showErrorAlert = (message, title, onPress = () => {}) => Alert.alert(title, message, [{ text: 'OK', onPress }], { cancelable: true }); export const showErrorAlert = (message, title, onPress = () => {}) => Alert.alert(title, message, [{ text: 'OK', onPress }], { cancelable: true });

23
app/utils/media.js Normal file
View File

@ -0,0 +1,23 @@
export const canUploadFile = (file, serverInfo) => {
const { FileUpload_MediaTypeWhiteList, FileUpload_MaxFileSize } = serverInfo;
if (!(file && file.path)) {
return true;
}
if (file.size > FileUpload_MaxFileSize) {
return false;
}
// if white list is empty, all media types are enabled
if (!FileUpload_MediaTypeWhiteList) {
return true;
}
const allowedMime = FileUpload_MediaTypeWhiteList.split(',');
if (allowedMime.includes(file.mime)) {
return true;
}
const wildCardGlob = '/*';
const wildCards = allowedMime.filter(item => item.indexOf(wildCardGlob) > 0);
if (wildCards.includes(file.mime.replace(/(\/.*)$/, wildCardGlob))) {
return true;
}
return false;
};

11
app/utils/moment.js Normal file
View File

@ -0,0 +1,11 @@
const localeKeys = {
en: 'en',
ru: 'ru',
'pt-BR': 'pt-br',
'zh-CN': 'zh-cn',
fr: 'fr',
de: 'de',
'pt-PT': 'pt'
};
export const toMomentLocale = locale => localeKeys[locale];

36
app/utils/navigation.js Normal file
View File

@ -0,0 +1,36 @@
import firebase from 'react-native-firebase';
import { HEADER_BACKGROUND, HEADER_TITLE, HEADER_BACK } from '../constants/colors';
export const defaultHeader = {
headerStyle: {
backgroundColor: HEADER_BACKGROUND
},
headerTitleStyle: {
color: HEADER_TITLE
},
headerBackTitle: null,
headerTintColor: HEADER_BACK
};
// gets the current screen from navigation state
export const getActiveRouteName = (navigationState) => {
if (!navigationState) {
return null;
}
const route = navigationState.routes[navigationState.index];
// dive into nested navigators
if (route.routes) {
return getActiveRouteName(route);
}
return route.routeName;
};
export const onNavigationStateChange = (prevState, currentState) => {
const currentScreen = getActiveRouteName(currentState);
const prevScreen = getActiveRouteName(prevState);
if (prevScreen !== currentScreen) {
firebase.analytics().setCurrentScreen(currentScreen);
}
};

36
app/utils/room.js Normal file
View File

@ -0,0 +1,36 @@
import moment from 'moment';
import I18n from '../i18n';
export const isOwner = room => room && room.roles && room.roles.length && !!room.roles.find(role => role === 'owner');
export const isMuted = (room, user) => room && room.muted && room.muted.find && !!room.muted.find(m => m === user.username);
export const isReadOnly = (room, user) => {
if (isOwner(room)) {
return false;
}
return (room && room.ro) || isMuted(room, user);
};
export const isBlocked = (room) => {
if (room) {
const { t, blocked, blocker } = room;
if (t === 'd' && (blocked || blocker)) {
return true;
}
}
return false;
};
export const capitalize = (s) => {
if (typeof s !== 'string') { return ''; }
return s.charAt(0).toUpperCase() + s.slice(1);
};
export const formatDate = date => moment(date).calendar(null, {
lastDay: `[${ I18n.t('Yesterday') }]`,
sameDay: 'LT',
lastWeek: 'dddd',
sameElse: 'MMM D'
});

View File

@ -7,7 +7,7 @@ import { connect } from 'react-redux';
import { SafeAreaView } from 'react-navigation'; import { SafeAreaView } from 'react-navigation';
import RocketChat from '../../lib/rocketchat'; import RocketChat from '../../lib/rocketchat';
import DirectoryItem from './DirectoryItem'; import DirectoryItem from '../../presentation/DirectoryItem';
import sharedStyles from '../Styles'; import sharedStyles from '../Styles';
import I18n from '../../i18n'; import I18n from '../../i18n';
import Touch from '../../utils/touch'; import Touch from '../../utils/touch';

View File

@ -98,46 +98,6 @@ export default StyleSheet.create({
marginHorizontal: 15, marginHorizontal: 15,
flex: 1 flex: 1
}, },
directoryItemButton: {
height: 54,
backgroundColor: COLOR_WHITE
},
directoryItemContainer: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
paddingHorizontal: 15
},
directoryItemAvatar: {
marginRight: 12
},
directoryItemTextTitle: {
flexDirection: 'row',
alignItems: 'center'
},
directoryItemTextContainer: {
flex: 1,
flexDirection: 'column',
justifyContent: 'center'
},
directoryItemName: {
flex: 1,
fontSize: 17,
...sharedStyles.textMedium,
...sharedStyles.textColorNormal
},
directoryItemUsername: {
fontSize: 14,
...sharedStyles.textRegular,
...sharedStyles.textColorDescription
},
directoryItemLabel: {
fontSize: 14,
paddingLeft: 10,
...sharedStyles.textRegular,
...sharedStyles.textColorDescription
},
inverted: { inverted: {
transform: [{ scaleY: -1 }] transform: [{ scaleY: -1 }]
}, },

View File

@ -13,7 +13,9 @@ import KeyboardView from '../../presentation/KeyboardView';
import sharedStyles from '../Styles'; import sharedStyles from '../Styles';
import styles from './styles'; import styles from './styles';
import scrollPersistTaps from '../../utils/scrollPersistTaps'; import scrollPersistTaps from '../../utils/scrollPersistTaps';
import { showErrorAlert, Toast } from '../../utils/info'; import { showErrorAlert } from '../../utils/info';
import { LISTENER } from '../../containers/Toast';
import EventEmitter from '../../utils/events';
import RocketChat from '../../lib/rocketchat'; import RocketChat from '../../lib/rocketchat';
import RCTextInput from '../../containers/TextInput'; import RCTextInput from '../../containers/TextInput';
import log from '../../utils/log'; import log from '../../utils/log';
@ -222,7 +224,7 @@ export default class ProfileView extends React.Component {
setUser({ ...params }); setUser({ ...params });
} }
this.setState({ saving: false, showPasswordAlert: false }); this.setState({ saving: false, showPasswordAlert: false });
this.toast.show(I18n.t('Profile_saved_successfully')); EventEmitter.emit(LISTENER, { message: I18n.t('Profile_saved_successfully') });
this.init(); this.init();
} }
} catch (e) { } catch (e) {
@ -235,7 +237,7 @@ export default class ProfileView extends React.Component {
try { try {
const { user } = this.props; const { user } = this.props;
await RocketChat.resetAvatar(user.id); await RocketChat.resetAvatar(user.id);
this.toast.show(I18n.t('Avatar_changed_successfully')); EventEmitter.emit(LISTENER, { message: I18n.t('Avatar_changed_successfully') });
this.init(); this.init();
} catch (e) { } catch (e) {
this.handleError(e, 'resetAvatar', 'changing_avatar'); this.handleError(e, 'resetAvatar', 'changing_avatar');
@ -386,7 +388,6 @@ export default class ProfileView extends React.Component {
keyboardVerticalOffset={128} keyboardVerticalOffset={128}
> >
<StatusBar /> <StatusBar />
<Toast ref={toast => this.toast = toast} />
<ScrollView <ScrollView
contentContainerStyle={sharedStyles.containerScrollView} contentContainerStyle={sharedStyles.containerScrollView}
testID='profile-view-list' testID='profile-view-list'

View File

@ -12,7 +12,9 @@ import KeyboardView from '../../presentation/KeyboardView';
import sharedStyles from '../Styles'; import sharedStyles from '../Styles';
import styles from './styles'; import styles from './styles';
import scrollPersistTaps from '../../utils/scrollPersistTaps'; import scrollPersistTaps from '../../utils/scrollPersistTaps';
import { showErrorAlert, Toast } from '../../utils/info'; import { showErrorAlert } from '../../utils/info';
import { LISTENER } from '../../containers/Toast';
import EventEmitter from '../../utils/events';
import database, { safeAddListener } from '../../lib/realm'; import database, { safeAddListener } from '../../lib/realm';
import RocketChat from '../../lib/rocketchat'; import RocketChat from '../../lib/rocketchat';
import RCTextInput from '../../containers/TextInput'; import RCTextInput from '../../containers/TextInput';
@ -215,7 +217,7 @@ export default class RoomInfoEditView extends React.Component {
if (error) { if (error) {
showErrorAlert(I18n.t('There_was_an_error_while_action', { action: I18n.t('saving_settings') })); showErrorAlert(I18n.t('There_was_an_error_while_action', { action: I18n.t('saving_settings') }));
} else { } else {
this.toast.show(I18n.t('Settings_succesfully_changed')); EventEmitter.emit(LISTENER, { message: I18n.t('Settings_succesfully_changed') });
} }
}, 100); }, 100);
} }
@ -428,7 +430,6 @@ export default class RoomInfoEditView extends React.Component {
<Text style={[sharedStyles.button_inverted, styles.colorDanger]} accessibilityTraits='button'>{I18n.t('DELETE')}</Text> <Text style={[sharedStyles.button_inverted, styles.colorDanger]} accessibilityTraits='button'>{I18n.t('DELETE')}</Text>
</TouchableOpacity> </TouchableOpacity>
<Loading visible={saving} /> <Loading visible={saving} />
<Toast ref={toast => this.toast = toast} />
</SafeAreaView> </SafeAreaView>
</ScrollView> </ScrollView>
</KeyboardView> </KeyboardView>

View File

@ -12,7 +12,8 @@ import UserItem from '../../presentation/UserItem';
import scrollPersistTaps from '../../utils/scrollPersistTaps'; import scrollPersistTaps from '../../utils/scrollPersistTaps';
import RocketChat from '../../lib/rocketchat'; import RocketChat from '../../lib/rocketchat';
import database, { safeAddListener } from '../../lib/realm'; import database, { safeAddListener } from '../../lib/realm';
import { Toast } from '../../utils/info'; import { LISTENER } from '../../containers/Toast';
import EventEmitter from '../../utils/events';
import log from '../../utils/log'; import log from '../../utils/log';
import I18n from '../../i18n'; import I18n from '../../i18n';
import SearchBox from '../../containers/SearchBox'; import SearchBox from '../../containers/SearchBox';
@ -232,7 +233,7 @@ export default class RoomMembersView extends React.Component {
const { rid, userLongPressed } = this.state; const { rid, userLongPressed } = this.state;
try { try {
await RocketChat.toggleMuteUserInRoom(rid, userLongPressed.username, !userLongPressed.muted); await RocketChat.toggleMuteUserInRoom(rid, userLongPressed.username, !userLongPressed.muted);
this.toast.show(I18n.t('User_has_been_key', { key: userLongPressed.muted ? I18n.t('unmuted') : I18n.t('muted') })); EventEmitter.emit(LISTENER, { message: I18n.t('User_has_been_key', { key: userLongPressed.muted ? I18n.t('unmuted') : I18n.t('muted') }) });
} catch (e) { } catch (e) {
log('err_handle_mute', e); log('err_handle_mute', e);
} }
@ -299,7 +300,6 @@ export default class RoomMembersView extends React.Component {
windowSize={10} windowSize={10}
{...scrollPersistTaps} {...scrollPersistTaps}
/> />
<Toast ref={toast => this.toast = toast} />
</SafeAreaView> </SafeAreaView>
); );
} }

View File

@ -64,7 +64,13 @@ const styles = StyleSheet.create({
export default class UploadProgress extends Component { export default class UploadProgress extends Component {
static propTypes = { static propTypes = {
window: PropTypes.object, window: PropTypes.object,
rid: PropTypes.string rid: PropTypes.string,
user: PropTypes.shape({
id: PropTypes.string.isRequired,
username: PropTypes.string.isRequired,
token: PropTypes.string.isRequired
}),
baseUrl: PropTypes.string.isRequired
} }
constructor(props) { constructor(props) {
@ -124,13 +130,13 @@ export default class UploadProgress extends Component {
} }
tryAgain = async(item) => { tryAgain = async(item) => {
const { rid } = this.props; const { rid, baseUrl: server, user } = this.props;
try { try {
database.write(() => { database.write(() => {
item.error = false; item.error = false;
}); });
await RocketChat.sendFileMessage(rid, item); await RocketChat.sendFileMessage(rid, item, undefined, server, user);
} catch (e) { } catch (e) {
log('err_upload_progress_try_again', e); log('err_upload_progress_try_again', e);
} }

View File

@ -41,7 +41,8 @@ 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 ReactionsModal from '../../containers/ReactionsModal'; import ReactionsModal from '../../containers/ReactionsModal';
import { Toast } from '../../utils/info'; import { LISTENER } from '../../containers/Toast';
import { isReadOnly, isBlocked } from '../../utils/room';
@connect(state => ({ @connect(state => ({
user: { user: {
@ -409,8 +410,9 @@ export default class RoomView extends React.Component {
} }
sendMessage = (message, tmid) => { sendMessage = (message, tmid) => {
const { user } = this.props;
LayoutAnimation.easeInEaseOut(); LayoutAnimation.easeInEaseOut();
RocketChat.sendMessage(this.rid, message, this.tmid || tmid).then(() => { RocketChat.sendMessage(this.rid, message, this.tmid || tmid, user).then(() => {
this.setLastOpen(null); this.setLastOpen(null);
}); });
}; };
@ -455,37 +457,6 @@ export default class RoomView extends React.Component {
} }
}; };
isOwner = () => {
const { room } = this.state;
return room && room.roles && room.roles.length && !!room.roles.find(role => role === 'owner');
}
isMuted = () => {
const { room } = this.state;
const { user } = this.props;
return room && room.muted && room.muted.find && !!room.muted.find(m => m === user.username);
}
isReadOnly = () => {
const { room } = this.state;
if (this.isOwner()) {
return false;
}
return (room && room.ro) || this.isMuted();
}
isBlocked = () => {
const { room } = this.state;
if (room) {
const { t, blocked, blocker } = room;
if (t === 'd' && (blocked || blocker)) {
return true;
}
}
return false;
}
// eslint-disable-next-line react/sort-comp // eslint-disable-next-line react/sort-comp
fetchThreadName = async(tmid) => { fetchThreadName = async(tmid) => {
try { try {
@ -502,7 +473,7 @@ export default class RoomView extends React.Component {
toggleFollowThread = async(isFollowingThread) => { toggleFollowThread = async(isFollowingThread) => {
try { try {
await RocketChat.toggleFollowMessage(this.tmid, !isFollowingThread); await RocketChat.toggleFollowMessage(this.tmid, !isFollowingThread);
this.toast.show(isFollowingThread ? 'Unfollowed thread' : 'Following thread'); EventEmitter.emit(LISTENER, { message: isFollowingThread ? 'Unfollowed thread' : 'Following thread' });
} catch (e) { } catch (e) {
log('err_toggle_follow_thread', e); log('err_toggle_follow_thread', e);
} }
@ -576,7 +547,7 @@ export default class RoomView extends React.Component {
renderFooter = () => { renderFooter = () => {
const { joined, room } = this.state; const { joined, room } = this.state;
const { navigation } = this.props; const { navigation, user } = this.props;
if (!joined && !this.tmid) { if (!joined && !this.tmid) {
return ( return (
@ -593,14 +564,14 @@ export default class RoomView extends React.Component {
</View> </View>
); );
} }
if (this.isReadOnly()) { if (isReadOnly(room, user)) {
return ( return (
<View style={styles.readOnly}> <View style={styles.readOnly}>
<Text style={styles.previewMode}>{I18n.t('This_room_is_read_only')}</Text> <Text style={styles.previewMode}>{I18n.t('This_room_is_read_only')}</Text>
</View> </View>
); );
} }
if (this.isBlocked()) { if (isBlocked(room)) {
return ( return (
<View style={styles.readOnly}> <View style={styles.readOnly}>
<Text style={styles.previewMode}>{I18n.t('This_room_is_blocked')}</Text> <Text style={styles.previewMode}>{I18n.t('This_room_is_blocked')}</Text>
@ -630,7 +601,7 @@ export default class RoomView extends React.Component {
return ( return (
<React.Fragment> <React.Fragment>
{room._id && showActions {room._id && showActions
? <MessageActions room={room} tmid={this.tmid} user={user} toast={this.toast} /> ? <MessageActions room={room} tmid={this.tmid} user={user} />
: null : null
} }
{showErrorActions ? <MessageErrorActions /> : null} {showErrorActions ? <MessageErrorActions /> : null}
@ -653,7 +624,7 @@ export default class RoomView extends React.Component {
{this.renderFooter()} {this.renderFooter()}
{this.renderActions()} {this.renderActions()}
<ReactionPicker onEmojiSelected={this.onReactionPress} /> <ReactionPicker onEmojiSelected={this.onReactionPress} />
<UploadProgress rid={this.rid} /> <UploadProgress rid={this.rid} user={user} baseUrl={baseUrl} />
<FileModal <FileModal
attachment={selectedAttachment} attachment={selectedAttachment}
isVisible={photoModalVisible} isVisible={photoModalVisible}
@ -668,7 +639,6 @@ export default class RoomView extends React.Component {
user={user} user={user}
baseUrl={baseUrl} baseUrl={baseUrl}
/> />
<Toast ref={toast => this.toast = toast} />
</SafeAreaView> </SafeAreaView>
); );
} }

View File

@ -0,0 +1,108 @@
import React from 'react';
import {
FlatList, StyleSheet, View
} from 'react-native';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { SafeAreaView } from 'react-navigation';
import I18n from '../i18n';
import database from '../lib/realm';
import StatusBar from '../containers/StatusBar';
import { COLOR_BACKGROUND_CONTAINER } from '../constants/colors';
import Navigation from '../lib/ShareNavigation';
import ServerItem, { ROW_HEIGHT } from '../presentation/ServerItem';
import sharedStyles from './Styles';
import RocketChat from '../lib/rocketchat';
const getItemLayout = (data, index) => ({ length: ROW_HEIGHT, offset: ROW_HEIGHT * index, index });
const keyExtractor = item => item.id;
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: COLOR_BACKGROUND_CONTAINER
},
list: {
marginVertical: 32,
...sharedStyles.separatorVertical
},
separator: {
...sharedStyles.separatorBottom,
marginLeft: 48
}
});
@connect(({ share }) => ({
server: share.server
}))
export default class SelectServerView extends React.Component {
static navigationOptions = () => ({
title: I18n.t('Select_Server')
})
static propTypes = {
server: PropTypes.string
}
constructor(props) {
super(props);
const { serversDB } = database.databases;
const servers = serversDB.objects('servers');
const filteredServers = servers.filter(server => server.roomsUpdatedAt);
this.state = {
servers: filteredServers
};
}
select = async(server) => {
const {
server: currentServer
} = this.props;
Navigation.navigate('ShareListView');
if (currentServer !== server) {
await RocketChat.shareExtensionInit(server);
}
}
renderItem = ({ item }) => {
const { server } = this.props;
return (
<ServerItem
server={server}
onPress={() => this.select(item.id)}
item={item}
hasCheck
/>
);
}
renderSeparator = () => <View style={styles.separator} />;
render() {
const { servers } = this.state;
return (
<SafeAreaView
style={styles.container}
forceInset={{ bottom: 'never' }}
>
<StatusBar />
<View style={styles.list}>
<FlatList
data={servers}
keyExtractor={keyExtractor}
renderItem={this.renderItem}
getItemLayout={getItemLayout}
ItemSeparatorComponent={this.renderSeparator}
enableEmptySections
removeClippedSubviews
keyboardShouldPersistTaps='always'
windowSize={7}
bounces={false}
/>
</View>
</SafeAreaView>
);
}
}

View File

@ -0,0 +1,52 @@
import React from 'react';
import {
View, StyleSheet, Text, TextInput
} from 'react-native';
import PropTypes from 'prop-types';
import I18n from '../../../i18n';
import { COLOR_WHITE, HEADER_TITLE } from '../../../constants/colors';
import sharedStyles from '../../Styles';
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center'
},
search: {
fontSize: 20,
color: COLOR_WHITE,
...sharedStyles.textRegular,
marginHorizontal: 14
},
title: {
fontSize: 20,
...sharedStyles.textBold,
color: HEADER_TITLE,
marginHorizontal: 16
}
});
const Header = React.memo(({ searching, onChangeSearchText }) => {
if (searching) {
return (
<View style={styles.container}>
<TextInput
style={styles.search}
placeholder={I18n.t('Search')}
placeholderTextColor='rgba(255, 255, 255, 0.5)'
onChangeText={onChangeSearchText}
autoFocus
/>
</View>
);
}
return <Text style={styles.title}>{I18n.t('Send_to')}</Text>;
});
Header.propTypes = {
searching: PropTypes.bool,
onChangeSearchText: PropTypes.func
};
export default Header;

View File

@ -0,0 +1,76 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import {
Keyboard, LayoutAnimation, View, StyleSheet
} from 'react-native';
import ShareExtension from 'rn-extensions-share';
import SearchBox from '../../../containers/SearchBox';
import { CloseShareExtensionButton } from '../../../containers/HeaderButton';
import { HEADER_BACKGROUND } from '../../../constants/colors';
import sharedStyles from '../../Styles';
const styles = StyleSheet.create({
container: {
backgroundColor: HEADER_BACKGROUND,
flexDirection: 'row',
...sharedStyles.separatorBottom
}
});
const Header = React.memo(({
searching, onChangeSearchText, initSearch, cancelSearch
}) => {
const [text, setText] = useState('');
const onChangeText = (searchText) => {
onChangeSearchText(searchText);
setText(searchText);
};
const onCancelPress = () => {
Keyboard.dismiss();
onChangeText('');
cancelSearch();
LayoutAnimation.easeInEaseOut();
};
const onFocus = () => {
initSearch();
LayoutAnimation.easeInEaseOut();
};
return (
<View style={styles.container}>
{
!searching
? (
<CloseShareExtensionButton
onPress={ShareExtension.close}
testID='share-extension-close'
/>
)
: null
}
<SearchBox
value={text}
hasCancel={searching}
onFocus={onFocus}
onCancelPress={onCancelPress}
onChangeText={onChangeText}
testID='rooms-list-view-search'
key='rooms-list-view-search'
/>
</View>
);
});
Header.propTypes = {
searching: PropTypes.bool,
onChangeSearchText: PropTypes.func,
initSearch: PropTypes.func,
cancelSearch: PropTypes.func
};
export default Header;

View File

@ -0,0 +1,30 @@
import React from 'react';
import PropTypes from 'prop-types';
import Header from './Header';
const ShareListHeader = React.memo(({
searching, initSearch, cancelSearch, search
}) => {
const onSearchChangeText = (text) => {
search(text.trim());
};
return (
<Header
searching={searching}
initSearch={initSearch}
cancelSearch={cancelSearch}
onChangeSearchText={onSearchChangeText}
/>
);
});
ShareListHeader.propTypes = {
searching: PropTypes.bool,
initSearch: PropTypes.func,
cancelSearch: PropTypes.func,
search: PropTypes.func
};
export default ShareListHeader;

View File

@ -0,0 +1,417 @@
import React from 'react';
import PropTypes from 'prop-types';
import {
View, Text, LayoutAnimation, FlatList, ActivityIndicator, Keyboard, BackHandler
} from 'react-native';
import { SafeAreaView } from 'react-navigation';
import ShareExtension from 'rn-extensions-share';
import { connect } from 'react-redux';
import RNFetchBlob from 'rn-fetch-blob';
import * as mime from 'react-native-mime-types';
import { isEqual } from 'lodash';
import Navigation from '../../lib/ShareNavigation';
import database from '../../lib/realm';
import { isIOS, isAndroid } from '../../utils/deviceInfo';
import I18n from '../../i18n';
import { CustomIcon } from '../../lib/Icons';
import log from '../../utils/log';
import { canUploadFile } from '../../utils/media';
import DirectoryItem, { ROW_HEIGHT } from '../../presentation/DirectoryItem';
import ServerItem from '../../presentation/ServerItem';
import { CloseShareExtensionButton, CustomHeaderButtons, Item } from '../../containers/HeaderButton';
import ShareListHeader from './Header';
import styles from './styles';
import StatusBar from '../../containers/StatusBar';
const LIMIT = 50;
const getItemLayout = (data, index) => ({ length: ROW_HEIGHT, offset: ROW_HEIGHT * index, index });
const keyExtractor = item => item.rid;
@connect(({ share }) => ({
userId: share.user && share.user.id,
token: share.user && share.user.token,
server: share.server,
baseUrl: share ? share.server : ''
}))
/** @extends React.Component */
export default class ShareListView extends React.Component {
static navigationOptions = ({ navigation }) => {
const searching = navigation.getParam('searching');
const initSearch = navigation.getParam('initSearch', () => {});
const cancelSearch = navigation.getParam('cancelSearch', () => {});
const search = navigation.getParam('search', () => {});
if (isIOS) {
return {
headerTitle: (
<ShareListHeader
searching={searching}
initSearch={initSearch}
cancelSearch={cancelSearch}
search={search}
/>
)
};
}
return {
headerBackTitle: null,
headerLeft: searching
? (
<CustomHeaderButtons left>
<Item title='cancel' iconName='cross' onPress={cancelSearch} />
</CustomHeaderButtons>
)
: (
<CloseShareExtensionButton
onPress={ShareExtension.close}
testID='share-extension-close'
/>
),
headerTitle: <ShareListHeader searching={searching} search={search} />,
headerRight: (
searching
? null
: (
<CustomHeaderButtons>
{isAndroid ? <Item title='search' iconName='magnifier' onPress={initSearch} /> : null}
</CustomHeaderButtons>
)
)
};
}
static propTypes = {
navigation: PropTypes.object,
server: PropTypes.string,
baseUrl: PropTypes.string,
token: PropTypes.string,
userId: PropTypes.string
}
constructor(props) {
super(props);
this.data = [];
this.state = {
showError: false,
searching: false,
searchText: '',
value: '',
isMedia: false,
mediaLoading: false,
fileInfo: null,
searchResults: [],
chats: [],
servers: [],
loading: true,
serverInfo: null
};
this.didFocusListener = props.navigation.addListener('didFocus', () => BackHandler.addEventListener('hardwareBackPress', this.handleBackPress));
this.willBlurListener = props.navigation.addListener('willBlur', () => BackHandler.addEventListener('hardwareBackPress', this.handleBackPress));
}
async componentDidMount() {
const { navigation, server } = this.props;
navigation.setParams({
initSearch: this.initSearch,
cancelSearch: this.cancelSearch,
search: this.search
});
try {
const { value, type } = await ShareExtension.data();
let fileInfo = null;
const isMedia = (type === 'media');
if (isMedia) {
this.setState({ mediaLoading: true });
const data = await RNFetchBlob.fs.stat(this.uriToPath(value));
fileInfo = {
name: data.filename,
description: '',
size: data.size,
mime: mime.lookup(data.path),
store: 'Uploads',
path: isIOS ? data.path : `file://${ data.path }`
};
}
this.setState({
value, fileInfo, isMedia, mediaLoading: false
});
} catch (e) {
log('err_process_media_share_extension', e);
this.setState({ mediaLoading: false });
}
this.getSubscriptions(server);
}
componentWillReceiveProps(nextProps) {
const { server } = this.props;
if (nextProps.server !== server) {
this.getSubscriptions(nextProps.server);
}
}
shouldComponentUpdate(nextProps, nextState) {
const { searching } = this.state;
if (nextState.searching !== searching) {
return true;
}
const { isMedia } = this.state;
if (nextState.isMedia !== isMedia) {
this.getSubscriptions(nextProps.server, nextState.fileInfo);
return true;
}
const { server } = this.props;
if (server !== nextProps.server) {
return true;
}
const { searchResults } = this.state;
if (!isEqual(nextState.searchResults, searchResults)) {
return true;
}
return false;
}
// eslint-disable-next-line react/sort-comp
internalSetState = (...args) => {
const { navigation } = this.props;
if (isIOS && navigation.isFocused()) {
LayoutAnimation.easeInEaseOut();
}
this.setState(...args);
}
getSubscriptions = (server, fileInfo) => {
const { fileInfo: fileData } = this.state;
const { serversDB } = database.databases;
if (server) {
this.data = database.objects('subscriptions').filtered('archived != true && open == true').sorted('roomUpdatedAt', true);
this.servers = serversDB.objects('servers');
this.chats = this.data.slice(0, LIMIT);
const serverInfo = serversDB.objectForPrimaryKey('servers', server);
this.internalSetState({
chats: this.chats ? this.chats.slice() : [],
servers: this.servers ? this.servers.slice() : [],
loading: false,
showError: !canUploadFile(fileInfo || fileData, serverInfo),
serverInfo
});
this.forceUpdate();
}
};
uriToPath = uri => decodeURIComponent(isIOS ? uri.replace(/^file:\/\//, '') : uri);
getRoomTitle = (item) => {
const { serverInfo } = this.state;
const { useRealName } = serverInfo;
return ((item.prid || useRealName) && item.fname) || item.name;
}
shareMessage = (item) => {
const { value, isMedia, fileInfo } = this.state;
const { navigation } = this.props;
navigation.navigate('ShareView', {
rid: item.rid,
value,
isMedia,
fileInfo,
name: this.getRoomTitle(item)
});
}
search = (text) => {
const result = database.objects('subscriptions').filtered('name CONTAINS[c] $0', text);
this.internalSetState({
searchResults: result.slice(0, LIMIT),
searchText: text
});
}
initSearch = () => {
const { chats } = this.state;
const { navigation } = this.props;
this.setState({ searching: true, searchResults: chats });
navigation.setParams({ searching: true });
}
cancelSearch = () => {
const { navigation } = this.props;
this.internalSetState({ searching: false, searchResults: [], searchText: '' });
navigation.setParams({ searching: false });
Keyboard.dismiss();
}
handleBackPress = () => {
const { searching } = this.state;
if (searching) {
this.cancelSearch();
return true;
}
return false;
}
renderSectionHeader = (header) => {
const { searching } = this.state;
if (searching) {
return null;
}
return (
<View style={styles.headerContainer}>
<Text style={styles.headerText}>
{I18n.t(header)}
</Text>
</View>
);
}
renderItem = ({ item }) => {
const { userId, token, baseUrl } = this.props;
return (
<DirectoryItem
user={{
userId,
token
}}
title={this.getRoomTitle(item)}
baseUrl={baseUrl}
avatar={this.getRoomTitle(item)}
description={
item.t === 'c'
? (item.topic || item.description)
: item.fname
}
type={item.t}
onPress={() => this.shareMessage(item)}
testID={`share-extension-item-${ item.name }`}
/>
);
}
renderSeparator = () => <View style={styles.separator} />;
renderBorderBottom = () => <View style={styles.borderBottom} />;
renderSelectServer = () => {
const { servers } = this.state;
const { server } = this.props;
const currentServer = servers.find(serverFiltered => serverFiltered.id === server);
return currentServer ? (
<React.Fragment>
{this.renderSectionHeader('Select_Server')}
<View style={styles.bordered}>
<ServerItem
server={server}
onPress={() => Navigation.navigate('SelectServerView')}
item={currentServer}
/>
</View>
</React.Fragment>
) : null;
}
renderEmptyComponent = () => (
<View style={[styles.container, styles.emptyContainer]}>
<Text style={styles.title}>{I18n.t('No_results_found')}</Text>
</View>
);
renderHeader = () => {
const { searching } = this.state;
return (
<React.Fragment>
{ !searching
? (
<React.Fragment>
{this.renderSelectServer()}
{this.renderSectionHeader('Chats')}
</React.Fragment>
)
: null
}
</React.Fragment>
);
}
renderContent = () => {
const {
chats, mediaLoading, loading, searchResults, searching, searchText
} = this.state;
if (mediaLoading || loading) {
return <ActivityIndicator style={styles.loading} />;
}
return (
<FlatList
data={searching ? searchResults : chats}
keyExtractor={keyExtractor}
style={styles.flatlist}
renderItem={this.renderItem}
getItemLayout={getItemLayout}
ItemSeparatorComponent={this.renderSeparator}
ListHeaderComponent={this.renderHeader}
ListFooterComponent={!searching && this.renderBorderBottom}
ListHeaderComponentStyle={!searching ? styles.borderBottom : {}}
ListEmptyComponent={searching && searchText ? this.renderEmptyComponent : null}
enableEmptySections
removeClippedSubviews
keyboardShouldPersistTaps='always'
initialNumToRender={12}
windowSize={20}
/>
);
}
renderError = () => {
const {
fileInfo: file, loading, searching, serverInfo
} = this.state;
const { FileUpload_MaxFileSize } = serverInfo;
const errorMessage = (FileUpload_MaxFileSize < file.size)
? 'error-file-too-large'
: 'error-invalid-file-type';
if (loading) {
return <ActivityIndicator style={styles.loading} />;
}
return (
<View style={styles.container}>
{ !searching
? (
<React.Fragment>
{this.renderSelectServer()}
</React.Fragment>
)
: null
}
<View style={[styles.container, styles.centered]}>
<Text style={styles.title}>{I18n.t(errorMessage)}</Text>
<CustomIcon name='circle-cross' size={120} style={styles.errorIcon} />
<Text style={styles.fileMime}>{ file.mime }</Text>
</View>
</View>
);
}
render() {
const { showError } = this.state;
return (
<SafeAreaView style={styles.container} forceInset={{ bottom: 'never' }}>
<StatusBar />
{ showError ? this.renderError() : this.renderContent() }
</SafeAreaView>
);
}
}

View File

@ -0,0 +1,74 @@
import { StyleSheet } from 'react-native';
import { isIOS } from '../../utils/deviceInfo';
import sharedStyles from '../Styles';
import {
COLOR_BACKGROUND_CONTAINER, COLOR_WHITE, COLOR_DANGER
} from '../../constants/colors';
export default StyleSheet.create({
container: {
flex: 1,
backgroundColor: COLOR_BACKGROUND_CONTAINER
},
emptyContainer: {
padding: 20,
justifyContent: 'center',
alignItems: 'center'
},
content: {
flex: 1,
backgroundColor: isIOS ? COLOR_WHITE : '#E1E5E8',
justifyContent: 'center',
alignItems: 'center'
},
centered: {
justifyContent: 'center',
alignItems: 'center'
},
flatlist: {
marginTop: isIOS ? 6 : 0, // the height of the navigation bar with the searchbar is larger
width: '100%',
backgroundColor: COLOR_BACKGROUND_CONTAINER
},
bordered: {
...sharedStyles.separatorVertical
},
borderBottom: {
...sharedStyles.separatorBottom
},
headerContainer: {
paddingHorizontal: 15,
backgroundColor: COLOR_BACKGROUND_CONTAINER,
paddingBottom: 10,
paddingTop: 17
},
headerText: {
...sharedStyles.textColorNormal,
...sharedStyles.textRegular,
fontSize: 17,
letterSpacing: 0.27
},
separator: {
...sharedStyles.separatorBottom,
marginLeft: 48
},
loading: {
flex: 1
},
errorIcon: {
color: COLOR_DANGER
},
fileMime: {
...sharedStyles.textColorNormal,
...sharedStyles.textBold,
...sharedStyles.textAlignCenter,
fontSize: 20,
marginBottom: 20
},
title: {
fontSize: 14,
...sharedStyles.textColorTitle,
...sharedStyles.textBold
}
});

View File

@ -0,0 +1,23 @@
import React from 'react';
import {
StyleSheet, ActivityIndicator, View
} from 'react-native';
import { COLOR_TEXT } from '../../constants/colors';
const styles = StyleSheet.create({
container: {
height: '100%',
width: '100%',
position: 'absolute',
justifyContent: 'center',
alignItems: 'center'
}
});
const Loading = React.memo(() => (
<View style={styles.container}>
<ActivityIndicator size='large' color={COLOR_TEXT} />
</View>
));
export default Loading;

View File

@ -0,0 +1,245 @@
import React from 'react';
import PropTypes from 'prop-types';
import {
View, Text, TextInput, Image
} from 'react-native';
import { connect } from 'react-redux';
import ShareExtension from 'rn-extensions-share';
import {
COLOR_TEXT_DESCRIPTION
} from '../../constants/colors';
import I18n from '../../i18n';
import RocketChat from '../../lib/rocketchat';
import { CustomIcon } from '../../lib/Icons';
import log from '../../utils/log';
import styles from './styles';
import Loading from './Loading';
import database from '../../lib/realm';
import { CustomHeaderButtons, Item } from '../../containers/HeaderButton';
import { isReadOnly, isBlocked } from '../../utils/room';
@connect(({ share }) => ({
user: {
id: share.user && share.user.id,
username: share.user && share.user.username,
token: share.user && share.user.token
},
baseUrl: share ? share.server : ''
}))
export default class ShareView extends React.Component {
static navigationOptions = ({ navigation }) => {
const canSend = navigation.getParam('canSend', true);
return ({
title: I18n.t('Share'),
headerRight:
canSend
? (
<CustomHeaderButtons>
<Item
title={I18n.t('Send')}
onPress={navigation.getParam('sendMessage')}
testID='send-message-share-view'
buttonStyle={styles.send}
/>
</CustomHeaderButtons>
)
: null
});
}
static propTypes = {
navigation: PropTypes.object,
user: PropTypes.shape({
id: PropTypes.string.isRequired,
username: PropTypes.string.isRequired,
token: PropTypes.string.isRequired
}),
baseUrl: PropTypes.string.isRequired
};
constructor(props) {
super(props);
const { navigation } = this.props;
const rid = navigation.getParam('rid', '');
const name = navigation.getParam('name', '');
const value = navigation.getParam('value', '');
const isMedia = navigation.getParam('isMedia', false);
const fileInfo = navigation.getParam('fileInfo', {});
this.rooms = database.objects('subscriptions').filtered('rid = $0', rid);
this.state = {
rid,
value,
isMedia,
name,
fileInfo,
loading: false,
room: this.rooms[0] || { rid },
file: {
name: fileInfo ? fileInfo.name : '',
description: ''
}
};
}
componentDidMount() {
const { room } = this.state;
const { navigation, user } = this.props;
const { username } = user;
navigation.setParams({ sendMessage: this._sendMessage, canSend: !(isReadOnly(room, { username }) || isBlocked(room)) });
}
bytesToSize = bytes => `${ (bytes / 1048576).toFixed(2) }MB`;
_sendMessage = async() => {
const { isMedia } = this.state;
this.setState({ loading: true });
if (isMedia) {
await this.sendMediaMessage();
} else {
await this.sendTextMessage();
}
this.setState({ loading: false });
ShareExtension.close();
}
sendMediaMessage = async() => {
const { rid, fileInfo, file } = this.state;
const { baseUrl: server, user } = this.props;
const { name, description } = file;
const fileMessage = { ...fileInfo, name, description };
if (fileInfo && rid !== '') {
try {
await RocketChat.sendFileMessage(rid, fileMessage, undefined, server, user);
} catch (e) {
log('err_send_media_message', e);
}
}
}
sendTextMessage = async() => {
const { value, rid } = this.state;
const { user } = this.props;
if (value !== '' && rid !== '') {
try {
await RocketChat.sendMessage(rid, value, undefined, user);
} catch (error) {
log('err_share_extension_send_message', error);
}
}
};
renderPreview = () => {
const { fileInfo } = this.state;
const icon = fileInfo.mime.match(/image/)
? <Image source={{ isStatic: true, uri: fileInfo.path }} style={styles.mediaImage} />
: (
<View style={styles.mediaIconContainer}>
<CustomIcon name='file-generic' style={styles.mediaIcon} />
</View>
);
return (
<View style={styles.mediaContent}>
{icon}
<View style={styles.mediaInfo}>
<Text style={styles.mediaText} numberOfLines={1}>{fileInfo.name}</Text>
<Text style={styles.mediaText}>{this.bytesToSize(fileInfo.size)}</Text>
</View>
</View>
);
};
renderMediaContent = () => {
const { fileInfo, file } = this.state;
return fileInfo ? (
<View style={styles.mediaContainer}>
{this.renderPreview()}
<View style={styles.mediaInputContent}>
<TextInput
style={[styles.mediaNameInput, styles.input]}
placeholder={I18n.t('File_name')}
onChangeText={name => this.setState({ file: { ...file, name } })}
underlineColorAndroid='transparent'
defaultValue={file.name}
placeholderTextColor={COLOR_TEXT_DESCRIPTION}
/>
<TextInput
style={[styles.mediaDescriptionInput, styles.input]}
placeholder={I18n.t('File_description')}
onChangeText={description => this.setState({ file: { ...file, description } })}
underlineColorAndroid='transparent'
defaultValue={file.description}
multiline
textAlignVertical='top'
placeholderTextColor={COLOR_TEXT_DESCRIPTION}
autoFocus
/>
</View>
</View>
) : null;
};
renderInput = () => {
const { value } = this.state;
return (
<TextInput
style={[styles.input, styles.textInput]}
placeholder=''
onChangeText={handleText => this.setState({ value: handleText })}
underlineColorAndroid='transparent'
defaultValue={value}
multiline
textAlignVertical='top'
placeholderTextColor={COLOR_TEXT_DESCRIPTION}
autoFocus
/>
);
}
renderError = () => {
const { room } = this.state;
return (
<View style={[styles.container, styles.centered]}>
<Text style={styles.title}>
{
isBlocked(room) ? I18n.t('This_room_is_blocked') : I18n.t('This_room_is_read_only')
}
</Text>
</View>
);
}
render() {
const { user } = this.props;
const { username } = user;
const {
name, loading, isMedia, room
} = this.state;
if (isReadOnly(room, { username }) || isBlocked(room)) {
return this.renderError();
}
return (
<View style={styles.container}>
<View style={isMedia ? styles.toContent : styles.toContentText}>
<Text style={styles.text} numberOfLines={1}>
<Text style={styles.to}>{`${ I18n.t('To') }: `}</Text>
<Text style={styles.name}>{`${ name }`}</Text>
</Text>
</View>
<View style={styles.content}>
{isMedia ? this.renderMediaContent() : this.renderInput()}
</View>
{ loading ? <Loading /> : null }
</View>
);
}
}

View File

@ -0,0 +1,116 @@
import { StyleSheet } from 'react-native';
import sharedStyles from '../Styles';
import {
COLOR_BACKGROUND_CONTAINER, COLOR_WHITE
} from '../../constants/colors';
export default StyleSheet.create({
container: {
flex: 1,
backgroundColor: COLOR_BACKGROUND_CONTAINER
},
centered: {
justifyContent: 'center',
alignItems: 'center'
},
title: {
fontSize: 18,
...sharedStyles.textBold,
...sharedStyles.textColorNormal,
...sharedStyles.textAlignCenter
},
text: {
paddingHorizontal: 16,
paddingVertical: 8,
...sharedStyles.textColorNormal,
...sharedStyles.textRegular
},
to: {
...sharedStyles.textColorDescription,
...sharedStyles.textRegular
},
toContent: {
width: '100%',
backgroundColor: COLOR_WHITE
},
toContentText: {
width: '100%',
backgroundColor: COLOR_BACKGROUND_CONTAINER,
...sharedStyles.textColorNormal,
...sharedStyles.textRegular
},
name: {
...sharedStyles.textRegular,
...sharedStyles.textColorTitle
},
content: {
flex: 1,
backgroundColor: COLOR_WHITE
},
mediaContainer: {
flex: 1,
backgroundColor: COLOR_BACKGROUND_CONTAINER
},
mediaContent: {
flexDirection: 'row',
padding: 16,
backgroundColor: COLOR_BACKGROUND_CONTAINER,
alignItems: 'center'
},
mediaImage: {
height: 64,
width: 64
},
mediaIcon: {
fontSize: 64,
...sharedStyles.textColorNormal
},
mediaIconContainer: {
alignItems: 'center',
justifyContent: 'center'
},
mediaInfo: {
marginLeft: 16,
flex: 1
},
mediaText: {
fontSize: 16,
...sharedStyles.textColorNormal,
...sharedStyles.textRegular
},
mediaInputContent: {
width: '100%',
...sharedStyles.separatorVertical,
backgroundColor: COLOR_WHITE
},
input: {
fontSize: 16,
...sharedStyles.textColorNormal,
...sharedStyles.textRegular,
backgroundColor: COLOR_WHITE
},
textInput: {
flex: 1,
paddingHorizontal: 16
},
mediaNameInput: {
marginLeft: 16,
paddingRight: 16,
paddingVertical: 8,
backgroundColor: COLOR_WHITE,
...sharedStyles.separatorBottom
},
mediaDescriptionInput: {
marginLeft: 16,
paddingRight: 16,
marginVertical: 8,
backgroundColor: COLOR_WHITE,
height: 100
},
send: {
...sharedStyles.textColorHeaderBack,
...sharedStyles.textSemibold,
fontSize: 16
}
});

View File

@ -1,7 +1,7 @@
import { StyleSheet, Platform } from 'react-native'; import { StyleSheet, Platform } from 'react-native';
import { import {
COLOR_DANGER, COLOR_BUTTON_PRIMARY, COLOR_SEPARATOR, COLOR_TEXT, COLOR_TEXT_DESCRIPTION, COLOR_TITLE, COLOR_BACKGROUND_CONTAINER, COLOR_WHITE, COLOR_PRIMARY COLOR_DANGER, COLOR_BUTTON_PRIMARY, COLOR_SEPARATOR, COLOR_TEXT, COLOR_TEXT_DESCRIPTION, COLOR_TITLE, COLOR_BACKGROUND_CONTAINER, COLOR_WHITE, COLOR_PRIMARY, HEADER_BACK
} from '../constants/colors'; } from '../constants/colors';
export default StyleSheet.create({ export default StyleSheet.create({
@ -72,6 +72,9 @@ export default StyleSheet.create({
textAlignRight: { textAlignRight: {
textAlign: 'right' textAlign: 'right'
}, },
textAlignCenter: {
textAlign: 'center'
},
opacity5: { opacity5: {
opacity: 0.5 opacity: 0.5
}, },
@ -176,6 +179,9 @@ export default StyleSheet.create({
textColorDescription: { textColorDescription: {
color: COLOR_TEXT_DESCRIPTION color: COLOR_TEXT_DESCRIPTION
}, },
textColorHeaderBack: {
color: HEADER_BACK
},
colorPrimary: { colorPrimary: {
color: COLOR_PRIMARY color: COLOR_PRIMARY
}, },
@ -192,5 +198,10 @@ export default StyleSheet.create({
borderBottomWidth: StyleSheet.hairlineWidth, borderBottomWidth: StyleSheet.hairlineWidth,
backgroundColor: COLOR_WHITE, backgroundColor: COLOR_WHITE,
marginVertical: 10 marginVertical: 10
},
notchLandscapeContainer: {
marginTop: -34,
paddingHorizontal: 30,
backgroundColor: COLOR_BACKGROUND_CONTAINER
} }
}); });

View File

@ -0,0 +1,51 @@
import React from 'react';
import {
StyleSheet, View, Text
} from 'react-native';
import ShareExtension from 'rn-extensions-share';
import { CloseShareExtensionButton } from '../containers/HeaderButton';
import sharedStyles from './Styles';
import I18n from '../i18n';
import { COLOR_WHITE } from '../constants/colors';
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: COLOR_WHITE,
justifyContent: 'center',
alignItems: 'center',
padding: 15
},
title: {
fontSize: 18,
...sharedStyles.textBold,
...sharedStyles.textColorNormal
},
content: {
fontSize: 14,
...sharedStyles.textAlignCenter,
...sharedStyles.textColorNormal,
...sharedStyles.textRegular
}
});
export default class WithoutServerView extends React.Component {
static navigationOptions = () => ({
headerLeft: (
<CloseShareExtensionButton
onPress={ShareExtension.close}
testID='share-extension-close'
/>
)
})
render() {
return (
<View style={styles.container}>
<Text style={styles.title}>{I18n.t('Without_Servers')}</Text>
<Text style={styles.content}>{I18n.t('You_need_to_access_at_least_one_RocketChat_server_to_share_something')}</Text>
</View>
);
}
}

View File

@ -2,10 +2,10 @@ import 'react-native-console-time-polyfill';
import './app/ReactotronConfig'; import './app/ReactotronConfig';
import { AppRegistry } from 'react-native'; import { AppRegistry } from 'react-native';
import App from './app/index'; import { name as appName, share as shareName } from './app.json';
import { name as appName } from './app.json';
AppRegistry.registerComponent(appName, () => App); AppRegistry.registerComponent(appName, () => require('./app/index').default);
AppRegistry.registerComponent(shareName, () => require('./app/share').default);
// For storybook, comment everything above and uncomment below // For storybook, comment everything above and uncomment below
// import './storybook'; // import './storybook';

View File

@ -27,12 +27,14 @@ target 'RocketChatRN' do
pod 'RNImageCropPicker', :path => '../node_modules/react-native-image-crop-picker' pod 'RNImageCropPicker', :path => '../node_modules/react-native-image-crop-picker'
pod 'RNDeviceInfo', :path => '../node_modules/react-native-device-info' pod 'RNDeviceInfo', :path => '../node_modules/react-native-device-info'
pod 'RNLocalize', :path => '../node_modules/react-native-localize'
pod 'RNScreens', :path => '../node_modules/react-native-screens' pod 'RNScreens', :path => '../node_modules/react-native-screens'
pod 'react-native-splash-screen', :path => '../node_modules/react-native-splash-screen' pod 'react-native-splash-screen', :path => '../node_modules/react-native-splash-screen'
pod 'react-native-orientation-locker', :path => '../node_modules/react-native-orientation-locker' pod 'react-native-orientation-locker', :path => '../node_modules/react-native-orientation-locker'
pod 'react-native-realm-path', :path => '../node_modules/react-native-realm-path'
pod 'yoga', :path => '../node_modules/react-native/ReactCommon/yoga' pod 'yoga', :path => '../node_modules/react-native/ReactCommon/yoga'
pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec' pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec'
@ -45,11 +47,49 @@ target 'RocketChatRN' do
pod 'Crashlytics', '~> 3.12.0' pod 'Crashlytics', '~> 3.12.0'
pod 'GoogleIDFASupport', '~> 3.14.0' pod 'GoogleIDFASupport', '~> 3.14.0'
pod 'Firebase/Performance', '~> 5.20.1' pod 'Firebase/Performance', '~> 5.20.1'
pod 'react-native-document-picker', :path => '../node_modules/react-native-document-picker'
use_unimodules! use_unimodules!
end end
target 'ShareRocketChatRN' do
rn_path = '../node_modules/react-native'
pod 'React', path: rn_path, subspecs: [
'Core',
'RCTActionSheet',
'RCTAnimation',
# 'RCTGeolocation',
'RCTImage',
'RCTLinkingIOS',
'RCTNetwork',
'RCTSettings',
'RCTText',
'RCTVibration',
'RCTWebSocket'
]
pod 'RNDeviceInfo', :path => '../node_modules/react-native-device-info'
pod 'RNLocalize', :path => '../node_modules/react-native-localize'
pod 'react-native-realm-path', :path => '../node_modules/react-native-realm-path'
pod 'rn-extensions-share', :path => '../node_modules/rn-extensions-share'
pod 'yoga', :path => '../node_modules/react-native/ReactCommon/yoga'
pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec'
pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec'
pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec'
pod 'Firebase/Core', '~> 5.20.1'
pod 'Fabric', '~> 1.9.0'
pod 'Crashlytics', '~> 3.12.0'
pod 'GoogleIDFASupport', '~> 3.14.0'
pod 'Firebase/Performance', '~> 5.20.1'
end
post_install do |installer| post_install do |installer|
installer.pods_project.targets.each do |target| installer.pods_project.targets.each do |target|
if target.name == "React" if target.name == "React"

View File

@ -109,8 +109,12 @@ PODS:
- QBImagePickerController (3.4.0) - QBImagePickerController (3.4.0)
- React (0.59.8): - React (0.59.8):
- React/Core (= 0.59.8) - React/Core (= 0.59.8)
- react-native-document-picker (3.2.2):
- React
- react-native-orientation-locker (1.1.5): - react-native-orientation-locker (1.1.5):
- React - React
- react-native-realm-path (1.2.11):
- React
- react-native-splash-screen (3.2.0): - react-native-splash-screen (3.2.0):
- React - React
- react-native-webview (5.8.1): - react-native-webview (5.8.1):
@ -141,12 +145,16 @@ PODS:
- React/Core - React/Core
- React/fishhook - React/fishhook
- React/RCTBlob - React/RCTBlob
- rn-extensions-share (2.3.10):
- React
- RNDeviceInfo (1.6.1): - RNDeviceInfo (1.6.1):
- React - React
- RNImageCropPicker (0.21.1): - RNImageCropPicker (0.24.1):
- QBImagePickerController - QBImagePickerController
- React/Core - React/Core
- RSKImageCropper - RSKImageCropper
- RNLocalize (1.1.4):
- React
- RNScreens (1.0.0-alpha.22): - RNScreens (1.0.0-alpha.22):
- React - React
- RSKImageCropper (2.2.1) - RSKImageCropper (2.2.1)
@ -182,7 +190,9 @@ DEPENDENCIES:
- Folly (from `../node_modules/react-native/third-party-podspecs/Folly.podspec`) - Folly (from `../node_modules/react-native/third-party-podspecs/Folly.podspec`)
- glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`)
- GoogleIDFASupport (~> 3.14.0) - GoogleIDFASupport (~> 3.14.0)
- react-native-document-picker (from `../node_modules/react-native-document-picker`)
- react-native-orientation-locker (from `../node_modules/react-native-orientation-locker`) - react-native-orientation-locker (from `../node_modules/react-native-orientation-locker`)
- react-native-realm-path (from `../node_modules/react-native-realm-path`)
- react-native-splash-screen (from `../node_modules/react-native-splash-screen`) - react-native-splash-screen (from `../node_modules/react-native-splash-screen`)
- react-native-webview (from `../node_modules/react-native-webview`) - react-native-webview (from `../node_modules/react-native-webview`)
- React/Core (from `../node_modules/react-native`) - React/Core (from `../node_modules/react-native`)
@ -195,8 +205,10 @@ DEPENDENCIES:
- React/RCTText (from `../node_modules/react-native`) - React/RCTText (from `../node_modules/react-native`)
- React/RCTVibration (from `../node_modules/react-native`) - React/RCTVibration (from `../node_modules/react-native`)
- React/RCTWebSocket (from `../node_modules/react-native`) - React/RCTWebSocket (from `../node_modules/react-native`)
- rn-extensions-share (from `../node_modules/rn-extensions-share`)
- RNDeviceInfo (from `../node_modules/react-native-device-info`) - RNDeviceInfo (from `../node_modules/react-native-device-info`)
- RNImageCropPicker (from `../node_modules/react-native-image-crop-picker`) - RNImageCropPicker (from `../node_modules/react-native-image-crop-picker`)
- RNLocalize (from `../node_modules/react-native-localize`)
- RNScreens (from `../node_modules/react-native-screens`) - RNScreens (from `../node_modules/react-native-screens`)
- UMBarCodeScannerInterface (from `../node_modules/unimodules-barcode-scanner-interface/ios`) - UMBarCodeScannerInterface (from `../node_modules/unimodules-barcode-scanner-interface/ios`)
- UMCameraInterface (from `../node_modules/unimodules-camera-interface/ios`) - UMCameraInterface (from `../node_modules/unimodules-camera-interface/ios`)
@ -261,16 +273,24 @@ EXTERNAL SOURCES:
:podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec" :podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec"
React: React:
:path: "../node_modules/react-native" :path: "../node_modules/react-native"
react-native-document-picker:
:path: "../node_modules/react-native-document-picker"
react-native-orientation-locker: react-native-orientation-locker:
:path: "../node_modules/react-native-orientation-locker" :path: "../node_modules/react-native-orientation-locker"
react-native-realm-path:
:path: "../node_modules/react-native-realm-path"
react-native-splash-screen: react-native-splash-screen:
:path: "../node_modules/react-native-splash-screen" :path: "../node_modules/react-native-splash-screen"
react-native-webview: react-native-webview:
:path: "../node_modules/react-native-webview" :path: "../node_modules/react-native-webview"
rn-extensions-share:
:path: "../node_modules/rn-extensions-share"
RNDeviceInfo: RNDeviceInfo:
:path: "../node_modules/react-native-device-info" :path: "../node_modules/react-native-device-info"
RNImageCropPicker: RNImageCropPicker:
:path: "../node_modules/react-native-image-crop-picker" :path: "../node_modules/react-native-image-crop-picker"
RNLocalize:
:path: "../node_modules/react-native-localize"
RNScreens: RNScreens:
:path: "../node_modules/react-native-screens" :path: "../node_modules/react-native-screens"
UMBarCodeScannerInterface: UMBarCodeScannerInterface:
@ -341,11 +361,15 @@ SPEC CHECKSUMS:
Protobuf: 7a877b7f3e5964e3fce995e2eb323dbc6831bb5a Protobuf: 7a877b7f3e5964e3fce995e2eb323dbc6831bb5a
QBImagePickerController: d54cf93db6decf26baf6ed3472f336ef35cae022 QBImagePickerController: d54cf93db6decf26baf6ed3472f336ef35cae022
React: 76e6aa2b87d05eb6cccb6926d72685c9a07df152 React: 76e6aa2b87d05eb6cccb6926d72685c9a07df152
react-native-document-picker: 94a07ce0494c559e2ae9fa86621d6c624d810fec
react-native-orientation-locker: 132a63bab4dddd2a5709f6f7935ad9676b0af7c5 react-native-orientation-locker: 132a63bab4dddd2a5709f6f7935ad9676b0af7c5
react-native-realm-path: 868473ea0bc4629850f1ec51a70d81055c06d091
react-native-splash-screen: 200d11d188e2e78cea3ad319964f6142b6384865 react-native-splash-screen: 200d11d188e2e78cea3ad319964f6142b6384865
react-native-webview: f3e28b48461c78db833f727feec08b13285e7b61 react-native-webview: f3e28b48461c78db833f727feec08b13285e7b61
rn-extensions-share: 4bfee75806ad54aadeff1dfa535697a6345a50b8
RNDeviceInfo: 958a1ed6f94e04557b865b8ef848cfc83db0ebba RNDeviceInfo: 958a1ed6f94e04557b865b8ef848cfc83db0ebba
RNImageCropPicker: e608efe182652dc8690268cb99cb5a201f2b5ea3 RNImageCropPicker: 6134b66a3d5bc13e2895a97c630a4254006902b4
RNLocalize: 62a949d2ec5bee0eb8f39a80a48f01e2f4f67080
RNScreens: 720a9e6968beb73e8196239801e887d8401f86ed RNScreens: 720a9e6968beb73e8196239801e887d8401f86ed
RSKImageCropper: 98296ad26b41753f796b6898d015509598f13d97 RSKImageCropper: 98296ad26b41753f796b6898d015509598f13d97
UMBarCodeScannerInterface: d5602e23de37f95bb4ee49ee3b2711e128058ae9 UMBarCodeScannerInterface: d5602e23de37f95bb4ee49ee3b2711e128058ae9
@ -362,6 +386,6 @@ SPEC CHECKSUMS:
UMTaskManagerInterface: 296793ab2a7e181fe5ebe2ba9b40ae208ab4b8fa UMTaskManagerInterface: 296793ab2a7e181fe5ebe2ba9b40ae208ab4b8fa
yoga: 92b2102c3d373d1a790db4ab761d2b0ffc634f64 yoga: 92b2102c3d373d1a790db4ab761d2b0ffc634f64
PODFILE CHECKSUM: b5e15bac5f306ea636e16393a7a6eb42c017ea99 PODFILE CHECKSUM: bfa056aa2707bd200eb8a39ada130c51b702380c
COCOAPODS: 1.6.2 COCOAPODS: 1.6.2

View File

@ -0,0 +1 @@
../../../../../node_modules/react-native-localize/ios/RNLocalize.h

View File

@ -0,0 +1 @@
../../../../../node_modules/react-native-document-picker/ios/RNDocumentPicker/RNDocumentPicker.h

View File

@ -0,0 +1 @@
../../../../../node_modules/react-native-realm-path/ios/RNRealmPath.h

View File

@ -0,0 +1 @@
../../../../../node_modules/rn-extensions-share/ios/ReactNativeShareExtension.h

View File

@ -0,0 +1 @@
../../../../../node_modules/react-native-localize/ios/RNLocalize.h

View File

@ -0,0 +1 @@
../../../../../node_modules/react-native-document-picker/ios/RNDocumentPicker/RNDocumentPicker.h

View File

@ -0,0 +1 @@
../../../../../node_modules/react-native-realm-path/ios/RNRealmPath.h

View File

@ -0,0 +1 @@
../../../../../node_modules/rn-extensions-share/ios/ReactNativeShareExtension.h

View File

@ -1,6 +1,6 @@
{ {
"name": "RNImageCropPicker", "name": "RNImageCropPicker",
"version": "0.21.1", "version": "0.24.1",
"summary": "Select single or multiple images, with cropping option", "summary": "Select single or multiple images, with cropping option",
"requires_arc": true, "requires_arc": true,
"license": "MIT", "license": "MIT",

View File

@ -0,0 +1,22 @@
{
"name": "RNLocalize",
"dependencies": {
"React": [
]
},
"version": "1.1.4",
"license": "MIT",
"description": "A toolbox for your React Native app localization.",
"summary": "A toolbox for your React Native app localization.",
"authors": "Mathieu Acthernoene <zoontek@gmail.com>",
"homepage": "https://github.com/react-native-community/react-native-localize",
"platforms": {
"ios": "9.0"
},
"source": {
"git": "https://github.com/react-native-community/react-native-localize.git",
"tag": "1.1.4"
},
"source_files": "ios/*.{h,m}"
}

View File

@ -0,0 +1,22 @@
{
"name": "react-native-document-picker",
"version": "3.2.2",
"summary": "A react native interface to access Documents from dropbox google drive, iCloud",
"license": "MIT",
"homepage": "https://github.com/Elyx0/react-native-document-picker#readme",
"authors": {
"Elyx0": "elyx00@gmail.com"
},
"source": {
"git": "https://github.com/Elyx0/react-native-document-picker"
},
"source_files": "ios/RNDocumentPicker/*.{h,m}",
"platforms": {
"ios": "7.0"
},
"dependencies": {
"React": [
]
}
}

View File

@ -0,0 +1,21 @@
{
"name": "react-native-realm-path",
"version": "1.2.11",
"summary": "A helper to Realm Path on AppGroup iOS.",
"license": "MIT",
"authors": "Djorkaeff Alexandre",
"homepage": "https://github.com/rocketchat/react-native-realm-path",
"platforms": {
"ios": "10.0"
},
"source": {
"git": "https://github.com/RocketChat/react-native-realm-path.git",
"tag": "v1.2.11"
},
"source_files": "ios/**/*.{h,m}",
"dependencies": {
"React": [
]
}
}

View File

@ -0,0 +1,25 @@
{
"name": "rn-extensions-share",
"version": "2.3.10",
"summary": "Share-Extension using react-native for both ios and android",
"license": "MIT",
"authors": {
"name": "Djorkaeff Alexandre",
"email": "djorkaeffalexandre@gmail.com",
"url": "http://github.com/djorkaeffalexandre"
},
"homepage": "https://github.com/RocketChat/rn-extensions-share",
"platforms": {
"ios": "8.0"
},
"source": {
"git": "https://github.com/RocketChat/rn-extensions-share.git",
"tag": "master"
},
"source_files": "ios/*.{h,m}",
"dependencies": {
"React": [
]
}
}

30
ios/Pods/Manifest.lock generated
View File

@ -109,8 +109,12 @@ PODS:
- QBImagePickerController (3.4.0) - QBImagePickerController (3.4.0)
- React (0.59.8): - React (0.59.8):
- React/Core (= 0.59.8) - React/Core (= 0.59.8)
- react-native-document-picker (3.2.2):
- React
- react-native-orientation-locker (1.1.5): - react-native-orientation-locker (1.1.5):
- React - React
- react-native-realm-path (1.2.11):
- React
- react-native-splash-screen (3.2.0): - react-native-splash-screen (3.2.0):
- React - React
- react-native-webview (5.8.1): - react-native-webview (5.8.1):
@ -141,12 +145,16 @@ PODS:
- React/Core - React/Core
- React/fishhook - React/fishhook
- React/RCTBlob - React/RCTBlob
- rn-extensions-share (2.3.10):
- React
- RNDeviceInfo (1.6.1): - RNDeviceInfo (1.6.1):
- React - React
- RNImageCropPicker (0.21.1): - RNImageCropPicker (0.24.1):
- QBImagePickerController - QBImagePickerController
- React/Core - React/Core
- RSKImageCropper - RSKImageCropper
- RNLocalize (1.1.4):
- React
- RNScreens (1.0.0-alpha.22): - RNScreens (1.0.0-alpha.22):
- React - React
- RSKImageCropper (2.2.1) - RSKImageCropper (2.2.1)
@ -182,7 +190,9 @@ DEPENDENCIES:
- Folly (from `../node_modules/react-native/third-party-podspecs/Folly.podspec`) - Folly (from `../node_modules/react-native/third-party-podspecs/Folly.podspec`)
- glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`)
- GoogleIDFASupport (~> 3.14.0) - GoogleIDFASupport (~> 3.14.0)
- react-native-document-picker (from `../node_modules/react-native-document-picker`)
- react-native-orientation-locker (from `../node_modules/react-native-orientation-locker`) - react-native-orientation-locker (from `../node_modules/react-native-orientation-locker`)
- react-native-realm-path (from `../node_modules/react-native-realm-path`)
- react-native-splash-screen (from `../node_modules/react-native-splash-screen`) - react-native-splash-screen (from `../node_modules/react-native-splash-screen`)
- react-native-webview (from `../node_modules/react-native-webview`) - react-native-webview (from `../node_modules/react-native-webview`)
- React/Core (from `../node_modules/react-native`) - React/Core (from `../node_modules/react-native`)
@ -195,8 +205,10 @@ DEPENDENCIES:
- React/RCTText (from `../node_modules/react-native`) - React/RCTText (from `../node_modules/react-native`)
- React/RCTVibration (from `../node_modules/react-native`) - React/RCTVibration (from `../node_modules/react-native`)
- React/RCTWebSocket (from `../node_modules/react-native`) - React/RCTWebSocket (from `../node_modules/react-native`)
- rn-extensions-share (from `../node_modules/rn-extensions-share`)
- RNDeviceInfo (from `../node_modules/react-native-device-info`) - RNDeviceInfo (from `../node_modules/react-native-device-info`)
- RNImageCropPicker (from `../node_modules/react-native-image-crop-picker`) - RNImageCropPicker (from `../node_modules/react-native-image-crop-picker`)
- RNLocalize (from `../node_modules/react-native-localize`)
- RNScreens (from `../node_modules/react-native-screens`) - RNScreens (from `../node_modules/react-native-screens`)
- UMBarCodeScannerInterface (from `../node_modules/unimodules-barcode-scanner-interface/ios`) - UMBarCodeScannerInterface (from `../node_modules/unimodules-barcode-scanner-interface/ios`)
- UMCameraInterface (from `../node_modules/unimodules-camera-interface/ios`) - UMCameraInterface (from `../node_modules/unimodules-camera-interface/ios`)
@ -261,16 +273,24 @@ EXTERNAL SOURCES:
:podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec" :podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec"
React: React:
:path: "../node_modules/react-native" :path: "../node_modules/react-native"
react-native-document-picker:
:path: "../node_modules/react-native-document-picker"
react-native-orientation-locker: react-native-orientation-locker:
:path: "../node_modules/react-native-orientation-locker" :path: "../node_modules/react-native-orientation-locker"
react-native-realm-path:
:path: "../node_modules/react-native-realm-path"
react-native-splash-screen: react-native-splash-screen:
:path: "../node_modules/react-native-splash-screen" :path: "../node_modules/react-native-splash-screen"
react-native-webview: react-native-webview:
:path: "../node_modules/react-native-webview" :path: "../node_modules/react-native-webview"
rn-extensions-share:
:path: "../node_modules/rn-extensions-share"
RNDeviceInfo: RNDeviceInfo:
:path: "../node_modules/react-native-device-info" :path: "../node_modules/react-native-device-info"
RNImageCropPicker: RNImageCropPicker:
:path: "../node_modules/react-native-image-crop-picker" :path: "../node_modules/react-native-image-crop-picker"
RNLocalize:
:path: "../node_modules/react-native-localize"
RNScreens: RNScreens:
:path: "../node_modules/react-native-screens" :path: "../node_modules/react-native-screens"
UMBarCodeScannerInterface: UMBarCodeScannerInterface:
@ -341,11 +361,15 @@ SPEC CHECKSUMS:
Protobuf: 7a877b7f3e5964e3fce995e2eb323dbc6831bb5a Protobuf: 7a877b7f3e5964e3fce995e2eb323dbc6831bb5a
QBImagePickerController: d54cf93db6decf26baf6ed3472f336ef35cae022 QBImagePickerController: d54cf93db6decf26baf6ed3472f336ef35cae022
React: 76e6aa2b87d05eb6cccb6926d72685c9a07df152 React: 76e6aa2b87d05eb6cccb6926d72685c9a07df152
react-native-document-picker: 94a07ce0494c559e2ae9fa86621d6c624d810fec
react-native-orientation-locker: 132a63bab4dddd2a5709f6f7935ad9676b0af7c5 react-native-orientation-locker: 132a63bab4dddd2a5709f6f7935ad9676b0af7c5
react-native-realm-path: 868473ea0bc4629850f1ec51a70d81055c06d091
react-native-splash-screen: 200d11d188e2e78cea3ad319964f6142b6384865 react-native-splash-screen: 200d11d188e2e78cea3ad319964f6142b6384865
react-native-webview: f3e28b48461c78db833f727feec08b13285e7b61 react-native-webview: f3e28b48461c78db833f727feec08b13285e7b61
rn-extensions-share: 4bfee75806ad54aadeff1dfa535697a6345a50b8
RNDeviceInfo: 958a1ed6f94e04557b865b8ef848cfc83db0ebba RNDeviceInfo: 958a1ed6f94e04557b865b8ef848cfc83db0ebba
RNImageCropPicker: e608efe182652dc8690268cb99cb5a201f2b5ea3 RNImageCropPicker: 6134b66a3d5bc13e2895a97c630a4254006902b4
RNLocalize: 62a949d2ec5bee0eb8f39a80a48f01e2f4f67080
RNScreens: 720a9e6968beb73e8196239801e887d8401f86ed RNScreens: 720a9e6968beb73e8196239801e887d8401f86ed
RSKImageCropper: 98296ad26b41753f796b6898d015509598f13d97 RSKImageCropper: 98296ad26b41753f796b6898d015509598f13d97
UMBarCodeScannerInterface: d5602e23de37f95bb4ee49ee3b2711e128058ae9 UMBarCodeScannerInterface: d5602e23de37f95bb4ee49ee3b2711e128058ae9
@ -362,6 +386,6 @@ SPEC CHECKSUMS:
UMTaskManagerInterface: 296793ab2a7e181fe5ebe2ba9b40ae208ab4b8fa UMTaskManagerInterface: 296793ab2a7e181fe5ebe2ba9b40ae208ab4b8fa
yoga: 92b2102c3d373d1a790db4ab761d2b0ffc634f64 yoga: 92b2102c3d373d1a790db4ab761d2b0ffc634f64
PODFILE CHECKSUM: b5e15bac5f306ea636e16393a7a6eb42c017ea99 PODFILE CHECKSUM: bfa056aa2707bd200eb8a39ada130c51b702380c
COCOAPODS: 1.6.2 COCOAPODS: 1.6.2

File diff suppressed because it is too large Load Diff

View File

@ -1568,6 +1568,31 @@ redistribute it freely, subject to the following restrictions:
distribution. distribution.
## react-native-document-picker
MIT License
Copyright (c) 2016 Elyx0
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
## react-native-orientation-locker ## react-native-orientation-locker
MIT License MIT License

View File

@ -1739,6 +1739,37 @@ redistribute it freely, subject to the following restrictions:
<key>FooterText</key> <key>FooterText</key>
<string>MIT License <string>MIT License
Copyright (c) 2016 Elyx0
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
</string>
<key>License</key>
<string>MIT</string>
<key>Title</key>
<string>react-native-document-picker</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>MIT License
Copyright (c) 2017 Wonday (@wonday.org) Copyright (c) 2017 Wonday (@wonday.org)
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy

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/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 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/RNLocalize" "${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-document-picker" "${PODS_ROOT}/Headers/Public/react-native-orientation-locker" "${PODS_ROOT}/Headers/Public/react-native-realm-path" "${PODS_ROOT}/Headers/Public/react-native-splash-screen" "${PODS_ROOT}/Headers/Public/react-native-webview" "${PODS_ROOT}/Headers/Public/rn-extensions-share" "${PODS_ROOT}/Headers/Public/yoga" $(inherited) ${PODS_ROOT}/Firebase/CoreOnly/Sources
LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/DoubleConversion" "${PODS_CONFIGURATION_BUILD_DIR}/EXAppLoaderProvider" "${PODS_CONFIGURATION_BUILD_DIR}/EXConstants" "${PODS_CONFIGURATION_BUILD_DIR}/EXFileSystem" "${PODS_CONFIGURATION_BUILD_DIR}/EXHaptics" "${PODS_CONFIGURATION_BUILD_DIR}/EXPermissions" "${PODS_CONFIGURATION_BUILD_DIR}/EXWebBrowser" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstanceID" "${PODS_CONFIGURATION_BUILD_DIR}/Folly" "${PODS_CONFIGURATION_BUILD_DIR}/GTMSessionFetcher" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleToolboxForMac" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/Protobuf" "${PODS_CONFIGURATION_BUILD_DIR}/QBImagePickerController" "${PODS_CONFIGURATION_BUILD_DIR}/RNDeviceInfo" "${PODS_CONFIGURATION_BUILD_DIR}/RNImageCropPicker" "${PODS_CONFIGURATION_BUILD_DIR}/RNScreens" "${PODS_CONFIGURATION_BUILD_DIR}/RSKImageCropper" "${PODS_CONFIGURATION_BUILD_DIR}/React" "${PODS_CONFIGURATION_BUILD_DIR}/UMCore" "${PODS_CONFIGURATION_BUILD_DIR}/UMReactNativeAdapter" "${PODS_CONFIGURATION_BUILD_DIR}/glog" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" "${PODS_CONFIGURATION_BUILD_DIR}/react-native-orientation-locker" "${PODS_CONFIGURATION_BUILD_DIR}/react-native-splash-screen" "${PODS_CONFIGURATION_BUILD_DIR}/react-native-webview" "${PODS_CONFIGURATION_BUILD_DIR}/yoga" "${PODS_ROOT}/GoogleIDFASupport/Libraries" 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}/RNLocalize" "${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-document-picker" "${PODS_CONFIGURATION_BUILD_DIR}/react-native-orientation-locker" "${PODS_CONFIGURATION_BUILD_DIR}/react-native-realm-path" "${PODS_CONFIGURATION_BUILD_DIR}/react-native-splash-screen" "${PODS_CONFIGURATION_BUILD_DIR}/react-native-webview" "${PODS_CONFIGURATION_BUILD_DIR}/yoga" "${PODS_ROOT}/GoogleIDFASupport/Libraries"
OTHER_LDFLAGS = $(inherited) -ObjC -l"AdIdAccessLibrary" -l"DoubleConversion" -l"EXAppLoaderProvider" -l"EXConstants" -l"EXFileSystem" -l"EXHaptics" -l"EXPermissions" -l"EXWebBrowser" -l"FirebaseCore" -l"FirebaseInstanceID" -l"Folly" -l"GTMSessionFetcher" -l"GoogleToolboxForMac" -l"GoogleUtilities" -l"Protobuf" -l"QBImagePickerController" -l"RNDeviceInfo" -l"RNImageCropPicker" -l"RNScreens" -l"RSKImageCropper" -l"React" -l"UMCore" -l"UMReactNativeAdapter" -l"c++" -l"glog" -l"nanopb" -l"react-native-orientation-locker" -l"react-native-splash-screen" -l"react-native-webview" -l"sqlite3" -l"stdc++" -l"yoga" -l"z" -framework "AdSupport" -framework "CoreTelephony" -framework "Crashlytics" -framework "FIRAnalyticsConnector" -framework "Fabric" -framework "FirebaseABTesting" -framework "FirebaseAnalytics" -framework "FirebaseCoreDiagnostics" -framework "FirebasePerformance" -framework "FirebaseRemoteConfig" -framework "Foundation" -framework "GoogleAppMeasurement" -framework "JavaScriptCore" -framework "Photos" -framework "QuartzCore" -framework "Security" -framework "StoreKit" -framework "SystemConfiguration" -framework "UIKit" 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"RNLocalize" -l"RNScreens" -l"RSKImageCropper" -l"React" -l"UMCore" -l"UMReactNativeAdapter" -l"c++" -l"glog" -l"nanopb" -l"react-native-document-picker" -l"react-native-orientation-locker" -l"react-native-realm-path" -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/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 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/RNLocalize" "${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-document-picker" "${PODS_ROOT}/Headers/Public/react-native-orientation-locker" "${PODS_ROOT}/Headers/Public/react-native-realm-path" "${PODS_ROOT}/Headers/Public/react-native-splash-screen" "${PODS_ROOT}/Headers/Public/react-native-webview" "${PODS_ROOT}/Headers/Public/rn-extensions-share" "${PODS_ROOT}/Headers/Public/yoga" $(inherited) ${PODS_ROOT}/Firebase/CoreOnly/Sources
LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/DoubleConversion" "${PODS_CONFIGURATION_BUILD_DIR}/EXAppLoaderProvider" "${PODS_CONFIGURATION_BUILD_DIR}/EXConstants" "${PODS_CONFIGURATION_BUILD_DIR}/EXFileSystem" "${PODS_CONFIGURATION_BUILD_DIR}/EXHaptics" "${PODS_CONFIGURATION_BUILD_DIR}/EXPermissions" "${PODS_CONFIGURATION_BUILD_DIR}/EXWebBrowser" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstanceID" "${PODS_CONFIGURATION_BUILD_DIR}/Folly" "${PODS_CONFIGURATION_BUILD_DIR}/GTMSessionFetcher" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleToolboxForMac" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/Protobuf" "${PODS_CONFIGURATION_BUILD_DIR}/QBImagePickerController" "${PODS_CONFIGURATION_BUILD_DIR}/RNDeviceInfo" "${PODS_CONFIGURATION_BUILD_DIR}/RNImageCropPicker" "${PODS_CONFIGURATION_BUILD_DIR}/RNScreens" "${PODS_CONFIGURATION_BUILD_DIR}/RSKImageCropper" "${PODS_CONFIGURATION_BUILD_DIR}/React" "${PODS_CONFIGURATION_BUILD_DIR}/UMCore" "${PODS_CONFIGURATION_BUILD_DIR}/UMReactNativeAdapter" "${PODS_CONFIGURATION_BUILD_DIR}/glog" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" "${PODS_CONFIGURATION_BUILD_DIR}/react-native-orientation-locker" "${PODS_CONFIGURATION_BUILD_DIR}/react-native-splash-screen" "${PODS_CONFIGURATION_BUILD_DIR}/react-native-webview" "${PODS_CONFIGURATION_BUILD_DIR}/yoga" "${PODS_ROOT}/GoogleIDFASupport/Libraries" 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}/RNLocalize" "${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-document-picker" "${PODS_CONFIGURATION_BUILD_DIR}/react-native-orientation-locker" "${PODS_CONFIGURATION_BUILD_DIR}/react-native-realm-path" "${PODS_CONFIGURATION_BUILD_DIR}/react-native-splash-screen" "${PODS_CONFIGURATION_BUILD_DIR}/react-native-webview" "${PODS_CONFIGURATION_BUILD_DIR}/yoga" "${PODS_ROOT}/GoogleIDFASupport/Libraries"
OTHER_LDFLAGS = $(inherited) -ObjC -l"AdIdAccessLibrary" -l"DoubleConversion" -l"EXAppLoaderProvider" -l"EXConstants" -l"EXFileSystem" -l"EXHaptics" -l"EXPermissions" -l"EXWebBrowser" -l"FirebaseCore" -l"FirebaseInstanceID" -l"Folly" -l"GTMSessionFetcher" -l"GoogleToolboxForMac" -l"GoogleUtilities" -l"Protobuf" -l"QBImagePickerController" -l"RNDeviceInfo" -l"RNImageCropPicker" -l"RNScreens" -l"RSKImageCropper" -l"React" -l"UMCore" -l"UMReactNativeAdapter" -l"c++" -l"glog" -l"nanopb" -l"react-native-orientation-locker" -l"react-native-splash-screen" -l"react-native-webview" -l"sqlite3" -l"stdc++" -l"yoga" -l"z" -framework "AdSupport" -framework "CoreTelephony" -framework "Crashlytics" -framework "FIRAnalyticsConnector" -framework "Fabric" -framework "FirebaseABTesting" -framework "FirebaseAnalytics" -framework "FirebaseCoreDiagnostics" -framework "FirebasePerformance" -framework "FirebaseRemoteConfig" -framework "Foundation" -framework "GoogleAppMeasurement" -framework "JavaScriptCore" -framework "Photos" -framework "QuartzCore" -framework "Security" -framework "StoreKit" -framework "SystemConfiguration" -framework "UIKit" 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"RNLocalize" -l"RNScreens" -l"RSKImageCropper" -l"React" -l"UMCore" -l"UMReactNativeAdapter" -l"c++" -l"glog" -l"nanopb" -l"react-native-document-picker" -l"react-native-orientation-locker" -l"react-native-realm-path" -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

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

View File

@ -0,0 +1,9 @@
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Crashlytics/iOS" "${PODS_ROOT}/Fabric/iOS" "${PODS_ROOT}/FirebaseABTesting/Frameworks" "${PODS_ROOT}/FirebaseAnalytics/Frameworks" "${PODS_ROOT}/FirebasePerformance/Frameworks" "${PODS_ROOT}/FirebaseRemoteConfig/Frameworks" "${PODS_ROOT}/GoogleAppMeasurement/Frameworks"
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 $(inherited) GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1 $(inherited) PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1 PB_ENABLE_MALLOC=1
HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/DoubleConversion" "${PODS_ROOT}/Headers/Public/EXAppLoaderProvider" "${PODS_ROOT}/Headers/Public/EXConstants" "${PODS_ROOT}/Headers/Public/EXFileSystem" "${PODS_ROOT}/Headers/Public/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/RNLocalize" "${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-document-picker" "${PODS_ROOT}/Headers/Public/react-native-orientation-locker" "${PODS_ROOT}/Headers/Public/react-native-realm-path" "${PODS_ROOT}/Headers/Public/react-native-splash-screen" "${PODS_ROOT}/Headers/Public/react-native-webview" "${PODS_ROOT}/Headers/Public/rn-extensions-share" "${PODS_ROOT}/Headers/Public/yoga" $(inherited) ${PODS_ROOT}/Firebase/CoreOnly/Sources
LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/DoubleConversion" "${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}/RNDeviceInfo" "${PODS_CONFIGURATION_BUILD_DIR}/RNLocalize" "${PODS_CONFIGURATION_BUILD_DIR}/React" "${PODS_CONFIGURATION_BUILD_DIR}/glog" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" "${PODS_CONFIGURATION_BUILD_DIR}/react-native-realm-path" "${PODS_CONFIGURATION_BUILD_DIR}/rn-extensions-share" "${PODS_CONFIGURATION_BUILD_DIR}/yoga" "${PODS_ROOT}/GoogleIDFASupport/Libraries"
OTHER_LDFLAGS = $(inherited) -ObjC -l"AdIdAccessLibrary" -l"DoubleConversion" -l"FirebaseCore" -l"FirebaseInstanceID" -l"Folly" -l"GTMSessionFetcher" -l"GoogleToolboxForMac" -l"GoogleUtilities" -l"Protobuf" -l"RNDeviceInfo" -l"RNLocalize" -l"React" -l"c++" -l"glog" -l"nanopb" -l"react-native-realm-path" -l"rn-extensions-share" -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 "QuartzCore" -framework "Security" -framework "StoreKit" -framework "SystemConfiguration" -framework "UIKit"
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
PODS_ROOT = ${SRCROOT}/Pods

View File

@ -0,0 +1,9 @@
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Crashlytics/iOS" "${PODS_ROOT}/Fabric/iOS" "${PODS_ROOT}/FirebaseABTesting/Frameworks" "${PODS_ROOT}/FirebaseAnalytics/Frameworks" "${PODS_ROOT}/FirebasePerformance/Frameworks" "${PODS_ROOT}/FirebaseRemoteConfig/Frameworks" "${PODS_ROOT}/GoogleAppMeasurement/Frameworks"
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 $(inherited) GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1 $(inherited) PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1 PB_ENABLE_MALLOC=1
HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/DoubleConversion" "${PODS_ROOT}/Headers/Public/EXAppLoaderProvider" "${PODS_ROOT}/Headers/Public/EXConstants" "${PODS_ROOT}/Headers/Public/EXFileSystem" "${PODS_ROOT}/Headers/Public/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/RNLocalize" "${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-document-picker" "${PODS_ROOT}/Headers/Public/react-native-orientation-locker" "${PODS_ROOT}/Headers/Public/react-native-realm-path" "${PODS_ROOT}/Headers/Public/react-native-splash-screen" "${PODS_ROOT}/Headers/Public/react-native-webview" "${PODS_ROOT}/Headers/Public/rn-extensions-share" "${PODS_ROOT}/Headers/Public/yoga" $(inherited) ${PODS_ROOT}/Firebase/CoreOnly/Sources
LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/DoubleConversion" "${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}/RNDeviceInfo" "${PODS_CONFIGURATION_BUILD_DIR}/RNLocalize" "${PODS_CONFIGURATION_BUILD_DIR}/React" "${PODS_CONFIGURATION_BUILD_DIR}/glog" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" "${PODS_CONFIGURATION_BUILD_DIR}/react-native-realm-path" "${PODS_CONFIGURATION_BUILD_DIR}/rn-extensions-share" "${PODS_CONFIGURATION_BUILD_DIR}/yoga" "${PODS_ROOT}/GoogleIDFASupport/Libraries"
OTHER_LDFLAGS = $(inherited) -ObjC -l"AdIdAccessLibrary" -l"DoubleConversion" -l"FirebaseCore" -l"FirebaseInstanceID" -l"Folly" -l"GTMSessionFetcher" -l"GoogleToolboxForMac" -l"GoogleUtilities" -l"Protobuf" -l"RNDeviceInfo" -l"RNLocalize" -l"React" -l"c++" -l"glog" -l"nanopb" -l"react-native-realm-path" -l"rn-extensions-share" -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 "QuartzCore" -framework "Security" -framework "StoreKit" -framework "SystemConfiguration" -framework "UIKit"
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
PODS_ROOT = ${SRCROOT}/Pods

View File

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

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