diff --git a/lib/widgets/bottom_sheet_header.dart b/lib/widgets/bottom_sheet_header.dart index 24c75c39..0f89ab32 100644 --- a/lib/widgets/bottom_sheet_header.dart +++ b/lib/widgets/bottom_sheet_header.dart @@ -65,15 +65,19 @@ class BottomSheetHeader extends StatelessWidget { @override Widget build(BuildContext context) { + final usesBackButton = leading == null && onBack != null; + // Determine the leading widget based on priority: leading > onBack > icon Widget? resolvedLeading; if (leading != null) { resolvedLeading = leading; } else if (onBack != null) { - resolvedLeading = ExcludeFocusTraversal( - child: IconButton( - icon: AppIcon(Symbols.arrow_back_rounded, fill: 1, color: iconColor), - onPressed: onBack, + resolvedLeading = SizedBox( + width: 24, + height: kMinInteractiveDimension, + child: Align( + alignment: Alignment.centerLeft, + child: ExcludeSemantics(child: AppIcon(Symbols.arrow_back_rounded, fill: 1, color: iconColor)), ), ); } else if (icon != null) { @@ -89,18 +93,40 @@ class BottomSheetHeader extends StatelessWidget { border: Border(bottom: BorderSide(color: Theme.of(context).dividerColor)), ) : null, - child: Row( + child: Stack( children: [ - if (resolvedLeading != null) ...[resolvedLeading, const SizedBox(width: 8)], - Expanded(child: Text(title, style: effectiveTitleStyle)), - ?action, - ExcludeFocusTraversal( - child: IconButton( - focusNode: closeFocusNode, - icon: AppIcon(Symbols.close_rounded, fill: 1, color: iconColor), - onPressed: onClose ?? () => OverlaySheetController.closeAdaptive(context), - ), + Row( + children: [ + if (resolvedLeading != null) ...[resolvedLeading, const SizedBox(width: 8)], + Expanded(child: Text(title, style: effectiveTitleStyle)), + ?action, + ExcludeFocusTraversal( + child: IconButton( + focusNode: closeFocusNode, + icon: AppIcon(Symbols.close_rounded, fill: 1, color: iconColor), + onPressed: onClose ?? () => OverlaySheetController.closeAdaptive(context), + ), + ), + ], ), + if (usesBackButton) + PositionedDirectional( + start: 0, + top: 0, + bottom: 0, + width: kMinInteractiveDimension, + child: ExcludeFocusTraversal( + child: Semantics( + label: MaterialLocalizations.of(context).backButtonTooltip, + button: true, + child: InkResponse( + onTap: onBack, + radius: kMinInteractiveDimension / 2, + child: const SizedBox.expand(), + ), + ), + ), + ), ], ), ); diff --git a/test/widgets/bottom_sheet_header_test.dart b/test/widgets/bottom_sheet_header_test.dart new file mode 100644 index 00000000..d145754c --- /dev/null +++ b/test/widgets/bottom_sheet_header_test.dart @@ -0,0 +1,34 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:material_symbols_icons/symbols.dart'; +import 'package:plezy/widgets/bottom_sheet_header.dart'; + +void main() { + testWidgets('back arrow aligns with regular leading icons', (tester) async { + var backPressed = false; + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: Column( + children: [ + BottomSheetHeader(title: 'Back', onBack: () => backPressed = true), + const BottomSheetHeader(title: 'Icon', icon: Symbols.filter_alt_rounded), + ], + ), + ), + ), + ); + + final backArrow = find.byWidgetPredicate((widget) => widget is Icon && widget.icon == Symbols.arrow_back_rounded); + final regularIcon = find.byWidgetPredicate((widget) => widget is Icon && widget.icon == Symbols.filter_alt_rounded); + + expect(backArrow, findsOneWidget); + expect(regularIcon, findsOneWidget); + expect(tester.getTopLeft(backArrow).dx, tester.getTopLeft(regularIcon).dx); + expect(tester.getTopLeft(find.text('Back')).dx, tester.getTopLeft(find.text('Icon')).dx); + + await tester.tapAt(tester.getCenter(backArrow) + const Offset(28, 0)); + expect(backPressed, isTrue); + }); +}