Update Dependencies and bug fixes (#7000)

* update dependencies

* update dependencies

* feedback review

* update @mattermost/react-native-turbo-mailer
This commit is contained in:
Elias Nahum 2023-01-24 09:14:23 +02:00 committed by GitHub
parent 4aaf08b12a
commit 7aa5bd0611
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
349 changed files with 4907 additions and 4641 deletions

11
.gitignore vendored
View file

@ -46,6 +46,8 @@ local.properties
*.iml
*.hprof
.cxx/
*.keystore
!debug.keystore
android/app/bin
android/app/build
android/build
@ -61,12 +63,6 @@ npm-debug.log
yarn-error.log
.yarninstall
# BUCK
buck-out/
\.buckd/
android/app/libs
*.keystore
# Vim
[._]*.s[a-w][a-z]
[._]s[a-w][a-z]
@ -114,3 +110,6 @@ launch.json
# Notice.txt generation
!build/notice-file
# Temporary files created by Metro to check the health of the file watcher
.metro-health-check*

View file

@ -1,65 +0,0 @@
# To learn about Buck see [Docs](https://buckbuild.com/).
# To run your application with Buck:
# - install Buck
# - `npm start` - to start the packager
# - `cd android`
# - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"`
# - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck
# - `buck install -r android/app` - compile, install and run application
#
lib_deps = []
for jarfile in glob(['libs/*.jar']):
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']):
name = 'aars__' + aarfile[aarfile.rindex('/') + 1: aarfile.rindex('.aar')]
lib_deps.append(':' + name)
android_prebuilt_aar(
name = name,
aar = aarfile,
)
android_library(
name = "all-libs",
exported_deps = lib_deps,
)
android_library(
name = "app-code",
srcs = glob([
"src/main/java/**/*.java",
]),
deps = [
":all-libs",
":build_config",
":res",
],
)
android_build_config(
name = "build_config",
package = "com.mattermost.rnbeta",
)
android_resource(
name = "res",
package = "com.mattermost.rnbeta",
res = "src/main/res",
)
android_binary(
name = "app",
keystore = "//android/keystores:debug",
manifest = "src/main/AndroidManifest.xml",
package_type = "debug",
deps = [
":app-code",
],
)

View file

@ -1,88 +1,56 @@
apply plugin: "com.android.application"
apply plugin: "com.facebook.react"
apply plugin: 'kotlin-android'
import com.android.build.OutputFile
import org.apache.tools.ant.taskdefs.condition.Os
/**
* The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
* and bundleReleaseJsAndAssets).
* These basically call `react-native bundle` with the correct arguments during the Android build
* cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
* bundle directly from the development server. Below you can see all the possible configurations
* and their defaults. If you decide to add a configuration block, make sure to add it before the
* `apply from: "../../node_modules/react-native/react.gradle"` line.
*
* project.ext.react = [
* // the name of the generated asset file containing your JS bundle
* bundleAssetName: "index.android.bundle",
*
* // the entry file for bundle generation. If none specified and
* // "index.android.js" exists, it will be used. Otherwise "index.js" is
* // default. Can be overridden with ENTRY_FILE environment variable.
* entryFile: "index.android.js",
*
* // whether to bundle JS and assets in debug mode
* bundleInDebug: false,
*
* // whether to bundle JS and assets in release mode
* bundleInRelease: true,
*
* // whether to bundle JS and assets in another build variant (if configured).
* // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
* // The configuration property can be in the following formats
* // 'bundleIn${productFlavor}${buildType}'
* // 'bundleIn${buildType}'
* // bundleInFreeDebug: true,
* // bundleInPaidRelease: true,
* // bundleInBeta: true,
*
* // whether to disable dev mode in custom build variants (by default only disabled in release)
* // for example: to disable dev mode in the staging build type (if configured)
* devDisabledInStaging: true,
* // The configuration property can be in the following formats
* // 'devDisabledIn${productFlavor}${buildType}'
* // 'devDisabledIn${buildType}'
*
* // the root of your project, i.e. where "package.json" lives
* root: "../../",
*
* // where to put the JS bundle asset in debug mode
* jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
*
* // where to put the JS bundle asset in release mode
* jsBundleDirRelease: "$buildDir/intermediates/assets/release",
*
* // where to put drawable resources / React Native assets, e.g. the ones you use via
* // require('./image.png')), in debug mode
* resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
*
* // where to put drawable resources / React Native assets, e.g. the ones you use via
* // require('./image.png')), in release mode
* resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
*
* // by default the gradle tasks are skipped if none of the JS files or assets change; this means
* // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
* // date; if you have any other folders that you want to ignore for performance reasons (gradle
* // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
* // for example, you might want to remove it from here.
* inputExcludes: ["android/**", "ios/**"],
*
* // override which node gets called and with what additional arguments
* nodeExecutableAndArgs: ["node"],
*
* // supply additional arguments to the packager
* extraPackagerArgs: []
* ]
* This is the configuration block to customize your React Native Android app.
* By default you don't need to apply any configuration, just uncomment the lines you need.
*/
project.ext.react = [
entryFile: "index.ts",
bundleConfig: "metro.config.js",
bundleCommand: "bundle",
enableHermes: true,
]
react {
/* Folders */
// The root of your project, i.e. where "package.json" lives. Default is '..'
// root = file("../")
// The folder where the react-native NPM package is. Default is ../node_modules/react-native
// reactNativeDir = file("../node_modules/react-native")
// The folder where the react-native Codegen package is. Default is ../node_modules/react-native-codegen
// codegenDir = file("../node_modules/react-native-codegen")
// The cli.js file which is the React Native CLI entrypoint. Default is ../node_modules/react-native/cli.js
// cliFile = file("../node_modules/react-native/cli.js")
/* Variants */
// The list of variants to that are debuggable. For those we're going to
// skip the bundling of the JS bundle and the assets. By default is just 'debug'.
// If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants.
// debuggableVariants = ["liteDebug", "prodDebug"]
/* Bundling */
// A list containing the node command and its flags. Default is just 'node'.
// nodeExecutableAndArgs = ["node"]
//
// The command to run when bundling. By default is 'bundle'
// bundleCommand = "ram-bundle"
//
// The path to the CLI configuration file. Default is empty.
// bundleConfig = file(../rn-cli.config.js)
//
// The name of the generated asset file containing your JS bundle
// bundleAssetName = "MyApplication.android.bundle"
//
// The entry file for bundle generation. Default is 'index.android.js' or 'index.js'
entryFile = file("../../index.ts")
//
// A list of extra flags to pass to the 'bundle' commands.
// See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle
// extraPackagerArgs = []
/* Hermes Commands */
// The hermes compiler command to run. By default it is 'hermesc'
// hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc"
//
// The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map"
// hermesFlags = ["-O", "-output-source-map"]
}
apply from: "../../node_modules/react-native/react.gradle"
apply from: "../../node_modules/react-native-vector-icons/fonts.gradle"
if (System.getenv("SENTRY_ENABLED") == "true") {
@ -95,33 +63,35 @@ if (System.getenv("SENTRY_ENABLED") == "true") {
}
/**
* Set this to true to create two separate APKs instead of one:
* - An APK that only works on ARM devices
* - An APK that only works on x86 devices
* The advantage is the size of the APK is reduced by about 4MB.
* Upload all the APKs to the Play Store and people will download
* the correct one based on the CPU architecture of their device.
* Set this to true to create four separate APKs instead of one,
* one for each native architecture. This is useful if you don't
* use App Bundles (https://developer.android.com/guide/app-bundle/)
* and want to have separate APKs to upload to the Play Store
*/
def enableSeparateBuildPerCPUArchitecture = project.hasProperty('separateApk') ? project.property('separateApk').toBoolean() : false
/**
* Run Proguard to shrink the Java bytecode in release builds.
* Set this to true to Run Proguard on Release builds to minify the Java bytecode.
*/
def enableProguardInReleaseBuilds = false
/**
* The preferred build flavor of JavaScriptCore (JSC)
*
* 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-intl:+'
/**
* Whether to enable the Hermes VM.
*
* This should be set on project.ext.react and that value will be read 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);
/**
* Architectures to build native code for.
* Private function to get the list of Native Architectures you want to build.
* This reads the value from reactNativeArchitectures in your gradle.properties
* file and works together with the --active-arch-only flag of react-native run-android.
*/
def reactNativeArchitectures() {
def value = project.getProperties().get("reactNativeArchitectures")
@ -131,16 +101,13 @@ def reactNativeArchitectures() {
android {
ndkVersion rootProject.ext.ndkVersion
compileSdkVersion rootProject.ext.compileSdkVersion
namespace "com.mattermost.rnbeta"
lintOptions {
checkReleaseBuilds false
abortOnError false
}
packagingOptions {
pickFirst '**/libc++_shared.so'
}
defaultConfig {
applicationId "com.mattermost.rnbeta"
minSdkVersion rootProject.ext.minSdkVersion
@ -149,66 +116,6 @@ android {
versionName "2.0.0"
testBuildType System.getProperty('testBuildType', 'debug')
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
if (isNewArchitectureEnabled()) {
// We configure the CMake build only if you decide to opt-in for the New Architecture.
externalNativeBuild {
cmake {
arguments "-DPROJECT_BUILD_DIR=$buildDir",
"-DREACT_ANDROID_DIR=$rootDir/../node_modules/react-native/ReactAndroid",
"-DREACT_ANDROID_BUILD_DIR=$rootDir/../node_modules/react-native/ReactAndroid/build",
"-DNODE_MODULES_DIR=$rootDir/../node_modules",
"-DANDROID_STL=c++_shared"
}
}
if (!enableSeparateBuildPerCPUArchitecture) {
ndk {
abiFilters (*reactNativeArchitectures())
}
}
}
}
if (isNewArchitectureEnabled()) {
// We configure the NDK build only if you decide to opt-in for the New Architecture.
externalNativeBuild {
cmake {
path "$projectDir/src/main/jni/CMakeLists.txt"
}
}
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 configureCMakeDebug* tasks and the preBuild tasks.
// This can be removed once this is solved: https://issuetracker.google.com/issues/207403732
configureCMakeDebugRelease.dependsOn(preReleaseBuild)
configureCMakeDebugDebug.dependsOn(preDebugBuild)
reactNativeArchitectures().each { architecture ->
tasks.findByName("configureCMakeDebugDebug[${architecture}]")?.configure {
dependsOn("preDebugBuild")
}
tasks.findByName("configureCMakeDebugRelease[${architecture}]")?.configure {
dependsOn("preReleaseBuild")
}
}
}
}
signingConfigs {
@ -281,70 +188,36 @@ repositories {
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
// The version of react-native is set by the React Native Gradle Plugin
implementation("com.facebook.react:react-android")
//noinspection GradleDynamicVersio
implementation "com.facebook.react:react-native:+" // From node_modules
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.0.0")
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2'
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
exclude group:'com.facebook.fbjni'
}
debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}")
debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
exclude group:'com.facebook.flipper'
}
debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") {
exclude group:'com.facebook.flipper'
exclude group:'com.squareup.okhttp3', module:'okhttp'
}
if (enableHermes) {
//noinspection GradleDynamicVersion
implementation("com.facebook.react:hermes-engine:+") { // From node_modules
exclude group:'com.facebook.fbjni'
}
debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}")
if (hermesEnabled.toBoolean()) {
implementation("com.facebook.react:hermes-android")
} else {
implementation jscFlavor
}
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2'
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation project(':reactnativenotifications')
implementation "com.google.firebase:firebase-messaging:$firebaseVersion"
// For animated GIF support
implementation 'com.facebook.fresco:fresco:2.6.0'
implementation 'com.facebook.fresco:animated-gif:2.6.0'
// For WebP support, including animated WebP
implementation 'com.facebook.fresco:animated-webp:2.6.0'
implementation 'com.facebook.fresco:webpsupport:2.6.0'
androidTestImplementation('com.wix:detox:+')
implementation project(':reactnativenotifications')
implementation project(':watermelondb-jsi')
}
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 {
force "com.facebook.soloader:soloader:0.10.1"
eachDependency { DependencyResolveDetails details ->
if (details.requested.name == 'play-services-base') {
details.useTarget group: details.requested.group, name: details.requested.name, version: '15.0.1'
@ -359,13 +232,13 @@ configurations.all {
details.useTarget group: details.requested.group, name: details.requested.name, version: '15.0.1'
}
if (details.requested.name == 'okhttp') {
details.useTarget group: details.requested.group, name: details.requested.name, version: '4.9.2'
details.useTarget group: details.requested.group, name: details.requested.name, version: '4.10.0'
}
if (details.requested.name == 'okhttp-tls') {
details.useTarget group: details.requested.group, name: details.requested.name, version: '4.9.2'
details.useTarget group: details.requested.group, name: details.requested.name, version: '4.10.0'
}
if (details.requested.name == 'okhttp-urlconnection') {
details.useTarget group: details.requested.group, name: details.requested.name, version: '4.9.2'
details.useTarget group: details.requested.group, name: details.requested.name, version: '4.10.0'
}
}
}
@ -380,11 +253,3 @@ 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"
}

BIN
android/app/debug.keystore Normal file

Binary file not shown.

View file

@ -4,7 +4,7 @@
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
* directory of this source tree.
*/
package com.rn;
package com.mattermost.flipper;
import android.content.Context;
import com.facebook.flipper.android.AndroidFlipperClient;
@ -17,19 +17,22 @@ import com.facebook.flipper.plugins.inspector.DescriptorMapping;
import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin;
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;
import okhttp3.OkHttpClient;
/**
* Class responsible of loading Flipper inside your React Native application. This is the debug
* flavor of it. Here you can add your own plugins and customize the Flipper setup.
*/
public class ReactNativeFlipper {
public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
if (FlipperUtils.shouldEnableFlipper(context)) {
final FlipperClient client = AndroidFlipperClient.getInstance(context);
client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults()));
client.addPlugin(new ReactFlipperPlugin());
client.addPlugin(new DatabasesFlipperPlugin(context));
client.addPlugin(new SharedPreferencesFlipperPlugin(context));
client.addPlugin(CrashReporterPlugin.getInstance());

View file

@ -1,10 +1,10 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mattermost.rnbeta">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission-sdk-23 android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO"/>
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

View file

@ -1,116 +0,0 @@
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.
*
* <p>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<ReactPackage> getPackages() {
List<ReactPackage> 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<JSIModuleSpec> getJSIModules(
final ReactApplicationContext reactApplicationContext,
final JavaScriptContextHolder jsContext) {
final List<JSIModuleSpec> 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<UIManager> 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;
}
};
}
}

View file

@ -1,36 +0,0 @@
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).
*
* <p>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);
}
}

View file

@ -1,48 +0,0 @@
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).
*
* <p>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<ReactPackage> 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<ReactPackage> 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;
}
}
}

View file

@ -6,37 +6,36 @@ 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;
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
import com.facebook.react.defaults.DefaultReactActivityDelegate;
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 String getMainComponentName() {
return "Mattermost";
}
@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;
}
/**
* Returns the instance of the {@link ReactActivityDelegate}. Here we use a util class {@link
* DefaultReactActivityDelegate} which allows you to easily enable Fabric and Concurrent React
* (aka React 18) with two boolean flags.
*/
@Override
protected ReactActivityDelegate createReactActivityDelegate() {
return new DefaultReactActivityDelegate(
this,
getMainComponentName(),
// If you opted-in for the New Architecture, we enable the Fabric Renderer.
DefaultNewArchitectureEntryPoint.getFabricEnabled(), // fabricEnabled
// If you opted-in for the New Architecture, we enable Concurrent React (i.e. React 18).
DefaultNewArchitectureEntryPoint.getConcurrentReactEnabled() // concurrentRootEnabled
);
}
@Override

View file

@ -1,7 +1,4 @@
package com.mattermost.rnbeta;
import com.facebook.react.bridge.JSIModuleSpec;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
@ -23,11 +20,12 @@ import com.wix.reactnativenotifications.core.AppLifecycleFacade;
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.defaults.DefaultNewArchitectureEntryPoint;
import com.facebook.react.defaults.DefaultReactNativeHost;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.TurboReactPackage;
import com.facebook.react.bridge.JSIModuleSpec;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.JSIModulePackage;
@ -36,8 +34,8 @@ import com.facebook.react.module.model.ReactModuleInfoProvider;
import com.facebook.react.modules.network.OkHttpClientProvider;
import com.facebook.soloader.SoLoader;
import com.mattermost.flipper.ReactNativeFlipper;
import com.mattermost.networkclient.RCTOkHttpClientFactory;
import com.mattermost.newarchitecture.MainApplicationReactNativeHost;
import com.nozbe.watermelondb.jsi.WatermelonDBJSIPackage;
public class MainApplication extends NavigationApplication implements INotificationsApplication {
@ -46,7 +44,7 @@ public class MainApplication extends NavigationApplication implements INotificat
public Boolean sharedExtensionIsOpened = false;
private final ReactNativeHost mReactNativeHost =
new ReactNativeHost(this) {
new DefaultReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
@ -106,30 +104,26 @@ public class MainApplication extends NavigationApplication implements INotificat
protected String getJSMainModuleName() {
return "index";
}
@Override
protected boolean isNewArchEnabled() {
return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
}
@Override
protected Boolean isHermesEnabled() {
return BuildConfig.IS_HERMES_ENABLED;
}
};
private final ReactNativeHost mNewArchitectureNativeHost =
new MainApplicationReactNativeHost(this);
@Override
public ReactNativeHost getReactNativeHost() {
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
return mNewArchitectureNativeHost;
} else {
return mReactNativeHost;
}
return mReactNativeHost;
}
@Override
public void onCreate() {
super.onCreate();
instance = this;
// 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());
Context context = getApplicationContext();
// Delete any previous temp files created by the app
@ -141,6 +135,13 @@ public class MainApplication extends NavigationApplication implements INotificat
// with a cookie jar defined in APIClientModule and an interceptor to intercept all
// requests that originate from React Native's OKHttpClient
OkHttpClientProvider.setOkHttpClientFactory(new RCTOkHttpClientFactory());
SoLoader.init(this, /* native exopackage */ false);
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
// If you opted-in for the New Architecture, we load the native entry point for this app.
DefaultNewArchitectureEntryPoint.load();
}
ReactNativeFlipper.initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
}
@Override
@ -153,26 +154,4 @@ public class MainApplication extends NavigationApplication implements INotificat
new JsIOHelper()
);
}
/**
* Loads Flipper in React Native templates. Call this in the onCreate method with something like
* initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
*/
private static void initializeFlipper(
Context context, ReactInstanceManager reactInstanceManager) {
if (BuildConfig.DEBUG) {
try {
/*
We use reflection here to pick up the class that initializes Flipper,
since Flipper library is not available in release mode
*/
Class<?> aClass = Class.forName("com.rn.ReactNativeFlipper");
aClass
.getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
.invoke(null, context, reactInstanceManager);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

View file

@ -90,22 +90,26 @@ public class ShareUtils {
}
private static Bitmap getBitmapAtTime(Context context, String filePath, int time) {
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
if (URLUtil.isFileUrl(filePath)) {
String decodedPath;
try {
decodedPath = URLDecoder.decode(filePath, "UTF-8");
} catch (UnsupportedEncodingException e) {
decodedPath = filePath;
try {
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
if (URLUtil.isFileUrl(filePath)) {
String decodedPath;
try {
decodedPath = URLDecoder.decode(filePath, "UTF-8");
} catch (UnsupportedEncodingException e) {
decodedPath = filePath;
}
retriever.setDataSource(decodedPath.replace("file://", ""));
} else if (filePath.contains("content://")) {
retriever.setDataSource(context, Uri.parse(filePath));
}
retriever.setDataSource(decodedPath.replace("file://", ""));
} else if (filePath.contains("content://")) {
retriever.setDataSource(context, Uri.parse(filePath));
Bitmap image = retriever.getFrameAtTime(time * 1000, MediaMetadataRetriever.OPTION_CLOSEST_SYNC);
retriever.release();
return image;
} catch (Exception e) {
throw new IllegalStateException("File doesn't exist or not supported");
}
Bitmap image = retriever.getFrameAtTime(time * 1000, MediaMetadataRetriever.OPTION_CLOSEST_SYNC);
retriever.release();
return image;
}
}

View file

@ -1,7 +0,0 @@
cmake_minimum_required(VERSION 3.13)
# Define the library name here.
project(rndiffapp_appmodules)
# This file includes all the necessary to let you build your application with the New Architecture.
include(${REACT_ANDROID_DIR}/cmake-utils/ReactNative-application.cmake)

View file

@ -1,32 +0,0 @@
#include "MainApplicationModuleProvider.h"
#include <rncli.h>
#include <rncore.h>
namespace facebook {
namespace react {
std::shared_ptr<TurboModule> MainApplicationModuleProvider(
const std::string &moduleName,
const JavaTurboModule::InitParams &params) {
// 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);
// Module providers autolinked by RN CLI
auto rncli_module = rncli_ModuleProvider(moduleName, params);
if (rncli_module != nullptr) {
return rncli_module;
}
return rncore_ModuleProvider(moduleName, params);
}
} // namespace react
} // namespace facebook

View file

@ -1,16 +0,0 @@
#pragma once
#include <memory>
#include <string>
#include <ReactCommon/JavaTurboModule.h>
namespace facebook {
namespace react {
std::shared_ptr<TurboModule> MainApplicationModuleProvider(
const std::string &moduleName,
const JavaTurboModule::InitParams &params);
} // namespace react
} // namespace facebook

View file

@ -1,45 +0,0 @@
#include "MainApplicationTurboModuleManagerDelegate.h"
#include "MainApplicationModuleProvider.h"
namespace facebook {
namespace react {
jni::local_ref<MainApplicationTurboModuleManagerDelegate::jhybriddata>
MainApplicationTurboModuleManagerDelegate::initHybrid(
jni::alias_ref<jhybridobject>) {
return makeCxxInstance();
}
void MainApplicationTurboModuleManagerDelegate::registerNatives() {
registerHybrid({
makeNativeMethod(
"initHybrid", MainApplicationTurboModuleManagerDelegate::initHybrid),
makeNativeMethod(
"canCreateTurboModule",
MainApplicationTurboModuleManagerDelegate::canCreateTurboModule),
});
}
std::shared_ptr<TurboModule>
MainApplicationTurboModuleManagerDelegate::getTurboModule(
const std::string &name,
const std::shared_ptr<CallInvoker> &jsInvoker) {
// Not implemented yet: provide pure-C++ NativeModules here.
return nullptr;
}
std::shared_ptr<TurboModule>
MainApplicationTurboModuleManagerDelegate::getTurboModule(
const std::string &name,
const JavaTurboModule::InitParams &params) {
return MainApplicationModuleProvider(name, params);
}
bool MainApplicationTurboModuleManagerDelegate::canCreateTurboModule(
const std::string &name) {
return getTurboModule(name, nullptr) != nullptr ||
getTurboModule(name, {.moduleName = name}) != nullptr;
}
} // namespace react
} // namespace facebook

View file

@ -1,38 +0,0 @@
#include <memory>
#include <string>
#include <ReactCommon/TurboModuleManagerDelegate.h>
#include <fbjni/fbjni.h>
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/rndiffapp/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate;";
static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jhybridobject>);
static void registerNatives();
std::shared_ptr<TurboModule> getTurboModule(
const std::string &name,
const std::shared_ptr<CallInvoker> &jsInvoker) override;
std::shared_ptr<TurboModule> getTurboModule(
const std::string &name,
const JavaTurboModule::InitParams &params) override;
/**
* Test-only method. Allows user to verify whether a TurboModule can be
* created by instances of this class.
*/
bool canCreateTurboModule(const std::string &name);
};
} // namespace react
} // namespace facebook

