diff options
Diffstat (limited to 'src/view/com/composer/photos/Gallery.tsx')
-rw-r--r-- | src/view/com/composer/photos/Gallery.tsx | 244 |
1 files changed, 135 insertions, 109 deletions
diff --git a/src/view/com/composer/photos/Gallery.tsx b/src/view/com/composer/photos/Gallery.tsx index f46c05333..c226d25cc 100644 --- a/src/view/com/composer/photos/Gallery.tsx +++ b/src/view/com/composer/photos/Gallery.tsx @@ -1,16 +1,16 @@ -import React, {useCallback} from 'react' +import React from 'react' import {ImageStyle, Keyboard} from 'react-native' import {GalleryModel} from 'state/models/media/gallery' import {observer} from 'mobx-react-lite' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' -import {colors} from 'lib/styles' +import {s, colors} from 'lib/styles' import {StyleSheet, TouchableOpacity, View} from 'react-native' -import {ImageModel} from 'state/models/media/image' import {Image} from 'expo-image' import {Text} from 'view/com/util/text/Text' import {isDesktopWeb} from 'platform/detection' import {openAltTextModal} from 'lib/media/alt-text' import {useStores} from 'state/index' +import {usePalette} from 'lib/hooks/usePalette' interface Props { gallery: GalleryModel @@ -18,67 +18,39 @@ interface Props { export const Gallery = observer(function ({gallery}: Props) { const store = useStores() - const getImageStyle = useCallback(() => { - let side: number + const pal = usePalette('default') - if (gallery.size === 1) { - side = 250 - } else { - side = (isDesktopWeb ? 560 : 350) / gallery.size - } + let side: number - return { - height: side, - width: side, - } - }, [gallery]) - - const imageStyle = getImageStyle() - const handleAddImageAltText = useCallback( - (image: ImageModel) => { - Keyboard.dismiss() - openAltTextModal(store, image) - }, - [store], - ) - const handleRemovePhoto = useCallback( - (image: ImageModel) => { - gallery.remove(image) - }, - [gallery], - ) + if (gallery.size === 1) { + side = 250 + } else { + side = (isDesktopWeb ? 560 : 350) / gallery.size + } - const handleEditPhoto = useCallback( - (image: ImageModel) => { - gallery.edit(image) - }, - [gallery], - ) + const imageStyle = { + height: side, + width: side, + } const isOverflow = !isDesktopWeb && gallery.size > 2 - const imageControlLabelStyle = { - borderRadius: 5, - paddingHorizontal: 10, - position: 'absolute' as const, - zIndex: 1, - ...(isOverflow - ? { - left: 4, - bottom: 4, - } - : isDesktopWeb && gallery.size < 3 - ? { - left: 8, - top: 8, - } - : { - left: 4, - top: 4, - }), - } + const altTextControlStyle = isOverflow + ? { + left: 4, + bottom: 4, + } + : isDesktopWeb && gallery.size < 3 + ? { + left: 8, + top: 8, + } + : { + left: 4, + top: 4, + } - const imageControlsSubgroupStyle = { + const imageControlsStyle = { display: 'flex' as const, flexDirection: 'row' as const, position: 'absolute' as const, @@ -103,63 +75,90 @@ export const Gallery = observer(function ({gallery}: Props) { } return !gallery.isEmpty ? ( - <View testID="selectedPhotosView" style={styles.gallery}> - {gallery.images.map(image => ( - <View key={`selected-image-${image.path}`} style={[imageStyle]}> - <TouchableOpacity - testID="altTextButton" - accessibilityRole="button" - accessibilityLabel="Add alt text" - accessibilityHint="" - onPress={() => { - handleAddImageAltText(image) - }} - style={imageControlLabelStyle}> - <Text style={styles.imageControlTextContent}>ALT</Text> - </TouchableOpacity> - <View style={imageControlsSubgroupStyle}> + <> + <View testID="selectedPhotosView" style={styles.gallery}> + {gallery.images.map(image => ( + <View key={`selected-image-${image.path}`} style={[imageStyle]}> <TouchableOpacity - testID="editPhotoButton" + testID="altTextButton" accessibilityRole="button" - accessibilityLabel="Edit image" + accessibilityLabel="Add alt text" accessibilityHint="" onPress={() => { - handleEditPhoto(image) + Keyboard.dismiss() + openAltTextModal(store, image) }} - style={styles.imageControl}> - <FontAwesomeIcon - icon="pen" - size={12} - style={{color: colors.white}} - /> + style={[styles.altTextControl, altTextControlStyle]}> + <Text style={styles.altTextControlLabel}>ALT</Text> + {image.altText.length > 0 ? ( + <FontAwesomeIcon + icon="check" + size={10} + style={{color: colors.green3}} + /> + ) : undefined} </TouchableOpacity> + <View style={imageControlsStyle}> + <TouchableOpacity + testID="editPhotoButton" + accessibilityRole="button" + accessibilityLabel="Edit image" + accessibilityHint="" + onPress={() => gallery.edit(image)} + style={styles.imageControl}> + <FontAwesomeIcon + icon="pen" + size={12} + style={{color: colors.white}} + /> + </TouchableOpacity> + <TouchableOpacity + testID="removePhotoButton" + accessibilityRole="button" + accessibilityLabel="Remove image" + accessibilityHint="" + onPress={() => gallery.remove(image)} + style={styles.imageControl}> + <FontAwesomeIcon + icon="xmark" + size={16} + style={{color: colors.white}} + /> + </TouchableOpacity> + </View> <TouchableOpacity - testID="removePhotoButton" accessibilityRole="button" - accessibilityLabel="Remove image" + accessibilityLabel="Add alt text" accessibilityHint="" - onPress={() => handleRemovePhoto(image)} - style={styles.imageControl}> - <FontAwesomeIcon - icon="xmark" - size={16} - style={{color: colors.white}} - /> - </TouchableOpacity> - </View> + onPress={() => { + Keyboard.dismiss() + openAltTextModal(store, image) + }} + style={styles.altTextHiddenRegion} + /> - <Image - testID="selectedPhotoImage" - style={[styles.image, imageStyle] as ImageStyle} - source={{ - uri: image.cropped?.path ?? image.path, - }} - accessible={true} - accessibilityIgnoresInvertColors - /> + <Image + testID="selectedPhotoImage" + style={[styles.image, imageStyle] as ImageStyle} + source={{ + uri: image.cropped?.path ?? image.path, + }} + accessible={true} + accessibilityIgnoresInvertColors + /> + </View> + ))} + </View> + <View style={[styles.reminder]}> + <View style={[styles.infoIcon, pal.viewLight]}> + <FontAwesomeIcon icon="info" size={12} color={pal.colors.text} /> </View> - ))} - </View> + <Text type="sm" style={[pal.textLight, s.flex1]}> + Alt text describes images for blind and low-vision users, and helps + give context to everyone. + </Text> + </View> + </> ) : null }) @@ -179,19 +178,46 @@ const styles = StyleSheet.create({ height: 24, borderRadius: 12, backgroundColor: 'rgba(0, 0, 0, 0.75)', - borderWidth: 0.5, alignItems: 'center', justifyContent: 'center', }, - imageControlTextContent: { + altTextControl: { + position: 'absolute', + zIndex: 1, borderRadius: 6, + backgroundColor: 'rgba(0, 0, 0, 0.75)', + paddingHorizontal: 8, + paddingVertical: 3, + flexDirection: 'row', + alignItems: 'center', + }, + altTextControlLabel: { color: 'white', fontSize: 12, fontWeight: 'bold', letterSpacing: 1, - backgroundColor: 'rgba(0, 0, 0, 0.75)', - borderWidth: 0.5, - paddingHorizontal: 10, - paddingVertical: 3, + }, + altTextHiddenRegion: { + position: 'absolute', + left: 4, + right: 4, + bottom: 4, + top: 30, + zIndex: 1, + }, + + reminder: { + flexDirection: 'row', + alignItems: 'center', + gap: 8, + borderRadius: 8, + paddingVertical: 14, + }, + infoIcon: { + width: 22, + height: 22, + borderRadius: 12, + alignItems: 'center', + justifyContent: 'center', }, }) |