diff options
author | dan <dan.abramov@gmail.com> | 2024-11-04 21:31:21 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-11-04 21:31:21 +0000 |
commit | 26c48373e29643ca7a3248315506131d53d05b8b (patch) | |
tree | 7931136c51cf779cad1a94cce28af78cc7cb0c6e /src/view/com/lightbox/ImageViewing/index.tsx | |
parent | 174988bc5ab00774d200a882312985f55d903d81 (diff) | |
download | voidsky-26c48373e29643ca7a3248315506131d53d05b8b.tar.zst |
Refactor lightbox prop drilling (#6073)
* Refactor lightbox footer to render prop * Unify lightbox types * Unindent * Refactor LightboxFooter props * Move LightboxFooter into the implementation file
Diffstat (limited to 'src/view/com/lightbox/ImageViewing/index.tsx')
-rw-r--r-- | src/view/com/lightbox/ImageViewing/index.tsx | 146 |
1 files changed, 126 insertions, 20 deletions
diff --git a/src/view/com/lightbox/ImageViewing/index.tsx b/src/view/com/lightbox/ImageViewing/index.tsx index 0d0ac4df1..40df4c819 100644 --- a/src/view/com/lightbox/ImageViewing/index.tsx +++ b/src/view/com/lightbox/ImageViewing/index.tsx @@ -8,13 +8,27 @@ // Original code copied and simplified from the link below as the codebase is currently not maintained: // https://github.com/jobtoday/react-native-image-viewing -import React, {ComponentType, useCallback, useMemo, useState} from 'react' -import {Platform, StyleSheet, View} from 'react-native' +import React, {useCallback, useMemo, useState} from 'react' +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,10 +40,11 @@ type Props = { visible: boolean onRequestClose: () => void backgroundColor?: string - HeaderComponent?: ComponentType<{imageIndex: number}> - FooterComponent?: ComponentType<{imageIndex: number}> + onPressSave: (uri: string) => void + onPressShare: (uri: string) => void } +const SCREEN_HEIGHT = Dimensions.get('window').height const DEFAULT_BG_COLOR = '#000' function ImageViewing({ @@ -39,8 +54,8 @@ function ImageViewing({ visible, onRequestClose, backgroundColor = DEFAULT_BG_COLOR, - HeaderComponent, - FooterComponent, + onPressSave, + onPressShare, }: Props) { const [isScaled, setIsScaled] = useState(false) const [isDragging, setIsDragging] = useState(false) @@ -96,13 +111,7 @@ function ImageViewing({ accessibilityViewIsModal> <View style={[styles.container, {backgroundColor}]}> <Animated.View style={[styles.header, animatedHeaderStyle]}> - {typeof HeaderComponent !== 'undefined' ? ( - React.createElement(HeaderComponent, { - imageIndex, - }) - ) : ( - <ImageDefaultHeader onRequestClose={onRequestClose} /> - )} + <ImageDefaultHeader onRequestClose={onRequestClose} /> </Animated.View> <PagerView scrollEnabled={!isScaled} @@ -129,18 +138,100 @@ function ImageViewing({ </View> ))} </PagerView> - {typeof FooterComponent !== 'undefined' && ( - <Animated.View style={[styles.footer, animatedFooterStyle]}> - {React.createElement(FooterComponent, { - imageIndex, - })} - </Animated.View> - )} + <Animated.View style={[styles.footer, animatedFooterStyle]}> + <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', @@ -169,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) => ( |