From d73fd3e6f1bab11aa0ccc5351b2d8760292986ff Mon Sep 17 00:00:00 2001 From: Daniela Henkel Date: Thu, 11 Sep 2025 23:44:40 +0200 Subject: [PATCH] add settings to disable metrics --- src/components/PostControls/index.tsx | 40 ++++--- .../components/ThreadItemAnchor.tsx | 33 ++++-- src/screens/Settings/DeerSettings.tsx | 102 ++++++++++++++++++ src/state/persisted/schema.ts | 10 ++ .../preferences/disable-likes-metrics.tsx | 50 +++++++++ .../preferences/disable-quotes-metrics.tsx | 52 +++++++++ .../preferences/disable-reply-metrics.tsx | 50 +++++++++ .../preferences/disable-reposts-metrics.tsx | 52 +++++++++ .../preferences/disable-saves-metrics.tsx | 50 +++++++++ src/state/preferences/index.tsx | 17 ++- 10 files changed, 435 insertions(+), 21 deletions(-) create mode 100644 src/state/preferences/disable-likes-metrics.tsx create mode 100644 src/state/preferences/disable-quotes-metrics.tsx create mode 100644 src/state/preferences/disable-reply-metrics.tsx create mode 100644 src/state/preferences/disable-reposts-metrics.tsx create mode 100644 src/state/preferences/disable-saves-metrics.tsx diff --git a/src/components/PostControls/index.tsx b/src/components/PostControls/index.tsx index f91bcd8a5..de9a2953a 100644 --- a/src/components/PostControls/index.tsx +++ b/src/components/PostControls/index.tsx @@ -15,6 +15,9 @@ import {useHaptics} from '#/lib/haptics' import {useOpenComposer} from '#/lib/hooks/useOpenComposer' import {type Shadow} from '#/state/cache/types' import {useFeedFeedbackContext} from '#/state/feed-feedback' +import {useDisableLikesMetrics} from '#/state/preferences/disable-likes-metrics' +import {useDisableReplyMetrics} from '#/state/preferences/disable-reply-metrics' +import {useDisableRepostsMetrics} from '#/state/preferences/disable-reposts-metrics' import { usePostLikeMutationQueue, usePostRepostMutationQueue, @@ -99,6 +102,11 @@ let PostControls = ({ const [hasLikeIconBeenToggled, setHasLikeIconBeenToggled] = useState(false) + // disable metrics + const disableLikesMetrics = useDisableLikesMetrics() + const disableRepostsMetrics = useDisableRepostsMetrics() + const disableReplyMetrics = useDisableReplyMetrics() + const onPressToggleLike = async () => { if (isBlocked) { Toast.show( @@ -231,17 +239,23 @@ let PostControls = ({ )} big={big}> - {typeof post.replyCount !== 'undefined' && post.replyCount > 0 && ( - - {formatPostStatCount(post.replyCount)} - - )} + {typeof post.replyCount !== 'undefined' && + post.replyCount > 0 && + !disableReplyMetrics && ( + + {formatPostStatCount(post.replyCount)} + + )} - + {!disableLikesMetrics ? ( + + ) : null} {/* Spacer! */} diff --git a/src/screens/PostThread/components/ThreadItemAnchor.tsx b/src/screens/PostThread/components/ThreadItemAnchor.tsx index 51bf41a76..1782994d1 100644 --- a/src/screens/PostThread/components/ThreadItemAnchor.tsx +++ b/src/screens/PostThread/components/ThreadItemAnchor.tsx @@ -27,6 +27,10 @@ import { import {useProfileShadow} from '#/state/cache/profile-shadow' import {FeedFeedbackProvider, useFeedFeedback} from '#/state/feed-feedback' import {useLanguagePrefs} from '#/state/preferences' +import {useDisableLikesMetrics} from '#/state/preferences/disable-likes-metrics' +import {useDisableQuotesMetrics} from '#/state/preferences/disable-quotes-metrics' +import {useDisableRepostsMetrics} from '#/state/preferences/disable-reposts-metrics' +import {useDisableSavesMetrics} from '#/state/preferences/disable-saves-metrics' import {type ThreadItem} from '#/state/queries/usePostThread/types' import {useSession} from '#/state/session' import {type OnPostSuccessData} from '#/state/shell/composer' @@ -201,6 +205,12 @@ const ThreadItemAnchorInner = memo(function ThreadItemAnchorInner({ const authorHref = makeProfileLink(post.author) const isThreadAuthor = getThreadAuthor(post, record) === currentAccount?.did + // disable metrics + const disableLikesMetrics = useDisableLikesMetrics() + const disableRepostsMetrics = useDisableRepostsMetrics() + const disableQuotesMetrics = useDisableQuotesMetrics() + const disableSavesMetrics = useDisableSavesMetrics() + const likesHref = useMemo(() => { const urip = new AtUri(post.uri) return makeProfileLink(post.author, 'post', urip.rkey, 'liked-by') @@ -414,10 +424,10 @@ const ThreadItemAnchorInner = memo(function ThreadItemAnchorInner({ post={item.value.post} isThreadAuthor={isThreadAuthor} /> - {post.repostCount !== 0 || - post.likeCount !== 0 || - post.quoteCount !== 0 || - post.bookmarkCount !== 0 ? ( + {(post.repostCount !== 0 && !disableRepostsMetrics) || + (post.likeCount !== 0 && !disableLikesMetrics) || + (post.quoteCount !== 0 && !disableQuotesMetrics) || + (post.bookmarkCount !== 0 && !disableSavesMetrics) ? ( // Show this section unless we're *sure* it has no engagement. - {post.repostCount != null && post.repostCount !== 0 ? ( + {post.repostCount != null && + post.repostCount !== 0 && + !disableRepostsMetrics ? ( ) : null} - {post.likeCount != null && post.likeCount !== 0 ? ( + {post.likeCount != null && + post.likeCount !== 0 && + !disableLikesMetrics ? ( ) : null} - {post.bookmarkCount != null && post.bookmarkCount !== 0 ? ( + {post.bookmarkCount != null && + post.bookmarkCount !== 0 && + !disableSavesMetrics ? ( diff --git a/src/screens/Settings/DeerSettings.tsx b/src/screens/Settings/DeerSettings.tsx index 9758da11c..12f3d17be 100644 --- a/src/screens/Settings/DeerSettings.tsx +++ b/src/screens/Settings/DeerSettings.tsx @@ -33,6 +33,26 @@ import { useDirectFetchRecords, useSetDirectFetchRecords, } from '#/state/preferences/direct-fetch-records' +import { + useDisableLikesMetrics, + useSetDisableLikesMetrics, +} from '#/state/preferences/disable-likes-metrics' +import { + useDisableQuotesMetrics, + useSetDisableQuotesMetrics, +} from '#/state/preferences/disable-quotes-metrics' +import { + useDisableReplyMetrics, + useSetDisableReplyMetrics, +} from '#/state/preferences/disable-reply-metrics' +import { + useDisableRepostsMetrics, + useSetDisableRepostsMetrics, +} from '#/state/preferences/disable-reposts-metrics' +import { + useDisableSavesMetrics, + useSetDisableSavesMetrics, +} from '#/state/preferences/disable-saves-metrics' import { useDisableViaRepostNotification, useSetDisableViaRepostNotification, @@ -234,6 +254,21 @@ export function DeerSettingsScreen({}: Props) { const disableViaRepostNotification = useDisableViaRepostNotification() const setDisableViaRepostNotification = useSetDisableViaRepostNotification() + const disableLikesMetrics = useDisableLikesMetrics() + const setDisableLikesMetrics = useSetDisableLikesMetrics() + + const disableRepostsMetrics = useDisableRepostsMetrics() + const setDisableRepostsMetrics = useSetDisableRepostsMetrics() + + const disableQuotesMetrics = useDisableQuotesMetrics() + const setDisableQuotesMetrics = useSetDisableQuotesMetrics() + + const disableSavesMetrics = useDisableSavesMetrics() + const setDisableSavesMetrics = useSetDisableSavesMetrics() + + const disableReplyMetrics = useDisableReplyMetrics() + const setDisableReplyMetrics = useSetDisableReplyMetrics() + const constellationInstance = useConstellationInstance() const setConstellationInstanceControl = Dialog.useDialogControl() @@ -531,6 +566,73 @@ export function DeerSettingsScreen({}: Props) { + + + + Metrics + + + setDisableLikesMetrics(value)} + style={[a.w_full]}> + + Disable Likes Metrics + + + + + setDisableRepostsMetrics(value)} + style={[a.w_full]}> + + Disable Reposts Metrics + + + + + setDisableQuotesMetrics(value)} + style={[a.w_full]}> + + Disable Quotes Metrics + + + + + setDisableSavesMetrics(value)} + style={[a.w_full]}> + + Disable Saves Metrics + + + + + setDisableReplyMetrics(value)} + style={[a.w_full]}> + + Disable Reply Metrics + + + + + diff --git a/src/state/persisted/schema.ts b/src/state/persisted/schema.ts index 7b296ff0d..79445b4c3 100644 --- a/src/state/persisted/schema.ts +++ b/src/state/persisted/schema.ts @@ -135,6 +135,11 @@ const schema = z.object({ showLinkInHandle: z.boolean().optional(), hideFeedsPromoTab: z.boolean().optional(), disableViaRepostNotification: z.boolean().optional(), + disableLikesMetrics: z.boolean().optional(), + disableRepostsMetrics: z.boolean().optional(), + disableQuotesMetrics: z.boolean().optional(), + disableSavesMetrics: z.boolean().optional(), + disableReplyMetrics: z.boolean().optional(), deerVerification: z .object({ enabled: z.boolean(), @@ -206,6 +211,11 @@ export const defaults: Schema = { showLinkInHandle: false, hideFeedsPromoTab: false, disableViaRepostNotification: false, + disableLikesMetrics: false, + disableRepostsMetrics: false, + disableQuotesMetrics: false, + disableSavesMetrics: false, + disableReplyMetrics: false, deerVerification: { enabled: false, // https://social.daniela.lol/profile/did:plc:p2cp5gopk7mgjegy6wadk3ep/post/3lndyqyyr4k2k diff --git a/src/state/preferences/disable-likes-metrics.tsx b/src/state/preferences/disable-likes-metrics.tsx new file mode 100644 index 000000000..320416c0c --- /dev/null +++ b/src/state/preferences/disable-likes-metrics.tsx @@ -0,0 +1,50 @@ +import React from 'react' + +import * as persisted from '#/state/persisted' + +// Preference: disableLikesMetrics – when true, disables likes metrics on posts + +type StateContext = persisted.Schema['disableLikesMetrics'] +// Same setter signature used across other preference modules +type SetContext = (v: persisted.Schema['disableLikesMetrics']) => void + +const stateContext = React.createContext( + persisted.defaults.disableLikesMetrics, +) +const setContext = React.createContext( + (_: persisted.Schema['disableLikesMetrics']) => {}, +) + +export function Provider({children}: React.PropsWithChildren<{}>) { + const [state, setState] = React.useState(persisted.get('disableLikesMetrics')) + + const setStateWrapped = React.useCallback( + (value: persisted.Schema['disableLikesMetrics']) => { + setState(value) + persisted.write('disableLikesMetrics', value) + }, + [setState], + ) + + React.useEffect(() => { + return persisted.onUpdate('disableLikesMetrics', next => { + setState(next) + }) + }, [setStateWrapped]) + + return ( + + + {children} + + + ) +} + +export function useDisableLikesMetrics() { + return React.useContext(stateContext) +} + +export function useSetDisableLikesMetrics() { + return React.useContext(setContext) +} diff --git a/src/state/preferences/disable-quotes-metrics.tsx b/src/state/preferences/disable-quotes-metrics.tsx new file mode 100644 index 000000000..e1025dc4a --- /dev/null +++ b/src/state/preferences/disable-quotes-metrics.tsx @@ -0,0 +1,52 @@ +import React from 'react' + +import * as persisted from '#/state/persisted' + +// Preference: disableQuotesMetrics – when true, disables quotes metrics on posts + +type StateContext = persisted.Schema['disableQuotesMetrics'] +// Same setter signature used across other preference modules +type SetContext = (v: persisted.Schema['disableQuotesMetrics']) => void + +const stateContext = React.createContext( + persisted.defaults.disableQuotesMetrics, +) +const setContext = React.createContext( + (_: persisted.Schema['disableQuotesMetrics']) => {}, +) + +export function Provider({children}: React.PropsWithChildren<{}>) { + const [state, setState] = React.useState( + persisted.get('disableQuotesMetrics'), + ) + + const setStateWrapped = React.useCallback( + (value: persisted.Schema['disableQuotesMetrics']) => { + setState(value) + persisted.write('disableQuotesMetrics', value) + }, + [setState], + ) + + React.useEffect(() => { + return persisted.onUpdate('disableQuotesMetrics', next => { + setState(next) + }) + }, [setStateWrapped]) + + return ( + + + {children} + + + ) +} + +export function useDisableQuotesMetrics() { + return React.useContext(stateContext) +} + +export function useSetDisableQuotesMetrics() { + return React.useContext(setContext) +} diff --git a/src/state/preferences/disable-reply-metrics.tsx b/src/state/preferences/disable-reply-metrics.tsx new file mode 100644 index 000000000..5ca7d2af6 --- /dev/null +++ b/src/state/preferences/disable-reply-metrics.tsx @@ -0,0 +1,50 @@ +import React from 'react' + +import * as persisted from '#/state/persisted' + +// Preference: disableReplyMetrics – when true, disables reply metrics on posts + +type StateContext = persisted.Schema['disableReplyMetrics'] +// Same setter signature used across other preference modules +type SetContext = (v: persisted.Schema['disableReplyMetrics']) => void + +const stateContext = React.createContext( + persisted.defaults.disableReplyMetrics, +) +const setContext = React.createContext( + (_: persisted.Schema['disableReplyMetrics']) => {}, +) + +export function Provider({children}: React.PropsWithChildren<{}>) { + const [state, setState] = React.useState(persisted.get('disableReplyMetrics')) + + const setStateWrapped = React.useCallback( + (value: persisted.Schema['disableReplyMetrics']) => { + setState(value) + persisted.write('disableReplyMetrics', value) + }, + [setState], + ) + + React.useEffect(() => { + return persisted.onUpdate('disableReplyMetrics', next => { + setState(next) + }) + }, [setStateWrapped]) + + return ( + + + {children} + + + ) +} + +export function useDisableReplyMetrics() { + return React.useContext(stateContext) +} + +export function useSetDisableReplyMetrics() { + return React.useContext(setContext) +} diff --git a/src/state/preferences/disable-reposts-metrics.tsx b/src/state/preferences/disable-reposts-metrics.tsx new file mode 100644 index 000000000..823ab884a --- /dev/null +++ b/src/state/preferences/disable-reposts-metrics.tsx @@ -0,0 +1,52 @@ +import React from 'react' + +import * as persisted from '#/state/persisted' + +// Preference: disableRepostsMetrics – when true, disables reposts metrics on posts + +type StateContext = persisted.Schema['disableRepostsMetrics'] +// Same setter signature used across other preference modules +type SetContext = (v: persisted.Schema['disableRepostsMetrics']) => void + +const stateContext = React.createContext( + persisted.defaults.disableRepostsMetrics, +) +const setContext = React.createContext( + (_: persisted.Schema['disableRepostsMetrics']) => {}, +) + +export function Provider({children}: React.PropsWithChildren<{}>) { + const [state, setState] = React.useState( + persisted.get('disableRepostsMetrics'), + ) + + const setStateWrapped = React.useCallback( + (value: persisted.Schema['disableRepostsMetrics']) => { + setState(value) + persisted.write('disableRepostsMetrics', value) + }, + [setState], + ) + + React.useEffect(() => { + return persisted.onUpdate('disableRepostsMetrics', next => { + setState(next) + }) + }, [setStateWrapped]) + + return ( + + + {children} + + + ) +} + +export function useDisableRepostsMetrics() { + return React.useContext(stateContext) +} + +export function useSetDisableRepostsMetrics() { + return React.useContext(setContext) +} diff --git a/src/state/preferences/disable-saves-metrics.tsx b/src/state/preferences/disable-saves-metrics.tsx new file mode 100644 index 000000000..a9337e106 --- /dev/null +++ b/src/state/preferences/disable-saves-metrics.tsx @@ -0,0 +1,50 @@ +import React from 'react' + +import * as persisted from '#/state/persisted' + +// Preference: disableSavesMetrics – when true, disables saves metrics on posts + +type StateContext = persisted.Schema['disableSavesMetrics'] +// Same setter signature used across other preference modules +type SetContext = (v: persisted.Schema['disableSavesMetrics']) => void + +const stateContext = React.createContext( + persisted.defaults.disableSavesMetrics, +) +const setContext = React.createContext( + (_: persisted.Schema['disableSavesMetrics']) => {}, +) + +export function Provider({children}: React.PropsWithChildren<{}>) { + const [state, setState] = React.useState(persisted.get('disableSavesMetrics')) + + const setStateWrapped = React.useCallback( + (value: persisted.Schema['disableSavesMetrics']) => { + setState(value) + persisted.write('disableSavesMetrics', value) + }, + [setState], + ) + + React.useEffect(() => { + return persisted.onUpdate('disableSavesMetrics', next => { + setState(next) + }) + }, [setStateWrapped]) + + return ( + + + {children} + + + ) +} + +export function useDisableSavesMetrics() { + return React.useContext(stateContext) +} + +export function useSetDisableSavesMetrics() { + return React.useContext(setContext) +} diff --git a/src/state/preferences/index.tsx b/src/state/preferences/index.tsx index cf80c779d..0d43a9a33 100644 --- a/src/state/preferences/index.tsx +++ b/src/state/preferences/index.tsx @@ -7,6 +7,11 @@ import {Provider as ConstellationInstanceProvider} from './constellation-instanc import {Provider as DeerVerificationProvider} from './deer-verification' import {Provider as DirectFetchRecordsProvider} from './direct-fetch-records' import {Provider as DisableHapticsProvider} from './disable-haptics' +import {Provider as DisableLikesMetricsProvider} from './disable-likes-metrics' +import {Provider as DisableQuotesMetricsProvider} from './disable-quotes-metrics' +import {Provider as DisableReplyMetricsProvider} from './disable-reply-metrics' +import {Provider as DisableRepostsMetricsProvider} from './disable-reposts-metrics' +import {Provider as DisableSavesMetricsProvider} from './disable-saves-metrics' import {Provider as DisableViaRepostNotificationProvider} from './disable-via-repost-notification' import {Provider as ExternalEmbedsProvider} from './external-embeds-prefs' import {Provider as GoLinksProvider} from './go-links-enabled' @@ -71,7 +76,17 @@ export function Provider({children}: React.PropsWithChildren<{}>) { - {children} + + + + + + {children} + + + + + -- 2.51.2