From a3dfd3cef17bb7dd439cf918fc2a8ebf7b9df1bc Mon Sep 17 00:00:00 2001 From: mikecoomber Date: Tue, 15 Oct 2024 14:14:40 +0100 Subject: [PATCH 1/7] removed extended search appbar, changed behaviour to close search --- .../pages/components/top_app_bar_example.dart | 78 +------- .../components/top_app_bar_widgetbook.dart | 2 +- .../screen_header_bar/screen_header_bar.dart | 2 +- .../top_app_bar/extended_top_app_bar.dart | 50 +++-- .../top_app_bar/search_top_app_bar.dart | 10 +- .../components/top_app_bar/top_app_bar.dart | 178 ++++++++++++------ 6 files changed, 150 insertions(+), 170 deletions(-) diff --git a/example/lib/pages/components/top_app_bar_example.dart b/example/lib/pages/components/top_app_bar_example.dart index 6adc0827..5c5d30fe 100644 --- a/example/lib/pages/components/top_app_bar_example.dart +++ b/example/lib/pages/components/top_app_bar_example.dart @@ -15,20 +15,7 @@ class TopAppBarExample extends StatefulWidget { } class _TopAppBarExampleState extends State { - final _searchControllerExtended = ZetaSearchController(); - final _searchControllerRegular = ZetaSearchController(); - - void _showHideSearchExtended() { - _searchControllerExtended.isEnabled - ? _searchControllerExtended.closeSearch() - : _searchControllerExtended.startSearch(); - } - - void _showHideSearchRegular() { - _searchControllerRegular.isEnabled - ? _searchControllerRegular.closeSearch() - : _searchControllerRegular.startSearch(); - } + final _searchController = ZetaSearchController(); @override Widget build(BuildContext context) { @@ -78,8 +65,7 @@ class _TopAppBarExampleState extends State { ], ), Text('Centered', style: ZetaTextStyles.titleLarge), - ZetaTopAppBar( - type: ZetaTopAppBarType.centeredTitle, + ZetaTopAppBar.centered( leading: IconButton( onPressed: () {}, icon: ZetaIcon(Icons.menu), @@ -119,24 +105,20 @@ class _TopAppBarExampleState extends State { ], ), Text('Search', style: ZetaTextStyles.titleLarge), - ZetaTopAppBar( - type: ZetaTopAppBarType.centeredTitle, - leading: BackButton(), + ZetaTopAppBar.search( + leading: IconButton( + onPressed: () {}, + icon: ZetaIcon(Icons.menu), + ), title: Text("Title"), - actions: [ - IconButton( - onPressed: _showHideSearchRegular, - icon: ZetaIcon(ZetaIcons.search), - ) - ], - searchController: _searchControllerRegular, + searchController: _searchController, onSearch: (text) => debugPrint('search text: $text'), onSearchMicrophoneIconPressed: () async { var sampleTexts = ['This is a sample text', 'Another sample', 'Speech recognition text', 'Example']; var generatedText = sampleTexts[Random().nextInt(sampleTexts.length)]; - _searchControllerRegular.text = generatedText; + _searchController.text = generatedText; }, ), Text('Extended', style: ZetaTextStyles.titleLarge), @@ -188,48 +170,6 @@ class _TopAppBarExampleState extends State { ], ), ), - Text('Extended Search', style: ZetaTextStyles.titleLarge), - SizedBox( - width: 800, - height: 200, - child: CustomScrollView( - slivers: [ - ZetaTopAppBar.extended( - leading: BackButton(), - title: Text("Title"), - actions: [ - IconButton( - onPressed: _showHideSearchExtended, - icon: ZetaIcon(ZetaIcons.search), - ) - ], - searchController: _searchControllerExtended, - onSearch: (text) => debugPrint('search text: $text'), - onSearchMicrophoneIconPressed: () async { - var sampleTexts = [ - 'This is a sample text', - 'Another sample', - 'Speech recognition text', - 'Example' - ]; - var generatedText = sampleTexts[Random().nextInt(sampleTexts.length)]; - _searchControllerExtended.text = generatedText; - }, - ), - SliverToBoxAdapter( - child: Container( - width: 800, - height: 800, - color: Zeta.of(context).colors.surfaceSelectedHover, - child: CustomPaint( - painter: Painter(context: context), - size: Size(800, 800), - ), - ), - ), - ], - ), - ), ].gap(20), ), ), diff --git a/example/widgetbook/pages/components/top_app_bar_widgetbook.dart b/example/widgetbook/pages/components/top_app_bar_widgetbook.dart index 96f80616..ea4ba12a 100644 --- a/example/widgetbook/pages/components/top_app_bar_widgetbook.dart +++ b/example/widgetbook/pages/components/top_app_bar_widgetbook.dart @@ -53,7 +53,7 @@ Widget defaultTopAppBarUseCase(BuildContext context) { icon: ZetaIcon(ZetaIcons.more_vertical), ) ] - : null, + : [], ), ], )); diff --git a/lib/src/components/screen_header_bar/screen_header_bar.dart b/lib/src/components/screen_header_bar/screen_header_bar.dart index 544eefe6..4212abf0 100644 --- a/lib/src/components/screen_header_bar/screen_header_bar.dart +++ b/lib/src/components/screen_header_bar/screen_header_bar.dart @@ -50,7 +50,7 @@ class ZetaScreenHeaderBar extends ZetaStatelessWidget { title: title, titleTextStyle: ZetaTextStyles.titleLarge, actions: actionButtonLabel == null - ? null + ? [] : [ ZetaButton( label: actionButtonLabel!, diff --git a/lib/src/components/top_app_bar/extended_top_app_bar.dart b/lib/src/components/top_app_bar/extended_top_app_bar.dart index b2577646..c6a8d289 100644 --- a/lib/src/components/top_app_bar/extended_top_app_bar.dart +++ b/lib/src/components/top_app_bar/extended_top_app_bar.dart @@ -15,7 +15,6 @@ class ZetaExtendedAppBarDelegate extends SliverPersistentHeaderDelegate { required this.shrinks, this.actions, this.leading, - this.searchController, }); /// Title of the app bar. @@ -27,56 +26,49 @@ class ZetaExtendedAppBarDelegate extends SliverPersistentHeaderDelegate { /// Widget displayed first in the app bar row. final Widget? leading; - /// Used to control the search textfield and states. - final ZetaSearchController? searchController; - /// If `ZetaTopAppBarType.extend` shrinks. Does not affect other types of app bar. final bool shrinks; static const double _maxExtent = 104; - static const double _minExtent = 52; + static const double _minExtent = 56; @override Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) { - final searchBarOffsetTop = Zeta.of(context).spacing.minimum * 1.5; - final searchBarOffsetRight = Zeta.of(context).spacing.minimum * 22; - final maxExtent = Zeta.of(context).spacing.minimum * 26; - final leftMin = Zeta.of(context).spacing.large; - final topMin = Zeta.of(context).spacing.xl; - final topMax = Zeta.of(context).spacing.minimum * 15; + final spacing = Zeta.of(context).spacing; + + final maxExtent = spacing.minimum * 26; + final leftMin = spacing.large; + final topMin = spacing.xl; + final topMax = spacing.minimum * 15; /// If there is no leading widget, the left margin should not change /// If there is a leading widget, the left margin should be the same as the leading widget's width plus padding - final leftMax = leading == null ? leftMin : _minExtent + Zeta.of(context).spacing.small; + final leftMax = leading == null ? leftMin : _minExtent + spacing.small; + + final top = shrinks + ? (topMax + (-1 * shrinkOffset)).clamp( + topMin - (spacing.minimum), + topMax - (spacing.minimum), + ) + : topMax; return ConstrainedBox( - constraints: BoxConstraints(minHeight: Zeta.of(context).spacing.xl_9, maxHeight: maxExtent), + constraints: BoxConstraints(minHeight: spacing.xl_9, maxHeight: maxExtent), child: ColoredBox( color: Zeta.of(context).colors.surfacePrimary, child: Stack( children: [ Positioned( - top: shrinks - ? (topMax + (-1 * shrinkOffset)).clamp( - topMin - - (searchController != null && searchController!.isEnabled - ? searchBarOffsetTop - : Zeta.of(context).spacing.none), - topMax, - ) - : topMax, + top: top, left: shrinks ? ((shrinkOffset / maxExtent) * _maxExtent).clamp(leftMin, leftMax) : leftMin, - right: searchController != null && searchController!.isEnabled - ? searchBarOffsetRight - : Zeta.of(context).spacing.none, + right: spacing.none, child: title, ), - if (leading != null) - Positioned(top: Zeta.of(context).spacing.medium, left: Zeta.of(context).spacing.small, child: leading!), + if (leading != null) Positioned(top: spacing.small, left: spacing.small, child: leading!), if (actions != null) Positioned( - top: Zeta.of(context).spacing.medium, - right: Zeta.of(context).spacing.small, + top: spacing.small, + right: spacing.small, child: Row(children: actions!), ), ], diff --git a/lib/src/components/top_app_bar/search_top_app_bar.dart b/lib/src/components/top_app_bar/search_top_app_bar.dart index a05b15f4..7507541f 100644 --- a/lib/src/components/top_app_bar/search_top_app_bar.dart +++ b/lib/src/components/top_app_bar/search_top_app_bar.dart @@ -66,20 +66,12 @@ class _ZetaTopAppBarSearchFieldState extends State wit @override void initState() { - _textFocusNode.addListener(_onFocusChanged); widget.searchController?.addListener(_onSearchControllerChanged); widget.searchController?.textEditingController ??= TextEditingController(); super.initState(); } - void _onFocusChanged() { - final text = widget.searchController?.text ?? ''; - final shouldCloseSearch = _isSearching && text.isEmpty && !_textFocusNode.hasFocus; - - if (shouldCloseSearch) _closeSearch(); - } - void _onSearchControllerChanged() { final controller = widget.searchController; if (controller == null) return; @@ -151,7 +143,7 @@ class _ZetaTopAppBarSearchFieldState extends State wit children: [ Row( mainAxisAlignment: - widget.type == ZetaTopAppBarType.centeredTitle ? MainAxisAlignment.center : MainAxisAlignment.start, + widget.type == ZetaTopAppBarType.centered ? MainAxisAlignment.center : MainAxisAlignment.start, children: [ widget.child ?? const Nothing(), ], diff --git a/lib/src/components/top_app_bar/top_app_bar.dart b/lib/src/components/top_app_bar/top_app_bar.dart index 21f11e5b..e2de918e 100644 --- a/lib/src/components/top_app_bar/top_app_bar.dart +++ b/lib/src/components/top_app_bar/top_app_bar.dart @@ -18,32 +18,58 @@ class ZetaTopAppBar extends ZetaStatefulWidget implements PreferredSizeWidget { const ZetaTopAppBar({ super.key, super.rounded, - this.actions, + this.actions = const [], this.automaticallyImplyLeading = true, - this.searchController, this.leading, this.title, this.titleTextStyle, this.type = ZetaTopAppBarType.defaultAppBar, - this.onSearch, - this.searchHintText = 'Search', - this.onSearchMicrophoneIconPressed, - }) : shrinks = false; + @Deprecated('Use ZetaTopAppBar.search instead. ' 'Deprecated as of 0.16.0') ValueChanged? onSearch, + @Deprecated('Use ZetaTopAppBar.search instead. ' 'Deprecated as of 0.16.0') String? searchHintText, + @Deprecated('Use ZetaTopAppBar.search instead. ' 'Deprecated as of 0.16.0') ZetaSearchController? searchController, + @Deprecated('Use ZetaTopAppBar.search instead. ' 'Deprecated as of 0.16.0') + VoidCallback? onSearchMicrophoneIconPressed, + }) : shrinks = false, + onSearch = null, + searchHintText = null, + searchController = null, + onSearchMicrophoneIconPressed = null; /// Creates a ZetaTopAppBar with centered title. const ZetaTopAppBar.centered({ super.key, super.rounded, - this.actions, + this.actions = const [], + this.automaticallyImplyLeading = true, + this.leading, + this.title, + this.titleTextStyle, + @Deprecated('Use ZetaTopAppBar.search instead. ' 'Deprecated as of 0.16.0') ValueChanged? onSearch, + @Deprecated('Use ZetaTopAppBar.search instead. ' 'Deprecated as of 0.16.0') String? searchHintText, + @Deprecated('Use ZetaTopAppBar.search instead. ' 'Deprecated as of 0.16.0') ZetaSearchController? searchController, + @Deprecated('Use ZetaTopAppBar.search instead. ' 'Deprecated as of 0.16.0') + VoidCallback? onSearchMicrophoneIconPressed, + }) : type = ZetaTopAppBarType.centered, + onSearch = null, + searchHintText = null, + searchController = null, + onSearchMicrophoneIconPressed = null, + shrinks = false; + + /// Creates a ZetaTopAppBar with an expanding search field. + const ZetaTopAppBar.search({ + super.key, + super.rounded, this.automaticallyImplyLeading = true, this.searchController, this.leading, this.title, this.titleTextStyle, this.onSearch, - this.searchHintText = 'Search', + this.searchHintText, this.onSearchMicrophoneIconPressed, - }) : type = ZetaTopAppBarType.centeredTitle, + this.actions = const [], + }) : type = ZetaTopAppBarType.centered, shrinks = false; /// Creates a ZetaTopAppBar with an extended title over 2 lines. @@ -52,23 +78,28 @@ class ZetaTopAppBar extends ZetaStatefulWidget implements PreferredSizeWidget { const ZetaTopAppBar.extended({ super.key, super.rounded, - this.actions, + this.actions = const [], this.automaticallyImplyLeading = true, - this.searchController, this.leading, this.title, this.titleTextStyle, - this.onSearch, - this.searchHintText = 'Search', - this.onSearchMicrophoneIconPressed, this.shrinks = true, - }) : type = ZetaTopAppBarType.extendedTitle; + @Deprecated('Use ZetaTopAppBar.search instead. ' 'Deprecated as of 0.16.0') ValueChanged? onSearch, + @Deprecated('Use ZetaTopAppBar.search instead. ' 'Deprecated as of 0.16.0') String? searchHintText, + @Deprecated('Use ZetaTopAppBar.search instead. ' 'Deprecated as of 0.16.0') ZetaSearchController? searchController, + @Deprecated('Use ZetaTopAppBar.search instead. ' 'Deprecated as of 0.16.0') + VoidCallback? onSearchMicrophoneIconPressed, + }) : type = ZetaTopAppBarType.extended, + onSearch = null, + searchHintText = null, + onSearchMicrophoneIconPressed = null, + searchController = null; /// Called when text in the search field is submitted. - final void Function(String)? onSearch; + final ValueChanged? onSearch; /// A list of Widgets to display in a row after the [title] widget. - final List? actions; + final List actions; /// Configures whether the back button to be displayed. final bool automaticallyImplyLeading; @@ -118,29 +149,25 @@ class ZetaTopAppBar extends ZetaStatefulWidget implements PreferredSizeWidget { } class _ZetaTopAppBarState extends State { - bool _isSearchEnabled = false; + late ZetaSearchController _searchController; + bool get _searchEnabled => widget.searchController != null || widget.onSearch != null; + bool get _searchActive => _searchController.isEnabled; @override void initState() { - widget.searchController?.addListener(_onSearchControllerChanged); + _searchController = widget.searchController ?? ZetaSearchController(); + _searchController.addListener(() => setState(() {})); super.initState(); } - void _onSearchControllerChanged() { - final controller = widget.searchController; - if (controller == null) return; - - setState(() => _isSearchEnabled = controller.isEnabled); - } - @override void dispose() { - widget.searchController?.removeListener(_onSearchControllerChanged); + _searchController.dispose(); super.dispose(); } Widget _getTitleText(ZetaColors colors) { - var title = widget.title; + Widget? title = widget.title; if (widget.title is Row) { final oldRow = widget.title! as Row; title = Row( @@ -169,35 +196,48 @@ class _ZetaTopAppBarState extends State { } List? _getActions(ZetaColors colors) { - return _isSearchEnabled - ? [ - IconButtonTheme( - data: IconButtonThemeData( - style: IconButton.styleFrom(iconSize: Zeta.of(context).spacing.xl), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - IconButton( - color: colors.cool.shade50, - onPressed: () => widget.searchController?.clearText(), - icon: const ZetaIcon(ZetaIcons.cancel), - ), - if (widget.onSearchMicrophoneIconPressed != null) ...[ - SizedBox( - height: Zeta.of(context).spacing.xl_2, - child: VerticalDivider(width: ZetaBorders.medium, color: colors.cool.shade70), - ), - IconButton( - onPressed: widget.onSearchMicrophoneIconPressed, - icon: const ZetaIcon(ZetaIcons.microphone), - ), - ], - ], + if (_searchActive) { + return [ + IconButtonTheme( + data: IconButtonThemeData( + style: IconButton.styleFrom(iconSize: Zeta.of(context).spacing.xl), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + color: colors.cool.shade50, + onPressed: () => _searchController.clearText(), + icon: const ZetaIcon(ZetaIcons.cancel), ), - ), - ] - : widget.actions; + if (widget.onSearchMicrophoneIconPressed != null) ...[ + SizedBox( + height: Zeta.of(context).spacing.xl_2, + child: VerticalDivider(width: ZetaBorders.medium, color: colors.cool.shade70), + ), + IconButton( + onPressed: widget.onSearchMicrophoneIconPressed, + icon: const ZetaIcon(ZetaIcons.microphone), + ), + ], + ], + ), + ), + ]; + } + + if (_searchEnabled) { + return [ + ...widget.actions, + IconButton( + onPressed: () => setState(() { + _searchController.startSearch(); + }), + icon: const ZetaIcon(ZetaIcons.search), + ), + ]; + } + return widget.actions; } @override @@ -213,24 +253,32 @@ class _ZetaTopAppBarState extends State { hintText: widget.searchHintText ?? 'Search', onSearch: widget.onSearch, type: widget.type, - isExtended: widget.type == ZetaTopAppBarType.extendedTitle, + isExtended: widget.type == ZetaTopAppBarType.extended, child: titleText, ) : titleText; - if (widget.type == ZetaTopAppBarType.extendedTitle) { + if (widget.type == ZetaTopAppBarType.extended) { return SliverPersistentHeader( pinned: true, delegate: ZetaExtendedAppBarDelegate( actions: actions, leading: widget.leading, - searchController: widget.searchController, title: title, shrinks: widget.shrinks, ), ); } + Widget? leading = widget.leading; + + if (_searchActive) { + leading = IconButton( + onPressed: _searchController.closeSearch, + icon: const ZetaIcon(ZetaIcons.arrow_back), + ); + } + return ZetaRoundedScope( rounded: context.rounded, child: ColoredBox( @@ -244,10 +292,10 @@ class _ZetaTopAppBarState extends State { scrolledUnderElevation: 0, iconTheme: IconThemeData(color: colors.cool.shade90), leadingWidth: Zeta.of(context).spacing.xl_6, - leading: widget.leading, + leading: leading, automaticallyImplyLeading: widget.automaticallyImplyLeading, surfaceTintColor: Colors.transparent, - centerTitle: widget.type == ZetaTopAppBarType.centeredTitle, + centerTitle: widget.type == ZetaTopAppBarType.centered, titleTextStyle: widget.titleTextStyle == null ? ZetaTextStyles.bodyLarge.copyWith(color: colors.textDefault) : widget.titleTextStyle!.copyWith(color: colors.textDefault), @@ -267,8 +315,16 @@ enum ZetaTopAppBarType { defaultAppBar, /// Title in the center. + @Deprecated('Use ZetaTopAppBar.centered instead. ' 'Deprecated as of 0.16.0') centeredTitle, + /// Aligns the title to the center of the app bar. + centered, + /// Title below the app bar. + @Deprecated('Use ZetaTopAppBar.extended instead. ' 'Deprecated as of 0.16.0') extendedTitle, + + /// Title extends over 2 lines and collapses when scrolled. + extended, } From da23afa809767cf1b08921a837336e8eb0fd53c1 Mon Sep 17 00:00:00 2001 From: mikecoomber Date: Tue, 15 Oct 2024 14:23:17 +0100 Subject: [PATCH 2/7] fix widgetbook --- .../Flutter/GeneratedPluginRegistrant.swift | 2 +- example/widgetbook/main.dart | 1 - .../components/top_app_bar_widgetbook.dart | 105 +----------------- .../components/top_app_bar/top_app_bar.dart | 9 +- 4 files changed, 11 insertions(+), 106 deletions(-) diff --git a/example/macos/Flutter/GeneratedPluginRegistrant.swift b/example/macos/Flutter/GeneratedPluginRegistrant.swift index 8c72a8c7..63ad0d13 100644 --- a/example/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -7,7 +7,7 @@ import Foundation import path_provider_foundation import shared_preferences_foundation -import sqflite_darwin +import sqflite import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { diff --git a/example/widgetbook/main.dart b/example/widgetbook/main.dart index 5397a190..a24e9628 100644 --- a/example/widgetbook/main.dart +++ b/example/widgetbook/main.dart @@ -126,7 +126,6 @@ class _HotReloadState extends State { useCases: [ WidgetbookUseCase(name: 'Default', builder: (context) => defaultTopAppBarUseCase(context)), WidgetbookUseCase(name: 'Search', builder: (context) => searchTopAppBarUseCase(context)), - WidgetbookUseCase(name: 'Extended', builder: (context) => extendedTopAppBarUseCase(context)), ], ), WidgetbookComponent( diff --git a/example/widgetbook/pages/components/top_app_bar_widgetbook.dart b/example/widgetbook/pages/components/top_app_bar_widgetbook.dart index ea4ba12a..0c5ec54a 100644 --- a/example/widgetbook/pages/components/top_app_bar_widgetbook.dart +++ b/example/widgetbook/pages/components/top_app_bar_widgetbook.dart @@ -13,7 +13,7 @@ Widget defaultTopAppBarUseCase(BuildContext context) { label: "Title Alignment", options: [ ZetaTopAppBarType.defaultAppBar, - ZetaTopAppBarType.centeredTitle, + ZetaTopAppBarType.centered, ], initialOption: ZetaTopAppBarType.defaultAppBar, labelBuilder: (option) { @@ -84,7 +84,7 @@ class _SearchUseCaseState extends State<_SearchUseCase> { label: "Title Alignment", options: [ ZetaTopAppBarType.defaultAppBar, - ZetaTopAppBarType.centeredTitle, + ZetaTopAppBarType.centered, ], initialOption: ZetaTopAppBarType.defaultAppBar, labelBuilder: (option) { @@ -101,7 +101,7 @@ class _SearchUseCaseState extends State<_SearchUseCase> { initialValue: false, ); - return ZetaTopAppBar( + return ZetaTopAppBar.search( leading: IconButton( onPressed: () {}, icon: ZetaIcon(leadingIcon), @@ -118,105 +118,6 @@ class _SearchUseCaseState extends State<_SearchUseCase> { searchController.text = generatedText; } : null, - actions: [ - IconButton( - onPressed: () { - searchController.isEnabled ? searchController.closeSearch() : searchController.startSearch(); - }, - icon: ZetaIcon(ZetaIcons.search)), - ], - ); - } -} - -Widget extendedTopAppBarUseCase(BuildContext context) => ExtendedSearch(); - -class ExtendedSearch extends StatefulWidget { - const ExtendedSearch({super.key}); - - @override - State createState() => _ExtendedSearchState(); -} - -class _ExtendedSearchState extends State { - final _searchControllerExtended = ZetaSearchController(); - - void _showHideSearchExtended() { - _searchControllerExtended.isEnabled - ? _searchControllerExtended.closeSearch() - : _searchControllerExtended.startSearch(); - } - - @override - Widget build(BuildContext context) { - final title = context.knobs.string(label: "Title", initialValue: "Title"); - - final leadingIcon = iconKnob(context, name: 'Leading Icon', initial: ZetaIcons.hamburger_menu); - - final showSearch = context.knobs.boolean(label: 'Search variant', initialValue: false); - - return WidgetbookScaffold( - removeBody: true, - builder: (context, constraints) => SafeArea( - child: SizedBox( - width: constraints.maxWidth, - height: constraints.maxHeight, - child: CustomScrollView( - slivers: [ - ZetaTopAppBar.extended( - leading: IconButton(icon: ZetaIcon(leadingIcon), onPressed: () {}), - title: Text(title), - actions: showSearch - ? [ - IconButton( - onPressed: _showHideSearchExtended, - icon: ZetaIcon(ZetaIcons.search), - ) - ] - : [ - IconButton( - onPressed: () {}, - icon: ZetaIcon(Icons.language), - ), - IconButton( - onPressed: () {}, - icon: ZetaIcon(Icons.favorite), - ), - IconButton( - onPressed: () {}, - icon: ZetaIcon(ZetaIcons.more_vertical), - ) - ], - searchController: showSearch ? _searchControllerExtended : null, - onSearch: showSearch ? (text) => debugPrint('search text: $text') : null, - onSearchMicrophoneIconPressed: showSearch - ? () async { - var sampleTexts = [ - 'This is a sample text', - 'Another sample', - 'Speech recognition text', - 'Example' - ]; - var generatedText = sampleTexts[Random().nextInt(sampleTexts.length)]; - _searchControllerExtended.text = generatedText; - } - : null, - ), - SliverToBoxAdapter( - child: Container( - width: constraints.maxWidth, - height: constraints.maxHeight * 4, - color: Zeta.of(context).colors.surfaceSecondary, - child: CustomPaint( - painter: Painter(context: context, constraints: constraints), - size: Size(constraints.maxWidth, constraints.maxHeight * 4), - ), - ), - ), - ], - ), - ), - ), ); } } diff --git a/lib/src/components/top_app_bar/top_app_bar.dart b/lib/src/components/top_app_bar/top_app_bar.dart index e2de918e..a896280c 100644 --- a/lib/src/components/top_app_bar/top_app_bar.dart +++ b/lib/src/components/top_app_bar/top_app_bar.dart @@ -57,9 +57,14 @@ class ZetaTopAppBar extends ZetaStatefulWidget implements PreferredSizeWidget { shrinks = false; /// Creates a ZetaTopAppBar with an expanding search field. + /// This will append a search icon to the right of the app bar. + /// When the search icon is pressed, the search field will expand and replace the title widget. + /// It will replace the leading widget with a back button which closes the search field. + /// The search field can be controlled externally by the [searchController]. const ZetaTopAppBar.search({ super.key, super.rounded, + this.type = ZetaTopAppBarType.defaultAppBar, this.automaticallyImplyLeading = true, this.searchController, this.leading, @@ -69,8 +74,8 @@ class ZetaTopAppBar extends ZetaStatefulWidget implements PreferredSizeWidget { this.searchHintText, this.onSearchMicrophoneIconPressed, this.actions = const [], - }) : type = ZetaTopAppBarType.centered, - shrinks = false; + }) : shrinks = false, + assert(type != ZetaTopAppBarType.extended, 'Search app bars cannot be extended'); /// Creates a ZetaTopAppBar with an extended title over 2 lines. /// From 56053ac269d7495817bbe5b104da315aa2060663 Mon Sep 17 00:00:00 2001 From: mikecoomber Date: Wed, 16 Oct 2024 10:30:42 +0100 Subject: [PATCH 3/7] app bar tests --- .../components/top_app_bar/top_app_bar.dart | 131 +++++++---- .../golden/top_app_bar_default.png | Bin 0 -> 3296 bytes .../top_app_bar/top_app_bar_test.dart | 214 ++++++++++++++++++ 3 files changed, 295 insertions(+), 50 deletions(-) create mode 100644 test/src/components/top_app_bar/golden/top_app_bar_default.png create mode 100644 test/src/components/top_app_bar/top_app_bar_test.dart diff --git a/lib/src/components/top_app_bar/top_app_bar.dart b/lib/src/components/top_app_bar/top_app_bar.dart index a896280c..4a04f9aa 100644 --- a/lib/src/components/top_app_bar/top_app_bar.dart +++ b/lib/src/components/top_app_bar/top_app_bar.dart @@ -33,6 +33,10 @@ class ZetaTopAppBar extends ZetaStatefulWidget implements PreferredSizeWidget { onSearch = null, searchHintText = null, searchController = null, + clearSemanticLabel = null, + microphoneSemanticLabel = null, + searchBackSemanticLabel = null, + searchSemanticLabel = null, onSearchMicrophoneIconPressed = null; /// Creates a ZetaTopAppBar with centered title. @@ -54,6 +58,10 @@ class ZetaTopAppBar extends ZetaStatefulWidget implements PreferredSizeWidget { searchHintText = null, searchController = null, onSearchMicrophoneIconPressed = null, + clearSemanticLabel = null, + searchBackSemanticLabel = null, + microphoneSemanticLabel = null, + searchSemanticLabel = null, shrinks = false; /// Creates a ZetaTopAppBar with an expanding search field. @@ -74,6 +82,10 @@ class ZetaTopAppBar extends ZetaStatefulWidget implements PreferredSizeWidget { this.searchHintText, this.onSearchMicrophoneIconPressed, this.actions = const [], + this.clearSemanticLabel, + this.microphoneSemanticLabel, + this.searchSemanticLabel, + this.searchBackSemanticLabel, }) : shrinks = false, assert(type != ZetaTopAppBarType.extended, 'Search app bars cannot be extended'); @@ -98,6 +110,10 @@ class ZetaTopAppBar extends ZetaStatefulWidget implements PreferredSizeWidget { onSearch = null, searchHintText = null, onSearchMicrophoneIconPressed = null, + clearSemanticLabel = null, + microphoneSemanticLabel = null, + searchSemanticLabel = null, + searchBackSemanticLabel = null, searchController = null; /// Called when text in the search field is submitted. @@ -133,6 +149,17 @@ class ZetaTopAppBar extends ZetaStatefulWidget implements PreferredSizeWidget { /// If `ZetaTopAppBarType.extend` shrinks. Does not affect other types of app bar. final bool shrinks; + /// The semantic label for the clear icon. + final String? clearSemanticLabel; + + /// The semantic label for the microphone icon. + final String? microphoneSemanticLabel; + + final String? searchSemanticLabel; + + /// The semantic label for the back icon when search is open. + final String? searchBackSemanticLabel; + @override State createState() => _ZetaTopAppBarState(); @@ -165,12 +192,6 @@ class _ZetaTopAppBarState extends State { super.initState(); } - @override - void dispose() { - _searchController.dispose(); - super.dispose(); - } - Widget _getTitleText(ZetaColors colors) { Widget? title = widget.title; if (widget.title is Row) { @@ -203,30 +224,36 @@ class _ZetaTopAppBarState extends State { List? _getActions(ZetaColors colors) { if (_searchActive) { return [ - IconButtonTheme( - data: IconButtonThemeData( - style: IconButton.styleFrom(iconSize: Zeta.of(context).spacing.xl), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - IconButton( + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Semantics( + label: widget.clearSemanticLabel, + button: true, + child: IconButton( color: colors.cool.shade50, onPressed: () => _searchController.clearText(), - icon: const ZetaIcon(ZetaIcons.cancel), - ), - if (widget.onSearchMicrophoneIconPressed != null) ...[ - SizedBox( - height: Zeta.of(context).spacing.xl_2, - child: VerticalDivider(width: ZetaBorders.medium, color: colors.cool.shade70), + icon: ZetaIcon( + ZetaIcons.cancel, + size: Zeta.of(context).spacing.xl, ), - IconButton( + ), + ), + if (widget.onSearchMicrophoneIconPressed != null) ...[ + SizedBox( + height: Zeta.of(context).spacing.xl_2, + child: VerticalDivider(width: ZetaBorders.medium, color: colors.cool.shade70), + ), + Semantics( + label: widget.microphoneSemanticLabel, + button: true, + child: IconButton( onPressed: widget.onSearchMicrophoneIconPressed, icon: const ZetaIcon(ZetaIcons.microphone), ), - ], + ), ], - ), + ], ), ]; } @@ -234,11 +261,15 @@ class _ZetaTopAppBarState extends State { if (_searchEnabled) { return [ ...widget.actions, - IconButton( - onPressed: () => setState(() { - _searchController.startSearch(); - }), - icon: const ZetaIcon(ZetaIcons.search), + Semantics( + label: widget.searchSemanticLabel, + button: true, + child: IconButton( + onPressed: () => setState(() { + _searchController.startSearch(); + }), + icon: const ZetaIcon(ZetaIcons.search), + ), ), ]; } @@ -278,9 +309,13 @@ class _ZetaTopAppBarState extends State { Widget? leading = widget.leading; if (_searchActive) { - leading = IconButton( - onPressed: _searchController.closeSearch, - icon: const ZetaIcon(ZetaIcons.arrow_back), + leading = Semantics( + label: widget.searchBackSemanticLabel, + button: true, + child: IconButton( + onPressed: _searchController.closeSearch, + icon: const ZetaIcon(ZetaIcons.arrow_back), + ), ); } @@ -288,25 +323,21 @@ class _ZetaTopAppBarState extends State { rounded: context.rounded, child: ColoredBox( color: colors.surfacePrimary, - child: IconButtonTheme( - data: IconButtonThemeData(style: IconButton.styleFrom(tapTargetSize: MaterialTapTargetSize.shrinkWrap)), - child: Padding( - padding: EdgeInsets.symmetric(horizontal: Zeta.of(context).spacing.minimum), - child: AppBar( - elevation: 0, - scrolledUnderElevation: 0, - iconTheme: IconThemeData(color: colors.cool.shade90), - leadingWidth: Zeta.of(context).spacing.xl_6, - leading: leading, - automaticallyImplyLeading: widget.automaticallyImplyLeading, - surfaceTintColor: Colors.transparent, - centerTitle: widget.type == ZetaTopAppBarType.centered, - titleTextStyle: widget.titleTextStyle == null - ? ZetaTextStyles.bodyLarge.copyWith(color: colors.textDefault) - : widget.titleTextStyle!.copyWith(color: colors.textDefault), - title: title, - actions: actions, - ), + child: Padding( + padding: EdgeInsets.symmetric(horizontal: Zeta.of(context).spacing.minimum), + child: AppBar( + elevation: 0, + scrolledUnderElevation: 0, + iconTheme: IconThemeData(color: colors.iconDefault), + leading: leading, + automaticallyImplyLeading: widget.automaticallyImplyLeading, + surfaceTintColor: Colors.transparent, + centerTitle: widget.type == ZetaTopAppBarType.centered, + titleTextStyle: widget.titleTextStyle == null + ? ZetaTextStyles.bodyLarge.copyWith(color: colors.textDefault) + : widget.titleTextStyle!.copyWith(color: colors.textDefault), + title: title, + actions: actions, ), ), ), diff --git a/test/src/components/top_app_bar/golden/top_app_bar_default.png b/test/src/components/top_app_bar/golden/top_app_bar_default.png new file mode 100644 index 0000000000000000000000000000000000000000..e17872e8cd3b74fce4fa8e3096c6d1fe06e3c504 GIT binary patch literal 3296 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9jkefq|#X)5S5QV$R!}8+i`}2(UWdUc~3|V!x75#*-5n4B7P$W-|Hd$KJIw z-pmNp+jo_jfuZ5G0MH5tw+5hTl8j6Y3@I!e3=9(lsUY~Q?AyWLk1M}<{`*k5Kg=I! zm%O|H1A~IH1CZIn0Ca*86AJ^w2@dKC{yuZ&l^_Gd0n;Be@DnY%xM#J_URgq4}Veg%W4tDnm{r-UW|Aj_20 literal 0 HcmV?d00001 diff --git a/test/src/components/top_app_bar/top_app_bar_test.dart b/test/src/components/top_app_bar/top_app_bar_test.dart new file mode 100644 index 00000000..82c537c4 --- /dev/null +++ b/test/src/components/top_app_bar/top_app_bar_test.dart @@ -0,0 +1,214 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:zeta_flutter/zeta_flutter.dart'; + +import '../../../test_utils/test_app.dart'; +import '../../../test_utils/tolerant_comparator.dart'; +import '../../../test_utils/utils.dart'; + +void main() { + const String componentName = 'ZetaTopAppbar'; + const String parentFolder = 'top_app_bar'; + + const goldenFile = GoldenFiles(component: parentFolder); + setUpAll(() { + goldenFileComparator = TolerantComparator(goldenFile.uri); + }); + + group('$componentName Accessibility Tests', () { + testWidgets('$componentName meets accessibility requirements', (WidgetTester tester) async { + final SemanticsHandle handle = tester.ensureSemantics(); + await tester.pumpWidget( + TestApp( + home: ZetaTopAppBar( + title: const Text('Title'), + actions: [ + IconButton( + icon: const Icon(Icons.search), + tooltip: 'Search', + onPressed: () {}, + ) + ], + leading: IconButton( + icon: const Icon(Icons.menu), + tooltip: 'Menu', + onPressed: () {}, + ), + ), + ), + ); + await expectLater(tester, meetsGuideline(androidTapTargetGuideline)); + await expectLater(tester, meetsGuideline(iOSTapTargetGuideline)); + await expectLater(tester, meetsGuideline(labeledTapTargetGuideline)); + await expectLater(tester, meetsGuideline(textContrastGuideline)); + + handle.dispose(); + }); + + testWidgets('$componentName passes semantic labels to the search actions', (WidgetTester tester) async { + const microphoneSemanticLabel = 'Search with voice'; + const clearSemanticLabel = 'Clear search'; + const searchBackSemanticLabel = 'Back'; + const searchSemanticLabel = 'Search'; + final ZetaSearchController searchController = ZetaSearchController(); + await tester.pumpWidget( + TestApp( + home: ZetaTopAppBar.search( + title: const Text('Title'), + microphoneSemanticLabel: microphoneSemanticLabel, + clearSemanticLabel: clearSemanticLabel, + searchController: searchController, + searchSemanticLabel: searchSemanticLabel, + searchBackSemanticLabel: searchBackSemanticLabel, + onSearchMicrophoneIconPressed: () {}, + ), + ), + ); + + expect( + find.bySemanticsLabel(searchSemanticLabel), + findsOneWidget, + ); + + searchController.startSearch(); + await tester.pumpAndSettle(); + + expect( + find.bySemanticsLabel(microphoneSemanticLabel), + findsOneWidget, + ); + expect( + find.bySemanticsLabel(clearSemanticLabel), + findsOneWidget, + ); + expect( + find.bySemanticsLabel(searchBackSemanticLabel), + findsOneWidget, + ); + }); + }); + + group('$componentName Content Tests', () { + final debugFillProperties = { + 'titleTextStyle': 'null', + 'onSearch': 'null', + 'automaticallyImplyLeading': 'true', + 'onSearchMicrophoneIconPressed': 'null', + 'searchController': 'null', + 'searchHintText': 'null', + 'type': 'defaultAppBar', + 'shrinks': 'false', + }; + debugFillPropertiesTest( + const ZetaTopAppBar(), + debugFillProperties, + ); + }); + + group('$componentName Dimensions Tests', () {}); + group('$componentName Styling Tests', () {}); + group('$componentName Interaction Tests', () { + late ZetaSearchController searchController; + const searchLabel = 'Search'; + const clearLabel = 'Clear'; + const backLabel = 'Back'; + + late Widget subject; + + setUp(() { + searchController = ZetaSearchController(); + subject = TestApp( + home: ZetaTopAppBar.search( + title: const Text('Title'), + searchController: searchController, + searchSemanticLabel: searchLabel, + clearSemanticLabel: clearLabel, + searchBackSemanticLabel: backLabel, + ), + ); + }); + + testWidgets( + '$componentName Search opens and closes the search bar when the search/back icon is tapped', + (WidgetTester tester) async { + await tester.pumpWidget(subject); + + expect(searchController.isEnabled, isFalse); + await tester.tap(find.bySemanticsLabel(searchLabel)); + await tester.pumpAndSettle(); + + expect(searchController.isEnabled, isTrue); + + await tester.tap(find.bySemanticsLabel(backLabel)); + await tester.pumpAndSettle(); + + expect(searchController.isEnabled, isFalse); + }, + ); + + testWidgets( + '$componentName Search allows text to be typed in the search field', + (WidgetTester tester) async { + await tester.pumpWidget(subject); + + searchController.startSearch(); + await tester.pumpAndSettle(); + + await tester.enterText(find.byType(TextField), 'Search text'); + expect(searchController.text, 'Search text'); + }, + ); + + testWidgets( + '$componentName Search gets cleared when the clear button is tapped', + (WidgetTester tester) async { + await tester.pumpWidget(subject); + + searchController.startSearch(); + await tester.pumpAndSettle(); + + await tester.enterText(find.byType(TextField), 'Search text'); + await tester.tap(find.bySemanticsLabel(clearLabel)); + expect(searchController.text, ''); + }, + ); + + testWidgets( + '$componentName Search submits the correct text when the search input is submitted', + (WidgetTester tester) async { + String inputtedText = ''; + await tester.pumpWidget( + TestApp( + home: ZetaTopAppBar.search( + title: const Text('Title'), + searchController: searchController, + onSearch: (String text) { + inputtedText = text; + }, + ), + ), + ); + + searchController.startSearch(); + await tester.pumpAndSettle(); + + await tester.enterText(find.byType(TextField), 'Search text'); + await tester.testTextInput.receiveAction(TextInputAction.done); + expect(inputtedText, 'Search text'); + }, + ); + }); + + group('$componentName Golden Tests', () { + goldenTest( + goldenFile, + const ZetaTopAppBar( + title: Text('Title'), + ), + ZetaTopAppBar, + 'top_app_bar_default', + ); + }); + + group('$componentName Performance Tests', () {}); +} From 1e7e0cd2c14ef3263a5b691665084e2709b999ce Mon Sep 17 00:00:00 2001 From: mikecoomber Date: Wed, 16 Oct 2024 12:01:18 +0100 Subject: [PATCH 4/7] optimized test helper --- .../components/top_app_bar/top_app_bar.dart | 47 ++- test/src/components/avatar/avatar_test.dart | 6 - test/src/components/badge/indicator_test.dart | 8 +- test/src/components/badge/label_test.dart | 10 +- .../components/badge/priority_pill_test.dart | 5 +- .../components/badge/status_label_test.dart | 3 +- test/src/components/badge/tag_test.dart | 4 +- test/src/components/banner/banner_test.dart | 2 +- test/src/components/button/button_test.dart | 13 +- .../components/chat_item/chat_item_test.dart | 58 +-- .../components/checkbox/checkbox_test.dart | 7 +- .../comms_button/comms_button_test.dart | 1 - test/src/components/dialpad/dialpad_test.dart | 3 - test/src/components/fab/fab_test.dart | 14 +- .../in_page_banner/in_page_banner_test.dart | 4 - .../password/password_input_test.dart | 7 +- .../search_bar/search_bar_test.dart | 7 +- test/src/components/tooltip/tooltip_test.dart | 8 +- .../extended_top_app_bar_test.dart | 169 -------- .../golden/extended_app_bar_shrinks.png | Bin 2230 -> 2051 bytes ...tended_app_bar_shrinks_with_no_leading.png | Bin 2206 -> 2043 bytes .../golden/top_app_bar_centered.png | Bin 0 -> 3318 bytes .../golden/top_app_bar_centered_actions.png | Bin 0 -> 3368 bytes .../golden/top_app_bar_default.png | Bin 3296 -> 3320 bytes .../golden/top_app_bar_default_actions.png | Bin 0 -> 3368 bytes .../golden/top_app_bar_extended.png | Bin 0 -> 2231 bytes .../golden/top_app_bar_extended_actions.png | Bin 0 -> 2271 bytes .../top_app_bar/golden/top_app_bar_search.png | Bin 0 -> 3320 bytes .../golden/top_app_bar_search_active.png | Bin 0 -> 3512 bytes .../golden/top_app_bar_search_centered.png | Bin 0 -> 3319 bytes .../top_app_bar/top_app_bar_test.dart | 375 +++++++++++++++++- test/test_utils/utils.dart | 44 +- 32 files changed, 455 insertions(+), 340 deletions(-) delete mode 100644 test/src/components/top_app_bar/extended_top_app_bar_test.dart create mode 100644 test/src/components/top_app_bar/golden/top_app_bar_centered.png create mode 100644 test/src/components/top_app_bar/golden/top_app_bar_centered_actions.png create mode 100644 test/src/components/top_app_bar/golden/top_app_bar_default_actions.png create mode 100644 test/src/components/top_app_bar/golden/top_app_bar_extended.png create mode 100644 test/src/components/top_app_bar/golden/top_app_bar_extended_actions.png create mode 100644 test/src/components/top_app_bar/golden/top_app_bar_search.png create mode 100644 test/src/components/top_app_bar/golden/top_app_bar_search_active.png create mode 100644 test/src/components/top_app_bar/golden/top_app_bar_search_centered.png diff --git a/lib/src/components/top_app_bar/top_app_bar.dart b/lib/src/components/top_app_bar/top_app_bar.dart index 4a04f9aa..86ff8a10 100644 --- a/lib/src/components/top_app_bar/top_app_bar.dart +++ b/lib/src/components/top_app_bar/top_app_bar.dart @@ -155,6 +155,7 @@ class ZetaTopAppBar extends ZetaStatefulWidget implements PreferredSizeWidget { /// The semantic label for the microphone icon. final String? microphoneSemanticLabel; + /// The semantic label for the search icon. final String? searchSemanticLabel; /// The semantic label for the back icon when search is open. @@ -176,7 +177,11 @@ class ZetaTopAppBar extends ZetaStatefulWidget implements PreferredSizeWidget { ..add(DiagnosticsProperty('searchController', searchController)) ..add(StringProperty('searchHintText', searchHintText)) ..add(EnumProperty('type', type)) - ..add(DiagnosticsProperty('shrinks', shrinks)); + ..add(DiagnosticsProperty('shrinks', shrinks)) + ..add(StringProperty('clearSemanticLabel', clearSemanticLabel)) + ..add(StringProperty('microphoneSemanticLabel', microphoneSemanticLabel)) + ..add(StringProperty('searchSemanticLabel', searchSemanticLabel)) + ..add(StringProperty('searchBackSemanticLabel', searchBackSemanticLabel)); } } @@ -192,7 +197,7 @@ class _ZetaTopAppBarState extends State { super.initState(); } - Widget _getTitleText(ZetaColors colors) { + Widget _getTitle(ZetaColors colors) { Widget? title = widget.title; if (widget.title is Row) { final oldRow = widget.title! as Row; @@ -279,9 +284,10 @@ class _ZetaTopAppBarState extends State { @override Widget build(BuildContext context) { final colors = Zeta.of(context).colors; + final spacing = Zeta.of(context).spacing; final actions = _getActions(colors); - final titleText = _getTitleText(colors); + final titleText = _getTitle(colors); final title = widget.searchController != null ? ZetaTopAppBarSearchField( @@ -321,24 +327,23 @@ class _ZetaTopAppBarState extends State { return ZetaRoundedScope( rounded: context.rounded, - child: ColoredBox( - color: colors.surfacePrimary, - child: Padding( - padding: EdgeInsets.symmetric(horizontal: Zeta.of(context).spacing.minimum), - child: AppBar( - elevation: 0, - scrolledUnderElevation: 0, - iconTheme: IconThemeData(color: colors.iconDefault), - leading: leading, - automaticallyImplyLeading: widget.automaticallyImplyLeading, - surfaceTintColor: Colors.transparent, - centerTitle: widget.type == ZetaTopAppBarType.centered, - titleTextStyle: widget.titleTextStyle == null - ? ZetaTextStyles.bodyLarge.copyWith(color: colors.textDefault) - : widget.titleTextStyle!.copyWith(color: colors.textDefault), - title: title, - actions: actions, - ), + child: Padding( + padding: EdgeInsets.symmetric(horizontal: spacing.minimum), + child: AppBar( + elevation: 0, + scrolledUnderElevation: 0, + backgroundColor: colors.surfacePrimary, + iconTheme: IconThemeData(color: colors.iconDefault), + leading: leading, + toolbarHeight: spacing.xl_9, + automaticallyImplyLeading: widget.automaticallyImplyLeading, + surfaceTintColor: Colors.transparent, + centerTitle: widget.type == ZetaTopAppBarType.centered, + titleTextStyle: widget.titleTextStyle == null + ? ZetaTextStyles.bodyLarge.copyWith(color: colors.textDefault) + : widget.titleTextStyle!.copyWith(color: colors.textDefault), + title: title, + actions: actions, ), ), ); diff --git a/test/src/components/avatar/avatar_test.dart b/test/src/components/avatar/avatar_test.dart index 7e02d661..10ab2880 100644 --- a/test/src/components/avatar/avatar_test.dart +++ b/test/src/components/avatar/avatar_test.dart @@ -322,7 +322,6 @@ void main() { ZetaAvatar( size: size, ), - ZetaAvatar, 'avatar_default_${size.toString().split('.').last}', ); goldenTest( @@ -331,7 +330,6 @@ void main() { initials: 'AB', size: size, ), - ZetaAvatar, 'avatar_initials_${size.toString().split('.').last}', ); goldenTest( @@ -340,7 +338,6 @@ void main() { image: Image.file(File('/assets/maxresdefault.jpg')), size: size, ), - ZetaAvatar, 'avatar_image_${size.toString().split('.').last}', ); goldenTest( @@ -349,7 +346,6 @@ void main() { name: 'John Doe', size: size, ), - ZetaAvatar, 'avatar_from_name_${size.toString().split('.').last}', ); goldenTest( @@ -358,7 +354,6 @@ void main() { upperBadge: const ZetaAvatarBadge.notification(value: 3), size: size, ), - ZetaAvatar, 'avatar_upper_badge_${size.toString().split('.').last}', ); goldenTest( @@ -367,7 +362,6 @@ void main() { lowerBadge: const ZetaAvatarBadge.icon(icon: Icons.star), size: size, ), - ZetaAvatar, 'avatar_lower_badge_${size.toString().split('.').last}', ); } diff --git a/test/src/components/badge/indicator_test.dart b/test/src/components/badge/indicator_test.dart index 12f768e5..43c683a8 100644 --- a/test/src/components/badge/indicator_test.dart +++ b/test/src/components/badge/indicator_test.dart @@ -157,8 +157,8 @@ void main() { group('Styling Tests', () {}); group('Interaction Tests', () {}); group('Golden Tests', () { - goldenTest(goldenFile, const ZetaIndicator(), ZetaIndicator, 'indicator_default'); - goldenTest(goldenFile, const ZetaIndicator.icon(), ZetaIndicator, 'indicator_icon_default'); + goldenTest(goldenFile, const ZetaIndicator(), 'indicator_default'); + goldenTest(goldenFile, const ZetaIndicator.icon(), 'indicator_icon_default'); goldenTest( goldenFile, const ZetaIndicator.icon( @@ -167,10 +167,9 @@ void main() { inverse: true, size: ZetaWidgetSize.medium, ), - ZetaIndicator, 'indicator_icon_values', ); - goldenTest(goldenFile, const ZetaIndicator.notification(), ZetaIndicator, 'indicator_notification_default'); + goldenTest(goldenFile, const ZetaIndicator.notification(), 'indicator_notification_default'); goldenTest( goldenFile, const ZetaIndicator.notification( @@ -180,7 +179,6 @@ void main() { size: ZetaWidgetSize.small, value: 1, ), - ZetaIndicator, 'indicator_notification_values', ); }); diff --git a/test/src/components/badge/label_test.dart b/test/src/components/badge/label_test.dart index ee6fa91e..24d1e99b 100644 --- a/test/src/components/badge/label_test.dart +++ b/test/src/components/badge/label_test.dart @@ -104,33 +104,29 @@ void main() { group('Styling Tests', () {}); group('Interaction Tests', () {}); group('Golden Tests', () { - goldenTest(goldenFile, const ZetaLabel(label: 'Test Label'), ZetaLabel, 'label_default'); + goldenTest(goldenFile, const ZetaLabel(label: 'Test Label'), 'label_default'); goldenTest( goldenFile, const ZetaLabel(label: 'Test Label', status: ZetaWidgetStatus.positive), - ZetaLabel, 'label_positive', ); goldenTest( goldenFile, const ZetaLabel(label: 'Test Label', status: ZetaWidgetStatus.warning), - ZetaLabel, 'label_warning', ); goldenTest( goldenFile, const ZetaLabel(label: 'Test Label', status: ZetaWidgetStatus.negative), - ZetaLabel, 'label_negative', ); goldenTest( goldenFile, const ZetaLabel(label: 'Test Label', status: ZetaWidgetStatus.neutral), - ZetaLabel, 'label_neutral', ); - goldenTest(goldenFile, const ZetaLabel(label: 'Test Label'), ZetaLabel, 'label_dark', themeMode: ThemeMode.dark); - goldenTest(goldenFile, const ZetaLabel(label: 'Test Label', rounded: false), ZetaLabel, 'label_sharp'); + goldenTest(goldenFile, const ZetaLabel(label: 'Test Label'), 'label_dark', themeMode: ThemeMode.dark); + goldenTest(goldenFile, const ZetaLabel(label: 'Test Label', rounded: false), 'label_sharp'); }); group('Performance Tests', () {}); } diff --git a/test/src/components/badge/priority_pill_test.dart b/test/src/components/badge/priority_pill_test.dart index 0c4b281f..92c120bb 100644 --- a/test/src/components/badge/priority_pill_test.dart +++ b/test/src/components/badge/priority_pill_test.dart @@ -121,7 +121,7 @@ void main() { group('Styling Tests', () {}); group('Interaction Tests', () {}); group('Golden Tests', () { - goldenTest(goldenFile, const ZetaPriorityPill(), ZetaPriorityPill, 'priority_pill_default'); + goldenTest(goldenFile, const ZetaPriorityPill(), 'priority_pill_default'); goldenTest( goldenFile, const ZetaPriorityPill( @@ -131,7 +131,6 @@ void main() { rounded: false, size: ZetaPriorityPillSize.small, ), - ZetaPriorityPill, 'priority_pill_high', ); goldenTest( @@ -140,7 +139,6 @@ void main() { type: ZetaPriorityPillType.medium, isBadge: true, ), - ZetaPriorityPill, 'priority_pill_medium', ); goldenTest( @@ -150,7 +148,6 @@ void main() { size: ZetaPriorityPillSize.small, isBadge: true, ), - ZetaPriorityPill, 'priority_pill_low', ); }); diff --git a/test/src/components/badge/status_label_test.dart b/test/src/components/badge/status_label_test.dart index 2198a529..992f6bad 100644 --- a/test/src/components/badge/status_label_test.dart +++ b/test/src/components/badge/status_label_test.dart @@ -57,14 +57,13 @@ void main() { group('Styling Tests', () {}); group('Interaction Tests', () {}); group('Golden Tests', () { - goldenTest(goldenFile, const ZetaStatusLabel(label: 'Test Label'), ZetaStatusLabel, 'status_label_default'); + goldenTest(goldenFile, const ZetaStatusLabel(label: 'Test Label'), 'status_label_default'); goldenTest( goldenFile, const ZetaStatusLabel( label: 'Custom Icon', customIcon: Icons.person, ), - ZetaStatusLabel, 'status_label_custom', ); }); diff --git a/test/src/components/badge/tag_test.dart b/test/src/components/badge/tag_test.dart index c7990a11..dc1cdba5 100644 --- a/test/src/components/badge/tag_test.dart +++ b/test/src/components/badge/tag_test.dart @@ -50,8 +50,8 @@ void main() { group('Styling Tests', () {}); group('Interaction Tests', () {}); group('Golden Tests', () { - goldenTest(goldenFile, const ZetaTag.right(label: 'Tag', rounded: false), ZetaTag, 'tag_right'); - goldenTest(goldenFile, const ZetaTag.left(label: 'Tag', rounded: true), ZetaTag, 'tag_left'); + goldenTest(goldenFile, const ZetaTag.right(label: 'Tag', rounded: false), 'tag_right'); + goldenTest(goldenFile, const ZetaTag.left(label: 'Tag', rounded: true), 'tag_left'); }); group('Performance Tests', () {}); } diff --git a/test/src/components/banner/banner_test.dart b/test/src/components/banner/banner_test.dart index 44d69c56..a221f5fb 100644 --- a/test/src/components/banner/banner_test.dart +++ b/test/src/components/banner/banner_test.dart @@ -347,8 +347,8 @@ void main() { ); }, ), - ZetaBanner, 'banner_${type.toString().split('.').last}', + widgetType: ZetaBanner, ); } }); diff --git a/test/src/components/button/button_test.dart b/test/src/components/button/button_test.dart index fb72ec0e..140d7537 100644 --- a/test/src/components/button/button_test.dart +++ b/test/src/components/button/button_test.dart @@ -258,47 +258,44 @@ void main() { }); group('Golden Tests', () { - goldenTest(goldenFile, ZetaButton.primary(onPressed: () {}, label: 'Test Button'), ZetaButton, 'button_primary'); + goldenTest( + goldenFile, + ZetaButton.primary(onPressed: () {}, label: 'Test Button'), + 'button_primary', + ); goldenTest( goldenFile, ZetaButton.secondary(onPressed: () {}, label: 'Test Button', leadingIcon: Icons.abc, size: ZetaWidgetSize.small), - ZetaButton, 'button_secondary', ); goldenTest( goldenFile, ZetaButton.positive(onPressed: () {}, label: 'Test Button', trailingIcon: Icons.abc), - ZetaButton, 'button_positive', ); goldenTest( goldenFile, ZetaButton.negative(onPressed: () {}, label: 'Test Button', size: ZetaWidgetSize.small), - ZetaButton, 'button_negative', ); goldenTest( goldenFile, ZetaButton.outline(onPressed: () {}, label: 'Test Button', size: ZetaWidgetSize.large), - ZetaButton, 'button_outline', ); goldenTest( goldenFile, const ZetaButton.outlineSubtle(label: 'Test Button', borderType: ZetaWidgetBorder.sharp), - ZetaButton, 'button_outline_subtle', ); goldenTest( goldenFile, ZetaButton.text(onPressed: () {}, label: 'Test Button', borderType: ZetaWidgetBorder.full), - ZetaButton, 'button_text', ); goldenTest( goldenFile, const ZetaButton.text(label: 'Test Button', borderType: ZetaWidgetBorder.full), - ZetaButton, 'button_disabled', ); }); diff --git a/test/src/components/chat_item/chat_item_test.dart b/test/src/components/chat_item/chat_item_test.dart index e72a00bf..88475d70 100644 --- a/test/src/components/chat_item/chat_item_test.dart +++ b/test/src/components/chat_item/chat_item_test.dart @@ -518,7 +518,7 @@ void main() { const subtitle = Text('Hello, how are you?'); final time = DateTime.now(); - goldenTestWithCallbacks( + goldenTest( goldenFile, Scaffold( body: Column( @@ -544,15 +544,15 @@ void main() { ], ), ), - ZetaChatItem, 'chat_item_default', - before: (tester) async { + widgetType: ZetaChatItem, + setUp: (tester) async { tester.view.devicePixelRatio = 1.0; tester.view.physicalSize = const Size(481, 480); }, ); - goldenTestWithCallbacks( + goldenTest( goldenFile, Column( children: [ @@ -578,15 +578,15 @@ void main() { ), ], ), - ZetaChatItem, 'chat_item_highlighted', - before: (tester) async { + widgetType: ZetaChatItem, + setUp: (tester) async { tester.view.devicePixelRatio = 1.0; tester.view.physicalSize = const Size(481, 480); }, ); - goldenTestWithCallbacks( + goldenTest( goldenFile, Column( children: [ @@ -604,20 +604,20 @@ void main() { ), ], ), - ZetaChatItem, 'chat_item_slidable_actions', - before: (tester) async { + widgetType: ZetaChatItem, + setUp: (tester) async { tester.view.devicePixelRatio = 1.0; tester.view.physicalSize = const Size(481, 480); }, - after: (tester) async { + beforeComparison: (tester) async { final chatItemFinder = find.byType(ZetaChatItem); await tester.drag(chatItemFinder, const Offset(-200, 0)); await tester.pumpAndSettle(); }, ); - goldenTestWithCallbacks( + goldenTest( goldenFile, Column( children: [ @@ -644,20 +644,20 @@ void main() { ), ], ), - ZetaChatItem, 'chat_item_pale_slidable_buttons', - before: (tester) async { + widgetType: ZetaChatItem, + setUp: (tester) async { tester.view.devicePixelRatio = 1.0; tester.view.physicalSize = const Size(481, 480); }, - after: (tester) async { + beforeComparison: (tester) async { final chatItemFinder = find.byType(ZetaChatItem); await tester.drag(chatItemFinder, const Offset(-200, 0)); await tester.pumpAndSettle(); }, ); - goldenTestWithCallbacks( + goldenTest( goldenFile, Column( children: [ @@ -689,20 +689,20 @@ void main() { ), ], ), - ZetaChatItem, 'chat_item_pale_and_regular_buttons', - before: (tester) async { + widgetType: ZetaChatItem, + setUp: (tester) async { tester.view.devicePixelRatio = 1.0; tester.view.physicalSize = const Size(481, 480); }, - after: (tester) async { + beforeComparison: (tester) async { final chatItemFinder = find.byType(ZetaChatItem); await tester.drag(chatItemFinder, const Offset(-200, 0)); await tester.pumpAndSettle(); }, ); - goldenTestWithCallbacks( + goldenTest( goldenFile, Column( children: [ @@ -724,15 +724,15 @@ void main() { ), ], ), - ZetaChatItem, 'chat_item_custom_leading', - before: (tester) async { + widgetType: ZetaChatItem, + setUp: (tester) async { tester.view.devicePixelRatio = 1.0; tester.view.physicalSize = const Size(481, 480); }, ); - goldenTestWithCallbacks( + goldenTest( goldenFile, Column( children: [ @@ -756,20 +756,20 @@ void main() { ), ], ), - ZetaChatItem, 'chat_item_custom_slidable_buttons', - before: (tester) async { + widgetType: ZetaChatItem, + setUp: (tester) async { tester.view.devicePixelRatio = 1.0; tester.view.physicalSize = const Size(481, 480); }, - after: (tester) async { + beforeComparison: (tester) async { final chatItemFinder = find.byType(ZetaChatItem); await tester.drag(chatItemFinder, const Offset(-200, 0)); await tester.pumpAndSettle(); }, ); - goldenTestWithCallbacks( + goldenTest( goldenFile, Column( children: [ @@ -788,13 +788,13 @@ void main() { ), ], ), - ZetaChatItem, 'chat_item_small_screen_slidable_button', - before: (tester) async { + widgetType: ZetaChatItem, + setUp: (tester) async { tester.view.devicePixelRatio = 1.0; tester.view.physicalSize = const Size(315, 480); }, - after: (tester) async { + beforeComparison: (tester) async { final chatItemFinder = find.byType(ZetaChatItem); await tester.drag(chatItemFinder, const Offset(-200, 0)); await tester.pumpAndSettle(); diff --git a/test/src/components/checkbox/checkbox_test.dart b/test/src/components/checkbox/checkbox_test.dart index b718cef9..f0b6c598 100644 --- a/test/src/components/checkbox/checkbox_test.dart +++ b/test/src/components/checkbox/checkbox_test.dart @@ -139,14 +139,13 @@ void main() { }); }); group('Golden Tests', () { - goldenTestWithCallbacks( + goldenTest( goldenFile, ZetaCheckbox( onChanged: (value) {}, ), - ZetaCheckbox, 'checkbox_hover', - after: (tester) async { + beforeComparison: (tester) async { final checkboxFinder = find.byType(ZetaCheckbox); // Hover state @@ -165,7 +164,6 @@ void main() { value: true, onChanged: print, ), - ZetaCheckbox, 'checkbox_enabled', ); @@ -174,7 +172,6 @@ void main() { ZetaCheckbox( value: true, ), - ZetaCheckbox, 'checkbox_disabled', ); }); diff --git a/test/src/components/comms_button/comms_button_test.dart b/test/src/components/comms_button/comms_button_test.dart index 2ff9c648..539792c0 100644 --- a/test/src/components/comms_button/comms_button_test.dart +++ b/test/src/components/comms_button/comms_button_test.dart @@ -217,7 +217,6 @@ void main() { icon: ZetaIcons.phone, type: type, ), - ZetaCommsButton, 'CommsButton_${type.name}', ); } diff --git a/test/src/components/dialpad/dialpad_test.dart b/test/src/components/dialpad/dialpad_test.dart index b4f5cc7e..37575292 100644 --- a/test/src/components/dialpad/dialpad_test.dart +++ b/test/src/components/dialpad/dialpad_test.dart @@ -287,21 +287,18 @@ void main() { onNumber: print, onText: print, ), - ZetaDialPad, 'dialpad_enabled', screenSize: const Size(1000, 1000), ); goldenTest( goldenFile, const ZetaDialPad(), - ZetaDialPad, 'dialpad_disabled', screenSize: const Size(1000, 1000), ); goldenTest( goldenFile, const ZetaDialPadButton(primary: '1'), - ZetaDialPadButton, 'dialpadbutton', screenSize: const Size(1000, 1000), ); diff --git a/test/src/components/fab/fab_test.dart b/test/src/components/fab/fab_test.dart index 2820f8ef..636f8b80 100644 --- a/test/src/components/fab/fab_test.dart +++ b/test/src/components/fab/fab_test.dart @@ -211,15 +211,13 @@ void main() { label: 'Label', onPressed: () {}, ), - ZetaFAB, 'FAB_default', ); - goldenTestWithCallbacks( + goldenTest( goldenFile, ZetaFAB(scrollController: ScrollController(), label: 'Label', onPressed: () => {}), - ZetaFAB, 'FAB_pressed', - after: (tester) async { + beforeComparison: (tester) async { await tester.press(find.byType(ZetaFAB)); await tester.pumpAndSettle(); }, @@ -233,15 +231,13 @@ void main() { shape: ZetaWidgetBorder.rounded, size: ZetaFabSize.large, ), - ZetaFAB, 'FAB_inverse', ); - goldenTestWithCallbacks( + goldenTest( goldenFile, ZetaFAB(scrollController: ScrollController(), label: 'Label', onPressed: () => {}), - ZetaFAB, 'FAB_pressed', - after: (tester) async { + beforeComparison: (tester) async { await tester.press(find.byType(ZetaFAB)); await tester.pumpAndSettle(); }, @@ -255,13 +251,11 @@ void main() { type: ZetaFabType.secondary, shape: ZetaWidgetBorder.sharp, ), - ZetaFAB, 'FAB_secondary', ); goldenTest( goldenFile, ZetaFAB(scrollController: ScrollController(), label: 'Disabled'), - ZetaFAB, 'FAB_disabled', ); }); diff --git a/test/src/components/in_page_banner/in_page_banner_test.dart b/test/src/components/in_page_banner/in_page_banner_test.dart index f29bffed..8d840214 100644 --- a/test/src/components/in_page_banner/in_page_banner_test.dart +++ b/test/src/components/in_page_banner/in_page_banner_test.dart @@ -145,19 +145,16 @@ void main() { goldenTest( goldenFile, const ZetaInPageBanner(content: Text('Test'), title: 'Title'), - ZetaInPageBanner, 'in_page_banner_default', ); goldenTest( goldenFile, ZetaInPageBanner(content: const Text('Test'), onClose: () {}, status: ZetaWidgetStatus.negative), - ZetaInPageBanner, 'in_page_banner_negative', ); goldenTest( goldenFile, const ZetaInPageBanner(content: Text('Test'), status: ZetaWidgetStatus.positive), - ZetaInPageBanner, 'in_page_banner_positive', ); goldenTest( @@ -172,7 +169,6 @@ void main() { ), ], ), - ZetaInPageBanner, 'in_page_banner_buttons', ); }); diff --git a/test/src/components/password/password_input_test.dart b/test/src/components/password/password_input_test.dart index c67a7ad6..d31f0479 100644 --- a/test/src/components/password/password_input_test.dart +++ b/test/src/components/password/password_input_test.dart @@ -90,9 +90,9 @@ void main() { group('Styling Tests', () {}); group('Interaction Tests', () {}); group('Golden Tests', () { - goldenTest(goldenFile, ZetaPasswordInput(), ZetaPasswordInput, 'password_default'); + goldenTest(goldenFile, ZetaPasswordInput(), 'password_default'); final formKey = GlobalKey(); - goldenTestWithCallbacks( + goldenTest( goldenFile, Form( key: formKey, @@ -106,9 +106,8 @@ void main() { rounded: false, ), ), - ZetaPasswordInput, 'password_error', - after: (tester) async { + beforeComparison: (tester) async { formKey.currentState?.validate(); await tester.pump(); }, diff --git a/test/src/components/search_bar/search_bar_test.dart b/test/src/components/search_bar/search_bar_test.dart index 42e1ed7b..6869471a 100644 --- a/test/src/components/search_bar/search_bar_test.dart +++ b/test/src/components/search_bar/search_bar_test.dart @@ -219,14 +219,13 @@ void main() { }); }); group('Golden Tests', () { - goldenTest(goldenFile, ZetaSearchBar(), ZetaSearchBar, 'search_bar_default'); - goldenTest(goldenFile, ZetaSearchBar(), ZetaSearchBar, 'search_bar_medium'); + goldenTest(goldenFile, ZetaSearchBar(), 'search_bar_default'); + goldenTest(goldenFile, ZetaSearchBar(), 'search_bar_medium'); goldenTest( goldenFile, ZetaSearchBar( size: ZetaWidgetSize.small, ), - ZetaSearchBar, 'search_bar_small', ); goldenTest( @@ -234,7 +233,6 @@ void main() { ZetaSearchBar( shape: ZetaWidgetBorder.full, ), - ZetaSearchBar, 'search_bar_full', ); goldenTest( @@ -242,7 +240,6 @@ void main() { ZetaSearchBar( shape: ZetaWidgetBorder.sharp, ), - ZetaSearchBar, 'search_bar_sharp', ); }); diff --git a/test/src/components/tooltip/tooltip_test.dart b/test/src/components/tooltip/tooltip_test.dart index ef2e6efc..31453509 100644 --- a/test/src/components/tooltip/tooltip_test.dart +++ b/test/src/components/tooltip/tooltip_test.dart @@ -204,8 +204,8 @@ void main() { child: Text('Tooltip up'), ), ), - ZetaTooltip, 'arrow_up', + widgetType: ZetaTooltip, ); goldenTest( goldenFile, @@ -214,8 +214,8 @@ void main() { child: Text('Tooltip down'), ), ), - ZetaTooltip, 'arrow_down', + widgetType: ZetaTooltip, ); goldenTest( goldenFile, @@ -225,8 +225,8 @@ void main() { child: Text('Tooltip left'), ), ), - ZetaTooltip, 'arrow_left', + widgetType: ZetaTooltip, ); goldenTest( goldenFile, @@ -236,8 +236,8 @@ void main() { child: Text('Tooltip right'), ), ), - ZetaTooltip, 'arrow_right', + widgetType: ZetaTooltip, ); }); group('Performance Tests', () {}); diff --git a/test/src/components/top_app_bar/extended_top_app_bar_test.dart b/test/src/components/top_app_bar/extended_top_app_bar_test.dart deleted file mode 100644 index ecc49885..00000000 --- a/test/src/components/top_app_bar/extended_top_app_bar_test.dart +++ /dev/null @@ -1,169 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:zeta_flutter/zeta_flutter.dart'; - -import '../../../test_utils/test_app.dart'; -import '../../../test_utils/tolerant_comparator.dart'; -import '../../../test_utils/utils.dart'; - -void main() { - const goldenFile = GoldenFiles(component: 'top_app_bar'); - - setUpAll(() { - goldenFileComparator = TolerantComparator(goldenFile.uri); - }); - - testWidgets('ZetaExtendedAppBarDelegate builds correctly', (WidgetTester tester) async { - const title = Text('Title'); - final actions = [IconButton(icon: const Icon(Icons.search), onPressed: () {})]; - final leading = IconButton(icon: const Icon(Icons.menu), onPressed: () {}); - const boxKey = Key('box'); - tester.view.devicePixelRatio = 1.0; - tester.view.physicalSize = const Size(481, 480); - - await tester.pumpWidget( - TestApp( - home: Builder( - builder: (context) { - return SizedBox( - child: CustomScrollView( - slivers: [ - ZetaTopAppBar.extended(leading: leading, title: title, actions: actions), - SliverToBoxAdapter( - child: Container( - width: 800, - height: 700, - color: Zeta.of(context).colors.surfaceSelectedHover, - key: boxKey, - ), - ), - ], - ), - ); - }, - ), - ), - ); - - final boxFinder = find.byKey(boxKey); - expect(boxFinder, findsOneWidget); - - await tester.drag(boxFinder.first, const Offset(0, -100)); - await tester.pumpAndSettle(); - - final appBarFinder = find.byType(ZetaTopAppBar); - expect(appBarFinder, findsOneWidget); - - final titleFinder = find.descendant(of: appBarFinder, matching: find.byWidget(title)); - expect(titleFinder, findsOneWidget); - - final actionsFinder = find.descendant(of: appBarFinder, matching: find.byWidget(actions[0])); - expect(actionsFinder, findsOneWidget); - - final leadingFinder = find.descendant(of: appBarFinder, matching: find.byWidget(leading)); - expect(leadingFinder, findsOneWidget); - - await expectLater( - appBarFinder, - matchesGoldenFile(goldenFile.getFileUri('extended_app_bar_shrinks')), - ); - }); - - testWidgets('ZetaExtendedAppBarDelegate shrinks correctly with padding', (WidgetTester tester) async { - const title = Text('Title'); - final actions = [IconButton(icon: const Icon(Icons.search), onPressed: () {})]; - final leading = IconButton(icon: const Icon(Icons.menu), onPressed: () {}); - const boxKey = Key('box'); - tester.view.devicePixelRatio = 1.0; - tester.view.physicalSize = const Size(481, 480); - - await tester.pumpWidget( - TestApp( - home: Builder( - builder: (context) { - return SizedBox( - child: CustomScrollView( - slivers: [ - ZetaTopAppBar.extended(leading: leading, title: title, actions: actions), - SliverToBoxAdapter( - child: Container( - width: 800, - height: 700, - color: Zeta.of(context).colors.surfaceSelectedHover, - key: boxKey, - ), - ), - ], - ), - ); - }, - ), - ), - ); - - final boxFinder = find.byKey(boxKey); - expect(boxFinder, findsOneWidget); - - await tester.drag(boxFinder.first, const Offset(0, -100)); - await tester.pumpAndSettle(); - - final appBarFinder = find.byType(ZetaTopAppBar); - expect(appBarFinder, findsOneWidget); - - final positionedFinder = find.descendant(of: appBarFinder, matching: find.byType(Positioned)); - - final positionedWidget = tester.widget(positionedFinder.first); - expect(positionedWidget.left, 60); - }); - testWidgets('ZetaExtendedAppBarDelegate shrinks correctly with padding and no leading', (WidgetTester tester) async { - const title = Text('Title'); - final actions = [IconButton(icon: const Icon(Icons.search), onPressed: () {})]; - - const boxKey = Key('box'); - tester.view.devicePixelRatio = 1.0; - tester.view.physicalSize = const Size(481, 480); - - await tester.pumpWidget( - TestApp( - home: Builder( - builder: (context) { - return SizedBox( - child: CustomScrollView( - slivers: [ - ZetaTopAppBar.extended(title: title, actions: actions), - SliverToBoxAdapter( - child: Container( - width: 800, - height: 700, - color: Zeta.of(context).colors.surfaceSelectedHover, - key: boxKey, - ), - ), - ], - ), - ); - }, - ), - ), - ); - - final boxFinder = find.byKey(boxKey); - expect(boxFinder, findsOneWidget); - - await tester.drag(boxFinder.first, const Offset(0, -100)); - await tester.pumpAndSettle(); - - final appBarFinder = find.byType(ZetaTopAppBar); - expect(appBarFinder, findsOneWidget); - - final positionedFinder = find.descendant(of: appBarFinder, matching: find.byType(Positioned)); - - final positionedWidget = tester.widget(positionedFinder.first); - expect(positionedWidget.left, 16); - - await expectLater( - appBarFinder, - matchesGoldenFile(goldenFile.getFileUri('extended_app_bar_shrinks_with_no_leading')), - ); - }); -} diff --git a/test/src/components/top_app_bar/golden/extended_app_bar_shrinks.png b/test/src/components/top_app_bar/golden/extended_app_bar_shrinks.png index 6a0c1237cf93e0ebf43cfba27e66b14b132d73f0..b821a451129da3c390ff8bf6b7a53bba842d0ce6 100644 GIT binary patch delta 214 zcmV;{04e{r5rYtrKsX1jNkl#N0zoz8QV&qO-tP4X{CGVd^#}l)SvA5-1VfVuY2 zAji=F5D{Sjh-`KzJa?UUR|~*W{?JZ~kD*xIbn=k-GL>K@fs~$(s z{dE)oEM*T3n#LHT9s&T4$Z<520RubW Q&;S4c07*qoM6N<$f{Bb(egFUf delta 403 zcmV;E0c`$*5VjGJKv4)_Nkl^?>~H; zW!B?I56ABA?tjm@xVRioo<5&tC+6|)!IgXBA&NA!m z@tbjQa4^d(0Peoq(jean13*L@gaIJ3vL9ys&2j$h>}))H{$lAn0k9d?wLwmkF#{%M ztn6n zz3hg-af~qz0Kn=_^#A~{SCg>6+J zg@xl7W7IpNa;drK74U;IbOWn zop&Qva&&kwHa8#DYXGFKuCB)MhmW(&dj9O`*x1;ZW!7ygorD44e{^|yIrjG6%rfi! z!Mm}&y*9-n^wt%iEl@Zd>U(dTnhn z-zLmr;VS_cTU$@Ym(QQ-HGXL^P195_0RRt?>u8hV0v!rjo_?!W0Dyi1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9jkefq`d%r;B4q#hkY{4fC7~MO+;_9_3DG`@6nFEwU}v;rGjn8>iS`whiBI z`>FKY&pk3dhI&9V=5M%GwR`_IT}B25KlcWpfFvUm149Z62Lr{CZ^id*8=LpvKmLxBVfiC=76yhB90Cjs3d#-)3=KUDKzA82QC08^(DycWJ%-=b z0?qz6b?dd;Z|PtwEqpR+CUsNBXn2l>Cryi<(F8V{z(x}ojq3H$%r%<1Ml;u7&RqI8 YoJG68O?jIO>}D`{y85}Sb4q9e0BEq&TL1t6 literal 0 HcmV?d00001 diff --git a/test/src/components/top_app_bar/golden/top_app_bar_centered_actions.png b/test/src/components/top_app_bar/golden/top_app_bar_centered_actions.png new file mode 100644 index 0000000000000000000000000000000000000000..2e6ac8905707721ac0468b183533928959430eaf GIT binary patch literal 3368 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9jkefr00er;B4q#hkad4D${-h&VWQ+{kt~{MX-w`S=FzOS42KD&6GQK2uV* z@%5=&%l9A8oHeh#)$kZ2149DuXPf;t^?ToXGcYvtD?0$m9tNPe5fcjo!wC)n1_lM{ z2`<+aw~t@9dd=q@_roID85rzN%AJ3#roh19;MM^2(@fv>3A%qvb2eYw!I6;v=l-{& zrtuGg-#oR+V`5@pNMYe%V3;5XS1rj%gy6G~+>(7UtJea(CI78R&YThMwVW!}*M<9Y zciJ#8eCW2Fcih(ji`R?iEPJ`L#_(9h{p&#Y{Xb=MUjID8y+pYH?6Xmo0P*k7DwfGmP<;~#f>gTe~ HDWM4fECsX^K{bj=L_t(|obB1M4Z=_m1wq@Q4oK*~A`)oi$Y=m-f8dz{PA^^E zJ~Oic000Dz)dK(kfa?&G5dl~f=63eM`{Q}`N&fJ8zgABG0DvDKk)KnMo)8NA%*^T$ o006)>__Lt_K?{?R0Xi1u3kcE=shp6hX#fBK07*qoM6N<$f*BMyUjP6A diff --git a/test/src/components/top_app_bar/golden/top_app_bar_default_actions.png b/test/src/components/top_app_bar/golden/top_app_bar_default_actions.png new file mode 100644 index 0000000000000000000000000000000000000000..725391c67186a18f8874677ea7a215d9400ffff5 GIT binary patch literal 3368 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9jkefr00er;B4q#hkad4D${-h&VWQd@x<`@Spmk#^f8UnY^x3JiZ<7O1Ij5 z<8IOXe{#nQYvj_}5-ot{=p@csHvRqj{<$m+3^!yMnHU&SSU4CMCI~7pFgUn1098m* zP0(`f&L2OEVpHZG|GVvk6$8Tt_2@nQvk`WL)i#-azrOKo(Bnl*bHBz^KdqEwIPgB_ zsa+lux$b%vl3TJbX7ySIh6eNKooJSQ-Esd~j2r{QkAq_GAFE;Wuw~!lA9Maov^^|d z&d9*akNGltqn(O j!_nGsv^J!mHvG&h@kD)MZ=^>k0}yz+`njxgN@xNAc^vO< literal 0 HcmV?d00001 diff --git a/test/src/components/top_app_bar/golden/top_app_bar_extended.png b/test/src/components/top_app_bar/golden/top_app_bar_extended.png new file mode 100644 index 0000000000000000000000000000000000000000..11817f09010e5788b6376c6fc6f8fe23360e7e14 GIT binary patch literal 2231 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9jkefq^5@)5S5QV$R!}8+n-=1y~&A1lcW~$P4nRY;tKhy7K&wRSaQ|w|$#2 zb0bar=14Ba(10w^25fcjo!wC)n1_lM?Q9&#La^~%Q=I_Ug&k9ZZu_u1F zIs?N2e>(*R1_!qW1_lO6MkWS^6c!E!h6#ey73`Zi^R6;5l8QetVsR9`q7LZAQ7{?; lqaiRF0;3@?GD9HZ5%=eF+$T3*YKsR2fTydU%Q~loCIFGPcvAoX literal 0 HcmV?d00001 diff --git a/test/src/components/top_app_bar/golden/top_app_bar_extended_actions.png b/test/src/components/top_app_bar/golden/top_app_bar_extended_actions.png new file mode 100644 index 0000000000000000000000000000000000000000..9677a10eccda3469eb87b6551f832072095b43c0 GIT binary patch literal 2271 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9jkefq|pb)5S5QV$R!J2Q!Zth`3&~*uhu*_@DNyvp&jR%)(9`JDPsXVLEa< zZr?V;V?TiUIcnC)0jWFf42%p6MocUW3@11Q7#I|k9T*rIdZ;G&W;Hv|mSUObrcdWy z|7`elZg~vCf_({$3kFZ_dI1{Vqi#N;b35x zaPyc%@>d|^fgF;hH1jGr_%{Fl+W2_SGo8e)>z_AP0bNpanrv?o9}8#9j!CR`2Zq7- z2MFH_DljlOxHSMpB^lvCLR&$gU87($1V%$(Gz3ONU_^$1!BO$Yjbhr{7Ju0d^1r96 KpUXO@geCw%a+cBn literal 0 HcmV?d00001 diff --git a/test/src/components/top_app_bar/golden/top_app_bar_search.png b/test/src/components/top_app_bar/golden/top_app_bar_search.png new file mode 100644 index 0000000000000000000000000000000000000000..00604a3329e24a8be851d99fc2a14ac196194b0c GIT binary patch literal 3320 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9jkefq`d{r;B4q#hkY{cjq!23OG1=8r+^B^fi8>@NOQX372;N`EYLj%p6G_ zv)Tux=YHi1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9ji|s42$_5I)B4<9c-4@{nKQ)eRc=Ka~Pb(b zd}|*o14E2_n1j;#`+H{{!%J$x5K{X=dau^Kh9RaK76wO^3vG)zwhQg z{Br&M#mC#t%-f!ypVueH&v2lIQ-FaXLU4WDz8#mIANyBXC(5^wnMhwAYvy2NNO0Bp z#Mm4@mG#88b9tqj3=9uuZDQqSU^sE33FtQS8wda0E7-7q`*mEnyK?XFK@x;!{5W2fzEN=eDlqvY;6V9FrUN7$iN_WOcLne zgiM;n3N2!K)XWA3BGVL=^Vn#}kA^%=3-QqeHk!aj6BvzJNTZo+G;@t+F1lx~XZ#m` XxUFB_b!G{$)yClI>gTe~DWM4fbchsZ literal 0 HcmV?d00001 diff --git a/test/src/components/top_app_bar/golden/top_app_bar_search_centered.png b/test/src/components/top_app_bar/golden/top_app_bar_search_centered.png new file mode 100644 index 0000000000000000000000000000000000000000..e65986b06df85d9e2a14d90ddda07960616ef33a GIT binary patch literal 3319 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYV2a>i1B%QlYbpRzjKx9jP7LeL$-D$|Sc;uI zLpXq-h9jkefq`eCr;B4q#hkY{Hx@b>inux^tTFR>^iNyKFx7+6Ptn}nc>ditn!8>~ z&V4?o|MFzRW1I{O5A4@$jeB=`n<@jtf#ZTe>m1w~fF?^aGBGfuuy8OiOrV+Iv+VB- z4U2#5`}bzv0qMK-`McE_WSZm!7#I|k9T*rIdKefP7>t-$7#L1)P*?D|<@3is6MHu1 z^D;0LXk@RQew&}B9;I7|j#@;AWIGzjqk%kHT+p+k7|n5`Ic_w^jpjJ|G)qTI8=93i b{}}2fi*`RL+OY}P#bEGs^>bP0l+XkKty7{Y literal 0 HcmV?d00001 diff --git a/test/src/components/top_app_bar/top_app_bar_test.dart b/test/src/components/top_app_bar/top_app_bar_test.dart index 82c537c4..8ae60e83 100644 --- a/test/src/components/top_app_bar/top_app_bar_test.dart +++ b/test/src/components/top_app_bar/top_app_bar_test.dart @@ -7,7 +7,6 @@ import '../../../test_utils/tolerant_comparator.dart'; import '../../../test_utils/utils.dart'; void main() { - const String componentName = 'ZetaTopAppbar'; const String parentFolder = 'top_app_bar'; const goldenFile = GoldenFiles(component: parentFolder); @@ -15,8 +14,8 @@ void main() { goldenFileComparator = TolerantComparator(goldenFile.uri); }); - group('$componentName Accessibility Tests', () { - testWidgets('$componentName meets accessibility requirements', (WidgetTester tester) async { + group('ZetaTopAppBar Accessibility Tests', () { + testWidgets('ZetaTopAppBar meets accessibility requirements', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); await tester.pumpWidget( TestApp( @@ -27,7 +26,7 @@ void main() { icon: const Icon(Icons.search), tooltip: 'Search', onPressed: () {}, - ) + ), ], leading: IconButton( icon: const Icon(Icons.menu), @@ -45,7 +44,7 @@ void main() { handle.dispose(); }); - testWidgets('$componentName passes semantic labels to the search actions', (WidgetTester tester) async { + testWidgets('ZetaTopAppBar passes semantic labels to the search actions', (WidgetTester tester) async { const microphoneSemanticLabel = 'Search with voice'; const clearSemanticLabel = 'Clear search'; const searchBackSemanticLabel = 'Back'; @@ -88,7 +87,7 @@ void main() { }); }); - group('$componentName Content Tests', () { + group('ZetaTopAppBar Content Tests', () { final debugFillProperties = { 'titleTextStyle': 'null', 'onSearch': 'null', @@ -98,16 +97,157 @@ void main() { 'searchHintText': 'null', 'type': 'defaultAppBar', 'shrinks': 'false', + 'clearSemanticLabel': 'null', + 'microphoneSemanticLabel': 'null', + 'searchSemanticLabel': 'null', + 'searchBackSemanticLabel': 'null', }; debugFillPropertiesTest( const ZetaTopAppBar(), debugFillProperties, ); + + test( + 'ZetaTopAppBar Search throws an assertion error if its type is set to extended', + () { + expect( + () => ZetaTopAppBar.search( + title: const Text('Title'), + type: ZetaTopAppBarType.extended, + ), + throwsA(isA()), + ); + }, + ); + + testWidgets('ZetaTopAppBar displays the title correctly', (WidgetTester tester) async { + await tester.pumpWidget( + const TestApp( + home: ZetaTopAppBar( + title: Text('Title'), + ), + ), + ); + + expect(find.text('Title'), findsOneWidget); + }); + + testWidgets('ZetaTopAppBar displays the leading widget correctly', (WidgetTester tester) async { + await tester.pumpWidget( + TestApp( + home: ZetaTopAppBar( + title: const Text('Title'), + leading: IconButton( + icon: const Icon(Icons.menu), + onPressed: () {}, + ), + ), + ), + ); + + expect(find.byIcon(Icons.menu), findsOneWidget); + }); + + testWidgets('ZetaTopAppBar displays the actions correctly', (WidgetTester tester) async { + await tester.pumpWidget( + TestApp( + home: ZetaTopAppBar( + title: const Text('Title'), + actions: [ + IconButton( + icon: const Icon(Icons.search), + onPressed: () {}, + ), + ], + ), + ), + ); + + expect(find.byIcon(Icons.search), findsOneWidget); + }); + + testWidgets('ZetaExtendedAppBarDelegate builds correctly', (WidgetTester tester) async { + const title = Text('Title'); + final actions = [IconButton(icon: const Icon(Icons.search), onPressed: () {})]; + final leading = IconButton(icon: const Icon(Icons.menu), onPressed: () {}); + const boxKey = Key('box'); + + await tester.pumpWidget( + TestApp( + home: Builder( + builder: (context) { + return SizedBox( + child: CustomScrollView( + slivers: [ + ZetaTopAppBar.extended(leading: leading, title: title, actions: actions), + SliverToBoxAdapter( + child: Container( + width: 800, + height: 700, + color: Zeta.of(context).colors.surfaceSelectedHover, + key: boxKey, + ), + ), + ], + ), + ); + }, + ), + ), + ); + + final boxFinder = find.byKey(boxKey); + expect(boxFinder, findsOneWidget); + + await tester.drag(boxFinder.first, const Offset(0, -100)); + await tester.pumpAndSettle(); + + final appBarFinder = find.byType(ZetaTopAppBar); + expect(appBarFinder, findsOneWidget); + + final titleFinder = find.descendant(of: appBarFinder, matching: find.byWidget(title)); + expect(titleFinder, findsOneWidget); + + final actionsFinder = find.descendant(of: appBarFinder, matching: find.byWidget(actions[0])); + expect(actionsFinder, findsOneWidget); + + final leadingFinder = find.descendant(of: appBarFinder, matching: find.byWidget(leading)); + expect(leadingFinder, findsOneWidget); + }); }); - group('$componentName Dimensions Tests', () {}); - group('$componentName Styling Tests', () {}); - group('$componentName Interaction Tests', () { + group('ZetaTopAppBar Dimensions Tests', () { + testWidgets('ZetaTopAppBar has the correct height', (WidgetTester tester) async { + await tester.pumpWidget( + const TestApp( + home: ZetaTopAppBar( + title: Text('Title'), + ), + ), + ); + + final appBar = tester.widget(find.byType(AppBar)); + expect(appBar.preferredSize.height, 64); + }); + }); + + group('ZetaTopAppBar Styling Tests', () { + testWidgets('ZetaTopAppBar has the correct background color', (WidgetTester tester) async { + await tester.pumpWidget( + const TestApp( + home: ZetaTopAppBar( + title: Text('Title'), + ), + ), + ); + + final BuildContext context = tester.element(find.byType(MaterialApp)); + final appBar = tester.widget(find.byType(AppBar)); + expect(appBar.backgroundColor, Zeta.of(context).colors.surfaceDefault); + }); + }); + + group('ZetaTopAppBar Interaction Tests', () { late ZetaSearchController searchController; const searchLabel = 'Search'; const clearLabel = 'Clear'; @@ -129,7 +269,7 @@ void main() { }); testWidgets( - '$componentName Search opens and closes the search bar when the search/back icon is tapped', + 'ZetaTopAppBar Search opens and closes the search bar when the search/back icon is tapped', (WidgetTester tester) async { await tester.pumpWidget(subject); @@ -147,7 +287,7 @@ void main() { ); testWidgets( - '$componentName Search allows text to be typed in the search field', + 'ZetaTopAppBar Search allows text to be typed in the search field', (WidgetTester tester) async { await tester.pumpWidget(subject); @@ -160,7 +300,7 @@ void main() { ); testWidgets( - '$componentName Search gets cleared when the clear button is tapped', + 'ZetaTopAppBar Search gets cleared when the clear button is tapped', (WidgetTester tester) async { await tester.pumpWidget(subject); @@ -174,7 +314,7 @@ void main() { ); testWidgets( - '$componentName Search submits the correct text when the search input is submitted', + 'ZetaTopAppBar Search submits the correct text when the search input is submitted', (WidgetTester tester) async { String inputtedText = ''; await tester.pumpWidget( @@ -197,18 +337,221 @@ void main() { expect(inputtedText, 'Search text'); }, ); + + testWidgets('ZetaExtendedAppBarDelegate shrinks correctly with padding', (WidgetTester tester) async { + const title = Text('Title'); + final actions = [IconButton(icon: const Icon(Icons.search), onPressed: () {})]; + final leading = IconButton(icon: const Icon(Icons.menu), onPressed: () {}); + const boxKey = Key('box'); + + await tester.pumpWidget( + TestApp( + home: Builder( + builder: (context) { + return SizedBox( + child: CustomScrollView( + slivers: [ + ZetaTopAppBar.extended(leading: leading, title: title, actions: actions), + SliverToBoxAdapter( + child: Container( + width: 800, + height: 700, + color: Zeta.of(context).colors.surfaceSelectedHover, + key: boxKey, + ), + ), + ], + ), + ); + }, + ), + ), + ); + + final boxFinder = find.byKey(boxKey); + expect(boxFinder, findsOneWidget); + + await tester.drag(boxFinder.first, const Offset(0, -100)); + await tester.pumpAndSettle(); + + final appBarFinder = find.byType(ZetaTopAppBar); + expect(appBarFinder, findsOneWidget); + + final positionedFinder = find.descendant(of: appBarFinder, matching: find.byType(Positioned)); + + final positionedWidget = tester.widget(positionedFinder.first); + expect(positionedWidget.left, 64); + }); + + testWidgets('ZetaExtendedAppBarDelegate shrinks correctly with padding and no leading', + (WidgetTester tester) async { + const title = Text('Title'); + final actions = [IconButton(icon: const Icon(Icons.search), onPressed: () {})]; + + const boxKey = Key('box'); + + await tester.pumpWidget( + TestApp( + home: Builder( + builder: (context) { + return SizedBox( + child: CustomScrollView( + slivers: [ + ZetaTopAppBar.extended(title: title, actions: actions), + SliverToBoxAdapter( + child: Container( + width: 800, + height: 700, + color: Zeta.of(context).colors.surfaceSelectedHover, + key: boxKey, + ), + ), + ], + ), + ); + }, + ), + ), + ); + + final boxFinder = find.byKey(boxKey); + expect(boxFinder, findsOneWidget); + + await tester.drag(boxFinder.first, const Offset(0, -100)); + await tester.pumpAndSettle(); + + final appBarFinder = find.byType(ZetaTopAppBar); + expect(appBarFinder, findsOneWidget); + + final positionedFinder = find.descendant(of: appBarFinder, matching: find.byType(Positioned)); + + final positionedWidget = tester.widget(positionedFinder.first); + expect(positionedWidget.left, 16); + }); }); - group('$componentName Golden Tests', () { + group('ZetaTopAppBar Golden Tests', () { goldenTest( goldenFile, const ZetaTopAppBar( title: Text('Title'), ), - ZetaTopAppBar, 'top_app_bar_default', ); + + goldenTest( + goldenFile, + ZetaTopAppBar( + title: const Text('Title'), + leading: IconButton(onPressed: () {}, icon: const Icon(Icons.menu)), + actions: [ + IconButton( + icon: const Icon(Icons.search), + tooltip: 'Search', + onPressed: () {}, + ), + ], + ), + 'top_app_bar_default_actions', + ); + + goldenTest( + goldenFile, + const ZetaTopAppBar.centered( + title: Text('Title'), + ), + 'top_app_bar_centered', + ); + + goldenTest( + goldenFile, + ZetaTopAppBar.centered( + leading: IconButton(onPressed: () {}, icon: const Icon(Icons.menu)), + actions: [ + IconButton( + icon: const Icon(Icons.search), + tooltip: 'Search', + onPressed: () {}, + ), + ], + title: const Text('Title'), + ), + 'top_app_bar_centered_actions', + ); + + goldenTest( + goldenFile, + const ZetaTopAppBar.search( + title: Text('Search'), + ), + 'top_app_bar_search', + ); + + goldenTest( + goldenFile, + const ZetaTopAppBar.search( + title: Text('Search'), + type: ZetaTopAppBarType.centered, + ), + 'top_app_bar_search_centered', + ); + + final searchController = ZetaSearchController(); + goldenTest( + goldenFile, + ZetaTopAppBar.search( + title: const Text('Search'), + type: ZetaTopAppBarType.centered, + searchController: searchController, + ), + beforeComparison: (tester) async { + searchController.startSearch(); + await tester.pumpAndSettle(); + }, + 'top_app_bar_search_active', + ); + + goldenTest( + goldenFile, + const CustomScrollView( + slivers: [ + ZetaTopAppBar.extended( + title: Text('Title'), + ), + ], + ), + widgetType: ZetaTopAppBar, + beforeComparison: (tester) async { + searchController.startSearch(); + await tester.pumpAndSettle(); + }, + 'top_app_bar_extended', + ); + + goldenTest( + goldenFile, + CustomScrollView( + slivers: [ + ZetaTopAppBar.extended( + title: const Text('Title'), + actions: [ + IconButton( + icon: const Icon(Icons.search), + tooltip: 'Search', + onPressed: () {}, + ), + ], + ), + ], + ), + widgetType: ZetaTopAppBar, + beforeComparison: (tester) async { + searchController.startSearch(); + await tester.pumpAndSettle(); + }, + 'top_app_bar_extended_actions', + ); }); - group('$componentName Performance Tests', () {}); + group('ZetaTopAppBar Performance Tests', () {}); } diff --git a/test/test_utils/utils.dart b/test/test_utils/utils.dart index 5117d045..ec5c9704 100644 --- a/test/test_utils/utils.dart +++ b/test/test_utils/utils.dart @@ -34,13 +34,19 @@ class GoldenFiles { void goldenTest( GoldenFiles goldenFile, Widget widget, - Type widgetType, String fileName, { + Type? widgetType, ThemeMode themeMode = ThemeMode.system, Size? screenSize, bool? rounded, + Future Function(WidgetTester)? setUp, + Future Function(WidgetTester)? beforeComparison, }) { testWidgets('$fileName golden', (WidgetTester tester) async { + final computedType = widgetType ?? widget.runtimeType; + if (setUp != null) { + await setUp(tester); + } await tester.pumpWidget( TestApp( screenSize: screenSize, @@ -50,42 +56,12 @@ void goldenTest( ), ); - await expectLater( - find.byType(widgetType), - matchesGoldenFile(goldenFile.getFileUri(fileName)), - ); - }); -} - -void goldenTestWithCallbacks( - GoldenFiles goldenFile, - Widget widget, - Type widgetType, - String fileName, { - Future Function(WidgetTester)? before, - Future Function(WidgetTester)? after, - bool darkMode = false, - Size? screenSize, -}) { - testWidgets('$fileName golden', (WidgetTester tester) async { - if (before != null) { - await before(tester); - } - - await tester.pumpWidget( - TestApp( - screenSize: screenSize, - themeMode: darkMode ? ThemeMode.dark : ThemeMode.light, - home: widget, - ), - ); - - if (after != null) { - await after(tester); + if (beforeComparison != null) { + await beforeComparison(tester); } await expectLater( - find.byType(widgetType), + find.byType(computedType), matchesGoldenFile(goldenFile.getFileUri(fileName)), ); }); From 5ad47ec1aeccb1e319f48335fb0f387436a0a1ca Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 16 Oct 2024 13:25:46 +0000 Subject: [PATCH 5/7] chore(automated): Lint commit and format --- example/macos/Flutter/GeneratedPluginRegistrant.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/macos/Flutter/GeneratedPluginRegistrant.swift b/example/macos/Flutter/GeneratedPluginRegistrant.swift index 63ad0d13..8c72a8c7 100644 --- a/example/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -7,7 +7,7 @@ import Foundation import path_provider_foundation import shared_preferences_foundation -import sqflite +import sqflite_darwin import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { From fd6026f125239b0d4b10e1b25cac08dca85d8621 Mon Sep 17 00:00:00 2001 From: mikecoomber Date: Thu, 17 Oct 2024 12:24:50 +0100 Subject: [PATCH 6/7] added widgetbook for extended appbar back --- example/widgetbook/main.dart | 1 + .../components/top_app_bar_widgetbook.dart | 63 ++++++++++++++++++- 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/example/widgetbook/main.dart b/example/widgetbook/main.dart index a24e9628..5397a190 100644 --- a/example/widgetbook/main.dart +++ b/example/widgetbook/main.dart @@ -126,6 +126,7 @@ class _HotReloadState extends State { useCases: [ WidgetbookUseCase(name: 'Default', builder: (context) => defaultTopAppBarUseCase(context)), WidgetbookUseCase(name: 'Search', builder: (context) => searchTopAppBarUseCase(context)), + WidgetbookUseCase(name: 'Extended', builder: (context) => extendedTopAppBarUseCase(context)), ], ), WidgetbookComponent( diff --git a/example/widgetbook/pages/components/top_app_bar_widgetbook.dart b/example/widgetbook/pages/components/top_app_bar_widgetbook.dart index 0c5ec54a..ecc9b378 100644 --- a/example/widgetbook/pages/components/top_app_bar_widgetbook.dart +++ b/example/widgetbook/pages/components/top_app_bar_widgetbook.dart @@ -122,6 +122,67 @@ class _SearchUseCaseState extends State<_SearchUseCase> { } } +Widget extendedTopAppBarUseCase(BuildContext context) => ExtendedTopAppBar(); + +class ExtendedTopAppBar extends StatefulWidget { + const ExtendedTopAppBar({super.key}); + + @override + State createState() => _ExtendedTopAppBarState(); +} + +class _ExtendedTopAppBarState extends State { + @override + Widget build(BuildContext context) { + final title = context.knobs.string(label: "Title", initialValue: "Title"); + + final leadingIcon = iconKnob(context, name: 'Leading Icon', initial: ZetaIcons.hamburger_menu); + + return WidgetbookScaffold( + removeBody: true, + builder: (context, constraints) => SafeArea( + child: SizedBox( + width: constraints.maxWidth, + height: constraints.maxHeight, + child: CustomScrollView( + slivers: [ + ZetaTopAppBar.extended( + leading: IconButton(icon: ZetaIcon(leadingIcon), onPressed: () {}), + title: Text(title), + actions: [ + IconButton( + onPressed: () {}, + icon: ZetaIcon(Icons.language), + ), + IconButton( + onPressed: () {}, + icon: ZetaIcon(Icons.favorite), + ), + IconButton( + onPressed: () {}, + icon: ZetaIcon(ZetaIcons.more_vertical), + ) + ], + ), + SliverToBoxAdapter( + child: Container( + width: constraints.maxWidth, + height: constraints.maxHeight * 4, + color: Zeta.of(context).colors.surfaceSecondary, + child: CustomPaint( + painter: Painter(context: context, constraints: constraints), + size: Size(constraints.maxWidth, constraints.maxHeight * 4), + ), + ), + ), + ], + ), + ), + ), + ); + } +} + class Painter extends CustomPainter { final BuildContext context; final BoxConstraints constraints; @@ -133,7 +194,7 @@ class Painter extends CustomPainter { var p1 = Offset(i, -10); var p2 = Offset(constraints.maxHeight + i, constraints.maxHeight * 4); var paint = Paint() - ..color = Zeta.of(context).colors.primary + ..color = Zeta.of(context).colors.surfacePrimarySubtle ..strokeWidth = Zeta.of(context).spacing.minimum; canvas.drawLine(p1, p2, paint); } From 65c1e3cdb2cea7c3b140e9fb0ae6dc75e0cf87ce Mon Sep 17 00:00:00 2001 From: mikecoomber Date: Thu, 17 Oct 2024 12:25:49 +0100 Subject: [PATCH 7/7] ci: changed pull request code coverage pass score --- .github/workflows/pull-request.yml | 36 +++++++++---------- .../components/top_app_bar/top_app_bar.dart | 2 ++ 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index a55af954..04b742f7 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -1,32 +1,30 @@ name: CI - Pull Request on: pull_request_target: - + # Pull Request Runs on the same branch will be cancelled concurrency: group: ${{ github.head_ref }} cancel-in-progress: true - jobs: code-quality: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - repository: ${{github.event.pull_request.head.repo.full_name}} - ref: ${{ github.head_ref }} - fetch-depth: 0 - - uses: subosito/flutter-action@v2 - with: - cache: true - - run: dart run build_runner build --delete-conflicting-outputs - - uses: ZebraDevs/flutter-code-quality@main - with: - token: ${{secrets.GITHUB_TOKEN}} - coverage-pass-score: '90' - - + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + repository: ${{github.event.pull_request.head.repo.full_name}} + ref: ${{ github.head_ref }} + fetch-depth: 0 + - uses: subosito/flutter-action@v2 + with: + cache: true + - run: dart run build_runner build --delete-conflicting-outputs + - uses: ZebraDevs/flutter-code-quality@main + with: + token: ${{secrets.GITHUB_TOKEN}} + coverage-pass-score: "80" + check-secret: runs-on: ubuntu-latest outputs: diff --git a/lib/src/components/top_app_bar/top_app_bar.dart b/lib/src/components/top_app_bar/top_app_bar.dart index 86ff8a10..07030848 100644 --- a/lib/src/components/top_app_bar/top_app_bar.dart +++ b/lib/src/components/top_app_bar/top_app_bar.dart @@ -8,6 +8,8 @@ import 'search_top_app_bar.dart'; export 'search_top_app_bar.dart' hide ZetaTopAppBarSearchField; /// Top app bars provide content and actions related to the current screen. +/// +/// To create Extended, Centered, or Search app bars, use the respective constructors. /// {@category Components} /// /// Figma: https://www.figma.com/design/JesXQFLaPJLc1BdBM4sisI/%F0%9F%A6%93-ZDS---Components?node-id=229-37&node-type=canvas&m=dev