[RELEASE] Merge beta into master (#1142)

This commit is contained in:
Diego Mello 2019-08-20 16:24:22 -03:00 committed by GitHub
parent 34dbfcde1e
commit 494890ad84
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1951 changed files with 113484 additions and 76281 deletions

View File

@ -1,9 +0,0 @@
{
"presets": ["module:metro-react-native-babel-preset"],
"plugins": [["@babel/plugin-proposal-decorators", { "legacy": true }]],
"env": {
"production": {
"plugins": ["transform-remove-console"]
}
}
}

View File

@ -106,8 +106,10 @@ jobs:
environment: environment:
# GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx4096m -XX:+HeapDumpOnOutOfMemoryError" # GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx4096m -XX:+HeapDumpOnOutOfMemoryError"
GRADLE_OPTS: -Xmx2048m -Dorg.gradle.daemon=false # GRADLE_OPTS: -Xmx2048m -Dorg.gradle.daemon=false
JVM_OPTS: -Xmx4096m # JVM_OPTS: -Xmx4096m
JAVA_OPTS: '-Xms512m -Xmx2g'
GRADLE_OPTS: '-Xmx3g -Dorg.gradle.daemon=false -Dorg.gradle.jvmargs="-Xmx2g -XX:+HeapDumpOnOutOfMemoryError"'
TERM: dumb TERM: dumb
BASH_ENV: "~/.nvm/nvm.sh" BASH_ENV: "~/.nvm/nvm.sh"
@ -133,7 +135,9 @@ jobs:
cd android cd android
echo -e "" > ./gradle.properties echo -e "" > ./gradle.properties
echo -e "android.enableAapt2=false" >> ./gradle.properties # echo -e "android.enableAapt2=false" >> ./gradle.properties
echo -e "android.useAndroidX=true" >> ./gradle.properties
echo -e "android.enableJetifier=true" >> ./gradle.properties
if [[ $KEYSTORE ]]; then if [[ $KEYSTORE ]]; then
echo $KEYSTORE_BASE64 | base64 --decode > ./app/$KEYSTORE echo $KEYSTORE_BASE64 | base64 --decode > ./app/$KEYSTORE
@ -154,6 +158,7 @@ jobs:
- run: - run:
name: Build Android App name: Build Android App
command: | command: |
npx jetify
cd android cd android
if [[ $KEYSTORE ]]; then if [[ $KEYSTORE ]]; then
./gradlew bundleRelease ./gradlew bundleRelease

View File

@ -46,6 +46,7 @@ module.exports = {
"jsx-quotes": [2, "prefer-single"], "jsx-quotes": [2, "prefer-single"],
"jsx-a11y/href-no-hash": 0, "jsx-a11y/href-no-hash": 0,
"import/prefer-default-export": 0, "import/prefer-default-export": 0,
"import/no-cycle": 0,
"camelcase": 0, "camelcase": 0,
"no-underscore-dangle": 0, "no-underscore-dangle": 0,
"no-return-assign": 0, "no-return-assign": 0,

View File

@ -60,13 +60,10 @@ Readme will guide you on how to config.
1) Jitsi integration 1) Jitsi integration
2) Notification Preferences 2) Notification Preferences
3) Two-way authentication 3) Two-way authentication
4) Authentication via SAML 4) Bugsnag
5) Authentication via Custom OAuth 5) Optional Analytics
6) Authentication via CAS 6) Typescript
7) Bugsnag 7) Prettier
8) Optional Analytics
9) Typescript
10) Prettier
## Features ## Features
| Feature | Status | | Feature | Status |
@ -89,8 +86,8 @@ Readme will guide you on how to config.
| 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 | ❌ |
@ -110,7 +107,7 @@ Readme will guide you on how to config.
| Accessibility (Advanced) | ❌ | | Accessibility (Advanced) | ❌ |
| Authentication via Meteor | ❌ | | Authentication via Meteor | ❌ |
| Authentication via Wordpress | ❌ | | Authentication via Wordpress | ❌ |
| Authentication via Custom OAuth | | | Authentication via Custom OAuth | |
| Add user to the room | ✅ | | Add user to the room | ✅ |
| Send message | ✅ | | Send message | ✅ |
| Authentication via Email | ✅ | | Authentication via Email | ✅ |

File diff suppressed because it is too large Load Diff

View File

@ -8,23 +8,13 @@
# - `buck install -r android/app` - compile, install and run application # - `buck install -r android/app` - compile, install and run application
# #
load(":build_defs.bzl", "create_aar_targets", "create_jar_targets")
lib_deps = [] lib_deps = []
for jarfile in glob(['libs/*.jar']): create_aar_targets(glob(["libs/*.aar"]))
name = 'jars__' + jarfile[jarfile.rindex('/') + 1: jarfile.rindex('.jar')]
lib_deps.append(':' + name)
prebuilt_jar(
name = name,
binary_jar = jarfile,
)
for aarfile in glob(['libs/*.aar']): create_jar_targets(glob(["libs/*.jar"]))
name = 'aars__' + aarfile[aarfile.rindex('/') + 1: aarfile.rindex('.aar')]
lib_deps.append(':' + name)
android_prebuilt_aar(
name = name,
aar = aarfile,
)
android_library( android_library(
name = "all-libs", name = "all-libs",

View File

@ -20,6 +20,9 @@ import com.android.build.OutputFile
* // the entry file for bundle generation * // the entry file for bundle generation
* entryFile: "index.android.js", * entryFile: "index.android.js",
* *
* // https://facebook.github.io/react-native/docs/performance#enable-the-ram-format
* bundleCommand: "ram-bundle",
*
* // whether to bundle JS and assets in debug mode * // whether to bundle JS and assets in debug mode
* bundleInDebug: false, * bundleInDebug: false,
* *
@ -76,7 +79,8 @@ import com.android.build.OutputFile
project.ext.react = [ project.ext.react = [
entryFile: "index.js", entryFile: "index.js",
iconFontNames: [ 'custom.ttf' ] iconFontNames: [ 'custom.ttf' ],
enableHermes: false, // clean and rebuild if changing
] ]
apply from: "../../node_modules/react-native/react.gradle" apply from: "../../node_modules/react-native/react.gradle"
@ -97,6 +101,27 @@ def enableSeparateBuildPerCPUArchitecture = false
*/ */
def enableProguardInReleaseBuilds = false def enableProguardInReleaseBuilds = false
/**
* The preferred build flavor of JavaScriptCore.
*
* For example, to use the international variant, you can use:
* `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
*
* The international variant includes ICU i18n library and necessary data
* allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
* give correct results when using with locales other than en-US. Note that
* this variant is about 6MiB larger per architecture than default.
*/
def jscFlavor = 'org.webkit:android-jsc:+'
/**
* Whether to enable the Hermes VM.
*
* This should be set on project.ext.react and mirrored here. If it is not set
* on project.ext.react, JavaScript will not be compiled to Hermes Bytecode
* and the benefits of using Hermes will therefore be sharply reduced.
*/
def enableHermes = project.ext.react.get("enableHermes", false);
android { android {
compileSdkVersion rootProject.ext.compileSdkVersion compileSdkVersion rootProject.ext.compileSdkVersion
@ -110,15 +135,10 @@ 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.17.0" versionName "1.18.0"
vectorDrawables.useSupportLibrary = true vectorDrawables.useSupportLibrary = true
} }
packagingOptions {
pickFirst '**/libjsc.so'
pickFirst '**/libc++_shared.so'
}
signingConfigs { signingConfigs {
release { release {
if (project.hasProperty('KEYSTORE')) { if (project.hasProperty('KEYSTORE')) {
@ -148,8 +168,8 @@ android {
applicationVariants.all { variant -> applicationVariants.all { variant ->
variant.outputs.each { output -> variant.outputs.each { output ->
// For each separate APK per architecture, set a unique version code as described here: // For each separate APK per architecture, set a unique version code as described here:
// http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits // https://developer.android.com/studio/build/configure-apk-splits.html
def versionCodes = ["armeabi-v7a":1, "x86":2, "arm64-v8a": 3, "x86_64": 4] def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
def abi = output.getFilter(OutputFile.ABI) def abi = output.getFilter(OutputFile.ABI)
if (abi != null) { // null for the universal-debug, universal-release variants if (abi != null) { // null for the universal-debug, universal-release variants
output.versionCodeOverride = output.versionCodeOverride =
@ -158,6 +178,15 @@ android {
} }
} }
packagingOptions {
pickFirst '**/armeabi-v7a/libc++_shared.so'
pickFirst '**/x86/libc++_shared.so'
pickFirst '**/arm64-v8a/libc++_shared.so'
pickFirst '**/x86_64/libc++_shared.so'
pickFirst '**/x86/libjsc.so'
pickFirst '**/armeabi-v7a/libjsc.so'
}
bundle { bundle {
language { language {
enableSplit = false enableSplit = false
@ -173,46 +202,24 @@ android {
dependencies { dependencies {
addUnimodulesDependencies() addUnimodulesDependencies()
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-webview')
implementation project(':react-native-orientation-locker')
implementation project(':react-native-splash-screen')
implementation project(':react-native-screens')
implementation project(':react-native-action-sheet')
implementation(project(":react-native-device-info"), {
exclude group: "com.google.android.gms"
})
implementation project(':react-native-gesture-handler')
implementation project(':react-native-image-crop-picker')
implementation project(':react-native-localize')
implementation project(':react-native-audio')
implementation project(":reactnativekeyboardinput")
implementation project(':react-native-video')
implementation project(':react-native-vector-icons')
implementation project(':react-native-fast-image')
implementation project(':realm')
implementation project(':reactnativenotifications') implementation project(':reactnativenotifications')
implementation project(":reactnativekeyboardinput")
implementation fileTree(dir: "libs", include: ["*.jar"]) implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "com.android.support:appcompat-v7:${ rootProject.ext.supportLibVersion }"
implementation "com.android.support:support-v4:${ rootProject.ext.supportLibVersion }"
implementation "com.android.support:customtabs:${ rootProject.ext.supportLibVersion }"
implementation "com.android.support:design:${ rootProject.ext.supportLibVersion }"
implementation "com.facebook.react:react-native:+" // From node_modules implementation "com.facebook.react:react-native:+" // From node_modules
implementation 'com.facebook.fresco:fresco:1.10.0'
implementation 'com.facebook.fresco:animated-gif:1.10.0'
implementation 'com.facebook.fresco:animated-webp:1.10.0'
implementation 'com.facebook.fresco:webpsupport:1.10.0'
implementation "com.google.android.gms:play-services-base:16.1.0"
implementation "com.google.firebase:firebase-messaging:18.0.0" implementation "com.google.firebase:firebase-messaging:18.0.0"
implementation "com.google.firebase:firebase-core:16.0.9" implementation "com.google.firebase:firebase-core:16.0.9"
implementation "com.google.firebase:firebase-perf:16.2.5" implementation "com.google.firebase:firebase-perf:17.0.2"
implementation('com.crashlytics.sdk.android:crashlytics:2.9.5@aar') { implementation('com.crashlytics.sdk.android:crashlytics:2.9.9@aar') {
transitive = true transitive = true
} }
if (enableHermes) {
def hermesPath = "../../node_modules/hermesvm/android/";
debugImplementation files(hermesPath + "hermes-debug.aar")
releaseImplementation files(hermesPath + "hermes-release.aar")
} else {
implementation jscFlavor
}
} }
// Run this once to be able to run the application with BUCK // Run this once to be able to run the application with BUCK
@ -223,3 +230,4 @@ task copyDownloadableDepsToLibs(type: Copy) {
} }
apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.gms.google-services'
apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)

View File

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

View File

@ -8,91 +8,3 @@
# http://developer.android.com/guide/developing/tools/proguard.html # http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here: # Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Disabling obfuscation is useful if you collect stack traces from production crashes
# (unless you are using a system that supports de-obfuscate the stack traces).
# -dontobfuscate
# React Native
# Keep our interfaces so they can be used by other ProGuard rules.
# See http://sourceforge.net/p/proguard/bugs/466/
-keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip
-keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters
-keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip
# Do not strip any method/class that is annotated with @DoNotStrip
-keep @com.facebook.proguard.annotations.DoNotStrip class *
-keep @com.facebook.common.internal.DoNotStrip class *
-keepclassmembers class * {
@com.facebook.proguard.annotations.DoNotStrip *;
@com.facebook.common.internal.DoNotStrip *;
}
-keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * {
void set*(***);
*** get*();
}
-keep class * extends com.facebook.react.bridge.JavaScriptModule { *; }
-keep class * extends com.facebook.react.bridge.NativeModule { *; }
-keepclassmembers,includedescriptorclasses class * { native <methods>; }
-keepclassmembers class * { @com.facebook.react.uimanager.UIProp <fields>; }
-keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp <methods>; }
-keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup <methods>; }
-dontwarn com.facebook.react.**
-keep,includedescriptorclasses class com.facebook.react.bridge.** { *; }
# TextLayoutBuilder uses a non-public Android constructor within StaticLayout.
# See libs/proxy/src/main/java/com/facebook/fbui/textlayoutbuilder/proxy for details.
-dontwarn android.text.StaticLayout
# okhttp
-keepattributes Signature
-keepattributes *Annotation*
-keep class okhttp3.** { *; }
-keep interface okhttp3.** { *; }
-dontwarn okhttp3.**
# okio
-keep class sun.misc.Unsafe { *; }
-dontwarn java.nio.file.*
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
-dontwarn okio.**
# Fresco
# Keep our interfaces so they can be used by other ProGuard rules.
# See http://sourceforge.net/p/proguard/bugs/466/
-keep,allowobfuscation @interface com.facebook.soloader.DoNotOptimize
# Do not strip any method/class that is annotated with @DoNotOptimize
-keep @com.facebook.soloader.DoNotOptimize class *
-keepclassmembers class * {
@com.facebook.soloader.DoNotOptimize *;
}
# Keep native methods
-keepclassmembers class * {
native <methods>;
}
# For Fabric to properly de-obfuscate your crash reports, you need to remove this line from your ProGuard config:
# -printmapping mapping.txt
-keepattributes SourceFile,LineNumberTable
-keep public class * extends java.lang.Exception
-keep class com.crashlytics.** { *; }
-dontwarn com.crashlytics.**
-dontwarn javax.annotation.**
-dontwarn com.facebook.infer.**

View File

@ -36,6 +36,7 @@ public class MainActivity extends ReactFragmentActivity {
}; };
} }
// from react-native-orientation
@Override @Override
public void onConfigurationChanged(Configuration newConfig) { public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig); super.onConfigurationChanged(newConfig);

View File

@ -1,50 +1,35 @@
package chat.rocket.reactnative; package chat.rocket.reactnative;
import android.app.Application; import android.app.Application;
import android.util.Log;
import android.content.Context;
import android.os.Bundle;
import com.facebook.react.PackageList;
import com.facebook.hermes.reactexecutor.HermesExecutorFactory;
import com.facebook.react.bridge.JavaScriptExecutorFactory;
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.fabric.crashlytics.RNFirebaseCrashlyticsPackage;
import io.invertase.firebase.analytics.RNFirebaseAnalyticsPackage;
import io.invertase.firebase.perf.RNFirebasePerformancePackage;
import com.reactnativecommunity.webview.RNCWebViewPackage;
import org.wonday.orientation.OrientationPackage;
import org.devio.rn.splashscreen.SplashScreenReactPackage;
import com.facebook.react.ReactNativeHost; import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage; import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.soloader.SoLoader; import com.facebook.soloader.SoLoader;
import com.reactcommunity.rnlocalize.RNLocalizePackage;
import com.reactnative.ivpusic.imagepicker.PickerPackage;
import com.brentvatne.react.ReactVideoPackage;
import com.dylanvann.fastimage.FastImageViewPackage;
import com.oblador.vectoricons.VectorIconsPackage;
import com.rnim.rn.audio.ReactNativeAudioPackage;
import com.wix.reactnativekeyboardinput.KeyboardInputPackage;
import com.wix.reactnativenotifications.RNNotificationsPackage;
import com.wix.reactnativenotifications.core.AppLaunchHelper;
import com.wix.reactnativenotifications.core.AppLifecycleFacade;
import com.wix.reactnativenotifications.core.JsIOHelper;
import com.wix.reactnativenotifications.core.notification.INotificationsApplication;
import com.wix.reactnativenotifications.core.notification.IPushNotification;
import com.swmansion.gesturehandler.react.RNGestureHandlerPackage;
import com.learnium.RNDeviceInfo.RNDeviceInfo;
import com.actionsheet.ActionSheetPackage;
import io.realm.react.RealmReactPackage;
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;
import org.unimodules.adapters.react.ModuleRegistryAdapter; import org.unimodules.adapters.react.ModuleRegistryAdapter;
import org.unimodules.adapters.react.ReactModuleRegistryProvider; import org.unimodules.adapters.react.ReactModuleRegistryProvider;
import org.unimodules.core.interfaces.SingletonModule; import org.unimodules.core.interfaces.SingletonModule;
import android.content.Context; import com.wix.reactnativenotifications.RNNotificationsPackage;
import android.os.Bundle; import com.wix.reactnativenotifications.core.AppLaunchHelper;
import com.wix.reactnativenotifications.core.AppLifecycleFacade;
import com.wix.reactnativenotifications.core.JsIOHelper;
import com.wix.reactnativenotifications.core.notification.INotificationsApplication;
import com.wix.reactnativenotifications.core.notification.IPushNotification;
import com.wix.reactnativekeyboardinput.KeyboardInputPackage;
import io.invertase.firebase.fabric.crashlytics.RNFirebaseCrashlyticsPackage;
import io.invertase.firebase.analytics.RNFirebaseAnalyticsPackage;
import io.invertase.firebase.perf.RNFirebasePerformancePackage;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@ -61,33 +46,15 @@ public class MainApplication extends Application implements ReactApplication, IN
@Override @Override
protected List<ReactPackage> getPackages() { protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList( @SuppressWarnings("UnnecessaryLocalVariable")
new MainReactPackage(), List<ReactPackage> packages = new PackageList(this).getPackages();
new DocumentPickerPackage(), packages.add(new RNFirebaseCrashlyticsPackage());
new RNFirebasePackage(), packages.add(new RNFirebaseAnalyticsPackage());
new RNFirebaseCrashlyticsPackage(), packages.add(new RNFirebasePerformancePackage());
new RNFirebaseAnalyticsPackage(), packages.add(new KeyboardInputPackage(MainApplication.this));
new RNFirebasePerformancePackage(), packages.add(new RNNotificationsPackage(MainApplication.this));
new RNCWebViewPackage(), packages.add(new ModuleRegistryAdapter(mModuleRegistryProvider));
new OrientationPackage(), return packages;
new SplashScreenReactPackage(),
new SharePackage(),
new RNFetchBlobPackage(),
new RNGestureHandlerPackage(),
new RNScreensPackage(),
new ActionSheetPackage(),
new RNDeviceInfo(),
new PickerPackage(),
new VectorIconsPackage(),
new RealmReactPackage(),
new ReactVideoPackage(),
new ReactNativeAudioPackage(),
new KeyboardInputPackage(MainApplication.this),
new FastImageViewPackage(),
new RNLocalizePackage(),
new RNNotificationsPackage(MainApplication.this),
new ModuleRegistryAdapter(mModuleRegistryProvider)
);
} }
@Override @Override

View File

@ -1,6 +1,7 @@
<resources> <resources>
<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>
<item name="android:textColor">#000000</item>
</style> </style>
<style name="Share.Window" parent="android:Theme"> <style name="Share.Window" parent="android:Theme">

View File

@ -5,8 +5,11 @@ buildscript {
minSdkVersion = 21 minSdkVersion = 21
compileSdkVersion = 28 compileSdkVersion = 28
targetSdkVersion = 28 targetSdkVersion = 28
supportLibVersion = "28.0.0"
glideVersion = "4.9.0" glideVersion = "4.9.0"
// googlePlayServicesVersion = "17.0.0"
// supportLibVersion = "1.0.2"
// mediaCompatVersion = '1.0.1'
// supportV4Version = '1.0.0'
} }
repositories { repositories {
mavenLocal() mavenLocal()
@ -17,10 +20,10 @@ buildscript {
} }
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.3.1' classpath 'com.android.tools.build:gradle:3.4.1'
classpath 'com.google.gms:google-services:4.2.0' classpath 'com.google.gms:google-services:4.2.0'
classpath 'io.fabric.tools:gradle:1.25.4' classpath 'io.fabric.tools:gradle:1.28.1'
classpath 'com.google.firebase:firebase-plugins:1.1.5' classpath 'com.google.firebase:perf-plugin:1.2.1'
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // in the individual module build.gradle files
@ -30,30 +33,33 @@ buildscript {
allprojects { allprojects {
repositories { repositories {
mavenLocal() mavenLocal()
google()
jcenter()
maven { url "https://jitpack.io" }
maven { maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url "$rootDir/../node_modules/react-native/android" url("$rootDir/../node_modules/react-native/android")
} }
maven { maven {
// Local Maven repo containing AARs with JSC library built for Android // Android JSC is installed from npm
url "$rootDir/../node_modules/jsc-android/dist" url("$rootDir/../node_modules/jsc-android/dist")
} }
google()
jcenter()
maven { url 'https://maven.google.com' }
maven { url "https://jitpack.io" }
} }
} }
subprojects { subproject -> // subprojects { subproject ->
afterEvaluate { // afterEvaluate {
if ((subproject.plugins.hasPlugin('android') || subproject.plugins.hasPlugin('android-library'))) { // if ((subproject.plugins.hasPlugin('android') || subproject.plugins.hasPlugin('android-library'))) {
android { // android {
compileSdkVersion 28 // compileSdkVersion 28
buildToolsVersion "28.0.3" // buildToolsVersion "28.0.3"
defaultConfig { // defaultConfig {
targetSdkVersion 28 // targetSdkVersion 28
} // }
} // }
} // }
} // }
} // }

View File

@ -16,6 +16,9 @@
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true # org.gradle.parallel=true
android.enableAapt2=false # commenting this makes notifications to stop working # android.enableAapt2=false # commenting this makes notifications to stop working
android.useDeprecatedNdk=true # android.useDeprecatedNdk=true
org.gradle.jvmargs=-Xmx2048M -XX\:MaxHeapSize\=32g
android.useAndroidX=true
android.enableJetifier=true
VERSIONCODE=999999999 VERSIONCODE=999999999

View File

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

126
android/gradlew vendored
View File

@ -1,4 +1,20 @@
#!/usr/bin/env bash #!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
############################################################################## ##############################################################################
## ##
@ -6,47 +22,6 @@
## ##
############################################################################## ##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME # Attempt to set APP_HOME
# Resolve links: $0 may be a link # Resolve links: $0 may be a link
PRG="$0" PRG="$0"
@ -61,9 +36,49 @@ while [ -h "$PRG" ] ; do
fi fi
done done
SAVED="`pwd`" SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&- cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`" APP_HOME="`pwd -P`"
cd "$SAVED" >&- cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=''
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@ -90,7 +105,7 @@ location of your Java installation."
fi fi
# Increase the maximum file descriptors if we can. # Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n` MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
@ -114,6 +129,7 @@ fi
if $cygwin ; then if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"` APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath # We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
@ -154,11 +170,19 @@ if $cygwin ; then
esac esac
fi fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules # Escape application args
function splitJvmOpts() { save () {
JVM_OPTS=("$@") for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
} }
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS APP_ARGS=$(save "$@")
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" # Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

30
android/gradlew.bat vendored
View File

@ -1,3 +1,19 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem http://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off @if "%DEBUG%" == "" @echo off
@rem ########################################################################## @rem ##########################################################################
@rem @rem
@ -8,14 +24,14 @@
@rem Set local scope for the variables with windows NT shell @rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0 set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=. if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0 set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME% set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe @rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome if defined JAVA_HOME goto findJavaFromJavaHome
@ -46,10 +62,9 @@ echo location of your Java installation.
goto fail goto fail
:init :init
@rem Get command-line arguments, handling Windowz variants @rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args :win9xME_args
@rem Slurp the command line arguments. @rem Slurp the command line arguments.
@ -60,11 +75,6 @@ set _SKIP=2
if "x%~1" == "x" goto execute if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%* set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute :execute
@rem Setup the command line @rem Setup the command line

View File

@ -1,8 +0,0 @@
keystore(
name = "debug",
properties = "debug.keystore.properties",
store = "debug.keystore",
visibility = [
"PUBLIC",
],
)

View File

@ -1,4 +0,0 @@
key.store=debug.keystore
key.alias=androiddebugkey
key.store.password=android
key.alias.password=android

View File

@ -2,44 +2,9 @@ apply from: '../node_modules/react-native-unimodules/gradle.groovy'
includeUnimodulesProjects() includeUnimodulesProjects()
rootProject.name = 'RocketChatRN' rootProject.name = 'RocketChatRN'
include ':react-native-document-picker' include ':reactnativenotifications'
project(':react-native-document-picker').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-document-picker/android') project(':reactnativenotifications').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-notifications/android/app')
include ':react-native-firebase'
project(':react-native-firebase').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-firebase/android')
include ':react-native-webview'
project(':react-native-webview').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-webview/android')
include ':react-native-orientation-locker'
project(':react-native-orientation-locker').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-orientation-locker/android')
include ':react-native-splash-screen'
project(':react-native-splash-screen').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-splash-screen/android')
include ':react-native-screens'
project(':react-native-screens').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-screens/android')
include ':react-native-action-sheet'
project(':react-native-action-sheet').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-action-sheet/android')
include ':react-native-device-info'
project(':react-native-device-info').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-device-info/android')
include ':react-native-gesture-handler'
project(':react-native-gesture-handler').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-gesture-handler/android')
include ':react-native-image-crop-picker'
project(':react-native-image-crop-picker').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-image-crop-picker/android')
include ':react-native-localize'
project(':react-native-localize').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-localize/android')
include ':react-native-fast-image'
project(':react-native-fast-image').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-fast-image/android')
include ':react-native-audio'
project(':react-native-audio').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-audio/android')
include ':reactnativekeyboardinput' include ':reactnativekeyboardinput'
project(':reactnativekeyboardinput').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-keyboard-input/lib/android') project(':reactnativekeyboardinput').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-keyboard-input/lib/android')
include ':react-native-video' apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
project(':react-native-video').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-video/android') include ':app'
include ':react-native-vector-icons'
project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android')
include ':realm'
project(':realm').projectDir = new File(rootProject.projectDir, '../node_modules/realm/android')
include ':reactnativenotifications'
project(':reactnativenotifications').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-notifications/android')
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')

3
app/constants/links.js Normal file
View File

@ -0,0 +1,3 @@
export const PLAY_MARKET_LINK = 'https://play.google.com/store/apps/details?id=chat.rocket.reactnative';
export const APP_STORE_LINK = 'https://itunes.apple.com/app/rocket-chat-experimental/id1272915472?ls=1&mt=8';
export const LICENSE_LINK = 'https://github.com/RocketChat/Rocket.Chat.ReactNative/blob/develop/LICENSE';

View File

@ -11,6 +11,9 @@ export default {
Accounts_PasswordPlaceholder: { Accounts_PasswordPlaceholder: {
type: 'valueAsString' type: 'valueAsString'
}, },
Accounts_PasswordReset: {
type: 'valueAsBoolean'
},
CROWD_Enable: { CROWD_Enable: {
type: 'valueAsBoolean' type: 'valueAsBoolean'
}, },
@ -79,5 +82,11 @@ export default {
}, },
AutoTranslate_Enabled: { AutoTranslate_Enabled: {
type: 'valueAsBoolean' type: 'valueAsBoolean'
},
CAS_enabled: {
type: 'valueAsBoolean'
},
CAS_login_url: {
type: 'valueAsString'
} }
}; };

View File

@ -23,9 +23,7 @@ const renderEmoji = (emoji, size, baseUrl) => {
); );
}; };
class EmojiCategory extends React.Component {
@responsive
export default class EmojiCategory extends React.Component {
static propTypes = { static propTypes = {
baseUrl: PropTypes.string.isRequired, baseUrl: PropTypes.string.isRequired,
emojis: PropTypes.any, emojis: PropTypes.any,
@ -79,3 +77,5 @@ export default class EmojiCategory extends React.Component {
); );
} }
} }
export default responsive(EmojiCategory);