View file

@ -1,65 +0,0 @@
#include "MainComponentsRegistry.h"
#include <CoreComponentsRegistry.h>
#include <fbjni/fbjni.h>
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
#include <react/renderer/components/rncore/ComponentDescriptors.h>
#include <rncli.h>
namespace facebook {
namespace react {
MainComponentsRegistry::MainComponentsRegistry(ComponentFactory *delegate) {}
std::shared_ptr<ComponentDescriptorProviderRegistry const>
MainComponentsRegistry::sharedProviderRegistry() {
auto providerRegistry = CoreComponentsRegistry::sharedProviderRegistry();
// Autolinked providers registered by RN CLI
rncli_registerProviders(providerRegistry);
// 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::jhybriddata>
MainComponentsRegistry::initHybrid(
jni::alias_ref<jclass>,
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<ComponentDescriptorRegistry>(registry);
mutableRegistry->setFallbackComponentDescriptor(
std::make_shared<UnimplementedNativeViewComponentDescriptor>(
ComponentDescriptorParameters{
eventDispatcher, contextContainer, nullptr}));
return registry;
};
delegate->buildRegistryFunction = buildRegistryFunction;
return instance;
}
void MainComponentsRegistry::registerNatives() {
registerHybrid({
makeNativeMethod("initHybrid", MainComponentsRegistry::initHybrid),
});
}
} // namespace react
} // namespace facebook

View file

@ -1,32 +0,0 @@
#pragma once
#include <ComponentFactory.h>
#include <fbjni/fbjni.h>
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
#include <react/renderer/componentregistry/ComponentDescriptorRegistry.h>
namespace facebook {
namespace react {
class MainComponentsRegistry
: public facebook::jni::HybridClass<MainComponentsRegistry> {
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<ComponentDescriptorProviderRegistry const>
sharedProviderRegistry();
static jni::local_ref<jhybriddata> initHybrid(
jni::alias_ref<jclass>,
ComponentFactory *delegate);
};
} // namespace react
} // namespace facebook

View file

@ -1,11 +0,0 @@
#include <fbjni/fbjni.h>
#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();
});
}

View file

@ -0,0 +1,19 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
* directory of this source tree.
*/
package com.mattermost.flipper;
import android.content.Context;
import com.facebook.react.ReactInstanceManager;
/**
* Class responsible of loading Flipper inside your React Native application. This is the release
* flavor of it so it's empty as we don't want to load Flipper.
*/
public class ReactNativeFlipper {
public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
// Do nothing as we don't want to initialize Flipper on Release.
}
}

View file

@ -2,22 +2,18 @@
buildscript {
ext {
buildToolsVersion = "31.0.0"
buildToolsVersion = "33.0.0"
minSdkVersion = 24
compileSdkVersion = 31
targetSdkVersion = 31
supportLibVersion = "31.0.0"
compileSdkVersion = 33
targetSdkVersion = 33
supportLibVersion = "33.0.0"
kotlinVersion = "1.5.30"
kotlin_version = "1.5.30"
firebaseVersion = "21.0.0"
RNNKotlinVersion = kotlinVersion
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"
}
// We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP.
ndkVersion = "23.1.7779620"
}
repositories {
mavenCentral()
@ -25,9 +21,8 @@ buildscript {
google()
}
dependencies {
classpath("com.android.tools.build:gradle:7.2.1")
classpath("com.android.tools.build:gradle:7.3.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.14')
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion")
@ -38,50 +33,9 @@ buildscript {
allprojects {
repositories {
exclusiveContent {
// We get React Native's Android binaries exclusively through npm,
// from a local Maven repo inside node_modules/react-native/.
// (The use of exclusiveContent prevents looking elsewhere like Maven Central
// and potentially getting a wrong version.)
filter {
includeGroup "com.facebook.react"
}
forRepository {
maven {
url "$rootDir/../node_modules/react-native/android"
}
}
}
google()
mavenCentral()
mavenLocal()
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url("$rootDir/../node_modules/react-native/android")
// Replace AAR from original RN with AAR from react-native-v8
// url("$rootDir/../node_modules/react-native-v8/dist")
}
maven {
// Local Maven repo containing AARs with JSC library built for Android
url("$rootDir/../node_modules/jsc-android/dist")
// prebuilt libv8android.so
// url("$rootDir/../node_modules/v8-android/dist")
}
maven {
url "https://www.jitpack.io"
}
maven {
url "$rootDir/../node_modules/detox/Detox-android"
}
mavenCentral {
// We don't want to fetch react-native from Maven Central as there are
// older versions over there.
content {
excludeGroup "com.facebook.react"
}
}
}
}

View file

@ -40,4 +40,8 @@ reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
# 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
newArchEnabled=false
# Use this property to enable or disable the Hermes JS engine.
# If set to false, you will be using JSC instead.
hermesEnabled=true

View file

@ -1,13 +1,5 @@
rootProject.name = 'Mattermost'
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')
}
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)
@ -15,3 +7,4 @@ include ':react-native-video'
project(':react-native-video').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-video/android-exoplayer')
include ':watermelondb-jsi'
project(':watermelondb-jsi').projectDir = new File(rootProject.projectDir, '../node_modules/@nozbe/watermelondb/native/android-jsi')
includeBuild('../node_modules/react-native-gradle-plugin')

View file

@ -1,8 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Model} from '@nozbe/watermelondb';
import {CHANNELS_CATEGORY, DMS_CATEGORY} from '@constants/categories';
import DatabaseManager from '@database/manager';
import {prepareCategoryChannels, queryCategoriesByTeamIds, getCategoryById, prepareCategoriesAndCategoriesChannels} from '@queries/servers/categories';
@ -11,6 +9,7 @@ import {queryMyTeams} from '@queries/servers/team';
import {isDMorGM} from '@utils/channel';
import {logError} from '@utils/log';
import type {Model} from '@nozbe/watermelondb';
import type ChannelModel from '@typings/database/models/servers/channel';
export const deleteCategory = async (serverUrl: string, categoryId: string) => {

View file

@ -1,13 +1,11 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Database} from '@nozbe/watermelondb';
import {DeviceEventEmitter} from 'react-native';
import {Navigation} from '@constants';
import {SYSTEM_IDENTIFIERS} from '@constants/database';
import DatabaseManager from '@database/manager';
import ServerDataOperator from '@database/operator/server_data_operator';
import {getMyChannel} from '@queries/servers/channel';
import {getCommonSystemValues, getTeamHistory} from '@queries/servers/system';
import {getTeamChannelHistory} from '@queries/servers/team';
@ -15,6 +13,9 @@ import {dismissAllModalsAndPopToRoot, dismissAllModalsAndPopToScreen} from '@scr
import {switchToChannel} from './channel';
import type ServerDataOperator from '@database/operator/server_data_operator';
import type {Database} from '@nozbe/watermelondb';
let mockIsTablet: jest.Mock;
const now = new Date('2020-01-01').getTime();

View file

@ -1,7 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Model} from '@nozbe/watermelondb';
import {DeviceEventEmitter} from 'react-native';
import {General, Navigation as NavigationConstants, Preferences, Screens} from '@constants';
@ -24,6 +23,7 @@ import {isTablet} from '@utils/helpers';
import {logError, logInfo} from '@utils/log';
import {displayGroupMessageName, displayUsername, getUserIdFromChannelName} from '@utils/user';
import type {Model} from '@nozbe/watermelondb';
import type ChannelModel from '@typings/database/models/servers/channel';
import type UserModel from '@typings/database/models/servers/user';

View file

