Various Fixes (#8212)

This commit is contained in:
Elias Nahum 2024-09-13 04:46:15 +08:00 committed by GitHub
parent 20d248fb99
commit 394da4487c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 259 additions and 77 deletions

View file

@ -6,6 +6,7 @@ import {Button} from '@rneui/base';
import React, {useCallback, useEffect, useMemo, useState} from 'react';
import {useIntl, type IntlShape} from 'react-intl';
import {Alert, StyleSheet} from 'react-native';
import Animated from 'react-native-reanimated';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {ITEM_HEIGHT} from '@components/option_item';
@ -149,20 +150,19 @@ const ChannelBookmark = ({
}
return (
<Button
containerStyle={styles.container}
buttonStyle={styles.button}
onPress={onGestureEvent}
onLongPress={handleLongPress}
// @ts-expect-error ref not present in TS def
ref={ref}
>
<BookmarkDetails
bookmark={bookmark}
file={file}
/>
</Button>
<Animated.View ref={ref}>
<Button
containerStyle={styles.container}
buttonStyle={styles.button}
onPress={onGestureEvent}
onLongPress={handleLongPress}
>
<BookmarkDetails
bookmark={bookmark}
file={file}
/>
</Button>
</Animated.View>
);
};

View file

@ -1,14 +1,17 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import RNUtils, {type WindowDimensions} from '@mattermost/rnutils';
import React, {type RefObject, useEffect, useRef, useState, useContext} from 'react';
import {AppState, DeviceEventEmitter, Keyboard, Platform, useWindowDimensions, View} from 'react-native';
import {AppState, DeviceEventEmitter, Keyboard, NativeEventEmitter, Platform, View} from 'react-native';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {DeviceContext} from '@context/device';
import type {KeyboardTrackingViewRef, KeyboardWillShowEventData} from '@mattermost/keyboard-tracker';
const utilsEmitter = new NativeEventEmitter(RNUtils);
export function useSplitView() {
const {isSplit} = React.useContext(DeviceContext);
return isSplit;
@ -28,6 +31,20 @@ export function useAppState() {
return appState;
}
export function useWindowDimensions() {
const [dimensions, setDimensions] = useState(RNUtils.getWindowDimensions());
useEffect(() => {
const listener = utilsEmitter.addListener('DimensionsChanged', (window: WindowDimensions) => {
setDimensions(window);
});
return () => listener.remove();
}, []);
return dimensions;
}
export function useIsTablet() {
const {isSplit, isTablet} = useContext(DeviceContext);
return isTablet && !isSplit;

View file

@ -3,12 +3,12 @@
import RNUtils from '@mattermost/rnutils';
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
import {useWindowDimensions, Platform} from 'react-native';
import {Platform} from 'react-native';
import {CaptionsEnabledContext} from '@calls/context';
import {hasCaptions} from '@calls/utils';
import useAndroidHardwareBackHandler from '@hooks/android_back_handler';
import {useIsTablet} from '@hooks/device';
import {useIsTablet, useWindowDimensions} from '@hooks/device';
import {useGalleryControls} from '@hooks/gallery';
import {dismissOverlay, setScreensOrientation} from '@screens/navigation';
import {freezeOtherScreens} from '@utils/gallery';
@ -35,7 +35,7 @@ const GalleryScreen = ({componentId, galleryIdentifier, hideActions, initialInde
const [captionsEnabled, setCaptionsEnabled] = useState<boolean[]>(new Array(items.length).fill(true));
const [captionsAvailable, setCaptionsAvailable] = useState<boolean[]>([]);
const {setControlsHidden, headerStyles, footerStyles} = useGalleryControls();
const dimensions = useMemo(() => ({width: dim.width, height: dim.height}), [dim.width]);
const dimensions = useMemo(() => ({width: dim.width, height: dim.height}), [dim]);
const galleryRef = useRef<GalleryRef>(null);
useEffect(() => {

View file

@ -2,7 +2,7 @@
// See LICENSE.txt for license information.
import React, {useCallback, useContext, useEffect, useMemo, useRef, useState} from 'react';
import {DeviceEventEmitter, StyleSheet, useWindowDimensions} from 'react-native';
import {DeviceEventEmitter, StyleSheet} from 'react-native';
import Animated, {
Easing,
useAnimatedStyle,
@ -47,7 +47,6 @@ const styles = StyleSheet.create({
});
const VideoRenderer = ({height, index, initialIndex, item, isPageActive, onShouldHideControls, width}: VideoRendererProps) => {
const dimensions = useWindowDimensions();
const fullscreen = useSharedValue(false);
const {bottom} = useSafeAreaInsets();
const serverUrl = useServerUrl();
@ -126,23 +125,15 @@ const VideoRenderer = ({height, index, initialIndex, item, isPageActive, onShoul
}, []);
const dimensionsStyle = useMemo(() => {
let w = width;
let h = height - (VIDEO_INSET + GALLERY_FOOTER_HEIGHT + bottom);
const w = width;
const h = height - (VIDEO_INSET + GALLERY_FOOTER_HEIGHT + bottom);
if (hasError) {
return {height: 0, width: 0};
}
if (fullscreen.value) {
w = dimensions.width;
h = dimensions.height;
} else if (dimensions.width > dimensions.height) {
w = h;
h = width;
}
return {width: w, height: h};
}, [hasError, fullscreen.value, dimensions.height]);
}, [hasError, fullscreen.value, height, width]);
const animatedStyle = useAnimatedStyle(() => {
return {

View file

@ -120,7 +120,7 @@ const GalleryViewer = ({
}
return (<ImageRenderer {...props}/>);
}, [items]);
}, [items, width, height]);
return (
<Pager

View file

@ -25,14 +25,13 @@ import {getIntlShape} from '@utils/general';
import {logError} from '@utils/log';
import {escapeRegex} from '@utils/markdown';
import {addNewServer} from '@utils/server';
import {removeProtocol, stripTrailingSlashes} from '@utils/url';
import {
TEAM_NAME_PATH_PATTERN,
IDENTIFIER_PATH_PATTERN,
ID_PATH_PATTERN,
} from '@utils/url/path';
import {removeProtocol} from '../url';
import type {DeepLinkChannel, DeepLinkDM, DeepLinkGM, DeepLinkPermalink, DeepLinkWithData, LaunchProps} from '@typings/launch';
import type {AvailableScreens} from '@typings/screens/navigation';
@ -121,29 +120,30 @@ export async function handleDeepLink(deepLinkUrl: string, intlShape?: IntlShape,
type ChannelPathParams = {
hostname: string;
serverUrl: string;
serverUrl: string[];
teamName: string;
path: 'channels' | 'messages';
identifier: string;
};
const CHANNEL_PATH = `:serverUrl(.*)/:teamName(${TEAM_NAME_PATH_PATTERN})/:path(channels|messages)/:identifier(${IDENTIFIER_PATH_PATTERN})`;
const CHANNEL_PATH = '*serverUrl/:teamName/:path/:identifier';
export const matchChannelDeeplink = match<ChannelPathParams>(CHANNEL_PATH);
type PermalinkPathParams = {
serverUrl: string;
serverUrl: string[];
teamName: string;
postId: string;
};
const PERMALINK_PATH = `:serverUrl(.*)/:teamName(${TEAM_NAME_PATH_PATTERN})/pl/:postId(${ID_PATH_PATTERN})`;
const PERMALINK_PATH = '*serverUrl/:teamName/pl/:postId';
export const matchPermalinkDeeplink = match<PermalinkPathParams>(PERMALINK_PATH);
type ServerPathParams = {
serverUrl: string;
path: string;
subpath?: string[];
}
export const matchServerDeepLink = match<ServerPathParams>(':serverUrl(.*)/:path(.*)', {decode: decodeURIComponent});
export const matchServerDeepLink = match<ServerPathParams>(':serverUrl/{:path}{/*subpath}', {decode: decodeURIComponent});
const reservedWords = ['login', 'signup', 'admin_console'];
export function extractServerUrl(url: string) {
@ -168,43 +168,72 @@ export function extractServerUrl(url: string) {
const matched = matchServerDeepLink(deepLinkUrl);
if (matched) {
const {path} = matched.params;
const segments = path.split('/');
const {path, subpath} = matched.params;
if (segments.length > 0 && reservedWords.includes(segments[segments.length - 1])) {
return matched.params.serverUrl;
let extra = '';
if (!path || reservedWords.includes(path)) {
return stripTrailingSlashes(matched.params.serverUrl);
}
return path ? `${matched.params.serverUrl}/${path}` : matched.params.serverUrl;
if (subpath && subpath.length > 0) {
if (reservedWords.includes(subpath[subpath.length - 1])) {
subpath.pop();
}
extra = subpath.join('/');
}
if (extra) {
return stripTrailingSlashes(`${matched.params.serverUrl}/${path}/${extra}`);
}
return stripTrailingSlashes(`${matched.params.serverUrl}/${path}`);
}
return deepLinkUrl;
}
function isValidTeamName(teamName: string): boolean {
const regex = new RegExp(`^${TEAM_NAME_PATH_PATTERN}$`);
return regex.test(teamName);
}
function isValidIdentifierPathPattern(id: string): boolean {
const regex = new RegExp(`^${IDENTIFIER_PATH_PATTERN}$`);
return regex.test(id);
}
function isValidPostId(id: string): boolean {
const regex = new RegExp(`^${ID_PATH_PATTERN}$`);
return regex.test(id);
}
export function parseDeepLink(deepLinkUrl: string, asServer = false): DeepLinkWithData {
try {
const url = removeProtocol(deepLinkUrl);
const channelMatch = matchChannelDeeplink(url);
if (channelMatch) {
if (channelMatch && isValidTeamName(channelMatch.params.teamName) && isValidIdentifierPathPattern(channelMatch.params.identifier)) {
const {params: {serverUrl, teamName, path, identifier}} = channelMatch;
if (path === 'channels') {
return {type: DeepLink.Channel, url: deepLinkUrl, data: {serverUrl, teamName, channelName: identifier}};
return {type: DeepLink.Channel, url: deepLinkUrl, data: {serverUrl: serverUrl.join('/'), teamName, channelName: identifier}};
}
if (path === 'messages') {
if (identifier.startsWith('@')) {
return {type: DeepLink.DirectMessage, url: deepLinkUrl, data: {serverUrl, teamName, userName: identifier.substring(1)}};
return {type: DeepLink.DirectMessage, url: deepLinkUrl, data: {serverUrl: serverUrl.join('/'), teamName, userName: identifier.substring(1)}};
}
return {type: DeepLink.GroupMessage, url: deepLinkUrl, data: {serverUrl, teamName, channelName: identifier}};
return {type: DeepLink.GroupMessage, url: deepLinkUrl, data: {serverUrl: serverUrl.join('/'), teamName, channelName: identifier}};
}
}
const permalinkMatch = matchPermalinkDeeplink(url);
if (permalinkMatch) {
if (permalinkMatch && isValidTeamName(permalinkMatch.params.teamName) && isValidPostId(permalinkMatch.params.postId)) {
const {params: {serverUrl, teamName, postId}} = permalinkMatch;
return {type: DeepLink.Permalink, url: deepLinkUrl, data: {serverUrl, teamName, postId}};
return {type: DeepLink.Permalink, url: deepLinkUrl, data: {serverUrl: serverUrl.join('/'), teamName, postId}};
}
if (asServer) {

View file

@ -16,17 +16,17 @@ GEM
artifactory (3.0.17)
atomos (0.1.3)
aws-eventstream (1.3.0)
aws-partitions (1.966.0)
aws-sdk-core (3.201.5)
aws-partitions (1.973.0)
aws-sdk-core (3.204.0)
aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.651.0)
aws-sigv4 (~> 1.9)
jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.88.0)
aws-sdk-core (~> 3, >= 3.201.0)
aws-sdk-kms (1.90.0)
aws-sdk-core (~> 3, >= 3.203.0)
aws-sigv4 (~> 1.5)
aws-sdk-s3 (1.159.0)
aws-sdk-core (~> 3, >= 3.201.0)
aws-sdk-s3 (1.161.0)
aws-sdk-core (~> 3, >= 3.203.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.5)
aws-sigv4 (1.9.1)
@ -188,8 +188,7 @@ GEM
trailblazer-option (>= 0.1.1, < 0.2.0)
uber (< 0.2.0)
retriable (3.1.2)
rexml (3.3.5)
strscan
rexml (3.3.7)
rouge (2.0.7)
ruby2_keywords (0.0.5)
rubyzip (2.3.2)
@ -202,7 +201,6 @@ GEM
simctl (1.6.10)
CFPropertyList
naturally
strscan (3.1.0)
terminal-notifier (2.0.0)
terminal-table (3.0.2)
unicode-display_width (>= 1.1.1, < 3)

View file

@ -69,6 +69,10 @@ class RNUtilsModuleImpl(private val reactContext: ReactApplicationContext) {
return SplitView.isRunningInSplitView()
}
fun getWindowDimensions(): WritableMap? {
return SplitView.getWindowDimensions()
}
fun unlockOrientation() {}
fun lockPortrait() {}

View file

@ -2,5 +2,6 @@ package com.mattermost.rnutils.enums
enum class Events(val event: String) {
SAVE_ERROR_EVENT("SaveError"),
SPLIT_VIEW_CHANGED("SplitViewChanged")
SPLIT_VIEW_CHANGED("SplitViewChanged"),
DIMENSIONS_CHANGED("DimensionsChanged")
}

View file

@ -1,6 +1,7 @@
package com.mattermost.rnutils.helpers
import android.app.Activity
import android.graphics.Rect
import androidx.window.core.layout.WindowHeightSizeClass
import androidx.window.core.layout.WindowSizeClass
import androidx.window.core.layout.WindowWidthSizeClass
@ -19,6 +20,7 @@ class FoldableObserver(activity: Activity) {
private lateinit var observable: Observable<WindowLayoutInfo>
var isDeviceFolded: Boolean = false
private val activityRef = WeakReference(activity)
private var windowBounds: Rect? = null
companion object {
private var instance: FoldableObserver? = null
@ -43,6 +45,7 @@ class FoldableObserver(activity: Activity) {
val activity = activityRef.get() ?: return
observable = WindowInfoTracker.getOrCreate(activity)
.windowLayoutInfoObservable(activity)
this.windowBounds = getWindowSize()
}
fun onStart() {
@ -52,6 +55,7 @@ class FoldableObserver(activity: Activity) {
disposable = observable.observeOn(AndroidSchedulers.mainThread())
.subscribe { layoutInfo ->
setIsDeviceFolded(layoutInfo)
handleWindowLayoutInfo(layoutInfo)
SplitView.setDeviceFolded()
}
}
@ -78,11 +82,43 @@ class FoldableObserver(activity: Activity) {
}
}
private fun handleWindowLayoutInfo(windowLayoutInfo: WindowLayoutInfo) {
val bounds = getWindowSize()
if (bounds?.width() != windowBounds?.width()) {
// emit the dimensions changed event
windowBounds = bounds
SplitView.emitDimensionsChanged()
}
}
private fun getWindowSize(): Rect? {
val activity = activityRef.get() ?: return null
val metrics = WindowMetricsCalculator.getOrCreate().computeCurrentWindowMetrics(activity)
val bounds = metrics.bounds
val widthPx = bounds.width()
val heightPx = bounds.height()
// Get the screen density (scale factor)
val displayMetrics = activity.resources.displayMetrics
val density = displayMetrics.density
// Adjust dimensions based on the scale factor (density)
val widthDp = (widthPx / density).toInt()
val heightDp = (heightPx / density).toInt()
return Rect(0, 0, widthDp, heightDp)
}
fun getWindowDimensions(): Rect? {
return this.windowBounds;
}
fun isCompactView(): Boolean {
val activity = activityRef.get() ?: return false
val metrics = WindowMetricsCalculator.getOrCreate().computeCurrentWindowMetrics(activity)
val width = metrics.bounds.width()
val height = metrics.bounds.height()
val bounds = getWindowSize()
val width = bounds?.width() ?: 0
val height = bounds?.height() ?: 0
val density = activity.resources.displayMetrics.density
val windowSizeClass = WindowSizeClass.compute(width / density, height / density)
val widthWindowSizeClass = windowSizeClass.windowWidthSizeClass

View file

@ -33,7 +33,6 @@ class SplitView {
return isLargeScreen || isSmallestWidthLarge || isNotPhone
}
fun setDeviceFolded() {
val map = getSplitViewResults(FoldableObserver.getInstance()?.isDeviceFolded == true)
RNUtilsModuleImpl.sendJSEvent(Events.SPLIT_VIEW_CHANGED.event, map)
@ -57,5 +56,28 @@ class SplitView {
fun isRunningInSplitView(): WritableMap? {
return getSplitViewResults(FoldableObserver.getInstance()?.isDeviceFolded == true)
}
fun getWindowDimensions(): WritableMap? {
if (context?.currentActivity != null) {
val map = Arguments.createMap()
val bounds = FoldableObserver.getInstance()?.getWindowDimensions()
if (bounds != null) {
map.putInt("width", bounds.width())
map.putInt("height", bounds.height())
} else {
map.putInt("width", 0)
map.putInt("height", 0)
}
return map
}
return null
}
fun emitDimensionsChanged() {
val map = getWindowDimensions()
RNUtilsModuleImpl.sendJSEvent(Events.DIMENSIONS_CHANGED.event, map)
}
}
}

View file

@ -27,6 +27,8 @@ class RNUtilsModule(val reactContext: ReactApplicationContext) : NativeRNUtilsSp
override fun isRunningInSplitView(): WritableMap? = implementation.isRunningInSplitView()
override fun getWindowDimensions(): WritableMap? = implementation.getWindowDimensions()
override fun unlockOrientation() {
implementation.unlockOrientation()
}

View file

@ -39,6 +39,11 @@ class RNUtilsModule(context: ReactApplicationContext) :
return implementation.isRunningInSplitView()
}
@ReactMethod(isBlockingSynchronousMethod = true)
fun getWindowDimensions(): WritableMap? {
return implementation.getWindowDimensions()
}
@ReactMethod
fun unlockOrientation() {
implementation.unlockOrientation()

View file

@ -3,6 +3,7 @@ import Foundation
extension RNUtilsWrapper {
enum Event: String, CaseIterable {
case SplitViewChanged
case DimensionsChanged
}
@objc

View file

@ -72,6 +72,10 @@ RCT_REMAP_BLOCKING_SYNCHRONOUS_METHOD(isRunningInSplitView, NSDictionary*, isSpl
return [wrapper isRunningInSplitView];
}
RCT_REMAP_BLOCKING_SYNCHRONOUS_METHOD(getWindowDimensions, NSDictionary*, windowDimensions) {
return [wrapper getWindowDimensions];
}
RCT_REMAP_METHOD(unlockOrientation, unlock) {
[wrapper unlockOrientation];
}
@ -158,6 +162,9 @@ RCT_EXPORT_METHOD(saveFile:(NSString *)filePath
return [wrapper isRunningInSplitView];
}
- (NSDictionary *)getWindowDimensions {
return [wrapper getWindowDimensions];
}
- (void)lockPortrait {
[wrapper lockOrientation];

View file

@ -22,6 +22,11 @@ import React
return sharedDirectory.appendingPathComponent("databases").path
}
func getWindowSize() -> (CGSize?, CGSize?) {
guard let w = UIApplication.shared.delegate?.window, let window = w else { return (nil, nil) }
return (window.screen.bounds.size, window.frame.size)
}
func isRunningInFullScreen() -> Bool {
guard let w = UIApplication.shared.delegate?.window, let window = w else { return false }
let screenSize = window.screen.bounds.size.width
@ -30,16 +35,37 @@ import React
return shouldBeConsideredFullScreen
}
@objc public func captureEvents() {
NotificationCenter.default.addObserver(self,
selector: #selector(isSplitView), name: NSNotification.Name.RCTUserInterfaceStyleDidChange,
object: nil)
func isRunningInFullScreen(screen: CGSize?, frame: CGSize?) -> Bool {
guard let screenSize = screen?.width,
let frameSize = frame?.width else {return false}
let shouldBeConsideredFullScreen = frameSize >= (screenSize * 0.6)
return shouldBeConsideredFullScreen
}
@objc func isSplitView() {
@objc public func captureEvents() {
DispatchQueue.main.async {
guard let w = UIApplication.shared.delegate?.window, let window = w else { return }
window.addObserver(self, forKeyPath: "frame", options: .new, context: nil)
}
}
override public func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "frame" {
let (screen, frame) = getWindowSize()
guard let screen = screen, let frame = frame else {return}
isSplitView(screen: screen, frame: frame)
delegate?.sendEvent(name: "DimensionsChanged", result: [
"width": frame.width,
"height": frame.height
])
}
}
@objc func isSplitView(screen: CGSize, frame: CGSize) {
if UIDevice.current.userInterfaceIdiom == .pad {
delegate?.sendEvent(name: "SplitViewChanged", result: [
"isSplitView": !isRunningInFullScreen(),
"isSplit": !isRunningInFullScreen(screen: screen, frame: frame),
"isTablet": UIDevice.current.userInterfaceIdiom == .pad,
])
}
@ -203,6 +229,28 @@ import React
]
}
@objc public func getWindowDimensions() -> Dictionary<String, Any> {
let queue = DispatchQueue.main
let group = DispatchGroup()
var dimensions = [
"width": 0.0,
"height": 0.0
]
group.enter()
queue.async(group: group) { [weak self] in
if let (_, frame) = self?.getWindowSize(),
let frame = frame {
dimensions = [
"width": frame.width,
"height": frame.height
]
}
group.leave()
}
group.wait()
return dimensions
}
@objc public func unlockOrientation() {
DispatchQueue.main.async {
OrientationManager.shared.unlockOrientation()

View file

@ -3,7 +3,7 @@
import {type TurboModule, TurboModuleRegistry} from 'react-native';
import type {Int32, UnsafeObject} from 'react-native/Libraries/Types/CodegenTypes';
import type {Double, Int32, UnsafeObject} from 'react-native/Libraries/Types/CodegenTypes';
export type SplitView = Readonly<{
isSplit: boolean;
@ -36,6 +36,11 @@ type Constants = Readonly<{
}>;
}>
export type WindowDimensionsChanged = Readonly<{
width: Double;
height: Double;
}>
export interface Spec extends TurboModule {
readonly getConstants: () => Constants;
@ -45,6 +50,7 @@ export interface Spec extends TurboModule {
getRealFilePath: (filePath: string) => Promise<string>;
saveFile: (filePath: string) => Promise<string>;
getWindowDimensions: () => WindowDimensionsChanged;
isRunningInSplitView: () => SplitView;
unlockOrientation: () => void;
lockPortrait: () => void;

View file

@ -2,7 +2,7 @@
// See LICENSE.txt for license information.
import {NativeModules, Platform} from 'react-native';
import type {Spec, SplitView} from './NativeRNUtils';
import type {Spec, SplitView, WindowDimensionsChanged} from './NativeRNUtils';
const LINKING_ERROR =
'The package \'@mattermost/rnutils\' doesn\'t seem to be linked. Make sure: \n\n' +
@ -26,5 +26,7 @@ const RNUtils = RNUtilsModule || new Proxy(
export type SplitViewResult = SplitView;
export type WindowDimensions = WindowDimensionsChanged;
export default RNUtils;

8
package-lock.json generated
View file

@ -62,7 +62,7 @@
"moment-timezone": "0.5.45",
"node-html-parser": "6.1.13",
"pako": "2.1.0",
"path-to-regexp": "7.1.0",
"path-to-regexp": "8.1.0",
"react": "18.2.0",
"react-freeze": "1.0.4",
"react-intl": "6.6.8",
@ -22634,9 +22634,9 @@
}
},
"node_modules/path-to-regexp": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-7.1.0.tgz",
"integrity": "sha512-ZToe+MbUF4lBqk6dV8GKot4DKfzrxXsplOddH8zN3YK+qw9/McvP7+4ICjZvOne0jQhN4eJwHsX6tT0Ns19fvw==",
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.1.0.tgz",
"integrity": "sha512-Bqn3vc8CMHty6zuD+tG23s6v2kwxslHEhTj4eYaVKGIEB+YX/2wd0/rgXLFD9G9id9KCtbVy/3ZgmvZjpa0UdQ==",
"license": "MIT",
"engines": {
"node": ">=16"

View file

@ -63,7 +63,7 @@
"moment-timezone": "0.5.45",
"node-html-parser": "6.1.13",
"pako": "2.1.0",
"path-to-regexp": "7.1.0",
"path-to-regexp": "8.1.0",
"react": "18.2.0",
"react-freeze": "1.0.4",
"react-intl": "6.6.8",

View file

@ -0,0 +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
--- 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())
}
internal func getVideoThumbnail(sourceFilename: URL, options: VideoThumbnailsOptions) throws -> [String: Any] {