diff --git a/src/lib/api/feed-manip.ts b/src/lib/api/feed-manip.ts
index a54b7d25d..e9a32b7a6 100644
--- a/src/lib/api/feed-manip.ts
+++ b/src/lib/api/feed-manip.ts
@@ -10,10 +10,12 @@ export type FeedTunerFn = (
) => void
export class FeedViewPostsSlice {
+ isFlattenedReply = false
+
constructor(public items: FeedViewPost[] = []) {}
get uri() {
- if (this.isReply) {
+ if (this.isFlattenedReply) {
return this.items[1].post.uri
}
return this.items[0].post.uri
@@ -39,12 +41,8 @@ export class FeedViewPostsSlice {
return this.isThread && !this.items[0].reply
}
- get isReply() {
- return this.items.length > 1 && !this.isThread
- }
-
get rootItem() {
- if (this.isReply) {
+ if (this.isFlattenedReply) {
return this.items[1]
}
return this.items[0]
@@ -70,6 +68,7 @@ export class FeedViewPostsSlice {
flattenReplyParent() {
if (this.items[0].reply?.parent) {
+ this.isFlattenedReply = true
this.items.splice(0, 0, {post: this.items[0].reply?.parent})
}
}
@@ -105,6 +104,11 @@ export class FeedTuner {
slices.unshift(new FeedViewPostsSlice([item]))
}
+ // run the custom tuners
+ for (const tunerFn of tunerFns) {
+ tunerFn(this, slices)
+ }
+
// remove any items already "seen"
const soonToBeSeenUris: Set<string> = new Set()
for (let i = slices.length - 1; i >= 0; i--) {
@@ -135,11 +139,6 @@ export class FeedTuner {
// sort by slice roots' timestamps
slices.sort((a, b) => b.ts.localeCompare(a.ts))
- // run the custom tuners
- for (const tunerFn of tunerFns) {
- tunerFn(this, slices)
- }
-
for (const slice of slices) {
for (const item of slice.items) {
this.seenUris.add(item.post.uri)
@@ -170,12 +169,12 @@ export class FeedTuner {
static likedRepliesOnly(tuner: FeedTuner, slices: FeedViewPostsSlice[]) {
// remove any replies without at least 2 likes
for (let i = slices.length - 1; i >= 0; i--) {
- if (slices[i].isFullThread) {
+ if (slices[i].isFullThread || !slices[i].rootItem.reply) {
continue
}
const item = slices[i].rootItem
const isRepost = Boolean(item.reason)
- if (item.reply && !isRepost && item.post.upvoteCount < 2) {
+ if (!isRepost && item.post.upvoteCount < 2) {
slices.splice(i, 1)
}
}
diff --git a/src/state/models/feed-view.ts b/src/state/models/feed-view.ts
index 954c19a8d..083863fe2 100644
--- a/src/state/models/feed-view.ts
+++ b/src/state/models/feed-view.ts
@@ -254,6 +254,7 @@ export class FeedModel {
// data
slices: FeedSliceModel[] = []
+ nextSlices: FeedSliceModel[] = []
constructor(
public rootStore: RootStoreModel,
@@ -325,6 +326,7 @@ export class FeedModel {
this.loadMoreCursor = undefined
this.pollCursor = undefined
this.slices = []
+ this.nextSlices = []
this.tuner.reset()
}
@@ -423,30 +425,6 @@ export class FeedModel {
})
/**
- * Load more posts to the start of the feed
- */
- loadLatest = bundleAsync(async () => {
- await this.lock.acquireAsync()
- try {
- this.setHasNewLatest(false)
- this._xLoading()
- try {
- const res = await this._getFeed({limit: PAGE_SIZE})
- await this._prependAll(res)
- this._xIdle()
- } catch (e: any) {
- this._xIdle() // don't bubble the error to the user
- this.rootStore.log.error('FeedView: Failed to load latest', {
- params: this.params,
- e,
- })
- }
- } finally {
- this.lock.release()
- }
- })
-
- /**
* Update content in-place
*/
update = bundleAsync(async () => {
@@ -487,22 +465,42 @@ export class FeedModel {
/**
* Check if new posts are available
*/
- async checkForLatest() {
+ async checkForLatest({autoPrepend}: {autoPrepend?: boolean} = {}) {
if (this.hasNewLatest || this.feedType === 'suggested') {
return
}
- const res = await this._getFeed({limit: 1})
- const currentLatestUri = this.pollCursor
- const item = res.data.feed?.[0]
- if (!item) {
- return
- }
- if (AppBskyFeedFeedViewPost.isReasonRepost(item.reason)) {
- if (item.reason.by.did === this.rootStore.me.did) {
- return // ignore reposts by the user
+ const res = await this._getFeed({limit: PAGE_SIZE})
+ const tuner = new FeedTuner()
+ const nextSlices = tuner.tune(res.data.feed, this.feedTuners)
+ if (nextSlices[0]?.uri !== this.slices[0]?.uri) {
+ const nextSlicesModels = nextSlices.map(
+ slice =>
+ new FeedSliceModel(this.rootStore, `item-${_idCounter++}`, slice),
+ )
+ if (autoPrepend) {
+ this.slices = nextSlicesModels.concat(
+ this.slices.filter(slice1 =>
+ nextSlicesModels.find(slice2 => slice1.uri === slice2.uri),
+ ),
+ )
+ this.setHasNewLatest(false)
+ } else {
+ this.nextSlices = nextSlicesModels
+ this.setHasNewLatest(true)
}
+ } else {
+ this.setHasNewLatest(false)
+ }
+ }
+
+ /**
+ * Sets the current slices to the "next slices" loaded by checkForLatest
+ */
+ resetToLatest() {
+ if (this.nextSlices.length) {
+ this.slices = this.nextSlices
}
- this.setHasNewLatest(item.post.uri !== currentLatestUri)
+ this.setHasNewLatest(false)
}
/**
@@ -574,27 +572,6 @@ export class FeedModel {
})
}
- private async _prependAll(
- res: GetTimeline.Response | GetAuthorFeed.Response,
- ) {
- this.pollCursor = res.data.feed[0]?.post.uri
-
- const slices = this.tuner.tune(res.data.feed, this.feedTuners)
-
- const toPrepend: FeedSliceModel[] = []
- for (const slice of slices) {
- const itemModel = new FeedSliceModel(
- this.rootStore,
- `item-${_idCounter++}`,
- slice,
- )
- toPrepend.push(itemModel)
- }
- runInAction(() => {
- this.slices = toPrepend.concat(this.slices)
- })
- }
-
private _updateAll(res: GetTimeline.Response | GetAuthorFeed.Response) {
for (const item of res.data.feed) {
const existingSlice = this.slices.find(slice =>
diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx
index e10e801e4..572eea927 100644
--- a/src/view/com/composer/Composer.tsx
+++ b/src/view/com/composer/Composer.tsx
@@ -166,7 +166,7 @@ export const ComposePost = observer(function ComposePost({
setIsProcessing(false)
return
}
- store.me.mainFeed.loadLatest()
+ store.me.mainFeed.checkForLatest({autoPrepend: true})
onPost?.()
hackfixOnClose()
Toast.show(`Your ${replyTo ? 'reply' : 'post'} has been published`)
diff --git a/src/view/screens/Home.tsx b/src/view/screens/Home.tsx
index 505f9e723..4f2bc4c15 100644
--- a/src/view/screens/Home.tsx
+++ b/src/view/screens/Home.tsx
@@ -158,7 +158,7 @@ const FeedPage = observer(
}, [feed])
const onPressLoadLatest = React.useCallback(() => {
- feed.refresh()
+ feed.resetToLatest()
scrollToTop()
}, [feed, scrollToTop])
diff --git a/src/view/screens/Notifications.tsx b/src/view/screens/Notifications.tsx
index b704f9c45..7da563843 100644
--- a/src/view/screens/Notifications.tsx
+++ b/src/view/screens/Notifications.tsx
@@ -74,7 +74,8 @@ export const NotificationsScreen = withAuthRequired(
React.useCallback(() => {
store.log.debug('NotificationsScreen: Updating feed')
const softResetSub = store.onScreenSoftReset(scrollToTop)
- store.me.notifications.update()
+ store.me.notifications.loadUnreadCount()
+ store.me.notifications.loadLatest()
screen('Notifications')
return () => {
|