Move LightboxFooter into the implementation file

This commit is contained in:
Dan Abramov
2024-11-02 00:17:25 +00:00
parent ab6877795f
commit 6ee2b05ac0
2 changed files with 125 additions and 120 deletions
+122 -4
View File
@@ -9,12 +9,26 @@
// https://github.com/jobtoday/react-native-image-viewing
import React, {useCallback, useMemo, useState} from 'react'
import {Platform, StyleSheet, View} from 'react-native'
import {
Dimensions,
LayoutAnimation,
Platform,
StyleSheet,
View,
} from 'react-native'
import PagerView from 'react-native-pager-view'
import {MeasuredDimensions} from 'react-native-reanimated'
import Animated, {useAnimatedStyle, withSpring} from 'react-native-reanimated'
import {useSafeAreaInsets} from 'react-native-safe-area-context'
import {Edge, SafeAreaView} from 'react-native-safe-area-context'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {Trans} from '@lingui/macro'
import {colors, s} from '#/lib/styles'
import {isIOS} from '#/platform/detection'
import {Button} from '#/view/com/util/forms/Button'
import {Text} from '#/view/com/util/text/Text'
import {ScrollView} from '#/view/com/util/Views'
import {ImageSource} from './@types'
import ImageDefaultHeader from './components/ImageDefaultHeader'
import ImageItem from './components/ImageItem/ImageItem'
@@ -26,9 +40,11 @@ type Props = {
visible: boolean
onRequestClose: () => void
backgroundColor?: string
renderFooter: (index: number) => React.ReactNode
onPressSave: (uri: string) => void
onPressShare: (uri: string) => void
}
const SCREEN_HEIGHT = Dimensions.get('window').height
const DEFAULT_BG_COLOR = '#000'
function ImageViewing({
@@ -38,7 +54,8 @@ function ImageViewing({
visible,
onRequestClose,
backgroundColor = DEFAULT_BG_COLOR,
renderFooter,
onPressSave,
onPressShare,
}: Props) {
const [isScaled, setIsScaled] = useState(false)
const [isDragging, setIsDragging] = useState(false)
@@ -122,13 +139,99 @@ function ImageViewing({
))}
</PagerView>
<Animated.View style={[styles.footer, animatedFooterStyle]}>
{renderFooter(imageIndex)}
<LightboxFooter
images={images}
index={imageIndex}
onPressSave={onPressSave}
onPressShare={onPressShare}
/>
</Animated.View>
</View>
</SafeAreaView>
)
}
function LightboxFooter({
images,
index,
onPressSave,
onPressShare,
}: {
images: ImageSource[]
index: number
onPressSave: (uri: string) => void
onPressShare: (uri: string) => void
}) {
const {alt: altText, uri} = images[index]
const [isAltExpanded, setAltExpanded] = React.useState(false)
const insets = useSafeAreaInsets()
const svMaxHeight = SCREEN_HEIGHT - insets.top - 50
const isMomentumScrolling = React.useRef(false)
return (
<ScrollView
style={[
{
backgroundColor: '#000d',
},
{maxHeight: svMaxHeight},
]}
scrollEnabled={isAltExpanded}
onMomentumScrollBegin={() => {
isMomentumScrolling.current = true
}}
onMomentumScrollEnd={() => {
isMomentumScrolling.current = false
}}
contentContainerStyle={{
paddingTop: 16,
paddingBottom: insets.bottom + 10,
paddingHorizontal: 24,
}}>
{altText ? (
<View accessibilityRole="button" style={styles.footerText}>
<Text
style={[s.gray3]}
numberOfLines={isAltExpanded ? undefined : 3}
selectable
onPress={() => {
if (isMomentumScrolling.current) {
return
}
LayoutAnimation.configureNext({
duration: 450,
update: {type: 'spring', springDamping: 1},
})
setAltExpanded(prev => !prev)
}}
onLongPress={() => {}}>
{altText}
</Text>
</View>
) : null}
<View style={styles.footerBtns}>
<Button
type="primary-outline"
style={styles.footerBtn}
onPress={() => onPressSave(uri)}>
<FontAwesomeIcon icon={['far', 'floppy-disk']} style={s.white} />
<Text type="xl" style={s.white}>
<Trans context="action">Save</Trans>
</Text>
</Button>
<Button
type="primary-outline"
style={styles.footerBtn}
onPress={() => onPressShare(uri)}>
<FontAwesomeIcon icon="arrow-up-from-bracket" style={s.white} />
<Text type="xl" style={s.white}>
<Trans context="action">Share</Trans>
</Text>
</Button>
</View>
</ScrollView>
)
}
const styles = StyleSheet.create({
screen: {
position: 'absolute',
@@ -157,6 +260,21 @@ const styles = StyleSheet.create({
zIndex: 1,
bottom: 0,
},
footerText: {
paddingBottom: isIOS ? 20 : 16,
},
footerBtns: {
flexDirection: 'row',
justifyContent: 'center',
gap: 8,
},
footerBtn: {
flexDirection: 'row',
alignItems: 'center',
gap: 8,
backgroundColor: 'transparent',
borderColor: colors.white,
},
})
const EnhancedImageViewing = (props: Props) => (
+3 -116
View File
@@ -1,24 +1,13 @@
import React from 'react'
import {Dimensions, LayoutAnimation, StyleSheet, View} from 'react-native'
import {useSafeAreaInsets} from 'react-native-safe-area-context'
import * as MediaLibrary from 'expo-media-library'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {msg, Trans} from '@lingui/macro'
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {saveImageToMediaLibrary, shareImageModal} from '#/lib/media/manip'
import {colors, s} from '#/lib/styles'
import {isIOS} from '#/platform/detection'
import {useLightbox, useLightboxControls} from '#/state/lightbox'
import {ImageSource} from '#/view/com/lightbox/ImageViewing/@types'
import {ScrollView} from '#/view/com/util/Views'
import {Button} from '../util/forms/Button'
import {Text} from '../util/text/Text'
import * as Toast from '../util/Toast'
import ImageView from './ImageViewing'
const SCREEN_HEIGHT = Dimensions.get('window').height
export function Lightbox() {
const {activeLightbox} = useLightbox()
const {closeLightbox} = useLightboxControls()
@@ -71,110 +60,8 @@ export function Lightbox() {
thumbDims={activeLightbox.thumbDims}
visible
onRequestClose={onClose}
renderFooter={index => (
<LightboxFooter
images={activeLightbox.images}
index={index}
onPressSave={saveImageToAlbumWithToasts}
/>
)}
onPressSave={saveImageToAlbumWithToasts}
onPressShare={uri => shareImageModal({uri})}
/>
)
}
function LightboxFooter({
images,
index,
onPressSave,
}: {
images: ImageSource[]
index: number
onPressSave: (uri: string) => void
}) {
const {alt: altText, uri} = images[index]
const [isAltExpanded, setAltExpanded] = React.useState(false)
const insets = useSafeAreaInsets()
const svMaxHeight = SCREEN_HEIGHT - insets.top - 50
const isMomentumScrolling = React.useRef(false)
return (
<ScrollView
style={[
{
backgroundColor: '#000d',
},
{maxHeight: svMaxHeight},
]}
scrollEnabled={isAltExpanded}
onMomentumScrollBegin={() => {
isMomentumScrolling.current = true
}}
onMomentumScrollEnd={() => {
isMomentumScrolling.current = false
}}
contentContainerStyle={{
paddingTop: 16,
paddingBottom: insets.bottom + 10,
paddingHorizontal: 24,
}}>
{altText ? (
<View accessibilityRole="button" style={styles.footerText}>
<Text
style={[s.gray3]}
numberOfLines={isAltExpanded ? undefined : 3}
selectable
onPress={() => {
if (isMomentumScrolling.current) {
return
}
LayoutAnimation.configureNext({
duration: 450,
update: {type: 'spring', springDamping: 1},
})
setAltExpanded(prev => !prev)
}}
onLongPress={() => {}}>
{altText}
</Text>
</View>
) : null}
<View style={styles.footerBtns}>
<Button
type="primary-outline"
style={styles.footerBtn}
onPress={() => onPressSave(uri)}>
<FontAwesomeIcon icon={['far', 'floppy-disk']} style={s.white} />
<Text type="xl" style={s.white}>
<Trans context="action">Save</Trans>
</Text>
</Button>
<Button
type="primary-outline"
style={styles.footerBtn}
onPress={() => shareImageModal({uri})}>
<FontAwesomeIcon icon="arrow-up-from-bracket" style={s.white} />
<Text type="xl" style={s.white}>
<Trans context="action">Share</Trans>
</Text>
</Button>
</View>
</ScrollView>
)
}
const styles = StyleSheet.create({
footerText: {
paddingBottom: isIOS ? 20 : 16,
},
footerBtns: {
flexDirection: 'row',
justifyContent: 'center',
gap: 8,
},
footerBtn: {
flexDirection: 'row',
alignItems: 'center',
gap: 8,
backgroundColor: 'transparent',
borderColor: colors.white,
},
})