From 1c2a7b0b5a085fa1c2911e31824a178b23232b53 Mon Sep 17 00:00:00 2001 From: Samuel Newman Date: Thu, 8 May 2025 21:58:32 +0300 Subject: [PATCH 1/3] Fix some more warnings for web (#8316) * export correct stub for web * use default import for package.json --- src/components/StarterPack/ShareDialog.tsx | 4 ++-- src/lib/media/manip.web.ts | 2 +- src/logger/sentry/setup/index.ts | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/StarterPack/ShareDialog.tsx b/src/components/StarterPack/ShareDialog.tsx index 354d7bc4ee..1d92c623c3 100644 --- a/src/components/StarterPack/ShareDialog.tsx +++ b/src/components/StarterPack/ShareDialog.tsx @@ -1,7 +1,7 @@ import {View} from 'react-native' import {Image} from 'expo-image' import {requestMediaLibraryPermissionsAsync} from 'expo-image-picker' -import {AppBskyGraphDefs} from '@atproto/api' +import {type AppBskyGraphDefs} from '@atproto/api' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' @@ -15,7 +15,7 @@ import {isNative, isWeb} from '#/platform/detection' import * as Toast from '#/view/com/util/Toast' import {atoms as a, useTheme} from '#/alf' import {Button, ButtonText} from '#/components/Button' -import {DialogControlProps} from '#/components/Dialog' +import {type DialogControlProps} from '#/components/Dialog' import * as Dialog from '#/components/Dialog' import {Loader} from '#/components/Loader' import {Text} from '#/components/Typography' 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 From 36697755c72805d141044513d1a08bd45f946a3b Mon Sep 17 00:00:00 2001 From: Samuel Newman Date: Thu, 8 May 2025 23:17:44 +0300 Subject: [PATCH 2/3] fix reply display name being clipped (#8315) --- src/view/com/composer/ComposerReplyTo.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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( From 207527f1d57b7dbde1201823a37751fb1ee6473e Mon Sep 17 00:00:00 2001 From: Samuel Newman Date: Thu, 8 May 2025 23:50:12 +0300 Subject: [PATCH 3/3] [Android] Save photos to "Bluesky" folder (#8018) --- src/components/StarterPack/ShareDialog.tsx | 2 +- src/lib/media/manip.ts | 32 ++++++++++++++++++++-- src/view/com/lightbox/Lightbox.tsx | 2 +- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/components/StarterPack/ShareDialog.tsx b/src/components/StarterPack/ShareDialog.tsx index 1d92c623c3..44d5eb8162 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 QR code!`), 'xmark') diff --git a/src/lib/media/manip.ts b/src/lib/media/manip.ts index 4578406e06..62cbc55ac5 100644 --- a/src/lib/media/manip.ts +++ b/src/lib/media/manip.ts @@ -126,6 +126,8 @@ export async function shareImageModal({uri}: {uri: string}) { safeDeleteAsync(imagePath) } +const ALBUM_NAME = 'Bluesky' + export async function saveImageToMediaLibrary({uri}: {uri: string}) { // download the file to cache // NOTE @@ -139,8 +141,34 @@ export async function saveImageToMediaLibrary({uri}: {uri: string}) { imagePath = normalizePath(await moveToPermanentPath(imagePath, '.png'), true) // save - await MediaLibrary.createAssetAsync(imagePath) - safeDeleteAsync(imagePath) + 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/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') }