about summary refs log tree commit diff
path: root/src/state/models/ui
diff options
context:
space:
mode:
Diffstat (limited to 'src/state/models/ui')
-rw-r--r--src/state/models/ui/preferences.ts56
-rw-r--r--src/state/models/ui/profile.ts61
-rw-r--r--src/state/models/ui/shell.ts35
3 files changed, 122 insertions, 30 deletions
diff --git a/src/state/models/ui/preferences.ts b/src/state/models/ui/preferences.ts
index e1c0b1f71..23668a3dc 100644
--- a/src/state/models/ui/preferences.ts
+++ b/src/state/models/ui/preferences.ts
@@ -1,9 +1,14 @@
 import {makeAutoObservable, runInAction} from 'mobx'
+import {LabelPreference as APILabelPreference} from '@atproto/api'
 import AwaitLock from 'await-lock'
 import isEqual from 'lodash.isequal'
 import {isObj, hasProp} from 'lib/type-guards'
 import {RootStoreModel} from '../root-store'
-import {ComAtprotoLabelDefs, AppBskyActorDefs} from '@atproto/api'
+import {
+  ComAtprotoLabelDefs,
+  AppBskyActorDefs,
+  ModerationOpts,
+} from '@atproto/api'
 import {LabelValGroup} from 'lib/labeling/types'
 import {getLabelValueGroup} from 'lib/labeling/helpers'
 import {
@@ -16,7 +21,8 @@ import {DEFAULT_FEEDS} from 'lib/constants'
 import {isIOS, deviceLocales} from 'platform/detection'
 import {LANGUAGES} from '../../../locale/languages'
 
-export type LabelPreference = 'show' | 'warn' | 'hide'
+// TEMP we need to permanently convert 'show' to 'ignore', for now we manually convert -prf
+export type LabelPreference = APILabelPreference | 'show'
 const LABEL_GROUPS = [
   'nsfw',
   'nudity',
@@ -408,6 +414,44 @@ export class PreferencesModel {
     return res
   }
 
+  get moderationOpts(): ModerationOpts {
+    return {
+      userDid: this.rootStore.session.currentSession?.did || '',
+      adultContentEnabled: this.adultContentEnabled,
+      labels: {
+        // TEMP translate old settings until this UI can be migrated -prf
+        porn: tempfixLabelPref(this.contentLabels.nsfw),
+        sexual: tempfixLabelPref(this.contentLabels.suggestive),
+        nudity: tempfixLabelPref(this.contentLabels.nudity),
+        nsfl: tempfixLabelPref(this.contentLabels.gore),
+        corpse: tempfixLabelPref(this.contentLabels.gore),
+        gore: tempfixLabelPref(this.contentLabels.gore),
+        torture: tempfixLabelPref(this.contentLabels.gore),
+        'self-harm': tempfixLabelPref(this.contentLabels.gore),
+        'intolerant-race': tempfixLabelPref(this.contentLabels.hate),
+        'intolerant-gender': tempfixLabelPref(this.contentLabels.hate),
+        'intolerant-sexual-orientation': tempfixLabelPref(
+          this.contentLabels.hate,
+        ),
+        'intolerant-religion': tempfixLabelPref(this.contentLabels.hate),
+        intolerant: tempfixLabelPref(this.contentLabels.hate),
+        'icon-intolerant': tempfixLabelPref(this.contentLabels.hate),
+        spam: tempfixLabelPref(this.contentLabels.spam),
+        impersonation: tempfixLabelPref(this.contentLabels.impersonation),
+        scam: 'warn',
+      },
+      labelers: [
+        {
+          labeler: {
+            did: '',
+            displayName: 'Bluesky Social',
+          },
+          labels: {},
+        },
+      ],
+    }
+  }
+
   async setSavedFeeds(saved: string[], pinned: string[]) {
     const oldSaved = this.savedFeeds
     const oldPinned = this.pinnedFeeds
@@ -485,3 +529,11 @@ export class PreferencesModel {
     this.requireAltTextEnabled = !this.requireAltTextEnabled
   }
 }
+
+// TEMP we need to permanently convert 'show' to 'ignore', for now we manually convert -prf
+function tempfixLabelPref(pref: LabelPreference): APILabelPreference {
+  if (pref === 'show') {
+    return 'ignore'
+  }
+  return pref
+}
diff --git a/src/state/models/ui/profile.ts b/src/state/models/ui/profile.ts
index a0249d768..9dae09ec5 100644
--- a/src/state/models/ui/profile.ts
+++ b/src/state/models/ui/profile.ts
@@ -6,8 +6,9 @@ import {ActorFeedsModel} from '../lists/actor-feeds'
 import {ListsListModel} from '../lists/lists-list'
 
 export enum Sections {
-  Posts = 'Posts',
+  PostsNoReplies = 'Posts',
   PostsWithReplies = 'Posts & replies',
+  PostsWithMedia = 'Media',
   CustomAlgorithms = 'Feeds',
   Lists = 'Lists',
 }
@@ -46,6 +47,7 @@ export class ProfileUiModel {
     this.feed = new PostsFeedModel(rootStore, 'author', {
       actor: params.user,
       limit: 10,
+      filter: 'posts_no_replies',
     })
     this.algos = new ActorFeedsModel(rootStore, {actor: params.user})
     this.lists = new ListsListModel(rootStore, params.user)
@@ -53,8 +55,9 @@ export class ProfileUiModel {
 
   get currentView(): PostsFeedModel | ActorFeedsModel | ListsListModel {
     if (
-      this.selectedView === Sections.Posts ||
-      this.selectedView === Sections.PostsWithReplies
+      this.selectedView === Sections.PostsNoReplies ||
+      this.selectedView === Sections.PostsWithReplies ||
+      this.selectedView === Sections.PostsWithMedia
     ) {
       return this.feed
     } else if (this.selectedView === Sections.Lists) {
@@ -76,7 +79,11 @@ export class ProfileUiModel {
   }
 
   get selectorItems() {
-    const items = [Sections.Posts, Sections.PostsWithReplies]
+    const items = [
+      Sections.PostsNoReplies,
+      Sections.PostsWithReplies,
+      Sections.PostsWithMedia,
+    ]
     if (this.algos.hasLoaded && !this.algos.isEmpty) {
       items.push(Sections.CustomAlgorithms)
     }
@@ -90,7 +97,7 @@ export class ProfileUiModel {
     // If, for whatever reason, the selected view index is not available, default back to posts
     // This can happen when the user was focused on a view but performed an action that caused
     // the view to disappear (e.g. deleting the last list in their list of lists https://imgflip.com/i/7txu1y)
-    return this.selectorItems[this.selectedViewIndex] || Sections.Posts
+    return this.selectorItems[this.selectedViewIndex] || Sections.PostsNoReplies
   }
 
   get uiItems() {
@@ -107,26 +114,25 @@ export class ProfileUiModel {
         },
       ])
     } else {
-      // not loading, no error, show content
       if (
-        this.selectedView === Sections.Posts ||
+        this.selectedView === Sections.PostsNoReplies ||
         this.selectedView === Sections.PostsWithReplies ||
-        this.selectedView === Sections.CustomAlgorithms
+        this.selectedView === Sections.PostsWithMedia
       ) {
         if (this.feed.hasContent) {
-          if (this.selectedView === Sections.CustomAlgorithms) {
-            arr = this.algos.feeds
-          } else if (this.selectedView === Sections.Posts) {
-            arr = this.feed.nonReplyFeed
-          } else {
-            arr = this.feed.slices.slice()
-          }
+          arr = this.feed.slices.slice()
           if (!this.feed.hasMore) {
             arr = arr.concat([ProfileUiModel.END_ITEM])
           }
         } else if (this.feed.isEmpty) {
           arr = arr.concat([ProfileUiModel.EMPTY_ITEM])
         }
+      } else if (this.selectedView === Sections.CustomAlgorithms) {
+        if (this.algos.hasContent) {
+          arr = this.algos.feeds
+        } else if (this.algos.isEmpty) {
+          arr = arr.concat([ProfileUiModel.EMPTY_ITEM])
+        }
       } else if (this.selectedView === Sections.Lists) {
         if (this.lists.hasContent) {
           arr = this.lists.lists
@@ -143,8 +149,9 @@ export class ProfileUiModel {
 
   get showLoadingMoreFooter() {
     if (
-      this.selectedView === Sections.Posts ||
-      this.selectedView === Sections.PostsWithReplies
+      this.selectedView === Sections.PostsNoReplies ||
+      this.selectedView === Sections.PostsWithReplies ||
+      this.selectedView === Sections.PostsWithMedia
     ) {
       return this.feed.hasContent && this.feed.hasMore && this.feed.isLoading
     } else if (this.selectedView === Sections.Lists) {
@@ -157,7 +164,27 @@ export class ProfileUiModel {
   // =
 
   setSelectedViewIndex(index: number) {
+    // ViewSelector fires onSelectView on mount
+    if (index === this.selectedViewIndex) return
+
     this.selectedViewIndex = index
+
+    let filter = 'posts_no_replies'
+    if (this.selectedView === Sections.PostsWithReplies) {
+      filter = 'posts_with_replies'
+    } else if (this.selectedView === Sections.PostsWithMedia) {
+      filter = 'posts_with_media'
+    }
+
+    this.feed = new PostsFeedModel(this.rootStore, 'author', {
+      actor: this.params.user,
+      limit: 10,
+      filter,
+    })
+
+    if (this.currentView instanceof PostsFeedModel) {
+      this.feed.setup()
+    }
   }
 
   async setup() {
diff --git a/src/state/models/ui/shell.ts b/src/state/models/ui/shell.ts
index e33a34acf..92d028c79 100644
--- a/src/state/models/ui/shell.ts
+++ b/src/state/models/ui/shell.ts
@@ -1,4 +1,4 @@
-import {AppBskyEmbedRecord} from '@atproto/api'
+import {AppBskyEmbedRecord, ModerationUI} from '@atproto/api'
 import {RootStoreModel} from '../root-store'
 import {makeAutoObservable, runInAction} from 'mobx'
 import {ProfileModel} from '../content/profile'
@@ -42,16 +42,21 @@ export interface ServerInputModal {
   onSelect: (url: string) => void
 }
 
-export interface ReportPostModal {
-  name: 'report-post'
-  postUri: string
-  postCid: string
+export interface ModerationDetailsModal {
+  name: 'moderation-details'
+  context: 'account' | 'content'
+  moderation: ModerationUI
 }
 
-export interface ReportAccountModal {
-  name: 'report-account'
-  did: string
-}
+export type ReportModal = {
+  name: 'report'
+} & (
+  | {
+      uri: string
+      cid: string
+    }
+  | {did: string}
+)
 
 export interface CreateOrEditMuteListModal {
   name: 'create-or-edit-mute-list'
@@ -94,6 +99,13 @@ export interface RepostModal {
   isReposted: boolean
 }
 
+export interface SelfLabelModal {
+  name: 'self-label'
+  labels: string[]
+  hasMedia: boolean
+  onChange: (labels: string[]) => void
+}
+
 export interface ChangeHandleModal {
   name: 'change-handle'
   onChanged: () => void
@@ -146,8 +158,8 @@ export type Modal =
   | PreferencesHomeFeed
 
   // Moderation
-  | ReportAccountModal
-  | ReportPostModal
+  | ModerationDetailsModal
+  | ReportModal
   | CreateOrEditMuteListModal
   | ListAddRemoveUserModal
 
@@ -157,6 +169,7 @@ export type Modal =
   | EditImageModal
   | ServerInputModal
   | RepostModal
+  | SelfLabelModal
 
   // Bluesky access
   | WaitlistModal