diff --git a/src/components/ListCard.tsx b/src/components/ListCard.tsx
index 0ed27cf50f..829f36d471 100644
--- a/src/components/ListCard.tsx
+++ b/src/components/ListCard.tsx
@@ -1,13 +1,20 @@
import React from 'react'
import {View} from 'react-native'
-import {AppBskyActorDefs, AppBskyGraphDefs, AtUri} from '@atproto/api'
+import {
+ AppBskyActorDefs,
+ AppBskyGraphDefs,
+ AtUri,
+ moderateUserList,
+ ModerationUI,
+} from '@atproto/api'
import {Trans} from '@lingui/macro'
import {useQueryClient} from '@tanstack/react-query'
import {sanitizeHandle} from 'lib/strings/handles'
+import {useModerationOpts} from 'state/preferences/moderation-opts'
import {precacheList} from 'state/queries/feed'
-import {useTheme} from '#/alf'
-import {atoms as a} from '#/alf'
+import {useSession} from 'state/session'
+import {atoms as a, useTheme} from '#/alf'
import {
Avatar,
Description,
@@ -16,6 +23,7 @@ import {
SaveButton,
} from '#/components/FeedCard'
import {Link as InternalLink, LinkProps} from '#/components/Link'
+import * as Hider from '#/components/moderation/Hider'
import {Text} from '#/components/Typography'
/*
@@ -43,6 +51,11 @@ type Props = {
export function Default(props: Props) {
const {view, showPinButton} = props
+ const moderationOpts = useModerationOpts()
+ const moderation = moderationOpts
+ ? moderateUserList(view, moderationOpts)
+ : undefined
+
return (
@@ -52,6 +65,7 @@ export function Default(props: Props) {
title={view.name}
creator={view.creator}
purpose={view.purpose}
+ modUi={moderation?.ui('contentView')}
/>
{showPinButton && view.purpose === CURATELIST && (
@@ -89,18 +103,40 @@ export function TitleAndByline({
title,
creator,
purpose = CURATELIST,
+ modUi,
}: {
title: string
creator?: AppBskyActorDefs.ProfileViewBasic
purpose?: AppBskyGraphDefs.ListView['purpose']
+ modUi?: ModerationUI
}) {
const t = useTheme()
+ const {currentAccount} = useSession()
return (
-
- {title}
-
+
+
+
+ Hidden list
+
+
+
+
+ {title}
+
+
+
+
{creator && (
void
meta: {
isNoPwi: boolean
- noOverride: boolean
+ allowOverride: boolean
}
}
@@ -27,24 +27,30 @@ export const useHider = () => React.useContext(Context)
export function Outer({
modui,
+ isContentVisibleInitialState,
+ allowOverride,
children,
}: React.PropsWithChildren<{
- modui: ModerationUI
+ isContentVisibleInitialState?: boolean
+ allowOverride?: boolean
+ modui: ModerationUI | undefined
}>) {
const control = useModerationDetailsDialogControl()
- const blur = modui.blurs[0]
- const [isContentVisible, setIsContentVisible] = React.useState(!blur)
+ const blur = modui?.blurs[0]
+ const [isContentVisible, setIsContentVisible] = React.useState(
+ isContentVisibleInitialState || !blur,
+ )
const info = useModerationCauseDescription(blur)
const meta = {
isNoPwi: Boolean(
- modui.blurs.find(
+ modui?.blurs.find(
cause =>
cause.type === 'label' &&
cause.labelDef.identifier === '!no-unauthenticated',
),
),
- noOverride: modui.noOverride,
+ allowOverride: allowOverride || !modui?.noOverride,
}
const showInfoDialog = () => {
@@ -52,7 +58,7 @@ export function Outer({
}
const onSetContentVisible = (show: boolean) => {
- if (meta.noOverride) return
+ if (meta.allowOverride) return
setIsContentVisible(show)
}
diff --git a/src/components/moderation/ModerationDetailsDialog.tsx b/src/components/moderation/ModerationDetailsDialog.tsx
index ebfe452325..b8f02582c6 100644
--- a/src/components/moderation/ModerationDetailsDialog.tsx
+++ b/src/components/moderation/ModerationDetailsDialog.tsx
@@ -18,7 +18,7 @@ export {useDialogControl as useModerationDetailsDialogControl} from '#/component
export interface ModerationDetailsDialogProps {
control: Dialog.DialogOuterProps['control']
- modcause: ModerationCause
+ modcause?: ModerationCause
}
export function ModerationDetailsDialog(props: ModerationDetailsDialogProps) {
@@ -123,7 +123,7 @@ function ModerationDetailsDialogInner({
{description}
- {modcause.type === 'label' && (
+ {modcause?.type === 'label' && (
<>
diff --git a/src/view/com/lists/ListCard.tsx b/src/view/com/lists/ListCard.tsx
deleted file mode 100644
index 587885502b..0000000000
--- a/src/view/com/lists/ListCard.tsx
+++ /dev/null
@@ -1,183 +0,0 @@
-import React from 'react'
-import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native'
-import {AppBskyGraphDefs, AtUri, RichText} from '@atproto/api'
-import {Trans} from '@lingui/macro'
-
-import {useSession} from '#/state/session'
-import {usePalette} from 'lib/hooks/usePalette'
-import {makeProfileLink} from 'lib/routes/links'
-import {sanitizeDisplayName} from 'lib/strings/display-names'
-import {sanitizeHandle} from 'lib/strings/handles'
-import {s} from 'lib/styles'
-import {atoms as a} from '#/alf'
-import {RichText as RichTextCom} from '#/components/RichText'
-import {Link} from '../util/Link'
-import {Text} from '../util/text/Text'
-import {UserAvatar} from '../util/UserAvatar'
-
-export const ListCard = ({
- testID,
- list,
- noBg,
- noBorder,
- renderButton,
- style,
-}: {
- testID?: string
- list: AppBskyGraphDefs.ListView
- noBg?: boolean
- noBorder?: boolean
- renderButton?: () => JSX.Element
- style?: StyleProp
-}) => {
- const pal = usePalette('default')
- const {currentAccount} = useSession()
-
- 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 (
-
-
-
-
-
-
-
- {sanitizeDisplayName(list.name)}
-
-
- {list.purpose === 'app.bsky.graph.defs#curatelist' &&
- (list.creator.did === currentAccount?.did ? (
- User list by you
- ) : (
-
- User list by {sanitizeHandle(list.creator.handle, '@')}
-
- ))}
- {list.purpose === 'app.bsky.graph.defs#modlist' &&
- (list.creator.did === currentAccount?.did ? (
- Moderation list by you
- ) : (
-
- Moderation list by {sanitizeHandle(list.creator.handle, '@')}
-
- ))}
-
-
- {list.viewer?.muted ? (
-
-
- Muted
-
-
- ) : null}
-
- {list.viewer?.blocked ? (
-
-
- Blocked
-
-
- ) : null}
-
-
- {renderButton ? (
- {renderButton()}
- ) : undefined}
-
- {descriptionRichText ? (
-
-
-
- ) : undefined}
-
- )
-}
-
-const styles = StyleSheet.create({
- outer: {
- borderTopWidth: StyleSheet.hairlineWidth,
- 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,
- },
-})
diff --git a/src/view/com/lists/MyLists.tsx b/src/view/com/lists/MyLists.tsx
index 472d2688c7..b56fa6c75f 100644
--- a/src/view/com/lists/MyLists.tsx
+++ b/src/view/com/lists/MyLists.tsx
@@ -4,7 +4,6 @@ import {
FlatList as RNFlatList,
RefreshControl,
StyleProp,
- StyleSheet,
View,
ViewStyle,
} from 'react-native'
@@ -18,10 +17,13 @@ import {MyListsFilter, useMyListsQuery} from '#/state/queries/my-lists'
import {useAnalytics} from 'lib/analytics/analytics'
import {usePalette} from 'lib/hooks/usePalette'
import {s} from 'lib/styles'
+import {isWeb} from 'platform/detection'
+import {useModerationOpts} from 'state/preferences/moderation-opts'
import {EmptyState} from 'view/com/util/EmptyState'
+import {atoms as a, useTheme} from '#/alf'
+import * as ListCard from '#/components/ListCard'
import {ErrorMessage} from '../util/error/ErrorMessage'
import {List} from '../util/List'
-import {ListCard} from './ListCard'
const LOADING = {_reactKey: '__loading__'}
const EMPTY = {_reactKey: '__empty__'}
@@ -41,8 +43,10 @@ export function MyLists({
testID?: string
}) {
const pal = usePalette('default')
+ const t = useTheme()
const {track} = useAnalytics()
const {_} = useLingui()
+ const moderationOpts = useModerationOpts()
const [isPTRing, setIsPTRing] = React.useState(false)
const {data, isFetching, isFetched, isError, error, refetch} =
useMyListsQuery(filter)
@@ -53,7 +57,7 @@ export function MyLists({
if (isError && isEmpty) {
items = items.concat([ERROR_ITEM])
}
- if (!isFetched && isFetching) {
+ if ((!isFetched && isFetching) || !moderationOpts) {
items = items.concat([LOADING])
} else if (isEmpty) {
items = items.concat([EMPTY])
@@ -61,7 +65,7 @@ export function MyLists({
items = items.concat(data)
}
return items
- }, [isError, isEmpty, isFetched, isFetching, data])
+ }, [isError, isEmpty, isFetched, isFetching, moderationOpts, data])
// events
// =
@@ -85,7 +89,6 @@ export function MyLists({
if (item === EMPTY) {
return (
)
} else if (item === LOADING) {
return (
-
+
)
@@ -109,15 +111,18 @@ export function MyLists({
return renderItem ? (
renderItem(item, index)
) : (
-
+
+
+
)
},
- [error, onRefresh, renderItem, _],
+ [renderItem, t.atoms.border_contrast_low, _, error, onRefresh],
)
if (inline) {
@@ -166,10 +171,3 @@ export function MyLists({
)
}
}
-
-const styles = StyleSheet.create({
- item: {
- paddingHorizontal: 18,
- paddingVertical: 4,
- },
-})
diff --git a/src/view/com/util/post-embeds/ListEmbed.tsx b/src/view/com/util/post-embeds/ListEmbed.tsx
deleted file mode 100644
index fc5ad270fc..0000000000
--- a/src/view/com/util/post-embeds/ListEmbed.tsx
+++ /dev/null
@@ -1,32 +0,0 @@
-import React from 'react'
-import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native'
-import {usePalette} from 'lib/hooks/usePalette'
-import {ListCard} from 'view/com/lists/ListCard'
-import {AppBskyGraphDefs} from '@atproto/api'
-import {s} from 'lib/styles'
-
-export function ListEmbed({
- item,
- style,
-}: {
- item: AppBskyGraphDefs.ListView
- style?: StyleProp
-}) {
- const pal = usePalette('default')
-
- return (
-
-
-
- )
-}
-
-const styles = StyleSheet.create({
- container: {
- borderRadius: 8,
- },
- card: {
- borderTopWidth: 0,
- borderRadius: 8,
- },
-})
diff --git a/src/view/com/util/post-embeds/index.tsx b/src/view/com/util/post-embeds/index.tsx
index 0462212fbd..9c13644834 100644
--- a/src/view/com/util/post-embeds/index.tsx
+++ b/src/view/com/util/post-embeds/index.tsx
@@ -25,13 +25,13 @@ import {useLargeAltBadgeEnabled} from '#/state/preferences/large-alt-badge'
import {useModerationOpts} from '#/state/preferences/moderation-opts'
import {usePalette} from 'lib/hooks/usePalette'
import {FeedSourceCard} from 'view/com/feeds/FeedSourceCard'
-import {atoms as a} from '#/alf'
+import {atoms as a, useTheme} from '#/alf'
+import * as ListCard from '#/components/ListCard'
import {Embed as StarterPackCard} from '#/components/StarterPack/StarterPackCard'
import {ContentHider} from '../../../../components/moderation/ContentHider'
import {AutoSizedImage} from '../images/AutoSizedImage'
import {ImageLayoutGrid} from '../images/ImageLayoutGrid'
import {ExternalLinkEmbed} from './ExternalLinkEmbed'
-import {ListEmbed} from './ListEmbed'
import {MaybeQuoteEmbed} from './QuoteEmbed'
type Embed =
@@ -203,10 +203,20 @@ function MaybeListCard({view}: {view: AppBskyGraphDefs.ListView}) {
const moderation = React.useMemo(() => {
return moderationOpts ? moderateUserList(view, moderationOpts) : undefined
}, [view, moderationOpts])
+ const t = useTheme()
return (
-
+
+
+
)
}
diff --git a/src/view/screens/ProfileList.tsx b/src/view/screens/ProfileList.tsx
index c0489c9fd9..0c2c6405fc 100644
--- a/src/view/screens/ProfileList.tsx
+++ b/src/view/screens/ProfileList.tsx
@@ -142,6 +142,7 @@ function ProfileListScreenLoaded({
const queryClient = useQueryClient()
const {openComposer} = useComposerControls()
const setMinimalShellMode = useSetMinimalShellMode()
+ const {currentAccount} = useSession()
const {rkey} = route.params
const feedSectionRef = React.useRef(null)
const aboutSectionRef = React.useRef(null)
@@ -149,6 +150,7 @@ function ProfileListScreenLoaded({
const isCurateList = list.purpose === AppBskyGraphDefs.CURATELIST
const isScreenFocused = useIsFocused()
const isHidden = list.labels?.findIndex(l => l.val === '!hide') !== -1
+ const isOwner = currentAccount?.did === list.creator.did
const moderation = React.useMemo(() => {
return moderateUserList(list, moderationOpts)
@@ -191,7 +193,7 @@ function ProfileListScreenLoaded({
if (isCurateList) {
return (
-
+
@@ -241,7 +243,7 @@ function ProfileListScreenLoaded({
)
}
return (
-
+