diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/buttons/button_component.dart b/packages/wyatt_ui_components/lib/src/domain/entities/buttons/button_component.dart
index 57b543c2..b412b05f 100644
--- a/packages/wyatt_ui_components/lib/src/domain/entities/buttons/button_component.dart
+++ b/packages/wyatt_ui_components/lib/src/domain/entities/buttons/button_component.dart
@@ -14,6 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
+import 'package:flutter/foundation.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
abstract class ButtonComponent extends Component {
@@ -26,6 +27,7 @@ abstract class ButtonComponent extends Component {
this.selectedStyle,
this.invalidStyle,
this.onPressed,
+ this.disabled,
super.themeResolver,
super.key,
});
@@ -51,6 +53,12 @@ abstract class ButtonComponent extends Component {
/// Style of this button in invalid state
final ButtonStyle? invalidStyle;
- /// Callback on button press
+ /// Callback on button press,
+ ///
+ /// [ControlState] is passed as argument and can be used to determine if the
+ /// button was pressed in disabled state or not.
final void Function(ControlState state)? onPressed;
+
+ /// Current state of this button
+ final ValueNotifier? disabled;
}
diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/buttons/file_selection_button_component.dart b/packages/wyatt_ui_components/lib/src/domain/entities/buttons/file_selection_button_component.dart
index b0e5866b..32639be6 100644
--- a/packages/wyatt_ui_components/lib/src/domain/entities/buttons/file_selection_button_component.dart
+++ b/packages/wyatt_ui_components/lib/src/domain/entities/buttons/file_selection_button_component.dart
@@ -36,6 +36,7 @@ abstract class FileSelectionButtonComponent extends ButtonComponent
super.selectedStyle,
super.invalidStyle,
super.onPressed,
+ super.disabled,
super.themeResolver,
super.key,
});
diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/buttons/file_selection_button_component.g.dart b/packages/wyatt_ui_components/lib/src/domain/entities/buttons/file_selection_button_component.g.dart
index aa5816fe..a22edea2 100644
--- a/packages/wyatt_ui_components/lib/src/domain/entities/buttons/file_selection_button_component.g.dart
+++ b/packages/wyatt_ui_components/lib/src/domain/entities/buttons/file_selection_button_component.g.dart
@@ -22,6 +22,7 @@ abstract class $FileSelectionButtonComponentCWProxy {
FileSelectionButtonComponent invalidStyle(ButtonStyle? invalidStyle);
FileSelectionButtonComponent onPressed(
void Function(ControlState)? onPressed);
+ FileSelectionButtonComponent disabled(ValueNotifier? disabled);
FileSelectionButtonComponent themeResolver(
ThemeResolver? themeResolver);
FileSelectionButtonComponent key(Key? key);
@@ -38,6 +39,7 @@ abstract class $FileSelectionButtonComponentCWProxy {
ButtonStyle? selectedStyle,
ButtonStyle? invalidStyle,
void Function(ControlState)? onPressed,
+ ValueNotifier? disabled,
ThemeResolver? themeResolver,
Key? key,
});
diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/buttons/flat_button_component.dart b/packages/wyatt_ui_components/lib/src/domain/entities/buttons/flat_button_component.dart
index 83420a59..e10d134c 100644
--- a/packages/wyatt_ui_components/lib/src/domain/entities/buttons/flat_button_component.dart
+++ b/packages/wyatt_ui_components/lib/src/domain/entities/buttons/flat_button_component.dart
@@ -34,6 +34,7 @@ abstract class FlatButtonComponent extends ButtonComponent
super.focusedStyle,
super.tappedStyle,
super.onPressed,
+ super.disabled,
super.themeResolver,
super.key,
});
diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/buttons/flat_button_component.g.dart b/packages/wyatt_ui_components/lib/src/domain/entities/buttons/flat_button_component.g.dart
index fb87d810..25acefba 100644
--- a/packages/wyatt_ui_components/lib/src/domain/entities/buttons/flat_button_component.g.dart
+++ b/packages/wyatt_ui_components/lib/src/domain/entities/buttons/flat_button_component.g.dart
@@ -17,6 +17,7 @@ abstract class $FlatButtonComponentCWProxy {
FlatButtonComponent focusedStyle(ButtonStyle? focusedStyle);
FlatButtonComponent tappedStyle(ButtonStyle? tappedStyle);
FlatButtonComponent onPressed(void Function(ControlState)? onPressed);
+ FlatButtonComponent disabled(ValueNotifier? disabled);
FlatButtonComponent themeResolver(
ThemeResolver? themeResolver);
FlatButtonComponent key(Key? key);
@@ -31,6 +32,7 @@ abstract class $FlatButtonComponentCWProxy {
ButtonStyle? focusedStyle,
ButtonStyle? tappedStyle,
void Function(ControlState)? onPressed,
+ ValueNotifier? disabled,
ThemeResolver? themeResolver,
Key? key,
});
diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/buttons/simple_icon_button_component.dart b/packages/wyatt_ui_components/lib/src/domain/entities/buttons/simple_icon_button_component.dart
index b9a3c746..c2260ac4 100644
--- a/packages/wyatt_ui_components/lib/src/domain/entities/buttons/simple_icon_button_component.dart
+++ b/packages/wyatt_ui_components/lib/src/domain/entities/buttons/simple_icon_button_component.dart
@@ -31,6 +31,7 @@ abstract class SimpleIconButtonComponent extends ButtonComponent
super.focusedStyle,
super.tappedStyle,
super.onPressed,
+ super.disabled,
super.themeResolver,
super.key,
});
diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/buttons/simple_icon_button_component.g.dart b/packages/wyatt_ui_components/lib/src/domain/entities/buttons/simple_icon_button_component.g.dart
index 9a4b83ac..fdbce6a8 100644
--- a/packages/wyatt_ui_components/lib/src/domain/entities/buttons/simple_icon_button_component.g.dart
+++ b/packages/wyatt_ui_components/lib/src/domain/entities/buttons/simple_icon_button_component.g.dart
@@ -14,6 +14,7 @@ abstract class $SimpleIconButtonComponentCWProxy {
SimpleIconButtonComponent focusedStyle(ButtonStyle? focusedStyle);
SimpleIconButtonComponent tappedStyle(ButtonStyle? tappedStyle);
SimpleIconButtonComponent onPressed(void Function(ControlState)? onPressed);
+ SimpleIconButtonComponent disabled(ValueNotifier? disabled);
SimpleIconButtonComponent themeResolver(
ThemeResolver? themeResolver);
SimpleIconButtonComponent key(Key? key);
@@ -25,6 +26,7 @@ abstract class $SimpleIconButtonComponentCWProxy {
ButtonStyle? focusedStyle,
ButtonStyle? tappedStyle,
void Function(ControlState)? onPressed,
+ ValueNotifier? disabled,
ThemeResolver? themeResolver,
Key? key,
});
diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/buttons/symbol_button_component.dart b/packages/wyatt_ui_components/lib/src/domain/entities/buttons/symbol_button_component.dart
index a09255d0..3a34c60a 100644
--- a/packages/wyatt_ui_components/lib/src/domain/entities/buttons/symbol_button_component.dart
+++ b/packages/wyatt_ui_components/lib/src/domain/entities/buttons/symbol_button_component.dart
@@ -34,6 +34,7 @@ abstract class SymbolButtonComponent extends ButtonComponent
super.tappedStyle,
super.selectedStyle,
super.onPressed,
+ super.disabled,
super.themeResolver,
super.key,
});
diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/buttons/symbol_button_component.g.dart b/packages/wyatt_ui_components/lib/src/domain/entities/buttons/symbol_button_component.g.dart
index a97dced0..be5cbb51 100644
--- a/packages/wyatt_ui_components/lib/src/domain/entities/buttons/symbol_button_component.g.dart
+++ b/packages/wyatt_ui_components/lib/src/domain/entities/buttons/symbol_button_component.g.dart
@@ -17,6 +17,7 @@ abstract class $SymbolButtonComponentCWProxy {
SymbolButtonComponent tappedStyle(ButtonStyle? tappedStyle);
SymbolButtonComponent selectedStyle(ButtonStyle? selectedStyle);
SymbolButtonComponent onPressed(void Function(ControlState)? onPressed);
+ SymbolButtonComponent disabled(ValueNotifier? disabled);
SymbolButtonComponent themeResolver(
ThemeResolver? themeResolver);
SymbolButtonComponent key(Key? key);
@@ -31,6 +32,7 @@ abstract class $SymbolButtonComponentCWProxy {
ButtonStyle? tappedStyle,
ButtonStyle? selectedStyle,
void Function(ControlState)? onPressed,
+ ValueNotifier? disabled,
ThemeResolver? themeResolver,
Key? key,
});
diff --git a/packages/wyatt_ui_kit/example/lib/buttons/file_selection_button/file_selection_buttons.dart b/packages/wyatt_ui_kit/example/lib/buttons/file_selection_button/file_selection_buttons.dart
index 0f398c13..d8863a85 100644
--- a/packages/wyatt_ui_kit/example/lib/buttons/file_selection_button/file_selection_buttons.dart
+++ b/packages/wyatt_ui_kit/example/lib/buttons/file_selection_button/file_selection_buttons.dart
@@ -15,14 +15,23 @@
// along with this program. If not, see .
import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:gap/gap.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
import 'package:wyatt_ui_kit_example/theme/constants.dart';
-class FileSelectionButtons extends StatelessWidget {
+class FileSelectionButtons extends StatefulWidget {
const FileSelectionButtons({super.key});
+ @override
+ State createState() => _FileSelectionButtonsState();
+}
+
+class _FileSelectionButtonsState extends State {
+ final _disabled = ValueNotifier(true);
+ final _dynamic = ValueNotifier(false);
+
Widget _leading() => const DecoratedBox(
decoration: BoxDecoration(
color: Constants.grey2,
@@ -48,6 +57,7 @@ class FileSelectionButtons extends StatelessWidget {
style: Theme.of(context).textTheme.titleMedium,
),
const Gap(20),
+ // Default
FileSelectionButton(
leading: _leading(),
title: const TextWrapper(
@@ -56,65 +66,99 @@ class FileSelectionButtons extends StatelessWidget {
subTitle: const TextWrapper('Taille max: 20 Mo'),
),
const Gap(20),
- FileSelectionButton(
- leading: _leading(),
- title: const TextWrapper(
- 'Enabled',
+ BlocProvider(
+ create: (context) => InvalidButtonCubit()..freeze(),
+ child: FileSelectionButton(
+ leading: _leading(),
+ title: const TextWrapper(
+ 'Enabled',
+ ),
+ subTitle: const TextWrapper('Subtitle'),
),
- subTitle: const TextWrapper('Subtitle'),
- )
- ..bloc.enable()
- ..bloc.freeze(),
+ ),
const Gap(20),
+ // Using a ValueNotifier to disable the button
FileSelectionButton(
leading: _leading(),
title: const TextWrapper(
'Disabled',
),
subTitle: const TextWrapper('Subtitle'),
- )
- ..bloc.disable()
- ..bloc.freeze(),
+ disabled: _disabled,
+ ),
const Gap(20),
- FileSelectionButton(
- leading: _leading(),
- title: const TextWrapper(
- 'Hovered',
+ BlocProvider(
+ create: (context) => InvalidButtonCubit()..hover(),
+ child: FileSelectionButton(
+ leading: _leading(),
+ title: const TextWrapper(
+ 'Hovered',
+ ),
+ subTitle: const TextWrapper('Subtitle'),
),
- subTitle: const TextWrapper('Subtitle'),
- )
- ..bloc.onMouseEnter()
- ..bloc.freeze(),
+ ),
const Gap(20),
- FileSelectionButton(
- leading: _leading(),
- title: const TextWrapper(
- 'Focused',
+ BlocProvider(
+ create: (context) => InvalidButtonCubit()..focus(),
+ child: FileSelectionButton(
+ leading: _leading(),
+ title: const TextWrapper(
+ 'Focused',
+ ),
+ subTitle: const TextWrapper('Subtitle'),
),
- subTitle: const TextWrapper('Subtitle'),
- )
- ..bloc.onFocus()
- ..bloc.freeze(),
+ ),
const Gap(20),
- FileSelectionButton(
- leading: _leading(),
- title: const TextWrapper(
- 'Tapped',
+ BlocProvider(
+ create: (context) => InvalidButtonCubit()..tap(),
+ child: FileSelectionButton(
+ leading: _leading(),
+ title: const TextWrapper(
+ 'Tapped',
+ ),
+ subTitle: const TextWrapper('Subtitle'),
),
- subTitle: const TextWrapper('Subtitle'),
- )
- ..bloc.onClickDown()
- ..bloc.freeze(),
+ ),
const Gap(20),
- FileSelectionButton(
- leading: _leading(),
- title: const TextWrapper(
- 'Invalid',
+ BlocProvider(
+ create: (context) => InvalidButtonCubit()..invalidate(),
+ child: FileSelectionButton(
+ leading: _leading(),
+ title: const TextWrapper(
+ 'Invalid',
+ ),
+ subTitle: const TextWrapper('Subtitle'),
),
- subTitle: const TextWrapper('Subtitle'),
- )
- ..bloc.invalidate()
- ..bloc.freeze(),
+ ),
+ const Gap(20),
+ // Dynamic, disabled with ValueNotifier and invalid with BlocProvider.
+ // Keep the state when the button is disabled.
+ Column(
+ children: [
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ const Text('Enabled'),
+ Checkbox(
+ value: !_dynamic.value,
+ onChanged: (value) {
+ setState(() {
+ _dynamic.value = !_dynamic.value;
+ });
+ },
+ ),
+ ],
+ ),
+ FileSelectionButton(
+ leading: _leading(),
+ title: const TextWrapper(
+ 'Dynamic',
+ ),
+ subTitle: const TextWrapper('Subtitle'),
+ disabled: _dynamic,
+ ),
+ ],
+ ),
const Gap(20),
],
);
diff --git a/packages/wyatt_ui_kit/example/lib/buttons/flat_button/flat_buttons.dart b/packages/wyatt_ui_kit/example/lib/buttons/flat_button/flat_buttons.dart
index 4c1a6b1d..e4b59a3c 100644
--- a/packages/wyatt_ui_kit/example/lib/buttons/flat_button/flat_buttons.dart
+++ b/packages/wyatt_ui_kit/example/lib/buttons/flat_button/flat_buttons.dart
@@ -15,13 +15,22 @@
// along with this program. If not, see .
import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:gap/gap.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
-class FlatButtons extends StatelessWidget {
+class FlatButtons extends StatefulWidget {
const FlatButtons({super.key});
+ @override
+ State createState() => _FlatButtonsState();
+}
+
+class _FlatButtonsState extends State {
+ final _disabled = ValueNotifier(true);
+ final _dynamic = ValueNotifier(false);
+
@override
Widget build(BuildContext context) => Column(
children: [
@@ -30,56 +39,80 @@ class FlatButtons extends StatelessWidget {
style: Theme.of(context).textTheme.titleMedium,
),
const Gap(20),
- Center(
+ // Default
+ const Center(
/// You can overwrite global textstyle of the label with [label],
/// but if you only want to override the color/gradient of the text
/// in a particular case you can override the style that will
/// be merge during the build.
child: FlatButton(
- label: const TextWrapper(
+ label: TextWrapper(
'Voir notre savoir faire',
),
),
),
const Gap(20),
Center(
- child: FlatButton(
- label: const TextWrapper('Enabled'),
- )
- ..bloc.enable()
- ..bloc.freeze(),
+ child: BlocProvider(
+ create: (context) => ButtonCubit()..freeze(),
+ child: const FlatButton(
+ label: TextWrapper('Enabled'),
+ ),
+ ),
),
const Gap(20),
+ // Disabled with ValueNotifier
Center(
child: FlatButton(
label: const TextWrapper('Disabled'),
- )
- ..bloc.disable()
- ..bloc.freeze(),
+ disabled: _disabled,
+ ),
),
const Gap(20),
Center(
- child: FlatButton(
- label: const TextWrapper('Hovered'),
- )
- ..bloc.onMouseEnter()
- ..bloc.freeze(),
+ child: BlocProvider(
+ create: (context) => ButtonCubit()..hover(),
+ child: const FlatButton(
+ label: TextWrapper('Hovered'),
+ ),
+ ),
),
const Gap(20),
Center(
- child: FlatButton(
- label: const TextWrapper('Focused'),
- )
- ..bloc.onFocus()
- ..bloc.freeze(),
+ child: BlocProvider(
+ create: (context) => ButtonCubit()..focus(),
+ child: const FlatButton(
+ label: TextWrapper('Focused'),
+ ),
+ ),
),
const Gap(20),
Center(
- child: FlatButton(
- label: const TextWrapper('Tapped'),
- )
- ..bloc.onClickDown()
- ..bloc.freeze(),
+ child: BlocProvider(
+ create: (context) => ButtonCubit()..tap(),
+ child: const FlatButton(
+ label: TextWrapper('Tapped'),
+ ),
+ ),
+ ),
+ const Gap(20),
+ // Dynamic, disabled with ValueNotifier and
+ // keep the state when the button is disabled
+ Row(
+ children: [
+ Checkbox(
+ value: !_dynamic.value,
+ onChanged: (value) {
+ setState(() {
+ _dynamic.value = !_dynamic.value;
+ });
+ },
+ ),
+ FlatButton(
+ label: const TextWrapper('Dynamic'),
+ disabled: _dynamic,
+ ),
+ ],
),
const Gap(20),
],
diff --git a/packages/wyatt_ui_kit/example/lib/buttons/simple_icon_button/simple_icon_buttons.dart b/packages/wyatt_ui_kit/example/lib/buttons/simple_icon_button/simple_icon_buttons.dart
index 1de93f70..44143a5c 100644
--- a/packages/wyatt_ui_kit/example/lib/buttons/simple_icon_button/simple_icon_buttons.dart
+++ b/packages/wyatt_ui_kit/example/lib/buttons/simple_icon_button/simple_icon_buttons.dart
@@ -15,12 +15,21 @@
// along with this program. If not, see .
import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:gap/gap.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
-class SimpleIconButtons extends StatelessWidget {
+class SimpleIconButtons extends StatefulWidget {
const SimpleIconButtons({super.key});
+ @override
+ State createState() => _SimpleIconButtonsState();
+}
+
+class _SimpleIconButtonsState extends State {
+ final _disabled = ValueNotifier(true);
+ final _dynamic = ValueNotifier(false);
+
@override
Widget build(BuildContext context) => Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -30,8 +39,9 @@ class SimpleIconButtons extends StatelessWidget {
style: Theme.of(context).textTheme.titleMedium,
),
const Gap(20),
- SimpleIconButton(
- icon: const Icon(
+ // Default
+ const SimpleIconButton(
+ icon: Icon(
Icons.storm_outlined,
size: 17,
),
@@ -42,71 +52,101 @@ class SimpleIconButtons extends StatelessWidget {
style: Theme.of(context).textTheme.labelMedium,
),
const Gap(10),
- SimpleIconButton(
- icon: const Icon(
- Icons.storm_outlined,
- size: 17,
+ BlocProvider(
+ create: (context) => ButtonCubit()..freeze(),
+ child: const SimpleIconButton(
+ icon: Icon(
+ Icons.storm_outlined,
+ size: 17,
+ ),
),
- )
- ..bloc.enable()
- ..bloc.freeze(),
+ ),
const Gap(20),
Text(
'Disabled',
style: Theme.of(context).textTheme.labelMedium,
),
const Gap(10),
+ // Disabled using ValueNotifier
SimpleIconButton(
icon: const Icon(
Icons.storm_outlined,
size: 17,
),
- )
- ..bloc.disable()
- ..bloc.freeze(),
+ disabled: _disabled,
+ ),
const Gap(20),
Text(
'Hovered',
style: Theme.of(context).textTheme.labelMedium,
),
const Gap(10),
- SimpleIconButton(
- icon: const Icon(
- Icons.storm_outlined,
- size: 17,
+ BlocProvider(
+ create: (context) => ButtonCubit()..hover(),
+ child: const SimpleIconButton(
+ icon: Icon(
+ Icons.storm_outlined,
+ size: 17,
+ ),
),
- )
- ..bloc.onMouseEnter()
- ..bloc.freeze(),
+ ),
const Gap(20),
Text(
'Focused',
style: Theme.of(context).textTheme.labelMedium,
),
const Gap(10),
- SimpleIconButton(
- icon: const Icon(
- Icons.storm_outlined,
- size: 17,
+ BlocProvider(
+ create: (context) => ButtonCubit()..focus(),
+ child: const SimpleIconButton(
+ icon: Icon(
+ Icons.storm_outlined,
+ size: 17,
+ ),
),
- )
- ..bloc.onFocus()
- ..bloc.freeze(),
+ ),
const Gap(20),
Text(
'Tapped',
style: Theme.of(context).textTheme.labelMedium,
),
const Gap(10),
- SimpleIconButton(
- icon: const Icon(
- Icons.storm_outlined,
- size: 17,
+ BlocProvider(
+ create: (context) => ButtonCubit()..tap(),
+ child: const SimpleIconButton(
+ icon: Icon(
+ Icons.storm_outlined,
+ size: 17,
+ ),
),
- )
- ..bloc.onClickDown()
- ..bloc.freeze(),
+ ),
const Gap(20),
+ Text(
+ 'Dynamic',
+ style: Theme.of(context).textTheme.labelMedium,
+ ),
+ const Gap(10),
+ // Dynamic, disabled with ValueNotifier and
+ // keep the state when the button is disabled
+ Row(
+ children: [
+ Checkbox(
+ value: !_dynamic.value,
+ onChanged: (value) {
+ setState(() {
+ _dynamic.value = !_dynamic.value;
+ });
+ },
+ ),
+ SimpleIconButton(
+ icon: const Icon(
+ Icons.storm_outlined,
+ size: 17,
+ ),
+ disabled: _dynamic,
+ ),
+ ],
+ ),
],
);
}
diff --git a/packages/wyatt_ui_kit/example/lib/buttons/symbol_button/symbol_buttons.dart b/packages/wyatt_ui_kit/example/lib/buttons/symbol_button/symbol_buttons.dart
index 54aa9cb5..659ae233 100644
--- a/packages/wyatt_ui_kit/example/lib/buttons/symbol_button/symbol_buttons.dart
+++ b/packages/wyatt_ui_kit/example/lib/buttons/symbol_button/symbol_buttons.dart
@@ -15,14 +15,23 @@
// along with this program. If not, see .
import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:gap/gap.dart';
import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
import 'package:wyatt_ui_kit_example/theme/constants.dart';
-class SymbolButtons extends StatelessWidget {
+class SymbolButtons extends StatefulWidget {
const SymbolButtons({super.key});
+ @override
+ State createState() => _SymbolButtonsState();
+}
+
+class _SymbolButtonsState extends State {
+ final _disabled = ValueNotifier(true);
+ final _dynamic = ValueNotifier(false);
+
Icon _icon(BuildContext context) => Icon(
Icons.android,
size: 25,
@@ -45,47 +54,70 @@ class SymbolButtons extends StatelessWidget {
icon: _icon(context),
),
const Gap(20),
- SymbolButton(
- label: const TextWrapper('Enabled'),
- icon: _icon(context),
- )
- ..bloc.enable()
- ..bloc.freeze(),
+ BlocProvider(
+ create: (context) => SelectableButtonCubit()..freeze(),
+ child: SymbolButton(
+ label: const TextWrapper('Enabled'),
+ icon: _icon(context),
+ ),
+ ),
const Gap(20),
+ // Disabled
SymbolButton(
label: const TextWrapper('Disabled'),
icon: _icon(context),
- )
- ..bloc.disable()
- ..bloc.freeze(),
+ disabled: _disabled,
+ ),
const Gap(20),
- SymbolButton(
- label: const TextWrapper('Hovered'),
- icon: _icon(context),
- )
- ..bloc.onMouseEnter()
- ..bloc.freeze(),
+ BlocProvider(
+ create: (context) => SelectableButtonCubit()..hover(),
+ child: SymbolButton(
+ label: const TextWrapper('Hovered'),
+ icon: _icon(context),
+ ),
+ ),
const Gap(20),
- SymbolButton(
- label: const TextWrapper('Focused'),
- icon: _icon(context),
- )
- ..bloc.onFocus()
- ..bloc.freeze(),
+ BlocProvider(
+ create: (context) => SelectableButtonCubit()..focus(),
+ child: SymbolButton(
+ label: const TextWrapper('Focused'),
+ icon: _icon(context),
+ ),
+ ),
const Gap(20),
- SymbolButton(
- label: const TextWrapper('Tapped'),
- icon: _icon(context),
- )
- ..bloc.onClickDown()
- ..bloc.freeze(),
+ BlocProvider(
+ create: (context) => SelectableButtonCubit()..tap(),
+ child: SymbolButton(
+ label: const TextWrapper('Tapped'),
+ icon: _icon(context),
+ ),
+ ),
const Gap(20),
- SymbolButton(
- label: const TextWrapper('Selected'),
- icon: _icon(context),
- )
- ..bloc.select()
- ..bloc.freeze(),
+ BlocProvider(
+ create: (context) => SelectableButtonCubit()..select(),
+ child: SymbolButton(
+ label: const TextWrapper('Selected'),
+ icon: _icon(context),
+ ),
+ ),
+ const Gap(20),
+ Row(
+ children: [
+ Checkbox(
+ value: !_dynamic.value,
+ onChanged: (value) {
+ setState(() {
+ _dynamic.value = !_dynamic.value;
+ });
+ },
+ ),
+ SymbolButton(
+ label: const TextWrapper('Dynamic'),
+ icon: _icon(context),
+ disabled: _dynamic,
+ ),
+ ],
+ ),
const Gap(20),
DecoratedBox(
decoration: BoxDecoration(
diff --git a/packages/wyatt_ui_kit/example/pubspec.yaml b/packages/wyatt_ui_kit/example/pubspec.yaml
index d9953115..cf855e24 100644
--- a/packages/wyatt_ui_kit/example/pubspec.yaml
+++ b/packages/wyatt_ui_kit/example/pubspec.yaml
@@ -10,6 +10,7 @@ environment:
dependencies:
flutter: { sdk: flutter }
+ flutter_bloc: ^8.1.2
flutter_localizations: { sdk: flutter }
gap: ^2.0.1
diff --git a/packages/wyatt_ui_kit/lib/src/components/buttons/buttons.dart b/packages/wyatt_ui_kit/lib/src/components/buttons/buttons.dart
index bf04a627..34d6fae2 100644
--- a/packages/wyatt_ui_kit/lib/src/components/buttons/buttons.dart
+++ b/packages/wyatt_ui_kit/lib/src/components/buttons/buttons.dart
@@ -14,6 +14,9 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
+export './cubit/button_cubit.dart';
+export './cubit/invalid_button_cubit.dart';
+export './cubit/selectable_button_cubit.dart';
export './file_selection_button/file_selection_button.dart';
export './flat_button/flat_button.dart';
export './simple_icon_button/simple_icon_button.dart';
diff --git a/packages/wyatt_ui_kit/lib/src/components/buttons/cubit/button_cubit.dart b/packages/wyatt_ui_kit/lib/src/components/buttons/cubit/button_cubit.dart
index d317a181..accafce5 100644
--- a/packages/wyatt_ui_kit/lib/src/components/buttons/cubit/button_cubit.dart
+++ b/packages/wyatt_ui_kit/lib/src/components/buttons/cubit/button_cubit.dart
@@ -23,8 +23,19 @@ import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart';
part 'button_state.dart';
class ButtonCubit extends Cubit {
- ButtonCubit() : super(const ButtonState.initial(ControlState.normal));
+ ButtonCubit() : super(const ButtonState.initial(ControlState.normal)) {
+ _previousState = state.copyWith();
+ }
+ /// The previous state of the button.
+ /// This is used to restore the state of the button when
+ /// the button is enabled again.
+ ButtonState? _previousState;
+
+ /// When the mouse enters the button. The button will change
+ /// its state to [ControlState.hovered].
+ ///
+ /// If the button is disabled or freezed, this method does nothing.
FutureOr onMouseEnter() async {
if (state.isDisabled || state.isFreezed) {
return;
@@ -32,6 +43,10 @@ class ButtonCubit extends Cubit {
emit(state.copyWith(state: ControlState.hovered));
}
+ /// When the mouse leaves the button. The button will change
+ /// its state to [ControlState.normal].
+ ///
+ /// If the button is disabled or freezed, this method does nothing.
FutureOr onMouseLeave() async {
if (state.isDisabled || state.isFreezed) {
return;
@@ -40,6 +55,10 @@ class ButtonCubit extends Cubit {
emit(state.copyWith(state: ControlState.normal));
}
+ /// When the button is focused. The button will change
+ /// its state to [ControlState.focused].
+ ///
+ /// If the button is disabled or freezed, this method does nothing.
FutureOr onFocus() async {
if (state.isDisabled || state.isFreezed) {
return;
@@ -47,6 +66,10 @@ class ButtonCubit extends Cubit {
emit(state.copyWith(state: ControlState.focused));
}
+ /// When the button is unfocused. The button will change
+ /// its state to [ControlState.normal].
+ ///
+ /// If the button is disabled or freezed, this method does nothing.
FutureOr onUnfocus() async {
if (state.isDisabled || state.isFreezed) {
return;
@@ -54,6 +77,10 @@ class ButtonCubit extends Cubit {
emit(state.copyWith(state: ControlState.normal));
}
+ /// When the mouse is pressed on the button. The button will change
+ /// its state to [ControlState.tapped].
+ ///
+ /// If the button is disabled or freezed, this method does nothing.
FutureOr onClickDown() async {
if (state.isDisabled || state.isFreezed) {
return;
@@ -61,39 +88,127 @@ class ButtonCubit extends Cubit {
emit(state.copyWith(state: ControlState.tapped));
}
+ /// When the mouse is released on the button. The button will change
+ /// its state to [ControlState.hovered].
+ ///
+ /// If the button is disabled or freezed, this method does nothing.
FutureOr onClickUpIn() async {
- if (state.isDisabled) {
+ if (state.isDisabled || state.isFreezed) {
return;
}
emit(state.copyWith(state: ControlState.hovered));
}
+ /// When the mouse is released outside the button. The button will change
+ /// its state to [ControlState.normal].
+ ///
+ /// If the button is disabled or freezed, this method does nothing.
FutureOr onClickUpOut() async {
- if (state.isDisabled) {
+ if (state.isDisabled || state.isFreezed) {
return;
}
emit(state.copyWith(state: ControlState.normal));
}
+ /// Programmatically change the state or extra states of the button.
+ FutureOr setState({
+ ControlState? state,
+ List? extraStates,
+ }) async {
+ emit(this.state.copyWith(state: state, extraStates: extraStates));
+ }
+
+ /// Disable the button.
+ ///
+ /// This will remove all extra states and set
+ /// the state to [ControlState.disabled] and add [ExtraState.freezed].
FutureOr disable() async {
- if (state.isFreezed) {
- return;
- }
- emit(state.copyWith(state: ControlState.disabled));
+ /// Save the previous state.
+ /// copyWith() is used to make sure the previous state is not
+ /// affected by any changes to the current state.
+ _previousState = state.copyWith();
+
+ emit(
+ const ButtonState(
+ state: ControlState.disabled,
+ extraStates: [ExtraState.freezed],
+ ),
+ );
}
+ /// Enable the button.
+ ///
+ /// This will restore the previous state of the button.
FutureOr enable() async {
- if (state.isFreezed) {
+ if (_previousState == null) {
return;
}
- emit(state.copyWith(state: ControlState.normal));
+
+ emit(_previousState!);
+ _previousState = null;
}
+ /// Set the button to hovered state and freeze it.
+ ///
+ /// Use this method to programmatically set the button to hovered state.
+ FutureOr hover() async {
+ emit(
+ state.copyWith(
+ state: ControlState.hovered,
+ extraStates: state.extraStates + [ExtraState.freezed],
+ ),
+ );
+ }
+
+ /// Set the button to focused state and freeze it.
+ ///
+ /// Use this method to programmatically set the button to focused state.
+ FutureOr focus() async {
+ emit(
+ state.copyWith(
+ state: ControlState.focused,
+ extraStates: state.extraStates + [ExtraState.freezed],
+ ),
+ );
+ }
+
+ /// Set the button to tapped state and freeze it.
+ ///
+ /// Use this method to programmatically set the button to tapped state.
+ FutureOr tap() async {
+ emit(
+ state.copyWith(
+ state: ControlState.tapped,
+ extraStates: state.extraStates + [ExtraState.freezed],
+ ),
+ );
+ }
+
+ /// Freeze the button in its current state.
+ ///
+ /// Shortcut for [setState] with extra state [ExtraState.freezed].
+ ///
+ /// Use this method to programmatically freeze the button.
FutureOr freeze() async {
- emit(state.copyWith(freezed: true));
+ emit(
+ state.copyWith(
+ extraStates: state.extraStates + [ExtraState.freezed],
+ ),
+ );
}
+ /// Unfreeze the button.
+ ///
+ /// Shortcut for [setState] without extra state [ExtraState.freezed].
+ ///
+ /// Use this method to programmatically unfreeze the button.
FutureOr unfreeze() async {
- emit(state.copyWith(freezed: false));
+ emit(
+ state.copyWith(
+ extraStates: state.extraStates
+ .where((element) => element != ExtraState.freezed)
+ .toList(),
+ ),
+ );
}
}
diff --git a/packages/wyatt_ui_kit/lib/src/components/buttons/cubit/button_state.dart b/packages/wyatt_ui_kit/lib/src/components/buttons/cubit/button_state.dart
index 1d2e5350..2abdd360 100644
--- a/packages/wyatt_ui_kit/lib/src/components/buttons/cubit/button_state.dart
+++ b/packages/wyatt_ui_kit/lib/src/components/buttons/cubit/button_state.dart
@@ -18,54 +18,41 @@
part of 'button_cubit.dart';
class ButtonState extends Equatable {
- const ButtonState({
- required this.state,
- required this.selected,
- required this.invalid,
- required this.freezed,
- });
+ const ButtonState({required this.state, required this.extraStates});
- const ButtonState.initial(this.state)
- : selected = false,
- invalid = false,
- freezed = false;
+ const ButtonState.initial(this.state) : extraStates = const [];
+ /// The control state of the button
final ControlState state;
- // Not in control state, because a button state can be
- // a control state + extra state
- // e.g : hover + invalid, or selected + tapped
- final bool selected;
- final bool invalid;
- final bool freezed;
+ /// Not in control state, because a button state can be
+ /// a control state + extra state
+ /// e.g :
+ /// - ControlState.hover + [ExtraState.invalid]
+ /// - ControlState.tapped + [ExtraState.invalid + ExtraState.freezed]
+ final List extraStates;
bool get isDisabled => state.isDisabled();
bool get isEnabled => state.isEnabled();
bool get isFocused => state.isFocused();
bool get isHovered => state.isHovered();
bool get isTapped => state.isTapped();
-
- // only for consistence
- bool get isSelected => selected;
- bool get isInvalid => invalid;
- bool get isFreezed => freezed;
+ bool get isSelected => extraStates.contains(ExtraState.selected);
+ bool get isInvalid => extraStates.contains(ExtraState.invalid);
+ bool get isFreezed => extraStates.contains(ExtraState.freezed);
@override
- List