Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ type AttachmentCarouselPagerContextValue = {

/** Callback for attachment errors */
onAttachmentError?: (source: AttachmentSource, state?: boolean) => void;

/** In case we need a gesture that should work simultaneously with panning in MultiGestureCanvas */
externalGestureHandler?: GestureType;
};

const AttachmentCarouselPagerContext = createContext<AttachmentCarouselPagerContextValue | null>(null);
Expand Down
46 changes: 21 additions & 25 deletions src/components/Attachments/AttachmentCarousel/Pager/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ import type {ForwardedRef, SetStateAction} from 'react';
import React, {useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState} from 'react';
import type {NativeSyntheticEvent} from 'react-native';
import {View} from 'react-native';
import type {NativeViewGestureHandlerProps} from 'react-native-gesture-handler';
import {createNativeWrapper} from 'react-native-gesture-handler';
import type {PagerViewProps} from 'react-native-pager-view';
import {Gesture, GestureDetector} from 'react-native-gesture-handler';
import PagerView from 'react-native-pager-view';
import Animated, {useAnimatedProps, useSharedValue} from 'react-native-reanimated';
import CarouselItem from '@components/Attachments/AttachmentCarousel/CarouselItem';
Expand All @@ -15,14 +13,7 @@ import shouldUseNewPager from '@libs/shouldUseNewPager';
import AttachmentCarouselPagerContext from './AttachmentCarouselPagerContext';
import usePageScrollHandler from './usePageScrollHandler';

const WrappedPagerView = createNativeWrapper(PagerView) as React.ForwardRefExoticComponent<
PagerViewProps &
NativeViewGestureHandlerProps &
React.RefAttributes<React.Component<PagerViewProps>> & {
useNext: boolean;
}
>;
const AnimatedPagerView = Animated.createAnimatedComponent(WrappedPagerView);
const AnimatedPagerView = Animated.createAnimatedComponent(PagerView);

