diff options
-rw-r--r-- | src/components/Link.tsx | 52 | ||||
-rw-r--r-- | src/components/RichText.tsx | 17 | ||||
-rw-r--r-- | src/lib/sharing.ts | 7 | ||||
-rw-r--r-- | src/state/modals/index.tsx | 1 | ||||
-rw-r--r-- | src/view/com/modals/LinkWarning.tsx | 46 |
5 files changed, 89 insertions, 34 deletions
diff --git a/src/components/Link.tsx b/src/components/Link.tsx index 7d0e83332..1a494626f 100644 --- a/src/components/Link.tsx +++ b/src/components/Link.tsx @@ -1,23 +1,24 @@ import React from 'react' import {GestureResponderEvent} from 'react-native' -import {useLinkProps, StackActions} from '@react-navigation/native' import {sanitizeUrl} from '@braintree/sanitize-url' +import {StackActions, useLinkProps} from '@react-navigation/native' -import {useInteractionState} from '#/components/hooks/useInteractionState' -import {isWeb} from '#/platform/detection' -import {useTheme, web, flatten, TextStyleProp, atoms as a} from '#/alf' -import {Button, ButtonProps} from '#/components/Button' import {AllNavigatorParams} from '#/lib/routes/types' +import {shareUrl} from '#/lib/sharing' import { convertBskyAppUrlIfNeeded, isExternalUrl, linkRequiresWarning, } from '#/lib/strings/url-helpers' +import {isNative, isWeb} from '#/platform/detection' import {useModalControls} from '#/state/modals' -import {router} from '#/routes' -import {Text, TextProps} from '#/components/Typography' -import {useOpenLink} from 'state/preferences/in-app-browser' +import {useOpenLink} from '#/state/preferences/in-app-browser' import {useNavigationDeduped} from 'lib/hooks/useNavigationDeduped' +import {atoms as a, flatten, TextStyleProp, useTheme, web} from '#/alf' +import {Button, ButtonProps} from '#/components/Button' +import {useInteractionState} from '#/components/hooks/useInteractionState' +import {Text, TextProps} from '#/components/Typography' +import {router} from '#/routes' /** * Only available within a `Link`, since that inherits from `Button`. @@ -60,6 +61,11 @@ type BaseLinkProps = Pick< * Web-only attribute. Sets `download` attr on web. */ download?: string + + /** + * Native-only attribute. If true, will open the share sheet on long press. + */ + shareOnLongPress?: boolean } export function useLink({ @@ -68,6 +74,7 @@ export function useLink({ action = 'push', disableMismatchWarning, onPress: outerOnPress, + shareOnLongPress, }: BaseLinkProps & { displayText: string }) { @@ -157,10 +164,34 @@ export function useLink({ ], ) + const handleLongPress = React.useCallback(() => { + const requiresWarning = Boolean( + !disableMismatchWarning && + displayText && + isExternal && + linkRequiresWarning(href, displayText), + ) + + if (requiresWarning) { + openModal({ + name: 'link-warning', + text: displayText, + href: href, + share: true, + }) + } else { + shareUrl(href) + } + }, [disableMismatchWarning, displayText, href, isExternal, openModal]) + + const onLongPress = + isNative && isExternal && shareOnLongPress ? handleLongPress : undefined + return { isExternal, href, onPress, + onLongPress, } } @@ -229,16 +260,18 @@ export function InlineLink({ download, selectable, label, + shareOnLongPress, ...rest }: InlineLinkProps) { const t = useTheme() const stringChildren = typeof children === 'string' - const {href, isExternal, onPress} = useLink({ + const {href, isExternal, onPress, onLongPress} = useLink({ to, displayText: stringChildren ? children : '', action, disableMismatchWarning, onPress: outerOnPress, + shareOnLongPress, }) const { state: hovered, @@ -270,6 +303,7 @@ export function InlineLink({ ]} role="link" onPress={download ? undefined : onPress} + onLongPress={onLongPress} onPressIn={onPressIn} onPressOut={onPressOut} onFocus={onFocus} diff --git a/src/components/RichText.tsx b/src/components/RichText.tsx index 1a14415cf..0e89e13b7 100644 --- a/src/components/RichText.tsx +++ b/src/components/RichText.tsx @@ -1,15 +1,15 @@ import React from 'react' -import {RichText as RichTextAPI, AppBskyRichtextFacet} from '@atproto/api' -import {useLingui} from '@lingui/react' +import {AppBskyRichtextFacet, RichText as RichTextAPI} from '@atproto/api' import {msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' -import {atoms as a, TextStyleProp, flatten, useTheme, web, native} from '#/alf' -import {InlineLink} from '#/components/Link' -import {Text, TextProps} from '#/components/Typography' -import {toShortUrl} from 'lib/strings/url-helpers' -import {TagMenu, useTagMenuControl} from '#/components/TagMenu' +import {toShortUrl} from '#/lib/strings/url-helpers' import {isNative} from '#/platform/detection' +import {atoms as a, flatten, native, TextStyleProp, useTheme, web} from '#/alf' import {useInteractionState} from '#/components/hooks/useInteractionState' +import {InlineLink} from '#/components/Link' +import {TagMenu, useTagMenuControl} from '#/components/TagMenu' +import {Text, TextProps} from '#/components/Typography' const WORD_WRAP = {wordWrap: 1} @@ -105,7 +105,8 @@ export function RichText({ to={link.uri} style={[...styles, {pointerEvents: 'auto'}]} // @ts-ignore TODO - dataSet={WORD_WRAP}> + dataSet={WORD_WRAP} + shareOnLongPress> {toShortUrl(segment.text)} </InlineLink>, ) diff --git a/src/lib/sharing.ts b/src/lib/sharing.ts index 9f402f873..c50a2734a 100644 --- a/src/lib/sharing.ts +++ b/src/lib/sharing.ts @@ -1,8 +1,9 @@ -import {isIOS, isAndroid} from 'platform/detection' +import {Share} from 'react-native' // import * as Sharing from 'expo-sharing' import Clipboard from '@react-native-clipboard/clipboard' -import * as Toast from '../view/com/util/Toast' -import {Share} from 'react-native' + +import {isAndroid, isIOS} from 'platform/detection' +import * as Toast from '#/view/com/util/Toast' /** * This function shares a URL using the native Share API if available, or copies it to the clipboard diff --git a/src/state/modals/index.tsx b/src/state/modals/index.tsx index aae4fc52f..e0bcc2f0f 100644 --- a/src/state/modals/index.tsx +++ b/src/state/modals/index.tsx @@ -122,6 +122,7 @@ export interface LinkWarningModal { name: 'link-warning' text: string href: string + share?: boolean } export interface EmbedConsentModal { diff --git a/src/view/com/modals/LinkWarning.tsx b/src/view/com/modals/LinkWarning.tsx index b5ff6700d..bf5bf6d29 100644 --- a/src/view/com/modals/LinkWarning.tsx +++ b/src/view/com/modals/LinkWarning.tsx @@ -1,22 +1,32 @@ import React from 'react' import {SafeAreaView, StyleSheet, View} from 'react-native' -import {ScrollView} from './util' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' -import {Text} from '../util/text/Text' -import {Button} from '../util/forms/Button' -import {s, colors} from 'lib/styles' -import {usePalette} from 'lib/hooks/usePalette' -import {isWeb} from 'platform/detection' -import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' -import {isPossiblyAUrl, splitApexDomain} from 'lib/strings/url-helpers' -import {Trans, msg} from '@lingui/macro' +import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' + +import {usePalette} from '#/lib/hooks/usePalette' +import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' +import {shareUrl} from '#/lib/sharing' +import {isPossiblyAUrl, splitApexDomain} from '#/lib/strings/url-helpers' +import {colors, s} from '#/lib/styles' +import {isWeb} from '#/platform/detection' import {useModalControls} from '#/state/modals' import {useOpenLink} from '#/state/preferences/in-app-browser' +import {Button} from '#/view/com/util/forms/Button' +import {Text} from '#/view/com/util/text/Text' +import {ScrollView} from './util' export const snapPoints = ['50%'] -export function Component({text, href}: {text: string; href: string}) { +export function Component({ + text, + href, + share, +}: { + text: string + href: string + share?: boolean +}) { const pal = usePalette('default') const {closeModal} = useModalControls() const {isMobile} = useWebMediaQueries() @@ -26,7 +36,11 @@ export function Component({text, href}: {text: string; href: string}) { const onPressVisit = () => { closeModal() - openLink(href) + if (share) { + shareUrl(href) + } else { + openLink(href) + } } return ( @@ -72,9 +86,13 @@ export function Component({text, href}: {text: string; href: string}) { testID="confirmBtn" type="primary" onPress={onPressVisit} - accessibilityLabel={_(msg`Visit Site`)} - accessibilityHint={_(msg`Opens the linked website`)} - label={_(msg`Visit Site`)} + accessibilityLabel={share ? _(msg`Share Link`) : _(msg`Visit Site`)} + accessibilityHint={ + share + ? _(msg`Shares the linked website`) + : _(msg`Opens the linked website`) + } + label={share ? _(msg`Share Link`) : _(msg`Visit Site`)} labelContainerStyle={{justifyContent: 'center', padding: 4}} labelStyle={[s.f18]} /> |