[APP-635] Mutelists (#601)
* Add lists and profilelist screens * Implement lists screen and lists-list in profiles * Add empty states to the lists screen * Switch (mostly) from blocklists to mutelists * Rework: create a new moderation screen and move everything related under it * Fix moderation screen on desktop web * Tune the empty state code * Change content moderation modal to content filtering * Add CreateMuteList modal * Implement mutelist creation * Add lists listings * Add the ability to create new mutelists * Add 'add to list' tool * Satisfy the hashtag hyphen haters * Add update/delete/subscribe/unsubscribe to lists * Show which list caused a mute * Add list un/subscribe * Add the mute override when viewing a profile's posts * Update to latest backend * Add simulation tests and tune some behaviors * Fix lint * Bump deps * Fix list refresh after creation * Mute list subscriptions -> Mute lists
This commit is contained in:
parent
34d8fa5991
commit
ebcd633386
48 changed files with 2984 additions and 151 deletions
|
@ -1,5 +1,6 @@
|
|||
import {
|
||||
AppBskyActorDefs,
|
||||
AppBskyGraphDefs,
|
||||
AppBskyEmbedRecordWithMedia,
|
||||
AppBskyEmbedRecord,
|
||||
AppBskyEmbedImages,
|
||||
|
@ -16,6 +17,7 @@ import {
|
|||
Label,
|
||||
LabelValGroup,
|
||||
ModerationBehaviorCode,
|
||||
ModerationBehavior,
|
||||
PostModeration,
|
||||
ProfileModeration,
|
||||
PostLabelInfo,
|
||||
|
@ -127,11 +129,15 @@ export function getPostModeration(
|
|||
|
||||
// muting
|
||||
if (postInfo.isMuted) {
|
||||
let msg = 'Post from an account you muted.'
|
||||
if (postInfo.mutedByList) {
|
||||
msg = `Muted by ${postInfo.mutedByList.name}`
|
||||
}
|
||||
return {
|
||||
avatar,
|
||||
list: hide('Post from an account you muted.'),
|
||||
thread: warn('Post from an account you muted.'),
|
||||
view: warn('Post from an account you muted.'),
|
||||
list: isMute(hide(msg)),
|
||||
thread: isMute(warn(msg)),
|
||||
view: isMute(warn(msg)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -273,6 +279,7 @@ export function getProfileViewBasicLabelInfo(
|
|||
profileLabels: filterProfileLabels(profile.labels),
|
||||
isMuted: profile.viewer?.muted || false,
|
||||
isBlocking: !!profile.viewer?.blocking || false,
|
||||
isBlockedBy: !!profile.viewer?.blockedBy || false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -302,6 +309,21 @@ export function getEmbedMuted(embed?: Embed): boolean {
|
|||
return false
|
||||
}
|
||||
|
||||
export function getEmbedMutedByList(
|
||||
embed?: Embed,
|
||||
): AppBskyGraphDefs.ListViewBasic | undefined {
|
||||
if (!embed) {
|
||||
return undefined
|
||||
}
|
||||
if (
|
||||
AppBskyEmbedRecord.isView(embed) &&
|
||||
AppBskyEmbedRecord.isViewRecord(embed.record)
|
||||
) {
|
||||
return embed.record.author.viewer?.mutedByList
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
export function getEmbedBlocking(embed?: Embed): boolean {
|
||||
if (!embed) {
|
||||
return false
|
||||
|
@ -401,6 +423,11 @@ function warnContent(reason: string) {
|
|||
}
|
||||
}
|
||||
|
||||
function isMute(behavior: ModerationBehavior): ModerationBehavior {
|
||||
behavior.isMute = true
|
||||
return behavior
|
||||
}
|
||||
|
||||
function warnImages(reason: string) {
|
||||
return {
|
||||
behavior: ModerationBehaviorCode.WarnImages,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {ComAtprotoLabelDefs} from '@atproto/api'
|
||||
import {ComAtprotoLabelDefs, AppBskyGraphDefs} from '@atproto/api'
|
||||
import {LabelPreferencesModel} from 'state/models/ui/preferences'
|
||||
|
||||
export type Label = ComAtprotoLabelDefs.Label
|
||||
|
@ -22,6 +22,7 @@ export interface PostLabelInfo {
|
|||
accountLabels: Label[]
|
||||
profileLabels: Label[]
|
||||
isMuted: boolean
|
||||
mutedByList?: AppBskyGraphDefs.ListViewBasic
|
||||
isBlocking: boolean
|
||||
isBlockedBy: boolean
|
||||
}
|
||||
|
@ -44,6 +45,7 @@ export enum ModerationBehaviorCode {
|
|||
|
||||
export interface ModerationBehavior {
|
||||
behavior: ModerationBehaviorCode
|
||||
isMute?: boolean
|
||||
noOverride?: boolean
|
||||
reason?: string
|
||||
}
|
||||
|
|
|
@ -5,10 +5,15 @@ export type {NativeStackScreenProps} from '@react-navigation/native-stack'
|
|||
|
||||
export type CommonNavigatorParams = {
|
||||
NotFound: undefined
|
||||
Moderation: undefined
|
||||
ModerationMuteLists: undefined
|
||||
ModerationMutedAccounts: undefined
|
||||
ModerationBlockedAccounts: undefined
|
||||
Settings: undefined
|
||||
Profile: {name: string; hideBackButton?: boolean}
|
||||
ProfileFollowers: {name: string}
|
||||
ProfileFollows: {name: string}
|
||||
ProfileList: {name: string; rkey: string}
|
||||
PostThread: {name: string; rkey: string}
|
||||
PostLikedBy: {name: string; rkey: string}
|
||||
PostRepostedBy: {name: string; rkey: string}
|
||||
|
@ -20,8 +25,6 @@ export type CommonNavigatorParams = {
|
|||
CommunityGuidelines: undefined
|
||||
CopyrightPolicy: undefined
|
||||
AppPasswords: undefined
|
||||
MutedAccounts: undefined
|
||||
BlockedAccounts: undefined
|
||||
}
|
||||
|
||||
export type BottomTabNavigatorParams = CommonNavigatorParams & {
|
||||
|
|
|
@ -94,6 +94,15 @@ export function convertBskyAppUrlIfNeeded(url: string): string {
|
|||
return url
|
||||
}
|
||||
|
||||
export function listUriToHref(url: string): string {
|
||||
try {
|
||||
const {hostname, rkey} = new AtUri(url)
|
||||
return `/profile/${hostname}/lists/${rkey}`
|
||||
} catch {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
export function getYoutubeVideoId(link: string): string | undefined {
|
||||
let url
|
||||
try {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue