Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at 999e52ed2d5a2c8b2f7b8747dfcfd0e2017e5eb0 1068 lines 39 kB view raw
1import {useState} from 'react' 2import {View} from 'react-native' 3import {type ProfileViewBasic} from '@atproto/api/dist/client/types/app/bsky/actor/defs' 4import {msg, Trans} from '@lingui/macro' 5import {useLingui} from '@lingui/react' 6import {type NativeStackScreenProps} from '@react-navigation/native-stack' 7 8import {usePalette} from '#/lib/hooks/usePalette' 9import {type CommonNavigatorParams} from '#/lib/routes/types' 10import * as persisted from '#/state/persisted' 11import {useGoLinksEnabled, useSetGoLinksEnabled} from '#/state/preferences' 12import { 13 useConstellationInstance, 14 useSetConstellationInstance, 15} from '#/state/preferences/constellation-instance' 16import { 17 useDeerVerificationEnabled, 18 useDeerVerificationTrusted, 19 useSetDeerVerificationEnabled, 20} from '#/state/preferences/deer-verification' 21import { 22 useDirectFetchRecords, 23 useSetDirectFetchRecords, 24} from '#/state/preferences/direct-fetch-records' 25import { 26 useDisableComposerPrompt, 27 useSetDisableComposerPrompt, 28} from '#/state/preferences/disable-composer-prompt' 29import { 30 useDisableFollowedByMetrics, 31 useSetDisableFollowedByMetrics, 32} from '#/state/preferences/disable-followed-by-metrics' 33import { 34 useDisableFollowersMetrics, 35 useSetDisableFollowersMetrics, 36} from '#/state/preferences/disable-followers-metrics' 37import { 38 useDisableFollowingMetrics, 39 useSetDisableFollowingMetrics, 40} from '#/state/preferences/disable-following-metrics' 41import { 42 useDisableLikesMetrics, 43 useSetDisableLikesMetrics, 44} from '#/state/preferences/disable-likes-metrics' 45import { 46 useDisablePostsMetrics, 47 useSetDisablePostsMetrics, 48} from '#/state/preferences/disable-posts-metrics' 49import { 50 useDisableQuotesMetrics, 51 useSetDisableQuotesMetrics, 52} from '#/state/preferences/disable-quotes-metrics' 53import { 54 useDisableReplyMetrics, 55 useSetDisableReplyMetrics, 56} from '#/state/preferences/disable-reply-metrics' 57import { 58 useDisableRepostsMetrics, 59 useSetDisableRepostsMetrics, 60} from '#/state/preferences/disable-reposts-metrics' 61import { 62 useDisableSavesMetrics, 63 useSetDisableSavesMetrics, 64} from '#/state/preferences/disable-saves-metrics' 65import { 66 useDisableVerifyEmailReminder, 67 useSetDisableVerifyEmailReminder, 68} from '#/state/preferences/disable-verify-email-reminder' 69import { 70 useDisableViaRepostNotification, 71 useSetDisableViaRepostNotification, 72} from '#/state/preferences/disable-via-repost-notification' 73import { 74 useSetShowExternalShareButtons, 75 useShowExternalShareButtons, 76} from '#/state/preferences/external-share-buttons' 77import { 78 useHideFeedsPromoTab, 79 useSetHideFeedsPromoTab, 80} from '#/state/preferences/hide-feeds-promo-tab' 81import { 82 useHideSimilarAccountsRecomm, 83 useSetHideSimilarAccountsRecomm, 84} from '#/state/preferences/hide-similar-accounts-recommendations' 85import { 86 useHideUnreplyablePosts, 87 useSetHideUnreplyablePosts, 88} from '#/state/preferences/hide-unreplyable-posts' 89import { 90 useHighQualityImages, 91 useSetHighQualityImages, 92} from '#/state/preferences/high-quality-images' 93import {useModerationOpts} from '#/state/preferences/moderation-opts' 94import { 95 useNoAppLabelers, 96 useSetNoAppLabelers, 97} from '#/state/preferences/no-app-labelers' 98import { 99 useNoDiscoverFallback, 100 useSetNoDiscoverFallback, 101} from '#/state/preferences/no-discover-fallback' 102import { 103 usePostReplacement, 104 useSetPostReplacement, 105} from '#/state/preferences/post-name-replacement' 106import { 107 useRepostCarouselEnabled, 108 useSetRepostCarouselEnabled, 109} from '#/state/preferences/repost-carousel-enabled' 110import { 111 useSetShowLinkInHandle, 112 useShowLinkInHandle, 113} from '#/state/preferences/show-link-in-handle.tsx' 114import { 115 useLibreTranslateInstance, 116 useSetLibreTranslateInstance, 117 useSetTranslationServicePreference, 118 useTranslationServicePreference, 119} from '#/state/preferences/translation-service-preference' 120import {useProfilesQuery} from '#/state/queries/profile' 121import * as SettingsList from '#/screens/Settings/components/SettingsList' 122import {atoms as a, useBreakpoints} from '#/alf' 123import {Admonition} from '#/components/Admonition' 124import {Button, ButtonText} from '#/components/Button' 125import * as Dialog from '#/components/Dialog' 126import * as TextField from '#/components/forms/TextField' 127import * as Toggle from '#/components/forms/Toggle' 128import {Atom_Stroke2_Corner0_Rounded as DeerIcon} from '#/components/icons/Atom' 129import {ChainLink_Stroke2_Corner0_Rounded as ChainLinkIcon} from '#/components/icons/ChainLink' 130import {Eye_Stroke2_Corner0_Rounded as VisibilityIcon} from '#/components/icons/Eye' 131import {Earth_Stroke2_Corner2_Rounded as EarthIcon} from '#/components/icons/Globe' 132import {Lab_Stroke2_Corner0_Rounded as _BeakerIcon} from '#/components/icons/Lab' 133import {PaintRoller_Stroke2_Corner2_Rounded as PaintRollerIcon} from '#/components/icons/PaintRoller' 134import {Pencil_Stroke2_Corner0_Rounded as PencilIcon} from '#/components/icons/Pencil' 135import {RaisingHand4Finger_Stroke2_Corner0_Rounded as RaisingHandIcon} from '#/components/icons/RaisingHand' 136import {Star_Stroke2_Corner0_Rounded as StarIcon} from '#/components/icons/Star' 137import {Verified_Stroke2_Corner2_Rounded as VerifiedIcon} from '#/components/icons/Verified' 138import * as Layout from '#/components/Layout' 139import {InlineLinkText} from '#/components/Link' 140import {Text} from '#/components/Typography' 141import {IS_WEB} from '#/env' 142import {SearchProfileCard} from '../Search/components/SearchProfileCard' 143 144type Props = NativeStackScreenProps<CommonNavigatorParams> 145 146function ConstellationInstanceDialog({ 147 control, 148}: { 149 control: Dialog.DialogControlProps 150}) { 151 const pal = usePalette('default') 152 const {_} = useLingui() 153 154 const constellationInstance = useConstellationInstance() 155 const [url, setUrl] = useState(constellationInstance ?? '') 156 const setConstellationInstance = useSetConstellationInstance() 157 158 const submit = () => { 159 setConstellationInstance(url) 160 control.close() 161 } 162 163 const shouldDisable = () => { 164 try { 165 return !new URL(url).hostname.includes('.') 166 } catch (e) { 167 return true 168 } 169 } 170 171 return ( 172 <Dialog.Outer 173 control={control} 174 nativeOptions={{preventExpansion: true}} 175 onClose={() => setUrl(constellationInstance ?? '')}> 176 <Dialog.Handle /> 177 <Dialog.ScrollableInner label={_(msg`Constellations instance URL`)}> 178 <View style={[a.gap_sm, a.pb_lg]}> 179 <Text style={[a.text_2xl, a.font_bold]}> 180 <Trans>Constellations instance URL</Trans> 181 </Text> 182 </View> 183 184 <View style={a.gap_lg}> 185 <Dialog.Input 186 label="Text input field" 187 autoFocus 188 style={[styles.textInput, pal.border, pal.text]} 189 onChangeText={value => { 190 setUrl(value) 191 }} 192 placeholder={persisted.defaults.constellationInstance} 193 placeholderTextColor={pal.colors.textLight} 194 onSubmitEditing={submit} 195 accessibilityHint={_( 196 msg`Input the url of the constellations instance to use`, 197 )} 198 defaultValue={constellationInstance} 199 /> 200 201 <View style={IS_WEB && [a.flex_row, a.justify_end]}> 202 <Button 203 label={_(msg`Save`)} 204 size="large" 205 onPress={submit} 206 variant="solid" 207 color="primary" 208 disabled={shouldDisable()}> 209 <ButtonText> 210 <Trans>Save</Trans> 211 </ButtonText> 212 </Button> 213 </View> 214 </View> 215 216 <Dialog.Close /> 217 </Dialog.ScrollableInner> 218 </Dialog.Outer> 219 ) 220} 221 222function LibreTranslateInstanceDialog({ 223 control, 224}: { 225 control: Dialog.DialogControlProps 226}) { 227 const pal = usePalette('default') 228 const {_} = useLingui() 229 230 const libreTranslateInstance = useLibreTranslateInstance() 231 const [url, setUrl] = useState(libreTranslateInstance ?? '') 232 const setLibreTranslateInstance = useSetLibreTranslateInstance() 233 234 const submit = () => { 235 setLibreTranslateInstance(url) 236 control.close() 237 } 238 239 const shouldDisable = () => { 240 try { 241 return !new URL(url).hostname.includes('.') 242 } catch (e) { 243 return true 244 } 245 } 246 247 return ( 248 <Dialog.Outer 249 control={control} 250 nativeOptions={{preventExpansion: true}} 251 onClose={() => setUrl(libreTranslateInstance ?? '')}> 252 <Dialog.Handle /> 253 <Dialog.ScrollableInner label={_(msg`LibreTranslate instance URL`)}> 254 <View style={[a.gap_sm, a.pb_lg]}> 255 <Text style={[a.text_2xl, a.font_bold]}> 256 <Trans>LibreTranslate instance URL</Trans> 257 </Text> 258 </View> 259 260 <View style={a.gap_lg}> 261 <Dialog.Input 262 label="Text input field" 263 autoFocus 264 style={[styles.textInput, pal.border, pal.text]} 265 onChangeText={value => { 266 setUrl(value) 267 }} 268 placeholder={persisted.defaults.libreTranslateInstance} 269 placeholderTextColor={pal.colors.textLight} 270 onSubmitEditing={submit} 271 accessibilityHint={_( 272 msg`Input the url of the LibreTranslate instance to use`, 273 )} 274 defaultValue={libreTranslateInstance} 275 /> 276 277 <View style={IS_WEB && [a.flex_row, a.justify_end]}> 278 <Button 279 label={_(msg`Save`)} 280 size="large" 281 onPress={submit} 282 variant="solid" 283 color="primary" 284 disabled={shouldDisable()}> 285 <ButtonText> 286 <Trans>Save</Trans> 287 </ButtonText> 288 </Button> 289 </View> 290 </View> 291 292 <Dialog.Close /> 293 </Dialog.ScrollableInner> 294 </Dialog.Outer> 295 ) 296} 297 298function TrustedVerifiersDialog({ 299 control, 300}: { 301 control: Dialog.DialogControlProps 302}) { 303 const {_} = useLingui() 304 305 return ( 306 <Dialog.Outer control={control} nativeOptions={{preventExpansion: true}}> 307 <Dialog.Handle /> 308 <Dialog.ScrollableInner label={_(msg`Trusted Verifiers`)}> 309 <View style={[a.gap_sm, a.pb_lg]}> 310 <Text style={[a.text_2xl, a.font_bold]}> 311 <Trans>Trusted Verifiers</Trans> 312 </Text> 313 </View> 314 315 <TrustedVerifiers /> 316 317 <Dialog.Close /> 318 </Dialog.ScrollableInner> 319 </Dialog.Outer> 320 ) 321} 322 323const TrustedVerifiers = (): React.ReactNode => { 324 const trusted = useDeerVerificationTrusted() 325 const moderationOpts = useModerationOpts() 326 327 const results = useProfilesQuery({ 328 handles: Array.from(trusted), 329 }) 330 331 const {gtMobile} = useBreakpoints() 332 333 return ( 334 results.data && 335 moderationOpts !== undefined && ( 336 <View style={[gtMobile ? a.pl_md : a.pl_sm, a.pb_sm]}> 337 {results.data.profiles.map(profile => ( 338 <SearchProfileCard 339 key={profile.did} 340 profile={profile as ProfileViewBasic} 341 moderationOpts={moderationOpts} 342 /> 343 ))} 344 </View> 345 ) 346 ) 347} 348 349export function DeerSettingsScreen({}: Props) { 350 const {_} = useLingui() 351 352 const goLinksEnabled = useGoLinksEnabled() 353 const setGoLinksEnabled = useSetGoLinksEnabled() 354 355 const directFetchRecords = useDirectFetchRecords() 356 const setDirectFetchRecords = useSetDirectFetchRecords() 357 358 const showExternalShareButtons = useShowExternalShareButtons() 359 const setShowExternalShareButtons = useSetShowExternalShareButtons() 360 361 const noAppLabelers = useNoAppLabelers() 362 const setNoAppLabelers = useSetNoAppLabelers() 363 364 const noDiscoverFallback = useNoDiscoverFallback() 365 const setNoDiscoverFallback = useSetNoDiscoverFallback() 366 367 const highQualityImages = useHighQualityImages() 368 const setHighQualityImages = useSetHighQualityImages() 369 370 const hideFeedsPromoTab = useHideFeedsPromoTab() 371 const setHideFeedsPromoTab = useSetHideFeedsPromoTab() 372 373 const disableViaRepostNotification = useDisableViaRepostNotification() 374 const setDisableViaRepostNotification = useSetDisableViaRepostNotification() 375 376 const disableComposerPrompt = useDisableComposerPrompt() 377 const setDisableComposerPrompt = useSetDisableComposerPrompt() 378 379 const disableLikesMetrics = useDisableLikesMetrics() 380 const setDisableLikesMetrics = useSetDisableLikesMetrics() 381 382 const disableRepostsMetrics = useDisableRepostsMetrics() 383 const setDisableRepostsMetrics = useSetDisableRepostsMetrics() 384 385 const disableQuotesMetrics = useDisableQuotesMetrics() 386 const setDisableQuotesMetrics = useSetDisableQuotesMetrics() 387 388 const disableSavesMetrics = useDisableSavesMetrics() 389 const setDisableSavesMetrics = useSetDisableSavesMetrics() 390 391 const disableReplyMetrics = useDisableReplyMetrics() 392 const setDisableReplyMetrics = useSetDisableReplyMetrics() 393 394 const disableFollowersMetrics = useDisableFollowersMetrics() 395 const setDisableFollowersMetrics = useSetDisableFollowersMetrics() 396 397 const disableFollowingMetrics = useDisableFollowingMetrics() 398 const setDisableFollowingMetrics = useSetDisableFollowingMetrics() 399 400 const disableFollowedByMetrics = useDisableFollowedByMetrics() 401 const setDisableFollowedByMetrics = useSetDisableFollowedByMetrics() 402 403 const disablePostsMetrics = useDisablePostsMetrics() 404 const setDisablePostsMetrics = useSetDisablePostsMetrics() 405 406 const hideSimilarAccountsRecomm = useHideSimilarAccountsRecomm() 407 const setHideSimilarAccountsRecomm = useSetHideSimilarAccountsRecomm() 408 409 const hideUnreplyablePosts = useHideUnreplyablePosts() 410 const setHideUnreplyablePosts = useSetHideUnreplyablePosts() 411 412 const disableVerifyEmailReminder = useDisableVerifyEmailReminder() 413 const setDisableVerifyEmailReminder = useSetDisableVerifyEmailReminder() 414 415 const constellationInstance = useConstellationInstance() 416 const setConstellationInstanceControl = Dialog.useDialogControl() 417 418 const setTrustedVerifiersDialogControl = Dialog.useDialogControl() 419 420 const deerVerificationEnabled = useDeerVerificationEnabled() 421 const setDeerVerificationEnabled = useSetDeerVerificationEnabled() 422 423 const repostCarouselEnabled = useRepostCarouselEnabled() 424 const setRepostCarouselEnabled = useSetRepostCarouselEnabled() 425 426 const showLinkInHandle = useShowLinkInHandle() 427 const setShowLinkInHandle = useSetShowLinkInHandle() 428 429 const translationServicePreference = useTranslationServicePreference() 430 const setTranslationServicePreference = useSetTranslationServicePreference() 431 432 const setLibreTranslateInstanceControl = Dialog.useDialogControl() 433 434 const postReplacement = usePostReplacement() 435 const setPostReplacement = useSetPostReplacement() 436 437 return ( 438 <Layout.Screen> 439 <Layout.Header.Outer> 440 <Layout.Header.BackButton /> 441 <Layout.Header.Content> 442 <Layout.Header.TitleText> 443 <Trans>Experiments</Trans> 444 </Layout.Header.TitleText> 445 </Layout.Header.Content> 446 <Layout.Header.Slot /> 447 </Layout.Header.Outer> 448 <Layout.Content> 449 <SettingsList.Container> 450 <SettingsList.Group contentContainerStyle={[a.gap_sm]}> 451 <SettingsList.ItemIcon icon={DeerIcon} /> 452 <SettingsList.ItemText> 453 <Trans>Redirects</Trans> 454 </SettingsList.ItemText> 455 <Toggle.Item 456 name="use_go_links" 457 label={_(msg`Redirect through go.bsky.app`)} 458 value={goLinksEnabled ?? false} 459 onChange={value => setGoLinksEnabled(value)} 460 style={[a.w_full]}> 461 <Toggle.LabelText style={[a.flex_1]}> 462 <Trans>Redirect through go.bsky.app</Trans> 463 </Toggle.LabelText> 464 <Toggle.Platform /> 465 </Toggle.Item> 466 </SettingsList.Group> 467 468 <SettingsList.Group contentContainerStyle={[a.gap_sm]}> 469 <SettingsList.ItemIcon icon={VisibilityIcon} /> 470 <SettingsList.ItemText> 471 <Trans>Visibility</Trans> 472 </SettingsList.ItemText> 473 <Toggle.Item 474 name="direct_fetch_records" 475 label={_( 476 msg`Fetch records directly from PDS to see through quote blocks`, 477 )} 478 value={directFetchRecords} 479 onChange={value => setDirectFetchRecords(value)} 480 style={[a.w_full]}> 481 <Toggle.LabelText style={[a.flex_1]}> 482 <Trans> 483 Fetch records directly from PDS to see contents of blocked and 484 detached quotes 485 </Trans> 486 </Toggle.LabelText> 487 <Toggle.Platform /> 488 </Toggle.Item> 489 </SettingsList.Group> 490 491 <SettingsList.Group contentContainerStyle={[a.gap_sm]}> 492 <SettingsList.ItemIcon icon={ChainLinkIcon} /> 493 <SettingsList.ItemText> 494 <Trans>Bridging and Fediverse</Trans> 495 </SettingsList.ItemText> 496 <Toggle.Item 497 name="external_share_buttons" 498 label={_( 499 msg`Show "Open original post" and "Open post in PDSls" buttons`, 500 )} 501 value={showExternalShareButtons} 502 onChange={value => setShowExternalShareButtons(value)} 503 style={[a.w_full]}> 504 <Toggle.LabelText style={[a.flex_1]}> 505 <Trans> 506 Show "Open original post" and "Open post in PDSls" buttons 507 </Trans> 508 </Toggle.LabelText> 509 <Toggle.Platform /> 510 </Toggle.Item> 511 </SettingsList.Group> 512 513 <SettingsList.Group contentContainerStyle={[a.gap_sm]}> 514 <SettingsList.ItemIcon icon={VerifiedIcon} /> 515 <SettingsList.ItemText> 516 <Trans>Verification</Trans> 517 </SettingsList.ItemText> 518 <Toggle.Item 519 name="custom_verifications" 520 label={_( 521 msg`Select your own set of trusted verifiers, and operate as a verifier`, 522 )} 523 value={deerVerificationEnabled} 524 onChange={value => setDeerVerificationEnabled(value)} 525 style={[a.w_full]}> 526 <Toggle.LabelText style={[a.flex_1]}> 527 <Trans> 528 Select your own set of trusted verifiers, and operate as a 529 verifier 530 </Trans> 531 </Toggle.LabelText> 532 <Toggle.Platform /> 533 </Toggle.Item> 534 </SettingsList.Group> 535 536 <SettingsList.Item> 537 <Admonition type="warning" style={[a.flex_1]}> 538 <Trans> 539 May slow down the client or fail to find all labels. Revoke and 540 grant trust in the meatball menu on a profile.{' '} 541 {deerVerificationEnabled 542 ? 'You currently' 543 : 'If enabled, you would'}{' '} 544 trust the following verifiers: 545 </Trans> 546 </Admonition> 547 </SettingsList.Item> 548 549 <SettingsList.Item> 550 <SettingsList.ItemIcon icon={VerifiedIcon} /> 551 <SettingsList.ItemText> 552 <Trans>{`Trusted Verifiers`}</Trans> 553 </SettingsList.ItemText> 554 <SettingsList.BadgeButton 555 label={_(msg`View`)} 556 onPress={() => setTrustedVerifiersDialogControl.open()} 557 /> 558 </SettingsList.Item> 559 560 <SettingsList.Item> 561 <SettingsList.ItemIcon icon={StarIcon} /> 562 <SettingsList.ItemText> 563 <Trans>{`Constellation Instance`}</Trans> 564 </SettingsList.ItemText> 565 <SettingsList.BadgeButton 566 label={_(msg`Change`)} 567 onPress={() => setConstellationInstanceControl.open()} 568 /> 569 </SettingsList.Item> 570 <SettingsList.Item> 571 <Admonition type="info" style={[a.flex_1]}> 572 <Trans> 573 Constellation is used to supplement AppView responses for custom 574 verifications and nuclear block bypass, via backlinks. Current 575 instance: 576 <InlineLinkText 577 to={constellationInstance} 578 label={constellationInstance}> 579 {constellationInstance} 580 </InlineLinkText> 581 </Trans> 582 </Admonition> 583 </SettingsList.Item> 584 585 <SettingsList.Divider /> 586 587 <SettingsList.Group contentContainerStyle={[a.gap_sm]}> 588 <SettingsList.ItemIcon icon={PencilIcon} /> 589 <SettingsList.ItemText> 590 <Trans> 591 Call posts{' '} 592 {postReplacement.string.length 593 ? postReplacement.string.toLowerCase() 594 : 'skeet'} 595 s 596 </Trans> 597 </SettingsList.ItemText> 598 <Toggle.Item 599 name="call_posts_skeets" 600 label={_( 601 msg`Changes post to another word of your choosing. Requires a refresh to update.`, 602 )} 603 value={postReplacement.enabled} 604 onChange={value => 605 setPostReplacement({ 606 enabled: value, 607 string: postReplacement.string, 608 }) 609 } 610 style={[a.w_full]}> 611 <Toggle.LabelText style={[a.flex_1]}> 612 <Trans> 613 Changes post to another word of your choosing. Requires a 614 refresh to update. 615 </Trans> 616 </Toggle.LabelText> 617 <Toggle.Platform /> 618 </Toggle.Item> 619 620 {postReplacement.enabled && ( 621 <SettingsList.Item> 622 <TextField.Root> 623 <TextField.Input 624 label={_(msg`Custom post name`)} 625 value={postReplacement.string} 626 onChangeText={(value: string) => 627 setPostReplacement( 628 (curr: {enabled: boolean; string: string}) => ({ 629 ...curr, 630 string: value, 631 }), 632 ) 633 } 634 /> 635 </TextField.Root> 636 </SettingsList.Item> 637 )} 638 </SettingsList.Group> 639 640 <SettingsList.Group contentContainerStyle={[a.gap_sm]}> 641 <SettingsList.ItemIcon icon={PaintRollerIcon} /> 642 <SettingsList.ItemText> 643 <Trans>Tweaks</Trans> 644 </SettingsList.ItemText> 645 <Toggle.Item 646 name="repost_carousel" 647 label={_(msg`Combine reposts into a horizontal carousel`)} 648 value={repostCarouselEnabled} 649 onChange={value => setRepostCarouselEnabled(value)} 650 style={[a.w_full]}> 651 <Toggle.LabelText style={[a.flex_1]}> 652 <Trans>Combine reposts into a horizontal carousel</Trans> 653 </Toggle.LabelText> 654 <Toggle.Platform /> 655 </Toggle.Item> 656 <Toggle.Item 657 name="no_discover_fallback" 658 label={_(msg`Do not fall back to discover feed`)} 659 value={noDiscoverFallback} 660 onChange={value => setNoDiscoverFallback(value)} 661 style={[a.w_full]}> 662 <Toggle.LabelText style={[a.flex_1]}> 663 <Trans>Do not fall back to discover feed</Trans> 664 </Toggle.LabelText> 665 <Toggle.Platform /> 666 </Toggle.Item> 667 <Toggle.Item 668 name="show_link_in_handle" 669 label={_( 670 msg`On non-bsky.social handles, show a link to that URL`, 671 )} 672 value={showLinkInHandle} 673 onChange={value => setShowLinkInHandle(value)} 674 style={[a.w_full]}> 675 <Toggle.LabelText style={[a.flex_1]}> 676 <Trans> 677 On non-bsky.social handles, show a link to that URL 678 </Trans> 679 </Toggle.LabelText> 680 <Toggle.Platform /> 681 </Toggle.Item> 682 683 <Toggle.Item 684 name="repost_carousel" 685 label={_(msg`Combine reposts into a horizontal carousel`)} 686 value={repostCarouselEnabled} 687 onChange={value => setRepostCarouselEnabled(value)} 688 style={[a.w_full]}> 689 <Toggle.LabelText style={[a.flex_1]}> 690 <Trans>Combine reposts into a horizontal carousel</Trans> 691 </Toggle.LabelText> 692 <Toggle.Platform /> 693 </Toggle.Item> 694 695 <Toggle.Item 696 name="no_discover_fallback" 697 label={_(msg`Do not fall back to discover feed`)} 698 value={noDiscoverFallback} 699 onChange={value => setNoDiscoverFallback(value)} 700 style={[a.w_full]}> 701 <Toggle.LabelText style={[a.flex_1]}> 702 <Trans>Do not fall back to discover feed</Trans> 703 </Toggle.LabelText> 704 <Toggle.Platform /> 705 </Toggle.Item> 706 707 <Toggle.Item 708 name="high_quality_images" 709 label={_(msg`Display images in higher quality`)} 710 value={highQualityImages} 711 onChange={value => setHighQualityImages(value)} 712 style={[a.w_full]}> 713 <Toggle.LabelText style={[a.flex_1]}> 714 <Trans>Display images in higher quality</Trans> 715 </Toggle.LabelText> 716 <Toggle.Platform /> 717 </Toggle.Item> 718 <Admonition type="info" style={[a.flex_1]}> 719 <Trans> 720 Images will be served as PNG instead of JPEG. Images will take 721 longer to load and use more bandwidth. 722 </Trans> 723 </Admonition> 724 725 <Toggle.Item 726 name="hide_feeds_promo_tab" 727 label={_(msg`Hide "Feeds ✨" tab when only one feed is selected`)} 728 value={hideFeedsPromoTab} 729 onChange={value => setHideFeedsPromoTab(value)} 730 style={[a.w_full]}> 731 <Toggle.LabelText style={[a.flex_1]}> 732 <Trans> 733 Hide "Feeds ✨" tab when only one feed is selected 734 </Trans> 735 </Toggle.LabelText> 736 <Toggle.Platform /> 737 </Toggle.Item> 738 739 <Toggle.Item 740 name="disable_via_repost_notification" 741 label={_(msg`Disable via repost notifications`)} 742 value={disableViaRepostNotification} 743 onChange={value => setDisableViaRepostNotification(value)} 744 style={[a.w_full]}> 745 <Toggle.LabelText style={[a.flex_1]}> 746 <Trans>Disable via repost notifications</Trans> 747 </Toggle.LabelText> 748 <Toggle.Platform /> 749 </Toggle.Item> 750 <Admonition type="info" style={[a.flex_1]}> 751 <Trans> 752 Forcefully disables the notifications other people receive when 753 you like/repost a post someone else has reposted for privacy. 754 </Trans> 755 </Admonition> 756 757 <Toggle.Item 758 name="hide_similar_accounts_recommendations" 759 label={_(msg`Hide similar accounts recommendations`)} 760 value={hideSimilarAccountsRecomm} 761 onChange={value => setHideSimilarAccountsRecomm(value)} 762 style={[a.w_full]}> 763 <Toggle.LabelText style={[a.flex_1]}> 764 <Trans>Hide similar accounts recommendations</Trans> 765 </Toggle.LabelText> 766 <Toggle.Platform /> 767 </Toggle.Item> 768 769 <Toggle.Item 770 name="hide_unreplyable_posts" 771 label={_(msg`Hide posts that cannot be replied to from feeds`)} 772 value={hideUnreplyablePosts} 773 onChange={value => setHideUnreplyablePosts(value)} 774 style={[a.w_full]}> 775 <Toggle.LabelText style={[a.flex_1]}> 776 <Trans>Hide posts that cannot be replied to from feeds</Trans> 777 </Toggle.LabelText> 778 <Toggle.Platform /> 779 </Toggle.Item> 780 <Admonition type="info" style={[a.flex_1]}> 781 <Trans> 782 Hides posts from feeds where replies are disabled (e.g. due to 783 postgates or other restrictions). Does not affect thread views. 784 </Trans> 785 </Admonition> 786 787 <Toggle.Item 788 name="disable_composer_prompt" 789 label={_(msg`Disable composer prompt`)} 790 value={disableComposerPrompt} 791 onChange={value => setDisableComposerPrompt(value)} 792 style={[a.w_full]}> 793 <Toggle.LabelText style={[a.flex_1]}> 794 <Trans>Disable composer prompt</Trans> 795 </Toggle.LabelText> 796 <Toggle.Platform /> 797 </Toggle.Item> 798 799 <Toggle.Item 800 name="disable_verify_email_reminder" 801 label={_(msg`Disable verify email reminder`)} 802 value={disableVerifyEmailReminder} 803 onChange={value => setDisableVerifyEmailReminder(value)} 804 style={[a.w_full]}> 805 <Toggle.LabelText style={[a.flex_1]}> 806 <Trans>Disable verify email reminder</Trans> 807 </Toggle.LabelText> 808 <Toggle.Platform /> 809 </Toggle.Item> 810 <Admonition type="warning" style={[a.flex_1]}> 811 <Trans> 812 This only gets rid of the reminder on app launch, useful if your 813 PDS does not have email verification setup.\nThis does NOT give 814 access to features locked behind email verification. 815 </Trans> 816 </Admonition> 817 </SettingsList.Group> 818 819 <SettingsList.Divider /> 820 821 <SettingsList.Group contentContainerStyle={[a.gap_sm]}> 822 <SettingsList.ItemIcon icon={EarthIcon} /> 823 <SettingsList.ItemText> 824 <Trans>Post Translation Engine</Trans> 825 </SettingsList.ItemText> 826 827 <Toggle.Item 828 name="service_google" 829 label={_(msg`Use Google Translate`)} 830 value={translationServicePreference === 'google'} 831 onChange={() => setTranslationServicePreference('google')} 832 style={[a.w_full]}> 833 <Toggle.LabelText style={[a.flex_1]}> 834 <Trans>Use Google Translate</Trans> 835 </Toggle.LabelText> 836 <Toggle.Radio /> 837 </Toggle.Item> 838 839 <Toggle.Item 840 name="service_kagi" 841 label={_(msg`Use Kagi Translate`)} 842 value={translationServicePreference === 'kagi'} 843 onChange={() => setTranslationServicePreference('kagi')} 844 style={[a.w_full]}> 845 <Toggle.LabelText style={[a.flex_1]}> 846 <Trans>Use Kagi Translate</Trans> 847 </Toggle.LabelText> 848 <Toggle.Radio /> 849 </Toggle.Item> 850 851 <Toggle.Item 852 name="service_papago" 853 label={_(msg`Use Naver Papago`)} 854 value={translationServicePreference === 'papago'} 855 onChange={() => setTranslationServicePreference('papago')} 856 style={[a.w_full]}> 857 <Toggle.LabelText style={[a.flex_1]}> 858 <Trans>Use Naver Papago</Trans> 859 </Toggle.LabelText> 860 <Toggle.Radio /> 861 </Toggle.Item> 862 863 <Toggle.Item 864 name="service_libreTranslate" 865 label={_(msg`Use LibreTranslate`)} 866 value={translationServicePreference === 'libreTranslate'} 867 onChange={() => setTranslationServicePreference('libreTranslate')} 868 style={[a.w_full]}> 869 <Toggle.LabelText style={[a.flex_1]}> 870 <Trans>Use LibreTranslate</Trans> 871 </Toggle.LabelText> 872 <Toggle.Radio /> 873 </Toggle.Item> 874 </SettingsList.Group> 875 876 {translationServicePreference === 'libreTranslate' && ( 877 <SettingsList.Item> 878 <SettingsList.ItemIcon icon={EarthIcon} /> 879 <SettingsList.ItemText> 880 <Trans>{`LibreTranslate Instance`}</Trans> 881 </SettingsList.ItemText> 882 <SettingsList.BadgeButton 883 label={_(msg`Change`)} 884 onPress={() => setLibreTranslateInstanceControl.open()} 885 /> 886 </SettingsList.Item> 887 )} 888 889 <SettingsList.Divider /> 890 891 <SettingsList.Group contentContainerStyle={[a.gap_sm]}> 892 <SettingsList.ItemIcon icon={VisibilityIcon} /> 893 <SettingsList.ItemText> 894 <Trans>Metrics</Trans> 895 </SettingsList.ItemText> 896 897 <Toggle.Item 898 name="disable_likes_metrics" 899 label={_(msg`Disable likes metrics`)} 900 value={disableLikesMetrics} 901 onChange={value => setDisableLikesMetrics(value)} 902 style={[a.w_full]}> 903 <Toggle.LabelText style={[a.flex_1]}> 904 <Trans>Disable likes metrics</Trans> 905 </Toggle.LabelText> 906 <Toggle.Platform /> 907 </Toggle.Item> 908 909 <Toggle.Item 910 name="disable_reposts_metrics" 911 label={_(msg`Disable Reposts Metrics`)} 912 value={disableRepostsMetrics} 913 onChange={value => setDisableRepostsMetrics(value)} 914 style={[a.w_full]}> 915 <Toggle.LabelText style={[a.flex_1]}> 916 <Trans>Disable Reposts Metrics</Trans> 917 </Toggle.LabelText> 918 <Toggle.Platform /> 919 </Toggle.Item> 920 921 <Toggle.Item 922 name="disable_quotes_metrics" 923 label={_(msg`Disable quotes metrics`)} 924 value={disableQuotesMetrics} 925 onChange={value => setDisableQuotesMetrics(value)} 926 style={[a.w_full]}> 927 <Toggle.LabelText style={[a.flex_1]}> 928 <Trans>Disable quotes metrics</Trans> 929 </Toggle.LabelText> 930 <Toggle.Platform /> 931 </Toggle.Item> 932 933 <Toggle.Item 934 name="disable_saves_metrics" 935 label={_(msg`Disable saves metrics`)} 936 value={disableSavesMetrics} 937 onChange={value => setDisableSavesMetrics(value)} 938 style={[a.w_full]}> 939 <Toggle.LabelText style={[a.flex_1]}> 940 <Trans>Disable saves metrics</Trans> 941 </Toggle.LabelText> 942 <Toggle.Platform /> 943 </Toggle.Item> 944 945 <Toggle.Item 946 name="disable_reply_metrics" 947 label={_(msg`Disable reply metrics`)} 948 value={disableReplyMetrics} 949 onChange={value => setDisableReplyMetrics(value)} 950 style={[a.w_full]}> 951 <Toggle.LabelText style={[a.flex_1]}> 952 <Trans>Disable reply metrics</Trans> 953 </Toggle.LabelText> 954 <Toggle.Platform /> 955 </Toggle.Item> 956 957 <Toggle.Item 958 name="disable_followers_metrics" 959 label={_(msg`Disable followers metrics`)} 960 value={disableFollowersMetrics} 961 onChange={value => setDisableFollowersMetrics(value)} 962 style={[a.w_full]}> 963 <Toggle.LabelText style={[a.flex_1]}> 964 <Trans>Disable followers metrics</Trans> 965 </Toggle.LabelText> 966 <Toggle.Platform /> 967 </Toggle.Item> 968 969 <Toggle.Item 970 name="disable_following_metrics" 971 label={_(msg`Disable following metrics`)} 972 value={disableFollowingMetrics} 973 onChange={value => setDisableFollowingMetrics(value)} 974 style={[a.w_full]}> 975 <Toggle.LabelText style={[a.flex_1]}> 976 <Trans>Disable following metrics</Trans> 977 </Toggle.LabelText> 978 <Toggle.Platform /> 979 </Toggle.Item> 980 981 <Toggle.Item 982 name="disable_followed_by_metrics" 983 label={_(msg`Disable "followed by" metrics`)} 984 value={disableFollowedByMetrics} 985 onChange={value => setDisableFollowedByMetrics(value)} 986 style={[a.w_full]}> 987 <Toggle.LabelText style={[a.flex_1]}> 988 <Trans>Disable "followed by" metrics</Trans> 989 </Toggle.LabelText> 990 <Toggle.Platform /> 991 </Toggle.Item> 992 993 <Toggle.Item 994 name="disable_posts_metrics" 995 label={_(msg`Disable posts metrics`)} 996 value={disablePostsMetrics} 997 onChange={value => setDisablePostsMetrics(value)} 998 style={[a.w_full]}> 999 <Toggle.LabelText style={[a.flex_1]}> 1000 <Trans>Disable posts metrics</Trans> 1001 </Toggle.LabelText> 1002 <Toggle.Platform /> 1003 </Toggle.Item> 1004 </SettingsList.Group> 1005 1006 <SettingsList.Divider /> 1007 1008 <SettingsList.Group contentContainerStyle={[a.gap_sm]}> 1009 <SettingsList.ItemIcon icon={RaisingHandIcon} /> 1010 <SettingsList.ItemText> 1011 <Trans>Labelers</Trans> 1012 </SettingsList.ItemText> 1013 <Toggle.Item 1014 name="no_app_labelers" 1015 label={_(msg`Do not declare any app labelers`)} 1016 value={noAppLabelers} 1017 onChange={value => setNoAppLabelers(value)} 1018 style={[a.w_full]}> 1019 <Toggle.LabelText style={[a.flex_1]}> 1020 <Trans>Do not declare any default app labelers</Trans> 1021 </Toggle.LabelText> 1022 <Toggle.Platform /> 1023 </Toggle.Item> 1024 </SettingsList.Group> 1025 1026 <SettingsList.Item> 1027 <Admonition type="warning" style={[a.flex_1]}> 1028 <Trans>Restart the app after changing this setting.</Trans> 1029 </Admonition> 1030 </SettingsList.Item> 1031 <SettingsList.Item> 1032 <Admonition type="tip" style={[a.flex_1]}> 1033 <Trans> 1034 Some App Views will default to using an app labeler if you have 1035 no labelers, so consider subscribing to at least one labeler if 1036 you have issues. 1037 </Trans> 1038 </Admonition> 1039 </SettingsList.Item> 1040 <SettingsList.Item> 1041 <Admonition type="info" style={[a.flex_1]}> 1042 <Trans> 1043 App labelers are mandatory top-level labelers that can perform 1044 "takedowns". This setting does not influence geolocation-based 1045 labelers. 1046 </Trans> 1047 </Admonition> 1048 </SettingsList.Item> 1049 </SettingsList.Container> 1050 </Layout.Content> 1051 <ConstellationInstanceDialog control={setConstellationInstanceControl} /> 1052 <TrustedVerifiersDialog control={setTrustedVerifiersDialogControl} /> 1053 <LibreTranslateInstanceDialog 1054 control={setLibreTranslateInstanceControl} 1055 /> 1056 </Layout.Screen> 1057 ) 1058} 1059 1060const styles = { 1061 textInput: { 1062 borderWidth: 1, 1063 borderRadius: 6, 1064 paddingHorizontal: 14, 1065 paddingVertical: 10, 1066 fontSize: 16, 1067 }, 1068}