diff --git a/src/state/models/ui/shell.ts b/src/state/models/ui/shell.ts
index dea220c55e..4a55c23ad2 100644
--- a/src/state/models/ui/shell.ts
+++ b/src/state/models/ui/shell.ts
@@ -48,11 +48,6 @@ export interface AltTextImageModal {
image: ImageModel
}
-export interface AltTextImageReadModal {
- name: 'alt-text-image-read'
- altText: string
-}
-
export interface DeleteAccountModal {
name: 'delete-account'
}
@@ -106,7 +101,6 @@ export type Modal =
// Posts
| AltTextImageModal
- | AltTextImageReadModal
| CropImageModal
| ServerInputModal
| RepostModal
@@ -127,9 +121,14 @@ export class ProfileImageLightbox implements LightboxModel {
}
}
+interface ImagesLightboxItem {
+ uri: string
+ alt?: string
+}
+
export class ImagesLightbox implements LightboxModel {
name = 'images'
- constructor(public uris: string[], public index: number) {
+ constructor(public images: ImagesLightboxItem[], public index: number) {
makeAutoObservable(this)
}
setIndex(index: number) {
@@ -173,7 +172,7 @@ export class ShellUiModel {
isModalActive = false
activeModals: Modal[] = []
isLightboxActive = false
- activeLightbox: ProfileImageLightbox | ImagesLightbox | undefined
+ activeLightbox: ProfileImageLightbox | ImagesLightbox | null = null
isComposerActive = false
composerOpts: ComposerOpts | undefined
@@ -262,7 +261,7 @@ export class ShellUiModel {
closeLightbox() {
this.isLightboxActive = false
- this.activeLightbox = undefined
+ this.activeLightbox = null
}
openComposer(opts: ComposerOpts) {
diff --git a/src/view/com/lightbox/Lightbox.tsx b/src/view/com/lightbox/Lightbox.tsx
index 06b48143b1..c4bc88cf12 100644
--- a/src/view/com/lightbox/Lightbox.tsx
+++ b/src/view/com/lightbox/Lightbox.tsx
@@ -1,31 +1,75 @@
import React from 'react'
+import {Pressable, StyleSheet, View} from 'react-native'
import {observer} from 'mobx-react-lite'
+import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import ImageView from './ImageViewing'
import {useStores} from 'state/index'
import * as models from 'state/models/ui/shell'
import {saveImageModal} from 'lib/media/manip'
-import {ImageSource} from './ImageViewing/@types'
+import {Text} from '../util/text/Text'
+import {s, colors} from 'lib/styles'
+import {Button} from '../util/forms/Button'
+import {isIOS} from 'platform/detection'
export const Lightbox = observer(function Lightbox() {
const store = useStores()
- if (!store.shell.isLightboxActive) {
- return null
- }
+ const [isAltExpanded, setAltExpanded] = React.useState(false)
- const onClose = () => {
+ const onClose = React.useCallback(() => {
store.shell.closeLightbox()
- }
- const onLongPress = (image: ImageSource) => {
- if (
- typeof image === 'object' &&
- 'uri' in image &&
- typeof image.uri === 'string'
- ) {
- saveImageModal({uri: image.uri})
- }
- }
+ }, [store])
- if (store.shell.activeLightbox?.name === 'profile-image') {
+ const LightboxFooter = React.useCallback(
+ ({imageIndex}: {imageIndex: number}) => {
+ const lightbox = store.shell.activeLightbox
+ if (!lightbox) {
+ return null
+ }
+
+ let altText = ''
+ let uri
+ if (lightbox.name === 'images') {
+ const opts = store.shell.activeLightbox as models.ImagesLightbox
+ uri = opts.images[imageIndex].uri
+ altText = opts.images[imageIndex].alt
+ } else if (store.shell.activeLightbox.name === 'profile-image') {
+ const opts = store.shell.activeLightbox as models.ProfileImageLightbox
+ uri = opts.profileView.avatar
+ }
+
+ return (
+
+ {altText ? (
+ setAltExpanded(!isAltExpanded)}
+ accessibilityRole="button">
+
+ {altText}
+
+
+ ) : null}
+
+
+
+
+ )
+ },
+ [store.shell.activeLightbox, isAltExpanded, setAltExpanded],
+ )
+
+ if (!store.shell.activeLightbox) {
+ return null
+ } else if (store.shell.activeLightbox.name === 'profile-image') {
const opts = store.shell.activeLightbox as models.ProfileImageLightbox
return (
)
- } else if (store.shell.activeLightbox?.name === 'images') {
+ } else if (store.shell.activeLightbox.name === 'images') {
const opts = store.shell.activeLightbox as models.ImagesLightbox
return (
({uri}))}
+ images={opts.images.map(({uri}) => ({uri}))}
imageIndex={opts.index}
visible
onRequestClose={onClose}
- onLongPress={onLongPress}
+ FooterComponent={LightboxFooter}
/>
)
} else {
return null
}
})
+
+const styles = StyleSheet.create({
+ footer: {
+ paddingTop: 16,
+ paddingBottom: isIOS ? 40 : 24,
+ paddingHorizontal: 24,
+ backgroundColor: '#000d',
+ },
+ footerText: {
+ paddingBottom: isIOS ? 20 : 16,
+ },
+ footerBtns: {
+ flexDirection: 'row',
+ justifyContent: 'center',
+ },
+ footerBtn: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ gap: 8,
+ backgroundColor: 'transparent',
+ borderColor: colors.white,
+ },
+})
diff --git a/src/view/com/lightbox/Lightbox.web.tsx b/src/view/com/lightbox/Lightbox.web.tsx
index 3388b54b20..eff9af2d22 100644
--- a/src/view/com/lightbox/Lightbox.web.tsx
+++ b/src/view/com/lightbox/Lightbox.web.tsx
@@ -10,11 +10,13 @@ import {observer} from 'mobx-react-lite'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {useStores} from 'state/index'
import * as models from 'state/models/ui/shell'
-import {colors} from 'lib/styles'
+import {colors, s} from 'lib/styles'
import ImageDefaultHeader from './ImageViewing/components/ImageDefaultHeader'
+import {Text} from '../util/text/Text'
interface Img {
uri: string
+ alt?: string
}
export const Lightbox = observer(function Lightbox() {
@@ -37,7 +39,7 @@ export const Lightbox = observer(function Lightbox() {
}
} else if (activeLightbox instanceof models.ImagesLightbox) {
const opts = activeLightbox
- imgs = opts.uris.map(uri => ({uri}))
+ imgs = opts.images
}
if (!imgs) {
@@ -131,6 +133,11 @@ function LightboxInner({
)}
+ {imgs[index].alt ? (
+
+ {imgs[index].alt}
+
+ ) : null}
@@ -183,4 +190,9 @@ const styles = StyleSheet.create({
right: 30,
top: '50%',
},
+ footer: {
+ paddingHorizontal: 32,
+ paddingVertical: 24,
+ backgroundColor: colors.black,
+ },
})
diff --git a/src/view/com/modals/AltImageRead.tsx b/src/view/com/modals/AltImageRead.tsx
deleted file mode 100644
index 985477287e..0000000000
--- a/src/view/com/modals/AltImageRead.tsx
+++ /dev/null
@@ -1,80 +0,0 @@
-import React, {useCallback} from 'react'
-import {StyleSheet, View} from 'react-native'
-import {usePalette} from 'lib/hooks/usePalette'
-import {gradients, s} from 'lib/styles'
-import {Text} from '../util/text/Text'
-import {TouchableOpacity} from 'react-native-gesture-handler'
-import LinearGradient from 'react-native-linear-gradient'
-import {useStores} from 'state/index'
-import {isDesktopWeb} from 'platform/detection'
-
-export const snapPoints = ['70%']
-
-interface Props {
- altText: string
-}
-
-export function Component({altText}: Props) {
- const pal = usePalette('default')
- const store = useStores()
-
- const onPress = useCallback(() => {
- store.shell.closeModal()
- }, [store])
-
- return (
-
- Image description
-
- {altText}
-
-
-
-
- Done
-
-
-
-
- )
-}
-
-const styles = StyleSheet.create({
- container: {
- gap: 18,
- paddingVertical: isDesktopWeb ? 0 : 18,
- paddingHorizontal: isDesktopWeb ? 0 : 12,
- height: '100%',
- width: '100%',
- },
- title: {
- textAlign: 'center',
- fontWeight: 'bold',
- fontSize: 24,
- },
- text: {
- borderRadius: 5,
- marginVertical: 18,
- paddingHorizontal: 18,
- paddingVertical: 16,
- },
- button: {
- flexDirection: 'row',
- alignItems: 'center',
- justifyContent: 'center',
- width: '100%',
- borderRadius: 32,
- padding: 10,
- },
-})
diff --git a/src/view/com/modals/Modal.tsx b/src/view/com/modals/Modal.tsx
index b5d71a116b..18b7ae4c4d 100644
--- a/src/view/com/modals/Modal.tsx
+++ b/src/view/com/modals/Modal.tsx
@@ -13,7 +13,6 @@ import * as ServerInputModal from './ServerInput'
import * as ReportPostModal from './ReportPost'
import * as RepostModal from './Repost'
import * as AltImageModal from './AltImage'
-import * as AltImageReadModal from './AltImageRead'
import * as ReportAccountModal from './ReportAccount'
import * as DeleteAccountModal from './DeleteAccount'
import * as ChangeHandleModal from './ChangeHandle'
@@ -76,9 +75,6 @@ export const ModalsContainer = observer(function ModalsContainer() {
} else if (activeModal?.name === 'alt-text-image') {
snapPoints = AltImageModal.snapPoints
element =
- } else if (activeModal?.name === 'alt-text-image-read') {
- snapPoints = AltImageReadModal.snapPoints
- element =
} else if (activeModal?.name === 'change-handle') {
snapPoints = ChangeHandleModal.snapPoints
element =
diff --git a/src/view/com/modals/Modal.web.tsx b/src/view/com/modals/Modal.web.tsx
index 50487e3eb4..9dcc8fa7e6 100644
--- a/src/view/com/modals/Modal.web.tsx
+++ b/src/view/com/modals/Modal.web.tsx
@@ -15,7 +15,6 @@ import * as DeleteAccountModal from './DeleteAccount'
import * as RepostModal from './Repost'
import * as CropImageModal from './crop-image/CropImage.web'
import * as AltTextImageModal from './AltImage'
-import * as AltTextImageReadModal from './AltImageRead'
import * as ChangeHandleModal from './ChangeHandle'
import * as WaitlistModal from './Waitlist'
import * as InviteCodesModal from './InviteCodes'
@@ -89,8 +88,6 @@ function Modal({modal}: {modal: ModalIface}) {
element =
} else if (modal.name === 'alt-text-image') {
element =
- } else if (modal.name === 'alt-text-image-read') {
- element =
} else {
return null
}
diff --git a/src/view/com/util/images/Gallery.tsx b/src/view/com/util/images/Gallery.tsx
index 5b6c3384d0..1a29b45306 100644
--- a/src/view/com/util/images/Gallery.tsx
+++ b/src/view/com/util/images/Gallery.tsx
@@ -1,8 +1,7 @@
import {AppBskyEmbedImages} from '@atproto/api'
-import React, {ComponentProps, FC, useCallback} from 'react'
-import {Pressable, StyleSheet, Text, TouchableOpacity, View} from 'react-native'
+import React, {ComponentProps, FC} from 'react'
+import {StyleSheet, Text, TouchableOpacity, View} from 'react-native'
import {Image} from 'expo-image'
-import {useStores} from 'state/index'
type EventFunction = (index: number) => void
@@ -26,22 +25,14 @@ export const GalleryItem: FC = ({
onLongPress,
}) => {
const image = images[index]
- const store = useStores()
-
- const onPressAltText = useCallback(() => {
- store.shell.openModal({
- name: 'alt-text-image-read',
- altText: image.alt,
- })
- }, [image.alt, store.shell])
return (
onPress?.(index)}
- onPressIn={() => onPressIn?.(index)}
- onLongPress={() => onLongPress?.(index)}
+ onPress={onPress ? () => onPress(index) : undefined}
+ onPressIn={onPressIn ? () => onPressIn(index) : undefined}
+ onLongPress={onLongPress ? () => onLongPress(index) : undefined}
accessibilityRole="button"
accessibilityLabel="View image"
accessibilityHint="">
@@ -54,15 +45,7 @@ export const GalleryItem: FC = ({
accessibilityIgnoresInvertColors
/>
- {image.alt === '' ? null : (
-
- ALT
-
- )}
+ {image.alt === '' ? null : ALT}
)
}
@@ -78,8 +61,8 @@ const styles = StyleSheet.create({
paddingHorizontal: 10,
paddingVertical: 3,
position: 'absolute',
- left: 10,
- top: -26,
+ left: 6,
+ bottom: 6,
width: 46,
},
})
diff --git a/src/view/com/util/post-embeds/index.tsx b/src/view/com/util/post-embeds/index.tsx
index 929c85adcb..2dda9069ee 100644
--- a/src/view/com/util/post-embeds/index.tsx
+++ b/src/view/com/util/post-embeds/index.tsx
@@ -1,11 +1,10 @@
-import React, {useCallback} from 'react'
+import React from 'react'
import {
StyleSheet,
StyleProp,
View,
ViewStyle,
Image as RNImage,
- Pressable,
Text,
} from 'react-native'
import {
@@ -20,7 +19,6 @@ import {ImageLayoutGrid} from '../images/ImageLayoutGrid'
import {ImagesLightbox} from 'state/models/ui/shell'
import {useStores} from 'state/index'
import {usePalette} from 'lib/hooks/usePalette'
-import {saveImageModal} from 'lib/media/manip'
import {YoutubeEmbed} from './YoutubeEmbed'
import {ExternalLinkEmbed} from './ExternalLinkEmbed'
import {getYoutubeVideoId} from 'lib/strings/url-helpers'
@@ -44,16 +42,6 @@ export function PostEmbeds({
const pal = usePalette('default')
const store = useStores()
- const onPressAltText = useCallback(
- (alt: string) => {
- store.shell.openModal({
- name: 'alt-text-image-read',
- altText: alt,
- })
- },
- [store.shell],
- )
-
if (
AppBskyEmbedRecordWithMedia.isView(embed) &&
AppBskyEmbedRecord.isViewRecord(embed.record.record) &&
@@ -103,20 +91,17 @@ export function PostEmbeds({
const {images} = embed
if (images.length > 0) {
- const uris = embed.images.map(img => img.fullsize)
+ const items = embed.images.map(img => ({uri: img.fullsize, alt: img.alt}))
const openLightbox = (index: number) => {
- store.shell.openLightbox(new ImagesLightbox(uris, index))
- }
- const onLongPress = (index: number) => {
- saveImageModal({uri: uris[index]})
+ store.shell.openLightbox(new ImagesLightbox(items, index))
}
const onPressIn = (index: number) => {
- const firstImageToShow = uris[index]
+ const firstImageToShow = items[index].uri
RNImage.prefetch(firstImageToShow)
- uris.forEach(uri => {
- if (firstImageToShow !== uri) {
+ items.forEach(item => {
+ if (firstImageToShow !== item.uri) {
// First image already prefeched above
- RNImage.prefetch(uri)
+ RNImage.prefetch(item.uri)
}
})
}
@@ -129,20 +114,9 @@ export function PostEmbeds({
alt={alt}
uri={thumb}
onPress={() => openLightbox(0)}
- onLongPress={() => onLongPress(0)}
onPressIn={() => onPressIn(0)}
style={styles.singleImage}>
- {alt === '' ? null : (
- {
- onPressAltText(alt)
- }}
- accessibilityRole="button"
- accessibilityLabel="View alt text"
- accessibilityHint="Opens modal with alt text">
- ALT
-
- )}
+ {alt === '' ? null : ALT}
)
@@ -153,7 +127,6 @@ export function PostEmbeds({
@@ -209,8 +182,8 @@ const styles = StyleSheet.create({
paddingHorizontal: 10,
paddingVertical: 3,
position: 'absolute',
- left: 10,
- top: -26,
+ left: 6,
+ bottom: 6,
width: 46,
},
})