diff --git a/.circleci/config.yml b/.circleci/config.yml index 9cfbb84ef..9b1814410 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,13 +1,13 @@ version: 2.1 orbs: owasp: entur/owasp@0.0.10 - node: circleci/node@4.5.1 + node: circleci/node@5.0.3 executors: android: parameters: resource_class: - default: large + default: xlarge type: string environment: NODE_OPTIONS: --max_old_space_size=12000 @@ -93,8 +93,7 @@ commands: description: "Get JavaScript dependencies" steps: - node/install: - node-version: '16.2.0' - install-npm: false + node-version: '16.15.0' - restore_cache: name: Restore npm cache key: v2-npm-{{ checksum "package.json" }}-{{ arch }} diff --git a/.eslintrc.json b/.eslintrc.json index 4c90e5998..2e8835ccf 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,13 +1,13 @@ { "extends": [ - "plugin:mattermost/react", + "./eslint/eslint-mattermost", + "./eslint/eslint-react", "plugin:@typescript-eslint/eslint-recommended", "plugin:@typescript-eslint/recommended" ], "parser": "@typescript-eslint/parser", "plugins": [ "@typescript-eslint", - "mattermost", "import" ], "settings": { diff --git a/.flowconfig b/.flowconfig index 53ab6fb5c..baad119d2 100644 --- a/.flowconfig +++ b/.flowconfig @@ -11,6 +11,8 @@ node_modules/react-native/Libraries/polyfills/.* ; Flow doesn't support platforms .*/Libraries/Utilities/LoadingView.js +.*/node_modules/resolve/test/resolver/malformed_package_json/package\.json$ + [untyped] .*/node_modules/@react-native-community/cli/.*/.* @@ -63,4 +65,4 @@ untyped-import untyped-type-import [version] -^0.162.0 +^0.176.3 diff --git a/.gitignore b/.gitignore index 0f8fa3058..5392a043e 100644 --- a/.gitignore +++ b/.gitignore @@ -32,8 +32,10 @@ DerivedData *.apk *.aab *.xcuserstate +ios/.xcode.env.local project.xcworkspace ios/Pods +/vendor/bundle/ .podinstall # Android/IntelliJ @@ -79,11 +81,11 @@ tags # For more information about the recommended setup visit: # https://docs.fastlane.tools/best-practices/source-control/ -*/fastlane/report.xml -*/fastlane/Preview.html -*/fastlane/screenshots +**/fastlane/report.xml +**/fastlane/Preview.html +**/fastlane/screenshots +**/fastlane/test_output fastlane/.env -fastlane/report.xml # Sentry android/sentry.properties diff --git a/android/app/build.gradle b/android/app/build.gradle index ec5900125..bb1e5e15f 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -120,9 +120,12 @@ def jscFlavor = 'org.webkit:android-jsc-intl:+' def enableHermes = project.ext.react.get("enableHermes", false); /** - * Architectures to build native code for in debug. + * Architectures to build native code for. */ -def nativeArchitectures = project.getProperties().get("reactNativeDebugArchitectures") +def reactNativeArchitectures() { + def value = project.getProperties().get("reactNativeArchitectures") + return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"] +} android { compileSdkVersion rootProject.ext.compileSdkVersion @@ -136,6 +139,78 @@ android { multiDexEnabled = true testBuildType System.getProperty('testBuildType', 'debug') testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' + buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() + + if (isNewArchitectureEnabled()) { + // We configure the NDK build only if you decide to opt-in for the New Architecture. + externalNativeBuild { + ndkBuild { + arguments "APP_PLATFORM=android-21", + "APP_STL=c++_shared", + "NDK_TOOLCHAIN_VERSION=clang", + "GENERATED_SRC_DIR=$buildDir/generated/source", + "PROJECT_BUILD_DIR=$buildDir", + "REACT_ANDROID_DIR=$rootDir/../node_modules/react-native/ReactAndroid", + "REACT_ANDROID_BUILD_DIR=$rootDir/../node_modules/react-native/ReactAndroid/build", + "NODE_MODULES_DIR=$rootDir/../node_modules" + cFlags "-Wall", "-Werror", "-fexceptions", "-frtti", "-DWITH_INSPECTOR=1" + cppFlags "-std=c++17" + // Make sure this target name is the same you specify inside the + // src/main/jni/Android.mk file for the `LOCAL_MODULE` variable. + targets "rndiffapp_appmodules" + // Fix for windows limit on number of character in file paths and in command lines + if (Os.isFamily(Os.FAMILY_WINDOWS)) { + arguments "NDK_APP_SHORT_COMMANDS=true" + } + } + } + if (!enableSeparateBuildPerCPUArchitecture) { + ndk { + abiFilters (*reactNativeArchitectures()) + } + } + } + } + + if (isNewArchitectureEnabled()) { + // We configure the NDK build only if you decide to opt-in for the New Architecture. + externalNativeBuild { + ndkBuild { + path "$projectDir/src/main/jni/Android.mk" + } + } + def reactAndroidProjectDir = project(':ReactAndroid').projectDir + def packageReactNdkDebugLibs = tasks.register("packageReactNdkDebugLibs", Copy) { + dependsOn(":ReactAndroid:packageReactNdkDebugLibsForBuck") + from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib") + into("$buildDir/react-ndk/exported") + } + def packageReactNdkReleaseLibs = tasks.register("packageReactNdkReleaseLibs", Copy) { + dependsOn(":ReactAndroid:packageReactNdkReleaseLibsForBuck") + from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib") + into("$buildDir/react-ndk/exported") + } + afterEvaluate { + // If you wish to add a custom TurboModule or component locally, + // you should uncomment this line. + // preBuild.dependsOn("generateCodegenArtifactsFromSchema") + preDebugBuild.dependsOn(packageReactNdkDebugLibs) + preReleaseBuild.dependsOn(packageReactNdkReleaseLibs) + + // Due to a bug inside AGP, we have to explicitly set a dependency + // between configureNdkBuild* tasks and the preBuild tasks. + // This can be removed once this is solved: https://issuetracker.google.com/issues/207403732 + configureNdkBuildRelease.dependsOn(preReleaseBuild) + configureNdkBuildDebug.dependsOn(preDebugBuild) + reactNativeArchitectures().each { architecture -> + tasks.findByName("configureNdkBuildDebug[${architecture}]")?.configure { + dependsOn("preDebugBuild") + } + tasks.findByName("configureNdkBuildRelease[${architecture}]")?.configure { + dependsOn("preReleaseBuild") + } + } + } } signingConfigs { release { @@ -152,22 +227,25 @@ android { reset() enable enableSeparateBuildPerCPUArchitecture universalApk enableSeparateBuildPerCPUArchitecture // If true, also generate a universal APK - include "armeabi-v7a", "x86", "arm64-v8a", "x86_64" + include (*reactNativeArchitectures()) } } buildTypes { + def useReleaseKey = project.hasProperty('MATTERMOST_RELEASE_STORE_FILE') release { minifyEnabled enableProguardInReleaseBuilds proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" - signingConfig signingConfigs.release + if (useReleaseKey) { + signingConfig signingConfigs.release + } else { + signingConfig signingConfigs.debug + } } debug { - minifyEnabled enableProguardInReleaseBuilds - proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" - if (nativeArchitectures) { - ndk { - abiFilters nativeArchitectures.split(',') - } + if (useReleaseKey) { + signingConfig signingConfigs.release + } else { + signingConfig signingConfigs.debug } } unsigned.initWith(buildTypes.release) @@ -212,25 +290,6 @@ repositories { } } -configurations.all { - resolutionStrategy { - eachDependency { DependencyResolveDetails details -> - if (details.requested.name == 'play-services-base') { - details.useTarget group: details.requested.group, name: details.requested.name, version: '15.0.1' - } - if (details.requested.name == 'play-services-tasks') { - details.useTarget group: details.requested.group, name: details.requested.name, version: '15.0.1' - } - if (details.requested.name == 'play-services-stats') { - details.useTarget group: details.requested.group, name: details.requested.name, version: '15.0.1' - } - if (details.requested.name == 'play-services-basement') { - details.useTarget group: details.requested.group, name: details.requested.name, version: '15.0.1' - } - } - } -} - dependencies { implementation fileTree(dir: "libs", include: ["*.jar"]) @@ -250,10 +309,10 @@ dependencies { if (enableHermes) { - def hermesPath = "../../node_modules/hermes-engine/android/"; - debugImplementation files(hermesPath + "hermes-debug.aar") - releaseImplementation files(hermesPath + "hermes-release.aar") - unsignedImplementation files(hermesPath + "hermes-release.aar") + //noinspection GradleDynamicVersion + implementation("com.facebook.react:hermes-engine:+") { // From node_modules + exclude group:'com.facebook.fbjni' + } } else { implementation jscFlavor } @@ -275,6 +334,39 @@ dependencies { androidTestImplementation('com.wix:detox:+') } +configurations.all { + if (isNewArchitectureEnabled()) { + // If new architecture is enabled, we let you build RN from source + // Otherwise we fallback to a prebuilt .aar bundled in the NPM package. + // This will be applied to all the imported transtitive dependency. + resolutionStrategy.dependencySubstitution { + substitute(module("com.facebook.react:react-native")) + .using(project(":ReactAndroid")) + .because("On New Architecture we're building React Native from source") + substitute(module("com.facebook.react:hermes-engine")) + .using(project(":ReactAndroid:hermes-engine")) + .because("On New Architecture we're building Hermes from source") + } + } + + resolutionStrategy { + eachDependency { DependencyResolveDetails details -> + if (details.requested.name == 'play-services-base') { + details.useTarget group: details.requested.group, name: details.requested.name, version: '15.0.1' + } + if (details.requested.name == 'play-services-tasks') { + details.useTarget group: details.requested.group, name: details.requested.name, version: '15.0.1' + } + if (details.requested.name == 'play-services-stats') { + details.useTarget group: details.requested.group, name: details.requested.name, version: '15.0.1' + } + if (details.requested.name == 'play-services-basement') { + details.useTarget group: details.requested.group, name: details.requested.name, version: '15.0.1' + } + } + } +} + // Run this once to be able to run the application with BUCK // puts all compile dependencies into folder libs for BUCK to use task copyDownloadableDepsToLibs(type: Copy) { @@ -284,3 +376,11 @@ task copyDownloadableDepsToLibs(type: Copy) { apply plugin: 'com.google.gms.google-services' apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) + +def isNewArchitectureEnabled() { + // To opt-in for the New Architecture, you can either: + // - Set `newArchEnabled` to true inside the `gradle.properties` file + // - Invoke gradle with `-newArchEnabled=true` + // - Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true` + return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml index 0063cf4f3..180b076f5 100644 --- a/android/app/src/debug/AndroidManifest.xml +++ b/android/app/src/debug/AndroidManifest.xml @@ -8,6 +8,6 @@ android:usesCleartextTraffic="true" tools:targetApi="28" tools:ignore="GoogleAppIndexingWarning"> - + diff --git a/android/app/src/debug/java/com/rn/ReactNativeFlipper.java b/android/app/src/debug/java/com/rn/ReactNativeFlipper.java index f6fb760e5..1197406be 100644 --- a/android/app/src/debug/java/com/rn/ReactNativeFlipper.java +++ b/android/app/src/debug/java/com/rn/ReactNativeFlipper.java @@ -1,5 +1,5 @@ /** - * Copyright (c) Facebook, Inc. and its affiliates. + * Copyright (c) Meta Platforms, Inc. and affiliates. * *

This source code is licensed under the MIT license found in the LICENSE file in the root * directory of this source tree. @@ -19,6 +19,7 @@ import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor; import com.facebook.flipper.plugins.network.NetworkFlipperPlugin; import com.facebook.flipper.plugins.react.ReactFlipperPlugin; import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin; +import com.facebook.react.ReactInstanceEventListener; import com.facebook.react.ReactInstanceManager; import com.facebook.react.bridge.ReactContext; import com.facebook.react.modules.network.NetworkingModule; @@ -47,7 +48,7 @@ public class ReactNativeFlipper { ReactContext reactContext = reactInstanceManager.getCurrentReactContext(); if (reactContext == null) { reactInstanceManager.addReactInstanceEventListener( - new ReactInstanceManager.ReactInstanceEventListener() { + new ReactInstanceEventListener() { @Override public void onReactContextInitialized(ReactContext reactContext) { reactInstanceManager.removeReactInstanceEventListener(this); diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 6fce38562..351221352 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -33,10 +33,12 @@ + android:taskAffinity="" + android:exported="true" + > @@ -72,7 +74,9 @@ android:screenOrientation="portrait" android:theme="@style/AppTheme" android:taskAffinity="com.mattermost.share" - android:launchMode="singleInstance"> + android:launchMode="singleInstance" + android:exported="true" + > diff --git a/android/app/src/main/java/com/mattermost/newarchitecture/MainApplicationReactNativeHost.java b/android/app/src/main/java/com/mattermost/newarchitecture/MainApplicationReactNativeHost.java new file mode 100644 index 000000000..5a5d736bf --- /dev/null +++ b/android/app/src/main/java/com/mattermost/newarchitecture/MainApplicationReactNativeHost.java @@ -0,0 +1,116 @@ +package com.mattermost.newarchitecture; + +import android.app.Application; +import androidx.annotation.NonNull; +import com.facebook.react.PackageList; +import com.facebook.react.ReactInstanceManager; +import com.facebook.react.ReactNativeHost; +import com.facebook.react.ReactPackage; +import com.facebook.react.ReactPackageTurboModuleManagerDelegate; +import com.facebook.react.bridge.JSIModulePackage; +import com.facebook.react.bridge.JSIModuleProvider; +import com.facebook.react.bridge.JSIModuleSpec; +import com.facebook.react.bridge.JSIModuleType; +import com.facebook.react.bridge.JavaScriptContextHolder; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.UIManager; +import com.facebook.react.fabric.ComponentFactory; +import com.facebook.react.fabric.CoreComponentsRegistry; +import com.facebook.react.fabric.FabricJSIModuleProvider; +import com.facebook.react.fabric.ReactNativeConfig; +import com.facebook.react.uimanager.ViewManagerRegistry; +import com.mattermost.rnbeta.BuildConfig; +import com.mattermost.newarchitecture.components.MainComponentsRegistry; +import com.mattermost.newarchitecture.modules.MainApplicationTurboModuleManagerDelegate; +import java.util.ArrayList; +import java.util.List; + +/** + * A {@link ReactNativeHost} that helps you load everything needed for the New Architecture, both + * TurboModule delegates and the Fabric Renderer. + * + *

Please note that this class is used ONLY if you opt-in for the New Architecture (see the + * `newArchEnabled` property). Is ignored otherwise. + */ +public class MainApplicationReactNativeHost extends ReactNativeHost { + public MainApplicationReactNativeHost(Application application) { + super(application); + } + + @Override + public boolean getUseDeveloperSupport() { + return BuildConfig.DEBUG; + } + + @Override + protected List getPackages() { + List packages = new PackageList(this).getPackages(); + // Packages that cannot be autolinked yet can be added manually here, for example: + // packages.add(new MyReactNativePackage()); + // TurboModules must also be loaded here providing a valid TurboReactPackage implementation: + // packages.add(new TurboReactPackage() { ... }); + // If you have custom Fabric Components, their ViewManagers should also be loaded here + // inside a ReactPackage. + return packages; + } + + @Override + protected String getJSMainModuleName() { + return "index"; + } + + @NonNull + @Override + protected ReactPackageTurboModuleManagerDelegate.Builder + getReactPackageTurboModuleManagerDelegateBuilder() { + // Here we provide the ReactPackageTurboModuleManagerDelegate Builder. This is necessary + // for the new architecture and to use TurboModules correctly. + return new MainApplicationTurboModuleManagerDelegate.Builder(); + } + + @Override + protected JSIModulePackage getJSIModulePackage() { + return new JSIModulePackage() { + @Override + public List getJSIModules( + final ReactApplicationContext reactApplicationContext, + final JavaScriptContextHolder jsContext) { + final List specs = new ArrayList<>(); + + // Here we provide a new JSIModuleSpec that will be responsible of providing the + // custom Fabric Components. + specs.add( + new JSIModuleSpec() { + @Override + public JSIModuleType getJSIModuleType() { + return JSIModuleType.UIManager; + } + + @Override + public JSIModuleProvider getJSIModuleProvider() { + final ComponentFactory componentFactory = new ComponentFactory(); + CoreComponentsRegistry.register(componentFactory); + + // Here we register a Components Registry. + // The one that is generated with the template contains no components + // and just provides you the one from React Native core. + MainComponentsRegistry.register(componentFactory); + + final ReactInstanceManager reactInstanceManager = getReactInstanceManager(); + + ViewManagerRegistry viewManagerRegistry = + new ViewManagerRegistry( + reactInstanceManager.getOrCreateViewManagers(reactApplicationContext)); + + return new FabricJSIModuleProvider( + reactApplicationContext, + componentFactory, + ReactNativeConfig.DEFAULT_CONFIG, + viewManagerRegistry); + } + }); + return specs; + } + }; + } +} \ No newline at end of file diff --git a/android/app/src/main/java/com/mattermost/newarchitecture/components/MainComponentsRegistry.java b/android/app/src/main/java/com/mattermost/newarchitecture/components/MainComponentsRegistry.java new file mode 100644 index 000000000..4168988bd --- /dev/null +++ b/android/app/src/main/java/com/mattermost/newarchitecture/components/MainComponentsRegistry.java @@ -0,0 +1,36 @@ +package com.mattermost.newarchitecture.components; + +import com.facebook.jni.HybridData; +import com.facebook.proguard.annotations.DoNotStrip; +import com.facebook.react.fabric.ComponentFactory; +import com.facebook.soloader.SoLoader; + +/** + * Class responsible to load the custom Fabric Components. This class has native methods and needs a + * corresponding C++ implementation/header file to work correctly (already placed inside the jni/ + * folder for you). + * + *

Please note that this class is used ONLY if you opt-in for the New Architecture (see the + * `newArchEnabled` property). Is ignored otherwise. + */ +@DoNotStrip +public class MainComponentsRegistry { + static { + SoLoader.loadLibrary("fabricjni"); + } + + @DoNotStrip private final HybridData mHybridData; + + @DoNotStrip + private native HybridData initHybrid(ComponentFactory componentFactory); + + @DoNotStrip + private MainComponentsRegistry(ComponentFactory componentFactory) { + mHybridData = initHybrid(componentFactory); + } + + @DoNotStrip + public static MainComponentsRegistry register(ComponentFactory componentFactory) { + return new MainComponentsRegistry(componentFactory); + } +} \ No newline at end of file diff --git a/android/app/src/main/java/com/mattermost/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate.java b/android/app/src/main/java/com/mattermost/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate.java new file mode 100644 index 000000000..a5e317674 --- /dev/null +++ b/android/app/src/main/java/com/mattermost/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate.java @@ -0,0 +1,48 @@ +package com.mattermost.newarchitecture.modules; + +import com.facebook.jni.HybridData; +import com.facebook.react.ReactPackage; +import com.facebook.react.ReactPackageTurboModuleManagerDelegate; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.soloader.SoLoader; +import java.util.List; + +/** + * Class responsible to load the TurboModules. This class has native methods and needs a + * corresponding C++ implementation/header file to work correctly (already placed inside the jni/ + * folder for you). + * + *

Please note that this class is used ONLY if you opt-in for the New Architecture (see the + * `newArchEnabled` property). Is ignored otherwise. + */ +public class MainApplicationTurboModuleManagerDelegate + extends ReactPackageTurboModuleManagerDelegate { + + private static volatile boolean sIsSoLibraryLoaded; + + protected MainApplicationTurboModuleManagerDelegate( + ReactApplicationContext reactApplicationContext, List packages) { + super(reactApplicationContext, packages); + } + + protected native HybridData initHybrid(); + + native boolean canCreateTurboModule(String moduleName); + + public static class Builder extends ReactPackageTurboModuleManagerDelegate.Builder { + protected MainApplicationTurboModuleManagerDelegate build( + ReactApplicationContext context, List packages) { + return new MainApplicationTurboModuleManagerDelegate(context, packages); + } + } + + @Override + protected synchronized void maybeLoadOtherSoLibraries() { + if (!sIsSoLibraryLoaded) { + // If you change the name of your application .so file in the Android.mk file, + // make sure you update the name here as well. + SoLoader.loadLibrary("rndiffapp_appmodules"); + sIsSoLibraryLoaded = true; + } + } +} \ No newline at end of file diff --git a/android/app/src/main/java/com/mattermost/rnbeta/CustomPushNotification.java b/android/app/src/main/java/com/mattermost/rnbeta/CustomPushNotification.java index 73468cb50..e084b1efa 100644 --- a/android/app/src/main/java/com/mattermost/rnbeta/CustomPushNotification.java +++ b/android/app/src/main/java/com/mattermost/rnbeta/CustomPushNotification.java @@ -22,6 +22,7 @@ import java.util.List; import java.util.Map; import com.wix.reactnativenotifications.core.notification.PushNotification; +import com.wix.reactnativenotifications.core.NotificationIntentAdapter; import com.wix.reactnativenotifications.core.AppLaunchHelper; import com.wix.reactnativenotifications.core.AppLifecycleFacade; import com.wix.reactnativenotifications.core.JsIOHelper; @@ -246,7 +247,7 @@ public class CustomPushNotification extends PushNotification { } private void buildNotification(Integer notificationId, boolean createSummary) { - final PendingIntent pendingIntent = super.getCTAPendingIntent(); + final PendingIntent pendingIntent = NotificationIntentAdapter.createPendingNotificationIntent(mContext, mNotificationProps); final Notification notification = buildNotification(pendingIntent); if (createSummary) { final Notification summary = getNotificationSummaryBuilder(pendingIntent).build(); diff --git a/android/app/src/main/java/com/mattermost/rnbeta/CustomPushNotificationHelper.java b/android/app/src/main/java/com/mattermost/rnbeta/CustomPushNotificationHelper.java index 1fbaff01f..5f89c5092 100644 --- a/android/app/src/main/java/com/mattermost/rnbeta/CustomPushNotificationHelper.java +++ b/android/app/src/main/java/com/mattermost/rnbeta/CustomPushNotificationHelper.java @@ -1,5 +1,6 @@ package com.mattermost.rnbeta; +import android.annotation.SuppressLint; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; @@ -128,11 +129,20 @@ public class CustomPushNotificationHelper { replyIntent.putExtra(NOTIFICATION_ID, notificationId); replyIntent.putExtra("pushNotification", bundle); - PendingIntent replyPendingIntent = PendingIntent.getBroadcast( - context, - notificationId, - replyIntent, - PendingIntent.FLAG_UPDATE_CURRENT); + PendingIntent replyPendingIntent; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + replyPendingIntent = PendingIntent.getBroadcast( + context, + notificationId, + replyIntent, + PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE); + } else { + replyPendingIntent = PendingIntent.getBroadcast( + context, + notificationId, + replyIntent, + PendingIntent.FLAG_UPDATE_CURRENT); + } RemoteInput remoteInput = new RemoteInput.Builder(KEY_TEXT_REPLY) .setLabel("Reply") @@ -381,10 +391,12 @@ public class CustomPushNotificationHelper { private static void setNotificationDeleteIntent(Context context, NotificationCompat.Builder notification, Bundle bundle, int notificationId) { // Let's add a delete intent when the notification is dismissed + final String PUSH_NOTIFICATION_EXTRA_NAME = "pushNotification"; Intent delIntent = new Intent(context, NotificationDismissService.class); - PushNotificationProps notificationProps = new PushNotificationProps(bundle); delIntent.putExtra(NOTIFICATION_ID, notificationId); - PendingIntent deleteIntent = NotificationIntentAdapter.createPendingNotificationIntent(context, delIntent, notificationProps); + delIntent.putExtra(PUSH_NOTIFICATION_EXTRA_NAME, bundle); + @SuppressLint("UnspecifiedImmutableFlag") + PendingIntent deleteIntent = PendingIntent.getService(context, (int) System.currentTimeMillis(), delIntent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE); notification.setDeleteIntent(deleteIntent); } diff --git a/android/app/src/main/java/com/mattermost/rnbeta/MainActivity.java b/android/app/src/main/java/com/mattermost/rnbeta/MainActivity.java index 537e76fcc..fe1b6fc4c 100644 --- a/android/app/src/main/java/com/mattermost/rnbeta/MainActivity.java +++ b/android/app/src/main/java/com/mattermost/rnbeta/MainActivity.java @@ -1,18 +1,44 @@ package com.mattermost.rnbeta; import android.os.Bundle; - -import androidx.annotation.NonNull; import androidx.annotation.Nullable; + import android.view.KeyEvent; import android.content.res.Configuration; +import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.WritableMap; +import com.facebook.react.ReactActivityDelegate; +import com.facebook.react.ReactRootView; import com.reactnativenavigation.NavigationActivity; import com.github.emilioicai.hwkeyboardevent.HWKeyboardEventModule; public class MainActivity extends NavigationActivity { private boolean HWKeyboardConnected = false; + public static class MainActivityDelegate extends ReactActivityDelegate { + public MainActivityDelegate(NavigationActivity activity, String mainComponentName) { + super(activity, mainComponentName); + } + + @Override + protected ReactRootView createRootView() { + ReactRootView reactRootView = new ReactRootView(getContext()); + // If you opted-in for the New Architecture, we enable the Fabric Renderer. + reactRootView.setIsFabric(BuildConfig.IS_NEW_ARCHITECTURE_ENABLED); + return reactRootView; + } + + @Override + protected boolean isConcurrentRootEnabled() { + // If you opted-in for the New Architecture, we enable Concurrent Root (i.e. React 18). + // More on this on https://reactjs.org/blog/2022/03/29/react-v18.html + return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; + } + } + @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -21,7 +47,7 @@ public class MainActivity extends NavigationActivity { } @Override - public void onConfigurationChanged(@NonNull Configuration newConfig) { + public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); if (newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO) { @@ -31,6 +57,12 @@ public class MainActivity extends NavigationActivity { } } + @Override + public void onWindowFocusChanged(boolean hasFocus) { + super.onWindowFocusChanged(hasFocus); + getReactGateway().onWindowFocusChanged(hasFocus); + } + /* https://mattermost.atlassian.net/browse/MM-10601 Required by react-native-hw-keyboard-event @@ -38,15 +70,24 @@ public class MainActivity extends NavigationActivity { */ @Override public boolean dispatchKeyEvent(KeyEvent event) { - if (HWKeyboardConnected && event.getKeyCode() == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_UP) { - String keyPressed = event.isShiftPressed() ? "shift-enter" : "enter"; - HWKeyboardEventModule.getInstance().keyPressed(keyPressed); - return true; + if (HWKeyboardConnected) { + int keyCode = event.getKeyCode(); + int keyAction = event.getAction(); + if (keyAction == KeyEvent.ACTION_UP) { + if (keyCode == KeyEvent.KEYCODE_ENTER) { + String keyPressed = event.isShiftPressed() ? "shift-enter" : "enter"; + HWKeyboardEventModule.getInstance().keyPressed(keyPressed); + return true; + } else if (keyCode == KeyEvent.KEYCODE_K && event.isCtrlPressed()) { + HWKeyboardEventModule.getInstance().keyPressed("find-channels"); + return true; + } + } } return super.dispatchKeyEvent(event); - } + }; private void setHWKeyboardConnected() { HWKeyboardConnected = getResources().getConfiguration().keyboard == Configuration.KEYBOARD_QWERTY; } -} +} \ No newline at end of file diff --git a/android/app/src/main/java/com/mattermost/rnbeta/MainApplication.java b/android/app/src/main/java/com/mattermost/rnbeta/MainApplication.java index 9316646dd..088af821d 100644 --- a/android/app/src/main/java/com/mattermost/rnbeta/MainApplication.java +++ b/android/app/src/main/java/com/mattermost/rnbeta/MainApplication.java @@ -25,16 +25,19 @@ import com.wix.reactnativenotifications.core.JsIOHelper; import com.facebook.react.PackageList; import com.facebook.react.ReactInstanceManager; import com.facebook.react.ReactPackage; +import com.facebook.react.config.ReactFeatureFlags; import com.facebook.react.ReactNativeHost; import com.facebook.react.TurboReactPackage; +import com.facebook.react.bridge.JSIModulePackage; import com.facebook.react.bridge.NativeModule; import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.module.model.ReactModuleInfo; import com.facebook.react.module.model.ReactModuleInfoProvider; import com.facebook.soloader.SoLoader; +import com.facebook.react.config.ReactFeatureFlags; -import com.facebook.react.bridge.JSIModulePackage; +import com.mattermost.newarchitecture.MainApplicationReactNativeHost; public class MainApplication extends NavigationApplication implements INotificationsApplication, INotificationsDrawerApplication { @@ -44,68 +47,75 @@ public class MainApplication extends NavigationApplication implements INotificat private Bundle mManagedConfig = null; -private final ReactNativeHost mReactNativeHost = - new ReactNativeHost(this) { - @Override - public boolean getUseDeveloperSupport() { - return BuildConfig.DEBUG; - } + private final ReactNativeHost mReactNativeHost = + new ReactNativeHost(this) { + @Override + public boolean getUseDeveloperSupport() { + return BuildConfig.DEBUG; + } - @Override - protected List getPackages() { - List packages = new PackageList(this).getPackages(); - // Packages that cannot be auto linked yet can be added manually here, for example: - // packages.add(new MyReactNativePackage()); - packages.add(new RNNotificationsPackage(MainApplication.this)); - packages.add( - new TurboReactPackage() { - @Override - public NativeModule getModule(String name, ReactApplicationContext reactContext) { - switch (name) { - case "MattermostManaged": - return MattermostManagedModule.getInstance(reactContext); - case "MattermostShare": - return new ShareModule(instance, reactContext); - case "NotificationPreferences": - return NotificationPreferencesModule.getInstance(instance, reactContext); - case "RNTextInputReset": - return new RNTextInputResetModule(reactContext); - default: - throw new IllegalArgumentException("Could not find module " + name); + @Override + protected List getPackages() { + List packages = new PackageList(this).getPackages(); + // Packages that cannot be auto linked yet can be added manually here, for example: + // packages.add(new MyReactNativePackage()); + packages.add(new RNNotificationsPackage(MainApplication.this)); + packages.add( + new TurboReactPackage() { + @Override + public NativeModule getModule(String name, ReactApplicationContext reactContext) { + switch (name) { + case "MattermostManaged": + return MattermostManagedModule.getInstance(reactContext); + case "MattermostShare": + return new ShareModule(instance, reactContext); + case "NotificationPreferences": + return NotificationPreferencesModule.getInstance(instance, reactContext); + case "RNTextInputReset": + return new RNTextInputResetModule(reactContext); + default: + throw new IllegalArgumentException("Could not find module " + name); + } + } + + @Override + public ReactModuleInfoProvider getReactModuleInfoProvider() { + return () -> { + Map map = new HashMap<>(); + map.put("MattermostManaged", new ReactModuleInfo("MattermostManaged", "com.mattermost.rnbeta.MattermostManagedModule", false, false, false, false, false)); + map.put("MattermostShare", new ReactModuleInfo("MattermostShare", "com.mattermost.share.ShareModule", false, false, true, false, false)); + map.put("NotificationPreferences", new ReactModuleInfo("NotificationPreferences", "com.mattermost.rnbeta.NotificationPreferencesModule", false, false, false, false, false)); + map.put("RNTextInputReset", new ReactModuleInfo("RNTextInputReset", "com.mattermost.rnbeta.RNTextInputResetModule", false, false, false, false, false)); + return map; + }; } } + ); - @Override - public ReactModuleInfoProvider getReactModuleInfoProvider() { - return () -> { - Map map = new HashMap<>(); - map.put("MattermostManaged", new ReactModuleInfo("MattermostManaged", "com.mattermost.rnbeta.MattermostManagedModule", false, false, false, false, false)); - map.put("MattermostShare", new ReactModuleInfo("MattermostShare", "com.mattermost.share.ShareModule", false, false, true, false, false)); - map.put("NotificationPreferences", new ReactModuleInfo("NotificationPreferences", "com.mattermost.rnbeta.NotificationPreferencesModule", false, false, false, false, false)); - map.put("RNTextInputReset", new ReactModuleInfo("RNTextInputReset", "com.mattermost.rnbeta.RNTextInputResetModule", false, false, false, false, false)); - return map; - }; - } - } - ); + return packages; + } - return packages; - } + @Override + protected String getJSMainModuleName() { + return "index"; + } - @Override - protected String getJSMainModuleName() { - return "index"; - } - - @Override - protected JSIModulePackage getJSIModulePackage() { - return (JSIModulePackage) new CustomMMKVJSIModulePackage(); - } + @Override + protected JSIModulePackage getJSIModulePackage() { + return (JSIModulePackage) new CustomMMKVJSIModulePackage(); + } }; + private final ReactNativeHost mNewArchitectureNativeHost = + new MainApplicationReactNativeHost(this); + @Override public ReactNativeHost getReactNativeHost() { - return mReactNativeHost; + if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { + return mNewArchitectureNativeHost; + } else { + return mReactNativeHost; + } } @Override @@ -118,6 +128,8 @@ private final ReactNativeHost mReactNativeHost = RealPathUtil.deleteTempFiles(tempFolder); Log.i("ReactNative", "Cleaning temp cache " + tempFolder.getAbsolutePath()); + // If you opted-in for the New Architecture, we enable the TurboModule system + ReactFeatureFlags.useTurboModules = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; SoLoader.init(this, /* native exopackage */ false); initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); } diff --git a/android/app/src/main/java/com/mattermost/rnbeta/NotificationReplyBroadcastReceiver.java b/android/app/src/main/java/com/mattermost/rnbeta/NotificationReplyBroadcastReceiver.java index c345222d0..754fd8476 100644 --- a/android/app/src/main/java/com/mattermost/rnbeta/NotificationReplyBroadcastReceiver.java +++ b/android/app/src/main/java/com/mattermost/rnbeta/NotificationReplyBroadcastReceiver.java @@ -129,9 +129,8 @@ public class NotificationReplyBroadcastReceiver extends BroadcastReceiver { } private void recreateNotification(int notificationId, final CharSequence message) { - final Intent cta = new Intent(mContext, ProxyService.class); final PushNotificationProps notificationProps = new PushNotificationProps(bundle); - final PendingIntent pendingIntent = NotificationIntentAdapter.createPendingNotificationIntent(mContext, cta, notificationProps); + final PendingIntent pendingIntent = NotificationIntentAdapter.createPendingNotificationIntent(mContext, notificationProps); NotificationCompat.Builder builder = CustomPushNotificationHelper.createNotificationBuilder(mContext, pendingIntent, bundle, false); Notification notification = builder.build(); NotificationCompat.MessagingStyle messagingStyle = NotificationCompat.MessagingStyle.extractMessagingStyleFromNotification(notification); diff --git a/android/app/src/main/jni/Android.mk b/android/app/src/main/jni/Android.mk new file mode 100644 index 000000000..710541138 --- /dev/null +++ b/android/app/src/main/jni/Android.mk @@ -0,0 +1,48 @@ +THIS_DIR := $(call my-dir) + +include $(REACT_ANDROID_DIR)/Android-prebuilt.mk + +# If you wish to add a custom TurboModule or Fabric component in your app you +# will have to include the following autogenerated makefile. +# include $(GENERATED_SRC_DIR)/codegen/jni/Android.mk +include $(CLEAR_VARS) + +LOCAL_PATH := $(THIS_DIR) + +# You can customize the name of your application .so file here. +LOCAL_MODULE := mattermost_appmodules + +LOCAL_C_INCLUDES := $(LOCAL_PATH) +LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp) +LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH) + +# If you wish to add a custom TurboModule or Fabric component in your app you +# will have to uncomment those lines to include the generated source +# files from the codegen (placed in $(GENERATED_SRC_DIR)/codegen/jni) +# +# LOCAL_C_INCLUDES += $(GENERATED_SRC_DIR)/codegen/jni +# LOCAL_SRC_FILES += $(wildcard $(GENERATED_SRC_DIR)/codegen/jni/*.cpp) +# LOCAL_EXPORT_C_INCLUDES += $(GENERATED_SRC_DIR)/codegen/jni + +# Here you should add any native library you wish to depend on. +LOCAL_SHARED_LIBRARIES := \ + libfabricjni \ + libfbjni \ + libfolly_runtime \ + libglog \ + libjsi \ + libreact_codegen_rncore \ + libreact_debug \ + libreact_nativemodule_core \ + libreact_render_componentregistry \ + libreact_render_core \ + libreact_render_debug \ + libreact_render_graphics \ + librrc_view \ + libruntimeexecutor \ + libturbomodulejsijni \ + libyoga + +LOCAL_CFLAGS := -DLOG_TAG=\"ReactNative\" -fexceptions -frtti -std=c++17 -Wall + +include $(BUILD_SHARED_LIBRARY) \ No newline at end of file diff --git a/android/app/src/main/jni/MainApplicationModuleProvider.cpp b/android/app/src/main/jni/MainApplicationModuleProvider.cpp new file mode 100644 index 000000000..39de093d1 --- /dev/null +++ b/android/app/src/main/jni/MainApplicationModuleProvider.cpp @@ -0,0 +1,24 @@ +#include "MainApplicationModuleProvider.h" + +#include + +namespace facebook { +namespace react { + +std::shared_ptr MainApplicationModuleProvider( + const std::string moduleName, + const JavaTurboModule::InitParams ¶ms) { + // Here you can provide your own module provider for TurboModules coming from + // either your application or from external libraries. The approach to follow + // is similar to the following (for a library called `samplelibrary`: + // + // auto module = samplelibrary_ModuleProvider(moduleName, params); + // if (module != nullptr) { + // return module; + // } + // return rncore_ModuleProvider(moduleName, params); + return rncore_ModuleProvider(moduleName, params); +} + +} // namespace react +} // namespace facebook \ No newline at end of file diff --git a/android/app/src/main/jni/MainApplicationModuleProvider.h b/android/app/src/main/jni/MainApplicationModuleProvider.h new file mode 100644 index 000000000..2f2fb24a3 --- /dev/null +++ b/android/app/src/main/jni/MainApplicationModuleProvider.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +#include + +namespace facebook { +namespace react { + +std::shared_ptr MainApplicationModuleProvider( + const std::string moduleName, + const JavaTurboModule::InitParams ¶ms); + +} // namespace react +} // namespace facebook \ No newline at end of file diff --git a/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.cpp b/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.cpp new file mode 100644 index 000000000..f2e4714dc --- /dev/null +++ b/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.cpp @@ -0,0 +1,45 @@ +#include "MainApplicationTurboModuleManagerDelegate.h" +#include "MainApplicationModuleProvider.h" + +namespace facebook { +namespace react { + +jni::local_ref +MainApplicationTurboModuleManagerDelegate::initHybrid( + jni::alias_ref) { + return makeCxxInstance(); +} + +void MainApplicationTurboModuleManagerDelegate::registerNatives() { + registerHybrid({ + makeNativeMethod( + "initHybrid", MainApplicationTurboModuleManagerDelegate::initHybrid), + makeNativeMethod( + "canCreateTurboModule", + MainApplicationTurboModuleManagerDelegate::canCreateTurboModule), + }); +} + +std::shared_ptr +MainApplicationTurboModuleManagerDelegate::getTurboModule( + const std::string name, + const std::shared_ptr jsInvoker) { + // Not implemented yet: provide pure-C++ NativeModules here. + return nullptr; +} + +std::shared_ptr +MainApplicationTurboModuleManagerDelegate::getTurboModule( + const std::string name, + const JavaTurboModule::InitParams ¶ms) { + return MainApplicationModuleProvider(name, params); +} + +bool MainApplicationTurboModuleManagerDelegate::canCreateTurboModule( + std::string name) { + return getTurboModule(name, nullptr) != nullptr || + getTurboModule(name, {.moduleName = name}) != nullptr; +} + +} // namespace react +} // namespace facebook \ No newline at end of file diff --git a/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.h b/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.h new file mode 100644 index 000000000..ea4a0fc98 --- /dev/null +++ b/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.h @@ -0,0 +1,38 @@ +#include +#include + +#include +#include + +namespace facebook { +namespace react { + +class MainApplicationTurboModuleManagerDelegate + : public jni::HybridClass< + MainApplicationTurboModuleManagerDelegate, + TurboModuleManagerDelegate> { + public: + // Adapt it to the package you used for your Java class. + static constexpr auto kJavaDescriptor = + "Lcom/mattermost/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate;"; + + static jni::local_ref initHybrid(jni::alias_ref); + + static void registerNatives(); + + std::shared_ptr getTurboModule( + const std::string name, + const std::shared_ptr jsInvoker) override; + std::shared_ptr getTurboModule( + const std::string name, + const JavaTurboModule::InitParams ¶ms) override; + + /** + * Test-only method. Allows user to verify whether a TurboModule can be + * created by instances of this class. + */ + bool canCreateTurboModule(std::string name); +}; + +} // namespace react +} // namespace facebook \ No newline at end of file diff --git a/android/app/src/main/jni/MainComponentsRegistry.cpp b/android/app/src/main/jni/MainComponentsRegistry.cpp new file mode 100644 index 000000000..c5188f4dc --- /dev/null +++ b/android/app/src/main/jni/MainComponentsRegistry.cpp @@ -0,0 +1,61 @@ +#include "MainComponentsRegistry.h" + +#include +#include +#include +#include + +namespace facebook { +namespace react { + +MainComponentsRegistry::MainComponentsRegistry(ComponentFactory *delegate) {} + +std::shared_ptr +MainComponentsRegistry::sharedProviderRegistry() { + auto providerRegistry = CoreComponentsRegistry::sharedProviderRegistry(); + + // Custom Fabric Components go here. You can register custom + // components coming from your App or from 3rd party libraries here. + // + // providerRegistry->add(concreteComponentDescriptorProvider< + // AocViewerComponentDescriptor>()); + return providerRegistry; +} + +jni::local_ref +MainComponentsRegistry::initHybrid( + jni::alias_ref, + ComponentFactory *delegate) { + auto instance = makeCxxInstance(delegate); + + auto buildRegistryFunction = + [](EventDispatcher::Weak const &eventDispatcher, + ContextContainer::Shared const &contextContainer) + -> ComponentDescriptorRegistry::Shared { + auto registry = MainComponentsRegistry::sharedProviderRegistry() + ->createComponentDescriptorRegistry( + {eventDispatcher, contextContainer}); + + auto mutableRegistry = + std::const_pointer_cast(registry); + + mutableRegistry->setFallbackComponentDescriptor( + std::make_shared( + ComponentDescriptorParameters{ + eventDispatcher, contextContainer, nullptr})); + + return registry; + }; + + delegate->buildRegistryFunction = buildRegistryFunction; + return instance; +} + +void MainComponentsRegistry::registerNatives() { + registerHybrid({ + makeNativeMethod("initHybrid", MainComponentsRegistry::initHybrid), + }); +} + +} // namespace react +} // namespace facebook \ No newline at end of file diff --git a/android/app/src/main/jni/MainComponentsRegistry.h b/android/app/src/main/jni/MainComponentsRegistry.h new file mode 100644 index 000000000..07af8980b --- /dev/null +++ b/android/app/src/main/jni/MainComponentsRegistry.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include +#include +#include + +namespace facebook { +namespace react { + +class MainComponentsRegistry + : public facebook::jni::HybridClass { + public: + // Adapt it to the package you used for your Java class. + constexpr static auto kJavaDescriptor = + "Lcom/mattermost/newarchitecture/components/MainComponentsRegistry;"; + + static void registerNatives(); + + MainComponentsRegistry(ComponentFactory *delegate); + + private: + static std::shared_ptr + sharedProviderRegistry(); + + static jni::local_ref initHybrid( + jni::alias_ref, + ComponentFactory *delegate); +}; + +} // namespace react +} // namespace facebook \ No newline at end of file diff --git a/android/app/src/main/jni/OnLoad.cpp b/android/app/src/main/jni/OnLoad.cpp new file mode 100644 index 000000000..ae1ef007d --- /dev/null +++ b/android/app/src/main/jni/OnLoad.cpp @@ -0,0 +1,11 @@ +#include +#include "MainApplicationTurboModuleManagerDelegate.h" +#include "MainComponentsRegistry.h" + +JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { + return facebook::jni::initialize(vm, [] { + facebook::react::MainApplicationTurboModuleManagerDelegate:: + registerNatives(); + facebook::react::MainComponentsRegistry::registerNatives(); + }); +} \ No newline at end of file diff --git a/android/build.gradle b/android/build.gradle index 6296de78b..f6af98fdf 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -2,16 +2,21 @@ buildscript { ext { - buildToolsVersion = "30.0.2" + buildToolsVersion = "31.0.0" minSdkVersion = 24 - compileSdkVersion = 30 - targetSdkVersion = 30 - supportLibVersion = "28.0.0" + compileSdkVersion = 31 + targetSdkVersion = 31 + supportLibVersion = "31.0.0" kotlinVersion = "1.5.30" firebaseVersion = "21.0.0" RNNKotlinVersion = kotlinVersion - ndkVersion = "21.4.7075529" - + if (System.properties['os.arch'] == "aarch64") { + // For M1 Users we need to use the NDK 24 which added support for aarch64 + ndkVersion = "24.0.8215888" + } else { + // Otherwise we default to the side-by-side NDK version from AGP. + ndkVersion = "21.4.7075529" + } } repositories { google() @@ -19,7 +24,9 @@ buildscript { mavenLocal() } dependencies { - classpath 'com.android.tools.build:gradle:4.2.2' + classpath 'com.android.tools.build:gradle:7.1.1' + classpath("com.facebook.react:react-native-gradle-plugin") + classpath("de.undercouch:gradle-download-task:5.0.1") classpath 'com.google.gms:google-services:4.3.10' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" diff --git a/android/gradle.properties b/android/gradle.properties index c88cd69c4..5bb2974a3 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -9,9 +9,8 @@ # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. -# Default value: -Xmx1024m -XX:MaxPermSize=256m -# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -org.gradle.jvmargs=-Xmx2048M +# Default value: -Xmx512m -XX:MaxMetaspaceSize=256m +org.gradle.jvmargs=-Xmx1024m -XX:MaxMetaspaceSize=512m # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit @@ -30,4 +29,15 @@ android.useAndroidX=true android.enableJetifier=true # Version of flipper SDK to use with React Native -FLIPPER_VERSION=0.99.0 +FLIPPER_VERSION=0.125.0 + +# Use this property to specify which architecture you want to build. +# You can also override it from the CLI using +# ./gradlew -PreactNativeArchitectures=x86_64 +reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 +# Use this property to enable support to the new architecture. +# This will allow you to use TurboModules and the Fabric render in +# your application. You should enable this flag either if you want +# to write custom TurboModules/Fabric components OR use libraries that +# are providing them. +newArchEnabled=false \ No newline at end of file diff --git a/android/gradle/wrapper/gradle-wrapper.jar b/android/gradle/wrapper/gradle-wrapper.jar index e708b1c02..7454180f2 100644 Binary files a/android/gradle/wrapper/gradle-wrapper.jar and b/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 966aa8e62..f338a8808 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip diff --git a/android/gradlew b/android/gradlew index 645f6ca31..a58591e97 100755 --- a/android/gradlew +++ b/android/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,78 +17,113 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${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='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # 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 - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -97,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -105,79 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=`expr $i + 1` - done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. -# 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" +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" \ No newline at end of file diff --git a/android/settings.gradle b/android/settings.gradle index 9369160c6..dc0b28055 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -3,3 +3,10 @@ include ':reactnativenotifications' project(':reactnativenotifications').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-notifications/lib/android/app') apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) include ':app' +includeBuild('../node_modules/react-native-gradle-plugin') +if (settings.hasProperty("newArchEnabled") && settings.newArchEnabled == "true") { + include(":ReactAndroid") + project(":ReactAndroid").projectDir = file('../node_modules/react-native/ReactAndroid') + include(":ReactAndroid:hermes-engine") + project(":ReactAndroid:hermes-engine").projectDir = file('../node_modules/react-native/ReactAndroid/hermes-engine') +} \ No newline at end of file diff --git a/app/components/__snapshots__/badge.test.js.snap b/app/components/__snapshots__/badge.test.js.snap index bf77c93db..efa6975da 100644 --- a/app/components/__snapshots__/badge.test.js.snap +++ b/app/components/__snapshots__/badge.test.js.snap @@ -3,14 +3,14 @@ exports[`Badge should match snapshot 1`] = ` `; diff --git a/app/components/__snapshots__/swiper.test.js.snap b/app/components/__snapshots__/swiper.test.js.snap index 9545911fb..7cdb8e044 100644 --- a/app/components/__snapshots__/swiper.test.js.snap +++ b/app/components/__snapshots__/swiper.test.js.snap @@ -4,8 +4,8 @@ exports[`Swiper should match snapshot 1`] = ` @John.Smith @@ -21,18 +21,18 @@ exports[`AtMention should match snapshot, with highlight 1`] = ` onLongPress={[Function]} onPress={[Function]} style={ - Object { + { "backgroundColor": "yellow", } } > { iconColor: { tintColor: theme.centerChannelColor, }, + iconSize: { + width: 10, + height: 16, + }, container: { flexDirection: 'row', alignItems: 'center', @@ -100,18 +104,14 @@ const SlashSuggestionItem = (props: Props) => { let image = ( ); if (props.icon === COMMAND_SUGGESTION_ERROR) { image = ( ); diff --git a/app/components/autocomplete_selector/autocomplete_selector.tsx b/app/components/autocomplete_selector/autocomplete_selector.tsx index 08283494f..5300bb787 100644 --- a/app/components/autocomplete_selector/autocomplete_selector.tsx +++ b/app/components/autocomplete_selector/autocomplete_selector.tsx @@ -204,6 +204,7 @@ export default class AutocompleteSelector extends PureComponent { goToSelectorScreen = preventDoubleTap(async () => { const closeButton = await CompassIcon.getImageSource(Platform.select({ios: 'arrow-back-ios', default: 'arrow-left'}), 24, this.props.theme.sidebarHeaderTextColor); + // @ts-expect-error context type definition const {formatMessage} = this.context.intl; const {actions, dataSource, options, placeholder, getDynamicOptions, theme} = this.props; const screen = 'SelectorScreen'; @@ -233,6 +234,7 @@ export default class AutocompleteSelector extends PureComponent { }); render() { + // @ts-expect-error context type definition const {intl} = this.context; const { placeholder, diff --git a/app/components/avatars/__snapshots__/avatars.test.tsx.snap b/app/components/avatars/__snapshots__/avatars.test.tsx.snap index 585590876..d63045143 100644 --- a/app/components/avatars/__snapshots__/avatars.test.tsx.snap +++ b/app/components/avatars/__snapshots__/avatars.test.tsx.snap @@ -7,14 +7,14 @@ exports[`Avatars should match snapshot for overflow 1`] = ` > `; exports[`CustomList should match snapshot, renderSectionHeader 1`] = ` - + `; diff --git a/app/components/emoji_picker/__snapshots__/emoji_picker.test.js.snap b/app/components/emoji_picker/__snapshots__/emoji_picker.test.js.snap index f159da5c4..c018dab55 100644 --- a/app/components/emoji_picker/__snapshots__/emoji_picker.test.js.snap +++ b/app/components/emoji_picker/__snapshots__/emoji_picker.test.js.snap @@ -1,15 +1,15 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`components/emoji_picker/emoji_picker.ios should match snapshot 1`] = ` - - + `; diff --git a/app/components/error_text/__snapshots__/error_text.test.js.snap b/app/components/error_text/__snapshots__/error_text.test.js.snap index 4171a0af9..2dbb436db 100644 --- a/app/components/error_text/__snapshots__/error_text.test.js.snap +++ b/app/components/error_text/__snapshots__/error_text.test.js.snap @@ -3,18 +3,18 @@ exports[`ErrorText should match snapshot 1`] = ` item, []); + const keyExtractor = React.useCallback((item: string) => item, []); - const renderPost = React.useCallback(({item}) => { + const renderPost = React.useCallback(({item}: ListRenderItemInfo) => { return ( @@ -40,7 +40,7 @@ exports[`Global Thread List Header Should render threads with functional tabs & > diff --git a/app/components/markdown/transform.test.js b/app/components/markdown/transform.test.js index fdedab7a9..80189a680 100644 --- a/app/components/markdown/transform.test.js +++ b/app/components/markdown/transform.test.js @@ -3100,50 +3100,6 @@ function nodeToString(node) { return out; } -const ignoredKeys = {_sourcepos: true, _lastLineBlank: true, _open: true, _string_content: true, _info: true, _isFenced: true, _fenceChar: true, _fenceLength: true, _fenceOffset: true, _onEnter: true, _onExit: true}; -function astToJson(node, visited = [], indent = '') { - let out = '{'; - - const myVisited = [...visited]; - myVisited.push(node); - - const keys = Object.keys(node).filter((key) => !ignoredKeys[key]); - if (keys.length > 0) { - out += '\n'; - } - - for (const [i, key] of keys.entries()) { - out += indent + ' "' + key + '":'; - - const value = node[key]; - if (myVisited.indexOf(value) !== -1) { - out += '[Circular]'; - } else if (value === null) { - out += 'null'; - } else if (typeof value === 'number') { - out += value; - } else if (typeof value === 'string') { - out += '"' + value + '"'; - } else if (typeof value === 'boolean') { - out += String(value); - } else if (typeof value === 'object') { - out += astToJson(value, myVisited, indent + ' '); // eslint-disable-line @typescript-eslint/no-unused-vars - } - - if (i !== keys.length - 1) { - out += ',\n'; - } - } - - if (keys.length > 0) { - out += '\n' + indent; - } - - out += '}'; - - return out; -} - // Converts an AST represented as a JavaScript object into a full Commonmark-compatitle AST. // This function is intended for use while testing. An example of input would be: // { diff --git a/app/components/post_draft/__snapshots__/post_draft.test.js.snap b/app/components/post_draft/__snapshots__/post_draft.test.js.snap index b2fce7be7..e8056f863 100644 --- a/app/components/post_draft/__snapshots__/post_draft.test.js.snap +++ b/app/components/post_draft/__snapshots__/post_draft.test.js.snap @@ -3,7 +3,7 @@ exports[`PostDraft Should render the Archived for channelIsArchived 1`] = ` - + `; diff --git a/app/components/post_draft/send_action/__snapshots__/send.test.js.snap b/app/components/post_draft/send_action/__snapshots__/send.test.js.snap index d940e01e0..069592290 100644 --- a/app/components/post_draft/send_action/__snapshots__/send.test.js.snap +++ b/app/components/post_draft/send_action/__snapshots__/send.test.js.snap @@ -3,7 +3,7 @@ exports[`SendAction should change theme backgroundColor to 0.3 opacity 1`] = ` { const {unreadCount} = this.props; + + // @ts-expect-error context type definition const {formatMessage} = this.context.intl; const isInitialMessage = unreadCount === count; diff --git a/app/components/post_list/post/body/content/message_attachments/__snapshots__/attachment_footer.test.tsx.snap b/app/components/post_list/post/body/content/message_attachments/__snapshots__/attachment_footer.test.tsx.snap index bee08d2fe..b30051ee7 100644 --- a/app/components/post_list/post/body/content/message_attachments/__snapshots__/attachment_footer.test.tsx.snap +++ b/app/components/post_list/post/body/content/message_attachments/__snapshots__/attachment_footer.test.tsx.snap @@ -3,7 +3,7 @@ exports[`AttachmentFooter it matches snapshot when both footer and footer_icon are provided 1`] = ` @username @username @username @other.user @username. @@ -233,8 +233,8 @@ exports[`renderSystemMessage uses renderer for Guest added and join to channel 2 exports[`renderSystemMessage uses renderer for OLD archived channel without a username 1`] = ` @username @username { + const registerViewableItemsListener = useCallback((listener: any) => { onViewableItemsChangedListener.current = listener; const removeListener = () => { onViewableItemsChangedListener.current = undefined; @@ -113,7 +113,7 @@ const PostList = ({ return removeListener; }, []); - const registerScrollEndIndexListener = useCallback((listener) => { + const registerScrollEndIndexListener = useCallback((listener: any) => { onScrollEndIndexListener.current = listener; const removeListener = () => { onScrollEndIndexListener.current = undefined; @@ -122,7 +122,7 @@ const PostList = ({ return removeListener; }, []); - const keyExtractor = useCallback((item) => { + const keyExtractor = useCallback((item: string) => { // All keys are strings (either post IDs or special keys) return item; }, []); @@ -173,7 +173,7 @@ const PostList = ({ } }, []); - const renderItem = useCallback(({item, index}) => { + const renderItem = useCallback(({item, index}: ListRenderItemInfo) => { if (isStartOfNewMessages(item)) { // postIds includes a date item after the new message indicator so 2 // needs to be added to the index for the length check to be correct. diff --git a/app/components/progressive_image/__snapshots__/progressive_image.test.js.snap b/app/components/progressive_image/__snapshots__/progressive_image.test.js.snap index 1ca1fdf6b..c22f90784 100644 --- a/app/components/progressive_image/__snapshots__/progressive_image.test.js.snap +++ b/app/components/progressive_image/__snapshots__/progressive_image.test.js.snap @@ -3,26 +3,26 @@ exports[`ProgressiveImage should match snapshot for BackgroundImage 1`] = ` @@ -56,8 +56,8 @@ exports[`ProgressiveImage should match snapshot for Default Image 1`] = ` resizeMode="contain" source="https://images.com/image.png" style={ - Array [ - Object { + [ + { "bottom": 0, "left": 0, "position": "absolute", @@ -75,14 +75,14 @@ exports[`ProgressiveImage should match snapshot for Default Image 1`] = ` exports[`ProgressiveImage should match snapshot for Image 1`] = ` } containerStyle={ - Object { + { "backgroundColor": "#ffffff", "flex": 1, "paddingBottom": 0, @@ -73,14 +73,14 @@ exports[`SearchBar should match snapshot 1`] = ` editable={true} enablesReturnKeyAutomatically={true} inputContainerStyle={ - Object { + { "backgroundColor": undefined, "borderRadius": 2, "height": 10, } } inputStyle={ - Object { + { "backgroundColor": "transparent", "color": "#fff", "fontSize": 14, @@ -93,7 +93,7 @@ exports[`SearchBar should match snapshot 1`] = ` keyboardAppearance="keyboard-appearance" keyboardType="keyboard-type" leftIconContainerStyle={ - Object { + { "marginLeft": 4, "width": 30, } @@ -114,11 +114,11 @@ exports[`SearchBar should match snapshot 1`] = ` name="magnify" size={24} style={ - Array [ - Object { + [ + { "flex": 1, }, - Object { + { "color": "#bbbbbb", "top": 8, }, diff --git a/app/components/sidebars/main/__snapshots__/main_sidebar.test.js.snap b/app/components/sidebars/main/__snapshots__/main_sidebar.test.js.snap index d955b64b8..40c1c0015 100644 --- a/app/components/sidebars/main/__snapshots__/main_sidebar.test.js.snap +++ b/app/components/sidebars/main/__snapshots__/main_sidebar.test.js.snap @@ -4,7 +4,7 @@ exports[`MainSidebar should match, full snapshot 1`] = ` diff --git a/app/components/sidebars/settings/__snapshots__/settings_sidebar.test.js.snap b/app/components/sidebars/settings/__snapshots__/settings_sidebar.test.js.snap index f56a457a1..eac01aae4 100644 --- a/app/components/sidebars/settings/__snapshots__/settings_sidebar.test.js.snap +++ b/app/components/sidebars/settings/__snapshots__/settings_sidebar.test.js.snap @@ -5,7 +5,7 @@ exports[`SettingsSidebar Custom Status should close sidebar when update custom s drawerPosition="right" drawerWidth={710} forwardRef={ - Object { + { "current": null, } } @@ -21,7 +21,7 @@ exports[`SettingsSidebar Custom Status should keep sidebar open when update cust drawerPosition="right" drawerWidth={710} forwardRef={ - Object { + { "current": null, } } @@ -37,7 +37,7 @@ exports[`SettingsSidebar should match snapshot 1`] = ` drawerPosition="right" drawerWidth={710} forwardRef={ - Object { + { "current": null, } } @@ -53,7 +53,7 @@ exports[`SettingsSidebar should match snapshot with custom status enabled 1`] = drawerPosition="right" drawerWidth={710} forwardRef={ - Object { + { "current": null, } } @@ -69,7 +69,7 @@ exports[`SettingsSidebar should match snapshot with custom status expiry 1`] = ` drawerPosition="right" drawerWidth={710} forwardRef={ - Object { + { "current": null, } } diff --git a/app/components/slide_up_panel/__snapshots__/slide_up_panel_indicator.test.js.snap b/app/components/slide_up_panel/__snapshots__/slide_up_panel_indicator.test.js.snap index e2e49dd9b..253701c84 100644 --- a/app/components/slide_up_panel/__snapshots__/slide_up_panel_indicator.test.js.snap +++ b/app/components/slide_up_panel/__snapshots__/slide_up_panel_indicator.test.js.snap @@ -3,7 +3,7 @@ exports[`SlideUpPanelIndicator should match snapshot 1`] = ` 00:15 diff --git a/app/products/calls/components/__snapshots__/floating_call_container.test.js.snap b/app/products/calls/components/__snapshots__/floating_call_container.test.js.snap index 31e9b18d9..ca28a87f8 100644 --- a/app/products/calls/components/__snapshots__/floating_call_container.test.js.snap +++ b/app/products/calls/components/__snapshots__/floating_call_container.test.js.snap @@ -4,8 +4,8 @@ exports[`FloatingCallContainer should match snapshot 1`] = ` { diff --git a/app/products/calls/components/join_call/__snapshots__/join_call.test.js.snap b/app/products/calls/components/join_call/__snapshots__/join_call.test.js.snap index 4df265679..a79cab84c 100644 --- a/app/products/calls/components/join_call/__snapshots__/join_call.test.js.snap +++ b/app/products/calls/components/join_call/__snapshots__/join_call.test.js.snap @@ -3,7 +3,7 @@ exports[`JoinCall should match snapshot 1`] = ` } userIds={ - Array [ + [ "user-1-id", "user-2-id", ] diff --git a/app/products/calls/hooks.ts b/app/products/calls/hooks.ts index d6911a7e1..4b09d545c 100644 --- a/app/products/calls/hooks.ts +++ b/app/products/calls/hooks.ts @@ -57,6 +57,7 @@ export const useCallsChannelSettings = () => { useEffect(() => { if (pluginEnabled) { + // @ts-expect-error ActionFunc dispatch(loadConfig()); } }, []); diff --git a/app/products/calls/screens/call/__snapshots__/call_screen.test.js.snap b/app/products/calls/screens/call/__snapshots__/call_screen.test.js.snap index 4bc3e1d4b..2456a2d2c 100644 --- a/app/products/calls/screens/call/__snapshots__/call_screen.test.js.snap +++ b/app/products/calls/screens/call/__snapshots__/call_screen.test.js.snap @@ -3,14 +3,14 @@ exports[`CallScreen Landscape should match snapshot 1`] = `