Bluesky app fork with some witchin' additions 💫 witchsky.app
bluesky fork client

add settings to disable metrics

+435 -21
+28 -12
src/components/PostControls/index.tsx
··· 15 15 import {useOpenComposer} from '#/lib/hooks/useOpenComposer' 16 16 import {type Shadow} from '#/state/cache/types' 17 17 import {useFeedFeedbackContext} from '#/state/feed-feedback' 18 + import {useDisableLikesMetrics} from '#/state/preferences/disable-likes-metrics' 19 + import {useDisableReplyMetrics} from '#/state/preferences/disable-reply-metrics' 20 + import {useDisableRepostsMetrics} from '#/state/preferences/disable-reposts-metrics' 18 21 import { 19 22 usePostLikeMutationQueue, 20 23 usePostRepostMutationQueue, ··· 98 101 const formatPostStatCount = useFormatPostStatCount() 99 102 100 103 const [hasLikeIconBeenToggled, setHasLikeIconBeenToggled] = useState(false) 104 + 105 + // disable metrics 106 + const disableLikesMetrics = useDisableLikesMetrics() 107 + const disableRepostsMetrics = useDisableRepostsMetrics() 108 + const disableReplyMetrics = useDisableReplyMetrics() 101 109 102 110 const onPressToggleLike = async () => { 103 111 if (isBlocked) { ··· 231 239 )} 232 240 big={big}> 233 241 <PostControlButtonIcon icon={Bubble} /> 234 - {typeof post.replyCount !== 'undefined' && post.replyCount > 0 && ( 235 - <PostControlButtonText> 236 - {formatPostStatCount(post.replyCount)} 237 - </PostControlButtonText> 238 - )} 242 + {typeof post.replyCount !== 'undefined' && 243 + post.replyCount > 0 && 244 + !disableReplyMetrics && ( 245 + <PostControlButtonText> 246 + {formatPostStatCount(post.replyCount)} 247 + </PostControlButtonText> 248 + )} 239 249 </PostControlButton> 240 250 </View> 241 251 <View style={[a.flex_1, a.align_start]}> 242 252 <RepostButton 243 253 isReposted={!!post.viewer?.repost} 244 - repostCount={(post.repostCount ?? 0) + (post.quoteCount ?? 0)} 254 + repostCount={ 255 + !disableRepostsMetrics 256 + ? (post.repostCount ?? 0) + (post.quoteCount ?? 0) 257 + : 0 258 + } 245 259 onRepost={onRepost} 246 260 onQuote={onQuote} 247 261 big={big} ··· 281 295 big={big} 282 296 hasBeenToggled={hasLikeIconBeenToggled} 283 297 /> 284 - <CountWheel 285 - likeCount={post.likeCount ?? 0} 286 - big={big} 287 - isLiked={Boolean(post.viewer?.like)} 288 - hasBeenToggled={hasLikeIconBeenToggled} 289 - /> 298 + {!disableLikesMetrics ? ( 299 + <CountWheel 300 + likeCount={post.likeCount ?? 0} 301 + big={big} 302 + isLiked={Boolean(post.viewer?.like)} 303 + hasBeenToggled={hasLikeIconBeenToggled} 304 + /> 305 + ) : null} 290 306 </PostControlButton> 291 307 </View> 292 308 {/* Spacer! */}
+25 -8
src/screens/PostThread/components/ThreadItemAnchor.tsx
··· 27 27 import {useProfileShadow} from '#/state/cache/profile-shadow' 28 28 import {FeedFeedbackProvider, useFeedFeedback} from '#/state/feed-feedback' 29 29 import {useLanguagePrefs} from '#/state/preferences' 30 + import {useDisableLikesMetrics} from '#/state/preferences/disable-likes-metrics' 31 + import {useDisableQuotesMetrics} from '#/state/preferences/disable-quotes-metrics' 32 + import {useDisableRepostsMetrics} from '#/state/preferences/disable-reposts-metrics' 33 + import {useDisableSavesMetrics} from '#/state/preferences/disable-saves-metrics' 30 34 import {type ThreadItem} from '#/state/queries/usePostThread/types' 31 35 import {useSession} from '#/state/session' 32 36 import {type OnPostSuccessData} from '#/state/shell/composer' ··· 200 204 const threadRootUri = record.reply?.root?.uri || post.uri 201 205 const authorHref = makeProfileLink(post.author) 202 206 const isThreadAuthor = getThreadAuthor(post, record) === currentAccount?.did 207 + 208 + // disable metrics 209 + const disableLikesMetrics = useDisableLikesMetrics() 210 + const disableRepostsMetrics = useDisableRepostsMetrics() 211 + const disableQuotesMetrics = useDisableQuotesMetrics() 212 + const disableSavesMetrics = useDisableSavesMetrics() 203 213 204 214 const likesHref = useMemo(() => { 205 215 const urip = new AtUri(post.uri) ··· 414 424 post={item.value.post} 415 425 isThreadAuthor={isThreadAuthor} 416 426 /> 417 - {post.repostCount !== 0 || 418 - post.likeCount !== 0 || 419 - post.quoteCount !== 0 || 420 - post.bookmarkCount !== 0 ? ( 427 + {(post.repostCount !== 0 && !disableRepostsMetrics) || 428 + (post.likeCount !== 0 && !disableLikesMetrics) || 429 + (post.quoteCount !== 0 && !disableQuotesMetrics) || 430 + (post.bookmarkCount !== 0 && !disableSavesMetrics) ? ( 421 431 // Show this section unless we're *sure* it has no engagement. 422 432 <View 423 433 style={[ ··· 434 444 a.py_md, 435 445 t.atoms.border_contrast_low, 436 446 ]}> 437 - {post.repostCount != null && post.repostCount !== 0 ? ( 447 + {post.repostCount != null && 448 + post.repostCount !== 0 && 449 + !disableRepostsMetrics ? ( 438 450 <Link to={repostsHref} label={_(msg`Reposts of this post`)}> 439 451 <Text 440 452 testID="repostCount-expanded" ··· 452 464 ) : null} 453 465 {post.quoteCount != null && 454 466 post.quoteCount !== 0 && 455 - !post.viewer?.embeddingDisabled ? ( 467 + !post.viewer?.embeddingDisabled && 468 + !disableQuotesMetrics ? ( 456 469 <Link to={quotesHref} label={_(msg`Quotes of this post`)}> 457 470 <Text 458 471 testID="quoteCount-expanded" ··· 468 481 </Text> 469 482 </Link> 470 483 ) : null} 471 - {post.likeCount != null && post.likeCount !== 0 ? ( 484 + {post.likeCount != null && 485 + post.likeCount !== 0 && 486 + !disableLikesMetrics ? ( 472 487 <Link to={likesHref} label={_(msg`Likes on this post`)}> 473 488 <Text 474 489 testID="likeCount-expanded" ··· 480 495 </Text> 481 496 </Link> 482 497 ) : null} 483 - {post.bookmarkCount != null && post.bookmarkCount !== 0 ? ( 498 + {post.bookmarkCount != null && 499 + post.bookmarkCount !== 0 && 500 + !disableSavesMetrics ? ( 484 501 <Text 485 502 testID="bookmarkCount-expanded" 486 503 style={[a.text_md, t.atoms.text_contrast_medium]}>
+102
src/screens/Settings/DeerSettings.tsx
··· 34 34 useSetDirectFetchRecords, 35 35 } from '#/state/preferences/direct-fetch-records' 36 36 import { 37 + useDisableLikesMetrics, 38 + useSetDisableLikesMetrics, 39 + } from '#/state/preferences/disable-likes-metrics' 40 + import { 41 + useDisableQuotesMetrics, 42 + useSetDisableQuotesMetrics, 43 + } from '#/state/preferences/disable-quotes-metrics' 44 + import { 45 + useDisableReplyMetrics, 46 + useSetDisableReplyMetrics, 47 + } from '#/state/preferences/disable-reply-metrics' 48 + import { 49 + useDisableRepostsMetrics, 50 + useSetDisableRepostsMetrics, 51 + } from '#/state/preferences/disable-reposts-metrics' 52 + import { 53 + useDisableSavesMetrics, 54 + useSetDisableSavesMetrics, 55 + } from '#/state/preferences/disable-saves-metrics' 56 + import { 37 57 useDisableViaRepostNotification, 38 58 useSetDisableViaRepostNotification, 39 59 } from '#/state/preferences/disable-via-repost-notification' ··· 233 253 234 254 const disableViaRepostNotification = useDisableViaRepostNotification() 235 255 const setDisableViaRepostNotification = useSetDisableViaRepostNotification() 256 + 257 + const disableLikesMetrics = useDisableLikesMetrics() 258 + const setDisableLikesMetrics = useSetDisableLikesMetrics() 259 + 260 + const disableRepostsMetrics = useDisableRepostsMetrics() 261 + const setDisableRepostsMetrics = useSetDisableRepostsMetrics() 262 + 263 + const disableQuotesMetrics = useDisableQuotesMetrics() 264 + const setDisableQuotesMetrics = useSetDisableQuotesMetrics() 265 + 266 + const disableSavesMetrics = useDisableSavesMetrics() 267 + const setDisableSavesMetrics = useSetDisableSavesMetrics() 268 + 269 + const disableReplyMetrics = useDisableReplyMetrics() 270 + const setDisableReplyMetrics = useSetDisableReplyMetrics() 236 271 237 272 const constellationInstance = useConstellationInstance() 238 273 const setConstellationInstanceControl = Dialog.useDialogControl() ··· 529 564 you like/repost a post someone else has reposted for privacy. 530 565 </Trans> 531 566 </Admonition> 567 + </SettingsList.Group> 568 + 569 + <SettingsList.Group contentContainerStyle={[a.gap_sm]}> 570 + <SettingsList.ItemIcon icon={VisibilityIcon} /> 571 + <SettingsList.ItemText> 572 + <Trans>Metrics</Trans> 573 + </SettingsList.ItemText> 574 + 575 + <Toggle.Item 576 + name="disable_likes_metrics" 577 + label={_(msg`Disable Likes Metrics`)} 578 + value={disableLikesMetrics} 579 + onChange={value => setDisableLikesMetrics(value)} 580 + style={[a.w_full]}> 581 + <Toggle.LabelText style={[a.flex_1]}> 582 + <Trans>Disable Likes Metrics</Trans> 583 + </Toggle.LabelText> 584 + <Toggle.Platform /> 585 + </Toggle.Item> 586 + 587 + <Toggle.Item 588 + name="disable_reposts_metrics" 589 + label={_(msg`Disable Reposts Metrics`)} 590 + value={disableRepostsMetrics} 591 + onChange={value => setDisableRepostsMetrics(value)} 592 + style={[a.w_full]}> 593 + <Toggle.LabelText style={[a.flex_1]}> 594 + <Trans>Disable Reposts Metrics</Trans> 595 + </Toggle.LabelText> 596 + <Toggle.Platform /> 597 + </Toggle.Item> 598 + 599 + <Toggle.Item 600 + name="disable_quotes_metrics" 601 + label={_(msg`Disable Quotes Metrics`)} 602 + value={disableQuotesMetrics} 603 + onChange={value => setDisableQuotesMetrics(value)} 604 + style={[a.w_full]}> 605 + <Toggle.LabelText style={[a.flex_1]}> 606 + <Trans>Disable Quotes Metrics</Trans> 607 + </Toggle.LabelText> 608 + <Toggle.Platform /> 609 + </Toggle.Item> 610 + 611 + <Toggle.Item 612 + name="disable_saves_metrics" 613 + label={_(msg`Disable Saves Metrics`)} 614 + value={disableSavesMetrics} 615 + onChange={value => setDisableSavesMetrics(value)} 616 + style={[a.w_full]}> 617 + <Toggle.LabelText style={[a.flex_1]}> 618 + <Trans>Disable Saves Metrics</Trans> 619 + </Toggle.LabelText> 620 + <Toggle.Platform /> 621 + </Toggle.Item> 622 + 623 + <Toggle.Item 624 + name="disable_reply_metrics" 625 + label={_(msg`Disable Reply Metrics`)} 626 + value={disableReplyMetrics} 627 + onChange={value => setDisableReplyMetrics(value)} 628 + style={[a.w_full]}> 629 + <Toggle.LabelText style={[a.flex_1]}> 630 + <Trans>Disable Reply Metrics</Trans> 631 + </Toggle.LabelText> 632 + <Toggle.Platform /> 633 + </Toggle.Item> 532 634 </SettingsList.Group> 533 635 534 636 <SettingsList.Group contentContainerStyle={[a.gap_sm]}>
+10
src/state/persisted/schema.ts
··· 135 135 showLinkInHandle: z.boolean().optional(), 136 136 hideFeedsPromoTab: z.boolean().optional(), 137 137 disableViaRepostNotification: z.boolean().optional(), 138 + disableLikesMetrics: z.boolean().optional(), 139 + disableRepostsMetrics: z.boolean().optional(), 140 + disableQuotesMetrics: z.boolean().optional(), 141 + disableSavesMetrics: z.boolean().optional(), 142 + disableReplyMetrics: z.boolean().optional(), 138 143 deerVerification: z 139 144 .object({ 140 145 enabled: z.boolean(), ··· 206 211 showLinkInHandle: false, 207 212 hideFeedsPromoTab: false, 208 213 disableViaRepostNotification: false, 214 + disableLikesMetrics: false, 215 + disableRepostsMetrics: false, 216 + disableQuotesMetrics: false, 217 + disableSavesMetrics: false, 218 + disableReplyMetrics: false, 209 219 deerVerification: { 210 220 enabled: false, 211 221 // https://social.daniela.lol/profile/did:plc:p2cp5gopk7mgjegy6wadk3ep/post/3lndyqyyr4k2k
+50
src/state/preferences/disable-likes-metrics.tsx
··· 1 + import React from 'react' 2 + 3 + import * as persisted from '#/state/persisted' 4 + 5 + // Preference: disableLikesMetrics – when true, disables likes metrics on posts 6 + 7 + type StateContext = persisted.Schema['disableLikesMetrics'] 8 + // Same setter signature used across other preference modules 9 + type SetContext = (v: persisted.Schema['disableLikesMetrics']) => void 10 + 11 + const stateContext = React.createContext<StateContext>( 12 + persisted.defaults.disableLikesMetrics, 13 + ) 14 + const setContext = React.createContext<SetContext>( 15 + (_: persisted.Schema['disableLikesMetrics']) => {}, 16 + ) 17 + 18 + export function Provider({children}: React.PropsWithChildren<{}>) { 19 + const [state, setState] = React.useState(persisted.get('disableLikesMetrics')) 20 + 21 + const setStateWrapped = React.useCallback( 22 + (value: persisted.Schema['disableLikesMetrics']) => { 23 + setState(value) 24 + persisted.write('disableLikesMetrics', value) 25 + }, 26 + [setState], 27 + ) 28 + 29 + React.useEffect(() => { 30 + return persisted.onUpdate('disableLikesMetrics', next => { 31 + setState(next) 32 + }) 33 + }, [setStateWrapped]) 34 + 35 + return ( 36 + <stateContext.Provider value={state}> 37 + <setContext.Provider value={setStateWrapped}> 38 + {children} 39 + </setContext.Provider> 40 + </stateContext.Provider> 41 + ) 42 + } 43 + 44 + export function useDisableLikesMetrics() { 45 + return React.useContext(stateContext) 46 + } 47 + 48 + export function useSetDisableLikesMetrics() { 49 + return React.useContext(setContext) 50 + }
+52
src/state/preferences/disable-quotes-metrics.tsx
··· 1 + import React from 'react' 2 + 3 + import * as persisted from '#/state/persisted' 4 + 5 + // Preference: disableQuotesMetrics – when true, disables quotes metrics on posts 6 + 7 + type StateContext = persisted.Schema['disableQuotesMetrics'] 8 + // Same setter signature used across other preference modules 9 + type SetContext = (v: persisted.Schema['disableQuotesMetrics']) => void 10 + 11 + const stateContext = React.createContext<StateContext>( 12 + persisted.defaults.disableQuotesMetrics, 13 + ) 14 + const setContext = React.createContext<SetContext>( 15 + (_: persisted.Schema['disableQuotesMetrics']) => {}, 16 + ) 17 + 18 + export function Provider({children}: React.PropsWithChildren<{}>) { 19 + const [state, setState] = React.useState( 20 + persisted.get('disableQuotesMetrics'), 21 + ) 22 + 23 + const setStateWrapped = React.useCallback( 24 + (value: persisted.Schema['disableQuotesMetrics']) => { 25 + setState(value) 26 + persisted.write('disableQuotesMetrics', value) 27 + }, 28 + [setState], 29 + ) 30 + 31 + React.useEffect(() => { 32 + return persisted.onUpdate('disableQuotesMetrics', next => { 33 + setState(next) 34 + }) 35 + }, [setStateWrapped]) 36 + 37 + return ( 38 + <stateContext.Provider value={state}> 39 + <setContext.Provider value={setStateWrapped}> 40 + {children} 41 + </setContext.Provider> 42 + </stateContext.Provider> 43 + ) 44 + } 45 + 46 + export function useDisableQuotesMetrics() { 47 + return React.useContext(stateContext) 48 + } 49 + 50 + export function useSetDisableQuotesMetrics() { 51 + return React.useContext(setContext) 52 + }
+50
src/state/preferences/disable-reply-metrics.tsx
··· 1 + import React from 'react' 2 + 3 + import * as persisted from '#/state/persisted' 4 + 5 + // Preference: disableReplyMetrics – when true, disables reply metrics on posts 6 + 7 + type StateContext = persisted.Schema['disableReplyMetrics'] 8 + // Same setter signature used across other preference modules 9 + type SetContext = (v: persisted.Schema['disableReplyMetrics']) => void 10 + 11 + const stateContext = React.createContext<StateContext>( 12 + persisted.defaults.disableReplyMetrics, 13 + ) 14 + const setContext = React.createContext<SetContext>( 15 + (_: persisted.Schema['disableReplyMetrics']) => {}, 16 + ) 17 + 18 + export function Provider({children}: React.PropsWithChildren<{}>) { 19 + const [state, setState] = React.useState(persisted.get('disableReplyMetrics')) 20 + 21 + const setStateWrapped = React.useCallback( 22 + (value: persisted.Schema['disableReplyMetrics']) => { 23 + setState(value) 24 + persisted.write('disableReplyMetrics', value) 25 + }, 26 + [setState], 27 + ) 28 + 29 + React.useEffect(() => { 30 + return persisted.onUpdate('disableReplyMetrics', next => { 31 + setState(next) 32 + }) 33 + }, [setStateWrapped]) 34 + 35 + return ( 36 + <stateContext.Provider value={state}> 37 + <setContext.Provider value={setStateWrapped}> 38 + {children} 39 + </setContext.Provider> 40 + </stateContext.Provider> 41 + ) 42 + } 43 + 44 + export function useDisableReplyMetrics() { 45 + return React.useContext(stateContext) 46 + } 47 + 48 + export function useSetDisableReplyMetrics() { 49 + return React.useContext(setContext) 50 + }
+52
src/state/preferences/disable-reposts-metrics.tsx
··· 1 + import React from 'react' 2 + 3 + import * as persisted from '#/state/persisted' 4 + 5 + // Preference: disableRepostsMetrics – when true, disables reposts metrics on posts 6 + 7 + type StateContext = persisted.Schema['disableRepostsMetrics'] 8 + // Same setter signature used across other preference modules 9 + type SetContext = (v: persisted.Schema['disableRepostsMetrics']) => void 10 + 11 + const stateContext = React.createContext<StateContext>( 12 + persisted.defaults.disableRepostsMetrics, 13 + ) 14 + const setContext = React.createContext<SetContext>( 15 + (_: persisted.Schema['disableRepostsMetrics']) => {}, 16 + ) 17 + 18 + export function Provider({children}: React.PropsWithChildren<{}>) { 19 + const [state, setState] = React.useState( 20 + persisted.get('disableRepostsMetrics'), 21 + ) 22 + 23 + const setStateWrapped = React.useCallback( 24 + (value: persisted.Schema['disableRepostsMetrics']) => { 25 + setState(value) 26 + persisted.write('disableRepostsMetrics', value) 27 + }, 28 + [setState], 29 + ) 30 + 31 + React.useEffect(() => { 32 + return persisted.onUpdate('disableRepostsMetrics', next => { 33 + setState(next) 34 + }) 35 + }, [setStateWrapped]) 36 + 37 + return ( 38 + <stateContext.Provider value={state}> 39 + <setContext.Provider value={setStateWrapped}> 40 + {children} 41 + </setContext.Provider> 42 + </stateContext.Provider> 43 + ) 44 + } 45 + 46 + export function useDisableRepostsMetrics() { 47 + return React.useContext(stateContext) 48 + } 49 + 50 + export function useSetDisableRepostsMetrics() { 51 + return React.useContext(setContext) 52 + }
+50
src/state/preferences/disable-saves-metrics.tsx
··· 1 + import React from 'react' 2 + 3 + import * as persisted from '#/state/persisted' 4 + 5 + // Preference: disableSavesMetrics – when true, disables saves metrics on posts 6 + 7 + type StateContext = persisted.Schema['disableSavesMetrics'] 8 + // Same setter signature used across other preference modules 9 + type SetContext = (v: persisted.Schema['disableSavesMetrics']) => void 10 + 11 + const stateContext = React.createContext<StateContext>( 12 + persisted.defaults.disableSavesMetrics, 13 + ) 14 + const setContext = React.createContext<SetContext>( 15 + (_: persisted.Schema['disableSavesMetrics']) => {}, 16 + ) 17 + 18 + export function Provider({children}: React.PropsWithChildren<{}>) { 19 + const [state, setState] = React.useState(persisted.get('disableSavesMetrics')) 20 + 21 + const setStateWrapped = React.useCallback( 22 + (value: persisted.Schema['disableSavesMetrics']) => { 23 + setState(value) 24 + persisted.write('disableSavesMetrics', value) 25 + }, 26 + [setState], 27 + ) 28 + 29 + React.useEffect(() => { 30 + return persisted.onUpdate('disableSavesMetrics', next => { 31 + setState(next) 32 + }) 33 + }, [setStateWrapped]) 34 + 35 + return ( 36 + <stateContext.Provider value={state}> 37 + <setContext.Provider value={setStateWrapped}> 38 + {children} 39 + </setContext.Provider> 40 + </stateContext.Provider> 41 + ) 42 + } 43 + 44 + export function useDisableSavesMetrics() { 45 + return React.useContext(stateContext) 46 + } 47 + 48 + export function useSetDisableSavesMetrics() { 49 + return React.useContext(setContext) 50 + }
+16 -1
src/state/preferences/index.tsx
··· 7 7 import {Provider as DeerVerificationProvider} from './deer-verification' 8 8 import {Provider as DirectFetchRecordsProvider} from './direct-fetch-records' 9 9 import {Provider as DisableHapticsProvider} from './disable-haptics' 10 + import {Provider as DisableLikesMetricsProvider} from './disable-likes-metrics' 11 + import {Provider as DisableQuotesMetricsProvider} from './disable-quotes-metrics' 12 + import {Provider as DisableReplyMetricsProvider} from './disable-reply-metrics' 13 + import {Provider as DisableRepostsMetricsProvider} from './disable-reposts-metrics' 14 + import {Provider as DisableSavesMetricsProvider} from './disable-saves-metrics' 10 15 import {Provider as DisableViaRepostNotificationProvider} from './disable-via-repost-notification' 11 16 import {Provider as ExternalEmbedsProvider} from './external-embeds-prefs' 12 17 import {Provider as GoLinksProvider} from './go-links-enabled' ··· 71 76 <KawaiiProvider> 72 77 <HideFeedsPromoTabProvider> 73 78 <DisableViaRepostNotificationProvider> 74 - {children} 79 + <DisableLikesMetricsProvider> 80 + <DisableRepostsMetricsProvider> 81 + <DisableQuotesMetricsProvider> 82 + <DisableSavesMetricsProvider> 83 + <DisableReplyMetricsProvider> 84 + {children} 85 + </DisableReplyMetricsProvider> 86 + </DisableSavesMetricsProvider> 87 + </DisableQuotesMetricsProvider> 88 + </DisableRepostsMetricsProvider> 89 + </DisableLikesMetricsProvider> 75 90 </DisableViaRepostNotificationProvider> 76 91 </HideFeedsPromoTabProvider> 77 92 </KawaiiProvider>