From c34c67e4dfdfe71040e088d3d7e6e39276f93f6b Mon Sep 17 00:00:00 2001 From: Samuel Newman Date: Tue, 22 Apr 2025 21:01:28 +0300 Subject: [PATCH 01/15] add demo storage --- src/screens/Settings/AboutSettings.tsx | 31 ++++++++++++++++++++++++-- src/storage/hooks/demo-mode.ts | 7 ++++++ src/storage/schema.ts | 1 + 3 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 src/storage/hooks/demo-mode.ts diff --git a/src/screens/Settings/AboutSettings.tsx b/src/screens/Settings/AboutSettings.tsx index 199d12e63d..0ce127ff3f 100644 --- a/src/screens/Settings/AboutSettings.tsx +++ b/src/screens/Settings/AboutSettings.tsx @@ -12,9 +12,10 @@ import {Statsig} from 'statsig-react-native-expo' import {appVersion, BUNDLE_DATE, bundleInfo} from '#/lib/app-info' import {STATUS_PAGE_URL} from '#/lib/constants' import {type CommonNavigatorParams} from '#/lib/routes/types' -import {isAndroid, isNative} from '#/platform/detection' +import {isAndroid, isIOS, isNative} from '#/platform/detection' import * as Toast from '#/view/com/util/Toast' import * as SettingsList from '#/screens/Settings/components/SettingsList' +import {Atom_Stroke2_Corner0_Rounded as AtomIcon} from '#/components/icons/Atom' import {BroomSparkle_Stroke2_Corner2_Rounded as BroomSparkleIcon} from '#/components/icons/BroomSparkle' import {CodeLines_Stroke2_Corner2_Rounded as CodeLinesIcon} from '#/components/icons/CodeLines' import {Globe_Stroke2_Corner0_Rounded as GlobeIcon} from '#/components/icons/Globe' @@ -22,6 +23,7 @@ import {Newspaper_Stroke2_Corner2_Rounded as NewspaperIcon} from '#/components/i import {Wrench_Stroke2_Corner2_Rounded as WrenchIcon} from '#/components/icons/Wrench' import * as Layout from '#/components/Layout' import {Loader} from '#/components/Loader' +import {useDemoMode} from '#/storage/hooks/demo-mode' import {useDevMode} from '#/storage/hooks/dev-mode' import {OTAInfo} from './components/OTAInfo' @@ -29,6 +31,7 @@ type Props = NativeStackScreenProps export function AboutSettingsScreen({}: Props) { const {_, i18n} = useLingui() const [devModeEnabled, setDevModeEnabled] = useDevMode() + const [demoModeEnabled, setDemoModeEnabled] = useDemoMode() const stableID = useMemo(() => Statsig.getStableID(), []) const {mutate: onClearImageCache, isPending: isClearingImageCache} = @@ -153,7 +156,31 @@ export function AboutSettingsScreen({}: Props) { {bundleInfo} - {devModeEnabled && } + {devModeEnabled && ( + <> + + {isIOS && ( + { + const newDemoModeEnabled = !demoModeEnabled + setDemoModeEnabled(newDemoModeEnabled) + Toast.show( + 'Demo mode ' + + (newDemoModeEnabled ? 'enabled' : 'disabled'), + ) + }} + label={ + demoModeEnabled ? 'Disable demo mode' : 'Enable demo mode' + } + disabled={isClearingImageCache}> + + + {demoModeEnabled ? 'Disable demo mode' : 'Enable demo mode'} + + + )} + + )} diff --git a/src/storage/hooks/demo-mode.ts b/src/storage/hooks/demo-mode.ts new file mode 100644 index 0000000000..b65dd147e2 --- /dev/null +++ b/src/storage/hooks/demo-mode.ts @@ -0,0 +1,7 @@ +import {device, useStorage} from '#/storage' + +export function useDemoMode() { + const [demoMode = false, setDemoMode] = useStorage(device, ['demoMode']) + + return [demoMode, setDemoMode] as const +} diff --git a/src/storage/schema.ts b/src/storage/schema.ts index 0e9b1985cb..7430532a96 100644 --- a/src/storage/schema.ts +++ b/src/storage/schema.ts @@ -10,6 +10,7 @@ export type Device = { } trendingBetaEnabled: boolean devMode: boolean + demoMode: boolean } export type Account = { From 91f9bc7ccbfcfb07434a707e43fb3244e7722d6f Mon Sep 17 00:00:00 2001 From: Samuel Newman Date: Tue, 22 Apr 2025 21:29:27 +0300 Subject: [PATCH 02/15] demo mode --- src/lib/api/feed/demo.ts | 20 + src/lib/demo.ts | 516 ++++++++++++++++++++++++ src/state/queries/post-feed.ts | 22 +- src/view/screens/Home.tsx | 65 ++- src/view/shell/bottom-bar/BottomBar.tsx | 14 +- 5 files changed, 616 insertions(+), 21 deletions(-) create mode 100644 src/lib/api/feed/demo.ts create mode 100644 src/lib/demo.ts diff --git a/src/lib/api/feed/demo.ts b/src/lib/api/feed/demo.ts new file mode 100644 index 0000000000..049e0f116e --- /dev/null +++ b/src/lib/api/feed/demo.ts @@ -0,0 +1,20 @@ +import {type AppBskyFeedDefs, type BskyAgent} from '@atproto/api' + +import {DEMO_FEED} from '#/lib/demo' +import {type FeedAPI, type FeedAPIResponse} from './types' + +export class DemoFeedAPI implements FeedAPI { + agent: BskyAgent + + constructor({agent}: {agent: BskyAgent}) { + this.agent = agent + } + + async peekLatest(): Promise { + return DEMO_FEED.feed[0] + } + + async fetch(): Promise { + return DEMO_FEED + } +} diff --git a/src/lib/demo.ts b/src/lib/demo.ts new file mode 100644 index 0000000000..96bb7f9b14 --- /dev/null +++ b/src/lib/demo.ts @@ -0,0 +1,516 @@ +import {type AppBskyFeedGetFeed} from '@atproto/api' + +export const DEMO_FEED = { + feed: [ + { + post: { + uri: 'at://did:plc:vwzwgnygau7ed7b7wt5ux7y2/app.bsky.feed.post/3lng6kvb6uc2a', + cid: 'bafyreifqyej7jivzucaagu22f7jj7rvjcpbzv2kxo27wt47ktduwwdpdae', + author: { + did: 'did:plc:vwzwgnygau7ed7b7wt5ux7y2', + handle: 'someoneelse.bsky.social', + displayName: 'Not David', + avatar: + 'https://cdn.bsky.app/img/avatar/plain/did:plc:vwzwgnygau7ed7b7wt5ux7y2/bafkreifrtz3ngpzz5qmhjliv5toj4nvyjovijxs5e2la67wddhmdhro5he@jpeg', + associated: { + chat: { + allowIncoming: 'following', + }, + }, + viewer: { + muted: false, + blockedBy: false, + following: + 'at://did:plc:p2cp5gopk7mgjegy6wadk3ep/app.bsky.graph.follow/3kcvvfzq6o32a', + followedBy: + 'at://did:plc:vwzwgnygau7ed7b7wt5ux7y2/app.bsky.graph.follow/3jwawchotz22h', + }, + labels: [], + createdAt: '2023-04-27T09:23:54.423Z', + verification: { + verifications: [ + { + issuer: 'did:plc:z72i7hdynmk6r22z27h6tvur', + uri: 'at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.graph.verification/3lndpxt7ur22f', + isValid: true, + createdAt: '2025-04-21T10:48:58.775Z', + }, + ], + verifiedStatus: 'valid', + trustedVerifierStatus: 'none', + }, + }, + record: { + $type: 'app.bsky.feed.post', + createdAt: '2025-04-22T17:15:30.525Z', + langs: ['en'], + reply: { + parent: { + cid: 'bafyreic7wmhywvu5fi4lupswxpmyydqn2gl5kwnt4n4jxvb3lpej2l72ku', + uri: 'at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.feed.post/3lng66dkzu222', + }, + root: { + cid: 'bafyreic7wmhywvu5fi4lupswxpmyydqn2gl5kwnt4n4jxvb3lpej2l72ku', + uri: 'at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.feed.post/3lng66dkzu222', + }, + }, + text: 'sometimes I go to the apple store just to look at them', + }, + replyCount: 0, + repostCount: 0, + likeCount: 6, + quoteCount: 0, + indexedAt: '2025-04-22T17:15:31.251Z', + viewer: { + threadMuted: false, + embeddingDisabled: false, + }, + labels: [], + }, + reply: { + root: { + uri: 'at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.feed.post/3lng66dkzu222', + cid: 'bafyreic7wmhywvu5fi4lupswxpmyydqn2gl5kwnt4n4jxvb3lpej2l72ku', + author: { + did: 'did:plc:vc7f4oafdgxsihk4cry2xpze', + handle: 'jasalterego.bsky.social', + displayName: 'Jerry Appleseed', + avatar: + 'https://cdn.bsky.app/img/avatar/plain/did:plc:vc7f4oafdgxsihk4cry2xpze/bafkreicwxwecqiko2rwwln5y3fqqb2zx6wfg5rxf5r7lukakkq2slqy5hy@jpeg', + associated: { + chat: { + allowIncoming: 'following', + }, + }, + viewer: { + muted: false, + blockedBy: false, + following: + 'at://did:plc:p2cp5gopk7mgjegy6wadk3ep/app.bsky.graph.follow/3jx4rnvlnhl25', + followedBy: + 'at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.graph.follow/3jx4siiniuc2e', + }, + labels: [ + { + cts: '2024-05-17T21:53:59.049Z', + src: 'did:plc:skibpmllbhxvbvwgtjxl3uao', + uri: 'did:plc:vc7f4oafdgxsihk4cry2xpze', + val: 'cringe', + ver: 1, + }, + { + cts: '2024-05-17T21:53:59.049Z', + src: 'did:plc:skibpmllbhxvbvwgtjxl3uao', + uri: 'did:plc:vc7f4oafdgxsihk4cry2xpze', + val: 'elder-watch', + ver: 1, + }, + { + src: 'did:plc:vc7f4oafdgxsihk4cry2xpze', + uri: 'at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.actor.profile/self', + cid: 'bafyreidfiuv3c22vliyu2onazf23zrp35rr7i3upsqa2dsn5cqimmlgugm', + val: '!no-unauthenticated', + cts: '1970-01-01T00:00:00.000Z', + }, + ], + createdAt: '2023-04-23T20:11:04.375Z', + }, + record: { + $type: 'app.bsky.feed.post', + createdAt: '2025-04-22T17:08:29.321Z', + langs: ['en'], + text: "(studying the blade) ow that's the sharp side", + }, + replyCount: 8, + repostCount: 37, + likeCount: 252, + quoteCount: 1, + indexedAt: '2025-04-22T17:08:29.458Z', + viewer: { + threadMuted: false, + embeddingDisabled: false, + }, + labels: [], + $type: 'app.bsky.feed.defs#postView', + }, + parent: { + uri: 'at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.feed.post/3lng66dkzu222', + cid: 'bafyreic7wmhywvu5fi4lupswxpmyydqn2gl5kwnt4n4jxvb3lpej2l72ku', + author: { + did: 'did:plc:vc7f4oafdgxsihk4cry2xpze', + handle: 'jasalterego.bsky.social', + displayName: 'Jerry Appleseed', + avatar: + 'https://cdn.bsky.app/img/avatar/plain/did:plc:vc7f4oafdgxsihk4cry2xpze/bafkreicwxwecqiko2rwwln5y3fqqb2zx6wfg5rxf5r7lukakkq2slqy5hy@jpeg', + associated: { + chat: { + allowIncoming: 'following', + }, + }, + viewer: { + muted: false, + blockedBy: false, + following: + 'at://did:plc:p2cp5gopk7mgjegy6wadk3ep/app.bsky.graph.follow/3jx4rnvlnhl25', + followedBy: + 'at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.graph.follow/3jx4siiniuc2e', + }, + labels: [ + { + cts: '2024-05-17T21:53:59.049Z', + src: 'did:plc:skibpmllbhxvbvwgtjxl3uao', + uri: 'did:plc:vc7f4oafdgxsihk4cry2xpze', + val: 'cringe', + ver: 1, + }, + { + cts: '2024-05-17T21:53:59.049Z', + src: 'did:plc:skibpmllbhxvbvwgtjxl3uao', + uri: 'did:plc:vc7f4oafdgxsihk4cry2xpze', + val: 'elder-watch', + ver: 1, + }, + { + src: 'did:plc:vc7f4oafdgxsihk4cry2xpze', + uri: 'at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.actor.profile/self', + cid: 'bafyreidfiuv3c22vliyu2onazf23zrp35rr7i3upsqa2dsn5cqimmlgugm', + val: '!no-unauthenticated', + cts: '1970-01-01T00:00:00.000Z', + }, + ], + createdAt: '2023-04-23T20:11:04.375Z', + }, + record: { + $type: 'app.bsky.feed.post', + createdAt: '2025-04-22T17:08:29.321Z', + langs: ['en'], + text: '*sees the studio display* i think i hauve covid', + }, + replyCount: 8, + repostCount: 37, + likeCount: 252, + quoteCount: 1, + indexedAt: '2025-04-22T17:08:29.458Z', + viewer: { + threadMuted: false, + embeddingDisabled: false, + }, + labels: [], + $type: 'app.bsky.feed.defs#postView', + }, + }, + }, + { + post: { + uri: 'at://did:plc:qvzn322kmcvd7xtnips5xaun/app.bsky.feed.post/3lnehbwkvzk2z', + cid: 'bafyreidshyla4xoolb7fexhtlqcjjbn6ts7z4xja7gnlinroms5cuqg3fq', + author: { + did: 'did:plc:qvzn322kmcvd7xtnips5xaun', + handle: 'scalzi.com', + displayName: 'John Scalzi', + avatar: + 'https://cdn.bsky.app/img/avatar/plain/did:plc:qvzn322kmcvd7xtnips5xaun/bafkreih4dn5gllculyzb6wlqcqparkax35zloe3bzn2nufeqeilz4sutsu@jpeg', + associated: { + chat: { + allowIncoming: 'following', + }, + }, + + viewer: { + muted: false, + blockedBy: false, + following: + 'at://did:plc:p2cp5gopk7mgjegy6wadk3ep/app.bsky.graph.follow/3kcvvfzq6o32a', + followedBy: + 'at://did:plc:vwzwgnygau7ed7b7wt5ux7y2/app.bsky.graph.follow/3jwawchotz22h', + }, + labels: [], + createdAt: '2023-04-27T16:05:17.859Z', + }, + record: { + $type: 'app.bsky.feed.post', + createdAt: '2025-04-22T00:46:14.095Z', + embed: { + $type: 'app.bsky.embed.images', + images: [ + { + alt: 'Smudge napping on the Eames chair, which is covered in a blanket to avoid getting cat hair on it. ', + aspectRatio: { + height: 2000, + width: 1505, + }, + image: { + $type: 'blob', + ref: { + $link: + 'bafkreigkfbcmttc4r4avknp4y2mlcjlws3sdcat6jcyd2mjr7yvz6sje4q', + }, + mimeType: 'image/jpeg', + size: 833834, + }, + }, + ], + }, + langs: ['en'], + text: 'Smudge found the Eames chair', + }, + embed: { + $type: 'app.bsky.embed.images#view', + images: [ + { + thumb: + 'https://cdn.bsky.app/img/feed_thumbnail/plain/did:plc:qvzn322kmcvd7xtnips5xaun/bafkreigkfbcmttc4r4avknp4y2mlcjlws3sdcat6jcyd2mjr7yvz6sje4q@jpeg', + fullsize: + 'https://cdn.bsky.app/img/feed_fullsize/plain/did:plc:qvzn322kmcvd7xtnips5xaun/bafkreigkfbcmttc4r4avknp4y2mlcjlws3sdcat6jcyd2mjr7yvz6sje4q@jpeg', + alt: 'Smudge napping on the Eames chair, which is covered in a blanket to avoid getting cat hair on it. ', + aspectRatio: { + height: 2000, + width: 1505, + }, + }, + ], + }, + replyCount: 47, + repostCount: 31, + likeCount: 1543, + quoteCount: 0, + indexedAt: '2025-04-22T00:46:17.457Z', + viewer: { + threadMuted: false, + embeddingDisabled: false, + }, + labels: [], + }, + }, + { + post: { + uri: 'at://did:plc:jb2q4yqmgpmefxd4xx66gepm/app.bsky.feed.post/3lng4m2memc2k', + cid: 'bafyreicvgwkd5xkbtu3eh756yodnynqbxoegzzqhhees5ou45t3gq3j6um', + author: { + did: 'did:plc:jb2q4yqmgpmefxd4xx66gepm', + handle: 'visionprofan.bsky.social', + displayName: 'Visionary', + avatar: + 'https://cdn.bsky.app/img/avatar/plain/did:plc:jb2q4yqmgpmefxd4xx66gepm/bafkreibqdpwilgj43m37ksjilzcnzqx2g3njcyiyifvazdar23rs5hlokm@jpeg', + associated: { + chat: { + allowIncoming: 'following', + }, + }, + + viewer: { + muted: false, + blockedBy: false, + following: + 'at://did:plc:p2cp5gopk7mgjegy6wadk3ep/app.bsky.graph.follow/3kcvvfzq6o32a', + followedBy: + 'at://did:plc:vwzwgnygau7ed7b7wt5ux7y2/app.bsky.graph.follow/3jwawchotz22h', + }, + labels: [ + { + cts: '2024-07-14T04:31:55.599Z', + src: 'did:plc:skibpmllbhxvbvwgtjxl3uao', + uri: 'did:plc:jb2q4yqmgpmefxd4xx66gepm', + val: 'cringe', + ver: 1, + }, + ], + createdAt: '2023-04-13T05:48:48.827Z', + }, + record: { + $type: 'app.bsky.feed.post', + createdAt: '2025-04-22T16:40:22.205Z', + embed: { + $type: 'app.bsky.embed.record', + record: { + cid: 'bafyreif6ks7dhjrgrio5guztdhf3byoygbwebbvehi4al2c5kmkevlqdky', + uri: 'at://did:plc:4llrhdclvdlmmynkwsmg5tdc/app.bsky.feed.post/3lnfspxzdd42p', + }, + }, + langs: ['en'], + text: 'Just got my Vision Pro! 🤯\n\nAny recommendations for apps to try out?', + }, + embed: { + $type: 'app.bsky.embed.record#view', + record: { + $type: 'app.bsky.embed.record#viewRecord', + uri: 'at://did:plc:4llrhdclvdlmmynkwsmg5tdc/app.bsky.feed.post/3lnfspxzdd42p', + cid: 'bafyreif6ks7dhjrgrio5guztdhf3byoygbwebbvehi4al2c5kmkevlqdky', + author: { + did: 'did:plc:4llrhdclvdlmmynkwsmg5tdc', + handle: 'atrupar.com', + displayName: 'Aaron Rupar', + avatar: + 'https://cdn.bsky.app/img/avatar/plain/did:plc:4llrhdclvdlmmynkwsmg5tdc/bafkreibmhm3h6ar52pogvolisrzjdhwa2myras5vkxzj67twxn2l6pogwu@jpeg', + associated: { + chat: { + allowIncoming: 'following', + }, + }, + viewer: { + muted: false, + blockedBy: false, + following: + 'at://did:plc:p2cp5gopk7mgjegy6wadk3ep/app.bsky.graph.follow/3l7eals2t4g2k', + }, + labels: [], + createdAt: '2023-04-28T00:47:57.437Z', + }, + value: { + $type: 'app.bsky.feed.post', + createdAt: '2025-04-22T13:43:36.261Z', + embed: { + $type: 'app.bsky.embed.video', + alt: '', + aspectRatio: { + height: 720, + width: 1280, + }, + captions: [ + { + $type: 'app.bsky.embed.video#caption', + file: { + $type: 'blob', + ref: { + $link: + 'bafkreihm7npnefqxqmn7d45lcbxzn4wnowc2abe5hxmd63qlob7fbszola', + }, + mimeType: 'text/vtt', + size: 1339, + }, + lang: 'en', + }, + ], + video: { + $type: 'blob', + ref: { + $link: + 'bafkreihovdkyvql2yswuimm5m35lqyo7tgsfiujm7vrxtfmi4gwej4hkpa', + }, + mimeType: 'video/mp4', + size: 6026932, + }, + }, + facets: [], + langs: ['en'], + text: 'Austin Scott previews how House Rs plan to cut Medicaid: "The federal govt is paying 90% of the Medicaid expansion. What we\'ve talked about is moving that 90% level of the expansion back... nobody would be kicked off Medicaid as long as governors decided they wanted to continue to fund the program"', + }, + labels: [], + likeCount: 880, + replyCount: 230, + repostCount: 347, + quoteCount: 145, + indexedAt: '2025-04-22T13:43:37.350Z', + embeds: [ + { + $type: 'app.bsky.embed.video#view', + cid: 'bafkreihovdkyvql2yswuimm5m35lqyo7tgsfiujm7vrxtfmi4gwej4hkpa', + playlist: + 'https://video.bsky.app/watch/did%3Aplc%3A4llrhdclvdlmmynkwsmg5tdc/bafkreihovdkyvql2yswuimm5m35lqyo7tgsfiujm7vrxtfmi4gwej4hkpa/playlist.m3u8', + thumbnail: + 'https://video.bsky.app/watch/did%3Aplc%3A4llrhdclvdlmmynkwsmg5tdc/bafkreihovdkyvql2yswuimm5m35lqyo7tgsfiujm7vrxtfmi4gwej4hkpa/thumbnail.jpg', + alt: '', + aspectRatio: { + height: 720, + width: 1280, + }, + }, + ], + }, + }, + replyCount: 11, + repostCount: 97, + likeCount: 399, + quoteCount: 3, + indexedAt: '2025-04-22T16:40:22.648Z', + viewer: { + threadMuted: false, + embeddingDisabled: false, + }, + labels: [], + }, + }, + { + post: { + uri: 'at://did:plc:5o6k7jvowuyaquloafzn3cfw/app.bsky.feed.post/3lng6lkuhxc2s', + cid: 'bafyreifwapmjx76kz5lkoeejfoes4ct2xhyycfyxwccmyr3mtxht5juyli', + author: { + did: 'did:plc:5o6k7jvowuyaquloafzn3cfw', + handle: 'johndoe.org', + displayName: 'John Doe', + avatar: + 'https://cdn.bsky.app/img/avatar/plain/did:plc:5o6k7jvowuyaquloafzn3cfw/bafkreierrwtdsf5quwprs2xqmmh2lu2k7au2cibyegfpard6wqyjs7nd6i@jpeg', + + viewer: { + muted: false, + blockedBy: false, + following: + 'at://did:plc:p2cp5gopk7mgjegy6wadk3ep/app.bsky.graph.follow/3kcvvfzq6o32a', + followedBy: + 'at://did:plc:vwzwgnygau7ed7b7wt5ux7y2/app.bsky.graph.follow/3jwawchotz22h', + }, + labels: [], + createdAt: '2023-05-16T02:37:39.269Z', + }, + record: { + $type: 'app.bsky.feed.post', + createdAt: '2025-04-22T17:15:53.178Z', + langs: ['en'], + text: "I'm running out of ideas for these fake posts. Alas, such is the demands of modern life. Do you like blueberries? Just remembered that blueberries are delicious! They're so tasty! I can't wait to try them!", + }, + replyCount: 13, + repostCount: 121, + likeCount: 345, + quoteCount: 6, + indexedAt: '2025-04-22T17:15:53.351Z', + viewer: { + threadMuted: false, + embeddingDisabled: false, + }, + labels: [], + }, + }, + { + post: { + uri: 'at://did:plc:5ywatwbfxoecxgb4xq6ods72/app.bsky.feed.post/3lng5w2fbvs2g', + cid: 'bafyreigi7d57fudzoybe4u6w7friw6ydz3pmzrdu3bvjwb5mvsvlprk23y', + author: { + did: 'did:plc:5ywatwbfxoecxgb4xq6ods72', + handle: 'cooking.bsky.social', + displayName: 'cooking tips', + avatar: + 'https://cdn.bsky.app/img/avatar/plain/did:plc:5ywatwbfxoecxgb4xq6ods72/bafkreibbsuyy25elibbys5vx25cnkcs6g4ih6dozypa4bomwhkwsi6f5wa@jpeg', + + viewer: { + muted: false, + blockedBy: false, + following: + 'at://did:plc:p2cp5gopk7mgjegy6wadk3ep/app.bsky.graph.follow/3kcvvfzq6o32a', + followedBy: + 'at://did:plc:vwzwgnygau7ed7b7wt5ux7y2/app.bsky.graph.follow/3jwawchotz22h', + }, + labels: [], + createdAt: '2024-05-28T00:18:08.531Z', + }, + record: { + $type: 'app.bsky.feed.post', + createdAt: '2025-04-22T17:03:51.259Z', + langs: ['en'], + text: 'and another thing. I have more things to say. I think. I forget :/', + }, + replyCount: 1, + repostCount: 4, + likeCount: 20, + quoteCount: 0, + indexedAt: '2025-04-22T17:03:52.050Z', + viewer: { + threadMuted: false, + embeddingDisabled: false, + }, + labels: [], + }, + }, + ], +} satisfies AppBskyFeedGetFeed.OutputSchema + +export const BOTTOM_BAR_AVI = 'https://bsky.social/about/hero-social-card.webp' diff --git a/src/state/queries/post-feed.ts b/src/state/queries/post-feed.ts index 82a118ec2c..f3fa13cfba 100644 --- a/src/state/queries/post-feed.ts +++ b/src/state/queries/post-feed.ts @@ -1,31 +1,32 @@ import React, {useCallback, useEffect, useRef} from 'react' import {AppState} from 'react-native' import { - AppBskyActorDefs, + type AppBskyActorDefs, AppBskyFeedDefs, - AppBskyFeedPost, + type AppBskyFeedPost, AtUri, - BskyAgent, + type BskyAgent, moderatePost, - ModerationDecision, + type ModerationDecision, } from '@atproto/api' import { - InfiniteData, - QueryClient, - QueryKey, + type InfiniteData, + type QueryClient, + type QueryKey, useInfiniteQuery, } from '@tanstack/react-query' import {AuthorFeedAPI} from '#/lib/api/feed/author' import {CustomFeedAPI} from '#/lib/api/feed/custom' +import {DemoFeedAPI} from '#/lib/api/feed/demo' import {FollowingFeedAPI} from '#/lib/api/feed/following' import {HomeFeedAPI} from '#/lib/api/feed/home' import {LikesFeedAPI} from '#/lib/api/feed/likes' import {ListFeedAPI} from '#/lib/api/feed/list' import {MergeFeedAPI} from '#/lib/api/feed/merge' -import {FeedAPI, ReasonFeedSource} from '#/lib/api/feed/types' +import {type FeedAPI, type ReasonFeedSource} from '#/lib/api/feed/types' import {aggregateUserInterests} from '#/lib/api/feed/utils' -import {FeedTuner, FeedTunerFn} from '#/lib/api/feed-manip' +import {FeedTuner, type FeedTunerFn} from '#/lib/api/feed-manip' import {DISCOVER_FEED_URI} from '#/lib/constants' import {BSKY_FEED_OWNER_DIDS} from '#/lib/constants' import {logger} from '#/logger' @@ -59,6 +60,7 @@ export type FeedDescriptor = | `feedgen|${FeedUri}` | `likes|${ActorDid}` | `list|${ListUri}` + | 'demo' export interface FeedParams { mergeFeedEnabled?: boolean mergeFeedSources?: string[] @@ -483,6 +485,8 @@ function createApi({ } else if (feedDesc.startsWith('list')) { const [_, list] = feedDesc.split('|') return new ListFeedAPI({agent, feedParams: {list}}) + } else if (feedDesc === 'demo') { + return new DemoFeedAPI({agent}) } else { // shouldnt happen return new FollowingFeedAPI({agent}) diff --git a/src/view/screens/Home.tsx b/src/view/screens/Home.tsx index a6e2595eec..e058e28831 100644 --- a/src/view/screens/Home.tsx +++ b/src/view/screens/Home.tsx @@ -8,28 +8,36 @@ import {useOTAUpdates} from '#/lib/hooks/useOTAUpdates' import {useSetTitle} from '#/lib/hooks/useSetTitle' import {useRequestNotificationsPermission} from '#/lib/notifications/notifications' import { - HomeTabNavigatorParams, - NativeStackScreenProps, + type HomeTabNavigatorParams, + type NativeStackScreenProps, } from '#/lib/routes/types' import {logEvent} from '#/lib/statsig/statsig' import {isWeb} from '#/platform/detection' import {emitSoftReset} from '#/state/events' -import {SavedFeedSourceInfo, usePinnedFeedsInfos} from '#/state/queries/feed' -import {FeedDescriptor, FeedParams} from '#/state/queries/post-feed' +import { + type SavedFeedSourceInfo, + usePinnedFeedsInfos, +} from '#/state/queries/feed' +import {type FeedDescriptor, type FeedParams} from '#/state/queries/post-feed' import {usePreferencesQuery} from '#/state/queries/preferences' -import {UsePreferencesQueryResponse} from '#/state/queries/preferences/types' +import {type UsePreferencesQueryResponse} from '#/state/queries/preferences/types' import {useSession} from '#/state/session' import {useSetMinimalShellMode} from '#/state/shell' import {useLoggedOutViewControls} from '#/state/shell/logged-out' import {useSelectedFeed, useSetSelectedFeed} from '#/state/shell/selected-feed' import {FeedPage} from '#/view/com/feeds/FeedPage' import {HomeHeader} from '#/view/com/home/HomeHeader' -import {Pager, PagerRef, RenderTabBarFnProps} from '#/view/com/pager/Pager' +import { + Pager, + type PagerRef, + type RenderTabBarFnProps, +} from '#/view/com/pager/Pager' import {CustomFeedEmptyState} from '#/view/com/posts/CustomFeedEmptyState' import {FollowingEmptyState} from '#/view/com/posts/FollowingEmptyState' import {FollowingEndOfFeed} from '#/view/com/posts/FollowingEndOfFeed' import {NoFeedsPinned} from '#/screens/Home/NoFeedsPinned' import * as Layout from '#/components/Layout' +import {useDemoMode} from '#/storage/hooks/demo-mode' type Props = NativeStackScreenProps export function HomeScreen(props: Props) { @@ -184,8 +192,22 @@ function HomeScreenReady({ [setMinimalShellMode], ) + const [demoMode] = useDemoMode() + const renderTabBar = React.useCallback( (props: RenderTabBarFnProps) => { + if (demoMode) { + return ( + + ) + } return ( ) }, - [onPressSelected, pinnedFeedInfos], + [onPressSelected, pinnedFeedInfos, demoMode], ) const renderFollowingEmptyState = React.useCallback(() => { @@ -218,6 +240,35 @@ function HomeScreenReady({ } }, [preferences]) + if (demoMode) { + return ( + + + + + ) + } + return hasSession ? ( @@ -259,7 +263,7 @@ export function BottomBar({navigation}: BottomTabBarProps) { {borderColor: pal.text.color}, ]}> Date: Tue, 22 Apr 2025 21:35:31 +0300 Subject: [PATCH 03/15] add more posts --- src/lib/demo.ts | 119 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/src/lib/demo.ts b/src/lib/demo.ts index 96bb7f9b14..ce0f594279 100644 --- a/src/lib/demo.ts +++ b/src/lib/demo.ts @@ -510,6 +510,125 @@ export const DEMO_FEED = { labels: [], }, }, + { + post: { + uri: 'at://did:plc:fpruhuo22xkm5o7ttr2ktxdo/app.bsky.feed.post/3lng5izl7kc2c', + cid: 'bafyreicsich65s4rq526rek5jmvd6djtcmr7kdavw26rrnf424awgvia7i', + author: { + did: 'did:plc:fpruhuo22xkm5o7ttr2ktxdo', + handle: 'danabra.mov', + displayName: 'dan', + avatar: + 'https://cdn.bsky.app/img/avatar/plain/did:plc:fpruhuo22xkm5o7ttr2ktxdo/bafkreif43mhqajnbnl62u3ezf37g6x22nd762im54thxbil4ga46eugcga@jpeg', + associated: { + chat: { + allowIncoming: 'all', + }, + }, + viewer: { + muted: false, + blockedBy: false, + following: + 'at://did:plc:p2cp5gopk7mgjegy6wadk3ep/app.bsky.graph.follow/3jtdzgbbysa2y', + followedBy: + 'at://did:plc:fpruhuo22xkm5o7ttr2ktxdo/app.bsky.graph.follow/3k7ht6lwu6t2a', + }, + labels: [], + createdAt: '2023-04-08T20:19:22.589Z', + verification: { + verifications: [ + { + issuer: 'did:plc:z72i7hdynmk6r22z27h6tvur', + uri: 'at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.graph.verification/3lndpxompy32z', + isValid: true, + createdAt: '2025-04-21T10:48:53.876Z', + }, + ], + verifiedStatus: 'valid', + trustedVerifierStatus: 'none', + }, + }, + record: { + $type: 'app.bsky.feed.post', + createdAt: '2025-04-22T16:56:34.198Z', + langs: ['en'], + text: 'maybe i should write something about vercel at some point', + }, + replyCount: 10, + repostCount: 1, + likeCount: 84, + quoteCount: 1, + indexedAt: '2025-04-22T16:56:34.356Z', + viewer: { + threadMuted: false, + replyDisabled: false, + embeddingDisabled: false, + }, + labels: [], + threadgate: { + uri: 'at://did:plc:fpruhuo22xkm5o7ttr2ktxdo/app.bsky.feed.threadgate/3lng5izl7kc2c', + cid: 'bafyreic4wpsh5wrmjvbngt7som5436xzjhdnld3mxnkzyhj2i4vh6lpefa', + record: { + $type: 'app.bsky.feed.threadgate', + allow: [ + { + $type: 'app.bsky.feed.threadgate#followerRule', + }, + { + $type: 'app.bsky.feed.threadgate#followingRule', + }, + { + $type: 'app.bsky.feed.threadgate#mentionRule', + }, + ], + createdAt: '2025-04-22T16:56:34.200Z', + hiddenReplies: [], + post: 'at://did:plc:fpruhuo22xkm5o7ttr2ktxdo/app.bsky.feed.post/3lng5izl7kc2c', + }, + lists: [], + }, + }, + }, + { + post: { + uri: 'at://did:plc:77tdak46psveqneyegsdyc7l/app.bsky.feed.post/3lnft75ivlc27', + cid: 'bafyreic24reeweaymcfe6hdsuhmffazdpa5hoqyculxrdp2sr7xkoehgay', + author: { + did: 'did:plc:77tdak46psveqneyegsdyc7l', + handle: 'werd.io', + displayName: 'Ben Werdmuller', + avatar: + 'https://cdn.bsky.app/img/avatar/plain/did:plc:77tdak46psveqneyegsdyc7l/bafkreicoqtayuefjlw73nrx4c7sioc3ujq74uisgbh4ddmuamevjwzt4fu@jpeg', + associated: { + chat: { + allowIncoming: 'following', + }, + }, + viewer: { + muted: false, + blockedBy: false, + }, + labels: [], + createdAt: '2023-03-07T15:40:54.229Z', + }, + record: { + $type: 'app.bsky.feed.post', + createdAt: '2025-04-22T13:52:05.353Z', + langs: ['en'], + text: 'This is obvious, but if people broadly rely on a black box to give them answers that help them understand the world, whoever controls the black box controls those answers and therefore the understanding that comes from them.\n\nOpenness is safety.', + }, + replyCount: 10, + repostCount: 84, + likeCount: 432, + quoteCount: 2, + indexedAt: '2025-04-22T13:52:05.755Z', + viewer: { + threadMuted: false, + embeddingDisabled: false, + }, + labels: [], + }, + }, ], } satisfies AppBskyFeedGetFeed.OutputSchema From eb2008cd8e300927d5f76276fd6a528183c87eeb Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 23 Apr 2025 14:50:10 -0500 Subject: [PATCH 04/15] Update data --- src/lib/demo.ts | 403 +++++++++--------------------------------------- 1 file changed, 72 insertions(+), 331 deletions(-) diff --git a/src/lib/demo.ts b/src/lib/demo.ts index ce0f594279..688be6c6c4 100644 --- a/src/lib/demo.ts +++ b/src/lib/demo.ts @@ -1,17 +1,23 @@ import {type AppBskyFeedGetFeed} from '@atproto/api' +import {subDays,subMinutes} from 'date-fns' + +const DID = `did:plc:z72i7hdynmk6r22z27h6tvur` +const NOW = new Date() +const POST_1_DATE = subMinutes(NOW, 2).toISOString() +const POST_2_DATE = subMinutes(NOW, 4).toISOString() +const POST_3_DATE = subMinutes(NOW, 5).toISOString() export const DEMO_FEED = { feed: [ { post: { - uri: 'at://did:plc:vwzwgnygau7ed7b7wt5ux7y2/app.bsky.feed.post/3lng6kvb6uc2a', - cid: 'bafyreifqyej7jivzucaagu22f7jj7rvjcpbzv2kxo27wt47ktduwwdpdae', + uri: `at://${DID}/app.bsky.feed.post/post1`, + cid: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', author: { - did: 'did:plc:vwzwgnygau7ed7b7wt5ux7y2', - handle: 'someoneelse.bsky.social', - displayName: 'Not David', - avatar: - 'https://cdn.bsky.app/img/avatar/plain/did:plc:vwzwgnygau7ed7b7wt5ux7y2/bafkreifrtz3ngpzz5qmhjliv5toj4nvyjovijxs5e2la67wddhmdhro5he@jpeg', + did: DID, + handle: 'forkedriver.blsky', + displayName: 'Forked River Band', + avatar: 'https://bsky.social/about/adi/post_1_avi.jpg', associated: { chat: { allowIncoming: 'following', @@ -20,261 +26,102 @@ export const DEMO_FEED = { viewer: { muted: false, blockedBy: false, - following: - 'at://did:plc:p2cp5gopk7mgjegy6wadk3ep/app.bsky.graph.follow/3kcvvfzq6o32a', - followedBy: - 'at://did:plc:vwzwgnygau7ed7b7wt5ux7y2/app.bsky.graph.follow/3jwawchotz22h', + following: `at://${DID}/app.bsky.graph.follow/post1`, }, labels: [], - createdAt: '2023-04-27T09:23:54.423Z', + createdAt: POST_1_DATE, verification: { verifications: [ { - issuer: 'did:plc:z72i7hdynmk6r22z27h6tvur', - uri: 'at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.graph.verification/3lndpxt7ur22f', + issuer: DID, + uri: `at://${DID}/app.bsky.graph.verification/post1`, isValid: true, - createdAt: '2025-04-21T10:48:58.775Z', + createdAt: subDays(NOW, 11).toISOString(), }, ], verifiedStatus: 'valid', trustedVerifierStatus: 'none', }, }, + embed: { + $type: 'app.bsky.embed.images#view', + images: [ + { + thumb: 'https://bsky.social/about/adi/post_1_image.jpg', + fullsize: 'https://bsky.social/about/adi/post_1_image.jpg', + alt: '', + aspectRatio: { + height: 1350, + width: 900, + }, + }, + ], + }, record: { $type: 'app.bsky.feed.post', - createdAt: '2025-04-22T17:15:30.525Z', + createdAt: POST_1_DATE, langs: ['en'], - reply: { - parent: { - cid: 'bafyreic7wmhywvu5fi4lupswxpmyydqn2gl5kwnt4n4jxvb3lpej2l72ku', - uri: 'at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.feed.post/3lng66dkzu222', - }, - root: { - cid: 'bafyreic7wmhywvu5fi4lupswxpmyydqn2gl5kwnt4n4jxvb3lpej2l72ku', - uri: 'at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.feed.post/3lng66dkzu222', - }, - }, - text: 'sometimes I go to the apple store just to look at them', + text: 'Sonoma County folks: Come tip your hats our way and see us play new and old tunes at Sebastopol Bluegrass Fest on June 14th.', }, - replyCount: 0, - repostCount: 0, - likeCount: 6, + replyCount: 1, + repostCount: 4, + likeCount: 18, quoteCount: 0, - indexedAt: '2025-04-22T17:15:31.251Z', + indexedAt: POST_1_DATE, viewer: { threadMuted: false, embeddingDisabled: false, }, labels: [], }, - reply: { - root: { - uri: 'at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.feed.post/3lng66dkzu222', - cid: 'bafyreic7wmhywvu5fi4lupswxpmyydqn2gl5kwnt4n4jxvb3lpej2l72ku', - author: { - did: 'did:plc:vc7f4oafdgxsihk4cry2xpze', - handle: 'jasalterego.bsky.social', - displayName: 'Jerry Appleseed', - avatar: - 'https://cdn.bsky.app/img/avatar/plain/did:plc:vc7f4oafdgxsihk4cry2xpze/bafkreicwxwecqiko2rwwln5y3fqqb2zx6wfg5rxf5r7lukakkq2slqy5hy@jpeg', - associated: { - chat: { - allowIncoming: 'following', - }, - }, - viewer: { - muted: false, - blockedBy: false, - following: - 'at://did:plc:p2cp5gopk7mgjegy6wadk3ep/app.bsky.graph.follow/3jx4rnvlnhl25', - followedBy: - 'at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.graph.follow/3jx4siiniuc2e', - }, - labels: [ - { - cts: '2024-05-17T21:53:59.049Z', - src: 'did:plc:skibpmllbhxvbvwgtjxl3uao', - uri: 'did:plc:vc7f4oafdgxsihk4cry2xpze', - val: 'cringe', - ver: 1, - }, - { - cts: '2024-05-17T21:53:59.049Z', - src: 'did:plc:skibpmllbhxvbvwgtjxl3uao', - uri: 'did:plc:vc7f4oafdgxsihk4cry2xpze', - val: 'elder-watch', - ver: 1, - }, - { - src: 'did:plc:vc7f4oafdgxsihk4cry2xpze', - uri: 'at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.actor.profile/self', - cid: 'bafyreidfiuv3c22vliyu2onazf23zrp35rr7i3upsqa2dsn5cqimmlgugm', - val: '!no-unauthenticated', - cts: '1970-01-01T00:00:00.000Z', - }, - ], - createdAt: '2023-04-23T20:11:04.375Z', - }, - record: { - $type: 'app.bsky.feed.post', - createdAt: '2025-04-22T17:08:29.321Z', - langs: ['en'], - text: "(studying the blade) ow that's the sharp side", - }, - replyCount: 8, - repostCount: 37, - likeCount: 252, - quoteCount: 1, - indexedAt: '2025-04-22T17:08:29.458Z', - viewer: { - threadMuted: false, - embeddingDisabled: false, - }, - labels: [], - $type: 'app.bsky.feed.defs#postView', - }, - parent: { - uri: 'at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.feed.post/3lng66dkzu222', - cid: 'bafyreic7wmhywvu5fi4lupswxpmyydqn2gl5kwnt4n4jxvb3lpej2l72ku', - author: { - did: 'did:plc:vc7f4oafdgxsihk4cry2xpze', - handle: 'jasalterego.bsky.social', - displayName: 'Jerry Appleseed', - avatar: - 'https://cdn.bsky.app/img/avatar/plain/did:plc:vc7f4oafdgxsihk4cry2xpze/bafkreicwxwecqiko2rwwln5y3fqqb2zx6wfg5rxf5r7lukakkq2slqy5hy@jpeg', - associated: { - chat: { - allowIncoming: 'following', - }, - }, - viewer: { - muted: false, - blockedBy: false, - following: - 'at://did:plc:p2cp5gopk7mgjegy6wadk3ep/app.bsky.graph.follow/3jx4rnvlnhl25', - followedBy: - 'at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.graph.follow/3jx4siiniuc2e', - }, - labels: [ - { - cts: '2024-05-17T21:53:59.049Z', - src: 'did:plc:skibpmllbhxvbvwgtjxl3uao', - uri: 'did:plc:vc7f4oafdgxsihk4cry2xpze', - val: 'cringe', - ver: 1, - }, - { - cts: '2024-05-17T21:53:59.049Z', - src: 'did:plc:skibpmllbhxvbvwgtjxl3uao', - uri: 'did:plc:vc7f4oafdgxsihk4cry2xpze', - val: 'elder-watch', - ver: 1, - }, - { - src: 'did:plc:vc7f4oafdgxsihk4cry2xpze', - uri: 'at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.actor.profile/self', - cid: 'bafyreidfiuv3c22vliyu2onazf23zrp35rr7i3upsqa2dsn5cqimmlgugm', - val: '!no-unauthenticated', - cts: '1970-01-01T00:00:00.000Z', - }, - ], - createdAt: '2023-04-23T20:11:04.375Z', - }, - record: { - $type: 'app.bsky.feed.post', - createdAt: '2025-04-22T17:08:29.321Z', - langs: ['en'], - text: '*sees the studio display* i think i hauve covid', - }, - replyCount: 8, - repostCount: 37, - likeCount: 252, - quoteCount: 1, - indexedAt: '2025-04-22T17:08:29.458Z', - viewer: { - threadMuted: false, - embeddingDisabled: false, - }, - labels: [], - $type: 'app.bsky.feed.defs#postView', - }, - }, }, { post: { - uri: 'at://did:plc:qvzn322kmcvd7xtnips5xaun/app.bsky.feed.post/3lnehbwkvzk2z', - cid: 'bafyreidshyla4xoolb7fexhtlqcjjbn6ts7z4xja7gnlinroms5cuqg3fq', + uri: `at://${DID}/app.bsky.feed.post/post2`, + cid: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', author: { - did: 'did:plc:qvzn322kmcvd7xtnips5xaun', - handle: 'scalzi.com', - displayName: 'John Scalzi', - avatar: - 'https://cdn.bsky.app/img/avatar/plain/did:plc:qvzn322kmcvd7xtnips5xaun/bafkreih4dn5gllculyzb6wlqcqparkax35zloe3bzn2nufeqeilz4sutsu@jpeg', + did: DID, + handle: 'dinh-designs.blsky', + displayName: 'Dinh Designs', + avatar: 'https://bsky.social/about/adi/post_2_avi.jpg', associated: { chat: { allowIncoming: 'following', }, }, - viewer: { muted: false, blockedBy: false, - following: - 'at://did:plc:p2cp5gopk7mgjegy6wadk3ep/app.bsky.graph.follow/3kcvvfzq6o32a', - followedBy: - 'at://did:plc:vwzwgnygau7ed7b7wt5ux7y2/app.bsky.graph.follow/3jwawchotz22h', + following: `at://${DID}/app.bsky.graph.follow/post2`, }, labels: [], - createdAt: '2023-04-27T16:05:17.859Z', - }, - record: { - $type: 'app.bsky.feed.post', - createdAt: '2025-04-22T00:46:14.095Z', - embed: { - $type: 'app.bsky.embed.images', - images: [ - { - alt: 'Smudge napping on the Eames chair, which is covered in a blanket to avoid getting cat hair on it. ', - aspectRatio: { - height: 2000, - width: 1505, - }, - image: { - $type: 'blob', - ref: { - $link: - 'bafkreigkfbcmttc4r4avknp4y2mlcjlws3sdcat6jcyd2mjr7yvz6sje4q', - }, - mimeType: 'image/jpeg', - size: 833834, - }, - }, - ], - }, - langs: ['en'], - text: 'Smudge found the Eames chair', + createdAt: POST_2_DATE, }, embed: { $type: 'app.bsky.embed.images#view', images: [ { - thumb: - 'https://cdn.bsky.app/img/feed_thumbnail/plain/did:plc:qvzn322kmcvd7xtnips5xaun/bafkreigkfbcmttc4r4avknp4y2mlcjlws3sdcat6jcyd2mjr7yvz6sje4q@jpeg', - fullsize: - 'https://cdn.bsky.app/img/feed_fullsize/plain/did:plc:qvzn322kmcvd7xtnips5xaun/bafkreigkfbcmttc4r4avknp4y2mlcjlws3sdcat6jcyd2mjr7yvz6sje4q@jpeg', - alt: 'Smudge napping on the Eames chair, which is covered in a blanket to avoid getting cat hair on it. ', + thumb: 'https://bsky.social/about/adi/post_2_image.jpg', + fullsize: 'https://bsky.social/about/adi/post_2_image.jpg', + alt: '', aspectRatio: { - height: 2000, - width: 1505, + height: 872, + width: 598, }, }, ], }, - replyCount: 47, - repostCount: 31, - likeCount: 1543, + record: { + $type: 'app.bsky.feed.post', + createdAt: POST_2_DATE, + langs: ['en'], + text: 'Details from our install at the Lucas residence in Joshua Tree. We populated the space with rich, earthy tones and locally-sourced materials to suit the landscape.', + }, + replyCount: 3, + repostCount: 1, + likeCount: 4, quoteCount: 0, - indexedAt: '2025-04-22T00:46:17.457Z', + indexedAt: POST_2_DATE, viewer: { threadMuted: false, embeddingDisabled: false, @@ -284,145 +131,37 @@ export const DEMO_FEED = { }, { post: { - uri: 'at://did:plc:jb2q4yqmgpmefxd4xx66gepm/app.bsky.feed.post/3lng4m2memc2k', - cid: 'bafyreicvgwkd5xkbtu3eh756yodnynqbxoegzzqhhees5ou45t3gq3j6um', + uri: `at://${DID}/app.bsky.feed.post/post3`, + cid: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', author: { - did: 'did:plc:jb2q4yqmgpmefxd4xx66gepm', - handle: 'visionprofan.bsky.social', + did: DID, + handle: 'visionprofan.blsky', displayName: 'Visionary', avatar: - 'https://cdn.bsky.app/img/avatar/plain/did:plc:jb2q4yqmgpmefxd4xx66gepm/bafkreibqdpwilgj43m37ksjilzcnzqx2g3njcyiyifvazdar23rs5hlokm@jpeg', + 'https://cdn.bsky.app/img/avatar/plain/did:plc:p2cp5gopk7mgjegy6wadk3ep/bafkreiaqsy36o6lpbpnonb4n46cvntfs6zoxbav35raix2sxhqgopxcjge@jpeg', associated: { chat: { allowIncoming: 'following', }, }, - viewer: { muted: false, blockedBy: false, - following: - 'at://did:plc:p2cp5gopk7mgjegy6wadk3ep/app.bsky.graph.follow/3kcvvfzq6o32a', - followedBy: - 'at://did:plc:vwzwgnygau7ed7b7wt5ux7y2/app.bsky.graph.follow/3jwawchotz22h', + following: `at://${DID}/app.bsky.graph.follow/post3`, }, - labels: [ - { - cts: '2024-07-14T04:31:55.599Z', - src: 'did:plc:skibpmllbhxvbvwgtjxl3uao', - uri: 'did:plc:jb2q4yqmgpmefxd4xx66gepm', - val: 'cringe', - ver: 1, - }, - ], - createdAt: '2023-04-13T05:48:48.827Z', + createdAt: POST_3_DATE, }, record: { $type: 'app.bsky.feed.post', - createdAt: '2025-04-22T16:40:22.205Z', - embed: { - $type: 'app.bsky.embed.record', - record: { - cid: 'bafyreif6ks7dhjrgrio5guztdhf3byoygbwebbvehi4al2c5kmkevlqdky', - uri: 'at://did:plc:4llrhdclvdlmmynkwsmg5tdc/app.bsky.feed.post/3lnfspxzdd42p', - }, - }, + createdAt: POST_3_DATE, langs: ['en'], text: 'Just got my Vision Pro! 🤯\n\nAny recommendations for apps to try out?', }, - embed: { - $type: 'app.bsky.embed.record#view', - record: { - $type: 'app.bsky.embed.record#viewRecord', - uri: 'at://did:plc:4llrhdclvdlmmynkwsmg5tdc/app.bsky.feed.post/3lnfspxzdd42p', - cid: 'bafyreif6ks7dhjrgrio5guztdhf3byoygbwebbvehi4al2c5kmkevlqdky', - author: { - did: 'did:plc:4llrhdclvdlmmynkwsmg5tdc', - handle: 'atrupar.com', - displayName: 'Aaron Rupar', - avatar: - 'https://cdn.bsky.app/img/avatar/plain/did:plc:4llrhdclvdlmmynkwsmg5tdc/bafkreibmhm3h6ar52pogvolisrzjdhwa2myras5vkxzj67twxn2l6pogwu@jpeg', - associated: { - chat: { - allowIncoming: 'following', - }, - }, - viewer: { - muted: false, - blockedBy: false, - following: - 'at://did:plc:p2cp5gopk7mgjegy6wadk3ep/app.bsky.graph.follow/3l7eals2t4g2k', - }, - labels: [], - createdAt: '2023-04-28T00:47:57.437Z', - }, - value: { - $type: 'app.bsky.feed.post', - createdAt: '2025-04-22T13:43:36.261Z', - embed: { - $type: 'app.bsky.embed.video', - alt: '', - aspectRatio: { - height: 720, - width: 1280, - }, - captions: [ - { - $type: 'app.bsky.embed.video#caption', - file: { - $type: 'blob', - ref: { - $link: - 'bafkreihm7npnefqxqmn7d45lcbxzn4wnowc2abe5hxmd63qlob7fbszola', - }, - mimeType: 'text/vtt', - size: 1339, - }, - lang: 'en', - }, - ], - video: { - $type: 'blob', - ref: { - $link: - 'bafkreihovdkyvql2yswuimm5m35lqyo7tgsfiujm7vrxtfmi4gwej4hkpa', - }, - mimeType: 'video/mp4', - size: 6026932, - }, - }, - facets: [], - langs: ['en'], - text: 'Austin Scott previews how House Rs plan to cut Medicaid: "The federal govt is paying 90% of the Medicaid expansion. What we\'ve talked about is moving that 90% level of the expansion back... nobody would be kicked off Medicaid as long as governors decided they wanted to continue to fund the program"', - }, - labels: [], - likeCount: 880, - replyCount: 230, - repostCount: 347, - quoteCount: 145, - indexedAt: '2025-04-22T13:43:37.350Z', - embeds: [ - { - $type: 'app.bsky.embed.video#view', - cid: 'bafkreihovdkyvql2yswuimm5m35lqyo7tgsfiujm7vrxtfmi4gwej4hkpa', - playlist: - 'https://video.bsky.app/watch/did%3Aplc%3A4llrhdclvdlmmynkwsmg5tdc/bafkreihovdkyvql2yswuimm5m35lqyo7tgsfiujm7vrxtfmi4gwej4hkpa/playlist.m3u8', - thumbnail: - 'https://video.bsky.app/watch/did%3Aplc%3A4llrhdclvdlmmynkwsmg5tdc/bafkreihovdkyvql2yswuimm5m35lqyo7tgsfiujm7vrxtfmi4gwej4hkpa/thumbnail.jpg', - alt: '', - aspectRatio: { - height: 720, - width: 1280, - }, - }, - ], - }, - }, replyCount: 11, repostCount: 97, likeCount: 399, quoteCount: 3, - indexedAt: '2025-04-22T16:40:22.648Z', + indexedAt: POST_3_DATE, viewer: { threadMuted: false, embeddingDisabled: false, @@ -430,6 +169,7 @@ export const DEMO_FEED = { labels: [], }, }, + /* { post: { uri: 'at://did:plc:5o6k7jvowuyaquloafzn3cfw/app.bsky.feed.post/3lng6lkuhxc2s', @@ -629,6 +369,7 @@ export const DEMO_FEED = { labels: [], }, }, + */ ], } satisfies AppBskyFeedGetFeed.OutputSchema From 9f66b7fe67ac5715f4b0188b76bd06ff043a5b6e Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 23 Apr 2025 15:01:19 -0500 Subject: [PATCH 05/15] Delete unused fake data, update bottom bar avi --- src/lib/demo.ts | 206 +----------------------------------------------- 1 file changed, 3 insertions(+), 203 deletions(-) diff --git a/src/lib/demo.ts b/src/lib/demo.ts index 688be6c6c4..5e09ff0aa0 100644 --- a/src/lib/demo.ts +++ b/src/lib/demo.ts @@ -1,5 +1,5 @@ import {type AppBskyFeedGetFeed} from '@atproto/api' -import {subDays,subMinutes} from 'date-fns' +import {subDays, subMinutes} from 'date-fns' const DID = `did:plc:z72i7hdynmk6r22z27h6tvur` const NOW = new Date() @@ -169,208 +169,8 @@ export const DEMO_FEED = { labels: [], }, }, - /* - { - post: { - uri: 'at://did:plc:5o6k7jvowuyaquloafzn3cfw/app.bsky.feed.post/3lng6lkuhxc2s', - cid: 'bafyreifwapmjx76kz5lkoeejfoes4ct2xhyycfyxwccmyr3mtxht5juyli', - author: { - did: 'did:plc:5o6k7jvowuyaquloafzn3cfw', - handle: 'johndoe.org', - displayName: 'John Doe', - avatar: - 'https://cdn.bsky.app/img/avatar/plain/did:plc:5o6k7jvowuyaquloafzn3cfw/bafkreierrwtdsf5quwprs2xqmmh2lu2k7au2cibyegfpard6wqyjs7nd6i@jpeg', - - viewer: { - muted: false, - blockedBy: false, - following: - 'at://did:plc:p2cp5gopk7mgjegy6wadk3ep/app.bsky.graph.follow/3kcvvfzq6o32a', - followedBy: - 'at://did:plc:vwzwgnygau7ed7b7wt5ux7y2/app.bsky.graph.follow/3jwawchotz22h', - }, - labels: [], - createdAt: '2023-05-16T02:37:39.269Z', - }, - record: { - $type: 'app.bsky.feed.post', - createdAt: '2025-04-22T17:15:53.178Z', - langs: ['en'], - text: "I'm running out of ideas for these fake posts. Alas, such is the demands of modern life. Do you like blueberries? Just remembered that blueberries are delicious! They're so tasty! I can't wait to try them!", - }, - replyCount: 13, - repostCount: 121, - likeCount: 345, - quoteCount: 6, - indexedAt: '2025-04-22T17:15:53.351Z', - viewer: { - threadMuted: false, - embeddingDisabled: false, - }, - labels: [], - }, - }, - { - post: { - uri: 'at://did:plc:5ywatwbfxoecxgb4xq6ods72/app.bsky.feed.post/3lng5w2fbvs2g', - cid: 'bafyreigi7d57fudzoybe4u6w7friw6ydz3pmzrdu3bvjwb5mvsvlprk23y', - author: { - did: 'did:plc:5ywatwbfxoecxgb4xq6ods72', - handle: 'cooking.bsky.social', - displayName: 'cooking tips', - avatar: - 'https://cdn.bsky.app/img/avatar/plain/did:plc:5ywatwbfxoecxgb4xq6ods72/bafkreibbsuyy25elibbys5vx25cnkcs6g4ih6dozypa4bomwhkwsi6f5wa@jpeg', - - viewer: { - muted: false, - blockedBy: false, - following: - 'at://did:plc:p2cp5gopk7mgjegy6wadk3ep/app.bsky.graph.follow/3kcvvfzq6o32a', - followedBy: - 'at://did:plc:vwzwgnygau7ed7b7wt5ux7y2/app.bsky.graph.follow/3jwawchotz22h', - }, - labels: [], - createdAt: '2024-05-28T00:18:08.531Z', - }, - record: { - $type: 'app.bsky.feed.post', - createdAt: '2025-04-22T17:03:51.259Z', - langs: ['en'], - text: 'and another thing. I have more things to say. I think. I forget :/', - }, - replyCount: 1, - repostCount: 4, - likeCount: 20, - quoteCount: 0, - indexedAt: '2025-04-22T17:03:52.050Z', - viewer: { - threadMuted: false, - embeddingDisabled: false, - }, - labels: [], - }, - }, - { - post: { - uri: 'at://did:plc:fpruhuo22xkm5o7ttr2ktxdo/app.bsky.feed.post/3lng5izl7kc2c', - cid: 'bafyreicsich65s4rq526rek5jmvd6djtcmr7kdavw26rrnf424awgvia7i', - author: { - did: 'did:plc:fpruhuo22xkm5o7ttr2ktxdo', - handle: 'danabra.mov', - displayName: 'dan', - avatar: - 'https://cdn.bsky.app/img/avatar/plain/did:plc:fpruhuo22xkm5o7ttr2ktxdo/bafkreif43mhqajnbnl62u3ezf37g6x22nd762im54thxbil4ga46eugcga@jpeg', - associated: { - chat: { - allowIncoming: 'all', - }, - }, - viewer: { - muted: false, - blockedBy: false, - following: - 'at://did:plc:p2cp5gopk7mgjegy6wadk3ep/app.bsky.graph.follow/3jtdzgbbysa2y', - followedBy: - 'at://did:plc:fpruhuo22xkm5o7ttr2ktxdo/app.bsky.graph.follow/3k7ht6lwu6t2a', - }, - labels: [], - createdAt: '2023-04-08T20:19:22.589Z', - verification: { - verifications: [ - { - issuer: 'did:plc:z72i7hdynmk6r22z27h6tvur', - uri: 'at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.graph.verification/3lndpxompy32z', - isValid: true, - createdAt: '2025-04-21T10:48:53.876Z', - }, - ], - verifiedStatus: 'valid', - trustedVerifierStatus: 'none', - }, - }, - record: { - $type: 'app.bsky.feed.post', - createdAt: '2025-04-22T16:56:34.198Z', - langs: ['en'], - text: 'maybe i should write something about vercel at some point', - }, - replyCount: 10, - repostCount: 1, - likeCount: 84, - quoteCount: 1, - indexedAt: '2025-04-22T16:56:34.356Z', - viewer: { - threadMuted: false, - replyDisabled: false, - embeddingDisabled: false, - }, - labels: [], - threadgate: { - uri: 'at://did:plc:fpruhuo22xkm5o7ttr2ktxdo/app.bsky.feed.threadgate/3lng5izl7kc2c', - cid: 'bafyreic4wpsh5wrmjvbngt7som5436xzjhdnld3mxnkzyhj2i4vh6lpefa', - record: { - $type: 'app.bsky.feed.threadgate', - allow: [ - { - $type: 'app.bsky.feed.threadgate#followerRule', - }, - { - $type: 'app.bsky.feed.threadgate#followingRule', - }, - { - $type: 'app.bsky.feed.threadgate#mentionRule', - }, - ], - createdAt: '2025-04-22T16:56:34.200Z', - hiddenReplies: [], - post: 'at://did:plc:fpruhuo22xkm5o7ttr2ktxdo/app.bsky.feed.post/3lng5izl7kc2c', - }, - lists: [], - }, - }, - }, - { - post: { - uri: 'at://did:plc:77tdak46psveqneyegsdyc7l/app.bsky.feed.post/3lnft75ivlc27', - cid: 'bafyreic24reeweaymcfe6hdsuhmffazdpa5hoqyculxrdp2sr7xkoehgay', - author: { - did: 'did:plc:77tdak46psveqneyegsdyc7l', - handle: 'werd.io', - displayName: 'Ben Werdmuller', - avatar: - 'https://cdn.bsky.app/img/avatar/plain/did:plc:77tdak46psveqneyegsdyc7l/bafkreicoqtayuefjlw73nrx4c7sioc3ujq74uisgbh4ddmuamevjwzt4fu@jpeg', - associated: { - chat: { - allowIncoming: 'following', - }, - }, - viewer: { - muted: false, - blockedBy: false, - }, - labels: [], - createdAt: '2023-03-07T15:40:54.229Z', - }, - record: { - $type: 'app.bsky.feed.post', - createdAt: '2025-04-22T13:52:05.353Z', - langs: ['en'], - text: 'This is obvious, but if people broadly rely on a black box to give them answers that help them understand the world, whoever controls the black box controls those answers and therefore the understanding that comes from them.\n\nOpenness is safety.', - }, - replyCount: 10, - repostCount: 84, - likeCount: 432, - quoteCount: 2, - indexedAt: '2025-04-22T13:52:05.755Z', - viewer: { - threadMuted: false, - embeddingDisabled: false, - }, - labels: [], - }, - }, - */ ], } satisfies AppBskyFeedGetFeed.OutputSchema -export const BOTTOM_BAR_AVI = 'https://bsky.social/about/hero-social-card.webp' +export const BOTTOM_BAR_AVI = + 'https://cdn.bsky.app/img/avatar/plain/did:plc:3jpt2mvvsumj2r7eqk4gzzjz/bafkreibrhptgequemf4anrjxgbf5lpgo6szvjobjcxyvt76ui7jtvebrfa@jpeg' From c1e090e9e3eff4235fe71d494a354c78b341eead Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 23 Apr 2025 15:29:17 -0500 Subject: [PATCH 06/15] Better data --- src/lib/demo.ts | 136 ++++++++++++++++++++++++++++++------------------ 1 file changed, 85 insertions(+), 51 deletions(-) diff --git a/src/lib/demo.ts b/src/lib/demo.ts index 5e09ff0aa0..65ba88e800 100644 --- a/src/lib/demo.ts +++ b/src/lib/demo.ts @@ -11,18 +11,14 @@ export const DEMO_FEED = { feed: [ { post: { - uri: `at://${DID}/app.bsky.feed.post/post1`, - cid: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + uri: 'at://did:plc:pvooorihapc2lf2pijehgrdf/app.bsky.feed.post/3lniysofyll2d', + cid: 'bafyreihwh3wxxme732ylbylhhdyz7ex6t4jtu6s3gjxxvnnh4feddhg3ku', author: { - did: DID, - handle: 'forkedriver.blsky', + did: 'did:plc:pvooorihapc2lf2pijehgrdf', + handle: 'forkedriverband.bsky.social', displayName: 'Forked River Band', - avatar: 'https://bsky.social/about/adi/post_1_avi.jpg', - associated: { - chat: { - allowIncoming: 'following', - }, - }, + avatar: + 'https://cdn.bsky.app/img/avatar/plain/did:plc:pvooorihapc2lf2pijehgrdf/bafkreiarkmzr3wa6ty75qigkkbvtgbler2yiqgfdrupmimy4whcnesu4d4@jpeg', viewer: { muted: false, blockedBy: false, @@ -43,13 +39,42 @@ export const DEMO_FEED = { trustedVerifierStatus: 'none', }, }, + record: { + $type: 'app.bsky.feed.post', + createdAt: POST_1_DATE, + // embed: { + // $type: 'app.bsky.embed.images', + // images: [ + // { + // alt: 'Fake flier for Sebastapol Bluegrass Fest', + // aspectRatio: { + // height: 1350, + // width: 900, + // }, + // image: { + // $type: 'blob', + // ref: { + // $link: + // 'bafkreig7gnirmz5guhhjutf3mqbjjzxzi3w4wvs5qy2gnxma5g3brbaidi', + // }, + // mimeType: 'image/jpeg', + // size: 562871, + // }, + // }, + // ], + // }, + langs: ['en'], + text: 'Sonoma County folks: Come tip your hats our way and see us play new and old tunes at Sebastopol Bluegrass Fest on June 14th.', + }, embed: { $type: 'app.bsky.embed.images#view', images: [ { - thumb: 'https://bsky.social/about/adi/post_1_image.jpg', - fullsize: 'https://bsky.social/about/adi/post_1_image.jpg', - alt: '', + thumb: + 'https://cdn.bsky.app/img/feed_thumbnail/plain/did:plc:pvooorihapc2lf2pijehgrdf/bafkreig7gnirmz5guhhjutf3mqbjjzxzi3w4wvs5qy2gnxma5g3brbaidi@jpeg', + fullsize: + 'https://cdn.bsky.app/img/feed_fullsize/plain/did:plc:pvooorihapc2lf2pijehgrdf/bafkreig7gnirmz5guhhjutf3mqbjjzxzi3w4wvs5qy2gnxma5g3brbaidi@jpeg', + alt: 'Fake flier for Sebastapol Bluegrass Fest', aspectRatio: { height: 1350, width: 900, @@ -57,12 +82,6 @@ export const DEMO_FEED = { }, ], }, - record: { - $type: 'app.bsky.feed.post', - createdAt: POST_1_DATE, - langs: ['en'], - text: 'Sonoma County folks: Come tip your hats our way and see us play new and old tunes at Sebastopol Bluegrass Fest on June 14th.', - }, replyCount: 1, repostCount: 4, likeCount: 18, @@ -77,18 +96,14 @@ export const DEMO_FEED = { }, { post: { - uri: `at://${DID}/app.bsky.feed.post/post2`, - cid: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + uri: 'at://did:plc:fhhqii56ppgyh5qcm2b3mokf/app.bsky.feed.post/3lnizc7fug52c', + cid: 'bafyreienuabsr55rycirdf4ewue5tjcseg5lzqompcsh2brqzag6hvxllm', author: { - did: DID, - handle: 'dinh-designs.blsky', + did: 'did:plc:fhhqii56ppgyh5qcm2b3mokf', + handle: 'dinh-designs.bsky.social', displayName: 'Dinh Designs', - avatar: 'https://bsky.social/about/adi/post_2_avi.jpg', - associated: { - chat: { - allowIncoming: 'following', - }, - }, + avatar: + 'https://cdn.bsky.app/img/avatar/plain/did:plc:fhhqii56ppgyh5qcm2b3mokf/bafkreidou2xiwmwgq4rz7jj3myyhtvvcd47v5rrmj5xpp5w3nst6tmeoxi@jpeg', viewer: { muted: false, blockedBy: false, @@ -97,13 +112,42 @@ export const DEMO_FEED = { labels: [], createdAt: POST_2_DATE, }, + record: { + $type: 'app.bsky.feed.post', + createdAt: POST_2_DATE, + // embed: { + // $type: 'app.bsky.embed.images', + // images: [ + // { + // alt: 'Placeholder image of interior design', + // aspectRatio: { + // height: 872, + // width: 598, + // }, + // image: { + // $type: 'blob', + // ref: { + // $link: + // 'bafkreidcjc6bjb4jjjejruin5cldhj5zovsuu4tydulenyprneziq5rfeu', + // }, + // mimeType: 'image/jpeg', + // size: 296003, + // }, + // }, + // ], + // }, + langs: ['en'], + text: 'Details from our install at the Lucas residence in Joshua Tree. We populated the space with rich, earthy tones and locally-sourced materials to suit the landscape.', + }, embed: { $type: 'app.bsky.embed.images#view', images: [ { - thumb: 'https://bsky.social/about/adi/post_2_image.jpg', - fullsize: 'https://bsky.social/about/adi/post_2_image.jpg', - alt: '', + thumb: + 'https://cdn.bsky.app/img/feed_thumbnail/plain/did:plc:fhhqii56ppgyh5qcm2b3mokf/bafkreidcjc6bjb4jjjejruin5cldhj5zovsuu4tydulenyprneziq5rfeu@jpeg', + fullsize: + 'https://cdn.bsky.app/img/feed_fullsize/plain/did:plc:fhhqii56ppgyh5qcm2b3mokf/bafkreidcjc6bjb4jjjejruin5cldhj5zovsuu4tydulenyprneziq5rfeu@jpeg', + alt: 'Placeholder image of interior design', aspectRatio: { height: 872, width: 598, @@ -111,12 +155,6 @@ export const DEMO_FEED = { }, ], }, - record: { - $type: 'app.bsky.feed.post', - createdAt: POST_2_DATE, - langs: ['en'], - text: 'Details from our install at the Lucas residence in Joshua Tree. We populated the space with rich, earthy tones and locally-sourced materials to suit the landscape.', - }, replyCount: 3, repostCount: 1, likeCount: 4, @@ -131,24 +169,20 @@ export const DEMO_FEED = { }, { post: { - uri: `at://${DID}/app.bsky.feed.post/post3`, - cid: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + uri: 'at://did:plc:h7fwnfejmmifveeea5eyxgkc/app.bsky.feed.post/3lnizna3g4f2t', + cid: 'bafyreiepn7obmlshliori4j34texpaukrqkyyu7cq6nmpzk4lkis7nqeae', author: { - did: DID, - handle: 'visionprofan.blsky', - displayName: 'Visionary', + did: 'did:plc:h7fwnfejmmifveeea5eyxgkc', + handle: 'visionprofan.bsky.social', + displayName: 'Sammy', avatar: - 'https://cdn.bsky.app/img/avatar/plain/did:plc:p2cp5gopk7mgjegy6wadk3ep/bafkreiaqsy36o6lpbpnonb4n46cvntfs6zoxbav35raix2sxhqgopxcjge@jpeg', - associated: { - chat: { - allowIncoming: 'following', - }, - }, + 'https://cdn.bsky.app/img/avatar/plain/did:plc:h7fwnfejmmifveeea5eyxgkc/bafkreia4fxcfoiny44sc5nujs7fpqxcxustuzepovxpsrq3e5cibcmscz4@jpeg', viewer: { muted: false, blockedBy: false, following: `at://${DID}/app.bsky.graph.follow/post3`, }, + labels: [], createdAt: POST_3_DATE, }, record: { @@ -160,7 +194,7 @@ export const DEMO_FEED = { replyCount: 11, repostCount: 97, likeCount: 399, - quoteCount: 3, + quoteCount: 0, indexedAt: POST_3_DATE, viewer: { threadMuted: false, @@ -173,4 +207,4 @@ export const DEMO_FEED = { } satisfies AppBskyFeedGetFeed.OutputSchema export const BOTTOM_BAR_AVI = - 'https://cdn.bsky.app/img/avatar/plain/did:plc:3jpt2mvvsumj2r7eqk4gzzjz/bafkreibrhptgequemf4anrjxgbf5lpgo6szvjobjcxyvt76ui7jtvebrfa@jpeg' + 'https://cdn.bsky.app/img/avatar/plain/did:plc:p2cp5gopk7mgjegy6wadk3ep/bafkreiaqsy36o6lpbpnonb4n46cvntfs6zoxbav35raix2sxhqgopxcjge@jpeg' From 6a8dd353ee26b2f9f53fc5623829241c4a9a7e2a Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 23 Apr 2025 15:54:29 -0500 Subject: [PATCH 07/15] Update bottom bar avi --- src/lib/demo.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/demo.ts b/src/lib/demo.ts index 65ba88e800..ad6beec8e2 100644 --- a/src/lib/demo.ts +++ b/src/lib/demo.ts @@ -207,4 +207,4 @@ export const DEMO_FEED = { } satisfies AppBskyFeedGetFeed.OutputSchema export const BOTTOM_BAR_AVI = - 'https://cdn.bsky.app/img/avatar/plain/did:plc:p2cp5gopk7mgjegy6wadk3ep/bafkreiaqsy36o6lpbpnonb4n46cvntfs6zoxbav35raix2sxhqgopxcjge@jpeg' + 'https://cdn.bsky.app/img/avatar/plain/did:plc:nz5fbenzdvllhkgqblvuobbx/bafkreifiodbgqfmn3n36xum2qjjzfbgnvnyhk54tlul6hpa5d7p5q36jd4@jpeg' From 9a7f6ad638772e33f3a28d4bf8d2beef1a1a7501 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 23 Apr 2025 18:30:25 -0500 Subject: [PATCH 08/15] Moar demo --- src/lib/demo.ts | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/src/lib/demo.ts b/src/lib/demo.ts index ad6beec8e2..377d8236a5 100644 --- a/src/lib/demo.ts +++ b/src/lib/demo.ts @@ -17,8 +17,7 @@ export const DEMO_FEED = { did: 'did:plc:pvooorihapc2lf2pijehgrdf', handle: 'forkedriverband.bsky.social', displayName: 'Forked River Band', - avatar: - 'https://cdn.bsky.app/img/avatar/plain/did:plc:pvooorihapc2lf2pijehgrdf/bafkreiarkmzr3wa6ty75qigkkbvtgbler2yiqgfdrupmimy4whcnesu4d4@jpeg', + avatar: 'https://bsky.social/about/adi/post_1_avi.jpg', viewer: { muted: false, blockedBy: false, @@ -70,10 +69,8 @@ export const DEMO_FEED = { $type: 'app.bsky.embed.images#view', images: [ { - thumb: - 'https://cdn.bsky.app/img/feed_thumbnail/plain/did:plc:pvooorihapc2lf2pijehgrdf/bafkreig7gnirmz5guhhjutf3mqbjjzxzi3w4wvs5qy2gnxma5g3brbaidi@jpeg', - fullsize: - 'https://cdn.bsky.app/img/feed_fullsize/plain/did:plc:pvooorihapc2lf2pijehgrdf/bafkreig7gnirmz5guhhjutf3mqbjjzxzi3w4wvs5qy2gnxma5g3brbaidi@jpeg', + thumb: 'https://bsky.social/about/adi/post_1_image.jpg', + fullsize: 'https://bsky.social/about/adi/post_1_image.jpg', alt: 'Fake flier for Sebastapol Bluegrass Fest', aspectRatio: { height: 1350, @@ -102,8 +99,7 @@ export const DEMO_FEED = { did: 'did:plc:fhhqii56ppgyh5qcm2b3mokf', handle: 'dinh-designs.bsky.social', displayName: 'Dinh Designs', - avatar: - 'https://cdn.bsky.app/img/avatar/plain/did:plc:fhhqii56ppgyh5qcm2b3mokf/bafkreidou2xiwmwgq4rz7jj3myyhtvvcd47v5rrmj5xpp5w3nst6tmeoxi@jpeg', + avatar: 'https://bsky.social/about/adi/post_2_avi.jpg', viewer: { muted: false, blockedBy: false, @@ -143,10 +139,8 @@ export const DEMO_FEED = { $type: 'app.bsky.embed.images#view', images: [ { - thumb: - 'https://cdn.bsky.app/img/feed_thumbnail/plain/did:plc:fhhqii56ppgyh5qcm2b3mokf/bafkreidcjc6bjb4jjjejruin5cldhj5zovsuu4tydulenyprneziq5rfeu@jpeg', - fullsize: - 'https://cdn.bsky.app/img/feed_fullsize/plain/did:plc:fhhqii56ppgyh5qcm2b3mokf/bafkreidcjc6bjb4jjjejruin5cldhj5zovsuu4tydulenyprneziq5rfeu@jpeg', + thumb: 'https://bsky.social/about/adi/post_2_image.jpg', + fullsize: 'https://bsky.social/about/adi/post_2_image.jpg', alt: 'Placeholder image of interior design', aspectRatio: { height: 872, @@ -174,9 +168,8 @@ export const DEMO_FEED = { author: { did: 'did:plc:h7fwnfejmmifveeea5eyxgkc', handle: 'visionprofan.bsky.social', - displayName: 'Sammy', - avatar: - 'https://cdn.bsky.app/img/avatar/plain/did:plc:h7fwnfejmmifveeea5eyxgkc/bafkreia4fxcfoiny44sc5nujs7fpqxcxustuzepovxpsrq3e5cibcmscz4@jpeg', + displayName: 'Sebastian', + avatar: 'https://bsky.social/about/adi/user_avi.jpg', viewer: { muted: false, blockedBy: false, @@ -206,5 +199,4 @@ export const DEMO_FEED = { ], } satisfies AppBskyFeedGetFeed.OutputSchema -export const BOTTOM_BAR_AVI = - 'https://cdn.bsky.app/img/avatar/plain/did:plc:nz5fbenzdvllhkgqblvuobbx/bafkreifiodbgqfmn3n36xum2qjjzfbgnvnyhk54tlul6hpa5d7p5q36jd4@jpeg' +export const BOTTOM_BAR_AVI = 'https://bsky.social/about/adi/user_avi.jpg' From ba002d82528993e1aff80101d63b4ae09a82141b Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Thu, 24 Apr 2025 09:31:04 -0700 Subject: [PATCH 09/15] Tune spacing for demo mode --- src/view/com/util/post-embeds/index.tsx | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/view/com/util/post-embeds/index.tsx b/src/view/com/util/post-embeds/index.tsx index 6f5f9d3ab9..812ba3b600 100644 --- a/src/view/com/util/post-embeds/index.tsx +++ b/src/view/com/util/post-embeds/index.tsx @@ -1,12 +1,12 @@ import React from 'react' import { InteractionManager, - StyleProp, + type StyleProp, StyleSheet, View, - ViewStyle, + type ViewStyle, } from 'react-native' -import {MeasuredDimensions, runOnJS, runOnUI} from 'react-native-reanimated' +import {type MeasuredDimensions, runOnJS, runOnUI} from 'react-native-reanimated' import {Image} from 'expo-image' import { AppBskyEmbedExternal, @@ -18,10 +18,10 @@ import { AppBskyGraphDefs, moderateFeedGenerator, moderateUserList, - ModerationDecision, + type ModerationDecision, } from '@atproto/api' -import {HandleRef, measureHandle} from '#/lib/hooks/useHandleRef' +import {type HandleRef, measureHandle} from '#/lib/hooks/useHandleRef' import {usePalette} from '#/lib/hooks/usePalette' import {useLightboxControls} from '#/state/lightbox' import {useModerationOpts} from '#/state/preferences/moderation-opts' @@ -29,8 +29,9 @@ import {FeedSourceCard} from '#/view/com/feeds/FeedSourceCard' import {atoms as a, useTheme} from '#/alf' import * as ListCard from '#/components/ListCard' import {Embed as StarterPackCard} from '#/components/StarterPack/StarterPackCard' +import {useDemoMode} from '#/storage/hooks/demo-mode' import {ContentHider} from '../../../../components/moderation/ContentHider' -import {Dimensions} from '../../lightbox/ImageViewing/@types' +import {type Dimensions} from '../../lightbox/ImageViewing/@types' import {AutoSizedImage} from '../images/AutoSizedImage' import {ImageLayoutGrid} from '../images/ImageLayoutGrid' import {ExternalLinkEmbed} from './ExternalLinkEmbed' @@ -64,6 +65,7 @@ export function PostEmbeds({ viewContext?: PostEmbedViewContext }) { const {openLightbox} = useLightboxControls() + const [demoMode] = useDemoMode() // quote post with media // = @@ -178,7 +180,13 @@ export function PostEmbeds({ const image = images[0] return ( - + Date: Fri, 25 Apr 2025 10:42:35 -0700 Subject: [PATCH 10/15] Updated demo copy --- src/lib/demo.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/demo.ts b/src/lib/demo.ts index 377d8236a5..8e3b16622d 100644 --- a/src/lib/demo.ts +++ b/src/lib/demo.ts @@ -63,7 +63,7 @@ export const DEMO_FEED = { // ], // }, langs: ['en'], - text: 'Sonoma County folks: Come tip your hats our way and see us play new and old tunes at Sebastopol Bluegrass Fest on June 14th.', + text: 'Sonoma County folks: Come tip your hats our way and see us play new and old bluegrass tunes at Sebastopol Solstice Fest on June 20th.', }, embed: { $type: 'app.bsky.embed.images#view', @@ -98,7 +98,7 @@ export const DEMO_FEED = { author: { did: 'did:plc:fhhqii56ppgyh5qcm2b3mokf', handle: 'dinh-designs.bsky.social', - displayName: 'Dinh Designs', + displayName: 'Rich Dinh Designs', avatar: 'https://bsky.social/about/adi/post_2_avi.jpg', viewer: { muted: false, From 7b245935eaa7b3ba8f051ea777ea7e5fcbc95813 Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Fri, 25 Apr 2025 10:49:10 -0700 Subject: [PATCH 11/15] Remove demo-mode spacing tweak --- src/view/com/util/post-embeds/index.tsx | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/view/com/util/post-embeds/index.tsx b/src/view/com/util/post-embeds/index.tsx index 812ba3b600..431baa2b22 100644 --- a/src/view/com/util/post-embeds/index.tsx +++ b/src/view/com/util/post-embeds/index.tsx @@ -6,7 +6,11 @@ import { View, type ViewStyle, } from 'react-native' -import {type MeasuredDimensions, runOnJS, runOnUI} from 'react-native-reanimated' +import { + type MeasuredDimensions, + runOnJS, + runOnUI, +} from 'react-native-reanimated' import {Image} from 'expo-image' import { AppBskyEmbedExternal, @@ -29,7 +33,6 @@ import {FeedSourceCard} from '#/view/com/feeds/FeedSourceCard' import {atoms as a, useTheme} from '#/alf' import * as ListCard from '#/components/ListCard' import {Embed as StarterPackCard} from '#/components/StarterPack/StarterPackCard' -import {useDemoMode} from '#/storage/hooks/demo-mode' import {ContentHider} from '../../../../components/moderation/ContentHider' import {type Dimensions} from '../../lightbox/ImageViewing/@types' import {AutoSizedImage} from '../images/AutoSizedImage' @@ -65,7 +68,6 @@ export function PostEmbeds({ viewContext?: PostEmbedViewContext }) { const {openLightbox} = useLightboxControls() - const [demoMode] = useDemoMode() // quote post with media // = @@ -180,13 +182,7 @@ export function PostEmbeds({ const image = images[0] return ( - + Date: Fri, 25 Apr 2025 11:51:33 -0700 Subject: [PATCH 12/15] Update third post in demo --- src/lib/demo.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib/demo.ts b/src/lib/demo.ts index 8e3b16622d..5ead62c9d3 100644 --- a/src/lib/demo.ts +++ b/src/lib/demo.ts @@ -167,9 +167,9 @@ export const DEMO_FEED = { cid: 'bafyreiepn7obmlshliori4j34texpaukrqkyyu7cq6nmpzk4lkis7nqeae', author: { did: 'did:plc:h7fwnfejmmifveeea5eyxgkc', - handle: 'visionprofan.bsky.social', - displayName: 'Sebastian', - avatar: 'https://bsky.social/about/adi/user_avi.jpg', + handle: 'rodyalbuerne.bsky.social', + displayName: 'Rody Albuerne', + avatar: 'https://bsky.social/about/adi/post_3_avi.jpg', viewer: { muted: false, blockedBy: false, @@ -182,7 +182,7 @@ export const DEMO_FEED = { $type: 'app.bsky.feed.post', createdAt: POST_3_DATE, langs: ['en'], - text: 'Just got my Vision Pro! 🤯\n\nAny recommendations for apps to try out?', + text: 'Tinkering with the basics of traditional wooden joinery in my shop lately. Starting small with this ox, made using simple mortise and tenon joints.', }, replyCount: 11, repostCount: 97, From 544f7befe0f7d3e61fb03365ec588a2ab3c5a17a Mon Sep 17 00:00:00 2001 From: hailey Date: Fri, 2 May 2025 13:23:39 -0700 Subject: [PATCH 13/15] bump it bop it upgrade it (rn 79/expo 53) (#8281) * basic bumps * more tweaking * fix rn patch * fix crop picker patch * fix media library patch * rm unnecessary patch * fix notifications patch * update bottomsheet * Update withAppDelegateReferrer.js * Delete withNoBundleCompression.js * rm withNoBundleCompression plugin * rm findLast shim * metro package exports is enabled by default * update react/react-dom/react-compiler * fix reanimated issue * vendor expo-ized emoji popup * fix types * hackfix view full thread * Update EmojiPickerModule.podspec * more upgrades * fix multiformats package version * add baseurl * bump mmkv * bumps * update react-keyed-flatten-children * bump locale packages * fix emoji picker dark mode * rn upgrades * Revert "bump locale packages" This reverts commit fc82f0f173032127dd7c18ed0316ae26f53db51d. * upgrade testing-library * rm test renderer * update patch name minors * rm findNodeHandle from tabbar * only do scrollview tag thing on ios * disable package exports * update expo notifications handler * memoize emoji picker styles * fix tests, mock multiformats * bump some dev deps with RC versions * completely rearchitect toasts * rm logs * layout animation config for composer footer * disable autolinking for patched libs * undo lingui changes * version bump from release candidate to 0.1 * update atproto deps * rm @did-plc/server * fix key issue (maybe) * move URL polyfill to the polyfill file * fix yarn lock * upgrade to 53.0.3 * reanimated layout anim bug patch * workletize a function that wasn't getting autoworkletized anymore (#8309) * bump to expo 53.0.4 * bump RN to 0.79.2 * fix yarn lock ci * Revert "completely rearchitect toasts" This reverts commit 2e2fcaeeed527580a6c485718544b85e8b4f52b9. * final upgrades * chore: cleanup yarn lock * prettier --------- Co-authored-by: Samuel Newman --- __mocks__/multiformats/cid.js | 3 + __mocks__/multiformats/hashes/hasher.js | 7 + __tests__/lib/string.test.ts | 4 +- app.config.js | 3 +- babel.config.js | 6 +- docs/build.md | 7 +- metro.config.js | 11 +- .../modules/bottomsheet/BottomSheetView.kt | 3 + .../bottomsheet/DialogRootViewGroup.kt | 14 +- .../ios/ExpoBlueskyGifView.podspec | 2 +- modules/expo-emoji-picker/LICENSE | 9 + modules/expo-emoji-picker/README.md | 3 + .../expo-emoji-picker/android/build.gradle | 46 + .../android/src/main/AndroidManifest.xml | 2 + .../modules/emojipicker/EmojiPickerModule.kt | 15 + .../emojipicker/EmojiPickerModuleView.kt | 40 + .../expo-emoji-picker/expo-module.config.json | 9 + modules/expo-emoji-picker/index.ts | 3 + .../ios/EmojiPickerModule.podspec | 25 + .../ios/EmojiPickerModule.swift | 11 + .../ios/EmojiPickerView.swift | 30 + .../src/EmojiPicker.android.tsx | 28 + modules/expo-emoji-picker/src/EmojiPicker.tsx | 15 + .../src/EmojiPickerModule.ts | 5 + .../src/EmojiPickerModule.types.ts | 20 + .../expo-emoji-picker/src/EmojiPickerView.tsx | 21 + .../ios/ExpoScrollForwarderView.swift | 43 +- .../src/ExpoScrollForwarder.types.ts | 2 - .../src/ExpoScrollForwarderView.ios.tsx | 3 +- .../src/ExpoScrollForwarderView.tsx | 4 +- package.json | 156 +- ...14.0.1.patch => expo-haptics+14.1.4.patch} | 0 ...14.0.0.md => expo-haptics+14.1.4.patch.md} | 0 patches/expo-image-manipulator+13.0.6.patch | 101 - ....patch => expo-media-library+17.1.6.patch} | 22 +- ...3.patch => expo-modules-core+2.3.12.patch} | 0 ...2.md => expo-modules-core+2.3.12.patch.md} | 0 patches/expo-notifications+0.29.14.patch | 169 - patches/expo-notifications+0.31.1.patch | 992 ++++++ ....md => expo-notifications+0.31.1.patch.md} | 0 ....27.4.patch => expo-updates+0.28.12.patch} | 0 ...patch.md => expo-updates+0.28.12.patch.md} | 0 patches/react-native+0.76.9.patch | 366 -- patches/react-native+0.79.2.patch | 119 + ....patch.md => react-native+0.79.2.patch.md} | 4 - ...react-native-gesture-handler+2.25.0.patch} | 0 ...act-native-image-crop-picker+0.42.0.patch} | 19 +- patches/react-native-reanimated+3.17.5.patch | 44 + ...0.patch => react-native-svg+15.11.2.patch} | 0 plugins/withAppDelegateReferrer.js | 46 +- plugins/withNoBundleCompression.js | 70 - src/App.native.tsx | 1 - src/alf/atoms.ts | 4 +- src/alf/typography.tsx | 14 +- .../StarterPack/ProfileStarterPacks.tsx | 3 +- src/components/dms/EmojiPopup.android.tsx | 29 +- src/components/dms/EmojiPopup.tsx | 2 +- src/lib/api/index.ts | 30 +- src/lib/hooks/useDraggableScrollView.ts | 8 +- src/lib/hooks/useNotificationHandler.ts | 13 +- src/lib/strings/starter-pack.ts | 2 +- src/platform/polyfills.ts | 5 +- src/platform/polyfills.web.ts | 5 +- src/screens/Profile/Sections/Feed.tsx | 4 +- src/screens/Profile/Sections/Labels.tsx | 4 +- src/view/com/composer/Composer.tsx | 74 +- src/view/com/composer/ComposerReplyTo.tsx | 4 +- src/view/com/feeds/ProfileFeedgens.tsx | 4 +- src/view/com/lightbox/ImageViewing/index.tsx | 18 +- src/view/com/lists/ProfileLists.tsx | 4 +- src/view/com/pager/DraggableScrollView.tsx | 23 +- src/view/com/pager/TabBar.tsx | 29 +- src/view/com/pager/TabBar.web.tsx | 8 +- src/view/com/posts/ViewFullThread.tsx | 7 +- src/view/com/util/Toast.tsx | 2 +- src/view/com/util/Toast.web.tsx | 7 +- .../com/util/forms/NativeDropdown.web.tsx | 3 +- .../com/util/load-latest/LoadLatestBtn.tsx | 5 +- src/view/shell/bottom-bar/BottomBarStyles.tsx | 5 +- src/view/shell/desktop/LeftNav.tsx | 6 +- src/view/shell/index.web.tsx | 6 +- tsconfig.json | 9 +- yarn.lock | 3046 +++++++---------- 83 files changed, 3006 insertions(+), 2880 deletions(-) create mode 100644 __mocks__/multiformats/cid.js create mode 100644 __mocks__/multiformats/hashes/hasher.js create mode 100644 modules/expo-emoji-picker/LICENSE create mode 100644 modules/expo-emoji-picker/README.md create mode 100644 modules/expo-emoji-picker/android/build.gradle create mode 100644 modules/expo-emoji-picker/android/src/main/AndroidManifest.xml create mode 100644 modules/expo-emoji-picker/android/src/main/java/expo/community/modules/emojipicker/EmojiPickerModule.kt create mode 100644 modules/expo-emoji-picker/android/src/main/java/expo/community/modules/emojipicker/EmojiPickerModuleView.kt create mode 100644 modules/expo-emoji-picker/expo-module.config.json create mode 100644 modules/expo-emoji-picker/index.ts create mode 100644 modules/expo-emoji-picker/ios/EmojiPickerModule.podspec create mode 100644 modules/expo-emoji-picker/ios/EmojiPickerModule.swift create mode 100644 modules/expo-emoji-picker/ios/EmojiPickerView.swift create mode 100644 modules/expo-emoji-picker/src/EmojiPicker.android.tsx create mode 100644 modules/expo-emoji-picker/src/EmojiPicker.tsx create mode 100644 modules/expo-emoji-picker/src/EmojiPickerModule.ts create mode 100644 modules/expo-emoji-picker/src/EmojiPickerModule.types.ts create mode 100644 modules/expo-emoji-picker/src/EmojiPickerView.tsx rename patches/{expo-haptics+14.0.1.patch => expo-haptics+14.1.4.patch} (100%) rename patches/{expo-haptics+14.0.0.md => expo-haptics+14.1.4.patch.md} (100%) delete mode 100644 patches/expo-image-manipulator+13.0.6.patch rename patches/{expo-media-library+17.0.6.patch => expo-media-library+17.1.6.patch} (50%) rename patches/{expo-modules-core+2.2.3.patch => expo-modules-core+2.3.12.patch} (100%) rename patches/{expo-modules-core+2.1.2.md => expo-modules-core+2.3.12.patch.md} (100%) delete mode 100644 patches/expo-notifications+0.29.14.patch create mode 100644 patches/expo-notifications+0.31.1.patch rename patches/{expo-notifications+0.29.11.patch.md => expo-notifications+0.31.1.patch.md} (100%) rename patches/{expo-updates+0.27.4.patch => expo-updates+0.28.12.patch} (100%) rename patches/{expo-updates+0.26.10.patch.md => expo-updates+0.28.12.patch.md} (100%) delete mode 100644 patches/react-native+0.76.9.patch create mode 100644 patches/react-native+0.79.2.patch rename patches/{react-native+0.76.6.patch.md => react-native+0.79.2.patch.md} (84%) rename patches/{react-native-gesture-handler+2.20.2.patch => react-native-gesture-handler+2.25.0.patch} (100%) rename patches/{react-native-image-crop-picker+0.41.6.patch => react-native-image-crop-picker+0.42.0.patch} (83%) create mode 100644 patches/react-native-reanimated+3.17.5.patch rename patches/{react-native-svg+15.8.0.patch => react-native-svg+15.11.2.patch} (100%) delete mode 100644 plugins/withNoBundleCompression.js diff --git a/__mocks__/multiformats/cid.js b/__mocks__/multiformats/cid.js new file mode 100644 index 0000000000..788505c189 --- /dev/null +++ b/__mocks__/multiformats/cid.js @@ -0,0 +1,3 @@ +export const CID = jest.fn().mockImplementation(() => { + return {} +}) diff --git a/__mocks__/multiformats/hashes/hasher.js b/__mocks__/multiformats/hashes/hasher.js new file mode 100644 index 0000000000..a525f1310c --- /dev/null +++ b/__mocks__/multiformats/hashes/hasher.js @@ -0,0 +1,7 @@ +export const from = jest.fn().mockImplementation(() => { + return { + digest: jest.fn().mockImplementation(() => { + return Promise.resolve('') + }), + } +}) diff --git a/__tests__/lib/string.test.ts b/__tests__/lib/string.test.ts index e212ef5c9b..b018da2361 100644 --- a/__tests__/lib/string.test.ts +++ b/__tests__/lib/string.test.ts @@ -1,11 +1,11 @@ import {RichText} from '@atproto/api' -import {parseEmbedPlayerFromUrl} from 'lib/strings/embed-player' +import {parseEmbedPlayerFromUrl} from '#/lib/strings/embed-player' import { createStarterPackGooglePlayUri, createStarterPackLinkFromAndroidReferrer, parseStarterPackUri, -} from 'lib/strings/starter-pack' +} from '#/lib/strings/starter-pack' import {cleanError} from '../../src/lib/strings/errors' import {createFullHandle, makeValidHandle} from '../../src/lib/strings/handles' import {enforceLen} from '../../src/lib/strings/helpers' diff --git a/app.config.js b/app.config.js index 0e30313294..dae8ca38cc 100644 --- a/app.config.js +++ b/app.config.js @@ -193,6 +193,7 @@ module.exports = function (_config) { plugins: [ 'expo-video', 'expo-localization', + 'expo-web-browser', [ 'react-native-edge-to-edge', {android: {enforceNavigationBarContrast: false}}, @@ -242,10 +243,8 @@ module.exports = function (_config) { './plugins/withAndroidStylesAccentColorPlugin.js', './plugins/withAndroidDayNightThemePlugin.js', './plugins/withAndroidNoJitpackPlugin.js', - './plugins/withNoBundleCompression.js', './plugins/shareExtension/withShareExtensions.js', './plugins/notificationsExtension/withNotificationsExtension.js', - './plugins/withAppDelegateReferrer.js', [ 'expo-font', { diff --git a/babel.config.js b/babel.config.js index ac872648fe..43e7eb54f3 100644 --- a/babel.config.js +++ b/babel.config.js @@ -17,7 +17,7 @@ module.exports = function (api) { ], plugins: [ 'macros', - ['babel-plugin-react-compiler', {target: '18'}], + ['babel-plugin-react-compiler', {target: '19'}], [ 'module:react-native-dotenv', { @@ -37,10 +37,6 @@ module.exports = function (api) { alias: { // This needs to be mirrored in tsconfig.json '#': './src', - lib: './src/lib', - platform: './src/platform', - state: './src/state', - view: './src/view', crypto: './src/platform/crypto.ts', }, }, diff --git a/docs/build.md b/docs/build.md index 7a29ab3553..7817dd0957 100644 --- a/docs/build.md +++ b/docs/build.md @@ -15,7 +15,7 @@ This is NOT required when developing for web. - Set up your environment [using the expo instructions](https://docs.expo.dev/guides/local-app-development/). - make sure that the JAVA_HOME points to the zulu-17 directory in your `.zshrc` or `.bashrc` file: `export JAVA_HOME=/Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home`. DO NOT use another JDK or you will encounter build errors. -- If you're running macOS, make sure you are running the correct versions of Ruby and Cocoapods:- +- If you're running macOS, make sure you are running the correct versions of Ruby and Cocoapods:- - If you are using Apple Silicon and this is the first time you are building for RN 0.74+, you may need to run: - `arch -arm64 brew install llvm` - `sudo gem install ffi` @@ -33,7 +33,7 @@ This is NOT required when developing for web. - After initial setup: - Copy `google-services.json.example` to `google-services.json` or provide your own `google-services.json`. (A real firebase project is NOT required) - `npx expo prebuild` -> you will also need to run this anytime `app.json` or native `package.json` deps change - + ### Running the Native App - iOS: `yarn ios` @@ -162,6 +162,9 @@ See [testing.md](./testing.md). `./platform/polyfills.*.ts` adds polyfills to the environment. Currently, this includes: - TextEncoder / TextDecoder +- react-native-url-polyfill +- Array#findLast (on web) +- atob (on native) ### Sentry sourcemaps diff --git a/metro.config.js b/metro.config.js index b180813363..dcdead3f5d 100644 --- a/metro.config.js +++ b/metro.config.js @@ -16,22 +16,21 @@ if (process.env.BSKY_PROFILE) { cfg.resolver.assetExts = [...cfg.resolver.assetExts, 'woff2'] +// Enabled by default in RN 0.79+, but this breaks Lingui + others +cfg.resolver.unstable_enablePackageExports = false + cfg.resolver.resolveRequest = (context, moduleName, platform) => { // HACK: manually resolve a few packages that use `exports` in `package.json`. // A proper solution is to enable `unstable_enablePackageExports` but this needs careful testing. if (moduleName.startsWith('multiformats/hashes/hasher')) { return context.resolveRequest( context, - 'multiformats/dist/src/hashes/hasher', + 'multiformats/cjs/src/hashes/hasher', platform, ) } if (moduleName.startsWith('multiformats/cid')) { - return context.resolveRequest( - context, - 'multiformats/dist/src/cid', - platform, - ) + return context.resolveRequest(context, 'multiformats/cjs/src/cid', platform) } if (moduleName === '@ipld/dag-cbor') { return context.resolveRequest(context, '@ipld/dag-cbor/src', platform) diff --git a/modules/bottom-sheet/android/src/main/java/expo/modules/bottomsheet/BottomSheetView.kt b/modules/bottom-sheet/android/src/main/java/expo/modules/bottomsheet/BottomSheetView.kt index 5df163b640..31eb739a66 100644 --- a/modules/bottom-sheet/android/src/main/java/expo/modules/bottomsheet/BottomSheetView.kt +++ b/modules/bottom-sheet/android/src/main/java/expo/modules/bottomsheet/BottomSheetView.kt @@ -317,6 +317,9 @@ class BottomSheetView( // View overrides to pass to DialogRootViewGroup instead override fun dispatchProvideStructure(structure: ViewStructure?) { + if (structure == null) { + return + } dialogRootViewGroup.dispatchProvideStructure(structure) } diff --git a/modules/bottom-sheet/android/src/main/java/expo/modules/bottomsheet/DialogRootViewGroup.kt b/modules/bottom-sheet/android/src/main/java/expo/modules/bottomsheet/DialogRootViewGroup.kt index c022924e99..4b02bae9f8 100644 --- a/modules/bottom-sheet/android/src/main/java/expo/modules/bottomsheet/DialogRootViewGroup.kt +++ b/modules/bottom-sheet/android/src/main/java/expo/modules/bottomsheet/DialogRootViewGroup.kt @@ -139,19 +139,7 @@ class DialogRootViewGroup( return super.onHoverEvent(event) } - @Deprecated("Deprecated in Java") - override fun onChildStartedNativeGesture(ev: MotionEvent?) { - eventDispatcher?.let { - if (ev != null) { - jSTouchDispatcher.onChildStartedNativeGesture(ev, it) - } - } - } - - override fun onChildStartedNativeGesture( - childView: View, - ev: MotionEvent, - ) { + override fun onChildStartedNativeGesture(childView: View?, ev: MotionEvent) { eventDispatcher?.let { jSTouchDispatcher.onChildStartedNativeGesture(ev, it) } jSPointerDispatcher?.onChildStartedNativeGesture(childView, ev, eventDispatcher) } diff --git a/modules/expo-bluesky-gif-view/ios/ExpoBlueskyGifView.podspec b/modules/expo-bluesky-gif-view/ios/ExpoBlueskyGifView.podspec index 352812640b..7640a5fc7c 100644 --- a/modules/expo-bluesky-gif-view/ios/ExpoBlueskyGifView.podspec +++ b/modules/expo-bluesky-gif-view/ios/ExpoBlueskyGifView.podspec @@ -10,7 +10,7 @@ Pod::Spec.new do |s| s.static_framework = true s.dependency 'ExpoModulesCore' - s.dependency 'SDWebImage', '~> 5.19.1' + s.dependency 'SDWebImage', '~> 5.21.0' s.dependency 'SDWebImageWebPCoder', '~> 0.14.6' # Swift/Objective-C compatibility diff --git a/modules/expo-emoji-picker/LICENSE b/modules/expo-emoji-picker/LICENSE new file mode 100644 index 0000000000..aa0254ccbe --- /dev/null +++ b/modules/expo-emoji-picker/LICENSE @@ -0,0 +1,9 @@ +MIT License + +Copyright (c) 2025 Alan Hughes + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/modules/expo-emoji-picker/README.md b/modules/expo-emoji-picker/README.md new file mode 100644 index 0000000000..d2fb3ae050 --- /dev/null +++ b/modules/expo-emoji-picker/README.md @@ -0,0 +1,3 @@ +# expo-emoji-picker + +Based on [react-native-emoji-popup](https://github.com/okwasniewski/react-native-emoji-popup) and [expo-emoji-picker](https://github.com/alanjhughes/expo-emoji-picker) diff --git a/modules/expo-emoji-picker/android/build.gradle b/modules/expo-emoji-picker/android/build.gradle new file mode 100644 index 0000000000..d34288dc79 --- /dev/null +++ b/modules/expo-emoji-picker/android/build.gradle @@ -0,0 +1,46 @@ +apply plugin: 'com.android.library' + +group = 'expo.community.modules.emojipicker' +version = '0.1.0' + +def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle") +apply from: expoModulesCorePlugin +applyKotlinExpoModulesCorePlugin() +useCoreDependencies() +useExpoPublishing() + +// If you want to use the managed Android SDK versions from expo-modules-core, set this to true. +// The Android SDK versions will be bumped from time to time in SDK releases and may introduce breaking changes in your module code. +// Most of the time, you may like to manage the Android SDK versions yourself. +def useManagedAndroidSdkVersions = false +if (useManagedAndroidSdkVersions) { + useDefaultAndroidSdkVersions() +} else { + buildscript { + // Simple helper that allows the root project to override versions declared by this library. + ext.safeExtGet = { prop, fallback -> + rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback + } + } + project.android { + compileSdkVersion safeExtGet("compileSdkVersion", 34) + defaultConfig { + minSdkVersion safeExtGet("minSdkVersion", 21) + targetSdkVersion safeExtGet("targetSdkVersion", 34) + } + } +} + +android { + namespace "expo.community.modules.emojipicker" + defaultConfig { + versionCode 1 + versionName "0.1.0" + } + lintOptions { + abortOnError false + } + dependencies { + implementation "androidx.emoji2:emoji2-emojipicker:1.5.0" + } +} diff --git a/modules/expo-emoji-picker/android/src/main/AndroidManifest.xml b/modules/expo-emoji-picker/android/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..bdae66c8f5 --- /dev/null +++ b/modules/expo-emoji-picker/android/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/modules/expo-emoji-picker/android/src/main/java/expo/community/modules/emojipicker/EmojiPickerModule.kt b/modules/expo-emoji-picker/android/src/main/java/expo/community/modules/emojipicker/EmojiPickerModule.kt new file mode 100644 index 0000000000..ebdc7a35e4 --- /dev/null +++ b/modules/expo-emoji-picker/android/src/main/java/expo/community/modules/emojipicker/EmojiPickerModule.kt @@ -0,0 +1,15 @@ +package expo.community.modules.emojipicker + +import expo.modules.kotlin.modules.Module +import expo.modules.kotlin.modules.ModuleDefinition +import java.net.URL + +class EmojiPickerModule : Module() { + override fun definition() = ModuleDefinition { + Name("EmojiPicker") + + View(EmojiPickerModuleView::class) { + Events("onEmojiSelected") + } + } +} diff --git a/modules/expo-emoji-picker/android/src/main/java/expo/community/modules/emojipicker/EmojiPickerModuleView.kt b/modules/expo-emoji-picker/android/src/main/java/expo/community/modules/emojipicker/EmojiPickerModuleView.kt new file mode 100644 index 0000000000..a6e5a066fe --- /dev/null +++ b/modules/expo-emoji-picker/android/src/main/java/expo/community/modules/emojipicker/EmojiPickerModuleView.kt @@ -0,0 +1,40 @@ +package expo.community.modules.emojipicker + +import android.annotation.SuppressLint +import android.content.Context +import android.content.res.Configuration +import androidx.emoji2.emojipicker.EmojiPickerView +import expo.modules.kotlin.AppContext +import expo.modules.kotlin.viewevent.EventDispatcher +import expo.modules.kotlin.views.ExpoView + + +@SuppressLint("ViewConstructor") +class EmojiPickerModuleView(context: Context, appContext: AppContext) : + ExpoView(context, appContext) { + private var emojiView: EmojiPickerView = EmojiPickerView(context) + private val onEmojiSelected by EventDispatcher() + + init { + setupView() + } + + private fun setupView() { + addView( + emojiView, LayoutParams( + LayoutParams.MATCH_PARENT, + LayoutParams.MATCH_PARENT + ) + ) + + emojiView.setOnEmojiPickedListener { emoji -> + onEmojiSelected(mapOf("emoji" to emoji.emoji)) + } + } + + override fun onConfigurationChanged(newConfig: Configuration?) { + super.onConfigurationChanged(newConfig) + removeView(emojiView) + setupView() + } +} diff --git a/modules/expo-emoji-picker/expo-module.config.json b/modules/expo-emoji-picker/expo-module.config.json new file mode 100644 index 0000000000..7576240d10 --- /dev/null +++ b/modules/expo-emoji-picker/expo-module.config.json @@ -0,0 +1,9 @@ +{ + "platforms": ["apple", "android"], + "apple": { + "modules": ["EmojiPickerModule"] + }, + "android": { + "modules": ["expo.community.modules.emojipicker.EmojiPickerModule"] + } +} diff --git a/modules/expo-emoji-picker/index.ts b/modules/expo-emoji-picker/index.ts new file mode 100644 index 0000000000..a555b730ab --- /dev/null +++ b/modules/expo-emoji-picker/index.ts @@ -0,0 +1,3 @@ +export {default as EmojiPicker} from './src/EmojiPicker' +export {default} from './src/EmojiPickerModule' +export * from './src/EmojiPickerModule.types' diff --git a/modules/expo-emoji-picker/ios/EmojiPickerModule.podspec b/modules/expo-emoji-picker/ios/EmojiPickerModule.podspec new file mode 100644 index 0000000000..e6a982a70e --- /dev/null +++ b/modules/expo-emoji-picker/ios/EmojiPickerModule.podspec @@ -0,0 +1,25 @@ +Pod::Spec.new do |s| + s.name = 'EmojiPickerModule' + s.version = '1.0.0' + s.summary = 'An emoji picker for use in Bluesky' + s.description = 'An emoji picker for use in Bluesky' + s.author = 'alanjhughes' + s.homepage = 'https://github.com/bluesky-social/social-app' + s.platforms = { + :ios => '15.1', + :tvos => '15.1' + } + s.source = { git: '' } + s.swift_version = '5.4' + s.static_framework = true + + s.dependency 'ExpoModulesCore' + s.dependency 'MCEmojiPicker' + + # Swift/Objective-C compatibility + s.pod_target_xcconfig = { + 'DEFINES_MODULE' => 'YES', + } + + s.source_files = "**/*.{h,m,mm,swift,hpp,cpp}" +end diff --git a/modules/expo-emoji-picker/ios/EmojiPickerModule.swift b/modules/expo-emoji-picker/ios/EmojiPickerModule.swift new file mode 100644 index 0000000000..57b6f959a9 --- /dev/null +++ b/modules/expo-emoji-picker/ios/EmojiPickerModule.swift @@ -0,0 +1,11 @@ +import ExpoModulesCore + +public class EmojiPickerModule: Module { + public func definition() -> ModuleDefinition { + Name("EmojiPicker") + + View(EmojiPickerView.self) { + Events("onEmojiSelected") + } + } +} diff --git a/modules/expo-emoji-picker/ios/EmojiPickerView.swift b/modules/expo-emoji-picker/ios/EmojiPickerView.swift new file mode 100644 index 0000000000..65089a2af6 --- /dev/null +++ b/modules/expo-emoji-picker/ios/EmojiPickerView.swift @@ -0,0 +1,30 @@ +import ExpoModulesCore +import WebKit +import MCEmojiPicker + +class EmojiPickerView: ExpoView, MCEmojiPickerDelegate { + let onEmojiSelected = EventDispatcher() + + override func layoutSubviews() { + let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:))) + self.addGestureRecognizer(tapGesture) + } + + @objc func handleTap(_ gesture: UITapGestureRecognizer) { + presentEmojiPicker() + } + + func presentEmojiPicker() { + let emojiPicker = MCEmojiPickerViewController() + let reactRootVC = reactViewController() + emojiPicker.sourceView = self + emojiPicker.delegate = self + reactRootVC?.present(emojiPicker, animated: true) + } + + func didGetEmoji(emoji: String) { + onEmojiSelected([ + "emoji": emoji + ]) + } +} diff --git a/modules/expo-emoji-picker/src/EmojiPicker.android.tsx b/modules/expo-emoji-picker/src/EmojiPicker.android.tsx new file mode 100644 index 0000000000..d8493b72e3 --- /dev/null +++ b/modules/expo-emoji-picker/src/EmojiPicker.android.tsx @@ -0,0 +1,28 @@ +import {useMemo} from 'react' +import {useColorScheme} from 'react-native' + +import {type EmojiPickerViewProps} from './EmojiPickerModule.types' +import EmojiPickerNativeView from './EmojiPickerView' + +const EmojiPicker = ({onEmojiSelected}: EmojiPickerViewProps) => { + const scheme = useColorScheme() + const styles = useMemo( + () => + ({ + flex: 1, + width: '100%', + backgroundColor: scheme === 'dark' ? '#000' : '#fff', + } as const), + [scheme], + ) + + return ( + { + onEmojiSelected(emoji) + }} + style={styles} + /> + ) +} +export default EmojiPicker diff --git a/modules/expo-emoji-picker/src/EmojiPicker.tsx b/modules/expo-emoji-picker/src/EmojiPicker.tsx new file mode 100644 index 0000000000..8fee11df78 --- /dev/null +++ b/modules/expo-emoji-picker/src/EmojiPicker.tsx @@ -0,0 +1,15 @@ +import {type EmojiPickerViewProps} from './EmojiPickerModule.types' +import EmojiPickerNativeView from './EmojiPickerView' + +const EmojiPicker = ({children, onEmojiSelected}: EmojiPickerViewProps) => { + return ( + { + onEmojiSelected(emoji) + }}> + {children} + + ) +} + +export default EmojiPicker diff --git a/modules/expo-emoji-picker/src/EmojiPickerModule.ts b/modules/expo-emoji-picker/src/EmojiPickerModule.ts new file mode 100644 index 0000000000..a5b04e662a --- /dev/null +++ b/modules/expo-emoji-picker/src/EmojiPickerModule.ts @@ -0,0 +1,5 @@ +import {NativeModule, requireNativeModule} from 'expo' + +declare class EmojiPickerModule extends NativeModule {} + +export default requireNativeModule('EmojiPicker') diff --git a/modules/expo-emoji-picker/src/EmojiPickerModule.types.ts b/modules/expo-emoji-picker/src/EmojiPickerModule.types.ts new file mode 100644 index 0000000000..14690a38a6 --- /dev/null +++ b/modules/expo-emoji-picker/src/EmojiPickerModule.types.ts @@ -0,0 +1,20 @@ +import {type ViewProps} from 'react-native' + +export type EmojiSelectionListener = (event: { + nativeEvent: SelectionEvent +}) => void + +export type SelectionEvent = { + emoji: string +} + +export type EmojiPickerViewProps = ViewProps & { + /* + * Callback that will be called when an emoji is selected. + */ + onEmojiSelected: (emoji: string) => void +} + +export type EmojiPickerNativeViewProps = ViewProps & { + onEmojiSelected: EmojiSelectionListener +} diff --git a/modules/expo-emoji-picker/src/EmojiPickerView.tsx b/modules/expo-emoji-picker/src/EmojiPickerView.tsx new file mode 100644 index 0000000000..0dff25fb55 --- /dev/null +++ b/modules/expo-emoji-picker/src/EmojiPickerView.tsx @@ -0,0 +1,21 @@ +import {requireNativeView} from 'expo' +import type * as React from 'react' + +import { + type EmojiPickerNativeViewProps, + type EmojiPickerViewProps, +} from './EmojiPickerModule.types' + +const NativeView: React.ComponentType = + requireNativeView('EmojiPicker') + +export default function EmojiPicker(props: EmojiPickerViewProps) { + return ( + { + props.onEmojiSelected(nativeEvent.emoji) + }} + /> + ) +} diff --git a/modules/expo-scroll-forwarder/ios/ExpoScrollForwarderView.swift b/modules/expo-scroll-forwarder/ios/ExpoScrollForwarderView.swift index 15993ef29e..e6ebef1d33 100644 --- a/modules/expo-scroll-forwarder/ios/ExpoScrollForwarderView.swift +++ b/modules/expo-scroll-forwarder/ios/ExpoScrollForwarderView.swift @@ -9,7 +9,7 @@ class ExpoScrollForwarderView: ExpoView, UIGestureRecognizerDelegate { } } - private var rctScrollView: RCTScrollView? + private var scrollView: UIScrollView? private var rctRefreshCtrl: RCTRefreshControl? private var cancelGestureRecognizers: [UIGestureRecognizer]? private var animTimer: Timer? @@ -68,7 +68,7 @@ class ExpoScrollForwarderView: ExpoView, UIGestureRecognizerDelegate { } @IBAction func callOnPan(_ sender: UIPanGestureRecognizer) { - guard let rctsv = self.rctScrollView, let sv = rctsv.scrollView else { + guard let sv = self.scrollView else { return } @@ -113,7 +113,7 @@ class ExpoScrollForwarderView: ExpoView, UIGestureRecognizerDelegate { } func startDecayAnimation(_ translation: CGFloat, _ velocity: CGFloat) { - guard let sv = self.rctScrollView?.scrollView else { + guard let sv = self.scrollView else { return } @@ -160,32 +160,49 @@ class ExpoScrollForwarderView: ExpoView, UIGestureRecognizerDelegate { return offset } + + private func findScrollView(in view: UIView, foundCount: Int) -> UIScrollView? { + var foundCount = foundCount + if let sv = view as? UIScrollView { return sv } + for child in view.subviews { + if let found = findScrollView(in: child, foundCount: foundCount) { + if foundCount == 1 { + print("found sv: \(found)") +// return found + } else { + print("found sv: \(found)") + foundCount += 1 + } + } + } + return nil + } func tryFindScrollView() { - guard let scrollViewTag = scrollViewTag else { - return - } - // Before we switch to a different scrollview, we always want to remove the cancel gesture recognizer. // Otherwise we might end up with duplicates when we switch back to that scrollview. self.removeCancelGestureRecognizers() + + guard let sv = self.findScrollView(in: self.superview!.superview!.superview!, foundCount: 0) else { + print("⚠️ ExpoScrollForwarder: couldn’t find UIScrollView under tag \(tag)") + return + } - self.rctScrollView = self.appContext? - .findView(withTag: scrollViewTag, ofType: RCTScrollView.self) - self.rctRefreshCtrl = self.rctScrollView?.scrollView.refreshControl as? RCTRefreshControl + self.scrollView = sv + self.rctRefreshCtrl = sv.refreshControl as? RCTRefreshControl self.addCancelGestureRecognizers() } func addCancelGestureRecognizers() { self.cancelGestureRecognizers?.forEach { r in - self.rctScrollView?.scrollView?.addGestureRecognizer(r) + self.scrollView?.addGestureRecognizer(r) } } func removeCancelGestureRecognizers() { self.cancelGestureRecognizers?.forEach { r in - self.rctScrollView?.scrollView?.removeGestureRecognizer(r) + self.scrollView?.removeGestureRecognizer(r) } } @@ -202,7 +219,7 @@ class ExpoScrollForwarderView: ExpoView, UIGestureRecognizerDelegate { } func scrollToOffset(_ offset: Int, animated: Bool = true) { - self.rctScrollView?.scroll(toOffset: CGPoint(x: 0, y: offset), animated: animated) + self.scrollView?.scrollRectToVisible(CGRect(x: 0, y: offset, width: 0, height: 0), animated: animated) } func stopTimer() { diff --git a/modules/expo-scroll-forwarder/src/ExpoScrollForwarder.types.ts b/modules/expo-scroll-forwarder/src/ExpoScrollForwarder.types.ts index 26b9e7553a..3f1e4a63da 100644 --- a/modules/expo-scroll-forwarder/src/ExpoScrollForwarder.types.ts +++ b/modules/expo-scroll-forwarder/src/ExpoScrollForwarder.types.ts @@ -1,5 +1,3 @@ -import React from 'react' - export interface ExpoScrollForwarderViewProps { scrollViewTag: number | null children: React.ReactNode diff --git a/modules/expo-scroll-forwarder/src/ExpoScrollForwarderView.ios.tsx b/modules/expo-scroll-forwarder/src/ExpoScrollForwarderView.ios.tsx index 21a2b9fb26..18bdb25c8a 100644 --- a/modules/expo-scroll-forwarder/src/ExpoScrollForwarderView.ios.tsx +++ b/modules/expo-scroll-forwarder/src/ExpoScrollForwarderView.ios.tsx @@ -1,7 +1,6 @@ -import * as React from 'react' import {requireNativeViewManager} from 'expo-modules-core' -import {ExpoScrollForwarderViewProps} from './ExpoScrollForwarder.types' +import {type ExpoScrollForwarderViewProps} from './ExpoScrollForwarder.types' const NativeView: React.ComponentType = requireNativeViewManager('ExpoScrollForwarder') diff --git a/modules/expo-scroll-forwarder/src/ExpoScrollForwarderView.tsx b/modules/expo-scroll-forwarder/src/ExpoScrollForwarderView.tsx index 0f5d01c130..d66eef7cbd 100644 --- a/modules/expo-scroll-forwarder/src/ExpoScrollForwarderView.tsx +++ b/modules/expo-scroll-forwarder/src/ExpoScrollForwarderView.tsx @@ -1,6 +1,4 @@ -import React from 'react' - -import {ExpoScrollForwarderViewProps} from './ExpoScrollForwarder.types' +import {type ExpoScrollForwarderViewProps} from './ExpoScrollForwarder.types' export function ExpoScrollForwarderView({ children, diff --git a/package.json b/package.json index 2ed14061f4..0d96e688cb 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,17 @@ "node": ">=20" }, "packageManager": "yarn@1.22.22", + "expo": { + "autolinking": { + "android": { + "buildFromSource": [ + "expo-notifications", + "expo-haptics", + "expo-media-library" + ] + } + } + }, "scripts": { "prepare": "is-ci || husky install", "postinstall": "patch-package && yarn intl:compile", @@ -58,13 +69,13 @@ "icons:optimize": "svgo -f ./assets/icons" }, "dependencies": { - "@atproto/api": "^0.15.3", + "@atproto/api": "^0.15.5", "@bitdrift/react-native": "^0.6.8", "@braintree/sanitize-url": "^6.0.2", "@discord/bottom-sheet": "bluesky-social/react-native-bottom-sheet", "@emoji-mart/react": "^1.1.1", - "@expo/html-elements": "^0.4.2", - "@expo/webpack-config": "^19.0.0", + "@expo/html-elements": "^0.12.4", + "@expo/webpack-config": "^19.0.1", "@floating-ui/dom": "^1.6.3", "@floating-ui/react-dom": "^2.0.8", "@formatjs/intl-locale": "^4.2.8", @@ -80,9 +91,9 @@ "@mattermost/react-native-paste-input": "^0.7.1", "@miblanchard/react-native-slider": "^2.3.1", "@mozzius/expo-dynamic-app-icon": "^1.5.0", - "@react-native-async-storage/async-storage": "1.23.1", - "@react-native-menu/menu": "^1.1.7", - "@react-native-picker/picker": "2.10.3", + "@react-native-async-storage/async-storage": "2.1.2", + "@react-native-menu/menu": "^1.2.3", + "@react-native-picker/picker": "2.11.0", "@react-navigation/bottom-tabs": "^6.5.20", "@react-navigation/drawer": "^6.6.15", "@react-navigation/native": "^6.1.17", @@ -119,33 +130,33 @@ "emoji-mart": "^5.5.2", "emoji-regex": "^10.4.0", "eventemitter3": "^5.0.1", - "expo": "~52.0.42", - "expo-application": "~6.0.2", - "expo-blur": "^14.0.3", - "expo-build-properties": "~0.13.2", - "expo-camera": "~16.0.18", - "expo-clipboard": "~7.0.1", - "expo-dev-client": "~5.0.19", - "expo-device": "~7.0.3", - "expo-file-system": "~18.0.12", - "expo-font": "~13.0.4", - "expo-haptics": "~14.0.1", - "expo-image": "~2.0.7", - "expo-image-manipulator": "~13.0.6", - "expo-image-picker": "~16.0.6", - "expo-linear-gradient": "~14.0.2", - "expo-linking": "~7.0.5", - "expo-localization": "~16.0.1", - "expo-media-library": "~17.0.6", - "expo-notifications": "~0.29.14", - "expo-screen-orientation": "~8.0.4", - "expo-sharing": "~13.0.1", - "expo-splash-screen": "~0.29.22", - "expo-system-ui": "~4.0.9", - "expo-task-manager": "~12.0.6", - "expo-updates": "~0.27.4", - "expo-video": "~2.0.6", - "expo-web-browser": "~14.0.2", + "expo": "^53.0.5", + "expo-application": "~6.1.4", + "expo-blur": "~14.1.4", + "expo-build-properties": "~0.14.6", + "expo-camera": "~16.1.6", + "expo-clipboard": "~7.1.4", + "expo-dev-client": "~5.1.7", + "expo-device": "~7.1.4", + "expo-file-system": "~18.1.8", + "expo-font": "~13.3.0", + "expo-haptics": "~14.1.4", + "expo-image": "~2.1.6", + "expo-image-manipulator": "~13.1.5", + "expo-image-picker": "~16.1.4", + "expo-linear-gradient": "~14.1.4", + "expo-linking": "~7.1.4", + "expo-localization": "~16.1.5", + "expo-media-library": "~17.1.6", + "expo-notifications": "~0.31.1", + "expo-screen-orientation": "~8.1.5", + "expo-sharing": "~13.1.5", + "expo-splash-screen": "~0.30.8", + "expo-system-ui": "~5.0.7", + "expo-task-manager": "~13.1.5", + "expo-updates": "~0.28.12", + "expo-video": "~2.1.8", + "expo-web-browser": "~14.1.6", "fast-text-encoding": "^1.0.6", "history": "^5.3.0", "hls.js": "^1.5.11", @@ -157,47 +168,47 @@ "lodash.isequal": "^4.5.0", "lodash.shuffle": "^4.2.0", "lodash.throttle": "^4.1.1", - "multiformats": "^13.1.0", + "multiformats": "9.9.0", "nanoid": "^5.0.5", "normalize-url": "^8.0.0", "patch-package": "^6.5.1", "postinstall-postinstall": "^2.1.0", "psl": "^1.9.0", "radix-ui": "^1.2.0", - "react": "18.3.1", - "react-compiler-runtime": "19.0.0-beta-a7bf2bd-20241110", - "react-dom": "18.3.1", + "react": "19.0.0", + "react-compiler-runtime": "^19.1.0-rc.1", + "react-dom": "19.0.0", "react-image-crop": "^11.0.7", - "react-keyed-flatten-children": "^3.0.0", - "react-native": "0.76.9", - "react-native-compressor": "1.10.3", - "react-native-date-picker": "^5.0.7", - "react-native-drawer-layout": "^4.1.1", + "react-is": "19", + "react-keyed-flatten-children": "^5.0.0", + "react-native": "0.79.2", + "react-native-compressor": "1.11.0", + "react-native-date-picker": "^5.0.12", + "react-native-drawer-layout": "^4.1.6", "react-native-edge-to-edge": "^1.6.0", - "react-native-emoji-popup": "^0.1.2", - "react-native-gesture-handler": "2.20.2", + "react-native-gesture-handler": "2.25.0", "react-native-get-random-values": "~1.11.0", - "react-native-image-crop-picker": "^0.41.6", + "react-native-image-crop-picker": "^0.42.0", "react-native-ios-context-menu": "^1.15.3", "react-native-keyboard-controller": "^1.17.1", "react-native-mmkv": "^2.12.2", - "react-native-pager-view": "6.5.1", + "react-native-pager-view": "6.7.1", "react-native-picker-select": "^9.3.1", "react-native-progress": "bluesky-social/react-native-progress", "react-native-qrcode-styled": "^0.3.3", - "react-native-reanimated": "~3.16.1", + "react-native-reanimated": "~3.17.5", "react-native-root-siblings": "^4.1.1", - "react-native-safe-area-context": "4.12.0", - "react-native-screens": "~4.4.0", - "react-native-svg": "15.8.0", + "react-native-safe-area-context": "5.4.0", + "react-native-screens": "~4.10.0", + "react-native-svg": "15.11.2", "react-native-uitextview": "^1.4.0", "react-native-url-polyfill": "^1.3.0", - "react-native-uuid": "^2.0.2", + "react-native-uuid": "^2.0.3", "react-native-view-shot": "^4.0.3", - "react-native-web": "~0.19.13", + "react-native-web": "~0.20.0", "react-native-web-webview": "^1.0.2", - "react-native-webview": "13.12.5", - "react-remove-scroll-bar": "^2.3.6", + "react-native-webview": "13.13.5", + "react-remove-scroll-bar": "^2.3.8", "react-responsive": "^9.0.2", "react-textarea-autosize": "^8.5.3", "rn-fetch-blob": "^0.12.0", @@ -209,77 +220,74 @@ "zod": "^3.20.2" }, "devDependencies": { - "@atproto/dev-env": "^0.3.87", + "@atproto/dev-env": "^0.3.128", "@babel/core": "^7.26.0", "@babel/preset-env": "^7.26.0", "@babel/runtime": "^7.26.0", - "@did-plc/server": "^0.0.1", - "@expo/config-plugins": "9.0.10", + "@expo/config-plugins": "~10.0.2", "@lingui/cli": "^4.14.1", "@lingui/macro": "^4.14.1", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.15", - "@react-native/eslint-config": "^0.76.9", - "@react-native/typescript-config": "^0.76.9", + "@react-native/eslint-config": "^0.79.2", + "@react-native/typescript-config": "^0.79.2", "@sentry/webpack-plugin": "^3.2.2", "@testing-library/jest-native": "^5.4.3", - "@testing-library/react-native": "^12.8.1", + "@testing-library/react-native": "^13.2.0", "@types/jest": "^29.4.0", "@types/lodash.chunk": "^4.2.7", "@types/lodash.debounce": "^4.0.7", "@types/lodash.isequal": "^4.5.6", "@types/lodash.shuffle": "^4.2.7", "@types/psl": "^1.1.1", - "@types/react-dom": "^18.3.1", + "@types/react-dom": "^19.1.2", "@types/react-responsive": "^8.0.5", - "@types/react-test-renderer": "^17.0.1", "@typescript-eslint/eslint-plugin": "^7.18.0", "@typescript-eslint/parser": "^7.18.0", "babel-jest": "^29.7.0", "babel-plugin-macros": "^3.1.0", "babel-plugin-module-resolver": "^5.0.2", - "babel-plugin-react-compiler": "19.0.0-beta-a7bf2bd-20241110", - "babel-preset-expo": "^12.0.2", + "babel-plugin-react-compiler": "^19.1.0-rc.1", + "babel-preset-expo": "~13.1.11", "eslint": "^8.19.0", "eslint-plugin-bsky-internal": "link:./eslint", "eslint-plugin-ft-flow": "^2.0.3", "eslint-plugin-import": "^2.31.0", "eslint-plugin-lingui": "^0.2.0", "eslint-plugin-react": "^7.33.2", - "eslint-plugin-react-compiler": "19.0.0-beta-a7bf2bd-20241110", + "eslint-plugin-react-compiler": "^19.1.0-rc.1", "eslint-plugin-react-native-a11y": "^3.3.0", "eslint-plugin-simple-import-sort": "^12.0.0", "file-loader": "6.2.0", "husky": "^8.0.3", "is-ci": "^3.0.1", "jest": "^29.7.0", - "jest-expo": "~52.0.6", + "jest-expo": "~53.0.3", "jest-junit": "^16.0.0", "lint-staged": "^13.2.3", "lockfile-lint": "^4.14.0", - "metro-react-native-babel-preset": "^0.76.9", + "metro-react-native-babel-preset": "^0.77.0", "prettier": "^2.8.3", "react-native-dotenv": "^3.4.11", "react-refresh": "^0.14.0", - "react-test-renderer": "18.2.0", "svgo": "^3.3.2", "ts-node": "^10.9.1", - "typescript": "^5.7.2", + "typescript": "~5.8.3", "webpack-bundle-analyzer": "^4.10.1" }, "resolutions": { "@expo/image-utils": "0.6.3", - "@react-native/babel-preset": "0.76.9", - "@react-native/normalize-colors": "0.76.1", + "@react-native/babel-preset": "0.79.2", + "@react-native/normalize-colors": "0.79.2", "@types/react": "^18", "**/expo-constants": "17.0.3", "**/expo-device": "7.0.1", - "**/zod": "3.23.8" + "**/zod": "3.23.8", + "**/multiformats": "9.9.0" }, "jest": { "preset": "jest-expo/ios", "setupFilesAfterEnv": [ - "./jest/jestSetup.js", - "@testing-library/jest-native/extend-expect" + "./jest/jestSetup.js" ], "moduleFileExtensions": [ "ts", diff --git a/patches/expo-haptics+14.0.1.patch b/patches/expo-haptics+14.1.4.patch similarity index 100% rename from patches/expo-haptics+14.0.1.patch rename to patches/expo-haptics+14.1.4.patch diff --git a/patches/expo-haptics+14.0.0.md b/patches/expo-haptics+14.1.4.patch.md similarity index 100% rename from patches/expo-haptics+14.0.0.md rename to patches/expo-haptics+14.1.4.patch.md diff --git a/patches/expo-image-manipulator+13.0.6.patch b/patches/expo-image-manipulator+13.0.6.patch deleted file mode 100644 index 02d4d5fb9a..0000000000 --- a/patches/expo-image-manipulator+13.0.6.patch +++ /dev/null @@ -1,101 +0,0 @@ -diff --git a/node_modules/expo-image-manipulator/src/ImageManipulator.web.ts b/node_modules/expo-image-manipulator/src/ImageManipulator.web.ts -new file mode 100644 -index 0000000..babbb3b ---- /dev/null -+++ b/node_modules/expo-image-manipulator/src/ImageManipulator.web.ts -@@ -0,0 +1,60 @@ -+import { useReleasingSharedObject } from 'expo-modules-core'; -+import { SharedRef } from 'expo-modules-core/types'; -+ -+import { Action, ImageResult, SaveFormat, SaveOptions } from './ImageManipulator.types'; -+import { ImageManipulatorContext } from './ImageManipulatorContext'; -+import ExpoImageManipulator from './NativeImageManipulatorModule'; -+import { validateArguments } from './validators'; -+ -+// @needsAudit -+/** -+ * Manipulate the image provided via `uri`. Available modifications are rotating, flipping (mirroring), -+ * resizing and cropping. Each invocation results in a new file. With one invocation you can provide -+ * a set of actions to perform over the image. Overwriting the source file would not have an effect -+ * in displaying the result as images are cached. -+ * @param uri URI of the file to manipulate. Should be on the local file system or a base64 data URI. -+ * @param actions An array of objects representing manipulation options. Each object should have -+ * __only one__ of the keys that corresponds to specific transformation. -+ * @param saveOptions A map defining how modified image should be saved. -+ * @return Promise which fulfils with [`ImageResult`](#imageresult) object. -+ * @deprecated It has been replaced by the new, contextual and object-oriented API. -+ * Use [`ImageManipulator.manipulate`](#manipulateuri) or [`useImageManipulator`](#useimagemanipulatoruri) instead. -+ */ -+export async function manipulateAsync( -+ uri: string, -+ actions: Action[] = [], -+ saveOptions: SaveOptions = {} -+): Promise { -+ validateArguments(uri, actions, saveOptions); -+ -+ const { format = SaveFormat.JPEG, ...rest } = saveOptions; -+ const context = ExpoImageManipulator.manipulate(uri); -+ -+ for (const action of actions) { -+ if ('resize' in action) { -+ context.resize(action.resize); -+ } else if ('rotate' in action) { -+ context.rotate(action.rotate); -+ } else if ('flip' in action) { -+ context.flip(action.flip); -+ } else if ('crop' in action) { -+ context.crop(action.crop); -+ } else if ('extent' in action && context.extent) { -+ context.extent(action.extent); -+ } -+ } -+ const image = await context.renderAsync(saveOptions.compress); -+ const result = await image.saveAsync({ format, ...rest }); -+ -+ // These shared objects will not be used anymore, so free up some memory. -+ context.release(); -+ image.release(); -+ -+ return result; -+} -+ -+export function useImageManipulator(source: string | SharedRef<'image'>): ImageManipulatorContext { -+ return useReleasingSharedObject(() => ExpoImageManipulator.manipulate(source), [source]); -+} -+ -+export { ExpoImageManipulator as ImageManipulator }; -diff --git a/node_modules/expo-image-manipulator/src/ImageManipulatorContext.ts b/node_modules/expo-image-manipulator/src/ImageManipulatorContext.ts -index 120d8d3..f8aa49c 100644 ---- a/node_modules/expo-image-manipulator/src/ImageManipulatorContext.ts -+++ b/node_modules/expo-image-manipulator/src/ImageManipulatorContext.ts -@@ -52,7 +52,7 @@ export declare class ImageManipulatorContext extends SharedObject { - /** - * Awaits for all manipulation tasks to finish and resolves with a reference to the resulted native image. - */ -- renderAsync(): Promise; -+ renderAsync(compress?: number): Promise; - } - - export default ExpoImageManipulator.Context as typeof ImageManipulatorContext; -diff --git a/node_modules/expo-image-manipulator/src/web/ImageManipulatorContext.web.ts b/node_modules/expo-image-manipulator/src/web/ImageManipulatorContext.web.ts -index 428848c..363a57a 100644 ---- a/node_modules/expo-image-manipulator/src/web/ImageManipulatorContext.web.ts -+++ b/node_modules/expo-image-manipulator/src/web/ImageManipulatorContext.web.ts -@@ -41,7 +41,7 @@ export default class ImageManipulatorContext extends SharedObject { - return this; - } - -- async renderAsync(): Promise { -+ async renderAsync(compress?: number): Promise { - const canvas = await this.currentTask; - - return new Promise((resolve) => { -@@ -49,7 +49,7 @@ export default class ImageManipulatorContext extends SharedObject { - const url = blob ? URL.createObjectURL(blob) : canvas.toDataURL(); - - resolve(new ImageManipulatorImageRef(url, canvas.width, canvas.height)); -- }); -+ }, typeof compress === 'number' ? 'image/jpeg' : undefined, compress); - }); - } - diff --git a/patches/expo-media-library+17.0.6.patch b/patches/expo-media-library+17.1.6.patch similarity index 50% rename from patches/expo-media-library+17.0.6.patch rename to patches/expo-media-library+17.1.6.patch index 7ef57f7687..4fa853ec3a 100644 --- a/patches/expo-media-library+17.0.6.patch +++ b/patches/expo-media-library+17.1.6.patch @@ -1,19 +1,19 @@ diff --git a/node_modules/expo-media-library/android/src/main/java/expo/modules/medialibrary/MediaLibraryModule.kt b/node_modules/expo-media-library/android/src/main/java/expo/modules/medialibrary/MediaLibraryModule.kt -index 64e6efe..e61485e 100644 +index f1255e8..a9b49e5 100644 --- a/node_modules/expo-media-library/android/src/main/java/expo/modules/medialibrary/MediaLibraryModule.kt +++ b/node_modules/expo-media-library/android/src/main/java/expo/modules/medialibrary/MediaLibraryModule.kt -@@ -111,12 +111,12 @@ class MediaLibraryModule : Module() { +@@ -112,11 +112,9 @@ class MediaLibraryModule : Module() { } - AsyncFunction("createAssetAsync") { localUri: String, promise: Promise -> + AsyncFunction("createAssetAsync") { localUri: String, albumId: String?, promise: Promise -> - throwUnlessPermissionsGranted { -+ //throwUnlessPermissionsGranted { - withModuleScope(promise) { - CreateAsset(context, localUri, promise) - .execute() - } -- } -+ //} +- withModuleScope(promise) { +- CreateAssetWithAlbumId(context, localUri, promise, true, albumId) +- .execute() +- } ++ withModuleScope(promise) { ++ CreateAssetWithAlbumId(context, localUri, promise, true, albumId) ++ .execute() + } } - AsyncFunction("addAssetsToAlbumAsync") { assetsId: List, albumId: String, copyToAlbum: Boolean, promise: Promise -> diff --git a/patches/expo-modules-core+2.2.3.patch b/patches/expo-modules-core+2.3.12.patch similarity index 100% rename from patches/expo-modules-core+2.2.3.patch rename to patches/expo-modules-core+2.3.12.patch diff --git a/patches/expo-modules-core+2.1.2.md b/patches/expo-modules-core+2.3.12.patch.md similarity index 100% rename from patches/expo-modules-core+2.1.2.md rename to patches/expo-modules-core+2.3.12.patch.md diff --git a/patches/expo-notifications+0.29.14.patch b/patches/expo-notifications+0.29.14.patch deleted file mode 100644 index dd70cc781b..0000000000 --- a/patches/expo-notifications+0.29.14.patch +++ /dev/null @@ -1,169 +0,0 @@ -diff --git a/node_modules/expo-notifications/android/build.gradle b/node_modules/expo-notifications/android/build.gradle -index 13bffbb..5ebbede 100644 ---- a/node_modules/expo-notifications/android/build.gradle -+++ b/node_modules/expo-notifications/android/build.gradle -@@ -46,6 +46,7 @@ dependencies { - implementation 'com.google.firebase:firebase-messaging:24.0.1' - - implementation 'me.leolin:ShortcutBadger:1.1.22@aar' -+ implementation project(':expo-background-notification-handler') - - if (project.findProject(':expo-modules-test-core')) { - testImplementation project(':expo-modules-test-core') -diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/interfaces/INotificationContent.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/interfaces/INotificationContent.kt -index 7b99e6c..45a450d 100644 ---- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/interfaces/INotificationContent.kt -+++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/interfaces/INotificationContent.kt -@@ -15,6 +15,7 @@ import org.json.JSONObject - * This interface exists to provide a common API for both classes. - * */ - interface INotificationContent : Parcelable { -+ val channelId: String? - val title: String? - val text: String? - val subText: String? -diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationContent.java b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationContent.java -index 191b64e..fe8b3c5 100644 ---- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationContent.java -+++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationContent.java -@@ -35,6 +35,7 @@ import kotlin.coroutines.Continuation; - * Refactoring this class may require a migration strategy for the data stored in SharedPreferences. - */ - public class NotificationContent implements Parcelable, Serializable, INotificationContent { -+ private String mChannelId; - private String mTitle; - private String mText; - private String mSubtitle; -@@ -65,6 +66,11 @@ public class NotificationContent implements Parcelable, Serializable, INotificat - } - }; - -+ @Nullable -+ public String getChannelId() { -+ return mChannelId; -+ } -+ - @Nullable - public String getTitle() { - return mTitle; -@@ -158,6 +164,7 @@ public class NotificationContent implements Parcelable, Serializable, INotificat - } - - protected NotificationContent(Parcel in) { -+ mChannelId = in.readString(); - mTitle = in.readString(); - mText = in.readString(); - mSubtitle = in.readString(); -@@ -183,6 +190,7 @@ public class NotificationContent implements Parcelable, Serializable, INotificat - - @Override - public void writeToParcel(Parcel dest, int flags) { -+ dest.writeString(mChannelId); - dest.writeString(mTitle); - dest.writeString(mText); - dest.writeString(mSubtitle); -@@ -203,6 +211,7 @@ public class NotificationContent implements Parcelable, Serializable, INotificat - private static final long serialVersionUID = 397666843266836802L; - - private void writeObject(java.io.ObjectOutputStream out) throws IOException { -+ out.writeObject(mChannelId); - out.writeObject(mTitle); - out.writeObject(mText); - out.writeObject(mSubtitle); -@@ -285,6 +294,11 @@ public class NotificationContent implements Parcelable, Serializable, INotificat - useDefaultVibrationPattern(); - } - -+ public Builder setChannelId(String channelId) { -+ content.mChannelId = channelId; -+ return this; -+ } -+ - public Builder setTitle(String title) { - content.mTitle = title; - return this; -diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationData.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationData.kt -index 39b5aad..e50797d 100644 ---- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationData.kt -+++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationData.kt -@@ -11,6 +11,9 @@ import org.json.JSONObject - * */ - @JvmInline - value class NotificationData(private val data: Map) { -+ val channelId: String? -+ get() = data["channelId"] -+ - val title: String? - get() = data["title"] - -diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/RemoteNotificationContent.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/RemoteNotificationContent.kt -index d2cc6cf..6a48ff2 100644 ---- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/RemoteNotificationContent.kt -+++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/RemoteNotificationContent.kt -@@ -31,6 +31,8 @@ class RemoteNotificationContent(private val remoteMessage: RemoteMessage) : INot - return remoteMessage.notification?.imageUrl != null - } - -+ override val channelId = remoteMessage.notification?.channelId ?: notificationData.channelId -+ - override val title = remoteMessage.notification?.title ?: notificationData.title - - override val text = remoteMessage.notification?.body ?: notificationData.message -diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/ExpoNotificationBuilder.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/ExpoNotificationBuilder.kt -index 8ca6ec5..57c3599 100644 ---- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/ExpoNotificationBuilder.kt -+++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/ExpoNotificationBuilder.kt -@@ -101,6 +101,9 @@ open class ExpoNotificationBuilder( - builder.setOngoing(content.isSticky) - - // see "Notification anatomy" https://developer.android.com/develop/ui/views/notifications#Templates -+ content.channelId?.let { -+ builder.setChannelId(it) -+ } - builder.setContentTitle(content.title) - builder.setContentText(content.text) - builder.setSubText(content.subText) -diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/service/delegates/FirebaseMessagingDelegate.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/service/delegates/FirebaseMessagingDelegate.kt -index 9f22441..5f92f80 100644 ---- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/service/delegates/FirebaseMessagingDelegate.kt -+++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/service/delegates/FirebaseMessagingDelegate.kt -@@ -2,6 +2,9 @@ package expo.modules.notifications.service.delegates - - import android.content.Context - import com.google.firebase.messaging.RemoteMessage -+import expo.modules.backgroundnotificationhandler.BackgroundNotificationHandler -+import expo.modules.backgroundnotificationhandler.BackgroundNotificationHandlerInterface -+import expo.modules.backgroundnotificationhandler.ExpoBackgroundNotificationHandlerModule - import expo.modules.interfaces.taskManager.TaskServiceProviderHelper - import expo.modules.notifications.notifications.RemoteMessageSerializer - import expo.modules.notifications.notifications.background.BackgroundRemoteNotificationTaskConsumer -@@ -17,7 +20,8 @@ import expo.modules.notifications.tokens.interfaces.FirebaseTokenListener - import java.lang.ref.WeakReference - import java.util.* - --open class FirebaseMessagingDelegate(protected val context: Context) : FirebaseMessagingDelegate { -+open class FirebaseMessagingDelegate(protected val context: Context) : FirebaseMessagingDelegate, -+ BackgroundNotificationHandlerInterface { - companion object { - // Unfortunately we cannot save state between instances of a service other way - // than by static properties. Fortunately, using weak references we can -@@ -94,8 +98,17 @@ open class FirebaseMessagingDelegate(protected val context: Context) : FirebaseM - DebugLogging.logRemoteMessage("FirebaseMessagingDelegate.onMessageReceived: message", remoteMessage) - val notification = createNotification(remoteMessage) - DebugLogging.logNotification("FirebaseMessagingDelegate.onMessageReceived: notification", notification) -- NotificationsService.receive(context, notification) -- runTaskManagerTasks(remoteMessage) -+ -+ if (!ExpoBackgroundNotificationHandlerModule.isForegrounded) { -+ BackgroundNotificationHandler(context, this).handleMessage(remoteMessage) -+ } else { -+ showMessage(remoteMessage) -+ runTaskManagerTasks(remoteMessage) -+ } -+ } -+ -+ override fun showMessage(remoteMessage: RemoteMessage) { -+ NotificationsService.receive(context, createNotification(remoteMessage)) - } - - private fun runTaskManagerTasks(remoteMessage: RemoteMessage) { diff --git a/patches/expo-notifications+0.31.1.patch b/patches/expo-notifications+0.31.1.patch new file mode 100644 index 0000000000..56e639a261 --- /dev/null +++ b/patches/expo-notifications+0.31.1.patch @@ -0,0 +1,992 @@ +diff --git a/node_modules/expo-notifications/android/.gradle/8.10/checksums/checksums.lock b/node_modules/expo-notifications/android/.gradle/8.10/checksums/checksums.lock +new file mode 100644 +index 0000000..883ef6a +Binary files /dev/null and b/node_modules/expo-notifications/android/.gradle/8.10/checksums/checksums.lock differ +diff --git a/node_modules/expo-notifications/android/.gradle/8.10/dependencies-accessors/gc.properties b/node_modules/expo-notifications/android/.gradle/8.10/dependencies-accessors/gc.properties +new file mode 100644 +index 0000000..e69de29 +diff --git a/node_modules/expo-notifications/android/.gradle/8.10/fileChanges/last-build.bin b/node_modules/expo-notifications/android/.gradle/8.10/fileChanges/last-build.bin +new file mode 100644 +index 0000000..f76dd23 +Binary files /dev/null and b/node_modules/expo-notifications/android/.gradle/8.10/fileChanges/last-build.bin differ +diff --git a/node_modules/expo-notifications/android/.gradle/8.10/fileHashes/fileHashes.lock b/node_modules/expo-notifications/android/.gradle/8.10/fileHashes/fileHashes.lock +new file mode 100644 +index 0000000..774caf7 +Binary files /dev/null and b/node_modules/expo-notifications/android/.gradle/8.10/fileHashes/fileHashes.lock differ +diff --git a/node_modules/expo-notifications/android/.gradle/8.10/gc.properties b/node_modules/expo-notifications/android/.gradle/8.10/gc.properties +new file mode 100644 +index 0000000..e69de29 +diff --git a/node_modules/expo-notifications/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/node_modules/expo-notifications/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +new file mode 100644 +index 0000000..a3c1514 +Binary files /dev/null and b/node_modules/expo-notifications/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock differ +diff --git a/node_modules/expo-notifications/android/.gradle/buildOutputCleanup/cache.properties b/node_modules/expo-notifications/android/.gradle/buildOutputCleanup/cache.properties +new file mode 100644 +index 0000000..0e5b4da +--- /dev/null ++++ b/node_modules/expo-notifications/android/.gradle/buildOutputCleanup/cache.properties +@@ -0,0 +1,2 @@ ++#Thu Apr 24 20:44:36 PDT 2025 ++gradle.version=8.10 +diff --git a/node_modules/expo-notifications/android/.gradle/config.properties b/node_modules/expo-notifications/android/.gradle/config.properties +new file mode 100644 +index 0000000..0bd71c6 +--- /dev/null ++++ b/node_modules/expo-notifications/android/.gradle/config.properties +@@ -0,0 +1,2 @@ ++#Thu Apr 24 20:44:32 PDT 2025 ++java.home=/Applications/Android Studio.app/Contents/jbr/Contents/Home +diff --git a/node_modules/expo-notifications/android/.gradle/vcs-1/gc.properties b/node_modules/expo-notifications/android/.gradle/vcs-1/gc.properties +new file mode 100644 +index 0000000..e69de29 +diff --git a/node_modules/expo-notifications/android/.idea/.gitignore b/node_modules/expo-notifications/android/.idea/.gitignore +new file mode 100644 +index 0000000..26d3352 +--- /dev/null ++++ b/node_modules/expo-notifications/android/.idea/.gitignore +@@ -0,0 +1,3 @@ ++# Default ignored files ++/shelf/ ++/workspace.xml +diff --git a/node_modules/expo-notifications/android/.idea/AndroidProjectSystem.xml b/node_modules/expo-notifications/android/.idea/AndroidProjectSystem.xml +new file mode 100644 +index 0000000..4a53bee +--- /dev/null ++++ b/node_modules/expo-notifications/android/.idea/AndroidProjectSystem.xml +@@ -0,0 +1,6 @@ ++ ++ ++ ++ ++ +\ No newline at end of file +diff --git a/node_modules/expo-notifications/android/.idea/caches/deviceStreaming.xml b/node_modules/expo-notifications/android/.idea/caches/deviceStreaming.xml +new file mode 100644 +index 0000000..9e9ba09 +--- /dev/null ++++ b/node_modules/expo-notifications/android/.idea/caches/deviceStreaming.xml +@@ -0,0 +1,607 @@ ++ ++ ++ ++ ++ ++ +\ No newline at end of file +diff --git a/node_modules/expo-notifications/android/.idea/gradle.xml b/node_modules/expo-notifications/android/.idea/gradle.xml +new file mode 100644 +index 0000000..b838237 +--- /dev/null ++++ b/node_modules/expo-notifications/android/.idea/gradle.xml +@@ -0,0 +1,12 @@ ++ ++ ++ ++ ++ ++ +\ No newline at end of file +diff --git a/node_modules/expo-notifications/android/.idea/migrations.xml b/node_modules/expo-notifications/android/.idea/migrations.xml +new file mode 100644 +index 0000000..f8051a6 +--- /dev/null ++++ b/node_modules/expo-notifications/android/.idea/migrations.xml +@@ -0,0 +1,10 @@ ++ ++ ++ ++ ++ ++ +\ No newline at end of file +diff --git a/node_modules/expo-notifications/android/.idea/misc.xml b/node_modules/expo-notifications/android/.idea/misc.xml +new file mode 100644 +index 0000000..3040d03 +--- /dev/null ++++ b/node_modules/expo-notifications/android/.idea/misc.xml +@@ -0,0 +1,10 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ +\ No newline at end of file +diff --git a/node_modules/expo-notifications/android/.idea/runConfigurations.xml b/node_modules/expo-notifications/android/.idea/runConfigurations.xml +new file mode 100644 +index 0000000..16660f1 +--- /dev/null ++++ b/node_modules/expo-notifications/android/.idea/runConfigurations.xml +@@ -0,0 +1,17 @@ ++ ++ ++ ++ ++ ++ +\ No newline at end of file +diff --git a/node_modules/expo-notifications/android/.idea/workspace.xml b/node_modules/expo-notifications/android/.idea/workspace.xml +new file mode 100644 +index 0000000..df26928 +--- /dev/null ++++ b/node_modules/expo-notifications/android/.idea/workspace.xml +@@ -0,0 +1,47 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ 1745552672693 ++ ++ ++ ++ +\ No newline at end of file +diff --git a/node_modules/expo-notifications/android/build.gradle b/node_modules/expo-notifications/android/build.gradle +index bc479ee..1ebfa00 100644 +--- a/node_modules/expo-notifications/android/build.gradle ++++ b/node_modules/expo-notifications/android/build.gradle +@@ -42,6 +42,7 @@ dependencies { + implementation 'com.google.firebase:firebase-messaging:24.0.1' + + implementation 'me.leolin:ShortcutBadger:1.1.22@aar' ++ implementation project(':expo-background-notification-handler') + + if (project.findProject(':expo-modules-test-core')) { + testImplementation project(':expo-modules-test-core') +diff --git a/node_modules/expo-notifications/android/local.properties b/node_modules/expo-notifications/android/local.properties +new file mode 100644 +index 0000000..ab4c86d +--- /dev/null ++++ b/node_modules/expo-notifications/android/local.properties +@@ -0,0 +1,8 @@ ++## This file must *NOT* be checked into Version Control Systems, ++# as it contains information specific to your local configuration. ++# ++# Location of the SDK. This is only used by Gradle. ++# For customization when using a Version Control System, please read the ++# header note. ++#Thu Apr 24 20:44:32 PDT 2025 ++sdk.dir=/Users/hailey/Library/Android/sdk +diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/interfaces/INotificationContent.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/interfaces/INotificationContent.kt +index 7b99e6c..45a450d 100644 +--- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/interfaces/INotificationContent.kt ++++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/interfaces/INotificationContent.kt +@@ -15,6 +15,7 @@ import org.json.JSONObject + * This interface exists to provide a common API for both classes. + * */ + interface INotificationContent : Parcelable { ++ val channelId: String? + val title: String? + val text: String? + val subText: String? +diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationContent.java b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationContent.java +index 191b64e..fe8b3c5 100644 +--- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationContent.java ++++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationContent.java +@@ -35,6 +35,7 @@ import kotlin.coroutines.Continuation; + * Refactoring this class may require a migration strategy for the data stored in SharedPreferences. + */ + public class NotificationContent implements Parcelable, Serializable, INotificationContent { ++ private String mChannelId; + private String mTitle; + private String mText; + private String mSubtitle; +@@ -65,6 +66,11 @@ public class NotificationContent implements Parcelable, Serializable, INotificat + } + }; + ++ @Nullable ++ public String getChannelId() { ++ return mChannelId; ++ } ++ + @Nullable + public String getTitle() { + return mTitle; +@@ -158,6 +164,7 @@ public class NotificationContent implements Parcelable, Serializable, INotificat + } + + protected NotificationContent(Parcel in) { ++ mChannelId = in.readString(); + mTitle = in.readString(); + mText = in.readString(); + mSubtitle = in.readString(); +@@ -183,6 +190,7 @@ public class NotificationContent implements Parcelable, Serializable, INotificat + + @Override + public void writeToParcel(Parcel dest, int flags) { ++ dest.writeString(mChannelId); + dest.writeString(mTitle); + dest.writeString(mText); + dest.writeString(mSubtitle); +@@ -203,6 +211,7 @@ public class NotificationContent implements Parcelable, Serializable, INotificat + private static final long serialVersionUID = 397666843266836802L; + + private void writeObject(java.io.ObjectOutputStream out) throws IOException { ++ out.writeObject(mChannelId); + out.writeObject(mTitle); + out.writeObject(mText); + out.writeObject(mSubtitle); +@@ -285,6 +294,11 @@ public class NotificationContent implements Parcelable, Serializable, INotificat + useDefaultVibrationPattern(); + } + ++ public Builder setChannelId(String channelId) { ++ content.mChannelId = channelId; ++ return this; ++ } ++ + public Builder setTitle(String title) { + content.mTitle = title; + return this; +diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationData.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationData.kt +index 3af254c..3c77e9d 100644 +--- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationData.kt ++++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationData.kt +@@ -11,6 +11,9 @@ import org.json.JSONObject + * */ + @JvmInline + value class NotificationData(private val data: Map) { ++ val channelId: String? ++ get() = data["channelId"] ++ + val title: String? + get() = data["title"] + +diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/RemoteNotificationContent.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/RemoteNotificationContent.kt +index d2cc6cf..6a48ff2 100644 +--- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/RemoteNotificationContent.kt ++++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/RemoteNotificationContent.kt +@@ -31,6 +31,8 @@ class RemoteNotificationContent(private val remoteMessage: RemoteMessage) : INot + return remoteMessage.notification?.imageUrl != null + } + ++ override val channelId = remoteMessage.notification?.channelId ?: notificationData.channelId ++ + override val title = remoteMessage.notification?.title ?: notificationData.title + + override val text = remoteMessage.notification?.body ?: notificationData.message +diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/ExpoNotificationBuilder.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/ExpoNotificationBuilder.kt +index 98f003f..2f745e8 100644 +--- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/ExpoNotificationBuilder.kt ++++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/ExpoNotificationBuilder.kt +@@ -101,6 +101,9 @@ open class ExpoNotificationBuilder( + builder.setOngoing(content.isSticky) + + // see "Notification anatomy" https://developer.android.com/develop/ui/views/notifications#Templates ++ content.channelId?.let { ++ builder.setChannelId(it) ++ } + builder.setContentTitle(content.title) + builder.setContentText(content.text) + builder.setSubText(content.subText) +diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/service/delegates/FirebaseMessagingDelegate.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/service/delegates/FirebaseMessagingDelegate.kt +index 90ca4ff..9d4cb09 100644 +--- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/service/delegates/FirebaseMessagingDelegate.kt ++++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/service/delegates/FirebaseMessagingDelegate.kt +@@ -3,6 +3,9 @@ package expo.modules.notifications.service.delegates + import android.content.Context + import android.os.Bundle + import com.google.firebase.messaging.RemoteMessage ++import expo.modules.backgroundnotificationhandler.BackgroundNotificationHandler ++import expo.modules.backgroundnotificationhandler.BackgroundNotificationHandlerInterface ++import expo.modules.backgroundnotificationhandler.ExpoBackgroundNotificationHandlerModule + import expo.modules.interfaces.taskManager.TaskServiceProviderHelper + import expo.modules.notifications.notifications.RemoteMessageSerializer + import expo.modules.notifications.notifications.background.BackgroundRemoteNotificationTaskConsumer +@@ -18,7 +21,7 @@ import expo.modules.notifications.tokens.interfaces.FirebaseTokenListener + import java.lang.ref.WeakReference + import java.util.* + +-open class FirebaseMessagingDelegate(protected val context: Context) : FirebaseMessagingDelegate { ++open class FirebaseMessagingDelegate(protected val context: Context) : FirebaseMessagingDelegate, BackgroundNotificationHandlerInterface{ + companion object { + // Unfortunately we cannot save state between instances of a service other way + // than by static properties. Fortunately, using weak references we can +@@ -105,8 +108,19 @@ open class FirebaseMessagingDelegate(protected val context: Context) : FirebaseM + DebugLogging.logRemoteMessage("FirebaseMessagingDelegate.onMessageReceived: message", remoteMessage) + val notification = createNotification(remoteMessage) + DebugLogging.logNotification("FirebaseMessagingDelegate.onMessageReceived: notification", notification) +- NotificationsService.receive(context, notification) +- runTaskManagerTasks(context.applicationContext, RemoteMessageSerializer.toBundle(remoteMessage)) ++ if (!ExpoBackgroundNotificationHandlerModule.isForegrounded) { ++ BackgroundNotificationHandler(context, this).handleMessage(remoteMessage) ++ } else { ++ NotificationsService.receive(context, notification) ++ runTaskManagerTasks( ++ context.applicationContext, ++ RemoteMessageSerializer.toBundle(remoteMessage) ++ ) ++ } ++ } ++ ++ override fun showMessage(remoteMessage: RemoteMessage) { ++ NotificationsService.receive(context, createNotification(remoteMessage)) + } + + protected fun createNotification(remoteMessage: RemoteMessage): Notification { diff --git a/patches/expo-notifications+0.29.11.patch.md b/patches/expo-notifications+0.31.1.patch.md similarity index 100% rename from patches/expo-notifications+0.29.11.patch.md rename to patches/expo-notifications+0.31.1.patch.md diff --git a/patches/expo-updates+0.27.4.patch b/patches/expo-updates+0.28.12.patch similarity index 100% rename from patches/expo-updates+0.27.4.patch rename to patches/expo-updates+0.28.12.patch diff --git a/patches/expo-updates+0.26.10.patch.md b/patches/expo-updates+0.28.12.patch.md similarity index 100% rename from patches/expo-updates+0.26.10.patch.md rename to patches/expo-updates+0.28.12.patch.md diff --git a/patches/react-native+0.76.9.patch b/patches/react-native+0.76.9.patch deleted file mode 100644 index 7e96d875c4..0000000000 --- a/patches/react-native+0.76.9.patch +++ /dev/null @@ -1,366 +0,0 @@ -diff --git a/node_modules/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts b/node_modules/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts -index 62f52a7..ca30165 100644 ---- a/node_modules/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts -+++ b/node_modules/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts -@@ -426,9 +426,10 @@ export interface ViewStyle extends FlexStyle, ShadowStyleIOS, TransformsStyle { - */ - pointerEvents?: 'box-none' | 'none' | 'box-only' | 'auto' | undefined; - isolation?: 'auto' | 'isolate' | undefined; -- cursor?: CursorValue | undefined; -+ cursor?: CursorValue | string | undefined; - boxShadow?: ReadonlyArray | string | undefined; - filter?: ReadonlyArray | string | undefined; -+ transformOrigin?: string | (string | number)[] | undefined; - } - - export type FontVariant = -@@ -536,7 +537,11 @@ export interface TextStyle extends TextStyleIOS, TextStyleAndroid, ViewStyle { - textShadowOffset?: {width: number; height: number} | undefined; - textShadowRadius?: number | undefined; - textTransform?: 'none' | 'capitalize' | 'uppercase' | 'lowercase' | undefined; -- userSelect?: 'auto' | 'none' | 'text' | 'contain' | 'all' | undefined; -+ userSelect?: 'auto' | 'none' | 'text' | 'contain' | 'all' | string | undefined; -+ cursor?: CursorValue | string | undefined; -+ boxShadow?: ReadonlyArray | string | undefined; -+ filter?: ReadonlyArray | string | undefined; -+ transformOrigin?: string | (string | number)[] | undefined; - } - - /** -@@ -558,5 +563,8 @@ export interface ImageStyle extends FlexStyle, ShadowStyleIOS, TransformsStyle { - tintColor?: ColorValue | undefined; - opacity?: AnimatableNumericValue | undefined; - objectFit?: 'cover' | 'contain' | 'fill' | 'scale-down' | undefined; -- cursor?: CursorValue | undefined; -+ cursor?: CursorValue | string | undefined; -+ boxShadow?: ReadonlyArray | string | undefined; -+ filter?: ReadonlyArray | string | undefined; -+ transformOrigin?: string | (string | number)[] | undefined; - } -diff --git a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTEnhancedScrollView.mm b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTEnhancedScrollView.mm -index 93af874..106f8ec 100644 ---- a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTEnhancedScrollView.mm -+++ b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTEnhancedScrollView.mm -@@ -66,28 +66,51 @@ - * ScrollView, we force it to be centered, but when you zoom or the content otherwise - * becomes larger than the ScrollView, there is no padding around the content but it - * can still fill the whole view. -+ * This implementation is based on https://petersteinberger.com/blog/2013/how-to-center-uiscrollview/. - */ --- (void)setContentOffset:(CGPoint)contentOffset -+-(void)centerContentIfNeeded - { -- if (_isSetContentOffsetDisabled) { -+ if (!_centerContent) { - return; - } - -- if (_centerContent && !CGSizeEqualToSize(self.contentSize, CGSizeZero)) { -- CGSize scrollViewSize = self.bounds.size; -- if (self.contentSize.width <= scrollViewSize.width) { -- contentOffset.x = -(scrollViewSize.width - self.contentSize.width) / 2.0; -- } -- if (self.contentSize.height <= scrollViewSize.height) { -- contentOffset.y = -(scrollViewSize.height - self.contentSize.height) / 2.0; -- } -+ CGSize contentSize = self.contentSize; -+ CGSize boundsSize = self.bounds.size; -+ if (CGSizeEqualToSize(contentSize, CGSizeZero) || -+ CGSizeEqualToSize(boundsSize, CGSizeZero)) { -+ return; - } - -+ CGFloat top = 0, left = 0; -+ if (contentSize.width < boundsSize.width) { -+ left = (boundsSize.width - contentSize.width) * 0.5f; -+ } -+ if (contentSize.height < boundsSize.height) { -+ top = (boundsSize.height - contentSize.height) * 0.5f; -+ } -+ self.contentInset = UIEdgeInsetsMake(top, left, top, left); -+} -+ -+- (void)setContentOffset:(CGPoint)contentOffset -+{ -+ if (_isSetContentOffsetDisabled) { -+ return; -+ } - super.contentOffset = CGPointMake( - RCTSanitizeNaNValue(contentOffset.x, @"scrollView.contentOffset.x"), - RCTSanitizeNaNValue(contentOffset.y, @"scrollView.contentOffset.y")); - } - -+- (void)setFrame:(CGRect)frame { -+ [super setFrame:frame]; -+ [self centerContentIfNeeded]; -+} -+ -+- (void)didAddSubview:(UIView *)subview { -+ [super didAddSubview:subview]; -+ [self centerContentIfNeeded]; -+} -+ - - (BOOL)touchesShouldCancelInContentView:(UIView *)view - { - if ([_overridingDelegate respondsToSelector:@selector(touchesShouldCancelInContentView:)]) { -@@ -257,6 +280,10 @@ - } - } - -+- (void)scrollViewDidZoom:(__unused UIScrollView *)scrollView { -+ [self centerContentIfNeeded]; -+} -+ - #pragma mark - - - - (BOOL)isHorizontal:(UIScrollView *)scrollView -diff --git a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.h b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.h -index e9b330f..ec5f58c 100644 ---- a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.h -+++ b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.h -@@ -15,5 +15,8 @@ - @property (nonatomic, copy) NSString *title; - @property (nonatomic, copy) RCTDirectEventBlock onRefresh; - @property (nonatomic, weak) UIScrollView *scrollView; -+@property (nonatomic, copy) UIColor *customTintColor; -+ -+- (void)forwarderBeginRefreshing; - - @end -diff --git a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.m b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.m -index 53bfd04..ff1b1ed 100644 ---- a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.m -+++ b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.m -@@ -23,6 +23,7 @@ - UIColor *_titleColor; - CGFloat _progressViewOffset; - BOOL _hasMovedToWindow; -+ UIColor *_customTintColor; - } - - - (instancetype)init -@@ -58,6 +59,12 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (NSCoder *)aDecoder) - _isInitialRender = false; - } - -+- (void)didMoveToSuperview -+{ -+ [super didMoveToSuperview]; -+ [self setTintColor:_customTintColor]; -+} -+ - - (void)didMoveToWindow - { - [super didMoveToWindow]; -@@ -221,4 +228,50 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (NSCoder *)aDecoder) - } - } - -+// Fix for https://github.com/facebook/react-native/issues/43388 -+// A bug in iOS 17.4 causes the haptic to not play when refreshing if the tintColor -+// is set before the refresh control gets added to the scrollview. We'll call this -+// function whenever the superview changes. We'll also call it if the value of customTintColor -+// changes. -+- (void)setTintColor:(UIColor *)tintColor -+{ -+ if ([self.superview isKindOfClass:[UIScrollView class]] && self.tintColor != tintColor) { -+ [super setTintColor:tintColor]; -+ } -+} -+ -+// This method is used by Bluesky's ExpoScrollForwarder. This allows other React Native -+// libraries to perform a refresh of a scrollview and access the refresh control's onRefresh -+// function. -+- (void)forwarderBeginRefreshing -+{ -+ _refreshingProgrammatically = NO; -+ -+ [self sizeToFit]; -+ -+ if (!self.scrollView) { -+ return; -+ } -+ -+ UIScrollView *scrollView = (UIScrollView *)self.scrollView; -+ -+ [UIView animateWithDuration:0.3 -+ delay:0 -+ options:UIViewAnimationOptionBeginFromCurrentState -+ animations:^(void) { -+ // Whenever we call this method, the scrollview will always be at a position of -+ // -130 or less. Scrolling back to -65 simulates the default behavior of RCTRefreshControl -+ [scrollView setContentOffset:CGPointMake(0, -65)]; -+ } -+ completion:^(__unused BOOL finished) { -+ [super beginRefreshing]; -+ [self setCurrentRefreshingState:super.refreshing]; -+ -+ if (self->_onRefresh) { -+ self->_onRefresh(nil); -+ } -+ } -+ ]; -+} -+ - @end -diff --git a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControlManager.m b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControlManager.m -index 40aaf9c..1c60164 100644 ---- a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControlManager.m -+++ b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControlManager.m -@@ -22,11 +22,12 @@ RCT_EXPORT_MODULE() - - RCT_EXPORT_VIEW_PROPERTY(onRefresh, RCTDirectEventBlock) - RCT_EXPORT_VIEW_PROPERTY(refreshing, BOOL) --RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor) - RCT_EXPORT_VIEW_PROPERTY(title, NSString) - RCT_EXPORT_VIEW_PROPERTY(titleColor, UIColor) - RCT_EXPORT_VIEW_PROPERTY(progressViewOffset, CGFloat) - -+RCT_REMAP_VIEW_PROPERTY(tintColor, customTintColor, UIColor) -+ - RCT_EXPORT_METHOD(setNativeRefreshing : (nonnull NSNumber *)viewTag toRefreshing : (BOOL)refreshing) - { - [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary *viewRegistry) { -diff --git a/node_modules/react-native/React/Views/ScrollView/RCTScrollView.m b/node_modules/react-native/React/Views/ScrollView/RCTScrollView.m -index 6f41b5c..9b4f77f 100644 ---- a/node_modules/react-native/React/Views/ScrollView/RCTScrollView.m -+++ b/node_modules/react-native/React/Views/ScrollView/RCTScrollView.m -@@ -159,26 +159,8 @@ - return !shouldDisableScrollInteraction; - } - --/* -- * Automatically centers the content such that if the content is smaller than the -- * ScrollView, we force it to be centered, but when you zoom or the content otherwise -- * becomes larger than the ScrollView, there is no padding around the content but it -- * can still fill the whole view. -- */ - - (void)setContentOffset:(CGPoint)contentOffset - { -- UIView *contentView = [self contentView]; -- if (contentView && _centerContent && !CGSizeEqualToSize(contentView.frame.size, CGSizeZero)) { -- CGSize subviewSize = contentView.frame.size; -- CGSize scrollViewSize = self.bounds.size; -- if (subviewSize.width <= scrollViewSize.width) { -- contentOffset.x = -(scrollViewSize.width - subviewSize.width) / 2.0; -- } -- if (subviewSize.height <= scrollViewSize.height) { -- contentOffset.y = -(scrollViewSize.height - subviewSize.height) / 2.0; -- } -- } -- - super.contentOffset = CGPointMake( - RCTSanitizeNaNValue(contentOffset.x, @"scrollView.contentOffset.x"), - RCTSanitizeNaNValue(contentOffset.y, @"scrollView.contentOffset.y")); -@@ -433,6 +415,11 @@ static inline void RCTApplyTransformationAccordingLayoutDirection( - // Does nothing - } - -+- (void)setFrame:(CGRect)frame { -+ [super setFrame:frame]; -+ [self centerContentIfNeeded]; -+} -+ - - (void)insertReactSubview:(UIView *)view atIndex:(NSInteger)atIndex - { - [super insertReactSubview:view atIndex:atIndex]; -@@ -449,6 +436,8 @@ static inline void RCTApplyTransformationAccordingLayoutDirection( - _contentView = view; - RCTApplyTransformationAccordingLayoutDirection(_contentView, self.reactLayoutDirection); - [_scrollView addSubview:view]; -+ -+ [self centerContentIfNeeded]; - } - } - -@@ -658,9 +647,46 @@ static inline void RCTApplyTransformationAccordingLayoutDirection( - } - - RCT_SCROLL_EVENT_HANDLER(scrollViewWillBeginDecelerating, onMomentumScrollBegin) --RCT_SCROLL_EVENT_HANDLER(scrollViewDidZoom, onScroll) - RCT_SCROLL_EVENT_HANDLER(scrollViewDidScrollToTop, onScrollToTop) - -+-(void)scrollViewDidZoom : (UIScrollView *)scrollView -+{ -+ [self centerContentIfNeeded]; -+ -+ RCT_SEND_SCROLL_EVENT(onScroll, nil); -+ RCT_FORWARD_SCROLL_EVENT(scrollViewDidZoom : scrollView); -+} -+ -+/* -+ * Automatically centers the content such that if the content is smaller than the -+ * ScrollView, we force it to be centered, but when you zoom or the content otherwise -+ * becomes larger than the ScrollView, there is no padding around the content but it -+ * can still fill the whole view. -+ * This implementation is based on https://petersteinberger.com/blog/2013/how-to-center-uiscrollview/. -+ */ -+-(void)centerContentIfNeeded -+{ -+ if (!_scrollView.centerContent) { -+ return; -+ } -+ -+ CGSize contentSize = self.contentSize; -+ CGSize boundsSize = self.bounds.size; -+ if (CGSizeEqualToSize(contentSize, CGSizeZero) || -+ CGSizeEqualToSize(boundsSize, CGSizeZero)) { -+ return; -+ } -+ -+ CGFloat top = 0, left = 0; -+ if (contentSize.width < boundsSize.width) { -+ left = (boundsSize.width - contentSize.width) * 0.5f; -+ } -+ if (contentSize.height < boundsSize.height) { -+ top = (boundsSize.height - contentSize.height) * 0.5f; -+ } -+ _scrollView.contentInset = UIEdgeInsetsMake(top, left, top, left); -+} -+ - - (void)addScrollListener:(NSObject *)scrollListener - { - [_scrollListeners addObject:scrollListener]; -@@ -939,6 +965,7 @@ RCT_SCROLL_EVENT_HANDLER(scrollViewDidScrollToTop, onScrollToTop) - CGSize contentSize = self.contentSize; - if (!CGSizeEqualToSize(_scrollView.contentSize, contentSize)) { - _scrollView.contentSize = contentSize; -+ [self centerContentIfNeeded]; - } - } - -@@ -1061,6 +1088,22 @@ RCT_SET_AND_PRESERVE_OFFSET(setShowsHorizontalScrollIndicator, showsHorizontalSc - RCT_SET_AND_PRESERVE_OFFSET(setShowsVerticalScrollIndicator, showsVerticalScrollIndicator, BOOL) - RCT_SET_AND_PRESERVE_OFFSET(setZoomScale, zoomScale, CGFloat); - -+- (void)setScrollIndicatorInsets:(UIEdgeInsets)value -+{ -+ [_scrollView setScrollIndicatorInsets:value]; -+} -+ -+- (UIEdgeInsets)scrollIndicatorInsets -+{ -+ UIEdgeInsets verticalScrollIndicatorInsets = [_scrollView verticalScrollIndicatorInsets]; -+ UIEdgeInsets horizontalScrollIndicatorInsets = [_scrollView horizontalScrollIndicatorInsets]; -+ return UIEdgeInsetsMake( -+ verticalScrollIndicatorInsets.top, -+ horizontalScrollIndicatorInsets.left, -+ verticalScrollIndicatorInsets.bottom, -+ horizontalScrollIndicatorInsets.right); -+} -+ - - (void)setAutomaticallyAdjustsScrollIndicatorInsets:(BOOL)automaticallyAdjusts API_AVAILABLE(ios(13.0)) - { - // `automaticallyAdjustsScrollIndicatorInsets` is available since iOS 13. -diff --git a/node_modules/react-native/React/Views/ScrollView/RCTScrollViewManager.m b/node_modules/react-native/React/Views/ScrollView/RCTScrollViewManager.m -index cd1e7eb..c1d0172 100644 ---- a/node_modules/react-native/React/Views/ScrollView/RCTScrollViewManager.m -+++ b/node_modules/react-native/React/Views/ScrollView/RCTScrollViewManager.m -@@ -83,6 +83,7 @@ RCT_EXPORT_VIEW_PROPERTY(showsVerticalScrollIndicator, BOOL) - RCT_EXPORT_VIEW_PROPERTY(scrollEventThrottle, NSTimeInterval) - RCT_EXPORT_VIEW_PROPERTY(zoomScale, CGFloat) - RCT_EXPORT_VIEW_PROPERTY(contentInset, UIEdgeInsets) -+RCT_EXPORT_VIEW_PROPERTY(scrollIndicatorInsets, UIEdgeInsets) - RCT_EXPORT_VIEW_PROPERTY(verticalScrollIndicatorInsets, UIEdgeInsets) - RCT_EXPORT_VIEW_PROPERTY(scrollToOverflowEnabled, BOOL) - RCT_EXPORT_VIEW_PROPERTY(snapToInterval, int) diff --git a/patches/react-native+0.79.2.patch b/patches/react-native+0.79.2.patch new file mode 100644 index 0000000000..609ae66178 --- /dev/null +++ b/patches/react-native+0.79.2.patch @@ -0,0 +1,119 @@ +diff --git a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.h b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.h +index e9b330f..ec5f58c 100644 +--- a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.h ++++ b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.h +@@ -15,5 +15,8 @@ + @property (nonatomic, copy) NSString *title; + @property (nonatomic, copy) RCTDirectEventBlock onRefresh; + @property (nonatomic, weak) UIScrollView *scrollView; ++@property (nonatomic, copy) UIColor *customTintColor; ++ ++- (void)forwarderBeginRefreshing; + + @end +diff --git a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.m b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.m +index 53bfd04..ff1b1ed 100644 +--- a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.m ++++ b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.m +@@ -23,6 +23,7 @@ + UIColor *_titleColor; + CGFloat _progressViewOffset; + BOOL _hasMovedToWindow; ++ UIColor *_customTintColor; + } + + - (instancetype)init +@@ -58,6 +59,12 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (NSCoder *)aDecoder) + _isInitialRender = false; + } + ++- (void)didMoveToSuperview ++{ ++ [super didMoveToSuperview]; ++ [self setTintColor:_customTintColor]; ++} ++ + - (void)didMoveToWindow + { + [super didMoveToWindow]; +@@ -221,4 +228,50 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (NSCoder *)aDecoder) + } + } + ++// Fix for https://github.com/facebook/react-native/issues/43388 ++// A bug in iOS 17.4 causes the haptic to not play when refreshing if the tintColor ++// is set before the refresh control gets added to the scrollview. We'll call this ++// function whenever the superview changes. We'll also call it if the value of customTintColor ++// changes. ++- (void)setTintColor:(UIColor *)tintColor ++{ ++ if ([self.superview isKindOfClass:[UIScrollView class]] && self.tintColor != tintColor) { ++ [super setTintColor:tintColor]; ++ } ++} ++ ++// This method is used by Bluesky's ExpoScrollForwarder. This allows other React Native ++// libraries to perform a refresh of a scrollview and access the refresh control's onRefresh ++// function. ++- (void)forwarderBeginRefreshing ++{ ++ _refreshingProgrammatically = NO; ++ ++ [self sizeToFit]; ++ ++ if (!self.scrollView) { ++ return; ++ } ++ ++ UIScrollView *scrollView = (UIScrollView *)self.scrollView; ++ ++ [UIView animateWithDuration:0.3 ++ delay:0 ++ options:UIViewAnimationOptionBeginFromCurrentState ++ animations:^(void) { ++ // Whenever we call this method, the scrollview will always be at a position of ++ // -130 or less. Scrolling back to -65 simulates the default behavior of RCTRefreshControl ++ [scrollView setContentOffset:CGPointMake(0, -65)]; ++ } ++ completion:^(__unused BOOL finished) { ++ [super beginRefreshing]; ++ [self setCurrentRefreshingState:super.refreshing]; ++ ++ if (self->_onRefresh) { ++ self->_onRefresh(nil); ++ } ++ } ++ ]; ++} ++ + @end +diff --git a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControlManager.m b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControlManager.m +index 40aaf9c..1c60164 100644 +--- a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControlManager.m ++++ b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControlManager.m +@@ -22,11 +22,12 @@ RCT_EXPORT_MODULE() + + RCT_EXPORT_VIEW_PROPERTY(onRefresh, RCTDirectEventBlock) + RCT_EXPORT_VIEW_PROPERTY(refreshing, BOOL) +-RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor) + RCT_EXPORT_VIEW_PROPERTY(title, NSString) + RCT_EXPORT_VIEW_PROPERTY(titleColor, UIColor) + RCT_EXPORT_VIEW_PROPERTY(progressViewOffset, CGFloat) + ++RCT_REMAP_VIEW_PROPERTY(tintColor, customTintColor, UIColor) ++ + RCT_EXPORT_METHOD(setNativeRefreshing : (nonnull NSNumber *)viewTag toRefreshing : (BOOL)refreshing) + { + [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary *viewRegistry) { +diff --git a/node_modules/react-native/React/Views/ScrollView/RCTScrollViewManager.m b/node_modules/react-native/React/Views/ScrollView/RCTScrollViewManager.m +index cd1e7eb..c1d0172 100644 +--- a/node_modules/react-native/React/Views/ScrollView/RCTScrollViewManager.m ++++ b/node_modules/react-native/React/Views/ScrollView/RCTScrollViewManager.m +@@ -83,6 +83,7 @@ RCT_EXPORT_VIEW_PROPERTY(showsVerticalScrollIndicator, BOOL) + RCT_EXPORT_VIEW_PROPERTY(scrollEventThrottle, NSTimeInterval) + RCT_EXPORT_VIEW_PROPERTY(zoomScale, CGFloat) + RCT_EXPORT_VIEW_PROPERTY(contentInset, UIEdgeInsets) ++RCT_EXPORT_VIEW_PROPERTY(scrollIndicatorInsets, UIEdgeInsets) + RCT_EXPORT_VIEW_PROPERTY(verticalScrollIndicatorInsets, UIEdgeInsets) + RCT_EXPORT_VIEW_PROPERTY(scrollToOverflowEnabled, BOOL) + RCT_EXPORT_VIEW_PROPERTY(snapToInterval, int) diff --git a/patches/react-native+0.76.6.patch.md b/patches/react-native+0.79.2.patch.md similarity index 84% rename from patches/react-native+0.76.6.patch.md rename to patches/react-native+0.79.2.patch.md index eacb9f267c..9c93aee5cb 100644 --- a/patches/react-native+0.76.6.patch.md +++ b/patches/react-native+0.79.2.patch.md @@ -11,7 +11,3 @@ in the RN repo: https://github.com/facebook/react-native/issues/43388 Patching `RCTRefreshControl.m` and `RCTRefreshControl.h` to add a new `forwarderBeginRefreshing` method to the class. This method is used by `ExpoScrollForwarder` to initiate a refresh of the underlying `UIScrollView` from inside that module. - -## ScrollView centerContent fix - -Includes https://github.com/facebook/react-native/pull/47591 early. Delete when it's in a release. diff --git a/patches/react-native-gesture-handler+2.20.2.patch b/patches/react-native-gesture-handler+2.25.0.patch similarity index 100% rename from patches/react-native-gesture-handler+2.20.2.patch rename to patches/react-native-gesture-handler+2.25.0.patch diff --git a/patches/react-native-image-crop-picker+0.41.6.patch b/patches/react-native-image-crop-picker+0.42.0.patch similarity index 83% rename from patches/react-native-image-crop-picker+0.41.6.patch rename to patches/react-native-image-crop-picker+0.42.0.patch index 57589931a3..c6124ad1e1 100644 --- a/patches/react-native-image-crop-picker+0.41.6.patch +++ b/patches/react-native-image-crop-picker+0.42.0.patch @@ -1,5 +1,5 @@ diff --git a/node_modules/react-native-image-crop-picker/android/src/main/AndroidManifest.xml b/node_modules/react-native-image-crop-picker/android/src/main/AndroidManifest.xml -index 391f303..8e2c3db 100644 +index a08629b..fab6299 100644 --- a/node_modules/react-native-image-crop-picker/android/src/main/AndroidManifest.xml +++ b/node_modules/react-native-image-crop-picker/android/src/main/AndroidManifest.xml @@ -24,7 +24,7 @@ @@ -8,12 +8,12 @@ index 391f303..8e2c3db 100644 android:name="com.yalantis.ucrop.UCropActivity" - android:theme="@style/Theme.AppCompat.Light.NoActionBar" /> + android:theme="@style/Theme.UCropNoEdgeToEdge" /> - - + + diff --git a/node_modules/react-native-image-crop-picker/android/src/main/res/values-v35/styles.xml b/node_modules/react-native-image-crop-picker/android/src/main/res/values-v35/styles.xml new file mode 100644 -index 0000000..396d5a8 +index 0000000..5301f74 --- /dev/null +++ b/node_modules/react-native-image-crop-picker/android/src/main/res/values-v35/styles.xml @@ -0,0 +1,5 @@ @@ -22,26 +22,27 @@ index 0000000..396d5a8 + true + + +\ No newline at end of file diff --git a/node_modules/react-native-image-crop-picker/android/src/main/res/values/styles.xml b/node_modules/react-native-image-crop-picker/android/src/main/res/values/styles.xml new file mode 100644 -index 0000000..50129b6 +index 0000000..55569aa --- /dev/null +++ b/node_modules/react-native-image-crop-picker/android/src/main/res/values/styles.xml @@ -0,0 +1,3 @@ + +