type AttachmentCarouselPagerHandle = {
setPage: (selectedPage: number) => void;
Expand Down Expand Up @@ -93,6 +84,8 @@ function AttachmentCarouselPager(

const extractItemKey = useCallback((item: Attachment, index: number) => `attachmentID-${item.attachmentID}-${index}`, []);

const nativeGestureHandler = Gesture.Native();

const contextValue = useMemo(
() => ({
pagerItems,
Expand All @@ -104,8 +97,9 @@ function AttachmentCarouselPager(
onSwipeDown: onClose,
onScaleChanged: handleScaleChange,
onAttachmentError,
externalGestureHandler: nativeGestureHandler,
}),
[pagerItems, activePageIndex, isPagerScrolling, isScrollEnabled, handleTap, onClose, handleScaleChange, onAttachmentError],
[pagerItems, activePageIndex, isPagerScrolling, isScrollEnabled, handleTap, onClose, handleScaleChange, nativeGestureHandler, onAttachmentError],
);

const animatedProps = useAnimatedProps(() => ({
Expand Down Expand Up @@ -141,19 +135,21 @@ function AttachmentCarouselPager(

return (
<AttachmentCarouselPagerContext.Provider value={contextValue}>
<AnimatedPagerView
pageMargin={40}
offscreenPageLimit={1}
onPageScroll={pageScrollHandler}
onPageSelected={onPageSelected}
style={styles.flex1}
initialPage={initialPage}
useNext={shouldUseNewPager()}
animatedProps={animatedProps}
ref={pagerRef}
>
{carouselItems}
</AnimatedPagerView>
<GestureDetector gesture={nativeGestureHandler}>
<AnimatedPagerView
pageMargin={40}
offscreenPageLimit={1}
onPageScroll={pageScrollHandler}
onPageSelected={onPageSelected}
style={styles.flex1}
initialPage={initialPage}
useNext={shouldUseNewPager()}
animatedProps={animatedProps}
ref={pagerRef}
>
{carouselItems}
</AnimatedPagerView>
</GestureDetector>
</AttachmentCarouselPagerContext.Provider>
);
}
Expand Down
11 changes: 7 additions & 4 deletions src/components/Lightbox/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {getCanvasFitScale} from '@components/MultiGestureCanvas/utils';
import useNetwork from '@hooks/useNetwork';
import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';
import * as FileUtils from '@libs/fileDownload/FileUtils';
import {isLocalFile} from '@libs/fileDownload/FileUtils';
import NUMBER_OF_CONCURRENT_LIGHTBOXES from './numberOfConcurrentLightboxes';

const cachedImageDimensions = new Map<string, ContentSize | undefined>();
Expand Down Expand Up @@ -65,6 +65,7 @@ function Lightbox({isAuthTokenRequired = false, uri, onScaleChanged: onScaleChan
onSwipeDown,
pagerRef,
isScrollEnabled,
externalGestureHandler,
} = useMemo(() => {
if (attachmentCarouselPagerContext === null) {
return {
Expand All @@ -78,6 +79,7 @@ function Lightbox({isAuthTokenRequired = false, uri, onScaleChanged: onScaleChan
onScaleChanged: () => {},
onSwipeDown: () => {},
pagerRef: undefined,
externalGestureHandler: undefined,
};
}

Expand Down Expand Up @@ -201,7 +203,7 @@ function Lightbox({isAuthTokenRequired = false, uri, onScaleChanged: onScaleChan
[onScaleChangedContext, onScaleChangedProp],
);

const isLocalFile = FileUtils.isLocalFile(uri);
const isALocalFile = isLocalFile(uri);

return (
<View
Expand All @@ -224,6 +226,7 @@ function Lightbox({isAuthTokenRequired = false, uri, onScaleChanged: onScaleChan
onTap={onTap}
onScaleChanged={scaleChange}
onSwipeDown={onSwipeDown}
externalGestureHandler={externalGestureHandler}
>
<Image
source={{uri}}
Expand Down Expand Up @@ -264,13 +267,13 @@ function Lightbox({isAuthTokenRequired = false, uri, onScaleChanged: onScaleChan
)}

{/* Show activity indicator while the lightbox is still loading the image. */}
{isLoading && (!isOffline || isLocalFile) && (
{isLoading && (!isOffline || isALocalFile) && (
<ActivityIndicator
size="large"
style={StyleSheet.absoluteFill}
/>
)}
{isLoading && !isLocalFile && <AttachmentOfflineIndicator />}
{isLoading && !isALocalFile && <AttachmentOfflineIndicator />}
</>
)}
</View>
Expand Down
10 changes: 8 additions & 2 deletions src/components/MultiGestureCanvas/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type {ForwardedRef} from 'react';
import React, {useCallback, useEffect, useMemo, useRef} from 'react';
import {View} from 'react-native';
import type {GestureType} from 'react-native-gesture-handler';
import {Gesture, GestureDetector} from 'react-native-gesture-handler';
import type {GestureType} from 'react-native-gesture-handler';
import type {GestureRef} from 'react-native-gesture-handler/lib/typescript/handlers/gestures/gesture';
import type PagerView from 'react-native-pager-view';
import type {SharedValue} from 'react-native-reanimated';
Expand Down Expand Up @@ -57,6 +57,9 @@ type MultiGestureCanvasProps = ChildrenProps & {

/** Handles swipe down event */
onSwipeDown?: OnSwipeDownCallback;

/** We need to ensure that any native gesture handlers in this component tree is working simultaneously with panning and do not get blocked. */
externalGestureHandler?: GestureType;
};

const defaultContentSize = {width: 1, height: 1};
Expand All @@ -74,6 +77,7 @@ function MultiGestureCanvas({
onTap,
onScaleChanged,
onSwipeDown,
externalGestureHandler,
}: MultiGestureCanvasProps) {
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
Expand Down Expand Up @@ -264,12 +268,14 @@ function MultiGestureCanvas({

const containerStyles = useMemo(() => [styles.flex1, StyleUtils.getMultiGestureCanvasContainerStyle(canvasSize.width)], [StyleUtils, canvasSize.width, styles.flex1]);

const panGestureWrapper = externalGestureHandler ? panGesture.simultaneousWithExternalGesture(externalGestureHandler) : panGesture;

return (
<View
collapsable={false}
style={containerStyles}
>
<GestureDetector gesture={Gesture.Simultaneous(pinchGesture, Gesture.Race(singleTapGesture, doubleTapGesture, panGesture))}>
<GestureDetector gesture={Gesture.Simultaneous(pinchGesture, Gesture.Race(singleTapGesture, doubleTapGesture, panGestureWrapper))}>
<View
collapsable={false}
onTouchEnd={(e) => e.preventDefault()}
Expand Down
Loading