diff --git a/src/screens/Settings/DeerSettings.tsx b/src/screens/Settings/DeerSettings.tsx index bcfdcb18c..d44748848 100644 --- a/src/screens/Settings/DeerSettings.tsx +++ b/src/screens/Settings/DeerSettings.tsx @@ -88,6 +88,10 @@ import { useHideSimilarAccountsRecomm, useSetHideSimilarAccountsRecomm, } from '#/state/preferences/hide-similar-accounts-recommendations' +import { + useHideUnreplyablePosts, + useSetHideUnreplyablePosts, +} from '#/state/preferences/hide-unreplyable-posts' import { useHighQualityImages, useSetHighQualityImages, @@ -443,6 +447,9 @@ export function DeerSettingsScreen({}: Props) { const hideSimilarAccountsRecomm = useHideSimilarAccountsRecomm() const setHideSimilarAccountsRecomm = useSetHideSimilarAccountsRecomm() + const hideUnreplyablePosts = useHideUnreplyablePosts() + const setHideUnreplyablePosts = useSetHideUnreplyablePosts() + const disableVerifyEmailReminder = useDisableVerifyEmailReminder() const setDisableVerifyEmailReminder = useSetDisableVerifyEmailReminder() @@ -754,6 +761,24 @@ export function DeerSettingsScreen({}: Props) { + setHideUnreplyablePosts(value)} + style={[a.w_full]}> + + Hide posts that cannot be replied to from feeds + + + + + + Hides posts from feeds where replies are disabled (e.g. due to + postgates or other restrictions). Does not affect thread views. + + + void + +const stateContext = React.createContext( + persisted.defaults.hideUnreplyablePosts, +) +const setContext = React.createContext( + (_: persisted.Schema['hideUnreplyablePosts']) => {}, +) + +export function Provider({children}: React.PropsWithChildren<{}>) { + const [state, setState] = React.useState( + persisted.get('hideUnreplyablePosts'), + ) + + const setStateWrapped = React.useCallback( + (hideUnreplyablePosts: persisted.Schema['hideUnreplyablePosts']) => { + setState(hideUnreplyablePosts) + persisted.write('hideUnreplyablePosts', hideUnreplyablePosts) + }, + [setState], + ) + + React.useEffect(() => { + return persisted.onUpdate('hideUnreplyablePosts', nextValue => { + setState(nextValue) + }) + }, [setStateWrapped]) + + return ( + + + {children} + + + ) +} + +export function useHideUnreplyablePosts() { + return ( + React.useContext(stateContext) ?? persisted.defaults.hideUnreplyablePosts + ) +} + +export function useSetHideUnreplyablePosts() { + return React.useContext(setContext) +} diff --git a/src/state/preferences/index.tsx b/src/state/preferences/index.tsx index e7a852ede..b7df1b568 100644 --- a/src/state/preferences/index.tsx +++ b/src/state/preferences/index.tsx @@ -26,6 +26,7 @@ import {Provider as GoLinksProvider} from './go-links-enabled' import {Provider as HiddenPostsProvider} from './hidden-posts' import {Provider as HideFeedsPromoTabProvider} from './hide-feeds-promo-tab' import {Provider as HideSimilarAccountsRecommProvider} from './hide-similar-accounts-recommendations' +import {Provider as HideUnreplyablePostsProvider} from './hide-unreplyable-posts' import {Provider as HighQualityImagesProvider} from './high-quality-images' import {Provider as InAppBrowserProvider} from './in-app-browser' import {Provider as KawaiiProvider} from './kawaii' @@ -96,13 +97,15 @@ export function Provider({children}: React.PropsWithChildren<{}>) { - - - - {children} - - - + + + + + {children} + + + + diff --git a/src/view/com/posts/PostFeed.tsx b/src/view/com/posts/PostFeed.tsx index 25e3ab95b..83fd162f0 100644 --- a/src/view/com/posts/PostFeed.tsx +++ b/src/view/com/posts/PostFeed.tsx @@ -38,6 +38,7 @@ import {isIOS, isNative, isWeb} from '#/platform/detection' import {usePostAuthorShadowFilter} from '#/state/cache/profile-shadow' import {listenPostCreated} from '#/state/events' import {useFeedFeedbackContext} from '#/state/feed-feedback' +import {useHideUnreplyablePosts} from '#/state/preferences/hide-unreplyable-posts' import {useRepostCarouselEnabled} from '#/state/preferences/repost-carousel-enabled' import {useTrendingSettings} from '#/state/preferences/trending' import {STALE} from '#/state/queries' @@ -433,6 +434,7 @@ let PostFeed = ({ const {trendingDisabled, trendingVideoDisabled} = useTrendingSettings() const repostCarouselEnabled = useRepostCarouselEnabled() + const hideUnreplyablePosts = useHideUnreplyablePosts() if (feedType === 'following') { useRepostCarousel = repostCarouselEnabled @@ -562,6 +564,27 @@ let PostFeed = ({ ? groupReposts(page.slices) : (page.slices as FeedPostSliceOrGroup[]) + // Filter out posts that cannot be replied to if the setting is enabled + if (hideUnreplyablePosts) { + slices = slices.filter(slice => { + if (slice.isRepostSlice) { + // For repost slices, filter the inner slices + slice.slices = slice.slices.filter(innerSlice => { + // Check if any item in the slice has replyDisabled + return !innerSlice.items.some( + item => item.post.viewer?.replyDisabled === true, + ) + }) + return slice.slices.length > 0 + } else { + // For regular slices, check if any item has replyDisabled + return !slice.items.some( + item => item.post.viewer?.replyDisabled === true, + ) + } + }) + } + for (const slice of slices) { sliceIndex++ @@ -769,6 +792,7 @@ let PostFeed = ({ isCurrentFeedAtStartupSelected, gate, blockedOrMutedAuthors, + hideUnreplyablePosts, ]) // events