Fixed ~24px caret-line cells bookend the status bar (left=sidebar, right=context); chevron flips per arrangement.isCollapsed (inward=collapse, outward=expand) and fires the existing sidebar.collapse / context.collapse commands — the mouse affordance for the already keyboard/CLI-addressable action (D-6). Visual only; no new collapse logic. Status items shift 28px inward for the reserved cells. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
92 lines
3.5 KiB
Dart
92 lines
3.5 KiB
Dart
/// Status-bar collapse toggles (T-294): a fixed cell bookends each end of the
|
|
/// status bar, flips a caret-line chevron per arrangement.isCollapsed, and fires
|
|
/// the existing sidebar.collapse / context.collapse commands.
|
|
library;
|
|
|
|
import 'package:clide/app.dart';
|
|
import 'package:clide/builtin/default_layout/default_layout.dart';
|
|
import 'package:clide/extension/extension.dart';
|
|
import 'package:clide/kernel/kernel.dart';
|
|
import 'package:clide/widgets/widgets.dart';
|
|
import 'package:flutter/widgets.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
import 'helpers/kernel_fixture.dart';
|
|
|
|
Finder _icon(PhosphorIconPainter p) => find.byWidgetPredicate((w) => w is ClideIcon && w.painter == p);
|
|
|
|
Widget _bar(KernelFixture f) => Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: ClideKernel(
|
|
services: f.services,
|
|
child: ClideTheme(
|
|
controller: f.services.theme,
|
|
child: const MediaQuery(
|
|
data: MediaQueryData(size: Size(800, 200)),
|
|
child: Align(
|
|
alignment: Alignment.topLeft,
|
|
child: SizedBox(width: 800, height: 26, child: StatusbarHost()),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
void main() {
|
|
late KernelFixture f;
|
|
|
|
setUp(() async {
|
|
f = await KernelFixture.create();
|
|
f.services.arrangement.applyPreset(const LayoutPresetContribution(
|
|
id: 'test',
|
|
displayName: 'test',
|
|
slots: [
|
|
LayoutSlot(slot: Slots.sidebar, position: SlotPosition.left, visible: true),
|
|
LayoutSlot(slot: Slots.contextPanel, position: SlotPosition.right, visible: true),
|
|
],
|
|
));
|
|
f.services.extensions.register(DefaultLayoutExtension());
|
|
await f.services.extensions.activate('builtin.default-layout');
|
|
});
|
|
tearDown(() => f.dispose());
|
|
|
|
testWidgets('both toggles show, chevrons point inward when panes are open', (tester) async {
|
|
await tester.pumpWidget(_bar(f));
|
|
await tester.pump();
|
|
// Sidebar (left end) collapses leftward → caret-line-left; context (right
|
|
// end) collapses rightward → caret-line-right.
|
|
expect(_icon(PhosphorIcons.caretLineLeft), findsOneWidget);
|
|
expect(_icon(PhosphorIcons.caretLineRight), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('a collapsed pane flips its chevron outward (expand affordance)', (tester) async {
|
|
f.services.arrangement.setCollapsed(Slots.sidebar, true);
|
|
await tester.pumpWidget(_bar(f));
|
|
await tester.pump();
|
|
// Sidebar now collapsed → its chevron points right (expand); context still
|
|
// open → right. So two right-pointing, none left.
|
|
expect(_icon(PhosphorIcons.caretLineRight), findsNWidgets(2));
|
|
expect(_icon(PhosphorIcons.caretLineLeft), findsNothing);
|
|
});
|
|
|
|
testWidgets('tapping the sidebar toggle fires sidebar.collapse', (tester) async {
|
|
await tester.pumpWidget(_bar(f));
|
|
await tester.pump();
|
|
expect(f.services.arrangement.isCollapsed(Slots.sidebar), isFalse);
|
|
|
|
await tester.tap(_icon(PhosphorIcons.caretLineLeft)); // the open-sidebar toggle
|
|
await tester.pump();
|
|
|
|
expect(f.services.arrangement.isCollapsed(Slots.sidebar), isTrue);
|
|
});
|
|
|
|
testWidgets('a hidden pane reserves the cell but shows no toggle', (tester) async {
|
|
f.services.arrangement.setVisible(Slots.contextPanel, false);
|
|
await tester.pumpWidget(_bar(f));
|
|
await tester.pump();
|
|
// Sidebar toggle present (open → left); context hidden → no right chevron.
|
|
expect(_icon(PhosphorIcons.caretLineLeft), findsOneWidget);
|
|
expect(_icon(PhosphorIcons.caretLineRight), findsNothing);
|
|
});
|
|
}
|