fix(app): retain Explorer tab state
This commit is contained in:
@@ -17,13 +17,19 @@ import { formatPrTabLabel, PullRequestTabIcon } from "@/git/pull-request-panel";
|
||||
import { usePanelStore, selectIsFileExplorerOpen, type ExplorerTab } from "@/stores/panel-store";
|
||||
import { useCloseFileExplorerGesture } from "@/mobile-panels/gestures";
|
||||
import { MobilePanelOverlay } from "@/mobile-panels/presentation";
|
||||
import { HEADER_INNER_HEIGHT } from "@/constants/layout";
|
||||
import {
|
||||
HEADER_INNER_HEIGHT,
|
||||
HEADER_INNER_HEIGHT_MOBILE,
|
||||
HEADER_TOP_PADDING_MOBILE,
|
||||
} from "@/constants/layout";
|
||||
import { ChangesSurface } from "@/git/diff-pane";
|
||||
import { FileExplorerPane } from "./file-explorer-pane";
|
||||
import { useKeyboardShiftStyle } from "@/hooks/use-keyboard-shift-style";
|
||||
import { shouldUseCompactExplorerKeyboardPadding } from "@/hooks/keyboard-shift-policy";
|
||||
import { useHasOwnedWindowChromeObstruction, WindowChromeSafeArea } from "@/utils/desktop-window";
|
||||
import { TitlebarDragRegion } from "@/components/desktop/titlebar-drag-region";
|
||||
import { RetainedPanelActivity } from "@/components/retained-panel";
|
||||
import { RetainedPanel, RetainedPanelActivity } from "@/components/retained-panel";
|
||||
import { useMountedTabSet } from "@/screens/workspace/use-mounted-tab-set";
|
||||
import { SidebarResizeHandle } from "@/components/sidebar-resize-handle";
|
||||
import { resolveDesktopExplorerWidth } from "@/components/desktop-sidebar-layout";
|
||||
import {
|
||||
@@ -82,9 +88,10 @@ export function CompactExplorerSidebar({
|
||||
workspaceRoot,
|
||||
isGit,
|
||||
});
|
||||
const usePanelKeyboardPadding = shouldUseCompactExplorerKeyboardPadding({ isGit, explorerTab });
|
||||
const { style: mobileKeyboardInsetStyle } = useKeyboardShiftStyle({
|
||||
mode: "padding",
|
||||
enabled: true,
|
||||
enabled: usePanelKeyboardPadding,
|
||||
});
|
||||
const { gesture: closeGesture } = useCloseFileExplorerGesture();
|
||||
|
||||
@@ -104,12 +111,19 @@ export function CompactExplorerSidebar({
|
||||
const mobileSidebarStyle = useMemo(
|
||||
() => [
|
||||
{
|
||||
paddingTop: insets.top,
|
||||
paddingTop: insets.top + HEADER_TOP_PADDING_MOBILE,
|
||||
paddingBottom: usePanelKeyboardPadding ? 0 : insets.bottom,
|
||||
backgroundColor: theme.colors.surfaceSidebar,
|
||||
},
|
||||
mobileKeyboardInsetStyle,
|
||||
],
|
||||
[insets.top, theme.colors.surfaceSidebar, mobileKeyboardInsetStyle],
|
||||
[
|
||||
insets.bottom,
|
||||
insets.top,
|
||||
mobileKeyboardInsetStyle,
|
||||
theme.colors.surfaceSidebar,
|
||||
usePanelKeyboardPadding,
|
||||
],
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -318,6 +332,16 @@ function ExplorerSidebarContent({
|
||||
!isGit && (activeTab === "changes" || activeTab === "pr") ? "files" : activeTab;
|
||||
const resolvedTab: ExplorerTab = requestedTab === "pr" && !showPrTab ? "changes" : requestedTab;
|
||||
const prTabLabel = formatPrTabLabel(prPane.prNumber);
|
||||
const availableTabs = useMemo<ExplorerTab[]>(() => {
|
||||
const tabs: ExplorerTab[] = isGit ? ["changes", "files"] : ["files"];
|
||||
if (isGit && showPrTab) tabs.push("pr");
|
||||
return tabs;
|
||||
}, [isGit, showPrTab]);
|
||||
const { mountedTabIds } = useMountedTabSet({
|
||||
activeTabId: resolvedTab,
|
||||
allTabIds: availableTabs,
|
||||
cap: availableTabs.length,
|
||||
});
|
||||
|
||||
return (
|
||||
<View style={styles.sidebarContent} pointerEvents="auto">
|
||||
@@ -391,31 +415,37 @@ function ExplorerSidebarContent({
|
||||
|
||||
{/* Content based on active tab */}
|
||||
<View style={styles.contentArea} testID="explorer-content-area">
|
||||
{resolvedTab === "changes" && (
|
||||
<ChangedFilesPane
|
||||
serverId={serverId}
|
||||
workspaceId={workspaceId}
|
||||
workspaceRoot={workspaceRoot}
|
||||
isOpen={isOpen}
|
||||
onOpenFile={onOpenFile}
|
||||
/>
|
||||
)}
|
||||
{resolvedTab === "files" && (
|
||||
<FilesPane
|
||||
serverId={serverId}
|
||||
workspaceId={workspaceId}
|
||||
workspaceRoot={workspaceRoot}
|
||||
onOpenFile={onOpenFile}
|
||||
/>
|
||||
)}
|
||||
{resolvedTab === "pr" && (
|
||||
<PrTabContent
|
||||
serverId={serverId}
|
||||
workspaceId={workspaceId}
|
||||
cwd={workspaceRoot}
|
||||
prPane={prPane}
|
||||
/>
|
||||
)}
|
||||
{mountedTabIds.has("changes") ? (
|
||||
<RetainedPanel active={resolvedTab === "changes"}>
|
||||
<ChangedFilesPane
|
||||
serverId={serverId}
|
||||
workspaceId={workspaceId}
|
||||
workspaceRoot={workspaceRoot}
|
||||
isOpen={isOpen}
|
||||
onOpenFile={onOpenFile}
|
||||
/>
|
||||
</RetainedPanel>
|
||||
) : null}
|
||||
{mountedTabIds.has("files") ? (
|
||||
<RetainedPanel active={resolvedTab === "files"}>
|
||||
<FilesPane
|
||||
serverId={serverId}
|
||||
workspaceId={workspaceId}
|
||||
workspaceRoot={workspaceRoot}
|
||||
onOpenFile={onOpenFile}
|
||||
/>
|
||||
</RetainedPanel>
|
||||
) : null}
|
||||
{mountedTabIds.has("pr") ? (
|
||||
<RetainedPanel active={resolvedTab === "pr"}>
|
||||
<PrTabContent
|
||||
serverId={serverId}
|
||||
workspaceId={workspaceId}
|
||||
cwd={workspaceRoot}
|
||||
prPane={prPane}
|
||||
/>
|
||||
</RetainedPanel>
|
||||
) : null}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
@@ -487,7 +517,10 @@ const styles = StyleSheet.create((theme) => ({
|
||||
},
|
||||
header: {
|
||||
position: "relative",
|
||||
height: HEADER_INNER_HEIGHT,
|
||||
height: {
|
||||
xs: HEADER_INNER_HEIGHT_MOBILE,
|
||||
md: HEADER_INNER_HEIGHT,
|
||||
},
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
export const DEFAULT_IOS_KEYBOARD_INSET_MIN_HEIGHT = 120;
|
||||
|
||||
export function shouldUseCompactExplorerKeyboardPadding(input: {
|
||||
isGit: boolean;
|
||||
explorerTab: "changes" | "files" | "pr";
|
||||
}): boolean {
|
||||
return !input.isGit || input.explorerTab !== "changes";
|
||||
}
|
||||
|
||||
export function resolveKeyboardShift(input: {
|
||||
rawKeyboardHeight: number;
|
||||
keyboardProgress: number;
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { resolveKeyboardShift } from "./keyboard-shift-policy";
|
||||
import {
|
||||
resolveKeyboardShift,
|
||||
shouldUseCompactExplorerKeyboardPadding,
|
||||
} from "./keyboard-shift-policy";
|
||||
|
||||
describe("resolveKeyboardShift", () => {
|
||||
it("keeps the existing open-keyboard offset behavior", () => {
|
||||
@@ -38,3 +41,17 @@ describe("resolveKeyboardShift", () => {
|
||||
).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("shouldUseCompactExplorerKeyboardPadding", () => {
|
||||
it("keeps the changes viewport stable while preserving padding for other tabs", () => {
|
||||
expect(shouldUseCompactExplorerKeyboardPadding({ isGit: true, explorerTab: "changes" })).toBe(
|
||||
false,
|
||||
);
|
||||
expect(shouldUseCompactExplorerKeyboardPadding({ isGit: true, explorerTab: "files" })).toBe(
|
||||
true,
|
||||
);
|
||||
expect(shouldUseCompactExplorerKeyboardPadding({ isGit: false, explorerTab: "changes" })).toBe(
|
||||
true,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user