| ... | @@ -2,6 +2,7 @@ import { makeTurnCommandMetadata } from "../../lib/commandMetadata"; | ... | @@ -2,6 +2,7 @@ import { makeTurnCommandMetadata } from "../../lib/commandMetadata"; |
| 2 | import { buildProjectThreadStartTurnInput } from "../../lib/projectThreadStartTurn"; | 2 | import { buildProjectThreadStartTurnInput } from "../../lib/projectThreadStartTurn"; |
| 3 | import { useWorktreeSetup } from "./use-worktree-setup"; | 3 | import { useWorktreeSetup } from "./use-worktree-setup"; |
| 4 | import { worktreeSetupAgentStarted } from "@t3tools/client-runtime/worktree-setup"; | 4 | import { worktreeSetupAgentStarted } from "@t3tools/client-runtime/worktree-setup"; |
| | 5 | import { ScreenHeader } from "../../components/ScreenHeader"; |
| 5 | import { | 6 | import { |
| 6 | StackActions, | 7 | StackActions, |
| 7 | useFocusEffect, | 8 | useFocusEffect, |
| ... | @@ -103,8 +104,50 @@ function firstRouteParam(value: string | string[] | undefined): string | null { | ... | @@ -103,8 +104,50 @@ function firstRouteParam(value: string | string[] | undefined): string | null { |
| 103 | return first === undefined || first.trim().length === 0 ? null : first; | 104 | return first === undefined || first.trim().length === 0 ? null : first; |
| 104 | } | 105 | } |
| 105 | | 106 | |
| | 107 | function ThreadPane(props: { readonly children: ReactNode }) { |
| | 108 | return ( |
| | 109 | <View className="flex-1 bg-screen android:overflow-hidden android:rounded-t-[28px] android:bg-thread-canvas"> |
| | 110 | {props.children} |
| | 111 | </View> |
| | 112 | ); |
| | 113 | } |
| | 114 | |
| | 115 | function ThreadRouteFallbackLayout(props: { readonly children: ReactNode }) { |
| | 116 | const navigation = useNavigation(); |
| | 117 | const { layout } = useAdaptiveWorkspaceLayout(); |
| | 118 | const { themeVariables } = useAppearancePreferences(); |
| | 119 | if (Platform.OS !== "android") return props.children; |
| | 120 | |
| | 121 | return ( |
| | 122 | <> |
| | 123 | <ScreenHeader |
| | 124 | title="Thread" |
| | 125 | options={{ contentStyle: { backgroundColor: themeVariables["--color-header"] } }} |
| | 126 | onBack={ |
| | 127 | layout.usesSplitView |
| | 128 | ? undefined |
| | 129 | : () => { |
| | 130 | if (navigation.canGoBack()) navigation.goBack(); |
| | 131 | else navigation.dispatch(StackActions.replace("Home")); |
| | 132 | } |
| | 133 | } |
| | 134 | hideBottomBorder |
| | 135 | /> |
| | 136 | <ThreadPane>{props.children}</ThreadPane> |
| | 137 | </> |
| | 138 | ); |
| | 139 | } |
| | 140 | |
| 106 | function OpeningThreadLoadingScreen() { | 141 | function OpeningThreadLoadingScreen() { |
| 107 | return <LoadingScreen message="Opening thread…" messagePlacement="above-spinner" />; | 142 | return ( |
| | 143 | <ThreadRouteFallbackLayout> |
| | 144 | <LoadingScreen |
| | 145 | message="Opening thread…" |
| | 146 | messagePlacement="above-spinner" |
| | 147 | embedded={Platform.OS === "android"} |
| | 148 | /> |
| | 149 | </ThreadRouteFallbackLayout> |
| | 150 | ); |
| 108 | } | 151 | } |
| 109 | | 152 | |
| 110 | type ThreadRouteScreenRouteProps = StaticScreenProps<{ | 153 | type ThreadRouteScreenRouteProps = StaticScreenProps<{ |
| ... | @@ -123,23 +166,25 @@ function ThreadUnavailableScreen(props: { | ... | @@ -123,23 +166,25 @@ function ThreadUnavailableScreen(props: { |
| 123 | readonly onAction: () => void; | 166 | readonly onAction: () => void; |
| 124 | }) { | 167 | }) { |
| 125 | return ( | 168 | return ( |
| 126 | <ScrollView | 169 | <ThreadRouteFallbackLayout> |
| 127 | contentInsetAdjustmentBehavior="automatic" | 170 | <ScrollView |
| 128 | contentContainerStyle={{ | 171 | contentInsetAdjustmentBehavior="automatic" |
| 129 | flexGrow: 1, | 172 | contentContainerStyle={{ |
| 130 | justifyContent: "center", | 173 | flexGrow: 1, |
| 131 | paddingHorizontal: 24, | 174 | justifyContent: "center", |
| 132 | paddingVertical: 32, | 175 | paddingHorizontal: 24, |
| 133 | }} | 176 | paddingVertical: 32, |
| 134 | className="bg-screen flex-1" | 177 | }} |
| 135 | > | 178 | className="bg-screen flex-1 android:bg-transparent" |
| 136 | <EmptyState | 179 | > |
| 137 | title="Thread unavailable" | 180 | <EmptyState |
| 138 | detail="This thread is not available in the current mobile snapshot." | 181 | title="Thread unavailable" |
| 139 | actionLabel={props.actionLabel} | 182 | detail="This thread is not available in the current mobile snapshot." |
| 140 | onAction={props.onAction} | 183 | actionLabel={props.actionLabel} |
| 141 | /> | 184 | onAction={props.onAction} |
| 142 | </ScrollView> | 185 | /> |
| | 186 | </ScrollView> |
| | 187 | </ThreadRouteFallbackLayout> |
| 143 | ); | 188 | ); |
| 144 | } | 189 | } |
| 145 | | 190 | |
| ... | @@ -931,7 +976,7 @@ function ThreadRouteContent( | ... | @@ -931,7 +976,7 @@ function ThreadRouteContent( |
| 931 | <> | 976 | <> |
| 932 | <GitActionProgressOverlay progress={gitActionProgress} onDismiss={dismissGitActionResult} /> | 977 | <GitActionProgressOverlay progress={gitActionProgress} onDismiss={dismissGitActionResult} /> |
| 933 | | 978 | |
| 934 | <View className="flex-1 bg-screen android:overflow-hidden android:rounded-t-[28px] android:bg-thread-canvas"> | 979 | <ThreadPane> |
| 935 | <ThreadDetailScreen | 980 | <ThreadDetailScreen |
| 936 | canOperateThread={canOperateThread} | 981 | canOperateThread={canOperateThread} |
| 937 | selectedThread={selectedThreadWithDraftSettings ?? selectedThread} | 982 | selectedThread={selectedThreadWithDraftSettings ?? selectedThread} |
| ... | @@ -1023,7 +1068,7 @@ function ThreadRouteContent( | ... | @@ -1023,7 +1068,7 @@ function ThreadRouteContent( |
| 1023 | onSubmitUserInput={requests.onSubmitUserInput} | 1068 | onSubmitUserInput={requests.onSubmitUserInput} |
| 1024 | onDismissUserInput={requests.onDismissUserInput} | 1069 | onDismissUserInput={requests.onDismissUserInput} |
| 1025 | /> | 1070 | /> |
| 1026 | </View> | 1071 | </ThreadPane> |
| 1027 | </> | 1072 | </> |
| 1028 | ); | 1073 | ); |
| 1029 | | 1074 | |