Bluesky app fork with some witchin' additions 💫

add option to remove "Feeds" promo when one feed is selected

+84 -6
+20
src/screens/Settings/DeerSettings.tsx
··· 35 useSetDirectFetchRecords, 36 } from '#/state/preferences/direct-fetch-records' 37 import { 38 useHideFollowNotifications, 39 useSetHideFollowNotifications, 40 } from '#/state/preferences/hide-follow-notifications' ··· 262 263 const hideFollowNotifications = useHideFollowNotifications() 264 const setHideFollowNotifications = useSetHideFollowNotifications() 265 266 const location = useGeolocation() 267 const setLocationControl = Dialog.useDialogControl() ··· 518 <Trans> 519 On non-bsky.social handles, show a link to that URL 520 </Trans> 521 </Toggle.LabelText> 522 <Toggle.Platform /> 523 </Toggle.Item>
··· 35 useSetDirectFetchRecords, 36 } from '#/state/preferences/direct-fetch-records' 37 import { 38 + useHideFeedsPromoTab, 39 + useSetHideFeedsPromoTab, 40 + } from '#/state/preferences/hide-feeds-promo-tab' 41 + import { 42 useHideFollowNotifications, 43 useSetHideFollowNotifications, 44 } from '#/state/preferences/hide-follow-notifications' ··· 266 267 const hideFollowNotifications = useHideFollowNotifications() 268 const setHideFollowNotifications = useSetHideFollowNotifications() 269 + 270 + const hideFeedsPromoTab = useHideFeedsPromoTab() 271 + const setHideFeedsPromoTab = useSetHideFeedsPromoTab() 272 273 const location = useGeolocation() 274 const setLocationControl = Dialog.useDialogControl() ··· 525 <Trans> 526 On non-bsky.social handles, show a link to that URL 527 </Trans> 528 + </Toggle.LabelText> 529 + <Toggle.Platform /> 530 + </Toggle.Item> 531 + <Toggle.Item 532 + name="hide_feeds_promo_tab" 533 + label={_( 534 + msg`Hide "Feeds ✨" tab when only one feed is selected`, 535 + )} 536 + value={hideFeedsPromoTab} 537 + onChange={value => setHideFeedsPromoTab(value)} 538 + style={[a.w_full]}> 539 + <Toggle.LabelText style={[a.flex_1]}> 540 + <Trans>Hide "Feeds ✨" tab when only one feed is selected</Trans> 541 </Toggle.LabelText> 542 <Toggle.Platform /> 543 </Toggle.Item>
+2
src/state/persisted/schema.ts
··· 134 hideFollowNotifications: z.boolean().optional(), 135 constellationInstance: z.string().optional(), 136 showLinkInHandle: z.boolean().optional(), 137 deerVerification: z 138 .object({ 139 enabled: z.boolean(), ··· 203 hideFollowNotifications: false, 204 constellationInstance: 'https://constellation.microcosm.blue/', 205 showLinkInHandle: false, 206 deerVerification: { 207 enabled: false, 208 // https://deer.social/profile/did:plc:p2cp5gopk7mgjegy6wadk3ep/post/3lndyqyyr4k2k
··· 134 hideFollowNotifications: z.boolean().optional(), 135 constellationInstance: z.string().optional(), 136 showLinkInHandle: z.boolean().optional(), 137 + hideFeedsPromoTab: z.boolean().optional(), 138 deerVerification: z 139 .object({ 140 enabled: z.boolean(), ··· 204 hideFollowNotifications: false, 205 constellationInstance: 'https://constellation.microcosm.blue/', 206 showLinkInHandle: false, 207 + hideFeedsPromoTab: false, 208 deerVerification: { 209 enabled: false, 210 // https://deer.social/profile/did:plc:p2cp5gopk7mgjegy6wadk3ep/post/3lndyqyyr4k2k
+50
src/state/preferences/hide-feeds-promo-tab.tsx
···
··· 1 + import React from 'react' 2 + 3 + import * as persisted from '#/state/persisted' 4 + 5 + // Preference: hideFeedsPromoTab – when true, suppress the "Feeds ✨" promotional tab in HomeHeader. 6 + 7 + type StateContext = persisted.Schema['hideFeedsPromoTab'] 8 + // Same setter signature used across other preference modules 9 + type SetContext = (v: persisted.Schema['hideFeedsPromoTab']) => void 10 + 11 + const stateContext = React.createContext<StateContext>( 12 + persisted.defaults.hideFeedsPromoTab, 13 + ) 14 + const setContext = React.createContext<SetContext>( 15 + (_: persisted.Schema['hideFeedsPromoTab']) => {}, 16 + ) 17 + 18 + export function Provider({children}: React.PropsWithChildren<{}>) { 19 + const [state, setState] = React.useState(persisted.get('hideFeedsPromoTab')) 20 + 21 + const setStateWrapped = React.useCallback( 22 + (value: persisted.Schema['hideFeedsPromoTab']) => { 23 + setState(value) 24 + persisted.write('hideFeedsPromoTab', value) 25 + }, 26 + [setState], 27 + ) 28 + 29 + React.useEffect(() => { 30 + return persisted.onUpdate('hideFeedsPromoTab', 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 useHideFeedsPromoTab() { 45 + return React.useContext(stateContext) 46 + } 47 + 48 + export function useSetHideFeedsPromoTab() { 49 + return React.useContext(setContext) 50 + }
+6 -2
src/state/preferences/index.tsx
··· 8 import {Provider as DirectFetchRecordsProvider} from './direct-fetch-records' 9 import {Provider as DisableHapticsProvider} from './disable-haptics' 10 import {Provider as ExternalEmbedsProvider} from './external-embeds-prefs' 11 import {Provider as GoLinksProvider} from './go-links-enabled' 12 import {Provider as HiddenPostsProvider} from './hidden-posts' 13 - import {Provider as FollowNotificationsProvider} from './hide-follow-notifications' 14 import {Provider as InAppBrowserProvider} from './in-app-browser' 15 import {Provider as KawaiiProvider} from './kawaii' 16 import {Provider as LanguagesProvider} from './languages' ··· 35 } from './external-embeds-prefs' 36 export {useGoLinksEnabled, useSetGoLinksEnabled} from './go-links-enabled' 37 export * from './hidden-posts' 38 export {useLabelDefinitions} from './label-defs' 39 export {useLanguagePrefs, useLanguagePrefsApi} from './languages' 40 export {useSetSubtitlesEnabled, useSubtitlesEnabled} from './subtitles' ··· 63 <TrendingSettingsProvider> 64 <RepostCarouselProvider> 65 <KawaiiProvider> 66 - {children} 67 </KawaiiProvider> 68 </RepostCarouselProvider> 69 </TrendingSettingsProvider>
··· 8 import {Provider as DirectFetchRecordsProvider} from './direct-fetch-records' 9 import {Provider as DisableHapticsProvider} from './disable-haptics' 10 import {Provider as ExternalEmbedsProvider} from './external-embeds-prefs' 11 + import {Provider as FollowNotificationsProvider} from './hide-follow-notifications' 12 import {Provider as GoLinksProvider} from './go-links-enabled' 13 import {Provider as HiddenPostsProvider} from './hidden-posts' 14 + import {Provider as HideFeedsPromoTabProvider} from './hide-feeds-promo-tab' 15 import {Provider as InAppBrowserProvider} from './in-app-browser' 16 import {Provider as KawaiiProvider} from './kawaii' 17 import {Provider as LanguagesProvider} from './languages' ··· 36 } from './external-embeds-prefs' 37 export {useGoLinksEnabled, useSetGoLinksEnabled} from './go-links-enabled' 38 export * from './hidden-posts' 39 + export {useHideFeedsPromoTab, useSetHideFeedsPromoTab} from './hide-feeds-promo-tab' 40 export {useLabelDefinitions} from './label-defs' 41 export {useLanguagePrefs, useLanguagePrefsApi} from './languages' 42 export {useSetSubtitlesEnabled, useSubtitlesEnabled} from './subtitles' ··· 65 <TrendingSettingsProvider> 66 <RepostCarouselProvider> 67 <KawaiiProvider> 68 + <HideFeedsPromoTabProvider> 69 + {children} 70 + </HideFeedsPromoTabProvider> 71 </KawaiiProvider> 72 </RepostCarouselProvider> 73 </TrendingSettingsProvider>
+6 -4
src/view/com/home/HomeHeader.tsx
··· 1 import React from 'react' 2 import {useNavigation} from '@react-navigation/native' 3 4 import {NavigationProp} from '#/lib/routes/types' 5 import {FeedSourceInfo} from '#/state/queries/feed' ··· 17 ) { 18 const {feeds} = props 19 const {hasSession} = useSession() 20 const navigation = useNavigation<NavigationProp>() 21 22 const hasPinnedCustom = React.useMemo<boolean>(() => { ··· 29 30 const items = React.useMemo(() => { 31 const pinnedNames = feeds.map(f => f.displayName) 32 - if (!hasPinnedCustom) { 33 return pinnedNames.concat('Feeds ✨') 34 } 35 return pinnedNames 36 - }, [hasPinnedCustom, feeds]) 37 38 const onPressFeedsLink = React.useCallback(() => { 39 navigation.navigate('Feeds') ··· 41 42 const onSelect = React.useCallback( 43 (index: number) => { 44 - if (!hasPinnedCustom && index === items.length - 1) { 45 onPressFeedsLink() 46 } else if (props.onSelect) { 47 props.onSelect(index) 48 } 49 }, 50 - [items.length, onPressFeedsLink, props, hasPinnedCustom], 51 ) 52 53 return (
··· 1 import React from 'react' 2 import {useNavigation} from '@react-navigation/native' 3 + import {useHideFeedsPromoTab} from '#/state/preferences/hide-feeds-promo-tab' 4 5 import {NavigationProp} from '#/lib/routes/types' 6 import {FeedSourceInfo} from '#/state/queries/feed' ··· 18 ) { 19 const {feeds} = props 20 const {hasSession} = useSession() 21 + const hideFeedsPromoTab = useHideFeedsPromoTab() 22 const navigation = useNavigation<NavigationProp>() 23 24 const hasPinnedCustom = React.useMemo<boolean>(() => { ··· 31 32 const items = React.useMemo(() => { 33 const pinnedNames = feeds.map(f => f.displayName) 34 + if (!hasPinnedCustom && !hideFeedsPromoTab) { 35 return pinnedNames.concat('Feeds ✨') 36 } 37 return pinnedNames 38 + }, [hasPinnedCustom, hideFeedsPromoTab, feeds]) 39 40 const onPressFeedsLink = React.useCallback(() => { 41 navigation.navigate('Feeds') ··· 43 44 const onSelect = React.useCallback( 45 (index: number) => { 46 + if (!hasPinnedCustom && !hideFeedsPromoTab && index === items.length - 1) { 47 onPressFeedsLink() 48 } else if (props.onSelect) { 49 props.onSelect(index) 50 } 51 }, 52 + [items.length, onPressFeedsLink, props, hasPinnedCustom, hideFeedsPromoTab], 53 ) 54 55 return (