about summary refs log tree commit diff
path: root/src/state/models/feeds/posts.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/state/models/feeds/posts.ts')
-rw-r--r--src/state/models/feeds/posts.ts270
1 files changed, 5 insertions, 265 deletions
diff --git a/src/state/models/feeds/posts.ts b/src/state/models/feeds/posts.ts
index ac32044b4..02ef5f38b 100644
--- a/src/state/models/feeds/posts.ts
+++ b/src/state/models/feeds/posts.ts
@@ -1,11 +1,8 @@
 import {makeAutoObservable, runInAction} from 'mobx'
 import {
   AppBskyFeedGetTimeline as GetTimeline,
-  AppBskyFeedDefs,
-  AppBskyFeedPost,
   AppBskyFeedGetAuthorFeed as GetAuthorFeed,
   AppBskyFeedGetFeed as GetCustomFeed,
-  RichText,
 } from '@atproto/api'
 import AwaitLock from 'await-lock'
 import {bundleAsync} from 'lib/async/bundle'
@@ -19,269 +16,11 @@ import {
   mergePosts,
 } from 'lib/api/build-suggested-posts'
 import {FeedTuner, FeedViewPostsSlice} from 'lib/api/feed-manip'
-import {updateDataOptimistically} from 'lib/async/revertible'
-import {PostLabelInfo, PostModeration} from 'lib/labeling/types'
-import {
-  getEmbedLabels,
-  getEmbedMuted,
-  getEmbedMutedByList,
-  getEmbedBlocking,
-  getEmbedBlockedBy,
-  getPostModeration,
-  mergePostModerations,
-  filterAccountLabels,
-  filterProfileLabels,
-} from 'lib/labeling/helpers'
-
-type FeedViewPost = AppBskyFeedDefs.FeedViewPost
-type ReasonRepost = AppBskyFeedDefs.ReasonRepost
-type PostView = AppBskyFeedDefs.PostView
+import {PostsFeedSliceModel} from './post'
 
 const PAGE_SIZE = 30
 let _idCounter = 0
 
