1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
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 {shareImageModal, saveImageToAlbum} from 'lib/media/manip'
import * as Toast from '../util/Toast'
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()
const [isAltExpanded, setAltExpanded] = React.useState(false)
const onClose = React.useCallback(() => {
store.shell.closeLightbox()
}, [store])
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 = lightbox as models.ImagesLightbox
uri = opts.images[imageIndex].uri
altText = opts.images[imageIndex].alt || ''
} else if (lightbox.name === 'profile-image') {
const opts = lightbox as models.ProfileImageLightbox
uri = opts.profileView.avatar || ''
}
return (
<View style={[styles.footer]}>
{altText ? (
<Pressable
onPress={() => setAltExpanded(!isAltExpanded)}
accessibilityRole="button">
<Text
style={[s.gray3, styles.footerText]}
numberOfLines={isAltExpanded ? undefined : 3}>
{altText}
</Text>
</Pressable>
) : null}
<View style={styles.footerBtns}>
<Button
type="primary-outline"
style={styles.footerBtn}
onPress={() => saveImageToAlbumWithToasts(uri)}>
<FontAwesomeIcon icon={['far', 'floppy-disk']} style={s.white} />
<Text type="xl" style={s.white}>
Save
</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}>
Share
</Text>
</Button>
</View>
</View>
)
},
[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 (
<ImageView
images={[{uri: opts.profileView.avatar}]}
imageIndex={0}
visible
onRequestClose={onClose}
FooterComponent={LightboxFooter}
/>
)
} else if (store.shell.activeLightbox.name === 'images') {
const opts = store.shell.activeLightbox as models.ImagesLightbox
return (
<ImageView
images={opts.images.map(({uri}) => ({uri}))}
imageIndex={opts.index}
visible
onRequestClose={onClose}
FooterComponent={LightboxFooter}
/>
)
} else {
return null
}
})
async function saveImageToAlbumWithToasts(uri: string) {
try {
await saveImageToAlbum({uri, album: 'Bluesky'})
Toast.show('Saved to the "Bluesky" album.')
} catch (e: any) {
Toast.show(`Failed to save image: ${String(e)}`)
}
}
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',
gap: 8,
},
footerBtn: {
flexDirection: 'row',
alignItems: 'center',
gap: 8,
backgroundColor: 'transparent',
borderColor: colors.white,
},
})
|