Avoid asking for read access to photo library when saving images on iOS (#9297)

* use saveToLibraryAsync on iOS

* use _(msg``) syntax
This commit is contained in:
Samuel Newman
2025-11-04 16:33:30 +02:00
committed by GitHub
parent 1b0fbd503e
commit c9033dbc39
3 changed files with 51 additions and 10 deletions
+1 -1
View File
@@ -157,7 +157,7 @@ export async function saveImageToMediaLibrary({uri}: {uri: string}) {
)
}
} else {
await MediaLibrary.createAssetAsync(imagePath)
await MediaLibrary.saveToLibraryAsync(imagePath)
}
} catch (err) {
logger.error(err instanceof Error ? err : String(err), {
+32
View File
@@ -0,0 +1,32 @@
import {useCallback} from 'react'
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {isNative} from '#/platform/detection'
import * as Toast from '#/components/Toast'
import {saveImageToMediaLibrary} from './manip'
/**
* Same as `saveImageToMediaLibrary`, but also handles permissions and toasts
*
* iOS doesn't not require permissions to save images to the media library,
* so this file is platform-split as it's much simpler than the Android version.
*/
export function useSaveImageToMediaLibrary() {
const {_} = useLingui()
return useCallback(
async (uri: string) => {
if (!isNative) {
throw new Error('useSaveImageToMediaLibrary is native only')
}
try {
await saveImageToMediaLibrary({uri})
Toast.show(_(msg`Image saved`))
} catch (e: any) {
Toast.show(_(msg`Failed to save image: ${String(e)}`), {type: 'error'})
}
},
[_],
)
}
+18 -9
View File
@@ -1,15 +1,17 @@
import {useCallback} from 'react'
import * as MediaLibrary from 'expo-media-library'
import {t} from '@lingui/macro'
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {isNative} from '#/platform/detection'
import * as Toast from '#/view/com/util/Toast'
import * as Toast from '#/components/Toast'
import {saveImageToMediaLibrary} from './manip'
/**
* Same as `saveImageToMediaLibrary`, but also handles permissions and toasts
*/
export function useSaveImageToMediaLibrary() {
const {_} = useLingui()
const [permissionResponse, requestPermission, getPermission] =
MediaLibrary.usePermissions({
granularPermissions: ['photo'],
@@ -23,9 +25,12 @@ export function useSaveImageToMediaLibrary() {
async function save() {
try {
await saveImageToMediaLibrary({uri})
Toast.show(t`Image saved`)
Toast.show(_(msg`Image saved`))
} catch (e: any) {
Toast.show(t`Failed to save image: ${String(e)}`, 'xmark')
Toast.show(_(msg`Failed to save image: ${String(e)}`), {
type: 'error',
})
}
}
@@ -42,18 +47,22 @@ export function useSaveImageToMediaLibrary() {
} else {
// since we've been explicitly denied, show a toast.
Toast.show(
t`Images cannot be saved unless permission is granted to access your photo library.`,
'xmark',
_(
msg`Images cannot be saved unless permission is granted to access your photo library.`,
),
{type: 'error'},
)
}
} else {
Toast.show(
t`Permission to access your photo library was denied. Please enable it in your system settings.`,
'xmark',
_(
msg`Permission to access your photo library was denied. Please enable it in your system settings.`,
),
{type: 'error'},
)
}
}
},
[permissionResponse, requestPermission, getPermission],
[permissionResponse, requestPermission, getPermission, _],
)
}