Add alt text support and rework image layout (#503)
* Add alt text support and rework image layout * Add additional BottomSheet implementation to account for nested Composer modal * Use mobile gallery layout on mobile web * Missing key * Fix lint * Move altimage modal into the standard modal system * Fix overflow wrapping of images * Fixes to the alt-image modal * Remove unnecessary switch * Restore old imagelayoutgrid code --------- Co-authored-by: Paul Frazee <pfrazee@gmail.com>
This commit is contained in:
parent
0f5735b616
commit
f0706dbe9f
19 changed files with 412 additions and 132 deletions
|
@ -1,4 +1,5 @@
|
|||
import React, {useCallback} 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'
|
||||
|
@ -6,6 +7,8 @@ import {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'
|
||||
|
||||
interface Props {
|
||||
gallery: GalleryModel
|
||||
|
@ -13,17 +16,28 @@ interface Props {
|
|||
|
||||
export const Gallery = observer(function ({gallery}: Props) {
|
||||
const getImageStyle = useCallback(() => {
|
||||
switch (gallery.size) {
|
||||
case 1:
|
||||
return styles.image250
|
||||
case 2:
|
||||
return styles.image175
|
||||
default:
|
||||
return styles.image85
|
||||
let side: number
|
||||
|
||||
if (gallery.size === 1) {
|
||||
side = 250
|
||||
} else {
|
||||
side = (isDesktopWeb ? 560 : 350) / gallery.size
|
||||
}
|
||||
|
||||
return {
|
||||
height: side,
|
||||
width: side,
|
||||
}
|
||||
}, [gallery])
|
||||
|
||||
const imageStyle = getImageStyle()
|
||||
const handleAddImageAltText = useCallback(
|
||||
(image: ImageModel) => {
|
||||
Keyboard.dismiss()
|
||||
gallery.setAltText(image)
|
||||
},
|
||||
[gallery],
|
||||
)
|
||||
const handleRemovePhoto = useCallback(
|
||||
(image: ImageModel) => {
|
||||
gallery.remove(image)
|
||||
|
@ -38,14 +52,68 @@ export const Gallery = observer(function ({gallery}: Props) {
|
|||
[gallery],
|
||||
)
|
||||
|
||||
const isOverflow = !isDesktopWeb && gallery.size > 2
|
||||
|
||||
const imageControlLabelStyle = {
|
||||
borderRadius: 5,
|
||||
paddingHorizontal: 10,
|
||||
position: 'absolute' as const,
|
||||
width: 46,
|
||||
zIndex: 1,
|
||||
...(isOverflow
|
||||
? {
|
||||
left: 4,
|
||||
bottom: 4,
|
||||
}
|
||||
: isDesktopWeb && gallery.size < 3
|
||||
? {
|
||||
left: 8,
|
||||
top: 8,
|
||||
}
|
||||
: {
|
||||
left: 4,
|
||||
top: 4,
|
||||
}),
|
||||
}
|
||||
|
||||
const imageControlsSubgroupStyle = {
|
||||
display: 'flex' as const,
|
||||
flexDirection: 'row' as const,
|
||||
position: 'absolute' as const,
|
||||
...(isOverflow
|
||||
? {
|
||||
top: 4,
|
||||
right: 4,
|
||||
gap: 4,
|
||||
}
|
||||
: isDesktopWeb && gallery.size < 3
|
||||
? {
|
||||
top: 8,
|
||||
right: 8,
|
||||
gap: 8,
|
||||
}
|
||||
: {
|
||||
top: 4,
|
||||
right: 4,
|
||||
gap: 4,
|
||||
}),
|
||||
zIndex: 1,
|
||||
}
|
||||
|
||||
return !gallery.isEmpty ? (
|
||||
<View testID="selectedPhotosView" style={styles.gallery}>
|
||||
{gallery.images.map(image =>
|
||||
image.compressed !== undefined ? (
|
||||
<View
|
||||
key={`selected-image-${image.path}`}
|
||||
style={[styles.imageContainer, imageStyle]}>
|
||||
<View style={styles.imageControls}>
|
||||
<View key={`selected-image-${image.path}`} style={[imageStyle]}>
|
||||
<TouchableOpacity
|
||||
testID="altTextButton"
|
||||
onPress={() => {
|
||||
handleAddImageAltText(image)
|
||||
}}
|
||||
style={[styles.imageControl, imageControlLabelStyle]}>
|
||||
<Text style={styles.imageControlTextContent}>ALT</Text>
|
||||
</TouchableOpacity>
|
||||
<View style={imageControlsSubgroupStyle}>
|
||||
<TouchableOpacity
|
||||
testID="cropPhotoButton"
|
||||
onPress={() => {
|
||||
|
@ -72,7 +140,7 @@ export const Gallery = observer(function ({gallery}: Props) {
|
|||
|
||||
<Image
|
||||
testID="selectedPhotoImage"
|
||||
style={[styles.image, imageStyle]}
|
||||
style={[styles.image, imageStyle] as ImageStyle}
|
||||
source={{
|
||||
uri: image.compressed.path,
|
||||
}}
|
||||
|
@ -88,36 +156,13 @@ const styles = StyleSheet.create({
|
|||
gallery: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
gap: 8,
|
||||
marginTop: 16,
|
||||
},
|
||||
imageContainer: {
|
||||
margin: 2,
|
||||
},
|
||||
image: {
|
||||
resizeMode: 'cover',
|
||||
borderRadius: 8,
|
||||
},
|
||||
image250: {
|
||||
width: 250,
|
||||
height: 250,
|
||||
},
|
||||
image175: {
|
||||
width: 175,
|
||||
height: 175,
|
||||
},
|
||||
image85: {
|
||||
width: 85,
|
||||
height: 85,
|
||||
},
|
||||
imageControls: {
|
||||
position: 'absolute',
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
gap: 4,
|
||||
top: 8,
|
||||
right: 8,
|
||||
zIndex: 1,
|
||||
},
|
||||
imageControl: {
|
||||
width: 24,
|
||||
height: 24,
|
||||
|
@ -127,4 +172,10 @@ const styles = StyleSheet.create({
|
|||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
imageControlTextContent: {
|
||||
color: 'white',
|
||||
fontSize: 12,
|
||||
fontWeight: 'bold',
|
||||
letterSpacing: 1,
|
||||
},
|
||||
})
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue