From 53af9e77f6909236a968aa5d3c6a32ba04712fda Mon Sep 17 00:00:00 2001 From: atanasyordanov21 <63714308+atanasyordanov21@users.noreply.github.com> Date: Mon, 29 Apr 2024 17:53:40 +0300 Subject: [PATCH] feat: Filter Selection (#36) * Filter Selection * use divide --- example/lib/home.dart | 2 + .../components/filter_selection_example.dart | 54 +++++++++++++++++ example/widgetbook/main.dart | 2 + .../filter_selection_widgetbook.dart | 37 ++++++++++++ lib/src/components/chips/chip.dart | 5 +- lib/src/components/chips/filter_chip.dart | 13 ++++ .../filter_selection/filter_selection.dart | 60 +++++++++++++++++++ lib/zeta_flutter.dart | 1 + 8 files changed, 172 insertions(+), 2 deletions(-) create mode 100644 example/lib/pages/components/filter_selection_example.dart create mode 100644 example/widgetbook/pages/components/filter_selection_widgetbook.dart create mode 100644 lib/src/components/filter_selection/filter_selection.dart diff --git a/example/lib/home.dart b/example/lib/home.dart index 3a55cec8..5e7db604 100644 --- a/example/lib/home.dart +++ b/example/lib/home.dart @@ -14,6 +14,7 @@ import 'package:zeta_example/pages/components/date_input_example.dart'; import 'package:zeta_example/pages/components/dialog_example.dart'; import 'package:zeta_example/pages/components/dialpad_example.dart'; import 'package:zeta_example/pages/components/dropdown_example.dart'; +import 'package:zeta_example/pages/components/filter_selection_example.dart'; import 'package:zeta_example/pages/components/list_item_example.dart'; import 'package:zeta_example/pages/components/navigation_bar_example.dart'; import 'package:zeta_example/pages/components/navigation_rail_example.dart'; @@ -76,6 +77,7 @@ final List components = [ Component(TooltipExample.name, (context) => const TooltipExample()), Component(NavigationRailExample.name, (context) => const NavigationRailExample()), Component(SelectInputExample.name, (context) => const SelectInputExample()), + Component(FilterSelectionExample.name, (context) => const FilterSelectionExample()), ]; final List theme = [ diff --git a/example/lib/pages/components/filter_selection_example.dart b/example/lib/pages/components/filter_selection_example.dart new file mode 100644 index 00000000..61cde4b4 --- /dev/null +++ b/example/lib/pages/components/filter_selection_example.dart @@ -0,0 +1,54 @@ +import 'package:flutter/material.dart'; +import 'package:zeta_flutter/zeta_flutter.dart'; + +import '../../widgets.dart'; + +class FilterSelectionExample extends StatefulWidget { + static const String name = 'FilterSelection'; + + const FilterSelectionExample({super.key}); + + @override + State createState() => _FilterSelectionExampleState(); +} + +class _FilterSelectionExampleState extends State { + final items = List.generate(12, (index) => false); + final items2 = List.generate(12, (index) => false); + + @override + Widget build(BuildContext context) { + return ExampleScaffold( + name: FilterSelectionExample.name, + child: Column( + children: [ + const SizedBox(height: ZetaSpacing.b), + ZetaFilterSelection( + items: [ + for (int i = 0; i < items.length; i++) + ZetaFilterChip( + label: 'Label ${i + 1}', + selected: items[i], + onTap: (value) => setState(() => items[i] = value), + ), + ], + onPressed: () {}, + ), + const SizedBox(height: ZetaSpacing.b), + ZetaFilterSelection( + rounded: false, + items: [ + for (int i = 0; i < items2.length; i++) + ZetaFilterChip( + label: 'Label ${i + 1}', + selected: items2[i], + onTap: (value) => setState(() => items2[i] = value), + ), + ], + onPressed: () {}, + ), + ], + ), + ); + } +} diff --git a/example/widgetbook/main.dart b/example/widgetbook/main.dart index c8882d05..28cf6e87 100644 --- a/example/widgetbook/main.dart +++ b/example/widgetbook/main.dart @@ -17,6 +17,7 @@ import 'pages/components/date_input_widgetbook.dart'; import 'pages/components/dial_pad_widgetbook.dart'; import 'pages/components/dialog_widgetbook.dart'; import 'pages/components/dropdown_widgetbook.dart'; +import 'pages/components/filter_selection_widgetbook.dart'; import 'pages/components/in_page_banner_widgetbook.dart'; import 'pages/components/list_item_widgetbook.dart'; import 'pages/components/navigation_bar_widgetbook.dart'; @@ -139,6 +140,7 @@ class HotReload extends StatelessWidget { WidgetbookUseCase(name: 'Navigation Rail', builder: (context) => navigationRailUseCase(context)), WidgetbookUseCase(name: 'Tooltip', builder: (context) => tooltipUseCase(context)), WidgetbookUseCase(name: 'Select Input', builder: (context) => selectInputUseCase(context)), + WidgetbookUseCase(name: 'Filter Selection', builder: (context) => filterSelectionUseCase(context)), ]..sort((a, b) => a.name.compareTo(b.name)), ), WidgetbookCategory( diff --git a/example/widgetbook/pages/components/filter_selection_widgetbook.dart b/example/widgetbook/pages/components/filter_selection_widgetbook.dart new file mode 100644 index 00000000..27abb913 --- /dev/null +++ b/example/widgetbook/pages/components/filter_selection_widgetbook.dart @@ -0,0 +1,37 @@ +import 'package:flutter/material.dart'; +import 'package:widgetbook/widgetbook.dart'; +import 'package:zeta_flutter/zeta_flutter.dart'; + +import '../../test/test_components.dart'; + +Widget filterSelectionUseCase(BuildContext context) { + final items = List.generate(12, (index) => false); + final rounded = context.knobs.boolean( + label: 'Rounded', + initialValue: true, + ); + + return WidgetbookTestWidget( + widget: StatefulBuilder( + builder: (_, setState) { + return Column( + children: [ + const SizedBox(height: ZetaSpacing.m), + ZetaFilterSelection( + rounded: rounded, + items: [ + for (int i = 0; i < items.length; i++) + ZetaFilterChip( + label: 'Label ${i + 1}', + selected: items[i], + onTap: (value) => setState(() => items[i] = value), + ), + ], + onPressed: () {}, + ), + ], + ); + }, + ), + ); +} diff --git a/lib/src/components/chips/chip.dart b/lib/src/components/chips/chip.dart index 6432b23d..42a9b768 100644 --- a/lib/src/components/chips/chip.dart +++ b/lib/src/components/chips/chip.dart @@ -54,7 +54,7 @@ class ZetaChip extends StatefulWidget { final bool? selected; /// Callback when chip is tapped. - final VoidCallback? onTap; + final ValueSetter? onTap; @override State createState() => _ZetaChipState(); @@ -66,7 +66,7 @@ class ZetaChip extends StatefulWidget { ..add(StringProperty('label', label)) ..add(DiagnosticsProperty('rounded', rounded)) ..add(DiagnosticsProperty('selected', selected)) - ..add(ObjectFlagProperty.has('onTap', onTap)); + ..add(ObjectFlagProperty?>.has('onTap', onTap)); } } @@ -91,6 +91,7 @@ class _ZetaChipState extends State { onPressed: () { if (widget.type == ZetaChipType.filter) { setState(() => selected = !selected); + widget.onTap?.call(selected); } }, style: ButtonStyle( diff --git a/lib/src/components/chips/filter_chip.dart b/lib/src/components/chips/filter_chip.dart index bcb08f4e..7fa98fe1 100644 --- a/lib/src/components/chips/filter_chip.dart +++ b/lib/src/components/chips/filter_chip.dart @@ -10,5 +10,18 @@ class ZetaFilterChip extends ZetaChip { required super.label, super.rounded, super.selected, + super.onTap, }) : super(type: ZetaChipType.filter); + + /// Creates another instance of [ZetaFilterChip]. + ZetaFilterChip copyWith({ + bool? rounded, + }) { + return ZetaFilterChip( + label: label, + selected: selected, + rounded: rounded ?? this.rounded, + onTap: onTap, + ); + } } diff --git a/lib/src/components/filter_selection/filter_selection.dart b/lib/src/components/filter_selection/filter_selection.dart new file mode 100644 index 00000000..46248b5e --- /dev/null +++ b/lib/src/components/filter_selection/filter_selection.dart @@ -0,0 +1,60 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +import '../../../zeta_flutter.dart'; + +/// Component [ZetaFilterSelection] +class ZetaFilterSelection extends StatelessWidget { + /// Constructor for the component [ZetaFilterSelection] + const ZetaFilterSelection({ + super.key, + required this.items, + this.rounded = true, + this.onPressed, + }); + + /// The filter items - list of [ZetaFilterChip]. + final List items; + + /// {@macro zeta-component-rounded} + final bool rounded; + + /// Called on filter button pressed. + final VoidCallback? onPressed; + + @override + Widget build(BuildContext context) { + return SizedBox( + height: ZetaSpacing.x11, + child: Row( + children: [ + IconButton( + visualDensity: VisualDensity.compact, + onPressed: onPressed, + icon: Icon( + rounded ? ZetaIcons.filter_round : ZetaIcons.filter_sharp, + size: ZetaSpacing.m, + ), + ), + Expanded( + child: ListView( + shrinkWrap: true, + scrollDirection: Axis.horizontal, + padding: const EdgeInsets.all(ZetaSpacing.xxs), + children: + items.map((e) => e.copyWith(rounded: rounded)).divide(const SizedBox(width: ZetaSpacing.x2)).toList(), + ), + ), + ], + ), + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('rounded', rounded)) + ..add(ObjectFlagProperty.has('onPressed', onPressed)); + } +} diff --git a/lib/zeta_flutter.dart b/lib/zeta_flutter.dart index dcb83bb9..e3414716 100644 --- a/lib/zeta_flutter.dart +++ b/lib/zeta_flutter.dart @@ -27,6 +27,7 @@ export 'src/components/date_input/date_input.dart'; export 'src/components/dial_pad/dial_pad.dart'; export 'src/components/dialog/dialog.dart'; export 'src/components/dropdown/dropdown.dart'; +export 'src/components/filter_selection/filter_selection.dart'; export 'src/components/list_item/list_item.dart'; export 'src/components/navigation bar/navigation_bar.dart'; export 'src/components/navigation_rail/navigation_rail.dart';