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