import {useState} from 'react' import {Image, View} from 'react-native' import Svg, {G, Path, Rect} from 'react-native-svg' import { FontAwesomeIcon, type FontAwesomeIconStyle, } from '@fortawesome/react-native-fontawesome' import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react' import {Trans} from '@lingui/react/macro' import { getPdsFallbackFaviconUrls, isBridgedPdsUrl, isBskyPdsUrl, } from '#/state/queries/pds-label.util' import {atoms as a, useBreakpoints, useTheme} from '#/alf' import {Button, ButtonText} from '#/components/Button' import * as Dialog from '#/components/Dialog' import {InlineLinkText} from '#/components/Link' import {Text} from '#/components/Typography' const failedFaviconUrls = new Set() function formatBskyPdsDisplayName(hostname: string): string { const match = hostname.match(/^([^.]+)\.([^.]+)\.host\.bsky\.network$/) if (match) { const name = match[1].charAt(0).toUpperCase() + match[1].slice(1) const rawRegion = match[2] const region = rawRegion .replace(/^us-east$/, 'US East') .replace(/^us-west$/, 'US West') .replace(/^eu-west$/, 'EU West') .replace( /^ap-(.+)$/, (_match: string, r: string) => `AP ${r.charAt(0).toUpperCase()}${r.slice(1)}`, ) return `${name} (${region})` } if (hostname === 'bsky.social') return 'Bluesky Social' return hostname } export function PdsDialog({ control, pdsUrl, faviconUrl, }: { control: Dialog.DialogControlProps pdsUrl: string faviconUrl: string | undefined }) { const {_} = useLingui() const {gtMobile} = useBreakpoints() let hostname = pdsUrl try { hostname = new URL(pdsUrl).hostname } catch {} const isBsky = isBskyPdsUrl(pdsUrl) const isBridged = isBridgedPdsUrl(pdsUrl) const displayName = isBsky ? formatBskyPdsDisplayName(hostname) : hostname return ( { {isBridged ? Fediverse : displayName} } {isBsky && ( Bluesky Social )} This badge represents the Personal Data Server this account is stored on:{' '} {displayName} . A PDS is where posts, follows, and other data live on the AT Protocol network. {isBridged && ( This account is bridged from the Fediverse via{' '} Bridgy Fed .{' '} {/* Their original account is avaiable at:{' '} {BridgedUrl} */} )} {!isBridged && ( Learn more {' '} about what a PDS is and how to{' '} self-host {' '} your own. )} ) } function BskyBadgeSVG({size}: {size: number}) { return ( ) } function FediverseBadgeSVG({size}: {size: number}) { return ( ) } function DbBadgeIcon({ size, borderRadius, }: { size: number borderRadius: number }) { const t = useTheme() return ( ) } function FaviconBadgeIcon({ size, borderRadius, faviconUrls, }: { size: number borderRadius: number faviconUrls: string[] }) { const t = useTheme() const getNextUrl = (currentUrl?: string) => faviconUrls.find( url => url !== currentUrl && url && !failedFaviconUrls.has(url), ) const [currentUrl, setCurrentUrl] = useState(getNextUrl) const [imageLoaded, setImageLoaded] = useState(false) if (!currentUrl) { return } return ( {!imageLoaded ? ( ) : null} { setImageLoaded(true) }} onError={() => { failedFaviconUrls.add(currentUrl) setImageLoaded(false) setCurrentUrl(getNextUrl(currentUrl)) }} /> ) } export function PdsBadgeIcon({ faviconUrl, pdsUrl, isBsky, isBridged, size, borderRadius, }: { faviconUrl?: string pdsUrl?: string isBsky: boolean isBridged: boolean size: number borderRadius?: number }) { const r = borderRadius ?? size / 5 if (isBsky) return if (isBridged) return const faviconCandidates = Array.from( new Set( [faviconUrl, ...(pdsUrl ? getPdsFallbackFaviconUrls(pdsUrl) : [])].filter( Boolean, ) as string[], ), ) if (faviconCandidates.length > 0) return ( ) return }