| ... | ... | @@ -1,11 +1,5 @@ |
| 1 | | import { |
| 2 | | type NavigationProp, |
| 3 | | type ParamListBase, |
| 4 | | type RouteProp, |
| 5 | | useNavigation, |
| 6 | | useRoute, |
| 7 | | } from "@react-navigation/native"; |
| 8 | | import { useCallback, useState } from "react"; |
| 1 | import { type NavigationProp, type ParamListBase, useNavigation } from "@react-navigation/native"; |
| 2 | import { useCallback, useLayoutEffect, useState } from "react"; |
| 9 | 3 | import { ActivityIndicator, Linking, Pressable, View } from "react-native"; |
| 10 | 4 | import { WebView } from "react-native-webview"; |
| 11 | 5 | |
| ... | ... | @@ -15,10 +9,6 @@ import { SymbolView } from "../../../components/AppSymbol"; |
| 15 | 9 | import { useThemeColor } from "../../../lib/useThemeColor"; |
| 16 | 10 | import { isLegalDocumentUrl, LEGAL_URL } from "../lib/legal-document-url"; |
| 17 | 11 | |
| 18 | | type SettingsLegalRouteParams = { |
| 19 | | SettingsLegal: { readonly externalUrl?: string } | undefined; |
| 20 | | }; |
| 21 | | |
| 22 | 12 | export function SettingsLegalDocumentCloseHeaderButton() { |
| 23 | 13 | const navigation = useNavigation(); |
| 24 | 14 | const iconColor = useThemeColor("--color-icon"); |
| ... | ... | @@ -42,20 +32,20 @@ export function SettingsLegalDocumentCloseHeaderButton() { |
| 42 | 32 | ); |
| 43 | 33 | } |
| 44 | 34 | |
| 45 | | export function SettingsLegalDocumentExternalHeaderButton() { |
| 35 | export function SettingsLegalDocumentExternalHeaderButton({ |
| 36 | externalUrl = LEGAL_URL, |
| 37 | }: { |
| 38 | readonly externalUrl?: string; |
| 39 | }) { |
| 46 | 40 | const iconColor = useThemeColor("--color-icon"); |
| 47 | | const route = useRoute<RouteProp<SettingsLegalRouteParams, "SettingsLegal">>(); |
| 48 | | const externalUrl = |
| 49 | | route.params?.externalUrl && isLegalDocumentUrl(route.params.externalUrl) |
| 50 | | ? route.params.externalUrl |
| 51 | | : LEGAL_URL; |
| 41 | const safeExternalUrl = isLegalDocumentUrl(externalUrl) ? externalUrl : LEGAL_URL; |
| 52 | 42 | |
| 53 | 43 | return ( |
| 54 | 44 | <Pressable |
| 55 | 45 | accessibilityLabel="Open legal documents in external browser" |
| 56 | 46 | accessibilityRole="button" |
| 57 | 47 | hitSlop={12} |
| 58 | | onPress={() => void Linking.openURL(externalUrl).catch(() => undefined)} |
| 48 | onPress={() => void Linking.openURL(safeExternalUrl).catch(() => undefined)} |
| 59 | 49 | className="p-2 active:opacity-60" |
| 60 | 50 | > |
| 61 | 51 | <SymbolView |
| ... | ... | @@ -83,6 +73,17 @@ export function SettingsLegalDocumentRouteScreen({ |
| 83 | 73 | const [reloadKey, setReloadKey] = useState(0); |
| 84 | 74 | const [loadProgress, setLoadProgress] = useState(0); |
| 85 | 75 | const [loadError, setLoadError] = useState<string | null>(null); |
| 76 | const [externalUrl, setExternalUrl] = useState(documentUrl); |
| 77 | const renderExternalHeaderButton = useCallback( |
| 78 | () => <SettingsLegalDocumentExternalHeaderButton externalUrl={externalUrl} />, |
| 79 | [externalUrl], |
| 80 | ); |
| 81 | |
| 82 | useLayoutEffect(() => { |
| 83 | navigation.setOptions({ |
| 84 | headerRight: renderExternalHeaderButton, |
| 85 | }); |
| 86 | }, [navigation, renderExternalHeaderButton]); |
| 86 | 87 | |
| 87 | 88 | const openExternalUrl = useCallback((url: string) => { |
| 88 | 89 | void Linking.openURL(url).catch(() => undefined); |
| ... | ... | @@ -160,7 +161,7 @@ export function SettingsLegalDocumentRouteScreen({ |
| 160 | 161 | }} |
| 161 | 162 | onLoadEnd={(event) => { |
| 162 | 163 | if (isLegalDocumentUrl(event.nativeEvent.url)) { |
| 163 | | navigation.setParams({ externalUrl: event.nativeEvent.url }); |
| 164 | setExternalUrl(event.nativeEvent.url); |
| 164 | 165 | } |
| 165 | 166 | setLoadProgress(0); |
| 166 | 167 | }} |