Bluesky app fork with some witchin' additions 💫

Show more replies in Following (different heuristic) (#4880)

authored by danabra.mov and committed by

GitHub b291a1ed 686d5ebb

+79 -15
+79 -15
src/lib/api/feed-manip.ts
··· 25 25 isParentBlocked: boolean 26 26 } 27 27 28 + type AuthorContext = { 29 + author: AppBskyActorDefs.ProfileViewBasic 30 + parentAuthor: AppBskyActorDefs.ProfileViewBasic | undefined 31 + grandparentAuthor: AppBskyActorDefs.ProfileViewBasic | undefined 32 + rootAuthor: AppBskyActorDefs.ProfileViewBasic | undefined 33 + } 34 + 28 35 export class FeedViewPostsSlice { 29 36 _reactKey: string 30 37 _feedPost: FeedViewPost ··· 159 166 return !!this.items.find(item => item.post.uri === uri) 160 167 } 161 168 162 - getAllAuthors(): AppBskyActorDefs.ProfileViewBasic[] { 169 + getAuthors(): AuthorContext { 163 170 const feedPost = this._feedPost 164 - const authors = [feedPost.post.author] 171 + let author: AppBskyActorDefs.ProfileViewBasic = feedPost.post.author 172 + let parentAuthor: AppBskyActorDefs.ProfileViewBasic | undefined 173 + let grandparentAuthor: AppBskyActorDefs.ProfileViewBasic | undefined 174 + let rootAuthor: AppBskyActorDefs.ProfileViewBasic | undefined 165 175 if (feedPost.reply) { 166 176 if (AppBskyFeedDefs.isPostView(feedPost.reply.parent)) { 167 - authors.push(feedPost.reply.parent.author) 177 + parentAuthor = feedPost.reply.parent.author 168 178 } 169 179 if (feedPost.reply.grandparentAuthor) { 170 - authors.push(feedPost.reply.grandparentAuthor) 180 + grandparentAuthor = feedPost.reply.grandparentAuthor 171 181 } 172 182 if (AppBskyFeedDefs.isPostView(feedPost.reply.root)) { 173 - authors.push(feedPost.reply.root.author) 183 + rootAuthor = feedPost.reply.root.author 174 184 } 175 185 } 176 - return authors 186 + return { 187 + author, 188 + parentAuthor, 189 + grandparentAuthor, 190 + rootAuthor, 191 + } 177 192 } 178 193 } 179 194 ··· 252 267 !slice.isRepost && 253 268 // This is not perfect but it's close as we can get to 254 269 // detecting threads without having to peek ahead. 255 - !areSameAuthor(slice.getAllAuthors()) 270 + !areSameAuthor(slice.getAuthors()) 256 271 ) { 257 272 slices.splice(i, 1) 258 273 i-- ··· 333 348 if ( 334 349 slice.isReply && 335 350 !slice.isRepost && 336 - !isFollowingAll(slice.getAllAuthors(), userDid) 351 + !shouldDisplayReplyInFollowing(slice.getAuthors(), userDid) 337 352 ) { 338 353 slices.splice(i, 1) 339 354 i-- ··· 389 404 } 390 405 } 391 406 392 - function areSameAuthor(authors: AppBskyActorDefs.ProfileViewBasic[]): boolean { 393 - const dids = authors.map(a => a.did) 394 - const set = new Set(dids) 395 - return set.size === 1 407 + function areSameAuthor(authors: AuthorContext): boolean { 408 + const {author, parentAuthor, grandparentAuthor, rootAuthor} = authors 409 + const authorDid = author.did 410 + if (parentAuthor && parentAuthor.did !== authorDid) { 411 + return false 412 + } 413 + if (grandparentAuthor && grandparentAuthor.did !== authorDid) { 414 + return false 415 + } 416 + if (rootAuthor && rootAuthor.did !== authorDid) { 417 + return false 418 + } 419 + return true 396 420 } 397 421 398 - function isFollowingAll( 399 - authors: AppBskyActorDefs.ProfileViewBasic[], 422 + function shouldDisplayReplyInFollowing( 423 + authors: AuthorContext, 400 424 userDid: string, 401 425 ): boolean { 402 - return authors.every(a => a.did === userDid || a.viewer?.following) 426 + const {author, parentAuthor, grandparentAuthor, rootAuthor} = authors 427 + if (!isSelfOrFollowing(author, userDid)) { 428 + // Only show replies from self or people you follow. 429 + return false 430 + } 431 + if (!parentAuthor || !grandparentAuthor || !rootAuthor) { 432 + // Don't surface orphaned reply subthreads. 433 + return false 434 + } 435 + if ( 436 + parentAuthor.did === author.did && 437 + grandparentAuthor.did === author.did && 438 + rootAuthor.did === author.did 439 + ) { 440 + // Always show self-threads. 441 + return true 442 + } 443 + // From this point on we need at least one more reason to show it. 444 + if ( 445 + parentAuthor.did !== author.did && 446 + isSelfOrFollowing(parentAuthor, userDid) 447 + ) { 448 + return true 449 + } 450 + if ( 451 + grandparentAuthor.did !== author.did && 452 + isSelfOrFollowing(grandparentAuthor, userDid) 453 + ) { 454 + return true 455 + } 456 + if (rootAuthor.did !== author.did && isSelfOrFollowing(rootAuthor, userDid)) { 457 + return true 458 + } 459 + return false 460 + } 461 + 462 + function isSelfOrFollowing( 463 + profile: AppBskyActorDefs.ProfileViewBasic, 464 + userDid: string, 465 + ) { 466 + return Boolean(profile.did === userDid || profile.viewer?.following) 403 467 }