Add permission checks before saving image (#945)
* catch permission errors when saving image to album * Save photos to media library alone (not an album) --------- Co-authored-by: Paul Frazee <pfrazee@gmail.com>zio/stable
parent
7cf0db7d14
commit
edff1992b1
|
@ -108,13 +108,7 @@ export async function shareImageModal({uri}: {uri: string}) {
|
||||||
RNFS.unlink(imagePath)
|
RNFS.unlink(imagePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function saveImageToAlbum({
|
export async function saveImageToMediaLibrary({uri}: {uri: string}) {
|
||||||
uri,
|
|
||||||
album,
|
|
||||||
}: {
|
|
||||||
uri: string
|
|
||||||
album: string
|
|
||||||
}) {
|
|
||||||
// download the file to cache
|
// download the file to cache
|
||||||
// NOTE
|
// NOTE
|
||||||
// assuming PNG
|
// assuming PNG
|
||||||
|
@ -126,14 +120,8 @@ export async function saveImageToAlbum({
|
||||||
let imagePath = downloadResponse.path()
|
let imagePath = downloadResponse.path()
|
||||||
imagePath = normalizePath(await moveToPermanentPath(imagePath, '.png'), true)
|
imagePath = normalizePath(await moveToPermanentPath(imagePath, '.png'), true)
|
||||||
|
|
||||||
// save to the album (creating as needed)
|
// save
|
||||||
const assetRef = await MediaLibrary.createAssetAsync(imagePath)
|
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> {
|
export function getImageDim(path: string): Promise<Dimensions> {
|
||||||
|
|
|
@ -5,21 +5,47 @@ import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||||
import ImageView from './ImageViewing'
|
import ImageView from './ImageViewing'
|
||||||
import {useStores} from 'state/index'
|
import {useStores} from 'state/index'
|
||||||
import * as models from 'state/models/ui/shell'
|
import * as models from 'state/models/ui/shell'
|
||||||
import {shareImageModal, saveImageToAlbum} from 'lib/media/manip'
|
import {shareImageModal, saveImageToMediaLibrary} from 'lib/media/manip'
|
||||||
import * as Toast from '../util/Toast'
|
import * as Toast from '../util/Toast'
|
||||||
import {Text} from '../util/text/Text'
|
import {Text} from '../util/text/Text'
|
||||||
import {s, colors} from 'lib/styles'
|
import {s, colors} from 'lib/styles'
|
||||||
import {Button} from '../util/forms/Button'
|
import {Button} from '../util/forms/Button'
|
||||||
import {isIOS} from 'platform/detection'
|
import {isIOS} from 'platform/detection'
|
||||||
|
import * as MediaLibrary from 'expo-media-library'
|
||||||
|
|
||||||
export const Lightbox = observer(function Lightbox() {
|
export const Lightbox = observer(function Lightbox() {
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
const [isAltExpanded, setAltExpanded] = React.useState(false)
|
const [isAltExpanded, setAltExpanded] = React.useState(false)
|
||||||
|
const [permissionResponse, requestPermission] = MediaLibrary.usePermissions()
|
||||||
|
|
||||||
const onClose = React.useCallback(() => {
|
const onClose = React.useCallback(() => {
|
||||||
store.shell.closeLightbox()
|
store.shell.closeLightbox()
|
||||||
}, [store])
|
}, [store])
|
||||||
|
|
||||||
|
const saveImageToAlbumWithToasts = React.useCallback(
|
||||||
|
async (uri: string) => {
|
||||||
|
if (!permissionResponse || permissionResponse.granted === false) {
|
||||||
|
Toast.show('Permission to access camera roll is required.')
|
||||||
|
if (permissionResponse?.canAskAgain) {
|
||||||
|
requestPermission()
|
||||||
|
} else {
|
||||||
|
Toast.show(
|
||||||
|
'Permission to access camera roll was denied. Please enable it in your system settings.',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await saveImageToMediaLibrary({uri})
|
||||||
|
Toast.show('Saved to your camera roll.')
|
||||||
|
} catch (e: any) {
|
||||||
|
Toast.show(`Failed to save image: ${String(e)}`)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[permissionResponse, requestPermission],
|
||||||
|
)
|
||||||
|
|
||||||
const LightboxFooter = React.useCallback(
|
const LightboxFooter = React.useCallback(
|
||||||
({imageIndex}: {imageIndex: number}) => {
|
({imageIndex}: {imageIndex: number}) => {
|
||||||
const lightbox = store.shell.activeLightbox
|
const lightbox = store.shell.activeLightbox
|
||||||
|
@ -74,7 +100,7 @@ export const Lightbox = observer(function Lightbox() {
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
[store.shell.activeLightbox, isAltExpanded, setAltExpanded],
|
[store.shell.activeLightbox, isAltExpanded, saveImageToAlbumWithToasts],
|
||||||
)
|
)
|
||||||
|
|
||||||
if (!store.shell.activeLightbox) {
|
if (!store.shell.activeLightbox) {
|
||||||
|
@ -106,15 +132,6 @@ 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({
|
const styles = StyleSheet.create({
|
||||||
footer: {
|
footer: {
|
||||||
paddingTop: 16,
|
paddingTop: 16,
|
||||||
|
|
Loading…
Reference in New Issue