-export class PostsFeedItemModel {
-  // ui state
-  _reactKey: string = ''
-
-  // data
-  post: PostView
-  postRecord?: AppBskyFeedPost.Record
-  reply?: FeedViewPost['reply']
-  reason?: FeedViewPost['reason']
-  richText?: RichText
-
-  constructor(
-    public rootStore: RootStoreModel,
-    reactKey: string,
-    v: FeedViewPost,
-  ) {
-    this._reactKey = reactKey
-    this.post = v.post
-    if (AppBskyFeedPost.isRecord(this.post.record)) {
-      const valid = AppBskyFeedPost.validateRecord(this.post.record)
-      if (valid.success) {
-        this.postRecord = this.post.record
-        this.richText = new RichText(this.postRecord, {cleanNewlines: true})
-      } else {
-        this.postRecord = undefined
-        this.richText = undefined
-        rootStore.log.warn(
-          'Received an invalid app.bsky.feed.post record',
-          valid.error,
-        )
-      }
-    } else {
-      this.postRecord = undefined
-      this.richText = undefined
-      rootStore.log.warn(
-        'app.bsky.feed.getTimeline or app.bsky.feed.getAuthorFeed served an unexpected record type',
-        this.post.record,
-      )
-    }
-    this.reply = v.reply
-    this.reason = v.reason
-    makeAutoObservable(this, {rootStore: false})
-  }
-
-  get rootUri(): string {
-    if (this.reply?.root.uri) {
-      return this.reply.root.uri
-    }
-    return this.post.uri
-  }
-
-  get isThreadMuted() {
-    return this.rootStore.mutedThreads.uris.has(this.rootUri)
-  }
-
-  get labelInfo(): PostLabelInfo {
-    return {
-      postLabels: (this.post.labels || []).concat(
-        getEmbedLabels(this.post.embed),
-      ),
-      accountLabels: filterAccountLabels(this.post.author.labels),
-      profileLabels: filterProfileLabels(this.post.author.labels),
-      isMuted:
-        this.post.author.viewer?.muted ||
-        getEmbedMuted(this.post.embed) ||
-        false,
-      mutedByList:
-        this.post.author.viewer?.mutedByList ||
-        getEmbedMutedByList(this.post.embed),
-      isBlocking:
-        !!this.post.author.viewer?.blocking ||
-        getEmbedBlocking(this.post.embed) ||
-        false,
-      isBlockedBy:
-        !!this.post.author.viewer?.blockedBy ||
-        getEmbedBlockedBy(this.post.embed) ||
-        false,
-    }
-  }
-
-  get moderation(): PostModeration {
-    return getPostModeration(this.rootStore, this.labelInfo)
-  }
-
-  copy(v: FeedViewPost) {
-    this.post = v.post
-    this.reply = v.reply
-    this.reason = v.reason
-  }
-
-  copyMetrics(v: FeedViewPost) {
-    this.post.replyCount = v.post.replyCount
-    this.post.repostCount = v.post.repostCount
-    this.post.likeCount = v.post.likeCount
-    this.post.viewer = v.post.viewer
-  }
-
-  get reasonRepost(): ReasonRepost | undefined {
-    if (this.reason?.$type === 'app.bsky.feed.defs#reasonRepost') {
-      return this.reason as ReasonRepost
-    }
-  }
-
-  async toggleLike() {
-    this.post.viewer = this.post.viewer || {}
-    if (this.post.viewer.like) {
-      const url = this.post.viewer.like
-      await updateDataOptimistically(
-        this.post,
-        () => {
-          this.post.likeCount = (this.post.likeCount || 0) - 1
-          this.post.viewer!.like = undefined
-        },
-        () => this.rootStore.agent.deleteLike(url),
-      )
-    } else {
-      await updateDataOptimistically(
-        this.post,
-        () => {
-          this.post.likeCount = (this.post.likeCount || 0) + 1
-          this.post.viewer!.like = 'pending'
-        },
-        () => this.rootStore.agent.like(this.post.uri, this.post.cid),
-        res => {
-          this.post.viewer!.like = res.uri
-        },
-      )
-    }
-  }
-
-  async toggleRepost() {
-    this.post.viewer = this.post.viewer || {}
-    if (this.post.viewer?.repost) {
-      const url = this.post.viewer.repost
-      await updateDataOptimistically(
-        this.post,
-        () => {
-          this.post.repostCount = (this.post.repostCount || 0) - 1
-          this.post.viewer!.repost = undefined
-        },
-        () => this.rootStore.agent.deleteRepost(url),
-      )
-    } else {
-      await updateDataOptimistically(
-        this.post,
-        () => {
-          this.post.repostCount = (this.post.repostCount || 0) + 1
-          this.post.viewer!.repost = 'pending'
-        },
-        () => this.rootStore.agent.repost(this.post.uri, this.post.cid),
-        res => {
-          this.post.viewer!.repost = res.uri
-        },
-      )
-    }
-  }
-
-  async toggleThreadMute() {
-    if (this.isThreadMuted) {
-      this.rootStore.mutedThreads.uris.delete(this.rootUri)
-    } else {
-      this.rootStore.mutedThreads.uris.add(this.rootUri)
-    }
-  }
-
-  async delete() {
-    await this.rootStore.agent.deletePost(this.post.uri)
-    this.rootStore.emitPostDeleted(this.post.uri)
-  }
-}
-
-export class PostsFeedSliceModel {
-  // ui state
-  _reactKey: string = ''
-
-  // data
-  items: PostsFeedItemModel[] = []
-
-  constructor(
-    public rootStore: RootStoreModel,
-    reactKey: string,
-    slice: FeedViewPostsSlice,
-  ) {
-    this._reactKey = reactKey
-    for (const item of slice.items) {
-      this.items.push(
-        new PostsFeedItemModel(rootStore, `item-${_idCounter++}`, item),
-      )
-    }
-    makeAutoObservable(this, {rootStore: false})
-  }
-
-  get uri() {
-    if (this.isReply) {
-      return this.items[1].post.uri
-    }
-    return this.items[0].post.uri
-  }
-
-  get isThread() {
-    return (
-      this.items.length > 1 &&
-      this.items.every(
-        item => item.post.author.did === this.items[0].post.author.did,
-      )
-    )
-  }
-
-  get isReply() {
-    return this.items.length > 1 && !this.isThread
-  }
-
-  get rootItem() {
-    if (this.isReply) {
-      return this.items[1]
-    }
-    return this.items[0]
-  }
-
-  get moderation() {
-    return mergePostModerations(this.items.map(item => item.moderation))
-  }
-
-  containsUri(uri: string) {
-    return !!this.items.find(item => item.post.uri === uri)
-  }
-
-  isThreadParentAt(i: number) {
-    if (this.items.length === 1) {
-      return false
-    }
-    return i < this.items.length - 1
-  }
-
-  isThreadChildAt(i: number) {
-    if (this.items.length === 1) {
-      return false
-    }
-    return i > 0
-  }
-}
-
 export class PostsFeedModel {
   // state
   isLoading = false
@@ -297,6 +36,7 @@ export class PostsFeedModel {
   loadMoreCursor: string | undefined
   pollCursor: string | undefined
   tuner = new FeedTuner()
+  pageSize = PAGE_SIZE
 
   // used to linearize async modifications to state
   lock = new AwaitLock()
@@ -418,7 +158,7 @@ export class PostsFeedModel {
       this.tuner.reset()
       this._xLoading(isRefreshing)
       try {
-        const res = await this._getFeed({limit: PAGE_SIZE})
+        const res = await this._getFeed({limit: this.pageSize})
         await this._replaceAll(res)
         this._xIdle()
       } catch (e: any) {
@@ -457,7 +197,7 @@ export class PostsFeedModel {
       try {
         const res = await this._getFeed({
           cursor: this.loadMoreCursor,
-          limit: PAGE_SIZE,
+          limit: this.pageSize,
         })
         await this._appendAll(res)
         this._xIdle()
@@ -526,7 +266,7 @@ export class PostsFeedModel {
     if (this.hasNewLatest || this.feedType === 'suggested') {
       return
     }
-    const res = await this._getFeed({limit: PAGE_SIZE})
+    const res = await this._getFeed({limit: this.pageSize})
     const tuner = new FeedTuner()
     const slices = tuner.tune(res.data.feed, this.feedTuners)
     this.setHasNewLatest(slices[0]?.uri !== this.slices[0]?.uri)