import { useCallback, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { Platform, Text, View } from "react-native";
import { StyleSheet, withUnistyles } from "react-native-unistyles";
import { router } from "expo-router";
import type { PluginHostProps } from "@getpaseo/plugin/client";
import { Button } from "@/components/ui/button";
import { DropdownMenuItem } from "@/components/ui/dropdown-menu";
import { useIsCompactFormFactor } from "@/constants/layout";
import { useHostFeature } from "@/runtime/host-features";
import { useHostRuntimeClient, useHostRuntimeIsConnected, useHosts } from "@/runtime/host-runtime";
import type { Theme } from "@/styles/theme";
import { useInstalledPlugin } from "../registry";
import { PluginRuntimeBoundary } from "../runtime-boundary";
import { SurfaceErrorBoundary } from "../surface-error-boundary";
import { toPluginTheme } from "../theme";
import { buildPluginSettingsRoute } from "./routes";
interface SettingsIdentity {
serverId: string;
pluginId: string;
screenId: string;
}
function PluginSettingsMenuItem({
serverId,
pluginId,
screenId,
title,
disabled,
}: SettingsIdentity & { title: string; disabled?: boolean }) {
const open = useCallback(
() => router.push(buildPluginSettingsRoute(serverId, pluginId, screenId)),
[serverId, pluginId, screenId],
);
return (
{title}
);
}
export function PluginSettingsMenuItems({
serverId,
pluginId,
disabled,
}: Omit & { disabled?: boolean }) {
const plugin = useInstalledPlugin(serverId, pluginId);
const supported = useHostFeature(serverId, "pluginSettings");
if (!supported || !plugin) return null;
return (
<>
{plugin.settingsScreens.map((screen) => (
))}
>
);
}
function SettingsContent({
serverId,
pluginId,
screenId,
theme,
}: SettingsIdentity & { theme: PluginHostProps["theme"] }) {
const { t } = useTranslation();
const plugin = useInstalledPlugin(serverId, pluginId);
const client = useHostRuntimeClient(serverId);
const connected = useHostRuntimeIsConnected(serverId);
const supported = useHostFeature(serverId, "pluginSettings");
const compact = useIsCompactFormFactor();
const hosts = useHosts();
const [attempt, setAttempt] = useState(0);
const screen = plugin?.settingsScreens.find((item) => item.id === screenId);
const retry = useCallback(() => setAttempt((value) => value + 1), []);
const renderError = useCallback(
(error: string) => (
{error}
),
[retry, t],
);
const host = useMemo(
() => ({
id: serverId,
label: hosts.find((candidate) => candidate.serverId === serverId)?.label ?? serverId,
}),
[hosts, serverId],
);
const platform = Platform.OS === "ios" || Platform.OS === "android" ? Platform.OS : "web";
const layout = useMemo(
() => ({ compact, platform }),
[compact, platform],
);
if (!connected)
return {t("settings.plugins.screens.offline")};
// COMPAT(pluginSettings): added in v0.8, remove after 2027-03-05.
if (!supported) return {t("settings.plugins.screens.update")};
if (!plugin || !screen || !client)
return {t("settings.plugins.screens.unavailable")};
const Component = screen.Component;
return (
);
}
const ThemedSettingsContent = withUnistyles(SettingsContent);
const themeMapping = (theme: Theme) => ({ theme: toPluginTheme(theme) });
export function PluginSettingsContent(props: SettingsIdentity) {
return ;
}
const styles = StyleSheet.create((theme) => ({ message: { color: theme.colors.foregroundMuted } }));