about summary refs log tree commit diff
path: root/src/state/models/feeds/custom-feed.ts
diff options
context:
space:
mode:
authorPaul Frazee <pfrazee@gmail.com>2023-05-25 21:17:11 -0500
committerPaul Frazee <pfrazee@gmail.com>2023-05-25 21:17:11 -0500
commit7b6948e6171b448e271f0564efd1f186ccadb9b8 (patch)
treee0d1b6e9f9c863cbff53f8832fd55d03cb670a83 /src/state/models/feeds/custom-feed.ts
parent15c1b6ee157471807a723161066ba4ce5e12c0b5 (diff)
parente832352e9844002408b45291396a3c495be23276 (diff)
downloadvoidsky-7b6948e6171b448e271f0564efd1f186ccadb9b8.tar.zst
Merge branch 'custom-algos' into main
Diffstat (limited to 'src/state/models/feeds/custom-feed.ts')
-rw-r--r--src/state/models/feeds/custom-feed.ts120
1 files changed, 120 insertions, 0 deletions
diff --git a/src/state/models/feeds/custom-feed.ts b/src/state/models/feeds/custom-feed.ts
new file mode 100644
index 000000000..8fc1eb1ec
--- /dev/null
+++ b/src/state/models/feeds/custom-feed.ts
@@ -0,0 +1,120 @@
+import {AppBskyFeedDefs} from '@atproto/api'
+import {makeAutoObservable, runInAction} from 'mobx'
+import {RootStoreModel} from 'state/models/root-store'
+import {sanitizeDisplayName} from 'lib/strings/display-names'
+import {updateDataOptimistically} from 'lib/async/revertible'
+
+export class CustomFeedModel {
+  // data
+  _reactKey: string
+  data: AppBskyFeedDefs.GeneratorView
+  isOnline: boolean
+  isValid: boolean
+
+  constructor(
+    public rootStore: RootStoreModel,
+    view: AppBskyFeedDefs.GeneratorView,
+    isOnline?: boolean,
+    isValid?: boolean,
+  ) {
+    this._reactKey = view.uri
+    this.data = view
+    this.isOnline = isOnline ?? true
+    this.isValid = isValid ?? true
+    makeAutoObservable(
+      this,
+      {
+        rootStore: false,
+      },
+      {autoBind: true},
+    )
+  }
+
+  // local actions
+  // =
+
+  get uri() {
+    return this.data.uri
+  }
+
+  get displayName() {
+    if (this.data.displayName) {
+      return sanitizeDisplayName(this.data.displayName)
+    }
+    return `Feed by @${this.data.creator.handle}`
+  }
+
+  get isSaved() {
+    return this.rootStore.preferences.savedFeeds.includes(this.uri)
+  }
+
+  get isLiked() {
+    return this.data.viewer?.like
+  }
+
+  // public apis
+  // =
+
+  async save() {
+    await this.rootStore.preferences.addSavedFeed(this.uri)
+  }
+
+  async unsave() {
+    await this.rootStore.preferences.removeSavedFeed(this.uri)
+  }
+
+  async like() {
+    try {
+      await updateDataOptimistically(
+        this.data,
+        () => {
+          this.data.viewer = this.data.viewer || {}
+          this.data.viewer.like = 'pending'
+          this.data.likeCount = (this.data.likeCount || 0) + 1
+        },
+        () => this.rootStore.agent.like(this.data.uri, this.data.cid),
+        res => {
+          this.data.viewer = this.data.viewer || {}
+          this.data.viewer.like = res.uri
+        },
+      )
+    } catch (e: any) {
+      this.rootStore.log.error('Failed to like feed', e)
+    }
+  }
+
+  async unlike() {
+    if (!this.data.viewer?.like) {
+      return
+    }
+    try {
+      const likeUri = this.data.viewer.like
+      await updateDataOptimistically(
+        this.data,
+        () => {
+          this.data.viewer = this.data.viewer || {}
+          this.data.viewer.like = undefined
+          this.data.likeCount = (this.data.likeCount || 1) - 1
+        },
+        () => this.rootStore.agent.deleteLike(likeUri),
+      )
+    } catch (e: any) {
+      this.rootStore.log.error('Failed to unlike feed', e)
+    }
+  }
+
+  async reload() {
+    const res = await this.rootStore.agent.app.bsky.feed.getFeedGenerator({
+      feed: this.data.uri,
+    })
+    runInAction(() => {
+      this.data = res.data.view
+      this.isOnline = res.data.isOnline
+      this.isValid = res.data.isValid
+    })
+  }
+
+  serialize() {
+    return JSON.stringify(this.data)
+  }
+}