[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:
Paul Frazee 2023-05-11 16:08:21 -05:00 committed by GitHub
parent 34d8fa5991
commit ebcd633386
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
48 changed files with 2984 additions and 151 deletions

View file

@ -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,

View file

@ -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
}

View file

@ -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 & {

View file

@ -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 {