Bluesky app fork with some witchin' additions 💫

Compare changes

Choose any two refs to compare.

Changed files
+126 -1
src
screens
Settings
state
+64
src/screens/Settings/DeerSettings.tsx
··· 80 useSetShowExternalShareButtons, 81 useShowExternalShareButtons, 82 } from '#/state/preferences/external-share-buttons' 83 import { 84 useHideFeedsPromoTab, 85 useSetHideFeedsPromoTab, ··· 467 const showLinkInHandle = useShowLinkInHandle() 468 const setShowLinkInHandle = useSetShowLinkInHandle() 469 470 const [gates, setGatesView] = useState(Object.assign({ 471 alt_share_icon: false, 472 debug_show_feedcontext: false, ··· 653 </Admonition> 654 </SettingsList.Item> 655 656 <SettingsList.Group contentContainerStyle={[a.gap_sm]}> 657 <SettingsList.ItemIcon icon={PaintRollerIcon} /> 658 <SettingsList.ItemText>
··· 80 useSetShowExternalShareButtons, 81 useShowExternalShareButtons, 82 } from '#/state/preferences/external-share-buttons' 83 + import { 84 + useSetTerminologyPreference, 85 + useTerminologyPreference, 86 + } from '#/state/preferences/terminology-preference' 87 import { 88 useHideFeedsPromoTab, 89 useSetHideFeedsPromoTab, ··· 471 const showLinkInHandle = useShowLinkInHandle() 472 const setShowLinkInHandle = useSetShowLinkInHandle() 473 474 + const terminologyPreference = useTerminologyPreference() 475 + const setTerminologyPreference = useSetTerminologyPreference() 476 + 477 const [gates, setGatesView] = useState(Object.assign({ 478 alt_share_icon: false, 479 debug_show_feedcontext: false, ··· 660 </Admonition> 661 </SettingsList.Item> 662 663 + <SettingsList.Group contentContainerStyle={[a.gap_sm]}> 664 + <SettingsList.ItemIcon icon={PaintRollerIcon} /> 665 + <SettingsList.ItemText> 666 + <Trans>Terminology</Trans> 667 + </SettingsList.ItemText> 668 + </SettingsList.Group> 669 + 670 + <SettingsList.Item> 671 + <Admonition type="info" style={[a.flex_1]}> 672 + <Trans> 673 + Choose your preferred terminology for posts throughout the app. 674 + </Trans> 675 + </Admonition> 676 + </SettingsList.Item> 677 + 678 + <SettingsList.Item> 679 + <Toggle.Item 680 + name="terminology_skeet" 681 + label={_(msg`Use "skeet(s)"`)} 682 + value={terminologyPreference === 'skeet'} 683 + onChange={() => setTerminologyPreference('skeet')} 684 + style={[a.w_full]}> 685 + <Toggle.LabelText style={[a.flex_1]}> 686 + <Trans>Use "skeet(s)"</Trans> 687 + </Toggle.LabelText> 688 + <Toggle.Radio /> 689 + </Toggle.Item> 690 + </SettingsList.Item> 691 + 692 + <SettingsList.Item> 693 + <Toggle.Item 694 + name="terminology_post" 695 + label={_(msg`Use "post(s)"`)} 696 + value={terminologyPreference === 'post'} 697 + onChange={() => setTerminologyPreference('post')} 698 + style={[a.w_full]}> 699 + <Toggle.LabelText style={[a.flex_1]}> 700 + <Trans>Use "post(s)"</Trans> 701 + </Toggle.LabelText> 702 + <Toggle.Radio /> 703 + </Toggle.Item> 704 + </SettingsList.Item> 705 + 706 + <SettingsList.Item> 707 + <Toggle.Item 708 + name="terminology_spell" 709 + label={_(msg`Use "spell(s)"`)} 710 + value={terminologyPreference === 'spell'} 711 + onChange={() => setTerminologyPreference('spell')} 712 + style={[a.w_full]}> 713 + <Toggle.LabelText style={[a.flex_1]}> 714 + <Trans>Use "spell(s)"</Trans> 715 + </Toggle.LabelText> 716 + <Toggle.Radio /> 717 + </Toggle.Item> 718 + </SettingsList.Item> 719 + 720 <SettingsList.Group contentContainerStyle={[a.gap_sm]}> 721 <SettingsList.ItemIcon icon={PaintRollerIcon} /> 722 <SettingsList.ItemText>
+2
src/state/persisted/schema.ts
··· 169 hideUnreplyablePosts: z.boolean().optional(), 170 171 showExternalShareButtons: z.boolean().optional(), 172 173 /** @deprecated */ 174 mutedThreads: z.array(z.string()), ··· 272 highQualityImages: false, 273 hideUnreplyablePosts: false, 274 showExternalShareButtons: false, 275 } 276 277 export function tryParse(rawData: string): Schema | undefined {
··· 169 hideUnreplyablePosts: z.boolean().optional(), 170 171 showExternalShareButtons: z.boolean().optional(), 172 + terminologyPreference: z.enum(['skeet', 'post', 'spell']).optional(), 173 174 /** @deprecated */ 175 mutedThreads: z.array(z.string()), ··· 273 highQualityImages: false, 274 hideUnreplyablePosts: false, 275 showExternalShareButtons: false, 276 + terminologyPreference: 'skeet', 277 } 278 279 export function tryParse(rawData: string): Schema | undefined {
+8 -1
src/state/preferences/index.tsx
··· 37 import {Provider as RepostCarouselProvider} from './repost-carousel-enabled' 38 import {Provider as ShowLinkInHandleProvider} from './show-link-in-handle' 39 import {Provider as SubtitlesProvider} from './subtitles' 40 import {Provider as TrendingSettingsProvider} from './trending' 41 import {Provider as UsedStarterPacksProvider} from './used-starter-packs' 42 ··· 59 export {useLabelDefinitions} from './label-defs' 60 export {useLanguagePrefs, useLanguagePrefsApi} from './languages' 61 export {useSetSubtitlesEnabled, useSubtitlesEnabled} from './subtitles' 62 63 export function Provider({children}: React.PropsWithChildren<{}>) { 64 return ( ··· 101 <EnableSquareAvatarsProvider> 102 <EnableSquareButtonsProvider> 103 <DisableVerifyEmailReminderProvider> 104 - {children} 105 </DisableVerifyEmailReminderProvider> 106 </EnableSquareButtonsProvider> 107 </EnableSquareAvatarsProvider>
··· 37 import {Provider as RepostCarouselProvider} from './repost-carousel-enabled' 38 import {Provider as ShowLinkInHandleProvider} from './show-link-in-handle' 39 import {Provider as SubtitlesProvider} from './subtitles' 40 + import {Provider as TerminologyPreferenceProvider} from './terminology-preference' 41 import {Provider as TrendingSettingsProvider} from './trending' 42 import {Provider as UsedStarterPacksProvider} from './used-starter-packs' 43 ··· 60 export {useLabelDefinitions} from './label-defs' 61 export {useLanguagePrefs, useLanguagePrefsApi} from './languages' 62 export {useSetSubtitlesEnabled, useSubtitlesEnabled} from './subtitles' 63 + export { 64 + useTerminologyPreference, 65 + useSetTerminologyPreference, 66 + } from './terminology-preference' 67 68 export function Provider({children}: React.PropsWithChildren<{}>) { 69 return ( ··· 106 <EnableSquareAvatarsProvider> 107 <EnableSquareButtonsProvider> 108 <DisableVerifyEmailReminderProvider> 109 + <TerminologyPreferenceProvider> 110 + {children} 111 + </TerminologyPreferenceProvider> 112 </DisableVerifyEmailReminderProvider> 113 </EnableSquareButtonsProvider> 114 </EnableSquareAvatarsProvider>
+52
src/state/preferences/terminology-preference.tsx
···
··· 1 + import React from 'react' 2 + 3 + import * as persisted from '#/state/persisted' 4 + 5 + type StateContext = persisted.Schema['terminologyPreference'] 6 + type SetContext = (v: persisted.Schema['terminologyPreference']) => void 7 + 8 + const stateContext = React.createContext<StateContext>( 9 + persisted.defaults.terminologyPreference, 10 + ) 11 + const setContext = React.createContext<SetContext>( 12 + (_: persisted.Schema['terminologyPreference']) => {}, 13 + ) 14 + 15 + export function Provider({children}: React.PropsWithChildren<{}>) { 16 + const [state, setState] = React.useState( 17 + persisted.get('terminologyPreference'), 18 + ) 19 + 20 + const setStateWrapped = React.useCallback( 21 + (terminologyPreference: persisted.Schema['terminologyPreference']) => { 22 + setState(terminologyPreference) 23 + persisted.write('terminologyPreference', terminologyPreference) 24 + }, 25 + [setState], 26 + ) 27 + 28 + React.useEffect(() => { 29 + return persisted.onUpdate( 30 + 'terminologyPreference', 31 + nextTerminologyPreference => { 32 + setState(nextTerminologyPreference) 33 + }, 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 useTerminologyPreference() { 47 + return React.useContext(stateContext) 48 + } 49 + 50 + export function useSetTerminologyPreference() { 51 + return React.useContext(setContext) 52 + }