1import { useState } from "react";
2import { View } from "react-native";
3import { WebView } from "react-native-webview";
4
5import { AppActivityIndicator } from "../../components/AppActivityIndicator";
6import { AppText as Text } from "../../components/AppText";
7import { FilePreviewLoading } from "./FilePreviewFeedback";
8import { LoadingStrip } from "../../components/LoadingStrip";
9
10export function WorkspaceFileWebPreview(props: { readonly uri: string | null }) {
11 const [loadProgress, setLoadProgress] = useState(0);
12 const [loadError, setLoadError] = useState<string | null>(null);
13
14 if (props.uri === null) {
15 return <FilePreviewLoading message="Preparing preview..." background="card" />;
16 }
17
18 return (
19 <View className="relative flex-1 bg-card">
20 {loadProgress > 0 && loadProgress < 1 ? <LoadingStrip progress={loadProgress} /> : null}
21 {loadError ? (
22 <View className="border-b border-border bg-card px-4 py-2">
23 <Text className="text-xs font-t3-bold text-foreground">Preview failed</Text>
24 <Text className="mt-0.5 text-xs leading-snug text-foreground-muted">{loadError}</Text>
25 </View>
26 ) : null}
27 <WebView
28 source={{ uri: props.uri }}
29 originWhitelist={["*"]}
30 allowsBackForwardNavigationGestures
31 allowsFullscreenVideo
32 setSupportMultipleWindows={false}
33 startInLoadingState
34 onLoadProgress={(event) => {
35 setLoadProgress(event.nativeEvent.progress);
36 }}
37 onLoadStart={() => {
38 setLoadProgress(0.05);
39 setLoadError(null);
40 }}
41 onLoadEnd={() => {
42 setLoadProgress(0);
43 }}
44 onError={(event) => {
45 setLoadProgress(0);
46 setLoadError(event.nativeEvent.description || "The file could not be rendered.");
47 }}
48 renderLoading={() => (
49 <View className="absolute inset-0 items-center justify-center bg-card">
50 <AppActivityIndicator />
51 </View>
52 )}
53 style={{ flex: 1, backgroundColor: "transparent" }}
54 />
55 </View>
56 );
57}