Repository navigation
Expand file tree
/
Copy pathImageCarouselFullScreenAndroid.tsx
More file actions
126 lines (117 loc) · 4.44 KB
/
Copy pathImageCarouselFullScreenAndroid.tsx
File metadata and controls
126 lines (117 loc) · 4.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import { useColor } from "@artsy/palette-mobile"
import {
ImageCarouselContext,
ImageCarouselMedia,
} from "app/Scenes/Artwork/Components/ImageCarousel/ImageCarouselContext"
import { ImageCarouselVimeoVideo } from "app/Scenes/Artwork/Components/ImageCarousel/ImageCarouselVimeoVideo"
import { GlobalStore } from "app/store/GlobalStore"
import { useScreenDimensions } from "app/utils/hooks/useScreenDimensions"
import { useCallback, useContext, useEffect, useMemo, useRef, useState } from "react"
import {
FlatList,
LayoutChangeEvent,
Modal,
NativeScrollEvent,
NativeSyntheticEvent,
} from "react-native"
import { GestureHandlerRootView } from "react-native-gesture-handler"
import { ImageCarouselCloseButton } from "./ImageCarouselCloseButton"
import { ImageZoomViewAndroid } from "./ImageZoomViewAndroid"
import { IndexIndicator } from "./IndexIndicator"
export const ImageCarouselFullScreenAndroid = () => {
const screenDimensions = useScreenDimensions()
const color = useColor()
const { media, dispatch, fullScreenState, imageIndex } = useContext(ImageCarouselContext)
fullScreenState.useUpdates()
const initialScrollIndex = useMemo(() => imageIndex.current, [])
const { setIsDeepZoomModalVisible } = GlobalStore.actions.devicePrefs
const [showBackButton, setShowBackButton] = useState(false)
const listRef = useRef<FlatList<ImageCarouselMedia>>(null)
// The modal is edge-to-edge on Android 15+, so it is taller than Dimensions' "window".
// Size the pages from the modal's own layout instead.
const [measuredPageSize, setMeasuredPageSize] = useState<{ width: number; height: number }>()
const pageWidth = measuredPageSize?.width ?? screenDimensions.width
const pageHeight = measuredPageSize?.height ?? screenDimensions.height
const onLayout = useCallback((e: LayoutChangeEvent) => {
const { width, height } = e.nativeEvent.layout
setMeasuredPageSize({ width, height })
}, [])
const onClose = useCallback(() => {
dispatch({ type: "FULL_SCREEN_DISMISSED" })
setIsDeepZoomModalVisible(false)
}, [])
useEffect(() => {
if (fullScreenState.current === "exiting") {
requestAnimationFrame(() => {
dispatch({ type: "FULL_SCREEN_FINISHED_EXITING" })
})
}
}, [fullScreenState.current])
const renderItem = useCallback(
({ item, index }: { item: ImageCarouselMedia; index: number }) => {
if (item.__typename === "Video") {
return <ImageCarouselVimeoVideo width={pageWidth} height={pageHeight} vimeoUrl={item.url} />
}
return (
<ImageZoomViewAndroid
image={item}
index={index}
width={pageWidth}
height={pageHeight}
parentScrollRef={listRef}
/>
)
},
[pageWidth, pageHeight]
)
// Update the imageIndex on scroll
const onScroll = useCallback(
(e: NativeSyntheticEvent<NativeScrollEvent>) => {
const nextImageIndex = Math.round(e.nativeEvent.contentOffset.x / pageWidth)
if (fullScreenState.current === "entered" && nextImageIndex !== imageIndex.current) {
dispatch({ type: "IMAGE_INDEX_CHANGED", nextImageIndex })
}
},
[pageWidth]
)
return (
// On mount we want the modal to be visible instantly and handle transitions elsewhere ourselves
// on unmount we use it's built-in fade transition
<Modal
transparent
animationType="fade"
hardwareAccelerated
supportedOrientations={["landscape", "portrait"]}
statusBarTranslucent
// 👇 responsible for closing the modal on android back button press
onRequestClose={onClose}
onShow={() => setShowBackButton(true)}
>
{!!showBackButton && <ImageCarouselCloseButton onClose={onClose} />}
<GestureHandlerRootView
style={{ flex: 1, backgroundColor: color("mono0") }}
onLayout={onLayout}
>
<FlatList<ImageCarouselMedia>
ref={listRef}
data={media}
pagingEnabled
showsHorizontalScrollIndicator={false}
horizontal
keyExtractor={(item, index) => `${item.url}-${index}`}
renderItem={renderItem}
key={screenDimensions.orientation}
initialScrollIndex={initialScrollIndex}
getItemLayout={(_, index) => ({
index,
offset: index * pageWidth,
length: pageWidth,
})}
onScroll={onScroll}
initialNumToRender={2}
/>
<IndexIndicator />
</GestureHandlerRootView>
</Modal>
)
}