diff --git a/package.json b/package.json index c515ecdcee..a879182d9f 100644 --- a/package.json +++ b/package.json @@ -93,7 +93,7 @@ "prettier": "prettier --check ." }, "dependencies": { - "@atproto/api": "0.20.8", + "@atproto/api": "0.20.9", "@atproto/syntax": "0.6.1", "@bitdrift/react-native": "^0.6.8", "@braintree/sanitize-url": "^6.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d0136363f7..0ac8974cf9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -242,8 +242,8 @@ importers: .: dependencies: '@atproto/api': - specifier: 0.20.8 - version: 0.20.8 + specifier: 0.20.9 + version: 0.20.9 '@atproto/syntax': specifier: 0.6.1 version: 0.6.1 @@ -877,8 +877,8 @@ packages: graphql: optional: true - '@atproto/api@0.20.8': - resolution: {integrity: sha512-rTkA6kOmA2axSrg6VgpdXpsCFWpofnHBOn6pKg69Ju5MpIHqk4haQMgjBcVh1G3kUxzwgSAr7SYrPS3dFe5Etg==} + '@atproto/api@0.20.9': + resolution: {integrity: sha512-Yuw7Ewn+yMJZ8GskbuvI3lKPW65rsXic1xjFA2Dpq6H8WjVYs6xNZ31bkwtTYDDwjKIZcJmAVbAVgdfjo4T9iw==} engines: {node: '>=22'} '@atproto/common-web@0.5.0': @@ -9493,7 +9493,7 @@ snapshots: '@0no-co/graphql.web@1.2.0': {} - '@atproto/api@0.20.8': + '@atproto/api@0.20.9': dependencies: '@atproto/common-web': 0.5.0 '@atproto/lexicon': 0.7.1 diff --git a/src/components/Post/Embed/GalleryFallbackEmbed.tsx b/src/components/Post/Embed/GalleryFallbackEmbed.tsx new file mode 100644 index 0000000000..60592ccc6c --- /dev/null +++ b/src/components/Post/Embed/GalleryFallbackEmbed.tsx @@ -0,0 +1,85 @@ +import {Linking, View} from 'react-native' +import {plural} from '@lingui/core/macro' +import {Trans, useLingui} from '@lingui/react/macro' + +import {BSKY_DOWNLOAD_URL} from '#/lib/constants' +import {atoms as a, useTheme} from '#/alf' +import {Button, ButtonText} from '#/components/Button' +import {Sparkle_Stroke2_Corner0_Rounded as Sparkle} from '#/components/icons/Sparkle' +import {Text} from '#/components/Typography' +import {IS_NATIVE} from '#/env' + +/** + * OTA-able fallback that ships to native builds which don't yet know how to + * render the new gallery embed (>4 images, Photos v2). Final copy and visual + * treatment pending design from Darrin/Danielle/Alex. + * + * Native-only per APP-2308 - web builds receive the new gallery support in + * the same release that adds it. + */ +export function GalleryFallbackEmbed({count}: {count?: number}) { + const t = useTheme() + const {t: l} = useLingui() + + if (!IS_NATIVE) return null + + const bodyStyle = [ + a.text_sm, + a.text_center, + a.leading_snug, + t.atoms.text_contrast_high, + ] + + return ( + + + + Something new is here + + {count ? ( + + + {plural(count, { + one: 'This post has # photo.', + other: 'This post has # photos.', + })} + + + {plural(count, { + one: 'Update your app to see it.', + other: 'Update your app to see them all.', + })} + + + ) : ( + + Update your app to see it. + + )} + + + ) +} diff --git a/src/components/Post/Embed/index.tsx b/src/components/Post/Embed/index.tsx index ab6f5dc439..211a7a7687 100644 --- a/src/components/Post/Embed/index.tsx +++ b/src/components/Post/Embed/index.tsx @@ -37,6 +37,7 @@ import { import {ChatInviteEmbed} from './ChatInviteEmbed' import {ExternalEmbed} from './ExternalEmbed' import {ModeratedFeedEmbed} from './FeedEmbed' +import {GalleryFallbackEmbed} from './GalleryFallbackEmbed' import {ImageEmbed} from './ImageEmbed' import {ModeratedListEmbed} from './ListEmbed' import {PostPlaceholder as PostPlaceholderText} from './PostPlaceholder' @@ -55,7 +56,8 @@ export function Embed({embed: rawEmbed, ...rest}: EmbedProps) { switch (embed.type) { case 'images': case 'link': - case 'video': { + case 'video': + case 'gallery': { return } case 'feed': @@ -148,6 +150,15 @@ function MediaEmbed({ ) } + case 'gallery': { + return ( + + + + ) + } default: { return null } diff --git a/src/types/bsky/post.ts b/src/types/bsky/post.ts index fada39da81..dd54c1ebdb 100644 --- a/src/types/bsky/post.ts +++ b/src/types/bsky/post.ts @@ -1,6 +1,7 @@ import { type $Typed, AppBskyEmbedExternal, + AppBskyEmbedGallery, AppBskyEmbedImages, AppBskyEmbedRecord, AppBskyEmbedRecordWithMedia, @@ -55,6 +56,10 @@ export type Embed = type: 'video' view: $Typed } + | { + type: 'gallery' + view: $Typed + } | { type: 'post_with_media' view: Embed @@ -140,6 +145,11 @@ export function parseEmbed(embed: AppBskyFeedDefs.PostView['embed']): Embed { view: parseEmbedRecordView(embed.record), media: parseEmbed(embed.media), } + } else if (AppBskyEmbedGallery.isView(embed)) { + return { + type: 'gallery', + view: embed, + } } else { return { type: 'unknown', diff --git a/src/view/screens/Storybook/GalleryFallback.tsx b/src/view/screens/Storybook/GalleryFallback.tsx new file mode 100644 index 0000000000..7cca087dba --- /dev/null +++ b/src/view/screens/Storybook/GalleryFallback.tsx @@ -0,0 +1,25 @@ +import {View} from 'react-native' + +import {atoms as a} from '#/alf' +import {GalleryFallbackEmbed} from '#/components/Post/Embed/GalleryFallbackEmbed' +import {H1, H3} from '#/components/Typography' + +export function GalleryFallback() { + return ( + +

Gallery fallback (APP-2308)

+ +

No count

+ + +

1 photo

+ + +

5 photos

+ + +

10 photos

+ +
+ ) +} diff --git a/src/view/screens/Storybook/Storybook.tsx b/src/view/screens/Storybook/Storybook.tsx index 8fb85e8e0a..33c31a9ee6 100644 --- a/src/view/screens/Storybook/Storybook.tsx +++ b/src/view/screens/Storybook/Storybook.tsx @@ -16,6 +16,7 @@ import {Breakpoints} from './Breakpoints' import {Buttons} from './Buttons' import {Dialogs} from './Dialogs' import {Forms} from './Forms' +import {GalleryFallback} from './GalleryFallback' import {Icons} from './Icons' import {Links} from './Links' import {Menus} from './Menus' @@ -120,6 +121,7 @@ export default function Storybook() { +