Merge branch 'codex/ui-tight-layout'

This commit is contained in:
Haitao Pan 2026-03-24 12:20:07 +08:00
commit 7c28c1e020
2 changed files with 90 additions and 10 deletions

View File

@ -25,6 +25,9 @@ import '../../widgets/surface_card.dart';
const double _assistantComposerDefaultInputHeight = 78;
const double _assistantWorkspaceMinConversationHeight = 180;
const double _assistantWorkspaceMinLowerPaneHeight = 124;
const double _assistantHorizontalResizeHandleWidth = 6;
const double _assistantHorizontalPaneGap = 2;
const double _assistantVerticalResizeHandleHeight = 10;
class AssistantPage extends StatefulWidget {
const AssistantPage({
@ -294,7 +297,7 @@ class _AssistantPageState extends State<AssistantPage> {
),
if (!_sidePaneCollapsed)
SizedBox(
width: 6,
width: _assistantHorizontalResizeHandleWidth,
child: PaneResizeHandle(
axis: Axis.horizontal,
onDelta: (delta) {
@ -306,7 +309,7 @@ class _AssistantPageState extends State<AssistantPage> {
},
),
),
const SizedBox(width: 2),
const SizedBox(width: _assistantHorizontalPaneGap),
Expanded(child: mainWorkspace),
],
);
@ -344,7 +347,7 @@ class _AssistantPageState extends State<AssistantPage> {
),
),
SizedBox(
width: 6,
width: _assistantHorizontalResizeHandleWidth,
child: PaneResizeHandle(
axis: Axis.horizontal,
onDelta: (delta) {
@ -356,7 +359,7 @@ class _AssistantPageState extends State<AssistantPage> {
},
),
),
const SizedBox(width: 2),
const SizedBox(width: _assistantHorizontalPaneGap),
Expanded(child: mainWorkspace),
],
);
@ -376,6 +379,10 @@ class _AssistantPageState extends State<AssistantPage> {
builder: (context, constraints) {
final baseComposerHeight = constraints.maxHeight >= 900 ? 180.0 : 152.0;
final composerContentWidth = math.max(240.0, constraints.maxWidth - 32);
final availableWorkspaceHeight = math.max(
0.0,
constraints.maxHeight - _assistantVerticalResizeHandleHeight,
);
final attachmentExtraHeight = _estimatedComposerWrapSectionHeight(
itemCount: _attachments.length,
availableWidth: composerContentWidth,
@ -387,20 +394,20 @@ class _AssistantPageState extends State<AssistantPage> {
averageChipWidth: 132,
);
final defaultComposerHeight = math.min(
math.max(0.0, constraints.maxHeight - 2),
availableWorkspaceHeight,
baseComposerHeight +
math.max(
0,
0.0,
_composerInputHeight - _assistantComposerDefaultInputHeight,
) +
attachmentExtraHeight +
selectedSkillExtraHeight,
);
final composerHeightUpperBound = math.min(
math.max(0.0, constraints.maxHeight - 2),
availableWorkspaceHeight,
math.max(
_assistantWorkspaceMinLowerPaneHeight,
constraints.maxHeight - _assistantWorkspaceMinConversationHeight,
availableWorkspaceHeight - _assistantWorkspaceMinConversationHeight,
),
);
final composerHeightLowerBound = math.min(
@ -435,7 +442,7 @@ class _AssistantPageState extends State<AssistantPage> {
),
SizedBox(
key: const Key('assistant-workspace-resize-handle'),
height: 10,
height: _assistantVerticalResizeHandleHeight,
child: PaneResizeHandle(
axis: Axis.vertical,
onDelta: (delta) {
@ -1305,7 +1312,11 @@ class _AssistantPageState extends State<AssistantPage> {
double _resolveMaxSidePaneWidth(double viewportWidth) {
final maxWidthByViewport =
viewportWidth - _mainWorkspaceMinWidth - _sidePaneViewportPadding;
viewportWidth -
_mainWorkspaceMinWidth -
_sidePaneViewportPadding -
_assistantHorizontalResizeHandleWidth -
_assistantHorizontalPaneGap;
return maxWidthByViewport
.clamp(_sidePaneMinWidth, viewportWidth - _sidePaneViewportPadding)
.toDouble();

View File

@ -19,6 +19,7 @@ import 'package:xworkmate/runtime/runtime_coordinator.dart';
import 'package:xworkmate/runtime/runtime_models.dart';
import 'package:xworkmate/runtime/secure_config_store.dart';
import 'package:xworkmate/theme/app_theme.dart';
import 'package:xworkmate/widgets/pane_resize_handle.dart';
import '../test_support.dart';
@ -573,6 +574,74 @@ void main() {
expect(expandedConversationHeight, greaterThan(initialConversationHeight));
});
testWidgets(
'AssistantPage keeps all three panes tightly packed after resize',
(WidgetTester tester) async {
final controller = await createTestController(tester);
await pumpPage(
tester,
child: AssistantPage(controller: controller, onOpenDetail: (_) {}),
platform: TargetPlatform.macOS,
);
final pageRect = tester.getRect(find.byType(AssistantPage));
final taskRail = find.byKey(const Key('assistant-task-rail'));
final horizontalHandle = find.byType(PaneResizeHandle).first;
final verticalHandle = find.byKey(
const Key('assistant-workspace-resize-handle'),
);
final conversationShell = find.byKey(
const Key('assistant-conversation-shell'),
);
final composerShell = find.byKey(const Key('assistant-composer-shell'));
await tester.drag(horizontalHandle, const Offset(360, 0));
await tester.pumpAndSettle();
await tester.drag(verticalHandle, const Offset(0, 260));
await tester.pumpAndSettle();
final taskRailRect = tester.getRect(taskRail);
final horizontalHandleRect = tester.getRect(horizontalHandle);
final conversationRect = tester.getRect(conversationShell);
final verticalHandleRect = tester.getRect(verticalHandle);
final composerRect = tester.getRect(composerShell);
expect(taskRailRect.left, moreOrLessEquals(pageRect.left, epsilon: 0.01));
expect(
taskRailRect.right,
moreOrLessEquals(horizontalHandleRect.left, epsilon: 0.01),
);
expect(
horizontalHandleRect.right,
moreOrLessEquals(conversationRect.left, epsilon: 2.01),
);
expect(
conversationRect.top,
moreOrLessEquals(pageRect.top, epsilon: 0.01),
);
expect(
conversationRect.bottom,
moreOrLessEquals(verticalHandleRect.top, epsilon: 0.01),
);
expect(
verticalHandleRect.bottom,
moreOrLessEquals(composerRect.top, epsilon: 0.01),
);
expect(
composerRect.bottom,
moreOrLessEquals(pageRect.bottom, epsilon: 0.01),
);
expect(
composerRect.right,
moreOrLessEquals(pageRect.right, epsilon: 0.01),
);
expect(conversationRect.width, greaterThan(620));
expect(conversationRect.height, greaterThanOrEqualTo(180));
expect(composerRect.height, greaterThanOrEqualTo(124));
},
);
// Known flutter_tester host-exit hang in this widget scenario.
testWidgets(
'AssistantPage syncs task selection with execution target menu and connection chip',