Add OTA fallback for gallery embed
Pre-update native builds don't recognize app.bsky.embed.gallery (Photos
v2, >4 images). Bump @atproto/api to 0.20.9 so the OTA bundle can parse
the embed, and render a friendly "Something new is here" prompt with the
photo count and a link to bsky.app/download in place of the unrenderable
gallery. Native-only; web ships with full gallery support in the same
release.
APP-2308
(cherry picked from commit f9023f48b1)
This commit is contained in:
committed by
Eric Bailey
parent
73b35eabe6
commit
00fcac0ee4
+1
-1
@@ -92,7 +92,7 @@
|
|||||||
"icons:optimize": "svgo -f ./assets/icons"
|
"icons:optimize": "svgo -f ./assets/icons"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@atproto/api": "0.20.8",
|
"@atproto/api": "0.20.9",
|
||||||
"@atproto/syntax": "0.6.1",
|
"@atproto/syntax": "0.6.1",
|
||||||
"@bitdrift/react-native": "^0.6.8",
|
"@bitdrift/react-native": "^0.6.8",
|
||||||
"@braintree/sanitize-url": "^6.0.2",
|
"@braintree/sanitize-url": "^6.0.2",
|
||||||
|
|||||||
Generated
+5
-5
@@ -242,8 +242,8 @@ importers:
|
|||||||
.:
|
.:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@atproto/api':
|
'@atproto/api':
|
||||||
specifier: 0.20.8
|
specifier: 0.20.9
|
||||||
version: 0.20.8
|
version: 0.20.9
|
||||||
'@atproto/syntax':
|
'@atproto/syntax':
|
||||||
specifier: 0.6.1
|
specifier: 0.6.1
|
||||||
version: 0.6.1
|
version: 0.6.1
|
||||||
@@ -877,8 +877,8 @@ packages:
|
|||||||
graphql:
|
graphql:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@atproto/api@0.20.8':
|
'@atproto/api@0.20.9':
|
||||||
resolution: {integrity: sha512-rTkA6kOmA2axSrg6VgpdXpsCFWpofnHBOn6pKg69Ju5MpIHqk4haQMgjBcVh1G3kUxzwgSAr7SYrPS3dFe5Etg==}
|
resolution: {integrity: sha512-Yuw7Ewn+yMJZ8GskbuvI3lKPW65rsXic1xjFA2Dpq6H8WjVYs6xNZ31bkwtTYDDwjKIZcJmAVbAVgdfjo4T9iw==}
|
||||||
engines: {node: '>=22'}
|
engines: {node: '>=22'}
|
||||||
|
|
||||||
'@atproto/common-web@0.5.0':
|
'@atproto/common-web@0.5.0':
|
||||||
@@ -9494,7 +9494,7 @@ snapshots:
|
|||||||
|
|
||||||
'@0no-co/graphql.web@1.2.0': {}
|
'@0no-co/graphql.web@1.2.0': {}
|
||||||
|
|
||||||
'@atproto/api@0.20.8':
|
'@atproto/api@0.20.9':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@atproto/common-web': 0.5.0
|
'@atproto/common-web': 0.5.0
|
||||||
'@atproto/lexicon': 0.7.1
|
'@atproto/lexicon': 0.7.1
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
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()
|
||||||
|
|
||||||
|
const bodyStyle = [
|
||||||
|
a.text_sm,
|
||||||
|
a.text_center,
|
||||||
|
a.leading_snug,
|
||||||
|
t.atoms.text_contrast_high,
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
a.mt_sm,
|
||||||
|
a.rounded_md,
|
||||||
|
a.border,
|
||||||
|
a.p_lg,
|
||||||
|
a.pb_2xl,
|
||||||
|
a.gap_sm,
|
||||||
|
a.align_center,
|
||||||
|
{
|
||||||
|
borderColor: t.palette.primary_200,
|
||||||
|
backgroundColor: t.palette.primary_25,
|
||||||
|
},
|
||||||
|
]}>
|
||||||
|
<Sparkle size="lg" fill={t.palette.primary_500} />
|
||||||
|
<Text style={[a.text_md, a.font_bold, a.text_center, t.atoms.text]}>
|
||||||
|
<Trans>Something new is here</Trans>
|
||||||
|
</Text>
|
||||||
|
{count ? (
|
||||||
|
<View>
|
||||||
|
<Text style={bodyStyle}>
|
||||||
|
{plural(count, {
|
||||||
|
one: 'This post has # photo.',
|
||||||
|
other: 'This post has # photos.',
|
||||||
|
})}
|
||||||
|
</Text>
|
||||||
|
{IS_NATIVE ? (
|
||||||
|
<Text style={bodyStyle}>
|
||||||
|
{plural(count, {
|
||||||
|
one: 'Update your app to see it.',
|
||||||
|
other: 'Update your app to see them all.',
|
||||||
|
})}
|
||||||
|
</Text>
|
||||||
|
) : (
|
||||||
|
<Text style={bodyStyle}>
|
||||||
|
{plural(count, {
|
||||||
|
one: 'Refresh the page to see it.',
|
||||||
|
other: 'Refresh the page to see them all.',
|
||||||
|
})}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
) : IS_NATIVE ? (
|
||||||
|
<Text style={bodyStyle}>
|
||||||
|
<Trans>Update your app to see it.</Trans>
|
||||||
|
</Text>
|
||||||
|
) : (
|
||||||
|
<Text style={bodyStyle}>
|
||||||
|
<Trans>Refresh the page to see it.</Trans>
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
{IS_NATIVE && (
|
||||||
|
<Button
|
||||||
|
label={l`Update your app`}
|
||||||
|
size="small"
|
||||||
|
color="primary"
|
||||||
|
onPress={() => {
|
||||||
|
void Linking.openURL(BSKY_DOWNLOAD_URL)
|
||||||
|
}}
|
||||||
|
style={[a.mt_xs]}>
|
||||||
|
<ButtonText>
|
||||||
|
<Trans>Update app</Trans>
|
||||||
|
</ButtonText>
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -35,6 +35,7 @@ import {
|
|||||||
} from '#/types/bsky/post'
|
} from '#/types/bsky/post'
|
||||||
import {ExternalEmbed} from './ExternalEmbed'
|
import {ExternalEmbed} from './ExternalEmbed'
|
||||||
import {ModeratedFeedEmbed} from './FeedEmbed'
|
import {ModeratedFeedEmbed} from './FeedEmbed'
|
||||||
|
import {GalleryFallbackEmbed} from './GalleryFallbackEmbed'
|
||||||
import {ImageEmbed} from './ImageEmbed'
|
import {ImageEmbed} from './ImageEmbed'
|
||||||
import {ModeratedListEmbed} from './ListEmbed'
|
import {ModeratedListEmbed} from './ListEmbed'
|
||||||
import {PostPlaceholder as PostPlaceholderText} from './PostPlaceholder'
|
import {PostPlaceholder as PostPlaceholderText} from './PostPlaceholder'
|
||||||
@@ -52,6 +53,7 @@ export function Embed({embed: rawEmbed, ...rest}: EmbedProps) {
|
|||||||
|
|
||||||
switch (embed.type) {
|
switch (embed.type) {
|
||||||
case 'images':
|
case 'images':
|
||||||
|
case 'gallery':
|
||||||
case 'link':
|
case 'link':
|
||||||
case 'video': {
|
case 'video': {
|
||||||
return <MediaEmbed embed={embed} {...rest} />
|
return <MediaEmbed embed={embed} {...rest} />
|
||||||
@@ -131,6 +133,15 @@ function MediaEmbed({
|
|||||||
</ContentHider>
|
</ContentHider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
case 'gallery': {
|
||||||
|
return (
|
||||||
|
<ContentHider
|
||||||
|
modui={rest.moderation?.ui('contentMedia')}
|
||||||
|
activeStyle={[a.mt_sm]}>
|
||||||
|
<GalleryFallbackEmbed count={embed.view.items.length} />
|
||||||
|
</ContentHider>
|
||||||
|
)
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
type $Typed,
|
type $Typed,
|
||||||
AppBskyEmbedExternal,
|
AppBskyEmbedExternal,
|
||||||
|
AppBskyEmbedGallery,
|
||||||
AppBskyEmbedImages,
|
AppBskyEmbedImages,
|
||||||
AppBskyEmbedRecord,
|
AppBskyEmbedRecord,
|
||||||
AppBskyEmbedRecordWithMedia,
|
AppBskyEmbedRecordWithMedia,
|
||||||
@@ -47,6 +48,10 @@ export type Embed =
|
|||||||
type: 'images'
|
type: 'images'
|
||||||
view: $Typed<AppBskyEmbedImages.View>
|
view: $Typed<AppBskyEmbedImages.View>
|
||||||
}
|
}
|
||||||
|
| {
|
||||||
|
type: 'gallery'
|
||||||
|
view: $Typed<AppBskyEmbedGallery.View>
|
||||||
|
}
|
||||||
| {
|
| {
|
||||||
type: 'link'
|
type: 'link'
|
||||||
view: $Typed<AppBskyEmbedExternal.View>
|
view: $Typed<AppBskyEmbedExternal.View>
|
||||||
@@ -122,6 +127,11 @@ export function parseEmbed(embed: AppBskyFeedDefs.PostView['embed']): Embed {
|
|||||||
type: 'images',
|
type: 'images',
|
||||||
view: embed,
|
view: embed,
|
||||||
}
|
}
|
||||||
|
} else if (AppBskyEmbedGallery.isView(embed)) {
|
||||||
|
return {
|
||||||
|
type: 'gallery',
|
||||||
|
view: embed,
|
||||||
|
}
|
||||||
} else if (AppBskyEmbedExternal.isView(embed)) {
|
} else if (AppBskyEmbedExternal.isView(embed)) {
|
||||||
return {
|
return {
|
||||||
type: 'link',
|
type: 'link',
|
||||||
|
|||||||
@@ -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 (
|
||||||
|
<View style={[a.gap_md]}>
|
||||||
|
<H1>Gallery fallback (APP-2308)</H1>
|
||||||
|
|
||||||
|
<H3>No count</H3>
|
||||||
|
<GalleryFallbackEmbed />
|
||||||
|
|
||||||
|
<H3>1 photo</H3>
|
||||||
|
<GalleryFallbackEmbed count={1} />
|
||||||
|
|
||||||
|
<H3>5 photos</H3>
|
||||||
|
<GalleryFallbackEmbed count={5} />
|
||||||
|
|
||||||
|
<H3>10 photos</H3>
|
||||||
|
<GalleryFallbackEmbed count={10} />
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -16,6 +16,7 @@ import {Breakpoints} from './Breakpoints'
|
|||||||
import {Buttons} from './Buttons'
|
import {Buttons} from './Buttons'
|
||||||
import {Dialogs} from './Dialogs'
|
import {Dialogs} from './Dialogs'
|
||||||
import {Forms} from './Forms'
|
import {Forms} from './Forms'
|
||||||
|
import {GalleryFallback} from './GalleryFallback'
|
||||||
import {Icons} from './Icons'
|
import {Icons} from './Icons'
|
||||||
import {Links} from './Links'
|
import {Links} from './Links'
|
||||||
import {Menus} from './Menus'
|
import {Menus} from './Menus'
|
||||||
@@ -120,6 +121,7 @@ export default function Storybook() {
|
|||||||
<Breakpoints />
|
<Breakpoints />
|
||||||
<Dialogs />
|
<Dialogs />
|
||||||
<Admonitions />
|
<Admonitions />
|
||||||
|
<GalleryFallback />
|
||||||
<Settings />
|
<Settings />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
Reference in New Issue
Block a user