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",
"binary": "pod",
"semver": "1.15.2",
"semver": "1.16.1",
"platform": "darwin"
}
],

View file

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

View file

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

View file

@ -9,14 +9,14 @@ apply plugin: "com.facebook.react"
react {
/* Folders */
// The root of your project, i.e. where "package.json" lives. Default is '..'
// root = file("../")
// The folder where the react-native NPM package is. Default is ../node_modules/react-native
// reactNativeDir = file("../node_modules/react-native")
// The folder where the react-native Codegen package is. Default is ../node_modules/@react-native/codegen
// codegenDir = file("../node_modules/@react-native/codegen")
// The cli.js file which is the React Native CLI entrypoint. Default is ../node_modules/react-native/cli.js
// cliFile = file("../node_modules/react-native/cli.js")
// The root of your project, i.e. where "package.json" lives. Default is '../..'
// root = file("../../")
// The folder where the react-native NPM package is. Default is ../../node_modules/react-native
// reactNativeDir = file("../../node_modules/react-native")
// The folder where the react-native Codegen package is. Default is ../../node_modules/@react-native/codegen
// codegenDir = file("../../node_modules/@react-native/codegen")
// The cli.js file which is the React Native CLI entrypoint. Default is ../../node_modules/react-native/cli.js
// cliFile = file("../../node_modules/react-native/cli.js")
/* Variants */
// The list of variants to that are debuggable. For those we're going to
// skip the bundling of the JS bundle and the assets. By default is just 'debug'.
@ -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"
// hermesFlags = ["-O", "-output-source-map"]
/* Autolinking */
autolinkLibrariesWithApp()
}
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 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();
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);
createClientOptions();
}

View file

