Update dependencies and upgrade to RN 0.76.5 (#8421)

* update dev deps

* partial update dependencies

* update watermelondb

* update rn to 0.76.5, expo to 52.0.18 and others

* upgrade android firebase

* upgrade detox deps

* fix package-lock.json

* update emm and paste-input

* update turbo-log

* update network library

* fix tests

* review feedback

* fix Keyboard blocking signIn button

* Fall back to iphone 14 iOS 17.2 simulator as app crashes on iOS 17.4

* changes in deleteCredentialsForServer is causing a crash

* withOptions x2 clearly is wrong

* re-add cli-platform-apple fix

* fix: RN 0.76.5 issue with bottom sheet disappearing (#8478)

* experiment, using view vs BottomSheetView

* revert previous & try disabling enableDynamicSizing

* revert an unintended removal

---------

Co-authored-by: yasserfaraazkhan <attitude3cena.yf@gmail.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
Co-authored-by: Rahim Rahman <rahim.rahman@mattermost.com>
This commit is contained in:
Elias Nahum 2025-01-16 22:11:32 +08:00 committed by GitHub
parent 52e05fba13
commit 2f3dfbbbfa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
101 changed files with 28335 additions and 33928 deletions

View file

@ -39,7 +39,7 @@
{ {
"rule": "cli", "rule": "cli",
"binary": "pod", "binary": "pod",
"semver": "1.15.2", "semver": "1.16.1",
"platform": "darwin" "platform": "darwin"
} }
], ],

View file

@ -1,3 +1,3 @@
source "https://rubygems.org" source "https://rubygems.org"
gem "cocoapods", "1.15.2" gem "cocoapods", "1.16.1"

View file

@ -5,16 +5,18 @@ GEM
base64 base64
nkf nkf
rexml rexml
activesupport (7.1.3.4) activesupport (7.2.2.1)
base64 base64
benchmark (>= 0.3)
bigdecimal bigdecimal
concurrent-ruby (~> 1.0, >= 1.0.2) concurrent-ruby (~> 1.0, >= 1.3.1)
connection_pool (>= 2.2.5) connection_pool (>= 2.2.5)
drb drb
i18n (>= 1.6, < 2) i18n (>= 1.6, < 2)
logger (>= 1.4.2)
minitest (>= 5.1) minitest (>= 5.1)
mutex_m securerandom (>= 0.3)
tzinfo (~> 2.0) tzinfo (~> 2.0, >= 2.0.5)
addressable (2.8.7) addressable (2.8.7)
public_suffix (>= 2.0.2, < 7.0) public_suffix (>= 2.0.2, < 7.0)
algoliasearch (1.27.5) algoliasearch (1.27.5)
@ -22,12 +24,13 @@ GEM
json (>= 1.5.1) json (>= 1.5.1)
atomos (0.1.3) atomos (0.1.3)
base64 (0.2.0) base64 (0.2.0)
benchmark (0.4.0)
bigdecimal (3.1.8) bigdecimal (3.1.8)
claide (1.1.0) claide (1.1.0)
cocoapods (1.15.2) cocoapods (1.16.1)
addressable (~> 2.8) addressable (~> 2.8)
claide (>= 1.0.2, < 2.0) claide (>= 1.0.2, < 2.0)
cocoapods-core (= 1.15.2) cocoapods-core (= 1.16.1)
cocoapods-deintegrate (>= 1.0.3, < 2.0) cocoapods-deintegrate (>= 1.0.3, < 2.0)
cocoapods-downloader (>= 2.1, < 3.0) cocoapods-downloader (>= 2.1, < 3.0)
cocoapods-plugins (>= 1.0.0, < 2.0) cocoapods-plugins (>= 1.0.0, < 2.0)
@ -41,8 +44,8 @@ GEM
molinillo (~> 0.8.0) molinillo (~> 0.8.0)
nap (~> 1.0) nap (~> 1.0)
ruby-macho (>= 2.3.0, < 3.0) ruby-macho (>= 2.3.0, < 3.0)
xcodeproj (>= 1.23.0, < 2.0) xcodeproj (>= 1.26.0, < 2.0)
cocoapods-core (1.15.2) cocoapods-core (1.16.1)
activesupport (>= 5.0, < 8) activesupport (>= 5.0, < 8)
addressable (~> 2.8) addressable (~> 2.8)
algoliasearch (~> 1.0) algoliasearch (~> 1.0)
@ -73,36 +76,37 @@ GEM
fuzzy_match (2.0.4) fuzzy_match (2.0.4)
gh_inspector (1.1.3) gh_inspector (1.1.3)
httpclient (2.8.3) httpclient (2.8.3)
i18n (1.14.5) i18n (1.14.6)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
json (2.7.2) json (2.9.0)
minitest (5.25.1) logger (1.6.3)
minitest (5.25.4)
molinillo (0.8.0) molinillo (0.8.0)
mutex_m (0.2.0) nanaimo (0.4.0)
nanaimo (0.3.0)
nap (1.1.0) nap (1.1.0)
netrc (0.11.0) netrc (0.11.0)
nkf (0.2.0) nkf (0.2.0)
public_suffix (4.0.7) public_suffix (4.0.7)
rexml (3.3.9) rexml (3.3.9)
ruby-macho (2.5.1) ruby-macho (2.5.1)
securerandom (0.4.0)
typhoeus (1.4.1) typhoeus (1.4.1)
ethon (>= 0.9.0) ethon (>= 0.9.0)
tzinfo (2.0.6) tzinfo (2.0.6)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
xcodeproj (1.25.0) xcodeproj (1.27.0)
CFPropertyList (>= 2.3.3, < 4.0) CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3) atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0) claide (>= 1.0.2, < 2.0)
colored2 (~> 3.1) colored2 (~> 3.1)
nanaimo (~> 0.3.0) nanaimo (~> 0.4.0)
rexml (>= 3.3.2, < 4.0) rexml (>= 3.3.6, < 4.0)
PLATFORMS PLATFORMS
ruby ruby
DEPENDENCIES DEPENDENCIES
cocoapods (= 1.15.2) cocoapods (= 1.16.1)
BUNDLED WITH BUNDLED WITH
2.5.11 2.5.11

View file

@ -9,14 +9,14 @@ apply plugin: "com.facebook.react"
react { react {
/* Folders */ /* Folders */
// The root of your project, i.e. where "package.json" lives. Default is '..' // The root of your project, i.e. where "package.json" lives. Default is '../..'
// root = file("../") // root = file("../../")
// The folder where the react-native NPM package is. Default is ../node_modules/react-native // The folder where the react-native NPM package is. Default is ../../node_modules/react-native
// reactNativeDir = file("../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 // The folder where the react-native Codegen package is. Default is ../../node_modules/@react-native/codegen
// codegenDir = file("../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 // 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") // cliFile = file("../../node_modules/react-native/cli.js")
/* Variants */ /* Variants */
// The list of variants to that are debuggable. For those we're going to // 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'. // skip the bundling of the JS bundle and the assets. By default is just 'debug'.
@ -47,6 +47,9 @@ apply plugin: "com.facebook.react"
// //
// The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map" // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map"
// hermesFlags = ["-O", "-output-source-map"] // hermesFlags = ["-O", "-output-source-map"]
/* Autolinking */
autolinkLibrariesWithApp()
} }
apply from: "../../node_modules/react-native-vector-icons/fonts.gradle" apply from: "../../node_modules/react-native-vector-icons/fonts.gradle"
@ -253,4 +256,3 @@ tasks.register('copyDownloadableDepsToLibs', Copy) {
} }
apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.gms.google-services'
apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)

View file

@ -21,7 +21,7 @@ public class Network {
private static final Promise emptyPromise = new ResolvePromise(); private static final Promise emptyPromise = new ResolvePromise();
public static void init(Context context) { public static void init(Context context) {
final ReactApplicationContext reactContext = (ApiClientModuleImpl.context == null) ? new ReactApplicationContext(context) : ApiClientModuleImpl.context; final ReactApplicationContext reactContext = (ApiClientModuleImpl.context == null) ? (ReactApplicationContext) context.getApplicationContext() : ApiClientModuleImpl.context;
clientModule = new ApiClientModuleImpl(reactContext); clientModule = new ApiClientModuleImpl(reactContext);
createClientOptions(); createClientOptions();
} }

View file

@ -1,6 +1,7 @@
package com.mattermost.helpers; package com.mattermost.helpers;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.WritableMap; import com.facebook.react.bridge.WritableMap;
@ -9,58 +10,59 @@ import com.facebook.react.bridge.WritableMap;
* ResolvePromise: Helper class that abstracts boilerplate * ResolvePromise: Helper class that abstracts boilerplate
*/ */
public class ResolvePromise implements Promise { public class ResolvePromise implements Promise {
@Override @Override
public void resolve(@javax.annotation.Nullable Object value) { public void reject(@NonNull String s) {
} }
@Override @Override
public void reject(String code, String message) { public void resolve(@Nullable Object o) {
} }
@Override @Override
public void reject(String code, @NonNull WritableMap map) { public void reject(@NonNull String s, @Nullable String s1) {
} }
@Override @Override
public void reject(String code, Throwable e) { public void reject(@NonNull String s, @Nullable Throwable throwable) {
} }
@Override @Override
public void reject(Throwable e, WritableMap map) { public void reject(@NonNull String s, @Nullable String s1, @Nullable Throwable throwable) {
} }
@Override @Override
public void reject(String code, Throwable e, WritableMap map) { public void reject(@NonNull Throwable throwable) {
} }
@Override @Override
public void reject(String code, String message, Throwable e, WritableMap map) { public void reject(@NonNull Throwable throwable, @NonNull WritableMap writableMap) {
} }
@Override @Override
public void reject(String code, String message, Throwable e) { public void reject(@NonNull String s, @NonNull WritableMap writableMap) {
} }
@Override @Override
public void reject(String code, String message, @NonNull WritableMap map) { public void reject(@NonNull String s, @Nullable Throwable throwable, @NonNull WritableMap writableMap) {
} }
@Override @Override
public void reject(String message) { public void reject(@NonNull String s, @Nullable String s1, @NonNull WritableMap writableMap) {
} }
@Override @Override
public void reject(Throwable reason) { public void reject(@Nullable String s, @Nullable String s1, @Nullable Throwable throwable, @Nullable WritableMap writableMap) {
} }
} }

View file

@ -22,12 +22,12 @@ internal suspend fun PushNotificationDataRunnable.Companion.fetch(serverUrl: Str
} }
} }
override fun reject(code: String, message: String) { override fun reject(code: String, message: String?) {
cont.resumeWith(Result.failure(IOException("Unexpected code $code $message"))) cont.resumeWith(Result.failure(IOException("Unexpected code $code $message")))
} }
override fun reject(reason: Throwable?) { override fun reject(throwable: Throwable) {
cont.resumeWith(Result.failure(IOException("Unexpected code $reason"))) cont.resumeWith(Result.failure(IOException("Unexpected code $throwable")))
} }
}) })
} }
@ -41,12 +41,12 @@ internal suspend fun PushNotificationDataRunnable.Companion.fetchWithPost(server
cont.resumeWith(Result.success(response)) cont.resumeWith(Result.success(response))
} }
override fun reject(code: String, message: String) { override fun reject(code: String, message: String?) {
cont.resumeWith(Result.failure(IOException("Unexpected code $code $message"))) cont.resumeWith(Result.failure(IOException("Unexpected code $code $message")))
} }
override fun reject(reason: Throwable?) { override fun reject(throwable: Throwable) {
cont.resumeWith(Result.failure(IOException("Unexpected code $reason"))) cont.resumeWith(Result.failure(IOException("Unexpected code $throwable")))
} }
}) })
} }

View file

@ -7,14 +7,13 @@ import android.content.res.Configuration
import android.os.Bundle import android.os.Bundle
import com.facebook.react.PackageList import com.facebook.react.PackageList
import com.facebook.react.ReactHost import com.facebook.react.ReactHost
import com.facebook.react.ReactInstanceManager
import com.facebook.react.ReactNativeHost import com.facebook.react.ReactNativeHost
import com.facebook.react.ReactPackage import com.facebook.react.ReactPackage
import com.facebook.react.bridge.ReactContext
import com.facebook.react.bridge.UiThreadUtil import com.facebook.react.bridge.UiThreadUtil
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
import com.facebook.react.defaults.DefaultReactNativeHost import com.facebook.react.defaults.DefaultReactNativeHost
import com.facebook.react.soloader.OpenSourceMergedSoMapping
import com.facebook.react.modules.network.OkHttpClientProvider import com.facebook.react.modules.network.OkHttpClientProvider
import com.facebook.soloader.SoLoader import com.facebook.soloader.SoLoader
import com.mattermost.networkclient.RCTOkHttpClientFactory import com.mattermost.networkclient.RCTOkHttpClientFactory
@ -22,6 +21,7 @@ import com.mattermost.rnshare.helpers.RealPathUtil
import com.mattermost.turbolog.TurboLog import com.mattermost.turbolog.TurboLog
import com.mattermost.turbolog.ConfigureOptions import com.mattermost.turbolog.ConfigureOptions
import com.nozbe.watermelondb.jsi.JSIInstaller import com.nozbe.watermelondb.jsi.JSIInstaller
import com.nozbe.watermelondb.jsi.WatermelonDBJSIPackage
import com.reactnativenavigation.NavigationApplication import com.reactnativenavigation.NavigationApplication
import com.wix.reactnativenotifications.RNNotificationsPackage import com.wix.reactnativenotifications.RNNotificationsPackage
import com.wix.reactnativenotifications.core.AppLaunchHelper import com.wix.reactnativenotifications.core.AppLaunchHelper
@ -45,6 +45,7 @@ class MainApplication : NavigationApplication(), INotificationsApplication {
// Packages that cannot be autolinked yet can be added manually here, for example: // Packages that cannot be autolinked yet can be added manually here, for example:
// add(MyReactNativePackage()) // add(MyReactNativePackage())
add(RNNotificationsPackage(this@MainApplication)) add(RNNotificationsPackage(this@MainApplication))
add(WatermelonDBJSIPackage())
} }
override fun getJSMainModuleName(): String = "index" override fun getJSMainModuleName(): String = "index"
@ -78,13 +79,12 @@ class MainApplication : NavigationApplication(), INotificationsApplication {
OkHttpClientProvider.setOkHttpClientFactory(RCTOkHttpClientFactory()) OkHttpClientProvider.setOkHttpClientFactory(RCTOkHttpClientFactory())
ExpoImageOkHttpClientGlideModule.okHttpClient = RCTOkHttpClientFactory().createNewNetworkModuleClient() ExpoImageOkHttpClientGlideModule.okHttpClient = RCTOkHttpClientFactory().createNewNetworkModuleClient()
SoLoader.init(this, false) SoLoader.init(this, OpenSourceMergedSoMapping)
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
// If you opted-in for the New Architecture, we load the native entry point for this app. // If you opted-in for the New Architecture, we load the native entry point for this app.
load(bridgelessEnabled = false) load(bridgelessEnabled = false)
} }
ApplicationLifecycleDispatcher.onApplicationCreate(this) ApplicationLifecycleDispatcher.onApplicationCreate(this)
registerJSIModules()
} }
override fun onConfigurationChanged(newConfig: Configuration) { override fun onConfigurationChanged(newConfig: Configuration) {
@ -117,27 +117,4 @@ class MainApplication : NavigationApplication(), INotificationsApplication {
} }
} }
} }
@Suppress("DEPRECATION")
private fun registerJSIModules() {
val reactInstanceManager = reactNativeHost.reactInstanceManager
if (!listenerAdded) {
listenerAdded = true
reactInstanceManager.addReactInstanceEventListener(object : ReactInstanceManager.ReactInstanceEventListener {
override fun onReactContextInitialized(context: ReactContext) {
runOnJSQueueThread {
registerWatermelonJSI(context)
}
}
})
}
}
private fun registerWatermelonJSI(context: ReactContext) {
val holder = context.javaScriptContextHolder?.get()
if (holder != null) {
JSIInstaller.install(context, holder)
}
}
} }

View file

