diff --git a/src/components/StarterPack/ShareDialog.tsx b/src/components/StarterPack/ShareDialog.tsx index ae7e6c418a..05efa197ac 100644 --- a/src/components/StarterPack/ShareDialog.tsx +++ b/src/components/StarterPack/ShareDialog.tsx @@ -73,7 +73,7 @@ function ShareDialogInner({ try { await saveImageToMediaLibrary({uri: imageUrl}) - Toast.show(_(msg`Image saved to your camera roll!`)) + Toast.show(_(msg`Image saved`)) control.close() } catch (e: unknown) { Toast.show(_(msg`An error occurred while saving the image!`), 'xmark') diff --git a/src/lib/media/manip.ts b/src/lib/media/manip.ts index 13f20ad61e..8d3d83efc3 100644 --- a/src/lib/media/manip.ts +++ b/src/lib/media/manip.ts @@ -95,6 +95,8 @@ export async function shareImageModal({uri}: {uri: string}) { }) } +const ALBUM_NAME = 'Bluesky' + export async function saveImageToMediaLibrary({uri}: {uri: string}) { // download the file to cache // NOTE @@ -103,8 +105,35 @@ export async function saveImageToMediaLibrary({uri}: {uri: string}) { // -prf const imageUri = await downloadImage(uri, createPath('png'), 5e3) const imagePath = await moveToPermanentPath(imageUri, '.png') - safeDeleteAsync(imageUri) - MediaLibrary.createAssetAsync(imagePath) + // save + try { + if (isAndroid) { + // android triggers an annoying permission prompt if you try and move an image + // between albums. therefore, we need to either create the album with the image + // as the starting image, or put it directly into the album + const album = await MediaLibrary.getAlbumAsync(ALBUM_NAME) + if (album) { + // if album exists, put the image straight in there + await MediaLibrary.createAssetAsync(imagePath, album) + } else { + // otherwise, create album with asset (albums must always have at least one asset) + await MediaLibrary.createAlbumAsync( + ALBUM_NAME, + undefined, + undefined, + imagePath, + ) + } + } else { + await MediaLibrary.createAssetAsync(imagePath) + } + } catch (err) { + logger.error(err instanceof Error ? err : String(err), { + message: 'Failed to save image to media library', + }) + } finally { + safeDeleteAsync(imagePath) + } } export function getImageDim(path: string): Promise { diff --git a/src/lib/media/manip.web.ts b/src/lib/media/manip.web.ts index f23b955d66..d0524e2d27 100644 --- a/src/lib/media/manip.web.ts +++ b/src/lib/media/manip.web.ts @@ -44,7 +44,7 @@ export async function shareImageModal(_opts: {uri: string}) { throw new Error('TODO') } -export async function saveImageToAlbum(_opts: {uri: string; album: string}) { +export async function saveImageToMediaLibrary(_opts: {uri: string}) { // TODO throw new Error('TODO') } diff --git a/src/logger/sentry/setup/index.ts b/src/logger/sentry/setup/index.ts index 34bbd36591..d6e1c320c1 100644 --- a/src/logger/sentry/setup/index.ts +++ b/src/logger/sentry/setup/index.ts @@ -5,14 +5,14 @@ import {init} from '@sentry/react-native' -import {version} from '#/../package.json' +import pkgJson from '#/../package.json' /** * Examples: * - `dev` * - `1.99.0` */ -const release = process.env.SENTRY_RELEASE || version +const release = process.env.SENTRY_RELEASE || pkgJson.version /** * The latest deployed commit hash diff --git a/src/view/com/composer/ComposerReplyTo.tsx b/src/view/com/composer/ComposerReplyTo.tsx index bafac18f5e..0ced143597 100644 --- a/src/view/com/composer/ComposerReplyTo.tsx +++ b/src/view/com/composer/ComposerReplyTo.tsx @@ -94,7 +94,7 @@ export function ComposerReplyTo({replyTo}: {replyTo: ComposerOptsPostRef}) { {sanitizeDisplayName( diff --git a/src/view/com/lightbox/Lightbox.tsx b/src/view/com/lightbox/Lightbox.tsx index 628bd2b9af..6772561917 100644 --- a/src/view/com/lightbox/Lightbox.tsx +++ b/src/view/com/lightbox/Lightbox.tsx @@ -41,7 +41,7 @@ export function Lightbox() { } try { await saveImageToMediaLibrary({uri}) - Toast.show(_(msg`Saved to your camera roll`)) + Toast.show(_(msg`Image saved`)) } catch (e: any) { Toast.show(_(msg`Failed to save image: ${String(e)}`), 'xmark') }