Compare commits

...

1 Commits

Author SHA1 Message Date
Samuel Newman 840cb09ce8 wip move to alf 2024-10-11 16:01:17 +03:00
2 changed files with 174 additions and 20 deletions
+22 -20
View File
@@ -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>
)
}