View File

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import HeaderButtons, { HeaderButton, Item } from 'react-navigation-header-buttons'; import { HeaderButtons, HeaderButton, Item } from 'react-navigation-header-buttons';
import { CustomIcon } from '../lib/Icons'; import { CustomIcon } from '../lib/Icons';
import { isIOS } from '../utils/deviceInfo'; import { isIOS } from '../utils/deviceInfo';

View File

@ -24,28 +24,7 @@ import { getMessageTranslation } from './message/utils';
import { LISTENER } from './Toast'; import { LISTENER } from './Toast';
import EventEmitter from '../utils/events'; import EventEmitter from '../utils/events';
@connect( class MessageActions extends React.Component {
state => ({
actionMessage: state.messages.actionMessage,
Message_AllowDeleting: state.settings.Message_AllowDeleting,
Message_AllowDeleting_BlockDeleteInMinutes: state.settings.Message_AllowDeleting_BlockDeleteInMinutes,
Message_AllowEditing: state.settings.Message_AllowEditing,
Message_AllowEditing_BlockEditInMinutes: state.settings.Message_AllowEditing_BlockEditInMinutes,
Message_AllowPinning: state.settings.Message_AllowPinning,
Message_AllowStarring: state.settings.Message_AllowStarring,
Message_Read_Receipt_Store_Users: state.settings.Message_Read_Receipt_Store_Users
}),
dispatch => ({
actionsHide: () => dispatch(actionsHideAction()),
deleteRequest: message => dispatch(deleteRequestAction(message)),
editInit: message => dispatch(editInitAction(message)),
toggleStarRequest: message => dispatch(toggleStarRequestAction(message)),
togglePinRequest: message => dispatch(togglePinRequestAction(message)),
toggleReactionPicker: message => dispatch(toggleReactionPickerAction(message)),
replyInit: (message, mention) => dispatch(replyInitAction(message, mention))
})
)
export default class MessageActions extends React.Component {
static propTypes = { static propTypes = {
actionsHide: PropTypes.func.isRequired, actionsHide: PropTypes.func.isRequired,
room: PropTypes.object.isRequired, room: PropTypes.object.isRequired,
@ -409,3 +388,26 @@ export default class MessageActions extends React.Component {
); );
} }
} }
const mapStateToProps = state => ({
actionMessage: state.messages.actionMessage,
Message_AllowDeleting: state.settings.Message_AllowDeleting,
Message_AllowDeleting_BlockDeleteInMinutes: state.settings.Message_AllowDeleting_BlockDeleteInMinutes,
Message_AllowEditing: state.settings.Message_AllowEditing,
Message_AllowEditing_BlockEditInMinutes: state.settings.Message_AllowEditing_BlockEditInMinutes,
Message_AllowPinning: state.settings.Message_AllowPinning,
Message_AllowStarring: state.settings.Message_AllowStarring,
Message_Read_Receipt_Store_Users: state.settings.Message_Read_Receipt_Store_Users
});
const mapDispatchToProps = dispatch => ({
actionsHide: () => dispatch(actionsHideAction()),
deleteRequest: message => dispatch(deleteRequestAction(message)),
editInit: message => dispatch(editInitAction(message)),
toggleStarRequest: message => dispatch(toggleStarRequestAction(message)),
togglePinRequest: message => dispatch(togglePinRequestAction(message)),
toggleReactionPicker: message => dispatch(toggleReactionPickerAction(message)),
replyInit: (message, mention) => dispatch(replyInitAction(message, mention))
});
export default connect(mapStateToProps, mapDispatchToProps)(MessageActions);

View File

@ -48,11 +48,7 @@ const styles = StyleSheet.create({
} }
}); });
@connect(state => ({ class ReplyPreview extends Component {
Message_TimeFormat: state.settings.Message_TimeFormat,
baseUrl: state.settings.Site_Url || state.server ? state.server.server : ''
}))
export default class ReplyPreview extends Component {
static propTypes = { static propTypes = {
message: PropTypes.object.isRequired, message: PropTypes.object.isRequired,
Message_TimeFormat: PropTypes.string.isRequired, Message_TimeFormat: PropTypes.string.isRequired,
@ -89,3 +85,10 @@ export default class ReplyPreview extends Component {
); );
} }
} }
const mapStateToProps = state => ({
Message_TimeFormat: state.settings.Message_TimeFormat,
baseUrl: state.settings.Site_Url || state.server ? state.server.server : ''
});
export default connect(mapStateToProps)(ReplyPreview);

View File

@ -104,12 +104,7 @@ const styles = StyleSheet.create({
}); });
@responsive class UploadModal extends Component {
@connect(state => ({
FileUpload_MediaTypeWhiteList: state.settings.FileUpload_MediaTypeWhiteList,
FileUpload_MaxFileSize: state.settings.FileUpload_MaxFileSize
}))
export default class UploadModal extends Component {
static propTypes = { static propTypes = {
isVisible: PropTypes.bool, isVisible: PropTypes.bool,
file: PropTypes.object, file: PropTypes.object,
@ -336,3 +331,10 @@ export default class UploadModal extends Component {
); );
} }
} }
const mapStateToProps = state => ({
FileUpload_MediaTypeWhiteList: state.settings.FileUpload_MediaTypeWhiteList,
FileUpload_MaxFileSize: state.settings.FileUpload_MaxFileSize
});
export default responsive(connect(mapStateToProps)(UploadModal));

View File

@ -9,15 +9,7 @@ import database from '../lib/realm';
import protectedFunction from '../lib/methods/helpers/protectedFunction'; import protectedFunction from '../lib/methods/helpers/protectedFunction';
import I18n from '../i18n'; import I18n from '../i18n';
@connect( class MessageErrorActions extends React.Component {
state => ({
actionMessage: state.messages.actionMessage
}),
dispatch => ({
errorActionsHide: () => dispatch(errorActionsHideAction())
})
)
export default class MessageErrorActions extends React.Component {
static propTypes = { static propTypes = {
errorActionsHide: PropTypes.func.isRequired, errorActionsHide: PropTypes.func.isRequired,
actionMessage: PropTypes.object actionMessage: PropTypes.object
@ -81,3 +73,13 @@ export default class MessageErrorActions extends React.Component {
); );
} }
} }
const mapStateToProps = state => ({
actionMessage: state.messages.actionMessage
});
const mapDispatchToProps = dispatch => ({
errorActionsHide: () => dispatch(errorActionsHideAction())
});
export default connect(mapStateToProps, mapDispatchToProps)(MessageErrorActions);

View File

