diff options
Diffstat (limited to 'src/state/models/feed-view.ts')
-rw-r--r-- | src/state/models/feed-view.ts | 134 |
1 files changed, 106 insertions, 28 deletions
diff --git a/src/state/models/feed-view.ts b/src/state/models/feed-view.ts index 2eced3dc9..5264aa27e 100644 --- a/src/state/models/feed-view.ts +++ b/src/state/models/feed-view.ts @@ -1,6 +1,5 @@ import {makeAutoObservable, runInAction} from 'mobx' import {bsky} from '@adxp/mock-api' -import _omit from 'lodash.omit' import {RootStoreModel} from './root-store' import * as apilib from '../lib/api' @@ -39,9 +38,22 @@ export class FeedViewItemModel implements bsky.FeedView.FeedItem { ) { makeAutoObservable(this, {rootStore: false}) this._reactKey = reactKey - Object.assign(this, _omit(v, 'myState')) + this.copy(v) + } + + copy(v: bsky.FeedView.FeedItem) { + this.uri = v.uri + this.author = v.author + this.repostedBy = v.repostedBy + this.record = v.record + this.embed = v.embed + this.replyCount = v.replyCount + this.repostCount = v.repostCount + this.likeCount = v.likeCount + this.indexedAt = v.indexedAt if (v.myState) { - Object.assign(this.myState, v.myState) + this.myState.hasLiked = v.myState.hasLiked + this.myState.hasReposted = v.myState.hasReposted } } @@ -85,7 +97,9 @@ export class FeedViewModel implements bsky.FeedView.Response { hasLoaded = false error = '' params: bsky.FeedView.Params + _loadPromise: Promise<void> | undefined _loadMorePromise: Promise<void> | undefined + _updatePromise: Promise<void> | undefined // data feed: FeedViewItemModel[] = [] @@ -97,6 +111,7 @@ export class FeedViewModel implements bsky.FeedView.Response { rootStore: false, params: false, _loadMorePromise: false, + _updatePromise: false, }, {autoBind: true}, ) @@ -125,33 +140,52 @@ export class FeedViewModel implements bsky.FeedView.Response { // public api // = - async setup() { - if (this._loadMorePromise) { - return this._loadMorePromise - } - if (this.hasContent) { - await this._refresh() - } else { - await this._initialLoad() + /** + * Load for first render + */ + async setup(isRefreshing = false) { + if (this._loadPromise) { + return this._loadPromise } + await this._pendingWork() + this._loadPromise = this._initialLoad(isRefreshing) + await this._loadPromise + this._loadPromise = undefined } + /** + * Reset and load + */ async refresh() { - if (this._loadMorePromise) { - return this._loadMorePromise - } - await this._refresh() + return this.setup(true) } + /** + * Load more posts to the end of the feed + */ async loadMore() { if (this._loadMorePromise) { return this._loadMorePromise } + await this._pendingWork() this._loadMorePromise = this._loadMore() await this._loadMorePromise this._loadMorePromise = undefined } + /** + * Update content in-place + */ + async update() { + if (this._updatePromise) { + return this._updatePromise + } + await this._pendingWork() + this._updatePromise = this._update() + await this._updatePromise + this._updatePromise = undefined + } + // state transitions // = @@ -171,9 +205,21 @@ export class FeedViewModel implements bsky.FeedView.Response { // loader functions // = - private async _initialLoad() { - this._xLoading() - await new Promise(r => setTimeout(r, 1e3)) // DEBUG + private async _pendingWork() { + if (this._loadPromise) { + await this._loadPromise + } + if (this._loadMorePromise) { + await this._loadMorePromise + } + if (this._updatePromise) { + await this._updatePromise + } + } + + private async _initialLoad(isRefreshing = false) { + this._xLoading(isRefreshing) + await new Promise(r => setTimeout(r, 250)) // DEBUG try { const res = (await this.rootStore.api.mainPds.view( 'blueskyweb.xyz:FeedView', @@ -188,7 +234,7 @@ export class FeedViewModel implements bsky.FeedView.Response { private async _loadMore() { this._xLoading() - await new Promise(r => setTimeout(r, 1e3)) // DEBUG + await new Promise(r => setTimeout(r, 250)) // DEBUG try { const params = Object.assign({}, this.params, { before: this.loadMoreCursor, @@ -204,19 +250,37 @@ export class FeedViewModel implements bsky.FeedView.Response { } } - private async _refresh() { - this._xLoading(true) - // TODO: refetch and update items - await new Promise(r => setTimeout(r, 1e3)) // DEBUG - this._xIdle() + private async _update() { + this._xLoading() + await new Promise(r => setTimeout(r, 250)) // DEBUG + let numToFetch = this.feed.length + let cursor = undefined + try { + do { + const res = (await this.rootStore.api.mainPds.view( + 'blueskyweb.xyz:FeedView', + { + before: cursor, + limit: Math.min(numToFetch, 100), + }, + )) as bsky.FeedView.Response + if (res.feed.length === 0) { + break // sanity check + } + this._updateAll(res) + numToFetch -= res.feed.length + cursor = this.feed[res.feed.length - 1].indexedAt + console.log(numToFetch, cursor, res.feed.length) + } while (numToFetch > 0) + this._xIdle() + } catch (e: any) { + this._xIdle(`Failed to update feed: ${e.toString()}`) + } } private _replaceAll(res: bsky.FeedView.Response) { this.feed.length = 0 - let counter = 0 - for (const item of res.feed) { - this._append(counter++, item) - } + this._appendAll(res) } private _appendAll(res: bsky.FeedView.Response) { @@ -230,4 +294,18 @@ export class FeedViewModel implements bsky.FeedView.Response { // TODO: validate .record this.feed.push(new FeedViewItemModel(this.rootStore, `item-${keyId}`, item)) } + + private _updateAll(res: bsky.FeedView.Response) { + for (const item of res.feed) { + const existingItem = this.feed.find( + // this find function has a key subtley- the indexedAt comparison + // the reason for this is reposts: they set the URI of the original post, not of the repost record + // the indexedAt time will be for the repost however, so we use that to help us + item2 => item.uri === item2.uri && item.indexedAt === item2.indexedAt, + ) + if (existingItem) { + existingItem.copy(item) + } + } + } } |