[APP-716] Add 'save image' button to the lightbox (#926)
* Add 'save image' button to the lightbox * Fix types * Fix typeszio/stable
parent
5fcca17129
commit
c72e24f841
|
@ -5,6 +5,7 @@ import {Image} from 'react-native-image-crop-picker'
|
|||
import * as RNFS from 'react-native-fs'
|
||||
import uuid from 'react-native-uuid'
|
||||
import * as Sharing from 'expo-sharing'
|
||||
import * as MediaLibrary from 'expo-media-library'
|
||||
import {Dimensions} from './types'
|
||||
import {isAndroid, isIOS} from 'platform/detection'
|
||||
|
||||
|
@ -75,7 +76,7 @@ export async function downloadAndResize(opts: DownloadAndResizeOpts) {
|
|||
}
|
||||
}
|
||||
|
||||
export async function saveImageModal({uri}: {uri: string}) {
|
||||
export async function shareImageModal({uri}: {uri: string}) {
|
||||
if (!(await Sharing.isAvailableAsync())) {
|
||||
// TODO might need to give an error to the user in this case -prf
|
||||
return
|
||||
|
@ -107,6 +108,34 @@ export async function saveImageModal({uri}: {uri: string}) {
|
|||
RNFS.unlink(imagePath)
|
||||
}
|
||||
|
||||
export async function saveImageToAlbum({
|
||||
uri,
|
||||
album,
|
||||
}: {
|
||||
uri: string
|
||||
album: string
|
||||
}) {
|
||||
// download the file to cache
|
||||
// NOTE
|
||||
// assuming PNG
|
||||
// we're currently relying on the fact our CDN only serves pngs
|
||||
// -prf
|
||||
const downloadResponse = await RNFetchBlob.config({
|
||||
fileCache: true,
|
||||
}).fetch('GET', uri)
|
||||
let imagePath = downloadResponse.path()
|
||||
imagePath = normalizePath(await moveToPermanentPath(imagePath, '.png'), true)
|
||||
|
||||
// save to the album (creating as needed)
|
||||
const assetRef = await MediaLibrary.createAssetAsync(imagePath)
|
||||
const albumRef = await MediaLibrary.getAlbumAsync(album)
|
||||
if (albumRef) {
|
||||
await MediaLibrary.addAssetsToAlbumAsync(assetRef, albumRef)
|
||||
} else {
|
||||
await MediaLibrary.createAlbumAsync(album, assetRef)
|
||||
}
|
||||
}
|
||||
|
||||
export function getImageDim(path: string): Promise<Dimensions> {
|
||||
return new Promise((resolve, reject) => {
|
||||
RNImage.getSize(
|
||||
|
|
|
@ -37,7 +37,12 @@ export async function downloadAndResize(opts: DownloadAndResizeOpts) {
|
|||
return await doResize(dataUri, opts)
|
||||
}
|
||||
|
||||
export async function saveImageModal(_opts: {uri: string}) {
|
||||
export async function shareImageModal(_opts: {uri: string}) {
|
||||
// TODO
|
||||
throw new Error('TODO')
|
||||
}
|
||||
|
||||
export async function saveImageToAlbum(_opts: {uri: string; album: string}) {
|
||||
// TODO
|
||||
throw new Error('TODO')
|
||||
}
|
||||
|
|
|
@ -5,7 +5,8 @@ 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 {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'
|
||||
|
@ -54,7 +55,16 @@ export const Lightbox = observer(function Lightbox() {
|
|||
<Button
|
||||
type="primary-outline"
|
||||
style={styles.footerBtn}
|
||||
onPress={() => saveImageModal({uri})}>
|
||||
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
|
||||
|
@ -96,6 +106,15 @@ export const Lightbox = observer(function Lightbox() {
|
|||
}
|
||||
})
|
||||
|
||||
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,
|
||||
|
@ -109,6 +128,7 @@ const styles = StyleSheet.create({
|
|||
footerBtns: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
gap: 8,
|
||||
},
|
||||
footerBtn: {
|
||||
flexDirection: 'row',
|
||||
|
|
|
@ -37,6 +37,7 @@ import {faEnvelope} from '@fortawesome/free-solid-svg-icons/faEnvelope'
|
|||
import {faExclamation} from '@fortawesome/free-solid-svg-icons/faExclamation'
|
||||
import {faEye} from '@fortawesome/free-solid-svg-icons/faEye'
|
||||
import {faEyeSlash as farEyeSlash} from '@fortawesome/free-regular-svg-icons/faEyeSlash'
|
||||
import {faFloppyDisk} from '@fortawesome/free-regular-svg-icons/faFloppyDisk'
|
||||
import {faGear} from '@fortawesome/free-solid-svg-icons/faGear'
|
||||
import {faGlobe} from '@fortawesome/free-solid-svg-icons/faGlobe'
|
||||
import {faHand} from '@fortawesome/free-solid-svg-icons/faHand'
|
||||
|
@ -124,6 +125,7 @@ export function setup() {
|
|||
faEye,
|
||||
faExclamation,
|
||||
farEyeSlash,
|
||||
faFloppyDisk,
|
||||
faGear,
|
||||
faGlobe,
|
||||
faHand,
|
||||
|
|
Loading…
Reference in New Issue