@ -5,10 +5,7 @@ import { connect } from 'react-redux';
import Status from './Status'; import Status from './Status';
import database, { safeAddListener } from '../../lib/realm'; import database, { safeAddListener } from '../../lib/realm';
@connect(state => ({ class StatusContainer extends React.PureComponent {
offline: !state.meteor.connected
}))
export default class StatusContainer extends React.PureComponent {
static propTypes = { static propTypes = {
id: PropTypes.string, id: PropTypes.string,
style: PropTypes.any, style: PropTypes.any,
@ -53,3 +50,9 @@ export default class StatusContainer extends React.PureComponent {
return <Status size={size} style={style} status={this.status} />; return <Status size={size} style={style} status={this.status} />;
} }
} }
const mapStateToProps = state => ({
offline: !state.meteor.connected
});
export default connect(mapStateToProps)(StatusContainer);

View File

@ -148,7 +148,7 @@ const Markdown = React.memo(({
>{m} >{m}
</MarkdownRenderer> </MarkdownRenderer>
); );
}, (prevProps, nextProps) => prevProps.msg === nextProps.msg); });
Markdown.propTypes = { Markdown.propTypes = {
msg: PropTypes.string, msg: PropTypes.string,

View File

@ -62,9 +62,9 @@ const OutsideStack = createStackNavigator({
defaultNavigationOptions: defaultHeader defaultNavigationOptions: defaultHeader
}); });
const OAuthStack = createStackNavigator({ const AuthenticationWebViewStack = createStackNavigator({
OAuthView: { AuthenticationWebView: {
getScreen: () => require('./views/OAuthView').default getScreen: () => require('./views/AuthenticationWebView').default
} }
}, { }, {
defaultNavigationOptions: defaultHeader defaultNavigationOptions: defaultHeader
@ -72,7 +72,7 @@ const OAuthStack = createStackNavigator({
const OutsideStackModal = createStackNavigator({ const OutsideStackModal = createStackNavigator({
OutsideStack, OutsideStack,
OAuthStack AuthenticationWebViewStack
}, },
{ {
mode: 'modal', mode: 'modal',

View File

@ -1,18 +1,16 @@
import { createStore as reduxCreateStore, applyMiddleware, compose } from 'redux'; import { createStore, applyMiddleware, compose } from 'redux';
import Reactotron from 'reactotron-react-native';
import createSagaMiddleware from 'redux-saga'; import createSagaMiddleware from 'redux-saga';
import applyAppStateListener from 'redux-enhancer-react-native-appstate'; import applyAppStateListener from 'redux-enhancer-react-native-appstate';
import reducers from '../reducers'; import reducers from '../reducers';
import sagas from '../sagas'; import sagas from '../sagas';
const createStore = __DEV__ ? Reactotron.createStore : reduxCreateStore;
let sagaMiddleware; let sagaMiddleware;
let enhancers; let enhancers;
if (__DEV__) { if (__DEV__) {
/* eslint-disable global-require */
const reduxImmutableStateInvariant = require('redux-immutable-state-invariant').default(); const reduxImmutableStateInvariant = require('redux-immutable-state-invariant').default();
const Reactotron = require('reactotron-react-native').default;
sagaMiddleware = createSagaMiddleware({ sagaMiddleware = createSagaMiddleware({
sagaMonitor: Reactotron.createSagaMonitor() sagaMonitor: Reactotron.createSagaMonitor()
}); });
@ -20,7 +18,8 @@ if (__DEV__) {
enhancers = compose( enhancers = compose(
applyAppStateListener(), applyAppStateListener(),
applyMiddleware(reduxImmutableStateInvariant), applyMiddleware(reduxImmutableStateInvariant),
applyMiddleware(sagaMiddleware) applyMiddleware(sagaMiddleware),
Reactotron.createEnhancer()
); );
} else { } else {
sagaMiddleware = createSagaMiddleware(); sagaMiddleware = createSagaMiddleware();
@ -33,11 +32,4 @@ if (__DEV__) {
const store = createStore(reducers, enhancers); const store = createStore(reducers, enhancers);
sagaMiddleware.run(sagas); sagaMiddleware.run(sagas);
if (module.hot && typeof module.hot.accept === 'function') {
module.hot.accept(() => {
store.replaceReducer(require('../reducers').default);
sagaMiddleware.run(require('../sagas').default);
});
}
export default store; export default store;

View File

@ -11,38 +11,14 @@ const removeListener = listener => listener.stop();
export default function subscribeRoom({ rid }) { export default function subscribeRoom({ rid }) {
let promises; let promises;
let timer = null;
let connectedListener; let connectedListener;
let disconnectedListener; let disconnectedListener;
let notifyRoomListener; let notifyRoomListener;
let messageReceivedListener; let messageReceivedListener;
const typingTimeouts = {}; const typingTimeouts = {};
const loop = () => {
if (timer) {
return;
}
timer = setTimeout(() => {
try {
clearTimeout(timer);
timer = false;
this.loadMissedMessages({ rid });
loop();
} catch (e) {
loop();
}
}, 5000);
};
const handleConnected = () => { const handleConnection = () => {
this.loadMissedMessages({ rid }); this.loadMissedMessages({ rid });
clearTimeout(timer);
timer = false;
};
const handleDisconnected = () => {
if (this.sdk.userId) {
loop();
}
}; };
const getUserTyping = username => ( const getUserTyping = username => (
@ -176,8 +152,6 @@ export default function subscribeRoom({ rid }) {
messageReceivedListener.then(removeListener); messageReceivedListener.then(removeListener);
messageReceivedListener = false; messageReceivedListener = false;
} }
clearTimeout(timer);
timer = false;
Object.keys(typingTimeouts).forEach((key) => { Object.keys(typingTimeouts).forEach((key) => {
if (typingTimeouts[key]) { if (typingTimeouts[key]) {
clearTimeout(typingTimeouts[key]); clearTimeout(typingTimeouts[key]);
@ -190,8 +164,8 @@ export default function subscribeRoom({ rid }) {
}); });
}; };
connectedListener = this.sdk.onStreamData('connected', handleConnected); connectedListener = this.sdk.onStreamData('connected', handleConnection);
disconnectedListener = this.sdk.onStreamData('close', handleDisconnected); disconnectedListener = this.sdk.onStreamData('close', handleConnection);
notifyRoomListener = this.sdk.onStreamData('stream-notify-room', handleNotifyRoomReceived); notifyRoomListener = this.sdk.onStreamData('stream-notify-room', handleNotifyRoomReceived);
messageReceivedListener = this.sdk.onStreamData('stream-room-messages', handleMessageReceived); messageReceivedListener = this.sdk.onStreamData('stream-room-messages', handleMessageReceived);

View File

@ -16,29 +16,8 @@ let streamListener;
let subServer; let subServer;
export default function subscribeRooms() { export default function subscribeRooms() {
let timer = null; const handleConnection = () => {
const loop = () => {
if (timer) {
return;
}
timer = setTimeout(() => {
clearTimeout(timer);
timer = false;
store.dispatch(roomsRequest()); store.dispatch(roomsRequest());
loop();
}, 5000);
};
const handleConnected = () => {
store.dispatch(roomsRequest());
clearTimeout(timer);
timer = false;
};
const handleDisconnected = () => {
if (this.sdk.userId) {
loop();
}
}; };
const handleStreamMessageReceived = protectedFunction((ddpMessage) => { const handleStreamMessageReceived = protectedFunction((ddpMessage) => {
@ -145,12 +124,10 @@ export default function subscribeRooms() {
streamListener.then(removeListener); streamListener.then(removeListener);
streamListener = false; streamListener = false;
} }
clearTimeout(timer);
timer = false;
}; };
connectedListener = this.sdk.onStreamData('connected', handleConnected); connectedListener = this.sdk.onStreamData('connected', handleConnection);
disconnectedListener = this.sdk.onStreamData('close', handleDisconnected); disconnectedListener = this.sdk.onStreamData('close', handleConnection);
streamListener = this.sdk.onStreamData('stream-notify-user', handleStreamMessageReceived); streamListener = this.sdk.onStreamData('stream-notify-user', handleStreamMessageReceived);
try { try {

View File

@ -297,7 +297,7 @@ const RocketChat = {
} }
}, },
async loginOAuth(params) { async loginOAuthOrSso(params) {
try { try {
const result = await this.login(params); const result = await this.login(params);
reduxStore.dispatch(loginRequest({ resume: result.token })); reduxStore.dispatch(loginRequest({ resume: result.token }));
@ -776,25 +776,50 @@ const RocketChat = {
}, },
async getLoginServices(server) { async getLoginServices(server) {
try { try {
let loginServicesFilter = []; let loginServices = [];
const loginServicesResult = await fetch(`${ server }/api/v1/settings.oauth`).then(response => response.json()); const loginServicesResult = await fetch(`${ server }/api/v1/settings.oauth`).then(response => response.json());
// TODO: remove this after SAML and custom oauth
const availableOAuth = ['facebook', 'github', 'gitlab', 'google', 'linkedin', 'meteor-developer', 'twitter'];
if (loginServicesResult.success && loginServicesResult.services.length > 0) { if (loginServicesResult.success && loginServicesResult.services.length > 0) {
const { services } = loginServicesResult; const { services } = loginServicesResult;
loginServicesFilter = services.filter(item => availableOAuth.includes(item.name)); loginServices = services;
const loginServicesReducer = loginServicesFilter.reduce((ret, item) => {
ret[item.name] = item; const loginServicesReducer = loginServices.reduce((ret, item) => {
const name = item.name || item.buttonLabelText || item.service;
const authType = this._determineAuthType(item);
if (authType !== 'not_supported') {
ret[name] = { ...item, name, authType };
}
return ret; return ret;
}, {}); }, {});
reduxStore.dispatch(setLoginServices(loginServicesReducer)); reduxStore.dispatch(setLoginServices(loginServicesReducer));
} }
return Promise.resolve(loginServicesFilter.length); return Promise.resolve(loginServices.length);
} catch (error) { } catch (error) {
console.warn(error); console.warn(error);
return Promise.reject(); return Promise.reject();
} }
}, },
_determineAuthType(services) {
const { name, custom, service } = services;
if (custom) {
return 'oauth_custom';
}
if (service === 'saml') {
return 'saml';
}
if (service === 'cas') {
return 'cas';
}
// TODO: remove this after other oauth providers are implemented. e.g. Drupal, github_enterprise
const availableOAuth = ['facebook', 'github', 'gitlab', 'google', 'linkedin', 'meteor-developer', 'twitter'];
return availableOAuth.includes(name) ? 'oauth' : 'not_supported';
},
getUsernameSuggestion() { getUsernameSuggestion() {
// RC 0.65.0 // RC 0.65.0
return this.sdk.get('users.getUsernameSuggestion'); return this.sdk.get('users.getUsernameSuggestion');

View File

@ -69,19 +69,7 @@ const styles = StyleSheet.create({
} }
}); });
@responsive class NotificationBadge extends React.Component {
@connect(
state => ({
userId: state.login.user && state.login.user.id,
baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
token: state.login.user && state.login.user.token,
notification: state.notification
}),
dispatch => ({
removeNotification: () => dispatch(removeNotificationAction())
})
)
export default class NotificationBadge extends React.Component {
static propTypes = { static propTypes = {
navigation: PropTypes.object, navigation: PropTypes.object,
baseUrl: PropTypes.string, baseUrl: PropTypes.string,
@ -227,3 +215,16 @@ export default class NotificationBadge extends React.Component {
); );
} }
} }
const mapStateToProps = state => ({
userId: state.login.user && state.login.user.id,
baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
token: state.login.user && state.login.user.token,
notification: state.notification
});
const mapDispatchToProps = dispatch => ({
removeNotification: () => dispatch(removeNotificationAction())
});
export default responsive(connect(mapStateToProps, mapDispatchToProps)(NotificationBadge));

View File

@ -1,5 +1,7 @@
import NotificationsIOS from 'react-native-notifications'; import NotificationsIOS from 'react-native-notifications';
import reduxStore from '../../lib/createStore';
class PushNotification { class PushNotification {
constructor() { constructor() {
this.onRegister = null; this.onRegister = null;
@ -10,8 +12,12 @@ class PushNotification {
this.deviceToken = deviceToken; this.deviceToken = deviceToken;
}); });
NotificationsIOS.addEventListener('notificationOpened', (notification) => { NotificationsIOS.addEventListener('notificationOpened', (notification, completion) => {
const { background } = reduxStore.getState().app;
if (background) {
this.onNotification(notification); this.onNotification(notification);
}
completion();
}); });
NotificationsIOS.requestPermissions(); NotificationsIOS.requestPermissions();
@ -30,7 +36,7 @@ class PushNotification {
this.onNotification = params.onNotification; this.onNotification = params.onNotification;
const initial = await NotificationsIOS.getInitialNotification(); const initial = await NotificationsIOS.getInitialNotification();
NotificationsIOS.consumeBackgroundQueue(); // NotificationsIOS.consumeBackgroundQueue();
return Promise.resolve(initial); return Promise.resolve(initial);
} }
} }

View File

@ -51,7 +51,6 @@ export default function login(state = initialState, action) {
return { return {
...state, ...state,
services: { services: {
...state.services,
...action.data ...action.data
} }
}; };

View File

@ -1,6 +1,5 @@
import { delay } from 'redux-saga';
import { import {
takeLatest, take, select, put, all takeLatest, take, select, put, all, delay
} from 'redux-saga/effects'; } from 'redux-saga/effects';
import RNUserDefaults from 'rn-user-defaults'; import RNUserDefaults from 'rn-user-defaults';

View File

@ -1,5 +1,6 @@
import { delay } from 'redux-saga'; import {
import { takeLatest, put, call } from 'redux-saga/effects'; takeLatest, put, call, delay
} from 'redux-saga/effects';
import Navigation from '../lib/Navigation'; import Navigation from '../lib/Navigation';
import { MESSAGES } from '../actions/actionsTypes'; import { MESSAGES } from '../actions/actionsTypes';

View File

@ -1,8 +1,7 @@
import { Alert } from 'react-native'; import { Alert } from 'react-native';
import { import {
call, takeLatest, take, select call, takeLatest, take, select, delay
} from 'redux-saga/effects'; } from 'redux-saga/effects';
import { delay } from 'redux-saga';
import Navigation from '../lib/Navigation'; import Navigation from '../lib/Navigation';
import * as types from '../actions/actionsTypes'; import * as types from '../actions/actionsTypes';

View File

@ -1,6 +1,5 @@
import { delay } from 'redux-saga';
import { import {
put, select, race, take, fork, cancel, takeLatest put, select, race, take, fork, cancel, takeLatest, delay
} from 'redux-saga/effects'; } from 'redux-saga/effects';
import { BACKGROUND, INACTIVE } from 'redux-enhancer-react-native-appstate'; import { BACKGROUND, INACTIVE } from 'redux-enhancer-react-native-appstate';

View File

@ -9,11 +9,7 @@ import StatusBar from '../../containers/StatusBar';
import { DrawerButton } from '../../containers/HeaderButton'; import { DrawerButton } from '../../containers/HeaderButton';
import styles from '../Styles'; import styles from '../Styles';
@connect(state => ({ class AdminPanelView extends React.Component {
baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
authToken: state.login.user && state.login.user.token
}))
export default class AdminPanelView extends React.Component {
static navigationOptions = ({ navigation }) => ({ static navigationOptions = ({ navigation }) => ({
headerLeft: <DrawerButton navigation={navigation} />, headerLeft: <DrawerButton navigation={navigation} />,
title: I18n.t('Admin_Panel') title: I18n.t('Admin_Panel')
@ -40,3 +36,10 @@ export default class AdminPanelView extends React.Component {
); );
} }
} }
const mapStateToProps = state => ({
baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
authToken: state.login.user && state.login.user.token
});
export default connect(mapStateToProps)(AdminPanelView);

View File

@ -24,14 +24,14 @@ const styles = StyleSheet.create({
} }
}); });
@connect(state => ({ class AuthenticationWebView extends React.PureComponent {
server: state.server.server static navigationOptions = ({ navigation }) => {
})) const authType = navigation.getParam('authType', 'oauth');
export default class OAuthView extends React.PureComponent { return {
static navigationOptions = ({ navigation }) => ({
headerLeft: <CloseModalButton navigation={navigation} />, headerLeft: <CloseModalButton navigation={navigation} />,
title: 'OAuth' title: authType === 'saml' || authType === 'cas' ? 'SSO' : 'OAuth'
}) };
}
static propTypes = { static propTypes = {
navigation: PropTypes.object, navigation: PropTypes.object,
@ -44,6 +44,7 @@ export default class OAuthView extends React.PureComponent {
logging: false, logging: false,
loading: false loading: false
}; };
this.authType = props.navigation.getParam('authType', 'oauth');
this.redirectRegex = new RegExp(`(?=.*(${ props.server }))(?=.*(credentialToken))(?=.*(credentialSecret))`, 'g'); this.redirectRegex = new RegExp(`(?=.*(${ props.server }))(?=.*(credentialToken))(?=.*(credentialSecret))`, 'g');
} }
@ -61,7 +62,7 @@ export default class OAuthView extends React.PureComponent {
this.setState({ logging: true }); this.setState({ logging: true });
try { try {
await RocketChat.loginOAuth(params); await RocketChat.loginOAuthOrSso(params);
} catch (e) { } catch (e) {
console.warn(e); console.warn(e);
} }
@ -69,29 +70,51 @@ export default class OAuthView extends React.PureComponent {
this.dismiss(); this.dismiss();
} }
render() { onNavigationStateChange = (webViewState) => {
const { navigation } = this.props;
const { loading } = this.state;
const oAuthUrl = navigation.getParam('oAuthUrl');
return (
<React.Fragment>
<StatusBar />
<WebView
useWebKit
source={{ uri: oAuthUrl }}
userAgent={userAgent}
onNavigationStateChange={(webViewState) => {
const url = decodeURIComponent(webViewState.url); const url = decodeURIComponent(webViewState.url);
if (this.authType === 'saml' || this.authType === 'cas') {
const { navigation } = this.props;
const ssoToken = navigation.getParam('ssoToken');
if (url.includes('ticket') || url.includes('validate')) {
let payload;
const credentialToken = { credentialToken: ssoToken };
if (this.authType === 'saml') {
payload = { ...credentialToken, saml: true };
} else {
payload = { cas: credentialToken };
}
// We need to set a timeout when the login is done with SSO in order to make it work on our side.
// It is actually due to the SSO server processing the response.
setTimeout(() => {
this.login(payload);
}, 3000);
}
}
if (this.authType === 'oauth') {
if (this.redirectRegex.test(url)) { if (this.redirectRegex.test(url)) {
const parts = url.split('#'); const parts = url.split('#');
const credentials = JSON.parse(parts[1]); const credentials = JSON.parse(parts[1]);
this.login({ oauth: { ...credentials } }); this.login({ oauth: { ...credentials } });
} }
}} }
}
render() {
const { navigation } = this.props;
const { loading } = this.state;
const uri = navigation.getParam('url');
return (
<React.Fragment>
<StatusBar />
<WebView
useWebKit
source={{ uri }}
userAgent={userAgent}
onNavigationStateChange={this.onNavigationStateChange}
onLoadStart={() => { onLoadStart={() => {
this.setState({ loading: true }); this.setState({ loading: true });
}} }}
onLoadEnd={() => { onLoadEnd={() => {
this.setState({ loading: false }); this.setState({ loading: false });
}} }}
@ -101,3 +124,9 @@ export default class OAuthView extends React.PureComponent {
); );
} }
} }
const mapStateToProps = state => ({
server: state.server.server
});
export default connect(mapStateToProps)(AuthenticationWebView);

View File

@ -127,7 +127,7 @@ export default class AutoTranslateView extends React.Component {
render() { render() {
const { languages } = this.state; const { languages } = this.state;
return ( return (
<SafeAreaView style={sharedStyles.listSafeArea} testID='auto-translate-view' forceInset={{ bottom: 'never' }}> <SafeAreaView style={sharedStyles.listSafeArea} testID='auto-translate-view' forceInset={{ vertical: 'never' }}>
<StatusBar /> <StatusBar />
<ScrollView <ScrollView
{...scrollPersistTaps} {...scrollPersistTaps}

View File

@ -76,22 +76,7 @@ const styles = StyleSheet.create({
} }
}); });
@connect(state => ({ class CreateChannelView extends React.Component {
baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
error: state.createChannel.error,
failure: state.createChannel.failure,
isFetching: state.createChannel.isFetching,
result: state.createChannel.result,
users: state.selectedUsers.users,
user: {
id: state.login.user && state.login.user.id,
token: state.login.user && state.login.user.token
}
}), dispatch => ({
create: data => dispatch(createChannelRequestAction(data)),
removeUser: user => dispatch(removeUserAction(user))
}))
export default class CreateChannelView extends React.Component {
static navigationOptions = ({ navigation }) => { static navigationOptions = ({ navigation }) => {
const submit = navigation.getParam('submit', () => {}); const submit = navigation.getParam('submit', () => {});
const showSubmit = navigation.getParam('showSubmit'); const showSubmit = navigation.getParam('showSubmit');
@ -135,9 +120,6 @@ export default class CreateChannelView extends React.Component {
componentDidMount() { componentDidMount() {
const { navigation } = this.props; const { navigation } = this.props;
navigation.setParams({ submit: this.submit }); navigation.setParams({ submit: this.submit });
this.timeout = setTimeout(() => {
this.channelNameRef.focus();
}, 600);
} }
shouldComponentUpdate(nextProps, nextState) { shouldComponentUpdate(nextProps, nextState) {
@ -196,12 +178,6 @@ export default class CreateChannelView extends React.Component {
} }
} }
componentWillUnmount() {
if (this.timeout) {
clearTimeout(this.timeout);
}
}
onChangeText = (channelName) => { onChangeText = (channelName) => {
const { navigation } = this.props; const { navigation } = this.props;
navigation.setParams({ showSubmit: channelName.trim().length > 0 }); navigation.setParams({ showSubmit: channelName.trim().length > 0 });
@ -333,11 +309,11 @@ export default class CreateChannelView extends React.Component {
keyboardVerticalOffset={128} keyboardVerticalOffset={128}
> >
<StatusBar /> <StatusBar />
<SafeAreaView testID='create-channel-view' style={styles.container} forceInset={{ bottom: 'never' }}> <SafeAreaView testID='create-channel-view' style={styles.container} forceInset={{ vertical: 'never' }}>
<ScrollView {...scrollPersistTaps}> <ScrollView {...scrollPersistTaps}>
<View style={sharedStyles.separatorVertical}> <View style={sharedStyles.separatorVertical}>
<TextInput <TextInput
ref={ref => this.channelNameRef = ref} autoFocus
style={styles.input} style={styles.input}
label={I18n.t('Channel_Name')} label={I18n.t('Channel_Name')}
value={channelName} value={channelName}
@ -369,3 +345,23 @@ export default class CreateChannelView extends React.Component {
); );
} }
} }
const mapStateToProps = state => ({
baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
error: state.createChannel.error,
failure: state.createChannel.failure,
isFetching: state.createChannel.isFetching,
result: state.createChannel.result,
users: state.selectedUsers.users,
user: {
id: state.login.user && state.login.user.id,
token: state.login.user && state.login.user.token
}
});
const mapDispatchToProps = dispatch => ({
create: data => dispatch(createChannelRequestAction(data)),
removeUser: user => dispatch(removeUserAction(user))
});
export default connect(mapStateToProps, mapDispatchToProps)(CreateChannelView);

View File

@ -20,15 +20,7 @@ import log from '../../utils/log';
import Options from './Options'; import Options from './Options';
import styles from './styles'; import styles from './styles';
@connect(state => ({ class DirectoryView extends React.Component {
baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
user: {
id: state.login.user && state.login.user.id,
token: state.login.user && state.login.user.token
},
isFederationEnabled: state.settings.FEDERATION_Enabled
}))
export default class DirectoryView extends React.Component {
static navigationOptions = () => ({ static navigationOptions = () => ({
title: I18n.t('Directory') title: I18n.t('Directory')
}) })
@ -215,7 +207,7 @@ export default class DirectoryView extends React.Component {
} = this.state; } = this.state;
const { isFederationEnabled } = this.props; const { isFederationEnabled } = this.props;
return ( return (
<SafeAreaView style={styles.safeAreaView} testID='directory-view' forceInset={{ bottom: 'never' }}> <SafeAreaView style={styles.safeAreaView} testID='directory-view' forceInset={{ vertical: 'never' }}>
<StatusBar /> <StatusBar />
<FlatList <FlatList
data={data} data={data}
@ -246,3 +238,14 @@ export default class DirectoryView extends React.Component {
); );
} }
} }
const mapStateToProps = state => ({
baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
user: {
id: state.login.user && state.login.user.id,
token: state.login.user && state.login.user.token
},
isFederationEnabled: state.settings.FEDERATION_Enabled
});
export default connect(mapStateToProps)(DirectoryView);

View File

@ -32,12 +32,6 @@ export default class ForgotPasswordView extends React.Component {
isFetching: false isFetching: false
} }
componentDidMount() {
this.timeout = setTimeout(() => {
this.emailInput.focus();
}, 600);
}
shouldComponentUpdate(nextProps, nextState) { shouldComponentUpdate(nextProps, nextState) {
const { email, invalidEmail, isFetching } = this.state; const { email, invalidEmail, isFetching } = this.state;
if (nextState.email !== email) { if (nextState.email !== email) {
@ -52,12 +46,6 @@ export default class ForgotPasswordView extends React.Component {
return false; return false;
} }
componentWillUnmount() {
if (this.timeout) {
clearTimeout(this.timeout);
}
}
validate = (email) => { validate = (email) => {
if (!isValidEmail(email)) { if (!isValidEmail(email)) {
this.setState({ invalidEmail: true }); this.setState({ invalidEmail: true });
@ -96,10 +84,10 @@ export default class ForgotPasswordView extends React.Component {
> >
<StatusBar /> <StatusBar />
<ScrollView {...scrollPersistTaps} contentContainerStyle={sharedStyles.containerScrollView}> <ScrollView {...scrollPersistTaps} contentContainerStyle={sharedStyles.containerScrollView}>
<SafeAreaView style={sharedStyles.container} testID='forgot-password-view' forceInset={{ bottom: 'never' }}> <SafeAreaView style={sharedStyles.container} testID='forgot-password-view' forceInset={{ vertical: 'never' }}>
<Text style={[sharedStyles.loginTitle, sharedStyles.textBold]}>{I18n.t('Forgot_password')}</Text> <Text style={[sharedStyles.loginTitle, sharedStyles.textBold]}>{I18n.t('Forgot_password')}</Text>
<TextInput <TextInput
inputRef={(e) => { this.emailInput = e; }} autoFocus
placeholder={I18n.t('Email')} placeholder={I18n.t('Email')}
keyboardType='email-address' keyboardType='email-address'
iconLeft='mail' iconLeft='mail'

View File

@ -41,12 +41,7 @@ const LANGUAGES = [
} }
]; ];
@connect(state => ({ class LanguageView extends React.Component {
userLanguage: state.login.user && state.login.user.language
}), dispatch => ({
setUser: params => dispatch(setUserAction(params))
}))
export default class LanguageView extends React.Component {
static navigationOptions = () => ({ static navigationOptions = () => ({
title: I18n.t('Change_Language') title: I18n.t('Change_Language')
}) })
@ -141,7 +136,7 @@ export default class LanguageView extends React.Component {
render() { render() {
const { saving } = this.state; const { saving } = this.state;
return ( return (
<SafeAreaView style={sharedStyles.listSafeArea} testID='language-view' forceInset={{ bottom: 'never' }}> <SafeAreaView style={sharedStyles.listSafeArea} testID='language-view' forceInset={{ vertical: 'never' }}>
<StatusBar /> <StatusBar />
<FlatList <FlatList
data={LANGUAGES} data={LANGUAGES}
@ -155,3 +150,13 @@ export default class LanguageView extends React.Component {
); );
} }
} }
const mapStateToProps = state => ({
userLanguage: state.login.user && state.login.user.language
});
const mapDispatchToProps = dispatch => ({
setUser: params => dispatch(setUserAction(params))
});
export default connect(mapStateToProps, mapDispatchToProps)(LanguageView);

View File

@ -52,10 +52,7 @@ const styles = StyleSheet.create({
const Separator = () => <View style={styles.separator} />; const Separator = () => <View style={styles.separator} />;
@connect(state => ({ class LegalView extends React.Component {
server: state.server.server
}))
export default class LegalView extends React.Component {
static navigationOptions = () => ({ static navigationOptions = () => ({
title: I18n.t('Legal') title: I18n.t('Legal')
}) })
@ -81,7 +78,7 @@ export default class LegalView extends React.Component {
render() { render() {
return ( return (
<SafeAreaView style={styles.container} testID='legal-view' forceInset={{ bottom: 'never' }}> <SafeAreaView style={styles.container} testID='legal-view' forceInset={{ vertical: 'never' }}>
<StatusBar /> <StatusBar />
<ScrollView {...scrollPersistTaps} contentContainerStyle={styles.scroll}> <ScrollView {...scrollPersistTaps} contentContainerStyle={styles.scroll}>
{this.renderItem({ text: 'Terms_of_Service', route: 'terms-of-service', testID: 'legal-terms-button' })} {this.renderItem({ text: 'Terms_of_Service', route: 'terms-of-service', testID: 'legal-terms-button' })}
@ -92,3 +89,9 @@ export default class LegalView extends React.Component {
); );
} }
} }
const mapStateToProps = state => ({
server: state.server.server
});
export default connect(mapStateToProps)(LegalView);

View File

@ -88,13 +88,7 @@ const styles = StyleSheet.create({
const SERVICE_HEIGHT = 58; const SERVICE_HEIGHT = 58;
const SERVICES_COLLAPSED_HEIGHT = 174; const SERVICES_COLLAPSED_HEIGHT = 174;
@connect(state => ({ class LoginSignupView extends React.Component {
server: state.server.server,
Site_Name: state.settings.Site_Name,
Gitlab_URL: state.settings.API_Gitlab_URL,
services: state.login.services
}))
export default class LoginSignupView extends React.Component {
static navigationOptions = ({ navigation }) => { static navigationOptions = ({ navigation }) => {
const title = navigation.getParam('title', 'Rocket.Chat'); const title = navigation.getParam('title', 'Rocket.Chat');
return { return {
@ -108,7 +102,9 @@ export default class LoginSignupView extends React.Component {
server: PropTypes.string, server: PropTypes.string,
services: PropTypes.object, services: PropTypes.object,
Site_Name: PropTypes.string, Site_Name: PropTypes.string,
Gitlab_URL: PropTypes.string Gitlab_URL: PropTypes.string,
CAS_enabled: PropTypes.bool,
CAS_login_url: PropTypes.string
} }
constructor(props) { constructor(props) {
@ -162,7 +158,7 @@ export default class LoginSignupView extends React.Component {
const scope = 'email'; const scope = 'email';
const state = this.getOAuthState(); const state = this.getOAuthState();
const params = `?client_id=${ clientId }&redirect_uri=${ redirect_uri }&scope=${ scope }&state=${ state }&display=touch`; const params = `?client_id=${ clientId }&redirect_uri=${ redirect_uri }&scope=${ scope }&state=${ state }&display=touch`;
this.openOAuth(`${ endpoint }${ params }`); this.openOAuth({ url: `${ endpoint }${ params }` });
} }
onPressGithub = () => { onPressGithub = () => {
@ -173,7 +169,7 @@ export default class LoginSignupView extends React.Component {
const scope = 'user:email'; const scope = 'user:email';
const state = this.getOAuthState(); const state = this.getOAuthState();
const params = `?client_id=${ clientId }&redirect_uri=${ redirect_uri }&scope=${ scope }&state=${ state }`; const params = `?client_id=${ clientId }&redirect_uri=${ redirect_uri }&scope=${ scope }&state=${ state }`;
this.openOAuth(`${ endpoint }${ encodeURIComponent(params) }`); this.openOAuth({ url: `${ endpoint }${ encodeURIComponent(params) }` });
} }
onPressGitlab = () => { onPressGitlab = () => {
@ -185,7 +181,7 @@ export default class LoginSignupView extends React.Component {
const scope = 'read_user'; const scope = 'read_user';
const state = this.getOAuthState(); const state = this.getOAuthState();
const params = `?client_id=${ clientId }&redirect_uri=${ redirect_uri }&scope=${ scope }&state=${ state }&response_type=code`; const params = `?client_id=${ clientId }&redirect_uri=${ redirect_uri }&scope=${ scope }&state=${ state }&response_type=code`;
this.openOAuth(`${ endpoint }${ params }`); this.openOAuth({ url: `${ endpoint }${ params }` });
} }
onPressGoogle = () => { onPressGoogle = () => {
@ -196,7 +192,7 @@ export default class LoginSignupView extends React.Component {
const scope = 'email'; const scope = 'email';
const state = this.getOAuthState(); const state = this.getOAuthState();
const params = `?client_id=${ clientId }&redirect_uri=${ redirect_uri }&scope=${ scope }&state=${ state }&response_type=code`; const params = `?client_id=${ clientId }&redirect_uri=${ redirect_uri }&scope=${ scope }&state=${ state }&response_type=code`;
this.openOAuth(`${ endpoint }${ params }`); this.openOAuth({ url: `${ endpoint }${ params }` });
} }
onPressLinkedin = () => { onPressLinkedin = () => {
@ -207,7 +203,7 @@ export default class LoginSignupView extends React.Component {
const scope = 'r_emailaddress'; const scope = 'r_emailaddress';
const state = this.getOAuthState(); const state = this.getOAuthState();
const params = `?client_id=${ clientId }&redirect_uri=${ redirect_uri }&scope=${ scope }&state=${ state }&response_type=code`; const params = `?client_id=${ clientId }&redirect_uri=${ redirect_uri }&scope=${ scope }&state=${ state }&response_type=code`;
this.openOAuth(`${ endpoint }${ params }`); this.openOAuth({ url: `${ endpoint }${ params }` });
} }
onPressMeteor = () => { onPressMeteor = () => {
@ -217,14 +213,42 @@ export default class LoginSignupView extends React.Component {
const redirect_uri = `${ server }/_oauth/meteor-developer`; const redirect_uri = `${ server }/_oauth/meteor-developer`;
const state = this.getOAuthState(); const state = this.getOAuthState();
const params = `?client_id=${ clientId }&redirect_uri=${ redirect_uri }&state=${ state }&response_type=code`; const params = `?client_id=${ clientId }&redirect_uri=${ redirect_uri }&state=${ state }&response_type=code`;
this.openOAuth(`${ endpoint }${ params }`); this.openOAuth({ url: `${ endpoint }${ params }` });
} }
onPressTwitter = () => { onPressTwitter = () => {
const { server } = this.props; const { server } = this.props;
const state = this.getOAuthState(); const state = this.getOAuthState();
const url = `${ server }/_oauth/twitter/?requestTokenAndRedirect=true&state=${ state }`; const url = `${ server }/_oauth/twitter/?requestTokenAndRedirect=true&state=${ state }`;
this.openOAuth(url); this.openOAuth({ url });
}
onPressCustomOAuth = (loginService) => {
const { server } = this.props;
const {
serverURL, authorizePath, clientId, scope, service
} = loginService;
const redirectUri = `${ server }/_oauth/${ service }`;
const state = this.getOAuthState();
const params = `?client_id=${ clientId }&redirect_uri=${ redirectUri }&response_type=code&state=${ state }&scope=${ scope }`;
const url = `${ serverURL }${ authorizePath }${ params }`;
this.openOAuth({ url });
}
onPressSaml = (loginService) => {
const { server } = this.props;
const { clientConfig } = loginService;
const { provider } = clientConfig;
const ssoToken = random(17);
const url = `${ server }/_saml/authorize/${ provider }/${ ssoToken }`;
this.openOAuth({ url, ssoToken, authType: 'saml' });
}
onPressCas = () => {
const { server, CAS_login_url } = this.props;
const ssoToken = random(17);
const url = `${ CAS_login_url }/?service=${ server }/_cas/${ ssoToken }`;
this.openOAuth({ url, ssoToken, authType: 'cas' });
} }
getOAuthState = () => { getOAuthState = () => {
@ -232,9 +256,9 @@ export default class LoginSignupView extends React.Component {
return Base64.encodeURI(JSON.stringify({ loginStyle: 'popup', credentialToken, isCordova: true })); return Base64.encodeURI(JSON.stringify({ loginStyle: 'popup', credentialToken, isCordova: true }));
} }
openOAuth = (oAuthUrl) => { openOAuth = ({ url, ssoToken, authType = 'oauth' }) => {
const { navigation } = this.props; const { navigation } = this.props;
navigation.navigate('OAuthView', { oAuthUrl }); navigation.navigate('AuthenticationWebView', { url, authType, ssoToken });
} }
login = () => { login = () => {
@ -271,6 +295,19 @@ export default class LoginSignupView extends React.Component {
this.setState(prevState => ({ collapsed: !prevState.collapsed })); this.setState(prevState => ({ collapsed: !prevState.collapsed }));
} }
getSocialOauthProvider = (name) => {
const oauthProviders = {
facebook: this.onPressFacebook,
github: this.onPressGithub,
gitlab: this.onPressGitlab,
google: this.onPressGoogle,
linkedin: this.onPressLinkedin,
'meteor-developer': this.onPressMeteor,
twitter: this.onPressTwitter
};
return oauthProviders[name];
}
renderServicesSeparator = () => { renderServicesSeparator = () => {
const { collapsed } = this.state; const { collapsed } = this.state;
const { services } = this.props; const { services } = this.props;
@ -298,40 +335,45 @@ export default class LoginSignupView extends React.Component {
let { name } = service; let { name } = service;
name = name === 'meteor-developer' ? 'meteor' : name; name = name === 'meteor-developer' ? 'meteor' : name;
const icon = `icon_${ name }`; const icon = `icon_${ name }`;
name = name.charAt(0).toUpperCase() + name.slice(1);
let onPress = () => {}; let onPress = () => {};
switch (service.name) {
case 'facebook': switch (service.authType) {
onPress = this.onPressFacebook; case 'oauth': {
onPress = this.getSocialOauthProvider(service.name);
break; break;
case 'github': }
onPress = this.onPressGithub; case 'oauth_custom': {
onPress = () => this.onPressCustomOAuth(service);
break; break;
case 'gitlab': }
onPress = this.onPressGitlab; case 'saml': {
onPress = () => this.onPressSaml(service);
break; break;
case 'google': }
onPress = this.onPressGoogle; case 'cas': {
break; onPress = () => this.onPressCas();
case 'linkedin':
onPress = this.onPressLinkedin;
break;
case 'meteor-developer':
onPress = this.onPressMeteor;
break;
case 'twitter':
onPress = this.onPressTwitter;
break; break;
}
default: default:
break; break;
} }
name = name.charAt(0).toUpperCase() + name.slice(1);
const { CAS_enabled } = this.props;
let buttonText;
if (service.service === 'saml' || (service.service === 'cas' && CAS_enabled)) {
buttonText = <Text style={styles.serviceName}>{name}</Text>;
} else {
buttonText = (
<>
{I18n.t('Continue_with')} <Text style={styles.serviceName}>{name}</Text>
</>
);
}
return ( return (
<RectButton key={service.name} onPress={onPress} style={styles.serviceButton}> <RectButton key={service.name} onPress={onPress} style={styles.serviceButton}>
<View style={styles.serviceButtonContainer}> <View style={styles.serviceButtonContainer}>
<Image source={{ uri: icon }} style={styles.serviceIcon} /> {service.authType === 'oauth' ? <Image source={{ uri: icon }} style={styles.serviceIcon} /> : null}
<Text style={styles.serviceText}> <Text style={styles.serviceText}>{buttonText}</Text>
{I18n.t('Continue_with')} <Text style={styles.serviceName}>{name}</Text>
</Text>
</View> </View>
</RectButton> </RectButton>
); );
@ -365,7 +407,7 @@ export default class LoginSignupView extends React.Component {
return ( return (
<ScrollView style={[sharedStyles.containerScrollView, sharedStyles.container, styles.container]} {...scrollPersistTaps}> <ScrollView style={[sharedStyles.containerScrollView, sharedStyles.container, styles.container]} {...scrollPersistTaps}>
<StatusBar /> <StatusBar />
<SafeAreaView testID='welcome-view' forceInset={{ bottom: 'never' }} style={styles.safeArea}> <SafeAreaView testID='welcome-view' forceInset={{ vertical: 'never' }} style={styles.safeArea}>
{this.renderServices()} {this.renderServices()}
{this.renderServicesSeparator()} {this.renderServicesSeparator()}
<Button <Button
@ -385,3 +427,14 @@ export default class LoginSignupView extends React.Component {
); );
} }
} }
const mapStateToProps = state => ({
server: state.server.server,
Site_Name: state.settings.Site_Name,
Gitlab_URL: state.settings.API_Gitlab_URL,
CAS_enabled: state.settings.CAS_enabled,
CAS_login_url: state.settings.CAS_login_url,
services: state.login.services
});
export default connect(mapStateToProps)(LoginSignupView);

View File

@ -41,17 +41,7 @@ const styles = StyleSheet.create({
} }
}); });
@connect(state => ({ class LoginView extends React.Component {
isFetching: state.login.isFetching,
failure: state.login.failure,
error: state.login.error && state.login.error.data,
Site_Name: state.settings.Site_Name,
Accounts_EmailOrUsernamePlaceholder: state.settings.Accounts_EmailOrUsernamePlaceholder,
Accounts_PasswordPlaceholder: state.settings.Accounts_PasswordPlaceholder
}), dispatch => ({
loginRequest: params => dispatch(loginRequestAction(params))
}))
export default class LoginView extends React.Component {
static navigationOptions = ({ navigation }) => { static navigationOptions = ({ navigation }) => {
const title = navigation.getParam('title', 'Rocket.Chat'); const title = navigation.getParam('title', 'Rocket.Chat');
return { return {
@ -67,10 +57,15 @@ export default class LoginView extends React.Component {
Site_Name: PropTypes.string, Site_Name: PropTypes.string,
Accounts_EmailOrUsernamePlaceholder: PropTypes.string, Accounts_EmailOrUsernamePlaceholder: PropTypes.string,
Accounts_PasswordPlaceholder: PropTypes.string, Accounts_PasswordPlaceholder: PropTypes.string,
Accounts_PasswordReset: PropTypes.bool,
isFetching: PropTypes.bool, isFetching: PropTypes.bool,
failure: PropTypes.bool failure: PropTypes.bool
} }
static defaultProps = {
Accounts_PasswordReset: true
}
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
@ -83,12 +78,6 @@ export default class LoginView extends React.Component {
this.setTitle(Site_Name); this.setTitle(Site_Name);
} }
componentDidMount() {
this.timeout = setTimeout(() => {
this.usernameInput.focus();
}, 600);
}
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
const { Site_Name, error } = this.props; const { Site_Name, error } = this.props;
if (nextProps.Site_Name && nextProps.Site_Name !== Site_Name) { if (nextProps.Site_Name && nextProps.Site_Name !== Site_Name) {
@ -97,11 +86,6 @@ export default class LoginView extends React.Component {
if (nextProps.error && nextProps.error.error === 'totp-required') { if (nextProps.error && nextProps.error.error === 'totp-required') {
LayoutAnimation.easeInEaseOut(); LayoutAnimation.easeInEaseOut();
this.setState({ showTOTP: true }); this.setState({ showTOTP: true });
setTimeout(() => {
if (this.codeInput && this.codeInput.focus) {
this.codeInput.focus();
}
}, 300);
return; return;
} }
Alert.alert(I18n.t('Oops'), I18n.t('Login_error')); Alert.alert(I18n.t('Oops'), I18n.t('Login_error'));
@ -148,12 +132,6 @@ export default class LoginView extends React.Component {
return false; return false;
} }
componentWillUnmount() {
if (this.timeout) {
clearTimeout(this.timeout);
}
}
setTitle = (title) => { setTitle = (title) => {
const { navigation } = this.props; const { navigation } = this.props;
navigation.setParams({ title }); navigation.setParams({ title });
@ -194,11 +172,12 @@ export default class LoginView extends React.Component {
renderTOTP = () => { renderTOTP = () => {
const { isFetching } = this.props; const { isFetching } = this.props;
return ( return (
<SafeAreaView style={sharedStyles.container} testID='login-view' forceInset={{ bottom: 'never' }}> <SafeAreaView style={sharedStyles.container} testID='login-view' forceInset={{ vertical: 'never' }}>
<Text style={[sharedStyles.loginTitle, sharedStyles.textBold, styles.loginTitle]}>{I18n.t('Two_Factor_Authentication')}</Text> <Text style={[sharedStyles.loginTitle, sharedStyles.textBold, styles.loginTitle]}>{I18n.t('Two_Factor_Authentication')}</Text>
<Text style={[sharedStyles.loginSubtitle, sharedStyles.textRegular]}>{I18n.t('Whats_your_2fa')}</Text> <Text style={[sharedStyles.loginSubtitle, sharedStyles.textRegular]}>{I18n.t('Whats_your_2fa')}</Text>
<TextInput <TextInput
inputRef={ref => this.codeInput = ref} inputRef={ref => this.codeInput = ref}
autoFocus
onChangeText={value => this.setState({ code: value })} onChangeText={value => this.setState({ code: value })}
keyboardType='numeric' keyboardType='numeric'
returnKeyType='send' returnKeyType='send'
@ -221,13 +200,13 @@ export default class LoginView extends React.Component {
renderUserForm = () => { renderUserForm = () => {
const { const {
Accounts_EmailOrUsernamePlaceholder, Accounts_PasswordPlaceholder, isFetching Accounts_EmailOrUsernamePlaceholder, Accounts_PasswordPlaceholder, Accounts_PasswordReset, isFetching
} = this.props; } = this.props;
return ( return (
<SafeAreaView style={sharedStyles.container} testID='login-view' forceInset={{ bottom: 'never' }}> <SafeAreaView style={sharedStyles.container} testID='login-view' forceInset={{ vertical: 'never' }}>
<Text style={[sharedStyles.loginTitle, sharedStyles.textBold]}>{I18n.t('Login')}</Text> <Text style={[sharedStyles.loginTitle, sharedStyles.textBold]}>{I18n.t('Login')}</Text>
<TextInput <TextInput
inputRef={(e) => { this.usernameInput = e; }} autoFocus
placeholder={Accounts_EmailOrUsernamePlaceholder || I18n.t('Username_or_email')} placeholder={Accounts_EmailOrUsernamePlaceholder || I18n.t('Username_or_email')}
keyboardType='email-address' keyboardType='email-address'
returnKeyType='next' returnKeyType='next'
@ -255,12 +234,14 @@ export default class LoginView extends React.Component {
loading={isFetching} loading={isFetching}
disabled={!this.valid()} disabled={!this.valid()}
/> />
{Accounts_PasswordReset && (
<Button <Button
title={I18n.t('Forgot_password')} title={I18n.t('Forgot_password')}
type='secondary' type='secondary'
onPress={this.forgotPassword} onPress={this.forgotPassword}
testID='login-view-forgot-password' testID='login-view-forgot-password'
/> />
)}
<View style={styles.bottomContainer}> <View style={styles.bottomContainer}>
<Text style={styles.dontHaveAccount}>{I18n.t('Dont_Have_An_Account')}</Text> <Text style={styles.dontHaveAccount}>{I18n.t('Dont_Have_An_Account')}</Text>
<Text <Text
@ -291,3 +272,19 @@ export default class LoginView extends React.Component {
); );
} }
} }
const mapStateToProps = state => ({
isFetching: state.login.isFetching,
failure: state.login.failure,
error: state.login.error && state.login.error.data,
Site_Name: state.settings.Site_Name,
Accounts_EmailOrUsernamePlaceholder: state.settings.Accounts_EmailOrUsernamePlaceholder,
Accounts_PasswordPlaceholder: state.settings.Accounts_PasswordPlaceholder,
Accounts_PasswordReset: state.settings.Accounts_PasswordReset
});
const mapDispatchToProps = dispatch => ({
loginRequest: params => dispatch(loginRequestAction(params))
});
export default connect(mapStateToProps, mapDispatchToProps)(LoginView);

View File

@ -18,15 +18,7 @@ import FileModal from '../../containers/FileModal';
const ACTION_INDEX = 0; const ACTION_INDEX = 0;
const CANCEL_INDEX = 1; const CANCEL_INDEX = 1;
@connect(state => ({ class MessagesView extends React.Component {
baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
user: {
id: state.login.user && state.login.user.id,
username: state.login.user && state.login.user.username,
token: state.login.user && state.login.user.token
}
}))
export default class MessagesView extends React.Component {
static navigationOptions = ({ navigation }) => ({ static navigationOptions = ({ navigation }) => ({
title: navigation.state.params.name title: navigation.state.params.name
}); });
@ -252,7 +244,7 @@ export default class MessagesView extends React.Component {
} }
return ( return (
<SafeAreaView style={styles.list} testID={this.content.testID} forceInset={{ bottom: 'never' }}> <SafeAreaView style={styles.list} testID={this.content.testID} forceInset={{ vertical: 'never' }}>
<StatusBar /> <StatusBar />
<FlatList <FlatList
data={messages} data={messages}
@ -273,3 +265,14 @@ export default class MessagesView extends React.Component {
); );
} }
} }
const mapStateToProps = state => ({
baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
user: {
id: state.login.user && state.login.user.id,
username: state.login.user && state.login.user.username,
token: state.login.user && state.login.user.token
}
});
export default connect(mapStateToProps)(MessagesView);

View File

@ -50,14 +50,7 @@ const styles = StyleSheet.create({
} }
}); });
@connect(state => ({ class NewMessageView extends React.Component {
baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
user: {
id: state.login.user && state.login.user.id,
token: state.login.user && state.login.user.token
}
}))
export default class NewMessageView extends React.Component {
static navigationOptions = ({ navigation }) => ({ static navigationOptions = ({ navigation }) => ({
headerLeft: <CloseModalButton navigation={navigation} testID='new-message-view-close' />, headerLeft: <CloseModalButton navigation={navigation} testID='new-message-view-close' />,
title: I18n.t('New_Message') title: I18n.t('New_Message')
@ -183,9 +176,19 @@ export default class NewMessageView extends React.Component {
} }
render = () => ( render = () => (
<SafeAreaView style={styles.safeAreaView} testID='new-message-view' forceInset={{ bottom: 'never' }}> <SafeAreaView style={styles.safeAreaView} testID='new-message-view' forceInset={{ vertical: 'never' }}>
<StatusBar /> <StatusBar />
{this.renderList()} {this.renderList()}
</SafeAreaView> </SafeAreaView>
); );
} }
const mapStateToProps = state => ({
baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
user: {
id: state.login.user && state.login.user.id,
token: state.login.user && state.login.user.token
}
});
export default connect(mapStateToProps)(NewMessageView);

View File

@ -46,12 +46,7 @@ const styles = StyleSheet.create({
const defaultServer = 'https://open.rocket.chat'; const defaultServer = 'https://open.rocket.chat';
@connect(state => ({ class NewServerView extends React.Component {
connecting: state.server.connecting
}), dispatch => ({
connectServer: server => dispatch(serverRequest(server))
}))
export default class NewServerView extends React.Component {
static navigationOptions = () => ({ static navigationOptions = () => ({
header: null header: null
}) })
@ -63,20 +58,20 @@ export default class NewServerView extends React.Component {
connectServer: PropTypes.func.isRequired connectServer: PropTypes.func.isRequired
} }
state = { constructor(props) {
text: '' super(props);
const server = props.navigation.getParam('server');
this.state = {
text: server || '',
autoFocus: !server
};
} }
componentDidMount() { componentDidMount() {
const { navigation, connectServer } = this.props; const { text } = this.state;
const server = navigation.getParam('server'); const { connectServer } = this.props;
if (server) { if (text) {
connectServer(server); connectServer(text);
this.setState({ text: server });
} else {
this.timeout = setTimeout(() => {
this.input.focus();
}, 600);
} }
} }
@ -92,12 +87,6 @@ export default class NewServerView extends React.Component {
return false; return false;
} }
componentWillUnmount() {
if (this.timeout) {
clearTimeout(this.timeout);
}
}
onChangeText = (text) => { onChangeText = (text) => {
this.setState({ text }); this.setState({ text });
} }
@ -155,7 +144,7 @@ export default class NewServerView extends React.Component {
render() { render() {
const { connecting } = this.props; const { connecting } = this.props;
const { text } = this.state; const { text, autoFocus } = this.state;
return ( return (
<KeyboardView <KeyboardView
contentContainerStyle={sharedStyles.container} contentContainerStyle={sharedStyles.container}
@ -164,11 +153,11 @@ export default class NewServerView extends React.Component {
> >
<StatusBar light /> <StatusBar light />
<ScrollView {...scrollPersistTaps} contentContainerStyle={sharedStyles.containerScrollView}> <ScrollView {...scrollPersistTaps} contentContainerStyle={sharedStyles.containerScrollView}>
<SafeAreaView style={sharedStyles.container} testID='new-server-view' forceInset={{ bottom: 'never' }}> <SafeAreaView style={sharedStyles.container} testID='new-server-view'>
<Image style={styles.image} source={{ uri: 'new_server' }} /> <Image style={styles.image} source={{ uri: 'new_server' }} />
<Text style={styles.title}>{I18n.t('Sign_in_your_server')}</Text> <Text style={styles.title}>{I18n.t('Sign_in_your_server')}</Text>
<TextInput <TextInput
inputRef={e => this.input = e} autoFocus={autoFocus}
containerStyle={styles.inputContainer} containerStyle={styles.inputContainer}
placeholder={defaultServer} placeholder={defaultServer}
value={text} value={text}
@ -182,7 +171,7 @@ export default class NewServerView extends React.Component {
title={I18n.t('Connect')} title={I18n.t('Connect')}
type='primary' type='primary'
onPress={this.submit} onPress={this.submit}
disabled={text.length === 0} disabled={!text}
loading={connecting} loading={connecting}
testID='new-server-view-button' testID='new-server-view-button'
/> />
@ -193,3 +182,13 @@ export default class NewServerView extends React.Component {
); );
} }
} }
const mapStateToProps = state => ({
connecting: state.server.connecting
});
const mapDispatchToProps = dispatch => ({
connectServer: server => dispatch(serverRequest(server))
});
export default connect(mapStateToProps, mapDispatchToProps)(NewServerView);

View File

@ -19,16 +19,7 @@ import { CustomIcon } from '../../lib/Icons';
import StatusBar from '../../containers/StatusBar'; import StatusBar from '../../containers/StatusBar';
import { COLOR_PRIMARY, COLOR_WHITE } from '../../constants/colors'; import { COLOR_PRIMARY, COLOR_WHITE } from '../../constants/colors';
@connect(state => ({ class OnboardingView extends React.Component {
currentServer: state.server.server,
adding: state.server.adding
}), dispatch => ({
initAdd: () => dispatch(serverInitAdd()),
finishAdd: () => dispatch(serverFinishAdd()),
selectServer: server => dispatch(selectServerRequest(server)),
appStart: root => dispatch(appStartAction(root))
}))
export default class OnboardingView extends React.Component {
static navigationOptions = () => ({ static navigationOptions = () => ({
header: null header: null
}) })
@ -134,7 +125,7 @@ export default class OnboardingView extends React.Component {
render() { render() {
return ( return (
<SafeAreaView style={styles.container} testID='onboarding-view' forceInset={{ bottom: 'never' }}> <SafeAreaView style={styles.container} testID='onboarding-view'>
<StatusBar light /> <StatusBar light />
<Image style={styles.onboarding} source={{ uri: 'onboarding' }} fadeDuration={0} /> <Image style={styles.onboarding} source={{ uri: 'onboarding' }} fadeDuration={0} />
<Text style={styles.title}>{I18n.t('Welcome_to_RocketChat')}</Text> <Text style={styles.title}>{I18n.t('Welcome_to_RocketChat')}</Text>
@ -168,3 +159,17 @@ export default class OnboardingView extends React.Component {
); );
} }
} }
const mapStateToProps = state => ({
currentServer: state.server.server,
adding: state.server.adding
});
const mapDispatchToProps = dispatch => ({
initAdd: () => dispatch(serverInitAdd()),
finishAdd: () => dispatch(serverFinishAdd()),
selectServer: server => dispatch(selectServerRequest(server)),
appStart: root => dispatch(appStartAction(root))
});
export default connect(mapStateToProps, mapDispatchToProps)(OnboardingView);

View File

@ -29,21 +29,7 @@ import { DrawerButton } from '../../containers/HeaderButton';
import StatusBar from '../../containers/StatusBar'; import StatusBar from '../../containers/StatusBar';
import { COLOR_TEXT } from '../../constants/colors'; import { COLOR_TEXT } from '../../constants/colors';
@connect(state => ({ class ProfileView extends React.Component {
user: {
id: state.login.user && state.login.user.id,
name: state.login.user && state.login.user.name,
username: state.login.user && state.login.user.username,
customFields: state.login.user && state.login.user.customFields,
emails: state.login.user && state.login.user.emails,
token: state.login.user && state.login.user.token
},
Accounts_CustomFields: state.settings.Accounts_CustomFields,
baseUrl: state.settings.Site_Url || state.server ? state.server.server : ''
}), dispatch => ({
setUser: params => dispatch(setUserAction(params))
}))
export default class ProfileView extends React.Component {
static navigationOptions = ({ navigation }) => ({ static navigationOptions = ({ navigation }) => ({
headerLeft: <DrawerButton navigation={navigation} />, headerLeft: <DrawerButton navigation={navigation} />,
title: I18n.t('Profile') title: I18n.t('Profile')
@ -393,7 +379,7 @@ export default class ProfileView extends React.Component {
testID='profile-view-list' testID='profile-view-list'
{...scrollPersistTaps} {...scrollPersistTaps}
> >
<SafeAreaView style={sharedStyles.container} testID='profile-view' forceInset={{ bottom: 'never' }}> <SafeAreaView style={sharedStyles.container} testID='profile-view' forceInset={{ vertical: 'never' }}>
<View style={styles.avatarContainer} testID='profile-view-avatar'> <View style={styles.avatarContainer} testID='profile-view-avatar'>
<Avatar <Avatar
text={username} text={username}
@ -487,3 +473,22 @@ export default class ProfileView extends React.Component {
); );
} }
} }
const mapStateToProps = state => ({
user: {
id: state.login.user && state.login.user.id,
name: state.login.user && state.login.user.name,
username: state.login.user && state.login.user.username,
customFields: state.login.user && state.login.user.customFields,
emails: state.login.user && state.login.user.emails,
token: state.login.user && state.login.user.token
},
Accounts_CustomFields: state.settings.Accounts_CustomFields,
baseUrl: state.settings.Site_Url || state.server ? state.server.server : ''
});
const mapDispatchToProps = dispatch => ({
setUser: params => dispatch(setUserAction(params))
});
export default connect(mapStateToProps, mapDispatchToProps)(ProfileView);

View File

@ -13,13 +13,7 @@ import I18n from '../../i18n';
import RocketChat from '../../lib/rocketchat'; import RocketChat from '../../lib/rocketchat';
import StatusBar from '../../containers/StatusBar'; import StatusBar from '../../containers/StatusBar';
@connect(state => ({ class ReadReceiptView extends React.Component {
Message_TimeFormat: state.settings.Message_TimeFormat,
baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
userId: state.login.user && state.login.user.id,
token: state.login.user && state.login.user.token
}))
export default class ReadReceiptsView extends React.Component {
static navigationOptions = { static navigationOptions = {
title: I18n.t('Read_Receipt') title: I18n.t('Read_Receipt')
} }
@ -144,3 +138,12 @@ export default class ReadReceiptsView extends React.Component {
); );
} }
} }
const mapStateToProps = state => ({
Message_TimeFormat: state.settings.Message_TimeFormat,
baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
userId: state.login.user && state.login.user.id,
token: state.login.user && state.login.user.token
});
export default connect(mapStateToProps)(ReadReceiptView);

View File

@ -23,12 +23,7 @@ import log from '../utils/log';
const shouldUpdateState = ['name', 'email', 'password', 'username', 'saving']; const shouldUpdateState = ['name', 'email', 'password', 'username', 'saving'];
@connect(state => ({ class RegisterView extends React.Component {
Accounts_CustomFields: state.settings.Accounts_CustomFields
}), dispatch => ({
loginRequest: params => dispatch(loginRequestAction(params))
}))
export default class RegisterView extends React.Component {
static navigationOptions = ({ navigation }) => { static navigationOptions = ({ navigation }) => {
const title = navigation.getParam('title', 'Rocket.Chat'); const title = navigation.getParam('title', 'Rocket.Chat');
return { return {
@ -70,12 +65,6 @@ export default class RegisterView extends React.Component {
}; };
} }
componentDidMount() {
this.timeout = setTimeout(() => {
this.nameInput.focus();
}, 600);
}
shouldComponentUpdate(nextProps, nextState) { shouldComponentUpdate(nextProps, nextState) {
const { customFields } = this.state; const { customFields } = this.state;
if (!equal(nextState.customFields, customFields)) { if (!equal(nextState.customFields, customFields)) {
@ -92,12 +81,6 @@ export default class RegisterView extends React.Component {
} }
} }
componentWillUnmount() {
if (this.timeout) {
clearTimeout(this.timeout);
}
}
setTitle = (title) => { setTitle = (title) => {
const { navigation } = this.props; const { navigation } = this.props;
navigation.setParams({ title }); navigation.setParams({ title });
@ -203,10 +186,10 @@ export default class RegisterView extends React.Component {
<KeyboardView contentContainerStyle={sharedStyles.container}> <KeyboardView contentContainerStyle={sharedStyles.container}>
<StatusBar /> <StatusBar />
<ScrollView {...scrollPersistTaps} contentContainerStyle={sharedStyles.containerScrollView}> <ScrollView {...scrollPersistTaps} contentContainerStyle={sharedStyles.containerScrollView}>
<SafeAreaView style={sharedStyles.container} testID='register-view' forceInset={{ bottom: 'never' }}> <SafeAreaView style={sharedStyles.container} testID='register-view' forceInset={{ vertical: 'never' }}>
<Text style={[sharedStyles.loginTitle, sharedStyles.textBold]}>{I18n.t('Sign_Up')}</Text> <Text style={[sharedStyles.loginTitle, sharedStyles.textBold]}>{I18n.t('Sign_Up')}</Text>
<TextInput <TextInput
inputRef={(e) => { this.nameInput = e; }} autoFocus
placeholder={I18n.t('Name')} placeholder={I18n.t('Name')}
returnKeyType='next' returnKeyType='next'
iconLeft='user' iconLeft='user'
@ -261,3 +244,13 @@ export default class RegisterView extends React.Component {
); );
} }
} }
const mapStateToProps = state => ({
Accounts_CustomFields: state.settings.Accounts_CustomFields
});
const mapDispatchToProps = dispatch => ({
loginRequest: params => dispatch(loginRequestAction(params))
});
export default connect(mapStateToProps, mapDispatchToProps)(RegisterView);

View File

@ -26,16 +26,7 @@ import { COLOR_WHITE } from '../../constants/colors';
const renderSeparator = () => <View style={styles.separator} />; const renderSeparator = () => <View style={styles.separator} />;
@connect(state => ({ class RoomActionsView extends React.Component {
user: {
id: state.login.user && state.login.user.id,
token: state.login.user && state.login.user.token
},
baseUrl: state.settings.Site_Url || state.server ? state.server.server : ''
}), dispatch => ({
leaveRoom: (rid, t) => dispatch(leaveRoomAction(rid, t))
}))
export default class RoomActionsView extends React.Component {
static navigationOptions = { static navigationOptions = {
title: I18n.t('Actions') title: I18n.t('Actions')
} }
@ -483,7 +474,7 @@ export default class RoomActionsView extends React.Component {
render() { render() {
return ( return (
<SafeAreaView style={styles.container} testID='room-actions-view' forceInset={{ bottom: 'never' }}> <SafeAreaView style={styles.container} testID='room-actions-view' forceInset={{ vertical: 'never' }}>
<StatusBar /> <StatusBar />
<SectionList <SectionList
contentContainerStyle={styles.contentContainer} contentContainerStyle={styles.contentContainer}
@ -500,3 +491,17 @@ export default class RoomActionsView extends React.Component {
); );
} }
} }
const mapStateToProps = state => ({
user: {
id: state.login.user && state.login.user.id,
token: state.login.user && state.login.user.token
},
baseUrl: state.settings.Site_Url || state.server ? state.server.server : ''
});
const mapDispatchToProps = dispatch => ({
leaveRoom: (rid, t) => dispatch(leaveRoomAction(rid, t))
});
export default connect(mapStateToProps, mapDispatchToProps)(RoomActionsView);

View File

@ -40,10 +40,7 @@ const PERMISSIONS_ARRAY = [
PERMISSION_DELETE_P PERMISSION_DELETE_P
]; ];
@connect(null, dispatch => ({ class RoomInfoEditView extends React.Component {
eraseRoom: (rid, t) => dispatch(eraseRoomAction(rid, t))
}))
export default class RoomInfoEditView extends React.Component {
static navigationOptions = { static navigationOptions = {
title: I18n.t('Room_Info_Edit') title: I18n.t('Room_Info_Edit')
} }
@ -299,7 +296,7 @@ export default class RoomInfoEditView extends React.Component {
testID='room-info-edit-view-list' testID='room-info-edit-view-list'
{...scrollPersistTaps} {...scrollPersistTaps}
> >
<SafeAreaView style={sharedStyles.container} testID='room-info-edit-view' forceInset={{ bottom: 'never' }}> <SafeAreaView style={sharedStyles.container} testID='room-info-edit-view' forceInset={{ vertical: 'never' }}>
<RCTextInput <RCTextInput
inputRef={(e) => { this.name = e; }} inputRef={(e) => { this.name = e; }}
label={I18n.t('Name')} label={I18n.t('Name')}
@ -436,3 +433,9 @@ export default class RoomInfoEditView extends React.Component {
); );
} }
} }
const mapDispatchToProps = dispatch => ({
eraseRoom: (rid, t) => dispatch(eraseRoomAction(rid, t))
});
export default connect(null, mapDispatchToProps)(RoomInfoEditView);

View File

@ -30,15 +30,7 @@ const getRoomTitle = room => (room.t === 'd'
) )
); );
@connect(state => ({ class RoomInfoView extends React.Component {
baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
user: {
id: state.login.user && state.login.user.id,
token: state.login.user && state.login.user.token
},
Message_TimeFormat: state.settings.Message_TimeFormat
}))
export default class RoomInfoView extends React.Component {
static navigationOptions = ({ navigation }) => { static navigationOptions = ({ navigation }) => {
const showEdit = navigation.getParam('showEdit'); const showEdit = navigation.getParam('showEdit');
const rid = navigation.getParam('rid'); const rid = navigation.getParam('rid');
@ -247,7 +239,7 @@ export default class RoomInfoView extends React.Component {
return ( return (
<ScrollView style={styles.scroll}> <ScrollView style={styles.scroll}>
<StatusBar /> <StatusBar />
<SafeAreaView style={styles.container} testID='room-info-view' forceInset={{ bottom: 'never' }}> <SafeAreaView style={styles.container} testID='room-info-view' forceInset={{ vertical: 'never' }}>
<View style={styles.avatarContainer}> <View style={styles.avatarContainer}>
{this.renderAvatar(room, roomUser)} {this.renderAvatar(room, roomUser)}
<View style={styles.roomTitleContainer}>{ getRoomTitle(room) }</View> <View style={styles.roomTitleContainer}>{ getRoomTitle(room) }</View>
@ -264,3 +256,14 @@ export default class RoomInfoView extends React.Component {
); );
} }
} }
const mapStateToProps = state => ({
baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
user: {
id: state.login.user && state.login.user.id,
token: state.login.user && state.login.user.token
},
Message_TimeFormat: state.settings.Message_TimeFormat
});
export default connect(mapStateToProps)(RoomInfoView);

View File

@ -23,14 +23,7 @@ import StatusBar from '../../containers/StatusBar';
const PAGE_SIZE = 25; const PAGE_SIZE = 25;
@connect(state => ({ class RoomMembersView extends React.Component {
baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
user: {
id: state.login.user && state.login.user.id,
token: state.login.user && state.login.user.token
}
}))
export default class RoomMembersView extends React.Component {
static navigationOptions = ({ navigation }) => { static navigationOptions = ({ navigation }) => {
const toggleStatus = navigation.getParam('toggleStatus', () => {}); const toggleStatus = navigation.getParam('toggleStatus', () => {});
const allUsers = navigation.getParam('allUsers'); const allUsers = navigation.getParam('allUsers');
@ -279,7 +272,7 @@ export default class RoomMembersView extends React.Component {
// return <ActivityIndicator style={styles.loading} />; // return <ActivityIndicator style={styles.loading} />;
// } // }
return ( return (
<SafeAreaView style={styles.list} testID='room-members-view' forceInset={{ bottom: 'never' }}> <SafeAreaView style={styles.list} testID='room-members-view' forceInset={{ vertical: 'never' }}>
<StatusBar /> <StatusBar />
<FlatList <FlatList
data={filtering ? membersFiltered : members} data={filtering ? membersFiltered : members}
@ -304,3 +297,13 @@ export default class RoomMembersView extends React.Component {
); );
} }
} }
const mapStateToProps = state => ({
baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
user: {
id: state.login.user && state.login.user.id,
token: state.login.user && state.login.user.token
}
});
export default connect(mapStateToProps)(RoomMembersView);

View File

@ -19,10 +19,6 @@ const styles = StyleSheet.create({
} }
}); });
@connect(state => ({
userId: state.login.user && state.login.user.id,
threadsEnabled: state.settings.Threads_enabled
}))
class RightButtonsContainer extends React.PureComponent { class RightButtonsContainer extends React.PureComponent {
static propTypes = { static propTypes = {
userId: PropTypes.string, userId: PropTypes.string,
@ -123,4 +119,9 @@ class RightButtonsContainer extends React.PureComponent {
} }
} }
export default RightButtonsContainer; const mapStateToProps = state => ({
userId: state.login.user && state.login.user.id,
threadsEnabled: state.settings.Threads_enabled
});
export default connect(mapStateToProps)(RightButtonsContainer);

View File

@ -8,31 +8,7 @@ import database, { safeAddListener } from '../../../lib/realm';
import Header from './Header'; import Header from './Header';
import RightButtons from './RightButtons'; import RightButtons from './RightButtons';
@responsive class RoomHeaderView extends Component {
@connect((state, ownProps) => {
let status;
let userId;
let isLoggedUser = false;
const { rid, type } = ownProps;
if (type === 'd') {
if (state.login.user && state.login.user.id) {
const { id: loggedUserId } = state.login.user;
userId = rid.replace(loggedUserId, '').trim();
isLoggedUser = userId === loggedUserId;
if (isLoggedUser) {
status = state.login.user.status; // eslint-disable-line
}
}
}
return {
connecting: state.meteor.connecting,
userId,
isLoggedUser,
status
};
})
export default class RoomHeaderView extends Component {
static propTypes = { static propTypes = {
title: PropTypes.string, title: PropTypes.string,
type: PropTypes.string, type: PropTypes.string,
@ -143,4 +119,30 @@ export default class RoomHeaderView extends Component {
} }
} }
const mapStateToProps = (state, ownProps) => {
let status;
let userId;
let isLoggedUser = false;
const { rid, type } = ownProps;
if (type === 'd') {
if (state.login.user && state.login.user.id) {
const { id: loggedUserId } = state.login.user;
userId = rid.replace(loggedUserId, '').trim();
isLoggedUser = userId === loggedUserId;
if (isLoggedUser) {
status = state.login.user.status; // eslint-disable-line
}
}
}
return {
connecting: state.meteor.connecting,
userId,
isLoggedUser,
status
};
};
export default responsive(connect(mapStateToProps)(RoomHeaderView));
export { RightButtons }; export { RightButtons };

View File

@ -13,14 +13,7 @@ import { isAndroid } from '../../utils/deviceInfo';
const margin = isAndroid ? 40 : 20; const margin = isAndroid ? 40 : 20;
const tabEmojiStyle = { fontSize: 15 }; const tabEmojiStyle = { fontSize: 15 };
@connect(state => ({ class ReactionPicker extends React.Component {
showReactionPicker: state.messages.showReactionPicker,
baseUrl: state.settings.Site_Url || state.server ? state.server.server : ''
}), dispatch => ({
toggleReactionPicker: message => dispatch(toggleReactionPickerAction(message))
}))
@responsive
export default class ReactionPicker extends React.Component {
static propTypes = { static propTypes = {
baseUrl: PropTypes.string.isRequired, baseUrl: PropTypes.string.isRequired,
window: PropTypes.any, window: PropTypes.any,
@ -74,3 +67,14 @@ export default class ReactionPicker extends React.Component {
); );
} }
} }
const mapStateToProps = state => ({
showReactionPicker: state.messages.showReactionPicker,
baseUrl: state.settings.Site_Url || state.server ? state.server.server : ''
});
const mapDispatchToProps = dispatch => ({
toggleReactionPicker: message => dispatch(toggleReactionPickerAction(message))
});
export default responsive(connect(mapStateToProps, mapDispatchToProps)(ReactionPicker));

View File

@ -60,8 +60,7 @@ const styles = StyleSheet.create({
} }
}); });
@responsive 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,
@ -193,3 +192,5 @@ export default class UploadProgress extends Component {
); );
} }
} }
export default responsive(UploadProgress);

View File

@ -44,34 +44,7 @@ import ReactionsModal from '../../containers/ReactionsModal';
import { LISTENER } from '../../containers/Toast'; import { LISTENER } from '../../containers/Toast';
import { isReadOnly, isBlocked } from '../../utils/room'; import { isReadOnly, isBlocked } from '../../utils/room';
@connect(state => ({ class RoomView extends React.Component {
user: {
id: state.login.user && state.login.user.id,
username: state.login.user && state.login.user.username,
token: state.login.user && state.login.user.token
},
actionMessage: state.messages.actionMessage,
editing: state.messages.editing,
replying: state.messages.replying,
showActions: state.messages.showActions,
showErrorActions: state.messages.showErrorActions,
appState: state.app.ready && state.app.foreground ? 'foreground' : 'background',
useRealName: state.settings.UI_Use_Real_Name,
isAuthenticated: state.login.isAuthenticated,
Message_GroupingPeriod: state.settings.Message_GroupingPeriod,
Message_TimeFormat: state.settings.Message_TimeFormat,
useMarkdown: state.markdown.useMarkdown,
baseUrl: state.settings.baseUrl || state.server ? state.server.server : '',
Message_Read_Receipt_Enabled: state.settings.Message_Read_Receipt_Enabled
}), dispatch => ({
editCancel: () => dispatch(editCancelAction()),
replyCancel: () => dispatch(replyCancelAction()),
toggleReactionPicker: message => dispatch(toggleReactionPickerAction(message)),
errorActionsShow: actionMessage => dispatch(errorActionsShowAction(actionMessage)),
actionsShow: actionMessage => dispatch(actionsShowAction(actionMessage)),
replyBroadcast: message => dispatch(replyBroadcastAction(message))
}))
export default class RoomView extends React.Component {
static navigationOptions = ({ navigation }) => { static navigationOptions = ({ navigation }) => {
const rid = navigation.getParam('rid'); const rid = navigation.getParam('rid');
const prid = navigation.getParam('prid'); const prid = navigation.getParam('prid');
@ -618,7 +591,7 @@ export default class RoomView extends React.Component {
const { rid, t } = room; const { rid, t } = room;
return ( return (
<SafeAreaView style={styles.container} testID='room-view' forceInset={{ bottom: 'never' }}> <SafeAreaView style={styles.container} testID='room-view' forceInset={{ vertical: 'never' }}>
<StatusBar /> <StatusBar />
<List rid={rid} t={t} tmid={this.tmid} renderRow={this.renderItem} /> <List rid={rid} t={t} tmid={this.tmid} renderRow={this.renderItem} />
{this.renderFooter()} {this.renderFooter()}
@ -643,3 +616,35 @@ export default class RoomView extends React.Component {
); );
} }
} }
const mapStateToProps = state => ({
user: {
id: state.login.user && state.login.user.id,
username: state.login.user && state.login.user.username,
token: state.login.user && state.login.user.token
},
actionMessage: state.messages.actionMessage,
editing: state.messages.editing,
replying: state.messages.replying,
showActions: state.messages.showActions,
showErrorActions: state.messages.showErrorActions,
appState: state.app.ready && state.app.foreground ? 'foreground' : 'background',
useRealName: state.settings.UI_Use_Real_Name,
isAuthenticated: state.login.isAuthenticated,
Message_GroupingPeriod: state.settings.Message_GroupingPeriod,
Message_TimeFormat: state.settings.Message_TimeFormat,
useMarkdown: state.markdown.useMarkdown,
baseUrl: state.settings.baseUrl || state.server ? state.server.server : '',
Message_Read_Receipt_Enabled: state.settings.Message_Read_Receipt_Enabled
});
const mapDispatchToProps = dispatch => ({
editCancel: () => dispatch(editCancelAction()),
replyCancel: () => dispatch(replyCancelAction()),
toggleReactionPicker: message => dispatch(toggleReactionPickerAction(message)),
errorActionsShow: actionMessage => dispatch(errorActionsShowAction(actionMessage)),
actionsShow: actionMessage => dispatch(actionsShowAction(actionMessage)),
replyBroadcast: message => dispatch(replyBroadcastAction(message))
});
export default connect(mapStateToProps, mapDispatchToProps)(RoomView);

View File

@ -43,13 +43,13 @@ const styles = StyleSheet.create({
}); });
const Header = React.memo(({ const Header = React.memo(({
connecting, isFetching, serverName, showServerDropdown, setSearchInputRef, showSearchHeader, onSearchChangeText, onPress connecting, isFetching, serverName, showServerDropdown, showSearchHeader, onSearchChangeText, onPress
}) => { }) => {
if (showSearchHeader) { if (showSearchHeader) {
return ( return (
<View style={styles.container}> <View style={styles.container}>
<TextInput <TextInput
ref={setSearchInputRef} autoFocus
style={styles.server} style={styles.server}
placeholder='Search' placeholder='Search'
placeholderTextColor='rgba(255, 255, 255, 0.5)' placeholderTextColor='rgba(255, 255, 255, 0.5)'
@ -81,7 +81,6 @@ Header.propTypes = {
showSearchHeader: PropTypes.bool.isRequired, showSearchHeader: PropTypes.bool.isRequired,
onPress: PropTypes.func.isRequired, onPress: PropTypes.func.isRequired,
onSearchChangeText: PropTypes.func.isRequired, onSearchChangeText: PropTypes.func.isRequired,
setSearchInputRef: PropTypes.func.isRequired,
connecting: PropTypes.bool, connecting: PropTypes.bool,
isFetching: PropTypes.bool, isFetching: PropTypes.bool,
serverName: PropTypes.string serverName: PropTypes.string

View File

@ -7,20 +7,7 @@ import {
} from '../../../actions/rooms'; } from '../../../actions/rooms';
import Header from './Header'; import Header from './Header';
@connect(state => ({ class RoomsListHeaderView extends PureComponent {
showServerDropdown: state.rooms.showServerDropdown,
showSortDropdown: state.rooms.showSortDropdown,
showSearchHeader: state.rooms.showSearchHeader,
connecting: state.meteor.connecting || state.server.loading,
isFetching: state.rooms.isFetching,
serverName: state.settings.Site_Name
}), dispatch => ({
close: () => dispatch(closeServerDropdown()),
open: () => dispatch(toggleServerDropdown()),
closeSort: () => dispatch(closeSortDropdown()),
setSearch: searchText => dispatch(setSearchAction(searchText))
}))
export default class RoomsListHeaderView extends PureComponent {
static propTypes = { static propTypes = {
showServerDropdown: PropTypes.bool, showServerDropdown: PropTypes.bool,
showSortDropdown: PropTypes.bool, showSortDropdown: PropTypes.bool,
@ -34,15 +21,6 @@ export default class RoomsListHeaderView extends PureComponent {
setSearch: PropTypes.func setSearch: PropTypes.func
} }
componentDidUpdate(prevProps) {
const { showSearchHeader } = this.props;
if (showSearchHeader && prevProps.showSearchHeader !== showSearchHeader) {
setTimeout(() => {
this.searchInputRef.focus();
}, 300);
}
}
onSearchChangeText = (text) => { onSearchChangeText = (text) => {
const { setSearch } = this.props; const { setSearch } = this.props;
setSearch(text.trim()); setSearch(text.trim());
@ -64,10 +42,6 @@ export default class RoomsListHeaderView extends PureComponent {
} }
} }
setSearchInputRef = (ref) => {
this.searchInputRef = ref;
}
render() { render() {
const { const {
serverName, showServerDropdown, showSearchHeader, connecting, isFetching serverName, showServerDropdown, showSearchHeader, connecting, isFetching
@ -80,10 +54,27 @@ export default class RoomsListHeaderView extends PureComponent {
showSearchHeader={showSearchHeader} showSearchHeader={showSearchHeader}
connecting={connecting} connecting={connecting}
isFetching={isFetching} isFetching={isFetching}
setSearchInputRef={this.setSearchInputRef}
onPress={this.onPress} onPress={this.onPress}
onSearchChangeText={text => this.onSearchChangeText(text)} onSearchChangeText={text => this.onSearchChangeText(text)}
/> />
); );
} }
} }
const mapStateToProps = state => ({
showServerDropdown: state.rooms.showServerDropdown,
showSortDropdown: state.rooms.showSortDropdown,
showSearchHeader: state.rooms.showSearchHeader,
connecting: state.meteor.connecting || state.server.loading,
isFetching: state.rooms.isFetching,
serverName: state.settings.Site_Name
});
const mapDispatchtoProps = dispatch => ({
close: () => dispatch(closeServerDropdown()),
open: () => dispatch(toggleServerDropdown()),
closeSort: () => dispatch(closeSortDropdown()),
setSearch: searchText => dispatch(setSearchAction(searchText))
});
export default connect(mapStateToProps, mapDispatchtoProps)(RoomsListHeaderView);

View File

@ -22,14 +22,6 @@ import Check from '../../containers/Check';
const ROW_HEIGHT = 68; const ROW_HEIGHT = 68;
const ANIMATION_DURATION = 200; const ANIMATION_DURATION = 200;
@connect(state => ({
closeServerDropdown: state.rooms.closeServerDropdown,
server: state.server.server
}), dispatch => ({
toggleServerDropdown: () => dispatch(toggleServerDropdownAction()),
selectServerRequest: server => dispatch(selectServerRequestAction(server)),
appStart: () => dispatch(appStartAction('outside'))
}))
class ServerDropdown extends Component { class ServerDropdown extends Component {
static propTypes = { static propTypes = {
navigation: PropTypes.object, navigation: PropTypes.object,
@ -211,4 +203,16 @@ class ServerDropdown extends Component {
); );
} }
} }
export default withNavigation(ServerDropdown);
const mapStateToProps = state => ({
closeServerDropdown: state.rooms.closeServerDropdown,
server: state.server.server
});
const mapDispatchToProps = dispatch => ({
toggleServerDropdown: () => dispatch(toggleServerDropdownAction()),
selectServerRequest: server => dispatch(selectServerRequestAction(server)),
appStart: () => dispatch(appStartAction('outside'))
});
export default withNavigation(connect(mapStateToProps, mapDispatchToProps)(ServerDropdown));

View File

@ -16,12 +16,7 @@ import Check from '../../containers/Check';
const ANIMATION_DURATION = 200; const ANIMATION_DURATION = 200;
@connect(state => ({ class Sort extends PureComponent {
closeSortDropdown: state.rooms.closeSortDropdown
}), dispatch => ({
setSortPreference: preference => dispatch(setPreference(preference))
}))
export default class Sort extends PureComponent {
static propTypes = { static propTypes = {
closeSortDropdown: PropTypes.bool, closeSortDropdown: PropTypes.bool,
close: PropTypes.func, close: PropTypes.func,
@ -176,3 +171,13 @@ export default class Sort extends PureComponent {
); );
} }
} }
const mapStateToProps = state => ({
closeSortDropdown: state.rooms.closeSortDropdown
});
const mapDispatchToProps = dispatch => ({
setSortPreference: preference => dispatch(setPreference(preference))
});
export default connect(mapStateToProps, mapDispatchToProps)(Sort);

View File

@ -37,33 +37,7 @@ const shouldUpdateProps = ['searchText', 'loadingServer', 'showServerDropdown',
const getItemLayout = (data, index) => ({ length: ROW_HEIGHT, offset: ROW_HEIGHT * index, index }); const getItemLayout = (data, index) => ({ length: ROW_HEIGHT, offset: ROW_HEIGHT * index, index });
const keyExtractor = item => item.rid; const keyExtractor = item => item.rid;
@connect(state => ({ class RoomsListView extends React.Component {
userId: state.login.user && state.login.user.id,
username: state.login.user && state.login.user.username,
token: state.login.user && state.login.user.token,
isAuthenticated: state.login.isAuthenticated,
server: state.server.server,
baseUrl: state.settings.baseUrl || state.server ? state.server.server : '',
searchText: state.rooms.searchText,
loadingServer: state.server.loading,
showServerDropdown: state.rooms.showServerDropdown,
showSortDropdown: state.rooms.showSortDropdown,
sortBy: state.sortPreferences.sortBy,
groupByType: state.sortPreferences.groupByType,
showFavorites: state.sortPreferences.showFavorites,
showUnread: state.sortPreferences.showUnread,
useRealName: state.settings.UI_Use_Real_Name,
appState: state.app.ready && state.app.foreground ? 'foreground' : 'background',
StoreLastMessage: state.settings.Store_Last_Message
}), dispatch => ({
toggleSortDropdown: () => dispatch(toggleSortDropdownAction()),
openSearchHeader: () => dispatch(openSearchHeaderAction()),
closeSearchHeader: () => dispatch(closeSearchHeaderAction()),
appStart: () => dispatch(appStartAction()),
roomsRequest: () => dispatch(roomsRequestAction()),
selectServerRequest: server => dispatch(selectServerRequestAction(server))
}))
export default class RoomsListView extends React.Component {
static navigationOptions = ({ navigation }) => { static navigationOptions = ({ navigation }) => {
const searching = navigation.getParam('searching'); const searching = navigation.getParam('searching');
const cancelSearchingAndroid = navigation.getParam('cancelSearchingAndroid'); const cancelSearchingAndroid = navigation.getParam('cancelSearchingAndroid');
@ -633,7 +607,7 @@ export default class RoomsListView extends React.Component {
} = this.props; } = this.props;
return ( return (
<SafeAreaView style={styles.container} testID='rooms-list-view' forceInset={{ bottom: 'never' }}> <SafeAreaView style={styles.container} testID='rooms-list-view' forceInset={{ vertical: 'never' }}>
<StatusBar /> <StatusBar />
{this.renderScroll()} {this.renderScroll()}
{showSortDropdown {showSortDropdown
@ -653,3 +627,34 @@ export default class RoomsListView extends React.Component {
); );
} }
} }
const mapStateToProps = state => ({
userId: state.login.user && state.login.user.id,
username: state.login.user && state.login.user.username,
token: state.login.user && state.login.user.token,
isAuthenticated: state.login.isAuthenticated,
server: state.server.server,
baseUrl: state.settings.baseUrl || state.server ? state.server.server : '',
searchText: state.rooms.searchText,
loadingServer: state.server.loading,
showServerDropdown: state.rooms.showServerDropdown,
showSortDropdown: state.rooms.showSortDropdown,
sortBy: state.sortPreferences.sortBy,
groupByType: state.sortPreferences.groupByType,
showFavorites: state.sortPreferences.showFavorites,
showUnread: state.sortPreferences.showUnread,
useRealName: state.settings.UI_Use_Real_Name,
appState: state.app.ready && state.app.foreground ? 'foreground' : 'background',
StoreLastMessage: state.settings.Store_Last_Message
});
const mapDispatchToProps = dispatch => ({
toggleSortDropdown: () => dispatch(toggleSortDropdownAction()),
openSearchHeader: () => dispatch(openSearchHeaderAction()),
closeSearchHeader: () => dispatch(closeSearchHeaderAction()),
appStart: () => dispatch(appStartAction()),
roomsRequest: () => dispatch(roomsRequestAction()),
selectServerRequest: server => dispatch(selectServerRequestAction(server))
});
export default connect(mapStateToProps, mapDispatchToProps)(RoomsListView);

View File

@ -17,15 +17,7 @@ import I18n from '../../i18n';
import StatusBar from '../../containers/StatusBar'; import StatusBar from '../../containers/StatusBar';
import log from '../../utils/log'; import log from '../../utils/log';
@connect(state => ({ class SearchMessagesView extends React.Component {
baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
user: {
id: state.login.user && state.login.user.id,
username: state.login.user && state.login.user.username,
token: state.login.user && state.login.user.token
}
}))
export default class SearchMessagesView extends React.Component {
static navigationOptions = { static navigationOptions = {
title: I18n.t('Search') title: I18n.t('Search')
} }
@ -46,10 +38,6 @@ export default class SearchMessagesView extends React.Component {
this.rid = props.navigation.getParam('rid'); this.rid = props.navigation.getParam('rid');
} }
componentDidMount() {
this.name.focus();
}
shouldComponentUpdate(nextProps, nextState) { shouldComponentUpdate(nextProps, nextState) {
const { loading, searchText, messages } = this.state; const { loading, searchText, messages } = this.state;
if (nextState.loading !== loading) { if (nextState.loading !== loading) {
@ -132,11 +120,11 @@ export default class SearchMessagesView extends React.Component {
render() { render() {
return ( return (
<SafeAreaView style={styles.container} testID='search-messages-view' forceInset={{ bottom: 'never' }}> <SafeAreaView style={styles.container} testID='search-messages-view' forceInset={{ vertical: 'never' }}>
<StatusBar /> <StatusBar />
<View style={styles.searchContainer}> <View style={styles.searchContainer}>
<RCTextInput <RCTextInput
inputRef={(e) => { this.name = e; }} autoFocus
label={I18n.t('Search')} label={I18n.t('Search')}
onChangeText={this.search} onChangeText={this.search}
placeholder={I18n.t('Search_Messages')} placeholder={I18n.t('Search_Messages')}
@ -150,3 +138,14 @@ export default class SearchMessagesView extends React.Component {
); );
} }
} }
const mapStateToProps = state => ({
baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
user: {
id: state.login.user && state.login.user.id,
username: state.login.user && state.login.user.username,
token: state.login.user && state.login.user.token
}
});
export default connect(mapStateToProps)(SearchMessagesView);

View File

@ -33,10 +33,7 @@ const styles = StyleSheet.create({
} }
}); });
@connect(({ share }) => ({ class SelectServerView extends React.Component {
server: share.server
}))
export default class SelectServerView extends React.Component {
static navigationOptions = () => ({ static navigationOptions = () => ({
title: I18n.t('Select_Server') title: I18n.t('Select_Server')
}) })
@ -85,7 +82,7 @@ export default class SelectServerView extends React.Component {
return ( return (
<SafeAreaView <SafeAreaView
style={styles.container} style={styles.container}
forceInset={{ bottom: 'never' }} forceInset={{ vertical: 'never' }}
> >
<StatusBar /> <StatusBar />
<View style={styles.list}> <View style={styles.list}>
@ -106,3 +103,9 @@ export default class SelectServerView extends React.Component {
); );
} }
} }
const mapStateToProps = (({ share }) => ({
server: share.server
}));
export default connect(mapStateToProps)(SelectServerView);

View File

@ -37,21 +37,7 @@ const styles = StyleSheet.create({
} }
}); });
@connect(state => ({ class SelectedUsersView extends React.Component {
baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
users: state.selectedUsers.users,
loading: state.selectedUsers.loading,
user: {
id: state.login.user && state.login.user.id,
token: state.login.user && state.login.user.token
}
}), dispatch => ({
addUser: user => dispatch(addUserAction(user)),
removeUser: user => dispatch(removeUserAction(user)),
reset: () => dispatch(resetAction()),
setLoadingInvite: loading => dispatch(setLoadingAction(loading))
}))
export default class SelectedUsersView extends React.Component {
static navigationOptions = ({ navigation }) => { static navigationOptions = ({ navigation }) => {
const title = navigation.getParam('title'); const title = navigation.getParam('title');
const nextAction = navigation.getParam('nextAction', () => {}); const nextAction = navigation.getParam('nextAction', () => {});
@ -270,7 +256,7 @@ export default class SelectedUsersView extends React.Component {
render = () => { render = () => {
const { loading } = this.props; const { loading } = this.props;
return ( return (
<SafeAreaView style={styles.safeAreaView} testID='select-users-view' forceInset={{ bottom: 'never' }}> <SafeAreaView style={styles.safeAreaView} testID='select-users-view' forceInset={{ vertical: 'never' }}>
<StatusBar /> <StatusBar />
{this.renderList()} {this.renderList()}
<Loading visible={loading} /> <Loading visible={loading} />
@ -278,3 +264,22 @@ export default class SelectedUsersView extends React.Component {
); );
} }
} }
const mapStateToProps = state => ({
baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
users: state.selectedUsers.users,
loading: state.selectedUsers.loading,
user: {
id: state.login.user && state.login.user.id,
token: state.login.user && state.login.user.token
}
});
const mapDispatchToProps = dispatch => ({
addUser: user => dispatch(addUserAction(user)),
removeUser: user => dispatch(removeUserAction(user)),
reset: () => dispatch(resetAction()),
setLoadingInvite: loading => dispatch(setLoadingAction(loading))
});
export default connect(mapStateToProps, mapDispatchToProps)(SelectedUsersView);

View File

@ -25,13 +25,7 @@ const styles = StyleSheet.create({
} }
}); });
@connect(state => ({ class SetUsernameView extends React.Component {
server: state.server.server,
token: state.login.user && state.login.user.token
}), dispatch => ({
loginRequest: params => dispatch(loginRequestAction(params))
}))
export default class SetUsernameView extends React.Component {
static navigationOptions = ({ navigation }) => { static navigationOptions = ({ navigation }) => {
const title = navigation.getParam('title'); const title = navigation.getParam('title');
return { return {
@ -59,9 +53,6 @@ export default class SetUsernameView extends React.Component {
} }
async componentDidMount() { async componentDidMount() {
this.timeout = setTimeout(() => {
this.usernameInput.focus();
}, 600);
const suggestion = await RocketChat.getUsernameSuggestion(); const suggestion = await RocketChat.getUsernameSuggestion();
if (suggestion.success) { if (suggestion.success) {
this.setState({ username: suggestion.result }); this.setState({ username: suggestion.result });
@ -79,12 +70,6 @@ export default class SetUsernameView extends React.Component {
return false; return false;
} }
componentWillUnmount() {
if (this.timeout) {
clearTimeout(this.timeout);
}
}
submit = async() => { submit = async() => {
const { username } = this.state; const { username } = this.state;
const { loginRequest, token } = this.props; const { loginRequest, token } = this.props;
@ -109,11 +94,11 @@ export default class SetUsernameView extends React.Component {
<KeyboardView contentContainerStyle={sharedStyles.container}> <KeyboardView contentContainerStyle={sharedStyles.container}>
<StatusBar /> <StatusBar />
<ScrollView {...scrollPersistTaps} contentContainerStyle={sharedStyles.containerScrollView}> <ScrollView {...scrollPersistTaps} contentContainerStyle={sharedStyles.containerScrollView}>
<SafeAreaView style={sharedStyles.container} testID='set-username-view' forceInset={{ bottom: 'never' }}> <SafeAreaView style={sharedStyles.container} testID='set-username-view' forceInset={{ vertical: 'never' }}>
<Text style={[sharedStyles.loginTitle, sharedStyles.textBold, styles.loginTitle]}>{I18n.t('Username')}</Text> <Text style={[sharedStyles.loginTitle, sharedStyles.textBold, styles.loginTitle]}>{I18n.t('Username')}</Text>
<Text style={[sharedStyles.loginSubtitle, sharedStyles.textRegular]}>{I18n.t('Set_username_subtitle')}</Text> <Text style={[sharedStyles.loginSubtitle, sharedStyles.textRegular]}>{I18n.t('Set_username_subtitle')}</Text>
<TextInput <TextInput
inputRef={e => this.usernameInput = e} autoFocus
placeholder={I18n.t('Username')} placeholder={I18n.t('Username')}
returnKeyType='send' returnKeyType='send'
iconLeft='at' iconLeft='at'
@ -138,3 +123,14 @@ export default class SetUsernameView extends React.Component {
); );
} }
} }
const mapStateToProps = state => ({
server: state.server.server,
token: state.login.user && state.login.user.token
});
const mapDispatchToProps = dispatch => ({
loginRequest: params => dispatch(loginRequestAction(params))
});
export default connect(mapStateToProps, mapDispatchToProps)(SetUsernameView);

View File

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import { import {
View, Linking, ScrollView, AsyncStorage, SafeAreaView, Switch View, Linking, ScrollView, AsyncStorage, SafeAreaView, Switch, Share
} from 'react-native'; } from 'react-native';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
@ -14,23 +14,17 @@ import { DisclosureImage } from '../../containers/DisclosureIndicator';
import Separator from '../../containers/Separator'; import Separator from '../../containers/Separator';
import I18n from '../../i18n'; import I18n from '../../i18n';
import { MARKDOWN_KEY } from '../../lib/rocketchat'; import { MARKDOWN_KEY } from '../../lib/rocketchat';
import { getReadableVersion, getDeviceModel } from '../../utils/deviceInfo'; import { getReadableVersion, getDeviceModel, isAndroid } from '../../utils/deviceInfo';
import openLink from '../../utils/openLink'; import openLink from '../../utils/openLink';
import scrollPersistTaps from '../../utils/scrollPersistTaps'; import scrollPersistTaps from '../../utils/scrollPersistTaps';
import { showErrorAlert } from '../../utils/info'; import { showErrorAlert } from '../../utils/info';
import styles from './styles'; import styles from './styles';
import sharedStyles from '../Styles'; import sharedStyles from '../Styles';
import { PLAY_MARKET_LINK, APP_STORE_LINK, LICENSE_LINK } from '../../constants/links';
const LICENSE_LINK = 'https://github.com/RocketChat/Rocket.Chat.ReactNative/blob/develop/LICENSE';
const SectionSeparator = React.memo(() => <View style={styles.sectionSeparatorBorder} />); const SectionSeparator = React.memo(() => <View style={styles.sectionSeparatorBorder} />);
@connect(state => ({ class SettingsView extends React.Component {
server: state.server,
useMarkdown: state.markdown.useMarkdown
}), dispatch => ({
toggleMarkdown: params => dispatch(toggleMarkdownAction(params))
}))
export default class SettingsView extends React.Component {
static navigationOptions = ({ navigation }) => ({ static navigationOptions = ({ navigation }) => ({
headerLeft: <DrawerButton navigation={navigation} />, headerLeft: <DrawerButton navigation={navigation} />,
title: I18n.t('Settings') title: I18n.t('Settings')
@ -68,6 +62,10 @@ export default class SettingsView extends React.Component {
} }
} }
shareApp = () => {
Share.share({ message: isAndroid ? PLAY_MARKET_LINK : APP_STORE_LINK });
}
onPressLicense = () => openLink(LICENSE_LINK) onPressLicense = () => openLink(LICENSE_LINK)
renderDisclosure = () => <DisclosureImage /> renderDisclosure = () => <DisclosureImage />
@ -110,6 +108,13 @@ export default class SettingsView extends React.Component {
right={this.renderDisclosure} right={this.renderDisclosure}
/> />
<Separator /> <Separator />
<ListItem
title={I18n.t('Share_this_app')}
onPress={this.shareApp}
showActionIndicator
testID='settings-view-share-app'
/>
<Separator />
<ListItem <ListItem
title={I18n.t('Theme')} title={I18n.t('Theme')}
showActionIndicator showActionIndicator
@ -117,12 +122,6 @@ export default class SettingsView extends React.Component {
testID='settings-view-theme' testID='settings-view-theme'
/> />
<Separator /> <Separator />
<ListItem
title={I18n.t('Share_this_app')}
showActionIndicator
disabled
testID='settings-view-share-app'
/>
<SectionSeparator /> <SectionSeparator />
@ -154,3 +153,14 @@ export default class SettingsView extends React.Component {
); );
} }
} }
const mapStateToProps = state => ({
server: state.server,
useMarkdown: state.markdown.useMarkdown
});
const mapDispatchToProps = dispatch => ({
toggleMarkdown: params => dispatch(toggleMarkdownAction(params))
});
export default connect(mapStateToProps, mapDispatchToProps)(SettingsView);

View File

@ -29,14 +29,7 @@ const LIMIT = 50;
const getItemLayout = (data, index) => ({ length: ROW_HEIGHT, offset: ROW_HEIGHT * index, index }); const getItemLayout = (data, index) => ({ length: ROW_HEIGHT, offset: ROW_HEIGHT * index, index });
const keyExtractor = item => item.rid; const keyExtractor = item => item.rid;
@connect(({ share }) => ({ class ShareListView extends React.Component {
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 }) => { static navigationOptions = ({ navigation }) => {
const searching = navigation.getParam('searching'); const searching = navigation.getParam('searching');
const initSearch = navigation.getParam('initSearch', () => {}); const initSearch = navigation.getParam('initSearch', () => {});
@ -407,10 +400,19 @@ export default class ShareListView extends React.Component {
render() { render() {
const { showError } = this.state; const { showError } = this.state;
return ( return (
<SafeAreaView style={styles.container} forceInset={{ bottom: 'never' }}> <SafeAreaView style={styles.container} forceInset={{ vertical: 'never' }}>
<StatusBar /> <StatusBar />
{ showError ? this.renderError() : this.renderContent() } { showError ? this.renderError() : this.renderContent() }
</SafeAreaView> </SafeAreaView>
); );
} }
} }
const mapStateToProps = (({ share }) => ({
userId: share.user && share.user.id,
token: share.user && share.user.token,
server: share.server,
baseUrl: share ? share.server : ''
}));
export default connect(mapStateToProps)(ShareListView);

View File

@ -19,15 +19,7 @@ import database from '../../lib/realm';
import { CustomHeaderButtons, Item } from '../../containers/HeaderButton'; import { CustomHeaderButtons, Item } from '../../containers/HeaderButton';
import { isReadOnly, isBlocked } from '../../utils/room'; import { isReadOnly, isBlocked } from '../../utils/room';
@connect(({ share }) => ({ class ShareView extends React.Component {
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 }) => { static navigationOptions = ({ navigation }) => {
const canSend = navigation.getParam('canSend', true); const canSend = navigation.getParam('canSend', true);
@ -250,3 +242,14 @@ export default class ShareView extends React.Component {
); );
} }
} }
const mapStateToProps = (({ 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 connect(mapStateToProps)(ShareView);

View File

@ -32,21 +32,7 @@ const permissions = [
'view-privileged-setting' 'view-privileged-setting'
]; ];
@connect(state => ({ class Sidebar extends Component {
Site_Name: state.settings.Site_Name,
user: {
id: state.login.user && state.login.user.id,
language: state.login.user && state.login.user.language,
status: state.login.user && state.login.user.status,
username: state.login.user && state.login.user.username,
token: state.login.user && state.login.user.token,
roles: state.login.user && state.login.user.roles
},
baseUrl: state.settings.Site_Url || state.server ? state.server.server : ''
}), dispatch => ({
logout: () => dispatch(logoutAction())
}))
export default class Sidebar extends Component {
static propTypes = { static propTypes = {
baseUrl: PropTypes.string, baseUrl: PropTypes.string,
navigation: PropTypes.object, navigation: PropTypes.object,
@ -282,3 +268,22 @@ export default class Sidebar extends Component {
); );
} }
} }
const mapStateToProps = state => ({
Site_Name: state.settings.Site_Name,
user: {
id: state.login.user && state.login.user.id,
language: state.login.user && state.login.user.language,
status: state.login.user && state.login.user.status,
username: state.login.user && state.login.user.username,
token: state.login.user && state.login.user.token,
roles: state.login.user && state.login.user.roles
},
baseUrl: state.settings.Site_Url || state.server ? state.server.server : ''
});
const mapDispatchToProps = dispatch => ({
logout: () => dispatch(logoutAction())
});
export default connect(mapStateToProps, mapDispatchToProps)(Sidebar);

View File

@ -21,16 +21,7 @@ import debounce from '../../utils/debounce';
const Separator = React.memo(() => <View style={styles.separator} />); const Separator = React.memo(() => <View style={styles.separator} />);
const API_FETCH_COUNT = 50; const API_FETCH_COUNT = 50;
@connect(state => ({ class ThreadMessagesView extends React.Component {
baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
user: {
id: state.login.user && state.login.user.id,
username: state.login.user && state.login.user.username,
token: state.login.user && state.login.user.token
},
useRealName: state.settings.UI_Use_Real_Name
}))
export default class ThreadMessagesView extends React.Component {
static navigationOptions = { static navigationOptions = {
title: I18n.t('Threads') title: I18n.t('Threads')
} }
@ -249,7 +240,7 @@ export default class ThreadMessagesView extends React.Component {
} }
return ( return (
<SafeAreaView style={styles.list} testID='thread-messages-view' forceInset={{ bottom: 'never' }}> <SafeAreaView style={styles.list} testID='thread-messages-view' forceInset={{ vertical: 'never' }}>
<StatusBar /> <StatusBar />
<FlatList <FlatList
data={messages} data={messages}
@ -269,3 +260,15 @@ export default class ThreadMessagesView extends React.Component {
); );
} }
} }
const mapStateToProps = state => ({
baseUrl: state.settings.Site_Url || state.server ? state.server.server : '',
user: {
id: state.login.user && state.login.user.id,
username: state.login.user && state.login.user.username,
token: state.login.user && state.login.user.token
},
useRealName: state.settings.UI_Use_Real_Name
});
export default connect(mapStateToProps)(ThreadMessagesView);

8
babel.config.js Normal file
View File

@ -0,0 +1,8 @@
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
env: {
production: {
plugins: ['transform-remove-console']
}
}
};

View File

@ -1,9 +1,11 @@
import 'react-native-console-time-polyfill'; import 'react-native-console-time-polyfill';
import './app/ReactotronConfig';
import { AppRegistry } from 'react-native'; import { AppRegistry } from 'react-native';
import { name as appName, share as shareName } from './app.json'; import { name as appName, share as shareName } from './app.json';
if (__DEV__) {
require('./app/ReactotronConfig');
}
AppRegistry.registerComponent(appName, () => require('./app/index').default); AppRegistry.registerComponent(appName, () => require('./app/index').default);
AppRegistry.registerComponent(shareName, () => require('./app/share').default); AppRegistry.registerComponent(shareName, () => require('./app/share').default);

View File

@ -1,99 +1,70 @@
platform :ios, '10.0' platform :ios, '10.0'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
require_relative '../node_modules/react-native-unimodules/cocoapods.rb' require_relative '../node_modules/react-native-unimodules/cocoapods.rb'
target 'RocketChatRN' do target 'RocketChatRN' do
# Uncomment the next line if you're using Swift or would like to use dynamic frameworks pod 'React', :path => '../node_modules/react-native/'
# use_frameworks! pod 'React-Core', :path => '../node_modules/react-native/React'
pod 'React-DevSupport', :path => '../node_modules/react-native/React'
# Pods for RocketChatRN pod 'React-fishhook', :path => '../node_modules/react-native/Libraries/fishhook'
# this is very important to have! pod 'React-RCTActionSheet', :path => '../node_modules/react-native/Libraries/ActionSheetIOS'
rn_path = '../node_modules/react-native' pod 'React-RCTAnimation', :path => '../node_modules/react-native/Libraries/NativeAnimation'
pod 'React-RCTBlob', :path => '../node_modules/react-native/Libraries/Blob'
pod 'React', path: rn_path, subspecs: [ pod 'React-RCTImage', :path => '../node_modules/react-native/Libraries/Image'
'Core', pod 'React-RCTLinking', :path => '../node_modules/react-native/Libraries/LinkingIOS'
'RCTActionSheet', pod 'React-RCTNetwork', :path => '../node_modules/react-native/Libraries/Network'
'RCTAnimation', pod 'React-RCTSettings', :path => '../node_modules/react-native/Libraries/Settings'
# 'RCTGeolocation', pod 'React-RCTText', :path => '../node_modules/react-native/Libraries/Text'
'RCTImage', pod 'React-RCTVibration', :path => '../node_modules/react-native/Libraries/Vibration'
'RCTLinkingIOS', pod 'React-RCTWebSocket', :path => '../node_modules/react-native/Libraries/WebSocket'
'RCTNetwork',
'RCTSettings',
'RCTText',
'RCTVibration',
'RCTWebSocket'
]
pod 'RNImageCropPicker', :path => '../node_modules/react-native-image-crop-picker'
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 '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-realm-path', :path => '../node_modules/react-native-realm-path'
pod 'React-cxxreact', :path => '../node_modules/react-native/ReactCommon/cxxreact'
pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi'
pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor'
pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector'
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'
pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.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 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec'
pod 'react-native-webview', :path => '../node_modules/react-native-webview'
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'
pod 'react-native-document-picker', :path => '../node_modules/react-native-document-picker'
use_native_modules!
use_unimodules! use_unimodules!
end end
target 'ShareRocketChatRN' do target 'ShareRocketChatRN' do
pod 'React', :path => '../node_modules/react-native/'
pod 'React-Core', :path => '../node_modules/react-native/React'
pod 'React-DevSupport', :path => '../node_modules/react-native/React'
pod 'React-fishhook', :path => '../node_modules/react-native/Libraries/fishhook'
pod 'React-RCTActionSheet', :path => '../node_modules/react-native/Libraries/ActionSheetIOS'
pod 'React-RCTAnimation', :path => '../node_modules/react-native/Libraries/NativeAnimation'
pod 'React-RCTBlob', :path => '../node_modules/react-native/Libraries/Blob'
pod 'React-RCTImage', :path => '../node_modules/react-native/Libraries/Image'
pod 'React-RCTLinking', :path => '../node_modules/react-native/Libraries/LinkingIOS'
pod 'React-RCTNetwork', :path => '../node_modules/react-native/Libraries/Network'
pod 'React-RCTSettings', :path => '../node_modules/react-native/Libraries/Settings'
pod 'React-RCTText', :path => '../node_modules/react-native/Libraries/Text'
pod 'React-RCTVibration', :path => '../node_modules/react-native/Libraries/Vibration'
pod 'React-RCTWebSocket', :path => '../node_modules/react-native/Libraries/WebSocket'
rn_path = '../node_modules/react-native' pod 'React-cxxreact', :path => '../node_modules/react-native/ReactCommon/cxxreact'
pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi'
pod 'React', path: rn_path, subspecs: [ pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor'
'Core', pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector'
'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 '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'
pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.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 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec'
pod 'Firebase/Core', '~> 5.20.1' use_native_modules!
pod 'Fabric', '~> 1.9.0'
pod 'Crashlytics', '~> 3.12.0'
pod 'GoogleIDFASupport', '~> 3.14.0'
pod 'Firebase/Performance', '~> 5.20.1'
end 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" target.build_configurations.each do |config|
target.remove_from_project config.build_settings['APPLICATION_EXTENSION_API_ONLY'] = 'NO'
end end
end end
end end

View File

@ -1,182 +1,260 @@
PODS: PODS:
- boost-for-react-native (1.63.0) - boost-for-react-native (1.63.0)
- Crashlytics (3.12.0): - Crashlytics (3.13.4):
- Fabric (~> 1.9.0) - Fabric (~> 1.10.2)
- DoubleConversion (1.1.6) - DoubleConversion (1.1.6)
- EXAppLoaderProvider (5.0.1) - EXAppLoaderProvider (6.0.0)
- EXConstants (5.0.1): - EXConstants (6.0.0):
- UMConstantsInterface - UMConstantsInterface
- UMCore - UMCore
- EXFileSystem (5.0.1): - EXFileSystem (6.0.2):
- UMCore - UMCore
- UMFileSystemInterface - UMFileSystemInterface
- EXHaptics (5.0.1): - EXHaptics (6.0.0):
- UMCore - UMCore
- EXPermissions (5.0.1): - EXPermissions (6.0.0):
- UMCore - UMCore
- UMPermissionsInterface - UMPermissionsInterface
- EXWebBrowser (5.0.3): - EXWebBrowser (6.0.0):
- UMCore - UMCore
- Fabric (1.9.0) - Fabric (1.10.2)
- Firebase/Core (5.20.2): - Firebase/Core (6.5.0):
- Firebase/CoreOnly - Firebase/CoreOnly
- FirebaseAnalytics (= 5.8.1) - FirebaseAnalytics (= 6.0.4)
- Firebase/CoreOnly (5.20.2): - Firebase/CoreOnly (6.5.0):
- FirebaseCore (= 5.4.1) - FirebaseCore (= 6.1.0)
- Firebase/Performance (5.20.2): - FirebaseAnalytics (6.0.4):
- Firebase/Core - FirebaseCore (~> 6.1)
- FirebasePerformance (= 2.2.4) - FirebaseInstanceID (~> 4.2)
- FirebaseABTesting (2.0.0): - GoogleAppMeasurement (= 6.0.4)
- FirebaseCore (~> 5.0) - GoogleUtilities/AppDelegateSwizzler (~> 6.0)
- Protobuf (~> 3.5) - GoogleUtilities/MethodSwizzler (~> 6.0)
- FirebaseAnalytics (5.8.1): - GoogleUtilities/Network (~> 6.0)
- FirebaseCore (~> 5.4) - "GoogleUtilities/NSData+zlib (~> 6.0)"
- FirebaseInstanceID (~> 3.8)
- GoogleAppMeasurement (= 5.8.1)
- GoogleUtilities/AppDelegateSwizzler (~> 5.2)
- GoogleUtilities/MethodSwizzler (~> 5.2)
- GoogleUtilities/Network (~> 5.2)
- "GoogleUtilities/NSData+zlib (~> 5.2)"
- nanopb (~> 0.3) - nanopb (~> 0.3)
- FirebaseCore (5.4.1): - FirebaseCore (6.1.0):
- GoogleUtilities/Environment (~> 5.2) - GoogleUtilities/Environment (~> 6.0)
- GoogleUtilities/Logger (~> 5.2) - GoogleUtilities/Logger (~> 6.0)
- FirebaseInstanceID (3.8.1): - FirebaseInstanceID (4.2.2):
- FirebaseCore (~> 5.2) - FirebaseCore (~> 6.0)
- GoogleUtilities/Environment (~> 5.2) - GoogleUtilities/Environment (~> 6.0)
- GoogleUtilities/UserDefaults (~> 5.2) - GoogleUtilities/UserDefaults (~> 6.0)
- FirebasePerformance (2.2.4):
- FirebaseAnalytics (~> 5.8)
- FirebaseInstanceID (~> 3.8)
- FirebaseRemoteConfig (~> 3.1)
- GoogleToolboxForMac/Logger (~> 2.1)
- "GoogleToolboxForMac/NSData+zlib (~> 2.1)"
- GoogleUtilities/ISASwizzler (~> 5.2)
- GoogleUtilities/MethodSwizzler (~> 5.2)
- GTMSessionFetcher/Core (~> 1.1)
- Protobuf (~> 3.5)
- FirebaseRemoteConfig (3.1.0):
- FirebaseABTesting (~> 2.0)
- FirebaseAnalytics (~> 5.3)
- FirebaseCore (~> 5.1)
- FirebaseInstanceID (~> 3.3)
- GoogleUtilities/Environment (~> 5.2)
- "GoogleUtilities/NSData+zlib (~> 5.2)"
- Protobuf (~> 3.5)
- Folly (2018.10.22.00): - Folly (2018.10.22.00):
- boost-for-react-native
- DoubleConversion
- Folly/Default (= 2018.10.22.00)
- glog
- Folly/Default (2018.10.22.00):
- boost-for-react-native - boost-for-react-native
- DoubleConversion - DoubleConversion
- glog - glog
- glog (0.3.5) - glog (0.3.5)
- GoogleAppMeasurement (5.8.1): - GoogleAppMeasurement (6.0.4):
- GoogleUtilities/AppDelegateSwizzler (~> 5.2) - GoogleUtilities/AppDelegateSwizzler (~> 6.0)
- GoogleUtilities/MethodSwizzler (~> 5.2) - GoogleUtilities/MethodSwizzler (~> 6.0)
- GoogleUtilities/Network (~> 5.2) - GoogleUtilities/Network (~> 6.0)
- "GoogleUtilities/NSData+zlib (~> 5.2)" - "GoogleUtilities/NSData+zlib (~> 6.0)"
- nanopb (~> 0.3) - nanopb (~> 0.3)
- GoogleIDFASupport (3.14.0) - GoogleUtilities/AppDelegateSwizzler (6.2.3):
- GoogleToolboxForMac/Defines (2.2.1)
- GoogleToolboxForMac/Logger (2.2.1):
- GoogleToolboxForMac/Defines (= 2.2.1)
- "GoogleToolboxForMac/NSData+zlib (2.2.1)":
- GoogleToolboxForMac/Defines (= 2.2.1)
- GoogleUtilities/AppDelegateSwizzler (5.8.0):
- GoogleUtilities/Environment - GoogleUtilities/Environment
- GoogleUtilities/Logger - GoogleUtilities/Logger
- GoogleUtilities/Network - GoogleUtilities/Network
- GoogleUtilities/Environment (5.8.0) - GoogleUtilities/Environment (6.2.3)
- GoogleUtilities/ISASwizzler (5.8.0) - GoogleUtilities/Logger (6.2.3):
- GoogleUtilities/Logger (5.8.0):
- GoogleUtilities/Environment - GoogleUtilities/Environment
- GoogleUtilities/MethodSwizzler (5.8.0): - GoogleUtilities/MethodSwizzler (6.2.3):
- GoogleUtilities/Logger - GoogleUtilities/Logger
- GoogleUtilities/Network (5.8.0): - GoogleUtilities/Network (6.2.3):
- GoogleUtilities/Logger - GoogleUtilities/Logger
- "GoogleUtilities/NSData+zlib" - "GoogleUtilities/NSData+zlib"
- GoogleUtilities/Reachability - GoogleUtilities/Reachability
- "GoogleUtilities/NSData+zlib (5.8.0)" - "GoogleUtilities/NSData+zlib (6.2.3)"
- GoogleUtilities/Reachability (5.8.0): - GoogleUtilities/Reachability (6.2.3):
- GoogleUtilities/Logger - GoogleUtilities/Logger
- GoogleUtilities/UserDefaults (5.8.0): - GoogleUtilities/UserDefaults (6.2.3):
- GoogleUtilities/Logger - GoogleUtilities/Logger
- GTMSessionFetcher/Core (1.2.2) - libwebp (1.0.2):
- libwebp/core (= 1.0.2)
- libwebp/dec (= 1.0.2)
- libwebp/demux (= 1.0.2)
- libwebp/dsp (= 1.0.2)
- libwebp/enc (= 1.0.2)
- libwebp/mux (= 1.0.2)
- libwebp/utils (= 1.0.2)
- libwebp/webp (= 1.0.2)
- libwebp/core (1.0.2):
- libwebp/webp
- libwebp/dec (1.0.2):
- libwebp/core
- libwebp/demux (1.0.2):
- libwebp/core
- libwebp/dsp (1.0.2):
- libwebp/core
- libwebp/enc (1.0.2):
- libwebp/core
- libwebp/mux (1.0.2):
- libwebp/core
- libwebp/utils (1.0.2):
- libwebp/core
- libwebp/webp (1.0.2)
- nanopb (0.3.901): - nanopb (0.3.901):
- nanopb/decode (= 0.3.901) - nanopb/decode (= 0.3.901)
- nanopb/encode (= 0.3.901) - nanopb/encode (= 0.3.901)
- nanopb/decode (0.3.901) - nanopb/decode (0.3.901)
- nanopb/encode (0.3.901) - nanopb/encode (0.3.901)
- Protobuf (3.7.0)
- QBImagePickerController (3.4.0) - QBImagePickerController (3.4.0)
- React (0.59.8): - React (0.60.4):
- React/Core (= 0.59.8) - React-Core (= 0.60.4)
- react-native-document-picker (3.2.2): - React-DevSupport (= 0.60.4)
- React-RCTActionSheet (= 0.60.4)
- React-RCTAnimation (= 0.60.4)
- React-RCTBlob (= 0.60.4)
- React-RCTImage (= 0.60.4)
- React-RCTLinking (= 0.60.4)
- React-RCTNetwork (= 0.60.4)
- React-RCTSettings (= 0.60.4)
- React-RCTText (= 0.60.4)
- React-RCTVibration (= 0.60.4)
- React-RCTWebSocket (= 0.60.4)
- React-Core (0.60.4):
- Folly (= 2018.10.22.00)
- React-cxxreact (= 0.60.4)
- React-jsiexecutor (= 0.60.4)
- yoga (= 0.60.4.React)
- React-cxxreact (0.60.4):
- boost-for-react-native (= 1.63.0)
- DoubleConversion
- Folly (= 2018.10.22.00)
- glog
- React-jsinspector (= 0.60.4)
- React-DevSupport (0.60.4):
- React-Core (= 0.60.4)
- React-RCTWebSocket (= 0.60.4)
- React-fishhook (0.60.4)
- React-jsi (0.60.4):
- boost-for-react-native (= 1.63.0)
- DoubleConversion
- Folly (= 2018.10.22.00)
- glog
- React-jsi/Default (= 0.60.4)
- React-jsi/Default (0.60.4):
- boost-for-react-native (= 1.63.0)
- DoubleConversion
- Folly (= 2018.10.22.00)
- glog
- React-jsiexecutor (0.60.4):
- DoubleConversion
- Folly (= 2018.10.22.00)
- glog
- React-cxxreact (= 0.60.4)
- React-jsi (= 0.60.4)
- React-jsinspector (0.60.4)
- react-native-document-picker (3.2.4):
- React - React
- react-native-orientation-locker (1.1.5): - react-native-keyboard-input (5.3.1):
- React
- react-native-keyboard-tracking-view (5.5.0):
- React
- react-native-notifications (2.0.3):
- React
- react-native-orientation-locker (1.1.6):
- React - React
- react-native-realm-path (1.2.11): - react-native-realm-path (1.2.11):
- React - 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-video (5.0.0):
- React - React
- React/Core (0.59.8): - react-native-video/Video (= 5.0.0)
- yoga (= 0.59.8.React) - react-native-video/Video (5.0.0):
- React/fishhook (0.59.8) - React
- React/RCTActionSheet (0.59.8): - react-native-webview (6.8.0):
- React/Core - React
- React/RCTAnimation (0.59.8): - React-RCTActionSheet (0.60.4):
- React/Core - React-Core (= 0.60.4)
- React/RCTBlob (0.59.8): - React-RCTAnimation (0.60.4):
- React/Core - React-Core (= 0.60.4)
- React/RCTImage (0.59.8): - React-RCTBlob (0.60.4):
- React/Core - React-Core (= 0.60.4)
- React/RCTNetwork - React-RCTNetwork (= 0.60.4)
- React/RCTLinkingIOS (0.59.8): - React-RCTWebSocket (= 0.60.4)
- React/Core - React-RCTImage (0.60.4):
- React/RCTNetwork (0.59.8): - React-Core (= 0.60.4)
- React/Core - React-RCTNetwork (= 0.60.4)
- React/RCTSettings (0.59.8): - React-RCTLinking (0.60.4):
- React/Core - React-Core (= 0.60.4)
- React/RCTText (0.59.8): - React-RCTNetwork (0.60.4):
- React/Core - React-Core (= 0.60.4)
- React/RCTVibration (0.59.8): - React-RCTSettings (0.60.4):
- React/Core - React-Core (= 0.60.4)
- React/RCTWebSocket (0.59.8): - React-RCTText (0.60.4):
- React/Core - React-Core (= 0.60.4)
- React/fishhook - React-RCTVibration (0.60.4):
- React/RCTBlob - React-Core (= 0.60.4)
- React-RCTWebSocket (0.60.4):
- React-Core (= 0.60.4)
- React-fishhook (= 0.60.4)
- rn-extensions-share (2.3.10): - rn-extensions-share (2.3.10):
- React - React
- RNDeviceInfo (1.6.1): - rn-fetch-blob (0.10.16):
- React-Core
- RNAudio (4.3.0):
- React - React
- RNImageCropPicker (0.24.1): - RNDeviceInfo (2.3.2):
- React
- RNFastImage (7.0.2):
- React
- SDWebImage (~> 5.0)
- SDWebImageWebPCoder (~> 0.2.3)
- RNFirebase (5.5.6):
- Firebase/Core
- React
- RNFirebase/Crashlytics (= 5.5.6)
- RNFirebase/Crashlytics (5.5.6):
- Crashlytics
- Fabric
- Firebase/Core
- React
- RNGestureHandler (1.3.0):
- React
- RNImageCropPicker (0.25.0):
- QBImagePickerController - QBImagePickerController
- React/Core - React-Core
- React-RCTImage
- RSKImageCropper - RSKImageCropper
- RNLocalize (1.1.4): - RNLocalize (1.1.4):
- React - React
- RNScreens (1.0.0-alpha.22): - RNScreens (1.0.0-alpha.23):
- React - React
- RSKImageCropper (2.2.1) - RNUserDefaults (1.3.5):
- UMBarCodeScannerInterface (2.0.1) - React
- UMCameraInterface (2.0.1) - RNVectorIcons (6.6.0):
- UMConstantsInterface (2.0.1) - React
- UMCore (2.0.1) - RSKImageCropper (2.2.3)
- UMFaceDetectorInterface (2.0.1) - SDWebImage (5.0.6):
- UMFileSystemInterface (2.0.1) - SDWebImage/Core (= 5.0.6)
- UMFontInterface (2.0.1) - SDWebImage/Core (5.0.6)
- UMImageLoaderInterface (2.0.1) - SDWebImageWebPCoder (0.2.3):
- UMPermissionsInterface (2.0.1) - libwebp (~> 1.0)
- UMReactNativeAdapter (2.0.1): - SDWebImage/Core (~> 5.0)
- UMBarCodeScannerInterface (3.0.0)
- UMCameraInterface (3.0.0)
- UMConstantsInterface (3.0.0)
- UMCore (3.0.2)
- UMFaceDetectorInterface (3.0.0)
- UMFileSystemInterface (3.0.0)
- UMFontInterface (3.0.0)
- UMImageLoaderInterface (3.0.0)
- UMPermissionsInterface (3.0.0)
- UMReactNativeAdapter (3.0.0):
- React - React
- UMCore - UMCore
- UMFontInterface - UMFontInterface
- UMSensorsInterface (2.0.1) - UMSensorsInterface (3.0.0)
- UMTaskManagerInterface (2.0.1) - UMTaskManagerInterface (3.0.0)
- yoga (0.59.8.React) - yoga (0.60.4.React)
DEPENDENCIES: DEPENDENCIES:
- Crashlytics (~> 3.12.0)
- DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
- EXAppLoaderProvider (from `../node_modules/expo-app-loader-provider/ios`) - EXAppLoaderProvider (from `../node_modules/expo-app-loader-provider/ios`)
- EXConstants (from `../node_modules/expo-constants/ios`) - EXConstants (from `../node_modules/expo-constants/ios`)
@ -184,32 +262,47 @@ DEPENDENCIES:
- EXHaptics (from `../node_modules/expo-haptics/ios`) - EXHaptics (from `../node_modules/expo-haptics/ios`)
- EXPermissions (from `../node_modules/expo-permissions/ios`) - EXPermissions (from `../node_modules/expo-permissions/ios`)
- EXWebBrowser (from `../node_modules/expo-web-browser/ios`) - EXWebBrowser (from `../node_modules/expo-web-browser/ios`)
- Fabric (~> 1.9.0)
- Firebase/Core (~> 5.20.1)
- Firebase/Performance (~> 5.20.1)
- 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) - React (from `../node_modules/react-native/`)
- React-Core (from `../node_modules/react-native/React`)
- React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`)
- React-DevSupport (from `../node_modules/react-native/React`)
- React-fishhook (from `../node_modules/react-native/Libraries/fishhook`)
- React-jsi (from `../node_modules/react-native/ReactCommon/jsi`)
- React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`)
- React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`)
- react-native-document-picker (from `../node_modules/react-native-document-picker`) - react-native-document-picker (from `../node_modules/react-native-document-picker`)
- react-native-keyboard-input (from `../node_modules/react-native-keyboard-input`)
- react-native-keyboard-tracking-view (from `../node_modules/react-native-keyboard-tracking-view`)
- react-native-notifications (from `../node_modules/react-native-notifications`)
- 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-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-video (from `../node_modules/react-native-video`)
- 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-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`)
- React/RCTActionSheet (from `../node_modules/react-native`) - React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`)
- React/RCTAnimation (from `../node_modules/react-native`) - React-RCTBlob (from `../node_modules/react-native/Libraries/Blob`)
- React/RCTImage (from `../node_modules/react-native`) - React-RCTImage (from `../node_modules/react-native/Libraries/Image`)
- React/RCTLinkingIOS (from `../node_modules/react-native`) - React-RCTLinking (from `../node_modules/react-native/Libraries/LinkingIOS`)
- React/RCTNetwork (from `../node_modules/react-native`) - React-RCTNetwork (from `../node_modules/react-native/Libraries/Network`)
- React/RCTSettings (from `../node_modules/react-native`) - React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`)
- React/RCTText (from `../node_modules/react-native`) - React-RCTText (from `../node_modules/react-native/Libraries/Text`)
- React/RCTVibration (from `../node_modules/react-native`) - React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`)
- React/RCTWebSocket (from `../node_modules/react-native`) - React-RCTWebSocket (from `../node_modules/react-native/Libraries/WebSocket`)
- rn-extensions-share (from `../node_modules/rn-extensions-share`) - rn-extensions-share (from `../node_modules/rn-extensions-share`)
- rn-fetch-blob (from `../node_modules/rn-fetch-blob`)
- RNAudio (from `../node_modules/react-native-audio`)
- RNDeviceInfo (from `../node_modules/react-native-device-info`) - RNDeviceInfo (from `../node_modules/react-native-device-info`)
- RNFastImage (from `../node_modules/react-native-fast-image`)
- RNFirebase (from `../node_modules/react-native-firebase/ios`)
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
- 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`) - RNLocalize (from `../node_modules/react-native-localize`)
- RNScreens (from `../node_modules/react-native-screens`) - RNScreens (from `../node_modules/react-native-screens`)
- RNUserDefaults (from `../node_modules/rn-user-defaults`)
- RNVectorIcons (from `../node_modules/react-native-vector-icons`)
- 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`)
- UMConstantsInterface (from `../node_modules/unimodules-constants-interface/ios`) - UMConstantsInterface (from `../node_modules/unimodules-constants-interface/ios`)
@ -230,21 +323,17 @@ SPEC REPOS:
- Crashlytics - Crashlytics
- Fabric - Fabric
- Firebase - Firebase
- FirebaseABTesting
- FirebaseAnalytics - FirebaseAnalytics
- FirebaseCore - FirebaseCore
- FirebaseInstanceID - FirebaseInstanceID
- FirebasePerformance
- FirebaseRemoteConfig
- GoogleAppMeasurement - GoogleAppMeasurement
- GoogleIDFASupport
- GoogleToolboxForMac
- GoogleUtilities - GoogleUtilities
- GTMSessionFetcher - libwebp
- nanopb - nanopb
- Protobuf
- QBImagePickerController - QBImagePickerController
- RSKImageCropper - RSKImageCropper
- SDWebImage
- SDWebImageWebPCoder
EXTERNAL SOURCES: EXTERNAL SOURCES:
DoubleConversion: DoubleConversion:
@ -272,27 +361,83 @@ EXTERNAL SOURCES:
glog: glog:
: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-Core:
:path: "../node_modules/react-native/React"
React-cxxreact:
:path: "../node_modules/react-native/ReactCommon/cxxreact"
React-DevSupport:
:path: "../node_modules/react-native/React"
React-fishhook:
:path: "../node_modules/react-native/Libraries/fishhook"
React-jsi:
:path: "../node_modules/react-native/ReactCommon/jsi"
React-jsiexecutor:
:path: "../node_modules/react-native/ReactCommon/jsiexecutor"
React-jsinspector:
:path: "../node_modules/react-native/ReactCommon/jsinspector"
react-native-document-picker: react-native-document-picker:
:path: "../node_modules/react-native-document-picker" :path: "../node_modules/react-native-document-picker"
react-native-keyboard-input:
:path: "../node_modules/react-native-keyboard-input"
react-native-keyboard-tracking-view:
:path: "../node_modules/react-native-keyboard-tracking-view"
react-native-notifications:
:path: "../node_modules/react-native-notifications"
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: react-native-realm-path:
:path: "../node_modules/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-video:
:path: "../node_modules/react-native-video"
react-native-webview: react-native-webview:
:path: "../node_modules/react-native-webview" :path: "../node_modules/react-native-webview"
React-RCTActionSheet:
:path: "../node_modules/react-native/Libraries/ActionSheetIOS"
React-RCTAnimation:
:path: "../node_modules/react-native/Libraries/NativeAnimation"
React-RCTBlob:
:path: "../node_modules/react-native/Libraries/Blob"
React-RCTImage:
:path: "../node_modules/react-native/Libraries/Image"
React-RCTLinking:
:path: "../node_modules/react-native/Libraries/LinkingIOS"
React-RCTNetwork:
:path: "../node_modules/react-native/Libraries/Network"
React-RCTSettings:
:path: "../node_modules/react-native/Libraries/Settings"
React-RCTText:
:path: "../node_modules/react-native/Libraries/Text"
React-RCTVibration:
:path: "../node_modules/react-native/Libraries/Vibration"
React-RCTWebSocket:
:path: "../node_modules/react-native/Libraries/WebSocket"
rn-extensions-share: rn-extensions-share:
:path: "../node_modules/rn-extensions-share" :path: "../node_modules/rn-extensions-share"
rn-fetch-blob:
:path: "../node_modules/rn-fetch-blob"
RNAudio:
:path: "../node_modules/react-native-audio"
RNDeviceInfo: RNDeviceInfo:
:path: "../node_modules/react-native-device-info" :path: "../node_modules/react-native-device-info"
RNFastImage:
:path: "../node_modules/react-native-fast-image"
RNFirebase:
:path: "../node_modules/react-native-firebase/ios"
RNGestureHandler:
:path: "../node_modules/react-native-gesture-handler"
RNImageCropPicker: RNImageCropPicker:
:path: "../node_modules/react-native-image-crop-picker" :path: "../node_modules/react-native-image-crop-picker"
RNLocalize: RNLocalize:
:path: "../node_modules/react-native-localize" :path: "../node_modules/react-native-localize"
RNScreens: RNScreens:
:path: "../node_modules/react-native-screens" :path: "../node_modules/react-native-screens"
RNUserDefaults:
:path: "../node_modules/rn-user-defaults"
RNVectorIcons:
:path: "../node_modules/react-native-vector-icons"
UMBarCodeScannerInterface: UMBarCodeScannerInterface:
:path: !ruby/object:Pathname :path: !ruby/object:Pathname
path: "../node_modules/unimodules-barcode-scanner-interface/ios" path: "../node_modules/unimodules-barcode-scanner-interface/ios"
@ -334,58 +479,82 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS: SPEC CHECKSUMS:
boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c
Crashlytics: 07fb167b1694128c1c9a5a5cc319b0e9c3ca0933 Crashlytics: 2dfd686bcb918dc10ee0e76f7f853fe42c7bd552
DoubleConversion: bb338842f62ab1d708ceb63ec3d999f0f3d98ecd DoubleConversion: 5805e889d232975c086db112ece9ed034df7a0b2
EXAppLoaderProvider: 8f2c04a0a8d9be91f7c37c2b8824077ee5d4bc01 EXAppLoaderProvider: 7a8185228d8ba9e689a0e2d6d957fe9bdd49c8a0
EXConstants: 9fe56eec8bf0a3ee9beb8f3381fa91340a5b1e57 EXConstants: 5d81e84ca71b9a552529889cc798b4a04e9e22b3
EXFileSystem: 96624bd4b93a0684335c421a6567a92b25bd7ddb EXFileSystem: 091907902fcec9f9182b656fdead41a82f30986a
EXHaptics: 6d594612afa321bfc8e167bdfb0b47f940f8f537 EXHaptics: f84c93d605e0905c47654e4a6e5dfbff78ed6906
EXPermissions: 8e05008ed4fc8c9be6c17ea95301fc3f3f005a7b EXPermissions: 99e52dc3e5f8e55153f1958004f6df2a30a1f2f5
EXWebBrowser: e03894b4583bb726e5ea05d01b341ba00134c2b5 EXWebBrowser: def838b95aa9d396f9ce71ace4e614ee16e7ee30
Fabric: f988e33c97f08930a413e08123064d2e5f68d655 Fabric: 706c8b8098fff96c33c0db69cbf81f9c551d0d74
Firebase: 0c8cf33f266410c61ab3e2265cfa412200351d9c Firebase: dedc9e48ea3f3649ad5f6b982f8a0c73508a14b5
FirebaseABTesting: 1f50b8d50f5e3469eea54e7463a7b7fe221d1f5e FirebaseAnalytics: 3fb375bc9d13779add4039716f868d233a473fad
FirebaseAnalytics: ece1aa57a4f43c64d53a648b5a5e05151aae947b FirebaseCore: aecf02fb2274ec361b9bebeac112f5daa18273bd
FirebaseCore: f1a9a8be1aee4bf71a2fc0f4096df6788bdfda61 FirebaseInstanceID: 662b8108a09fe9ed01aafdedba100fde8536b0f6
FirebaseInstanceID: a122b0c258720cf250551bb2bedf48c699f80d90 Folly: 30e7936e1c45c08d884aa59369ed951a8e68cf51
FirebasePerformance: 25ecee2a260bcf398d7f32d6f4804438df953100 glog: 1f3da668190260b06b429bb211bfbee5cd790c28
FirebaseRemoteConfig: 7e11c65f0769c09bff6947997c209515058c5318 GoogleAppMeasurement: 183bd916af7f80deb67c01888368f1108d641832
Folly: de497beb10f102453a1afa9edbf8cf8a251890de GoogleUtilities: d2b0e277a95962e09bb27f5cd42f5f0b6a506c7d
glog: aefd1eb5dda2ab95ba0938556f34b98e2da3a60d libwebp: b068a3bd7c45f7460f6715be7bed1a18fd5d6b48
GoogleAppMeasurement: ffe513e90551844a739e7bcbb1d2aca1c28a4338
GoogleIDFASupport: aaf8c10bd429abb1c15349d5252244f5eda8ead1
GoogleToolboxForMac: b3553629623a3b1bff17f555e736cd5a6d95ad55
GoogleUtilities: 04fce34bcd5620c1ee76fb79172105c74a4df335
GTMSessionFetcher: 61bb0f61a4cb560030f1222021178008a5727a23
nanopb: 2901f78ea1b7b4015c860c2fdd1ea2fee1a18d48 nanopb: 2901f78ea1b7b4015c860c2fdd1ea2fee1a18d48
Protobuf: 7a877b7f3e5964e3fce995e2eb323dbc6831bb5a
QBImagePickerController: d54cf93db6decf26baf6ed3472f336ef35cae022 QBImagePickerController: d54cf93db6decf26baf6ed3472f336ef35cae022
React: 76e6aa2b87d05eb6cccb6926d72685c9a07df152 React: ff7ee2ae5ee1c1d9ae2183b4111045b25294bb01
react-native-document-picker: 94a07ce0494c559e2ae9fa86621d6c624d810fec React-Core: 8e0ea421cae5609d2562850f98421b15030476fa
react-native-orientation-locker: 132a63bab4dddd2a5709f6f7935ad9676b0af7c5 React-cxxreact: 326880209990151a7182a813311054e9772ba510
React-DevSupport: e9f10e6721e78e87622fc985db695c0c0168db8a
React-fishhook: 1f0e5b08449403fa75c3fb3881a0beefbada14af
React-jsi: 21d3153b1153fbf6510a92b6b11e33e725cb7432
React-jsiexecutor: 7549641e48bafae7bfee3f3ea19bf4901639c5de
React-jsinspector: 73f24a02fa684ed6a2b828ba116874a2191ded88
react-native-document-picker: c36bf5f067a581657ecaf7124dcd921a8be19061
react-native-keyboard-input: 2a01e0aceac330592bbe9b3101761bb9d8e6d1fb
react-native-keyboard-tracking-view: 1ebd24a2b6ca2314549aa51775995678094bffa1
react-native-notifications: 3385ff44e246c62e0eabe7ee414fc5e2e6a61fec
react-native-orientation-locker: 23918c400376a7043e752c639c122fcf6bce8f1c
react-native-realm-path: 868473ea0bc4629850f1ec51a70d81055c06d091 react-native-realm-path: 868473ea0bc4629850f1ec51a70d81055c06d091
react-native-splash-screen: 200d11d188e2e78cea3ad319964f6142b6384865 react-native-splash-screen: 200d11d188e2e78cea3ad319964f6142b6384865
react-native-webview: f3e28b48461c78db833f727feec08b13285e7b61 react-native-video: 6555881252c8ca039760e1cd6df28ac28ffb2baf
react-native-webview: 9f588ea09ede9bd1f5443f4aa4ddfadeb51fcd28
React-RCTActionSheet: 9f71d7ae3e8fb10e08d162cbf14c621349dbfab3
React-RCTAnimation: 981d8c95b0e30918a9832ccac32af83562a27fae
React-RCTBlob: 21e73d1020a302a75fed30dbaee9f15287b80baa
React-RCTImage: c0bc6ac0926517b6fb7e4c279b04843113e99d1d
React-RCTLinking: 1af3f3c59114bed3deec0107c62e7efad0932ee5
React-RCTNetwork: 35df9de46e19cda5c56380be1a7759b9b8cb2fcd
React-RCTSettings: f580504c2cd1f44e25add10fb9ed3954f67f8ac5
React-RCTText: e0f224898b13af9aa036ea7cb3d438daa68c1044
React-RCTVibration: 0bea40cd51bd089bd591a8f74c86e91fdf2666c5
React-RCTWebSocket: 163873f4cdd5f1058a9483443404fc3801581cb6
rn-extensions-share: 4bfee75806ad54aadeff1dfa535697a6345a50b8 rn-extensions-share: 4bfee75806ad54aadeff1dfa535697a6345a50b8
RNDeviceInfo: 958a1ed6f94e04557b865b8ef848cfc83db0ebba rn-fetch-blob: 651b8d076b43d0d7aa294a3d9ec16c00aab8bef9
RNImageCropPicker: 6134b66a3d5bc13e2895a97c630a4254006902b4 RNAudio: cae2991f2dccb75163f260b60da8051717b959fa
RNDeviceInfo: 17e34f6dd902f08d88cbe2c0b7a01be948d43641
RNFastImage: 9b0c22643872bb7494c8d87bbbb66cc4c0d9e7a2
RNFirebase: ac0de8b24c6f91ae9459575491ed6a77327619c6
RNGestureHandler: 5329a942fce3d41c68b84c2c2276ce06a696d8b0
RNImageCropPicker: 0a731d984e64ee4c28bddaa7ce52262e4b80979f
RNLocalize: 62a949d2ec5bee0eb8f39a80a48f01e2f4f67080 RNLocalize: 62a949d2ec5bee0eb8f39a80a48f01e2f4f67080
RNScreens: 720a9e6968beb73e8196239801e887d8401f86ed RNScreens: f28b48b8345f2f5f39ed6195518291515032a788
RSKImageCropper: 98296ad26b41753f796b6898d015509598f13d97 RNUserDefaults: 8a4928443510aa99e4ccb3b53f1bf186593d690b
UMBarCodeScannerInterface: d5602e23de37f95bb4ee49ee3b2711e128058ae9 RNVectorIcons: 0bb4def82230be1333ddaeee9fcba45f0b288ed4
UMCameraInterface: dde8491778ed062348e569bad33a890e60c32c9d RSKImageCropper: a446db0e8444a036b34f3c43db01b2373baa4b2a
UMConstantsInterface: de48a63a5af572fc4dcc0e68051b00503b83e301 SDWebImage: 920f1a2ff1ca8296ad34f6e0510a1ef1d70ac965
UMCore: 047dc01ae4ccdd0c993f2c190f2489e5409c3ad0 SDWebImageWebPCoder: 7568737603c50f6237850afedd7e9e28e5917e6b
UMFaceDetectorInterface: badd9e3d206f5ba254c85a26afa43da06638575f UMBarCodeScannerInterface: 84ea2d6b58ff0dc27ef9b68bab71286be18ee020
UMFileSystemInterface: ff9a18c26ee6321dc21a3f9663efe3a55313d4db UMCameraInterface: 26b26005d1756a0d5f4f04f1e168e39ea9154535
UMFontInterface: 0575f33184974a38f3528a4750729c7f5256b848 UMConstantsInterface: 038bacb19de12b6fd328c589122c8dc977cccf61
UMImageLoaderInterface: ee8642347161d66272e841377a888957feb1f48e UMCore: 733094f43f7244c60ce1f0592d00013ed68fa52c
UMPermissionsInterface: 2238fe9d7f99457a5cfe7f3140c2521c5bf453a6 UMFaceDetectorInterface: c9c3ae4cb045421283667a1698c2f31331f55e3f
UMReactNativeAdapter: 110be971ff044f8cfd37cbf565a264cd79858391 UMFileSystemInterface: e9adc71027017de38eaf7d05fa58b2848ecb3797
UMSensorsInterface: cda3ec177c7ff0a138e3135414b4a29013389358 UMFontInterface: f0c5846977ee8a93d7cfa8ae7e666772c727d195
UMTaskManagerInterface: 296793ab2a7e181fe5ebe2ba9b40ae208ab4b8fa UMImageLoaderInterface: 36e54e570acc4d720856f03ceebc441f73ea472c
yoga: 92b2102c3d373d1a790db4ab761d2b0ffc634f64 UMPermissionsInterface: 938d010c74c43fcefc9bb990633a7c5a1631267e
UMReactNativeAdapter: 131ea2b944ade8035f0b54c6570c405f6000548d
UMSensorsInterface: 0ed023ce9b96f2ca6fada7bda05b7760da60b293
UMTaskManagerInterface: 8664abd37a00715727e60df9ecd65e42ba47b548
yoga: c2c050f6ae6e222534760cc82f559b89214b67e2
PODFILE CHECKSUM: bfa056aa2707bd200eb8a39ada130c51b702380c PODFILE CHECKSUM: c9c0e4d6e34886493451eb2fdba48bc7e89d4551
COCOAPODS: 1.6.2 COCOAPODS: 1.6.2

View File

@ -1,39 +1,23 @@
![Crashlytics Header](https://docs.fabric.io/ios/cocoapod-readmes/cocoapods-crashlytics-header.png)
Part of [Google Fabric](https://get.fabric.io), [Crashlytics](http://try.crashlytics.com/) offers the most powerful, yet lightest weight crash reporting solution for iOS. Crashlytics also provides real-time analytics through [Answers](https://answers.io/) and app distributions to testers using [Beta](http://try.crashlytics.com/beta/). # Crashlytics
## Overview
[Crashlytics](https://firebase.google.com/docs/crashlytics/get-started?platform=ios) offers the most powerful, yet lightest weight crash reporting solution for iOS.
## Setup ## Setup
1. Visit [https://fabric.io/sign_up](https://fabric.io/sign_up) to create your Fabric account and to download Fabric.app. To start using Crashlytics, there are two options:
1. Open Fabric.app, login and select the Crashlytics SDK. 1) The recommended way is to go to the [Firebase Crashlytics Docs](https://firebase.google.com/docs/crashlytics/get-started?platform=ios) and follow the directions there.
![Fabric Plugin](https://docs.fabric.io/ios/cocoapod-readmes/cocoapods-fabric-plugin.png) 2) If you aren't using Firebase yet, go to [Fabric Kits](https://fabric.io/kits), and follow the directions for Crashlytics.
1. The Fabric app automatically detects when a project uses CocoaPods and gives you the option to install via the Podfile or Xcode.
![Fabric Installation Options](https://docs.fabric.io/ios/cocoapod-readmes/cocoapods-pod-installation-option.png)
1. Select the Podfile option and follow the installation instructions to update your Podfile. **Note:** the Crashlytics Pod includes Answers. If you have Answers included as a separate Pod it should be removed from your Podfile to avoid duplicate symbol errors.
```
pod 'Fabric'
pod 'Crashlytics'
```
1. Run `pod install`
1. Add a Run Script Build Phase and build your app.
![Fabric Run Script Build Phase](https://docs.fabric.io/ios/cocoapod-readmes/cocoapods-rsbp.png)
1. Initialize the SDK by inserting code outlined in the Fabric.app.
1. Run your app to finish the installation.
## Resources ## Resources
* [Documentation](https://docs.fabric.io/apple/crashlytics/overview.html) * [API Reference](https://firebase.google.com/docs/reference/ios/crashlytics/api/reference/Classes)
* [Forums](https://stackoverflow.com/questions/tagged/google-fabric) * [Forums](https://stackoverflow.com/questions/tagged/google-fabric)
* [Website](http://try.crashlytics.com/) * [Website](https://firebase.google.com/docs/crashlytics)
* Follow us on Twitter: [@fabric](https://twitter.com/fabric) and [@crashlytics](https://twitter.com/crashlytics) * Follow us on Twitter: [@crashlytics](https://twitter.com/crashlytics)

Binary file not shown.

Binary file not shown.

View File

@ -3,26 +3,71 @@
# run # run
# #
# Copyright (c) 2015 Crashlytics. All rights reserved. # Copyright (c) 2015 Crashlytics. All rights reserved.
#
#
# This script is meant to be run as a Run Script in the "Build Phases" section
# of your Xcode project. It sends debug symbols to symbolicate stacktraces,
# sends build events to track versions, and onboard apps for Crashlytics.
#
# This script calls upload-symbols twice:
#
# 1) First it calls upload-symbols synchronously in "validation" mode. If the
# script finds issues with the build environment, it will report errors to Xcode.
# In validation mode it exits before doing any time consuming work.
#
# 2) Then it calls upload-symbols in the background to actually send the build
# event and upload symbols. It does this in the background so that it doesn't
# slow down your builds. If an error happens here, you won't see it in Xcode.
#
# You can find the output for the background execution in Console.app, by
# searching for "upload-symbols".
#
# If you want verbose output, you can pass the --debug flag to this script
#
# Figure out where we're being called from # Figure out where we're being called from
DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
# Quote path in case of spaces or special chars # If the first argument is specified without a dash, treat it as the Fabric API
DIR="\"${DIR}" # Key and add it as an argument
if [ -z "$1" ] || [[ $1 == -* ]]; then
API_KEY_ARG=""
else
API_KEY_ARG="-a $1"; shift
fi
PATH_SEP="/" # If a second argument is specified without a dash, treat it as the Build Secret
VALIDATE_COMMAND="uploadDSYM\" $@ validate run-script" # and add it as an argument
UPLOAD_COMMAND="uploadDSYM\" $@ run-script" if [ -z "$1" ] || [[ $1 == -* ]]; then
BUILD_SECRET_ARG=""
else
BUILD_SECRET_ARG="-bs $1"; shift
fi
# Ensure params are as expected, run in sync mode to validate # Build up the arguments list, passing through any flags added after the
eval $DIR$PATH_SEP$VALIDATE_COMMAND # API Key and Build Secret
ARGUMENTS="$API_KEY_ARG $BUILD_SECRET_ARG $@"
VALIDATE_ARGUMENTS="$ARGUMENTS --build-phase --validate"
UPLOAD_ARGUMENTS="$ARGUMENTS --build-phase"
# Quote the path to handle folders with special characters
COMMAND_PATH="\"$DIR/upload-symbols\" "
# Ensure params are as expected, run in sync mode to validate,
# and cause a build error if validation fails
eval $COMMAND_PATH$VALIDATE_ARGUMENTS
return_code=$? return_code=$?
if [[ $return_code != 0 ]]; then if [[ $return_code != 0 ]]; then
exit $return_code exit $return_code
fi fi
# Verification passed, upload dSYM in background to prevent Xcode from waiting # Verification passed, convert and upload cSYMs in the background to prevent
# Note: Validation is performed again before upload. # build delays
# Output can still be found in Console.app #
eval $DIR$PATH_SEP$UPLOAD_COMMAND > /dev/null 2>&1 & # Note: Validation is performed again at this step before upload
#
# Note: Output can still be found in Console.app, by searching for
# "upload-symbols"
#
eval $COMMAND_PATH$UPLOAD_ARGUMENTS > /dev/null 2>&1 &

BIN
ios/Pods/Crashlytics/iOS/Crashlytics.framework/upload-symbols generated vendored Executable file

Binary file not shown.

Binary file not shown.

View File

@ -1,38 +1,23 @@
![Fabric Header](https://docs.fabric.io/ios/cocoapod-readmes/cocoapods-fabric-header.png)
# Fabric # Fabric
## Overview ## Overview
[Fabric](https://get.fabric.io) provides developers with the tools they need to build the best apps. Developed and maintained by Google and the team that built Crashlytics, Fabric provides an easy way to manage all your SDKs so that youll never have to worry about tedious configurations or juggling different accounts. We let you get right into coding and building the next big app. [Fabric](https://get.fabric.io) provides developers with the tools they need to build the best apps. Developed and maintained by Google and the team that built Crashlytics.
For a full list of SDKs provided through Fabric visit [https://fabric.io/kits](https://fabric.io/kits).
To follow the migration to Firebase, check out the [Fabric Roadmap](https://get.fabric.io/roadmap).
For a full list of SDK provided through Fabric visit [https://fabric.io/kits](https://fabric.io/kits).
## Setup ## Setup
The Fabric Pod is a dependency for all Fabric SDKs and is included when installing any Fabric related Pods. General setup instructions are shown below; however, these vary depending on the selected SDK. Fabric is a dependency for the Crashlytics SDK. To start using Crashlytics, there are two options:
1. Visit [https://fabric.io/sign_up](https://fabric.io/sign_up) to create your Fabric account and to download Fabric.app. 1) The recommended way is to go to the [Firebase Crashlytics Docs](https://firebase.google.com/docs/crashlytics/get-started?platform=ios) and follow the directions there.
1. Open Fabric.app, login and select an SDK to install. 2) If you aren't using Firebase yet, go to [Fabric Kits](https://fabric.io/kits), and follow the directions for Crashlytics.
![Fabric Plugin](https://docs.fabric.io/ios/cocoapod-readmes/cocoapods-fabric-plugin.png)
1. The Fabric app automatically detects when a project uses CocoaPods and gives you the option to install via the Podfile or Xcode.
![Fabric Installation Options](https://docs.fabric.io/ios/cocoapod-readmes/cocoapods-pod-installation-option.png)
1. Select the Podfile option and follow the installation instructions to update your Podfile. Note: the example below is for the Crashlytics SDK. The instructions will vary based on the selected SDK.
![Fabric Podfile Instructions](https://docs.fabric.io/ios/cocoapod-readmes/cocoapods-podfile-instructions.png)
1. Add a Run Script Build Phase and build your app.
![Fabric Run Script Build Phase](https://docs.fabric.io/ios/cocoapod-readmes/cocoapods-rsbp.png)
1. Initialize the SDK by inserting code outlined in Fabric.app.
1. Run your app to finish the installation.
## Resources ## Resources

Binary file not shown.

Binary file not shown.

View File

@ -3,26 +3,71 @@
# run # run
# #
# Copyright (c) 2015 Crashlytics. All rights reserved. # Copyright (c) 2015 Crashlytics. All rights reserved.
#
#
# This script is meant to be run as a Run Script in the "Build Phases" section
# of your Xcode project. It sends debug symbols to symbolicate stacktraces,
# sends build events to track versions, and onboard apps for Crashlytics.
#
# This script calls upload-symbols twice:
#
# 1) First it calls upload-symbols synchronously in "validation" mode. If the
# script finds issues with the build environment, it will report errors to Xcode.
# In validation mode it exits before doing any time consuming work.
#
# 2) Then it calls upload-symbols in the background to actually send the build
# event and upload symbols. It does this in the background so that it doesn't
# slow down your builds. If an error happens here, you won't see it in Xcode.
#
# You can find the output for the background execution in Console.app, by
# searching for "upload-symbols".
#
# If you want verbose output, you can pass the --debug flag to this script
#
# Figure out where we're being called from # Figure out where we're being called from
DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
# Quote path in case of spaces or special chars # If the first argument is specified without a dash, treat it as the Fabric API
DIR="\"${DIR}" # Key and add it as an argument
if [ -z "$1" ] || [[ $1 == -* ]]; then
API_KEY_ARG=""
else
API_KEY_ARG="-a $1"; shift
fi
PATH_SEP="/" # If a second argument is specified without a dash, treat it as the Build Secret
VALIDATE_COMMAND="uploadDSYM\" $@ validate run-script" # and add it as an argument
UPLOAD_COMMAND="uploadDSYM\" $@ run-script" if [ -z "$1" ] || [[ $1 == -* ]]; then
BUILD_SECRET_ARG=""
else
BUILD_SECRET_ARG="-bs $1"; shift
fi
# Ensure params are as expected, run in sync mode to validate # Build up the arguments list, passing through any flags added after the
eval $DIR$PATH_SEP$VALIDATE_COMMAND # API Key and Build Secret
ARGUMENTS="$API_KEY_ARG $BUILD_SECRET_ARG $@"
VALIDATE_ARGUMENTS="$ARGUMENTS --build-phase --validate"
UPLOAD_ARGUMENTS="$ARGUMENTS --build-phase"
# Quote the path to handle folders with special characters
COMMAND_PATH="\"$DIR/upload-symbols\" "
# Ensure params are as expected, run in sync mode to validate,
# and cause a build error if validation fails
eval $COMMAND_PATH$VALIDATE_ARGUMENTS
return_code=$? return_code=$?
if [[ $return_code != 0 ]]; then if [[ $return_code != 0 ]]; then
exit $return_code exit $return_code
fi fi
# Verification passed, upload dSYM in background to prevent Xcode from waiting # Verification passed, convert and upload cSYMs in the background to prevent
# Note: Validation is performed again before upload. # build delays
# Output can still be found in Console.app #
eval $DIR$PATH_SEP$UPLOAD_COMMAND > /dev/null 2>&1 & # Note: Validation is performed again at this step before upload
#
# Note: Output can still be found in Console.app, by searching for
# "upload-symbols"
#
eval $COMMAND_PATH$UPLOAD_ARGUMENTS > /dev/null 2>&1 &

BIN
ios/Pods/Fabric/iOS/Fabric.framework/upload-symbols generated vendored Executable file

Binary file not shown.

Binary file not shown.

67
ios/Pods/Fabric/run generated
View File

@ -3,26 +3,71 @@
# run # run
# #
# Copyright (c) 2015 Crashlytics. All rights reserved. # Copyright (c) 2015 Crashlytics. All rights reserved.
#
#
# This script is meant to be run as a Run Script in the "Build Phases" section
# of your Xcode project. It sends debug symbols to symbolicate stacktraces,
# sends build events to track versions, and onboard apps for Crashlytics.
#
# This script calls upload-symbols twice:
#
# 1) First it calls upload-symbols synchronously in "validation" mode. If the
# script finds issues with the build environment, it will report errors to Xcode.
# In validation mode it exits before doing any time consuming work.
#
# 2) Then it calls upload-symbols in the background to actually send the build
# event and upload symbols. It does this in the background so that it doesn't
# slow down your builds. If an error happens here, you won't see it in Xcode.
#
# You can find the output for the background execution in Console.app, by
# searching for "upload-symbols".
#
# If you want verbose output, you can pass the --debug flag to this script
#
# Figure out where we're being called from # Figure out where we're being called from
DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
# Quote path in case of spaces or special chars # If the first argument is specified without a dash, treat it as the Fabric API
DIR="\"${DIR}" # Key and add it as an argument
if [ -z "$1" ] || [[ $1 == -* ]]; then
API_KEY_ARG=""
else
API_KEY_ARG="-a $1"; shift
fi
PATH_SEP="/" # If a second argument is specified without a dash, treat it as the Build Secret
VALIDATE_COMMAND="uploadDSYM\" $@ validate run-script" # and add it as an argument
UPLOAD_COMMAND="uploadDSYM\" $@ run-script" if [ -z "$1" ] || [[ $1 == -* ]]; then
BUILD_SECRET_ARG=""
else
BUILD_SECRET_ARG="-bs $1"; shift
fi
# Ensure params are as expected, run in sync mode to validate # Build up the arguments list, passing through any flags added after the
eval $DIR$PATH_SEP$VALIDATE_COMMAND # API Key and Build Secret
ARGUMENTS="$API_KEY_ARG $BUILD_SECRET_ARG $@"
VALIDATE_ARGUMENTS="$ARGUMENTS --build-phase --validate"
UPLOAD_ARGUMENTS="$ARGUMENTS --build-phase"
# Quote the path to handle folders with special characters
COMMAND_PATH="\"$DIR/upload-symbols\" "
# Ensure params are as expected, run in sync mode to validate,
# and cause a build error if validation fails
eval $COMMAND_PATH$VALIDATE_ARGUMENTS
return_code=$? return_code=$?
if [[ $return_code != 0 ]]; then if [[ $return_code != 0 ]]; then
exit $return_code exit $return_code
fi fi
# Verification passed, upload dSYM in background to prevent Xcode from waiting # Verification passed, convert and upload cSYMs in the background to prevent
# Note: Validation is performed again before upload. # build delays
# Output can still be found in Console.app #
eval $DIR$PATH_SEP$UPLOAD_COMMAND > /dev/null 2>&1 & # Note: Validation is performed again at this step before upload
#
# Note: Output can still be found in Console.app, by searching for
# "upload-symbols"
#
eval $COMMAND_PATH$UPLOAD_ARGUMENTS > /dev/null 2>&1 &

Binary file not shown.

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