Bluesky app fork with some witchin' additions 💫 witchsky.app
bluesky fork client
119
fork

Configure Feed

Select the types of activity you want to include in your feed.

demo mode

authored by

Samuel Newman and committed by
Eric Bailey
91f9bc7c c34c67e4

+616 -21
+20
src/lib/api/feed/demo.ts
··· 1 + import {type AppBskyFeedDefs, type BskyAgent} from '@atproto/api' 2 + 3 + import {DEMO_FEED} from '#/lib/demo' 4 + import {type FeedAPI, type FeedAPIResponse} from './types' 5 + 6 + export class DemoFeedAPI implements FeedAPI { 7 + agent: BskyAgent 8 + 9 + constructor({agent}: {agent: BskyAgent}) { 10 + this.agent = agent 11 + } 12 + 13 + async peekLatest(): Promise<AppBskyFeedDefs.FeedViewPost> { 14 + return DEMO_FEED.feed[0] 15 + } 16 + 17 + async fetch(): Promise<FeedAPIResponse> { 18 + return DEMO_FEED 19 + } 20 + }
+516
src/lib/demo.ts
··· 1 + import {type AppBskyFeedGetFeed} from '@atproto/api' 2 + 3 + export const DEMO_FEED = { 4 + feed: [ 5 + { 6 + post: { 7 + uri: 'at://did:plc:vwzwgnygau7ed7b7wt5ux7y2/app.bsky.feed.post/3lng6kvb6uc2a', 8 + cid: 'bafyreifqyej7jivzucaagu22f7jj7rvjcpbzv2kxo27wt47ktduwwdpdae', 9 + author: { 10 + did: 'did:plc:vwzwgnygau7ed7b7wt5ux7y2', 11 + handle: 'someoneelse.bsky.social', 12 + displayName: 'Not David', 13 + avatar: 14 + 'https://cdn.bsky.app/img/avatar/plain/did:plc:vwzwgnygau7ed7b7wt5ux7y2/bafkreifrtz3ngpzz5qmhjliv5toj4nvyjovijxs5e2la67wddhmdhro5he@jpeg', 15 + associated: { 16 + chat: { 17 + allowIncoming: 'following', 18 + }, 19 + }, 20 + viewer: { 21 + muted: false, 22 + blockedBy: false, 23 + following: 24 + 'at://did:plc:p2cp5gopk7mgjegy6wadk3ep/app.bsky.graph.follow/3kcvvfzq6o32a', 25 + followedBy: 26 + 'at://did:plc:vwzwgnygau7ed7b7wt5ux7y2/app.bsky.graph.follow/3jwawchotz22h', 27 + }, 28 + labels: [], 29 + createdAt: '2023-04-27T09:23:54.423Z', 30 + verification: { 31 + verifications: [ 32 + { 33 + issuer: 'did:plc:z72i7hdynmk6r22z27h6tvur', 34 + uri: 'at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.graph.verification/3lndpxt7ur22f', 35 + isValid: true, 36 + createdAt: '2025-04-21T10:48:58.775Z', 37 + }, 38 + ], 39 + verifiedStatus: 'valid', 40 + trustedVerifierStatus: 'none', 41 + }, 42 + }, 43 + record: { 44 + $type: 'app.bsky.feed.post', 45 + createdAt: '2025-04-22T17:15:30.525Z', 46 + langs: ['en'], 47 + reply: { 48 + parent: { 49 + cid: 'bafyreic7wmhywvu5fi4lupswxpmyydqn2gl5kwnt4n4jxvb3lpej2l72ku', 50 + uri: 'at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.feed.post/3lng66dkzu222', 51 + }, 52 + root: { 53 + cid: 'bafyreic7wmhywvu5fi4lupswxpmyydqn2gl5kwnt4n4jxvb3lpej2l72ku', 54 + uri: 'at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.feed.post/3lng66dkzu222', 55 + }, 56 + }, 57 + text: 'sometimes I go to the apple store just to look at them', 58 + }, 59 + replyCount: 0, 60 + repostCount: 0, 61 + likeCount: 6, 62 + quoteCount: 0, 63 + indexedAt: '2025-04-22T17:15:31.251Z', 64 + viewer: { 65 + threadMuted: false, 66 + embeddingDisabled: false, 67 + }, 68 + labels: [], 69 + }, 70 + reply: { 71 + root: { 72 + uri: 'at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.feed.post/3lng66dkzu222', 73 + cid: 'bafyreic7wmhywvu5fi4lupswxpmyydqn2gl5kwnt4n4jxvb3lpej2l72ku', 74 + author: { 75 + did: 'did:plc:vc7f4oafdgxsihk4cry2xpze', 76 + handle: 'jasalterego.bsky.social', 77 + displayName: 'Jerry Appleseed', 78 + avatar: 79 + 'https://cdn.bsky.app/img/avatar/plain/did:plc:vc7f4oafdgxsihk4cry2xpze/bafkreicwxwecqiko2rwwln5y3fqqb2zx6wfg5rxf5r7lukakkq2slqy5hy@jpeg', 80 + associated: { 81 + chat: { 82 + allowIncoming: 'following', 83 + }, 84 + }, 85 + viewer: { 86 + muted: false, 87 + blockedBy: false, 88 + following: 89 + 'at://did:plc:p2cp5gopk7mgjegy6wadk3ep/app.bsky.graph.follow/3jx4rnvlnhl25', 90 + followedBy: 91 + 'at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.graph.follow/3jx4siiniuc2e', 92 + }, 93 + labels: [ 94 + { 95 + cts: '2024-05-17T21:53:59.049Z', 96 + src: 'did:plc:skibpmllbhxvbvwgtjxl3uao', 97 + uri: 'did:plc:vc7f4oafdgxsihk4cry2xpze', 98 + val: 'cringe', 99 + ver: 1, 100 + }, 101 + { 102 + cts: '2024-05-17T21:53:59.049Z', 103 + src: 'did:plc:skibpmllbhxvbvwgtjxl3uao', 104 + uri: 'did:plc:vc7f4oafdgxsihk4cry2xpze', 105 + val: 'elder-watch', 106 + ver: 1, 107 + }, 108 + { 109 + src: 'did:plc:vc7f4oafdgxsihk4cry2xpze', 110 + uri: 'at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.actor.profile/self', 111 + cid: 'bafyreidfiuv3c22vliyu2onazf23zrp35rr7i3upsqa2dsn5cqimmlgugm', 112 + val: '!no-unauthenticated', 113 + cts: '1970-01-01T00:00:00.000Z', 114 + }, 115 + ], 116 + createdAt: '2023-04-23T20:11:04.375Z', 117 + }, 118 + record: { 119 + $type: 'app.bsky.feed.post', 120 + createdAt: '2025-04-22T17:08:29.321Z', 121 + langs: ['en'], 122 + text: "(studying the blade) ow that's the sharp side", 123 + }, 124 + replyCount: 8, 125 + repostCount: 37, 126 + likeCount: 252, 127 + quoteCount: 1, 128 + indexedAt: '2025-04-22T17:08:29.458Z', 129 + viewer: { 130 + threadMuted: false, 131 + embeddingDisabled: false, 132 + }, 133 + labels: [], 134 + $type: 'app.bsky.feed.defs#postView', 135 + }, 136 + parent: { 137 + uri: 'at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.feed.post/3lng66dkzu222', 138 + cid: 'bafyreic7wmhywvu5fi4lupswxpmyydqn2gl5kwnt4n4jxvb3lpej2l72ku', 139 + author: { 140 + did: 'did:plc:vc7f4oafdgxsihk4cry2xpze', 141 + handle: 'jasalterego.bsky.social', 142 + displayName: 'Jerry Appleseed', 143 + avatar: 144 + 'https://cdn.bsky.app/img/avatar/plain/did:plc:vc7f4oafdgxsihk4cry2xpze/bafkreicwxwecqiko2rwwln5y3fqqb2zx6wfg5rxf5r7lukakkq2slqy5hy@jpeg', 145 + associated: { 146 + chat: { 147 + allowIncoming: 'following', 148 + }, 149 + }, 150 + viewer: { 151 + muted: false, 152 + blockedBy: false, 153 + following: 154 + 'at://did:plc:p2cp5gopk7mgjegy6wadk3ep/app.bsky.graph.follow/3jx4rnvlnhl25', 155 + followedBy: 156 + 'at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.graph.follow/3jx4siiniuc2e', 157 + }, 158 + labels: [ 159 + { 160 + cts: '2024-05-17T21:53:59.049Z', 161 + src: 'did:plc:skibpmllbhxvbvwgtjxl3uao', 162 + uri: 'did:plc:vc7f4oafdgxsihk4cry2xpze', 163 + val: 'cringe', 164 + ver: 1, 165 + }, 166 + { 167 + cts: '2024-05-17T21:53:59.049Z', 168 + src: 'did:plc:skibpmllbhxvbvwgtjxl3uao', 169 + uri: 'did:plc:vc7f4oafdgxsihk4cry2xpze', 170 + val: 'elder-watch', 171 + ver: 1, 172 + }, 173 + { 174 + src: 'did:plc:vc7f4oafdgxsihk4cry2xpze', 175 + uri: 'at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.actor.profile/self', 176 + cid: 'bafyreidfiuv3c22vliyu2onazf23zrp35rr7i3upsqa2dsn5cqimmlgugm', 177 + val: '!no-unauthenticated', 178 + cts: '1970-01-01T00:00:00.000Z', 179 + }, 180 + ], 181 + createdAt: '2023-04-23T20:11:04.375Z', 182 + }, 183 + record: { 184 + $type: 'app.bsky.feed.post', 185 + createdAt: '2025-04-22T17:08:29.321Z', 186 + langs: ['en'], 187 + text: '*sees the studio display* i think i hauve covid', 188 + }, 189 + replyCount: 8, 190 + repostCount: 37, 191 + likeCount: 252, 192 + quoteCount: 1, 193 + indexedAt: '2025-04-22T17:08:29.458Z', 194 + viewer: { 195 + threadMuted: false, 196 + embeddingDisabled: false, 197 + }, 198 + labels: [], 199 + $type: 'app.bsky.feed.defs#postView', 200 + }, 201 + }, 202 + }, 203 + { 204 + post: { 205 + uri: 'at://did:plc:qvzn322kmcvd7xtnips5xaun/app.bsky.feed.post/3lnehbwkvzk2z', 206 + cid: 'bafyreidshyla4xoolb7fexhtlqcjjbn6ts7z4xja7gnlinroms5cuqg3fq', 207 + author: { 208 + did: 'did:plc:qvzn322kmcvd7xtnips5xaun', 209 + handle: 'scalzi.com', 210 + displayName: 'John Scalzi', 211 + avatar: 212 + 'https://cdn.bsky.app/img/avatar/plain/did:plc:qvzn322kmcvd7xtnips5xaun/bafkreih4dn5gllculyzb6wlqcqparkax35zloe3bzn2nufeqeilz4sutsu@jpeg', 213 + associated: { 214 + chat: { 215 + allowIncoming: 'following', 216 + }, 217 + }, 218 + 219 + viewer: { 220 + muted: false, 221 + blockedBy: false, 222 + following: 223 + 'at://did:plc:p2cp5gopk7mgjegy6wadk3ep/app.bsky.graph.follow/3kcvvfzq6o32a', 224 + followedBy: 225 + 'at://did:plc:vwzwgnygau7ed7b7wt5ux7y2/app.bsky.graph.follow/3jwawchotz22h', 226 + }, 227 + labels: [], 228 + createdAt: '2023-04-27T16:05:17.859Z', 229 + }, 230 + record: { 231 + $type: 'app.bsky.feed.post', 232 + createdAt: '2025-04-22T00:46:14.095Z', 233 + embed: { 234 + $type: 'app.bsky.embed.images', 235 + images: [ 236 + { 237 + alt: 'Smudge napping on the Eames chair, which is covered in a blanket to avoid getting cat hair on it. ', 238 + aspectRatio: { 239 + height: 2000, 240 + width: 1505, 241 + }, 242 + image: { 243 + $type: 'blob', 244 + ref: { 245 + $link: 246 + 'bafkreigkfbcmttc4r4avknp4y2mlcjlws3sdcat6jcyd2mjr7yvz6sje4q', 247 + }, 248 + mimeType: 'image/jpeg', 249 + size: 833834, 250 + }, 251 + }, 252 + ], 253 + }, 254 + langs: ['en'], 255 + text: 'Smudge found the Eames chair', 256 + }, 257 + embed: { 258 + $type: 'app.bsky.embed.images#view', 259 + images: [ 260 + { 261 + thumb: 262 + 'https://cdn.bsky.app/img/feed_thumbnail/plain/did:plc:qvzn322kmcvd7xtnips5xaun/bafkreigkfbcmttc4r4avknp4y2mlcjlws3sdcat6jcyd2mjr7yvz6sje4q@jpeg', 263 + fullsize: 264 + 'https://cdn.bsky.app/img/feed_fullsize/plain/did:plc:qvzn322kmcvd7xtnips5xaun/bafkreigkfbcmttc4r4avknp4y2mlcjlws3sdcat6jcyd2mjr7yvz6sje4q@jpeg', 265 + alt: 'Smudge napping on the Eames chair, which is covered in a blanket to avoid getting cat hair on it. ', 266 + aspectRatio: { 267 + height: 2000, 268 + width: 1505, 269 + }, 270 + }, 271 + ], 272 + }, 273 + replyCount: 47, 274 + repostCount: 31, 275 + likeCount: 1543, 276 + quoteCount: 0, 277 + indexedAt: '2025-04-22T00:46:17.457Z', 278 + viewer: { 279 + threadMuted: false, 280 + embeddingDisabled: false, 281 + }, 282 + labels: [], 283 + }, 284 + }, 285 + { 286 + post: { 287 + uri: 'at://did:plc:jb2q4yqmgpmefxd4xx66gepm/app.bsky.feed.post/3lng4m2memc2k', 288 + cid: 'bafyreicvgwkd5xkbtu3eh756yodnynqbxoegzzqhhees5ou45t3gq3j6um', 289 + author: { 290 + did: 'did:plc:jb2q4yqmgpmefxd4xx66gepm', 291 + handle: 'visionprofan.bsky.social', 292 + displayName: 'Visionary', 293 + avatar: 294 + 'https://cdn.bsky.app/img/avatar/plain/did:plc:jb2q4yqmgpmefxd4xx66gepm/bafkreibqdpwilgj43m37ksjilzcnzqx2g3njcyiyifvazdar23rs5hlokm@jpeg', 295 + associated: { 296 + chat: { 297 + allowIncoming: 'following', 298 + }, 299 + }, 300 + 301 + viewer: { 302 + muted: false, 303 + blockedBy: false, 304 + following: 305 + 'at://did:plc:p2cp5gopk7mgjegy6wadk3ep/app.bsky.graph.follow/3kcvvfzq6o32a', 306 + followedBy: 307 + 'at://did:plc:vwzwgnygau7ed7b7wt5ux7y2/app.bsky.graph.follow/3jwawchotz22h', 308 + }, 309 + labels: [ 310 + { 311 + cts: '2024-07-14T04:31:55.599Z', 312 + src: 'did:plc:skibpmllbhxvbvwgtjxl3uao', 313 + uri: 'did:plc:jb2q4yqmgpmefxd4xx66gepm', 314 + val: 'cringe', 315 + ver: 1, 316 + }, 317 + ], 318 + createdAt: '2023-04-13T05:48:48.827Z', 319 + }, 320 + record: { 321 + $type: 'app.bsky.feed.post', 322 + createdAt: '2025-04-22T16:40:22.205Z', 323 + embed: { 324 + $type: 'app.bsky.embed.record', 325 + record: { 326 + cid: 'bafyreif6ks7dhjrgrio5guztdhf3byoygbwebbvehi4al2c5kmkevlqdky', 327 + uri: 'at://did:plc:4llrhdclvdlmmynkwsmg5tdc/app.bsky.feed.post/3lnfspxzdd42p', 328 + }, 329 + }, 330 + langs: ['en'], 331 + text: 'Just got my Vision Pro! 🤯\n\nAny recommendations for apps to try out?', 332 + }, 333 + embed: { 334 + $type: 'app.bsky.embed.record#view', 335 + record: { 336 + $type: 'app.bsky.embed.record#viewRecord', 337 + uri: 'at://did:plc:4llrhdclvdlmmynkwsmg5tdc/app.bsky.feed.post/3lnfspxzdd42p', 338 + cid: 'bafyreif6ks7dhjrgrio5guztdhf3byoygbwebbvehi4al2c5kmkevlqdky', 339 + author: { 340 + did: 'did:plc:4llrhdclvdlmmynkwsmg5tdc', 341 + handle: 'atrupar.com', 342 + displayName: 'Aaron Rupar', 343 + avatar: 344 + 'https://cdn.bsky.app/img/avatar/plain/did:plc:4llrhdclvdlmmynkwsmg5tdc/bafkreibmhm3h6ar52pogvolisrzjdhwa2myras5vkxzj67twxn2l6pogwu@jpeg', 345 + associated: { 346 + chat: { 347 + allowIncoming: 'following', 348 + }, 349 + }, 350 + viewer: { 351 + muted: false, 352 + blockedBy: false, 353 + following: 354 + 'at://did:plc:p2cp5gopk7mgjegy6wadk3ep/app.bsky.graph.follow/3l7eals2t4g2k', 355 + }, 356 + labels: [], 357 + createdAt: '2023-04-28T00:47:57.437Z', 358 + }, 359 + value: { 360 + $type: 'app.bsky.feed.post', 361 + createdAt: '2025-04-22T13:43:36.261Z', 362 + embed: { 363 + $type: 'app.bsky.embed.video', 364 + alt: '', 365 + aspectRatio: { 366 + height: 720, 367 + width: 1280, 368 + }, 369 + captions: [ 370 + { 371 + $type: 'app.bsky.embed.video#caption', 372 + file: { 373 + $type: 'blob', 374 + ref: { 375 + $link: 376 + 'bafkreihm7npnefqxqmn7d45lcbxzn4wnowc2abe5hxmd63qlob7fbszola', 377 + }, 378 + mimeType: 'text/vtt', 379 + size: 1339, 380 + }, 381 + lang: 'en', 382 + }, 383 + ], 384 + video: { 385 + $type: 'blob', 386 + ref: { 387 + $link: 388 + 'bafkreihovdkyvql2yswuimm5m35lqyo7tgsfiujm7vrxtfmi4gwej4hkpa', 389 + }, 390 + mimeType: 'video/mp4', 391 + size: 6026932, 392 + }, 393 + }, 394 + facets: [], 395 + langs: ['en'], 396 + 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"', 397 + }, 398 + labels: [], 399 + likeCount: 880, 400 + replyCount: 230, 401 + repostCount: 347, 402 + quoteCount: 145, 403 + indexedAt: '2025-04-22T13:43:37.350Z', 404 + embeds: [ 405 + { 406 + $type: 'app.bsky.embed.video#view', 407 + cid: 'bafkreihovdkyvql2yswuimm5m35lqyo7tgsfiujm7vrxtfmi4gwej4hkpa', 408 + playlist: 409 + 'https://video.bsky.app/watch/did%3Aplc%3A4llrhdclvdlmmynkwsmg5tdc/bafkreihovdkyvql2yswuimm5m35lqyo7tgsfiujm7vrxtfmi4gwej4hkpa/playlist.m3u8', 410 + thumbnail: 411 + 'https://video.bsky.app/watch/did%3Aplc%3A4llrhdclvdlmmynkwsmg5tdc/bafkreihovdkyvql2yswuimm5m35lqyo7tgsfiujm7vrxtfmi4gwej4hkpa/thumbnail.jpg', 412 + alt: '', 413 + aspectRatio: { 414 + height: 720, 415 + width: 1280, 416 + }, 417 + }, 418 + ], 419 + }, 420 + }, 421 + replyCount: 11, 422 + repostCount: 97, 423 + likeCount: 399, 424 + quoteCount: 3, 425 + indexedAt: '2025-04-22T16:40:22.648Z', 426 + viewer: { 427 + threadMuted: false, 428 + embeddingDisabled: false, 429 + }, 430 + labels: [], 431 + }, 432 + }, 433 + { 434 + post: { 435 + uri: 'at://did:plc:5o6k7jvowuyaquloafzn3cfw/app.bsky.feed.post/3lng6lkuhxc2s', 436 + cid: 'bafyreifwapmjx76kz5lkoeejfoes4ct2xhyycfyxwccmyr3mtxht5juyli', 437 + author: { 438 + did: 'did:plc:5o6k7jvowuyaquloafzn3cfw', 439 + handle: 'johndoe.org', 440 + displayName: 'John Doe', 441 + avatar: 442 + 'https://cdn.bsky.app/img/avatar/plain/did:plc:5o6k7jvowuyaquloafzn3cfw/bafkreierrwtdsf5quwprs2xqmmh2lu2k7au2cibyegfpard6wqyjs7nd6i@jpeg', 443 + 444 + viewer: { 445 + muted: false, 446 + blockedBy: false, 447 + following: 448 + 'at://did:plc:p2cp5gopk7mgjegy6wadk3ep/app.bsky.graph.follow/3kcvvfzq6o32a', 449 + followedBy: 450 + 'at://did:plc:vwzwgnygau7ed7b7wt5ux7y2/app.bsky.graph.follow/3jwawchotz22h', 451 + }, 452 + labels: [], 453 + createdAt: '2023-05-16T02:37:39.269Z', 454 + }, 455 + record: { 456 + $type: 'app.bsky.feed.post', 457 + createdAt: '2025-04-22T17:15:53.178Z', 458 + langs: ['en'], 459 + 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!", 460 + }, 461 + replyCount: 13, 462 + repostCount: 121, 463 + likeCount: 345, 464 + quoteCount: 6, 465 + indexedAt: '2025-04-22T17:15:53.351Z', 466 + viewer: { 467 + threadMuted: false, 468 + embeddingDisabled: false, 469 + }, 470 + labels: [], 471 + }, 472 + }, 473 + { 474 + post: { 475 + uri: 'at://did:plc:5ywatwbfxoecxgb4xq6ods72/app.bsky.feed.post/3lng5w2fbvs2g', 476 + cid: 'bafyreigi7d57fudzoybe4u6w7friw6ydz3pmzrdu3bvjwb5mvsvlprk23y', 477 + author: { 478 + did: 'did:plc:5ywatwbfxoecxgb4xq6ods72', 479 + handle: 'cooking.bsky.social', 480 + displayName: 'cooking tips', 481 + avatar: 482 + 'https://cdn.bsky.app/img/avatar/plain/did:plc:5ywatwbfxoecxgb4xq6ods72/bafkreibbsuyy25elibbys5vx25cnkcs6g4ih6dozypa4bomwhkwsi6f5wa@jpeg', 483 + 484 + viewer: { 485 + muted: false, 486 + blockedBy: false, 487 + following: 488 + 'at://did:plc:p2cp5gopk7mgjegy6wadk3ep/app.bsky.graph.follow/3kcvvfzq6o32a', 489 + followedBy: 490 + 'at://did:plc:vwzwgnygau7ed7b7wt5ux7y2/app.bsky.graph.follow/3jwawchotz22h', 491 + }, 492 + labels: [], 493 + createdAt: '2024-05-28T00:18:08.531Z', 494 + }, 495 + record: { 496 + $type: 'app.bsky.feed.post', 497 + createdAt: '2025-04-22T17:03:51.259Z', 498 + langs: ['en'], 499 + text: 'and another thing. I have more things to say. I think. I forget :/', 500 + }, 501 + replyCount: 1, 502 + repostCount: 4, 503 + likeCount: 20, 504 + quoteCount: 0, 505 + indexedAt: '2025-04-22T17:03:52.050Z', 506 + viewer: { 507 + threadMuted: false, 508 + embeddingDisabled: false, 509 + }, 510 + labels: [], 511 + }, 512 + }, 513 + ], 514 + } satisfies AppBskyFeedGetFeed.OutputSchema 515 + 516 + export const BOTTOM_BAR_AVI = 'https://bsky.social/about/hero-social-card.webp'
+13 -9
src/state/queries/post-feed.ts
··· 1 1 import React, {useCallback, useEffect, useRef} from 'react' 2 2 import {AppState} from 'react-native' 3 3 import { 4 - AppBskyActorDefs, 4 + type AppBskyActorDefs, 5 5 AppBskyFeedDefs, 6 - AppBskyFeedPost, 6 + type AppBskyFeedPost, 7 7 AtUri, 8 - BskyAgent, 8 + type BskyAgent, 9 9 moderatePost, 10 - ModerationDecision, 10 + type ModerationDecision, 11 11 } from '@atproto/api' 12 12 import { 13 - InfiniteData, 14 - QueryClient, 15 - QueryKey, 13 + type InfiniteData, 14 + type QueryClient, 15 + type QueryKey, 16 16 useInfiniteQuery, 17 17 } from '@tanstack/react-query' 18 18 19 19 import {AuthorFeedAPI} from '#/lib/api/feed/author' 20 20 import {CustomFeedAPI} from '#/lib/api/feed/custom' 21 + import {DemoFeedAPI} from '#/lib/api/feed/demo' 21 22 import {FollowingFeedAPI} from '#/lib/api/feed/following' 22 23 import {HomeFeedAPI} from '#/lib/api/feed/home' 23 24 import {LikesFeedAPI} from '#/lib/api/feed/likes' 24 25 import {ListFeedAPI} from '#/lib/api/feed/list' 25 26 import {MergeFeedAPI} from '#/lib/api/feed/merge' 26 - import {FeedAPI, ReasonFeedSource} from '#/lib/api/feed/types' 27 + import {type FeedAPI, type ReasonFeedSource} from '#/lib/api/feed/types' 27 28 import {aggregateUserInterests} from '#/lib/api/feed/utils' 28 - import {FeedTuner, FeedTunerFn} from '#/lib/api/feed-manip' 29 + import {FeedTuner, type FeedTunerFn} from '#/lib/api/feed-manip' 29 30 import {DISCOVER_FEED_URI} from '#/lib/constants' 30 31 import {BSKY_FEED_OWNER_DIDS} from '#/lib/constants' 31 32 import {logger} from '#/logger' ··· 59 60 | `feedgen|${FeedUri}` 60 61 | `likes|${ActorDid}` 61 62 | `list|${ListUri}` 63 + | 'demo' 62 64 export interface FeedParams { 63 65 mergeFeedEnabled?: boolean 64 66 mergeFeedSources?: string[] ··· 483 485 } else if (feedDesc.startsWith('list')) { 484 486 const [_, list] = feedDesc.split('|') 485 487 return new ListFeedAPI({agent, feedParams: {list}}) 488 + } else if (feedDesc === 'demo') { 489 + return new DemoFeedAPI({agent}) 486 490 } else { 487 491 // shouldnt happen 488 492 return new FollowingFeedAPI({agent})
+58 -7
src/view/screens/Home.tsx
··· 8 8 import {useSetTitle} from '#/lib/hooks/useSetTitle' 9 9 import {useRequestNotificationsPermission} from '#/lib/notifications/notifications' 10 10 import { 11 - HomeTabNavigatorParams, 12 - NativeStackScreenProps, 11 + type HomeTabNavigatorParams, 12 + type NativeStackScreenProps, 13 13 } from '#/lib/routes/types' 14 14 import {logEvent} from '#/lib/statsig/statsig' 15 15 import {isWeb} from '#/platform/detection' 16 16 import {emitSoftReset} from '#/state/events' 17 - import {SavedFeedSourceInfo, usePinnedFeedsInfos} from '#/state/queries/feed' 18 - import {FeedDescriptor, FeedParams} from '#/state/queries/post-feed' 17 + import { 18 + type SavedFeedSourceInfo, 19 + usePinnedFeedsInfos, 20 + } from '#/state/queries/feed' 21 + import {type FeedDescriptor, type FeedParams} from '#/state/queries/post-feed' 19 22 import {usePreferencesQuery} from '#/state/queries/preferences' 20 - import {UsePreferencesQueryResponse} from '#/state/queries/preferences/types' 23 + import {type UsePreferencesQueryResponse} from '#/state/queries/preferences/types' 21 24 import {useSession} from '#/state/session' 22 25 import {useSetMinimalShellMode} from '#/state/shell' 23 26 import {useLoggedOutViewControls} from '#/state/shell/logged-out' 24 27 import {useSelectedFeed, useSetSelectedFeed} from '#/state/shell/selected-feed' 25 28 import {FeedPage} from '#/view/com/feeds/FeedPage' 26 29 import {HomeHeader} from '#/view/com/home/HomeHeader' 27 - import {Pager, PagerRef, RenderTabBarFnProps} from '#/view/com/pager/Pager' 30 + import { 31 + Pager, 32 + type PagerRef, 33 + type RenderTabBarFnProps, 34 + } from '#/view/com/pager/Pager' 28 35 import {CustomFeedEmptyState} from '#/view/com/posts/CustomFeedEmptyState' 29 36 import {FollowingEmptyState} from '#/view/com/posts/FollowingEmptyState' 30 37 import {FollowingEndOfFeed} from '#/view/com/posts/FollowingEndOfFeed' 31 38 import {NoFeedsPinned} from '#/screens/Home/NoFeedsPinned' 32 39 import * as Layout from '#/components/Layout' 40 + import {useDemoMode} from '#/storage/hooks/demo-mode' 33 41 34 42 type Props = NativeStackScreenProps<HomeTabNavigatorParams, 'Home' | 'Start'> 35 43 export function HomeScreen(props: Props) { ··· 184 192 [setMinimalShellMode], 185 193 ) 186 194 195 + const [demoMode] = useDemoMode() 196 + 187 197 const renderTabBar = React.useCallback( 188 198 (props: RenderTabBarFnProps) => { 199 + if (demoMode) { 200 + return ( 201 + <HomeHeader 202 + key="FEEDS_TAB_BAR" 203 + {...props} 204 + testID="homeScreenFeedTabs" 205 + onPressSelected={onPressSelected} 206 + // @ts-ignore 207 + feeds={[{displayName: 'Following'}, {displayName: 'Discover'}]} 208 + /> 209 + ) 210 + } 189 211 return ( 190 212 <HomeHeader 191 213 key="FEEDS_TAB_BAR" ··· 196 218 /> 197 219 ) 198 220 }, 199 - [onPressSelected, pinnedFeedInfos], 221 + [onPressSelected, pinnedFeedInfos, demoMode], 200 222 ) 201 223 202 224 const renderFollowingEmptyState = React.useCallback(() => { ··· 217 239 : [], 218 240 } 219 241 }, [preferences]) 242 + 243 + if (demoMode) { 244 + return ( 245 + <Pager 246 + ref={pagerRef} 247 + testID="homeScreen" 248 + onPageSelected={onPageSelected} 249 + onPageScrollStateChanged={onPageScrollStateChanged} 250 + renderTabBar={renderTabBar} 251 + initialPage={selectedIndex}> 252 + <FeedPage 253 + testID="demoFeedPage" 254 + isPageFocused 255 + isPageAdjacent={false} 256 + feed="demo" 257 + renderEmptyState={renderCustomFeedEmptyState} 258 + feedInfo={pinnedFeedInfos[0]} 259 + /> 260 + <FeedPage 261 + testID="customFeedPage" 262 + isPageFocused 263 + isPageAdjacent={false} 264 + feed={`feedgen|${PROD_DEFAULT_FEED('whats-hot')}`} 265 + renderEmptyState={renderCustomFeedEmptyState} 266 + feedInfo={pinnedFeedInfos[0]} 267 + /> 268 + </Pager> 269 + ) 270 + } 220 271 221 272 return hasSession ? ( 222 273 <Pager
+9 -5
src/view/shell/bottom-bar/BottomBar.tsx
··· 1 - import React, {ComponentProps} from 'react' 2 - import {GestureResponderEvent, View} from 'react-native' 1 + import React, {type ComponentProps} from 'react' 2 + import {type GestureResponderEvent, View} from 'react-native' 3 3 import Animated from 'react-native-reanimated' 4 4 import {useSafeAreaInsets} from 'react-native-safe-area-context' 5 5 import {msg, plural, Trans} from '@lingui/macro' 6 6 import {useLingui} from '@lingui/react' 7 - import {BottomTabBarProps} from '@react-navigation/bottom-tabs' 7 + import {type BottomTabBarProps} from '@react-navigation/bottom-tabs' 8 8 import {StackActions} from '@react-navigation/native' 9 9 10 10 import {PressableScale} from '#/lib/custom-animations/PressableScale' 11 + import {BOTTOM_BAR_AVI} from '#/lib/demo' 11 12 import {useHaptics} from '#/lib/haptics' 12 13 import {useDedupe} from '#/lib/hooks/useDedupe' 13 14 import {useMinimalShellFooterTransform} from '#/lib/hooks/useMinimalShellTransform' ··· 47 48 Message_Stroke2_Corner0_Rounded as Message, 48 49 Message_Stroke2_Corner0_Rounded_Filled as MessageFilled, 49 50 } from '#/components/icons/Message' 51 + import {useDemoMode} from '#/storage/hooks/demo-mode' 50 52 import {styles} from './BottomBarStyles' 51 53 52 54 type TabOptions = ··· 123 125 playHaptic() 124 126 accountSwitchControl.open() 125 127 }, [accountSwitchControl, playHaptic]) 128 + 129 + const [demoMode] = useDemoMode() 126 130 127 131 return ( 128 132 <> ··· 259 263 {borderColor: pal.text.color}, 260 264 ]}> 261 265 <UserAvatar 262 - avatar={profile?.avatar} 266 + avatar={demoMode ? BOTTOM_BAR_AVI : profile?.avatar} 263 267 size={iconWidth - 3} 264 268 // See https://github.com/bluesky-social/social-app/pull/1801: 265 269 usePlainRNImage={true} ··· 270 274 <View 271 275 style={[styles.ctrlIcon, pal.text, styles.profileIcon]}> 272 276 <UserAvatar 273 - avatar={profile?.avatar} 277 + avatar={demoMode ? BOTTOM_BAR_AVI : profile?.avatar} 274 278 size={iconWidth - 3} 275 279 // See https://github.com/bluesky-social/social-app/pull/1801: 276 280 usePlainRNImage={true}