diff options
author | Paul Frazee <pfrazee@gmail.com> | 2023-03-31 13:17:26 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-03-31 13:17:26 -0500 |
commit | a3334a01a221877d3e06e02f960fda441f3460bd (patch) | |
tree | 64cdbb1232d1a3c00750c346b6e3ae529b51d1b0 /src/state/models/feed-view.ts | |
parent | 19f3a2fa92a61ddb785fc4e42d73792c1d0e772c (diff) | |
download | voidsky-a3334a01a221877d3e06e02f960fda441f3460bd.tar.zst |
Lex refactor (#362)
* Remove the hackcheck for upgrades * Rename the PostEmbeds folder to match the codebase style * Updates to latest lex refactor * Update to use new bsky agent * Update to use api package's richtext library * Switch to upsertProfile * Add TextEncoder/TextDecoder polyfill * Add Intl.Segmenter polyfill * Update composer to calculate lengths by grapheme * Fix detox * Fix login in e2e * Create account e2e passing * Implement an e2e mocking framework * Don't use private methods on mobx models as mobx can't track them * Add tooling for e2e-specific builds and add e2e media-picker mock * Add some tests and fix some bugs around profile editing * Add shell tests * Add home screen tests * Add thread screen tests * Add tests for other user profile screens * Add search screen tests * Implement profile imagery change tools and tests * Update to new embed behaviors * Add post tests * Fix to profile-screen test * Fix session resumption * Update web composer to new api * 1.11.0 * Fix pagination cursor parameters * Add quote posts to notifications * Fix embed layouts * Remove youtube inline player and improve tap handling on link cards * Reset minimal shell mode on all screen loads and feed swipes (close #299) * Update podfile.lock * Improve post notfound UI (close #366) * Bump atproto packages
Diffstat (limited to 'src/state/models/feed-view.ts')
-rw-r--r-- | src/state/models/feed-view.ts | 153 |
1 files changed, 59 insertions, 94 deletions
diff --git a/src/state/models/feed-view.ts b/src/state/models/feed-view.ts index 083863fe2..8b62c958f 100644 --- a/src/state/models/feed-view.ts +++ b/src/state/models/feed-view.ts @@ -1,32 +1,29 @@ import {makeAutoObservable, runInAction} from 'mobx' import { AppBskyFeedGetTimeline as GetTimeline, - AppBskyFeedFeedViewPost, + AppBskyFeedDefs, AppBskyFeedPost, AppBskyFeedGetAuthorFeed as GetAuthorFeed, + RichText, } from '@atproto/api' import AwaitLock from 'await-lock' import {bundleAsync} from 'lib/async/bundle' import sampleSize from 'lodash.samplesize' -type FeedViewPost = AppBskyFeedFeedViewPost.Main -type ReasonRepost = AppBskyFeedFeedViewPost.ReasonRepost -type PostView = AppBskyFeedPost.View -import {AtUri} from '../../third-party/uri' import {RootStoreModel} from './root-store' -import * as apilib from 'lib/api/index' import {cleanError} from 'lib/strings/errors' -import {RichText} from 'lib/strings/rich-text' import {SUGGESTED_FOLLOWS} from 'lib/constants' import { getCombinedCursors, getMultipleAuthorsPosts, mergePosts, } from 'lib/api/build-suggested-posts' - import {FeedTuner, FeedViewPostsSlice} from 'lib/api/feed-manip' -const PAGE_SIZE = 30 +type FeedViewPost = AppBskyFeedDefs.FeedViewPost +type ReasonRepost = AppBskyFeedDefs.ReasonRepost +type PostView = AppBskyFeedDefs.PostView +const PAGE_SIZE = 30 let _idCounter = 0 export class FeedItemModel { @@ -51,11 +48,7 @@ export class FeedItemModel { const valid = AppBskyFeedPost.validateRecord(this.post.record) if (valid.success) { this.postRecord = this.post.record - this.richText = new RichText( - this.postRecord.text, - this.postRecord.entities, - {cleanNewlines: true}, - ) + this.richText = new RichText(this.postRecord, {cleanNewlines: true}) } else { rootStore.log.warn( 'Received an invalid app.bsky.feed.post record', @@ -82,7 +75,7 @@ export class FeedItemModel { copyMetrics(v: FeedViewPost) { this.post.replyCount = v.post.replyCount this.post.repostCount = v.post.repostCount - this.post.upvoteCount = v.post.upvoteCount + this.post.likeCount = v.post.likeCount this.post.viewer = v.post.viewer } @@ -92,68 +85,43 @@ export class FeedItemModel { } } - async toggleUpvote() { - const wasUpvoted = !!this.post.viewer.upvote - const wasDownvoted = !!this.post.viewer.downvote - const res = await this.rootStore.api.app.bsky.feed.setVote({ - subject: { - uri: this.post.uri, - cid: this.post.cid, - }, - direction: wasUpvoted ? 'none' : 'up', - }) - runInAction(() => { - if (wasDownvoted) { - this.post.downvoteCount-- - } - if (wasUpvoted) { - this.post.upvoteCount-- - } else { - this.post.upvoteCount++ - } - this.post.viewer.upvote = res.data.upvote - this.post.viewer.downvote = res.data.downvote - }) - } - - async toggleDownvote() { - const wasUpvoted = !!this.post.viewer.upvote - const wasDownvoted = !!this.post.viewer.downvote - const res = await this.rootStore.api.app.bsky.feed.setVote({ - subject: { - uri: this.post.uri, - cid: this.post.cid, - }, - direction: wasDownvoted ? 'none' : 'down', - }) - runInAction(() => { - if (wasUpvoted) { - this.post.upvoteCount-- - } - if (wasDownvoted) { - this.post.downvoteCount-- - } else { - this.post.downvoteCount++ - } - this.post.viewer.upvote = res.data.upvote - this.post.viewer.downvote = res.data.downvote - }) + async toggleLike() { + if (this.post.viewer?.like) { + await this.rootStore.agent.deleteLike(this.post.viewer.like) + runInAction(() => { + this.post.likeCount = this.post.likeCount || 0 + this.post.viewer = this.post.viewer || {} + this.post.likeCount-- + this.post.viewer.like = undefined + }) + } else { + const res = await this.rootStore.agent.like(this.post.uri, this.post.cid) + runInAction(() => { + this.post.likeCount = this.post.likeCount || 0 + this.post.viewer = this.post.viewer || {} + this.post.likeCount++ + this.post.viewer.like = res.uri + }) + } } async toggleRepost() { - if (this.post.viewer.repost) { - await apilib.unrepost(this.rootStore, this.post.viewer.repost) + if (this.post.viewer?.repost) { + await this.rootStore.agent.deleteRepost(this.post.viewer.repost) runInAction(() => { + this.post.repostCount = this.post.repostCount || 0 + this.post.viewer = this.post.viewer || {} this.post.repostCount-- this.post.viewer.repost = undefined }) } else { - const res = await apilib.repost( - this.rootStore, + const res = await this.rootStore.agent.repost( this.post.uri, this.post.cid, ) runInAction(() => { + this.post.repostCount = this.post.repostCount || 0 + this.post.viewer = this.post.viewer || {} this.post.repostCount++ this.post.viewer.repost = res.uri }) @@ -161,10 +129,7 @@ export class FeedItemModel { } async delete() { - await this.rootStore.api.app.bsky.feed.post.delete({ - did: this.post.author.did, - rkey: new AtUri(this.post.uri).rkey, - }) + await this.rootStore.agent.deletePost(this.post.uri) this.rootStore.emitPostDeleted(this.post.uri) } } @@ -250,7 +215,7 @@ export class FeedModel { tuner = new FeedTuner() // used to linearize async modifications to state - private lock = new AwaitLock() + lock = new AwaitLock() // data slices: FeedSliceModel[] = [] @@ -291,8 +256,8 @@ export class FeedModel { const params = this.params as GetAuthorFeed.QueryParams const item = slice.rootItem const isRepost = - item?.reasonRepost?.by?.handle === params.author || - item?.reasonRepost?.by?.did === params.author + item?.reasonRepost?.by?.handle === params.actor || + item?.reasonRepost?.by?.did === params.actor return ( !item.reply || // not a reply isRepost || // but allow if it's a repost @@ -338,7 +303,7 @@ export class FeedModel { return this.setup() } - private get feedTuners() { + get feedTuners() { if (this.feedType === 'goodstuff') { return [ FeedTuner.dedupReposts, @@ -406,7 +371,7 @@ export class FeedModel { this._xLoading() try { const res = await this._getFeed({ - before: this.loadMoreCursor, + cursor: this.loadMoreCursor, limit: PAGE_SIZE, }) await this._appendAll(res) @@ -439,7 +404,7 @@ export class FeedModel { try { do { const res: GetTimeline.Response = await this._getFeed({ - before: cursor, + cursor, limit: Math.min(numToFetch, 100), }) if (res.data.feed.length === 0) { @@ -478,14 +443,18 @@ export class FeedModel { 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) + runInAction(() => { + this.slices = nextSlicesModels.concat( + this.slices.filter(slice1 => + nextSlicesModels.find(slice2 => slice1.uri === slice2.uri), + ), + ) + this.setHasNewLatest(false) + }) } else { - this.nextSlices = nextSlicesModels + runInAction(() => { + this.nextSlices = nextSlicesModels + }) this.setHasNewLatest(true) } } else { @@ -519,13 +488,13 @@ export class FeedModel { // state transitions // = - private _xLoading(isRefreshing = false) { + _xLoading(isRefreshing = false) { this.isLoading = true this.isRefreshing = isRefreshing this.error = '' } - private _xIdle(err?: any) { + _xIdle(err?: any) { this.isLoading = false this.isRefreshing = false this.hasLoaded = true @@ -538,14 +507,12 @@ export class FeedModel { // helper functions // = - private async _replaceAll( - res: GetTimeline.Response | GetAuthorFeed.Response, - ) { + async _replaceAll(res: GetTimeline.Response | GetAuthorFeed.Response) { this.pollCursor = res.data.feed[0]?.post.uri return this._appendAll(res, true) } - private async _appendAll( + async _appendAll( res: GetTimeline.Response | GetAuthorFeed.Response, replace = false, ) { @@ -572,7 +539,7 @@ export class FeedModel { }) } - private _updateAll(res: GetTimeline.Response | GetAuthorFeed.Response) { + _updateAll(res: GetTimeline.Response | GetAuthorFeed.Response) { for (const item of res.data.feed) { const existingSlice = this.slices.find(slice => slice.containsUri(item.post.uri), @@ -596,7 +563,7 @@ export class FeedModel { const responses = await getMultipleAuthorsPosts( this.rootStore, sampleSize(SUGGESTED_FOLLOWS(String(this.rootStore.agent.service)), 20), - params.before, + params.cursor, 20, ) const combinedCursor = getCombinedCursors(responses) @@ -611,9 +578,7 @@ export class FeedModel { headers: lastHeaders, } } else if (this.feedType === 'home') { - return this.rootStore.api.app.bsky.feed.getTimeline( - params as GetTimeline.QueryParams, - ) + return this.rootStore.agent.getTimeline(params as GetTimeline.QueryParams) } else if (this.feedType === 'goodstuff') { const res = await getGoodStuff( this.rootStore.session.currentSession?.accessJwt || '', @@ -624,7 +589,7 @@ export class FeedModel { ) return res } else { - return this.rootStore.api.app.bsky.feed.getAuthorFeed( + return this.rootStore.agent.getAuthorFeed( params as GetAuthorFeed.QueryParams, ) } |