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