diff options
Diffstat (limited to 'src/state/models')
-rw-r--r-- | src/state/models/content/post-thread.ts | 22 | ||||
-rw-r--r-- | src/state/models/content/post.ts | 122 | ||||
-rw-r--r-- | src/state/models/content/profile.ts | 18 | ||||
-rw-r--r-- | src/state/models/discovery/suggested-posts.ts | 88 | ||||
-rw-r--r-- | src/state/models/feeds/notifications.ts | 54 | ||||
-rw-r--r-- | src/state/models/feeds/posts.ts | 22 |
6 files changed, 106 insertions, 220 deletions
diff --git a/src/state/models/content/post-thread.ts b/src/state/models/content/post-thread.ts index 76cab5c61..8f9a55032 100644 --- a/src/state/models/content/post-thread.ts +++ b/src/state/models/content/post-thread.ts @@ -10,6 +10,13 @@ import {RootStoreModel} from '../root-store' import * as apilib from 'lib/api/index' import {cleanError} from 'lib/strings/errors' import {updateDataOptimistically} from 'lib/async/revertible' +import {PostLabelInfo, PostModeration} from 'lib/labeling/types' +import { + getEmbedLabels, + filterAccountLabels, + filterProfileLabels, + getPostModeration, +} from 'lib/labeling/helpers' export class PostThreadItemModel { // ui state @@ -46,6 +53,21 @@ export class PostThreadItemModel { 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 || false, + } + } + + get moderation(): PostModeration { + return getPostModeration(this.rootStore, this.labelInfo) + } + constructor( public rootStore: RootStoreModel, v: AppBskyFeedDefs.ThreadViewPost, diff --git a/src/state/models/content/post.ts b/src/state/models/content/post.ts deleted file mode 100644 index 7ba633366..000000000 --- a/src/state/models/content/post.ts +++ /dev/null @@ -1,122 +0,0 @@ -import {makeAutoObservable} from 'mobx' -import {AppBskyFeedPost as Post} from '@atproto/api' -import {AtUri} from '@atproto/api' -import {RootStoreModel} from '../root-store' -import {cleanError} from 'lib/strings/errors' - -type RemoveIndex<T> = { - [P in keyof T as string extends P - ? never - : number extends P - ? never - : P]: T[P] -} -export class PostModel implements RemoveIndex<Post.Record> { - // state - isLoading = false - hasLoaded = false - error = '' - uri: string = '' - - // data - text: string = '' - entities?: Post.Entity[] - reply?: Post.ReplyRef - createdAt: string = '' - - constructor(public rootStore: RootStoreModel, uri: string) { - makeAutoObservable( - this, - { - rootStore: false, - uri: false, - }, - {autoBind: true}, - ) - this.uri = uri - } - - get hasContent() { - return this.createdAt !== '' - } - - get hasError() { - return this.error !== '' - } - - get isEmpty() { - return this.hasLoaded && !this.hasContent - } - - get rootUri(): string { - if (this.reply?.root.uri) { - return this.reply.root.uri - } - return this.uri - } - - get isThreadMuted() { - return this.rootStore.mutedThreads.uris.has(this.rootUri) - } - - // public api - // = - - async setup() { - await this._load() - } - - async toggleThreadMute() { - if (this.isThreadMuted) { - this.rootStore.mutedThreads.uris.delete(this.rootUri) - } else { - this.rootStore.mutedThreads.uris.add(this.rootUri) - } - } - - // state transitions - // = - - _xLoading() { - this.isLoading = true - this.error = '' - } - - _xIdle(err?: any) { - this.isLoading = false - this.hasLoaded = true - this.error = cleanError(err) - if (err) { - this.rootStore.log.error('Failed to fetch post', err) - } - } - - // loader functions - // = - - async _load() { - this._xLoading() - try { - const urip = new AtUri(this.uri) - const res = await this.rootStore.agent.getPost({ - repo: urip.host, - rkey: urip.rkey, - }) - // TODO - // if (!res.valid) { - // throw new Error(res.error) - // } - this._replaceAll(res.value) - this._xIdle() - } catch (e: any) { - this._xIdle(e) - } - } - - _replaceAll(res: Post.Record) { - this.text = res.text - this.entities = res.entities - this.reply = res.reply - this.createdAt = res.createdAt - } -} diff --git a/src/state/models/content/profile.ts b/src/state/models/content/profile.ts index c26dc8749..ea75d19c6 100644 --- a/src/state/models/content/profile.ts +++ b/src/state/models/content/profile.ts @@ -10,6 +10,12 @@ import * as apilib from 'lib/api/index' import {cleanError} from 'lib/strings/errors' import {FollowState} from '../cache/my-follows' import {Image as RNImage} from 'react-native-image-crop-picker' +import {ProfileLabelInfo, ProfileModeration} from 'lib/labeling/types' +import { + getProfileModeration, + filterAccountLabels, + filterProfileLabels, +} from 'lib/labeling/helpers' export const ACTOR_TYPE_USER = 'app.bsky.system.actorUser' @@ -75,6 +81,18 @@ export class ProfileModel { return this.hasLoaded && !this.hasContent } + get labelInfo(): ProfileLabelInfo { + return { + accountLabels: filterAccountLabels(this.labels), + profileLabels: filterProfileLabels(this.labels), + isMuted: this.viewer?.muted || false, + } + } + + get moderation(): ProfileModeration { + return getProfileModeration(this.rootStore, this.labelInfo) + } + // public api // = diff --git a/src/state/models/discovery/suggested-posts.ts b/src/state/models/discovery/suggested-posts.ts deleted file mode 100644 index 6c8de3023..000000000 --- a/src/state/models/discovery/suggested-posts.ts +++ /dev/null @@ -1,88 +0,0 @@ -import {makeAutoObservable, runInAction} from 'mobx' -import {RootStoreModel} from '../root-store' -import {PostsFeedItemModel} from '../feeds/posts' -import {cleanError} from 'lib/strings/errors' -import {TEAM_HANDLES} from 'lib/constants' -import { - getMultipleAuthorsPosts, - mergePosts, -} from 'lib/api/build-suggested-posts' - -export class SuggestedPostsModel { - // state - isLoading = false - hasLoaded = false - error = '' - - // data - posts: PostsFeedItemModel[] = [] - - constructor(public rootStore: RootStoreModel) { - makeAutoObservable( - this, - { - rootStore: false, - }, - {autoBind: true}, - ) - } - - get hasContent() { - return this.posts.length > 0 - } - - get hasError() { - return this.error !== '' - } - - get isEmpty() { - return this.hasLoaded && !this.hasContent - } - - // public api - // = - - async setup() { - this._xLoading() - try { - const responses = await getMultipleAuthorsPosts( - this.rootStore, - TEAM_HANDLES(String(this.rootStore.agent.service)), - undefined, - 30, - ) - runInAction(() => { - const finalPosts = mergePosts(responses, {repostsOnly: true}) - // hydrate into models - this.posts = finalPosts.map((post, i) => { - // strip the reasons to hide that these are reposts - delete post.reason - return new PostsFeedItemModel(this.rootStore, `post-${i}`, post) - }) - }) - this._xIdle() - } catch (e: any) { - this.rootStore.log.error('SuggestedPostsView: Failed to load posts', { - e, - }) - this._xIdle() // dont bubble to the user - } - } - - // state transitions - // = - - _xLoading() { - this.isLoading = true - this.error = '' - } - - _xIdle(err?: any) { - this.isLoading = false - this.hasLoaded = true - this.error = cleanError(err) - if (err) { - this.rootStore.log.error('Failed to fetch suggested posts', err) - } - } -} diff --git a/src/state/models/feeds/notifications.ts b/src/state/models/feeds/notifications.ts index 220e04bce..02f58819f 100644 --- a/src/state/models/feeds/notifications.ts +++ b/src/state/models/feeds/notifications.ts @@ -15,6 +15,16 @@ import {bundleAsync} from 'lib/async/bundle' import {RootStoreModel} from '../root-store' import {PostThreadModel} from '../content/post-thread' import {cleanError} from 'lib/strings/errors' +import { + PostLabelInfo, + PostModeration, + ModerationBehaviorCode, +} from 'lib/labeling/types' +import { + getPostModeration, + filterAccountLabels, + filterProfileLabels, +} from 'lib/labeling/helpers' const GROUPABLE_REASONS = ['like', 'repost', 'follow'] const PAGE_SIZE = 30 @@ -90,6 +100,24 @@ export class NotificationsFeedItemModel { } } + get labelInfo(): PostLabelInfo { + const addedInfo = this.additionalPost?.thread?.labelInfo + return { + postLabels: (this.labels || []).concat(addedInfo?.postLabels || []), + accountLabels: filterAccountLabels(this.author.labels).concat( + addedInfo?.accountLabels || [], + ), + profileLabels: filterProfileLabels(this.author.labels).concat( + addedInfo?.profileLabels || [], + ), + isMuted: this.author.viewer?.muted || addedInfo?.isMuted || false, + } + } + + get moderation(): PostModeration { + return getPostModeration(this.rootStore, this.labelInfo) + } + get numUnreadInGroup(): number { if (this.additional?.length) { return ( @@ -520,16 +548,22 @@ export class NotificationsFeedModel { _filterNotifications( items: NotificationsFeedItemModel[], ): NotificationsFeedItemModel[] { - return items.filter(item => { - const hideByLabel = - this.rootStore.preferences.getLabelPreference(item.labels).pref === - 'hide' - let mutedThread = !!( - item.reasonSubjectRootUri && - this.rootStore.mutedThreads.uris.has(item.reasonSubjectRootUri) - ) - return !hideByLabel && !mutedThread - }) + return items + .filter(item => { + const hideByLabel = + item.moderation.list.behavior === ModerationBehaviorCode.Hide + let mutedThread = !!( + item.reasonSubjectRootUri && + this.rootStore.mutedThreads.uris.has(item.reasonSubjectRootUri) + ) + return !hideByLabel && !mutedThread + }) + .map(item => { + if (item.additional?.length) { + item.additional = this._filterNotifications(item.additional) + } + return item + }) } async _fetchItemModels( diff --git a/src/state/models/feeds/posts.ts b/src/state/models/feeds/posts.ts index cbff707d0..62c6da3de 100644 --- a/src/state/models/feeds/posts.ts +++ b/src/state/models/feeds/posts.ts @@ -20,6 +20,13 @@ import { } 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, + getPostModeration, + filterAccountLabels, + filterProfileLabels, +} from 'lib/labeling/helpers' type FeedViewPost = AppBskyFeedDefs.FeedViewPost type ReasonRepost = AppBskyFeedDefs.ReasonRepost @@ -83,6 +90,21 @@ export class PostsFeedItemModel { 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 || false, + } + } + + get moderation(): PostModeration { + return getPostModeration(this.rootStore, this.labelInfo) + } + copy(v: FeedViewPost) { this.post = v.post this.reply = v.reply |