From 06c2e76be4f6f5e678c5939c854b8659b1717db4 Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Fri, 12 Jun 2026 02:17:15 +0200 Subject: [PATCH] remove the dead ColumnHat widget; keep hatHeight (T-385) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ColumnHat was superseded by the hat bar in app.dart and survived only through a zero-coverage smoke test. Its file also carried the live hatHeight constant (D-57's 24px hats) consumed by the hat bar and the menu bar — that moves to widgets/src/chrome_metrics.dart. Co-Authored-By: Claude Fable 5 --- lib/widgets/src/chrome_metrics.dart | 11 ++ lib/widgets/src/clide_column_hat.dart | 124 ------------------- lib/widgets/widgets.dart | 2 +- test/widgets/zero_coverage_widgets_test.dart | 38 +----- 4 files changed, 13 insertions(+), 162 deletions(-) create mode 100644 lib/widgets/src/chrome_metrics.dart delete mode 100644 lib/widgets/src/clide_column_hat.dart diff --git a/lib/widgets/src/chrome_metrics.dart b/lib/widgets/src/chrome_metrics.dart new file mode 100644 index 00000000..b2c3d4ef --- /dev/null +++ b/lib/widgets/src/chrome_metrics.dart @@ -0,0 +1,11 @@ +/// Shared window-chrome metrics. +/// +/// `hatHeight` used to live in clide_column_hat.dart; the per-column +/// `ColumnHat` widget there was dead (duplicated by the hat bar in +/// app.dart, kept alive only by a zero-coverage test) and was removed +/// in the T-385 sweep — the constant is the part the live chrome +/// (app.dart hat bar, menu bar) actually consumes (D-57). +library; + +/// Height of the per-column 24px window hats (D-57). +const double hatHeight = 24; diff --git a/lib/widgets/src/clide_column_hat.dart b/lib/widgets/src/clide_column_hat.dart deleted file mode 100644 index d542c059..00000000 --- a/lib/widgets/src/clide_column_hat.dart +++ /dev/null @@ -1,124 +0,0 @@ -import 'dart:io' show Platform; - -import 'package:clide/clide.dart' show clideName; -import 'package:clide/kernel/src/theme/controller.dart'; -import 'package:clide/kernel/src/theme/tokens.dart'; -import 'package:clide/kernel/src/window_controls.dart'; -import 'package:clide/widgets/src/clide_icon.dart'; -import 'package:clide/widgets/src/clide_tappable.dart'; -import 'package:clide/widgets/src/clide_text.dart'; -import 'package:clide/widgets/src/icons/phosphor.dart'; -import 'package:clide/widgets/src/typography.dart'; -import 'package:flutter/foundation.dart' show kIsWeb; -import 'package:flutter/widgets.dart'; - -const double hatHeight = 24; - -class ColumnHat extends StatelessWidget { - const ColumnHat._({required this.position, required this.windowControls, this.projectLabel, this.branchLabel}); - - final HatPosition position; - final WindowControls windowControls; - final String? projectLabel; - final String? branchLabel; - - factory ColumnHat.left({required WindowControls windowControls}) => ColumnHat._(position: HatPosition.left, windowControls: windowControls); - - factory ColumnHat.center({required WindowControls windowControls, String? project, String? branch}) => - ColumnHat._(position: HatPosition.center, windowControls: windowControls, projectLabel: project, branchLabel: branch); - - factory ColumnHat.right({required WindowControls windowControls}) => ColumnHat._(position: HatPosition.right, windowControls: windowControls); - - @override - Widget build(BuildContext context) { - final tokens = ClideTheme.of(context).surface; - return GestureDetector( - onPanStart: (_) => windowControls.startDrag(), - child: Container( - height: hatHeight, - color: tokens.panelHeader, - child: switch (position) { - HatPosition.left => _LeftContent(tokens: tokens, wc: windowControls), - HatPosition.center => _CenterContent(tokens: tokens, project: projectLabel, branch: branchLabel), - HatPosition.right => _RightContent(tokens: tokens, wc: windowControls), - }, - ), - ); - } -} - -enum HatPosition { left, center, right } - -class _LeftContent extends StatelessWidget { - const _LeftContent({required this.tokens, required this.wc}); - final SurfaceTokens tokens; - final WindowControls wc; - - @override - Widget build(BuildContext context) { - // On macOS the native titlebar draws traffic lights; skip duplicates. - return const SizedBox.expand(); - } -} - -class _CenterContent extends StatelessWidget { - const _CenterContent({required this.tokens, this.project, this.branch}); - final SurfaceTokens tokens; - final String? project; - final String? branch; - - @override - Widget build(BuildContext context) { - final parts = []; - if (project != null) parts.add(project!); - if (branch != null) parts.add(branch!); - final label = parts.isEmpty ? clideName : parts.join(' > '); - return Center( - child: ClideText(label, fontSize: 12, color: tokens.globalTextMuted, fontFamily: clideMonoFamily), - ); - } -} - -class _RightContent extends StatelessWidget { - const _RightContent({required this.tokens, required this.wc}); - final SurfaceTokens tokens; - final WindowControls wc; - - @override - Widget build(BuildContext context) { - if (kIsWeb) return const SizedBox.expand(); - final isMac = !kIsWeb && Platform.isMacOS; - if (isMac) return const SizedBox.expand(); - return Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - _WinButton(icon: const PhosphorIconPainter(0xe32a), onTap: wc.minimize, tokens: tokens), - _WinButton(icon: const PhosphorIconPainter(0xe45e), onTap: wc.toggleMaximize, tokens: tokens), - _WinButton(icon: PhosphorIcons.byName('x'), onTap: wc.close, tokens: tokens, isClose: true), - ], - ); - } -} - -class _WinButton extends StatelessWidget { - const _WinButton({required this.icon, required this.onTap, required this.tokens, this.isClose = false}); - final ClideIconPainter icon; - final VoidCallback onTap; - final SurfaceTokens tokens; - final bool isClose; - - @override - Widget build(BuildContext context) { - final hoverBg = isClose ? tokens.windowControlCloseHoverBackground : tokens.listItemHoverBackground; - return ClideTappable( - onTap: onTap, - builder: (context, hovered, _) => Container( - width: 36, - height: hatHeight, - color: hovered ? hoverBg : null, - alignment: Alignment.center, - child: ClideIcon(icon, size: 14, color: hovered && isClose ? tokens.windowControlCloseHoverForeground : tokens.globalTextMuted), - ), - ); - } -} diff --git a/lib/widgets/widgets.dart b/lib/widgets/widgets.dart index fff028de..4ca25380 100644 --- a/lib/widgets/widgets.dart +++ b/lib/widgets/widgets.dart @@ -5,12 +5,12 @@ /// Flutter chrome widgets directly. library; +export 'src/chrome_metrics.dart'; export 'src/clide_accordion.dart'; export 'src/clide_anchored.dart'; export 'src/clide_button.dart'; export 'src/clide_card_metrics.dart'; export 'src/clide_collapser_card.dart'; -export 'src/clide_column_hat.dart'; export 'src/clide_code_block.dart'; export 'src/clide_divider.dart'; export 'src/clide_file_image.dart'; diff --git a/test/widgets/zero_coverage_widgets_test.dart b/test/widgets/zero_coverage_widgets_test.dart index fe4ba756..637ca297 100644 --- a/test/widgets/zero_coverage_widgets_test.dart +++ b/test/widgets/zero_coverage_widgets_test.dart @@ -1,11 +1,10 @@ /// Smoke + branch tests for the previously-uncovered widgets under -/// `lib/widgets/src/`: ClidePalette, ClideFilterBox, ColumnHat, +/// `lib/widgets/src/`: ClidePalette, ClideFilterBox, /// ClideIconRail, ClideSpine, ClideResizeBorder. library; import 'package:clide/clide.dart'; import 'package:clide/extension/extension.dart'; -import 'package:clide/widgets/src/clide_column_hat.dart'; import 'package:clide/widgets/src/clide_filter_box.dart'; import 'package:clide/widgets/src/clide_icon.dart'; import 'package:clide/widgets/src/clide_icon_rail.dart'; @@ -311,41 +310,6 @@ void main() { }); }); - group('ColumnHat', () { - late KernelFixture f; - setUp(() async => f = await KernelFixture.create()); - tearDown(() async => f.dispose()); - - testWidgets('left / center / right factories render', (tester) async { - final wc = WindowControls(); - addTearDown(wc.dispose); - await tester.pumpWidget( - harness( - f, - Column( - children: [ - SizedBox(width: 200, child: ColumnHat.left(windowControls: wc)), - SizedBox( - width: 200, - child: ColumnHat.center(windowControls: wc, project: 'clide', branch: 'main'), - ), - SizedBox(width: 200, child: ColumnHat.right(windowControls: wc)), - ], - ), - ), - ); - // Center hat renders the joined label. - expect(find.text('clide > main'), findsOneWidget); - }); - - testWidgets('center hat falls back to "clide" with no project/branch', (tester) async { - final wc = WindowControls(); - addTearDown(wc.dispose); - await tester.pumpWidget(harness(f, SizedBox(width: 200, child: ColumnHat.center(windowControls: wc)))); - expect(find.text('clide'), findsOneWidget); - }); - }); - group('ClideIconRail', () { late KernelFixture f; setUp(() async => f = await KernelFixture.create());