@ -255,8 +255,6 @@ export async function deletePosts(serverUrl: string, postIds: string[]) {
const postsFormatted = `'${postIds.join("','")}'`;
await database.write(() => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
return database.adapter.unsafeExecute({
sqls: [
[`DELETE FROM ${POST} where id IN (${postsFormatted})`, []],

View file

@ -1,16 +1,15 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {IntlShape} from 'react-intl';
import {sendEphemeralPost} from '@actions/local/post';
import ClientError from '@client/rest/error';
import {AppCallResponseTypes} from '@constants/apps';
import NetworkManager from '@managers/network_manager';
import {cleanForm, createCallRequest, makeCallErrorResponse} from '@utils/apps';
import type {Client} from '@client/rest';
import type ClientError from '@client/rest/error';
import type PostModel from '@typings/database/models/servers/post';
import type {IntlShape} from 'react-intl';
export async function handleBindingClick<Res=unknown>(serverUrl: string, binding: AppBinding, context: AppContext, intl: IntlShape): Promise<{data?: AppCallResponse<Res>; error?: AppCallResponse<Res>}> {
// Fetch form

View file

@ -2,8 +2,6 @@
// See LICENSE.txt for license information.
/* eslint-disable max-lines */
import {Model} from '@nozbe/watermelondb';
import {IntlShape} from 'react-intl';
import {DeviceEventEmitter} from 'react-native';
import {addChannelToDefaultCategory, storeCategories} from '@actions/local/category';
@ -40,7 +38,9 @@ import {addCurrentUserToTeam, fetchTeamByName, removeCurrentUserFromTeam} from '
import {fetchProfilesInGroupChannels, fetchProfilesPerChannels, fetchUsersByIds, updateUsersNoLongerVisible} from './user';
import type {Client} from '@client/rest';
import type {Model} from '@nozbe/watermelondb';
import type ChannelModel from '@typings/database/models/servers/channel';
import type {IntlShape} from 'react-intl';
export type MyChannelsRequest = {
categories?: CategoryWithChannels[];

View file

@ -1,11 +1,9 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {IntlShape} from 'react-intl';
import {Alert} from 'react-native';
import {doAppSubmit, postEphemeralCallResponseForCommandArgs} from '@actions/remote/apps';
import {Client} from '@client/rest';
import {AppCommandParser} from '@components/autocomplete/slash_suggestion/app_command_parser/app_command_parser';
import {AppCallResponseTypes} from '@constants/apps';
import DatabaseManager from '@database/manager';
@ -18,6 +16,9 @@ import {showAppForm} from '@screens/navigation';
import {handleDeepLink, matchDeepLink} from '@utils/deep_link';
import {tryOpenURL} from '@utils/url';
import type {Client} from '@client/rest';
import type {IntlShape} from 'react-intl';
export const executeCommand = async (serverUrl: string, intl: IntlShape, message: string, channelId: string, rootId?: string): Promise<{data?: CommandResponse; error?: string | {message: string}}> => {
const operator = DatabaseManager.serverDatabases[serverUrl]?.operator;
if (!operator) {

View file

@ -2,13 +2,14 @@
// See LICENSE.txt for license information.
import {forceLogoutIfNecessary} from '@actions/remote/session';
import {Client} from '@client/rest';
import {Emoji, General} from '@constants';
import DatabaseManager from '@database/manager';
import {debounce} from '@helpers/api/general';
import NetworkManager from '@managers/network_manager';
import {queryCustomEmojisByName} from '@queries/servers/custom_emoji';
import type {Client} from '@client/rest';
export const fetchCustomEmojis = async (serverUrl: string, page = 0, perPage = General.PAGE_SIZE_DEFAULT, sort = Emoji.SORT_BY_NAME) => {
let client: Client;
try {

View file

@ -1,8 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Database, Model} from '@nozbe/watermelondb';
import {dataRetentionCleanup} from '@actions/local/systems';
import {fetchMissingDirectChannelsInfo, fetchMyChannelsForTeam, handleKickFromChannel, MyChannelsRequest} from '@actions/remote/channel';
import {fetchGroupsForMember} from '@actions/remote/groups';
@ -38,6 +36,7 @@ import {logDebug} from '@utils/log';
import {processIsCRTEnabled} from '@utils/thread';
import type ClientError from '@client/rest/error';
import type {Database, Model} from '@nozbe/watermelondb';
export type AppEntryData = {
initialTeamId: string;

View file

@ -1,10 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Database} from '@nozbe/watermelondb';
import {storeConfigAndLicense} from '@actions/local/systems';
import {MyChannelsRequest} from '@actions/remote/channel';
import {fetchGroupsForMember} from '@actions/remote/groups';
import {fetchPostsForUnreadChannels} from '@actions/remote/post';
import {fetchDataRetentionPolicy} from '@actions/remote/systems';
@ -26,7 +23,9 @@ import {processIsCRTEnabled} from '@utils/thread';
import {teamsToRemove, FETCH_UNREADS_TIMEOUT, entryRest, EntryResponse, entryInitialChannelId, restDeferredAppEntryActions, getRemoveTeamIds} from './common';
import type {MyChannelsRequest} from '@actions/remote/channel';
import type ClientError from '@client/rest/error';
import type {Database} from '@nozbe/watermelondb';
import type ChannelModel from '@typings/database/models/servers/channel';
export async function deferredAppEntryGraphQLActions(

View file

@ -1,20 +1,25 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {ClientResponse, ClientResponseError} from '@mattermost/react-native-network-client';
import {Client} from '@client/rest';
import ClientError from '@client/rest/error';
import {DOWNLOAD_TIMEOUT} from '@constants/network';
import NetworkManager from '@managers/network_manager';
import {forceLogoutIfNecessary} from './session';
import type {Client} from '@client/rest';
import type ClientError from '@client/rest/error';
import type {ClientResponse, ClientResponseError} from '@mattermost/react-native-network-client';
export const downloadFile = (serverUrl: string, fileId: string, desitnation: string) => { // Let it throw and handle it accordingly
const client = NetworkManager.getClient(serverUrl);
return client.apiClient.download(client.getFileRoute(fileId), desitnation.replace('file://', ''), {timeoutInterval: DOWNLOAD_TIMEOUT});
};
export const downloadProfileImage = (serverUrl: string, userId: string, lastPictureUpdate: number, destination: string) => { // Let it throw and handle it accordingly
const client = NetworkManager.getClient(serverUrl);
return client.apiClient.download(client.getProfilePictureUrl(userId, lastPictureUpdate), destination.replace('file://', ''), {timeoutInterval: DOWNLOAD_TIMEOUT});
};
export const uploadFile = (
serverUrl: string,
file: FileInfo,

View file

@ -1,7 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Client} from '@client/rest';
import DatabaseManager from '@database/manager';
import NetworkManager from '@managers/network_manager';
import {getChannelById} from '@queries/servers/channel';
@ -9,6 +8,8 @@ import {getTeamById} from '@queries/servers/team';
import {forceLogoutIfNecessary} from './session';
import type {Client} from '@client/rest';
export const fetchGroup = async (serverUrl: string, id: string, fetchOnly = false) => {
try {
const {operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);

View file

@ -1,8 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Model} from '@nozbe/watermelondb';
import {addRecentReaction} from '@actions/local/reactions';
import DatabaseManager from '@database/manager';
import NetworkManager from '@managers/network_manager';
@ -14,6 +12,7 @@ import {getEmojiFirstAlias} from '@utils/emoji/helpers';
import {forceLogoutIfNecessary} from './session';
import type {Client} from '@client/rest';
import type {Model} from '@nozbe/watermelondb';
import type PostModel from '@typings/database/models/servers/post';
export async function addReaction(serverUrl: string, postId: string, emojiName: string) {

View file

@ -1,11 +1,9 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Model} from '@nozbe/watermelondb';
import {DeviceEventEmitter} from 'react-native';
import {removeUserFromTeam as localRemoveUserFromTeam} from '@actions/local/team';
import {Client} from '@client/rest';
import {PER_PAGE_DEFAULT} from '@client/rest/constants';
import {Events} from '@constants';
import DatabaseManager from '@database/manager';
@ -27,7 +25,9 @@ import {fetchPostsForChannel, fetchPostsForUnreadChannels} from './post';
import {fetchRolesIfNeeded} from './role';
import {forceLogoutIfNecessary} from './session';
import type {Client} from '@client/rest';
import type ClientError from '@client/rest/error';
import type {Model} from '@nozbe/watermelondb';
export type MyTeamsRequest = {
teams?: Team[];

View file

@ -1,8 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import Model from '@nozbe/watermelondb/Model';
import {markTeamThreadsAsRead, markThreadAsViewed, processReceivedThreads, switchToThread, updateTeamThreadsSync, updateThread} from '@actions/local/thread';
import {fetchPostThread} from '@actions/remote/post';
import {General} from '@constants';
@ -19,6 +17,7 @@ import {getThreadsListEdges} from '@utils/thread';
import {forceLogoutIfNecessary} from './session';
import type {Client} from '@client/rest';
import type Model from '@nozbe/watermelondb/Model';
type FetchThreadsOptions = {
before?: string;

View file

@ -3,7 +3,6 @@
/* eslint-disable max-lines */
import {Model} from '@nozbe/watermelondb';
import {chunk} from 'lodash';
import {updateChannelsDisplayName} from '@actions/local/channel';
@ -26,6 +25,7 @@ import {forceLogoutIfNecessary} from './session';
import type {Client} from '@client/rest';
import type ClientError from '@client/rest/error';
import type {Model} from '@nozbe/watermelondb';
import type UserModel from '@typings/database/models/servers/user';
export type MyUserRequest = {

View file

@ -1,8 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Model} from '@nozbe/watermelondb';
import {addChannelToDefaultCategory} from '@actions/local/category';
import {
markChannelAsViewed, removeCurrentUserFromChannel, setChannelDeleteAt,
@ -22,6 +20,8 @@ import {getCurrentUser, getTeammateNameDisplay, getUserById} from '@queries/serv
import EphemeralStore from '@store/ephemeral_store';
import {logDebug} from '@utils/log';
import type {Model} from '@nozbe/watermelondb';
// Received when current user created a channel in a different client
export async function handleChannelCreatedEvent(serverUrl: string, msg: any) {
const operator = DatabaseManager.serverDatabases[serverUrl]?.operator;

View file

@ -1,7 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Model} from '@nozbe/watermelondb';
import {DeviceEventEmitter} from 'react-native';
import {storeMyChannelsForTeam, markChannelAsUnread, markChannelAsViewed, updateLastPostAt} from '@actions/local/channel';
@ -20,12 +19,11 @@ import NavigationStore from '@store/navigation_store';
import {isTablet} from '@utils/helpers';
import {isFromWebhook, isSystemMessage, shouldIgnorePost} from '@utils/post';
import type {Model} from '@nozbe/watermelondb';
import type MyChannelModel from '@typings/database/models/servers/my_channel';
function preparedMyChannelHack(myChannel: MyChannelModel) {
// @ts-expect-error hack accessing _preparedState
if (!myChannel._preparedState) {
// @ts-expect-error hack setting _preparedState
myChannel._preparedState = null;
}
}

View file

@ -1,15 +1,12 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Model} from '@nozbe/watermelondb';
import {removeUserFromTeam} from '@actions/local/team';
import {fetchMyChannelsForTeam} from '@actions/remote/channel';
import {fetchRoles} from '@actions/remote/role';
import {fetchMyTeam, handleKickFromTeam, updateCanJoinTeams} from '@actions/remote/team';
import {updateUsersNoLongerVisible} from '@actions/remote/user';
import DatabaseManager from '@database/manager';
import ServerDataOperator from '@database/operator/server_data_operator';
import NetworkManager from '@managers/network_manager';
import {prepareCategoriesAndCategoriesChannels} from '@queries/servers/categories';
import {prepareMyChannelsForTeam} from '@queries/servers/channel';
@ -19,6 +16,9 @@ import EphemeralStore from '@store/ephemeral_store';
import {setTeamLoading} from '@store/team_load_store';
import {logDebug} from '@utils/log';
import type ServerDataOperator from '@database/operator/server_data_operator';
import type {Model} from '@nozbe/watermelondb';
export async function handleTeamArchived(serverUrl: string, msg: WebSocketMessage) {
try {
const {database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);

View file

@ -1,7 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Model} from '@nozbe/watermelondb';
import {DeviceEventEmitter} from 'react-native';
import {updateChannelsDisplayName} from '@actions/local/channel';
@ -16,6 +15,8 @@ import {getConfig, getLicense} from '@queries/servers/system';
import {getCurrentUser} from '@queries/servers/user';
import {displayUsername} from '@utils/user';
import type {Model} from '@nozbe/watermelondb';
export async function handleUserUpdatedEvent(serverUrl: string, msg: WebSocketMessage) {
const operator = DatabaseManager.serverDatabases[serverUrl]?.operator;
if (!operator) {

View file

@ -1,11 +1,12 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Client} from '@client/rest';
import {MEMBERS_PER_PAGE} from '@constants/graphql';
import NetworkManager from '@managers/network_manager';
import QueryNames from './constants';
import type {Client} from '@client/rest';
const doGQLQuery = async (serverUrl: string, query: string, variables: {[name: string]: any}, operationName: string) => {
let client: Client;
try {

View file

@ -1,10 +1,10 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {ClientResponse, ClientResponseError, ProgressPromise, UploadRequestOptions} from '@mattermost/react-native-network-client';
import {toMilliseconds} from '@utils/datetime';
import type {ClientResponse, ClientResponseError, ProgressPromise, UploadRequestOptions} from '@mattermost/react-native-network-client';
export interface ClientFilesMix {
getFileUrl: (fileId: string, timestamp: number) => string;
getFileThumbnailUrl: (fileId: string, timestamp: number) => string;

View file

@ -31,8 +31,9 @@ const getStyleFromTheme = makeStyleSheetFromTheme((theme) => {
elevation: 3,
},
shadow: {
backgroundColor: theme.centerChannelBg,
shadowColor: '#000',
shadowOpacity: 0.12,
shadowOpacity: 1,
shadowRadius: 6,
shadowOffset: {
width: 0,

View file

@ -1,9 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Database} from '@nozbe/watermelondb';
import {IntlShape} from 'react-intl';
import {doAppFetchForm, doAppLookup} from '@actions/remote/apps';
import {fetchChannelById, fetchChannelByName, searchChannels} from '@actions/remote/channel';
import {fetchUsersByIds, fetchUsersByUsernames, searchUsers} from '@actions/remote/user';
@ -17,8 +14,10 @@ import {createCallRequest, filterEmptyOptions} from '@utils/apps';
import {getChannelSuggestions, getUserSuggestions, inTextMentionSuggestions} from './mentions';
import type {Database} from '@nozbe/watermelondb';
import type ChannelModel from '@typings/database/models/servers/channel';
import type UserModel from '@typings/database/models/servers/user';
import type {IntlShape} from 'react-intl';
/* eslint-disable max-lines */

View file

@ -1,7 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {MessageDescriptor} from '@formatjs/intl/src/types';
import React from 'react';
import {StyleProp, TextStyle, View, ViewStyle} from 'react-native';
@ -9,6 +8,8 @@ import FormattedText from '@components/formatted_text';
import {useTheme} from '@context/theme';
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
import type {MessageDescriptor} from '@formatjs/intl/src/types';
const getStyleSheet = makeStyleSheetFromTheme((theme) => {
return {
container: {

View file

@ -3,12 +3,13 @@
import React, {useCallback} from 'react';
import {useIntl} from 'react-intl';
import {StyleProp, ViewStyle} from 'react-native';
import OptionBox from '@components/option_box';
import {Screens} from '@constants';
import {dismissBottomSheet, goToScreen, showModal} from '@screens/navigation';
import type {StyleProp, ViewStyle} from 'react-native';
type Props = {
channelId: string;
containerStyle?: StyleProp<ViewStyle>;

View file

@ -3,13 +3,14 @@
import React, {useCallback} from 'react';
import {useIntl} from 'react-intl';
import {StyleProp, ViewStyle} from 'react-native';
import {toggleFavoriteChannel} from '@actions/remote/category';
import OptionBox from '@components/option_box';
import {useServerUrl} from '@context/server';
import {dismissBottomSheet} from '@screens/navigation';
import type {StyleProp, ViewStyle} from 'react-native';
type Props = {
channelId: string;
containerStyle?: StyleProp<ViewStyle>;

View file

@ -3,7 +3,6 @@
import React, {useCallback} from 'react';
import {useIntl} from 'react-intl';
import {StyleProp, ViewStyle} from 'react-native';
import CompassIcon from '@components/compass_icon';
import OptionBox from '@components/option_box';
@ -12,6 +11,8 @@ import {Screens} from '@constants';
import {useTheme} from '@context/theme';
import {dismissBottomSheet, showModal} from '@screens/navigation';
import type {StyleProp, ViewStyle} from 'react-native';
type Props = {
channelId: string;
containerStyle?: StyleProp<ViewStyle>;

View file

@ -3,13 +3,14 @@
import React, {useCallback} from 'react';
import {useIntl} from 'react-intl';
import {StyleProp, ViewStyle} from 'react-native';
import {toggleMuteChannel} from '@actions/remote/channel';
import OptionBox from '@components/option_box';
import {useServerUrl} from '@context/server';
import {dismissBottomSheet} from '@screens/navigation';
import type {StyleProp, ViewStyle} from 'react-native';
type Props = {
channelId: string;
containerStyle?: StyleProp<ViewStyle>;

View file

@ -3,12 +3,13 @@
import React, {useCallback} from 'react';
import {useIntl} from 'react-intl';
import {StyleProp, ViewStyle} from 'react-native';
import OptionBox from '@components/option_box';
import {Screens} from '@constants';
import {dismissBottomSheet, goToScreen, showModal} from '@screens/navigation';
import type {StyleProp, ViewStyle} from 'react-native';
type Props = {
channelId: string;
containerStyle?: StyleProp<ViewStyle>;

View file

@ -2,6 +2,23 @@
exports[`components/channel_list/categories/body/channel_item should match snapshot 1`] = `
<View
accessibilityState={
{
"busy": undefined,
"checked": undefined,
"disabled": undefined,
"expanded": undefined,
"selected": undefined,
}
}
accessibilityValue={
{
"max": undefined,
"min": undefined,
"now": undefined,
"text": undefined,
}
}
accessible={true}
collapsable={false}
focusable={true}
@ -115,6 +132,23 @@ exports[`components/channel_list/categories/body/channel_item should match snaps
exports[`components/channel_list/categories/body/channel_item should match snapshot when it has a call 1`] = `
<View
accessibilityState={
{
"busy": undefined,
"checked": undefined,
"disabled": undefined,
"expanded": undefined,
"selected": undefined,
}
}
accessibilityValue={
{
"max": undefined,
"min": undefined,
"now": undefined,
"text": undefined,
}
}
accessible={true}
collapsable={false}
focusable={true}
@ -257,6 +291,23 @@ exports[`components/channel_list/categories/body/channel_item should match snaps
exports[`components/channel_list/categories/body/channel_item should match snapshot when it has a draft 1`] = `
<View
accessibilityState={
{
"busy": undefined,
"checked": undefined,
"disabled": undefined,
"expanded": undefined,
"selected": undefined,
}
}
accessibilityValue={
{
"max": undefined,
"min": undefined,
"now": undefined,
"text": undefined,
}
}
accessible={true}
collapsable={false}
focusable={true}

View file

@ -9,6 +9,23 @@ exports[`components/channel_list_row should be selected 1`] = `
}
>
<View
accessibilityState={
{
"busy": undefined,
"checked": undefined,
"disabled": undefined,
"expanded": undefined,
"selected": undefined,
}
}
accessibilityValue={
{
"max": undefined,
"min": undefined,
"now": undefined,
"text": undefined,
}
}
accessible={true}
collapsable={false}
focusable={true}
@ -103,6 +120,23 @@ exports[`components/channel_list_row should match snapshot with delete_at filled
}
>
<View
accessibilityState={
{
"busy": undefined,
"checked": undefined,
"disabled": undefined,
"expanded": undefined,
"selected": undefined,
}
}
accessibilityValue={
{
"max": undefined,
"min": undefined,
"now": undefined,
"text": undefined,
}
}
accessible={true}
collapsable={false}
focusable={true}
@ -175,6 +209,23 @@ exports[`components/channel_list_row should match snapshot with open channel ico
}
>
<View
accessibilityState={
{
"busy": undefined,
"checked": undefined,
"disabled": undefined,
"expanded": undefined,
"selected": undefined,
}
}
accessibilityValue={
{
"max": undefined,
"min": undefined,
"now": undefined,
"text": undefined,
}
}
accessible={true}
collapsable={false}
focusable={true}
@ -247,6 +298,23 @@ exports[`components/channel_list_row should match snapshot with private channel
}
>
<View
accessibilityState={
{
"busy": undefined,
"checked": undefined,
"disabled": undefined,
"expanded": undefined,
"selected": undefined,
}
}
accessibilityValue={
{
"max": undefined,
"min": undefined,
"now": undefined,
"text": undefined,
}
}
accessible={true}
collapsable={false}
focusable={true}
@ -319,6 +387,23 @@ exports[`components/channel_list_row should match snapshot with purpose filled i
}
>
<View
accessibilityState={
{
"busy": undefined,
"checked": undefined,
"disabled": undefined,
"expanded": undefined,
"selected": undefined,
}
}
accessibilityValue={
{
"max": undefined,
"min": undefined,
"now": undefined,
"text": undefined,
}
}
accessible={true}
collapsable={false}
focusable={true}
@ -406,6 +491,23 @@ exports[`components/channel_list_row should match snapshot with shared filled in
}
>
<View
accessibilityState={
{
"busy": undefined,
"checked": undefined,
"disabled": undefined,
"expanded": undefined,
"selected": undefined,
}
}
accessibilityValue={
{
"max": undefined,
"min": undefined,
"now": undefined,
"text": undefined,
}
}
accessible={true}
collapsable={false}
focusable={true}

View file

@ -1,7 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import Database from '@nozbe/watermelondb/Database';
import React from 'react';
import {renderWithEverything} from '@test/intl-test-helper';
@ -9,6 +8,8 @@ import TestHelper from '@test/test_helper';
import ChannelListRow from '.';
import type Database from '@nozbe/watermelondb/Database';
describe('components/channel_list_row', () => {
let database: Database;
const channel: Channel = {

View file

@ -5,7 +5,6 @@ import Clipboard from '@react-native-clipboard/clipboard';
import React, {useCallback} from 'react';
import {BaseOption} from '@components/common_post_options';
import {Screens} from '@constants';
import {SNACK_BAR_TYPE} from '@constants/snack_bar';
import {useServerUrl} from '@context/server';
import {t} from '@i18n';
@ -13,10 +12,11 @@ import {dismissBottomSheet} from '@screens/navigation';
import {showSnackBar} from '@utils/snack_bar';
import type PostModel from '@typings/database/models/servers/post';
import type {AvailableScreens} from '@typings/screens/navigation';
type Props = {
bottomSheetId: typeof Screens[keyof typeof Screens];
sourceScreen: typeof Screens[keyof typeof Screens];
bottomSheetId: AvailableScreens;
sourceScreen: AvailableScreens;
post: PostModel;
teamName: string;
}

View file

@ -5,15 +5,15 @@ import React, {useCallback} from 'react';
import {updateThreadFollowing} from '@actions/remote/thread';
import {BaseOption} from '@components/common_post_options';
import {Screens} from '@constants';
import {useServerUrl} from '@context/server';
import {t} from '@i18n';
import {dismissBottomSheet} from '@screens/navigation';
import type ThreadModel from '@typings/database/models/servers/thread';
import type {AvailableScreens} from '@typings/screens/navigation';
type FollowThreadOptionProps = {
bottomSheetId: typeof Screens[keyof typeof Screens];
bottomSheetId: AvailableScreens;
thread: ThreadModel;
teamId?: string;
};

View file

@ -5,16 +5,16 @@ import React, {useCallback} from 'react';
import {fetchAndSwitchToThread} from '@actions/remote/thread';
import {BaseOption} from '@components/common_post_options';
import {Screens} from '@constants';
import {useServerUrl} from '@context/server';
import {t} from '@i18n';
import {dismissBottomSheet} from '@screens/navigation';
import type PostModel from '@typings/database/models/servers/post';
import type {AvailableScreens} from '@typings/screens/navigation';
type Props = {
post: PostModel;
bottomSheetId: typeof Screens[keyof typeof Screens];
bottomSheetId: AvailableScreens;
}
const ReplyOption = ({post, bottomSheetId}: Props) => {
const serverUrl = useServerUrl();

View file

@ -5,13 +5,14 @@ import React, {useCallback} from 'react';
import {deleteSavedPost, savePostPreference} from '@actions/remote/preference';
import {BaseOption} from '@components/common_post_options';
import {Screens} from '@constants';
import {useServerUrl} from '@context/server';
import {t} from '@i18n';
import {dismissBottomSheet} from '@screens/navigation';
import type {AvailableScreens} from '@typings/screens/navigation';
type CopyTextProps = {
bottomSheetId: typeof Screens[keyof typeof Screens];
bottomSheetId: AvailableScreens;
isSaved: boolean;
postId: string;
}

View file

@ -2,6 +2,23 @@
exports[`components/custom_status/clear_button should match snapshot 1`] = `
<View
accessibilityState={
{
"busy": undefined,
"checked": undefined,
"disabled": undefined,
"expanded": undefined,
"selected": undefined,
}
}
accessibilityValue={
{
"max": undefined,
"min": undefined,
"now": undefined,
"text": undefined,
}
}
accessible={true}
collapsable={false}
focusable={true}

View file

@ -1,7 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import Database from '@nozbe/watermelondb/Database';
import React from 'react';
import CustomStatusEmoji from '@components/custom_status/custom_status_emoji';
@ -9,6 +8,8 @@ import {CustomStatusDurationEnum} from '@constants/custom_status';
import {renderWithEverything} from '@test/intl-test-helper';
import TestHelper from '@test/test_helper';
import type Database from '@nozbe/watermelondb/Database';
describe('components/custom_status/custom_status_emoji', () => {
let database: Database | undefined;
beforeAll(async () => {

View file

@ -3,7 +3,7 @@
import React, {useMemo} from 'react';
import {EmojiComponent, EmojiProps} from '@typings/components/emoji';
import type {EmojiComponent, EmojiProps} from '@typings/components/emoji';
let emojiComponent: EmojiComponent;

View file

@ -1,7 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {ClientResponse, ProgressPromise} from '@mattermost/react-native-network-client';
import React, {forwardRef, useImperativeHandle, useRef, useState} from 'react';
import {useIntl} from 'react-intl';
import {Platform, StatusBar, StatusBarStyle, StyleSheet, TouchableOpacity, View} from 'react-native';
@ -21,6 +20,7 @@ import {emptyFunction} from '@utils/general';
import FileIcon from './file_icon';
import type {Client} from '@client/rest';
import type {ClientResponse, ProgressPromise} from '@mattermost/react-native-network-client';
export type DocumentFileRef = {
handlePreviewPress: () => void;

View file

@ -104,7 +104,8 @@ const ImageFile = ({
const props: ProgressiveImageProps = {};
if (file.localPath) {
props.defaultSource = {uri: file.localPath};
const prefix = file.localPath.startsWith('file://') ? '' : 'file://';
props.defaultSource = {uri: prefix + file.localPath};
} else if (file.id) {
if (file.mini_preview && file.mime_type) {
props.thumbnailUri = `data:${file.mime_type};base64,${file.mini_preview}`;

View file

@ -73,6 +73,23 @@ exports[`Loading Error should match snapshot 1`] = `
Error description
</Text>
<View
accessibilityState={
{
"busy": undefined,
"checked": undefined,
"disabled": undefined,
"expanded": undefined,
"selected": undefined,
}
}
accessibilityValue={
{
"max": undefined,
"min": undefined,
"now": undefined,
"text": undefined,
}
}
accessible={true}
collapsable={false}
focusable={true}

View file

@ -2,7 +2,6 @@
// See LICENSE.txt for license information.
import {useManagedConfig} from '@mattermost/react-native-emm';
import {Database} from '@nozbe/watermelondb';
import Clipboard from '@react-native-clipboard/clipboard';
import React, {useCallback, useEffect, useMemo} from 'react';
import {useIntl} from 'react-intl';
@ -21,6 +20,7 @@ import {bottomSheet, dismissBottomSheet, openAsBottomSheet} from '@screens/navig
import {bottomSheetSnapPoint} from '@utils/helpers';
import {displayUsername, getUsersByUsername} from '@utils/user';
import type {Database} from '@nozbe/watermelondb';
import type GroupModelType from '@typings/database/models/servers/group';
import type GroupMembershipModel from '@typings/database/models/servers/group_membership';
import type UserModelType from '@typings/database/models/servers/user';
@ -34,7 +34,7 @@ type AtMentionProps = {
location: string;
mentionKeys?: Array<{key: string }>;
mentionName: string;
mentionStyle: TextStyle;
mentionStyle: StyleProp<TextStyle>;
onPostPress?: (e: GestureResponderEvent) => void;
teammateNameDisplay: string;
textStyle?: StyleProp<TextStyle>;
@ -203,7 +203,7 @@ const AtMention = ({
}
}, [managedConfig, intl, theme, bottom]);
const mentionTextStyle = [];
const mentionTextStyle: StyleProp<TextStyle> = [];
let backgroundColor;
let canPress = false;

View file

@ -5,7 +5,7 @@ import {useManagedConfig} from '@mattermost/react-native-emm';
import {Parser, Node} from 'commonmark';
import Renderer from 'commonmark-react-renderer';
import React, {ReactElement, useMemo, useRef} from 'react';
import {Dimensions, GestureResponderEvent, Platform, StyleProp, Text, TextStyle, View, ViewStyle} from 'react-native';
import {Dimensions, GestureResponderEvent, Platform, StyleProp, StyleSheet, Text, TextStyle, View, ViewStyle} from 'react-native';
import CompassIcon from '@components/compass_icon';
import Emoji from '@components/emoji';
@ -143,13 +143,15 @@ const Markdown = ({
if (disableAtMentions) {
return renderText({context, literal: `@${mentionName}`});
}
const computedStyles = StyleSheet.flatten(computeTextStyle(textStyles, baseTextStyle, context));
const {fontFamily, fontSize, fontWeight} = computedStyles;
return (
<AtMention
channelId={channelId}
disableAtChannelMentionHighlight={disableAtChannelMentionHighlight}
mentionStyle={textStyles.mention}
textStyle={[computeTextStyle(textStyles, baseTextStyle, context), style.atMentionOpacity]}
mentionStyle={[textStyles.mention, {fontSize, fontWeight, fontFamily}]}
textStyle={[computedStyles, style.atMentionOpacity]}
isSearchResult={isSearchResult}
location={location}
mentionName={mentionName}

View file

@ -1,7 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {PasteInputRef} from '@mattermost/react-native-paste-input';
import React, {useCallback, useRef} from 'react';
import {LayoutChangeEvent, Platform, ScrollView, View} from 'react-native';
import {Edge, SafeAreaView} from 'react-native-safe-area-context';
@ -16,6 +15,8 @@ import SendAction from '../send_action';
import Typing from '../typing';
import Uploads from '../uploads';
import type {PasteInputRef} from '@mattermost/react-native-paste-input';
type Props = {
testID?: string;
channelId: string;

View file

@ -7,7 +7,7 @@ import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
import {IntlShape, useIntl} from 'react-intl';
import {
Alert, AppState, AppStateStatus, DeviceEventEmitter, EmitterSubscription, Keyboard,
KeyboardTypeOptions, NativeSyntheticEvent, Platform, TextInputSelectionChangeEventData,
NativeSyntheticEvent, Platform, TextInputSelectionChangeEventData,
} from 'react-native';
import HWKeyboardEvent from 'react-native-hw-keyboard-event';
@ -20,9 +20,10 @@ import {useIsTablet} from '@hooks/device';
import {t} from '@i18n';
import NavigationStore from '@store/navigation_store';
import {extractFileInfo} from '@utils/file';
import {switchKeyboardForCodeBlocks} from '@utils/markdown';
import {changeOpacity, makeStyleSheetFromTheme, getKeyboardAppearanceFromTheme} from '@utils/theme';
import type {AvailableScreens} from '@typings/screens/navigation';
type Props = {
testID?: string;
channelDisplayName?: string;
@ -125,7 +126,6 @@ export default function PostInput({
const lastNativeValue = useRef('');
const previousAppState = useRef(AppState.currentState);
const [keyboardType, setKeyboardType] = useState<KeyboardTypeOptions>('default');
const [longMessageAlertShown, setLongMessageAlertShown] = useState(false);
const disableCopyAndPaste = managedConfig.copyAndPasteProtection === 'true';
@ -180,11 +180,6 @@ export default function PostInput({
const handlePostDraftSelectionChanged = useCallback((event: NativeSyntheticEvent<TextInputSelectionChangeEventData> | null, fromHandleTextChange = false) => {
const cp = fromHandleTextChange ? cursorPosition : event!.nativeEvent.selection.end;
if (Platform.OS === 'ios') {
const newKeyboardType = switchKeyboardForCodeBlocks(value, cp);
setKeyboardType(newKeyboardType);
}
updateCursorPosition(cp);
}, [updateCursorPosition, cursorPosition]);
@ -194,11 +189,6 @@ export default function PostInput({
checkMessageLength(newValue);
// Workaround to avoid iOS emdash autocorrect in Code Blocks
if (Platform.OS === 'ios') {
handlePostDraftSelectionChanged(null, true);
}
if (
newValue &&
lastTypingEventSent.current + timeBetweenUserTypingUpdatesMilliseconds < Date.now() &&
@ -211,7 +201,6 @@ export default function PostInput({
}, [
updateValue,
checkMessageLength,
handlePostDraftSelectionChanged,
timeBetweenUserTypingUpdatesMilliseconds,
channelId,
rootId,
@ -228,7 +217,7 @@ export default function PostInput({
const handleHardwareEnterPress = useCallback((keyEvent: {pressedKey: string}) => {
const topScreen = NavigationStore.getVisibleScreen();
let sourceScreen = Screens.CHANNEL;
let sourceScreen: AvailableScreens = Screens.CHANNEL;
if (rootId) {
sourceScreen = Screens.THREAD;
} else if (isTablet) {
@ -307,24 +296,24 @@ export default function PostInput({
return (
<PasteableTextInput
allowFontScaling={true}
testID={testID}
ref={inputRef}
disableCopyPaste={disableCopyAndPaste}
style={pasteInputStyle}
disableFullscreenUI={true}
keyboardAppearance={getKeyboardAppearanceFromTheme(theme)}
multiline={true}
onBlur={onBlur}
onChangeText={handleTextChange}
onFocus={onFocus}
onPaste={onPaste}
onSelectionChange={handlePostDraftSelectionChanged}
placeholder={intl.formatMessage(getPlaceHolder(rootId), {channelDisplayName})}
placeholderTextColor={changeOpacity(theme.centerChannelColor, 0.5)}
multiline={true}
onBlur={onBlur}
onFocus={onFocus}
blurOnSubmit={false}
ref={inputRef}
smartPunctuation='disable'
submitBehavior='newline'
style={pasteInputStyle}
testID={testID}
underlineColorAndroid='transparent'
keyboardType={keyboardType}
onPaste={onPaste}
disableFullscreenUI={true}
textContentType='none'
keyboardAppearance={getKeyboardAppearanceFromTheme(theme)}
/>
);
}

View file

@ -4,7 +4,6 @@
import React from 'react';
import {useIntl} from 'react-intl';
import {View} from 'react-native';
import {CameraOptions} from 'react-native-image-picker';
import FormattedText from '@components/formatted_text';
import SlideUpPanelItem from '@components/slide_up_panel_item';
@ -14,6 +13,8 @@ import {dismissBottomSheet} from '@screens/navigation';
import {makeStyleSheetFromTheme} from '@utils/theme';
import {typography} from '@utils/typography';
import type {CameraOptions} from 'react-native-image-picker';
type Props = {
onPress: (options: CameraOptions) => void;
}

View file

@ -4,7 +4,6 @@
import React, {useCallback} from 'react';
import {useIntl} from 'react-intl';
import {Alert, StyleSheet} from 'react-native';
import {CameraOptions} from 'react-native-image-picker';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import CompassIcon from '@components/compass_icon';
@ -22,6 +21,7 @@ import {changeOpacity} from '@utils/theme';
import CameraType from './camera_type';
import type {QuickActionAttachmentProps} from '@typings/components/post_draft_quick_action';
import type {CameraOptions} from 'react-native-image-picker';
const style = StyleSheet.create({
icon: {

View file

@ -46,7 +46,6 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
animatedContainer: {
position: 'absolute',
margin: 8,
backgroundColor: theme.buttonBg,
},
cancelContainer: {
alignItems: 'center',
@ -55,6 +54,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
justifyContent: 'center',
},
container: {
backgroundColor: theme.buttonBg,
flexDirection: 'row',
justifyContent: 'space-evenly',
alignItems: 'center',

View file

@ -132,8 +132,6 @@ const ButtonBinding = ({currentTeamId, binding, post, teamID, theme}: Props) =>
/>
</Button>
);
return null;
};
const withTeamId = withObservables(['post'], ({post, database}: {post: PostModel} & WithDatabaseArgs) => ({

View file

@ -69,8 +69,9 @@ const ImagePreview = ({expandedLink, isReplyPost, layoutWidth, link, location, m
width: imageProps.width,
height: imageProps.height,
name: extractFilenameFromUrl(imageUrl) || 'imagePreview.png',
mime_type: lookupMimeType(imageUrl) || 'images/png',
mime_type: lookupMimeType(imageUrl) || 'image/png',
type: 'image',
lastPictureUpdate: 0,
};
openGalleryAtIndex(galleryIdentifier, 0, [item]);
};

View file

@ -72,8 +72,9 @@ const AttachmentImage = ({imageUrl, imageMetadata, layoutWidth, location, postId
width: imageMetadata.width,
height: imageMetadata.height,
name: extractFilenameFromUrl(imageUrl) || 'attachmentImage.png',
mime_type: lookupMimeType(imageUrl) || 'images/png',
mime_type: lookupMimeType(imageUrl) || 'image/png',
type: 'image',
lastPictureUpdate: 0,
};
openGalleryAtIndex(galleryIdentifier, 0, [item]);
};

View file

@ -98,8 +98,9 @@ const OpengraphImage = ({isReplyPost, layoutWidth, location, metadata, openGraph
width: imageDimensions.width,
height: imageDimensions.height,
name: extractFilenameFromUrl(imageUrl) || 'openGraph.png',
mime_type: lookupMimeType(imageUrl) || 'images/png',
mime_type: lookupMimeType(imageUrl) || 'image/png',
type: 'image',
lastPictureUpdate: 0,
};
openGalleryAtIndex(galleryIdentifier, 0, [item]);
};

View file

@ -43,6 +43,7 @@ const Image = ({author, forwardRef, iconSize, size, source, url}: Props) => {
const style = getStyleSheet(theme);
const fIStyle = useMemo(() => ({
borderRadius: size / 2,
backgroundColor: theme.centerChannelBg,
height: size,
width: size,
}), [size]);

View file

@ -2,10 +2,11 @@
// See LICENSE.txt for license information.
import React from 'react';
import {ColorValue, StyleProp} from 'react-native';
import FastImage, {ImageStyle, Source} from 'react-native-fast-image';
import Animated, {SharedValue} from 'react-native-reanimated';
import type {ColorValue, StyleProp} from 'react-native';
// @ts-expect-error FastImage does work with Animated.createAnimatedComponent
const AnimatedFastImage = Animated.createAnimatedComponent(FastImage);

View file

@ -96,6 +96,7 @@ const TOAST_BOTTOM_MARGIN = 24;
const getStyleFromTheme = makeStyleSheetFromTheme((theme) => {
return {
container: {
backgroundColor: theme.centerChannelBg,
borderBottomWidth: 0,
borderColor: changeOpacity(theme.centerChannelColor, 0.16),
borderTopLeftRadius: 12,
@ -232,10 +233,10 @@ export default function SelectedUsers({
}, [showToast, keyboard]);
const animatedViewStyle = useAnimatedStyle(() => ({
height: withTiming(totalPanelHeight.value, {duration: 250}),
height: withTiming(totalPanelHeight.value + insets.bottom, {duration: 250}),
borderWidth: isVisible ? 1 : 0,
maxHeight: isVisible ? PANEL_MAX_HEIGHT + BUTTON_HEIGHT : 0,
}), [totalPanelHeight.value, isVisible]);
maxHeight: isVisible ? PANEL_MAX_HEIGHT + BUTTON_HEIGHT + insets.bottom : 0,
}), [isVisible, insets]);
const animatedButtonStyle = useAnimatedStyle(() => ({
opacity: withTiming(isVisible ? 1 : 0, {duration: isVisible ? 500 : 100}),

View file

@ -5,7 +5,19 @@ exports[`Server Icon Server Icon Component should match snapshot 1`] = `
<View
accessibilityState={
{
"busy": undefined,
"checked": undefined,
"disabled": true,
"expanded": undefined,
"selected": undefined,
}
}
accessibilityValue={
{
"max": undefined,
"min": undefined,
"now": undefined,
"text": undefined,
}
}
accessible={true}
@ -46,7 +58,19 @@ exports[`Server Icon Server Icon Component should match snapshot with mentions 1
<View
accessibilityState={
{
"busy": undefined,
"checked": undefined,
"disabled": true,
"expanded": undefined,
"selected": undefined,
}
}
accessibilityValue={
{
"max": undefined,
"min": undefined,
"now": undefined,
"text": undefined,
}
}
accessible={true}
@ -122,7 +146,19 @@ exports[`Server Icon Server Icon Component should match snapshot with unreads 1`
<View
accessibilityState={
{
"busy": undefined,
"checked": undefined,
"disabled": true,
"expanded": undefined,
"selected": undefined,
}
}
accessibilityValue={
{
"max": undefined,
"min": undefined,
"now": undefined,
"text": undefined,
}
}
accessible={true}

View file

@ -2,7 +2,6 @@
// See LICENSE.txt for license information.
import React from 'react';
import {StyleProp, TextStyle} from 'react-native';
import FormattedText from '@components/formatted_text';
import {General} from '@constants';
@ -11,6 +10,8 @@ import {t} from '@i18n';
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
import {typography} from '@utils/typography';
import type {StyleProp, TextStyle} from 'react-native';
type StatusLabelProps = {
status?: string;
labelStyle?: StyleProp<TextStyle>;

View file

@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {useCallback} from 'react';
import React, {useCallback, useRef} from 'react';
import {FlatList, ListRenderItemInfo, ScrollView, StyleSheet, Text} from 'react-native';
import {createStyleObject} from 'react-syntax-highlighter/create-element';
@ -115,6 +115,7 @@ function createNativeElement({node, stylesheet, key, defaultColor, fontFamily, f
}
const CodeHighlightRenderer = ({defaultColor, digits, fontFamily, fontSize, rows, selectable, stylesheet}: Props) => {
const listKey = useRef(generateId()).current;
const renderItem = useCallback(({item, index}: ListRenderItemInfo<any>) => {
return createNativeElement({
node: item,
@ -137,7 +138,9 @@ const CodeHighlightRenderer = ({defaultColor, digits, fontFamily, fontSize, rows
<FlatList
data={rows}
renderItem={renderItem}
listKey={generateId()}
//@ts-expect-error key not defined in types
listKey={listKey}
/>
</ScrollView>
);

View file

@ -2,6 +2,23 @@
exports[`Thread item in the channel list Threads Component should match snapshot 1`] = `
<View
accessibilityState={
{
"busy": undefined,
"checked": undefined,
"disabled": undefined,
"expanded": undefined,
"selected": undefined,
}
}
accessibilityValue={
{
"max": undefined,
"min": undefined,
"now": undefined,
"text": undefined,
}
}
accessible={true}
collapsable={false}
focusable={true}
@ -86,6 +103,23 @@ exports[`Thread item in the channel list Threads Component should match snapshot
exports[`Thread item in the channel list Threads Component should match snapshot with isInfo 1`] = `
<View
accessibilityState={
{
"busy": undefined,
"checked": undefined,
"disabled": undefined,
"expanded": undefined,
"selected": undefined,
}
}
accessibilityValue={
{
"max": undefined,
"min": undefined,
"now": undefined,
"text": undefined,
}
}
accessible={true}
collapsable={false}
focusable={true}
@ -177,6 +211,23 @@ exports[`Thread item in the channel list Threads Component should match snapshot
exports[`Thread item in the channel list Threads Component should match snapshot, groupUnreadsSeparately false, always show 1`] = `
<View
accessibilityState={
{
"busy": undefined,
"checked": undefined,
"disabled": undefined,
"expanded": undefined,
"selected": undefined,
}
}
accessibilityValue={
{
"max": undefined,
"min": undefined,
"now": undefined,
"text": undefined,
}
}
accessible={true}
collapsable={false}
focusable={true}

View file

@ -7,7 +7,6 @@ import {of as of$} from 'rxjs';
import {switchMap} from 'rxjs/operators';
import Preferences from '@constants/preferences';
import {PreferenceModel} from '@database/models/server';
import {getPreferenceAsBool} from '@helpers/api/preference';
import {queryPreferencesByCategoryAndName} from '@queries/servers/preference';
import {observeCurrentChannelId, observeCurrentTeamId, observeOnlyUnreads} from '@queries/servers/system';
@ -16,6 +15,7 @@ import {observeUnreadsAndMentionsInTeam} from '@queries/servers/thread';
import ThreadsButton from './threads_button';
import type {WithDatabaseArgs} from '@typings/database/database';
import type PreferenceModel from '@typings/database/models/servers/preference';
const enhanced = withObservables([], ({database}: WithDatabaseArgs) => {
const currentTeamId = observeCurrentTeamId(database);

View file

@ -40,7 +40,7 @@ const TouchableWithFeedbackAndroid = ({borderlessRipple = false, children, rippl
{children}
</TouchableOpacity>
);
case 'none':
default:
return (
<TouchableWithoutFeedback
testID={testID}
@ -50,8 +50,6 @@ const TouchableWithFeedbackAndroid = ({borderlessRipple = false, children, rippl
</TouchableWithoutFeedback>
);
}
return null;
};
export default memo(TouchableWithFeedbackAndroid);

View file

@ -41,7 +41,7 @@ const TouchableWithFeedbackIOS = ({testID, children, type = 'native', cancelTouc
{children}
</TouchableOpacity>
);
case 'none':
default:
return (
<TouchableWithoutFeedback
testID={testID}
@ -51,8 +51,6 @@ const TouchableWithFeedbackIOS = ({testID, children, type = 'native', cancelTouc
</TouchableWithoutFeedback>
);
}
return null;
};
export default memo(TouchableWithFeedbackIOS);

View file

@ -1,7 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {BottomSheetProps} from '@gorhom/bottom-sheet';
import React, {useCallback} from 'react';
import {useIntl} from 'react-intl';
import {StyleProp, Text, TouchableOpacity, View, ViewStyle} from 'react-native';
@ -20,6 +19,7 @@ import {typography} from '@utils/typography';
import UserAvatar from './user_avatar';
import UsersList from './users_list';
import type {BottomSheetProps} from '@gorhom/bottom-sheet';
import type UserModel from '@typings/database/models/servers/user';
const OVERFLOW_DISPLAY_LIMIT = 99;

View file

@ -74,6 +74,7 @@ exports[`components/channel_list_row should show no results 1`] = `
>
<View>
<View
onFocusCapture={[Function]}
onLayout={[Function]}
style={null}
>
@ -111,6 +112,7 @@ exports[`components/channel_list_row should show no results 1`] = `
</View>
</View>
<View
onFocusCapture={[Function]}
onLayout={[Function]}
style={null}
>
@ -129,6 +131,14 @@ exports[`components/channel_list_row should show no results 1`] = `
onStartShouldSetResponderCapture={[Function]}
>
<View
accessibilityValue={
{
"max": undefined,
"min": undefined,
"now": undefined,
"text": undefined,
}
}
accessible={true}
focusable={true}
onClick={[Function]}
@ -247,6 +257,7 @@ exports[`components/channel_list_row should show no results 1`] = `
</View>
</View>
<View
onFocusCapture={[Function]}
onLayout={[Function]}
style={null}
/>
@ -346,6 +357,7 @@ exports[`components/channel_list_row should show results and tutorial 1`] = `
>
<View>
<View
onFocusCapture={[Function]}
onLayout={[Function]}
style={null}
>
@ -383,6 +395,7 @@ exports[`components/channel_list_row should show results and tutorial 1`] = `
</View>
</View>
<View
onFocusCapture={[Function]}
onLayout={[Function]}
style={null}
>
@ -401,6 +414,14 @@ exports[`components/channel_list_row should show results and tutorial 1`] = `
onStartShouldSetResponderCapture={[Function]}
>
<View
accessibilityValue={
{
"max": undefined,
"min": undefined,
"now": undefined,
"text": undefined,
}
}
accessible={true}
focusable={true}
onClick={[Function]}
@ -519,6 +540,7 @@ exports[`components/channel_list_row should show results and tutorial 1`] = `
</View>
</View>
<View
onFocusCapture={[Function]}
onLayout={[Function]}
style={null}
/>
@ -618,6 +640,7 @@ exports[`components/channel_list_row should show results no tutorial 1`] = `
>
<View>
<View
onFocusCapture={[Function]}
onLayout={[Function]}
style={null}
>
@ -655,6 +678,7 @@ exports[`components/channel_list_row should show results no tutorial 1`] = `
</View>
</View>
<View
onFocusCapture={[Function]}
onLayout={[Function]}
style={null}
>
@ -673,6 +697,14 @@ exports[`components/channel_list_row should show results no tutorial 1`] = `
onStartShouldSetResponderCapture={[Function]}
>
<View
accessibilityValue={
{
"max": undefined,
"min": undefined,
"now": undefined,
"text": undefined,
}
}
accessible={true}
focusable={true}
onClick={[Function]}
@ -791,6 +823,7 @@ exports[`components/channel_list_row should show results no tutorial 1`] = `
</View>
</View>
<View
onFocusCapture={[Function]}
onLayout={[Function]}
style={null}
/>

View file

@ -1,7 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import Database from '@nozbe/watermelondb/Database';
import React from 'react';
import {renderWithEverything} from '@test/intl-test-helper';
@ -9,6 +8,8 @@ import TestHelper from '@test/test_helper';
import UserList from '.';
import type Database from '@nozbe/watermelondb/Database';
describe('components/channel_list_row', () => {
let database: Database;
const user: UserProfile = {

View file

@ -133,7 +133,7 @@ export default {
THREAD_FOLLOW_BUTTON,
THREAD_OPTIONS,
USER_PROFILE,
};
} as const;
export const MODAL_SCREENS_WITHOUT_BACK = new Set<string>([
BROWSE_CHANNELS,

View file

@ -1,7 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Database} from '@nozbe/watermelondb';
import DatabaseProvider from '@nozbe/watermelondb/DatabaseProvider';
import React, {ComponentType, useEffect, useState} from 'react';
@ -11,6 +10,7 @@ import UserLocaleProvider from '@context/user_locale';
import DatabaseManager from '@database/manager';
import {subscribeActiveServers} from '@database/subscription/servers';
import type {Database} from '@nozbe/watermelondb';
import type ServersModel from '@typings/database/models/app/servers';
type State = {

View file

@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Database, Q} from '@nozbe/watermelondb';
import {Database, Model, Q} from '@nozbe/watermelondb';
import LokiJSAdapter from '@nozbe/watermelondb/adapters/lokijs';
import logger from '@nozbe/watermelondb/utils/common/logger';
import {DeviceEventEmitter, Platform} from 'react-native';
@ -45,14 +45,14 @@ class DatabaseManager {
private readonly serverModels: Models;
constructor() {
this.appModels = [InfoModel, GlobalModel, ServersModel];
this.appModels = [InfoModel, GlobalModel, ServersModel] as unknown[] as Model[];
this.serverModels = [
CategoryModel, CategoryChannelModel, ChannelModel, ChannelInfoModel, ChannelMembershipModel, ConfigModel, CustomEmojiModel, DraftModel, FileModel,
GroupModel, GroupChannelModel, GroupTeamModel, GroupMembershipModel, MyChannelModel, MyChannelSettingsModel, MyTeamModel,
PostModel, PostsInChannelModel, PostsInThreadModel, PreferenceModel, ReactionModel, RoleModel,
SystemModel, TeamModel, TeamChannelHistoryModel, TeamMembershipModel, TeamSearchHistoryModel,
ThreadModel, ThreadParticipantModel, ThreadInTeamModel, TeamThreadsSyncModel, UserModel,
];
] as unknown[] as Model[];
this.databaseDirectory = '';
}

View file

@ -43,14 +43,14 @@ class DatabaseManager {
private readonly serverModels: Models;
constructor() {
this.appModels = [InfoModel, GlobalModel, ServersModel];
this.appModels = [InfoModel, GlobalModel, ServersModel] as unknown[] as Models;
this.serverModels = [
CategoryModel, CategoryChannelModel, ChannelModel, ChannelInfoModel, ChannelMembershipModel, ConfigModel, CustomEmojiModel, DraftModel, FileModel,
GroupModel, GroupChannelModel, GroupTeamModel, GroupMembershipModel, MyChannelModel, MyChannelSettingsModel, MyTeamModel,
PostModel, PostsInChannelModel, PostsInThreadModel, PreferenceModel, ReactionModel, RoleModel,
SystemModel, TeamModel, TeamChannelHistoryModel, TeamMembershipModel, TeamSearchHistoryModel,
ThreadModel, ThreadParticipantModel, ThreadInTeamModel, TeamThreadsSyncModel, UserModel,
];
] as unknown[] as Models;
this.databaseDirectory = Platform.OS === 'ios' ? getIOSAppGroupDetails().appGroupDatabase : `${FileSystem.DocumentDirectoryPath}/databases/`;
}

View file

@ -1,12 +1,12 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Relation} from '@nozbe/watermelondb';
import {field, immutableRelation, relation} from '@nozbe/watermelondb/decorators';
import Model, {Associations} from '@nozbe/watermelondb/Model';
import {MM_TABLES} from '@constants/database';
import type {Relation} from '@nozbe/watermelondb';
import type CategoryModel from '@typings/database/models/servers/category';
import type CategoryChannelInterface from '@typings/database/models/servers/category_channel';
import type ChannelModel from '@typings/database/models/servers/channel';

View file

@ -1,12 +1,12 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Query, Relation} from '@nozbe/watermelondb';
import {children, field, immutableRelation} from '@nozbe/watermelondb/decorators';
import Model, {Associations} from '@nozbe/watermelondb/Model';
import {MM_TABLES} from '@constants/database';
import type {Query, Relation} from '@nozbe/watermelondb';
import type CategoryChannelModel from '@typings/database/models/servers/category_channel';
import type ChannelModelInterface from '@typings/database/models/servers/channel';
import type ChannelInfoModel from '@typings/database/models/servers/channel_info';

View file

@ -1,12 +1,12 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Relation} from '@nozbe/watermelondb';
import {field, immutableRelation} from '@nozbe/watermelondb/decorators';
import Model, {Associations} from '@nozbe/watermelondb/Model';
import {MM_TABLES} from '@constants/database';
import type {Relation} from '@nozbe/watermelondb';
import type ChannelModel from '@typings/database/models/servers/channel';
import type ChannelInfoInterface from '@typings/database/models/servers/channel_info';

View file

@ -1,12 +1,12 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Relation} from '@nozbe/watermelondb';
import {field, immutableRelation} from '@nozbe/watermelondb/decorators';
import Model, {Associations} from '@nozbe/watermelondb/Model';
import {MM_TABLES} from '@constants/database';
import type {Relation} from '@nozbe/watermelondb';
import type FileModelInterface from '@typings/database/models/servers/file';
import type PostModel from '@typings/database/models/servers/post';

View file

@ -1,12 +1,12 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Relation} from '@nozbe/watermelondb';
import {field, immutableRelation} from '@nozbe/watermelondb/decorators';
import Model, {Associations} from '@nozbe/watermelondb/Model';
import {MM_TABLES} from '@constants/database';
import type {Relation} from '@nozbe/watermelondb';
import type ChannelModel from '@typings/database/models/servers/channel';
import type GroupModel from '@typings/database/models/servers/group';
import type GroupChannelInterface from '@typings/database/models/servers/group_channel';

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