[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

@ -0,0 +1,155 @@
import React from 'react'
import {StyleSheet, View} from 'react-native'
import {AtUri, AppBskyGraphDefs, RichText} from '@atproto/api'
import {Link} from '../util/Link'
import {Text} from '../util/text/Text'
import {RichText as RichTextCom} from '../util/text/RichText'
import {UserAvatar} from '../util/UserAvatar'
import {s} from 'lib/styles'
import {usePalette} from 'lib/hooks/usePalette'
import {useStores} from 'state/index'
import {sanitizeDisplayName} from 'lib/strings/display-names'
export const ListCard = ({
testID,
list,
noBg,
noBorder,
renderButton,
}: {
testID?: string
list: AppBskyGraphDefs.ListView
noBg?: boolean
noBorder?: boolean
renderButton?: () => JSX.Element
}) => {
const pal = usePalette('default')
const store = useStores()
const rkey = React.useMemo(() => {
try {
const urip = new AtUri(list.uri)
return urip.rkey
} catch {
return ''
}
}, [list])
const descriptionRichText = React.useMemo(() => {
if (list.description) {
return new RichText({
text: list.description,
facets: list.descriptionFacets,
})
}
return undefined
}, [list])
return (
<Link
testID={testID}
style={[
styles.outer,
pal.border,
noBorder && styles.outerNoBorder,
!noBg && pal.view,
]}
href={`/profile/${list.creator.did}/lists/${rkey}`}
title={list.name}
asAnchor
anchorNoUnderline>
<View style={styles.layout}>
<View style={styles.layoutAvi}>
<UserAvatar size={40} avatar={list.avatar} />
</View>
<View style={styles.layoutContent}>
<Text
type="lg"
style={[s.bold, pal.text]}
numberOfLines={1}
lineHeight={1.2}>
{sanitizeDisplayName(list.name)}
</Text>
<Text type="md" style={[pal.textLight]} numberOfLines={1}>
{list.purpose === 'app.bsky.graph.defs#modlist' && 'Mute list'} by{' '}
{list.creator.did === store.me.did
? 'you'
: `@${list.creator.handle}`}
</Text>
{!!list.viewer?.muted && (
<View style={s.flexRow}>
<View style={[s.mt5, pal.btn, styles.pill]}>
<Text type="xs" style={pal.text}>
Subscribed
</Text>
</View>
</View>
)}
</View>
{renderButton ? (
<View style={styles.layoutButton}>{renderButton()}</View>
) : undefined}
</View>
{descriptionRichText ? (
<View style={styles.details}>
<RichTextCom
style={pal.text}
numberOfLines={20}
richText={descriptionRichText}
/>
</View>
) : undefined}
</Link>
)
}
const styles = StyleSheet.create({
outer: {
borderTopWidth: 1,
paddingHorizontal: 6,
},
outerNoBorder: {
borderTopWidth: 0,
},
layout: {
flexDirection: 'row',
alignItems: 'center',
},
layoutAvi: {
width: 54,
paddingLeft: 4,
paddingTop: 8,
paddingBottom: 10,
},
avi: {
width: 40,
height: 40,
borderRadius: 20,
resizeMode: 'cover',
},
layoutContent: {
flex: 1,
paddingRight: 10,
paddingTop: 10,
paddingBottom: 10,
},
layoutButton: {
paddingRight: 10,
},
details: {
paddingLeft: 54,
paddingRight: 10,
paddingBottom: 10,
},
pill: {
borderRadius: 4,
paddingHorizontal: 6,
paddingVertical: 2,
},
btn: {
paddingVertical: 7,
borderRadius: 50,
marginLeft: 6,
paddingHorizontal: 14,
},
})