| ... | @@ -6,7 +6,10 @@ import { | ... | @@ -6,7 +6,10 @@ import { |
| 6 | } from "../../state/use-composer-drafts"; | 6 | } from "../../state/use-composer-drafts"; |
| 7 | import { useWorktreeSetup } from "./use-worktree-setup"; | 7 | import { useWorktreeSetup } from "./use-worktree-setup"; |
| 8 | import { worktreeSetupAgentStarted } from "@t3tools/client-runtime/worktree-setup"; | 8 | import { worktreeSetupAgentStarted } from "@t3tools/client-runtime/worktree-setup"; |
| 9 | import { NativeStackScreenOptions } from "../../native/StackHeader"; | 9 | import { ScreenHeader } from "../../components/ScreenHeader"; |
| | 10 | import { ScreenHeaderButton } from "../../components/ScreenHeaderButton"; |
| | 11 | import type { ScreenHeaderAction } from "../../components/ScreenHeader.types"; |
| | 12 | import { useThreadHeaderOptions } from "./useThreadHeaderOptions"; |
| 10 | import { | 13 | import { |
| 11 | StackActions, | 14 | StackActions, |
| 12 | useFocusEffect, | 15 | useFocusEffect, |
| ... | @@ -43,12 +46,6 @@ import { useEnvironmentQuery } from "../../state/query"; | ... | @@ -43,12 +46,6 @@ import { useEnvironmentQuery } from "../../state/query"; |
| 43 | import { dismissGitActionResult, useGitActionProgress } from "../../state/use-vcs-action-state"; | 46 | import { dismissGitActionResult, useGitActionProgress } from "../../state/use-vcs-action-state"; |
| 44 | import { vcsEnvironment } from "../../state/vcs"; | 47 | import { vcsEnvironment } from "../../state/vcs"; |
| 45 | import { EmptyState } from "../../components/EmptyState"; | 48 | import { EmptyState } from "../../components/EmptyState"; |
| 46 | import { | | |
| 47 | AndroidHeaderIconButton, | | |
| 48 | AndroidScreenHeader, | | |
| 49 | type AndroidHeaderAction, | | |
| 50 | } from "../../components/AndroidScreenHeader"; | | |
| 51 | import { AndroidWorkspaceSidebarButton } from "../layout/workspace-sidebar-toolbar"; | | |
| 52 | import { LoadingScreen } from "../../components/LoadingScreen"; | 49 | import { LoadingScreen } from "../../components/LoadingScreen"; |
| 53 | import { scopedThreadKey } from "../../lib/scopedEntities"; | 50 | import { scopedThreadKey } from "../../lib/scopedEntities"; |
| 54 | import { NATIVE_LIQUID_GLASS_SUPPORTED } from "../../native/native-glass"; | 51 | import { NATIVE_LIQUID_GLASS_SUPPORTED } from "../../native/native-glass"; |
| ... | @@ -73,11 +70,6 @@ import { | ... | @@ -73,11 +70,6 @@ import { |
| 73 | } from "../terminal/terminalLaunchContext"; | 70 | } from "../terminal/terminalLaunchContext"; |
| 74 | import { terminalDebugLog } from "../terminal/terminalDebugLog"; | 71 | import { terminalDebugLog } from "../terminal/terminalDebugLog"; |
| 75 | import { ThreadDetailScreen, type ThreadDetailScreenProps } from "./ThreadDetailScreen"; | 72 | import { ThreadDetailScreen, type ThreadDetailScreenProps } from "./ThreadDetailScreen"; |
| 76 | import { | | |
| 77 | ThreadGitControls, | | |
| 78 | useThreadGitCenterHeaderItems, | | |
| 79 | useThreadGitRightHeaderItems, | | |
| 80 | } from "./ThreadGitControls"; | | |
| 81 | import { GitOverviewSheet } from "./git/GitOverviewSheet"; | 73 | import { GitOverviewSheet } from "./git/GitOverviewSheet"; |
| 82 | import { useAtomCommand } from "../../state/use-atom-command"; | 74 | import { useAtomCommand } from "../../state/use-atom-command"; |
| 83 | import { useSelectedThreadGitActions } from "../../state/use-selected-thread-git-actions"; | 75 | import { useSelectedThreadGitActions } from "../../state/use-selected-thread-git-actions"; |
| ... | @@ -93,7 +85,6 @@ import { | ... | @@ -93,7 +85,6 @@ import { |
| 93 | useAdaptiveWorkspacePaneRole, | 85 | useAdaptiveWorkspacePaneRole, |
| 94 | useRegisterWorkspaceInspector, | 86 | useRegisterWorkspaceInspector, |
| 95 | } from "../layout/AdaptiveWorkspaceLayout"; | 87 | } from "../layout/AdaptiveWorkspaceLayout"; |
| 96 | import { withNativeGlassHeaderItem } from "../layout/native-glass-header-items"; | | |
| 97 | import { ThreadFileNavigatorPane } from "../files/thread-file-navigator-pane"; | 88 | import { ThreadFileNavigatorPane } from "../files/thread-file-navigator-pane"; |
| 98 | import { | 89 | import { |
| 99 | ThreadInspectorContentStack, | 90 | ThreadInspectorContentStack, |
| ... | @@ -101,13 +92,109 @@ import { | ... | @@ -101,13 +92,109 @@ import { |
| 101 | } from "./thread-inspector-content-stack"; | 92 | } from "./thread-inspector-content-stack"; |
| 102 | import { threadRouteIsHydrating } from "./thread-route-hydration"; | 93 | import { threadRouteIsHydrating } from "./thread-route-hydration"; |
| 103 | | 94 | |
| | 95 | function ThreadHeader( |
| | 96 | props: Parameters<typeof useThreadHeaderOptions>[0] & { |
| | 97 | readonly hasThreadCwd: boolean; |
| | 98 | readonly hasWorkspaceRoot: boolean; |
| | 99 | readonly fileInspectorSupported: boolean; |
| | 100 | readonly inspectorMode: ThreadInspectorMode | null; |
| | 101 | readonly onToggleInspector: () => void; |
| | 102 | readonly onOpenGitInspector: () => void; |
| | 103 | readonly onOpenFilesInspector: () => void; |
| | 104 | }, |
| | 105 | ) { |
| | 106 | const navigation = useNavigation(); |
| | 107 | const { layout, panes, toggleAuxiliaryPane } = useAdaptiveWorkspaceLayout(); |
| | 108 | const { onOpenTerminal } = props.gitControls; |
| | 109 | const native = useThreadHeaderOptions(props); |
| | 110 | const androidHeaderActions = useMemo<ReadonlyArray<ScreenHeaderAction>>(() => { |
| | 111 | const actions: ScreenHeaderAction[] = []; |
| | 112 | if (props.onReturnToThread) { |
| | 113 | actions.push({ |
| | 114 | accessibilityLabel: "Return to chat", |
| | 115 | icon: "chevron.left", |
| | 116 | onPress: props.onReturnToThread, |
| | 117 | }); |
| | 118 | } |
| | 119 | if (props.hasThreadCwd) { |
| | 120 | const filesVisible = props.inspectorMode === "files" && panes.auxiliaryPaneVisible; |
| | 121 | actions.push({ |
| | 122 | accessibilityLabel: filesVisible ? "Close files" : "Open files", |
| | 123 | selected: filesVisible, |
| | 124 | icon: "folder", |
| | 125 | onPress: filesVisible ? toggleAuxiliaryPane : props.onOpenFilesInspector, |
| | 126 | }); |
| | 127 | } |
| | 128 | if (props.hasWorkspaceRoot) { |
| | 129 | actions.push({ |
| | 130 | accessibilityLabel: "Open terminal", |
| | 131 | icon: "terminal", |
| | 132 | onPress: () => onOpenTerminal(null), |
| | 133 | }); |
| | 134 | } |
| | 135 | actions.push({ |
| | 136 | accessibilityLabel: "Open git controls", |
| | 137 | icon: "point.topleft.down.curvedto.point.bottomright.up", |
| | 138 | onPress: props.onOpenGitInspector, |
| | 139 | }); |
| | 140 | return actions; |
| | 141 | }, [ |
| | 142 | props.inspectorMode, |
| | 143 | panes.auxiliaryPaneVisible, |
| | 144 | props.onOpenFilesInspector, |
| | 145 | onOpenTerminal, |
| | 146 | props.onOpenGitInspector, |
| | 147 | toggleAuxiliaryPane, |
| | 148 | props.onReturnToThread, |
| | 149 | props.hasThreadCwd, |
| | 150 | props.hasWorkspaceRoot, |
| | 151 | ]); |
| | 152 | |
| | 153 | return ( |
| | 154 | <> |
| | 155 | <ScreenHeader |
| | 156 | title={props.title} |
| | 157 | subtitle={props.subtitle} |
| | 158 | sidebar={native.sidebar} |
| | 159 | options={native.options} |
| | 160 | optionsVersion={props.gitControls.projectScripts} |
| | 161 | trailing={ |
| | 162 | props.fileInspectorSupported && props.hasThreadCwd ? ( |
| | 163 | <ScreenHeaderButton |
| | 164 | accessibilityLabel={ |
| | 165 | props.inspectorMode !== null && panes.auxiliaryPaneVisible |
| | 166 | ? "Hide inspector" |
| | 167 | : "Show inspector" |
| | 168 | } |
| | 169 | icon="sidebar.right" |
| | 170 | selected={props.inspectorMode !== null && panes.auxiliaryPaneVisible} |
| | 171 | onPress={props.onToggleInspector} |
| | 172 | /> |
| | 173 | ) : null |
| | 174 | } |
| | 175 | onBack={ |
| | 176 | layout.usesSplitView |
| | 177 | ? undefined |
| | 178 | : () => { |
| | 179 | // A deep link or cold start has no previous route; Home is the way out. |
| | 180 | // Read the history at press time: it changes without re-rendering this screen. |
| | 181 | if (navigation.canGoBack()) navigation.goBack(); |
| | 182 | else navigation.dispatch(StackActions.replace("Home")); |
| | 183 | } |
| | 184 | } |
| | 185 | actions={androidHeaderActions} |
| | 186 | hideBottomBorder |
| | 187 | /> |
| | 188 | {native.fallback} |
| | 189 | </> |
| | 190 | ); |
| | 191 | } |
| | 192 | |
| 104 | interface ThreadInspectorSelection { | 193 | interface ThreadInspectorSelection { |
| 105 | readonly routeThreadIdentity: string | null; | 194 | readonly routeThreadIdentity: string | null; |
| 106 | readonly mode: ThreadInspectorMode; | 195 | readonly mode: ThreadInspectorMode; |
| 107 | } | 196 | } |
| 108 | | 197 | |
| 109 | type NativeHeaderItems = ReadonlyArray<Record<string, unknown>>; | | |
| 110 | | | |
| 111 | function InspectorPaneRoleActivation() { | 198 | function InspectorPaneRoleActivation() { |
| 112 | useAdaptiveWorkspacePaneRole("inspector"); | 199 | useAdaptiveWorkspacePaneRole("inspector"); |
| 113 | return null; | 200 | return null; |
| ... | @@ -237,14 +324,8 @@ function ThreadRouteContent( | ... | @@ -237,14 +324,8 @@ function ThreadRouteContent( |
| 237 | ) { | 324 | ) { |
| 238 | const { themeVariables } = useAppearancePreferences(); | 325 | const { themeVariables } = useAppearancePreferences(); |
| 239 | const headerColor = themeVariables["--color-header"]; | 326 | const headerColor = themeVariables["--color-header"]; |
| 240 | const { | 327 | const { fileInspector, layout, panes, showAuxiliaryPane, toggleAuxiliaryPane } = |
| 241 | fileInspector, | 328 | useAdaptiveWorkspaceLayout(); |
| 242 | layout, | | |
| 243 | panes, | | |
| 244 | showAuxiliaryPane, | | |
| 245 | toggleAuxiliaryPane, | | |
| 246 | togglePrimarySidebar, | | |
| 247 | } = useAdaptiveWorkspaceLayout(); | | |
| 248 | const { connectionState } = useRemoteConnectionStatus(); | 329 | const { connectionState } = useRemoteConnectionStatus(); |
| 249 | const { onReconnectEnvironment } = useRemoteConnections(); | 330 | const { onReconnectEnvironment } = useRemoteConnections(); |
| 250 | const { | 331 | const { |
| ... | @@ -701,94 +782,6 @@ function ThreadRouteContent( | ... | @@ -701,94 +782,6 @@ function ThreadRouteContent( |
| 701 | onPull: gitActions.onPullSelectedThreadBranch, | 782 | onPull: gitActions.onPullSelectedThreadBranch, |
| 702 | onRunAction: gitActions.onRunSelectedThreadGitAction, | 783 | onRunAction: gitActions.onRunSelectedThreadGitAction, |
| 703 | }; | 784 | }; |
| 704 | const threadCenterHeaderItems = useThreadGitCenterHeaderItems(threadGitControlProps); | | |
| 705 | const compactRightHeaderItems = useThreadGitRightHeaderItems(threadGitControlProps); | | |
| 706 | const splitLeftHeaderItems = useMemo<NativeHeaderItems>( | | |
| 707 | () => [ | | |
| 708 | { | | |
| 709 | // Match Mail's split-view detail toolbar: the first detail action sits | | |
| 710 | // inside the content pane, not flush against the sidebar divider. | | |
| 711 | spacing: 18, | | |
| 712 | type: "spacing" as const, | | |
| 713 | }, | | |
| 714 | ...(props.onReturnToThread | | |
| 715 | ? [ | | |
| 716 | withNativeGlassHeaderItem({ | | |
| 717 | accessibilityLabel: "Return to chat", | | |
| 718 | icon: { name: "chevron.left", type: "sfSymbol" as const }, | | |
| 719 | identifier: "thread-left-return", | | |
| 720 | onPress: props.onReturnToThread, | | |
| 721 | type: "button" as const, | | |
| 722 | }), | | |
| 723 | ] | | |
| 724 | : []), | | |
| 725 | withNativeGlassHeaderItem({ | | |
| 726 | accessibilityLabel: panes.primarySidebarVisible | | |
| 727 | ? "Maximize content" | | |
| 728 | : "Show thread sidebar", | | |
| 729 | icon: { | | |
| 730 | name: panes.primarySidebarVisible ? "arrow.up.left.and.arrow.down.right" : "sidebar.left", | | |
| 731 | type: "sfSymbol" as const, | | |
| 732 | }, | | |
| 733 | identifier: "thread-left-sidebar", | | |
| 734 | onPress: togglePrimarySidebar, | | |
| 735 | type: "button" as const, | | |
| 736 | }), | | |
| 737 | withNativeGlassHeaderItem({ | | |
| 738 | accessibilityLabel: "New task", | | |
| 739 | icon: { name: "square.and.pencil", type: "sfSymbol" as const }, | | |
| 740 | identifier: "thread-left-new-task", | | |
| 741 | onPress: () => navigation.navigate("NewTaskSheet", { screen: "NewTask" }), | | |
| 742 | type: "button" as const, | | |
| 743 | }), | | |
| 744 | ], | | |
| 745 | [panes.primarySidebarVisible, props.onReturnToThread, navigation, togglePrimarySidebar], | | |
| 746 | ); | | |
| 747 | const androidHeaderActions = useMemo<ReadonlyArray<AndroidHeaderAction>>(() => { | | |
| 748 | if (Platform.OS !== "android") return []; | | |
| 749 | | | |
| 750 | const actions: AndroidHeaderAction[] = []; | | |
| 751 | if (props.onReturnToThread) { | | |
| 752 | actions.push({ | | |
| 753 | accessibilityLabel: "Return to chat", | | |
| 754 | icon: "chevron.left", | | |
| 755 | onPress: props.onReturnToThread, | | |
| 756 | }); | | |
| 757 | } | | |
| 758 | if (selectedThreadCwd !== null) { | | |
| 759 | const filesVisible = inspectorMode === "files" && panes.auxiliaryPaneVisible; | | |
| 760 | actions.push({ | | |
| 761 | accessibilityLabel: filesVisible ? "Close files" : "Open files", | | |
| 762 | selected: filesVisible, | | |
| 763 | icon: "folder", | | |
| 764 | onPress: filesVisible ? toggleAuxiliaryPane : handleOpenFilesInspector, | | |
| 765 | }); | | |
| 766 | } | | |
| 767 | if (selectedThreadProject?.workspaceRoot) { | | |
| 768 | actions.push({ | | |
| 769 | accessibilityLabel: "Open terminal", | | |
| 770 | icon: "terminal", | | |
| 771 | onPress: () => handleOpenTerminal(null), | | |
| 772 | }); | | |
| 773 | } | | |
| 774 | actions.push({ | | |
| 775 | accessibilityLabel: "Open git controls", | | |
| 776 | icon: "point.topleft.down.curvedto.point.bottomright.up", | | |
| 777 | onPress: handleOpenGitInspector, | | |
| 778 | }); | | |
| 779 | return actions; | | |
| 780 | }, [ | | |
| 781 | inspectorMode, | | |
| 782 | panes.auxiliaryPaneVisible, | | |
| 783 | handleOpenFilesInspector, | | |
| 784 | handleOpenTerminal, | | |
| 785 | handleOpenGitInspector, | | |
| 786 | toggleAuxiliaryPane, | | |
| 787 | props.onReturnToThread, | | |
| 788 | selectedThreadCwd, | | |
| 789 | selectedThreadProject?.workspaceRoot, | | |
| 790 | ]); | | |
| 791 | | | |
| 792 | const handleEditFailedCreation = useCallback(async () => { | 785 | const handleEditFailedCreation = useCallback(async () => { |
| 793 | const creation = selectedThreadCreation?.message; | 786 | const creation = selectedThreadCreation?.message; |
| 794 | if (!creation?.creation || routeThreadIdentity === null) { | 787 | if (!creation?.creation || routeThreadIdentity === null) { |
| ... | @@ -929,23 +922,6 @@ function ThreadRouteContent( | ... | @@ -929,23 +922,6 @@ function ThreadRouteContent( |
| 929 | preparingWorktree: selectedThreadCreation.message.creation?.workspaceMode === "worktree", | 922 | preparingWorktree: selectedThreadCreation.message.creation?.workspaceMode === "worktree", |
| 930 | }; | 923 | }; |
| 931 | })(); | 924 | })(); |
| 932 | // Deep links / cold starts land with Thread as the ONLY route, where the | | |
| 933 | // native back button does not render. Provide an explicit Home escape for | | |
| 934 | // that case; when history exists the native back button is used instead. | | |
| 935 | const canGoBack = navigation.canGoBack(); | | |
| 936 | const compactHomeHeaderItems = useMemo<NativeHeaderItems>( | | |
| 937 | () => [ | | |
| 938 | withNativeGlassHeaderItem({ | | |
| 939 | accessibilityLabel: "Go to threads list", | | |
| 940 | icon: { name: "list.bullet", type: "sfSymbol" as const }, | | |
| 941 | identifier: "thread-left-home", | | |
| 942 | onPress: () => navigation.dispatch(StackActions.replace("Home")), | | |
| 943 | type: "button" as const, | | |
| 944 | }), | | |
| 945 | ], | | |
| 946 | [navigation], | | |
| 947 | ); | | |
| 948 | | | |
| 949 | if (!environmentId || !threadId) { | 925 | if (!environmentId || !threadId) { |
| 950 | return <OpeningThreadLoadingScreen />; | 926 | return <OpeningThreadLoadingScreen />; |
| 951 | } | 927 | } |
| ... | @@ -967,10 +943,8 @@ function ThreadRouteContent( | ... | @@ -967,10 +943,8 @@ function ThreadRouteContent( |
| 967 | connectionState: routeConnectionState, | 943 | connectionState: routeConnectionState, |
| 968 | }); | 944 | }); |
| 969 | const serverConfig = routeEnvironmentRuntime?.serverConfig ?? null; | 945 | const serverConfig = routeEnvironmentRuntime?.serverConfig ?? null; |
| 970 | const renderThreadRouteBody = (showActionControls: boolean) => ( | 946 | const renderThreadRouteBody = () => ( |
| 971 | <> | 947 | <> |
| 972 | <ThreadGitControls {...threadGitControlProps} showActionControls={showActionControls} /> | | |
| 973 | | | |
| 974 | <GitActionProgressOverlay progress={gitActionProgress} onDismiss={dismissGitActionResult} /> | 948 | <GitActionProgressOverlay progress={gitActionProgress} onDismiss={dismissGitActionResult} /> |
| 975 | | 949 | |
| 976 | <View | 950 | <View |
| ... | @@ -1069,84 +1043,23 @@ function ThreadRouteContent( | ... | @@ -1069,84 +1043,23 @@ function ThreadRouteContent( |
| 1069 | return ( | 1043 | return ( |
| 1070 | <> | 1044 | <> |
| 1071 | {activeInspectorRenderer ? <InspectorPaneRoleActivation /> : null} | 1045 | {activeInspectorRenderer ? <InspectorPaneRoleActivation /> : null} |
| 1072 | <NativeStackScreenOptions | 1046 | <ThreadHeader |
| 1073 | optionsVersion={threadGitControlProps.projectScripts} | 1047 | title={selectedThread.title} |
| 1074 | options={{ | 1048 | subtitle={headerSubtitle} |
| 1075 | // Android draws its own in-flow header (AndroidScreenHeader below); | 1049 | headerColor={headerColor} |
| 1076 | // the native stack header stays iOS-only. | 1050 | usesNativeHeaderGlass={usesNativeHeaderGlass} |
| 1077 | headerShown: Platform.OS !== "android", | 1051 | gitControls={threadGitControlProps} |
| 1078 | headerTitle: selectedThread.title, | 1052 | hasThreadCwd={selectedThreadCwd !== null} |
| 1079 | headerTitleStyle: usesNativeHeaderGlass | 1053 | hasWorkspaceRoot={Boolean(selectedThreadProject?.workspaceRoot)} |
| 1080 | ? { | 1054 | fileInspectorSupported={fileInspector.supported} |
| 1081 | fontSize: 17, | 1055 | inspectorMode={inspectorMode} |
| 1082 | fontWeight: "800", | 1056 | onToggleInspector={handleToggleInspector} |
| 1083 | } | 1057 | onOpenGitInspector={handleOpenGitInspector} |
| 1084 | : undefined, | 1058 | onOpenFilesInspector={handleOpenFilesInspector} |
| 1085 | title: selectedThread.title, | 1059 | onReturnToThread={props.onReturnToThread} |
| 1086 | headerBackVisible: !layout.usesSplitView, | | |
| 1087 | // Compact uses the NATIVE back button when a previous route exists; | | |
| 1088 | // deep links / cold starts get an explicit Home button instead. | | |
| 1089 | // Split view always uses its custom left items. | | |
| 1090 | unstable_headerLeftItems: | | |
| 1091 | Platform.OS === "ios" | | |
| 1092 | ? layout.usesSplitView | | |
| 1093 | ? () => splitLeftHeaderItems | | |
| 1094 | : canGoBack | | |
| 1095 | ? undefined | | |
| 1096 | : () => compactHomeHeaderItems | | |
| 1097 | : undefined, | | |
| 1098 | // Search lives in the persistent sidebar, so the split header keeps | | |
| 1099 | // the git controls on the RIGHT (no center items — center space is | | |
| 1100 | // reserved for future breadcrumbs/status). | | |
| 1101 | unstable_headerRightItems: | | |
| 1102 | Platform.OS === "ios" | | |
| 1103 | ? () => (layout.usesSplitView ? threadCenterHeaderItems : compactRightHeaderItems) | | |
| 1104 | : undefined, | | |
| 1105 | unstable_headerSubtitle: usesNativeHeaderGlass ? headerSubtitle : undefined, | | |
| 1106 | contentStyle: | | |
| 1107 | Platform.OS === "android" && true ? { backgroundColor: headerColor } : undefined, | | |
| 1108 | }} | | |
| 1109 | /> | 1060 | /> |
| 1110 | | 1061 | |
| 1111 | {Platform.OS === "android" ? ( | 1062 | {renderThreadRouteBody()} |
| 1112 | <AndroidScreenHeader | | |
| 1113 | title={selectedThread.title} | | |
| 1114 | subtitle={headerSubtitle} | | |
| 1115 | leading={<AndroidWorkspaceSidebarButton />} | | |
| 1116 | trailing={ | | |
| 1117 | fileInspector.supported && selectedThreadCwd !== null ? ( | | |
| 1118 | <AndroidHeaderIconButton | | |
| 1119 | accessibilityLabel={ | | |
| 1120 | inspectorMode !== null && panes.auxiliaryPaneVisible | | |
| 1121 | ? "Hide inspector" | | |
| 1122 | : "Show inspector" | | |
| 1123 | } | | |
| 1124 | icon="sidebar.right" | | |
| 1125 | selected={inspectorMode !== null && panes.auxiliaryPaneVisible} | | |
| 1126 | onPress={handleToggleInspector} | | |
| 1127 | /> | | |
| 1128 | ) : null | | |
| 1129 | } | | |
| 1130 | onBack={ | | |
| 1131 | layout.usesSplitView | | |
| 1132 | ? undefined | | |
| 1133 | : () => { | | |
| 1134 | // A deep link or cold start has no previous route; Home is the way out. | | |
| 1135 | // Read the history at press time: it changes without re-rendering this screen. | | |
| 1136 | if (navigation.canGoBack()) navigation.goBack(); | | |
| 1137 | else navigation.dispatch(StackActions.replace("Home")); | | |
| 1138 | } | | |
| 1139 | } | | |
| 1140 | actions={androidHeaderActions} | | |
| 1141 | hideBottomBorder | | |
| 1142 | /> | | |
| 1143 | ) : null} | | |
| 1144 | | | |
| 1145 | {/* Android surfaces the git/files/inspector actions in its in-flow | | |
| 1146 | header above, so the fallback action toolbar stays iOS-only. */} | | |
| 1147 | {renderThreadRouteBody( | | |
| 1148 | Platform.OS !== "android" && !layout.usesSplitView && !usesNativeHeaderGlass, | | |
| 1149 | )} | | |
| 1150 | </> | 1063 | </> |
| 1151 | ); | 1064 | ); |
| 1152 | } | 1065 | } |