@ -1,14 +1,14 @@
buildscript { buildscript {
ext { ext {
buildToolsVersion = "34.0.0" buildToolsVersion = "35.0.0"
minSdkVersion = 24 minSdkVersion = 24
compileSdkVersion = 34 compileSdkVersion = 35
targetSdkVersion = 34 targetSdkVersion = 34
supportLibVersion = "33.0.0" supportLibVersion = "35.0.0"
kotlinVersion = "1.9.22" kotlinVersion = "1.9.24"
kotlin_version = kotlinVersion kotlin_version = kotlinVersion
RNNKotlinVersion = kotlinVersion RNNKotlinVersion = kotlinVersion
firebaseVersion = "24.0.0" firebaseVersion = "24.1.0"
ndkVersion = "26.1.10909125" ndkVersion = "26.1.10909125"
} }
repositories { repositories {

View file

@ -25,9 +25,6 @@ org.gradle.jvmargs=-Xmx4096m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF
# https://developer.android.com/topic/libraries/support-library/androidx-rn # https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true
# Use this property to specify which architecture you want to build. # Use this property to specify which architecture you want to build.
# You can also override it from the CLI using # You can also override it from the CLI using
# ./gradlew <task> -PreactNativeArchitectures=x86_64 # ./gradlew <task> -PreactNativeArchitectures=x86_64

Binary file not shown.

View file

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME

7
android/gradlew vendored
View file

@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# #
# SPDX-License-Identifier: Apache-2.0
#
############################################################################## ##############################################################################
# #
@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop. # Darwin, MinGW, and NonStop.
# #
# (3) This script is generated from the Groovy template # (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project. # within the Gradle project.
# #
# You can find Gradle at https://github.com/gradle/gradle/. # You can find Gradle at https://github.com/gradle/gradle/.
@ -84,7 +86,8 @@ done
# shellcheck disable=SC2034 # shellcheck disable=SC2034
APP_BASE_NAME=${0##*/} APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum MAX_FD=maximum

2
android/gradlew.bat vendored
View file

@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and @rem See the License for the specific language governing permissions and
@rem limitations under the License. @rem limitations under the License.
@rem @rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off @if "%DEBUG%"=="" @echo off
@rem ########################################################################## @rem ##########################################################################

View file

@ -1,8 +1,11 @@
pluginManagement { includeBuild("../node_modules/@react-native/gradle-plugin") }
plugins { id("com.facebook.react.settings") }
extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autolinkLibrariesFromCommand() }
rootProject.name = 'Mattermost' rootProject.name = 'Mattermost'
include ':app' include ':app'
include ':reactnativenotifications' include ':reactnativenotifications'
project(':reactnativenotifications').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-notifications/lib/android/app') project(':reactnativenotifications').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-notifications/lib/android/app')
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
include ':watermelondb-jsi' include ':watermelondb-jsi'
project(':watermelondb-jsi').projectDir = new File(rootProject.projectDir, '../node_modules/@nozbe/watermelondb/native/android-jsi') project(':watermelondb-jsi').projectDir = new File(rootProject.projectDir, '../node_modules/@nozbe/watermelondb/native/android-jsi')
includeBuild('../node_modules/@react-native/gradle-plugin') includeBuild('../node_modules/@react-native/gradle-plugin')

View file

@ -141,7 +141,7 @@ describe('ClientTraking', () => {
group.urls = { group.urls = {
'https://example.com/api': { 'https://example.com/api': {
count: 2, count: 2,
metrics: {latency: 200, networkType: 'Wi-Fi', tlsCipherSuite: 'none', tlsVersion: 'none', isCached: false, httpVersion: 'h2', compressedSize: 10 * 1024, size: 6 * 1024 * 1024, connectionTime: 0}, metrics: {latency: 200, networkType: 'Wi-Fi', tlsCipherSuite: 'none', tlsVersion: 'none', isCached: false, httpVersion: 'h2', compressedSize: 10 * 1024, size: 6 * 1024 * 1024, connectionTime: 0, startTime: 0, endTime: 100, speedInMbps: 1},
}, },
}; };

View file

@ -114,7 +114,7 @@ const AnnouncementBanner = ({
snapPoints: [1, snapPoint], snapPoints: [1, snapPoint],
theme, theme,
}); });
}, [theme.sidebarHeaderTextColor, intl.locale, renderContent, allowDismissal]); }, [intl, allowDismissal, renderContent, theme]);
const handleDismiss = useCallback(() => { const handleDismiss = useCallback(() => {
dismissAnnouncement(serverUrl, bannerText); dismissAnnouncement(serverUrl, bannerText);
@ -129,7 +129,7 @@ const AnnouncementBanner = ({
height.value = withTiming(visible ? ANNOUNCEMENT_BAR_HEIGHT : 0, { height.value = withTiming(visible ? ANNOUNCEMENT_BAR_HEIGHT : 0, {
duration: 200, duration: 200,
}); });
}, [visible]); }, [height, visible]);
const bannerStyle = useAnimatedStyle(() => ({ const bannerStyle = useAnimatedStyle(() => ({
height: height.value, height: height.value,

View file

@ -3,7 +3,7 @@
import {Image, type ImageStyle} from 'expo-image'; import {Image, type ImageStyle} from 'expo-image';
import React, {useState, useCallback} from 'react'; import React, {useState, useCallback} from 'react';
import {type StyleProp, type TextStyle, type ViewStyle} from 'react-native'; import {type StyleProp, type TextStyle} from 'react-native';
import CompassIcon from '@components/compass_icon'; import CompassIcon from '@components/compass_icon';
import Emoji from '@components/emoji'; import Emoji from '@components/emoji';
@ -18,7 +18,7 @@ type Props = {
iconSize: number; iconSize: number;
imageStyle?: StyleProp<ImageStyle>; imageStyle?: StyleProp<ImageStyle>;
imageUrl?: string; imageUrl?: string;
genericStyle: StyleProp<ViewStyle>; genericStyle: StyleProp<TextStyle>;
} }
const BookmarkIcon = ({emoji, emojiSize, emojiStyle, file, genericStyle, iconSize, imageStyle, imageUrl}: Props) => { const BookmarkIcon = ({emoji, emojiSize, emojiStyle, file, genericStyle, iconSize, imageStyle, imageUrl}: Props) => {

View file

@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {LinearGradient} from 'expo-linear-gradient'; import {LinearGradient, type LinearGradientProps} from 'expo-linear-gradient';
import React, {useCallback, useMemo, useState} from 'react'; import React, {useCallback, useMemo, useState} from 'react';
import {FlatList, View, type ListRenderItemInfo, type NativeSyntheticEvent, type NativeScrollEvent} from 'react-native'; import {FlatList, View, type ListRenderItemInfo, type NativeSyntheticEvent, type NativeScrollEvent} from 'react-native';
import Animated from 'react-native-reanimated'; import Animated from 'react-native-reanimated';
@ -31,7 +31,7 @@ type Props = {
separator?: boolean; separator?: boolean;
} }
const GRADIENT_LOCATIONS = [0, 0.64, 1]; const GRADIENT_LOCATIONS: LinearGradientProps['locations'] = [0, 0.64, 1];
const SCROLL_OFFSET = 10; const SCROLL_OFFSET = 10;
const isCloseToBottom = ({layoutMeasurement, contentOffset, contentSize}: NativeScrollEvent) => { const isCloseToBottom = ({layoutMeasurement, contentOffset, contentSize}: NativeScrollEvent) => {
@ -112,7 +112,7 @@ const ChannelBookmarks = ({
setAllowEndFade(isCloseToBottom(e.nativeEvent)); setAllowEndFade(isCloseToBottom(e.nativeEvent));
}, []); }, []);
const gradientColors = useMemo(() => [ const gradientColors: LinearGradientProps['colors'] = useMemo(() => [
theme.centerChannelBg, theme.centerChannelBg,
changeOpacity(theme.centerChannelBg, 0.6458), changeOpacity(theme.centerChannelBg, 0.6458),
changeOpacity(theme.centerChannelBg, 0), changeOpacity(theme.centerChannelBg, 0),

View file

@ -11,13 +11,13 @@ import {useTheme} from '@context/theme';
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
import type UserModel from '@typings/database/models/servers/user'; import type UserModel from '@typings/database/models/servers/user';
import type {StyleProp, ViewStyle} from 'react-native'; import type {StyleProp, TextStyle, ViewStyle} from 'react-native';
type Props = { type Props = {
authorId: string; authorId: string;
author?: UserModel; author?: UserModel;
isOnCenterBg?: boolean; isOnCenterBg?: boolean;
style: StyleProp<ViewStyle>; style: StyleProp<Intersection<TextStyle, ViewStyle>>;
size: number; size: number;
} }

View file

@ -2,7 +2,7 @@
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import React from 'react'; import React from 'react';
import {type StyleProp, Text, View, type ViewStyle} from 'react-native'; import {type StyleProp, Text, type TextStyle, View, type ViewStyle} from 'react-native';
import CompassIcon from '@components/compass_icon'; import CompassIcon from '@components/compass_icon';
import General from '@constants/general'; import General from '@constants/general';
@ -23,7 +23,7 @@ type ChannelIconProps = {
name: string; name: string;
shared: boolean; shared: boolean;
size?: number; size?: number;
style?: StyleProp<ViewStyle>; style?: StyleProp<Intersection<TextStyle, ViewStyle>>;
testID?: string; testID?: string;
type: string; type: string;
}; };
@ -125,12 +125,12 @@ const ChannelIcon = ({
mutedStyle = styles.muted; mutedStyle = styles.muted;
} }
const commonStyles = [ const commonStyles: StyleProp<Intersection<TextStyle, ViewStyle>> = [
style, style,
mutedStyle, mutedStyle,
]; ];
const commonIconStyles = [ const commonIconStyles: StyleProp<TextStyle> = [
styles.icon, styles.icon,
unreadIcon, unreadIcon,
activeIcon, activeIcon,

View file

@ -6,13 +6,13 @@ import React from 'react';
import CustomStatusEmoji from '@components/custom_status/custom_status_emoji'; import CustomStatusEmoji from '@components/custom_status/custom_status_emoji';
import type {EmojiCommonStyle} from '@typings/components/emoji'; import type {EmojiCommonStyle} from '@typings/components/emoji';
import type {StyleProp} from 'react-native'; import type {StyleProp, TextStyle} from 'react-native';
type Props = { type Props = {
customStatus?: UserCustomStatus; customStatus?: UserCustomStatus;
customStatusExpired: boolean; customStatusExpired: boolean;
isCustomStatusEnabled: boolean; isCustomStatusEnabled: boolean;
style: StyleProp<EmojiCommonStyle>; style: StyleProp<Intersection<EmojiCommonStyle, TextStyle>>;
} }
const CustomStatus = ({customStatus, customStatusExpired, isCustomStatusEnabled, style}: Props) => { const CustomStatus = ({customStatus, customStatusExpired, isCustomStatusEnabled, style}: Props) => {

View file

@ -150,7 +150,7 @@ const ConnectionBanner = ({
height.value = withTiming(visible ? ANNOUNCEMENT_BAR_HEIGHT : 0, { height.value = withTiming(visible ? ANNOUNCEMENT_BAR_HEIGHT : 0, {
duration: 200, duration: 200,
}); });
}, [visible]); }, [height, visible]);
const bannerStyle = useAnimatedStyle(() => ({ const bannerStyle = useAnimatedStyle(() => ({
height: height.value, height: height.value,

View file

@ -6,12 +6,12 @@ import React from 'react';
import Emoji from '@components/emoji'; import Emoji from '@components/emoji';
import type {EmojiCommonStyle} from '@typings/components/emoji'; import type {EmojiCommonStyle} from '@typings/components/emoji';
import type {StyleProp} from 'react-native'; import type {StyleProp, TextStyle} from 'react-native';
interface ComponentProps { interface ComponentProps {
customStatus: UserCustomStatus; customStatus: UserCustomStatus;
emojiSize?: number; emojiSize?: number;
style?: StyleProp<EmojiCommonStyle>; style?: StyleProp<Intersection<EmojiCommonStyle, TextStyle>>;
} }
const CustomStatusEmoji = ({customStatus, emojiSize = 16, style}: ComponentProps) => { const CustomStatusEmoji = ({customStatus, emojiSize = 16, style}: ComponentProps) => {

View file

@ -12,7 +12,7 @@ import {makeStyleSheetFromTheme} from '@utils/theme';
type ErrorProps = { type ErrorProps = {
error: unknown; error: unknown;
testID?: string; testID?: string;
textStyle?: StyleProp<ViewStyle> | StyleProp<TextStyle>; textStyle?: StyleProp<Intersection<TextStyle, ViewStyle>> | StyleProp<TextStyle>;
} }
const ErrorTextComponent = ({error, testID, textStyle}: ErrorProps) => { const ErrorTextComponent = ({error, testID, textStyle}: ErrorProps) => {

View file

@ -3,7 +3,7 @@
import React, {useEffect, useMemo, useState} from 'react'; import React, {useEffect, useMemo, useState} from 'react';
import {DeviceEventEmitter, type StyleProp, StyleSheet, View, type ViewStyle} from 'react-native'; import {DeviceEventEmitter, type StyleProp, StyleSheet, View, type ViewStyle} from 'react-native';
import Animated, {useDerivedValue} from 'react-native-reanimated'; import Animated from 'react-native-reanimated';
import {Events} from '@constants'; import {Events} from '@constants';
import {GalleryInit} from '@context/gallery'; import {GalleryInit} from '@context/gallery';
@ -56,21 +56,21 @@ const Files = ({canDownloadFiles, failed, filesInfo, isReplyPost, layoutWidth, l
const {images: imageAttachments, nonImages: nonImageAttachments} = useImageAttachments(filesInfo, publicLinkEnabled); const {images: imageAttachments, nonImages: nonImageAttachments} = useImageAttachments(filesInfo, publicLinkEnabled);
const filesForGallery = useDerivedValue(() => imageAttachments.concat(nonImageAttachments), const filesForGallery = useMemo(() => imageAttachments.concat(nonImageAttachments),
[imageAttachments, nonImageAttachments]); [imageAttachments, nonImageAttachments]);
const attachmentIndex = (fileId: string) => { const attachmentIndex = (fileId: string) => {
return filesForGallery.value.findIndex((file) => file.id === fileId) || 0; return filesForGallery.findIndex((file) => file.id === fileId) || 0;
}; };
const handlePreviewPress = preventDoubleTap((idx: number) => { const handlePreviewPress = preventDoubleTap((idx: number) => {
const items = filesForGallery.value.map((f) => fileToGalleryItem(f, f.user_id, postProps)); const items = filesForGallery.map((f) => fileToGalleryItem(f, f.user_id, postProps));
openGalleryAtIndex(galleryIdentifier, idx, items); openGalleryAtIndex(galleryIdentifier, idx, items);
}); });
const updateFileForGallery = (idx: number, file: FileInfo) => { const updateFileForGallery = (idx: number, file: FileInfo) => {
'worklet'; 'worklet';
filesForGallery.value[idx] = file; filesForGallery[idx] = file;
}; };
const isSingleImage = useMemo(() => filesInfo.filter((f) => isImage(f) || isVideo(f)).length === 1, [filesInfo]); const isSingleImage = useMemo(() => filesInfo.filter((f) => isImage(f) || isVideo(f)).length === 1, [filesInfo]);

View file

@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {LinearGradient} from 'expo-linear-gradient'; import {LinearGradient, type LinearGradientProps} from 'expo-linear-gradient';
import React, {useCallback, useMemo, useState} from 'react'; import React, {useCallback, useMemo, useState} from 'react';
import {StyleSheet, useWindowDimensions, View} from 'react-native'; import {StyleSheet, useWindowDimensions, View} from 'react-native';
@ -30,9 +30,9 @@ type ImageFileProps = {
const SMALL_IMAGE_MAX_HEIGHT = 48; const SMALL_IMAGE_MAX_HEIGHT = 48;
const SMALL_IMAGE_MAX_WIDTH = 48; const SMALL_IMAGE_MAX_WIDTH = 48;
const GRADIENT_COLORS = ['rgba(0, 0, 0, 0)', 'rgba(0, 0, 0, .32)']; const GRADIENT_COLORS: LinearGradientProps['colors'] = ['rgba(0, 0, 0, 0)', 'rgba(0, 0, 0, .32)'];
const GRADIENT_END = {x: 1, y: 1}; const GRADIENT_END = {x: 1, y: 1};
const GRADIENT_LOCATIONS = [0.5, 1]; const GRADIENT_LOCATIONS: LinearGradientProps['locations'] = [0.5, 1];
const GRADIENT_START = {x: 0.5, y: 0.5}; const GRADIENT_START = {x: 0.5, y: 0.5};
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({

View file

@ -274,7 +274,7 @@ const FloatingTextChipsInput = forwardRef<Ref, Props>(({
> >
{label} {label}
</Animated.Text> </Animated.Text>
<View style={textInputContainerStyles}> <View style={textInputContainerStyles as StyleProp<ViewStyle>}>
{chipsValues && chipsValues?.length > 0 && chipsValues.map((chipValue) => ( {chipsValues && chipsValues?.length > 0 && chipsValues.map((chipValue) => (
<SelectedChip <SelectedChip
key={chipValue} key={chipValue}

View file

@ -255,7 +255,7 @@ const FloatingTextInput = forwardRef<FloatingTextInputRef, FloatingTextInputProp
> >
{label} {label}
</Animated.Text> </Animated.Text>
<View style={combinedTextInputContainerStyle}> <View style={combinedTextInputContainerStyle as StyleProp<ViewStyle>}>
<TextInput <TextInput
{...props} {...props}
editable={isKeyboardInput && editable} editable={isKeyboardInput && editable}

View file

@ -114,7 +114,7 @@ const FormattedMarkdownText = ({baseTextStyle, channelId, defaultMessage, id, lo
}; };
const renderParagraph = ({children, first}: {children: ReactElement; first: boolean}) => { const renderParagraph = ({children, first}: {children: ReactElement; first: boolean}) => {
const blockStyle: StyleProp<ViewStyle> = [styles.block]; const blockStyle: StyleProp<Intersection<TextStyle, ViewStyle>> = [styles.block];
if (!first) { if (!first) {
const blockS = getMarkdownBlockStyles(theme); const blockS = getMarkdownBlockStyles(theme);
blockStyle.push(blockS.adjacentParagraph); blockStyle.push(blockS.adjacentParagraph);

View file

@ -332,7 +332,7 @@ const Markdown = ({
return ( return (
<View <View
style={containerStyle} style={containerStyle as StyleProp<ViewStyle>}
testID='markdown_heading' testID='markdown_heading'
> >
<Text style={textStyle}> <Text style={textStyle}>

View file

@ -2,13 +2,13 @@
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import React, {type ReactNode} from 'react'; import React, {type ReactNode} from 'react';
import {StyleSheet, type TextStyle, View, type ViewStyle} from 'react-native'; import {type StyleProp, StyleSheet, type TextStyle, View, type ViewStyle} from 'react-native';
import CompassIcon from '@components/compass_icon'; import CompassIcon from '@components/compass_icon';
type MarkdownBlockQuoteProps = { type MarkdownBlockQuoteProps = {
continueBlock?: boolean; continueBlock?: boolean;
iconStyle: ViewStyle | TextStyle; iconStyle: StyleProp<Intersection<ViewStyle, TextStyle>>;
children: ReactNode | ReactNode[]; children: ReactNode | ReactNode[];
}; };

View file

@ -48,7 +48,7 @@ const NavigationHeaderLargeTitle = ({
const containerStyle = useMemo(() => { const containerStyle = useMemo(() => {
return [{height: heightOffset}, styles.container]; return [{height: heightOffset}, styles.container];
}, [heightOffset, theme]); }, [heightOffset, styles.container]);
return ( return (
<Animated.View style={[containerStyle, transform]}> <Animated.View style={[containerStyle, transform]}>

View file

@ -61,7 +61,7 @@ const AnimatedOptionBox = ({
animate.value = withTiming(1, {duration: 150, easing: Easing.out(Easing.linear)}); animate.value = withTiming(1, {duration: 150, easing: Easing.out(Easing.linear)});
setActivated(true); setActivated(true);
onPress(); onPress();
}, [onPress]); }, [animate, onPress]);
const backgroundStyle = useAnimatedStyle(() => ({ const backgroundStyle = useAnimatedStyle(() => ({
backgroundColor: interpolateColor( backgroundColor: interpolateColor(
@ -111,7 +111,7 @@ const AnimatedOptionBox = ({
clearTimeout(t); clearTimeout(t);
} }
}; };
}, [activated, animate.value, onAnimationEnd]); }, [activated, animate, onAnimationEnd]);
return ( return (
<AnimatedPressable <AnimatedPressable

View file

@ -112,7 +112,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
export type OptionItemProps = { export type OptionItemProps = {
action?: (React.Dispatch<React.SetStateAction<string | boolean>>)|((value: string | boolean) => void); action?: (React.Dispatch<React.SetStateAction<string | boolean>>)|((value: string | boolean) => void);
arrowStyle?: StyleProp<ViewStyle>; arrowStyle?: StyleProp<Intersection<TextStyle, ViewStyle>>;
containerStyle?: StyleProp<ViewStyle>; containerStyle?: StyleProp<ViewStyle>;
description?: string; description?: string;
destructive?: boolean; destructive?: boolean;

View file

@ -121,7 +121,7 @@ function Typing({
useEffect(() => { useEffect(() => {
typingHeight.value = typing.current.length ? TYPING_HEIGHT : 0; typingHeight.value = typing.current.length ? TYPING_HEIGHT : 0;
}, [refresh]); }, [refresh, typingHeight]);
useEffect(() => { useEffect(() => {
typing.current = []; typing.current = [];
@ -130,7 +130,7 @@ function Typing({
clearTimeout(timeoutToDisappear.current); clearTimeout(timeoutToDisappear.current);
timeoutToDisappear.current = undefined; timeoutToDisappear.current = undefined;
} }
}, [channelId, rootId]); }, [channelId, rootId, typingHeight]);
const renderTyping = () => { const renderTyping = () => {
const nextTyping = typing.current.map(({username}) => username); const nextTyping = typing.current.map(({username}) => username);

View file

@ -82,6 +82,7 @@ function Uploads({
const errorHeight = useSharedValue(ERROR_HEIGHT_MIN); const errorHeight = useSharedValue(ERROR_HEIGHT_MIN);
const containerHeight = useSharedValue(files.length ? CONTAINER_HEIGHT_MAX : CONTAINER_HEIGHT_MIN); const containerHeight = useSharedValue(files.length ? CONTAINER_HEIGHT_MAX : CONTAINER_HEIGHT_MIN);
const filesForGallery = useRef(files.filter((f) => !f.failed && !DraftUploadManager.isUploading(f.clientId!))); const filesForGallery = useRef(files.filter((f) => !f.failed && !DraftUploadManager.isUploading(f.clientId!)));
const hasFiles = files.length > 0;
const errorAnimatedStyle = useAnimatedStyle(() => { const errorAnimatedStyle = useAnimatedStyle(() => {
return { return {
@ -109,21 +110,21 @@ function Uploads({
} else { } else {
errorHeight.value = ERROR_HEIGHT_MIN; errorHeight.value = ERROR_HEIGHT_MIN;
} }
}, [uploadFileError]); }, [errorHeight, uploadFileError]);
useEffect(() => { useEffect(() => {
if (files.length) { if (hasFiles) {
containerHeight.value = CONTAINER_HEIGHT_MAX; containerHeight.value = CONTAINER_HEIGHT_MAX;
return; return;
} }
containerHeight.value = CONTAINER_HEIGHT_MIN; containerHeight.value = CONTAINER_HEIGHT_MIN;
}, [files.length > 0]); }, [containerHeight, hasFiles]);
const openGallery = useCallback((file: FileInfo) => { const openGallery = useCallback((file: FileInfo) => {
const items = filesForGallery.current.map((f) => fileToGalleryItem(f, currentUserId)); const items = filesForGallery.current.map((f) => fileToGalleryItem(f, currentUserId));
const index = filesForGallery.current.findIndex((f) => f.clientId === file.clientId); const index = filesForGallery.current.findIndex((f) => f.clientId === file.clientId);
openGalleryAtIndex(galleryIdentifier, index, items, true); openGalleryAtIndex(galleryIdentifier, index, items, true);
}, [currentUserId, files]); }, [currentUserId, galleryIdentifier]);
const buildFilePreviews = () => { const buildFilePreviews = () => {
return files.map((file, index) => { return files.map((file, index) => {

View file

@ -2,7 +2,7 @@
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import React from 'react'; import React from 'react';
import {type StyleProp, View, type ViewStyle} from 'react-native'; import {type StyleProp, type TextStyle, View, type ViewStyle} from 'react-native';
import FormattedDate, {type FormattedDateFormat} from '@components/formatted_date'; import FormattedDate, {type FormattedDateFormat} from '@components/formatted_date';
import FormattedText from '@components/formatted_text'; import FormattedText from '@components/formatted_text';
@ -13,7 +13,7 @@ import {typography} from '@utils/typography';
type DateSeparatorProps = { type DateSeparatorProps = {
date: number | Date; date: number | Date;
style?: StyleProp<ViewStyle>; style?: StyleProp<Intersection<TextStyle, ViewStyle>>;
timezone?: string | null; timezone?: string | null;
}; };
@ -81,7 +81,7 @@ const DateSeparator = (props: DateSeparatorProps) => {
const styles = getStyleSheet(theme); const styles = getStyleSheet(theme);
return ( return (
<View style={[styles.container, props.style]}> <View style={[styles.container, props.style as StyleProp<ViewStyle>]}>
<View style={styles.line}/> <View style={styles.line}/>
<RecentDate <RecentDate
{...props} {...props}

View file

@ -214,7 +214,7 @@ const MoreMessages = ({
top.value = 0; top.value = 0;
resetMessageCount(serverUrl, channelId); resetMessageCount(serverUrl, channelId);
pressed.current = false; pressed.current = false;
}, [serverUrl, channelId]); }, [top, serverUrl, channelId]);
const onPress = useCallback(() => { const onPress = useCallback(() => {
if (pressed.current) { if (pressed.current) {
@ -223,7 +223,7 @@ const MoreMessages = ({
pressed.current = true; pressed.current = true;
scrollToIndex(newMessageLineIndex, true); scrollToIndex(newMessageLineIndex, true);
}, [newMessageLineIndex]); }, [newMessageLineIndex, scrollToIndex]);
useDidUpdate(() => { useDidUpdate(() => {
setLoading(EphemeralStore.isLoadingMessagesForChannel(serverUrl, channelId)); setLoading(EphemeralStore.isLoadingMessagesForChannel(serverUrl, channelId));

View file

@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {LinearGradient} from 'expo-linear-gradient'; import {LinearGradient, type LinearGradientProps} from 'expo-linear-gradient';
import React from 'react'; import React from 'react';
import {TouchableOpacity, View} from 'react-native'; import {TouchableOpacity, View} from 'react-native';
@ -74,7 +74,7 @@ const ShowMoreButton = ({highlight, onPress, showMore = true, theme}: ShowMoreBu
iconName = 'chevron-up'; iconName = 'chevron-up';
} }
let gradientColors = [ let gradientColors: LinearGradientProps['colors'] = [
changeOpacity(theme.centerChannelBg, 0), changeOpacity(theme.centerChannelBg, 0),
changeOpacity(theme.centerChannelBg, 0.75), changeOpacity(theme.centerChannelBg, 0.75),
theme.centerChannelBg, theme.centerChannelBg,

View file

@ -117,20 +117,13 @@ const PostList = ({
const serverUrl = useServerUrl(); const serverUrl = useServerUrl();
const orderedPosts = useMemo(() => { const orderedPosts = useMemo(() => {
return preparePostList(posts, lastViewedAt, showNewMessageLine, currentUserId, currentUsername, shouldShowJoinLeaveMessages, currentTimezone, location === Screens.THREAD, savedPostIds); return preparePostList(posts, lastViewedAt, showNewMessageLine, currentUserId, currentUsername, shouldShowJoinLeaveMessages, currentTimezone, location === Screens.THREAD, savedPostIds);
}, [posts, lastViewedAt, showNewMessageLine, currentTimezone, currentUsername, shouldShowJoinLeaveMessages, location, savedPostIds]); }, [posts, lastViewedAt, showNewMessageLine, currentUserId, currentUsername, shouldShowJoinLeaveMessages, currentTimezone, location, savedPostIds]);
const initialIndex = useMemo(() => { const initialIndex = useMemo(() => {
return orderedPosts.findIndex((i) => i.type === 'start-of-new-messages'); return orderedPosts.findIndex((i) => i.type === 'start-of-new-messages');
}, [orderedPosts]); }, [orderedPosts]);
const isNewMessage = useMemo(() => { const isNewMessage = lastPostId ? posts[0]?.id !== lastPostId : false;
if (!lastPostId) {
// Avoid flash when the channel loads without posts
// e.g. The first time we navigate to a channel
return false;
}
return posts[0]?.id !== lastPostId;
}, [posts[0]?.id, lastPostId]);
useEffect(() => { useEffect(() => {
const t = setTimeout(() => { const t = setTimeout(() => {
@ -266,7 +259,6 @@ const PostList = ({
case 'user-activity': { case 'user-activity': {
const postProps = { const postProps = {
currentUsername, currentUsername,
key: item.value,
postId: item.value, postId: item.value,
location, location,
style: styles.container, style: styles.container,
@ -275,7 +267,11 @@ const PostList = ({
theme, theme,
}; };
return (<CombinedUserActivity {...postProps}/>); return (
<CombinedUserActivity
{...postProps}
key={item.value}
/>);
} }
default: { default: {
const post = item.value.currentPost; const post = item.value.currentPost;
@ -289,7 +285,6 @@ const PostList = ({
highlight: highlightedId === post.id, highlight: highlightedId === post.id,
highlightPinnedOrSaved, highlightPinnedOrSaved,
isSaved, isSaved,
key: post.id,
location, location,
nextPost, nextPost,
post, post,
@ -300,10 +295,15 @@ const PostList = ({
testID: `${testID}.post`, testID: `${testID}.post`,
}; };
return (<Post {...postProps}/>); return (
<Post
{...postProps}
key={post.id}
/>
);
} }
} }
}, [appsEnabled, currentTimezone, customEmojiNames, highlightPinnedOrSaved, isCRTEnabled, isPostAcknowledgementEnabled, shouldRenderReplyButton, theme]); }, [appsEnabled, currentTimezone, currentUsername, customEmojiNames, highlightPinnedOrSaved, highlightedId, isCRTEnabled, isPostAcknowledgementEnabled, location, rootId, shouldRenderReplyButton, shouldShowJoinLeaveMessages, testID, theme]);
const scrollToIndex = useCallback((index: number, animated = true, applyOffset = true) => { const scrollToIndex = useCallback((index: number, animated = true, applyOffset = true) => {
listRef.current?.scrollToIndex({ listRef.current?.scrollToIndex({

View file

@ -61,6 +61,14 @@ exports[`ThreadOverview should match snapshot when post is saved and has replies
onGestureHandlerStateChange={[Function]} onGestureHandlerStateChange={[Function]}
onHandlerStateChange={[Function]} onHandlerStateChange={[Function]}
rippleColor={0} rippleColor={0}
style={
[
undefined,
{
"cursor": undefined,
},
]
}
testID="thread-overview.save.button" testID="thread-overview.save.button"
touchSoundDisabled={false} touchSoundDisabled={false}
> >
@ -94,6 +102,14 @@ exports[`ThreadOverview should match snapshot when post is saved and has replies
onGestureHandlerStateChange={[Function]} onGestureHandlerStateChange={[Function]}
onHandlerStateChange={[Function]} onHandlerStateChange={[Function]}
rippleColor={0} rippleColor={0}
style={
[
undefined,
{
"cursor": undefined,
},
]
}
testID="thread-overview.post_options.button" testID="thread-overview.post_options.button"
touchSoundDisabled={false} touchSoundDisabled={false}
> >

View file

@ -9,7 +9,6 @@ import Animated from 'react-native-reanimated';
import {useTheme} from '@context/theme'; import {useTheme} from '@context/theme';
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
const AnimatedImageBackground = Animated.createAnimatedComponent(ImageBackground);
const AnimatedImage = Animated.createAnimatedComponent(Image); const AnimatedImage = Animated.createAnimatedComponent(Image);
type Props = ProgressiveImageProps & { type Props = ProgressiveImageProps & {
@ -55,14 +54,14 @@ const ProgressiveImage = ({
if (isBackgroundImage && imageUri) { if (isBackgroundImage && imageUri) {
return ( return (
<View style={[styles.defaultImageContainer, style]}> <View style={[styles.defaultImageContainer, style]}>
<AnimatedImageBackground <ImageBackground
key={id} key={id}
source={{uri: imageUri}} source={{uri: imageUri}}
contentFit='cover' contentFit='cover'
style={[StyleSheet.absoluteFill, imageStyle]} style={[StyleSheet.absoluteFill, imageStyle as StyleProp<ViewStyle>]}
> >
{children} {children}
</AnimatedImageBackground> </ImageBackground>
</View> </View>
); );
} }

View file

@ -2,7 +2,7 @@
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import React, {useMemo} from 'react'; import React, {useMemo} from 'react';
import {type StyleProp, StyleSheet, View, type ViewStyle} from 'react-native'; import {type StyleProp, StyleSheet, type TextStyle, View, type ViewStyle} from 'react-native';
import Badge from '@components/badge'; import Badge from '@components/badge';
import CompassIcon from '@components/compass_icon'; import CompassIcon from '@components/compass_icon';
@ -14,7 +14,7 @@ type Props = {
badgeBackgroundColor?: string; badgeBackgroundColor?: string;
badgeBorderColor?: string; badgeBorderColor?: string;
badgeColor?: string; badgeColor?: string;
badgeStyle?: StyleProp<ViewStyle>; badgeStyle?: StyleProp<TextStyle>;
hasUnreads: boolean; hasUnreads: boolean;
iconColor?: string; iconColor?: string;
mentionCount: number; mentionCount: number;
@ -22,7 +22,7 @@ type Props = {
size?: number; size?: number;
style?: StyleProp<ViewStyle>; style?: StyleProp<ViewStyle>;
testID?: string; testID?: string;
unreadStyle?: StyleProp<ViewStyle>; unreadStyle?: StyleProp<TextStyle>;
} }
const hitSlop = {top: 20, bottom: 5, left: 40, right: 20}; const hitSlop = {top: 20, bottom: 5, left: 40, right: 20};

View file

@ -14,7 +14,7 @@ export default schemaMigrations({migrations: [
{ {
toVersion: 6, toVersion: 6,
steps: [ steps: [
unsafeExecuteSql('CREATE INDEX IF NOT EXISTS Post_type ON Post (type)'), unsafeExecuteSql('CREATE INDEX IF NOT EXISTS Post_type ON Post (type);'),
], ],
}, },
{ {

View file

@ -1,5 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {renderHook} from '@testing-library/react-hooks'; import {renderHook} from '@testing-library/react-hooks';
import {act} from '@testing-library/react-native'; import {act} from '@testing-library/react-native';
@ -12,10 +13,6 @@ const LARGE_HEADER_TITLE_HEIGHT = 128;
const HEADER_OFFSET = LARGE_HEADER_TITLE_HEIGHT - ViewConstants.DEFAULT_HEADER_HEIGHT; const HEADER_OFFSET = LARGE_HEADER_TITLE_HEIGHT - ViewConstants.DEFAULT_HEADER_HEIGHT;
describe('useCollapsibleHeader', () => { describe('useCollapsibleHeader', () => {
afterEach(() => {
jest.resetAllMocks();
});
const commonHookResponse = { const commonHookResponse = {
largeHeight: LARGE_HEADER_TITLE_HEIGHT, largeHeight: LARGE_HEADER_TITLE_HEIGHT,
scrollRef: {current: null}, scrollRef: {current: null},

View file

@ -56,7 +56,7 @@ export const setServerCredentials = (serverUrl: string, token: string) => {
accessGroup = appGroup.appGroupIdentifier; accessGroup = appGroup.appGroupIdentifier;
} }
const options: KeyChain.Options = { const options: KeyChain.SetOptions = {
accessGroup, accessGroup,
securityLevel: KeyChain.SECURITY_LEVEL.SECURE_SOFTWARE, securityLevel: KeyChain.SECURITY_LEVEL.SECURE_SOFTWARE,
}; };
@ -67,16 +67,7 @@ export const setServerCredentials = (serverUrl: string, token: string) => {
}; };
export const removeServerCredentials = async (serverUrl: string) => { export const removeServerCredentials = async (serverUrl: string) => {
const options: KeyChain.Options = { return KeyChain.resetInternetCredentials(serverUrl);
securityLevel: KeyChain.SECURITY_LEVEL.SECURE_SOFTWARE,
};
if (Platform.OS === 'ios') {
const appGroup = getIOSAppGroupDetails();
options.accessGroup = appGroup.appGroupIdentifier;
}
await KeyChain.resetInternetCredentials(serverUrl, options);
}; };
export const removeActiveServerCredentials = async () => { export const removeActiveServerCredentials = async () => {

View file

@ -12,7 +12,7 @@ import type {CurrentCall} from '@calls/types/calls';
type Props = { type Props = {
pressableStyle: StyleProp<ViewStyle>; pressableStyle: StyleProp<ViewStyle>;
iconStyle: StyleProp<ViewStyle>; iconStyle: StyleProp<TextStyle>;
buttonTextStyle: StyleProp<TextStyle>; buttonTextStyle: StyleProp<TextStyle>;
currentCall: CurrentCall; currentCall: CurrentCall;
} }

View file

@ -17,7 +17,7 @@ import {makeStyleSheetFromTheme} from '@utils/theme';
type Props = { type Props = {
pressableStyle: StyleProp<ViewStyle>; pressableStyle: StyleProp<ViewStyle>;
iconStyle: StyleProp<ViewStyle>; iconStyle: StyleProp<TextStyle>;
buttonTextStyle: StyleProp<TextStyle>; buttonTextStyle: StyleProp<TextStyle>;
currentCall: CurrentCall; currentCall: CurrentCall;
} }
@ -33,7 +33,6 @@ export const AudioDeviceButton = ({pressableStyle, iconStyle, buttonTextStyle, c
const theme = useTheme(); const theme = useTheme();
const style = getStyleFromTheme(theme); const style = getStyleFromTheme(theme);
const isTablet = Device.IS_TABLET; // not `useIsTablet` because even if we're in splitView, we're still using a tablet. const isTablet = Device.IS_TABLET; // not `useIsTablet` because even if we're in splitView, we're still using a tablet.
const color = theme.awayIndicator;
const audioDeviceInfo = currentCall.audioDeviceInfo; const audioDeviceInfo = currentCall.audioDeviceInfo;
const phoneLabel = intl.formatMessage({id: 'mobile.calls_phone', defaultMessage: 'Phone'}); const phoneLabel = intl.formatMessage({id: 'mobile.calls_phone', defaultMessage: 'Phone'});
const tabletLabel = intl.formatMessage({id: 'mobile.calls_tablet', defaultMessage: 'Tablet'}); const tabletLabel = intl.formatMessage({id: 'mobile.calls_tablet', defaultMessage: 'Tablet'});
@ -111,7 +110,11 @@ export const AudioDeviceButton = ({pressableStyle, iconStyle, buttonTextStyle, c
title: intl.formatMessage({id: 'mobile.calls_audio_device', defaultMessage: 'Select audio device'}), title: intl.formatMessage({id: 'mobile.calls_audio_device', defaultMessage: 'Select audio device'}),
theme, theme,
}); });
}, [setPreferredAudioRoute, audioDeviceInfo, color]); }, [
audioDeviceInfo.selectedAudioDevice, audioDeviceInfo.availableAudioDeviceList,
intl, theme, isTablet, tabletLabel, style.checkIcon,
phoneLabel, speakerLabel, bluetoothLabel, headsetLabel,
]);
let icon = 'volume-high'; let icon = 'volume-high';
let label = speakerLabel; let label = speakerLabel;

View file

@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import React, {useMemo} from 'react'; import React, {useCallback, useMemo} from 'react';
import {useIntl} from 'react-intl'; import {useIntl} from 'react-intl';
import {Pressable, Text, View} from 'react-native'; import {Pressable, Text, View} from 'react-native';
import Permissions from 'react-native-permissions'; import Permissions from 'react-native-permissions';
@ -99,6 +99,10 @@ const MessageBar = ({type, onDismiss}: Props) => {
const style = getStyleSheet(callsTheme); const style = getStyleSheet(callsTheme);
const warning = type === Calls.MessageBarType.CallQuality; const warning = type === Calls.MessageBarType.CallQuality;
const onPress = useCallback(() => {
Permissions.openSettings();
}, []);
let message = ''; let message = '';
let icon = <></>; let icon = <></>;
switch (type) { switch (type) {
@ -129,7 +133,7 @@ const MessageBar = ({type, onDismiss}: Props) => {
return ( return (
<View style={[style.outerContainer, warning && style.outerContainerWarning]}> <View style={[style.outerContainer, warning && style.outerContainerWarning]}>
<Pressable <Pressable
onPress={Permissions.openSettings} onPress={onPress}
style={[style.innerContainer, warning && style.innerContainerWarning]} style={[style.innerContainer, warning && style.innerContainerWarning]}
> >
<View style={style.iconContainer}> <View style={style.iconContainer}>

View file

@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import BottomSheetM, {BottomSheetBackdrop, type BottomSheetBackdropProps} from '@gorhom/bottom-sheet'; import BottomSheetM, {BottomSheetBackdrop, BottomSheetView, type BottomSheetBackdropProps} from '@gorhom/bottom-sheet';
import React, {type ReactNode, useCallback, useEffect, useMemo, useRef} from 'react'; import React, {type ReactNode, useCallback, useEffect, useMemo, useRef} from 'react';
import {DeviceEventEmitter, type Handle, InteractionManager, Keyboard, type StyleProp, View, type ViewStyle} from 'react-native'; import {DeviceEventEmitter, type Handle, InteractionManager, Keyboard, type StyleProp, View, type ViewStyle} from 'react-native';
import {ReduceMotion, type WithSpringConfig} from 'react-native-reanimated'; import {ReduceMotion, type WithSpringConfig} from 'react-native-reanimated';
@ -71,6 +71,9 @@ export const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
borderTopWidth: 1, borderTopWidth: 1,
borderColor: changeOpacity(theme.centerChannelColor, 0.08), borderColor: changeOpacity(theme.centerChannelColor, 0.08),
}, },
view: {
flex: 1,
},
}; };
}); });
@ -221,8 +224,11 @@ const BottomSheet = ({
keyboardBlurBehavior='restore' keyboardBlurBehavior='restore'
onClose={close} onClose={close}
bottomInset={insets.bottom} bottomInset={insets.bottom}
enableDynamicSizing={false}
> >
{renderContainerContent()} <BottomSheetView style={styles.view}>
{renderContainerContent()}
</BottomSheetView>
</BottomSheetM> </BottomSheetM>
); );
}; };

View file

@ -3,7 +3,7 @@
import {useHardwareKeyboardEvents} from '@mattermost/hardware-keyboard'; import {useHardwareKeyboardEvents} from '@mattermost/hardware-keyboard';
import {createBottomTabNavigator, type BottomTabBarProps} from '@react-navigation/bottom-tabs'; import {createBottomTabNavigator, type BottomTabBarProps} from '@react-navigation/bottom-tabs';
import {NavigationContainer} from '@react-navigation/native'; import {NavigationContainer, DefaultTheme} from '@react-navigation/native';
import React, {useCallback, useEffect, useMemo} from 'react'; import React, {useCallback, useEffect, useMemo} from 'react';
import {useIntl} from 'react-intl'; import {useIntl} from 'react-intl';
import {DeviceEventEmitter, Platform} from 'react-native'; import {DeviceEventEmitter, Platform} from 'react-native';
@ -139,8 +139,10 @@ export function HomeScreen(props: HomeProps) {
<> <>
<NavigationContainer <NavigationContainer
theme={{ theme={{
...DefaultTheme,
dark: false, dark: false,
colors: { colors: {
...DefaultTheme.colors,
primary: theme.centerChannelColor, primary: theme.centerChannelColor,
background: 'transparent', background: 'transparent',
card: theme.centerChannelBg, card: theme.centerChannelBg,
@ -151,7 +153,7 @@ export function HomeScreen(props: HomeProps) {
}} }}
> >
<Tab.Navigator <Tab.Navigator
screenOptions={{headerShown: false, unmountOnBlur: false, lazy: true}} screenOptions={{headerShown: false, freezeOnBlur: false, lazy: true}}
backBehavior='none' backBehavior='none'
tabBar={(tabProps: BottomTabBarProps) => ( tabBar={(tabProps: BottomTabBarProps) => (
<TabBar <TabBar
@ -161,29 +163,29 @@ export function HomeScreen(props: HomeProps) {
> >
<Tab.Screen <Tab.Screen
name={Screens.HOME} name={Screens.HOME}
options={{tabBarTestID: 'tab_bar.home.tab', unmountOnBlur: false, freezeOnBlur: true}} options={{tabBarButtonTestID: 'tab_bar.home.tab', freezeOnBlur: true}}
> >
{() => <ChannelList {...props}/>} {() => <ChannelList {...props}/>}
</Tab.Screen> </Tab.Screen>
<Tab.Screen <Tab.Screen
name={Screens.SEARCH} name={Screens.SEARCH}
component={Search} component={Search}
options={{tabBarTestID: 'tab_bar.search.tab', unmountOnBlur: false, freezeOnBlur: true, lazy: true}} options={{tabBarButtonTestID: 'tab_bar.search.tab', freezeOnBlur: true, lazy: true}}
/> />
<Tab.Screen <Tab.Screen
name={Screens.MENTIONS} name={Screens.MENTIONS}
component={RecentMentions} component={RecentMentions}
options={{tabBarTestID: 'tab_bar.mentions.tab', freezeOnBlur: true, lazy: true}} options={{tabBarButtonTestID: 'tab_bar.mentions.tab', freezeOnBlur: true, lazy: true}}
/> />
<Tab.Screen <Tab.Screen
name={Screens.SAVED_MESSAGES} name={Screens.SAVED_MESSAGES}
component={SavedMessages} component={SavedMessages}
options={{tabBarTestID: 'tab_bar.saved_messages.tab', freezeOnBlur: true, lazy: true}} options={{tabBarButtonTestID: 'tab_bar.saved_messages.tab', freezeOnBlur: true, lazy: true}}
/> />
<Tab.Screen <Tab.Screen
name={Screens.ACCOUNT} name={Screens.ACCOUNT}
component={Account} component={Account}
options={{tabBarTestID: 'tab_bar.account.tab', freezeOnBlur: true, lazy: true}} options={{tabBarButtonTestID: 'tab_bar.account.tab', freezeOnBlur: true, lazy: true}}
/> />
</Tab.Navigator> </Tab.Navigator>
</NavigationContainer> </NavigationContainer>

View file

@ -4,7 +4,7 @@
import {useIsFocused, useRoute} from '@react-navigation/native'; import {useIsFocused, useRoute} from '@react-navigation/native';
import React, {useCallback, useState, useEffect, useMemo} from 'react'; import React, {useCallback, useState, useEffect, useMemo} from 'react';
import {useIntl} from 'react-intl'; import {useIntl} from 'react-intl';
import {ActivityIndicator, DeviceEventEmitter, FlatList, type ListRenderItemInfo, StyleSheet, View} from 'react-native'; import {ActivityIndicator, DeviceEventEmitter, type ListRenderItemInfo, View} from 'react-native';
import Animated, {useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated'; import Animated, {useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated';
import {SafeAreaView, type Edge} from 'react-native-safe-area-context'; import {SafeAreaView, type Edge} from 'react-native-safe-area-context';
@ -19,13 +19,13 @@ import {useServerUrl} from '@context/server';
import {useTheme} from '@context/theme'; import {useTheme} from '@context/theme';
import {useCollapsibleHeader} from '@hooks/header'; import {useCollapsibleHeader} from '@hooks/header';
import {getDateForDateLine, selectOrderedPosts} from '@utils/post_list'; import {getDateForDateLine, selectOrderedPosts} from '@utils/post_list';
import {makeStyleSheetFromTheme} from '@utils/theme';
import EmptyState from './components/empty'; import EmptyState from './components/empty';
import type {PostListItem, PostListOtherItem, ViewableItemsChanged} from '@typings/components/post_list'; import type {PostListItem, PostListOtherItem, ViewableItemsChanged} from '@typings/components/post_list';
import type PostModel from '@typings/database/models/servers/post'; import type PostModel from '@typings/database/models/servers/post';
const AnimatedFlatList = Animated.createAnimatedComponent(FlatList);
const EDGES: Edge[] = ['bottom', 'left', 'right']; const EDGES: Edge[] = ['bottom', 'left', 'right'];
type Props = { type Props = {
@ -35,9 +35,10 @@ type Props = {
mentions: PostModel[]; mentions: PostModel[];
} }
const styles = StyleSheet.create({ const getStyleSheet = makeStyleSheetFromTheme((theme) => ({
flex: { flex: {
flex: 1, flex: 1,
backgroundColor: theme.centerChannelBg,
}, },
container: { container: {
flex: 1, flex: 1,
@ -47,7 +48,7 @@ const styles = StyleSheet.create({
flex: 1, flex: 1,
justifyContent: 'center', justifyContent: 'center',
}, },
}); }));
const RecentMentionsScreen = ({appsEnabled, customEmojiNames, mentions, currentTimezone}: Props) => { const RecentMentionsScreen = ({appsEnabled, customEmojiNames, mentions, currentTimezone}: Props) => {
const theme = useTheme(); const theme = useTheme();
@ -57,6 +58,7 @@ const RecentMentionsScreen = ({appsEnabled, customEmojiNames, mentions, currentT
const [refreshing, setRefreshing] = useState(false); const [refreshing, setRefreshing] = useState(false);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const serverUrl = useServerUrl(); const serverUrl = useServerUrl();
const styles = getStyleSheet(theme);
const params = route.params as {direction: string}; const params = route.params as {direction: string};
const toLeft = params.direction === 'left'; const toLeft = params.direction === 'left';
@ -85,7 +87,7 @@ const RecentMentionsScreen = ({appsEnabled, customEmojiNames, mentions, currentT
} }
}, [serverUrl, isFocused]); }, [serverUrl, isFocused]);
const {scrollPaddingTop, scrollRef, scrollValue, onScroll, headerHeight} = useCollapsibleHeader<FlatList<string>>(true, onSnap); const {scrollPaddingTop, scrollRef, scrollValue, onScroll, headerHeight} = useCollapsibleHeader<Animated.FlatList<string>>(true, onSnap);
const paddingTop = useMemo(() => ({paddingTop: scrollPaddingTop, flexGrow: 1}), [scrollPaddingTop]); const paddingTop = useMemo(() => ({paddingTop: scrollPaddingTop, flexGrow: 1}), [scrollPaddingTop]);
const posts = useMemo(() => selectOrderedPosts(mentions, 0, false, '', '', false, currentTimezone, false).reverse(), [mentions]); const posts = useMemo(() => selectOrderedPosts(mentions, 0, false, '', '', false, currentTimezone, false).reverse(), [mentions]);
@ -181,7 +183,7 @@ const RecentMentionsScreen = ({appsEnabled, customEmojiNames, mentions, currentT
<Animated.View style={top}> <Animated.View style={top}>
<RoundedHeaderContext/> <RoundedHeaderContext/>
</Animated.View> </Animated.View>
<AnimatedFlatList <Animated.FlatList
ref={scrollRef} ref={scrollRef}
contentContainerStyle={paddingTop} contentContainerStyle={paddingTop}
ListEmptyComponent={renderEmptyList()} ListEmptyComponent={renderEmptyList()}

View file

@ -4,7 +4,7 @@
import {useIsFocused, useRoute} from '@react-navigation/native'; import {useIsFocused, useRoute} from '@react-navigation/native';
import React, {useCallback, useEffect, useMemo, useState} from 'react'; import React, {useCallback, useEffect, useMemo, useState} from 'react';
import {useIntl} from 'react-intl'; import {useIntl} from 'react-intl';
import {DeviceEventEmitter, FlatList, type ListRenderItemInfo, StyleSheet, View} from 'react-native'; import {DeviceEventEmitter, type ListRenderItemInfo, View} from 'react-native';
import Animated, {useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated'; import Animated, {useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated';
import {type Edge, SafeAreaView} from 'react-native-safe-area-context'; import {type Edge, SafeAreaView} from 'react-native-safe-area-context';
@ -20,6 +20,7 @@ import {useServerUrl} from '@context/server';
import {useTheme} from '@context/theme'; import {useTheme} from '@context/theme';
import {useCollapsibleHeader} from '@hooks/header'; import {useCollapsibleHeader} from '@hooks/header';
import {getDateForDateLine, selectOrderedPosts} from '@utils/post_list'; import {getDateForDateLine, selectOrderedPosts} from '@utils/post_list';
import {makeStyleSheetFromTheme} from '@utils/theme';
import EmptyState from './components/empty'; import EmptyState from './components/empty';
@ -33,12 +34,12 @@ type Props = {
posts: PostModel[]; posts: PostModel[];
} }
const AnimatedFlatList = Animated.createAnimatedComponent(FlatList);
const edges: Edge[] = ['bottom', 'left', 'right']; const edges: Edge[] = ['bottom', 'left', 'right'];
const styles = StyleSheet.create({ const getStyleSheet = makeStyleSheetFromTheme((theme) => ({
flex: { flex: {
flex: 1, flex: 1,
backgroundColor: theme.centerChannelBg,
}, },
container: { container: {
flex: 1, flex: 1,
@ -48,7 +49,7 @@ const styles = StyleSheet.create({
flex: 1, flex: 1,
justifyContent: 'center', justifyContent: 'center',
}, },
}); }));
function SavedMessages({appsEnabled, posts, currentTimezone, customEmojiNames}: Props) { function SavedMessages({appsEnabled, posts, currentTimezone, customEmojiNames}: Props) {
const intl = useIntl(); const intl = useIntl();
@ -58,6 +59,7 @@ function SavedMessages({appsEnabled, posts, currentTimezone, customEmojiNames}:
const serverUrl = useServerUrl(); const serverUrl = useServerUrl();
const route = useRoute(); const route = useRoute();
const isFocused = useIsFocused(); const isFocused = useIsFocused();
const styles = getStyleSheet(theme);
const params = route.params as {direction: string}; const params = route.params as {direction: string};
const toLeft = params.direction === 'left'; const toLeft = params.direction === 'left';
@ -86,7 +88,7 @@ function SavedMessages({appsEnabled, posts, currentTimezone, customEmojiNames}:
} }
}, [serverUrl, isFocused]); }, [serverUrl, isFocused]);
const {scrollPaddingTop, scrollRef, scrollValue, onScroll, headerHeight} = useCollapsibleHeader<FlatList<string>>(true, onSnap); const {scrollPaddingTop, scrollRef, scrollValue, onScroll, headerHeight} = useCollapsibleHeader<Animated.FlatList<string>>(true, onSnap);
const paddingTop = useMemo(() => ({paddingTop: scrollPaddingTop, flexGrow: 1}), [scrollPaddingTop]); const paddingTop = useMemo(() => ({paddingTop: scrollPaddingTop, flexGrow: 1}), [scrollPaddingTop]);
const data = useMemo(() => selectOrderedPosts(posts, 0, false, '', '', false, currentTimezone, false).reverse(), [posts]); const data = useMemo(() => selectOrderedPosts(posts, 0, false, '', '', false, currentTimezone, false).reverse(), [posts]);
@ -183,7 +185,7 @@ function SavedMessages({appsEnabled, posts, currentTimezone, customEmojiNames}:
<Animated.View style={top}> <Animated.View style={top}>
<RoundedHeaderContext/> <RoundedHeaderContext/>
</Animated.View> </Animated.View>
<AnimatedFlatList <Animated.FlatList
ref={scrollRef} ref={scrollRef}
contentContainerStyle={paddingTop} contentContainerStyle={paddingTop}
ListEmptyComponent={emptyList} ListEmptyComponent={emptyList}

View file

@ -5,7 +5,7 @@ import {useHardwareKeyboardEvents} from '@mattermost/hardware-keyboard';
import {useIsFocused, useNavigation} from '@react-navigation/native'; import {useIsFocused, useNavigation} from '@react-navigation/native';
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
import {useIntl} from 'react-intl'; import {useIntl} from 'react-intl';
import {FlatList, type LayoutChangeEvent, Platform, StyleSheet, type ViewStyle, KeyboardAvoidingView, Keyboard} from 'react-native'; import {FlatList, type LayoutChangeEvent, Platform, type ViewStyle, KeyboardAvoidingView, Keyboard} from 'react-native';
import Animated, {useAnimatedStyle, useDerivedValue, withTiming, type AnimatedStyle} from 'react-native-reanimated'; import Animated, {useAnimatedStyle, useDerivedValue, withTiming, type AnimatedStyle} from 'react-native-reanimated';
import {type Edge, SafeAreaView, useSafeAreaInsets} from 'react-native-safe-area-context'; import {type Edge, SafeAreaView, useSafeAreaInsets} from 'react-native-safe-area-context';
@ -27,6 +27,7 @@ import {useCollapsibleHeader} from '@hooks/header';
import NavigationStore from '@store/navigation_store'; import NavigationStore from '@store/navigation_store';
import {type FileFilter, FileFilters, filterFileExtensions} from '@utils/file'; import {type FileFilter, FileFilters, filterFileExtensions} from '@utils/file';
import {TabTypes, type TabType} from '@utils/search'; import {TabTypes, type TabType} from '@utils/search';
import {makeStyleSheetFromTheme} from '@utils/theme';
import Initial from './initial'; import Initial from './initial';
import Results from './results'; import Results from './results';
@ -52,9 +53,10 @@ type Props = {
teams: TeamModel[]; teams: TeamModel[];
} }
const styles = StyleSheet.create({ const getStyleSheet = makeStyleSheetFromTheme((theme) => ({
flex: { flex: {
flex: 1, flex: 1,
backgroundColor: theme.centerChannelBg,
}, },
loading: { loading: {
flex: 1, flex: 1,
@ -63,7 +65,7 @@ const styles = StyleSheet.create({
autocompleteContainer: { autocompleteContainer: {
zIndex: 11, zIndex: 11,
}, },
}); }));
const getSearchParams = (terms: string, filterValue?: FileFilter) => { const getSearchParams = (terms: string, filterValue?: FileFilter) => {
const fileExtensions = filterFileExtensions(filterValue); const fileExtensions = filterFileExtensions(filterValue);
@ -84,6 +86,7 @@ const SearchScreen = ({teamId, teams}: Props) => {
const theme = useTheme(); const theme = useTheme();
const insets = useSafeAreaInsets(); const insets = useSafeAreaInsets();
const keyboardHeight = useKeyboardHeight(); const keyboardHeight = useKeyboardHeight();
const styles = getStyleSheet(theme);
const stateIndex = nav.getState()?.index; const stateIndex = nav.getState()?.index;
const serverUrl = useServerUrl(); const serverUrl = useServerUrl();
@ -114,17 +117,9 @@ const SearchScreen = ({teamId, teams}: Props) => {
setSearchTeamId(teamId); setSearchTeamId(teamId);
}, [teamId]); }, [teamId]);
useEffect(() => { const onSnap = useCallback((offset: number, animated = true) => {
if (searchTerm) {
resetToInitial();
setSearchValue(searchTerm);
handleSearch(searchTeamId, searchTerm);
}
}, [searchTerm]);
const onSnap = (offset: number, animated = true) => {
scrollRef.current?.scrollToOffset({offset, animated}); scrollRef.current?.scrollToOffset({offset, animated});
}; }, []);
const onSnapWithTimeout = useCallback((offset: number, animated = true) => { const onSnapWithTimeout = useCallback((offset: number, animated = true) => {
// wait until the keyboard is completely dismissed before scrolling to where the header should be // wait until the keyboard is completely dismissed before scrolling to where the header should be
@ -203,7 +198,7 @@ const SearchScreen = ({teamId, teams}: Props) => {
setFileChannelIds(channels?.length ? channels : emptyChannelIds); setFileChannelIds(channels?.length ? channels : emptyChannelIds);
handleLoading(false); handleLoading(false);
setShowResults(true); setShowResults(true);
}, [filter, handleClearSearch, handleLoading]); }, [filter, handleClearSearch, handleLoading, hideHeader, serverUrl]);
const onBlur = useCallback(() => { const onBlur = useCallback(() => {
setSearchIsFocused(false); setSearchIsFocused(false);
@ -233,7 +228,7 @@ const SearchScreen = ({teamId, teams}: Props) => {
setFileInfos(files?.length ? files : emptyFileResults); setFileInfos(files?.length ? files : emptyFileResults);
setFileChannelIds(channels?.length ? channels : emptyChannelIds); setFileChannelIds(channels?.length ? channels : emptyChannelIds);
setResultsLoading(false); setResultsLoading(false);
}, [lastSearchedValue, searchTeamId]); }, [lastSearchedValue, searchTeamId, serverUrl]);
const handleResultsTeamChange = useCallback((newTeamId: string) => { const handleResultsTeamChange = useCallback((newTeamId: string) => {
setSearchTeamId(newTeamId); setSearchTeamId(newTeamId);
@ -267,8 +262,11 @@ const SearchScreen = ({teamId, teams}: Props) => {
teams={teams} teams={teams}
/> />
); );
}, [handleRecentSearch, handleTextChange, loading, }, [
scrollPaddingTop, searchTeamId, searchValue, theme]); handleModifierTextChange, handleRecentSearch,
loading, scrollEnabled, scrollPaddingTop, searchTeamId,
searchValue, styles.loading, teams, theme.buttonBg,
]);
const animated = useAnimatedStyle(() => { const animated = useAnimatedStyle(() => {
if (isFocused) { if (isFocused) {
@ -320,6 +318,14 @@ const SearchScreen = ({teamId, teams}: Props) => {
} }
}, [unlock, onSnapWithTimeout]); }, [unlock, onSnapWithTimeout]);
useEffect(() => {
if (searchTerm) {
resetToInitial();
setSearchValue(searchTerm);
handleSearch(searchTeamId, searchTerm);
}
}, [handleSearch, resetToInitial, searchTeamId, searchTerm]);
useDidUpdate(() => { useDidUpdate(() => {
if (isFocused) { if (isFocused) {
setTimeout(() => { setTimeout(() => {

View file

@ -200,7 +200,7 @@ function TabBar({state, descriptors, navigation, theme}: BottomTabBarProps & {th
accessibilityRole='button' accessibilityRole='button'
accessibilityState={isFocused ? {selected: true} : {}} accessibilityState={isFocused ? {selected: true} : {}}
accessibilityLabel={options.tabBarAccessibilityLabel} accessibilityLabel={options.tabBarAccessibilityLabel}
testID={options.tabBarTestID} testID={options.tabBarButtonTestID}
onPress={onPress} onPress={onPress}
onLongPress={onLongPress} onLongPress={onLongPress}
style={style.item} style={style.item}

View file

@ -167,7 +167,7 @@ export const bottomSheetModalOptions = (theme: Theme, closeButtonId?: string): O
default: OptionsModalPresentationStyle.overCurrentContext, default: OptionsModalPresentationStyle.overCurrentContext,
}), }),
statusBar: { statusBar: {
backgroundColor: null, backgroundColor: theme.sidebarBg,
drawBehind: true, drawBehind: true,
translucent: true, translucent: true,
}, },
@ -468,6 +468,7 @@ export function goToScreen(name: AvailableScreens, title: string, passProps = {}
}, },
statusBar: { statusBar: {
style: isDark ? 'light' : 'dark', style: isDark ? 'light' : 'dark',
backgroundColor: theme.sidebarBg,
}, },
topBar: { topBar: {
animate: true, animate: true,
@ -579,6 +580,7 @@ export function showModal(name: AvailableScreens, title: string, passProps = {},
}, },
statusBar: { statusBar: {
visible: true, visible: true,
backgroundColor: theme.sidebarBg,
}, },
topBar: { topBar: {
animate: true, animate: true,

View file

@ -1,9 +1,9 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import React, {useEffect, useMemo, useRef, useState} from 'react'; import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
import {useIntl} from 'react-intl'; import {useIntl} from 'react-intl';
import {DeviceEventEmitter, Text, TouchableOpacity, useWindowDimensions, type ViewStyle} from 'react-native'; import {DeviceEventEmitter, Text, TouchableOpacity, useWindowDimensions, type StyleProp, type ViewStyle} from 'react-native';
import {Gesture, GestureDetector, GestureHandlerRootView} from 'react-native-gesture-handler'; import {Gesture, GestureDetector, GestureHandlerRootView} from 'react-native-gesture-handler';
import {type ComponentEvent, Navigation} from 'react-native-navigation'; import {type ComponentEvent, Navigation} from 'react-native-navigation';
import Animated, { import Animated, {
@ -141,8 +141,8 @@ const SnackBar = ({
return [ return [
styles.mobile, styles.mobile,
isTablet && tabletStyle, isTablet && tabletStyle,
] as ViewStyle; ] as StyleProp<ViewStyle>;
}, [theme, barType]); }, [windowWidth, styles.mobile, isTablet, sourceScreen]);
const toastStyle = useMemo(() => { const toastStyle = useMemo(() => {
let backgroundColor: string; let backgroundColor: string;
@ -158,7 +158,7 @@ const SnackBar = ({
break; break;
} }
return [styles.toast, {backgroundColor}]; return [styles.toast, {backgroundColor}];
}, [theme, config?.type]); }, [config?.type, styles.toast, theme.onlineIndicator, theme.errorTextColor, theme.centerChannelColor]);
const animatedMotion = useAnimatedStyle(() => { const animatedMotion = useAnimatedStyle(() => {
return { return {
@ -197,10 +197,10 @@ const SnackBar = ({
runOnJS(hideSnackBar)(); runOnJS(hideSnackBar)();
}); });
const animateHiding = (forceHiding: boolean) => { const animateHiding = useCallback((forceHiding: boolean) => {
const duration = forceHiding ? 0 : 200; const duration = forceHiding ? 0 : 200;
offset.value = withTiming(200, {duration}, () => runOnJS(hideSnackBar)()); offset.value = withTiming(200, {duration}, () => runOnJS(hideSnackBar)());
}; }, [offset]);
const onUndoPressHandler = () => { const onUndoPressHandler = () => {
userHasUndo.current = true; userHasUndo.current = true;
@ -220,7 +220,7 @@ const SnackBar = ({
stopTimers(); stopTimers();
mounted.current = false; mounted.current = false;
}; };
}, [isPanned.value]); }, [animateHiding, isPanned]);
// This effect dismisses the Navigation Overlay after we have hidden the snack bar // This effect dismisses the Navigation Overlay after we have hidden the snack bar
useEffect(() => { useEffect(() => {
@ -230,7 +230,7 @@ const SnackBar = ({
} }
dismissOverlay(componentId); dismissOverlay(componentId);
} }
}, [showSnackBar, onAction]); }, [showSnackBar, onAction, componentId]);
// This effect checks if we are navigating away and if so, it dismisses the snack bar // This effect checks if we are navigating away and if so, it dismisses the snack bar
useEffect(() => { useEffect(() => {

View file

@ -78,7 +78,7 @@ export const getErrorMessage = (error: unknown, intl?: IntlShape) => {
return error; return error;
} }
if (isErrorWithIntl(error)) { if (isErrorWithIntl(error)) {
return intl ? intl.formatMessage({id: error.intl.id, defaultMessage: error.intl.defaultMessage}, error.intl.values) : error.intl.defaultMessage; return intl ? intl.formatMessage({id: error.intl.id, defaultMessage: error.intl.defaultMessage}, error.intl.values) : error.intl.defaultMessage!;
} }
if (isErrorWithMessage(error)) { if (isErrorWithMessage(error)) {

View file

@ -10,10 +10,6 @@ jest.mock('expo-application', () => ({
applicationId: 'com.example.rnbeta', applicationId: 'com.example.rnbeta',
})); }));
jest.mock('expo-crypto', () => ({
randomUUID: jest.fn(() => '12345678-1234-1234-1234-1234567890ab'),
}));
jest.mock('react-intl', () => ({ jest.mock('react-intl', () => ({
createIntl: jest.fn((config) => config), createIntl: jest.fn((config) => config),
})); }));

View file

@ -2,7 +2,7 @@
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
// Import necessary dependencies and functions // Import necessary dependencies and functions
import * as Sentry from '@sentry/react-native'; // Importing Sentry as module mock import Sentry from '@sentry/react-native'; // Importing Sentry as module mock
import {Platform} from 'react-native'; import {Platform} from 'react-native';
import Config from '@assets/config.json'; import Config from '@assets/config.json';
@ -21,7 +21,9 @@ jest.mock('@sentry/react-native', () => ({
addBreadcrumb: jest.fn(), addBreadcrumb: jest.fn(),
setContext: jest.fn(), setContext: jest.fn(),
ReactNativeTracing: jest.fn(), ReactNativeTracing: jest.fn(),
ReactNativeNavigationInstrumentation: jest.fn(), reactNativeNavigationIntegration: jest.fn().mockImplementation(() => ({
name: 'reactNativeNavigation',
})),
})); }));
jest.mock('@assets/config.json', () => ({ jest.mock('@assets/config.json', () => ({
@ -107,7 +109,7 @@ describe('initializeSentry function', () => {
attachStacktrace: true, // Adjust based on your actual logic attachStacktrace: true, // Adjust based on your actual logic
enableCaptureFailedRequests: false, enableCaptureFailedRequests: false,
integrations: [ integrations: [
expect.any(Sentry.ReactNativeTracing), {name: 'reactNativeNavigation'},
], ],
beforeSend: expect.any(Function), beforeSend: expect.any(Function),
}); });

View file

@ -15,7 +15,7 @@ import {isBetaApp} from '@utils/general';
import {logError, logWarning} from './log'; import {logError, logWarning} from './log';
import type {Database} from '@nozbe/watermelondb'; import type {Database} from '@nozbe/watermelondb';
import type {Breadcrumb, Event} from '@sentry/types'; import type {Breadcrumb, ErrorEvent} from '@sentry/types';
export const BREADCRUMB_UNCAUGHT_APP_ERROR = 'uncaught-app-error'; export const BREADCRUMB_UNCAUGHT_APP_ERROR = 'uncaught-app-error';
export const BREADCRUMB_UNCAUGHT_NON_ERROR = 'uncaught-non-error'; export const BREADCRUMB_UNCAUGHT_NON_ERROR = 'uncaught-non-error';
@ -41,7 +41,7 @@ export function initializeSentry() {
environment: isBetaApp ? 'beta' : 'production', environment: isBetaApp ? 'beta' : 'production',
tracesSampleRate: isBetaApp ? 1.0 : 0.2, tracesSampleRate: isBetaApp ? 1.0 : 0.2,
sampleRate: isBetaApp ? 1.0 : 0.2, sampleRate: isBetaApp ? 1.0 : 0.2,
attachStacktrace: isBetaApp, // For Beta, stack traces are automatically attached to all messages logged attachStacktrace: Boolean(isBetaApp), // For Beta, stack traces are automatically attached to all messages logged
}; };
const eventFilter = Array.isArray(Config.SentryOptions?.severityLevelFilter) ? Config.SentryOptions.severityLevelFilter : []; const eventFilter = Array.isArray(Config.SentryOptions?.severityLevelFilter) ? Config.SentryOptions.severityLevelFilter : [];
@ -55,16 +55,9 @@ export function initializeSentry() {
...sentryOptions, ...sentryOptions,
enableCaptureFailedRequests: false, enableCaptureFailedRequests: false,
integrations: [ integrations: [
new Sentry.ReactNativeTracing({ Sentry.reactNativeNavigationIntegration({navigation: Navigation}),
// Pass instrumentation to be used as `routingInstrumentation`
routingInstrumentation: new Sentry.ReactNativeNavigationInstrumentation(
Navigation,
{enableTabsInstrumentation: false},
),
}),
], ],
beforeSend: (event: Event) => { beforeSend: (event: ErrorEvent) => {
if (isBetaApp || (event?.level && eventFilter.includes(event.level))) { if (isBetaApp || (event?.level && eventFilter.includes(event.level))) {
return event; return event;
} }

View file

@ -65,6 +65,7 @@ class LoginScreen {
await this.usernameInput.replaceText(user.newUser.email); await this.usernameInput.replaceText(user.newUser.email);
await this.passwordInput.tap(); await this.passwordInput.tap();
await this.passwordInput.replaceText(user.newUser.password); await this.passwordInput.replaceText(user.newUser.password);
await element(by.text(/^Log In to Your Account*$/)).tap();
await this.signinButton.tap(); await this.signinButton.tap();
await wait(timeouts.FOUR_SEC); await wait(timeouts.FOUR_SEC);

5518
detox/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -4,25 +4,25 @@
"repository": "git@github.com:mattermost/mattermost-mobile.git", "repository": "git@github.com:mattermost/mattermost-mobile.git",
"author": "Mattermost, Inc.", "author": "Mattermost, Inc.",
"devDependencies": { "devDependencies": {
"@aws-sdk/client-s3": "3.650.0", "@aws-sdk/client-s3": "3.712.0",
"@aws-sdk/lib-storage": "3.650.0", "@aws-sdk/lib-storage": "3.712.0",
"@babel/plugin-proposal-class-properties": "7.18.6", "@babel/plugin-proposal-class-properties": "7.18.6",
"@babel/plugin-transform-modules-commonjs": "7.24.8", "@babel/plugin-transform-modules-commonjs": "7.26.3",
"@babel/plugin-transform-runtime": "7.25.4", "@babel/plugin-transform-runtime": "7.25.9",
"@babel/preset-env": "7.25.4", "@babel/preset-env": "7.26.0",
"@jest/test-sequencer": "29.7.0", "@jest/test-sequencer": "29.7.0",
"@types/jest": "29.5.12", "@types/jest": "29.5.14",
"@types/tough-cookie": "4.0.5", "@types/tough-cookie": "4.0.5",
"@types/uuid": "10.0.0", "@types/uuid": "10.0.0",
"async": "3.2.6", "async": "3.2.6",
"axios": "1.7.7", "axios": "1.7.9",
"axios-cookiejar-support": "5.0.2", "axios-cookiejar-support": "5.0.4",
"babel-jest": "29.7.0", "babel-jest": "29.7.0",
"babel-plugin-module-resolver": "5.0.2", "babel-plugin-module-resolver": "5.0.2",
"client-oauth2": "4.3.3", "client-oauth2": "4.3.3",
"deepmerge": "4.3.1", "deepmerge": "4.3.1",
"detox": "20.26.2", "detox": "20.28.0",
"form-data": "4.0.0", "form-data": "4.0.1",
"jest": "29.7.0", "jest": "29.7.0",
"jest-circus": "29.7.0", "jest-circus": "29.7.0",
"jest-cli": "29.7.0", "jest-cli": "29.7.0",
@ -30,15 +30,15 @@
"jest-junit": "16.0.0", "jest-junit": "16.0.0",
"jest-stare": "2.5.2", "jest-stare": "2.5.2",
"junit-report-merger": "7.0.0", "junit-report-merger": "7.0.0",
"moment-timezone": "0.5.45", "moment-timezone": "0.5.46",
"recursive-readdir": "2.2.3", "recursive-readdir": "2.2.3",
"sanitize-filename": "1.6.3", "sanitize-filename": "1.6.3",
"shelljs": "0.8.5", "shelljs": "0.8.5",
"tough-cookie": "5.0.0", "tough-cookie": "5.0.0",
"ts-jest": "29.2.5", "ts-jest": "29.2.5",
"tslib": "2.7.0", "tslib": "2.8.1",
"typescript": "5.6.2", "typescript": "5.7.2",
"uuid": "10.0.0", "uuid": "11.0.3",
"xml2js": "0.6.2" "xml2js": "0.6.2"
}, },
"scripts": { "scripts": {

View file

@ -4,8 +4,8 @@
/* eslint-disable no-process-env */ /* eslint-disable no-process-env */
/* eslint-disable no-console */ /* eslint-disable no-console */
const fs = require('fs'); const fs = require('fs');
const deviceName = process.env.DEVICE_NAME || 'iPhone 15 Pro'; const deviceName = process.env.DEVICE_NAME || 'iPhone 14';
const deviceOSVersion = process.env.DEVICE_OS_VERSION || 'iOS 17.4'; const deviceOSVersion = process.env.DEVICE_OS_VERSION || 'iOS 17.2';
const detoxConfigTemplate = fs.readFileSync('../.detoxrc.json', 'utf8'); const detoxConfigTemplate = fs.readFileSync('../.detoxrc.json', 'utf8');
const detoxConfig = detoxConfigTemplate.replace('__DEVICE_NAME__', deviceName).replace('__DEVICE_OS_VERSION__', deviceOSVersion); const detoxConfig = detoxConfigTemplate.replace('__DEVICE_NAME__', deviceName).replace('__DEVICE_OS_VERSION__', deviceOSVersion);

View file

@ -15,8 +15,8 @@ func initSentryAppExt(){
if(SENTRY_ENABLED=="true"){ if(SENTRY_ENABLED=="true"){
SentrySDK.start { options in SentrySDK.start { options in
options.dsn = SENTRY_DSN options.dsn = SENTRY_DSN
options.enableAppHangTracking = true options.enableAppHangTracking = false
options.enableCaptureFailedRequests = false options.enableCaptureFailedRequests = true
} }
} }
} }

View file

@ -1393,6 +1393,9 @@
"${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/ExpoConstants_privacy.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/ExpoConstants_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/ExpoDevice/ExpoDevice_privacy.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/ExpoDevice/ExpoDevice_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/ExpoFileSystem/ExpoFileSystem_privacy.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/ExpoFileSystem/ExpoFileSystem_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/RCT-Folly/RCT-Folly_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/RNPermissions/RNPermissionsPrivacyInfo.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/RNSVG/RNSVGFilters.bundle",
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/AntDesign.ttf", "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/AntDesign.ttf",
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Entypo.ttf", "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Entypo.ttf",
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/EvilIcons.ttf", "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/EvilIcons.ttf",
@ -1412,12 +1415,16 @@
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Octicons.ttf", "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Octicons.ttf",
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/SimpleLineIcons.ttf", "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/SimpleLineIcons.ttf",
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Zocial.ttf", "${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Zocial.ttf",
"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/RCTI18nStrings.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/React-Core_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/React-cxxreact/React-cxxreact_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage/SDWebImage.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage/SDWebImage.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/Sentry/Sentry.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/Sentry/Sentry.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/Starscream/Starscream_Privacy.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/Starscream/Starscream_Privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/SwiftyJSON/SwiftyJSON.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyJSON/SwiftyJSON.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/boost/boost_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/glog/glog_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/react-native-cameraroll/RNCameraRollPrivacyInfo.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/react-native-cameraroll/RNCameraRollPrivacyInfo.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/react-native-image-picker/RNImagePickerPrivacyInfo.bundle",
); );
name = "[CP] Copy Pods Resources"; name = "[CP] Copy Pods Resources";
outputPaths = ( outputPaths = (
@ -1428,6 +1435,9 @@
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoConstants_privacy.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoConstants_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoDevice_privacy.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoDevice_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoFileSystem_privacy.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoFileSystem_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCT-Folly_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RNPermissionsPrivacyInfo.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RNSVGFilters.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AntDesign.ttf", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AntDesign.ttf",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Entypo.ttf", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Entypo.ttf",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EvilIcons.ttf", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EvilIcons.ttf",
@ -1447,12 +1457,16 @@
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Octicons.ttf", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Octicons.ttf",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/SimpleLineIcons.ttf", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/SimpleLineIcons.ttf",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Zocial.ttf", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Zocial.ttf",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCTI18nStrings.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-Core_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-cxxreact_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/SDWebImage.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/SDWebImage.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Sentry.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Sentry.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Starscream_Privacy.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Starscream_Privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/SwiftyJSON.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/SwiftyJSON.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/boost_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/glog_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RNCameraRollPrivacyInfo.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RNCameraRollPrivacyInfo.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RNImagePickerPrivacyInfo.bundle",
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
@ -1989,7 +2003,7 @@
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
HEADER_SEARCH_PATHS = "$(inherited)"; HEADER_SEARCH_PATHS = "$(inherited)";
INFOPLIST_FILE = Mattermost/Info.plist; INFOPLIST_FILE = Mattermost/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.4; IPHONEOS_DEPLOYMENT_TARGET = 15.1;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -2031,7 +2045,7 @@
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
HEADER_SEARCH_PATHS = "$(inherited)"; HEADER_SEARCH_PATHS = "$(inherited)";
INFOPLIST_FILE = Mattermost/Info.plist; INFOPLIST_FILE = Mattermost/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.4; IPHONEOS_DEPLOYMENT_TARGET = 15.1;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -2079,7 +2093,7 @@
DEVELOPMENT_TEAM = UQ8HT4Q2XM; DEVELOPMENT_TEAM = UQ8HT4Q2XM;
GCC_C_LANGUAGE_STANDARD = gnu11; GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = NotificationService/Info.plist; INFOPLIST_FILE = NotificationService/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.4; IPHONEOS_DEPLOYMENT_TARGET = 15.1;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -2128,7 +2142,7 @@
DEVELOPMENT_TEAM = UQ8HT4Q2XM; DEVELOPMENT_TEAM = UQ8HT4Q2XM;
GCC_C_LANGUAGE_STANDARD = gnu11; GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = NotificationService/Info.plist; INFOPLIST_FILE = NotificationService/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.4; IPHONEOS_DEPLOYMENT_TARGET = 15.1;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -2175,7 +2189,7 @@
GCC_C_LANGUAGE_STANDARD = gnu11; GCC_C_LANGUAGE_STANDARD = gnu11;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = MattermostShare/Info.plist; INFOPLIST_FILE = MattermostShare/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 15.0; IPHONEOS_DEPLOYMENT_TARGET = 15.1;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -2225,7 +2239,7 @@
GCC_C_LANGUAGE_STANDARD = gnu11; GCC_C_LANGUAGE_STANDARD = gnu11;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = MattermostShare/Info.plist; INFOPLIST_FILE = MattermostShare/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 15.0; IPHONEOS_DEPLOYMENT_TARGET = 15.1;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -2307,6 +2321,7 @@
OTHER_LDFLAGS = "$(inherited)"; OTHER_LDFLAGS = "$(inherited)";
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos; SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG";
USE_HERMES = true; USE_HERMES = true;
}; };
name = Debug; name = Debug;
@ -2421,7 +2436,7 @@
repositoryURL = "https://github.com/getsentry/sentry-cocoa.git"; repositoryURL = "https://github.com/getsentry/sentry-cocoa.git";
requirement = { requirement = {
kind = exactVersion; kind = exactVersion;
version = 8.36.0; version = 8.41.0;
}; };
}; };
7FD4822A2864D73300A5B18B /* XCRemoteSwiftPackageReference "OpenGraph" */ = { 7FD4822A2864D73300A5B18B /* XCRemoteSwiftPackageReference "OpenGraph" */ = {

View file

@ -60,8 +60,8 @@
"repositoryURL": "https://github.com/getsentry/sentry-cocoa.git", "repositoryURL": "https://github.com/getsentry/sentry-cocoa.git",
"state": { "state": {
"branch": null, "branch": null,
"revision": "5575af93efb776414f243e93d6af9f6258dc539a", "revision": "56bfb7e723c76614be4c0861ee820ccbaed14c6d",
"version": "8.36.0" "version": "8.41.0"
} }
}, },
{ {

View file

@ -37,7 +37,7 @@ NSString* const NOTIFICATION_TEST_ACTION = @"test";
NSArray<NSString*> *servers = [keychain getAllServersForInternetPasswords]; NSArray<NSString*> *servers = [keychain getAllServersForInternetPasswords];
NSLog(@"Servers %@", servers); NSLog(@"Servers %@", servers);
for (NSString *server in servers) { for (NSString *server in servers) {
[keychain deleteCredentialsForServer:server]; [keychain deleteCredentialsForServer:server withOptions:nil];
} }
[[NSUserDefaults standardUserDefaults] setValue:@YES forKey:@"FirstRun"]; [[NSUserDefaults standardUserDefaults] setValue:@YES forKey:@"FirstRun"];

View file

@ -12,7 +12,7 @@ require File.join(File.dirname(`node --print "require.resolve('expo/package.json
node_require('react-native/scripts/react_native_pods.rb') node_require('react-native/scripts/react_native_pods.rb')
node_require('react-native-permissions/scripts/setup.rb') node_require('react-native-permissions/scripts/setup.rb')
platform :ios, min_ios_version_supported platform :ios, '15.1' #min_ios_version_supported
prepare_react_native_project! prepare_react_native_project!
linkage = ENV['USE_FRAMEWORKS'] linkage = ENV['USE_FRAMEWORKS']
@ -54,7 +54,7 @@ target 'Mattermost' do
# installer.pods_project.targets.each do |target| # installer.pods_project.targets.each do |target|
# target.build_configurations.each do |config| # target.build_configurations.each do |config|
# config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.4' # config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.1'
# end # end
# end # end
end end

File diff suppressed because it is too large Load diff

51700
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -11,34 +11,37 @@
"npm": "^9 || ^10" "npm": "^9 || ^10"
}, },
"dependencies": { "dependencies": {
"@formatjs/intl-datetimeformat": "6.12.5", "@formatjs/intl-datetimeformat": "6.17.1",
"@formatjs/intl-getcanonicallocales": "2.3.0", "@formatjs/intl-getcanonicallocales": "2.5.4",
"@formatjs/intl-listformat": "7.5.7", "@formatjs/intl-listformat": "7.7.8",
"@formatjs/intl-locale": "4.0.0", "@formatjs/intl-locale": "4.2.8",
"@formatjs/intl-numberformat": "8.10.3", "@formatjs/intl-numberformat": "8.15.1",
"@formatjs/intl-pluralrules": "5.2.14", "@formatjs/intl-pluralrules": "5.4.1",
"@gorhom/bottom-sheet": "4.6.4", "@gorhom/bottom-sheet": "5.0.6",
"@mattermost/calls": "github:mattermost/calls-common#030ff7c0a37ee9b0ccc5fae0b2ea9c0e1c08473f", "@mattermost/calls": "github:mattermost/calls-common#030ff7c0a37ee9b0ccc5fae0b2ea9c0e1c08473f",
"@mattermost/compass-icons": "0.1.48", "@mattermost/compass-icons": "0.1.48",
"@mattermost/hardware-keyboard": "file:./libraries/@mattermost/hardware-keyboard", "@mattermost/hardware-keyboard": "file:./libraries/@mattermost/hardware-keyboard",
"@mattermost/react-native-emm": "1.5.0", "@mattermost/react-native-emm": "1.5.1",
"@mattermost/react-native-network-client": "github:mattermost/react-native-network-client#ad7b88412f41c5a1024420a4f4c7461883cd0e63", "@mattermost/react-native-network-client": "1.8.0",
"@mattermost/react-native-paste-input": "0.8.0", "@mattermost/react-native-paste-input": "0.8.1",
"@mattermost/react-native-turbo-log": "github:mattermost/react-native-turbo-log#d8ddf5e7974546aff3e83b2c563907eb609ac5f4", "@mattermost/react-native-turbo-log": "0.5.0",
"@mattermost/rnshare": "file:./libraries/@mattermost/rnshare", "@mattermost/rnshare": "file:./libraries/@mattermost/rnshare",
"@mattermost/rnutils": "file:./libraries/@mattermost/rnutils", "@mattermost/rnutils": "file:./libraries/@mattermost/rnutils",
"@msgpack/msgpack": "2.8.0", "@msgpack/msgpack": "2.8.0",
"@nozbe/watermelondb": "0.27.1", "@nozbe/watermelondb": "0.28.0-1",
"@react-native-camera-roll/camera-roll": "7.8.3", "@react-native-camera-roll/camera-roll": "7.9.0",
"@react-native-clipboard/clipboard": "1.14.1", "@react-native-clipboard/clipboard": "1.15.0",
"@react-native-community/cli": "15.1.3",
"@react-native-community/cli-platform-android": "15.1.3",
"@react-native-community/cli-platform-ios": "15.1.3",
"@react-native-community/datetimepicker": "8.2.0", "@react-native-community/datetimepicker": "8.2.0",
"@react-native-community/netinfo": "11.3.2", "@react-native-community/netinfo": "11.4.1",
"@react-native-cookies/cookies": "6.2.1", "@react-native-cookies/cookies": "6.2.1",
"@react-navigation/bottom-tabs": "6.6.1", "@react-navigation/bottom-tabs": "7.2.0",
"@react-navigation/native": "6.1.18", "@react-navigation/native": "7.0.14",
"@react-navigation/stack": "6.4.1", "@react-navigation/stack": "7.1.0",
"@rneui/base": "4.0.0-rc.8", "@rneui/base": "4.0.0-rc.8",
"@sentry/react-native": "5.33.2", "@sentry/react-native": "6.4.0",
"@stream-io/flat-list-mvcp": "0.10.3", "@stream-io/flat-list-mvcp": "0.10.3",
"@voximplant/react-native-foreground-service": "3.0.2", "@voximplant/react-native-foreground-service": "3.0.2",
"base-64": "1.0.0", "base-64": "1.0.0",
@ -46,123 +49,123 @@
"commonmark-react-renderer": "github:mattermost/commonmark-react-renderer#81b5d27509652bae50b4b510ede777dd3bd923cf", "commonmark-react-renderer": "github:mattermost/commonmark-react-renderer#81b5d27509652bae50b4b510ede777dd3bd923cf",
"deep-equal": "2.2.3", "deep-equal": "2.2.3",
"deepmerge": "4.3.1", "deepmerge": "4.3.1",
"emoji-regex": "10.3.0", "emoji-regex": "10.4.0",
"expo": "51.0.24", "expo": "52.0.19",
"expo-application": "5.9.1", "expo-application": "6.0.1",
"expo-crypto": "13.0.2", "expo-crypto": "14.0.1",
"expo-device": "6.0.2", "expo-device": "7.0.1",
"expo-image": "1.12.13", "expo-image": "2.0.3",
"expo-linear-gradient": "13.0.2", "expo-linear-gradient": "14.0.1",
"expo-store-review": "7.0.2", "expo-store-review": "8.0.0",
"expo-video-thumbnails": "8.0.0", "expo-video-thumbnails": "9.0.2",
"expo-web-browser": "13.0.3", "expo-web-browser": "14.0.1",
"fflate": "0.8.2", "fflate": "0.8.2",
"fuse.js": "7.0.0", "fuse.js": "7.0.0",
"html-entities": "2.5.2", "html-entities": "2.5.2",
"mime-db": "1.53.0", "mime-db": "1.53.0",
"moment-timezone": "0.5.45", "moment-timezone": "0.5.46",
"node-html-parser": "6.1.13", "node-html-parser": "6.1.13",
"path-to-regexp": "8.1.0", "path-to-regexp": "8.2.0",
"react": "18.2.0", "react": "18.3.1",
"react-freeze": "1.0.4", "react-freeze": "1.0.4",
"react-intl": "6.6.8", "react-intl": "7.0.4",
"react-native": "0.74.5", "react-native": "0.76.5",
"react-native-background-timer": "2.4.1", "react-native-background-timer": "2.4.1",
"react-native-document-picker": "9.3.0", "react-native-document-picker": "9.3.1",
"react-native-dotenv": "3.4.11", "react-native-dotenv": "3.4.11",
"react-native-exception-handler": "2.10.10", "react-native-exception-handler": "2.10.10",
"react-native-file-viewer": "2.1.5", "react-native-file-viewer": "2.1.5",
"react-native-gesture-handler": "2.18.1", "react-native-gesture-handler": "2.21.2",
"react-native-haptic-feedback": "2.2.0", "react-native-haptic-feedback": "2.3.3",
"react-native-image-picker": "7.1.2", "react-native-image-picker": "7.2.3",
"react-native-incall-manager": "4.2.0", "react-native-incall-manager": "4.2.0",
"react-native-keyboard-aware-scroll-view": "0.9.5", "react-native-keyboard-aware-scroll-view": "0.9.5",
"react-native-keychain": "8.2.0", "react-native-keychain": "9.2.2",
"react-native-localize": "3.2.1", "react-native-localize": "3.3.0",
"react-native-math-view": "3.9.5", "react-native-math-view": "3.9.5",
"react-native-navigation": "7.40.1", "react-native-navigation": "7.40.3",
"react-native-notifications": "5.1.0", "react-native-notifications": "5.1.0",
"react-native-performance": "5.1.2", "react-native-performance": "5.1.2",
"react-native-permissions": "4.1.5", "react-native-permissions": "5.2.1",
"react-native-reanimated": "3.14.0", "react-native-reanimated": "3.16.5",
"react-native-safe-area-context": "4.10.8", "react-native-safe-area-context": "5.0.0",
"react-native-screens": "3.34.0", "react-native-screens": "4.3.0",
"react-native-section-list-get-item-layout": "2.2.3", "react-native-section-list-get-item-layout": "2.2.3",
"react-native-shadow-2": "7.1.0", "react-native-shadow-2": "7.1.1",
"react-native-share": "10.2.1", "react-native-share": "12.0.3",
"react-native-svg": "15.4.0", "react-native-svg": "15.10.1",
"react-native-url-polyfill": "2.0.0", "react-native-url-polyfill": "2.0.0",
"react-native-vector-icons": "10.1.0", "react-native-vector-icons": "10.2.0",
"react-native-video": "6.4.3", "react-native-video": "6.8.2",
"react-native-walkthrough-tooltip": "1.6.0", "react-native-walkthrough-tooltip": "1.6.0",
"react-native-webrtc": "124.0.3", "react-native-webrtc": "124.0.4",
"react-syntax-highlighter": "15.5.0", "react-syntax-highlighter": "15.6.1",
"semver": "7.6.3", "semver": "7.6.3",
"tinycolor2": "1.6.0", "tinycolor2": "1.6.0",
"url-parse": "1.5.10" "url-parse": "1.5.10"
}, },
"devDependencies": { "devDependencies": {
"@babel/cli": "7.24.8", "@babel/cli": "7.26.4",
"@babel/core": "7.25.2", "@babel/core": "7.26.0",
"@babel/eslint-parser": "7.25.1", "@babel/eslint-parser": "7.25.9",
"@babel/plugin-proposal-class-properties": "7.18.6", "@babel/plugin-proposal-class-properties": "7.18.6",
"@babel/plugin-proposal-decorators": "7.24.7", "@babel/plugin-proposal-decorators": "7.25.9",
"@babel/plugin-transform-flow-strip-types": "7.25.2", "@babel/plugin-transform-flow-strip-types": "7.25.9",
"@babel/plugin-transform-runtime": "7.24.7", "@babel/plugin-transform-runtime": "7.25.9",
"@babel/preset-env": "7.25.3", "@babel/preset-env": "7.26.0",
"@babel/preset-typescript": "7.24.7", "@babel/preset-typescript": "7.26.0",
"@babel/register": "7.24.6", "@babel/register": "7.25.9",
"@babel/runtime": "7.25.0", "@babel/runtime": "7.26.0",
"@react-native/babel-preset": "0.74.87", "@react-native/babel-preset": "0.76.5",
"@react-native/eslint-config": "0.74.87", "@react-native/eslint-config": "0.76.5",
"@react-native/metro-config": "0.74.87", "@react-native/metro-config": "0.76.5",
"@react-native/typescript-config": "0.74.87", "@react-native/typescript-config": "0.76.5",
"@testing-library/react-hooks": "8.0.1", "@testing-library/react-hooks": "8.0.1",
"@testing-library/react-native": "12.5.2", "@testing-library/react-native": "12.9.0",
"@types/base-64": "1.0.2", "@types/base-64": "1.0.2",
"@types/commonmark": "0.27.9", "@types/commonmark": "0.27.9",
"@types/commonmark-react-renderer": "4.3.4", "@types/commonmark-react-renderer": "4.3.4",
"@types/deep-equal": "1.0.4", "@types/deep-equal": "1.0.4",
"@types/jest": "29.5.12", "@types/jest": "29.5.14",
"@types/lodash": "4.17.7", "@types/lodash": "4.17.13",
"@types/mime-db": "1.43.5", "@types/mime-db": "1.43.5",
"@types/pako": "2.0.3", "@types/pako": "2.0.3",
"@types/querystringify": "2.0.2", "@types/querystringify": "2.0.2",
"@types/react": "18.3.3", "@types/react": "18.3.12",
"@types/react-native-background-timer": "2.0.2", "@types/react-native-background-timer": "2.0.2",
"@types/react-native-dotenv": "0.2.2", "@types/react-native-dotenv": "0.2.2",
"@types/react-native-share": "3.3.8", "@types/react-native-share": "6.0.0",
"@types/react-syntax-highlighter": "15.5.13", "@types/react-syntax-highlighter": "15.5.13",
"@types/semver": "7.5.8", "@types/semver": "7.5.8",
"@types/tinycolor2": "1.4.6", "@types/tinycolor2": "1.4.6",
"@types/tough-cookie": "4.0.5", "@types/tough-cookie": "4.0.5",
"@types/url-parse": "1.4.11", "@types/url-parse": "1.4.11",
"@types/uuid": "10.0.0", "@types/uuid": "10.0.0",
"@typescript-eslint/eslint-plugin": "7.13.1", "@typescript-eslint/eslint-plugin": "7.14.1",
"@typescript-eslint/parser": "7.13.1", "@typescript-eslint/parser": "7.14.1",
"babel-jest": "29.7.0", "babel-jest": "29.7.0",
"babel-loader": "9.1.3", "babel-loader": "9.2.1",
"babel-plugin-module-resolver": "5.0.2", "babel-plugin-module-resolver": "5.0.2",
"eslint": "8.57.0", "eslint": "8.57.1",
"eslint-plugin-header": "3.1.1", "eslint-plugin-header": "3.1.1",
"eslint-plugin-import": "2.29.1", "eslint-plugin-import": "2.31.0",
"eslint-plugin-jest": "28.7.0", "eslint-plugin-jest": "28.9.0",
"eslint-plugin-react": "7.35.0", "eslint-plugin-react": "7.37.2",
"eslint-plugin-react-hooks": "4.6.2", "eslint-plugin-react-hooks": "5.1.0",
"husky": "9.1.4", "husky": "9.1.7",
"isomorphic-fetch": "3.0.0", "isomorphic-fetch": "3.0.0",
"jest": "29.7.0", "jest": "29.7.0",
"jest-cli": "29.7.0", "jest-cli": "29.7.0",
"jest-expo": "51.0.3", "jest-expo": "52.0.2",
"jetifier": "2.0.0", "jetifier": "2.0.0",
"mmjstool": "github:mattermost/mattermost-utilities#83b1b311972b8f5e750aae4019457a40abb5aa44", "mmjstool": "github:mattermost/mattermost-utilities#83b1b311972b8f5e750aae4019457a40abb5aa44",
"nock": "13.5.4", "nock": "13.5.6",
"patch-package": "8.0.0", "patch-package": "8.0.0",
"react-devtools-core": "5.3.1", "react-devtools-core": "6.0.1",
"tough-cookie": "4.1.4", "tough-cookie": "5.0.0",
"ts-jest": "29.2.4", "ts-jest": "29.2.5",
"typescript": "5.5.4", "typescript": "5.7.2",
"uuid": "10.0.0" "uuid": "11.0.3"
}, },
"scripts": { "scripts": {
"android": "react-native run-android", "android": "react-native run-android",
@ -198,25 +201,21 @@
}, },
"overrides": { "overrides": {
"@testing-library/react-native": { "@testing-library/react-native": {
"react": "^18.2.0" "react": "^18.3.1"
}, },
"@testing-library/react-hooks": { "@testing-library/react-hooks": {
"@types/react": "^18.2.37", "@types/react": "^18.2.37",
"react": "^18.2.0", "react": "^18.3.1",
"react-test-renderer": "^18.2.0" "react-test-renderer": "^18.2.0"
}, },
"@react-native-community/datetimepicker": { "@react-native-community/datetimepicker": {
"react-native": "^0.74.2" "react-native": "^0.76.5"
},
"@react-native/eslint-config": {
"@typescript-eslint/eslint-plugin": "^7.12.0",
"@typescript-eslint/parser": "^7.12.0"
}, },
"@react-native-clipboard/clipboard": { "@react-native-clipboard/clipboard": {
"react-native": "^0.74.2" "react-native": "^0.76.5"
}, },
"react-native-windows": { "react-native-windows": {
"react-native": "^0.74.2" "react-native": "^0.76.5"
} }
}, },
"expo": { "expo": {

View file

@ -1,21 +1,21 @@
diff --git a/node_modules/@nozbe/watermelondb/Database/index.d.ts b/node_modules/@nozbe/watermelondb/Database/index.d.ts diff --git a/node_modules/@nozbe/watermelondb/Database/index.d.ts b/node_modules/@nozbe/watermelondb/Database/index.d.ts
index 861ed06..d2d6527 100644 index e6eefec..d3a7dc0 100644
--- a/node_modules/@nozbe/watermelondb/Database/index.d.ts --- a/node_modules/@nozbe/watermelondb/Database/index.d.ts
+++ b/node_modules/@nozbe/watermelondb/Database/index.d.ts +++ b/node_modules/@nozbe/watermelondb/Database/index.d.ts
@@ -88,6 +88,8 @@ export default class Database { @@ -93,6 +93,8 @@ export default class Database {
// Yes, this sucks and there should be some safety mechanisms or warnings. Please contribute! // has a significant performance impact so should only be enabled when debugging.
unsafeResetDatabase(): Promise<void> experimentalIsVerbose: boolean
+ unsafeVacuum(): Promise<void> + unsafeVacuum(): Promise<void>
+ +
_ensureInWriter(diagnosticMethodName: string): void _ensureInWriter(diagnosticMethodName: string): void
// (experimental) puts Database in a broken state // (experimental) puts Database in a broken state
diff --git a/node_modules/@nozbe/watermelondb/Database/index.js b/node_modules/@nozbe/watermelondb/Database/index.js diff --git a/node_modules/@nozbe/watermelondb/Database/index.js b/node_modules/@nozbe/watermelondb/Database/index.js
index fa82516..de24ff2 100644 index 9139dd4..aec45b5 100644
--- a/node_modules/@nozbe/watermelondb/Database/index.js --- a/node_modules/@nozbe/watermelondb/Database/index.js
+++ b/node_modules/@nozbe/watermelondb/Database/index.js +++ b/node_modules/@nozbe/watermelondb/Database/index.js
@@ -91,7 +91,9 @@ var Database = /*#__PURE__*/function () { @@ -92,7 +92,9 @@ var Database = exports.default = /*#__PURE__*/function () {
var preparedState = record._preparedState; var preparedState = record._preparedState;
if (!preparedState) { if (!preparedState) {
(0, _common.invariant)('disposable' !== record._raw._status, "Cannot batch a disposable record"); (0, _common.invariant)('disposable' !== record._raw._status, "Cannot batch a disposable record");
@ -26,22 +26,21 @@ index fa82516..de24ff2 100644
} }
var raw = record._raw; var raw = record._raw;
var { var {
@@ -122,6 +124,10 @@ var Database = /*#__PURE__*/function () { @@ -123,6 +125,9 @@ var Database = exports.default = /*#__PURE__*/function () {
// subsequent changes to the record don't trip up the invariant // subsequent changes to the record don't trip up the invariant
// TODO: What if this fails? // TODO: What if this fails?
record._preparedState = null; record._preparedState = null;
+
+ if ('update' === preparedState) { + if ('update' === preparedState) {
+ record.__original = null; + record.__original = null;
+ } + }
} }
if (!changeNotifications[table]) { if (!changeNotifications[table]) {
changeNotifications[table] = []; changeNotifications[table] = [];
@@ -379,6 +385,57 @@ var Database = /*#__PURE__*/function () { @@ -399,6 +404,57 @@ var Database = exports.default = /*#__PURE__*/function () {
}
}.bind(this)); }.bind(this));
}; }
+ _proto.unsafeVacuum = function unsafeVacuum() {
+ _proto.unsafeVacuum = function () {
+ return new Promise(function ($return, $error) { + return new Promise(function ($return, $error) {
+ var $Try_3_Finally = function ($Try_3_Exit) { + var $Try_3_Finally = function ($Try_3_Exit) {
+ return function ($Try_3_Value) { + return function ($Try_3_Value) {
@ -75,7 +74,6 @@ index fa82516..de24ff2 100644
+ } = this); + } = this);
+ ErrorAdapter = require('../adapters/error').default; + ErrorAdapter = require('../adapters/error').default;
+ this.adapter = new ErrorAdapter(); + this.adapter = new ErrorAdapter();
+
+ // Vacuum the database + // Vacuum the database
+ return Promise.resolve(adapter.unsafeVacuum()).then(function () { + return Promise.resolve(adapter.unsafeVacuum()).then(function () {
+ try { + try {
@ -92,11 +90,12 @@ index fa82516..de24ff2 100644
+ } + }
+ }.bind(this)); + }.bind(this));
+ }; + };
_proto._ensureInWriter = function _ensureInWriter(diagnosticMethodName) { +
(0, _common.invariant)(this._workQueue.isWriterRunning, "".concat(diagnosticMethodName, " can only be called from inside of a Writer. See docs for more details.")); // (experimental) if true, Models will print to console diagnostic information on every
} // prepareCreate/Update/Delete call, as well as on commit (Database.batch() call). Note that this
// has a significant performance impact so should only be enabled when debugging.
diff --git a/node_modules/@nozbe/watermelondb/Model/index.d.ts b/node_modules/@nozbe/watermelondb/Model/index.d.ts diff --git a/node_modules/@nozbe/watermelondb/Model/index.d.ts b/node_modules/@nozbe/watermelondb/Model/index.d.ts
index 96114ec..ecfe3c1 100644 index 96114ec..258bb92 100644
--- a/node_modules/@nozbe/watermelondb/Model/index.d.ts --- a/node_modules/@nozbe/watermelondb/Model/index.d.ts
+++ b/node_modules/@nozbe/watermelondb/Model/index.d.ts +++ b/node_modules/@nozbe/watermelondb/Model/index.d.ts
@@ -61,6 +61,8 @@ export default class Model { @@ -61,6 +61,8 @@ export default class Model {
@ -104,20 +103,20 @@ index 96114ec..ecfe3c1 100644
prepareUpdate(recordUpdater?: (_: this) => void): this prepareUpdate(recordUpdater?: (_: this) => void): this
+ cancelPrepareUpdate(): void + cancelPrepareUpdate(): void
+ +
prepareMarkAsDeleted(): this prepareMarkAsDeleted(): this
prepareDestroyPermanently(): this prepareDestroyPermanently(): this
diff --git a/node_modules/@nozbe/watermelondb/Model/index.js b/node_modules/@nozbe/watermelondb/Model/index.js diff --git a/node_modules/@nozbe/watermelondb/Model/index.js b/node_modules/@nozbe/watermelondb/Model/index.js
index dbfdf6e..2e63166 100644 index a5b6815..18a21d8 100644
--- a/node_modules/@nozbe/watermelondb/Model/index.js --- a/node_modules/@nozbe/watermelondb/Model/index.js
+++ b/node_modules/@nozbe/watermelondb/Model/index.js +++ b/node_modules/@nozbe/watermelondb/Model/index.js
@@ -80,7 +80,17 @@ var Model = /*#__PURE__*/function () { @@ -101,7 +101,18 @@ var Model = exports.default = /*#__PURE__*/function () {
*/; */;
_proto.prepareUpdate = function prepareUpdate(recordUpdater = _noop.default) { _proto.prepareUpdate = function (recordUpdater = _noop.default) {
var _this = this; var _this = this;
- (0, _invariant.default)(!this._preparedState, "Cannot update a record with pending changes. Update attempted for table ".concat(this.table, " and record ").concat(this.id, ".")); - (0, _invariant.default)(!this._preparedState, "Cannot update a record with pending changes (".concat(this.__debugName, ")"));
+ // (0, _invariant.default)(!this._preparedState, "Cannot update a record with pending changes. Update attempted for table ".concat(this.table, " and record ").concat(this.id, ".")); + // (0, _invariant.default)(!this._preparedState, "Cannot update a record with pending changes (".concat(this.__debugName, ")"));
+ if ('deleted' === this._raw._status) { + if ('deleted' === this._raw._status) {
+ console.debug("Updating a deleted record in table " + _this.table); + console.debug("Updating a deleted record in table " + _this.table);
+ return this; + return this;
@ -128,16 +127,16 @@ index dbfdf6e..2e63166 100644
+ } else { + } else {
+ this.__original = Object.assign({}, this._raw); + this.__original = Object.assign({}, this._raw);
+ } + }
+
this.__ensureNotDisposable("Model.prepareUpdate()"); this.__ensureNotDisposable("Model.prepareUpdate()");
this._isEditing = true; this._isEditing = true;
@@ -125,6 +135,21 @@ var Model = /*#__PURE__*/function () { @@ -147,6 +158,20 @@ var Model = exports.default = /*#__PURE__*/function () {
}.bind(this)); }.bind(this));
} }
+ _proto.cancelPrepareUpdate = function cancelPrepareUpdate() { + _proto.cancelPrepareUpdate = function () {
+ var _this = this; + var _this = this;
+
+ if ('test' !== process.env.NODE_ENV && 'undefined' !== typeof process && process) { + if ('test' !== process.env.NODE_ENV && 'undefined' !== typeof process && process) {
+ (0, _invariant.default)('update' === _this._preparedState, "Cannot cancel an update on a model that has not been prepared in table " + _this.table); + (0, _invariant.default)('update' === _this._preparedState, "Cannot cancel an update on a model that has not been prepared in table " + _this.table);
+ } + }
@ -153,12 +152,12 @@ index dbfdf6e..2e63166 100644
/** /**
* Prepares record to be marked as deleted * Prepares record to be marked as deleted
* *
@@ -173,7 +198,10 @@ var Model = /*#__PURE__*/function () { @@ -196,7 +221,10 @@ var Model = exports.default = /*#__PURE__*/function () {
* @see {Database#batch} * @see {Database#batch}
*/; */;
_proto.prepareDestroyPermanently = function prepareDestroyPermanently() { _proto.prepareDestroyPermanently = function () {
- (0, _invariant.default)(!this._preparedState, "Cannot destroy permanently a record with pending changes"); - (0, _invariant.default)(!this._preparedState, "Cannot destroy permanently record with pending changes (".concat(this.__debugName, ")"));
+ // (0, _invariant.default)(!this._preparedState, "Cannot destroy permanently a record with pending changes"); + // (0, _invariant.default)(!this._preparedState, "Cannot destroy permanently record with pending changes (".concat(this.__debugName, ")"));
+ if (this._preparedState) { + if (this._preparedState) {
+ console.debug("Deleting a record with pending changes in table " + this.table); + console.debug("Deleting a record with pending changes in table " + this.table);
+ } + }
@ -179,28 +178,28 @@ index 51879c7..435ad72 100644
getLocal(key: string): Promise<string | undefined> getLocal(key: string): Promise<string | undefined>
diff --git a/node_modules/@nozbe/watermelondb/adapters/compat.js b/node_modules/@nozbe/watermelondb/adapters/compat.js diff --git a/node_modules/@nozbe/watermelondb/adapters/compat.js b/node_modules/@nozbe/watermelondb/adapters/compat.js
index 4a0b5ef..9b8ff13 100644 index 138bc91..82c6311 100644
--- a/node_modules/@nozbe/watermelondb/adapters/compat.js --- a/node_modules/@nozbe/watermelondb/adapters/compat.js
+++ b/node_modules/@nozbe/watermelondb/adapters/compat.js +++ b/node_modules/@nozbe/watermelondb/adapters/compat.js
@@ -76,6 +76,12 @@ var DatabaseAdapterCompat = /*#__PURE__*/function () { @@ -76,6 +76,12 @@ var DatabaseAdapterCompat = exports.default = /*#__PURE__*/function () {
return _this11.underlyingAdapter.unsafeResetDatabase(callback); return _this11.underlyingAdapter.unsafeResetDatabase(callback);
}); });
}; };
+ _proto.unsafeVacuum = function unsafeVacuum() { + _proto.unsafeVacuum = function () {
+ var _this16 = this; + var _this16 = this;
+ return (0, _Result.toPromise)(function (callback) { + return (0, _Result.toPromise)(function (callback) {
+ return _this16.underlyingAdapter.unsafeVacuum(callback); + return _this16.underlyingAdapter.unsafeVacuum(callback);
+ }); + });
+ }; + };
_proto.unsafeExecute = function unsafeExecute(work) { _proto.unsafeExecute = function (work) {
var _this12 = this; var _this12 = this;
return (0, _Result.toPromise)(function (callback) { return (0, _Result.toPromise)(function (callback) {
diff --git a/node_modules/@nozbe/watermelondb/adapters/error.js b/node_modules/@nozbe/watermelondb/adapters/error.js diff --git a/node_modules/@nozbe/watermelondb/adapters/error.js b/node_modules/@nozbe/watermelondb/adapters/error.js
index 70a4c11..453dca2 100644 index 83b5754..f023e14 100644
--- a/node_modules/@nozbe/watermelondb/adapters/error.js --- a/node_modules/@nozbe/watermelondb/adapters/error.js
+++ b/node_modules/@nozbe/watermelondb/adapters/error.js +++ b/node_modules/@nozbe/watermelondb/adapters/error.js
@@ -13,7 +13,7 @@ var throwError = function (name) { @@ -13,7 +13,7 @@ var throwError = function (name) {
var ErrorAdapter = /*#__PURE__*/function () { var ErrorAdapter = exports.default = /*#__PURE__*/function () {
function ErrorAdapter() { function ErrorAdapter() {
var _this = this; var _this = this;
- ['find', 'query', 'queryIds', 'count', 'batch', 'getDeletedRecords', 'destroyDeletedRecords', 'unsafeResetDatabase', 'getLocal', 'setLocal', 'removeLocal', 'testClone'].forEach(function (name) { - ['find', 'query', 'queryIds', 'count', 'batch', 'getDeletedRecords', 'destroyDeletedRecords', 'unsafeResetDatabase', 'getLocal', 'setLocal', 'removeLocal', 'testClone'].forEach(function (name) {
@ -209,7 +208,7 @@ index 70a4c11..453dca2 100644
_this[name] = function () { _this[name] = function () {
return throwError(name); return throwError(name);
diff --git a/node_modules/@nozbe/watermelondb/adapters/lokijs/common.d.ts b/node_modules/@nozbe/watermelondb/adapters/lokijs/common.d.ts diff --git a/node_modules/@nozbe/watermelondb/adapters/lokijs/common.d.ts b/node_modules/@nozbe/watermelondb/adapters/lokijs/common.d.ts
index 5528dc1..0408198 100644 index f8d179f..4b39cf9 100644
--- a/node_modules/@nozbe/watermelondb/adapters/lokijs/common.d.ts --- a/node_modules/@nozbe/watermelondb/adapters/lokijs/common.d.ts
+++ b/node_modules/@nozbe/watermelondb/adapters/lokijs/common.d.ts +++ b/node_modules/@nozbe/watermelondb/adapters/lokijs/common.d.ts
@@ -13,6 +13,7 @@ export type WorkerExecutorType = @@ -13,6 +13,7 @@ export type WorkerExecutorType =
@ -234,24 +233,24 @@ index e09fb14..51d42d9 100644
getLocal(key: string, callback: ResultCallback<string | undefined>): void getLocal(key: string, callback: ResultCallback<string | undefined>): void
diff --git a/node_modules/@nozbe/watermelondb/adapters/lokijs/index.js b/node_modules/@nozbe/watermelondb/adapters/lokijs/index.js diff --git a/node_modules/@nozbe/watermelondb/adapters/lokijs/index.js b/node_modules/@nozbe/watermelondb/adapters/lokijs/index.js
index 9d5ea84..aa8397d 100644 index 08916f6..672fc29 100644
--- a/node_modules/@nozbe/watermelondb/adapters/lokijs/index.js --- a/node_modules/@nozbe/watermelondb/adapters/lokijs/index.js
+++ b/node_modules/@nozbe/watermelondb/adapters/lokijs/index.js +++ b/node_modules/@nozbe/watermelondb/adapters/lokijs/index.js
@@ -105,6 +105,9 @@ var LokiJSAdapter = /*#__PURE__*/function () { @@ -105,6 +105,9 @@ var LokiJSAdapter = exports.default = /*#__PURE__*/function () {
_proto.unsafeResetDatabase = function unsafeResetDatabase(callback) { _proto.unsafeResetDatabase = function (callback) {
this._dispatcher.call('unsafeResetDatabase', [], callback); this._dispatcher.call('unsafeResetDatabase', [], callback);
}; };
+ _proto.unsafeVacuum = function unssafeVacuum(callback) { + _proto.unsafeVacuum = function (callback) {
+ this._dispatcher.call('unsafeVacuum', [], callback); + this._dispatcher.call('unsafeVacuum', [], callback);
+ }; + };
_proto.unsafeExecute = function unsafeExecute(operations, callback) { _proto.unsafeExecute = function (operations, callback) {
this._dispatcher.call('unsafeExecute', [operations], callback); this._dispatcher.call('unsafeExecute', [operations], callback);
}; };
diff --git a/node_modules/@nozbe/watermelondb/adapters/lokijs/worker/DatabaseBridge.js b/node_modules/@nozbe/watermelondb/adapters/lokijs/worker/DatabaseBridge.js diff --git a/node_modules/@nozbe/watermelondb/adapters/lokijs/worker/DatabaseBridge.js b/node_modules/@nozbe/watermelondb/adapters/lokijs/worker/DatabaseBridge.js
index ca35a79..7079572 100644 index e7acc55..afc44d0 100644
--- a/node_modules/@nozbe/watermelondb/adapters/lokijs/worker/DatabaseBridge.js --- a/node_modules/@nozbe/watermelondb/adapters/lokijs/worker/DatabaseBridge.js
+++ b/node_modules/@nozbe/watermelondb/adapters/lokijs/worker/DatabaseBridge.js +++ b/node_modules/@nozbe/watermelondb/adapters/lokijs/worker/DatabaseBridge.js
@@ -33,7 +33,7 @@ var DatabaseBridge = /*#__PURE__*/function () { @@ -33,7 +33,7 @@ var DatabaseBridge = exports.default = /*#__PURE__*/function () {
type: type, type: type,
payload: payload payload: payload
} = action; } = action;
@ -261,22 +260,22 @@ index ca35a79..7079572 100644
} else { } else {
var response = this._driverAction(type).apply(void 0, (0, _toConsumableArray2.default)(payload)); var response = this._driverAction(type).apply(void 0, (0, _toConsumableArray2.default)(payload));
diff --git a/node_modules/@nozbe/watermelondb/adapters/lokijs/worker/DatabaseDriver.js b/node_modules/@nozbe/watermelondb/adapters/lokijs/worker/DatabaseDriver.js diff --git a/node_modules/@nozbe/watermelondb/adapters/lokijs/worker/DatabaseDriver.js b/node_modules/@nozbe/watermelondb/adapters/lokijs/worker/DatabaseDriver.js
index ee89cff..04de604 100644 index 85626c4..e448e9b 100644
--- a/node_modules/@nozbe/watermelondb/adapters/lokijs/worker/DatabaseDriver.js --- a/node_modules/@nozbe/watermelondb/adapters/lokijs/worker/DatabaseDriver.js
+++ b/node_modules/@nozbe/watermelondb/adapters/lokijs/worker/DatabaseDriver.js +++ b/node_modules/@nozbe/watermelondb/adapters/lokijs/worker/DatabaseDriver.js
@@ -216,6 +216,12 @@ var DatabaseDriver = /*#__PURE__*/function () { @@ -216,6 +216,12 @@ var DatabaseDriver = exports.default = /*#__PURE__*/function () {
}.bind(this)); }.bind(this));
} }
+ _proto.unsafeVacuum = function unsafeVacuum() { + _proto.unsafeVacuum = function () {
+ return new Promise(function ($return, $error) { + return new Promise(function ($return, $error) {
+ return Promise.resolve(0); + return Promise.resolve(0);
+ }.bind(this)); + }.bind(this));
+ } + };
+ +
// *** LocalStorage *** // *** LocalStorage ***
; ;
_proto.getLocal = function getLocal(key) { _proto.getLocal = function (key) {
diff --git a/node_modules/@nozbe/watermelondb/adapters/sqlite/index.d.ts b/node_modules/@nozbe/watermelondb/adapters/sqlite/index.d.ts diff --git a/node_modules/@nozbe/watermelondb/adapters/sqlite/index.d.ts b/node_modules/@nozbe/watermelondb/adapters/sqlite/index.d.ts
index 88c43a0..cef8232 100644 index 88c43a0..cef8232 100644
--- a/node_modules/@nozbe/watermelondb/adapters/sqlite/index.d.ts --- a/node_modules/@nozbe/watermelondb/adapters/sqlite/index.d.ts
@ -291,14 +290,14 @@ index 88c43a0..cef8232 100644
getLocal(key: string, callback: ResultCallback<string | undefined>): void getLocal(key: string, callback: ResultCallback<string | undefined>): void
diff --git a/node_modules/@nozbe/watermelondb/adapters/sqlite/index.js b/node_modules/@nozbe/watermelondb/adapters/sqlite/index.js diff --git a/node_modules/@nozbe/watermelondb/adapters/sqlite/index.js b/node_modules/@nozbe/watermelondb/adapters/sqlite/index.js
index 985dbd6..bcc232d 100644 index 0af2b6c..193d7e9 100644
--- a/node_modules/@nozbe/watermelondb/adapters/sqlite/index.js --- a/node_modules/@nozbe/watermelondb/adapters/sqlite/index.js
+++ b/node_modules/@nozbe/watermelondb/adapters/sqlite/index.js +++ b/node_modules/@nozbe/watermelondb/adapters/sqlite/index.js
@@ -237,6 +237,14 @@ var SQLiteAdapter = /*#__PURE__*/function () { @@ -237,6 +237,14 @@ var SQLiteAdapter = exports.default = /*#__PURE__*/function () {
callback(result); callback(result);
}); });
}; };
+ _proto.unsafeVacuum = function unsafeVacuum(callback) { + _proto.unsafeVacuum = function (callback) {
+ this._dispatcher.call('unsafeVacuum', [], function (result) { + this._dispatcher.call('unsafeVacuum', [], function (result) {
+ if (result.value) { + if (result.value) {
+ _common.logger.log('[SQLite] Database is now vacuumed'); + _common.logger.log('[SQLite] Database is now vacuumed');
@ -306,45 +305,45 @@ index 985dbd6..bcc232d 100644
+ callback(result); + callback(result);
+ }); + });
+ }; + };
_proto.unsafeExecute = function unsafeExecute(operations, callback) { _proto.unsafeExecute = function (operations, callback) {
if ('production' !== process.env.NODE_ENV) { if ('production' !== process.env.NODE_ENV) {
(0, _common.invariant)(operations && 'object' === typeof operations && 1 === Object.keys(operations).length && (Array.isArray(operations.sqls) || 'string' === typeof operations.sqlString), "unsafeExecute expects an { sqls: [ [sql, [args..]], ... ] } or { sqlString: 'foo; bar' } object"); (0, _common.invariant)(operations && 'object' === typeof operations && 1 === Object.keys(operations).length && (Array.isArray(operations.sqls) || 'string' === typeof operations.sqlString), "unsafeExecute expects an { sqls: [ [sql, [args..]], ... ] } or { sqlString: 'foo; bar' } object");
diff --git a/node_modules/@nozbe/watermelondb/adapters/sqlite/sqlite-node/DatabaseBridge.js b/node_modules/@nozbe/watermelondb/adapters/sqlite/sqlite-node/DatabaseBridge.js diff --git a/node_modules/@nozbe/watermelondb/adapters/sqlite/sqlite-node/DatabaseBridge.js b/node_modules/@nozbe/watermelondb/adapters/sqlite/sqlite-node/DatabaseBridge.js
index a93b0a7..df63896 100644 index 896e027..ce4866d 100644
--- a/node_modules/@nozbe/watermelondb/adapters/sqlite/sqlite-node/DatabaseBridge.js --- a/node_modules/@nozbe/watermelondb/adapters/sqlite/sqlite-node/DatabaseBridge.js
+++ b/node_modules/@nozbe/watermelondb/adapters/sqlite/sqlite-node/DatabaseBridge.js +++ b/node_modules/@nozbe/watermelondb/adapters/sqlite/sqlite-node/DatabaseBridge.js
@@ -113,6 +113,14 @@ var DatabaseBridge = /*#__PURE__*/function () { @@ -113,6 +113,14 @@ var DatabaseBridge = /*#__PURE__*/function () {
}); });
}); });
}; };
+ _proto.unsafeVacuum = function unsafeVacuum(tag, schema, schemaVersion, resolve, reject) { + _proto.unsafeVacuum = function (tag, schema, schemaVersion, resolve, reject) {
+ this.withDriver(tag, resolve, reject, 'unsafeVacuum', function (driver) { + this.withDriver(tag, resolve, reject, 'unsafeVacuum', function (driver) {
+ return driver.unsafeVacuum({ + return driver.unsafeVacuum({
+ version: schemaVersion, + version: schemaVersion,
+ sql: schema + sql: schema
+ }); + });
+ }); + }
+ }; + };
_proto.getLocal = function getLocal(tag, key, resolve, reject) { _proto.getLocal = function (tag, key, resolve, reject) {
this.withDriver(tag, resolve, reject, 'getLocal', function (driver) { this.withDriver(tag, resolve, reject, 'getLocal', function (driver) {
return driver.getLocal(key); return driver.getLocal(key);
diff --git a/node_modules/@nozbe/watermelondb/adapters/sqlite/sqlite-node/DatabaseDriver.js b/node_modules/@nozbe/watermelondb/adapters/sqlite/sqlite-node/DatabaseDriver.js diff --git a/node_modules/@nozbe/watermelondb/adapters/sqlite/sqlite-node/DatabaseDriver.js b/node_modules/@nozbe/watermelondb/adapters/sqlite/sqlite-node/DatabaseDriver.js
index 483884c..c325299 100644 index 40f7af6..97033b0 100644
--- a/node_modules/@nozbe/watermelondb/adapters/sqlite/sqlite-node/DatabaseDriver.js --- a/node_modules/@nozbe/watermelondb/adapters/sqlite/sqlite-node/DatabaseDriver.js
+++ b/node_modules/@nozbe/watermelondb/adapters/sqlite/sqlite-node/DatabaseDriver.js +++ b/node_modules/@nozbe/watermelondb/adapters/sqlite/sqlite-node/DatabaseDriver.js
@@ -198,6 +198,10 @@ var DatabaseDriver = /*#__PURE__*/function () { @@ -198,6 +198,10 @@ var DatabaseDriver = /*#__PURE__*/function () {
_this5.database.userVersion = schema.version; _this5.database.userVersion = schema.version;
}); });
}; };
+ _proto.unsafeVacuum = function unsafeVacuum() { + _proto.unsafeVacuum = function () {
+ var _this5 = this; + var _this5 = this;
+ this.database.unsafeVacuum(); + this.database.unsafeVacuum();
+ }; + };
_proto.migrate = function migrate(migrations) { _proto.migrate = function (migrations) {
var _this6 = this; var _this6 = this;
var databaseVersion = this.database.userVersion; var databaseVersion = this.database.userVersion;
diff --git a/node_modules/@nozbe/watermelondb/adapters/sqlite/type.d.ts b/node_modules/@nozbe/watermelondb/adapters/sqlite/type.d.ts diff --git a/node_modules/@nozbe/watermelondb/adapters/sqlite/type.d.ts b/node_modules/@nozbe/watermelondb/adapters/sqlite/type.d.ts
index 16a8a71..ce6e743 100644 index 5d1a321..bb7a195 100644
--- a/node_modules/@nozbe/watermelondb/adapters/sqlite/type.d.ts --- a/node_modules/@nozbe/watermelondb/adapters/sqlite/type.d.ts
+++ b/node_modules/@nozbe/watermelondb/adapters/sqlite/type.d.ts +++ b/node_modules/@nozbe/watermelondb/adapters/sqlite/type.d.ts
@@ -45,6 +45,7 @@ export type SqliteDispatcherMethod = @@ -45,6 +45,7 @@ export type SqliteDispatcherMethod =
@ -356,10 +355,10 @@ index 16a8a71..ce6e743 100644
| 'unsafeExecuteMultiple' | 'unsafeExecuteMultiple'
diff --git a/node_modules/@nozbe/watermelondb/adapters/type.d.ts b/node_modules/@nozbe/watermelondb/adapters/type.d.ts diff --git a/node_modules/@nozbe/watermelondb/adapters/type.d.ts b/node_modules/@nozbe/watermelondb/adapters/type.d.ts
index 027c366..5807e79 100644 index 3a73e71..0e9395d 100644
--- a/node_modules/@nozbe/watermelondb/adapters/type.d.ts --- a/node_modules/@nozbe/watermelondb/adapters/type.d.ts
+++ b/node_modules/@nozbe/watermelondb/adapters/type.d.ts +++ b/node_modules/@nozbe/watermelondb/adapters/type.d.ts
@@ -66,6 +66,9 @@ export interface DatabaseAdapter { @@ -67,6 +67,9 @@ export interface DatabaseAdapter {
// Destroys the whole database, its schema, indexes, everything. // Destroys the whole database, its schema, indexes, everything.
unsafeResetDatabase(callback: ResultCallback<void>): void unsafeResetDatabase(callback: ResultCallback<void>): void
@ -595,16 +594,16 @@ index f0073c5..028031b 100644
void executeMultiple(std::string sql); void executeMultiple(std::string sql);
diff --git a/node_modules/@nozbe/watermelondb/native/shared/DatabaseBridge.cpp b/node_modules/@nozbe/watermelondb/native/shared/DatabaseBridge.cpp diff --git a/node_modules/@nozbe/watermelondb/native/shared/DatabaseBridge.cpp b/node_modules/@nozbe/watermelondb/native/shared/DatabaseBridge.cpp
index ef0f23b..cb49ecd 100644 index ef0f23b..d1a6742 100644
--- a/node_modules/@nozbe/watermelondb/native/shared/DatabaseBridge.cpp --- a/node_modules/@nozbe/watermelondb/native/shared/DatabaseBridge.cpp
+++ b/node_modules/@nozbe/watermelondb/native/shared/DatabaseBridge.cpp +++ b/node_modules/@nozbe/watermelondb/native/shared/DatabaseBridge.cpp
@@ -213,6 +213,18 @@ void Database::install(jsi::Runtime *runtime) { @@ -75,7 +75,17 @@ void Database::install(jsi::Runtime *runtime) {
std::abort(); databaseToDestroy->destroy();
} }
}); });
-
+ createMethod(rt, adapter, "unsafeVacuum", 0, [database](jsi::Runtime &rt, const jsi::Value *args) { + createMethod(rt, adapter, "unsafeVacuum", 0, [database](jsi::Runtime &rt, const jsi::Value *args) {
+ assert(database->initialized_); + assert(database->initialized_);
+
+ try { + try {
+ database->unsafeVacuum(); + database->unsafeVacuum();
+ return jsi::Value::undefined(); + return jsi::Value::undefined();
@ -614,9 +613,9 @@ index ef0f23b..cb49ecd 100644
+ std::abort(); + std::abort();
+ } + }
+ }); + });
createMethod(rt, adapter, "unsafeClose", 0, [database](jsi::Runtime &rt, const jsi::Value *args) { createMethod(rt, adapter, "initialize", 2, [database](jsi::Runtime &rt, const jsi::Value *args) {
assert(database->initialized_); jsi::String dbName = args[0].getString(rt);
database->destroy(); int expectedVersion = (int)args[1].getNumber();
diff --git a/node_modules/@nozbe/watermelondb/native/shared/Sqlite.cpp b/node_modules/@nozbe/watermelondb/native/shared/Sqlite.cpp diff --git a/node_modules/@nozbe/watermelondb/native/shared/Sqlite.cpp b/node_modules/@nozbe/watermelondb/native/shared/Sqlite.cpp
index e08153b..2fca075 100644 index e08153b..2fca075 100644
--- a/node_modules/@nozbe/watermelondb/native/shared/Sqlite.cpp --- a/node_modules/@nozbe/watermelondb/native/shared/Sqlite.cpp
@ -645,34 +644,32 @@ index 4fe52f1..a4a99da 100644
sqlite3 *sqlite; sqlite3 *sqlite;
diff --git a/node_modules/@nozbe/watermelondb/src/Database/index.js b/node_modules/@nozbe/watermelondb/src/Database/index.js diff --git a/node_modules/@nozbe/watermelondb/src/Database/index.js b/node_modules/@nozbe/watermelondb/src/Database/index.js
index d4ca4e7..75c1f8e 100644 index 6175192..3333e7c 100644
--- a/node_modules/@nozbe/watermelondb/src/Database/index.js --- a/node_modules/@nozbe/watermelondb/src/Database/index.js
+++ b/node_modules/@nozbe/watermelondb/src/Database/index.js +++ b/node_modules/@nozbe/watermelondb/src/Database/index.js
@@ -361,6 +361,24 @@ export default class Database { @@ -380,6 +380,22 @@ export default class Database {
} }
} }
+ async unsafeVacuum(): Promise<void> { + async unsafeVacuum(): Promise<void> {
+ try { + try {
+ // Kill ability to call adapter methods during reset (to catch bugs if someone does this) + // Kill ability to call adapter methods during reset (to catch bugs if someone does this)
+ const { adapter } = this + const { adapter } = this
+ const ErrorAdapter = require('../adapters/error').default + const ErrorAdapter = require('../adapters/error').default
+ this.adapter = (new ErrorAdapter(): any) + this.adapter = (new ErrorAdapter(): any)
+ + // Vacuum the database
+ // Vacuum the database + await adapter.unsafeVacuum()
+ await adapter.unsafeVacuum() + // Restore working Database
+ + this._resetCount += 1
+ // Restore working Database + this.adapter = adapter
+ this._resetCount += 1 + } finally {
+ this.adapter = adapter + this._isBeingReset = false
+ } finally {
+ this._isBeingReset = false
+ }
+ } + }
+}
+ +
_ensureInWriter(diagnosticMethodName: string): void { // (experimental) if true, Models will print to console diagnostic information on every
invariant( // prepareCreate/Update/Delete call, as well as on commit (Database.batch() call). Note that this
this._workQueue.isWriterRunning, // has a significant performance impact so should only be enabled when debugging.
diff --git a/node_modules/@nozbe/watermelondb/src/adapters/compat.js b/node_modules/@nozbe/watermelondb/src/adapters/compat.js diff --git a/node_modules/@nozbe/watermelondb/src/adapters/compat.js b/node_modules/@nozbe/watermelondb/src/adapters/compat.js
index c5175c0..c8c0c17 100644 index c5175c0..c8c0c17 100644
--- a/node_modules/@nozbe/watermelondb/src/adapters/compat.js --- a/node_modules/@nozbe/watermelondb/src/adapters/compat.js
@ -701,20 +698,20 @@ index 9f1e847..cdd3af4 100644
'setLocal', 'setLocal',
'removeLocal', 'removeLocal',
diff --git a/node_modules/@nozbe/watermelondb/src/adapters/sqlite/index.js b/node_modules/@nozbe/watermelondb/src/adapters/sqlite/index.js diff --git a/node_modules/@nozbe/watermelondb/src/adapters/sqlite/index.js b/node_modules/@nozbe/watermelondb/src/adapters/sqlite/index.js
index 72a5af9..908ef6d 100644 index 72a5af9..d7871d9 100644
--- a/node_modules/@nozbe/watermelondb/src/adapters/sqlite/index.js --- a/node_modules/@nozbe/watermelondb/src/adapters/sqlite/index.js
+++ b/node_modules/@nozbe/watermelondb/src/adapters/sqlite/index.js +++ b/node_modules/@nozbe/watermelondb/src/adapters/sqlite/index.js
@@ -339,6 +339,19 @@ export default class SQLiteAdapter implements DatabaseAdapter { @@ -339,6 +339,19 @@ export default class SQLiteAdapter implements DatabaseAdapter {
) )
} }
+ unsafeVacuum(callback: ResultCallback<void): void { + unsafeVacuum(callback: ResultCallback<
+ this._dispatcher.call( + this._dispatcher.call(
+ 'unsafeVacuum', + 'unsafeVacuum',
+ [], + [],
+ (result) => { + (result) => {
+ if (result.value) { + if (result.value) {
+ logger.log('[SQLite] Database is vacuumed') + logger.log('[SQLite] Database
+ } + }
+ callback(result) + callback(result)
+ }, + },
@ -773,7 +770,7 @@ index 63c955f..4e2f43e 100644
| 'unsafeExecuteMultiple' | 'unsafeExecuteMultiple'
diff --git a/node_modules/@nozbe/watermelondb/src/adapters/type.js b/node_modules/@nozbe/watermelondb/src/adapters/type.js diff --git a/node_modules/@nozbe/watermelondb/src/adapters/type.js b/node_modules/@nozbe/watermelondb/src/adapters/type.js
index 8929541..bc3f95d 100644 index 8929541..b9a4174 100644
--- a/node_modules/@nozbe/watermelondb/src/adapters/type.js --- a/node_modules/@nozbe/watermelondb/src/adapters/type.js
+++ b/node_modules/@nozbe/watermelondb/src/adapters/type.js +++ b/node_modules/@nozbe/watermelondb/src/adapters/type.js
@@ -68,6 +68,8 @@ export interface DatabaseAdapter { @@ -68,6 +68,8 @@ export interface DatabaseAdapter {
@ -781,7 +778,7 @@ index 8929541..bc3f95d 100644
unsafeResetDatabase(callback: ResultCallback<void>): void; unsafeResetDatabase(callback: ResultCallback<void>): void;
+ unsafeVacuum(callback: ResultCallback<void>): void; + unsafeVacuum(callback: ResultCallback<void>): void;
+ +
// Performs work on the underlying database - see concrete DatabaseAdapter implementation for more details // Performs work on the underlying database - see concrete DatabaseAdapter implementation for more details
unsafeExecute(work: UnsafeExecuteOperations, callback: ResultCallback<void>): void; unsafeExecute(work: UnsafeExecuteOperations, callback: ResultCallback<void>): void;

View file

@ -1,22 +1,22 @@
diff --git a/node_modules/@react-native-community/cli-platform-apple/build/commands/runCommand/getBuildSettings.js b/node_modules/@react-native-community/cli-platform-apple/build/commands/runCommand/getBuildSettings.js diff --git a/node_modules/@react-native-community/cli-platform-apple/build/commands/runCommand/getBuildSettings.js b/node_modules/@react-native-community/cli-platform-apple/build/commands/runCommand/getBuildSettings.js
index 147bb53..b7cb80c 100644 index 8e60c59..bc201d2 100644
--- a/node_modules/@react-native-community/cli-platform-apple/build/commands/runCommand/getBuildSettings.js --- a/node_modules/@react-native-community/cli-platform-apple/build/commands/runCommand/getBuildSettings.js
+++ b/node_modules/@react-native-community/cli-platform-apple/build/commands/runCommand/getBuildSettings.js +++ b/node_modules/@react-native-community/cli-platform-apple/build/commands/runCommand/getBuildSettings.js
@@ -31,10 +31,16 @@ async function getBuildSettings(xcodeProject, mode, buildOutput, scheme, target) @@ -31,10 +31,16 @@ async function getBuildSettings(xcodeProject, mode, buildOutput, scheme, target)
encoding: 'utf8' encoding: 'utf8'
}); });
const settings = JSON.parse(buildSettings); const settings = JSON.parse(buildSettings);
+ const fistIndexForAppTarget = Math.max( + const firstIndexForAppTarget = Math.max(
+ 0, + 0,
+ settings.findIndex(({ + settings.findIndex(({
+ buildSettings: bs + buildSettings: bs
+ }) => bs.WRAPPER_EXTENSION === 'app') + }) => bs.WRAPPER_EXTENSION === 'app')
+ ); + );
const targets = settings.map(({ const targets = settings.map(({
target: settingsTarget target: settingsTarget
}) => settingsTarget); }) => settingsTarget);
- let selectedTarget = targets[0]; - let selectedTarget = targets[0];
+ let selectedTarget = targets[fistIndexForAppTarget]; + let selectedTarget = targets[firstIndexForAppTarget];
if (target) { if (target) {
if (!targets.includes(target)) { if (!targets.includes(target)) {
_cliTools().logger.info(`Target ${_chalk().default.bold(target)} not found for scheme ${_chalk().default.bold(scheme)}, automatically selected target ${_chalk().default.bold(selectedTarget)}`); _cliTools().logger.info(`Target ${_chalk().default.bold(target)} not found for scheme ${_chalk().default.bold(scheme)}, automatically selected target ${_chalk().default.bold(selectedTarget)}`);

View file

@ -1,70 +0,0 @@
diff --git a/node_modules/@sentry/utils/cjs/object.js b/node_modules/@sentry/utils/cjs/object.js
index a6151b5..67dcf57 100644
--- a/node_modules/@sentry/utils/cjs/object.js
+++ b/node_modules/@sentry/utils/cjs/object.js
@@ -203,7 +203,11 @@ function dropUndefinedKeys(inputValue) {
return _dropUndefinedKeys(inputValue, memoizationMap);
}
-function _dropUndefinedKeys(inputValue, memoizationMap) {
+function _dropUndefinedKeys(inputValue, memoizationMap, depth = 0) {
+ if (depth >= 5) {
+ return inputValue;
+ }
+
if (isPojo(inputValue)) {
// If this node has already been visited due to a circular reference, return the object it was mapped to in the new object
const memoVal = memoizationMap.get(inputValue);
@@ -217,7 +221,7 @@ function _dropUndefinedKeys(inputValue, memoizationMap) {
for (const key of Object.keys(inputValue)) {
if (typeof inputValue[key] !== 'undefined') {
- returnValue[key] = _dropUndefinedKeys(inputValue[key], memoizationMap);
+ returnValue[key] = _dropUndefinedKeys(inputValue[key], memoizationMap, depth + 1);
}
}
@@ -236,7 +240,7 @@ function _dropUndefinedKeys(inputValue, memoizationMap) {
memoizationMap.set(inputValue, returnValue);
inputValue.forEach((item) => {
- returnValue.push(_dropUndefinedKeys(item, memoizationMap));
+ returnValue.push(_dropUndefinedKeys(item, memoizationMap, depth + 1));
});
return returnValue ;
diff --git a/node_modules/@sentry/utils/esm/object.js b/node_modules/@sentry/utils/esm/object.js
index c63c177..3e43a58 100644
--- a/node_modules/@sentry/utils/esm/object.js
+++ b/node_modules/@sentry/utils/esm/object.js
@@ -201,7 +201,11 @@ function dropUndefinedKeys(inputValue) {
return _dropUndefinedKeys(inputValue, memoizationMap);
}
-function _dropUndefinedKeys(inputValue, memoizationMap) {
+function _dropUndefinedKeys(inputValue, memoizationMap, depth = 0) {
+ if (depth >= 5) {
+ return inputValue;
+ }
+
if (isPojo(inputValue)) {
// If this node has already been visited due to a circular reference, return the object it was mapped to in the new object
const memoVal = memoizationMap.get(inputValue);
@@ -215,7 +219,7 @@ function _dropUndefinedKeys(inputValue, memoizationMap) {
for (const key of Object.keys(inputValue)) {
if (typeof inputValue[key] !== 'undefined') {
- returnValue[key] = _dropUndefinedKeys(inputValue[key], memoizationMap);
+ returnValue[key] = _dropUndefinedKeys(inputValue[key], memoizationMap, depth + 1);
}
}
@@ -234,7 +238,7 @@ function _dropUndefinedKeys(inputValue, memoizationMap) {
memoizationMap.set(inputValue, returnValue);
inputValue.forEach((item) => {
- returnValue.push(_dropUndefinedKeys(item, memoizationMap));
+ returnValue.push(_dropUndefinedKeys(item, memoizationMap, depth + 1));
});
return returnValue ;

View file

@ -1,15 +1,14 @@
diff --git a/node_modules/expo-image/android/src/main/java/expo/modules/image/okhttp/ExpoImageOkHttpClientGlideModule.kt b/node_modules/expo-image/android/src/main/java/expo/modules/image/okhttp/ExpoImageOkHttpClientGlideModule.kt diff --git a/node_modules/expo-image/android/src/main/java/expo/modules/image/okhttp/ExpoImageOkHttpClientGlideModule.kt b/node_modules/expo-image/android/src/main/java/expo/modules/image/okhttp/ExpoImageOkHttpClientGlideModule.kt
index 071907c..e5c39f5 100644 index 071907c..edf10c1 100644
--- a/node_modules/expo-image/android/src/main/java/expo/modules/image/okhttp/ExpoImageOkHttpClientGlideModule.kt --- a/node_modules/expo-image/android/src/main/java/expo/modules/image/okhttp/ExpoImageOkHttpClientGlideModule.kt
+++ b/node_modules/expo-image/android/src/main/java/expo/modules/image/okhttp/ExpoImageOkHttpClientGlideModule.kt +++ b/node_modules/expo-image/android/src/main/java/expo/modules/image/okhttp/ExpoImageOkHttpClientGlideModule.kt
@@ -70,8 +70,16 @@ data class GlideUrlWrapper(val glideUrl: GlideUrl) { @@ -70,8 +70,15 @@ data class GlideUrlWrapper(val glideUrl: GlideUrl) {
@GlideModule @GlideModule
class ExpoImageOkHttpClientGlideModule : LibraryGlideModule() { class ExpoImageOkHttpClientGlideModule : LibraryGlideModule() {
+ companion object { + companion object {
+ var okHttpClient: OkHttpClient? = null + var okHttpClient: OkHttpClient? = null
+ } + }
+
override fun registerComponents(context: Context, glide: Glide, registry: Registry) { override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
- val client = OkHttpClient() - val client = OkHttpClient()
+ val client = if (okHttpClient != null) { + val client = if (okHttpClient != null) {
@ -21,13 +20,13 @@ index 071907c..e5c39f5 100644
// to make sure that the app will use only one client. // to make sure that the app will use only one client.
registry.replace(GlideUrl::class.java, InputStream::class.java, OkHttpUrlLoader.Factory(client)) registry.replace(GlideUrl::class.java, InputStream::class.java, OkHttpUrlLoader.Factory(client))
diff --git a/node_modules/expo-image/ios/ExpoImage.podspec b/node_modules/expo-image/ios/ExpoImage.podspec diff --git a/node_modules/expo-image/ios/ExpoImage.podspec b/node_modules/expo-image/ios/ExpoImage.podspec
index de8bc65..564397d 100644 index 21bef71..d662d23 100644
--- a/node_modules/expo-image/ios/ExpoImage.podspec --- a/node_modules/expo-image/ios/ExpoImage.podspec
+++ b/node_modules/expo-image/ios/ExpoImage.podspec +++ b/node_modules/expo-image/ios/ExpoImage.podspec
@@ -18,9 +18,7 @@ Pod::Spec.new do |s| @@ -20,9 +20,7 @@ Pod::Spec.new do |s|
s.dependency 'ExpoModulesCore' s.dependency 'ExpoModulesCore'
s.dependency 'SDWebImage', '~> 5.19.1' s.dependency 'SDWebImage', '~> 5.19.1'
s.dependency 'SDWebImageWebPCoder', '~> 0.14.6'
- s.dependency 'SDWebImageAVIFCoder', '~> 0.11.0' - s.dependency 'SDWebImageAVIFCoder', '~> 0.11.0'
s.dependency 'SDWebImageSVGCoder', '~> 1.7.0' s.dependency 'SDWebImageSVGCoder', '~> 1.7.0'
- s.dependency 'libavif/libdav1d' - s.dependency 'libavif/libdav1d'
@ -35,23 +34,22 @@ index de8bc65..564397d 100644
# Swift/Objective-C compatibility # Swift/Objective-C compatibility
s.pod_target_xcconfig = { s.pod_target_xcconfig = {
diff --git a/node_modules/expo-image/ios/ImageModule.swift b/node_modules/expo-image/ios/ImageModule.swift diff --git a/node_modules/expo-image/ios/ImageModule.swift b/node_modules/expo-image/ios/ImageModule.swift
index e4b7fca..5057b0a 100644 index 4bab386..a41d924 100644
--- a/node_modules/expo-image/ios/ImageModule.swift --- a/node_modules/expo-image/ios/ImageModule.swift
+++ b/node_modules/expo-image/ios/ImageModule.swift +++ b/node_modules/expo-image/ios/ImageModule.swift
@@ -3,7 +3,6 @@ @@ -2,7 +2,6 @@
import ExpoModulesCore import ExpoModulesCore
import SDWebImage import SDWebImage
import SDWebImageWebPCoder
-import SDWebImageAVIFCoder -import SDWebImageAVIFCoder
import SDWebImageSVGCoder import SDWebImageSVGCoder
public final class ImageModule: Module { public final class ImageModule: Module {
@@ -193,7 +192,7 @@ public final class ImageModule: Module { @@ -211,7 +210,6 @@ public final class ImageModule: Module {
// This coder is much slower, but it's the only one that works in iOS 13 static func registerCoders() {
SDImageCodersManager.shared.addCoder(SDImageWebPCoder.shared) // By default Animated WebP is not supported
} SDImageCodersManager.shared.addCoder(SDImageAWebPCoder.shared)
- SDImageCodersManager.shared.addCoder(SDImageAVIFCoder.shared) - SDImageCodersManager.shared.addCoder(SDImageAVIFCoder.shared)
+
SDImageCodersManager.shared.addCoder(SDImageSVGCoder.shared) SDImageCodersManager.shared.addCoder(SDImageSVGCoder.shared)
SDImageCodersManager.shared.addCoder(SDImageHEICCoder.shared) SDImageCodersManager.shared.addCoder(SDImageHEICCoder.shared)
} }

View file

@ -1,10 +0,0 @@
diff --git a/node_modules/expo-modules-core/build/web/CoreModule.js b/node_modules/expo-modules-core/build/web/CoreModule.js
index 7a02851..b1b9561 100644
--- a/node_modules/expo-modules-core/build/web/CoreModule.js
+++ b/node_modules/expo-modules-core/build/web/CoreModule.js
@@ -1,4 +1,4 @@
-import uuid from '../uuid';
+import * as uuid from 'uuid';
class EventEmitter {
listeners;
addListener(eventName, listener) {

View file

@ -0,0 +1,12 @@
Binary files /dev/null and b/node_modules/expo-modules-core/android/build/tmp/kotlin-classes/debug/expo/modules/rncompatibility/ReactNativeFeatureFlags.class differ
diff --git a/node_modules/expo-modules-core/src/web/index.web.ts b/node_modules/expo-modules-core/src/web/index.web.ts
index 611564a..d9b46db 100644
--- a/node_modules/expo-modules-core/src/web/index.web.ts
+++ b/node_modules/expo-modules-core/src/web/index.web.ts
@@ -1,5 +1,5 @@
import { EventEmitter, NativeModule, SharedObject, SharedRef } from './CoreModule';
-import uuid from '../uuid';
+import * as uuid from 'uuid';
// jest-expo imports to this file directly without going through the global types
// Exporting the types to let jest-expo to know the globalThis types

View file

@ -1,13 +1,13 @@
diff --git a/node_modules/expo-video-thumbnails/ios/VideoThumbnailsModule.swift b/node_modules/expo-video-thumbnails/ios/VideoThumbnailsModule.swift diff --git a/node_modules/expo-video-thumbnails/ios/VideoThumbnailsModule.swift b/node_modules/expo-video-thumbnails/ios/VideoThumbnailsModule.swift
index 2b01a1d..78c7ffa 100644 index 069e3e4..c32ba6c 100644
--- a/node_modules/expo-video-thumbnails/ios/VideoThumbnailsModule.swift --- a/node_modules/expo-video-thumbnails/ios/VideoThumbnailsModule.swift
+++ b/node_modules/expo-video-thumbnails/ios/VideoThumbnailsModule.swift +++ b/node_modules/expo-video-thumbnails/ios/VideoThumbnailsModule.swift
@@ -7,7 +7,7 @@ public class VideoThumbnailsModule: Module { @@ -7,7 +7,7 @@ public class VideoThumbnailsModule: Module {
public func definition() -> ModuleDefinition { public func definition() -> ModuleDefinition {
Name("ExpoVideoThumbnails") Name("ExpoVideoThumbnails")
- AsyncFunction("getThumbnail", getVideoThumbnail).runOnQueue(.main) - AsyncFunction("getThumbnail", getVideoThumbnail)
+ AsyncFunction("getThumbnail", getVideoThumbnail).runOnQueue(.global()) + AsyncFunction("getThumbnail", getVideoThumbnail).runOnQueue(.global())
} }
internal func getVideoThumbnail(sourceFilename: URL, options: VideoThumbnailsOptions) throws -> [String: Any] { internal func getVideoThumbnail(sourceFilename: URL, options: VideoThumbnailsOptions) throws -> [String: Any] {

View file

@ -1,169 +0,0 @@
diff --git a/node_modules/react-native-keychain/RNKeychainManager/RNKeychainManager.h b/node_modules/react-native-keychain/RNKeychainManager/RNKeychainManager.h
index 4a1234f..f3e2308 100644
--- a/node_modules/react-native-keychain/RNKeychainManager/RNKeychainManager.h
+++ b/node_modules/react-native-keychain/RNKeychainManager/RNKeychainManager.h
@@ -10,5 +10,6 @@
#import <React/RCTLog.h>
@interface RNKeychainManager : NSObject <RCTBridgeModule>
-
+-(OSStatus)deleteCredentialsForServer:(NSString *)server;
+-(NSArray<NSString*>*)getAllServersForInternetPasswords;
@end
diff --git a/node_modules/react-native-keychain/RNKeychainManager/RNKeychainManager.m b/node_modules/react-native-keychain/RNKeychainManager/RNKeychainManager.m
index 58d555f..d8c4069 100644
--- a/node_modules/react-native-keychain/RNKeychainManager/RNKeychainManager.m
+++ b/node_modules/react-native-keychain/RNKeychainManager/RNKeychainManager.m
@@ -275,6 +275,36 @@ SecAccessControlCreateFlags accessControlValue(NSDictionary *options)
return SecItemDelete((__bridge CFDictionaryRef) query);
}
+-(NSArray<NSString*>*)getAllServersForInternetPasswords
+{
+ NSMutableDictionary *query = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+ (__bridge id)kCFBooleanTrue, (__bridge id)kSecReturnAttributes,
+ (__bridge id)kSecMatchLimitAll, (__bridge id)kSecMatchLimit,
+ nil];
+ NSMutableArray<NSString*> *servers = [NSMutableArray<NSString*> new];
+
+ [query setObject:(__bridge id)kSecClassInternetPassword forKey:(__bridge id)kSecClass];
+ NSArray *result = nil;
+ CFTypeRef resultRef = NULL;
+ OSStatus osStatus = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef*)&resultRef);
+ if (osStatus != noErr && osStatus != errSecItemNotFound) {
+ NSError *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:osStatus userInfo:nil];
+ @throw error;
+ } else if (osStatus != errSecItemNotFound) {
+ result = (__bridge NSArray*)(resultRef);
+ if (result != NULL) {
+ for (id entry in result) {
+ NSString *serverData = [entry objectForKey:(__bridge NSString *)kSecAttrServer];
+ if (serverData != NULL) {
+ [servers addObject:serverData];
+ }
+ }
+ }
+ }
+
+ return servers;
+}
+
-(NSArray<NSString*>*)getAllServicesForSecurityClasses:(NSArray *)secItemClasses
{
NSMutableDictionary *query = [NSMutableDictionary dictionaryWithObjectsAndKeys:
@@ -607,4 +637,14 @@ RCT_EXPORT_METHOD(getAllGenericPasswordServices:(RCTPromiseResolveBlock)resolve
}
}
+RCT_EXPORT_METHOD(getAllInternetPasswordServers:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
+{
+ @try {
+ NSArray *servers = [self getAllServersForInternetPasswords];
+ return resolve(servers);
+ } @catch (NSError *nsError) {
+ return rejectWithError(reject, nsError);
+ }
+}
+
@end
diff --git a/node_modules/react-native-keychain/android/src/main/java/com/oblador/keychain/KeychainModule.java b/node_modules/react-native-keychain/android/src/main/java/com/oblador/keychain/KeychainModule.java
index 9413000..422581a 100644
--- a/node_modules/react-native-keychain/android/src/main/java/com/oblador/keychain/KeychainModule.java
+++ b/node_modules/react-native-keychain/android/src/main/java/com/oblador/keychain/KeychainModule.java
@@ -1,6 +1,7 @@
package com.oblador.keychain;
import android.os.Build;
+import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
@@ -129,6 +130,7 @@ public class KeychainModule extends ReactContextBaseJavaModule {
//region Members
/** Name-to-instance lookup map. */
private final Map<String, CipherStorage> cipherStorageMap = new HashMap<>();
+ private final Map<String, Bundle> cachedCredentialsMap = new HashMap<>();
/** Shared preferences storage. */
private final PrefsStorage prefsStorage;
//endregion
@@ -140,13 +142,7 @@ public class KeychainModule extends ReactContextBaseJavaModule {
super(reactContext);
prefsStorage = new PrefsStorage(reactContext);
- addCipherStorageToMap(new CipherStorageFacebookConceal(reactContext));
addCipherStorageToMap(new CipherStorageKeystoreAesCbc());
-
- // we have a references to newer api that will fail load of app classes in old androids OS
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- addCipherStorageToMap(new CipherStorageKeystoreRsaEcb());
- }
}
/** Allow initialization in chain. */
@@ -278,6 +274,11 @@ public class KeychainModule extends ReactContextBaseJavaModule {
@Nullable final ReadableMap options,
@NonNull final Promise promise) {
try {
+ Bundle cached = cachedCredentialsMap.get(alias);
+ if (cached != null) {
+ promise.resolve(Arguments.fromBundle(cached));
+ return;
+ }
final ResultSet resultSet = prefsStorage.getEncryptedEntry(alias);
if (resultSet == null) {
@@ -310,6 +311,7 @@ public class KeychainModule extends ReactContextBaseJavaModule {
credentials.putString(Maps.USERNAME, decryptionResult.username);
credentials.putString(Maps.PASSWORD, decryptionResult.password);
credentials.putString(Maps.STORAGE, cipher.getCipherStorageName());
+ cachedCredentialsMap.put(alias, Arguments.toBundle(credentials));
promise.resolve(credentials);
} catch (KeyStoreAccessException e) {
@@ -382,6 +384,7 @@ public class KeychainModule extends ReactContextBaseJavaModule {
}
// And then we remove the entry in the shared preferences
prefsStorage.removeEntry(alias);
+ cachedCredentialsMap.remove(alias);
promise.resolve(true);
} catch (KeyStoreAccessException e) {
diff --git a/node_modules/react-native-keychain/index.js b/node_modules/react-native-keychain/index.js
index 083938e..c8728a0 100644
--- a/node_modules/react-native-keychain/index.js
+++ b/node_modules/react-native-keychain/index.js
@@ -351,6 +351,21 @@ export function canImplyAuthentication(options?: Options): Promise<boolean> {
return RNKeychainManager.canCheckAuthentication(options);
}
+/**
++ * Gets all `kSecAttrServer` values used in internet credentials for iOS.
++ * @return {Promise} Resolves to an array of strings
++ */
+export async function getAllInternetPasswordServers(): Promise<string[]> {
+ if (Platform.OS !== 'ios') {
+ return Promise.reject(
+ new Error(
+ `getAllInternetPasswordServers() is not supported on ${Platform.OS}`
+ )
+ );
+ }
+ return RNKeychainManager.getAllInternetPasswordServers();
+}
+
//* ANDROID ONLY */
/**
diff --git a/node_modules/react-native-keychain/typings/react-native-keychain.d.ts b/node_modules/react-native-keychain/typings/react-native-keychain.d.ts
index 6846468..bc03596 100644
--- a/node_modules/react-native-keychain/typings/react-native-keychain.d.ts
+++ b/node_modules/react-native-keychain/typings/react-native-keychain.d.ts
@@ -97,6 +97,8 @@ declare module 'react-native-keychain' {
function getAllGenericPasswordServices(): Promise<string[]>;
+ function getAllInternetPasswordServers(): Promise<string[]>;
+
function hasInternetCredentials(server: string): Promise<false | Result>;
function setInternetCredentials(

View file

@ -0,0 +1,122 @@
diff --git a/node_modules/react-native-keychain/ios/RNKeychainManager/RNKeychainManager.h b/node_modules/react-native-keychain/ios/RNKeychainManager/RNKeychainManager.h
index 4a1234f..f3e2308 100644
--- a/node_modules/react-native-keychain/ios/RNKeychainManager/RNKeychainManager.h
+++ b/node_modules/react-native-keychain/ios/RNKeychainManager/RNKeychainManager.h
@@ -10,5 +10,6 @@
#import <React/RCTLog.h>
@interface RNKeychainManager : NSObject <RCTBridgeModule>
-
+-(OSStatus)deleteCredentialsForServer:(NSString *)server withOptions:(NSDictionary * __nullable)options;
+-(NSArray<NSString*>*)getAllServersForInternetPasswords;
@end
diff --git a/node_modules/react-native-keychain/ios/RNKeychainManager/RNKeychainManager.m b/node_modules/react-native-keychain/ios/RNKeychainManager/RNKeychainManager.m
index 18e42ab..ff130ab 100644
--- a/node_modules/react-native-keychain/ios/RNKeychainManager/RNKeychainManager.m
+++ b/node_modules/react-native-keychain/ios/RNKeychainManager/RNKeychainManager.m
@@ -209,6 +209,36 @@ SecAccessControlCreateFlags accessControlValue(NSDictionary *options)
return 0;
}
+-(NSArray<NSString*>*)getAllServersForInternetPasswords
+{
+ NSMutableDictionary *query = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+ (__bridge id)kCFBooleanTrue, (__bridge id)kSecReturnAttributes,
+ (__bridge id)kSecMatchLimitAll, (__bridge id)kSecMatchLimit,
+ nil];
+ NSMutableArray<NSString*> *servers = [NSMutableArray<NSString*> new];
+
+ [query setObject:(__bridge id)kSecClassInternetPassword forKey:(__bridge id)kSecClass];
+ NSArray *result = nil;
+ CFTypeRef resultRef = NULL;
+ OSStatus osStatus = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef*)&resultRef);
+ if (osStatus != noErr && osStatus != errSecItemNotFound) {
+ NSError *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:osStatus userInfo:nil];
+ @throw error;
+ } else if (osStatus != errSecItemNotFound) {
+ result = (__bridge NSArray*)(resultRef);
+ if (result != NULL) {
+ for (id entry in result) {
+ NSString *serverData = [entry objectForKey:(__bridge NSString *)kSecAttrServer];
+ if (serverData != NULL) {
+ [servers addObject:serverData];
+ }
+ }
+ }
+ }
+
+ return servers;
+}
+
- (void)insertKeychainEntry:(NSDictionary *)attributes
withOptions:(NSDictionary * __nullable)options
resolver:(RCTPromiseResolveBlock)resolve
@@ -663,4 +693,14 @@ RCT_EXPORT_METHOD(getAllGenericPasswordServices:(RCTPromiseResolveBlock)resolve
}
}
+RCT_EXPORT_METHOD(getAllInternetPasswordServers:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
+{
+ @try {
+ NSArray *servers = [self getAllServersForInternetPasswords];
+ return resolve(servers);
+ } @catch (NSError *nsError) {
+ return rejectWithError(reject, nsError);
+ }
+}
+
@end
diff --git a/node_modules/react-native-keychain/lib/typescript/index.d.ts b/node_modules/react-native-keychain/lib/typescript/index.d.ts
index 43f2e2f..dcef782 100644
--- a/node_modules/react-native-keychain/lib/typescript/index.d.ts
+++ b/node_modules/react-native-keychain/lib/typescript/index.d.ts
@@ -73,6 +73,17 @@ export declare function resetGenericPassword(serviceOrOptions?: string | BaseOpt
* ```
*/
export declare function getAllGenericPasswordServices(): Promise<string[]>;
+/**
+* Gets all `kSecAttrServer` values used in internet credentials for iOS.
+* @return {Promise<string[]>} Resolves to an array of strings
+*
+* @example
+* ```typescript
+* const servers = await Keychain.getAllInternetPasswordServers();
+* console.log('Servers:', servers);
+* ```
+*/
+export declare function getAllInternetPasswordServers(): Promise<string[]>;
/**
* Checks if internet credentials exist for the given server.
*
diff --git a/node_modules/react-native-keychain/src/index.ts b/node_modules/react-native-keychain/src/index.ts
index 7bfe371..3ac11b5 100644
--- a/node_modules/react-native-keychain/src/index.ts
+++ b/node_modules/react-native-keychain/src/index.ts
@@ -132,6 +132,27 @@ export function getAllGenericPasswordServices(): Promise<string[]> {
return RNKeychainManager.getAllGenericPasswordServices();
}
+/**
+* Gets all `kSecAttrServer` values used in internet credentials for iOS.
+* @return {Promise<string>} Resolves to an array of strings
+*
+* @example
+* ```typescript
+* const servers = await Keychain.getAllInternetPasswordServers();
+* console.log('Servers:', servers);
+* ```
+*/
+export async function getAllInternetPasswordServers(): Promise<string[]> {
+ if (Platform.OS !== 'ios') {
+ return Promise.reject(
+ new Error(
+ `getAllInternetPasswordServers() is not supported on ${Platform.OS}`
+ )
+ );
+ }
+ return RNKeychainManager.getAllInternetPasswordServers();
+}
+
/**
* Checks if internet credentials exist for the given server.
*

View file

@ -73,6 +73,31 @@ index 481aaf0..609e359 100644
public void requestPermissions(String[] permissions, int requestCode, PermissionListener listener) { public void requestPermissions(String[] permissions, int requestCode, PermissionListener listener) {
mPermissionListener = listener; mPermissionListener = listener;
requestPermissions(permissions, requestCode); requestPermissions(permissions, requestCode);
diff --git a/node_modules/react-native-navigation/lib/android/app/src/main/java/com/reactnativenavigation/NavigationApplication.java b/node_modules/react-native-navigation/lib/android/app/src/main/java/com/reactnativenavigation/NavigationApplication.java
index 0eced0f..251d72c 100644
--- a/node_modules/react-native-navigation/lib/android/app/src/main/java/com/reactnativenavigation/NavigationApplication.java
+++ b/node_modules/react-native-navigation/lib/android/app/src/main/java/com/reactnativenavigation/NavigationApplication.java
@@ -4,6 +4,7 @@ import android.app.Application;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
+import com.facebook.react.soloader.OpenSourceMergedSoMapping;
import com.facebook.soloader.SoLoader;
import com.reactnativenavigation.react.ReactGateway;
import com.reactnativenavigation.viewcontrollers.externalcomponent.ExternalComponentCreator;
@@ -23,7 +24,11 @@ public abstract class NavigationApplication extends Application implements React
public void onCreate() {
super.onCreate();
instance = this;
- SoLoader.init(this, false);
+ try {
+ SoLoader.init(this, OpenSourceMergedSoMapping.INSTANCE);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
reactGateway = createReactGateway();
}
diff --git a/node_modules/react-native-navigation/lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationModule.java b/node_modules/react-native-navigation/lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationModule.java diff --git a/node_modules/react-native-navigation/lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationModule.java b/node_modules/react-native-navigation/lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationModule.java
index 4cc09eb..857bbd4 100644 index 4cc09eb..857bbd4 100644
--- a/node_modules/react-native-navigation/lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationModule.java --- a/node_modules/react-native-navigation/lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationModule.java
@ -296,6 +321,18 @@ index 834d734..3fc00c3 100644
want |= Typeface.ITALIC; want |= Typeface.ITALIC;
} }
diff --git a/node_modules/react-native-navigation/lib/android/app/src/main/java/com/reactnativenavigation/utils/ReactViewGroup.kt b/node_modules/react-native-navigation/lib/android/app/src/main/java/com/reactnativenavigation/utils/ReactViewGroup.kt
index f92580c..a58fa7b 100644
--- a/node_modules/react-native-navigation/lib/android/app/src/main/java/com/reactnativenavigation/utils/ReactViewGroup.kt
+++ b/node_modules/react-native-navigation/lib/android/app/src/main/java/com/reactnativenavigation/utils/ReactViewGroup.kt
@@ -4,4 +4,4 @@ import com.facebook.react.views.view.ReactViewBackgroundDrawable
import com.facebook.react.views.view.ReactViewGroup
val ReactViewGroup.borderRadius: Float
- get() = (background as? ReactViewBackgroundDrawable)?.fullBorderRadius ?: 0f
\ No newline at end of file
+ get() = 0f
\ No newline at end of file
diff --git a/node_modules/react-native-navigation/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/child/ChildController.java b/node_modules/react-native-navigation/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/child/ChildController.java diff --git a/node_modules/react-native-navigation/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/child/ChildController.java b/node_modules/react-native-navigation/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/child/ChildController.java
index 3acc41d..ebc8d18 100644 index 3acc41d..ebc8d18 100644
--- a/node_modules/react-native-navigation/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/child/ChildController.java --- a/node_modules/react-native-navigation/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/child/ChildController.java
@ -327,6 +364,32 @@ index 3acc41d..ebc8d18 100644
return insets; return insets;
} }
diff --git a/node_modules/react-native-navigation/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/viewcontroller/LayoutDirectionApplier.kt b/node_modules/react-native-navigation/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/viewcontroller/LayoutDirectionApplier.kt
index 89216ae..345207a 100644
--- a/node_modules/react-native-navigation/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/viewcontroller/LayoutDirectionApplier.kt
+++ b/node_modules/react-native-navigation/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/viewcontroller/LayoutDirectionApplier.kt
@@ -1,15 +1,17 @@
package com.reactnativenavigation.viewcontrollers.viewcontroller
+import com.facebook.react.bridge.ReactContext
import com.facebook.react.ReactInstanceManager
import com.facebook.react.modules.i18nmanager.I18nUtil
import com.reactnativenavigation.options.Options
class LayoutDirectionApplier {
fun apply(root: ViewController<*>, options: Options, instanceManager: ReactInstanceManager) {
- if (options.layout.direction.hasValue() && instanceManager.currentReactContext != null) {
+ val reactContext = instanceManager.currentReactContext as? ReactContext
+ if (reactContext != null && options.layout.direction.hasValue()) {
root.activity.window.decorView.layoutDirection = options.layout.direction.get()
- I18nUtil.getInstance().allowRTL(instanceManager.currentReactContext, options.layout.direction.isRtl)
- I18nUtil.getInstance().forceRTL(instanceManager.currentReactContext, options.layout.direction.isRtl)
+ I18nUtil.getInstance().allowRTL(reactContext, options.layout.direction.isRtl)
+ I18nUtil.getInstance().forceRTL(reactContext, options.layout.direction.isRtl)
}
}
}
\ No newline at end of file
diff --git a/node_modules/react-native-navigation/lib/android/app/src/reactNative71/java/com/reactnativenavigation/react/ReactGateway.java b/node_modules/react-native-navigation/lib/android/app/src/reactNative71/java/com/reactnativenavigation/react/ReactGateway.java diff --git a/node_modules/react-native-navigation/lib/android/app/src/reactNative71/java/com/reactnativenavigation/react/ReactGateway.java b/node_modules/react-native-navigation/lib/android/app/src/reactNative71/java/com/reactnativenavigation/react/ReactGateway.java
index 035ec31..630b8d4 100644 index 035ec31..630b8d4 100644
--- a/node_modules/react-native-navigation/lib/android/app/src/reactNative71/java/com/reactnativenavigation/react/ReactGateway.java --- a/node_modules/react-native-navigation/lib/android/app/src/reactNative71/java/com/reactnativenavigation/react/ReactGateway.java
@ -342,6 +405,76 @@ index 035ec31..630b8d4 100644
+ } + }
+ } + }
} }
diff --git a/node_modules/react-native-navigation/lib/android/app/src/reactNative71/java/com/reactnativenavigation/react/modal/ModalContentLayout.kt b/node_modules/react-native-navigation/lib/android/app/src/reactNative71/java/com/reactnativenavigation/react/modal/ModalContentLayout.kt
index ea8516f..f275c18 100644
--- a/node_modules/react-native-navigation/lib/android/app/src/reactNative71/java/com/reactnativenavigation/react/modal/ModalContentLayout.kt
+++ b/node_modules/react-native-navigation/lib/android/app/src/reactNative71/java/com/reactnativenavigation/react/modal/ModalContentLayout.kt
@@ -50,13 +50,19 @@ class ModalContentLayout(context: Context?) : ReactViewGroup(context), RootView{
}
}
override fun onChildStartedNativeGesture(child: View, androidEvent: MotionEvent?) {
- mJSTouchDispatcher.onChildStartedNativeGesture(androidEvent, this.getEventDispatcher())
+ androidEvent?.let {
+ mJSTouchDispatcher.onChildStartedNativeGesture(it, this.getEventDispatcher()!!)
+ }
}
override fun onChildStartedNativeGesture(androidEvent: MotionEvent?) {
- mJSTouchDispatcher.onChildStartedNativeGesture(androidEvent, this.getEventDispatcher())
+ androidEvent?.let {
+ mJSTouchDispatcher.onChildStartedNativeGesture(it, this.getEventDispatcher()!!)
+ }
}
override fun onChildEndedNativeGesture(child: View, androidEvent: MotionEvent?) {
- mJSTouchDispatcher.onChildEndedNativeGesture(androidEvent, this.getEventDispatcher())
+ androidEvent?.let {
+ mJSTouchDispatcher.onChildEndedNativeGesture(it, this.getEventDispatcher()!!)
+ }
}
override fun requestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {}
private fun getEventDispatcher(): EventDispatcher? {
@@ -74,12 +80,16 @@ class ModalContentLayout(context: Context?) : ReactViewGroup(context), RootView{
}
override fun onInterceptTouchEvent(event: MotionEvent?): Boolean {
- mJSTouchDispatcher.handleTouchEvent(event, getEventDispatcher())
+ event?.let {
+ mJSTouchDispatcher.handleTouchEvent(it, getEventDispatcher()!!)
+ }
return super.onInterceptTouchEvent(event)
}
override fun onTouchEvent(event: MotionEvent?): Boolean {
- mJSTouchDispatcher.handleTouchEvent(event, getEventDispatcher())
+ event?.let {
+ mJSTouchDispatcher.handleTouchEvent(it, getEventDispatcher()!!)
+ }
super.onTouchEvent(event)
return true
}
diff --git a/node_modules/react-native-navigation/lib/ios/BottomTabsBasePresenter.m b/node_modules/react-native-navigation/lib/ios/BottomTabsBasePresenter.m
index 75aa424..f0a7e08 100644
--- a/node_modules/react-native-navigation/lib/ios/BottomTabsBasePresenter.m
+++ b/node_modules/react-native-navigation/lib/ios/BottomTabsBasePresenter.m
@@ -29,8 +29,6 @@
[self applyBackgroundColor:[withDefault.bottomTabs.backgroundColor withDefault:nil]
translucent:[withDefault.bottomTabs.translucent withDefault:NO]];
[bottomTabs setTabBarHideShadow:[withDefault.bottomTabs.hideShadow withDefault:NO]];
- [bottomTabs setTabBarStyle:[RCTConvert UIBarStyle:[withDefault.bottomTabs.barStyle
- withDefault:@"default"]]];
[self applyTabBarBorder:withDefault.bottomTabs];
[self applyTabBarShadow:withDefault.bottomTabs.shadow];
}
@@ -59,10 +57,6 @@
[self setTabBarBackgroundColor:mergeOptions.bottomTabs.backgroundColor.get];
}
- if (mergeOptions.bottomTabs.barStyle.hasValue) {
- [bottomTabs setTabBarStyle:[RCTConvert UIBarStyle:mergeOptions.bottomTabs.barStyle.get]];
- }
-
if (mergeOptions.bottomTabs.translucent.hasValue) {
[bottomTabs setTabBarTranslucent:mergeOptions.bottomTabs.translucent.get];
}
diff --git a/node_modules/react-native-navigation/lib/ios/RNNComponentViewController.m b/node_modules/react-native-navigation/lib/ios/RNNComponentViewController.m diff --git a/node_modules/react-native-navigation/lib/ios/RNNComponentViewController.m b/node_modules/react-native-navigation/lib/ios/RNNComponentViewController.m
index fc482a6..9406bbf 100644 index fc482a6..9406bbf 100644
--- a/node_modules/react-native-navigation/lib/ios/RNNComponentViewController.m --- a/node_modules/react-native-navigation/lib/ios/RNNComponentViewController.m
@ -376,6 +509,30 @@ index b44f24f..bf4e1c3 100644
[hitTestResult isKindOfClass:[RCTModalHostView class]] || [hitTestResult isKindOfClass:[RCTModalHostView class]] ||
[hitTestResult isKindOfClass:NSClassFromString(@"RCTRootComponentView")]) { [hitTestResult isKindOfClass:NSClassFromString(@"RCTRootComponentView")]) {
return nil; return nil;
diff --git a/node_modules/react-native-navigation/lib/ios/RNNStackPresenter.m b/node_modules/react-native-navigation/lib/ios/RNNStackPresenter.m
index 5f4218e..8513863 100644
--- a/node_modules/react-native-navigation/lib/ios/RNNStackPresenter.m
+++ b/node_modules/react-native-navigation/lib/ios/RNNStackPresenter.m
@@ -67,8 +67,6 @@
[_interactivePopGestureDelegate setEnabled:[withDefault.popGesture withDefault:YES]];
stack.interactivePopGestureRecognizer.delegate = _interactivePopGestureDelegate;
- [stack
- setBarStyle:[RCTConvert UIBarStyle:[withDefault.topBar.barStyle withDefault:@"default"]]];
[stack setRootBackgroundImage:[withDefault.rootBackgroundImage withDefault:nil]];
[stack setNavigationBarTestId:[withDefault.topBar.testID withDefault:nil]];
[stack setNavigationBarVisible:[withDefault.topBar.visible withDefault:YES]
@@ -125,10 +123,6 @@
[stack hideBarsOnScroll:[mergeOptions.topBar.hideOnScroll get]];
}
- if (mergeOptions.topBar.barStyle.hasValue) {
- [stack setBarStyle:[RCTConvert UIBarStyle:mergeOptions.topBar.barStyle.get]];
- }
-
if (mergeOptions.topBar.background.clipToBounds.hasValue) {
[stack setNavigationBarClipsToBounds:[mergeOptions.topBar.background.clipToBounds get]];
}
diff --git a/node_modules/react-native-navigation/lib/src/interfaces/Options.ts b/node_modules/react-native-navigation/lib/src/interfaces/Options.ts diff --git a/node_modules/react-native-navigation/lib/src/interfaces/Options.ts b/node_modules/react-native-navigation/lib/src/interfaces/Options.ts
index 1ab5b4e..ccd0b74 100644 index 1ab5b4e..ccd0b74 100644
--- a/node_modules/react-native-navigation/lib/src/interfaces/Options.ts --- a/node_modules/react-native-navigation/lib/src/interfaces/Options.ts

View file

@ -0,0 +1,12 @@
diff --git a/node_modules/react-native-reanimated/src/mock.ts b/node_modules/react-native-reanimated/src/mock.ts
index 3d8e3f8..b32d457 100644
--- a/node_modules/react-native-reanimated/src/mock.ts
+++ b/node_modules/react-native-reanimated/src/mock.ts
@@ -114,6 +114,7 @@ const hook = {
}),
// useFrameCallback: ADD ME IF NEEDED
useAnimatedKeyboard: () => ({ height: 0, state: 0 }),
+ useReducedMotion: () => false,
// useScrollViewOffset: ADD ME IF NEEDED
};

View file

@ -1,8 +1,8 @@
diff --git a/node_modules/react-native-svg/src/xml.tsx b/node_modules/react-native-svg/src/xml.tsx diff --git a/node_modules/react-native-svg/src/xml.tsx b/node_modules/react-native-svg/src/xml.tsx
index 9e2352a..fb45382 100644 index edfaa9b..41246bb 100644
--- a/node_modules/react-native-svg/src/xml.tsx --- a/node_modules/react-native-svg/src/xml.tsx
+++ b/node_modules/react-native-svg/src/xml.tsx +++ b/node_modules/react-native-svg/src/xml.tsx
@@ -138,9 +138,11 @@ export function SvgUri(props: UriProps) { @@ -87,9 +87,11 @@ export function SvgUri(props: UriProps) {
uri uri
? fetchText(uri) ? fetchText(uri)
.then((data) => { .then((data) => {

View file

@ -1,17 +0,0 @@
diff --git a/node_modules/react-native-video/ios/Video/Features/RCTVideoUtils.swift b/node_modules/react-native-video/ios/Video/Features/RCTVideoUtils.swift
index c13c4d9..b86a860 100644
--- a/node_modules/react-native-video/ios/Video/Features/RCTVideoUtils.swift
+++ b/node_modules/react-native-video/ios/Video/Features/RCTVideoUtils.swift
@@ -9,7 +9,11 @@ enum RCTVideoAssetsUtils {
for mediaCharacteristic: AVMediaCharacteristic
) async -> AVMediaSelectionGroup? {
if #available(iOS 15, tvOS 15, visionOS 1.0, *) {
- return try? await asset?.loadMediaSelectionGroup(for: mediaCharacteristic)
+ if let mediaSelectionGroup = try? await asset?.loadMediaSelectionGroup(for: mediaCharacteristic) {
+ return mediaSelectionGroup
+ }
+
+ return nil
} else {
#if !os(visionOS)
return asset?.mediaSelectionGroup(forMediaCharacteristic: mediaCharacteristic)

View file

@ -16,7 +16,7 @@ if [[ "$OSTYPE" == "darwin"* ]]; then
gem install bundler --version 2.5.11 || exit 1 gem install bundler --version 2.5.11 || exit 1
fi fi
if !(gem list cocoapods -i --version 1.15.2) > /dev/null 2>&1; then if !(gem list cocoapods -i --version 1.16.1) > /dev/null 2>&1; then
cocoapods cocoapods
fi fi
fi fi

View file

@ -2,7 +2,7 @@
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {Image} from 'expo-image'; import {Image} from 'expo-image';
import {LinearGradient} from 'expo-linear-gradient'; import {LinearGradient, type LinearGradientProps} from 'expo-linear-gradient';
import React, {useMemo} from 'react'; import React, {useMemo} from 'react';
import {StyleSheet, useWindowDimensions, View} from 'react-native'; import {StyleSheet, useWindowDimensions, View} from 'react-native';
@ -20,9 +20,9 @@ type Props = {
type?: 'image' | 'video'; type?: 'image' | 'video';
} }
const GRADIENT_COLORS = ['rgba(0, 0, 0, 0)', 'rgba(0, 0, 0, .16)']; const GRADIENT_COLORS: LinearGradientProps['colors'] = ['rgba(0, 0, 0, 0)', 'rgba(0, 0, 0, .16)'];
const GRADIENT_END = {x: 1, y: 1}; const GRADIENT_END = {x: 1, y: 1};
const GRADIENT_LOCATIONS = [0.5, 1]; const GRADIENT_LOCATIONS: LinearGradientProps['locations'] = [0.5, 1];
const GRADIENT_START = {x: 0.3, y: 0.3}; const GRADIENT_START = {x: 0.3, y: 0.3};
const getStyles = makeStyleSheetFromTheme((theme: Theme) => ({ const getStyles = makeStyleSheetFromTheme((theme: Theme) => ({
@ -81,7 +81,7 @@ const Thumbnail = ({contentMode, file, hasError, theme, type}: Props) => {
styles.container, styles.container,
hasError && styles.error, hasError && styles.error,
styles.radius, styles.radius,
]), [styles, imgStyle, hasError]); ]), [styles, hasError]);
const source = useMemo(() => ({uri: type === 'video' ? file.videoThumb : file.value}), [type, file]); const source = useMemo(() => ({uri: type === 'video' ? file.videoThumb : file.value}), [type, file]);

View file

@ -33,7 +33,7 @@ export const getServerHasChannels = async (serverUrl: string) => {
export const observeServerHasChannels = (serverUrl: string) => { export const observeServerHasChannels = (serverUrl: string) => {
return queryHasChannels(serverUrl)?.observe().pipe( return queryHasChannels(serverUrl)?.observe().pipe(
switchMap((channels) => of$(channels?.length > 0 ?? false)), switchMap((channels) => of$(channels.length > 0)),
) || of$(false); ) || of$(false);
}; };

View file

@ -31,6 +31,10 @@ jest.mock('expo-application', () => {
}; };
}); });
jest.mock('expo-crypto', () => ({
randomUUID: jest.fn(() => '12345678-1234-1234-1234-1234567890ab'),
}));
jest.mock('expo-device', () => { jest.mock('expo-device', () => {
return { return {
deviceName: 'Device', deviceName: 'Device',
@ -235,7 +239,6 @@ jest.mock('react-native-vector-icons', () => {
}; };
}); });
jest.mock('react-native/Libraries/Animated/NativeAnimatedHelper');
jest.mock('../node_modules/react-native/Libraries/EventEmitter/NativeEventEmitter'); jest.mock('../node_modules/react-native/Libraries/EventEmitter/NativeEventEmitter');
jest.mock('react-native-localize', () => ({ jest.mock('react-native-localize', () => ({
@ -392,7 +395,7 @@ jest.mock('react-native-reanimated', () => require('react-native-reanimated/mock
jest.mock('react-native-permissions', () => require('react-native-permissions/mock')); jest.mock('react-native-permissions', () => require('react-native-permissions/mock'));
jest.mock('react-native-haptic-feedback', () => { jest.mock('react-native-haptic-feedback', () => {
const RNHF = jest.requireActual('react-native-haptic-feedback'); const RNHF = jest.requireActual('react-native-haptic-feedback/src/types');
return { return {
...RNHF, ...RNHF,
trigger: () => '', trigger: () => '',

View file

@ -16,7 +16,7 @@ export type EmojiProps = {
size?: number; size?: number;
textStyle?: StyleProp<TextStyle>; textStyle?: StyleProp<TextStyle>;
imageStyle?: StyleProp<ImageStyle>; imageStyle?: StyleProp<ImageStyle>;
commonStyle?: StyleProp<EmojiCommonStyle>; commonStyle?: StyleProp<Intersection<TextStyle, EmojiCommonStyle>>;
customEmojis: CustomEmojiModel[]; customEmojis: CustomEmojiModel[];
testID?: string; testID?: string;
} }

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