Move workspace gate background and root layout off useUnistyles
The workspace gate (loading/unreachable/missing) used surfaceWorkspace, which clashed with the panels' surface0. Switch the gate shell to surface0 so it matches the agent panel. Also remove three hot-path useUnistyles() calls from _layout.tsx that were re-rendering the whole app on every theme/breakpoint/insets change: RootLayout and AppContainer move to StyleSheet.create, and the desktop window-controls effect lifts into a small leaf component.
This commit is contained in:
@@ -26,7 +26,7 @@ import { Gesture, GestureDetector, GestureHandlerRootView } from "react-native-g
|
|||||||
import { KeyboardProvider } from "react-native-keyboard-controller";
|
import { KeyboardProvider } from "react-native-keyboard-controller";
|
||||||
import { Extrapolation, interpolate, runOnJS, useSharedValue } from "react-native-reanimated";
|
import { Extrapolation, interpolate, runOnJS, useSharedValue } from "react-native-reanimated";
|
||||||
import { SafeAreaProvider } from "react-native-safe-area-context";
|
import { SafeAreaProvider } from "react-native-safe-area-context";
|
||||||
import { UnistylesRuntime, useUnistyles } from "react-native-unistyles";
|
import { StyleSheet, UnistylesRuntime, useUnistyles } from "react-native-unistyles";
|
||||||
import { CommandCenter } from "@/components/command-center";
|
import { CommandCenter } from "@/components/command-center";
|
||||||
import { WorktreeSetupCalloutSource } from "@/components/worktree-setup-callout-source";
|
import { WorktreeSetupCalloutSource } from "@/components/worktree-setup-callout-source";
|
||||||
import { DownloadToast } from "@/components/download-toast";
|
import { DownloadToast } from "@/components/download-toast";
|
||||||
@@ -58,7 +58,6 @@ import { getDesktopHost } from "@/desktop/host";
|
|||||||
import { RosettaCalloutSource } from "@/desktop/updates/rosetta-callout-source";
|
import { RosettaCalloutSource } from "@/desktop/updates/rosetta-callout-source";
|
||||||
import { UpdateCalloutSource } from "@/desktop/updates/update-callout-source";
|
import { UpdateCalloutSource } from "@/desktop/updates/update-callout-source";
|
||||||
import { useActiveWorktreeNewAction } from "@/hooks/use-active-worktree-new-action";
|
import { useActiveWorktreeNewAction } from "@/hooks/use-active-worktree-new-action";
|
||||||
import { useColorScheme } from "@/hooks/use-color-scheme";
|
|
||||||
import { useFaviconStatus } from "@/hooks/use-favicon-status";
|
import { useFaviconStatus } from "@/hooks/use-favicon-status";
|
||||||
import { useKeyboardShortcuts } from "@/hooks/use-keyboard-shortcuts";
|
import { useKeyboardShortcuts } from "@/hooks/use-keyboard-shortcuts";
|
||||||
import { useOpenProject } from "@/hooks/use-open-project";
|
import { useOpenProject } from "@/hooks/use-open-project";
|
||||||
@@ -393,7 +392,6 @@ function AppContainer({
|
|||||||
selectedAgentId,
|
selectedAgentId,
|
||||||
chromeEnabled: chromeEnabledOverride,
|
chromeEnabled: chromeEnabledOverride,
|
||||||
}: AppContainerProps) {
|
}: AppContainerProps) {
|
||||||
const { theme } = useUnistyles();
|
|
||||||
const daemons = useHosts();
|
const daemons = useHosts();
|
||||||
const { settings, updateSettings } = useAppSettings();
|
const { settings, updateSettings } = useAppSettings();
|
||||||
const toggleMobileAgentList = usePanelStore((state) => state.toggleMobileAgentList);
|
const toggleMobileAgentList = usePanelStore((state) => state.toggleMobileAgentList);
|
||||||
@@ -450,13 +448,8 @@ function AppContainer({
|
|||||||
|
|
||||||
useActiveWorktreeNewAction();
|
useActiveWorktreeNewAction();
|
||||||
|
|
||||||
const containerStyle = useMemo(
|
|
||||||
() => ({ flex: 1 as const, backgroundColor: theme.colors.surface0 }),
|
|
||||||
[theme.colors.surface0],
|
|
||||||
);
|
|
||||||
|
|
||||||
const content = (
|
const content = (
|
||||||
<View style={containerStyle}>
|
<View style={layoutStyles.surfaceFill}>
|
||||||
<View style={rowStyle}>
|
<View style={rowStyle}>
|
||||||
{!isCompactLayout && chromeEnabled && !isFocusModeEnabled && (
|
{!isCompactLayout && chromeEnabled && !isFocusModeEnabled && (
|
||||||
<LeftSidebar selectedAgentId={selectedAgentId} />
|
<LeftSidebar selectedAgentId={selectedAgentId} />
|
||||||
@@ -594,9 +587,6 @@ function MobileGestureWrapper({
|
|||||||
function ProvidersWrapper({ children }: { children: ReactNode }) {
|
function ProvidersWrapper({ children }: { children: ReactNode }) {
|
||||||
const { settings, isLoading: settingsLoading } = useAppSettings();
|
const { settings, isLoading: settingsLoading } = useAppSettings();
|
||||||
const { upsertConnectionFromOfferUrl } = useHostMutations();
|
const { upsertConnectionFromOfferUrl } = useHostMutations();
|
||||||
const systemColorScheme = useColorScheme();
|
|
||||||
const { theme } = useUnistyles();
|
|
||||||
const resolvedTheme = settings.theme === "auto" ? (systemColorScheme ?? "light") : settings.theme;
|
|
||||||
|
|
||||||
// Apply theme setting on mount and when it changes
|
// Apply theme setting on mount and when it changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -609,21 +599,9 @@ function ProvidersWrapper({ children }: { children: ReactNode }) {
|
|||||||
}
|
}
|
||||||
}, [settingsLoading, settings.theme]);
|
}, [settingsLoading, settings.theme]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (settingsLoading || isNative) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateDesktopWindowControls({
|
|
||||||
backgroundColor: theme.colors.surface0,
|
|
||||||
foregroundColor: theme.colors.foreground,
|
|
||||||
}).catch((error) => {
|
|
||||||
console.warn("[DesktopWindow] Failed to update window controls overlay", error);
|
|
||||||
});
|
|
||||||
}, [settingsLoading, resolvedTheme, theme.colors.foreground, theme.colors.surface0]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<VoiceProvider>
|
<VoiceProvider>
|
||||||
|
<DesktopWindowControlsSync enabled={!settingsLoading} />
|
||||||
<OfferLinkListener upsertDaemonFromOfferUrl={upsertConnectionFromOfferUrl} />
|
<OfferLinkListener upsertDaemonFromOfferUrl={upsertConnectionFromOfferUrl} />
|
||||||
<HostSessionManager />
|
<HostSessionManager />
|
||||||
<FaviconStatusSync />
|
<FaviconStatusSync />
|
||||||
@@ -632,6 +610,24 @@ function ProvidersWrapper({ children }: { children: ReactNode }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function DesktopWindowControlsSync({ enabled }: { enabled: boolean }) {
|
||||||
|
const { theme } = useUnistyles();
|
||||||
|
const surface0 = theme.colors.surface0;
|
||||||
|
const foreground = theme.colors.foreground;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!enabled || isNative) return;
|
||||||
|
void updateDesktopWindowControls({
|
||||||
|
backgroundColor: surface0,
|
||||||
|
foregroundColor: foreground,
|
||||||
|
}).catch((error) => {
|
||||||
|
console.warn("[DesktopWindow] Failed to update window controls overlay", error);
|
||||||
|
});
|
||||||
|
}, [enabled, surface0, foreground]);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
function OfferLinkListener({
|
function OfferLinkListener({
|
||||||
upsertDaemonFromOfferUrl,
|
upsertDaemonFromOfferUrl,
|
||||||
}: {
|
}: {
|
||||||
@@ -911,20 +907,23 @@ function RootProviders({ children }: { children: ReactNode }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function RootLayout() {
|
export default function RootLayout() {
|
||||||
const { theme } = useUnistyles();
|
|
||||||
const gestureRootStyle = useMemo(
|
|
||||||
() => ({ flex: 1, backgroundColor: theme.colors.surface0 }),
|
|
||||||
[theme.colors.surface0],
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<GestureHandlerRootView style={gestureRootStyle}>
|
<GestureHandlerRootView style={flexStyle}>
|
||||||
<NavigationActiveWorkspaceObserver />
|
<View style={layoutStyles.surfaceFill}>
|
||||||
<RootProviders>
|
<NavigationActiveWorkspaceObserver />
|
||||||
<RuntimeProviders>
|
<RootProviders>
|
||||||
<AppShell />
|
<RuntimeProviders>
|
||||||
</RuntimeProviders>
|
<AppShell />
|
||||||
</RootProviders>
|
</RuntimeProviders>
|
||||||
|
</RootProviders>
|
||||||
|
</View>
|
||||||
</GestureHandlerRootView>
|
</GestureHandlerRootView>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const layoutStyles = StyleSheet.create((theme) => ({
|
||||||
|
surfaceFill: {
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: theme.colors.surface0,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|||||||
@@ -1259,7 +1259,7 @@ function renderWorkspaceScreenGateShell(input: {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<WorkspaceFocusProvider workspaceKey={input.workspaceKey}>
|
<WorkspaceFocusProvider workspaceKey={input.workspaceKey}>
|
||||||
<View style={containerWithWorkspaceBackgroundStyle}>
|
<View style={styles.container}>
|
||||||
<View style={styles.threePaneRow}>
|
<View style={styles.threePaneRow}>
|
||||||
<View style={styles.centerColumn}>
|
<View style={styles.centerColumn}>
|
||||||
<WorkspaceScreenGateFrame>{input.gate}</WorkspaceScreenGateFrame>
|
<WorkspaceScreenGateFrame>{input.gate}</WorkspaceScreenGateFrame>
|
||||||
|
|||||||
Reference in New Issue
Block a user