tangled mirror of catsky-🐱 Soothing soft social-app fork with all the niche toggles! (Unofficial); for issues and PRs please put them on github:NekoDrone/catsky-social

Merge pull request #87 from pyrox0/antlers/feat/PDSls

authored by isabelroses.com and committed by GitHub a4dbb14e 3406e37c

Changed files
+201 -25
src
components
screens
state
+44
src/components/PostControls/ShareMenu/ShareMenuItems.tsx
··· 5 5 import {useLingui} from '@lingui/react' 6 6 import {useNavigation} from '@react-navigation/native' 7 7 8 + import {useOpenLink} from '#/lib/hooks/useOpenLink' 8 9 import {makeProfileLink} from '#/lib/routes/links' 9 10 import {type NavigationProp} from '#/lib/routes/types' 10 11 import {shareText, shareUrl} from '#/lib/sharing' ··· 13 14 import {isIOS} from '#/platform/detection' 14 15 import {useAgeAssurance} from '#/state/ageAssurance/useAgeAssurance' 15 16 import {useProfileShadow} from '#/state/cache/profile-shadow' 17 + import {useShowExternalShareButtons} from '#/state/preferences/external-share-buttons' 16 18 import {useSession} from '#/state/session' 17 19 import * as Toast from '#/view/com/util/Toast' 18 20 import {atoms as a} from '#/alf' ··· 23 25 import {ChainLink_Stroke2_Corner0_Rounded as ChainLinkIcon} from '#/components/icons/ChainLink' 24 26 import {Clipboard_Stroke2_Corner2_Rounded as ClipboardIcon} from '#/components/icons/Clipboard' 25 27 import {PaperPlane_Stroke2_Corner0_Rounded as PaperPlaneIcon} from '#/components/icons/PaperPlane' 28 + import {SquareArrowTopRight_Stroke2_Corner0_Rounded as ExternalIcon} from '#/components/icons/SquareArrowTopRight' 26 29 import * as Menu from '#/components/Menu' 27 30 import {useDevMode} from '#/storage/hooks/dev-mode' 28 31 import {RecentChats} from './RecentChats' ··· 38 41 const sendViaChatControl = useDialogControl() 39 42 const [devModeEnabled] = useDevMode() 40 43 const {isAgeRestricted} = useAgeAssurance() 44 + const openLink = useOpenLink() 41 45 42 46 const postUri = post.uri 43 47 const postAuthor = useProfileShadow(post.author) ··· 88 92 shareText(postAuthor.did) 89 93 } 90 94 95 + const showExternalShareButtons = useShowExternalShareButtons() 96 + const isBridgedPost = 97 + !!post.record.bridgyOriginalUrl || !!post.record.fediverseId 98 + const originalPostUrl = (post.record.bridgyOriginalUrl || 99 + post.record.fediverseId) as string | undefined 100 + 101 + const onOpenOriginalPost = () => { 102 + originalPostUrl && openLink(originalPostUrl, true) 103 + } 104 + 105 + const onOpenPostInPdsls = () => { 106 + openLink(`https://pdsls.dev/${post.uri}`, true) 107 + } 108 + 91 109 return ( 92 110 <> 93 111 <Menu.Outer> ··· 107 125 <Trans>Send via direct message</Trans> 108 126 </Menu.ItemText> 109 127 <Menu.ItemIcon icon={PaperPlaneIcon} position="right" /> 128 + </Menu.Item> 129 + </Menu.Group> 130 + )} 131 + 132 + {showExternalShareButtons && ( 133 + <Menu.Group> 134 + {isBridgedPost && ( 135 + <Menu.Item 136 + testID="postDropdownOpenOriginalPost" 137 + label={_(msg`Open original post`)} 138 + onPress={onOpenOriginalPost}> 139 + <Menu.ItemText> 140 + <Trans>Open original post</Trans> 141 + </Menu.ItemText> 142 + <Menu.ItemIcon icon={ExternalIcon} position="right" /> 143 + </Menu.Item> 144 + )} 145 + 146 + <Menu.Item 147 + testID="postDropdownOpenInPdsls" 148 + label={_(msg`Open post in PDSls`)} 149 + onPress={onOpenPostInPdsls}> 150 + <Menu.ItemText> 151 + <Trans>Open post in PDSls</Trans> 152 + </Menu.ItemText> 153 + <Menu.ItemIcon icon={ExternalIcon} position="right" /> 110 154 </Menu.Item> 111 155 </Menu.Group> 112 156 )}
+42
src/components/PostControls/ShareMenu/ShareMenuItems.web.tsx
··· 4 4 import {useLingui} from '@lingui/react' 5 5 import {useNavigation} from '@react-navigation/native' 6 6 7 + import {useOpenLink} from '#/lib/hooks/useOpenLink' 7 8 import {makeProfileLink} from '#/lib/routes/links' 8 9 import {type NavigationProp} from '#/lib/routes/types' 9 10 import {shareText, shareUrl} from '#/lib/sharing' ··· 12 13 import {isWeb} from '#/platform/detection' 13 14 import {useAgeAssurance} from '#/state/ageAssurance/useAgeAssurance' 14 15 import {useProfileShadow} from '#/state/cache/profile-shadow' 16 + import {useShowExternalShareButtons} from '#/state/preferences/external-share-buttons' 15 17 import {useSession} from '#/state/session' 16 18 import {useBreakpoints} from '#/alf' 17 19 import {useDialogControl} from '#/components/Dialog' ··· 21 23 import {Clipboard_Stroke2_Corner2_Rounded as ClipboardIcon} from '#/components/icons/Clipboard' 22 24 import {CodeBrackets_Stroke2_Corner0_Rounded as CodeBracketsIcon} from '#/components/icons/CodeBrackets' 23 25 import {PaperPlane_Stroke2_Corner0_Rounded as Send} from '#/components/icons/PaperPlane' 26 + import {SquareArrowTopRight_Stroke2_Corner0_Rounded as ExternalIcon} from '#/components/icons/SquareArrowTopRight' 24 27 import * as Menu from '#/components/Menu' 25 28 import {useDevMode} from '#/storage/hooks/dev-mode' 26 29 import {type ShareMenuItemsProps} from './ShareMenuItems.types' ··· 39 42 const sendViaChatControl = useDialogControl() 40 43 const [devModeEnabled] = useDevMode() 41 44 const {isAgeRestricted} = useAgeAssurance() 45 + const openLink = useOpenLink() 42 46 43 47 const postUri = post.uri 44 48 const postCid = post.cid ··· 80 84 shareText(postAuthor.did) 81 85 } 82 86 87 + const showExternalShareButtons = useShowExternalShareButtons() 88 + const isBridgedPost = 89 + !!post.record.bridgyOriginalUrl || !!post.record.fediverseId 90 + const originalPostUrl = (post.record.bridgyOriginalUrl || 91 + post.record.fediverseId) as string | undefined 92 + 93 + const onOpenOriginalPost = () => { 94 + originalPostUrl && openLink(originalPostUrl, true) 95 + } 96 + 97 + const onOpenPostInPdsls = () => { 98 + openLink(`https://pdsls.dev/${post.uri}`, true) 99 + } 100 + 83 101 const copyLinkItem = ( 84 102 <Menu.Item 85 103 testID="postDropdownShareBtn" ··· 96 114 <> 97 115 <Menu.Outer> 98 116 {!hideInPWI && copyLinkItem} 117 + 118 + {showExternalShareButtons && isBridgedPost && ( 119 + <Menu.Item 120 + testID="postDropdownOpenOriginalPost" 121 + label={_(msg`Open original post`)} 122 + onPress={onOpenOriginalPost}> 123 + <Menu.ItemText> 124 + <Trans>Open original post</Trans> 125 + </Menu.ItemText> 126 + <Menu.ItemIcon icon={ExternalIcon} position="right" /> 127 + </Menu.Item> 128 + )} 129 + 130 + {showExternalShareButtons && ( 131 + <Menu.Item 132 + testID="postDropdownOpenInPdsls" 133 + label={_(msg`Open post in PDSls`)} 134 + onPress={onOpenPostInPdsls}> 135 + <Menu.ItemText> 136 + <Trans>Open post in PDSls</Trans> 137 + </Menu.ItemText> 138 + <Menu.ItemIcon icon={ExternalIcon} position="right" /> 139 + </Menu.Item> 140 + )} 99 141 100 142 {hasSession && !isAgeRestricted && ( 101 143 <Menu.Item
+30
src/screens/Settings/ExperimentalSettings.tsx
··· 19 19 useDirectFetchRecords, 20 20 useSetDirectFetchRecords, 21 21 } from '#/state/preferences/direct-fetch-records' 22 + import { 23 + useSetShowExternalShareButtons, 24 + useShowExternalShareButtons, 25 + } from '#/state/preferences/external-share-buttons' 22 26 import * as SettingsList from '#/screens/Settings/components/SettingsList' 23 27 import {atoms as a} from '#/alf' 24 28 import {Admonition} from '#/components/Admonition' 25 29 import * as Toggle from '#/components/forms/Toggle' 26 30 import {Atom_Stroke2_Corner0_Rounded as ExperimentalIcon} from '#/components/icons/Atom' 31 + import {ChainLink_Stroke2_Corner0_Rounded as ChainLinkIcon} from '#/components/icons/ChainLink' 27 32 import {Eye_Stroke2_Corner0_Rounded as VisibilityIcon} from '#/components/icons/Eye' 28 33 import {PaintRoller_Stroke2_Corner2_Rounded as PaintRollerIcon} from '#/components/icons/PaintRoller' 29 34 import * as Layout from '#/components/Layout' ··· 41 46 42 47 const directFetchRecords = useDirectFetchRecords() 43 48 const setDirectFetchRecords = useSetDirectFetchRecords() 49 + 50 + const showExternalShareButtons = useShowExternalShareButtons() 51 + const setShowExternalShareButtons = useSetShowExternalShareButtons() 44 52 45 53 const [gates, setGatesView] = useState(Object.fromEntries(useGatesCache())) 46 54 const dangerousSetGate = useDangerousSetGate() ··· 116 124 <Toggle.LabelText style={[a.flex_1]}> 117 125 <Trans> 118 126 TODO: Fall back to constellation api to find blocked replies 127 + </Trans> 128 + </Toggle.LabelText> 129 + <Toggle.Platform /> 130 + </Toggle.Item> 131 + </SettingsList.Group> 132 + 133 + <SettingsList.Group contentContainerStyle={[a.gap_sm]}> 134 + <SettingsList.ItemIcon icon={ChainLinkIcon} /> 135 + <SettingsList.ItemText> 136 + <Trans>Bridging and Fediverse</Trans> 137 + </SettingsList.ItemText> 138 + <Toggle.Item 139 + name="external_share_buttons" 140 + label={_( 141 + msg`Show "Open original post" and "Open post in PDSls" buttons`, 142 + )} 143 + value={showExternalShareButtons} 144 + onChange={value => setShowExternalShareButtons(value)} 145 + style={[a.w_full]}> 146 + <Toggle.LabelText style={[a.flex_1]}> 147 + <Trans> 148 + Show "Open original post" and "Open post in PDSls" buttons 119 149 </Trans> 120 150 </Toggle.LabelText> 121 151 <Toggle.Platform />
+3
src/state/persisted/schema.ts
··· 130 130 directFetchRecords: z.boolean().optional(), 131 131 unfollowConfirm: z.boolean().optional(), 132 132 133 + showExternalShareButtons: z.boolean().optional(), 134 + 133 135 /** @deprecated */ 134 136 mutedThreads: z.array(z.string()), 135 137 trendingDisabled: z.boolean().optional(), ··· 187 189 constellationEnabled: false, 188 190 directFetchRecords: false, 189 191 unfollowConfirm: false, 192 + showExternalShareButtons: false, 190 193 } 191 194 192 195 export function tryParse(rawData: string): Schema | undefined {
+54
src/state/preferences/external-share-buttons.tsx
··· 1 + import React from 'react' 2 + 3 + import * as persisted from '#/state/persisted' 4 + 5 + type StateContext = persisted.Schema['showExternalShareButtons'] 6 + type SetContext = (v: persisted.Schema['showExternalShareButtons']) => void 7 + 8 + const stateContext = React.createContext<StateContext>( 9 + persisted.defaults.showExternalShareButtons, 10 + ) 11 + const setContext = React.createContext<SetContext>( 12 + (_: persisted.Schema['showExternalShareButtons']) => {}, 13 + ) 14 + 15 + export function Provider({children}: React.PropsWithChildren<{}>) { 16 + const [state, setState] = React.useState( 17 + persisted.get('showExternalShareButtons'), 18 + ) 19 + 20 + const setStateWrapped = React.useCallback( 21 + ( 22 + showExternalShareButtons: persisted.Schema['showExternalShareButtons'], 23 + ) => { 24 + setState(showExternalShareButtons) 25 + persisted.write('showExternalShareButtons', showExternalShareButtons) 26 + }, 27 + [setState], 28 + ) 29 + 30 + React.useEffect(() => { 31 + return persisted.onUpdate( 32 + 'showExternalShareButtons', 33 + nextShowExternalShareButtons => { 34 + setState(nextShowExternalShareButtons) 35 + }, 36 + ) 37 + }, [setStateWrapped]) 38 + 39 + return ( 40 + <stateContext.Provider value={state}> 41 + <setContext.Provider value={setStateWrapped}> 42 + {children} 43 + </setContext.Provider> 44 + </stateContext.Provider> 45 + ) 46 + } 47 + 48 + export function useShowExternalShareButtons() { 49 + return React.useContext(stateContext) 50 + } 51 + 52 + export function useSetShowExternalShareButtons() { 53 + return React.useContext(setContext) 54 + }
+28 -25
src/state/preferences/index.tsx
··· 6 6 import {Provider as DirectFetchRecordsProvider} from './direct-fetch-records' 7 7 import {Provider as DisableHapticsProvider} from './disable-haptics' 8 8 import {Provider as ExternalEmbedsProvider} from './external-embeds-prefs' 9 + import {Provider as ExternalShareButtonsProvider} from './external-share-buttons' 9 10 import {Provider as GoLinksProvider} from './go-links-enabled' 10 11 import {Provider as HiddenPostsProvider} from './hidden-posts' 11 12 import {Provider as InAppBrowserProvider} from './in-app-browser' ··· 36 37 return ( 37 38 <LanguagesProvider> 38 39 <AltTextRequiredProvider> 39 - <GoLinksProvider> 40 - <DirectFetchRecordsProvider> 41 - <ConstellationProvider> 42 - <LargeAltBadgeProvider> 43 - <ExternalEmbedsProvider> 44 - <HiddenPostsProvider> 45 - <InAppBrowserProvider> 46 - <DisableHapticsProvider> 47 - <AutoplayProvider> 48 - <UsedStarterPacksProvider> 49 - <SubtitlesProvider> 50 - <TrendingSettingsProvider> 51 - <KawaiiProvider>{children}</KawaiiProvider> 52 - </TrendingSettingsProvider> 53 - </SubtitlesProvider> 54 - </UsedStarterPacksProvider> 55 - </AutoplayProvider> 56 - </DisableHapticsProvider> 57 - </InAppBrowserProvider> 58 - </HiddenPostsProvider> 59 - </ExternalEmbedsProvider> 60 - </LargeAltBadgeProvider> 61 - </ConstellationProvider> 62 - </DirectFetchRecordsProvider> 63 - </GoLinksProvider> 40 + <ExternalShareButtonsProvider> 41 + <GoLinksProvider> 42 + <DirectFetchRecordsProvider> 43 + <ConstellationProvider> 44 + <LargeAltBadgeProvider> 45 + <ExternalEmbedsProvider> 46 + <HiddenPostsProvider> 47 + <InAppBrowserProvider> 48 + <DisableHapticsProvider> 49 + <AutoplayProvider> 50 + <UsedStarterPacksProvider> 51 + <SubtitlesProvider> 52 + <TrendingSettingsProvider> 53 + <KawaiiProvider>{children}</KawaiiProvider> 54 + </TrendingSettingsProvider> 55 + </SubtitlesProvider> 56 + </UsedStarterPacksProvider> 57 + </AutoplayProvider> 58 + </DisableHapticsProvider> 59 + </InAppBrowserProvider> 60 + </HiddenPostsProvider> 61 + </ExternalEmbedsProvider> 62 + </LargeAltBadgeProvider> 63 + </ConstellationProvider> 64 + </DirectFetchRecordsProvider> 65 + </GoLinksProvider> 66 + </ExternalShareButtonsProvider> 64 67 </AltTextRequiredProvider> 65 68 </LanguagesProvider> 66 69 )