Implement blocks (#554)

* Quick fix to prompt

* Add blocked accounts screen

* Add blocking tools to profile

* Blur avis/banners of blocked users

* Factor blocking state into moderation dsl

* Filter post slices from the feed if any are hidden

* Handle various block UIs

* Filter in the client on blockedBy

* Implement block list

* Fix some copy

* Bump deps

* Fix lint
This commit is contained in:
Paul Frazee 2023-04-28 20:03:13 -05:00 committed by GitHub
parent e68aa75429
commit a95c03e280
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 974 additions and 291 deletions

View file

@ -13,6 +13,9 @@ import {updateDataOptimistically} from 'lib/async/revertible'
import {PostLabelInfo, PostModeration} from 'lib/labeling/types'
import {
getEmbedLabels,
getEmbedMuted,
getEmbedBlocking,
getEmbedBlockedBy,
filterAccountLabels,
filterProfileLabels,
getPostModeration,
@ -30,7 +33,10 @@ export class PostThreadItemModel {
// data
post: AppBskyFeedDefs.PostView
postRecord?: FeedPost.Record
parent?: PostThreadItemModel | AppBskyFeedDefs.NotFoundPost
parent?:
| PostThreadItemModel
| AppBskyFeedDefs.NotFoundPost
| AppBskyFeedDefs.BlockedPost
replies?: (PostThreadItemModel | AppBskyFeedDefs.NotFoundPost)[]
richText?: RichText
@ -60,7 +66,18 @@ export class PostThreadItemModel {
),
accountLabels: filterAccountLabels(this.post.author.labels),
profileLabels: filterProfileLabels(this.post.author.labels),
isMuted: this.post.author.viewer?.muted || false,
isMuted:
this.post.author.viewer?.muted ||
getEmbedMuted(this.post.embed) ||
false,
isBlocking:
!!this.post.author.viewer?.blocking ||
getEmbedBlocking(this.post.embed) ||
false,
isBlockedBy:
!!this.post.author.viewer?.blockedBy ||
getEmbedBlockedBy(this.post.embed) ||
false,
}
}
@ -114,6 +131,8 @@ export class PostThreadItemModel {
this.parent = parentModel
} else if (AppBskyFeedDefs.isNotFoundPost(v.parent)) {
this.parent = v.parent
} else if (AppBskyFeedDefs.isBlockedPost(v.parent)) {
this.parent = v.parent
}
}
// replies
@ -218,6 +237,7 @@ export class PostThreadModel {
// data
thread?: PostThreadItemModel
isBlocked = false
constructor(
public rootStore: RootStoreModel,
@ -377,11 +397,17 @@ export class PostThreadModel {
this._replaceAll(res)
this._xIdle()
} catch (e: any) {
console.log(e)
this._xIdle(e)
}
}
_replaceAll(res: GetPostThread.Response) {
this.isBlocked = AppBskyFeedDefs.isBlockedPost(res.data.thread)
if (this.isBlocked) {
return
}
pruneReplies(res.data.thread)
sortThread(res.data.thread)
const thread = new PostThreadItemModel(
this.rootStore,
@ -399,7 +425,20 @@ export class PostThreadModel {
type MaybePost =
| AppBskyFeedDefs.ThreadViewPost
| AppBskyFeedDefs.NotFoundPost
| AppBskyFeedDefs.BlockedPost
| {[k: string]: unknown; $type: string}
function pruneReplies(post: MaybePost) {
if (post.replies) {
post.replies = (post.replies as MaybePost[]).filter((reply: MaybePost) => {
if (reply.blocked) {
return false
}
pruneReplies(reply)
return true
})
}
}
function sortThread(post: MaybePost) {
if (post.notFound) {
return

View file

@ -1,5 +1,6 @@
import {makeAutoObservable, runInAction} from 'mobx'
import {
AtUri,
ComAtprotoLabelDefs,
AppBskyActorGetProfile as GetProfile,
AppBskyActorProfile,
@ -23,6 +24,8 @@ export class ProfileViewerModel {
muted?: boolean
following?: string
followedBy?: string
blockedBy?: boolean
blocking?: string
constructor() {
makeAutoObservable(this)
@ -86,6 +89,8 @@ export class ProfileModel {
accountLabels: filterAccountLabels(this.labels),
profileLabels: filterProfileLabels(this.labels),
isMuted: this.viewer?.muted || false,
isBlocking: !!this.viewer?.blocking || false,
isBlockedBy: !!this.viewer?.blockedBy || false,
}
}
@ -185,6 +190,33 @@ export class ProfileModel {
await this.refresh()
}
async blockAccount() {
const res = await this.rootStore.agent.app.bsky.graph.block.create(
{
repo: this.rootStore.me.did,
},
{
subject: this.did,
createdAt: new Date().toISOString(),
},
)
this.viewer.blocking = res.uri
await this.refresh()
}
async unblockAccount() {
if (!this.viewer.blocking) {
return
}
const {rkey} = new AtUri(this.viewer.blocking)
await this.rootStore.agent.app.bsky.graph.block.delete({
repo: this.rootStore.me.did,
rkey,
})
this.viewer.blocking = undefined
await this.refresh()
}
// state transitions
// =