about summary refs log tree commit diff
path: root/src/state/models
diff options
context:
space:
mode:
Diffstat (limited to 'src/state/models')
-rw-r--r--src/state/models/content/post-thread.ts37
-rw-r--r--src/state/models/ui/preferences.ts30
2 files changed, 60 insertions, 7 deletions
diff --git a/src/state/models/content/post-thread.ts b/src/state/models/content/post-thread.ts
index 7e3650948..2d3a3d64a 100644
--- a/src/state/models/content/post-thread.ts
+++ b/src/state/models/content/post-thread.ts
@@ -241,7 +241,7 @@ export class PostThreadModel {
       res.data.thread as AppBskyFeedDefs.ThreadViewPost,
       thread.uri,
     )
-    sortThread(thread)
+    sortThread(thread, this.rootStore.preferences)
     this.thread = thread
   }
 }
@@ -263,11 +263,16 @@ function pruneReplies(post: MaybePost) {
   }
 }
 
+interface SortSettings {
+  threadDefaultSort: string
+  threadFollowedUsersFirst: boolean
+}
+
 type MaybeThreadItem =
   | PostThreadItemModel
   | AppBskyFeedDefs.NotFoundPost
   | AppBskyFeedDefs.BlockedPost
-function sortThread(item: MaybeThreadItem) {
+function sortThread(item: MaybeThreadItem, opts: SortSettings) {
   if ('notFound' in item) {
     return
   }
@@ -296,13 +301,31 @@ function sortThread(item: MaybeThreadItem) {
       if (modScore(a.moderation) !== modScore(b.moderation)) {
         return modScore(a.moderation) - modScore(b.moderation)
       }
-      if (a.post.likeCount === b.post.likeCount) {
-        return b.post.indexedAt.localeCompare(a.post.indexedAt) // newest
-      } else {
-        return (b.post.likeCount || 0) - (a.post.likeCount || 0) // most likes
+      if (opts.threadFollowedUsersFirst) {
+        const af = a.post.author.viewer?.following
+        const bf = b.post.author.viewer?.following
+        if (af && !bf) {
+          return -1
+        } else if (!af && bf) {
+          return 1
+        }
+      }
+      if (opts.threadDefaultSort === 'oldest') {
+        return a.post.indexedAt.localeCompare(b.post.indexedAt)
+      } else if (opts.threadDefaultSort === 'newest') {
+        return b.post.indexedAt.localeCompare(a.post.indexedAt)
+      } else if (opts.threadDefaultSort === 'most-likes') {
+        if (a.post.likeCount === b.post.likeCount) {
+          return b.post.indexedAt.localeCompare(a.post.indexedAt) // newest
+        } else {
+          return (b.post.likeCount || 0) - (a.post.likeCount || 0) // most likes
+        }
+      } else if (opts.threadDefaultSort === 'random') {
+        return 0.5 - Math.random() // this is vaguely criminal but we can get away with it
       }
+      return b.post.indexedAt.localeCompare(a.post.indexedAt)
     })
-    item.replies.forEach(reply => sortThread(reply))
+    item.replies.forEach(reply => sortThread(reply, opts))
   }
 }
 
diff --git a/src/state/models/ui/preferences.ts b/src/state/models/ui/preferences.ts
index 3790b3a92..03f08bc1b 100644
--- a/src/state/models/ui/preferences.ts
+++ b/src/state/models/ui/preferences.ts
@@ -25,6 +25,7 @@ const VISIBILITY_VALUES = ['ignore', 'warn', 'hide']
 const DEFAULT_LANG_CODES = (deviceLocales || [])
   .concat(['en', 'ja', 'pt', 'de'])
   .slice(0, 6)
+const THREAD_SORT_VALUES = ['oldest', 'newest', 'most-likes', 'random']
 
 export class LabelPreferencesModel {
   nsfw: LabelPreference = 'hide'
@@ -55,6 +56,8 @@ export class PreferencesModel {
   homeFeedRepostsEnabled: boolean = true
   homeFeedQuotePostsEnabled: boolean = true
   homeFeedMergeFeedEnabled: boolean = false
+  threadDefaultSort: string = 'oldest'
+  threadFollowedUsersFirst: boolean = true
   requireAltTextEnabled: boolean = false
 
   // used to linearize async modifications to state
@@ -86,6 +89,8 @@ export class PreferencesModel {
       homeFeedRepostsEnabled: this.homeFeedRepostsEnabled,
       homeFeedQuotePostsEnabled: this.homeFeedQuotePostsEnabled,
       homeFeedMergeFeedEnabled: this.homeFeedMergeFeedEnabled,
+      threadDefaultSort: this.threadDefaultSort,
+      threadFollowedUsersFirst: this.threadFollowedUsersFirst,
       requireAltTextEnabled: this.requireAltTextEnabled,
     }
   }
@@ -189,6 +194,21 @@ export class PreferencesModel {
       ) {
         this.homeFeedMergeFeedEnabled = v.homeFeedMergeFeedEnabled
       }
+      // check if thread sort order is set in preferences, then hydrate
+      if (
+        hasProp(v, 'threadDefaultSort') &&
+        typeof v.threadDefaultSort === 'string' &&
+        THREAD_SORT_VALUES.includes(v.threadDefaultSort)
+      ) {
+        this.threadDefaultSort = v.threadDefaultSort
+      }
+      // check if tread followed-users-first is enabled in preferences, then hydrate
+      if (
+        hasProp(v, 'threadFollowedUsersFirst') &&
+        typeof v.threadFollowedUsersFirst === 'boolean'
+      ) {
+        this.threadFollowedUsersFirst = v.threadFollowedUsersFirst
+      }
       // check if requiring alt text is enabled in preferences, then hydrate
       if (
         hasProp(v, 'requireAltTextEnabled') &&
@@ -494,6 +514,16 @@ export class PreferencesModel {
     this.homeFeedMergeFeedEnabled = !this.homeFeedMergeFeedEnabled
   }
 
+  setThreadDefaultSort(v: string) {
+    if (THREAD_SORT_VALUES.includes(v)) {
+      this.threadDefaultSort = v
+    }
+  }
+
+  toggleThreadFollowedUsersFirst() {
+    this.threadFollowedUsersFirst = !this.threadFollowedUsersFirst
+  }
+
   toggleRequireAltTextEnabled() {
     this.requireAltTextEnabled = !this.requireAltTextEnabled
   }