Open share sheet when long pressing link (#3317)
* uitextview use library w/ fixes bump bump multiple uitextview fixes * bump * Open share sheet on link long press * rm package manager field * add link warning to longpress --------- Co-authored-by: Hailey <me@haileyok.com>zio/stable
parent
4d28dcc48f
commit
9f657fbace
|
@ -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}
|
||||
|
|
|
@ -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>,
|
||||
)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -122,6 +122,7 @@ export interface LinkWarningModal {
|
|||
name: 'link-warning'
|
||||
text: string
|
||||
href: string
|
||||
share?: boolean
|
||||
}
|
||||
|
||||
export interface EmbedConsentModal {
|
||||
|
|
|
@ -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,8 +36,12 @@ export function Component({text, href}: {text: string; href: string}) {
|
|||
|
||||
const onPressVisit = () => {
|
||||
closeModal()
|
||||
if (share) {
|
||||
shareUrl(href)
|
||||
} else {
|
||||
openLink(href)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<SafeAreaView style={[s.flex1, pal.view]}>
|
||||
|
@ -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]}
|
||||
/>
|
||||
|
|
Loading…
Reference in New Issue