@ -1,6 +1,7 @@
package com.mattermost.helpers;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.WritableMap;
@ -9,58 +10,59 @@ import com.facebook.react.bridge.WritableMap;
* ResolvePromise: Helper class that abstracts boilerplate
*/
public class ResolvePromise implements Promise {
@Override
public void resolve(@javax.annotation.Nullable Object value) {
public void reject(@NonNull String s) {
}
@Override
public void reject(String code, String message) {
public void resolve(@Nullable Object o) {
}
@Override
public void reject(String code, @NonNull WritableMap map) {
public void reject(@NonNull String s, @Nullable String s1) {
}
@Override
public void reject(String code, Throwable e) {
public void reject(@NonNull String s, @Nullable Throwable throwable) {
}
@Override
public void reject(Throwable e, WritableMap map) {
public void reject(@NonNull String s, @Nullable String s1, @Nullable Throwable throwable) {
}
@Override
public void reject(String code, Throwable e, WritableMap map) {
public void reject(@NonNull Throwable throwable) {
}
@Override
public void reject(String code, String message, Throwable e, WritableMap map) {
public void reject(@NonNull Throwable throwable, @NonNull WritableMap writableMap) {
}
@Override
public void reject(String code, String message, Throwable e) {
public void reject(@NonNull String s, @NonNull WritableMap writableMap) {
}
@Override
public void reject(String code, String message, @NonNull WritableMap map) {
public void reject(@NonNull String s, @Nullable Throwable throwable, @NonNull WritableMap writableMap) {
}
@Override
public void reject(String message) {
public void reject(@NonNull String s, @Nullable String s1, @NonNull WritableMap writableMap) {
}
@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")))
}
override fun reject(reason: Throwable?) {
cont.resumeWith(Result.failure(IOException("Unexpected code $reason")))
override fun reject(throwable: Throwable) {
cont.resumeWith(Result.failure(IOException("Unexpected code $throwable")))
}
})
}
@ -41,12 +41,12 @@ internal suspend fun PushNotificationDataRunnable.Companion.fetchWithPost(server
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")))
}
override fun reject(reason: Throwable?) {
cont.resumeWith(Result.failure(IOException("Unexpected code $reason")))
override fun reject(throwable: Throwable) {
cont.resumeWith(Result.failure(IOException("Unexpected code $throwable")))
}
})
}

View file

@ -7,14 +7,13 @@ import android.content.res.Configuration
import android.os.Bundle
import com.facebook.react.PackageList
import com.facebook.react.ReactHost
import com.facebook.react.ReactInstanceManager
import com.facebook.react.ReactNativeHost
import com.facebook.react.ReactPackage
import com.facebook.react.bridge.ReactContext
import com.facebook.react.bridge.UiThreadUtil
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
import com.facebook.react.defaults.DefaultReactNativeHost
import com.facebook.react.soloader.OpenSourceMergedSoMapping
import com.facebook.react.modules.network.OkHttpClientProvider
import com.facebook.soloader.SoLoader
import com.mattermost.networkclient.RCTOkHttpClientFactory
@ -22,6 +21,7 @@ import com.mattermost.rnshare.helpers.RealPathUtil
import com.mattermost.turbolog.TurboLog
import com.mattermost.turbolog.ConfigureOptions
import com.nozbe.watermelondb.jsi.JSIInstaller
import com.nozbe.watermelondb.jsi.WatermelonDBJSIPackage
import com.reactnativenavigation.NavigationApplication
import com.wix.reactnativenotifications.RNNotificationsPackage
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:
// add(MyReactNativePackage())
add(RNNotificationsPackage(this@MainApplication))
add(WatermelonDBJSIPackage())
}
override fun getJSMainModuleName(): String = "index"
@ -78,13 +79,12 @@ class MainApplication : NavigationApplication(), INotificationsApplication {
OkHttpClientProvider.setOkHttpClientFactory(RCTOkHttpClientFactory())
ExpoImageOkHttpClientGlideModule.okHttpClient = RCTOkHttpClientFactory().createNewNetworkModuleClient()
SoLoader.init(this, false)
SoLoader.init(this, OpenSourceMergedSoMapping)
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
// If you opted-in for the New Architecture, we load the native entry point for this app.
load(bridgelessEnabled = false)
}
ApplicationLifecycleDispatcher.onApplicationCreate(this)
registerJSIModules()
}
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 {
ext {
buildToolsVersion = "34.0.0"
buildToolsVersion = "35.0.0"
minSdkVersion = 24
compileSdkVersion = 34
compileSdkVersion = 35
targetSdkVersion = 34
supportLibVersion = "33.0.0"
kotlinVersion = "1.9.22"
supportLibVersion = "35.0.0"
kotlinVersion = "1.9.24"
kotlin_version = kotlinVersion
RNNKotlinVersion = kotlinVersion
firebaseVersion = "24.0.0"
firebaseVersion = "24.1.0"
ndkVersion = "26.1.10909125"
}
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
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.
# You can also override it from the CLI using
# ./gradlew <task> -PreactNativeArchitectures=x86_64

Binary file not shown.

View file

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
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
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

7
android/gradlew vendored
View file

@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (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.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@ -84,7 +86,8 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# 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.
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 limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@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'
include ':app'
include ':reactnativenotifications'
project(':reactnativenotifications').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-notifications/lib/android/app')
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
include ':watermelondb-jsi'
project(':watermelondb-jsi').projectDir = new File(rootProject.projectDir, '../node_modules/@nozbe/watermelondb/native/android-jsi')
includeBuild('../node_modules/@react-native/gradle-plugin')

View file

@ -141,7 +141,7 @@ describe('ClientTraking', () => {
group.urls = {
'https://example.com/api': {
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],
theme,
});
}, [theme.sidebarHeaderTextColor, intl.locale, renderContent, allowDismissal]);
}, [intl, allowDismissal, renderContent, theme]);
const handleDismiss = useCallback(() => {
dismissAnnouncement(serverUrl, bannerText);
@ -129,7 +129,7 @@ const AnnouncementBanner = ({
height.value = withTiming(visible ? ANNOUNCEMENT_BAR_HEIGHT : 0, {
duration: 200,
});
}, [visible]);
}, [height, visible]);
const bannerStyle = useAnimatedStyle(() => ({
height: height.value,

View file

@ -3,7 +3,7 @@
import {Image, type ImageStyle} from 'expo-image';
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 Emoji from '@components/emoji';
@ -18,7 +18,7 @@ type Props = {
iconSize: number;
imageStyle?: StyleProp<ImageStyle>;
imageUrl?: string;
genericStyle: StyleProp<ViewStyle>;
genericStyle: StyleProp<TextStyle>;
}
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.
// 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 {FlatList, View, type ListRenderItemInfo, type NativeSyntheticEvent, type NativeScrollEvent} from 'react-native';
import Animated from 'react-native-reanimated';
@ -31,7 +31,7 @@ type Props = {
separator?: boolean;
}
const GRADIENT_LOCATIONS = [0, 0.64, 1];
const GRADIENT_LOCATIONS: LinearGradientProps['locations'] = [0, 0.64, 1];
const SCROLL_OFFSET = 10;
const isCloseToBottom = ({layoutMeasurement, contentOffset, contentSize}: NativeScrollEvent) => {
@ -112,7 +112,7 @@ const ChannelBookmarks = ({
setAllowEndFade(isCloseToBottom(e.nativeEvent));
}, []);
const gradientColors = useMemo(() => [
const gradientColors: LinearGradientProps['colors'] = useMemo(() => [
theme.centerChannelBg,
changeOpacity(theme.centerChannelBg, 0.6458),
changeOpacity(theme.centerChannelBg, 0),

View file

@ -11,13 +11,13 @@ import {useTheme} from '@context/theme';
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
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 = {
authorId: string;
author?: UserModel;
isOnCenterBg?: boolean;
style: StyleProp<ViewStyle>;
style: StyleProp<Intersection<TextStyle, ViewStyle>>;
size: number;
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -3,7 +3,7 @@
import React, {useEffect, useMemo, useState} from 'react';
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 {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 filesForGallery = useDerivedValue(() => imageAttachments.concat(nonImageAttachments),
const filesForGallery = useMemo(() => imageAttachments.concat(nonImageAttachments),
[imageAttachments, nonImageAttachments]);
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 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);
});
const updateFileForGallery = (idx: number, file: FileInfo) => {
'worklet';
filesForGallery.value[idx] = file;
filesForGallery[idx] = file;
};
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.
// 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 {StyleSheet, useWindowDimensions, View} from 'react-native';
@ -30,9 +30,9 @@ type ImageFileProps = {
const SMALL_IMAGE_MAX_HEIGHT = 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_LOCATIONS = [0.5, 1];
const GRADIENT_LOCATIONS: LinearGradientProps['locations'] = [0.5, 1];
const GRADIENT_START = {x: 0.5, y: 0.5};
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({

View file

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

View file

@ -255,7 +255,7 @@ const FloatingTextInput = forwardRef<FloatingTextInputRef, FloatingTextInputProp
>
{label}
</Animated.Text>
<View style={combinedTextInputContainerStyle}>
<View style={combinedTextInputContainerStyle as StyleProp<ViewStyle>}>
<TextInput
{...props}
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 blockStyle: StyleProp<ViewStyle> = [styles.block];
const blockStyle: StyleProp<Intersection<TextStyle, ViewStyle>> = [styles.block];
if (!first) {
const blockS = getMarkdownBlockStyles(theme);
blockStyle.push(blockS.adjacentParagraph);

View file

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

View file

@ -2,13 +2,13 @@
// See LICENSE.txt for license information.
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';
type MarkdownBlockQuoteProps = {
continueBlock?: boolean;
iconStyle: ViewStyle | TextStyle;
iconStyle: StyleProp<Intersection<ViewStyle, TextStyle>>;
children: ReactNode | ReactNode[];
};

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// 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 {TouchableOpacity, View} from 'react-native';
@ -74,7 +74,7 @@ const ShowMoreButton = ({highlight, onPress, showMore = true, theme}: ShowMoreBu
iconName = 'chevron-up';
}
let gradientColors = [
let gradientColors: LinearGradientProps['colors'] = [
changeOpacity(theme.centerChannelBg, 0),
changeOpacity(theme.centerChannelBg, 0.75),
theme.centerChannelBg,

View file

@ -117,20 +117,13 @@ const PostList = ({
const serverUrl = useServerUrl();
const orderedPosts = useMemo(() => {
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(() => {
return orderedPosts.findIndex((i) => i.type === 'start-of-new-messages');
}, [orderedPosts]);
const isNewMessage = useMemo(() => {
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]);
const isNewMessage = lastPostId ? posts[0]?.id !== lastPostId : false;
useEffect(() => {
const t = setTimeout(() => {
@ -266,7 +259,6 @@ const PostList = ({
case 'user-activity': {
const postProps = {
currentUsername,
key: item.value,
postId: item.value,
location,
style: styles.container,
@ -275,7 +267,11 @@ const PostList = ({
theme,
};
return (<CombinedUserActivity {...postProps}/>);
return (
<CombinedUserActivity
{...postProps}
key={item.value}
/>);
}
default: {
const post = item.value.currentPost;
@ -289,7 +285,6 @@ const PostList = ({
highlight: highlightedId === post.id,
highlightPinnedOrSaved,
isSaved,
key: post.id,
location,
nextPost,
post,
@ -300,10 +295,15 @@ const PostList = ({
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) => {
listRef.current?.scrollToIndex({

View file

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

View file

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

View file

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

View file

@ -14,7 +14,7 @@ export default schemaMigrations({migrations: [
{
toVersion: 6,
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.
// See LICENSE.txt for license information.
import {renderHook} from '@testing-library/react-hooks';
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;
describe('useCollapsibleHeader', () => {
afterEach(() => {
jest.resetAllMocks();
});
const commonHookResponse = {
largeHeight: LARGE_HEADER_TITLE_HEIGHT,
scrollRef: {current: null},

View file

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

View file

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

View file

@ -17,7 +17,7 @@ import {makeStyleSheetFromTheme} from '@utils/theme';
type Props = {
pressableStyle: StyleProp<ViewStyle>;
iconStyle: StyleProp<ViewStyle>;
iconStyle: StyleProp<TextStyle>;
buttonTextStyle: StyleProp<TextStyle>;
currentCall: CurrentCall;
}
@ -33,7 +33,6 @@ export const AudioDeviceButton = ({pressableStyle, iconStyle, buttonTextStyle, c
const theme = useTheme();
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 color = theme.awayIndicator;
const audioDeviceInfo = currentCall.audioDeviceInfo;
const phoneLabel = intl.formatMessage({id: 'mobile.calls_phone', defaultMessage: 'Phone'});
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'}),
theme,
});
}, [setPreferredAudioRoute, audioDeviceInfo, color]);
}, [
audioDeviceInfo.selectedAudioDevice, audioDeviceInfo.availableAudioDeviceList,
intl, theme, isTablet, tabletLabel, style.checkIcon,
phoneLabel, speakerLabel, bluetoothLabel, headsetLabel,
]);
let icon = 'volume-high';
let label = speakerLabel;

View file

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

View file

@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// 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 {DeviceEventEmitter, type Handle, InteractionManager, Keyboard, type StyleProp, View, type ViewStyle} from 'react-native';
import {ReduceMotion, type WithSpringConfig} from 'react-native-reanimated';
@ -71,6 +71,9 @@ export const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
borderTopWidth: 1,
borderColor: changeOpacity(theme.centerChannelColor, 0.08),
},
view: {
flex: 1,
},
};
});
@ -221,8 +224,11 @@ const BottomSheet = ({
keyboardBlurBehavior='restore'
onClose={close}
bottomInset={insets.bottom}
enableDynamicSizing={false}
>
{renderContainerContent()}
<BottomSheetView style={styles.view}>
{renderContainerContent()}
</BottomSheetView>
</BottomSheetM>
);
};

View file

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

View file

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

View file

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

View file

@ -5,7 +5,7 @@ import {useHardwareKeyboardEvents} from '@mattermost/hardware-keyboard';
import {useIsFocused, useNavigation} from '@react-navigation/native';
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
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 {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 {type FileFilter, FileFilters, filterFileExtensions} from '@utils/file';
import {TabTypes, type TabType} from '@utils/search';
import {makeStyleSheetFromTheme} from '@utils/theme';
import Initial from './initial';
import Results from './results';
@ -52,9 +53,10 @@ type Props = {
teams: TeamModel[];
}
const styles = StyleSheet.create({
const getStyleSheet = makeStyleSheetFromTheme((theme) => ({
flex: {
flex: 1,
backgroundColor: theme.centerChannelBg,
},
loading: {
flex: 1,
@ -63,7 +65,7 @@ const styles = StyleSheet.create({
autocompleteContainer: {
zIndex: 11,
},
});
}));
const getSearchParams = (terms: string, filterValue?: FileFilter) => {
const fileExtensions = filterFileExtensions(filterValue);
@ -84,6 +86,7 @@ const SearchScreen = ({teamId, teams}: Props) => {
const theme = useTheme();
const insets = useSafeAreaInsets();
const keyboardHeight = useKeyboardHeight();
const styles = getStyleSheet(theme);
const stateIndex = nav.getState()?.index;
const serverUrl = useServerUrl();
@ -114,17 +117,9 @@ const SearchScreen = ({teamId, teams}: Props) => {
setSearchTeamId(teamId);
}, [teamId]);
useEffect(() => {
if (searchTerm) {
resetToInitial();
setSearchValue(searchTerm);
handleSearch(searchTeamId, searchTerm);
}
}, [searchTerm]);
const onSnap = (offset: number, animated = true) => {
const onSnap = useCallback((offset: number, animated = true) => {
scrollRef.current?.scrollToOffset({offset, animated});
};
}, []);
const onSnapWithTimeout = useCallback((offset: number, animated = true) => {
// 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);
handleLoading(false);
setShowResults(true);
}, [filter, handleClearSearch, handleLoading]);
}, [filter, handleClearSearch, handleLoading, hideHeader, serverUrl]);
const onBlur = useCallback(() => {
setSearchIsFocused(false);
@ -233,7 +228,7 @@ const SearchScreen = ({teamId, teams}: Props) => {
setFileInfos(files?.length ? files : emptyFileResults);
setFileChannelIds(channels?.length ? channels : emptyChannelIds);
setResultsLoading(false);
}, [lastSearchedValue, searchTeamId]);
}, [lastSearchedValue, searchTeamId, serverUrl]);
const handleResultsTeamChange = useCallback((newTeamId: string) => {
setSearchTeamId(newTeamId);
@ -267,8 +262,11 @@ const SearchScreen = ({teamId, teams}: Props) => {
teams={teams}
/>
);
}, [handleRecentSearch, handleTextChange, loading,
scrollPaddingTop, searchTeamId, searchValue, theme]);
}, [
handleModifierTextChange, handleRecentSearch,
loading, scrollEnabled, scrollPaddingTop, searchTeamId,
searchValue, styles.loading, teams, theme.buttonBg,
]);
const animated = useAnimatedStyle(() => {
if (isFocused) {
@ -320,6 +318,14 @@ const SearchScreen = ({teamId, teams}: Props) => {
}
}, [unlock, onSnapWithTimeout]);
useEffect(() => {
if (searchTerm) {
resetToInitial();
setSearchValue(searchTerm);
handleSearch(searchTeamId, searchTerm);
}
}, [handleSearch, resetToInitial, searchTeamId, searchTerm]);
useDidUpdate(() => {
if (isFocused) {
setTimeout(() => {

View file

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

View file

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

View file

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

View file

@ -78,7 +78,7 @@ export const getErrorMessage = (error: unknown, intl?: IntlShape) => {
return 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)) {

View file

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

View file

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

View file

@ -15,7 +15,7 @@ import {isBetaApp} from '@utils/general';
import {logError, logWarning} from './log';
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_NON_ERROR = 'uncaught-non-error';
@ -41,7 +41,7 @@ export function initializeSentry() {
environment: isBetaApp ? 'beta' : 'production',
tracesSampleRate: 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 : [];
@ -55,16 +55,9 @@ export function initializeSentry() {
...sentryOptions,
enableCaptureFailedRequests: false,
integrations: [
new Sentry.ReactNativeTracing({
// Pass instrumentation to be used as `routingInstrumentation`
routingInstrumentation: new Sentry.ReactNativeNavigationInstrumentation(
Navigation,
{enableTabsInstrumentation: false},
),
}),
Sentry.reactNativeNavigationIntegration({navigation: Navigation}),
],
beforeSend: (event: Event) => {
beforeSend: (event: ErrorEvent) => {
if (isBetaApp || (event?.level && eventFilter.includes(event.level))) {
return event;
}

View file

@ -65,6 +65,7 @@ class LoginScreen {
await this.usernameInput.replaceText(user.newUser.email);
await this.passwordInput.tap();
await this.passwordInput.replaceText(user.newUser.password);
await element(by.text(/^Log In to Your Account*$/)).tap();
await this.signinButton.tap();
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",
"author": "Mattermost, Inc.",
"devDependencies": {
"@aws-sdk/client-s3": "3.650.0",
"@aws-sdk/lib-storage": "3.650.0",
"@aws-sdk/client-s3": "3.712.0",
"@aws-sdk/lib-storage": "3.712.0",
"@babel/plugin-proposal-class-properties": "7.18.6",
"@babel/plugin-transform-modules-commonjs": "7.24.8",
"@babel/plugin-transform-runtime": "7.25.4",
"@babel/preset-env": "7.25.4",
"@babel/plugin-transform-modules-commonjs": "7.26.3",
"@babel/plugin-transform-runtime": "7.25.9",
"@babel/preset-env": "7.26.0",
"@jest/test-sequencer": "29.7.0",
"@types/jest": "29.5.12",
"@types/jest": "29.5.14",
"@types/tough-cookie": "4.0.5",
"@types/uuid": "10.0.0",
"async": "3.2.6",
"axios": "1.7.7",
"axios-cookiejar-support": "5.0.2",
"axios": "1.7.9",
"axios-cookiejar-support": "5.0.4",
"babel-jest": "29.7.0",
"babel-plugin-module-resolver": "5.0.2",
"client-oauth2": "4.3.3",
"deepmerge": "4.3.1",
"detox": "20.26.2",
"form-data": "4.0.0",
"detox": "20.28.0",
"form-data": "4.0.1",
"jest": "29.7.0",
"jest-circus": "29.7.0",
"jest-cli": "29.7.0",
@ -30,15 +30,15 @@
"jest-junit": "16.0.0",
"jest-stare": "2.5.2",
"junit-report-merger": "7.0.0",
"moment-timezone": "0.5.45",
"moment-timezone": "0.5.46",
"recursive-readdir": "2.2.3",
"sanitize-filename": "1.6.3",
"shelljs": "0.8.5",
"tough-cookie": "5.0.0",
"ts-jest": "29.2.5",
"tslib": "2.7.0",
"typescript": "5.6.2",
"uuid": "10.0.0",
"tslib": "2.8.1",
"typescript": "5.7.2",
"uuid": "11.0.3",
"xml2js": "0.6.2"
},
"scripts": {

View file

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

View file

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

View file

@ -1393,6 +1393,9 @@
"${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/ExpoConstants_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/ExpoDevice/ExpoDevice_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/Entypo.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/SimpleLineIcons.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}/Sentry/Sentry.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/Starscream/Starscream_Privacy.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-image-picker/RNImagePickerPrivacyInfo.bundle",
);
name = "[CP] Copy Pods Resources";
outputPaths = (
@ -1428,6 +1435,9 @@
"${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}/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}/Entypo.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}/SimpleLineIcons.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}/Sentry.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}/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}/RNImagePickerPrivacyInfo.bundle",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
@ -1989,7 +2003,7 @@
ENABLE_BITCODE = NO;
HEADER_SEARCH_PATHS = "$(inherited)";
INFOPLIST_FILE = Mattermost/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.4;
IPHONEOS_DEPLOYMENT_TARGET = 15.1;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -2031,7 +2045,7 @@
ENABLE_BITCODE = NO;
HEADER_SEARCH_PATHS = "$(inherited)";
INFOPLIST_FILE = Mattermost/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.4;
IPHONEOS_DEPLOYMENT_TARGET = 15.1;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -2079,7 +2093,7 @@
DEVELOPMENT_TEAM = UQ8HT4Q2XM;
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = NotificationService/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.4;
IPHONEOS_DEPLOYMENT_TARGET = 15.1;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -2128,7 +2142,7 @@
DEVELOPMENT_TEAM = UQ8HT4Q2XM;
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = NotificationService/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.4;
IPHONEOS_DEPLOYMENT_TARGET = 15.1;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -2175,7 +2189,7 @@
GCC_C_LANGUAGE_STANDARD = gnu11;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = MattermostShare/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
IPHONEOS_DEPLOYMENT_TARGET = 15.1;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -2225,7 +2239,7 @@
GCC_C_LANGUAGE_STANDARD = gnu11;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = MattermostShare/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
IPHONEOS_DEPLOYMENT_TARGET = 15.1;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -2307,6 +2321,7 @@
OTHER_LDFLAGS = "$(inherited)";
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG";
USE_HERMES = true;
};
name = Debug;
@ -2421,7 +2436,7 @@
repositoryURL = "https://github.com/getsentry/sentry-cocoa.git";
requirement = {
kind = exactVersion;
version = 8.36.0;
version = 8.41.0;
};
};
7FD4822A2864D73300A5B18B /* XCRemoteSwiftPackageReference "OpenGraph" */ = {

View file

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

View file

@ -37,7 +37,7 @@ NSString* const NOTIFICATION_TEST_ACTION = @"test";
NSArray<NSString*> *servers = [keychain getAllServersForInternetPasswords];
NSLog(@"Servers %@", servers);
for (NSString *server in servers) {
[keychain deleteCredentialsForServer:server];
[keychain deleteCredentialsForServer:server withOptions:nil];
}
[[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-permissions/scripts/setup.rb')
platform :ios, min_ios_version_supported
platform :ios, '15.1' #min_ios_version_supported
prepare_react_native_project!
linkage = ENV['USE_FRAMEWORKS']
@ -54,7 +54,7 @@ target 'Mattermost' do
# installer.pods_project.targets.each do |target|
# 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

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"
},
"dependencies": {
"@formatjs/intl-datetimeformat": "6.12.5",
"@formatjs/intl-getcanonicallocales": "2.3.0",
"@formatjs/intl-listformat": "7.5.7",
"@formatjs/intl-locale": "4.0.0",
"@formatjs/intl-numberformat": "8.10.3",
"@formatjs/intl-pluralrules": "5.2.14",
"@gorhom/bottom-sheet": "4.6.4",
"@formatjs/intl-datetimeformat": "6.17.1",
"@formatjs/intl-getcanonicallocales": "2.5.4",
"@formatjs/intl-listformat": "7.7.8",
"@formatjs/intl-locale": "4.2.8",
"@formatjs/intl-numberformat": "8.15.1",
"@formatjs/intl-pluralrules": "5.4.1",
"@gorhom/bottom-sheet": "5.0.6",
"@mattermost/calls": "github:mattermost/calls-common#030ff7c0a37ee9b0ccc5fae0b2ea9c0e1c08473f",
"@mattermost/compass-icons": "0.1.48",
"@mattermost/hardware-keyboard": "file:./libraries/@mattermost/hardware-keyboard",
"@mattermost/react-native-emm": "1.5.0",
"@mattermost/react-native-network-client": "github:mattermost/react-native-network-client#ad7b88412f41c5a1024420a4f4c7461883cd0e63",
"@mattermost/react-native-paste-input": "0.8.0",
"@mattermost/react-native-turbo-log": "github:mattermost/react-native-turbo-log#d8ddf5e7974546aff3e83b2c563907eb609ac5f4",
"@mattermost/react-native-emm": "1.5.1",
"@mattermost/react-native-network-client": "1.8.0",
"@mattermost/react-native-paste-input": "0.8.1",
"@mattermost/react-native-turbo-log": "0.5.0",
"@mattermost/rnshare": "file:./libraries/@mattermost/rnshare",
"@mattermost/rnutils": "file:./libraries/@mattermost/rnutils",
"@msgpack/msgpack": "2.8.0",
"@nozbe/watermelondb": "0.27.1",
"@react-native-camera-roll/camera-roll": "7.8.3",
"@react-native-clipboard/clipboard": "1.14.1",
"@nozbe/watermelondb": "0.28.0-1",
"@react-native-camera-roll/camera-roll": "7.9.0",
"@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/netinfo": "11.3.2",
"@react-native-community/netinfo": "11.4.1",
"@react-native-cookies/cookies": "6.2.1",
"@react-navigation/bottom-tabs": "6.6.1",
"@react-navigation/native": "6.1.18",
"@react-navigation/stack": "6.4.1",
"@react-navigation/bottom-tabs": "7.2.0",
"@react-navigation/native": "7.0.14",
"@react-navigation/stack": "7.1.0",
"@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",
"@voximplant/react-native-foreground-service": "3.0.2",
"base-64": "1.0.0",
@ -46,123 +49,123 @@
"commonmark-react-renderer": "github:mattermost/commonmark-react-renderer#81b5d27509652bae50b4b510ede777dd3bd923cf",
"deep-equal": "2.2.3",
"deepmerge": "4.3.1",
"emoji-regex": "10.3.0",
"expo": "51.0.24",
"expo-application": "5.9.1",
"expo-crypto": "13.0.2",
"expo-device": "6.0.2",
"expo-image": "1.12.13",
"expo-linear-gradient": "13.0.2",
"expo-store-review": "7.0.2",
"expo-video-thumbnails": "8.0.0",
"expo-web-browser": "13.0.3",
"emoji-regex": "10.4.0",
"expo": "52.0.19",
"expo-application": "6.0.1",
"expo-crypto": "14.0.1",
"expo-device": "7.0.1",
"expo-image": "2.0.3",
"expo-linear-gradient": "14.0.1",
"expo-store-review": "8.0.0",
"expo-video-thumbnails": "9.0.2",
"expo-web-browser": "14.0.1",
"fflate": "0.8.2",
"fuse.js": "7.0.0",
"html-entities": "2.5.2",
"mime-db": "1.53.0",
"moment-timezone": "0.5.45",
"moment-timezone": "0.5.46",
"node-html-parser": "6.1.13",
"path-to-regexp": "8.1.0",
"react": "18.2.0",
"path-to-regexp": "8.2.0",
"react": "18.3.1",
"react-freeze": "1.0.4",
"react-intl": "6.6.8",
"react-native": "0.74.5",
"react-intl": "7.0.4",
"react-native": "0.76.5",
"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-exception-handler": "2.10.10",
"react-native-file-viewer": "2.1.5",
"react-native-gesture-handler": "2.18.1",
"react-native-haptic-feedback": "2.2.0",
"react-native-image-picker": "7.1.2",
"react-native-gesture-handler": "2.21.2",
"react-native-haptic-feedback": "2.3.3",
"react-native-image-picker": "7.2.3",
"react-native-incall-manager": "4.2.0",
"react-native-keyboard-aware-scroll-view": "0.9.5",
"react-native-keychain": "8.2.0",
"react-native-localize": "3.2.1",
"react-native-keychain": "9.2.2",
"react-native-localize": "3.3.0",
"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-performance": "5.1.2",
"react-native-permissions": "4.1.5",
"react-native-reanimated": "3.14.0",
"react-native-safe-area-context": "4.10.8",
"react-native-screens": "3.34.0",
"react-native-permissions": "5.2.1",
"react-native-reanimated": "3.16.5",
"react-native-safe-area-context": "5.0.0",
"react-native-screens": "4.3.0",
"react-native-section-list-get-item-layout": "2.2.3",
"react-native-shadow-2": "7.1.0",
"react-native-share": "10.2.1",
"react-native-svg": "15.4.0",
"react-native-shadow-2": "7.1.1",
"react-native-share": "12.0.3",
"react-native-svg": "15.10.1",
"react-native-url-polyfill": "2.0.0",
"react-native-vector-icons": "10.1.0",
"react-native-video": "6.4.3",
"react-native-vector-icons": "10.2.0",
"react-native-video": "6.8.2",
"react-native-walkthrough-tooltip": "1.6.0",
"react-native-webrtc": "124.0.3",
"react-syntax-highlighter": "15.5.0",
"react-native-webrtc": "124.0.4",
"react-syntax-highlighter": "15.6.1",
"semver": "7.6.3",
"tinycolor2": "1.6.0",
"url-parse": "1.5.10"
},
"devDependencies": {
"@babel/cli": "7.24.8",
"@babel/core": "7.25.2",
"@babel/eslint-parser": "7.25.1",
"@babel/cli": "7.26.4",
"@babel/core": "7.26.0",
"@babel/eslint-parser": "7.25.9",
"@babel/plugin-proposal-class-properties": "7.18.6",
"@babel/plugin-proposal-decorators": "7.24.7",
"@babel/plugin-transform-flow-strip-types": "7.25.2",
"@babel/plugin-transform-runtime": "7.24.7",
"@babel/preset-env": "7.25.3",
"@babel/preset-typescript": "7.24.7",
"@babel/register": "7.24.6",
"@babel/runtime": "7.25.0",
"@react-native/babel-preset": "0.74.87",
"@react-native/eslint-config": "0.74.87",
"@react-native/metro-config": "0.74.87",
"@react-native/typescript-config": "0.74.87",
"@babel/plugin-proposal-decorators": "7.25.9",
"@babel/plugin-transform-flow-strip-types": "7.25.9",
"@babel/plugin-transform-runtime": "7.25.9",
"@babel/preset-env": "7.26.0",
"@babel/preset-typescript": "7.26.0",
"@babel/register": "7.25.9",
"@babel/runtime": "7.26.0",
"@react-native/babel-preset": "0.76.5",
"@react-native/eslint-config": "0.76.5",
"@react-native/metro-config": "0.76.5",
"@react-native/typescript-config": "0.76.5",
"@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/commonmark": "0.27.9",
"@types/commonmark-react-renderer": "4.3.4",
"@types/deep-equal": "1.0.4",
"@types/jest": "29.5.12",
"@types/lodash": "4.17.7",
"@types/jest": "29.5.14",
"@types/lodash": "4.17.13",
"@types/mime-db": "1.43.5",
"@types/pako": "2.0.3",
"@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-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/semver": "7.5.8",
"@types/tinycolor2": "1.4.6",
"@types/tough-cookie": "4.0.5",
"@types/url-parse": "1.4.11",
"@types/uuid": "10.0.0",
"@typescript-eslint/eslint-plugin": "7.13.1",
"@typescript-eslint/parser": "7.13.1",
"@typescript-eslint/eslint-plugin": "7.14.1",
"@typescript-eslint/parser": "7.14.1",
"babel-jest": "29.7.0",
"babel-loader": "9.1.3",
"babel-loader": "9.2.1",
"babel-plugin-module-resolver": "5.0.2",
"eslint": "8.57.0",
"eslint": "8.57.1",
"eslint-plugin-header": "3.1.1",
"eslint-plugin-import": "2.29.1",
"eslint-plugin-jest": "28.7.0",
"eslint-plugin-react": "7.35.0",
"eslint-plugin-react-hooks": "4.6.2",
"husky": "9.1.4",
"eslint-plugin-import": "2.31.0",
"eslint-plugin-jest": "28.9.0",
"eslint-plugin-react": "7.37.2",
"eslint-plugin-react-hooks": "5.1.0",
"husky": "9.1.7",
"isomorphic-fetch": "3.0.0",
"jest": "29.7.0",
"jest-cli": "29.7.0",
"jest-expo": "51.0.3",
"jest-expo": "52.0.2",
"jetifier": "2.0.0",
"mmjstool": "github:mattermost/mattermost-utilities#83b1b311972b8f5e750aae4019457a40abb5aa44",
"nock": "13.5.4",
"nock": "13.5.6",
"patch-package": "8.0.0",
"react-devtools-core": "5.3.1",
"tough-cookie": "4.1.4",
"ts-jest": "29.2.4",
"typescript": "5.5.4",
"uuid": "10.0.0"
"react-devtools-core": "6.0.1",
"tough-cookie": "5.0.0",
"ts-jest": "29.2.5",
"typescript": "5.7.2",
"uuid": "11.0.3"
},
"scripts": {
"android": "react-native run-android",
@ -198,25 +201,21 @@
},
"overrides": {
"@testing-library/react-native": {
"react": "^18.2.0"
"react": "^18.3.1"
},
"@testing-library/react-hooks": {
"@types/react": "^18.2.37",
"react": "^18.2.0",
"react": "^18.3.1",
"react-test-renderer": "^18.2.0"
},
"@react-native-community/datetimepicker": {
"react-native": "^0.74.2"
},
"@react-native/eslint-config": {
"@typescript-eslint/eslint-plugin": "^7.12.0",
"@typescript-eslint/parser": "^7.12.0"
"react-native": "^0.76.5"
},
"@react-native-clipboard/clipboard": {
"react-native": "^0.74.2"
"react-native": "^0.76.5"
},
"react-native-windows": {
"react-native": "^0.74.2"
"react-native": "^0.76.5"
}
},
"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
index 861ed06..d2d6527 100644
index e6eefec..d3a7dc0 100644
--- a/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 {
// Yes, this sucks and there should be some safety mechanisms or warnings. Please contribute!
unsafeResetDatabase(): Promise<void>
@@ -93,6 +93,8 @@ export default class Database {
// has a significant performance impact so should only be enabled when debugging.
experimentalIsVerbose: boolean
+ unsafeVacuum(): Promise<void>
+
+
_ensureInWriter(diagnosticMethodName: string): void
// (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
index fa82516..de24ff2 100644
index 9139dd4..aec45b5 100644
--- a/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;
if (!preparedState) {
(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 {
@@ -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
// TODO: What if this fails?
record._preparedState = null;
+
+ if ('update' === preparedState) {
+ record.__original = null;
+ }
}
if (!changeNotifications[table]) {
changeNotifications[table] = [];
@@ -379,6 +385,57 @@ var Database = /*#__PURE__*/function () {
}
@@ -399,6 +404,57 @@ var Database = exports.default = /*#__PURE__*/function () {
}.bind(this));
};
+ _proto.unsafeVacuum = function unsafeVacuum() {
}
+ _proto.unsafeVacuum = function () {
+ return new Promise(function ($return, $error) {
+ var $Try_3_Finally = function ($Try_3_Exit) {
+ return function ($Try_3_Value) {
@ -75,7 +74,6 @@ index fa82516..de24ff2 100644
+ } = this);
+ ErrorAdapter = require('../adapters/error').default;
+ this.adapter = new ErrorAdapter();
+
+ // Vacuum the database
+ return Promise.resolve(adapter.unsafeVacuum()).then(function () {
+ try {
@ -92,11 +90,12 @@ index fa82516..de24ff2 100644
+ }
+ }.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
index 96114ec..ecfe3c1 100644
index 96114ec..258bb92 100644
--- a/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 {
@ -104,20 +103,20 @@ index 96114ec..ecfe3c1 100644
prepareUpdate(recordUpdater?: (_: this) => void): this
+ cancelPrepareUpdate(): void
+
+
prepareMarkAsDeleted(): this
prepareDestroyPermanently(): this
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
+++ 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;
- (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. 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 (".concat(this.__debugName, ")"));
+ if ('deleted' === this._raw._status) {
+ console.debug("Updating a deleted record in table " + _this.table);
+ return this;
@ -128,16 +127,16 @@ index dbfdf6e..2e63166 100644
+ } else {
+ this.__original = Object.assign({}, this._raw);
+ }
+
this.__ensureNotDisposable("Model.prepareUpdate()");
this._isEditing = true;
@@ -125,6 +135,21 @@ var Model = /*#__PURE__*/function () {
@@ -147,6 +158,20 @@ var Model = exports.default = /*#__PURE__*/function () {
}.bind(this));
}
+ _proto.cancelPrepareUpdate = function cancelPrepareUpdate() {
+ _proto.cancelPrepareUpdate = function () {
+ var _this = this;
+
+ 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);
+ }
@ -153,12 +152,12 @@ index dbfdf6e..2e63166 100644
/**
* 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}
*/;
_proto.prepareDestroyPermanently = function prepareDestroyPermanently() {
- (0, _invariant.default)(!this._preparedState, "Cannot destroy permanently a record with pending changes");
+ // (0, _invariant.default)(!this._preparedState, "Cannot destroy permanently a record with pending changes");
_proto.prepareDestroyPermanently = function () {
- (0, _invariant.default)(!this._preparedState, "Cannot destroy permanently record with pending changes (".concat(this.__debugName, ")"));
+ // (0, _invariant.default)(!this._preparedState, "Cannot destroy permanently record with pending changes (".concat(this.__debugName, ")"));
+ if (this._preparedState) {
+ 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>
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
+++ 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);
});
};
+ _proto.unsafeVacuum = function unsafeVacuum() {
+ _proto.unsafeVacuum = function () {
+ var _this16 = this;
+ return (0, _Result.toPromise)(function (callback) {
+ return _this16.underlyingAdapter.unsafeVacuum(callback);
+ });
+ };
_proto.unsafeExecute = function unsafeExecute(work) {
_proto.unsafeExecute = function (work) {
var _this12 = this;
return (0, _Result.toPromise)(function (callback) {
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
+++ b/node_modules/@nozbe/watermelondb/adapters/error.js
@@ -13,7 +13,7 @@ var throwError = function (name) {
var ErrorAdapter = /*#__PURE__*/function () {
var ErrorAdapter = exports.default = /*#__PURE__*/function () {
function ErrorAdapter() {
var _this = this;
- ['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 () {
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
index 5528dc1..0408198 100644
index f8d179f..4b39cf9 100644
--- a/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 =
@ -234,24 +233,24 @@ index e09fb14..51d42d9 100644
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
index 9d5ea84..aa8397d 100644
index 08916f6..672fc29 100644
--- a/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 () {
_proto.unsafeResetDatabase = function unsafeResetDatabase(callback) {
@@ -105,6 +105,9 @@ var LokiJSAdapter = exports.default = /*#__PURE__*/function () {
_proto.unsafeResetDatabase = function (callback) {
this._dispatcher.call('unsafeResetDatabase', [], callback);
};
+ _proto.unsafeVacuum = function unssafeVacuum(callback) {
+ _proto.unsafeVacuum = function (callback) {
+ this._dispatcher.call('unsafeVacuum', [], callback);
+ };
_proto.unsafeExecute = function unsafeExecute(operations, callback) {
_proto.unsafeExecute = function (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
index ca35a79..7079572 100644
index e7acc55..afc44d0 100644
--- a/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,
payload: payload
} = action;
@ -261,22 +260,22 @@ index ca35a79..7079572 100644
} else {
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
index ee89cff..04de604 100644
index 85626c4..e448e9b 100644
--- a/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));
}
+ _proto.unsafeVacuum = function unsafeVacuum() {
+ _proto.unsafeVacuum = function () {
+ return new Promise(function ($return, $error) {
+ return Promise.resolve(0);
+ }.bind(this));
+ }
+ };
+
// *** 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
index 88c43a0..cef8232 100644
--- 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
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
+++ 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);
});
};
+ _proto.unsafeVacuum = function unsafeVacuum(callback) {
+ _proto.unsafeVacuum = function (callback) {
+ this._dispatcher.call('unsafeVacuum', [], function (result) {
+ if (result.value) {
+ _common.logger.log('[SQLite] Database is now vacuumed');
@ -306,45 +305,45 @@ index 985dbd6..bcc232d 100644
+ callback(result);
+ });
+ };
_proto.unsafeExecute = function unsafeExecute(operations, callback) {
_proto.unsafeExecute = function (operations, callback) {
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");
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
+++ b/node_modules/@nozbe/watermelondb/adapters/sqlite/sqlite-node/DatabaseBridge.js
@@ -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) {
+ return driver.unsafeVacuum({
+ version: schemaVersion,
+ 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) {
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
index 483884c..c325299 100644
index 40f7af6..97033b0 100644
--- a/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 () {
_this5.database.userVersion = schema.version;
});
};
+ _proto.unsafeVacuum = function unsafeVacuum() {
+ _proto.unsafeVacuum = function () {
+ var _this5 = this;
+ this.database.unsafeVacuum();
+ };
_proto.migrate = function migrate(migrations) {
_proto.migrate = function (migrations) {
var _this6 = this;
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
index 16a8a71..ce6e743 100644
index 5d1a321..bb7a195 100644
--- a/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 =
@ -356,10 +355,10 @@ index 16a8a71..ce6e743 100644
| 'unsafeExecuteMultiple'
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
+++ 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.
unsafeResetDatabase(callback: ResultCallback<void>): void
@ -595,16 +594,16 @@ index f0073c5..028031b 100644
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
index ef0f23b..cb49ecd 100644
index ef0f23b..d1a6742 100644
--- a/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) {
std::abort();
@@ -75,7 +75,17 @@ void Database::install(jsi::Runtime *runtime) {
databaseToDestroy->destroy();
}
});
-
+ createMethod(rt, adapter, "unsafeVacuum", 0, [database](jsi::Runtime &rt, const jsi::Value *args) {
+ assert(database->initialized_);
+
+ try {
+ database->unsafeVacuum();
+ return jsi::Value::undefined();
@ -614,9 +613,9 @@ index ef0f23b..cb49ecd 100644
+ std::abort();
+ }
+ });
createMethod(rt, adapter, "unsafeClose", 0, [database](jsi::Runtime &rt, const jsi::Value *args) {
assert(database->initialized_);
database->destroy();
createMethod(rt, adapter, "initialize", 2, [database](jsi::Runtime &rt, const jsi::Value *args) {
jsi::String dbName = args[0].getString(rt);
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
index e08153b..2fca075 100644
--- a/node_modules/@nozbe/watermelondb/native/shared/Sqlite.cpp
@ -645,34 +644,32 @@ index 4fe52f1..a4a99da 100644
sqlite3 *sqlite;
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
+++ 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> {
+ try {
+ // Kill ability to call adapter methods during reset (to catch bugs if someone does this)
+ const { adapter } = this
+ const ErrorAdapter = require('../adapters/error').default
+ this.adapter = (new ErrorAdapter(): any)
+
+ // Vacuum the database
+ await adapter.unsafeVacuum()
+
+ // Restore working Database
+ this._resetCount += 1
+ this.adapter = adapter
+ } finally {
+ this._isBeingReset = false
+ }
+ try {
+ // Kill ability to call adapter methods during reset (to catch bugs if someone does this)
+ const { adapter } = this
+ const ErrorAdapter = require('../adapters/error').default
+ this.adapter = (new ErrorAdapter(): any)
+ // Vacuum the database
+ await adapter.unsafeVacuum()
+ // Restore working Database
+ this._resetCount += 1
+ this.adapter = adapter
+ } finally {
+ this._isBeingReset = false
+ }
+}
+
_ensureInWriter(diagnosticMethodName: string): void {
invariant(
this._workQueue.isWriterRunning,
// (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/src/adapters/compat.js b/node_modules/@nozbe/watermelondb/src/adapters/compat.js
index c5175c0..c8c0c17 100644
--- a/node_modules/@nozbe/watermelondb/src/adapters/compat.js
@ -701,20 +698,20 @@ index 9f1e847..cdd3af4 100644
'setLocal',
'removeLocal',
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
+++ b/node_modules/@nozbe/watermelondb/src/adapters/sqlite/index.js
@@ -339,6 +339,19 @@ export default class SQLiteAdapter implements DatabaseAdapter {
)
}
+ unsafeVacuum(callback: ResultCallback<void): void {
+ unsafeVacuum(callback: ResultCallback<
+ this._dispatcher.call(
+ 'unsafeVacuum',
+ [],
+ (result) => {
+ if (result.value) {
+ logger.log('[SQLite] Database is vacuumed')
+ logger.log('[SQLite] Database
+ }
+ callback(result)
+ },
@ -773,7 +770,7 @@ index 63c955f..4e2f43e 100644
| 'unsafeExecuteMultiple'
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
+++ b/node_modules/@nozbe/watermelondb/src/adapters/type.js
@@ -68,6 +68,8 @@ export interface DatabaseAdapter {
@ -781,7 +778,7 @@ index 8929541..bc3f95d 100644
unsafeResetDatabase(callback: ResultCallback<void>): void;
+ unsafeVacuum(callback: ResultCallback<void>): void;
+
+
// Performs work on the underlying database - see concrete DatabaseAdapter implementation for more details
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
index 147bb53..b7cb80c 100644
index 8e60c59..bc201d2 100644
--- 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
@@ -31,10 +31,16 @@ async function getBuildSettings(xcodeProject, mode, buildOutput, scheme, target)
encoding: 'utf8'
});
const settings = JSON.parse(buildSettings);
+ const fistIndexForAppTarget = Math.max(
+ 0,
+ settings.findIndex(({
+ buildSettings: bs
+ }) => bs.WRAPPER_EXTENSION === 'app')
+ const firstIndexForAppTarget = Math.max(
+ 0,
+ settings.findIndex(({
+ buildSettings: bs
+ }) => bs.WRAPPER_EXTENSION === 'app')
+ );
const targets = settings.map(({
target: settingsTarget
}) => settingsTarget);
- let selectedTarget = targets[0];
+ let selectedTarget = targets[fistIndexForAppTarget];
+ let selectedTarget = targets[firstIndexForAppTarget];
if (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)}`);

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
index 071907c..e5c39f5 100644
index 071907c..edf10c1 100644
--- 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
@@ -70,8 +70,16 @@ data class GlideUrlWrapper(val glideUrl: GlideUrl) {
@@ -70,8 +70,15 @@ data class GlideUrlWrapper(val glideUrl: GlideUrl) {
@GlideModule
class ExpoImageOkHttpClientGlideModule : LibraryGlideModule() {
+ companion object {
+ var okHttpClient: OkHttpClient? = null
+ }
+
override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
- val client = OkHttpClient()
+ val client = if (okHttpClient != null) {
@ -21,13 +20,13 @@ index 071907c..e5c39f5 100644
// to make sure that the app will use only one 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
index de8bc65..564397d 100644
index 21bef71..d662d23 100644
--- a/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 'SDWebImage', '~> 5.19.1'
s.dependency 'SDWebImageWebPCoder', '~> 0.14.6'
- s.dependency 'SDWebImageAVIFCoder', '~> 0.11.0'
s.dependency 'SDWebImageSVGCoder', '~> 1.7.0'
- s.dependency 'libavif/libdav1d'
@ -35,23 +34,22 @@ index de8bc65..564397d 100644
# Swift/Objective-C compatibility
s.pod_target_xcconfig = {
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
+++ b/node_modules/expo-image/ios/ImageModule.swift
@@ -3,7 +3,6 @@
@@ -2,7 +2,6 @@
import ExpoModulesCore
import SDWebImage
import SDWebImageWebPCoder
-import SDWebImageAVIFCoder
import SDWebImageSVGCoder
public final class ImageModule: Module {
@@ -193,7 +192,7 @@ public final class ImageModule: Module {
// This coder is much slower, but it's the only one that works in iOS 13
SDImageCodersManager.shared.addCoder(SDImageWebPCoder.shared)
}
@@ -211,7 +210,6 @@ public final class ImageModule: Module {
static func registerCoders() {
// By default Animated WebP is not supported
SDImageCodersManager.shared.addCoder(SDImageAWebPCoder.shared)
- SDImageCodersManager.shared.addCoder(SDImageAVIFCoder.shared)
+
SDImageCodersManager.shared.addCoder(SDImageSVGCoder.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
index 2b01a1d..78c7ffa 100644
index 069e3e4..c32ba6c 100644
--- a/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 {
public func definition() -> ModuleDefinition {
Name("ExpoVideoThumbnails")
- AsyncFunction("getThumbnail", getVideoThumbnail).runOnQueue(.main)
+ AsyncFunction("getThumbnail", getVideoThumbnail).runOnQueue(.global())
- AsyncFunction("getThumbnail", getVideoThumbnail)
+ AsyncFunction("getThumbnail", getVideoThumbnail).runOnQueue(.global())
}
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) {
mPermissionListener = listener;
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
index 4cc09eb..857bbd4 100644
--- 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;
}
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
index 3acc41d..ebc8d18 100644
--- 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;
}
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
index 035ec31..630b8d4 100644
--- 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
index fc482a6..9406bbf 100644
--- a/node_modules/react-native-navigation/lib/ios/RNNComponentViewController.m
@ -376,6 +509,30 @@ index b44f24f..bf4e1c3 100644
[hitTestResult isKindOfClass:[RCTModalHostView class]] ||
[hitTestResult isKindOfClass:NSClassFromString(@"RCTRootComponentView")]) {
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
index 1ab5b4e..ccd0b74 100644
--- 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
index 9e2352a..fb45382 100644
index edfaa9b..41246bb 100644
--- a/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
? fetchText(uri)
.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
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
fi
fi

View file

@ -2,7 +2,7 @@
// See LICENSE.txt for license information.
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 {StyleSheet, useWindowDimensions, View} from 'react-native';
@ -20,9 +20,9 @@ type Props = {
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_LOCATIONS = [0.5, 1];
const GRADIENT_LOCATIONS: LinearGradientProps['locations'] = [0.5, 1];
const GRADIENT_START = {x: 0.3, y: 0.3};
const getStyles = makeStyleSheetFromTheme((theme: Theme) => ({
@ -81,7 +81,7 @@ const Thumbnail = ({contentMode, file, hasError, theme, type}: Props) => {
styles.container,
hasError && styles.error,
styles.radius,
]), [styles, imgStyle, hasError]);
]), [styles, hasError]);
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) => {
return queryHasChannels(serverUrl)?.observe().pipe(
switchMap((channels) => of$(channels?.length > 0 ?? false)),
switchMap((channels) => of$(channels.length > 0)),
) || 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', () => {
return {
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('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-haptic-feedback', () => {
const RNHF = jest.requireActual('react-native-haptic-feedback');
const RNHF = jest.requireActual('react-native-haptic-feedback/src/types');
return {
...RNHF,
trigger: () => '',

View file

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

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