wip move to alf
This commit is contained in:
+22
-20
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import React, {useCallback, useState} from 'react'
|
||||
import {
|
||||
GestureResponderEvent,
|
||||
Pressable,
|
||||
@@ -20,10 +20,11 @@ import {
|
||||
} from '#/lib/strings/url-helpers'
|
||||
import {isNative, isWeb} from '#/platform/detection'
|
||||
import {shouldClickOpenNewTab} from '#/platform/urls'
|
||||
import {useModalControls} from '#/state/modals'
|
||||
import {useOpenLink} from '#/state/preferences/in-app-browser'
|
||||
import {useCloseAllActiveElements} from '#/state/util'
|
||||
import {atoms as a, flatten, TextStyleProp, useTheme, web} from '#/alf'
|
||||
import {Button, ButtonProps} from '#/components/Button'
|
||||
import {useDialogControl} from '#/components/Dialog'
|
||||
import {useInteractionState} from '#/components/hooks/useInteractionState'
|
||||
import {Text, TextProps} from '#/components/Typography'
|
||||
import {router} from '#/routes'
|
||||
@@ -87,10 +88,20 @@ export function useLink({
|
||||
typeof to === 'string' ? convertBskyAppUrlIfNeeded(sanitizeUrl(to)) : to,
|
||||
})
|
||||
const isExternal = isExternalUrl(href)
|
||||
const {openModal, closeModal} = useModalControls()
|
||||
const openLink = useOpenLink()
|
||||
const dismissEverything = useCloseAllActiveElements()
|
||||
const [_warningMode, setWarningMode] = useState<'open' | 'share'>('open')
|
||||
const linkWarningControl = useDialogControl()
|
||||
|
||||
const onPress = React.useCallback(
|
||||
const showWarningDialog = useCallback(
|
||||
(mode: 'open' | 'share') => {
|
||||
setWarningMode(mode)
|
||||
linkWarningControl.open()
|
||||
},
|
||||
[linkWarningControl],
|
||||
)
|
||||
|
||||
const onPress = useCallback(
|
||||
(e: GestureResponderEvent) => {
|
||||
const exitEarlyIfFalse = outerOnPress?.(e)
|
||||
|
||||
@@ -108,11 +119,7 @@ export function useLink({
|
||||
}
|
||||
|
||||
if (requiresWarning) {
|
||||
openModal({
|
||||
name: 'link-warning',
|
||||
text: displayText,
|
||||
href: href,
|
||||
})
|
||||
showWarningDialog('open')
|
||||
} else {
|
||||
if (isExternal) {
|
||||
openLink(href)
|
||||
@@ -128,7 +135,7 @@ export function useLink({
|
||||
) {
|
||||
openLink(href)
|
||||
} else {
|
||||
closeModal() // close any active modals
|
||||
dismissEverything() // close any active dialogs
|
||||
|
||||
if (action === 'push') {
|
||||
navigation.dispatch(StackActions.push(...router.matchPath(href)))
|
||||
@@ -152,15 +159,15 @@ export function useLink({
|
||||
displayText,
|
||||
isExternal,
|
||||
href,
|
||||
openModal,
|
||||
openLink,
|
||||
closeModal,
|
||||
action,
|
||||
navigation,
|
||||
showWarningDialog,
|
||||
dismissEverything,
|
||||
],
|
||||
)
|
||||
|
||||
const handleLongPress = React.useCallback(() => {
|
||||
const handleLongPress = useCallback(() => {
|
||||
const requiresWarning = Boolean(
|
||||
!disableMismatchWarning &&
|
||||
displayText &&
|
||||
@@ -169,16 +176,11 @@ export function useLink({
|
||||
)
|
||||
|
||||
if (requiresWarning) {
|
||||
openModal({
|
||||
name: 'link-warning',
|
||||
text: displayText,
|
||||
href: href,
|
||||
share: true,
|
||||
})
|
||||
showWarningDialog('share')
|
||||
} else {
|
||||
shareUrl(href)
|
||||
}
|
||||
}, [disableMismatchWarning, displayText, href, isExternal, openModal])
|
||||
}, [disableMismatchWarning, displayText, href, isExternal, showWarningDialog])
|
||||
|
||||
const onLongPress =
|
||||
isNative && isExternal && shareOnLongPress ? handleLongPress : undefined
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
import React from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {useOpenLink} from '#/lib/hooks/useOpenLink'
|
||||
import {shareUrl} from '#/lib/sharing'
|
||||
import {isPossiblyAUrl, splitApexDomain} from '#/lib/strings/url-helpers'
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import {Button, ButtonText} from '#/components/Button'
|
||||
import * as Dialog from '#/components/Dialog'
|
||||
import {Text} from '#/components/Typography'
|
||||
|
||||
export function LinkWarningDialog({
|
||||
control,
|
||||
linkText,
|
||||
linkHref,
|
||||
mode = 'open',
|
||||
}: {
|
||||
control: Dialog.DialogControlProps
|
||||
linkText: string
|
||||
linkHref: string
|
||||
mode?: 'open' | 'share'
|
||||
}) {
|
||||
return (
|
||||
<Dialog.Outer control={control}>
|
||||
<Dialog.Handle />
|
||||
<DialogInner linkHref={linkHref} linkText={linkText} mode={mode} />
|
||||
</Dialog.Outer>
|
||||
)
|
||||
}
|
||||
|
||||
function DialogInner({
|
||||
linkText,
|
||||
linkHref,
|
||||
mode,
|
||||
}: {
|
||||
linkText: string
|
||||
linkHref: string
|
||||
mode: 'open' | 'share'
|
||||
}) {
|
||||
const control = Dialog.useDialogContext()
|
||||
const {_} = useLingui()
|
||||
const potentiallyMisleading = isPossiblyAUrl(linkText)
|
||||
const openLink = useOpenLink()
|
||||
|
||||
const share = mode === 'share'
|
||||
|
||||
const onPressVisit = () => {
|
||||
control.close(() => {
|
||||
if (share) {
|
||||
shareUrl(linkHref)
|
||||
} else {
|
||||
openLink(linkHref)
|
||||
}
|
||||
})
|
||||
}
|
||||
return (
|
||||
<Dialog.Inner label={''}>
|
||||
<View style={[]}>
|
||||
{potentiallyMisleading ? (
|
||||
<>
|
||||
{/* <FontAwesomeIcon
|
||||
icon="circle-exclamation"
|
||||
color={pal.colors.text}
|
||||
size={18}
|
||||
/> */}
|
||||
<Text style={[]}>
|
||||
<Trans>Potentially Misleading Link</Trans>
|
||||
</Text>
|
||||
</>
|
||||
) : (
|
||||
<Text style={[]}>
|
||||
<Trans>Leaving Bluesky</Trans>
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
|
||||
<View style={{gap: 10}}>
|
||||
<Text>
|
||||
<Trans>This link is taking you to the following website:</Trans>
|
||||
</Text>
|
||||
|
||||
<LinkBox href={linkHref} />
|
||||
|
||||
{potentiallyMisleading && (
|
||||
<Text>
|
||||
<Trans>Make sure this is where you intend to go!</Trans>
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
|
||||
<View style={[]}>
|
||||
<Button
|
||||
label={share ? _(msg`Share Link`) : _(msg`Visit Site`)}
|
||||
onPress={onPressVisit}
|
||||
color="primary"
|
||||
size="large"
|
||||
variant="solid"
|
||||
style={a.mt_xl}>
|
||||
<ButtonText>
|
||||
<Trans>Done</Trans>
|
||||
</ButtonText>
|
||||
</Button>
|
||||
<Button
|
||||
label={_(msg`Cancel`)}
|
||||
onPress={() => control.close()}
|
||||
color="secondary"
|
||||
size="large"
|
||||
variant="solid">
|
||||
<ButtonText>
|
||||
<Trans>Done</Trans>
|
||||
</ButtonText>
|
||||
</Button>
|
||||
</View>
|
||||
</Dialog.Inner>
|
||||
)
|
||||
}
|
||||
|
||||
function LinkBox({href}: {href: string}) {
|
||||
const t = useTheme()
|
||||
const [scheme, hostname, rest] = React.useMemo(() => {
|
||||
try {
|
||||
const urlp = new URL(href)
|
||||
const [subdomain, apexdomain] = splitApexDomain(urlp.hostname)
|
||||
return [
|
||||
urlp.protocol + '//' + subdomain,
|
||||
apexdomain,
|
||||
urlp.pathname + urlp.search + urlp.hash,
|
||||
]
|
||||
} catch {
|
||||
return ['', href, '']
|
||||
}
|
||||
}, [href])
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
t.atoms.bg,
|
||||
t.atoms.border_contrast_medium,
|
||||
a.border,
|
||||
a.rounded_sm,
|
||||
a.px_md,
|
||||
a.py_sm,
|
||||
]}>
|
||||
<Text style={[t.atoms.text_contrast_high]}>
|
||||
{scheme}
|
||||
<Text style={[t.atoms.text, a.font_bold]}>{hostname}</Text>
|
||||
{rest}
|
||||
</Text>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user