import { NativeHeaderToolbar, NativeStackScreenOptions } from "../../native/StackHeader"; import { useNavigation } from "@react-navigation/native"; import { SymbolView } from "../../components/AppSymbol"; import type { EnvironmentId } from "@t3tools/contracts"; import { useCallback, useState } from "react"; import { Platform, ScrollView, View } from "react-native"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import { AppText as Text } from "../../components/AppText"; import { AndroidScreenHeader } from "../../components/AndroidScreenHeader"; import { CloudEnvironmentRows } from "../connection/CloudEnvironmentRows"; import { ConnectionEnvironmentRow } from "../connection/ConnectionEnvironmentRow"; import { splitEnvironmentSections } from "../connection/environmentSections"; import { cn } from "../../lib/cn"; import { useUniwindTheme } from "../../lib/useUniwindTheme"; import { useRemoteConnections } from "../../state/use-remote-environment-registry"; import { applyShowcaseLocalEnvironmentDisplayUrls, resolveShowcaseEnvironmentUpdateDisplayUrl, SHOWCASE_AVAILABLE_CLOUD_ENVIRONMENTS, SHOWCASE_CONNECTED_CLOUD_ENVIRONMENTS, } from "../showcase/showcaseEnvironmentRows"; const SHOWCASE_ENABLED = process.env.EXPO_PUBLIC_SHOWCASE === "1"; export function SettingsEnvironmentsRouteScreen() { const { connectedEnvironments, onReconnectEnvironment, onRemoveEnvironmentPress, onUpdateEnvironment, } = useRemoteConnections(); const navigation = useNavigation(); const insets = useSafeAreaInsets(); const environmentSections = splitEnvironmentSections({ connectedEnvironments, cloudEnvironments: null, }); const localEnvironments = SHOWCASE_ENABLED ? applyShowcaseLocalEnvironmentDisplayUrls(environmentSections.localEnvironments) : environmentSections.localEnvironments; const connectedCloudEnvironments = SHOWCASE_ENABLED ? SHOWCASE_CONNECTED_CLOUD_ENVIRONMENTS : environmentSections.connectedCloudEnvironments; const hasLocalEnvironments = localEnvironments.length > 0; const [expandedId, setExpandedId] = useState(null); const headerIconColor = useUniwindTheme()["--color-icon"]; const handleToggle = useCallback((environmentId: EnvironmentId) => { setExpandedId((prev) => (prev === environmentId ? null : environmentId)); }, []); const handleUpdateEnvironment = useCallback( ( environmentId: EnvironmentId, updates: { readonly label: string; readonly displayUrl: string }, ) => { if (!SHOWCASE_ENABLED) return onUpdateEnvironment(environmentId, updates); const actualEnvironment = environmentSections.localEnvironments.find( (environment) => environment.environmentId === environmentId, ); const presentedEnvironment = localEnvironments.find( (environment) => environment.environmentId === environmentId, ); return onUpdateEnvironment(environmentId, { ...updates, displayUrl: actualEnvironment && presentedEnvironment ? resolveShowcaseEnvironmentUpdateDisplayUrl({ actualDisplayUrl: actualEnvironment.displayUrl, presentedDisplayUrl: presentedEnvironment.displayUrl, submittedDisplayUrl: updates.displayUrl, }) : updates.displayUrl, }); }, [environmentSections.localEnvironments, localEnvironments, onUpdateEnvironment], ); return ( {Platform.OS === "android" ? ( <> {/* Android renders its own in-screen header instead of the native bar. */} navigation.goBack()} actions={[ { accessibilityLabel: "Add environment", icon: "plus", onPress: () => navigation.navigate("SettingsSheet", { screen: "SettingsContent", params: { screen: "SettingsEnvironmentNew" }, }), }, ]} /> ) : ( navigation.navigate("SettingsSheet", { screen: "SettingsContent", params: { screen: "SettingsEnvironmentNew" }, }) } separateBackground tintColor={headerIconColor} /> )} {hasLocalEnvironments ? ( {localEnvironments.map((environment, index) => ( handleToggle(environment.environmentId)} onReconnect={onReconnectEnvironment} onRemove={onRemoveEnvironmentPress} onUpdate={handleUpdateEnvironment} /> ))} ) : ( No environments connected yet.{"\n"}Tap{" "} + to add one. )} {/* Always mounted: already-connected relay environments must stay visible (and removable) even when cloud config is missing or the user is signed out — the component gates discovery itself. */} ); }