about summary refs log tree commit diff
path: root/src/view/com/lightbox/Lightbox.tsx
blob: d1fd701cf62345b488b61224a688de42e85e1a90 (plain) (blame)
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,
  },
})