From cd828035bf240b09573e60168af2341fa031cf0c Mon Sep 17 00:00:00 2001 From: RexMa Date: Mon, 11 Jan 2021 11:07:32 -0700 Subject: [PATCH 001/176] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 010828c..0f38f46 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ A builder that adds loading and disabled states on top of buttons that perform asynchronous. It can be used with most any button or even on top of a custom Material button. It includes fluid animation between states as well using `AnimatedSize`.

- +

## Getting Started From de3458f69b46dbd34ce2afc3935f66c29b607dab Mon Sep 17 00:00:00 2001 From: Nolence Date: Mon, 11 Jan 2021 11:09:19 -0700 Subject: [PATCH 002/176] Maybe? --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0f38f46..363f04e 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ A builder that adds loading and disabled states on top of buttons that perform asynchronous. It can be used with most any button or even on top of a custom Material button. It includes fluid animation between states as well using `AnimatedSize`.

- +

## Getting Started From feaa7c6e2f7d7fd887842f455705629dc6041d0e Mon Sep 17 00:00:00 2001 From: Nolence Date: Mon, 11 Jan 2021 11:10:38 -0700 Subject: [PATCH 003/176] Fixed typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 363f04e..f91d6c5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # async_button_builder -A builder that adds loading and disabled states on top of buttons that perform asynchronous. It can be used with most any button or even on top of a custom Material button. It includes fluid animation between states as well using `AnimatedSize`. +A builder that adds loading and disabled states on top of buttons that perform asynchronous tasks. It can be used with most any button or even on top of a custom Material button. It includes fluid animation between states as well using `AnimatedSize`.

From 20151b25997735b25af555084b0b30c1d5892fd4 Mon Sep 17 00:00:00 2001 From: Nolence Date: Tue, 12 Jan 2021 08:55:16 -0700 Subject: [PATCH 004/176] Better docs --- CHANGELOG.md | 4 ++ example/pubspec.lock | 2 +- lib/async_button_builder.dart | 78 +++++++++++++++++++++++------------ pubspec.yaml | 2 +- 4 files changed, 57 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d67c37..039b404 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## [0.0.1-nullsafety.1] - 2021-01-12 + +Adds docs to parameters and removes use of unnecessary undescore internal variables. + ## [0.0.1-nullsafety.0] - 2021-01-11 Holds basic builder AsyncButtonBuilder. No tests yet. NNBD is supported diff --git a/example/pubspec.lock b/example/pubspec.lock index a380070..8eae530 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -42,7 +42,7 @@ packages: path: ".." relative: true source: path - version: "0.0.1-nullsafety.0" + version: "0.0.1-nullsafety.1" boolean_selector: dependency: transitive description: diff --git a/lib/async_button_builder.dart b/lib/async_button_builder.dart index 3edf9c5..a5131af 100644 --- a/lib/async_button_builder.dart +++ b/lib/async_button_builder.dart @@ -10,21 +10,50 @@ typedef _AsyncWidgetBuilder = Widget Function( class AsyncButtonBuilder extends StatefulWidget { final _AsyncWidgetBuilder builder; + /// The child of the button. In the case of an [IconButton], this can be a an + /// [Icon]. For a [TextButton], a [Text]. + /// + /// This child will be animated between for the [loadingWidget] or default + /// [CircularProgressIndicator] when the asynchronous [onPressed] is called. + /// The animation will take place over [duration]. final Widget child; + /// The animation's duration between [child] and [loadingWidget] using + /// [AnimatedSize]. final Duration duration; + /// A callback that runs the async task. This is wrapped in order to begin + /// the button's internal `isLoading` before and after the operation + /// completes. final AsyncCallback onPressed; - final bool? _isLoading; - - final Widget? _loadingWidget; - - final Color? _valueColor; - - final EdgeInsets? _padding; - - final EdgeInsets? _loadingPadding; + /// This is used to manually drive the state of the loading button. + final bool? isLoading; + + /// The widget used to replace the [child] when the button is in a loading + /// state. If this is null the default widget is: + /// + /// SizedBox( + /// height: 16.0, + /// width: 16.0, + /// child: CircularProgressIndicator( + /// valueColor: valueColor, + /// ), + /// ) + final Widget? loadingWidget; + + /// This color changes the color of the default loading widget k-- a + /// [CircularProgressIndicator]. + final Color? valueColor; + + /// Optional padding around the child. This is useful if you are creating + /// your own button with [Material] and need padding around the inner child. + final EdgeInsets? padding; + + /// Optional padding around the loading widget. This is useful if you are + /// creating your own button with [Material] and need a seperate padding + /// around the loading indicator unequal to the child's [padding]. + final EdgeInsets? loadingPadding; const AsyncButtonBuilder({ Key? key, @@ -32,17 +61,12 @@ class AsyncButtonBuilder extends StatefulWidget { required this.child, required this.onPressed, this.duration = const Duration(milliseconds: 250), - bool? isLoading, - Widget? loadingWidget, - Color? valueColor, - EdgeInsets? padding, - EdgeInsets? loadingPadding, - }) : _loadingWidget = loadingWidget, - _isLoading = isLoading, - _valueColor = valueColor, - _padding = padding, - _loadingPadding = loadingPadding, - super(key: key); + this.isLoading, + this.loadingWidget, + this.valueColor, + this.padding, + this.loadingPadding, + }) : super(key: key); @override _AsyncButtonBuilderState createState() => _AsyncButtonBuilderState(); @@ -54,14 +78,14 @@ class _AsyncButtonBuilderState extends State @override void initState() { - isLoading = widget._isLoading ?? false; + isLoading = widget.isLoading ?? false; super.initState(); } @override void didUpdateWidget(covariant AsyncButtonBuilder oldWidget) { - if (widget._isLoading != oldWidget._isLoading) { - final loading = widget._isLoading; + if (widget.isLoading != oldWidget.isLoading) { + final loading = widget.isLoading; if (loading != null) { setState(() { @@ -75,15 +99,15 @@ class _AsyncButtonBuilderState extends State @override Widget build(BuildContext context) { - final color = widget._valueColor; - final padding = widget._padding; - final loadingPadding = widget._loadingPadding; + final color = widget.valueColor; + final padding = widget.padding; + final loadingPadding = widget.loadingPadding; final valueColor = color == null ? null : AlwaysStoppedAnimation(color); final child = padding == null ? widget.child : Padding(padding: padding, child: widget.child); - var loadingWidget = widget._loadingWidget ?? + var loadingWidget = widget.loadingWidget ?? SizedBox( height: 16.0, width: 16.0, diff --git a/pubspec.yaml b/pubspec.yaml index df3d727..39f2d04 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_builder description: A builder to wrap around buttons that handles loading and disabled state -version: 0.0.1-nullsafety.0 +version: 0.0.1-nullsafety.1 homepage: https://github.com/Nolence/async_button_builder environment: From 5af79de0bd2ad7fb81aeeb16ea674b13a2e2315d Mon Sep 17 00:00:00 2001 From: Nolence Date: Tue, 12 Jan 2021 09:13:13 -0700 Subject: [PATCH 005/176] Remove typedef and add analysis options --- CHANGELOG.md | 4 ++++ analysis_options.yaml | 1 + example/pubspec.lock | 2 +- lib/async_button_builder.dart | 16 +++++++++------- pubspec.lock | 7 +++++++ pubspec.yaml | 3 ++- 6 files changed, 24 insertions(+), 9 deletions(-) create mode 100644 analysis_options.yaml diff --git a/CHANGELOG.md b/CHANGELOG.md index 039b404..643def4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## [0.0.1-nullsafety.2] - 2021-01-12 + +Adds analysis options and removes unnecessary typedef + ## [0.0.1-nullsafety.1] - 2021-01-12 Adds docs to parameters and removes use of unnecessary undescore internal variables. diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..108d105 --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1 @@ +include: package:pedantic/analysis_options.yaml diff --git a/example/pubspec.lock b/example/pubspec.lock index 8eae530..df5e145 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -42,7 +42,7 @@ packages: path: ".." relative: true source: path - version: "0.0.1-nullsafety.1" + version: "0.0.1-nullsafety.2" boolean_selector: dependency: transitive description: diff --git a/lib/async_button_builder.dart b/lib/async_button_builder.dart index a5131af..193bb88 100644 --- a/lib/async_button_builder.dart +++ b/lib/async_button_builder.dart @@ -1,14 +1,16 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -typedef _AsyncWidgetBuilder = Widget Function( - BuildContext context, - Widget child, - AsyncCallback? callback, -); - +/// A `builder` that wraps a button automatically providing disabled and loading +/// states while retaining full access to a Button's API. Useful for any long +/// running operations or to prevent the user from clicking multiple times +/// while an asynchronous task is running. class AsyncButtonBuilder extends StatefulWidget { - final _AsyncWidgetBuilder builder; + final Widget Function( + BuildContext context, + Widget child, + AsyncCallback? callback, + ) builder; /// The child of the button. In the case of an [IconButton], this can be a an /// [Icon]. For a [TextButton], a [Text]. diff --git a/pubspec.lock b/pubspec.lock index bb284fa..c89f420 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -81,6 +81,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.8.0-nullsafety.3" + pedantic: + dependency: "direct dev" + description: + name: pedantic + url: "https://pub.dartlang.org" + source: hosted + version: "1.10.0-nullsafety.3" sky_engine: dependency: transitive description: flutter diff --git a/pubspec.yaml b/pubspec.yaml index 39f2d04..e20917f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_builder description: A builder to wrap around buttons that handles loading and disabled state -version: 0.0.1-nullsafety.1 +version: 0.0.1-nullsafety.2 homepage: https://github.com/Nolence/async_button_builder environment: @@ -14,5 +14,6 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter + pedantic: ^1.10.0-nullsafety.3 flutter: \ No newline at end of file From 9be09f0ff79c06f5ecc6254816118739fcda45b6 Mon Sep 17 00:00:00 2001 From: Nolence Date: Tue, 12 Jan 2021 11:02:10 -0700 Subject: [PATCH 006/176] Removed bool isLoading in favor of ValueNotifier --- CHANGELOG.md | 4 ++++ README.md | 39 +++++++++++++++++++++++++++++++++++ example/lib/main.dart | 22 ++++++++++++++++++-- lib/async_button_builder.dart | 14 ++++++++----- 4 files changed, 72 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 643def4..9ff02ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## [0.1.0-nullsafety.0] - 2021-01-12 + +Replaces the bool type of isLoading for a ValueNotifier. + ## [0.0.1-nullsafety.2] - 2021-01-12 Adds analysis options and removes unnecessary typedef diff --git a/README.md b/README.md index f91d6c5..54bc308 100644 --- a/README.md +++ b/README.md @@ -64,3 +64,42 @@ Material( ), ``` +To listen to the loading state, you can pass through a `isLoading` `ValueNotifier` to AsyncButtonBuilder. The value will be listened to inside the builder. You can also use this value to set the initial state of the button or change it programatically depending on your requirements. + +```dart +class Example extends StatefulWidget { + @override + _ExampleState createState() => _ExampleState(); +} + +class _ExampleState extends State { + final isLoading = ValueNotifier(false); + + @override + Widget build(BuildContext context) { + return AsyncButtonBuilder( + child: Text('Click Me'), + isLoading: isLoading, + onPressed: () async { + await Future.delayed(Duration(seconds: 1)); + }, + builder: (context, child, callback) { + // This value is only listened to inside of `builder` + print(isLoading.value); + + return OutlinedButton( + child: child, + onPressed: callback, + style: ButtonStyle( + tapTargetSize: isLoading.value + ? MaterialTapTargetSize.shrinkWrap + : MaterialTapTargetSize.padded, + ), + ); + }, + ); + } +} +``` + +Issues and PR's welcome \ No newline at end of file diff --git a/example/lib/main.dart b/example/lib/main.dart index ceb048c..5840c87 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,4 +1,5 @@ import 'package:async_button_builder/async_button_builder.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; void main() => runApp(MyApp()); @@ -14,7 +15,14 @@ class MyApp extends StatelessWidget { } } -class MyHomePage extends StatelessWidget { +class MyHomePage extends StatefulWidget { + @override + _MyHomePageState createState() => _MyHomePageState(); +} + +class _MyHomePageState extends State { + final isLoading = ValueNotifier(false); + @override Widget build(BuildContext context) { return Scaffold( @@ -36,6 +44,7 @@ class MyHomePage extends StatelessWidget { return TextButton( child: child, onPressed: callback, + style: ButtonStyle(), ); }, ), @@ -57,14 +66,23 @@ class MyHomePage extends StatelessWidget { Text('Custom Outline Button:'), AsyncButtonBuilder( child: Text('Click Me'), + isLoading: isLoading, loadingWidget: Text('Loading...'), onPressed: () async { await Future.delayed(Duration(seconds: 1)); }, builder: (context, child, callback) { - return OutlineButton( + // This value is only listened to inside of `builder` + print(isLoading.value); + + return OutlinedButton( child: child, onPressed: callback, + style: ButtonStyle( + tapTargetSize: isLoading.value + ? MaterialTapTargetSize.shrinkWrap + : MaterialTapTargetSize.padded, + ), ); }, ), diff --git a/lib/async_button_builder.dart b/lib/async_button_builder.dart index 193bb88..6c5b3fe 100644 --- a/lib/async_button_builder.dart +++ b/lib/async_button_builder.dart @@ -30,7 +30,7 @@ class AsyncButtonBuilder extends StatefulWidget { final AsyncCallback onPressed; /// This is used to manually drive the state of the loading button. - final bool? isLoading; + final ValueNotifier? isLoading; /// The widget used to replace the [child] when the button is in a loading /// state. If this is null the default widget is: @@ -80,18 +80,18 @@ class _AsyncButtonBuilderState extends State @override void initState() { - isLoading = widget.isLoading ?? false; + isLoading = widget.isLoading?.value ?? false; super.initState(); } @override void didUpdateWidget(covariant AsyncButtonBuilder oldWidget) { - if (widget.isLoading != oldWidget.isLoading) { + if (widget.isLoading?.value != oldWidget.isLoading?.value) { final loading = widget.isLoading; if (loading != null) { setState(() { - isLoading = loading; + isLoading = loading.value; }); } } @@ -101,6 +101,8 @@ class _AsyncButtonBuilderState extends State @override Widget build(BuildContext context) { + // TODO: All of these values can be memoized and only updated when their + // corresponding field value changes. This would be easier in hooks... final color = widget.valueColor; final padding = widget.padding; final loadingPadding = widget.loadingPadding; @@ -125,12 +127,13 @@ class _AsyncButtonBuilderState extends State context, AnimatedSize( duration: widget.duration, - vsync: this, child: isLoading ? loadingWidget : child, + vsync: this, ), isLoading ? null : () async { + widget.isLoading?.value = true; setState(() { isLoading = true; }); @@ -141,6 +144,7 @@ class _AsyncButtonBuilderState extends State rethrow; } finally { if (mounted) { + widget.isLoading?.value = false; setState(() { isLoading = false; }); From 64d48794b086b97a2e4e98ba68246eacca2409f1 Mon Sep 17 00:00:00 2001 From: Nolence Date: Tue, 12 Jan 2021 11:03:31 -0700 Subject: [PATCH 007/176] Forgot version change --- example/pubspec.lock | 2 +- pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/example/pubspec.lock b/example/pubspec.lock index df5e145..2a3d011 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -42,7 +42,7 @@ packages: path: ".." relative: true source: path - version: "0.0.1-nullsafety.2" + version: "0.1.0-nullsafety.0" boolean_selector: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index e20917f..ee272bb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_builder description: A builder to wrap around buttons that handles loading and disabled state -version: 0.0.1-nullsafety.2 +version: 0.1.0-nullsafety.0 homepage: https://github.com/Nolence/async_button_builder environment: From 4c84c8c2ffe403fd866c4e3e0c09c7727800041e Mon Sep 17 00:00:00 2001 From: Nolence Date: Tue, 12 Jan 2021 19:07:54 -0700 Subject: [PATCH 008/176] add loading param to builder plus new disabled field --- CHANGELOG.md | 4 ++ example/lib/main.dart | 42 ++++++++----------- example/pubspec.lock | 2 +- lib/async_button_builder.dart | 77 +++++++++++++++++++---------------- pubspec.yaml | 2 +- 5 files changed, 64 insertions(+), 63 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ff02ab..2394b02 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## [1.0.0-nullsafety.0] - 2021-01-12 + +Breaking. Adds a fourth argument of loading to the builder. This removes the value notifier that was difficult or confusing to manage in actual usage in my use cases. The argument isLoading is now a `bool`. This also adds a `disabled` field in order to set that on construction. + ## [0.1.0-nullsafety.0] - 2021-01-12 Replaces the bool type of isLoading for a ValueNotifier. diff --git a/example/lib/main.dart b/example/lib/main.dart index 5840c87..8b3d0b5 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,5 +1,4 @@ import 'package:async_button_builder/async_button_builder.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; void main() => runApp(MyApp()); @@ -15,14 +14,7 @@ class MyApp extends StatelessWidget { } } -class MyHomePage extends StatefulWidget { - @override - _MyHomePageState createState() => _MyHomePageState(); -} - -class _MyHomePageState extends State { - final isLoading = ValueNotifier(false); - +class MyHomePage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( @@ -40,7 +32,7 @@ class _MyHomePageState extends State { onPressed: () async { await Future.delayed(Duration(seconds: 1)); }, - builder: (context, child, callback) { + builder: (context, child, callback, _) { return TextButton( child: child, onPressed: callback, @@ -55,7 +47,7 @@ class _MyHomePageState extends State { onPressed: () async { await Future.delayed(Duration(seconds: 1)); }, - builder: (context, child, callback) { + builder: (context, child, callback, _) { return ElevatedButton( child: child, onPressed: callback, @@ -66,20 +58,18 @@ class _MyHomePageState extends State { Text('Custom Outline Button:'), AsyncButtonBuilder( child: Text('Click Me'), - isLoading: isLoading, loadingWidget: Text('Loading...'), + // Change me to see value change + isLoading: true, onPressed: () async { await Future.delayed(Duration(seconds: 1)); }, - builder: (context, child, callback) { - // This value is only listened to inside of `builder` - print(isLoading.value); - + builder: (context, child, callback, isLoading) { return OutlinedButton( child: child, onPressed: callback, style: ButtonStyle( - tapTargetSize: isLoading.value + tapTargetSize: isLoading ? MaterialTapTargetSize.shrinkWrap : MaterialTapTargetSize.padded, ), @@ -94,19 +84,21 @@ class _MyHomePageState extends State { shape: StadiumBorder(), child: AsyncButtonBuilder( valueColor: Colors.white, - padding: const EdgeInsets.symmetric( - horizontal: 16.0, - vertical: 8.0, - ), loadingPadding: const EdgeInsets.all(8.0), - child: Text( - 'Click Me', - style: TextStyle(color: Colors.white), + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16.0, + vertical: 8.0, + ), + child: Text( + 'Click Me', + style: TextStyle(color: Colors.white), + ), ), onPressed: () async { await Future.delayed(Duration(seconds: 1)); }, - builder: (context, child, callback) { + builder: (context, child, callback, _) { return InkWell( child: child, onTap: callback, diff --git a/example/pubspec.lock b/example/pubspec.lock index 2a3d011..856775f 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -42,7 +42,7 @@ packages: path: ".." relative: true source: path - version: "0.1.0-nullsafety.0" + version: "1.0.0-nullsafety.0" boolean_selector: dependency: transitive description: diff --git a/lib/async_button_builder.dart b/lib/async_button_builder.dart index 6c5b3fe..3af8e16 100644 --- a/lib/async_button_builder.dart +++ b/lib/async_button_builder.dart @@ -10,6 +10,7 @@ class AsyncButtonBuilder extends StatefulWidget { BuildContext context, Widget child, AsyncCallback? callback, + bool isLoading, ) builder; /// The child of the button. In the case of an [IconButton], this can be a an @@ -30,7 +31,14 @@ class AsyncButtonBuilder extends StatefulWidget { final AsyncCallback onPressed; /// This is used to manually drive the state of the loading button. - final ValueNotifier? isLoading; + /// + /// Until otherwise requested, if the button is not loading it will still + /// respond to presses and change the internal `isLoading`. In that case, + /// this `isLoading` will not match the actual one of the widget. + final bool isLoading; + + /// This is used to manually drive the disabled state of the button. + final bool disabled; /// The widget used to replace the [child] when the button is in a loading /// state. If this is null the default widget is: @@ -44,8 +52,7 @@ class AsyncButtonBuilder extends StatefulWidget { /// ) final Widget? loadingWidget; - /// This color changes the color of the default loading widget k-- a - /// [CircularProgressIndicator]. + /// This changes the color of the default [CircularProgressIndicator]. final Color? valueColor; /// Optional padding around the child. This is useful if you are creating @@ -59,15 +66,16 @@ class AsyncButtonBuilder extends StatefulWidget { const AsyncButtonBuilder({ Key? key, - required this.builder, required this.child, required this.onPressed, + required this.builder, this.duration = const Duration(milliseconds: 250), - this.isLoading, - this.loadingWidget, - this.valueColor, + this.isLoading = false, + this.disabled = false, this.padding, + this.loadingWidget, this.loadingPadding, + this.valueColor, }) : super(key: key); @override @@ -80,20 +88,16 @@ class _AsyncButtonBuilderState extends State @override void initState() { - isLoading = widget.isLoading?.value ?? false; + isLoading = widget.isLoading; super.initState(); } @override void didUpdateWidget(covariant AsyncButtonBuilder oldWidget) { - if (widget.isLoading?.value != oldWidget.isLoading?.value) { - final loading = widget.isLoading; - - if (loading != null) { - setState(() { - isLoading = loading.value; - }); - } + if (widget.isLoading != oldWidget.isLoading) { + setState(() { + isLoading = widget.isLoading; + }); } super.didUpdateWidget(oldWidget); @@ -101,8 +105,6 @@ class _AsyncButtonBuilderState extends State @override Widget build(BuildContext context) { - // TODO: All of these values can be memoized and only updated when their - // corresponding field value changes. This would be easier in hooks... final color = widget.valueColor; final padding = widget.padding; final loadingPadding = widget.loadingPadding; @@ -130,27 +132,30 @@ class _AsyncButtonBuilderState extends State child: isLoading ? loadingWidget : child, vsync: this, ), - isLoading + widget.disabled ? null - : () async { - widget.isLoading?.value = true; - setState(() { - isLoading = true; - }); - - try { - await widget.onPressed(); - } catch (error) { - rethrow; - } finally { - if (mounted) { - widget.isLoading?.value = false; + : isLoading + ? null + : () async { + // FIXME: I might not want to set isLoading if we're being + // driven by widget.isLoading setState(() { - isLoading = false; + isLoading = true; }); - } - } - }, + + try { + await widget.onPressed(); + } catch (error) { + rethrow; + } finally { + if (mounted) { + setState(() { + isLoading = false; + }); + } + } + }, + isLoading, ); } } diff --git a/pubspec.yaml b/pubspec.yaml index ee272bb..c6926a4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_builder description: A builder to wrap around buttons that handles loading and disabled state -version: 0.1.0-nullsafety.0 +version: 1.0.0-nullsafety.0 homepage: https://github.com/Nolence/async_button_builder environment: From c5da8cdf682c7fe54347fd8100082fed19563668 Mon Sep 17 00:00:00 2001 From: Nolence Date: Tue, 12 Jan 2021 19:18:14 -0700 Subject: [PATCH 009/176] Update readme --- README.md | 74 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 54bc308..687f1da 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ AsyncButtonBuilder( onPressed: () async { await Future.delayed(Duration(seconds: 1)); }, - builder: (context, child, callback) { + builder: (context, child, callback, _) { return TextButton( child: child, onPressed: callback, @@ -31,9 +31,31 @@ AsyncButtonBuilder( ), ``` +The fourth value in the builder allows you listen to the loading state. This can be used to conditionally style the button. + +```dart +AsyncButtonBuilder( + child: Text('Click Me'), + onPressed: () async { + await Future.delayed(Duration(seconds: 1)); + }, + builder: (context, child, callback, isLoading) { + return OutlinedButton( + child: child, + onPressed: callback, + style: ButtonStyle( + tapTargetSize: isLoading.value + ? MaterialTapTargetSize.shrinkWrap + : MaterialTapTargetSize.padded, + ), + ); + }, +), +``` + You can also change the loading indicator with anything you prefer using the `loadingWidget` field. By default it uses a `CircularProgressIndicator`. -For a custom button, you can specify properties such as `padding` and `loadingPadding`. +For a custom button, you can also specify properties such as `padding` and `loadingPadding`. These are convenience fields and the same result can be achieved by instead wrapping `child` and `loadingWidget` in `Padding`s. ```dart @@ -54,7 +76,7 @@ Material( onPressed: () async { await Future.delayed(Duration(seconds: 1)); }, - builder: (context, child, callback) { + builder: (context, child, callback, _) { return InkWell( child: child, onTap: callback, @@ -64,42 +86,22 @@ Material( ), ``` -To listen to the loading state, you can pass through a `isLoading` `ValueNotifier` to AsyncButtonBuilder. The value will be listened to inside the builder. You can also use this value to set the initial state of the button or change it programatically depending on your requirements. +If you need to drive the value of isLoading externally you can pass your value to the field `isLoading`. ```dart -class Example extends StatefulWidget { - @override - _ExampleState createState() => _ExampleState(); -} - -class _ExampleState extends State { - final isLoading = ValueNotifier(false); - - @override - Widget build(BuildContext context) { - return AsyncButtonBuilder( - child: Text('Click Me'), - isLoading: isLoading, - onPressed: () async { - await Future.delayed(Duration(seconds: 1)); - }, - builder: (context, child, callback) { - // This value is only listened to inside of `builder` - print(isLoading.value); - - return OutlinedButton( - child: child, - onPressed: callback, - style: ButtonStyle( - tapTargetSize: isLoading.value - ? MaterialTapTargetSize.shrinkWrap - : MaterialTapTargetSize.padded, - ), - ); - }, +AsyncButtonBuilder( + child: Text('Click Me'), + isLoading: false, + onPressed: () async { + await Future.delayed(Duration(seconds: 1)); + }, + builder: (context, child, callback, _) { + return OutlinedButton( + child: child, + onPressed: callback, ); - } -} + }, +), ``` Issues and PR's welcome \ No newline at end of file From 8e083fdf99fe46406b20a5e9c0ea04d709f3aa3a Mon Sep 17 00:00:00 2001 From: Nolence Date: Sat, 23 Jan 2021 14:12:39 -0700 Subject: [PATCH 010/176] Missing docs and examples --- LICENSE | 2 +- example/ios/Flutter/Debug.xcconfig | 1 + example/ios/Flutter/Release.xcconfig | 1 + example/ios/Podfile.lock | 2 +- .../contents.xcworkspacedata | 2 +- example/lib/main.dart | 23 +- example/pubspec.lock | 16 +- lib/async_button_builder.dart | 201 +++++--- lib/src/button_state/button_state.dart | 38 ++ .../button_state/button_state.freezed.dart | 445 ++++++++++++++++++ pubspec.lock | 324 ++++++++++++- pubspec.yaml | 3 + 12 files changed, 979 insertions(+), 79 deletions(-) create mode 100644 lib/src/button_state/button_state.dart create mode 100644 lib/src/button_state/button_state.freezed.dart diff --git a/LICENSE b/LICENSE index df4fb86..8da5f16 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2021 RexMa +Copyright (c) 2021 Rex Magana Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/example/ios/Flutter/Debug.xcconfig b/example/ios/Flutter/Debug.xcconfig index e8efba1..b2f5fae 100644 --- a/example/ios/Flutter/Debug.xcconfig +++ b/example/ios/Flutter/Debug.xcconfig @@ -1,2 +1,3 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/example/ios/Flutter/Release.xcconfig b/example/ios/Flutter/Release.xcconfig index 399e934..88c2914 100644 --- a/example/ios/Flutter/Release.xcconfig +++ b/example/ios/Flutter/Release.xcconfig @@ -1,2 +1,3 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index b69431a..f0772ce 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -19,4 +19,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c -COCOAPODS: 1.10.0 +COCOAPODS: 1.10.1 diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 1d526a1..919434a 100644 --- a/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/example/lib/main.dart b/example/lib/main.dart index 8b3d0b5..74d0bb5 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -36,7 +36,6 @@ class MyHomePage extends StatelessWidget { return TextButton( child: child, onPressed: callback, - style: ButtonStyle(), ); }, ), @@ -59,19 +58,25 @@ class MyHomePage extends StatelessWidget { AsyncButtonBuilder( child: Text('Click Me'), loadingWidget: Text('Loading...'), - // Change me to see value change - isLoading: true, onPressed: () async { await Future.delayed(Duration(seconds: 1)); + + throw 'shucks'; }, - builder: (context, child, callback, isLoading) { + builder: (context, child, callback, buttonState) { + final buttonColor = buttonState.when( + idling: () => Colors.pink, + loading: () => Colors.yellow, + completing: () => Colors.deepPurple, + erroring: () => Colors.blueGrey, + ); + return OutlinedButton( child: child, onPressed: callback, - style: ButtonStyle( - tapTargetSize: isLoading - ? MaterialTapTargetSize.shrinkWrap - : MaterialTapTargetSize.padded, + style: OutlinedButton.styleFrom( + primary: Colors.white, + backgroundColor: buttonColor, ), ); }, @@ -83,8 +88,6 @@ class MyHomePage extends StatelessWidget { color: Colors.lightBlue, shape: StadiumBorder(), child: AsyncButtonBuilder( - valueColor: Colors.white, - loadingPadding: const EdgeInsets.all(8.0), child: Padding( padding: const EdgeInsets.symmetric( horizontal: 16.0, diff --git a/example/pubspec.lock b/example/pubspec.lock index 856775f..c475e4d 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -142,6 +142,13 @@ packages: description: flutter source: sdk version: "0.0.0" + freezed_annotation: + dependency: transitive + description: + name: freezed_annotation + url: "https://pub.dartlang.org" + source: hosted + version: "0.13.0-nullsafety.0" fuchsia_remote_debug_protocol: dependency: transitive description: flutter @@ -173,6 +180,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.6.3-nullsafety.3" + json_annotation: + dependency: transitive + description: + name: json_annotation + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.0-nullsafety.0" json_rpc_2: dependency: transitive description: @@ -389,5 +403,5 @@ packages: source: hosted version: "2.2.1" sdks: - dart: ">=2.12.0-0.0 <3.0.0" + dart: ">=2.12.0-0.0.dev <3.0.0" flutter: ">=1.17.0" diff --git a/lib/async_button_builder.dart b/lib/async_button_builder.dart index 3af8e16..364ba57 100644 --- a/lib/async_button_builder.dart +++ b/lib/async_button_builder.dart @@ -1,3 +1,6 @@ +import 'dart:async'; + +import 'package:async_button_builder/src/button_state/button_state.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -10,7 +13,7 @@ class AsyncButtonBuilder extends StatefulWidget { BuildContext context, Widget child, AsyncCallback? callback, - bool isLoading, + ButtonState buttonState, ) builder; /// The child of the button. In the case of an [IconButton], this can be a an @@ -30,12 +33,13 @@ class AsyncButtonBuilder extends StatefulWidget { /// completes. final AsyncCallback onPressed; - /// This is used to manually drive the state of the loading button. + /// This is used to manually drive the state of the loading button thus + /// initiating the corresponding animation and button state /// /// Until otherwise requested, if the button is not loading it will still /// respond to presses and change the internal `isLoading`. In that case, /// this `isLoading` will not match the actual one of the widget. - final bool isLoading; + final ButtonState buttonState; /// This is used to manually drive the disabled state of the button. final bool disabled; @@ -50,19 +54,35 @@ class AsyncButtonBuilder extends StatefulWidget { /// valueColor: valueColor, /// ), /// ) - final Widget? loadingWidget; + final Widget loadingWidget; + + final AnimatedSwitcherTransitionBuilder idlingTransitionBuilder; + + final AnimatedSwitcherTransitionBuilder loadingTransitionBuilder; + + final AnimatedSwitcherTransitionBuilder completingTransitionBuilder; + + final AnimatedSwitcherTransitionBuilder erroringTransitionBuilder; + + /// The widget used to replace the [child] when the button is in a completing + /// state. If this is null the default widget is: + /// + /// SizedBox( + /// height: 16.0, + /// width: 16.0, + /// child: Icons(Icon.check) + /// ) + final Widget completingWidget; + + final Duration completingIdleTime; - /// This changes the color of the default [CircularProgressIndicator]. - final Color? valueColor; + final Duration erroringIdleTime; - /// Optional padding around the child. This is useful if you are creating - /// your own button with [Material] and need padding around the inner child. - final EdgeInsets? padding; + final Widget erroringWidget; - /// Optional padding around the loading widget. This is useful if you are - /// creating your own button with [Material] and need a seperate padding - /// around the loading indicator unequal to the child's [padding]. - final EdgeInsets? loadingPadding; + final Curve switchInCurve; + + final Curve switchOutCurve; const AsyncButtonBuilder({ Key? key, @@ -70,12 +90,30 @@ class AsyncButtonBuilder extends StatefulWidget { required this.onPressed, required this.builder, this.duration = const Duration(milliseconds: 250), - this.isLoading = false, + this.buttonState = const ButtonState.idling(), this.disabled = false, - this.padding, - this.loadingWidget, - this.loadingPadding, - this.valueColor, + this.completingIdleTime = const Duration(seconds: 1), + this.erroringIdleTime = const Duration(seconds: 1), + this.loadingWidget = const SizedBox( + height: 16.0, + width: 16.0, + child: CircularProgressIndicator(), + ), + this.completingWidget = const Icon( + Icons.check, + color: Colors.green, + ), + this.erroringWidget = const Icon( + Icons.error, + color: Colors.red, + ), + this.loadingTransitionBuilder = AnimatedSwitcher.defaultTransitionBuilder, + this.idlingTransitionBuilder = AnimatedSwitcher.defaultTransitionBuilder, + this.completingTransitionBuilder = + AnimatedSwitcher.defaultTransitionBuilder, + this.erroringTransitionBuilder = AnimatedSwitcher.defaultTransitionBuilder, + this.switchInCurve = Curves.linear, + this.switchOutCurve = Curves.linear, }) : super(key: key); @override @@ -84,19 +122,22 @@ class AsyncButtonBuilder extends StatefulWidget { class _AsyncButtonBuilderState extends State with SingleTickerProviderStateMixin { - late bool isLoading; + late ButtonState buttonState; + late final AnimationController controller; + Timer? timer; @override void initState() { - isLoading = widget.isLoading; + buttonState = widget.buttonState; + // am I going to need a different controller for each animation? super.initState(); } @override void didUpdateWidget(covariant AsyncButtonBuilder oldWidget) { - if (widget.isLoading != oldWidget.isLoading) { + if (widget.buttonState != oldWidget.buttonState) { setState(() { - isLoading = widget.isLoading; + buttonState = buttonState; }); } @@ -105,57 +146,89 @@ class _AsyncButtonBuilderState extends State @override Widget build(BuildContext context) { - final color = widget.valueColor; - final padding = widget.padding; - final loadingPadding = widget.loadingPadding; - final valueColor = - color == null ? null : AlwaysStoppedAnimation(color); - final child = padding == null - ? widget.child - : Padding(padding: padding, child: widget.child); - var loadingWidget = widget.loadingWidget ?? - SizedBox( - height: 16.0, - width: 16.0, - child: CircularProgressIndicator( - valueColor: valueColor, - ), - ); - loadingWidget = loadingPadding == null - ? loadingWidget - : Padding(padding: loadingPadding, child: loadingWidget); - return widget.builder( context, AnimatedSize( duration: widget.duration, - child: isLoading ? loadingWidget : child, vsync: this, + child: AnimatedSwitcher( + switchInCurve: widget.switchInCurve, + duration: widget.duration, + transitionBuilder: buttonState.when( + idling: () => widget.idlingTransitionBuilder, + loading: () => widget.loadingTransitionBuilder, + completing: () => widget.completingTransitionBuilder, + erroring: () => widget.erroringTransitionBuilder, + ), + child: buttonState.when( + idling: () => widget.child, + loading: () => widget.loadingWidget, + completing: () => widget.completingWidget, + erroring: () => widget.erroringWidget, + ), + ), ), widget.disabled ? null - : isLoading - ? null - : () async { - // FIXME: I might not want to set isLoading if we're being - // driven by widget.isLoading - setState(() { - isLoading = true; - }); - - try { - await widget.onPressed(); - } catch (error) { - rethrow; - } finally { - if (mounted) { - setState(() { - isLoading = false; - }); - } + : buttonState.maybeWhen( + idling: () => () async { + // FIXME: I might not want to set buttonState if we're being + // driven by widget.buttonState... + setState(() { + buttonState = ButtonState.loading(); + }); + + try { + await widget.onPressed(); + + timer?.cancel(); + + if (mounted) { + setState(() { + buttonState = ButtonState.completing(); + }); + + timer = Timer( + widget.completingIdleTime, + () { + timer?.cancel(); + + if (mounted) { + setState(() { + buttonState = ButtonState.idling(); + }); + } + }, + ); } - }, - isLoading, + } catch (error) { + timer?.cancel(); + + if (mounted) { + setState(() { + buttonState = ButtonState.erroring(); + }); + + timer = Timer( + widget.erroringIdleTime, + () { + timer?.cancel(); + + if (mounted) { + setState(() { + buttonState = ButtonState.idling(); + }); + } + }, + ); + } + + rethrow; + } + }, + orElse: () => null, + ), + buttonState, ); } } diff --git a/lib/src/button_state/button_state.dart b/lib/src/button_state/button_state.dart new file mode 100644 index 0000000..bbcfe5d --- /dev/null +++ b/lib/src/button_state/button_state.dart @@ -0,0 +1,38 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'button_state.freezed.dart'; + +/// This union class represents the state of the button in either a [Normal], +/// [Loading] or [Completing] state. This can be considered a enum with extra +/// utilities for ease of use. +/// +/// {@tool snippet} +/// +/// ```dart +/// final buttonColor = buttonState.when( +/// normal: () => Colors.pink, +/// loading: () => Colors.red, +/// completing: () => Colors.green, +/// ); +/// ``` +/// {@end-tool} +/// +/// You can also disregard other states and handle only those you'd like using +/// the `.maybeWhen` syntax. +/// +/// /// {@tool snippet} +/// +/// ```dart +/// final buttonColor = buttonState.maybeWhen( +/// normal: () => Colors.pink, +/// orElse: () => Colors.red, +/// ); +/// ``` +/// {@end-tool} +@freezed +abstract class ButtonState with _$ButtonState { + const factory ButtonState.idling() = Idling; + const factory ButtonState.loading() = Loading; + const factory ButtonState.completing() = Completing; + const factory ButtonState.erroring() = Erroring; +} diff --git a/lib/src/button_state/button_state.freezed.dart b/lib/src/button_state/button_state.freezed.dart new file mode 100644 index 0000000..d40dd20 --- /dev/null +++ b/lib/src/button_state/button_state.freezed.dart @@ -0,0 +1,445 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies + +part of 'button_state.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +/// @nodoc +class _$ButtonStateTearOff { + const _$ButtonStateTearOff(); + + Idling idling() { + return const Idling(); + } + + Loading loading() { + return const Loading(); + } + + Completing completing() { + return const Completing(); + } + + Erroring erroring() { + return const Erroring(); + } +} + +/// @nodoc +const $ButtonState = _$ButtonStateTearOff(); + +/// @nodoc +mixin _$ButtonState { + @optionalTypeArgs + TResult when({ + required TResult Function() idling, + required TResult Function() loading, + required TResult Function() completing, + required TResult Function() erroring, + }); + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? idling, + TResult Function()? loading, + TResult Function()? completing, + TResult Function()? erroring, + required TResult orElse(), + }); + @optionalTypeArgs + TResult map({ + required TResult Function(Idling value) idling, + required TResult Function(Loading value) loading, + required TResult Function(Completing value) completing, + required TResult Function(Erroring value) erroring, + }); + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Idling value)? idling, + TResult Function(Loading value)? loading, + TResult Function(Completing value)? completing, + TResult Function(Erroring value)? erroring, + required TResult orElse(), + }); +} + +/// @nodoc +abstract class $ButtonStateCopyWith<$Res> { + factory $ButtonStateCopyWith( + ButtonState value, $Res Function(ButtonState) then) = + _$ButtonStateCopyWithImpl<$Res>; +} + +/// @nodoc +class _$ButtonStateCopyWithImpl<$Res> implements $ButtonStateCopyWith<$Res> { + _$ButtonStateCopyWithImpl(this._value, this._then); + + final ButtonState _value; + // ignore: unused_field + final $Res Function(ButtonState) _then; +} + +/// @nodoc +abstract class $IdlingCopyWith<$Res> { + factory $IdlingCopyWith(Idling value, $Res Function(Idling) then) = + _$IdlingCopyWithImpl<$Res>; +} + +/// @nodoc +class _$IdlingCopyWithImpl<$Res> extends _$ButtonStateCopyWithImpl<$Res> + implements $IdlingCopyWith<$Res> { + _$IdlingCopyWithImpl(Idling _value, $Res Function(Idling) _then) + : super(_value, (v) => _then(v as Idling)); + + @override + Idling get _value => super._value as Idling; +} + +/// @nodoc +class _$Idling implements Idling { + const _$Idling(); + + @override + String toString() { + return 'ButtonState.idling()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || (other is Idling); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() idling, + required TResult Function() loading, + required TResult Function() completing, + required TResult Function() erroring, + }) { + return idling(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? idling, + TResult Function()? loading, + TResult Function()? completing, + TResult Function()? erroring, + required TResult orElse(), + }) { + if (idling != null) { + return idling(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(Idling value) idling, + required TResult Function(Loading value) loading, + required TResult Function(Completing value) completing, + required TResult Function(Erroring value) erroring, + }) { + return idling(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Idling value)? idling, + TResult Function(Loading value)? loading, + TResult Function(Completing value)? completing, + TResult Function(Erroring value)? erroring, + required TResult orElse(), + }) { + if (idling != null) { + return idling(this); + } + return orElse(); + } +} + +abstract class Idling implements ButtonState { + const factory Idling() = _$Idling; +} + +/// @nodoc +abstract class $LoadingCopyWith<$Res> { + factory $LoadingCopyWith(Loading value, $Res Function(Loading) then) = + _$LoadingCopyWithImpl<$Res>; +} + +/// @nodoc +class _$LoadingCopyWithImpl<$Res> extends _$ButtonStateCopyWithImpl<$Res> + implements $LoadingCopyWith<$Res> { + _$LoadingCopyWithImpl(Loading _value, $Res Function(Loading) _then) + : super(_value, (v) => _then(v as Loading)); + + @override + Loading get _value => super._value as Loading; +} + +/// @nodoc +class _$Loading implements Loading { + const _$Loading(); + + @override + String toString() { + return 'ButtonState.loading()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || (other is Loading); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() idling, + required TResult Function() loading, + required TResult Function() completing, + required TResult Function() erroring, + }) { + return loading(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? idling, + TResult Function()? loading, + TResult Function()? completing, + TResult Function()? erroring, + required TResult orElse(), + }) { + if (loading != null) { + return loading(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(Idling value) idling, + required TResult Function(Loading value) loading, + required TResult Function(Completing value) completing, + required TResult Function(Erroring value) erroring, + }) { + return loading(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Idling value)? idling, + TResult Function(Loading value)? loading, + TResult Function(Completing value)? completing, + TResult Function(Erroring value)? erroring, + required TResult orElse(), + }) { + if (loading != null) { + return loading(this); + } + return orElse(); + } +} + +abstract class Loading implements ButtonState { + const factory Loading() = _$Loading; +} + +/// @nodoc +abstract class $CompletingCopyWith<$Res> { + factory $CompletingCopyWith( + Completing value, $Res Function(Completing) then) = + _$CompletingCopyWithImpl<$Res>; +} + +/// @nodoc +class _$CompletingCopyWithImpl<$Res> extends _$ButtonStateCopyWithImpl<$Res> + implements $CompletingCopyWith<$Res> { + _$CompletingCopyWithImpl(Completing _value, $Res Function(Completing) _then) + : super(_value, (v) => _then(v as Completing)); + + @override + Completing get _value => super._value as Completing; +} + +/// @nodoc +class _$Completing implements Completing { + const _$Completing(); + + @override + String toString() { + return 'ButtonState.completing()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || (other is Completing); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() idling, + required TResult Function() loading, + required TResult Function() completing, + required TResult Function() erroring, + }) { + return completing(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? idling, + TResult Function()? loading, + TResult Function()? completing, + TResult Function()? erroring, + required TResult orElse(), + }) { + if (completing != null) { + return completing(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(Idling value) idling, + required TResult Function(Loading value) loading, + required TResult Function(Completing value) completing, + required TResult Function(Erroring value) erroring, + }) { + return completing(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Idling value)? idling, + TResult Function(Loading value)? loading, + TResult Function(Completing value)? completing, + TResult Function(Erroring value)? erroring, + required TResult orElse(), + }) { + if (completing != null) { + return completing(this); + } + return orElse(); + } +} + +abstract class Completing implements ButtonState { + const factory Completing() = _$Completing; +} + +/// @nodoc +abstract class $ErroringCopyWith<$Res> { + factory $ErroringCopyWith(Erroring value, $Res Function(Erroring) then) = + _$ErroringCopyWithImpl<$Res>; +} + +/// @nodoc +class _$ErroringCopyWithImpl<$Res> extends _$ButtonStateCopyWithImpl<$Res> + implements $ErroringCopyWith<$Res> { + _$ErroringCopyWithImpl(Erroring _value, $Res Function(Erroring) _then) + : super(_value, (v) => _then(v as Erroring)); + + @override + Erroring get _value => super._value as Erroring; +} + +/// @nodoc +class _$Erroring implements Erroring { + const _$Erroring(); + + @override + String toString() { + return 'ButtonState.erroring()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || (other is Erroring); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() idling, + required TResult Function() loading, + required TResult Function() completing, + required TResult Function() erroring, + }) { + return erroring(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? idling, + TResult Function()? loading, + TResult Function()? completing, + TResult Function()? erroring, + required TResult orElse(), + }) { + if (erroring != null) { + return erroring(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(Idling value) idling, + required TResult Function(Loading value) loading, + required TResult Function(Completing value) completing, + required TResult Function(Erroring value) erroring, + }) { + return erroring(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Idling value)? idling, + TResult Function(Loading value)? loading, + TResult Function(Completing value)? completing, + TResult Function(Erroring value)? erroring, + required TResult orElse(), + }) { + if (erroring != null) { + return erroring(this); + } + return orElse(); + } +} + +abstract class Erroring implements ButtonState { + const factory Erroring() = _$Erroring; +} diff --git a/pubspec.lock b/pubspec.lock index c89f420..c9a5973 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,6 +1,27 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + url: "https://pub.dartlang.org" + source: hosted + version: "14.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + url: "https://pub.dartlang.org" + source: hosted + version: "0.41.2" + args: + dependency: transitive + description: + name: args + url: "https://pub.dartlang.org" + source: hosted + version: "1.6.0" async: dependency: transitive description: @@ -15,6 +36,62 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0-nullsafety.3" + build: + dependency: transitive + description: + name: build + url: "https://pub.dartlang.org" + source: hosted + version: "1.6.1" + build_config: + dependency: transitive + description: + name: build_config + url: "https://pub.dartlang.org" + source: hosted + version: "0.4.5" + build_daemon: + dependency: transitive + description: + name: build_daemon + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.6" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + url: "https://pub.dartlang.org" + source: hosted + version: "1.5.2" + build_runner: + dependency: "direct dev" + description: + name: build_runner + url: "https://pub.dartlang.org" + source: hosted + version: "1.10.13" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + url: "https://pub.dartlang.org" + source: hosted + version: "6.1.6" + built_collection: + dependency: transitive + description: + name: built_collection + url: "https://pub.dartlang.org" + source: hosted + version: "4.3.2" + built_value: + dependency: transitive + description: + name: built_value + url: "https://pub.dartlang.org" + source: hosted + version: "7.1.0" characters: dependency: transitive description: @@ -29,6 +106,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.0-nullsafety.3" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.4" + cli_util: + dependency: transitive + description: + name: cli_util + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.0" clock: dependency: transitive description: @@ -36,6 +127,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.0-nullsafety.3" + code_builder: + dependency: transitive + description: + name: code_builder + url: "https://pub.dartlang.org" + source: hosted + version: "3.6.0" collection: dependency: transitive description: @@ -43,6 +141,27 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.15.0-nullsafety.5" + convert: + dependency: transitive + description: + name: convert + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.1" + crypto: + dependency: transitive + description: + name: crypto + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.5" + dart_style: + dependency: transitive + description: + name: dart_style + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.11" fake_async: dependency: transitive description: @@ -50,6 +169,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.0-nullsafety.3" + file: + dependency: transitive + description: + name: file + url: "https://pub.dartlang.org" + source: hosted + version: "5.2.1" + fixnum: + dependency: transitive + description: + name: fixnum + url: "https://pub.dartlang.org" + source: hosted + version: "0.10.11" flutter: dependency: "direct main" description: flutter @@ -60,6 +193,83 @@ packages: description: flutter source: sdk version: "0.0.0" + freezed: + dependency: "direct dev" + description: + name: freezed + url: "https://pub.dartlang.org" + source: hosted + version: "0.13.0-nullsafety.0" + freezed_annotation: + dependency: "direct main" + description: + name: freezed_annotation + url: "https://pub.dartlang.org" + source: hosted + version: "0.13.0-nullsafety.0" + glob: + dependency: transitive + description: + name: glob + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + graphs: + dependency: transitive + description: + name: graphs + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.0" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.0" + http_parser: + dependency: transitive + description: + name: http_parser + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.4" + intl: + dependency: transitive + description: + name: intl + url: "https://pub.dartlang.org" + source: hosted + version: "0.16.1" + io: + dependency: transitive + description: + name: io + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.4" + js: + dependency: transitive + description: + name: js + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.2" + json_annotation: + dependency: transitive + description: + name: json_annotation + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.0-nullsafety.0" + logging: + dependency: transitive + description: + name: logging + url: "https://pub.dartlang.org" + source: hosted + version: "0.11.4" matcher: dependency: transitive description: @@ -74,6 +284,34 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.0-nullsafety.6" + mime: + dependency: transitive + description: + name: mime + url: "https://pub.dartlang.org" + source: hosted + version: "0.9.7" + node_interop: + dependency: transitive + description: + name: node_interop + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.1" + node_io: + dependency: transitive + description: + name: node_io + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + package_config: + dependency: transitive + description: + name: package_config + url: "https://pub.dartlang.org" + source: hosted + version: "1.9.3" path: dependency: transitive description: @@ -88,11 +326,60 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.10.0-nullsafety.3" + pool: + dependency: transitive + description: + name: pool + url: "https://pub.dartlang.org" + source: hosted + version: "1.4.0" + pub_semver: + dependency: transitive + description: + name: pub_semver + url: "https://pub.dartlang.org" + source: hosted + version: "1.4.4" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.7" + quiver: + dependency: transitive + description: + name: quiver + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.5" + shelf: + dependency: transitive + description: + name: shelf + url: "https://pub.dartlang.org" + source: hosted + version: "0.7.9" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.3" sky_engine: dependency: transitive description: flutter source: sdk version: "0.0.99" + source_gen: + dependency: transitive + description: + name: source_gen + url: "https://pub.dartlang.org" + source: hosted + version: "0.9.10+1" source_span: dependency: transitive description: @@ -114,6 +401,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0-nullsafety.3" + stream_transform: + dependency: transitive + description: + name: stream_transform + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" string_scanner: dependency: transitive description: @@ -135,6 +429,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.2.19-nullsafety.6" + timing: + dependency: transitive + description: + name: timing + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.1+3" typed_data: dependency: transitive description: @@ -149,6 +450,27 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0-nullsafety.5" + watcher: + dependency: transitive + description: + name: watcher + url: "https://pub.dartlang.org" + source: hosted + version: "0.9.7+15" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + yaml: + dependency: transitive + description: + name: yaml + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.1" sdks: - dart: ">=2.12.0-0.0 <3.0.0" + dart: ">=2.12.0-0.0.dev <3.0.0" flutter: ">=1.17.0" diff --git a/pubspec.yaml b/pubspec.yaml index c6926a4..88a945c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -10,10 +10,13 @@ environment: dependencies: flutter: sdk: flutter + freezed_annotation: ^0.13.0-nullsafety.0 dev_dependencies: flutter_test: sdk: flutter + build_runner: ^1.10.13 + freezed: ^0.13.0-nullsafety.0 pedantic: ^1.10.0-nullsafety.3 flutter: \ No newline at end of file From faed4de2157ace88fd6ee10a6ab3cdf9b25e3e9a Mon Sep 17 00:00:00 2001 From: Nolence Date: Mon, 25 Jan 2021 10:37:08 -0700 Subject: [PATCH 011/176] Finalized pre release add asset --- CHANGELOG.md | 4 + README.md | 113 ++++++---- example/lib/main.dart | 92 ++++++--- example/pubspec.lock | 2 +- lib/async_button_builder.dart | 236 +-------------------- lib/src/async_button_builder.dart | 274 +++++++++++++++++++++++++ lib/src/button_state/button_state.dart | 7 +- pubspec.yaml | 2 +- screenshots/ezgif-1-492fa074abc6.gif | Bin 0 -> 449650 bytes screenshots/ezgif-2-22348353c16f.gif | Bin 585417 -> 0 bytes 10 files changed, 425 insertions(+), 305 deletions(-) create mode 100644 lib/src/async_button_builder.dart create mode 100644 screenshots/ezgif-1-492fa074abc6.gif delete mode 100644 screenshots/ezgif-2-22348353c16f.gif diff --git a/CHANGELOG.md b/CHANGELOG.md index 2394b02..c466227 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## [2.0.0-dev.1] - 2021-01-25 + +Breaking. Replaces the fourth argument with a sealed union that better allows for directly managing states, removes unnecessary arguments such as padding, adds transition builders for custom transitions. Currently still includes AnimatedSize. + ## [1.0.0-nullsafety.0] - 2021-01-12 Breaking. Adds a fourth argument of loading to the builder. This removes the value notifier that was difficult or confusing to manage in actual usage in my use cases. The argument isLoading is now a `bool`. This also adds a `disabled` field in order to set that on construction. diff --git a/README.md b/README.md index 687f1da..5d5005c 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,11 @@ # async_button_builder -A builder that adds loading and disabled states on top of buttons that perform asynchronous tasks. It can be used with most any button or even on top of a custom Material button. It includes fluid animation between states as well using `AnimatedSize`. +## This is a pre release and I'd like suggestions on naming, usability, further improvments. Thank you! + +A builder that adds loading, disabled, errored and completed states on top of buttons that perform asynchronous tasks. It can be used with most any button or even on top of a custom Material button. It includes fluid animation between states as well using `AnimatedSize` as well as the possibility to define your own transition builder.

- +

## Getting Started @@ -31,7 +33,7 @@ AsyncButtonBuilder( ), ``` -The fourth value in the builder allows you listen to the loading state. This can be used to conditionally style the button. +The fourth value in the builder allows you listen to the loading state. This can be used to conditionally style the button. This package depends `freezed` in order to create a sealed union to better handle the possible states. ```dart AsyncButtonBuilder( @@ -39,66 +41,99 @@ AsyncButtonBuilder( onPressed: () async { await Future.delayed(Duration(seconds: 1)); }, - builder: (context, child, callback, isLoading) { - return OutlinedButton( + builder: (context, child, callback, state) { + return ElevatedButton( child: child, onPressed: callback, - style: ButtonStyle( - tapTargetSize: isLoading.value - ? MaterialTapTargetSize.shrinkWrap - : MaterialTapTargetSize.padded, + style: ElevatedButton.styleFrom( + primary: state.when( + idling: () => Colors.pink, + loading: () => Colors.grey, + completing: () => Colors.pinkAccent, + erroring: () => Colors.red[100], + ), ), ); }, ), ``` -You can also change the loading indicator with anything you prefer using the `loadingWidget` field. By default it uses a `CircularProgressIndicator`. +You can also drive the state of the button yourself using the `buttonState` field: + +```dart +AsyncButtonBuilder( + buttonState: ButtonState.completing(), + // ... +), +``` -For a custom button, you can also specify properties such as `padding` and `loadingPadding`. These are convenience fields and the same result can be achieved by instead wrapping `child` and `loadingWidget` in `Padding`s. +`async_button_builder` even works for custom buttons. You can define your own widgets for loading, error, and completion as well as define the transitions between them. This example is a little verbose but shows some of what's possible. ```dart -Material( - color: Colors.lightBlue, - shape: StadiumBorder(), - child: AsyncButtonBuilder( - valueColor: Colors.white, +AsyncButtonBuilder( + child: Padding( + // Value keys are important as otherwise our custom transitions + // will have no way to differentiate between children. This is not + // specific to this library but Flutter's `AnimatedSwitcher`. + key: ValueKey('foo'), padding: const EdgeInsets.symmetric( horizontal: 16.0, vertical: 8.0, ), - loadingPadding: const EdgeInsets.all(8.0), child: Text( 'Click Me', style: TextStyle(color: Colors.white), ), - onPressed: () async { - await Future.delayed(Duration(seconds: 1)); - }, - builder: (context, child, callback, _) { - return InkWell( - child: child, - onTap: callback, - ); - }, ), -), -``` - -If you need to drive the value of isLoading externally you can pass your value to the field `isLoading`. - -```dart -AsyncButtonBuilder( - child: Text('Click Me'), - isLoading: false, + loadingWidget: Padding( + key: ValueKey('bar'), + padding: const EdgeInsets.all(8.0), + child: SizedBox( + height: 16.0, + width: 16.0, + child: CircularProgressIndicator( + valueColor: AlwaysStoppedAnimation(Colors.white), + ), + ), + ), + completingWidget: Padding( + key: ValueKey('foobar'), + padding: const EdgeInsets.all(4.0), + child: Icon( + Icons.check, + color: Colors.purpleAccent, + ), + ), onPressed: () async { - await Future.delayed(Duration(seconds: 1)); + await Future.delayed(Duration(seconds: 2)); }, - builder: (context, child, callback, _) { - return OutlinedButton( + loadingSwitchInCurve: Curves.bounceInOut, + loadingTransitionBuilder: (child, animation) { + // The loading indicator will come up from the button using a + // `bounceInOut` curve. + return SlideTransition( + position: Tween( + begin: Offset(0, 1.0), + end: Offset(0, 0), + ).animate(animation), child: child, - onPressed: callback, + ); + }, + builder: (context, child, callback, state) { + return Material( + color: state.maybeWhen( + completing: () => Colors.purple[100], + orElse: () => Colors.blue, + ), + // This prevents the loading indicator showing below the + // button + clipBehavior: Clip.hardEdge, + shape: StadiumBorder(), + child: InkWell( + child: child, + onTap: callback, + ), ); }, ), diff --git a/example/lib/main.dart b/example/lib/main.dart index 74d0bb5..7e397d9 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -8,7 +8,7 @@ class MyApp extends StatelessWidget { Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', - theme: ThemeData(primarySwatch: Colors.blue), + theme: ThemeData.dark(), home: MyHomePage(), ); } @@ -54,7 +54,7 @@ class MyHomePage extends StatelessWidget { }, ), Divider(), - Text('Custom Outline Button:'), + Text('Custom Outlined Button (Error):'), AsyncButtonBuilder( child: Text('Click Me'), loadingWidget: Text('Loading...'), @@ -65,17 +65,17 @@ class MyHomePage extends StatelessWidget { }, builder: (context, child, callback, buttonState) { final buttonColor = buttonState.when( - idling: () => Colors.pink, - loading: () => Colors.yellow, - completing: () => Colors.deepPurple, - erroring: () => Colors.blueGrey, + idling: () => Colors.yellow[200], + loading: () => Colors.grey, + completing: () => Colors.orangeAccent, + erroring: () => Colors.orange, ); return OutlinedButton( child: child, onPressed: callback, style: OutlinedButton.styleFrom( - primary: Colors.white, + primary: Colors.black, backgroundColor: buttonColor, ), ); @@ -84,30 +84,68 @@ class MyHomePage extends StatelessWidget { Divider(), Text('Custom Material Button:'), const SizedBox(height: 6.0), - Material( - color: Colors.lightBlue, - shape: StadiumBorder(), - child: AsyncButtonBuilder( - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 16.0, - vertical: 8.0, - ), - child: Text( - 'Click Me', - style: TextStyle(color: Colors.white), + AsyncButtonBuilder( + child: Padding( + // Value keys are important as otherwise our custom transitions + // will have no way to differentiate between children. + key: ValueKey('lust'), + padding: const EdgeInsets.symmetric( + horizontal: 16.0, + vertical: 8.0, + ), + child: Text( + 'Click Me', + style: TextStyle(color: Colors.white), + ), + ), + loadingWidget: Padding( + key: ValueKey('envy'), + padding: const EdgeInsets.all(8.0), + child: SizedBox( + height: 16.0, + width: 16.0, + child: CircularProgressIndicator( + valueColor: AlwaysStoppedAnimation(Colors.white), ), ), - onPressed: () async { - await Future.delayed(Duration(seconds: 1)); - }, - builder: (context, child, callback, _) { - return InkWell( + ), + completingWidget: Padding( + key: ValueKey('sloth'), + padding: const EdgeInsets.all(4.0), + child: Icon( + Icons.check, + color: Colors.purpleAccent, + ), + ), + onPressed: () async { + await Future.delayed(Duration(seconds: 2)); + }, + loadingSwitchInCurve: Curves.bounceInOut, + loadingTransitionBuilder: (child, animation) { + return SlideTransition( + position: Tween( + begin: Offset(0, 1.0), + end: Offset(0, 0), + ).animate(animation), + child: child, + ); + }, + builder: (context, child, callback, state) { + return Material( + color: state.maybeWhen( + completing: () => Colors.purple[100], + orElse: () => Colors.blue, + ), + // This prevents the loading indicator showing below the + // button + clipBehavior: Clip.hardEdge, + shape: StadiumBorder(), + child: InkWell( child: child, onTap: callback, - ); - }, - ), + ), + ); + }, ), Divider(), Spacer(), diff --git a/example/pubspec.lock b/example/pubspec.lock index c475e4d..3b90ec6 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -42,7 +42,7 @@ packages: path: ".." relative: true source: path - version: "1.0.0-nullsafety.0" + version: "2.0.0-dev.1" boolean_selector: dependency: transitive description: diff --git a/lib/async_button_builder.dart b/lib/async_button_builder.dart index 364ba57..9afabcc 100644 --- a/lib/async_button_builder.dart +++ b/lib/async_button_builder.dart @@ -1,234 +1,2 @@ -import 'dart:async'; - -import 'package:async_button_builder/src/button_state/button_state.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; - -/// A `builder` that wraps a button automatically providing disabled and loading -/// states while retaining full access to a Button's API. Useful for any long -/// running operations or to prevent the user from clicking multiple times -/// while an asynchronous task is running. -class AsyncButtonBuilder extends StatefulWidget { - final Widget Function( - BuildContext context, - Widget child, - AsyncCallback? callback, - ButtonState buttonState, - ) builder; - - /// The child of the button. In the case of an [IconButton], this can be a an - /// [Icon]. For a [TextButton], a [Text]. - /// - /// This child will be animated between for the [loadingWidget] or default - /// [CircularProgressIndicator] when the asynchronous [onPressed] is called. - /// The animation will take place over [duration]. - final Widget child; - - /// The animation's duration between [child] and [loadingWidget] using - /// [AnimatedSize]. - final Duration duration; - - /// A callback that runs the async task. This is wrapped in order to begin - /// the button's internal `isLoading` before and after the operation - /// completes. - final AsyncCallback onPressed; - - /// This is used to manually drive the state of the loading button thus - /// initiating the corresponding animation and button state - /// - /// Until otherwise requested, if the button is not loading it will still - /// respond to presses and change the internal `isLoading`. In that case, - /// this `isLoading` will not match the actual one of the widget. - final ButtonState buttonState; - - /// This is used to manually drive the disabled state of the button. - final bool disabled; - - /// The widget used to replace the [child] when the button is in a loading - /// state. If this is null the default widget is: - /// - /// SizedBox( - /// height: 16.0, - /// width: 16.0, - /// child: CircularProgressIndicator( - /// valueColor: valueColor, - /// ), - /// ) - final Widget loadingWidget; - - final AnimatedSwitcherTransitionBuilder idlingTransitionBuilder; - - final AnimatedSwitcherTransitionBuilder loadingTransitionBuilder; - - final AnimatedSwitcherTransitionBuilder completingTransitionBuilder; - - final AnimatedSwitcherTransitionBuilder erroringTransitionBuilder; - - /// The widget used to replace the [child] when the button is in a completing - /// state. If this is null the default widget is: - /// - /// SizedBox( - /// height: 16.0, - /// width: 16.0, - /// child: Icons(Icon.check) - /// ) - final Widget completingWidget; - - final Duration completingIdleTime; - - final Duration erroringIdleTime; - - final Widget erroringWidget; - - final Curve switchInCurve; - - final Curve switchOutCurve; - - const AsyncButtonBuilder({ - Key? key, - required this.child, - required this.onPressed, - required this.builder, - this.duration = const Duration(milliseconds: 250), - this.buttonState = const ButtonState.idling(), - this.disabled = false, - this.completingIdleTime = const Duration(seconds: 1), - this.erroringIdleTime = const Duration(seconds: 1), - this.loadingWidget = const SizedBox( - height: 16.0, - width: 16.0, - child: CircularProgressIndicator(), - ), - this.completingWidget = const Icon( - Icons.check, - color: Colors.green, - ), - this.erroringWidget = const Icon( - Icons.error, - color: Colors.red, - ), - this.loadingTransitionBuilder = AnimatedSwitcher.defaultTransitionBuilder, - this.idlingTransitionBuilder = AnimatedSwitcher.defaultTransitionBuilder, - this.completingTransitionBuilder = - AnimatedSwitcher.defaultTransitionBuilder, - this.erroringTransitionBuilder = AnimatedSwitcher.defaultTransitionBuilder, - this.switchInCurve = Curves.linear, - this.switchOutCurve = Curves.linear, - }) : super(key: key); - - @override - _AsyncButtonBuilderState createState() => _AsyncButtonBuilderState(); -} - -class _AsyncButtonBuilderState extends State - with SingleTickerProviderStateMixin { - late ButtonState buttonState; - late final AnimationController controller; - Timer? timer; - - @override - void initState() { - buttonState = widget.buttonState; - // am I going to need a different controller for each animation? - super.initState(); - } - - @override - void didUpdateWidget(covariant AsyncButtonBuilder oldWidget) { - if (widget.buttonState != oldWidget.buttonState) { - setState(() { - buttonState = buttonState; - }); - } - - super.didUpdateWidget(oldWidget); - } - - @override - Widget build(BuildContext context) { - return widget.builder( - context, - AnimatedSize( - duration: widget.duration, - vsync: this, - child: AnimatedSwitcher( - switchInCurve: widget.switchInCurve, - duration: widget.duration, - transitionBuilder: buttonState.when( - idling: () => widget.idlingTransitionBuilder, - loading: () => widget.loadingTransitionBuilder, - completing: () => widget.completingTransitionBuilder, - erroring: () => widget.erroringTransitionBuilder, - ), - child: buttonState.when( - idling: () => widget.child, - loading: () => widget.loadingWidget, - completing: () => widget.completingWidget, - erroring: () => widget.erroringWidget, - ), - ), - ), - widget.disabled - ? null - : buttonState.maybeWhen( - idling: () => () async { - // FIXME: I might not want to set buttonState if we're being - // driven by widget.buttonState... - setState(() { - buttonState = ButtonState.loading(); - }); - - try { - await widget.onPressed(); - - timer?.cancel(); - - if (mounted) { - setState(() { - buttonState = ButtonState.completing(); - }); - - timer = Timer( - widget.completingIdleTime, - () { - timer?.cancel(); - - if (mounted) { - setState(() { - buttonState = ButtonState.idling(); - }); - } - }, - ); - } - } catch (error) { - timer?.cancel(); - - if (mounted) { - setState(() { - buttonState = ButtonState.erroring(); - }); - - timer = Timer( - widget.erroringIdleTime, - () { - timer?.cancel(); - - if (mounted) { - setState(() { - buttonState = ButtonState.idling(); - }); - } - }, - ); - } - - rethrow; - } - }, - orElse: () => null, - ), - buttonState, - ); - } -} +export 'package:async_button_builder/src/async_button_builder.dart'; +export 'package:async_button_builder/src/button_state/button_state.dart'; diff --git a/lib/src/async_button_builder.dart b/lib/src/async_button_builder.dart new file mode 100644 index 0000000..3234aee --- /dev/null +++ b/lib/src/async_button_builder.dart @@ -0,0 +1,274 @@ +import 'dart:async'; + +import 'package:async_button_builder/src/button_state/button_state.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +/// A `builder` that wraps a button automatically providing disabled and loading +/// states while retaining full access to a Button's API. Useful for any long +/// running operations or to prevent the user from clicking multiple times +/// while an asynchronous task is running. +class AsyncButtonBuilder extends StatefulWidget { + final Widget Function( + BuildContext context, + Widget child, + AsyncCallback? callback, + ButtonState buttonState, + ) builder; + + /// The child of the button. In the case of an [IconButton], this can be a an + /// [Icon]. For a [TextButton], a [Text]. + /// + /// This child will be animated between for the [loadingWidget] or default + /// [CircularProgressIndicator] when the asynchronous [onPressed] is called. + /// The animation will take place over [duration]. + final Widget child; + + /// The animation's duration between [child] and [loadingWidget] using + /// [AnimatedSize]. + final Duration duration; + + /// A callback that runs the async task. This is wrapped in order to begin + /// the button's internal `isLoading` before and after the operation + /// completes. + final AsyncCallback onPressed; + + /// This is used to manually drive the state of the loading button thus + /// initiating the corresponding animation and showing the correct button + /// child + final ButtonState buttonState; + + /// This is used to manually drive the disabled state of the button. + final bool disabled; + + /// The widget used to replace the [child] when the button is in a loading + /// state. If this is null the default widget is: + /// + /// SizedBox( + /// height: 16.0, + /// width: 16.0, + /// child: CircularProgressIndicator( + /// valueColor: valueColor, + /// ), + /// ) + final Widget? loadingWidget; + + /// The widget used to replace the [child] when the button is in a completing + /// state. If this is null the default widget is: + /// + /// SizedBox( + /// height: 16.0, + /// width: 16.0, + /// child: Icons(Icon.check) + /// ) + final Widget? completingWidget; + + final Widget? erroringWidget; + + final AnimatedSwitcherTransitionBuilder idlingTransitionBuilder; + + final AnimatedSwitcherTransitionBuilder loadingTransitionBuilder; + + final AnimatedSwitcherTransitionBuilder completingTransitionBuilder; + + final AnimatedSwitcherTransitionBuilder erroringTransitionBuilder; + + final Duration completingIdleTime; + + final Duration erroringIdleTime; + + final Curve idlingSwitchInCurve; + + final Curve loadingSwitchInCurve; + + final Curve completingSwitchInCurve; + + final Curve erroringSwitchInCurve; + + final Curve idlingSwitchOutCurve; + + final Curve loadingSwitchOutCurve; + + final Curve completingSwitchOutCurve; + + final Curve erroringSwitchOutCurve; + + const AsyncButtonBuilder({ + Key? key, + required this.child, + required this.onPressed, + required this.builder, + this.loadingWidget, + this.completingWidget, + this.erroringWidget, + this.duration = const Duration(milliseconds: 250), + this.buttonState = const ButtonState.idling(), + this.disabled = false, + this.completingIdleTime = const Duration(seconds: 1), + this.erroringIdleTime = const Duration(seconds: 1), + this.loadingTransitionBuilder = AnimatedSwitcher.defaultTransitionBuilder, + this.idlingTransitionBuilder = AnimatedSwitcher.defaultTransitionBuilder, + this.completingTransitionBuilder = + AnimatedSwitcher.defaultTransitionBuilder, + this.erroringTransitionBuilder = AnimatedSwitcher.defaultTransitionBuilder, + this.idlingSwitchInCurve = Curves.linear, + this.loadingSwitchInCurve = Curves.linear, + this.completingSwitchInCurve = Curves.linear, + this.erroringSwitchInCurve = Curves.linear, + this.idlingSwitchOutCurve = Curves.linear, + this.loadingSwitchOutCurve = Curves.linear, + this.completingSwitchOutCurve = Curves.linear, + this.erroringSwitchOutCurve = Curves.linear, + }) : super(key: key); + // TODO: I need asserts that will assert the keys are different for child, + // loading, error, etc. because otherwise transitions won't work as expected + + // assert(widget.child.key != loadingWidget.key && + // loadingWidget.key != completingWidget.key && + // completingWidget.key != erroringWidget.key); + + @override + _AsyncButtonBuilderState createState() => _AsyncButtonBuilderState(); +} + +class _AsyncButtonBuilderState extends State + with SingleTickerProviderStateMixin { + late ButtonState buttonState; + late final AnimationController controller; + Timer? timer; + + @override + void initState() { + buttonState = widget.buttonState; + super.initState(); + } + + @override + void didUpdateWidget(covariant AsyncButtonBuilder oldWidget) { + if (widget.buttonState != oldWidget.buttonState) { + setState(() { + buttonState = buttonState; + }); + } + + super.didUpdateWidget(oldWidget); + } + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + final loadingWidget = widget.loadingWidget ?? + const SizedBox( + height: 16.0, + width: 16.0, + child: CircularProgressIndicator(), + ); + final completingWidget = widget.completingWidget ?? + Icon( + Icons.check, + color: theme.accentColor, + ); + final erroringWidget = widget.erroringWidget ?? + Icon( + Icons.error, + color: theme.errorColor, + ); + + return widget.builder( + context, + AnimatedSize( + // TODO: Expose these fields + duration: widget.duration, + vsync: this, + child: AnimatedSwitcher( + duration: widget.duration, + switchInCurve: buttonState.when( + idling: () => widget.idlingSwitchInCurve, + loading: () => widget.loadingSwitchInCurve, + completing: () => widget.completingSwitchInCurve, + erroring: () => widget.erroringSwitchInCurve, + ), + switchOutCurve: buttonState.when( + idling: () => widget.idlingSwitchOutCurve, + loading: () => widget.loadingSwitchOutCurve, + completing: () => widget.completingSwitchOutCurve, + erroring: () => widget.erroringSwitchOutCurve, + ), + transitionBuilder: buttonState.when( + idling: () => widget.idlingTransitionBuilder, + loading: () => widget.loadingTransitionBuilder, + completing: () => widget.completingTransitionBuilder, + erroring: () => widget.erroringTransitionBuilder, + ), + child: buttonState.when( + idling: () => widget.child, + loading: () => loadingWidget, + completing: () => completingWidget, + erroring: () => erroringWidget, + ), + ), + ), + widget.disabled + ? null + : buttonState.maybeWhen( + idling: () => () async { + // FIXME: I might not want to set buttonState if we're being + // driven by widget.buttonState... + setState(() { + buttonState = ButtonState.loading(); + }); + + try { + await widget.onPressed(); + + timer?.cancel(); + + if (mounted) { + setState(() { + buttonState = ButtonState.completing(); + }); + + timer = Timer( + widget.completingIdleTime, + () { + timer?.cancel(); + + if (mounted) { + setState(() { + buttonState = ButtonState.idling(); + }); + } + }, + ); + } + } catch (error) { + timer?.cancel(); + + if (mounted) { + setState(() { + buttonState = ButtonState.erroring(); + }); + + timer = Timer( + widget.erroringIdleTime, + () { + timer?.cancel(); + + if (mounted) { + setState(() { + buttonState = ButtonState.idling(); + }); + } + }, + ); + } + + rethrow; + } + }, + orElse: () => null, + ), + buttonState, + ); + } +} diff --git a/lib/src/button_state/button_state.dart b/lib/src/button_state/button_state.dart index bbcfe5d..7921989 100644 --- a/lib/src/button_state/button_state.dart +++ b/lib/src/button_state/button_state.dart @@ -10,9 +10,10 @@ part 'button_state.freezed.dart'; /// /// ```dart /// final buttonColor = buttonState.when( -/// normal: () => Colors.pink, -/// loading: () => Colors.red, +/// idling: () => Colors.pink, +/// loading: () => Colors.blue, /// completing: () => Colors.green, +/// erroring: () => Colors.red, /// ); /// ``` /// {@end-tool} @@ -24,7 +25,7 @@ part 'button_state.freezed.dart'; /// /// ```dart /// final buttonColor = buttonState.maybeWhen( -/// normal: () => Colors.pink, +/// idling: () => Colors.pink, /// orElse: () => Colors.red, /// ); /// ``` diff --git a/pubspec.yaml b/pubspec.yaml index 88a945c..9a7e1ec 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_builder description: A builder to wrap around buttons that handles loading and disabled state -version: 1.0.0-nullsafety.0 +version: 2.0.0-dev.1 homepage: https://github.com/Nolence/async_button_builder environment: diff --git a/screenshots/ezgif-1-492fa074abc6.gif b/screenshots/ezgif-1-492fa074abc6.gif new file mode 100644 index 0000000000000000000000000000000000000000..6ebb2cd6ac4603040ed01b38ada6b3ede451bcc9 GIT binary patch literal 449650 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

SZGt1w0eemi^OirufN-3^$VTI?66roC70Jq|QG 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

eSy~gf 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�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
8>gmj7GszO)*qs<|7E7s_-O2!2;`rt`Ywolo)-U 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 z%0A1D1`(J*ZYO58w1 z-yn;JtypAO9M^og$H}6-_+9hzxd@(j?l~ zy+a@-e~gw&Rse&{eVH{9tj?d`YvFFG`Xoo11_B$K=A5T+T69{dQ(y{*=+86Coz`)7 zYWaspmY9{*KbQ~D&47oVZktA~EYf+&i zwxksE14xJp^8y208kW|BTti%Z3uMjt)8~< z%`J&u?-4>y?}zbEajyBQ=1h4NggqIt#VJ>5P6vCnyzDb~uW@EYd9QK^9IezL#D~O9 ztE9bUlWte;1Y{32MxLj)k9ikvS$jma@NRB7pD8^%An*_n&8VN!pPOFWNGR{tGpNZL z>0Wpz!f}RYR`+K1qQRodhwr_I6)5}2l?S(N2?H6kH&9MUj^hKIV7)j1Lg(F|B2-V za!1YnE>ZGdGB5m#%M1QV^TK}@tmdnr)SnIJgVYWar95uX+|<5yh!t0S{m)?a_~zf1 z7swCnsa<`3KLdE*iAwRC%Imkb1UQldrMta)`z(CU#3k+x2+seYL8;P(>C1)-r z(;|ezh03q#YVq_|MJibyM0%E#@qd;vRo}~FrQ;523ucu?X-FMB5N}QrQn8QL<2=X- zB(IK1+s9no_(X*%CSH;SD3G*t7P?QIsCYW_| z3cM@P37IoVbV$#c2}#(D3Lp+LLXoOrCRgR-R$Mh zLFjURMJL%oRraSS$vt(OB}}W)#y$&QZT8d_H5kwYkc|Ap<{Ufi#nOHPj5B|+ zU+j!?w79pfd>-f4(%A_=WC;0P_=}-gJyjlj>?BA2sxDOXQCp(M`A)tumSfoCW#{6$3N-lxdS?0$5hdbw`-8*w({k#R__t4X=0i za_b?EgIv}Voh~x+=IAzGy0Qz&5SXhLibz#%N=CGQwK@EX<=C-rorxY%j68QtK^hjj zrJgrt1qlx-Wj}v1u@M9D@LUInE9% z%sX4K-Tp@|Hl;!0ve>GD?o~<4{9N31AP**N)0N514X( zvODd77KbVGO%_Z@&7bOlw$3@g)Y#?-LeD~5D}j2Tm&t+};rV_*J<#4G5THIuUVjzv zQ6r>Uxx_?DsUOh@cDxU6WD>@4 zs6FFx#upvAmB$9TE&Cp!=uo?Q_8ZzZJzchh02T#r1T4+##*-TSxH9>JMTM9cMWx+fs}EF3BXi1h+lQp(W|wjFXH z2dj(bB=~8W80ua>W9CNc&eXYc;s*oL=+Vp6XRczG9l+fzB8)7Dm>e0Oo^zZl0?i27 z!pqKK94{6_IP0w(CagN;=u6iE#1!;0J`JytrE5}|Nb`|u;=r0D;z^+5k3 zdtlaRcacI}M~{pDMm7~*tVGf4^~l=DSu!YA8R_WtZrpf4iz`-J)a&yf-^ktRE>_>} zp!eO~-FOH>lmIJv{h>UYBo@PxGhChhkt&;c==c)tWBLOz7MqW_drEW^I|mZ{H}f%w zQeB+>;JvKP0x`o<{Y#yL>5ZF(GV!Gb_WJL##y5+UdPJc?NzZvm2cnWwM76%AC3JD1ed$1K`f2;9Du{F@MFn4@0 zn6Y~b%)3KoF{%pX>ZUTQ?lk|YY2eDv8*bq7r`SD>{Hvw`MOy?o+EqCuX*@g$l~Xwm z7FsbyOX`Z{oTM?pDWE8K)>dho`$v@QtHHsy3@^`cra_@IVZxyonC03vk<5dPN6^+s z&Px@WWW5RF=j?4Yy~mbGF<6kx{@(3i^xNU8@ZvlDFZDowd$=k*@cR&5?d#w2a%C^f zm+>!$>%ceEmXU?x>dR+EiapCl0lV)=$mbLTSup59X`Xt`4{-Tlo`^G zOi{JoPj`E14r*H6E@Bj{VsB@Af2H?~7=cx@`FWYpnK&^%2F}$2BA9vZX~gplKErHc z?V{{;4>8`Hz5cDb7G-Bh)n}m}{O#=i>q%l_SpFHtq8Q%LB~IZ2UgldwxjXSmgRQD> z)6H~Q)k1DtiJoB~a_f$v4yJn@UxAA>l?^b2N&repU7o!xTZ`Ij9R~?LB{I+ZJ;^&$h zQLlEY>)Gvc&kw$dDw7*`dtU;LjhCiWr@F*_U#Ha2LN(N85cD4B6O&)eUW-m%zU|d| z@^-dh%MWM6SH3P;S`6^=UA0btS<$$bU3pDKjh2iw$IcwyE7_|R*H~&lxAFcdv6Ve; z9o73VaO+j{&-%Rk{vq5i`O>UHWo2Bv@;6#e&&m*8xo=L!DSGm~<u5)wh z;&g+ZyxvMfjYpzHqe2&k0WK@pi1I6+RY|(-r0pe^?5SZ5hk+tsWa0NkAmRGkm)Zj^ zM?tPcp{f+F$QAp;+5IiGBQdf*M$O131+=p+`lv(1F{RK|8mfzMcZ^O8tnfzWVbHrt zLCg$J%cRKLwm~TC=rbnBk8hb|7QvuB zIe0hfKoTC^o{p$vMx`jBn^|Coh^QJ*WE~n33_|qDA`1u*z>arw6vsNkeWD5qiX1D#JFXiv)s)cKs}AG-iW-7Gf%V?djn@5@>Vj+N>KJ3===) z<}@qwE3}n{CH!=NngEeYG_2W7H*AzEEFG!l5i^H(7-L4wkq~Y6UO+ASBq7L@f}F)8 z`l*Q53(+kFPStl}j<#P5sPh}w@tf8OO&c*-qj^&>$kDciJ^u^T9jQj~@tYON~e z%=eVxR+$Sp1;QmD3F#D;;Z)3JP@xl)x=nn*Wf0nqG#iZ+H1WN2%z*n?ESkkhsM)u{ z;hdlzvgQJk#O<_@ik!tDX&b0{ED}=}_A%UjhJc_00WcbB0O~Ox?mkJ43nnx5$|6Z6 zxWH%u?h!<92@43%OvPp{kfJB$@29bXGL{ip_mSlpxC3*7x!+Og;tYApSyL=VpWTqD z-%-&ZP=(+9_=fw*4LZdjX;Ba4IPE?IC@bSu#z65sH!l$Pk?c2mId7M44uqsx!TUgn{v-qyk5qLu zgi}GBWatMf+ovi-MiqP-lMixZqq`wS`VmxW<{~-w{ZJmd6Z+*H%7?&^Uxi3Zdbo#2 z8ag5u=~cxJ;=1kB!~4t2 z)^l4`D!8x}!ZfyNHx@o6)fp@@kw+Jff55a3Dzh#d^k?A2G7R#79bp<0zQu{kx@;uS zh6VZw2iyYmuu-BkyqWan`x813_y(43mIm)gg7?u7^HgMD7jc6cwdQCm=@5Fa(m|wmkg9Y6L8=OhinQFg_qk{9d(W9ObG|an@F`)| zyZ-Og0VxS(}=XtryU~y2=QfK-Z`&EY`6?;bb0P3>X*HKb6S~- zRowwGajggR-V!)oL8)8m8>ZJH-2&X1F~>XAC%N^v*ulXo7905)+O4u*>yTr{wVMza zWoN@JE7`qg4Jxg#7Y{-G_LjR0V9HgLn~(nfexucbA@{z%xm**&jO6z^+JzO=9?m`e z|MOmz0t5n?frTOe>w4|~oCEsr2f)m!|7UhJp3JT$2HhNzMh{_lbQo~|ja>zbgEUny z2N?!{dpl77*wtZ7gaz+Eb~WXSQ+}D^r<)AQZUg_ZUQ1?Ia}9D6xuG94RWuy}uO18A zaxfu)iv&NJhU=*{cf%~0k(HWxeH-tIPuVDx0V$m+WHbZSs5kL_oN`)SmY&?k)T-Z+dGL1l{JyU9D7fDp(`(nKtW$=vf)M7 z)L@{>GlBvd%JIN^B22w{SWJ^uIu07Tmm@*RyfxN3OPeiaBI-?LG#ReUCn3#KCpITc zz|#)u7%?pi6Yi+r2-v)&^%U!#fzvl{lXQ|#L%p(vXYhQ0|| zVN}+_IWewUS;B>uQoeplI2gEC(=>lm(KqVw?v2^~2VquS)t?bE7exR`#Go-jEJJlN z{360)=?+GeH%<+sXU=7%e_OCx9d-2<+p?zQaf399zMw;;+Vc>1GHN~u_9_Go zK{f`mA|HY*fg4~W7s90)`w2J`)WIG{0UKZcrYukXXGoK8(bMfDA9W#)UWHwM5+k)j zXxXdl1t@97CG-i6GCJP?8Omk{7$f9Y(@s+3=WnNlOI)hVCCHExTY)NG29&at2(~Z# z7B(@Iobz(I`;6YG@-MQJVn|f)WS%xXl)|;0pB-K1?|E&-f3T?pN!L6@NIPu+gDC6-HOGqG9X_zjyzl*)Oo~!;Jq|S^~n2;8R@pZq(CmWod3@Z?UsTWIw^gM+@G1( zZZ0~6sJ)kZ@R)lmHJ(bDiu`yQ35Uy_CZf-z`#{j~Oyn$>{d8~~R^hC`LNP81mjY*A zIm~?%aiJIzB<0K!6|#S9{cct=#Ga%*8kR^>S{_v_?~*n0x%(WOsvZ+BVMyQb4#FE*jNBb`T4^eV}{ zfXa3IhR8RD09fGUE$TYT3pDu%ed9v5^kz-M`JKyymSurKpHnymiSWUL7%&<7d~sf) zhjh!kWs_hAeHL`j`!21WJAt81Qaa@zeaoJyc6PvD-Mw=>^g;+wwQ8OKi?iIxR-Ai1 z>iHUXR8k7A?Z9%AfK|s2(i_!1CZj$;h;+PGwzBgA`jpt=;h+>qgOfl8raYo%(!uKf z=23othTNnYRJo6y993sx;!+W`RwjZV@A?=O{W+`9`PB3$an-Qdf?)?#mrjsxZhR|t z;63l!ho66oSQfCubf+S%aExjrEH&im^o~xni*{knqevl!an99a+G;1SL=7QrJ2Oi< zUa6!QU|k|QsEP6dR4H86IXBi_RfWBX8&5kXBA3VLjx~+KKf3G{0~qJOq7n)PpGq>i zn)g6;1Vi~5fHl5uae;TB9yU;CXMB>bK{5l650bUWD66ZPy2ee#ay1HN^+Bi>r`fjX z14uGJNH_FY)B>Q~VFEmzE#iLz$|2lQfs6LxoNW}Q)LnzFHJb^!<<1riKy)zKl!erA zWDP zLRA>*t<&_G#l}aWxEgPP&=)E|RgVL03JCo-uoVHcP#(UgOq!MS+%OxUM+960Q3l_q zS7NJ`H`CQOcqNs#9_tM+Opk=>AF$-1t!upeO*jaYFi_ z*+8Z29O%4tZ8S?eD!8c@6TMQNlqjRI?@LgU*QJp1tkcy?c%-?|0Sg4wYf<2j&a20i zpI?P-_!9Q7GOuqS0U6WR=iN-!_2ueG513+ZccseRHnbf8`v<&@PEEh}Y@s^D3|s@u zOdEV=xt{d?Y9;{}0R3X}7a9eP|6Z8-Iv6ZAfOxJd`i16h>)XXHmbF5VA8-ej$KM8a zA=q**;QD2BLE}o$S@*yWz3*}Cpl0sh-1rUGBf%<>3wcdf z29P^Elv`|&$$YI$XGVf;sB_S7b}B`3Iw{LN<@edPIncv9J?R9i;F z)PXu;F#1+UdZXkWJUBvyzI`}hfqs2IxJ4z@R2h0=x+N zJgoGg2B6yK0ng#=+XT)G0ikfrq^kUlXU|{_Muj2f?F_awInU?ay&j>j33pJ+) z2dyA3K^a&8!V!WE(bsOTfUyCA_ZWieLpb-ZanE-8>BUiAlL)zC;vrxHoE};}3S=s{ z%tqhLVM?VM51fbbc<2XtH&OzYf zgE$t+cxt0~W-knxUFDyMXCDLvEzlBPv|OpcWl}0|#Vek+hJ14>AvuQ@iA_|!o~V*a zJ0Fm!otmiIoTxvSX!ti#=Ru;HMIsWLWR#j@-kfBrm1L4iD>#wlIGA*&Bpl7%{xUv4L({9rQ=4TEV- zsp&1vKpRzh```4pB|z8p3@WaS*1`0_)b!y8>7&=v-&1AuSY%B6O`8$Q?AOZdEXi2- zoBmNNeQ7XriWHH7aX|g|faI-?;4G%~?o?tnba) z+jH5QS}2fr_Mu@qG&1`*m3SzTO=U!+NCVEbh=4GW^dS4I7r<N7z-O~!6cw>UJb6;2%KQ1j! zBFz=Y92XPF>}m^hgha_}?~;`N$*vxk5ZOv|WlQrdOWC_o{r5_4C3%_z<~l(krz?1TK?MH)58mS2WGB%7;4mRwaWU8Osz2H0ybay1NAHB3G=Ea^3Dtu-7A zH5bZs$#U@cagBZms#m+#K)P1&MCA}$Euy3R=eYJpNVOEZssPFA&9(JfnPH{+mN$xJ zCDJEv#2IRpPgI1h>NG`CHPY*l(kPwbI^;T?pPgwh*0+z)Ez2bK_O(~h{&MZF4%)u3GcKjK?=7@{ zJ89o%fA>S~-J#XH-#+h-bXs=P-^tXxJN2QLJb9-liP{qB5LH5*KkAS&YDexdOfPgu zqRXjhIvGT{R;)T%tXo+B^Y)r`Y|BX}w|p1(vrgU-483oca9fvXxf*n_OM;_YO1@j# zy8GM{C6m!DyJtmP)2$fQt#H~c%h97O-$P^6bKSQ`Gowe_x`(c&2e;UxeA;8E+hgq9 zt1sGX)&>}I^jf#|SZ4IviT2%&>M`HzHlgWrXzPC9-1kVnN8TEJEYbhWy8pRvzh_4O z(?!60vERSEpXQ)HNPZwtejtoyfZBZ^lH}X(+cprhI1tk|5XvzaDLn%ZDpyMp`q_z0TcUl631UBjcwd$Q5HD^ymlqQDKMC_oAcIQJBvJ;8PoB zes2T`j0td!N(GLcOOA;;j7dq3E$%UJ%l*IXs_uK*xPR>GQQP}-j&X`n0BkdUsyhzL z9RC$Hj$9fCEsax=<<-aIGzt??vb?G=P8~PF5IsQ}8NqT+aw|;o+D!8MP5%GqfHGq# zNb*yW+htcXr({Q~F11Z5o=xF6r^W&lv{^U( zW(?0dWHY|pVO&lMFATSIK&Vz=>yiSG10d=ui{|fgIr~z#~HAQbX!46z`pgvEOB1$G#Iul zz}Ap^S>SD}AHcmPYile9UPUPuc~b^bVq}0Z+7(VT-9m?l6jpkMzdbb*=#rpS{cyjF z;JRx61WC9j8s|I}FrSVE4gx-8CC$>R%@nPn8jew?D^_IdH#m2th@<~B6Z4yhnqx+p zWVSn}tzjHCIS%s18a5ZKT*&<4hl)-30o{kuk>tP5?@7;Rl@vA~ zeb|`!^sDA2BzeEj`0Z!^lGw_q2^V^50|0)p{d3lL-RRWhzxxIg`@gad*xnr=v0J#W z2OJlFaKEd{6W4wpM)%82Sf~ml^zMgv)ep(vWPBC%Q_AkAAnNDk?4Q?Nf6B%FlqdaE zjQy$b>F3q#AAGJ_8ke-+an67)aXtKIpcPwUexz^ovgDJ*5A#oKY3F53FZK1RN(h<1 z9B=%-WB2>s%im5_A2vG{^eX5=zfIw$=&bDCVKk$pYUp-X=$^X13mm|3uhEhzTUXM% z*p;V-*l;OH%HN;qf?eC?fCx$@*aGN58pusD=Lj75$J@1C9&24G^H0n@w!eNE_v#V_ z-3gJ-2lX~)g=S%&I_P%*qK3SrnVokQ46whVK@={-VeKq$`b zBwjI;&2-14)U?9ZRHB>fh99I6k)(;CvP~V-c&$`L>-dLs%8*38`SP!;?2Jxp- z8>68LqE{WB0==2R7Ni|WQp(s*m*uy9KCdM|hj+-;^dnT`>pcc}tsGtQSIMGDFA{&+ zmt}ME{F^%?;RtKki{mLaItKk1507PaLv?vna5zmpOK$ztpKV9#=eQ1OdB4+~aL@dE zE|}spR^g%>R-4;Hc>a3&)HkH8@|ayYrw*q$EWVKD7 z3!{Ja+|3Pp&XLCry@nnkA(;0ee#0(mw9%y$otrPfkw)2Yl{l;>*z*BrZ zZ0sRp)9*CbKGx!?`|qNEWCphwVc7#KuOrw!KHhD#dGRUqnyuGnL8GnDswpTv{1Dn` zC$S(@#}U}~7slhxAS2@t!hEaAA?)IF8ArUp>n6v@OARugL+E}t-j*!-C37cEgTMJs zf`R(~1-qJjuZ7I6hRHrGDJpCsJuIstv#S-2U&!q0JD8kvO+SCD^PBhTa*yjj-fMl_ z_$f@zrFpZ^XIy2c@1#-n#}}W*wm7?N50KK71pk>@F4o9>nNy}N^1A0IJs>KVU) zEB*(&`oZp%#sxm#{lLv1>q2`9T6Vu*`K?c9e;RcA7S*}jsQNaV{?Ex#N&9E-uu!iH zn>u~>=e3tX1t$^*7IqZ=xYq!wbJ`4d?QEkTLyF|?D4o7^qknkd7ifzef?3z3HCZ-E zd%=6m>Ly2iK`;OMMcjs(D=F~kz+PMVhyjT)yurFiRFgeYI!htQ@zt$7-%3`-mlHy- zg|HsE{TI6m#mI7fa|==HSw>n}y4AWG-W^@pq*_DeM zIk+J!X{0}@Y%((qM?FVGna>2kI5t?w*NZ1&JbFHJ{z}nM{5BEm2U))eWz|$3b9X=@ zaxk6iyjGpBZwcFJ&8FfqH(L+AE6RqD&NyO+bs z`&eB<2D2o<>`JhJ?qxOO^i>v<^YF;!oNPPaSwR&BNm8z)C(lAwfb4#XI(Bd!9gRw7(=tpLB**lg_)V>a=DWOfr={0JK>(oyI~22191@b zmNX~ECTq+?&C2BQ&ocSJVi?gt+~sZ-R$yIqdPst)4 z^sF4(!k)57(16>0Qb$E# zTN8xfG@v|fgy%VI91v4Xyw7(Nz=bgy=_7cJ12dY`ajcq^pxX~qFv%!l^ zQDL6r?$(DPxWZA%vkL3r%dU^PCfVoXfXuyF_cqvjiWq-7hH9{=ovd4;k|_U>$uc(w z)20&2*ZAN`;7kMG+w_nduo=wu z?6-WWg0?_0Uz|9@uRm&)-=`E*Db9rtePJ!?DMDwTjWvI>8D+nIlIUPp6}4g1Bde zE1kFq@=d$ygF7kfU{I1!jOd{5>A*$c&OUdX4&ZQ-xMYeF;8fs;6~trN1gHl1kZiIzVq=407iZksX9NNrd|l zYj`0!fjH(r@$^rXnB4(Ic%AadzO-0Ay|ZQ$8+A96H+Hlvfz-my@kOT_p~dj+GQC)B zr3?eRL{E3YM7M%2+n=8*G3ji*)T;QcZe`Il71f>`p-#1DJsKfBnu$GH`90coJvu!- zy3;*+>pl91JqD28O^0$r-rk$iy~e7&CMLb6cY1F<>op7MHBaodkf#2cqn75LX_b*` zJ>6@|5UGC3Wt+jS=cr^S&1z3WgOu)zN2gc}UX``(Q;HClZ@m$Iv&SieUM#))QBU9H z)V`J-vC!kBC$nuX84T_zeIe#D{3qEKf_1@~B2O0?&e-t56BqW@@Ew%3p$Yve6pe%y z4%ZbXeU@vUTT-8QG`^W5?i?aoZbnT())g8|K48g0%jJ~IE zF-giS`r`bxaAmYaDF;K8ZkAgezJeF=Bq02mNyJSwUa;wM5rfvu?!e2GB<12ujMgoB zWkWHzjzt}%%!`+tslJHRy%7%Y8O-$(g!8NBtFpqQk(^6MNsg@Aiy=B^PVelLi*;3s!={L; z6g}qCoII`cxEx8JCiocxp7{-)d00|@yH_=*E{DAh|!4yEAHkD1r49@S>#RR6}AhZZ0A42_c|y81A+rnZVGQuMtQ=Y zRoDFNWMrsdgF}VkvTfFOCSgun2F`;CWt;=_MFm|(7;dbS@fz<@w+ zMZ*C+eBT&n8US|+fMHDnoj`#&5EKVe#hg;`N@zzfzRvSQ@K;MV~YMQ~cGI*pX z;s)n*piG#iP%Uz3Li-BUdAErH-<0Y`Gz@DDC4z1tVCaEqNj_s~(*VkSQ#cMJsb^wq z3X(X2wp52d_YB9H&cu7(48a9ZcEngL1=!)>mQ9opPY@h*3o>g8lL>HA2(Vy8z;GZ4 zkx~y4{$d~Q={9BZ_*T3GRM8V;`^(gBBiemw23UbUn}yx?46qh6BX>$pUrk-Fn5ol# zpza8{Jq~}F68@qi;RWXe$&-<40HA;cn101hK@ov=voNLoa8pn)wYiDmSJMZa2wzTw zD|8wF1v|}#J@+uaX4B44KO1X4ZF3g=RKd)}CV;*e`V0h8nhm=R1iF}l;7w*pk1f>{ z%wV1%NC(8`DBK?x{-U~uWz>TAuZ5%n1tAFpItqS?ozqnSN#30!zci>4GZ7mPcE^SL z;BHoawd6do$QCn(AI&}{1k_xyyjvWgYh#iWddtQmz|13n+6j8U1MW>Uzw~w?&Tz`y z#>C~!{29wajo8AQnVB{|B^pmj7P+Jc1l+0F`P3$nU<@@j&YZm0R9C&8o&u0lLwq0O^ z+&2uPZUS8n{bZwHW_M=$lon#yG(VvCDH@nb1dLs6<}&f0UI`leXWE|C+n$du>)xG5 zirf1w&A`Wl)C|M@-KG$a?PJ|+63nLqJp-63sUG;PhM0q(#h{$gm9qj{kW5G()c(QJ zt>cZQ@tLKRnMu5<4UnY4dLaT1Fq&W8Aq z13o>6yC0}ZqSw;gJ`*%EC_#ZXSW8+K*h_QR!dd78i9k9D3VH-ZD8Kaz?HBTgPQ^5U zq&6Ftns-05*g6Q9!bwCheVHSyEZEG33E*Hai(wu|!SjzPUz$Tg=>n6#+>-dR9DBhO zTD-+IT==RoLgvEM;{w{(vmboEAlf%t?;M5S3JCVug6@h1J|sdV5rMRXhw!G=kXh5K zObF=?DtE2hnadF_8&1&b5RD5|0(}S#76g(AYCj2gND0CoLGP~w&2NM}UZHg9-Gzca zao@6aS(c#~Yaeb{Y$NIhv!4YK zzb+SDS+tAZ5-Q}ndv7u}yK8Q{=MA0eKXOYlt={91v;l^81Ug1NYXIO5d?J_ z*wCv6|7`ylH4c_0z^nWv0yQa%SEe4M*c0tRlOTw$-?m*-xb=CcPQU}3Uc}SPFO#;b zKTE=gQ!R5`BK|5Om{E~e16^;}K<**JjRS&1VjdP=c@%=1QdbAa6+4mipo(tWCHE|&5iU?-xVOxcLW-$kt@~NyA*5x_Em1t8ddp(QrBM-|@zcCtrPMjP}UgG)Rr%5)ZZDay3F79l6 zkuKY2FwbW7?8nqLu=#)Idui}OF6U2>hUcC;Ozc;7 zjMH)ZGLSD7Xiok%@uj??8l`#KYj>L3!VPge9SlGH-Gd+QKOOma3SBB0BMAqo7{UHaq_brK z|J7^fE1P~%`+i;hXWilFTgm6!Mdv$>=ezyqdmqogZk~VpbN(Gp+Gi#m2#|hUBmLAM z9h#AT-6#EiLHZL;I!Y$}Eg~H^l1}M4k4rT_H$jDd(+yt{yx_ z;AXkg0e4>%+qEZqTL(M?1a6IZ(FZ?xhZ2R&YMr-#@QtKM-JdLf@RNTmL-xgwz3ra@ z<3#0fjM&3N!O48>WU0qHhug~jhDA3k9{v*kP;S}y&H`e|~)3{c~xhBM44Ur&T4fM(T-tHD&$Z;dD3cqRV$SbAr=)a;GR*A~9*kG1y`lC)2*ep_sL@xAXw%C-HKu5kKG zE~hd-)`yZWyM8;pez-MRWL)KPCi{DDzVYezZ)b8x`)mCPmt4=~j}Lb~zH$A2u5fzv zV{@v?m85undi>|-_wS?|0Tf6XY#@})6B|S&+=LCLl|90SptWUkUhErsa+&1hZ8a%eFHuAnhMZ->uNY&fpW0C4k zq?~9?FPo2O?Vxb0=$ld56VbW}Z8@>}8A~6rhPj8WVvS4QCt^*jNS3mujc;0I&CMHW z;;m1)=f&F&hUBVV?(e@5fBV-zqN+VJZsAe~1+~0HCzRb+qKitTO`@Cj#+@8vAbEOL zUJA*3&`oD?I@xE{JoH_K)4=3FljXff3|R29N6ZlWVZCnrbrCuF%iNLJCzoyTx&@cj z<$czlTK@NC(f`|CI`;qEOG}Y^={PB9f%F7Ej!&II^uP7e5>p0H{`xHGL75{qa z)_A-H_rG3R^YA`zZlZ5P=4=o)y59329Ny@vR;K!?eMT@OjKBqUJ+c{**^9l1S7(3ZB4g&T7%ArFd_hlEU?Z^T#_@PgxBb0PMgPPsh4GyMer2cK<;)*7cLsTR zsO2+RE5N*(`ji(_693rVpp=t)A?(xg6f5H&eAu}Zj$;J-wUPKe=l(p|^%W2zN()J- zZu5)}XMdW&$FjtUCAW=`HJa~arzqQFr{)>~LzyN`0iwG4ob|aJm!wMYmew@_6@z1) zNm!nq`H~Ixidm=ULaD-imVt(uiiuN+rEk+w4Fhre>?mGb$E8NGRg8Ns zCk4%mMj9RvLe*S&l@g+&3AeSb;2_+dhRVI*C`PKjd@z4hN`VRu64IOUAgKgr-`aof-=u?75?=KsN8b5R+pVTT200(=pUY0PH}-!Ib%B(Jx=$ zD=pEu5@61p;U?TspswmyV?iV0T)I=57T8n>&gmja2y1W@ch1si+FQiYBg+SZ=yPkd zU#E5Pn-?fq&ljs+0NaSS|bNa|U6E8<>;qe107nqU+F@^{s)r9iRmyqT*Z&G&>s zOg;Ha#93TcSE_0kf5>7vZtb45hVBz_)&7R{=e!~GkZbGRz(BV!g1Lr0UIGv^13{i$&*~4{)0t9Fy5} z26m?u9{ar!d3W-=(vke3tg>W);Tnx3HJMMXt6w>uqzbe}Pr)Y)H)yXA^v;gfcSBid z#mDXaY_vBkaPTOa=`8i=*RG_qf>5OR`RSkRf~B5d3gQ~G9Eo*5;KQo53j;_h2vAc% zL=hoBlYkP*he0eO_P3p}00^TR@Z=_?PfSrKCXFC0&C&(XTqf`eirpQNCBxxIiMJ~Z zu@vP<+7|=e>2B4*9wLZk5(BQ|0^0#zDrX^^0T7Ij10oEga<$d5MJ(C}k>>J)<<12l z#Jz)8_W5=!{hEDIbyZPLx_N9L2l`%(lt#OW@)T=Nsy^yHh?%^da4!2pRsQ%OlJ6uB zJJZ+2H&hiHtjh~#K2o~QC`pKnT0cxgh+9Y+J*QiRtElg*YkAk2zmlRzE*C`WG3Cb$ zpX3XR-F-XO?8;+nT_C!URC}cKgbPvnN%V!6fO^Y5w$U2#$5U&B(<@T%Yl1O6jghQs z^yp`Z7D@}{OJdjdgP9ZUrT{AR^}7^gQhPJ{$&{jvwyJmnHiybhVC=bUxMP3Ia5^S8 zOSfl|Yu_kAiMuzLE%VuEaifpYJB z?8vJLt%xUrSF=pc5D*@dBCZ=wkJLMIgOm&SV8S>Ge#m6(k`NAhJw3vW=BPU`UYg5) zgQ+EtsK38A$|q|B@`m&VG&x4vmV!G<5X?vIn zas!Va#emVAN*^rg1wMLVSJg&b1{)pog`y*o#alR>nVEsUH`ksso>rgYo?fMcL+m*G zMn`#oG8GS>ivIwcQ%-eY6qqZllIjMgB7o5z`Ti_eX;S@e%NzXx>JglvL<I!0iEwy zOG7b2adXaYK`%Vrf^B3z&m2ppTvqQ~PZG+9UmbW@Ee@s$N}O+_YF24ulyEI!2xk2X z3=r;j%$zhwdY!&320#K z5geoKfp-`O-*)BTRV5s#I{Kk#f(D=h%xex`7Y{;dUSJ_+c%efhOy}8KEadi&1;&-1 z)$dfE9Eah*^j3fzH4N<_Lfe5j;a9kog|4W zib+7#NzG5X5@%07u6S|fc(_A6YfwBiC;o~g zO8jrU1XThJIzjqx{AG&-anb|S@0Iv#5ef3m!1d+?#kmB`#wUy(j>QmqPgU- zIiNlwEl()DLMW|fJ6(?|BWW=G-GlT3s`O5+j6tom%#2?<3GNe}RwN z=(&jWsZ{iWSAy_CrZ$NRv&NdVI+qC;Wj%|?njOrV-_Bap%G#&OVz$Ws?Uj8*){0Y^ z!>hB;|7L^Oh+tVF#F7Z}CL+>^$QB~aJTWW?HS&dMoFtF&HfONRdG#@yr6q@BK8G_B z#kP|pnuOrC%;neS67|XzZpnR<6DN9{E5Vj0C7UO}kRvUt!|a_W+mdJOkS8y!^=&^- zSvFs_G>q3WKg$I5Dp2!wGvn(Rhqn>F+-YrGG^F?H{B7m(ph)s!YJ1;m* zDa^Z=emysms#Eu=(@d|^ZmrW@s8dUSqtDJr$6kMRqRM2L z;f7EBCCN9I?DXVhS|YCAz7=Ck?xlSi5QimBt@Mtq4ZIHZF6@m@oHP;Go9*)x60MqLw}IE`&B?<++M{OL ziRRRkW@2kIQnDpUq=opZxlqnNL$0OtQA_bcbJcE3g-$DVO-sI2OSMmH6MJi#Tx*F{ zYwd1p_i$^cNLzndYsqj6qdRKsua{nE1=g(E zCw<<2NpIguZ~sEwzGw9>nO-F)(+h8Rt=`T1y!&j0-Wz{+e)8^Y;T}Il2W0V`og5mf z+aVa&0TS)t?d%}!cA#iFLC-rdN}VuY3=54tTT~~82E$GUKXf~}PtjbW%@396J`=k{ z+q#eeMnV%^Qm0+QT-_pjT@q24bpjyQhPhhag&gk|SnZNh>Nz~<7Uk-ZI_Q?!WB3U| zk?ZK2G`)#l8A!=qa~hOsMw(x0uW?&%Yjd)#Xs`WZhNFC+iFMx_szj%ZzK7Ns@QFUl z(>^zj)F-@xHIhM8_ zB*)Sz8G~swH<_%%HChH~(YeGnAX|Q@usj#)IaI0}25KFuMe6t||kSk+b1wgL|*d=sdaHnjOqP@2@^2+R^a}o@UejvIsbB=p~ zbaQ#pq3I4hV#|T+f##3^4A}{5cJStZ6~D4d8T~nT<0C585ZElFlp7D?2)xZPN~upi zC}4V{TLJX1&|Lg_=Zyle<#w+Cj`{r>;NYNR_HzOUqB=$l1K!@;&j8ZypazFfhZ6R` ztDTV@1z$l)h!5y}02NzG_s7ld7m3iS%$|Wd!wg0Pp)aO5PQ0==Xr+D3{a|>|a!loC*R1OW&_ue#GbURl|5g#OEZR?gb zba8CO?|#b4s$-`c^3Bp@6GClO=T}sMD$aLmzwI>1?pEvXHe~JoBJMVdd(ubS$QqZc7{$*PFA>J)70fwcX+I`6@g=IhDV~o))-h z`|XSWx2>#iJMG{0T+loAGc6f(6N*DINpzVpb%xc((&Sj!jn1{AK8sNXOb(FU=zcEO z1y>`G_7FKxkSN*`;_zM7$^(IhkAd!mfX2lr4v-z+VXkj*M0+|{z`_u2E(WNtJQq{i z$9#GdPo#0YZ=6HA#^t=fcg3CVPi1Xe2jz{UnQJ*B7hdj5QvYlNp>LjH>^pz3F1?Ys zh`tj|e}VM<%J2s|_ruFMbk|*Lxx|2L{eX%BT5lX8xWdTZc>s3!{#NVF#Qwv)7l3;; zEeVH6d<$qVqP5=9A+d+?(?kA(epg=tk+f)PF%N9#cO>Y$vJcH#4!}4{zhnQ);{^Zz zQ1{kfQTXe^_At~iFvF;HD4=vmcMOemgM=d8f^<4`hjcr1NK1#(C7nZeDJaq)$UA=b z+0Q=DS?8R0pR?Zgi9Y~-V9l`Zb>G+Lx}G1M@!jLWl29pq5%%qZ&?OcaF8JjmDYI;nAK`8&Cf8SW&H;vUuIEZ+cWslYq)Im`Y7 z@1glsb#ap4xw-t?lFouI`2?IVURKra{2MQg4S6V&roJu}3ZWJcCezrE zi6s8ROaI&uccb_lFFg=(qmUz$uDPw4!fxDP)ToNllFH|>(o+g}@h`meDV<=hY|O(D ztK&V*B9(0Mn1Op}UYcfKr#Itlqtyd^J~2t5d+;}2I#c)1puu7Jcb34|T6Ck^;mQm; z^7i7B-|cT=Z{j19BxAfsa&0L&D?Kq>?#sLS$L3|x%r6~LIz@rx+?;Q5s1114J;3G- z1{&t418=DHf=F%*&buE;+*z*n8LQiTA3Vp(*rYbPJeqShCZy61Ym#w0OpypvovrS$ z1G~%W=^FoLW4u&wTnw_D0&__SjXoxSVhd z+$Ys=OhOq>No-O!^?*|X?{RTF#?uID_l5@wRL&F>@&QnZQ%)I}JW-9zeKlS#St32{ z8d;K;q9xK`tAdGQ7u%k{c#NE%hT6S%RS)Y)6vnh;2X*|2sx|PGb^mu zHGJL6rxzzk&XB!K!y=8Lc~sWNognD7i7o3&?=l-c%4J!_B*^vSNpsrr$=ohSPlMrW zHSTjm=YGCZgEwOiEFA7x?V5(7%h(m9Xd&YL9H$9(@V!q76O&84+j#=QYd4dOCcamJ z{cCKy&G+t$hzg+rDT!9+@&cl!nvHPAthD0T7|pb&j?^uULkZuO24BW&f49krFn%~+ z)pXx-o+ed##gjXWtE{;=N#ZyDBhL*}rplb+;8a!Q&ug#UMk5Aq+I$x@FFny)*0)fU z|8d8=prrK=FI|&o^{r;Ch{>jIE_T4a;cvXO`@U_<54k<_wu>E~*R6ke=}uh6Hm7bv zc~R$HQmZ!S{zqY=Zw48Q+unS6+V5Km;n{6FVb4An)oYiw;?GWnGcK#`YQ82~OH@>l z4484tqo$vJUUhsP?b_e&v06`cdm%^CG#qmaN44B@EVHM> zS{EP->AI&`9sE=VUyK(dO)(4e*s#ul(9gX8y*C~vajGOdnaf2(G7&B>V|qWiNrnL| zqpcEbN>nH)%c46Gsn=slQr{%Y;XV=d63dLNS5S^SWg^;2#*AX7Nshl^BIb3l8P&F+ zyzuNq?B(P%b^ED|m}A5rURv4+)gV}pHDP&Ra31?GGZh&9exRA=2*7gQ4MnxD}& zo4>Z*lqoiDNLK|{Bxc{wSQqi)RrZ>FU_Vt?>{oez*jM-6`+{G)1(O14r_E^O8?=}A zTkdn<9wyh(5v~}f8?lGGBMWsR=fZa{c%;7aRi` z9xnE~^O?`3^h3�TEl!pm}U(_t{tHIY$Go4^ppdND8pnyB1%>H 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

xlqMC6|7GMl{g zPlNfVD}Oi5`7|*bi>V}q1dHiwx{VeyH-}5oK;JBEEa#%S+$}@C@)(v2xfkRAI9|Mr z+TjmfK9@HCBel`$pTbj5C0;zaYQjj7Yf{_u^^Lh@`WMKuJ9(+@G^7IbPM4A{=+J#H zXBG71j$3`#H|90aKb3b5`gEOmw;A&Bz#J3t@C14uhoGLbvJ$NJTK`>syV`5>E@983wf{DK3!N>+mv;)Y%f{uM{Vu@|hI0Y?-SW^5|Mj5m)JZRf^4qDu#h; zR^9QONoWpw5Jt7%QHjM=Rs|q@aV=6qBp}{{YEHd%9q->HYA+}PVScsbTx$^xF`>&P zCAAut8it?LQ&X5JYc+p*Chcs@jM7v@oAvaq^b<$iWp5Qw4ck>^*zL?crDe|2-_x*j zShz`K-*t@JcVcFxx~9S74wtiM@8m71<7~A%$+ypDlp=3w!f9fGd%^M(vMH956!x}5 z|6%GH8-|b~q@ALG<=^944HAIeL0cf%7QHb2RMFIsUGDe0{Y#CDKXxCtyOaICzSN}R zv1`;3;|Js8rRH}pxlm+{v-%@K&6(GY~He#grn19#-D9{T_u9NsIO>#{OcRz5dmVhjZ9AtG_9O6}OKm25gplKSy{y4<4)tlB)3Su=1)d-M;(e z==pzqyVkv4_If@&6QCRLO<1*c+woz@)IteAF1FGNlE zW5?l|>dXecFyo4k9j9g$wKhIk_BW-CN!7f3^H%A&EhlZTy5`l>EBaB#bjLpS*VNQB zEJqQmN4eQGudBHaPcwAKr*^!qZMEKg*7VNktkLT?MfCD>#kv#P4rl6y8g^fy-k4ZE zd(pVu-Toq1cd`R8{CLLNAkLSbPAYlb@YPz>cI5BmpZ?d4zZy6xZ%*6&O{Z6*QRa)vIsJ2Qx&lRxdksDwGQ9JqJIuy7`$Oft>5Df#rxJ{F zX7m;;KfLL^&}f|ZqjJIe$D8*F!fNuKTPOjlmN#+tS=!Dgiw?$heQ60MC2IPg_qo^g zXQn+bG=B2g_1t=i*k_Zn^tYeLcj^X8ZO%`Z-}vJBqHgeMf@$S3{eOHv)D6`%n*NpF zhY6Ue8&>%>^6XgkIQUR?Kq-0AKg6tsKu*f6#>U z*fw<<@(w_$DCG5rIn``8rC%z0%f-8y)t)%J$A7;caI~hTZUxAVy%?g*NP^jP-x5Dt zhEkbs7peR6WXI3rZ>PF^+bN_XtK${l#w4FvAny5nmFnNA^0~GZA2xN}Po1H-!Hzu; zdvV##+i`9oHraqObv;mzp}0mi+c*C_n9h!tyDlq&=xVy=xMn4r}ZfT5#?=96U)hJ z(f3$M!AS8#Gikq^3@gfjn6QMrpX~mmN_Ce z{$MRUP(6gZcft?hJ2n9v=Wa4SYqL+oIku1eb~iC}UBQ_4QW%C+LgKD1VzdBXE0g#nq!U>EnZ%nhIsAxe}UFuO6e1 zC-LE$DBBnY*1k!9gz<&Vv!yVwc$z_kf|)wWti5HBNa{GLYRlvrA-Q;UhDH1?6AVMC zo@gM;{pj$(T$W*gWEjShTK*{LW^yf>r|}3?3qY}92$+4Qd07^`a|CFz!FYE~+BO5M zUII`lN9(Sq_fGg5>5;71Tx0&U1cqVg0Y0{(Xp5gvvs5t**#_HqfDPfr7R`mhMBzja zWav*aJk|Wj5NNhR`nAb0pwP7R{4ANhJC8L#$x;j~;*X;YhW z4W}EjI114;kO#*!an2``s3x2LV&9l;EJvc2V+;5CmczA0awRsJEX&e9S(6+~7)k^X z(FH4wV=KhdbP2tVCUm9t0+1e9YX<|Au?>{TAZqv*SLbr|oi(K6X;>t;!!6ipKz09j zFfWPTpiLF%Go&OEE#P))-5>PpiIR#<3uovS7_J}Uk(`O0X#vZkmhRz5l-nR0*ee~} zYSKe8u+&nyXpo7XJzIigFi_~KiQ2Ql&{YI#rGmSTE9_DClEeWHOdVDwD-%N)*mxjr zm80)rCuw45-VHXarORaiwL?Oz1Yi?MkhBL~SICmv6L%4~%qE_U2Z(`C+38`YCP~-r z2B|C3upxIx?{hz0DxL6^u=U`2crjji+J#6r+trtWAZ2nms%|aaP*#apPfOJS2*GZ( z4P`yJooF=2GKOLhzfDsr4nOz*=4NT$-(V3vOfR0`*=&6t(>|r&E^J< z&If6J+WT37$eweg5bx;#W<}?1nP6=XJNGRO_0RmVl}9=}6YcJ32NBB@*tvWaT-YHLLk=Ih zd1bpvW{qBWYCfb+*Ni}yTLszeh@2{rCXRz@-3Fak?Ib%NRg=i)8h1yk zu@pHcDNaZd2O-`2Q}aaY?c%gd$Hj;a>1I=Esr6SSn~i{bPs6{xoZO!X`X0aS=eRc? z#J02PoW>LAB3ThmloEqgJA-ZzZi%*g=%nLIEooX_@NvlQ=i{d1kAg3JvRws9N7FBL z=s(Y$Dj$8o2Q5t{awHPzmL+;WeIK+=oFbN`8xlYb*)(jeo#|30QyNki_fUQkb@Drw z7*7O*HD7Lg^5ajWO5{Dv5xpmk%Y!Equ_f%MH|+t@i4ftajOx8e%TtQbP)SHM7holJ za}_9hwicfE)vDr+a2ne zQ&dqsx9pfoGV12s{k34q-_d;}x-AY=_uOmzEO6MY9C~QkR#rJxb2}ds7}6f6N>nFF zW;I!?_D+8px3n*v*I@%j{f;C&mNDXZCIXt{5vJ|DaiVMV)0;+uMi%Li za+X;+M~un|x@0H0p`#E^T5nnkADo`JkZ8F2%@OzFaNgH)RAHTH(PnkI-1W?L!K5CJ zV428~i4BX;W*b}R=)I3PF}*|MM^N(xlA1lxaAPiV1+1sIP1DKYj#&kzU&HVE?aIEX zqaO39?laafKJO`NUIzXQwM8O)IwPS#GFbeADW~tMA(ffg$*FT~d0@>kpp5YQ)~P8C zrz7*G9ACbO&@NvVkjx?kdLv6*SKWrE`Ih(CyHG&}8C1~A$q0$hrjhqtb=ihmU;ux& z9y`K7k*GoaVwS9EG5bwI7qBygWb)~-=?1Xm$RwFdM+J`QvjU)}^kqT*Yk94nd0M!v zoElHACW^aq7NU(~zb{WW_aF_-8Bdig#_QM-%9l?&0`;n%?7G^dH+#n*N?UqE$7YoS z(*nCp1m2u_i?BFGY&}E%X<|f-qcg$pM556n#*icJ^!tap z@j!Lnr`0QkNaZHH9>Y)_Y#6VEEZ3qMH7OuTrg~g`Ns!D24LS7Tk{#VJhC$h73Swj$5YYBKlUO(WQYmGiwJ*P%#sYzz9p&k|7@SLlk z0gMT()JdJ5i(_cT=V9TX#R%UBeT?`vNu+a4QguI&bLgo`*tNvj`B-kEuE5S;akTM6(@ zJExHeHl*6^BG4a9f^v!%E!OB-I6IA!3%`2`Eioh&Y0&qM?b$(~jg9xW$t_jD1$^Wmg?dke-dg3S0Yn;y*C2ma(p0xo^An=-v7=+rO{h{e5S<(e`fRz3t}kyUkCw zTjn&*%ELV3l@dQfJtb2)Utv|DQH#442xUA4mV^Bt#Y(5ldYE&rnJ|xZiVc- zqvclW@#c2ufqMo)J4(#>=x5qUQ(R+zCIFZ%Y%AvdW0)%UzD1W;hvyxj#Bo=y=!a zZsg##rFPmsHFvj9ct1PZl)OBDGs^cxNK2gc+abRrPov(~T@ia-=@&iSeWlqu`kCju zt3a6a-Yk6UrKNi9+M290$J)|Woig{{KO5S0&oDd;xqQSjLFBKrv~_mO@ehv-)7)84 zaxBlyQQ9)CA6z&&_WI1iP{V_ZrzfAb1#mCye#xFLyQSsbnDggDWAlo`J)7LP^ZyJ# z47eu? zAfOPsNVOo+JE#bu_g+GmsvwF4lqM>O0wR#j|9N(1cV}nLIq%QAyvih#nI!k`zOL`5 zW@Z2;HEBLbue3Kah{VAyh8PURXNQ<9j4g&)Zura&vpJ_)jBwnpnH}LeCeI^@-1qhl zN;5(rjC|Pp;&Y>nYIFVqS=6yf1(`ZQj7CZ2=*OdRwW`-9E-zk{zEq(+X90Y0@$d(~ zw8nh0aa6X0S7CYpqa`LYV0~^{C2s}BBTY6;Du_NIRhecr+@Q`48HxAE_FR41SWKBH z-Fo4E8oYoB-^b0*>H)tJuc_kbtqJ!|#yr@qMM*j=E+c<^${i`=pe zqj5uH|jzK@HX+tx}^Gt=h_%hABvZIcJ7w9sYWbDZC|>$1}gXFKaA(PH(&Uf@8Nb zld)&tJwJGwqw2ZDwd$e#5SnYdMP(8f*~St3z>t-zQr{Q&<8s1D2?`@hKVC>UnmZwN z$|e`ws^lt{_ZlU>64``u0tC6u$~K74*xGD2-z(9DCgfzPM|iNBsvp%U<$2tq?)PHM{Ep_sD#Zm9q=-BNO>_;E4!SihJIF^(2-l zYlYzppSF zl--tj2IlIX;lRbSBuI<+^Bk$rLh2bPTe?4ZCr-$*9CLx~b@$7|o{8iWC-J&O(s)|I zmum*E`r9AZZ@8I8JnmJ@dgBE|(EfVw9RAkbnTL24W(==zOFk4%7Y{!qDs9KE?^tPXC^pr5&m#90Y`vd5g6 z!;GqfWMXJ!8KhG~8^B!sWzW&i^bii&B>MB;o*b%JRH-48QVw7BJ>|#gMqZkzPwY9G zCsGI(c$^v)kc$YBP6f|Rm~roH)a+#onofT~lh3loXi0;#c$r!Huf);EC4eZ^LHNc$uwsZCjmTe@;KA?} z)mNm4+9KY?L3iIgI>EtZ*5J&I0aU`{`ydr|@HO*=K83(xIy$TMXZ7bGgf$RmN}!L~ z`3NQgtkbrjr6J|a^X~04QuhP2z!C-|&5)I9xT6V6Ys@e<pMZUMCf7kxv^VSQJ7|cU&sDBjGf_s*%V&ssQWKf@L76UihAs{?06hC!C@QM+!fYlw@xalBhG`bydLsjc7X zIMEAc`s!6sGr$X?@Uw$FrKeNIe`++{?SAF}1kGjdZ@R=7(WnCMvWsx1y^U10(@H;* zy><}C!~5{Vr`$8-(BrYGfR?5t%rlkPcsFy-&ZQShd^6L{Em(JNUwLfUZR&8P-+lC_4$tl5jLcgamOrY`D)4ca$XlKYJ!&jDXDqJu z`Y_uPnmQTi>+7GlawS#_*EXN|UD53$oUXOKxhzxuuKn`T_G;?`kbl`^r>Rz!LU&q_ ze-!c5g71=f^wLeA`)=C6&Ef-3(6fMe6&(^iFVi4#VP8|N3rqW4ahSv9;8CjuU(u|7 z^k_*&*pTpA?**+=F+MFYGw$o*^?BDdG5Y6E7-MeJzcCXy!*z#;M>jP4n-S8NF~@_VxQ;VvXZP; zQ(eJ#->`oxB%ZMLw*}-McU%8`Iw%b5{#o$z{_(%hK;H0vWZ`~-!WoI7=s$h1gEUWC zVQ$`g*$dj3f71Fnr_b(9`4=7*9G`9Bcq3*r3V&BnYF!rp;SCD^ya_x1=FA(p{I>9@ zS>rkAV||v6NK63Z@%c|YZxjhxbTX`PagbFM^;M$i?-YgKE#bYtV^(y!*n07&zUZ9f zney)O@dHCEepEnB{@E81^53bV2fyoXoqzWv|NF!nee(9!#h)tj`S+sev!A!f=UZg* zxdZ?h0H7iO==K5hl0XK^Fb)C8u@B@X0LDmYM9G@Yz>%aRSS|ppL;$PpgK?4&-2jLo z;jrf?#NI`SY#u<_`=p|Y+i;Mib`PMwQ3|@fPtD|K?h~CE)kb4Q`f9yYwdBOySGa+92X6ru=1x0ilrRh^g}3Far19Z1RX#cU zV6*H>Q&k}awR&uEiD!dLUHV#(GM^H+Z#Kqb-La1yWTNr}%S1ILd%ho-o#;UO{pngc zjHDxF2{JXn(<$~x4OpT%ap;$0EM@hIap1ZhLCX;!XCa9b@P>b+ge%}RTSE!gs<3$n ziKDQDla|J4(-}>`qxqnmg-j$)W=_8>da8BUI&G-xI{KoY#U?eF>}beY-;cw+4#=P6 zO2k4%v5LReB`^BX#r@{0+R{>jisK~S5fTTb9i7W?X|>#}7H80lGed*8AUGg_1j?&q zD+Ms?fTVl^Ibkn37J)n>zw@G;#UeI2Is1b;fM`{rb7I(-z2CR+3JDq9gZQ- zgfKo)sT$ zP;3D6*2AX*_HoUORyY<2iB^+TLS|lTGX~XX*jKB1n?V08XB4H>o25)K^yK zV#c-_!;S`wP$(uH5L!Z_KPu*wcR~LOVvnCy%>Tmc2ZTXM93StX9q{#MMi@k@ZE_Ps zZ6dp>2O5K=IugRBigNH+a&xlqh~iy?SL2j}i-nU4GyQ}1$M^gY~ojws4KS^R8vX(mmaze0BC${@eDBqgj*H1yh z2A8p^Bp3vTR<1zrmo_`;14HDX$^DkqFVR7^Hz2WL26PrqIDceTwFhpGcEI<8ypaNk zvowb31k0Q|gzm%Z{2gMG)lA2j6?<&4%4$BBloGwV=FGgtnrI`iU>e&4M_&yyzF_O1;IY**H%CRqyS zwXidXzQ=HtvPlbaU98b!@TG96g%mxE;y3z+5=B;T)>A&H0j2w;<-9ZEmLvO(e+h_A?PuY{!*Yu6S<94l!0${HGn~dbjOvzKl?c(SKl~x& z#<9+uXn5mYWqY45dkT@sfke4^#++D<0i|&7<4TN*yZlHko+MTeXAXlmFp1QgYxvM9 z0P_ivE#ev9++*$q_994WQDi+_wA~e2nQ7%F297)T>e{xH;9+)pnB=SRRO{#-!+3IkFPmYe=Qz`~7`ILuT^J~qS;SQ! zw~K8+2Udb6K@7I8XLIe)6FLLDUJhXIFyBk%4xnnrVUsmUu%|?`NfN4(Ns%nT#UsLT z1Y)&w2=UCtM3El4*?rmvGOn(%mV4qmoU1NB%{?h$1QioYD5Hz`Hy%}NvVgRzgTz5A zjSqGLF{Un#Yc?KvypyAm>pGtc@u(F4@s7&%}szT&9$*zM3IGf9}UhHn|aR)x-kxBl*_iSTdX0wn<^D zYbbSigK9|_{dkOMKUZpEjq}N`+7d?1?O!Lja<>}0%5-*`6G_XXkrH}eh(M`8QbQ+q}}8@0`V3D89A2`P@v6=zRKNUHc{bMUz;Hw zKt&=xKy2mhcLj~=m&tYRgcFh{WQV@8!jeo?p%bYfD|%tBEnXNsj*)#;KB99ST+DD{ z38Y4+?c;7{7@$&5SOA)N^T0=hHP~JvPt)CCNC_NrX{w|eGNTmSKuWHhWkdg?=aFa7 z!lvt#${z!+*E4V(X@VFXF_R)tM2Qu)f@`7MV`>eSGxl7NmY2^bSQV$vzem-xmNZZD zMC{?Cg85khxz^l9A4A!9Q(&4p|1V96)?+hSeLmg@iM*UU;r?a!Ud z*o?kcr4qR6Xq-Lz92CBPLTLxcr1GkUp7>pgwXwiUnfk8=ygJ%TtBc-QyHs6iG?VA9 z^Y^A@#lBg!rV z1g{S^ki@E;E{j(rM7Z;RHAJh2LWhDHwC{ZEBDfywToGY?tc7bGO8c@6W7KW`q9r%* z&>t;s`c`q|KD|oI-g1-oN>7?f>yJ-e8=T+iRonJSLywLx)Q~PpJ~Mqd$iFZi^#^C8 zFE$iz0yVx1ynN2Dpcc8dvs6K*zvYKk+3Rg=ypG|HGz?!B9;}pzt~lxyyK(Kay5n8{ z%X$S5@V@U6>W7kg1xg!D0_4xeq;ng_nBS!9(=lJtesd-C+&;dQ{4-03*8-V1${V#% zuk$!IdP;{;1vMozt+&m7IUZUx zRXP1=DflFC*|I|Y)QT?esb#i+P)?wU(&l4xzZ+an>|Xs9dT~{H$6dwv!&oKgxQ)YI z(}&E|L&vJ zNB%vhKPLQpFD_sKeITT9KtDBaYQO+gVlrS5p#cvZVl*=j9A>?h8aTq~KN(2miG~M_ z@@4G#2Q3VE1dWT<<$qN9Q@k;)BG4W;ts*yQ{CHA&rLqyE_VbKW?Ki5&;j1NC$*P+8GxN_9J zahV%#7SC8;#@$w~ggKJ`$j)wGyL$O$J}7dpj)?fT*Yr6(^2Zx6zp*UogehFP{I#p- z_DIo(zXpE((@}@i!Wzp;TRE=jzu%cft7&|dje8`7PsR*TuVt7$_`6w@aq$;wTl!FH zvAAsd&sI5q^q;L!+U~>CpBj?CxrZfscdYAp_fRxq;w6B~KAMzeu6{7jS|5#;c`QR} zF+?J~AF4hR%Mwxy(kiCX^wMJcwyh5UC-+Vt_$P>ed`{jDQ~Os?#!F(?zbuLEff*B` zpa5R>zW0L%=Y%8;bSZ5F`w#}o5Oo{C%Q14?2lK)K%S1+$W^mn1s}j+d_e$9|sJf|c zGf=ujI;T3CiQHsmR1}ICNBN^OBG(X@ZtUZV-Y`gnrPd|24j#peyS0gj zQ4U(g9{`>fDlJH*-4q~1nUwPj{t?kXRKq0ag{&dx-y2^2aDZ^~8j<%98T{M4!Tr#< z5POU6st@ihPg+eO^qJI3kkGbqXyI&nzOjdD$ z8b|%=Co_LF5PX*y+8*~Rq@o|sqweH|2ragJ!je!eywX0V*i&C>7Nsc}7V$PeXd#ZT z&kY@Y^2pNVE$=~}z0nQmV)eVq;5YHkijxP)DqomVj+-tqMHEv3xSv7c2ip>#i`u0p*>Vkz@n45J`vD~h1N%+T9Wu~e{9U;yOe7dhs8G$2VJ1`@X7=9)D z%>`K`NqODq#%jv*%%1y1-q!w9WbDG@dJ{jVCsz%>nxatsZTeqg`=NQS0_(pg_`0&; z5YfB*{v_@?yghAq7yUHHo8-&Pe?>pc-jOaOoWHt~PeP92*tj2=$LNSTeDJzOqb_cdL}wyvyum}>u1|bcPj`R|V0v`&I=(x?Zohee z!=sU?d9!_8?LEcFSGv9Xk65%g!!$p+04h2 z!NrCj!tNXc!)z1WsOa2PA1S{bo3LMOv7pzz&K~83xst#9P47DY^CrHvK_Tfgudz#m zj0p2Si5UiZs&ZU`SH4_+b4=oc8P^8U{FUk=ZfUi7aQKRdp02K#O;OKZ!gsWfkb=^V zuTDDe%FHk*nt@G|U2d#00b@9TM|iAoeE2`P^c;38YW*D4`_4{s2ypV4 zwnrd-riAh9&V;3iqnCDAch=CxnR)-}cZ-aDhNw+)Y0|?`PO`E{J3`4NWV+rzow)=oIo6Hijex&$Rz~?5;)e;fSb7#291>hF6;+`S=+~m(OrYNl zaM?e$Vit)z4GP)sbFxUH=61ioen8!`_9j#K?28Ma$48 z{0a&=C(!p52RXC3-Kv3jVz%XOdzOaVnaQRzb2#K^BAZ(;$So0Y$-7<=Zai1Vm`p*s<4&a z()Hmc(|5#M_&*_7!NisWWK1>SiK4n4f%e!O`RiSH`e@2}tnBkf&r=ln=A&XNY1V)j zZ4XDD2KmW`ohVqT9|s5k=>r)M&^{V`Kx#}eAc6{4P>Fohmhwgf%_NdGlx6TfIc+&P z4RVCoT|>MMaKBrA@6Lj|G4bmA>-Tq=q6TTX?ACx-Cr~tP=yW+<|61(5vb4Y9X%Vq$ zi`yBie7@1;!58m!TDKDX;vYtyxKkTODqN=)$bu8^UEJRn(^GyL~7qt z(7Tn3Eoly7uEO6xF`gFi@(|SNK7v_lW${xsB`6WxKuW4FROAvU8wJlO zM@X{Ad5+~2#NH@qyg_D$R|TXGSXtW1dyBQ+Qyn$juK?6BW$=bjH=)>`7bBe{bBuLh z8Vn2c*EQZBrV*br5WYnuhJi<^jT4zWv zAP6@K4lfD3zoZsd2Ja|#R}Qxe3voCaa>%>%e9JPcTa(QAL6Z^V7Db62wj|j5Eyg@D zEMgKxZ^$CkzZh&2=+xZqt+qTWznd6Sk+d-6$Ksya>_lhn1UgVuk0(HvL(~qIqnM4# zS`JbQm{@-`QgApJ_O93BP?F_VQOA;dyk5GxqWU%F3?l;2Wc&`%$zI4!P1@+G+?|S6 z=b}G@**w{{l%-t0(4g46k5--=nnYxoh^qgwy#{=W;JH`fuWUW`qzveWXl+lG6AI04 zi@W6M)flD+CD2aq=l2O}S8h}Wq*RN5)neQbKT(txWu}6=S@)P<$fd%YqB;U8HdKbr zYyfI66nr{U_k*lPQf_rs?u{|9L3%l&pFmeGLN*FzdyS&LmeUf{bVuDw6V^Y26x6L2 zku9q}t#odBwK?;8P7vM{Lw#Eor}Cv{u^IPP^vz7Jh1*?Rj3|5@g&+YGkDlnhf1<@G zT2oD7Zoim)jj=zcsDcFOqhcB_j8Bnr%790(7l8V9KwVk2mprjLHAEVuwqLpS3si16SoJ$Vd0$g?HwH2L2MMc!j~T)EuQmwgJ?YSd ziFCe(N;W9nXt=b}04;9l&wMkzT)(fadIUiJ=tHnas#aYStGrW@Bw24}DSJ|kv3R0z zg;lX{zJ8A7rny-23aZ&crP(U7c}|YpeAcHB16D-8PyjcJ8cehp zT$Q~tUw>eZH0Wf!a6;~(1Vi-Xn!X@8uX;v&i+$|gYQ-eKKht`siTs0Val6r?`>o9u z8YHqQXe=!^h7*4N8t^u!UEmvq}nQQOPc)pJ6!F-!FlGF;Bz zWFCoin#dqu*;c%=XZ)SX*OAASBg6H_9I3S-eTBbEH@0c>Zp+J8(mmfO231G>YzGu0 zyLc6;KOo|~?sof7Xw%*CEsSd()&pV^TG?Jxaax_W$Hk@t>n(0j4YcSz z^cFZPrak$VQ{d7~{@44?P+^FH+}#z}s~_Cgo7d;7-3L4C)F~BvSlq&D)X(D6&z9QH zQPa;wDP>5v3|`Cr_^ZFSq3;ZZ)AmL);A2_hV^567p81SXQll?w#_}e|3iif|;NvCY<7LL< z6+Yt?#)vo{gg_ua-+IV+9eko*e4^2KqSoq zRmW&-|L)%OPxxEXQ0Ia1+he}oKdEnjGNJ$g>|Y2K6aWQ?|2M>9{r?KFobEdhC2M0a zcsI0RL;2Vf5zAK&V+|D(&m~>QFiM$#fyC26ItKJq-AQo;TS$+mS-4xnATY~;< zmHB@|EY?NJAt-@*$;8-l?iY^#6JnX4eu_nn>+s&8KrB~VYd=+snt%K>(OUPpH^xM{ z0GPF}iQ*7|yKzw<7GfqPNiJ?4>p~?JWVAZj-njLa)>jkFmnpVAUv2r?ajK*F+k1lR zM4?G%%lDPG;BTu_ovlAV_r<|@O}p9-Hb$R_-J0%dKirxryIN%0-SOw!Qlt0h>F&AfU4IX^=U?A?+tdB;czL{NKspx6f~Td&y(~wa8iwgw<;ePb*Zt z77Lf(UW-HNiIC!%ZM;Yc>>kymM0DsjDG8G(vYsrE?X~_;q_TQFMZ9Hu{gLE|$VRH{ zJFks2#m(xCbk(EnjSNldOJ6c|SZ{yHG7x(C<*~8+{|&J?gzmU!k)tjN8J%SgPAY6~ z%WUTIe<}fB7Z(OM^I2c6feI*5IUx_nuRB{>D`%Iyw9nvowo8&tn=&*W%I|KMW$KCU zls~n(vs01d@oJ|sKXiAesyI<}x4Jz0&hE?V%2&IuYFc)8UlT^iqTgzo-rf23rfu`p zx7x0w-EVb$)M9&tAy)6b`ca|RdkvHF-}V}3^u)e5E!cQ}Z(j0v{k`R5=(q2!Yl&h% z+P?gMhFE;|`v*vIlJ^hA_x9`dRmJ~*39yWy&7kbOlT}m?LwX|zyZkfEjyJb? zr1+ruPcqf_i4q!Th$;WxT=*xA=<`$J+i3EMJuP78eI}6F97}z6i_Bcz3qoY#kApD) ztd|D#heR~;=^98%5l1gS6UXpnjav5v2lOzWNYda5ocZ$%xxD_IYrN~M&MltJP3%oOFOb(XSf9dW4C zL+jss^wBw}sGNgTPaj&&_c?lrgoCs@QT&|Td_<*=`gC6hTAnF(qS{e?ddTk$ZmO61 zTB2?lQD^}SSwvq?{#sUscsX`L(a>mpHY*_BO-S&bp@~os=Brndh`y51-JD-ft7Qc* zU2h+^>bS;TlloQcCdXBqX~t*GK3^}Jy|{Yq$F*nO;$J1=E{)#;$>fX(c&Mb(U3C$% zeDPMtLpD-r%0ZebcW`L)N^`r3r-x?hCGm<;6m`lmxX4h!~Et5mlP z-$r~mEIgU4Qa>J}KrE++MF9G0O&X(_SW0}3)}&gCEqBI0$`uV}pivsf&8FD>E@hvp z)>9atO^^6phM|9Hpl>wyIQMtCh{;Q%>*I6T9lt9i(_R{Ta?U?2-b`A#Gltr^xwXW zdMdqMHFfTb(^YZ2mX0@<3)+cEaxl@iNgQQCgOrkP*uS@lYm#HGkE_<)HA2ZGF9w}B z5uGKjiwq2y*6*MUu&+c>O?K`)*}nEJu%Jh+j_+PYy63r2{Ys1#dDm!TIK=RwMUD6v zQpZ0gerKyP?Il?h1ATU%j+Kw`MuHWe-}`_!R}=A>Gt+*o(3m$`1LZM^9AyG8Zq|fU zUH!CccigcwRU6tm@##mzapxL+T{!XT>aX16u5FXLi1!n#d{Z0U1HPYBc1Z&fOYgb2 z+lXqkztY2+Hn^|&(5P)Q+=}mF6SR!7SDSH0-XCS*J!E$eCUI%7z8d5;sNs#j%2*F? zo$A?fThLsC2SU6r$8?#~{skPUi;WUH8khhacX<|1Mmcn=#n0%O)PzY+V zwHWU~FyqH@2fRV)JZLspazQmcV92%aM@%EA3yXS?y4)x`a;SJ3fih+i;Q8aU@Gwo2 zU4pip`@lX)k_q@gqb|V05k3?iJF_*8(2F1bC=tWt2gJ zC}|YOwp&>zD(GNGX1=WV2tdHa)+4D@*Y`kKhq&sFyHv93Rr2zqv)a?tA;p6nMn@eW zg0p@C0sawd;w6jPHKh+pWt3`I#<&l)F<&95i-F&IBWSyK<9eSO+;ly*Nqy;km=>FmAM!Ow4b^EAL#8+8`Ipq| z$^+J;y$lJ0-(-%b0$b=|e(0c-GS3(`Gxg*6>*UP9^QKF>qm9)bFhT z&@4TT6c|$F@g@`%5{5F=q!!cn7st?i)^wv4cKfyOIQd>q^F4@k-47Hfe7_1{G82%X zKpWwKs>Cpu>O~+GQ1ec{FkrOsCVUtW39_(<#?XLfk!y#BH~9nQoKPt=$kb~IqDQp* z#Jj;QG3E78h)$A8HK4c8>0%AhE{t;Vv^K#6e{Vzu&O}1U&T$Iia`H!BP;=-_0M+%F z+s;mbKQ$v#D(M(K!@Y~?Y!y(3L=;NIBOp5tIqL-`B|ri0doj*etK`7)$Yxtqv`2u4 z4N8+Or9j?3ToJVr5PO=Lavl?QImfTI8t|dv|wPhuEE-pjdx zK4IOBIuLnD4@K9a)g_EN3UDFiq{y;G&?F%;Si`r79#)nSB1^8j=6Au_57^{&WjzAU zD{fJm^Rw5H)AC4Q{G**Vw>B@Nm;L0*Ln1N zR9E5lV=oWa{jauQ4?X=G8Anv%?W1x!w_SCVp7`HJ;Vxyq72o+dQaWs z^zd{H{7a6R94{U#y?A=#MfSZHIWJ!1w!g?xjjL72Gm>xnsJa?$HV!MJlqL2kLqsWj z*FIFK@*xInRU|U`k1%QdDTzs_YD@^K>(D%WmjB36{I zel@CHy;Iv6k2tBQ{b5(THU8!UXWGIz;zz*aOD}H)Q)<{W8e`QiKotTd;7a|?^*`ye zZ>}^e1kpqS^dEuVo-jsR&(KL=T5$z>*Fz@=99Qe%o%Lhk-jna$!sw(=*0lEk$Vp8& z#YvLnYLrreN?&c1A&WIC<~7R08ddTdRlhZAJZe;fHOax6w68YdyeSW0l8;~`l;f6N zB!bnoBt=s9%WDz=Mv)#&FhSxo5W|2FEhj1)48+-+%8)?S??L4h8RE=^cV2Af%uArdcAJZlB7T%tr72<@5$fu&1-R1Y2#C930rBo32QMI33ckc zYrWkD1+?2cwb=)>*%PQ^%;~oS5aL61){&C*VCRYnXgCI3Sr38|Kw|sAM(@ssf57I~ zfR2ey5Wce~ud^Ytv&Xx0ms)lb2AS_sQjX|{!EQ9Hl>GSgsY!{cCuF*14h;Wa_gz?7Sk`;RsL~u-~oH>O464R1_DaZGMeny2{8Dm zNQJ1h*q7Qno3x5+41E1)eTGLn{CU$I6k`qbgUGr+frh2t9kY>6YeBvh;V#RJe5y!! zj5rV*d|SfiB_7_!kC^e2E~pM%m=z9>l16!QeWMfCgJ;U^8WjLCax;u+0f}afU={N*$`}MFi$xI+wm=UTz#&f@ z#;Abfk-^M5GsD#N3=B2QLQ-Rjfn#xTpr3gtnKdv*lU*zZEM5YNkr}3v0%HJdMi!Hh zEHESxESkz_DuoivS4?CW0s$k4Gu}c6!;q}rsKH5?GrMyoX*_r<}RKAc)rfE!XM9t(&n;VnbSG*$l?#Pc4*$*}GWSY0zwH4&A*)(r(j zi)up7yri0ci0gjRML6H%;6Bp4MUx5_sPat!R2a ztg$u=1`?0uQQn&KF`Bfim8iP~jP#Q7O=pvO`(Q3-cKb90aV7xni{fJ&iok;~nJAI9 z1t?_;8tCKf3R$TEgz8WKfkSRivXX>RnEg4*KiSjQ0J&M=$whC`{fV_yhOY2{T|l18 z286YnxvK_{HxmytKot(Zmze=qPO(qVyh|d-F}VOIq2^%eHE?M^3?Bs5&SVm1rR{tJ z__C*c-C&-kA4ZK`6lM6}#*{+s96%%l#GI$x`-FNzbZFuFB!~kc&7n~9P&cL__oLe# zsFc`6ROv?)@p2l`gz;O|yGE`RM{RaeST#p|UsS<}xCMQ#jXX>h+9w$Y2GRy$P$JzZ zULq?+DuMPI5I#d2Y7(fwNcZ;@M+#Nl(g^4wF|jw2grIF#PxzTy9QwT1{^?| zqz>%YTVtKQ2?;Yr1psGc$T1N6EAmv_OnmtF^jOB*tEh$*aCMD*-WlWbPZOXL;v;qW z=MNYgqF$CyU%D}=a-$3JgE(2VijL3epa~`#U9ij@5bLgt#(2D&X87EFdw5UHK9deR5z9+iy8IRQbzgrKQR zS>mf5z)3DV#GHbA5fERUY6ba)?_|Rs>y3}l51sb>JX`&Faq$ztyARUXhw$#dI0L8R zsC$b68wBK!)5pAJh%YGmMM>Hlnjqf3EvnuF^ydQ}@&WIy&ai#jrI>fBmqsVt5F45F z4aIckF%T)#p)^_JQ1;fLeDtAW(V=qhq3Y*D_1;6p7_jLYRa+I{lO|#ZbzN{nYfBUH zsSiG74$VeUJI+wqME|iZ`eWDo$KmrI$}EQy?~#kfk>gLQKqtDF1a}h!+f_%&E9HoV z5qK{KR-<_wdh0km`Z%KKII8#f!RO-`@^LKhNxa5M;;obTqT{g{_}iFwJ{i(K0}x*c zztTU$Q=|W87yZrc{hR;!Zz1__G4ClQJXn6~^hF)uZRY8eIsNiJJsPU643`!kK|Iz# ztY^{-7X8bw`q%aOUk~|TAMe?K#@W!Vvk|ki*Mfmr-m0;iSP zL!EEVkO9u7Ynri8IFC+_IY}##o?AVh-C|uUmSu{=>V0|vD2hq#0fgh)7lX%w{|jPy zHKg!%O)r!Ju|&PF^c>1lQy2h?2LA_QN#oJYwc5E>X;Pq`z-hf}^~(B<<8ZF^H=Ej< z-4Cd^Z1!v$+^7DZAr{2|zWxMyUOk`V%-G<4MhyzYB5gx_@*jxho~QfN|AJUp_GKs# z%WhZxjowftGZCK;2IRM-!2_|0`G4U$0r?O%D*}$1H$+m4R`@AF3o6kh zsSQ_HAZQ~reoN|5a|sYA5Q~nKF3a_DBrX_YQOp(S@gIoAe@IIIKM;#PZ!|>O0Gsq* z5Q~nqq2TlXKrBV^(ngm`R5SC3CxN0@FSmYaxGK>LkujDc3N#wayw#C0*G>f4wQ0WA;ZWAfLSL}i%F^uox2)B5_vXbU8`zK2LTMpMbl zl|<3E*t%-W|F(61p5P;|^&&yu?sip0i=B7fu)Mu*>(>^0|6VEuhd`qB)Qz^ed)W?m zRpgG}xG@9n-n?h6vR>=6IULsPebMHf9sOZSVa@5Yrq>I%?qNNr1pQb@b{wZg3{P2` zq}*zPgr7nFAb|Qc_e1d!MYl{pmi8|}#3xX}+_G;aDtWx{tW>gp=slw3SrGPP zfx9r8TG^{aqHJrkBtuX6cE!ee`0c8q#M3L!%PQr`6A4x=@1&+h^K$Rh^-`<&)Dwj| zeH!2DsrWX_FkLBa`Gi3DtqDX#`gZcee){Ed=h1k_jiee(W(>j|0+Qj;*8aIW{ab28 z-moaeQQ>H_pmE;TvtOeL^HIUmDnz2!@QuxXXvi2&?e5}r&+fbLZzZXPE_+sWAAMjk zuKG5sO?@ZdyBMe*PD&E)3E#-jSHJi5xo6M4t++a&yp_;f_X>lU+w{<^ty?{j%ws#$ zxjyoxJ#OI*FB9|4|Kf>UafmA#Zuj@}E~7_(>Mg>{^v)@@p>Ei(xc z@y>8}MQzS^Gl>dA&WO8h+B`=yNt6>)R08Fclyx>)U&n>N0uA58ka+7AKikuvd4YxD+TDLdg{1xF1G2(x6G#b$Gf7xD(Wl0n@tb1O8K$h zrmy~MH{yO*Di89p!uKeBzO{$6Sl-ytA@2Cpm_69%ju9&i(0oE*|f|(tBe1tM%hrMN{ve?_zhF{T22cl@N=sJJtPy9j9pmg zbBH<~(i!*CgB&(E*~So8!1L*TR@%TtGC`<{poB0tvXpG0aLXfj`k?Ij{4E_%<;8Z> z(3bgvpYfimUmvFVIF)gIaboJ~x}DQ={@siW@zR`!Nc2>A7sb59R53=(5H3G0x%FsM z`|YOrL%p<8mir%cr8=7Q{T9l2scswSDqnk?y-+T!d)vsm<63shLdEAGKCO2$mbvd1 zDiwxro8IlPEIeAM(xAFyj#nPWJuE}(>)yHcti!5Oe(|MQ!X2v$W$RZqi?6N^-?3@# zu&xbVe0__`+jf`|6U<($@sJ}bIX$HhXj**ZpWyBARrz|yyT#hDVQ{HMCI$Ht712o z{jRA>*Y}RKm|dQ6OLKvHQchI+@>1gMmfUBTJ-uO-D;}Y(x8{8PZi_j5{2<@>BY?)) zJU1^+^0{B&lNJ9`v75;YQ`o^5e*T3jt-E$%*rA9^GrLkEPdY~0sr&sx?={}s?SXcD z`dS;gA@=!b?!AIQmM!J}rtJBT=bo{@{bQ(9oh~tkdmfIK;sf7VP$?|+BNGGS1y!A) z*Ovy^MgkIv15WRfH?lGPvBEa%JqhCGgME~exS9AH4at5cvL z0TtC5n0TU{@u)v%^xeP!ZjNk0uX0Ap_zIR}cMg2yC=x^0;{=z5YfbRSeY3g# zBT#A2i6(e0F6!ng>))e*c+ul^-k}(XB6EO8#Z0@KdK^D%j=8%~z&h{SHa(Mk5HiF9 zKK1f8M8q)wM&$$ql%LS3jLx!GR)@Rm#_>yCNT%w60f3T|q$^ymU!FOXGeYch^y<9Q zqx&|{%cCP2ZEHJbtr2tO>P@vjvKWGNe)6Vg$5dh8q#Mp7E!zvTB}mTcJ|P?Ln~r3w z=cUp^);O0N?Bvyo=)c=l#i2I|hs`gZeYaJ~U1`piZF_V1hhH2b9PqnbBhuLM>2U{J%V_SbQ}_9yJt;waE5DcB+I-C+2kWO7!jy8{@VmGJl0 znpIPnNb$C*>Z!^$gK%QoKU#l-r19@-I~tUo_z~L?nPNPBU=H{uZfhcM^#I{ISjOwA z|L=TL>PX?{6#9eEu;N8lYBYRsp0SNuwKy=%Z*+U3o=U|IEm{?}0OsB{C#s&+pG1p4 zI5^u+QdtN*Deb4jE{7gzoMgdoot?o7kAf8%D7a64*#`#XnI(KU6f(cTy}eIdKK~!= zy?0lWalht!6VeDNH%(DmR8+7AMLHNdNDI;x6a)nn1r+HeAwcLwibyjQrCEYls2X|^ zX@Y=&f*?)A(2hkHb*tpXZ5+$q^zE02hJ6d02i}wa*N4p0?8>qozM_bO` zl|d0k#vvkf&Imf4tPJJ}H5ch9@2YzTY&3}fCT;dMOw76YZtQFGjbLAXb%-TvwLuGb zB@|SzR?bK+J5=@K7lKnBG6T3zBDqd_00<%gbs@vYn9IBru!3845az6)e7^z_P=WBb zPu_{adA3G4N9G8JMT8KcDO-rUAR_TH5q=^iZxM078xf=sVcHEj=}VRj1faeE=bIm{ zKt_)+C0Cf|DyUaIBAUz)Aw>uu5NE|L;m?oYu8eTrKsZK1jF}N6ZUp;;dabxuv_{=| z&hUjR69z+4jyM5FMu7_o|@%_yLPm&*8&7iHIPi z*uqwPT)JA@SLAmJJeZDfvyN~g!woyMj0~gUBN{;jm|8bc+NlWxZ6s;|R_I2wp*DgE zb=aTVU9X45|d2=X~>ZXyFoIqb^Wcz=HLz;8@DDk z+j@;>5uAmP00lh-3gW&njn$*{_8@{D(^8h+;$889jT{L(H%L4>sT(ri8f>Tyx2`94 zhYy-5%To~Eglta$@ms(2W~N?rtia|X&99;*(7fs9N=x=+o0_B^Ri*8;VcR_^)wa8_ zQZa2MMez!JPc|>Zl*TkI=G%%V+YkzXAu?jnu~uFt|GMFYC+WHzw)|}p88fI`veL@o zN?3Vm6WxH5-Bjd=n!IV_%N2F`Tz$@}fT;(Wm!XrbWpLiyz}i+@+6`De9&tO8*?uee zce%l%`9}Xqgc*~liZ)DiYPu!bDAmV|^9r+9P)4|Q{0J~Ci|p`mK?LJzvaOnR^SW=t zJ`Ii#aUD8e1Dl3znbQm(V46Npvyn5W1NN|`v%p&Ciyn@U-25VZO zJ$Fl9K=W2XO+x75%0vJLc5qNTgR-PSXd_}U%$_rvFc@)Bu-k1?57!92jx_SxFxnZ3 zZatB)c^P_gjA@;seY?icdY%bdhutP3EKJEpNG_NQz^6*a)=({wx=$KRG<&--Ldvg} zIg<+TGrm2ueZ;pTOm0<@z-=-Z`ElrMWC#+jLGD4v)?-JE=#pv+BR$VR;~%kbzR2!3 zTD>ws+LIkEb_Be{StQ#&y>mFF31Q#c@VQglyx`=U=vGN%`}8h#*{Wev9- zXG6jQa3%qK3>}LRvTS6;ZR;A*epBVz&*G}e&aE&=tq%WTvq9TFxGw;+4hwK0oztdX zj5W2W0r(=}gE1;fs%jUWL>oV&8K{P585;j|GWey^x6YE0(5x4RX>pcoZZNujcbM2@ zM;k-Cf(H$bNOpZ((LMBucw?rFItZ0q(VR7GYP2=9u9duQ(cb*b!ubvKh-AmndGj-> z7ZD`D#{vlIRJe z%5U0jsR%>`Fez(d9IhSjbtz00&_G5sn^oRcfUgegVN^O~IZFs+L|XQ+{+X`|^F2+& zaA$z}UdWK#s6(^`)Ka?d%oBa?!}Y|5Zo7ncN?!bB*fakck@sYH^pVVKzRpeVi?T=x z967>%Y5~X+xsPQV4XBWn?7LGlYweLxulx0pLBL6Cm>2!L{`1j~s$a#$lmohHZYQ<* znrv{gw$5OLtbILJ>nfi$^!i{#&hHA`^P!^!J@&qc_TK}eWtW?xo&+SumBlda0cvD_ z^Ur6^2nD#_D$U+HTw9Nu5XmiT9cE90H(DqLgH5kG^uulgMvU&@BE$mq@O(JxhHACF z9_;8!gPY1l8x=!Yg_@AWft=qqC3cneiO{5!ChL(_6c};B$>w{kMXjIBtGeOaARJaf z#){gn1R97~C|cdGX^LT@t|;CGsGyV~CXif&K|r65>I*qMjqKRUy!1_|`&P<#Hmp0W zA-i^8+PI&Eq5~6pN0f9;8<>6at+Jz=a0R89OXCbH1zU%At~L-y8)odntn+`sRaJEE zsDwxvt30z>wsm~2McZR&sb*O#$9EX-_2m+y`An_OYBkkJ3hpdCBz4Epc>_i)>i8h2 z7i2h!^rHFb)ot}V$>itzh+emR++c!dW2#0aAjTw5ntKCA4m=jH$%__2+?Ri^AyMo6tZ=Gl8Gq`nx3j ztf1XS(zF5U*{7YVD=x*B2Bd!K>?h+OVP(^dp3;G=tPxEz2_>BG0dJ3id z_jjH;!f!*h)+@ro+8%C6mi4t)wT6yjBU)E!LDp42k2I%hGSwvBDk zbncK$H5zrUxX(R5k59uazWw8mpZi6)({`ok^NGIi%GE(g7S|unM3y=F$)7w^4_Jb* zVd>P)9i6l*k)K7YRldDf(V=a>EtnBLP|$~;!V6+)@xKpw@^_hl61mT14jAxw3RaEc zs=lR;dGK?h%^!{X+@m5jB7azlj(8NvwmTsoqs324ycAlhC7lvoI+cXKTf6TxEdBLt z@{)An(y@0-$6J<83@n|TUOKhDbQ-Zt*t;xqboq?@a_d>$Wm&7`bI!|hKFjj7dkO=Q z)R}6fcgxBx%PIrQs?*DA>&xd6E5yAk>PJ^Nz&%af6)me3ZRZsopA}u&ir&K&{X(y} zp))be6~loQqv;jn^%WDuDrxVk>Cx4T@~dXLtL9d#7S5}dKC4!=RqKbVHh;YGWL0QaZOx@nAgV5ISLtpyVd>Vu z+U=J7z0+&%h;{14-yTQT@3uT~lV7hGqmlnZxzX&uDmNa2a6x)FZ+5(9^uH@NO3Lq% z&Kq+yN>{k|Kgx}@kxrab5Y6OccI~f=KNpfhHd*SVCXIcl;O)T*nUaB*_6^Zu278WL zMA>~TvHSS;`S3fBe=RpwpG&%wYW+Gq9N@k`CT3W{7;i9e1kr#s7dAffkU@@NmTJtx@L^HQPu0&{}alMvwn?}$s`@=pDE^+u0K<)ZxsJb^mLZj7uV@*->Ks1oWQl&>BnUFu^D>Uo_~}ZkCe>h#s2Rr zH(qNqshIzydB=YvHejJ@{_U?9N!w$~FML@=%I>~X-%3yCuPyxg^8rAdU@@V4Ips#= z(PylBwER4)0o48fYq@cC(D~)g+KA5|)fraUojV)!k6Sx`X9{2LZqC2^v%AG9H?p@^ z2He>@8`Ce@yW8u3IQ3dI9YE+YA^TZmq#+%$x0MN3VqImkvcMHmBGHY@%Lm^eB#1}c z8)*nkR*rzk9s*Tc>%vfjP(^|>&mKXi{p}>C>?B3eNHP~c+^r+?)D-7$eMf}Jst4Kd zUW}y_8CxJQ{F(fPtHdd+7t7Gqru z^Y;(5Hp^8l#(Bi%i%#pcD1BXw_wC3RUym&Elwu~31@+%=%Oz;+f0Y<$C|QWjZPig) zN=l3^kUXm2cHz>}gZ>|gzl37KJ?o@oI{Jx}u73N)3{JVx@X0Z&wsy;^rBp`j;rYIC zY|r0(iCqw>rlw!!r=`jDZt&9y=O<@M^dm zIh#CdcoXHs`>|t6*4<_AaVaydj*&q$TmwQ0w1=U5rx8CYLw%0XbGXZR5};#1`xJSxGooact%5FlN2w^g;cVZ(z%Z3j?-Al6??;riyh-G zXkGdb<;Kl&WKL&6dVV-$LEX&#HlwibE1aKl^Q5!hS+9CfOi4#Ro)8-!rWIFWUU;Fu z!%qUz>F(#$ z`)|#-2GR#n;R4)Eprpu81%!aa6h;hAL+3LG6<#@HF{doJ{v=*&=!lM^sA$SRJ{c*2 zSc>=7a$_{}T)lDF+oo^o#%pd@gtErF!D_bmon+fj&+qtrysVsr3(KG)RBn94j@*nF zo8^=#dL6J6*RbN#_?Gh#}{QfBO0yPez+i`y;n=P(FI40Ni#07;$ zUYw>zyeRck^O;>!dmdtiC>x|H2$CHr72ck~E6wNRM#cf6b=7DqT%noka`U5)w$m(l z0H^Z;q;u6RsJ0N@GAn$~r8fX9kA#oFwYw`;?-NA`4^p!x_fp@9+FLMwK;6DeuL}dG z)L7?BZhdL?9I7+leYLN^U<%-r8{1WOUqMy2BX%O*bzBa<_i$qSr?~F;ek(QFJse{C z*!l*nQ5Y`6pB*=wkzX03eD(oXV(5h$0NAhB>?3b?IxtJKHHNy7!$pEz-EP3*cB%eC zw_{gtP(|rFSsvO!SFHfD@b~O++EwP2Ym$z&{jCuJLVMLNu^olqZ6IV{)Zvb(qzke+ zb2P6GOz^ZQdFH)Or#;otL z`WU55QvfjWS2YjqBO5nTzcX?7A}2=TsizdHWa6C-l|_#4(q#N=(7}=UqD|hS%IF-7 zTVH^vl3ImWI{_U?eki)ZKH}}wLK)XhnAqQCz2MWug>`58cSjj46n0TYII}+c_=B5Y zR(sxS#k{K+JlFCumkZ-_o?GOH@99n&-2N3|uPDL&ANSdwD!nG96btqieF+o4LDEWKuh4)wTJhdUutPP&@Bz zvh{U%cdeqUmh;)SzHRNUGjZ=(G?VQgBJ7P;llMyxySAs4*?+qe-merUlzLf*;J>W< zYm9x2UkG4tMW05pH(C-#Dw5e-nDO1e)h~Cb&%SS=P1&1bOTlZ$f!zh?khS%YAUhjt zJbPW74f6^1(Sz#+<#}3h6#?);a%9+PtgjwYfg)&4+2czQj>I?i2T|WCe!C8i(-iId zPxB^uCV%#s)V4|djDcE%QxHqnJbWchmf3W6dPH-kJ=!M9LDW=n{&gXR3TR$j^RB1Q3UFt+)yzEdA>;$ zih#!F+P8UxEM7;1$?`XQfHz#^O$kl|EO@BLH9-m*k&E%3K$Va2qCi+JldL^M6ELNz zuv_H+hDJuW(kAKpdlq33zEDp`%Md0sLID>rNFzlk+LB?9eKFqMv~4mKy9fyZ6rw33bTYmw(Y)pBQxY=0m_fo=%};t6G+7=srZ@nc)ksVd0%pqb^M>A_?WW^D@6)x z8)QUe!rwu%+?Rx{)&yWSc1a;|QTSZ13$FADutNkd4T39)r*W+yOCiBpGmfV?@nWMH zq>LAvYx9SIGg-l|5t4Wv64AcrI%lwxhtSXQRwxj%m&CV02tTTrXvNlygDhfK@!&4u z)N=-i^#Cxrmol`Iq=wFo6F@W*Kzi_P)3Hyr<6(mdw#f!fco0hmOp1ZaZGd2z#u^=` z>z54ZpNrH5*OmZC9f0jl;a^N~(+5|W1~+)fvxDajGE;G^6c0rZK}^B*q(U7G`I8=+ znLSK@0>nH4t`Qzy=1C8g=ChXu13ma6rO(~3ycE%vN|xrwF}Tu;qau zEx8S(RD#C(>3b-8PljZBTGLT1g98LG>2HPrUpf+>i6T5K_e(U*PltJOx!XM2SC@tA z&d7ItVB=_JZKmzljGi zWAxxQ0GF7Hp#vfrAgY88`3eYq1rQ!NLCYB!5*LnvDrF#D@Q{PuDRn$_iD&@B0NkY^ z_M96=X6ji~w#Qk_?c&sfRa~wN%rMKY9nb4Z&%j;)G5$HMD0mDVt#coZC2?_O$h*w~ zSbW|A26Bdp+v&#XWx(?)b2=6C1@}K41~u7a>@cAq$woeG_6ddwTw?HeZrTkKFb5f2 zLYof}Ww|bN+^}2@H(v%fyH3kHN-jC75aod=W!VkC#k|2o&K5s~mOU|%&gcQv&sskU zyC8q1JCO0f{$lk0EBh2_vKL1dkM@$MKpAD{Qt4`k{WP4qqr zx>r(Ng5Dm(bvjNxf9%Vhc6EQUD;Zl_dU|$RvX|<_wW4u7gbU>6r3%CMrm=U?WP?Q6XaOVqsvhy!~GQ zLFVlod-nNFNeq~us-G@`LZ&L6iYfsDiCJ}zUPF2;SH7l+v?Dg7%QKIFE(`!xm*zq& zg)Jfti&KX$$lq(rkSRvY5$w`3o*ym%T#4#xuAog@vA0gA=`N4I&>&MFq}bSK}-rz6G+0;0?39+Za);j?qYppC!6rx<1Xzcm)oHgc7UI!}N~ zL0ryf-1s5f&4A-&FN6=qo2gm&^&Iwg3!g)G|Iw48YN3^^jO)vm}O(mb#gQ`Q`s~1c{}w zMbN1u^WPW^2m5lluc2Yu(ZV)WrbQg1;h$HOH@oAF&fR#^{-*SwMnjyUW>e$AGtK{M zG-yzO1IX#zAqlNmax0N=a^wSdJGlAFNus@%xC=LiqfFdmHP)skvwwiU#=+s zPcj+|<=Xmjaf<(6G#dVSMR}KIQn^@1T?m+d@oS-))qMQ0+IDMzxa#k(x30Y3ToaN0 zunYgcM#FNq?&+PCJ}dW~|86wwtdG%72m8*a7$-n}Cj2iO4HS@re-b(ucUy`n@#J&! zIq0=0$yh9iVucb{NLa5KM{yuI>x|$Sgwm?c<)26u7i1ytd35q=kjQ7^bIGov4f{|? zgc5tMtkR4@$IsX|%j6wM@N?7^27C1vL@;FVkXIFmJU^18=tZ9p zf3i$dI`W?z4XrI|n~Mo#bO9cr->R{HDKXNp;Naf2R-IFGAVfcR8t+=AmGuHFEH5}D z-_~aAzx3aYhBSi*Po2^Q%>J9v@Z^NE{>MvSm(nUao}BV&`*>w@=^+#Slt9z(xVC>e zz18sPnTKs1H#gly(IPtmS#$v+V zltW^32WO^Od_Cd2`S}v(W~Ta5|Itj67{xcAZ#Ip;7iNA>@+3lbw+xL@;b?I@&B(I^ zh+A0M2iVt}w3&X6wp_5)*+E?7@(6np+*kbIva@;8F|Lx`zI^1T5lb$R4EPEa8NCrT zZ}T(y*NL{(eLEOl(=KvpHvw zmVW2^;P4g7pj=5ezUh3;qM7o>DvsUSe3p@faqoUz7I5z%g;yodfyAn!mlPyjSgp;l%z4YD3X=n(>f~nd64A2;2S?KwQLmLI>%r)`ih# zPIH9tw~Zu@P%Id6f*IOyjrv9i1l6E-cQu8AuWQIpnPNNuV^I`H%NXdGk}LINHDCRYt$KP&6+gx;r86g*oj(4tk&2L(vt*CSi%Z2l8 zm=~H=Y(H>)C5I|H=o?{V(vI`=I>aR8oP5fwilb#TG-1x^=2tJ`?hzgLeXNKemEN-J zdr{RLc6)}X7Kd>$cl=NZ*S&<8|8-U1A)|XwYp&*K?9G+R;(D<=<=J+&)Yo33W2Evz zv*)+(lt08v8X-I!PF}2gBvL)+CRMrkblm6smggE=Zej`Zr@24#d&{W&yLWMpA>6ii zw{u47Qr$cP%ofH_UF)0)&G|wZl@saWeIje+b#L9QN!H}B;B=zt+dx~F>ulmlr`@2T zUf9TELPBMSv+;7q@b;8KS7oP9=W@>0HV1Q4)lD;A$rIU`(KD&)eb~A3RC#BXlu*@I zXuMi-d1ubLtLn?U&eazIJHPC4)q^d@Yp*hQ=3PvxzYcV+y{+E)?U7JDGHtwGHN3On z8*)i$t#keTvfZ0tT+J1O%*BXjN`IV{RDS$hqaj3A-D}%x6>@mbMIUG??G7vDKN=19 zUWm{5wt$XZmE@Pn0~rA=#OcUT-3nks;CZl<;E%oW1~j#2#UMg~%*C=Ib3-A)Cp|u|M`gm* zr%vxu@MG)=-H??QV1cIaSqsEVlK)JHu=j>=jy0C|lDRz*DAIM>AbicJCmQ2|m0B{@>4UxBsqs@q6DTgS?v9P^(NDKp2H-_e@DHjl;6-iAvM8UNJ zm~J3}fx4k}lg&V`t#dwS1T2X{J{w|yBqLb>F946>sIM_x%{s2;9qJMg40DN4Y>fI#OW ziqC{TmZByIlhG`oeheL+9u@A3W-^fWV?p|Q;3;HC#YW_hb%3J<9a^K=bX-$6${vI) zv;bADz&k1G;=9=3L(~E!vW|rly&lh|qtigh0S_)jchuuna-d$!p&5B7GNho0cbJZQ z)`}h&j50`%TP&jFZ-j^_1dsX3_uxV6jZhSzwOVglN9HM42!-=RZ?w|#Bcp>f!?4AG z3mDgRm<9}mLJ!1aTH}O^%ahf6<7`sNb5w*X)| z%ggHVLUOg6r$e~g67x2quuRI^8S)RSXdg2!s7zc~WOQ2v$VR|j6X6HPXuJ%{>5Zh& zA%q6n#Oxde_jsxA0?9$G zNx_a(#5j;s31a=yIaLDuqX-$Kf|@Tl45a;759Lo!v?>N>7(qCEYG6Z%T%-=dfr@w( z%DJ?O&;y%YXq56q*a2Rb*3kWfG+s6V912UL7lFG(E&tD`t;i5W1vREJ2}MHGjYW%I z58}>!5bl@)uhV4dgJfT0SQ!$Dtz#Pf6tPiMslnKnexY|RfHKhv-W#F* zQlJ};l0mVeNi+!Mneo4M*VE!ZVazD}SL#TjJ(24_k74=`XeR*<^7g<@Y`{F6YFsZ=Vg7yExn}K%V>8820$yHguKm@*IaT zb6TUw;@}=rQb9N@RCedsl@1PLCd=Ri9Ek^Y2V2t5a@5g~Jtk5XS~6q!e@G1bpD|`M zHyeIFJp5O{Sgxn20hjI)DjNaGkiB;!!^2XN8|C?BpD7;FZ%@q*JTqzdm@Kzq^3NDn zYiH%&|JE4xe}ysA*-6FKE!R;wbk@`VH-`O34Es-Yw7W6+(0%v+C5HWQuc5M`0mrV$ zL;$P0|1O68r#d>SSBJX93Kj04!{uA+u>LG69-WKS)vM>vV1-E;=Ax{GUl6uWiJTb8 z5TB%zjS{(iTGAuV2of-UtrOlmgAsDL?X`%vXgmdhDj_X)nPEd<(JV&og4-=qUN&@CG)FLkK!G!2M zYvvc$GX9nneLrJESJ8N`C$Rp`J`^k5(6zmD$dy<)r68^Bzh4>91Bxc~5Gpfu=1-4} zMZQQTLxMLG=tsPAUS@Wf-&ZnA`9UpumVE4b(ard~9)izG^E-&G{ujgB<4f#*yC{A} zk*kj30brvTQl->aSz-*i4SS5bHP%3|RL6RxrKL3-MA*)$f?4=IuQTakFykK0RWMUxM1Q0@^M_TOk@)JryRG)SE*5jE}pm$ z!F7plz2@^M(*gNyN73$9&QXpGw!inD*MuQLu_P(}!4(ePXoDsL9Os(5qA5DAH4A7L zUUf;76&X3#d~TQTGGP9rcJ=vmsHV^Gtqx7mHea}G%2vW<@NLZ~p@n4TGkk{wxL^DY zm&@T?6{OH#)NUYLQ!|vp;tz=|i6IoP*v5qv{lL|xy2e@1x*t8r7cJ4AK5KmW;$8bg zBImxbW_ojn?@7IRd%6>TzN##C;f7{WsiW=%#NAFeVm^Cc8-XLyC}Z9#7w_+gMkb8f z#@!+eFnogTZnmh;c&4Z3zcyP|?8yC^a&w>et%aurM~!AL_?+&3F3_ma>-zG-#!*z+ zuO?0LPp66&;``E!-;`K=nzO9l>}SNkdFE{N>(cP%mx|6eFMK}zy0W!7z{I{~(2VA< ziEItF8ozz@@YDPa<*lLa__wbMjeg&}y!Cak^X=PrpMKv7*y3y#LD(d&%5i*o_ z7Ok16|C2t(6LER_hj3R#vwY`be8Bbu9#`3_`z_0-aY5`48~HlV!>94=PJ_Wav!_I| zdZJ6moxS-$7*USMMID2PtdU1yf@1(wWejgmVxEHcV$Cw+xghF5AJ3UpZsx)a%AVQx z<^=%lcrj!1*uSq(&uJ4WO}Sl7;lpUxf?V)($)L-$m5hfB**B6wx#OX$deNo~Yxd%ilp z4%E}{DT}j*I`X-amA`79|J(EAJ$_eecCLpKZ$WqX<1sz*g{K#&b9cn=wiZD+eCG$7 z6MuI-n&rB?H(uey@A)NE5mOcmM@~PM7#pZ%Z=5}bCAiuDq2X$OisSFY6IFjZM~5so zeb}5^auoS6$b@0L*M0k&2OF-Pq$3svgE~jZ=?-(V6@ej#> zqu!K!l@<7+l<@zS0$nds)CR-Vil*xRZc#l=pFN z39~2yr1T=feSA|V?#Ix>xyyL$tUxJWpiVw~dm!Xiq2ec9aBASb{zfp8=$%#C_|?lx08PyX1GWD0_LI^T;S}2by<$`3vswL2YLAr%uU<=v#K z=tGWbD+G#}fNo0&VmvBrz~`M*z;&1VnH7q(BG8rwSP7#`!GOa>_w(dqlBo9)3Sj+f zE?i(QMq0UA`m(bJl^Z`nE*!r zK)+^$*%XFC7w^IyC;YpiBRmZ*&M3Mc^@ULqQ69K;f)w>f%E_UyFEqv8 zjR*5HDXmuEk3={Jj{tX7JjjeJSx-icr=)vudA6iv3PeD-;G?AE7%zj4mO%f(`xmX0 zMvHhpgr%YC5@&>!4*LSP@Zcv9GerP3WzqW6wDKYj)+jkEKh<*|0&?Jyp>%=*Pa<8w zN7pJe(Ag_wZ^D&zYQZ62!;QH4^$2%`^pdl*KZOrpe-3$3tURpePhi1xW&&2;>+PK(YZLq^KT)UPna=9J6g@(Cat4k3NSdP(NswK5*A0)j{Kd3d=8~*X(!7HI5LLH;ZgD=Kvk=zrQ6N#RU zbwP&$3Uciu6U)%qsMxT@C1(DEf9YDf#>u)=2&Yd%>xy8~+7IH^4q^_xgMC%N2p|(B z&O;&ck&-Xnzw;&>zZ$QixIB%1tm$*g&TnPzlh8FQHCy#~QD)FDc6XU0jX9;_i#*}p zOT$rhVnNZa>fnYxxRGG&{#3c?&~ghcP0ZSp$!`?3l!0s%su9nvF4c;6@Z~x8P7M5N z=R0zL|26Az?`glt?(lsPk#>CA$Q3b<#kfMe$N50{oEYU14{ohR9w#ji9(}#Uumx#m zzK7=iq-&HXO<;riNhGv^hmex0f5hd}o-rK_S&HNZNXl4X%Q4sAi`+DI->t#ov67@+QIBWqmJB0sr zs0JEU5Q@`Y*`IeA)j`nAJ{|}>Rd))uKk@W|>P;{N+TRSianI^LzmNf;QHcpCkW8G$ z%5oLq$?LzZl#84jNeTd;CJtiy1#*qMa{7?AnlK+hqwAQxkh)H!0(ck3tM$G55!^@6 zg-2SZ7&4;vx=(V%pI7Drb4Qs}g#t*4ZO~8n+-HYEi-0^@)yS(TM)07+vojKsceQ7w zS+}_MNCE2ISQ+2R?7!08nhj8y4b2xIvXmS)@kBl!t19ob+HbwgB4}Q|n*B!8p-W*+ z!y@3*>JTdRMB;^`rqopAONfWyinyR5@6p6dC_Tm=kpHRk)^87L z+}48ApF3LvJWqZHEbwAN0{%1$;CjGQ-QA(iC`nJg+uYaZDG>5<_C+4OyZa`q=IN$WSctgF1s5$vWv)l^=WRm)2 zBxL{P`;5@5l|343NBG!yEuIU^Tpjk^>qo=!bv$sMH1PH{G9Igi*)OVx(({%-{H*SP zGf9*GEk3bNzftw9?KMi+*dy*M33$KKNP(uA2j{Yq;?AlY3wYZ@k0Bc=NE^%+QX_QJ zlMXb>XzY2ArwMC(X&H2p3)Sq=5Q^uEhqW82uf5fYDd2m6pS`LcmY8y)h^+p+!AU=G zS^oz*3_#jwGA!{_;q;>@-oL5*eDYZuH?)Afln$;(p-C6+GZQm94r>bfflEA+>D-Sf z^xP*|p>_i?`vf)Vv8G4WrL5MfzvUEu#o**04fil<6&=WPz*n`{( zS|@UAoDHSmU3&YR_`g2TgR)#6A4XHc1-T@SmCJJfR=JCp>Mt^y3=KV;r4DeDsC8fQ ziBNt?JLzc7>j;2V9+ng1-b@s@zm{T_2J}E(_^ye(*J-p9xIzsqBVxo=~s=m*m zn?4O5-Npx;zD?RK@#h!JCBh_CBh_0J!I-5|d_|U}VRd;Dq_s2E4c0yit#5d7!!Y)m z{iyD|K8R~F2X;j2Ks9OVb=aQ6eiv^VTM-5*PIMj{vPQlr1omW4XCb#fpMr&lHdUb> zKPMWga5^ScgiSI$`bzVL0ZBTMc1kiIY^%4w1>pO z6BmwtfsvjZKayy5)vwD6p^s9(6a!v9HE>wLqXe@5aM+PD`-i6~jfSYw#N+(dqpy?LW2@KTuNVI?s? zc<@Xl12W^GEuMb#VD@hr!`|Z{MB08Fdf)a%j3vbPfb&DdBi`iUhhk| zAy)07vc8!8*zZJPWMhYh;Nh2GXFIK8C8)^!f_%HcI&8Z`R@Ww1R~~o zF>UqU?>O_`d{UQx$FB%a0rLlr0{WF-TH?LL@Aj8s`ILtSu=hqzNDAC^t{!=O=Q-8Z zkn6_y-;woQFW=Dp9%erb&j}vHMKH-zfhIM~1DzJ9G$$qWFTehA^n?2ulq3(>rFT@S z>u)4(odp@H>^Xe5cK-hE%Jiv;x4NhK8uNEo-#_h`9=<&o-FGDN2vcd^$K6GACG(n- zsyhF|4xjiP3Z}+n_vNqK#Lv1;jvkLC{ZdVKetK8kDJ`o>mb+`clU21jhI3>4FW+^e z>Ym=7(N*9-aSB|!B+1X~h0>eI+1)(*d7XZMG+HfmQ)fi%PZ1tfR%ftgMOO7bH1`zv zD({9&y8SiO8*XipaS+r7j0L^?=Wd*Ac<8xVX0f;7WS=8w$xnGLbh>!;W_6)UFSn2(mhe2mQRa6vWKS(PfgdNDiAeLiH!MWU#uGsDVd(CV>k84o1Pw(FHaM z*d97&h6KuyqDJ7N?_jEbn#d?t2-5TLYKwXp39||ayG=q2NGMJNswX|cnCPIe$V=ux z3dBs*{N;JRp%}4Sr8Gg!Dl38PSjf@Es}P$U%My^2K@r zDBtalaz2D2M_k++aa|7-?Zan#^Hq+ap`Oktwnvg(8T_?9czz6$&WIiyyzG_hdbZ9w zw(lsK$30~n;*k#87Xp?`p))N>kUAUa;>BlR9Lj;akb$YxyRu5f$&BNmGRb^=CqjyV zKO_+0C%~iwM`gi>o?3~mDe%PzR#QAQGWO-sB=mtRSas;RVj%n-3}%K}V&UZU?NK25 zxI-%L0K5t~z==uHTLsw6R5&&55Y4ap_4U&>2fmwO#;wr?_S_UQDASGNC`Hf26Yxdc z1Dgjtx#sCnhg^;`8@i3CO!suMb{Hgq^$&y;6x; z+$UN78k2_KQ(9@HjXxme%Gbm&N0hm7A{zI_Opit0F)7e;AHi0^gW0klJ#*Jk{qS$; zOrA2#2M_M&MSzkAcTX|kmI&L^42~D`Z?kazbbw$9K5+!S7#hFAA05BMFHfck9N@G@ zV;JY?Gkx)cEq)4|NdeDS)72Yw**n#qm7kD+zAMH_x)G99E`dh9Ej;nt*-pgoJ#9MWd|z>g0K%8tcLSjwlA z70p?PRm($*E<8pNv+^jR_wk@V1HP*H+&ujXXYO_7seC_;`^qu!PfsD%!6~V1zYbIJ z6oLCM_t6%mm-{XBD)e8X#~=N&1gmH-Vb@Lw%)MMcz<_e_ipnp4-`{u3<2eT;ncgQ^ zHp}2wE)%?5wkM!WIJ0bjb(!dJnfO*2UgXt5>+lz2bl* z&nTD6UM`no2mAvhsZ?FAGF+~+)-zfY*ANuP;=;HXMF!y!Dz??bGeS zKR|k88Suucl;67gjm0oX_2ILvesiT1yjl%9#JmwUeT(vZYm>?EHvCp<@vYrQ@TLLZ z-2jYZCU`#v^vQgS>3MgDw<0PJgCbT$T&@Vu#C)Y!#8y|t4_72^RXh->jEkwD1yrDj zmC2mu=y2u3Ta{^0$3-x$hO#aSL1TS-c<6d>>Y}-Y;MNuoCcLJQu1 z;O_AcfGCq)3PNp}JnGDyUmtjDK44-$;A}teonXQPnF698_8QjlxYcoYFvUcf``kWA z%-0D$WAZ!T*2dniGU`u^)FWfTV>CtD>QR(>nURL$+YQo& zIE}1^6^{?P&l*%}8dpdSJf4l3Ss>A^@uFd)dThh#K+qFjo+GP>Cq-Q*b9bYs3*KC9XIS);~@W`ugP8=CKkEr%}vQdR2t-CFVN zXRVSob#aERU`K1XXg$`ml~B`~a-uCMt1WB3H95BRZ)sc9NL!*xdrnOoJ+@9*y+y39 zU2wepDA&iMqAlVFKJqzy#8W=vazE~=`-mC;D9Y8rd!VDdru}smf1_J-Wnjn4j*fw? zj&9LUy(*vjPF#p0eHzUA^tI;G$jGN}+n>fnJAbHjPTF=(1$Kr+bqaobKWF%IgJ7=yT1(&q{IrkkQZWdp{FZ`?T!(%v*69xBD*C_Q4Kx>woGaiS=Jp?KijUw+!mH z&hEcd+iyGCe`TlNUhK;?qjDA*w^#Lx%TBj*_7}P7_a>jd9A5w8G3u$QIH2a!?Txv2 zH+z78y)$t1ONiaQTVjKUt-gc>4Mt`UMrW7#)(*z+3?_aOIw&^8CqI;u?GX?(l=0~` zwRUK0st?*Tn6q=|k?Pl{L0^mFz`X3QGZDBapT08U%1gzDUvui=LBkb6h1G8!}Y2ojdml=K_ji%Bki>#9it=@-iqodWsUu(5S*rTID z<^yA5)WKto~tTmeVeb%?H~P?IEnp(`JNc|Z6)Y?vh&bJ?f1TE>~^-n^|)TP z>R9{qcPLhOEoclC@5S?e>`BiUc6W?VZCvomI7#*Uo}6(_t8e?`C569@jTN{eKJ9g7+B?Tf&kpIMCgA^mnxKwj&rhF7str0dLsgrOV87?1 z39_vYJd*^6KA7Un8DXFrI~)y2`pK>D z02_E34E(+xBC!$j5(vGzL3Q7tC2T}cGkf`&^E=*hjKF z(mt1x#cHxyRmXtm^w^m*-0a71^LG{x4Ap-4j{|^9@Ky1H2zOFN9FZupCM<>(bb4&q#fC5fF zy%6)NKNXilaYYv?1MCaS4gy61PkbtfoO#$$E<`Q}GR8iG%-NBh32{`wmEi~q(L{q( zv4fyqx`JmhNCt9js)DY$nGn2Memi zF(Df=!=H%G*>j+D@FA%LgGm$jP!e(cqcx3gXApggR3Qn_7 zMf7qY-VS7lEpyG~b;d9Hly4k91|3{nCdC*CLz$8s4e)3X4T!)-2x@@GSHaqQygu-S=f@WEg zpt$I%>AzboBO9XEy25P6zV#B4JD0ce_~TEjg6GJFd{$3w#}l&Wamgtx$XsK|#0O5I z?1(Z-kgKvbwS-Ezl2G6RRv=Mj4gZ)spJJAcpsN%hN0EmZpFDSh(AK?o1rJI`?B9YV z>F&l4(m(+Mf%|v7ty-)Xsnyy2haPqcE2ztecB0q!wCnNy@v3Acs45gS9SF3z6GE!9 zza3Hq6mmrrszwDm!=k9w4pQ78NTR@tCu9^hn-Sz+R12Tv+~E$kBv5T}Iaa+45`|lh z4OFRWNq`nRls(5q>>Axbt( z#~U>v#B~U%*;cyrjZdK`TOdmYbj$*sVf>~hD2mexZDS7J!LVYsvm(&;b0?&TC1&W^ zO3ez0w8w}sF+cMOUp$16p>eG!Xmev0AH_mBijO!o!P*f|!Z7~PM}~RxO6KTzygEiK zKn*OU#pY z{ge@u?IPtXWmy^|%?FaE#3cJ>xl3M#uQeFSB@lbru1^lrm?sHlCXYEREH2ZT&xGbc ziWyC6Rx^>(|FUK_wb?tmZPT0I1ZOzKInMhCWMkw+XFAV?4|<$ao$rLFqud!!de##^ zBx$BS^|{aD#FC%?1ZY#}p`2s})Sw4NCPEduP^Dm#p$~;}k75 z8q|`!qaHLJNITkL4}09?9q(A_O7C$G1-v67R&7VdPWheRu;v|f^U&7j@zbXcq^v|m ztC((54|g!NChAa!KkNaNr`p3G?@-50B1b}o=+&-FK^BtzzgRe7+M?6RakF%x~ zCIxlu|3orJ!@5RJ0sR<=KN72eee9zjjYY^isES$4_H`cm(1)KCpbxYBG_#hm2WTTZ zTjM-cANJ^npQaIwV`zgQab;>j`~j9xKtvzmP(Uk~@iM`hawk@uhB?q-R;9KB9+87q zUXQ0q+Di1L-K~f{s9KOagw`PIkV6u5**Mj@r>Y3~sayx5iC0zisqbJ%i>8Y-$bxqv z-}SFUaAFU1Kx-gNfWi<4Qj2!@10B<4!9tK)5UZ|MxC(Gbg%Q$^>2Bdw*L_EDE9~Kd z)B~ynafduK9N>)fm&Ic_id_fdgeE9p6Q+>GBEpabFDL*VXAML!N^20yA|$TDD6fd* z|C^YzqGK9YP=JT^agV|hSOHyd0*?nmRX$!8s4uPvfWb^T*r8(^1v!Rgg`fao_^CbS zP=^ySn~mYDV<7er8?3au4g)7-2vDd7Itm--f#^U1Y(Q?6>1AhiMD8dq4lqy0j1lG7 zLmi#f@EuGsR0ZH79R6sp0s>LqQfOnkhc$>Jev#-3`{T@4$ifnApnz>urM)sB$eC5! zsz3w+5CgewQ@J~7VvB?~mJr64A8Zhss<+Jw$pS%W;E-u=cp%YMz!e;E=OGWo!)K1O zF1CH;C=!R4r?&C$0u1PrALh(MpZzZ zi=hCKZ^KXV5On0=5!VU}ognI^^+1q-kYw+dAV^ohR116IClACK3c&V2YD^F^5X2H- zm$*Uv(T|!BTj@h9HCf<0{$NJ^K59Fsz1vNrcdt0_5|F<4M@vty3 z%kP2^;kQffM{a{bhksSD2N;spa%s!Lb@S- z2RhVU`@rMg$7a85EdgXz^#)@f2>F5WUmNFjbo=WH00(|>hj<9C*IEcMFbFSzzk`?t zT1y9XSS9vLj0uxKb1SS+BLryillwzDS;#%FGl*@7hJv`iY8i+mQvg|jg3kLivmyxH zQauIWh3#X!sXH?kV1xaFx6o055llOKh`6T&JB zzZ*D+v73f)U@CsI1cD&Gl`}X6fC9(6Fa=;fQ)sVhyECM^zTcXzqKm)gLkKpgI0aa< zWb+5c@;f2qL>OD3fd~TyZ~`aju`OFMOMt?MD=vtzgf(EpA!7rAn7#^IKy~;BT7Wl$ zAcRCCAu{N(G0;1A0IN<^0NU%soA3vHXvBw0HXn zzIdnyZM2HdQh?wJhiNpcBCE!M0LM2RI_r~%dVoV>Btl|zrS>wj3q!}GBOnutzy10T zKY6-98pp7+Izk$+>9Q>FsRy}gEOgK-SlO?8i#K$8F{YzO|M;qjz3Yd#%Bsp5$H)mT zb=V69FtK{LE^~XT3=0ebDJwyfD}Q(pfv_v38oYt3qQbf^dpN2W?2ebA$N=LsVvI*~ zd$ijtte<)iI)p91LQ0JbG2DX{b}F$9t1!^2Nzluj0>nM0x`&%szl&@?bgTz-C`s76 zuQ!~B%&9CtDL@mWn+v?RqpC8a62tX?ss*Y`S2759fX8{Tw8%Nj*aOSKv_KyN3bHz? z31h0vK`o`UJ+RtJrrODm9Eh=;Ox<9O_|k{7yfeen2X}BtzhtUltFXTO$}uxWdb|lS z{HfL)Mu>Pczk1AraLtAIsmXG>Vav;l#D{4T%GexA|A`3BrP#y@JWawx&f)-{)J)Fi z%n#;t&ghiR>D;D?qR#7Vi`~S|?c~nx1f}Ej&hUH*G7-=6R15Gl&-5&b>Qm451eTz5 z&-g?MoRZJ_w9oqt6Zpi>{p8R7R15v|&j1zB0d0xyBhUk_hpwNMe^2SmD13Y8iS-OvX`&kvQ)dGJsXMbMu#(G*qD?L>+hTG9TT2Y#5R7ZuQU zqR|`0QS;Q!9Ocm-_0b=Fv41HD-yqT!D$*l0(j-OFB~{WUWzr{g(kO+}DV5SHrP3?4 z(k#W&E!EO4<jVl4(I_4#37EnK_zW1h%b{5 z7Rn>@$kyRWh(uwdhDaW(IEZp!hjfTmO9@wueH3vqhwAy1__!eu;)(q^qs92wn8}X7 z;EQnu3JGW;kr9hL;f;TYj9~GWgE`g2*bl1R6v#M=nChEqWvFtPhpWhnn-HF@xQl~W z9io`mjCm=mAqKaxm(f620UHPnK-Y6H5)*VN@+pXH=pK$8T7^)KYLJeiU>DP9R-Mg{ zaY&s05gyQSh^!(A?eV807$DYpSp|TF^bs)o;3FMb2rgKih%gZ*-~vdH6+o(uuO)_1 zkRZo(6hUwjqBvN@$RANTh?Nxz|NFRF6sigYIwOKu27>6DTrGo*?W?9O2zKDXg{Xuh z7>L1GTZ2ek*h~m6FoS165eX=SatKk{)eKEh1@v(RY{)7h-3oGm6|flCf*=L~LEaE5 zpD{Y8QsIX$Lkz2t&~$KFUDA|9Acat{9|a(W2#nu@_y-fgkPa#c?==Wl@RTS48-gf- zyr_!AWsSxq-xbjZcV&q2k_!@k0fHdm-WB1YB3@5Hgn=M5pD_dCrMbMtg8Yf!SpWwS zE{NF3s$nP`b)YJ+sEtMwynfN$}$j1*plVv#GJ*|m@H5Ux> z+=D=oZ@?&$$l}o86oU9v|Anwzp1=oG%Os#k9&aFCP{4wGLI^hz9j_1yWBH)F#Z2MJ zjf=J7;s7Lr@R<*KgW3=cVjv+^kXQwfkcC)a1xRBBcmv}xT-InHPAeP&q9Mhwiw3q2 z7p)h-Re-BqIG-5bK{gIc!HUJvjl7}X;Q)=(O^g|xWP-p3)R~CFF^Ahli2lin%7I5?hEe1{ooT#Mue32wDa?HghfFL*)@n{;D@SshWI51vG5!P zAR?$S2#VQ*7Ah4Jp%Q@Z4}lEy{Jh!>a{E+7SQXc68SjC@6i0Qe1eorix= zmJ&drv8axQkPkCj2tYy~Ym{g~0iJ{)AF!B{e<2Ew*6J6@RqfH(=bZ<|F%86^3v|sd zr1+A?NlOKIT4>N9k(m*cp`RGVhF&NPYBR02k2Q;=RtV-Qh&84k07(wz_y-apiFNr2LfImO zXa`OkrEV6Huo~lio{<(&j-5DLudwW#YSo$&h;(r8_coB^_|`HaiK$qmY|a=Q>9QR$ z+aN3m_r~nh01n0#2&xDo)9MN;k?OlX7@MsU#JMGX-HVh!-0q6=I!}mlrmgkX^M^>u7XAuMDO#s;AOU*VOdZe27i2&5!f+9fhw@=X8f4byDxl z%KBOlrt}s0sRbgmsDrCnhpVVd2wKN=TyKb6=k-`OvR>!)g#h+oSBN;Hb#yofbwCHu zgu@nhEJgn)kHoC@+B?-Et@yk4(yI1qM7e^yVn}`bo_R6&#m0z z_HmS~3OD0`>B+8cPC_Z-SFA`IDEsldrM4Yx$LDJe6m8 znSc42cX`H(d7HO+oX7c_Z+V*6`Iql`x$F6w4|KP0dlDcBu^$Mr_j<7>ffY!5v{!qzR{*w$`?r^Sw14}yUwgMN zd$(Wvy1)CrxBIcz`?=@)z^D7OF9;Gqfjc{gcA$rL5KNtt%GuI5cZl^daDo|7fEh4? z82|zw*nA+E0U6+d&)0m;9|#~oeFaE;)CU69XZ_ZH{nvN>)sOw!w|&@8{nMxY|J}F! z*(V6rcm3a={o5aX)Sm$!;DLf5glza_#$rdu+W3}QseYhFBQOF5z_m?+0_{78&q`sZ zcM+#D2p>=Y9KeA@x_&Y&hkbZr@HdkM#QYxsB^5~gfna|XbALzqH(tU76axr!3I-A^ zXz(DygbEijZ0PVI#E23nQmkn4BF2mwH*)Ogap60IGd_|mY0}}0kptH$a5rz>$(S-{ z(yVFoCeEBXCGIQuV<*s{F$$`47xXC7q)L}EZF*Cn0+vpvepG>iAWL^4sdDY=^()x0 z8IAT-phCe^B=@HT!P(R=r)AsdHd~G0He&V!6pM(h3TEFwjWY5pfv` z&F!GT3@t8{S#9<~l;c6kF*)B!+j%okfHYcpC6*;^6&_l)@nA#^|1Q+fg#tdfFpv?s z;gAMFHxlFm4@M@GWG{+D` zg9<8;R}ctcD6ow(3ZNh!LjMgUOAOm3G~z)v+^GN%feyq96oRIeTu0lz)l#Cl>bfgI ziz*PF3LskK!x9P{^Upy36g1Kg*zse~HazyVnGYk$x!6E8G|Qr&3Y~&Nkw(S!`yhukp%DBfJwCms_P-5ERZpzdWOCIFAsiKr#17O2Uo=jg-R;3P2&6 z5$o}A=B6sD2t|LZ4m?n~I@}P04k^_@P_zXhVFbq87SU=)|F>2-FU&D>2jfNQp`eK{ z3Mi|97zCxGfG~Hg&|EMBkw6d%H{2it3JEU(0*?wn-LDNlsI;TT*dB!HK+i7ALrMzk zID-x!u_iOxX}{(xM#4pxgAH@Ku**Nuy5Ov&C>%Y|5IgWNvO$X|pdmr%@WR7?X_zul ztPmE&2FC=cKsFBw(4v6X15KV#ksqb=vf81GewRRHP4wIkx8;BxvW}Rg!U`+IU`avP zq0=eJJjXu9LI11*NWur{LQoUfDTz=ZS}Opr6OJzbk*Ny2J395%%LU_E>Nb?ygK3;I z&>f#DFodvwE-z{D3gDqa`U;!^jXrjtsf^({kc>$Z|EwZZax?_3UQm%pEK^6mHlLDL(tuYJ_ z9fVker^=U*V;DhW3P4ul2=WLqw67!WDwG1~L5~L#v4}fi+eMCN5UczE2okFtpi+bm zNhu&lBP@s&azq1ykO?897y^-IaJ;^3CI%mwsG*wKkCd}KuF0|K=6U>2*hi6 z_*9x`WtM^rVhaUzhk@`*7s1d4?i8?u{~@%-fZa*RMkZw*!$h&{|T5*&bS21Y=E>kI;j9?YNz+(HPvaEH5RDqtEpR6suj z60LKT;~-Fa2rdWmyK7`K{}NRg5V*43$X+y6aWZ7RH#~9yQA__c~8OAW2KOZphT?G8G`5_ z2D>PT3mmGnUo0;dQ!|z$wB}3&=%XMjXn{c_(Wzg+!GsF4rsN8OjzI{aYll3@6~M?j zB-CI;nK|h#ZMBb|xwJ4XEi0m`r93cH|B(y?$(gAjSw)NvghFjxo-+(mi!5AWAbHhM z#CS9VeO*-na%d?!!r|6}IAI7dl*d54KoDIxqZTLt0tese5Y@D6dT9MDXb%F@VTnjo z1d$Xil#y3*3`7T&6G$WnA`CdJ;6K|yN4!YrLR2J3xoA*?9}Gz#ADk>6J`h5L?Cp7rgqI44 z;GTmB0e~qS2-Hkj&MPzlGf#32jD8N}e6a2CEQ zfE6Sr1RciLt>`Ye$e=|cM=qoza}8t%Ab?%OK(iwhpdd{<`Tz>plOrk*gvu!R4+jVG zfiTbD16Te@ax+vI0Nf8GdxzD+5uma{Qk@;9{22gMU z5s;9Qu%(FzGYD3jLA1{r#$a+K`sH)nl%{6s0Cp*n50V5c1N@|J&{9rxKBC2r<6sFQDR zhyX_B7%z3W(G6&E$)2?)Y-Rn7_N7T*E z6m(R{c}A?wl+?bIw97pyZ2y(yWJpA;*S+tDN~OzlS$4k@J~nsPi%X}=np_t?CiZN+ zP42!A6T(i=M#N>i|GpPZ$lHYOoPSDSE?23*I}lqedB^5IKNCNy9w(A_X#&-8w${(& z@w6w2J?!z0m#N?qT()ez~lDD-%IYbo-PFueO`LrjGl}o4(TbN_{T4a=dWK9 zdW2*hRCGd`oGsIzlfV4tKR^1@um1J3zx*a@vlA9OkQZs+BxkL^N$9~2b9_UloC7&v12hx_E64&X7z8UUjslnh z5E7vg4&gu~{~;0{;SxGw5kesoKA{puVHHlH6*l1&N+B0+p%-c)7(SsX{2(hVLoryx z1TLUD(4Y;r;Zl$wJgi$cTmv*TLkb>X9S#IEK*KW}U?1|K9|j^I4&omcq97U~As(V4 zCL$vuq9ZQiBQ_!=`r$M5U^7$$L1=>l7KJ<1g9%p8ORQVhxnY*PLoqC37L8$Kf+ zu|qki|KdQH!!VJfEd~)i)Wcc5qCSR2*FnQ9D4+s3V?Z8?5DAe#0%SsV1vDDO&wS%U z7Kl0mq(9yRaaH79tXuZU#Sn3%MT8l%QSSrCmM*UhZX3 z76f17rC$DJUOI$e4kkksCM`AuV)i9LEM{O9=3@#bVIpQ^{^evs=4DD|W?H6VQs!pz z|K(@yWo3dUPRJ!=GDSUvBttwPYqln9K7?z=CQTZIY`P|F*5+$E1a9W$YVPK2(xz|f zW^fAUZr)~bHiU2fWs6YZ(MA5CkZ+Mmd~=F1kh>CMbsPr#x0AI4A&XeW-_qD2R@zh?Xdco~VhY zD2lGAinb_=zNm}FD2&dijMgZL4g@)jLyqpKj`k>z{-}=zDUc4SkQOPC9;uNg|0$9# zsggD+lRl}FMk$m|sgRbXjb15@W+|4+Xpky^j*3G9E(AMZLoX0SGAIBx#NC!^DVx@4 zc)qDufI~K%X+a>%3n&CMT!THT#WSv(hr$Y!TLm29z=I5XiYN8VAVveU{ zcBW?@=A=?8W?Jf{E<~has%CO3Xd9;xgS09IOdKn>rfWtl<3VtzD;UHtrlkVV|E0RtYe&pO zIxJwHW+Op_DY??cvw)|)4y;Br>(6u}JNyiHdaIYFL%9+x#3qJG4g`E+s{&-hH<-h} zMl8pEhp7^TIs76vbYQGLY*O$8J_u~bu53ko;x87fTofNaG$qT{>_p&T4Dzd8(5ub% z>}3)Jx`GAI`Yh32=V?N$H!3AeByC3=?MalNsal^oLPYV+W(fvuMc_m6&4aBXNZfbF`XrAFNqRtW79u&e4mgY|vn)Y@*;u@*kS|7`UhgxApB1skqG@WY-C zgfp7$Cq^VZJf5n`@Bo+Y7DrC_y6y_IFl2zIKFlUQTmuak#5ly_U03Sq$ zI<5k`2ECfYltd`&hA1HWjMna)nl7jqABr7R13vugg$l4S6e~iK)iNN9_4)DlI&ts5 zf;kjl9rvyRm_a2x!?`-09VoyTZ~{S;0T*bmUpnKRYOsY81QQH!LL8(0Is~lJoiY4D zLeO0llz}NDL^be3Gaf|RovBn_vNynl8DIe-7sM^U|A8W44m?~k7hu5`2*M2iK|vw} zxwaFUo^p(+0**q&+04T^9D?pDW7&rs}y zE~wKM(^3CwS1W)xXmC(2|F1dkBpyeEz|I3dgaTI213@o@R3gMO z+$CGePKILVPbw;_$QRuI*Xh8fP;?An`zW!VnjH6E_blz%2a3x|P8)kn;&=j?+yq`!4gd6yIF|H*6Sp11mr|cwQW$EUcn%3>Nl$ z55yaAGp`0EPJ81#{6m5tL^syy2@iyAWA{P$veu4bB&T5ZQPMH~!8r$h1*|HD5Rcl9F69z1gK8S-oct>nVPX}k1K8@OyB zDbyL9#>U^dZ+Cs_|yD+-WQ1 z!2`m^pe%;90(b*AfAI*DRTSJp@p0!{4}?A+u~MJuWdk~#A4El$L-C#P_aKX*OXNVL zz#jafi(^iRPXs^A0swe$R4c^#qPPM?0XF=DH)3uhU9 zaGb7#EUC{gnuM?Cj`g$^FdA@7O*Zh)bT*{qJ>^|nO3yLAK*ZM<&qyH zKMc3n!n6Vyf&!2N*ed`QMCjZa_CPdnC3|__aeCj)q=*lM9h3nUfOC!)gfB0|Etk6C zF0>Szxk2>8&rI}kg7`6#|H4Ass$ehl+F!nFh`bWRXB0p_LYTf1(`H0adNy#g$eaE( zoH#-ZH+=du-$KJYW5FSev*%&KGTS3QxV-z~^*|f}ES$TQ8wLqNaW6RZysE;Ok0U>j zH9>d++$(?p+ixA8qSrKVFEs1A6+%<~YOEIDPU}6HD?o&zB)Q^4A07fX7Xm5B?hRAA z0`vkW2m&%=T;a++K(tdZaNsn z58Ogx3TCMy2QT8eiUt)tBY1J)p@l3lF7&7XUrwJtfd&;ilxR_-N0BBC+EZy$r%$0q zm1=ZeRf#hR&eLeM|0h2MFbDD*$quGVf*QZV^U8A`J9q~9r8A56YFd162llMWG-FPD zaQT^2fNh*tt?=IB!{_y%Uz99zG-#P>MZ}VIcmGOod)9?_E4uxj%TU7&IqcBG51FIu!1cZ&@iM+%n&+;9)(a2866b?S zBMK2j5vUe1|6-5D1JU~p$E@_?DZspd6D>%fAhb%v>t>72vLc_n?!p#HjIb>gD^qbV z5V`DZP3IlrkeVVYH7R-RLT^&!Cdb54@Y~ z)H6mpr>t_m0?DFL%R0x5R8pmso7B=vIV^KdOgZgz&LS7}RMb%`!lzPFQB76VRatG- zRZ`J>Rn}Q)t<~0BX;lo@U3u-**I$7RR@h;QE!Nm$g&GOjWtnZ(*=Lc9720VvbkbT) zZ@ku8qO{#ssBWF)7FTF(DyTNjX${cbL?pf%ed&P&GY7{7m=%NrB=$y@JUK&|b zrA`;7ao{3|pRKFb`YU$2$;&OyqVC%4vqeSv9eeI++wHg8mb&eB?umIJd+@eL0ld-f z+iy$fK{`~a1!hv5zY$Md@l^2%ZSlt;k33Ar+m+n%%Q4Sf^UXO2G3LYD>|FHGH@DkR z(os)6^U76k-F2y(eqHw2&o-I%+i_Re_S|{z-S^*t5B@pUg)iQCT!}wk`L0E}55qx| z|L==XR-<3u`l=0zh%BfpV$HgLg2srcQ-f-7_wypUUj5+Z-1?kz`1waU9nC^|8GgtQ zDw%OU9u#N${QU;G$ED=K);7ttT3ty}dej&&(P9vgT7$YJYNudIUaS#Q#A}CDY{{nsZ zq6#K7Q6h&6g#s=qj{Y@8j&$@SuW)w4;ZWy?ZBb*a1QP|HyvZi|Nm@=c61GpyQgY`= zjd(axkse~?hp-sPB*Ov}>QIp&c2K1P%tDY}3}t1YtT25XBzDnMDZ>m`sAaBPZ81PVA_ePho-O1-D@4`RGFs zPM|9rw@9P{4ygct?#Y%!8KD9m@`ha6K^^>1hbPwgnU)a8ar*S=ufU>3vDD`$jTnbL z2hzt9c10oyRe%;D!VZ#R1PjX;$P+J9kv%+ZA*ujHMJf@QPJWcA`_#xd|H`n=bhHI6 zWbp|;Iia_g`s5s4OhF|y>C~a5poiIbg92#H?3E|@NJrF+ z!ApV0iXD-eAn5F{PMoplO-%V|O1XHR$Si3^oP2C#ivm#Ca%hA&EyrDQxlVBOuW^DP zNITeJ4oNn`Zb+P9%u>)oSQ4bB3&Fw>y@8_X@Z+HSDa1g=I$ICrPrF=7K^Z&&3s`vK zJ_ebE0(ywSfp9`HCHw;;E1^n%&I5FSRKPU|(v8|Q^_2vXr%$#v|Bg!%#1#!h?NI5| zT?KpUKLmNf5uVGRMWS~h0O*T)k9kaU^u(nE385!q2B|~ZR4~R^EJprIkRyEI5ScBG zY!|%A1=Emkm}IZkoO&A54MZO^QtttI!VZ3v1F`s100y&}%gTMmAP?b*dIzE$@5wS0 zjFd=YXY3sAW;sI*@`_-{F2#qsqR&FzX;sq>!5>Y`s!7+;Ruh%eu(tK))_UvC|H*pR`joM*6Njc=d-T`9 z{@ZJfoor=CPL0cs9HtdqY-dlKXuDbVsHFzY>ZrQe)K=WEy&Z09A$!rvGWMUuoo=aB z;~EWKoawNw?tF6d8t?dK<)Lhr_{-ImaG2*4+%vcN z&2gS{o$s9Ixw~%9fgW_B51r^mH~P_$o^+)zo#{Q%S;)v=y+t#6&{ zUHAIeA;%Ydf}QM1*>Ty?o_5$0ob3e{O55Q+6u7tj|Lt=pICcf@6SpI!9<5Y+0mlXH zHI2)GffpCyOH^pVFZbtvcf3&e;rGXTGVs-_{NcgnCB+zc@}18K=RF^KuQWdNrI&o^ zJ%4)C{~ax)Up?y=qx#pUT{)niz2j|vd)@m^<~<8ggh);F+_R6E>G1Qd0N$7S)I3gd zT>S2ZM(0e@G#$>Q8Ct?O0*v}`1E%`8Fq2MS-v;u7011-uy z`tpx)iixsZ;j{uO(-gqBT!}+)DuxDxl7eCn|FY>RVr2pk1TE~~56+GtTJFZW=Uz%> zi*hOhS!GGE!7Q#}z#Y<79t&3LnA0+hiC#tpaFvRzdWZp;%|A6C04I8vUy;=^T24aMcU>Gi9cisaZVuvH1A%%oZ z2gh(Zx-fqE{kSHg}D;BxNC!}zV z0AwD-PXQu~BZg5Bks>0@01Lj5AdU$Z|CwS1*NfraWB7bR+D7pyl%=W6;lIufr^-J1_H>aqZ-QK5AaJPtZY$2NUp#_ z5THSx&JisNOW9#xaJk9KsPF zWNANciybbaB88$67h)L5YZhu!BgiYWy2u#uffM#BGM@ha72N@B;X>#x-a?vUw z0{uABBL_mxLT5>02F(WI7EYt_|4s!<7UCRwLJ$g)AgppYmc$dBPyu=jDAYkAfJh@` z;wwlY!UiIRPGgxMFd2?XE)Giq&Z{DxXb;~)Fnvfca&ahdh6yN30q;)%zA9|qN3UYT zzcAwBmTL4&qkxRR1u=#bKf7}f$GQu8b%WG@BLD|~AiBEw>Yb8`%WIFIKAAb}#%!$EeY zB4i3@jNv~~f;vS6MIZrd|MpCoB;y!Q=(#W``S@WRzN(|B0|uFE!Un<^u)qe%iXcub zm>^I^SZf{=}jh7a~4o`=%NqR%Pr<1tURn`(#Hd*lRaXFFXAFHT4)PVLL=&Qiyo;% zkx>=sX{IoOD(@>8|1km|6<~}CHM1TPlL$4K4C{^xf~B-ZmXblPYSU7Uv?4N<9cB|5 zPZAabZT{SYDJF?r2cj4A!g0EY69-}_#c+n^GAg1Y9_tT|EF+q-p%Ca1zbxZ8J=7o) zfe8>x&#>SYBI8c63trEMDWFgQA0mbJU>v}QAS8g1Itnf7N;cLaVif?Gv;-rn;Rt+- zA6%jw>=ni`l^{ZcT!G0n6(9=i;NmEYJEm0u{I0cf$jQV9A!;fzfD;A(HT@JomKw-1 zD2pys$t*mA32q@}uFETStYC#>A^2 zDI{)W&BCH5{~B=^45AxA0Sgq;K!jov!GUXFs@aZ!y*{ICu;d7(5t)<~|Mr!`D9m4< z7HaunG6zETu%ry=Q3JNtD}*rPY-ES%b&~8L!X#42v<4n9C^U&OiS|lu9q@!KtQ_2J zA)s(o-{Kqz!uqh`W)BreDsgWyf(s-M)GU(=n4p2AlOP5X7U?o-CF3Nb(JZ0>79)&3 zyr(DZl_35~c({>v@S(#LLYCe_M+R1CCn$V7!%PjLZD*oR3~Wj0RRJ2Pjef#LPNFKj zq7j}ULI*+}JygirS7ry}fEMV;LM=waA}t|d5BA`+M9_LKNpA_lV~^;F&e9uH@+z$C zg1L1d|0)5AH0c~33m(kEfJqcAR)lz{HFKd>hRoq23`4rUVjNtef|P|RU{XGV+|FX&;eVyIRZ!usTc`eeo{ z$U!jVWJb2;ibW(ftdkU#G$N_Ye1T(k@ID>;*nU99= zfo>R+o9O1=#z}APL2uZm9Rxy>^X8JJY9OR)lfj8G^}&;WOO!Qvl*Or=Dx$FjBI4Qx zZ|)712V#*4LLX>(lC?=4RJopb?33?7Z3n`V$4MYwxgzxDnu@ubX!(`fK^@e=ng#-w z|6%zt4se;VER;q0mpK`nR+%8;hK7#=-C)B+;&O=`H3AibJ=j4)1SQhq(lAGEo+GT zIU^obhBhMtz1i4aUasUN^;6e{8Y@Vc>c;sG4s4isP)oT08208F5Iu(@oJ)xokw zfUFr{Ao3co51_OWV6+_ouSa`YGh4GGtFZ5(D&7H15L*GjfFM?TAx?WB4j{B~dm$J= z3p61b{=pyoVW?eO(IBNC>e{yl!U1wy0T{r!fr7eYHMt?nDp2aPL)!sTJGCpK0xDp- zrJKB^8v#Olx*2;Qm;oK~=995oyST5ewSWQkdLVrJwDnuB38De^db-nly1}~v7$6Yh z`_8HYZ)&?DPJ6m{yRpHW0u*2aD8K<0K)MMW!0|h@5g-H(oXg%J#1)_)|LzR|9-y>U zJGvEs3>07!R$(AsJPjUzv3onU4?wq1{KIEV#0P>V7@)LE+q)l}Ad~?ed;$$BK(8Hu z!~5H)bsV;2yQm4`0`mH_gB-f^dKF{?9hf#OxSSxspuzL|#tGsV(BZ6+`^h6~6YgNO z_j<|KdmxNFHZ0pGoIwFZz`pTY0la%5&RVI}e3oRpnSDaTeL^<;fjWxYACzGe9N@m6 zThA3>5duB3HhBX~ytJpg0mwXfW8;6e<{v~|AGQG<7C{6QfYUquzQbV~>b%mai8zDd zxq*AMkKxWSqONtpi>yx{{vjAPfdU#p$Pu8^b73I*!9rnOpXwVU|5h7kieVw{S^?-c zeu^6%rr`lD0J0Y%&Ih6%-l4UZoq%51+fyCVdvYN>`~p(D0mwQ8wBQ#i`>3t&A68)l z?AyB;Ahj8r7RLRf!XXV7g3KEL0c4>r&{(w3y8@Oxv>!kVHi6zn9UYWG6H;5i`TgHL zN<@4+v>RXp(g4?qTmi^>!z+RTHedsO!PQ0mAFy2n@_g7+JGbA#AEaF4XUVsro3YVg z51X7I0Nl43n-78^)c=7NECJ>j8@w07y>Wh;nEtn8!^k6J8$=)k9-!lc9>7mq3(x=^ z(BT+H;p(%Vx))*_5L?`z-gKGe3-+F@*W0`+;>T7L`JB36{kwmh!Oe3t1joPx8{3nKA`-8s0 z`<~CIu0pTQ$`ye7(|sGzAl1!Zzpp?2d3(=AU>X2on*s&&1{yqwFrmVQ3>!Lp2r;6> zi4-eZyofQQ#*G|1di)47q{xvIg^8$u0KtI+3K}TT|ATI!ON9&+)MS7&r%nYb5%5%i zCY-^7B#Rn7iZrRxrA(VTeG1j+G!Y_vDqvX?p+AH^8C1Y&@WIsw7aAbg$spy*1~X$S zutzki+_`k?c8qH`uim|U5pHw)V5Y$ZyPO&P_s^gM1`TpHIG_^DqE%HNq|}+xfrG{h zHvLoguCM6Pq)VGVjXL$fdHN7GaA0#_13C=Tz&_}5k>Oyb7N^CjmgQyzfeeOLjXb&X z<;jx>ay$ zVAh)z4qE?*-C_4tXV4-cJb=?;SFtqE1q1b?|3E$UO-Lb9@KlIlh99A1lVbyY=g)tw zB^01R%4p(1R|BP|zy=0gs9}sU&PZd8BMG+O1smXE7=R@zz|VaE8WfBs2juiqT2`Sm zpp8yG31yTO&NI(D??BifPd;Il(stQk=MQ#F#w4Ty;WRUlSSzB}r2<>6CS{y*&PgX} zRw{tyK$jh$nM)4zw+S-_y@}8?zyPAa1-EI&;%y30$6lS1DktBhmNJJAIznB*AZ)%d zpqT@FXtGN+Tad*%L4*CS! zS+AOeZ#Ij&@bu2sRwM933^waV7ibflOM~9flzKB6ObPOlTDP5aUT*` zHC>l6>PVjDs&_M{wjy>B$`1ZuU99bRywvDE!F!u7e zn8C+~ras)2+N}BVT72hEeqp>EnUu@~27=6&QNG$O)Rme1rUjF$Z-%xHsnRCB{p)f@ z43pOCFB(@k{o0#5Jod&6{&(SiUa8WBxyJP~tBdoiUw_JT1J13+Ab}UPe^)UPLjT8wuAXRAUn8A>cgF2nyRHD7P~GAhXm!9GT_g$ z>b3AFYzUk&|Ax$L0(Dkhr~m~A`7?Fph)$7k(VS&+3m+9)LKGR6$pN{~Cp=tS7v@{I zyof~gayRj^5^C3|^T1G7A7V~}ssh?dFqO-5x9Ft-PWo!e2N8CM(FPQSDg#d+h~Xtj zVhxTsnSZIP-MeiS<5tAUyxszr@H*u1;O1iag6a=FN{kNDMzN7c!sV_HqoaRva%THH zlqon&1Q~F%3-kAh>P|)yGd|p)agEcD`ojWeEarb;GGv%5np(lKu3~DhY22NZQk!#2 znDy1L{?N^|#)kFV&(4M)pSY)W(b%ZC`wm-f)MwPN@Z5QSLz_@%lT~5GBT#OyZC#L* z(jbez`Q?W0Bt;zi9|W(8W(gA3jfnu4PjB3G=kW4#<@%$lE^DY>&-RTv@1Vg}`mj9F zk8LfN!mU)EcxXHv?!f^}RaYUa*AHVb3cnDtlOI3Ri{|{!L8UXGN|cot9$LE=AEaMDzjFoL^*s9N8Brw zk=uUcyqSQOPc736t9VrD@HpJ)ajDS*0sRAmA2qihSDATkKWcTDu9r})u+(vUR?B4E z456)deJrRl>o5}<6Ki~cW>ErwhfL-QYePpJls!ymd!cl$IxoOWG?lXfgv*cUuqrw3 z_S_+drdniAm74_leB)wIeOTi|OIl@Joq?Pky(nXEYw8G9h{*UK7PK431 zyH5V?Pv;~;o8C1FyGr@bhZfPbw7;ma_V!=+0X=PL{JdjV9{sHP(M%%+eonCZ5)#k8 za*s3SN4amYrrA_3ebx4rgYWn=v(pOtj=fj`|C!;%qZRtkaNkz z$^@d?nOfCfE&&%Zzwy&g8bBbCFs>@|vz7ENT~CpS+P38zgrz6hG&cCbCphWUlP?!n zbzUmk=AUiIKjbvB%5N->GBB(5OVjOHQ0-cV9!Yj7N<2*rjIoNu;s#W8-Br^r*EnHw zgEBUvsbr$-Jmhmj&pPTo4M(hnxFmG7-LjjzmVeG#_BHn=4U%u)9w47p!GMFFUkF9 zdv7;2N;>aa4a3+_#!Vkz_P5z;UHGTxHZ@*MV;miyz5B7))Et(!;}R|7^^2{!m62}$ zP33~cx><9(=dE7vVP>GJcg_rpSY7 zGDF=c8>LrhYR9_;*3RoI{#*+i1r0N3Cw6 zFE_=`b8q#@cIZi&OZA*Zt>3rd0MBYN<~_T9sf9O-N6qQK_S|dF`gX>SBUaz<82P13Mir3^8FFwb?gWJ3C;4jKhx5OR01Xbzg;&}0vChwn~h9m-qb@;9$SH`lcH-*}n*ZFU@X z!DUY~k@b3?P2uWTuJ-IV{^z&f_{NKaz$u$RB1xCdhsZzS_;+M>uWytgcV>{JxBwVm z5H;BK$HSm8kQ4pWKx9eK3SAH@IGAHV31@D|i3^122lL>Z*vo=TKuBSnLlarZP+zbZ z#{Q07NNIS86wY3BAmpoYh=QcOJYVQ%wa^E4js+2+&2*t!Eq1M&q3se#gEB`7^{`4C zIi|1Q@2EzSq-n#HP>hMJ0!cjb)uT+yP{kRFrKl*9?~#=#MQ=>h(sz8+2bAJR_2}zDn44F0yART_KU#z| z>dUNb1s@@*`tmDIrw$cERTMLv5jBd5fvCnzX2?#d$4+>~s$0d*p`;cDVrNfcnbu;L z)#KLf;xwpGn`Lo3196@f(R&OM2jKV@Z@mA`D(KtAxg3+%jH?5VobRb*>1RSo+WZ`N%MV$ z?wTjn6ej7v3aU6vVx~&$xS0(9YUfFnW-|I|vS+srv`}j%P5Xgc%3e~6 z;9xuo4MqV{_kzJ5RH=x&smyMv9EquEH-Z178To%p3qT)_WYPG)Y5{UIKK^$tfM^mh zFHw}VSezgVyQM}Wv^>~Q{%IrSt3b~RP|01LOrBvq1knH z=zaEGzKI69unD-R>Jnuel9(8z+)}sHBg6mx!NLbpXm0{nps-U*VIo_Sm_o0Nt6LwB zvUoJxJ6wM}ixik%^--w!Rzsp>d#+A)6O0|G!I!|Ha;!+(cyD;|xvMI6b)cW;mXFLC zW;T~fS6Su-Iw^=Z$MJW^l;r6FNd!H9*BtQa>@Q|2BvfAi)A=cOm5aWcGg3*Qm&+z$ z{L7cX0Um9V_x_|e5J~|2t+J(H{l?B<#km_a<`3CK?3TkA7Qc6!lImnE6SB6rA0foP zy!t#OQIg**1)4CgD4qH1rcHTgZCCv7RxN#ZzkR~+Dn=AaLQL^z6iMPrCzX#Rh14yP zM9Zu3TR*r*Lt`2_eM2?!F~YbUK%%3|zmY*l#1BuT%_8fEWcZ2`XS()jz+do%fX#>MlTd{vY)D>**A5p{qSKBi6c~%xdT7fh64t!iME)e3teR8>OF_8podovlL{^$o823Fs8IY{0Y-x3PCm--yaze#nE=OV-MRL!7j*Smg89CLFM;C^ zI=py#SOe51zPKp(jR=}|hbED|#BH6DBfQnEnnG|c9NN@q-~%zP;G$hsGH&&K0g?_< zQ@Civx2y#x5b-Ma1SjLcr|)SG-aB#C-;HB< zHK5XbgeD85N>{=U&Gc}(mx5H#`HCo9g1jrwO<~7Os#089EdSlWr=mYMK;I(uW(yFC z`2`GHNsYOgV^2ZiDBA+DK8ZL|_3xF5*D-|;f_}!yfef@sehoZ)4<~;O%7hxc>Pe70 zIZTisdi0LF2nlgEAUbv&;METr(3B4IL$W+#;^^83T%Z$BI|0dBy8N#gUg*Nq&? zkP{92&%+y7;4#>ch)aOM6RMQgrfbYWbFm1=E>5LOq-^+G&Nox;>hunsyofbzGInMY z!Jg219nm7{lWe-?oU{-t_X?1KfA(>=3XL3Og56;u6zHy4t^5@MdK{HVzH&by%Go~X z8vIbAARiAsW+Y)19p)A5qlycrA-bOpv>hL^VTVcG;fSL8%|L^Ww80q?HIA5w&bmg( zH0(q~M9nLWfm$AE+$jVn5;Z_XqnrUo;*RJch&&-Lb=jA_2T2EtF!IcKE(Hg{)hPpf z6OElh5Wi^DwM#ic*+~zckXVEOTdb?iZd8)yXR?ztiX+ygLJ(pMDZm5~xZ!gn4$*-y zvG1qKq=*~uElh~Si(eU*LyK-eFwtUjw;mZJJ|cq25n8xT%8hmaBeUMjX zzm%*1dT>$XRt3?K5b5^kbjN=bFehEC+V0$VFyu*lsAFcXW)UB=SLAVu%uH!`SeAkG%pMWb2newbjLI;BT!)?|9 zibd|}!tN=mu7umlsEI7+3afJB$wb#e&c%>UtyYNBTWvux-OY~qnn{@YtXJM&AS_r0W%~E>h=WkQ3ftoF+n5Z$(}25I+iV zeH%iD%4P0`l`D%?=_h_r!T@quW2kc8?ddDMvQXe#>g%Gl5I4#d+721$1UHBlly>qb zOrVkzf%!!jS;%aeVe8Mti6M&ML{f#lAE*PNLeTI`$KkE7v+shBjVjiN@8lyu<6~(8 z{j7AHMNbg-=vGrNoZ!_-+5F>d10}*|JKhTyi?|b7;~CL#s*Q`^X1)n8i2j57YYZDM zbGZyBXaRV252OAQ_m}RUr0mNzKD-`53o!O4t(~9+_)pBpEUV*u8u!8pW@LKSTWWge z6U^P8qxs~vw4bO?(f{!%w6xlWl%G%P6&zP*7wu@-f~Wa`gzUZ?hvh@{x!T2q#y7wA zP=n#XHQm$J@fXZ%d0f@A*xHaP;Zv{h_bF{41`&F;1p;1QUI?Z}bH*Q#&ZzG=8=3oyV~V zQ^22g-MQXd=wVyn4LqCr0{>eWc(wgf;ewVEf6yFwwV4;FysZHHv&nva+8=nx8%T_K zhkt@x-V8i=5&-54pv*uL@dc1E1X1_|;-3T^^#@)(3<6{Xt=|u#$`4xY4KwzCipHYh|DdR?`a4xE*PE>EF~EtG7ut!3Ar^JEC3D_wF?!ugG;D~ z9+!qJ_J?ZlQ9a-b)tiMIg2NtTLZNP9l9Hj^8DTH&0!{70bQr?9B*X3O!p|eZ2xk?} z1L3x1;rGE2j+k&aRHy=91fxL&Q&$9sWW=rI2sj6dUJ3OKjN-OHS%GgxsRsz)CsC*U zC={WcRWdTfE;0-i8KM3*XErhy7l~$wg1UhVo<^1UM3rSkRkTD^%|_MWqUso;>m{Q< zMZj_&M3aZYTAnJmwM2`kMs+a6bW6sxM!-7NV~A3~11&Kl>hyCnF%t~2hHh`aJ&m3A ziJi@eC3laW=ac?C8@t31C)^dgVkfn)ABV|^+m=)tYKcoXgdH!%W&Dl(V<&a=G#-}` zf8G**Sq8^W#7F&&2S`aCxyBQ>-Us<6Kw1+hGR1HS36zY9qfZmy{E2kFi42*EOs$D5 zbBSzci3r9dPN^hrlO!JBB)-UZ5XCrtei5O$qZimUtEJLM_5XDRxba3EuEh;_?$?_Bb}l`@K0Yv#gN8AK z{!v1xZw4weBdRqcW-cS{EF*z2Gf65l#UwNB>~*+r=C|ggthvld!}MIntTeH-f=CuQ zldQ7LEV1;fgi^Ml*Yvh9b_#J~FH zAQN+jT60FvawZtxqcc*znY{nioi(jN_dWCd&$;)Dl(r+hw_<%@)6PnE{8GP^HiLE1p;jaLYh3ba|PT6 z`6AnJQRzYnze35ZLg}_b+4(~G^Fl?YB4z2KUr!5F{fd^-3)KDKBdtZc=SAFI$vTi? zphc09U-46cRFfw0Jl{PR7ziKqUh$$U)>;ok@Y5QUL_d8gcB*f#AlYA17I#~NsWD_DbmnAz9Q?P z{20HY?4g^En&s&8T~8{4i*z`Y*O zbp7T)b%L%~9&)vWyjibsojI>$w0%M4T}B@YTb+-1&*Z+D<+|!xh>e0L(Y^_gcDvGt z01v?s1Ub-x)FI3L_qO~A8p=vVX_jD*!9J#bP)zRy@7LGo^{$1^!05Hgw;(sWCu&K$ z45!QO*gn8`x2N^ZXU_n{IgYhf)OmY^Zchp8^8lp6`TcotIN4+C%hf z)6PD)b=`r8P(nm%IQ+9QiuLBpc~jWOn7X?7au`$#&U8WJbOtT*HTok`J3eQI=}i?g zs7Y?Ak?{*S#agEL1(Y#0m(5oLyvujnn%^!o2V68G3C4Aqme6M{;r^}{el5W5{PK#% zDDu2J=PgOuxiH3xzamx7nEufM9qGxR-j?~V6Z58cpRSRu37j1RS z?e#M44bR$}{M!eE8dNkJ)VG^jF4{*k%9(>G-(^*_G1CrGEh*m0ZMiR!OR8$iH+Vc8b&%xRx?{O6vzxA~NUH(S{6L;XARcJ(`$IX>M!jK>N} zVmqrURAE?n2TRu%>btND!K__)=fHB+_D@|U+^62VLrWIqdd+PZ!Ye$X}j(s>%VTG1sBX?Ax^KSaP^WJC86J)%_rhXr=1R`ZEU zSH}#DPZ0h}t2;NOwN8?}8Vy)ZfYN#?uvhtOOprv7_Ug515r42IQtd6D)q*5glO{rC zKi$VMM{l4juFz1zWw~8WpTnmsO*E%L06YY6a^*n%H|}p36=sMo&l*o_H6Nbp2Gp_;HO;_ zwm%xh4fIKWz$`B{ES{@Q2h)~)f(s}P6X)v^Q@IG)b|0*2f6=Gvs{*`22x5wK1<^pC zk2hbK!>4{eyuYiFdJFEP_%){lpjGTgOa#tYZxCG8qpSnQ!^iu|`O9UfbgkiLC4iO* z31SXMm<6f7HvB8r3YbrRK#@Z=3hzdM#601fh=vJwqZX>K%t}U+<)b$Z$UGAq)w1Cs z=GKThL#njZRQN^ndm{{~Y-IbLiL4!KNkLG2`IlrVz!hSvIt_!?$21FSp3Hc04LDG|k^q=gan`xv4KgeiA|Q5%4<`U?Y>2t7W-U*3>_Ow}{`i*gLFJ zwDyAXXDnC9m(0V;9M-OIFuB)J+BH!xu@sXsDK}Vn`OH%FG`ZG`|>doqmMC z2;t{9MWQfai8r^yh87gAEcFMd_Jcyne3LAE28ve9m~+ZV7aW{}V@R#5)B z@O5lO=k225xLr>EUB;*#Ew8vGk^F(ZKLj8~BpAl;IM4>y0m-^enc!j^> z<20N1XWt6^y$U#l5B-HP?a9w$?|q5m%iH6SKVmEY!(zInHQ%NFB~crH@6xLjVc{{G|dM3_l_M016d>-nmt+$ey={?IG01z!D0X;inK+0Mr!#oCKJS z1E8I!Q0ys*(s7X9se~rZL;-H50QdL}2+f1T5I9+;6Q4V9dPO3F92bHF_@pJ2aq*;w<3~9PD~7><1w093uVjEYb^3kA}y>3TP7upWUG@?4z)+Fu(~6kA0M# z0E%G8W&SQOiU%Ysz>S8jNk34EwG%a!zNcrEf2ye7^*I4ZYi@)l)vj@7 zqYv6LN!>N;cz1P8%JLMuR7XMc{DpqyZ9~#kn$S*^c_EO5m=w$ zp5G+u(|tcFA!~Bxwg2mLAldjg*NHfDxalRL^9`Y zuKI`V*gg%7^5n~qx&6qv(1uXxZIx*o?u8~d)c|+Ig+G>h68b(YrI6L0r_IiIbppgn zdSvf#pNsf|QH8Y>(>Pw_R&1ZNqpWibnA=*&ZHdU5wQf=*zVZ6lqM@+(REIQRFgyn} zF!}YSraw2zNoNLh?^Va#wB&C5cV#dI)qaW7DqF<0zo8y;DV^L!NhnRrN1d=wkNreT zjk%Pn+XO^izO1)#p(G#59b>uw=CmnleADurv&HK^*#^=x z50xj|aw0wY#>L^e!XZDNP`GInI?K2*S-3-kAK_;LdP~1Q0?f&-U zcZ9;dFRSz&g^%^OBi^5F1-ievK6^{1kTRVz6=}t`fAKp8o}tK_9}@%%H7B_xsRS{e z2&V5f2NA4{P%pw+5Iczl_<^MI&9sS7UR4Xo;}&JQCW00q)PllVQiW-Hf}paufO@v5 zu$@dqD3H8@he@h((oLcs5;FU#Evh^claYF%uV{)T9|#yvMm_1}d`Xw_;5H{2+q2zQ z3=wY>@1_|@S&3UR{b*5>Xqt?53AJQd=S$lfos9D!S!F$Lc_@D}86QYug&>tuSEl=x z5TRg7I@s+ zeW%7fzS?7*^^{)AbUG=*uEF}YC%=kMihH`t?%JI&sSzqra>jG<^}DI9+7vv=nJ+vx z#6E&G?Tx3h8t{MD@0FJ8y!QIwCTIcdl;5LZmIC6TA3f}D6f#aysg0m%z7n(mOg+)BJ%Xu^ z?bIL4C&tCm1S9U*Yu=4|l-gvJFXUNH!pvlt1!^d|cZ*%y?OfsczELpz*k1pl+%TW+ zN7=&%4v$jXj7lVal!7Db9}DVt=~FLo21%U*=m#Zq~n~b_Fe3>4iR(Z7iiOyuzOCmB-yhacTdcy z7Ahw!Z#k;@sCw1cDeqd}Yd49xo%S*B#Vb9f9l`Oq=>`>{Vr#v2)9I$^#@aAvCu^B! z^V8E!&0n2gd$vDYJeh9(Li*Y@Oy>Ct-AqgWgV*ky#dvVJ#~(s8HUBx4%yEUciUA{mAou2?8nOzI7>itfW7n;dXAF!YXQh5weTj{Id3 zRWwffKf1qX0U7`#(HZdH?(a+9|I+=f6tI@@PNj6ba4?zAu;Te(eerNQ^#LEksG4o$ zzq!9Rb!czDg|KQiluZ`$SPP)2i2uFh3u|?*_)$rjX#UF~m3^l6c_5NitEp-(rJF?J zF<`CgS?3(iI-kJUA_X6G7v`TOAKwa! zyW^f-BwtAjTozY`S&0^@-*_A&K5fTkBeYn?6(PJ2o{y0S@vkMQ(%G*is`HeuC231+ zttIQL@vo;C8QZU?KD8-dPkZjQwVrMsPFV6;rP*&}+Le@VWH~i$ZDhOl@!R_Fj-CCG zm76awb-?ZpKF$pQX)?({0Q{JI6pw>NUbuh*4LXkQhiy@cvBOqzhE2s*Nsia{Rw+7M zV7sg+&0)K|tfXSQqN-_oyRxniFR)Y9Fzv8Y-Lg@!Q}gMhO(3@eB)F@Y0Cn6|!HN6r z)lu0PIvk<$X8nRXGo}d_s_6MztGw-ieM8b?_2)!|XS0XG)B$FEL*k@tSak;Z<>IJ*VRmw&ch z`&<4Zr`r7D@@U2de}&tu#a~~Z9uVF@3N(OBy%WfUMS``_K>C4BkTf<39)l+NEEXaZ znvdAf@0Us95wf!iVcD?jKS&FsB#lua>dIbn8wl$5E=n-jLz0pG@@in>(X$(@T>fw_ z4)e(gVcl)X|A1fWg1yODjgY38mg+TV2uvts*#fUny!i@!V^wIkitCpg>Vh&t44ypx z)F<`r5aebzNeIWz(^&t2zIoomatTmmtOs{{^y(8G4RAF$(e}AxRe%saVyT>g2aGE{ z9(5J3?p=b_rJ#Qzw>qioT#MD!1OR{_mNm%{s=<3h6-j}giWEoC8gDv#qEp2CIaMMx zf>QEXY>x_fUyu%|F|AR0sB%SjFjSgGeM1z<7Sj06Rmh*!r-FRf8K*c@7&&Xx*Pj*( zlivg=b`YiM?Q+W7WD0nxP9;_Mas&Eq0B#!*bFVA1-8cBruMa}z1T}=PF6x6GUs|&1 zsots@xQmCn$Xc>g$##>A%tZ$>9HBwN5t6zC-EP>w`OsKCRbGL~s7FTybfbJ~?Idxp zg^1Bet8Ov%yJK8AmMnexilVv8U9UZeS?ZZg#ZAC~#OqbYo1H~>t}S9L7`PaR%hV*$ z;P~5gy=4`DZ0=3qNbN4UnDLUmlE1Ov(PmuCONf4$ZLyI%mYDheukt&6{-5uhxtLV4niS$#H0Xznh8pG)o;dFkqF5)gIGroOO_>MxFItU@(ztr!{*b?im`ls z7d&b;a&4ebY%GZKWlj%z&Ah;pU2DOe<&dS|T{w_JI^K~F&9o}n?`q;X#FzUmVyzP- zuB%RADa*w?nd)4%WB_%2zREakZhyZwU+bj>JH}TJy;IZU3`jbLhv6e(ep>?6VQOj$vZ2bpS}R7f%FL zL;@K)0c3Vc)RPDl@aN&k<5osa54r*3c?v-(GE*XO!be4x3Amadnkee^4A;LM=8zz;B`xqwtl-V#ATmro;!<)^MSE00 zdbmx1^o&eltpMObV@1{YN|Bf^HX)dnV0(cR0hyL|bZfVP5ICrT?B;HgkQFs);$I@G zt8#LuC8ETQMx}}T%@Br#SqQcXD1o)TFP3c-DBqbCBn1(PRTx9{0mCmB`Q3Z`zeAt?EroFgQ(hJzt`QPBT3?ZF zg6A0WL&-K`gEu9W%tjcfmr{3^TL}00E*Q~}L*E5Mu*&@?;PjlK1;o^|_kM$zAC(Tm zq5Zfi}wf))L9u=7;eqddvhi3jS`RCmSTK6@GG|c zx%oT7-?ll;1W(gC{rh7@*f~AMu3h2!14I~MK9Pl|d7rL>GS}{5TvmK2lJaQNpQ~sr z^LC#E?l69C=K92t?8geDJ`q_cfC7o=<#fUW?(=paf@=Qai3>hZhQ4N>qAly35nF#} z?VU%&0qz3bPQZMvl$oHMRb*;1xDL79y-W#zm#1u>+-L6*{@U(|!>4H*PI_Q87WQG2 zu(^ZU*SXvC3WRSs+BFB+M)=tFBPr3O*{=FGB`I}Eogn6Kvw_~Pjh&s-kRSVkVtCw{ z5x_KkNaqs87=VHv=}d&Oa|8*v_XV*qycTJ(i?p#dN8dmqkjiAOJ07DDQPub4ikRjrDCb-`=ti+h;n>YN; zQ)eT)aJwhY^&7zgDA2o7e_=3+2?a>*3qtw0bPSdR7p~<<9>;mngl2K8fHqI3V-u!$~?*@DWB%`WVgjC9q zDlI6rjL_zrwuMilPD<_1N}|!~9;He4Q%@X9%OWk+k=3tYeq~XhE~hq02XJXr)snrZ zPjqe>;0G^Ui5I?K_po9mX3P#=`OxXwOThkvFMkHS?=;T7Oyh|T$@9IdI59Lx7 z#OTvvy$CLP@2|!Q^+^v&4P@KxxdB6ie0MX^Y=r)$YK=Hq%+x~cjO4NUO!uGLr zJWny?ztOFFvcQX>|9--z*+`(hX=YN(8QYkoC!2b0726pEm{6y`>QgoUAL({8$79-l^S#eT z`DX6hlda7>BuD^*4yAMWhi)q{1u+uan8E}#0ec%;T}^mcs;OT&fo_N3nQ1oL{H6Ob z4i&(H-2Z#J-QKC~B+zYLFP-D=hXJ0--TD!UovNC0wQZ=vq^7BLDO$dLL$=Vk(m87} zK=5_+a@>DGw;h)!I|p9?WJ1_Z5_%_W7nrvS+f8x*|D@X(7Kt2pt%Sa``sA@P7F(yo z|3|vrB~+o42_H?U(mNkbs`FO=ze~6Fi?8f&lHRRBuEyWb#Sn_(62&|%pp)#*CAOE|Ee{?~Qk-Dz^boq&P30N6M#p*wl(Y_qN>4j0ds zF{ZGQkvw+sTPABva^td4QEJ`wp$tZ;6DR;-+XRqFU7o_+Q$kobhuLvZQWyb3nek=4 z_pZAXz?%9*Yt%Hr4~emXB0=QjyXGV+>Sa`E3FH8g9!W_%1)m%kyAVYRIi5&`G{u5Y zT+R-~zX6xAz9ItL#9BZ`gA{O$6D-`9{Zzz?38E<>A+UyJk_VFU5Vb=TN&X7#LyJ6) z>aL!d&@v4rrwS8fGV(!a0TYqpgOE=a;Q}LhU}4FA0H6~AsNAK&LW_w#-MyqA@lgtH5&FC8jsS5LgoetxY0GFSlq)h(-}@f ziy(RgR3v`r(?u?hK>3O%u$;Rjs()7$mOF%jBtB+tny)Y(cxW>KJ8A2D ztRPn91CD%(L7V!D(k1rVd_#XwHMoaTn%Du8%N~Xvk#NFHDb^{)@||?bszQe%9&&ya zLLI-ROq_g3VfTDBX@k!u?-NSN($$p#>jUDCJdA%Dpu(~y(l13b#CylDFmn~rCsNS` zQQx?>JYRv{r7ScWAfQ( zGLXVFz+ob&Q}3T7q0uUvO;clcNh}M_BPB%E3;Mmy$wqb5WcOaLFN*|0EN{n~qY zVe$N=xs$TSHA3s>3e#!JfKH8j`tZ*U>C@JU*cy*gtzX-wr){&NHD1lbzxMr3+m|S7 zefqT)|74wh!syic5#k>wZKt2Hv9)hEwSJ$^pLXCzYXeS)e_x-UegQ!1kYw6RKxSMg zSoc5Bt!wW@K0rugi1k`TUGmO1IsaK=Jrda|G1t407!O>Ji~EYq;v|feWtE297pb~! z0E6|E`=7Q%0KX?%gbidMDA4M1#@f7rgkpDQ#6Udl5+E1>APO&Vji>!)rT+K~pc`JF z^r0$&muwqI;e#ZusRDpRmIlF+Vn8Tz9puxBN9dV}Dt%Wfy=T`t0u}j~NhnshSIRg> zYN43Qj0QaXz6HE7`6hv2x)m4n8#kFw=HH)KlVvU%r!aq0m{(;R+`u>xU6U*U_-ret z(mI)C_LpenCld60iO60=J@vpN=sr2qXu#r8^50z>5fV#UbMQwc#0y?wTc(+|0QU;! zPJjuY3ef^UG|xr2lq`p7xWeXRQ)BfmF#=7*p%^01SA{gs;2brbuFqLb*|%~rogzc1 zid-w9`Po$`Jp4Yk|9Wq4?$pD6jW|uQ95)FLva;odzm}h0){5MjfRysCwuZA!7qrdumzmv;5lcE?I${?TKiwhs+7iMzk zc(nqv%6Ur_-XDNXj&moMzsQkZVJVapNohnV-Kp)UW9YX25 zl$oQM1Y+oaj}(zH{@(5Tq%vFO5e!#ml)LViC`hz&Ed8ZZ?9!m39Sb0nU1C@ekyg0; z5c_;>ZiLJgxk7piW9(=_Tj^3Vr0|Lj1w!Q_My8Yh(7FS3BzrJ;^rZq@ewa%h>(xU4 z)Vc4t71_@&n)3;5swWhjbwthg9s5gpN>AYnYH;Q{qC#xI-H01x2pimnwN@!ld75=u znj0wJ6O1M`hf`wEWXGp~BzgyXxYt0xbxAt%ir2;)eS^M^sC2`wX7i2nCS2b*#B#&) zT{y3+?HjXA_;izPAsK&hnym(gPrb}TWR{P7mjCQNKXV;;Y>B@M4ZDKFk_*T{2C%fG zu$#u=ua#b__Hq8l;Uy6P@16i@i2psjWKsX0@$PUbo}E_A;pf1I!v7!d{x^n~|BHB+ zw5-A%e#zkbui>SYlcqeQMam-yb?a2}Z*Oj;-T2l+7+y*@TmL7+%l}op+xpLkm)BBy zyLNexz7gs6Tpz-|{3K5?+kNw2!%KQ2SUuzB1GoRR;pKmV zch49cr!;?1-~Dc+)#vs@l|SZqI!0%-QNJlb=X?LFbRBxx%M9V~KO9a~z5dJLrMx6( zc;Qh4a7p~O{%V}cZK<^wz1O~L>6W=?8_7?`S~t@DuUj#BF1mi3#UZcHw#o~0rFT-A zq5eA+?Plk@OG~#e_DlZi`eSl-*!&N^5aa!@9rSmk_Pb{~KK-eDh>yL$8e@n8u5x!6 zNRee)j!6-Za$V!r(p|34Fr~HE=ex}Z*B99SJNW;3c)4^%mn5;r_&*IVdDXihrr2PH z5j5!jKo`^x8-k$72R~HrzL}-3zoie5A&lYZ+OT0FG5Hj>>OD;J*l@{_e5m(858F95 zLXn~Xj*n39_C};k*wSHTC1ZB^Q5R<5$QW(ysZI zRK2z)c!zP=y#L+%h|D zi(S)A^Q+aapZn!7N;7Tq$2C5qm1d_yGacv0wMa^#7jqRz?@z~Oq4%nQ-}9mV;wK+m z!Xm7AwdRIQz3LOIoow#-&yBvCX3L>;wp9|GA9tVrnBv?obG{BGZBS`+wyw0AqhFZE zH+eSge5`h!<2Cs;oz{%SIy>1{E_jvourg;q)ZAQ$k&1h>ug^wE6>0t2%I#_U{&`=1 zEb+yz=}h|qX{}f5#jicDnNRDtTzn?m&5q+vKkd`jzMZ>RJaB7fA9WUb{5cG^zNkVp zf+giK54u50^YrG&PSqegb3xZT}C{UtXHh6 zTjLTlA=2YfPa+q!COv8y)Ms-~EUsD$Qau|op&N)#d~3x@&N!rN_9ubt(VEa&3;qVs zUQN1#a$~FQBrO(Qjol@3?qwa{`x3r0I=zefPrA5Y|i9f8D5uF#o;F>!jXW&e=vxW^Qt<@k6DYlLK`T6e1ZR zJ+Cz5*=R~MrLRaua+A1E(t>{3xKr-PVn28QNfvw7MG5)y(sNKn>9e+{MQKusgCbTwyCGlE5vRQU3wXDnIZb5B2PNy9bPND?uLX4 zFbqgfbG)GfUAZYdQPdv}i;H+>v$-u@Wv!Nve9ealBd$eEYhhxGY_Ed)*xF=rUf({X zHQpr7>}m@Fg!bXy?!GKdoBN%36g1%{vUnRzLsB2-(|={UHQO)lKhMryj$*6r>cPA-?g-;QrgX$?aoUQS2)k9c<&uiuu)6EZ%WGIOT zVkDfeePRol+t6*)eiOuA%?r2hqKKe`;w8>mMZ`Tq*Ze0$f+I471%haA`$>iS$&a8- zOCV+(SRxgz<9+xB;@x(^b1Xo94oNwK zrBJgAg#akW0hExsPz|3@AW@hmDpUs*YKWsSunW_F8urvD%w#s~8DE%1S(p)DxV3ut z(}6HOpKyCjsG6j|CYW+UpK?wF&i@^{A1t&1ct<|zO={r@Btj8$pn@4tA-ISLb$BQW z6<&sl#N$w5Pd(#jQArq7N*N$vz#F(sIZY-H0^dpc0iC%AUsZ&z)j`+vp>OS?ss^Ig zkx|u{e?ki7lF=Vd~KlqMK%;zVO9#@kLja0SNA|G9N!+V$}Jo=bHfe zQZ@fcJNV?&SW>sxZ|d-QyVw~_?Ce17?~K@0zPM!{hjmmOp$vESY3!0=EZ{iq?3I@f z#&orbem5chJR^R1-5ql14HK8YW8=jcD$l`fax?)2n><0JC||n1*hM=4=ajJK&{Zt# zG9ijeL;msMqkBEjH30My3mdS5ZXps$_-WZR#I{7BGg#O#fD$hP<&k=Jjjrch_n?ykaL z48mXDNZVOWwd7CRR!Ot9PumJfbDV=)oW)z0r-As>H+$0FXrynfrn$AkT{7YCw$lCQ z;1%I1n*2l%^HebnDDPmR>0vr}IRiwLnaG%d%uIW$kr^MEnQWh#KA7pcm6>@XD}OHS zy+&5CZ+fXox{ryxS9w->X1X7L7DXa-MI;qqo&hii>6j!}X()yIW> zTjxWp;Ky5=h*XUmIo-Y)>-stU<#l&b+4h{m-CIgvt#k`BkJ zS02K(c$>Ffjfrrr(GhPC( za~{>^DKhyuL>PG+hFj(9AtE*1QV;<2U!8sFp@)mM(G37V59Q%g?om4n^vDJ|OiYZ> zLsgy=a!)vYvqj68{h&LPj|1SJrlW1K)s-x?c`E-b>z^PqZGai|B;sDsTyhx8AR{>cHqtm`A9-cx~Oo4WUa8?|qQ49pJ;|3$y2AT{qI zHSWU6+fWVxwHS&Lyes6A+n~aktbUI}onTi?(U2S>GUv-X zEU{A9@wtF9CNrA&T-4^43>y3+;vIp)B(v{EW_hkxP zr$k(@Y5(GQ_OyuwsA+HJeJw^SGXzl6e9p*r5%F<~X|9WL2Ch#=p7+4Ayb>${ij z!<6x(8tw^(Q%_Hd2emFzT8Cb?j=XCf``gNpXnS?6?e&?qH^Z&2FRgwF9-1cbBbaUT zoWE_0678hU#3v>i3=;or?#;D#?ce{lvm`ox9_!dR(@{U5$2LJt92Gg$i)JzTL60N8 zJt6Jpi*6Iq+W^9^Cmp=G&5!=lF_N8v2Ax74o%>@tMTlV>+Y5ULu;43Q(PYLV=;EMwFLRO1)@WcI^M ztKuG;)*jor9=n|$f@H6QL9cbO;WV}QhYxxl-=1OLy-lEhUwruDcZHuvivPtv1gS45 zrtjiT#rd7SpyIyZxxP@3{s4pia~J!sWb|K??7uM5Kg;9?G&ZmQ)b?$xIx|#tp7W*Z zTgI+T zc7|xJLzl0&J@XiT9y8ojJlxVc+&VYhzB5dh9O*I`>G2rpiy0YEZM*#P*2vt**v<$; za`ctK=xdMBH!-6##iMUqN9X27=XXY#l4FYoW6K_6pJK*VipNIkLKTH{JI|QxJ7fZ~ zHMuv^Eb6DQJ~vpBqx)ya_!j}agL|@VzyNzPpf?!s5(c7;fqc(E?J_V@6M}{lLY@=* zZ%l}mOjwz@9uztw?x~b874d_Fl2^m55JC}z(1Rymsoo$Vdz?c)qSr`X+MM?ux}KBT z@40eIG-LafRthR`3BAWcn*>jSykF~jzTRP?cNi$SHg}TmOVEV#CIij>h+e^<`mx9s z3|W9ZbykYpLgniXMSj7*b`C~gG)Mm+x=4B+d44EzS10E!4f%k?OT>UALV+0Fpl2^9_I? z&h^&MmGaM()a_j5d`k5=06+GBN_n9-vBTo z6V8~W-vC^|!#|KvTMYEc-_Do)&jp#fg!H0Usk||m`ELFNiLr9<<~6W{$sF*RP-M1%Ega#&v|FI z&hqulMI?jyY4?-u*e9eqCV|t=w3l9SQU{ID_zn0cx3Id8{m~p6?*#%Axi=pi3rKGG zbgzMF6N}-UpBHAryIANLgTQ2^-`Xd;_&&3&}KX-jwE#F)2+6A~% zpkIitb$dF88YhQHyreAVcSFqh{4#IZ^0QcGaO}zn=_Tsu^h>}h)k*jHD7uIWxjeSm zE42ciSp0kvqj~(J-TZ1*>DQI_^Tpq1<1xs`ZEw7OIj`VQkJUePsJ;D_wOrc%DN+6H zr_se0=_Sip=10Si?lkxp2Kqbg1Ht#*9*zGc9UuZ&+1C!RYQTJwT39XlgtVIzCII=F zYh9UdB>>O~>OwB(`x3#_g)NNCrvcAXpmLZMBK?;f4gRpnX3O@|};ip*{cg z$G3T*P{bH{z2p!Rx57_HV2Q{Bvvd z%<@25{cieq!X zYGAa~JmM5^@dtp9!bCCQIdQO#dccWOK<0;e6n5t!_H`!!N>b;nu+XOM{FLu#fbp$T z5E;TRZB{^7FiGZ@I-V$Mzi5^&tai4iz<$Xh>)!~4pB4D)EQa|$*+n~?e}TBR)l>K= z6o!yiN*x?}U9PPoED2v$ohgB#RSa;A=LeHva7kPs3qPz9_c!mn1Bnz*hQa}mmk$~~ zYMaH^hmw+lzh2$)^nBaM3I5Pma_0A? zdF+p^Uk}#ucwljw-j|$Q`CLpo_naO^etFyR&`8P+6~P4hy2l9N*dy3yubtk-n!nQx zk0&Hj4l!*gt zS;_K9Vw#Am=WUGrFFIiLy93P56=~b#31m212rQ8Cs!tUPg8dejYR0=HLTZEUI>9f? zM=tsg6G0Q2&tE22KD9gcgG(r+rf+;6xSw%>YW&f}b-7aYrra3EWKpO%ppaLsH4Vsm zCVtBNoZVyX+oCU#$!J9$YxBD|wwn(c8J;rNadL90${d$}>5%gfx_CwrtcFkv;1LkQ zW4g)(9WCzl7q2R})}b&OwKeLBj@{*2b7p*y4;fGI>AUsno(X>O@p+ltU)}?^jYN>I zI}eIX;1tQyGhYDY=Vtw)0efx`WRU_yV-}`rs0bENF!M#8OXXj9_@}n*`I#hh+|)ic?azO!pRa_`g1OuAHz<2B{VG2 zV5(7Je_ts7cF(d-@r{6&!7n~MhcCt^9=KFR%(_4y{3s;qPb4z%JfeN>3sWb{#p(VM zJiLOZ9Q<9Hg-q0R*ZXBWQw7i5ZGWN3r`BWyGmLlXl1P4;8D}I zPC}31tdl6qv-^O#?$m3a^6XO&tYkT8>wCC(gbK(UUd&Te5VplkHs0nQ8VP{DQ`4M< zH{YWI)1vrZh4O$y5Pf+;qg)H^tU*_T zF&(q+6we30|=PHh~^ieEr~bh_x}(za~N>1cqvF$Jt{{`cWbVC`Rp?3 zK?DSOv%q`IvDr4D{HOHqK$sEI_lb2_CiV(P0j?f?-qLf=tcd-}Pi-|y3#NTgw<;*$ z=#;)y>a3|)4Sr-_TGYu4a_iY`m5WCb#7?-q6)+L}l41z|ITE@5H5FNBX{d5!$VZ1* zd||}q;JW##i_yOhLkA!5ewz^%z=qr1H{cQq+q&bOriDZj;@}PIUh?awRSVCQ#DCrG zJGeg=SO~ZHxDtOWd+YUsii#A&@3M{NpDsA$4B6fz~5#wY0d^HadQKi2^f*G)~@6^AUYN(N`25pp~qv_o; zEJCt+MvkQo`E;g;|CbX2Hyv4eLSDa3NgN-A4VNge@WX3u7XoxHJh=MIRO;1h9`eru z3-3~7)=QyJ8qGfAx#!RA)4w4do7e32_KmX@-}^o}Gm@xvDLn1NU1iC0Ha-0gPk`92 zQmwJE)rwq+np@4%O_)hw=7v=z{D^XQ%c(w*v^ zjVkboYPme&=JV@tJXuatHZj>ZuUF;=q5m4hfcbt7LJvsG(Ms&xC*R)F8P641_-_*B zkNXJk-uApWr+EhSQcXZ=uQ>jLJvzb>r8h+AQ*mB+tW7HGJs+iMOkDF3ukgm)B&^d% zx=_~v+{WR(Ia!iqTkA}>%*;)}qkfzh{C&ug!BYVvy0nAG))ZNfwix}C##aAk(Waiq zVon!@2>M!gnnw_T@Qd8g3;*;|zsDsBqvOcWj5N0TPwZn5LsR0o1Xv0o$~b1@Pdu7( zX)G!EohR3`E@yN)aow>Ov;vOmUH|py+NTTN8llqQ$B~b3x29gFW1j;e>PYt@2Q^DVo>)yRb8NUE6e#?&< zf2p?F$KSs2b0sk^0lNx_Ix2)^aY!PqOrCR=UBd05++X?vIwh({@pxFe%iN+!e^j4N z`+BCt+!8>B-Om#%K@Oi=K4^Ju$f^Bu{)@SfYwX{hQ^x3@Dm@bO1o~)Xdw9tqs)P|N zni2P%KUC=bils&i{A!SLY;0*P{JEEuTzLQAxyjfop|1_UTzU{a`?B*Y?M2BC^1+?? z>9bep$E4QJY3xi%eAwuJwEGF%d2OuU7-fv9l)MKsT#*utewBL`ScTqQweQ%TdRV$y z9@qBO>&K7T>C&ybJ2%!ML;k*><{bZh|MTvTYxlO3!5!>&qxK)yjjk`CIlo5ZVp(^7 z>~I?=e!qEeob@Q=`U*E&Kjqb?KN6PZ_bWjLq8Yb6)e*b(;=}Hbl(?ObMseHIAO7*U z>}__$Z6B-T@c%JNW_AD-=pb!6j~N~8NQXEY*(@plIt_r^!Y{mg=6eRtm+=t!ntt*$ zfX^}2_Z=OxOy_e12)xFVS#;jl+WRsdqAtSskKjcVItBfVh5X={#7==7ym+0l*qpJn zwy}(3s$?Bq!lM%_WRgfX7QJ``D`YHD+$m{ml8Eh6)`lb3I)xlf4#t?s=b0R;doGVO zQL8jjR_Hz?)Qw5(lB(3 zj1|mcFT61Id%@?}W7OJZs%>VTVP<7(W?g4y6JcsnY<9BM%x=WY*3az3j+xP14_?*W zVa@Ect+}IQ@6|KrE*H(O9P6<3c;V{Ui@s=PY1ZixWA55xZeL9Icx~>z*6aSv+zV+z zbTsinn)`e7S*Z4z7+9R&F%P_GL9n$r2R1ufY+>ALadFP#!j45^bvLTAFYvXwduwlq zpZOKDzKa+8FWL4-{4%?$ZE?+`Cn&@6x>?U@1Irs8mZZ7;uf_CaYMW)-4rXV-GqkPK z{RVHD4VpPx7iL&zsaoe058gJgF0QlAY_%>;w7!e9DawGORQnAahpO_9+>fxipZD-V z-caDaYB$x+nx3IEH-|_7fb1VI1i}3)s|w_jQ!XIb|3~;hpsXWZ^gjt7T;32-KcgMF z<2dv`=n+qU7KIcR_O4m~Lr(o$wsfNcDRi>JrsQAQQXbwqZ=Qe8mQtTS`B%0ycp&Z) zSC9DLv!yOR9kDn5?$?+dO;=jnL?|(j1Q`EOtD(_s{UafxcKa*3Fu~|n!p1Gs{#cXNY z*85cXW_|Z$jsH^kV6OsZ$TZgN_Xgi!Q~U8fe)LR2eY|X$yCK%9^L|qWS*lEY88={D z{(6Zl^*Z&9iK_r6hbD(G@HSs7Bk_v|oynU z(8?4G6`16?;5tGkYNl9h__cN2v5MK@kqlv*=(4jL?E=)&KgX17JP_q{YrH<4VlHXL zi_Ol8!#@_kV%4d|eAOjz{BbTqDFrly%i53dJ0V!@Yq~DhT_=D`$9Pir{}yg1UXj1L zQ;;IN9+u@lN6zoVS|0q9o#~C?i2x-`OJYRZ7aQpg+RRF%mk^NofH)SW1u!k z;I^e><;k{{$*B2qkwJF9RF-76G_Hoicn+%m(&|WK1;1;g|T+1}yYd?4bv6Ww&04Dw?R+XW7*{0xKy1 zO(CpvpUINUK=GW!8Z|2}v>a(4wI*U!25`v(@@cHd9~{eW^ydiqJaT1|rNs43tF*jD zYjNFYI|yml?l(%%LVJ%WT%a+w7y06v%tiU)liUjAZ*|kj*w)Tl;h}Pfc4mtH^X()J zq^~Fg8>G+7Muk(lMFTKqk`R;kWr7NnG>>GBjW0L74H9I=MJ;4)0DL~G-8UJS9sz?1 zFDKhP(H+boW$n;Z8><&0aZ&Myur^55&`wbf=3yrydgjQ^9T`qjpY#yxgGw!#w}C*? zC;+5KC^SmmFw+!)Y(pKY$wHOP9to8&{u?x&yIv+}rIp$^d#gjxBM-(nw~}rYCR%@5{jrgcNrUkdGgk zAoGoxqPItYdaZe*X8-~2<6N(F^iPOAW?7(s$?IF3(3agz28nJDrmFxXcNmHWBW0uv z73T0PyGx=$V3DZ41?gsLtL}B4jg2tHc+jDN>%c6n+^0ls1#@22H5=EtazVj?aP{en zP}MwOmv&{L?x{A4;7+ILpjEQwP*952&RyAU9Q*!ahL)SpS)sj`3l)JBSIq;#^ID&Ov#~ z%2pw$u+vQnQHiWEfNN#Sj#eC}$h_dNRMKIBb^~pAtdC*2C*=MK?}v+G!voD@k0-L^ zgQigNbE+jqvFDTjNwZs7zWSp{42-D9AVh=4*BAKR`YLTNsh=~>U(l&Q`Mv+9yVBdv zolgoy>{m%CH;$auiOn+=NYYJ^YS6UtvpX}v2b9s896}ja0>m}{d^Z^n%Zf9QN7$*S z>P|jZ6yQrNs5!f7l)v}I8^1gcsCdhek%_duEYB17n4%TT^!TSyJudAsVMI0oOH`wnZw1X~uwl?LmQ4;;eeOU}cTT44MRV$`cO&I?D=XrbA!1N*3mQYxaI5P$~rwd2od z=b_rE2xU&ei9rC#9C4U)YBa^#vI(Ok3H9u~jLMCa82u5dk!U^L~fu6%ROWw$#?`gw<& z6~7S*4DV`vW1(0~^fnc}gF)w|9lPm#`?X&WM>PLp-z@T@-~s($FPKbk`|fE7CO0S=K*bAIlqs<&&x{TXr^g-|q$e$Txe zwT75XO$g`j{DSY+lF+?UD= znn3T{u)5`lxk`jc)dECbqYTesc4_>GP>36*oI^$7wlnV2pl9e%1O~OuM0eIy^}1?C z&KAC7@%b{qXIbzfA|jdzIfH?Xl29*d045wNpc5e4Pvx7W@ei+}e$Wf^28;9Eb)f60 z@06Ns<$^upeXd6B3=aO>+U^Gt<;MV%Y60&EckdO}a0hvD&6+iXh5byp4g>Opid>-a z4`KN{0U-330t6id7C@!QioH}YZZxndi7#Ng>KzVYL<7%6m(LOq zkXqiRP~<77)+PgWnZsQV7MXRoWZ?j^hJt7T+=s5ieMr1xERlCKK3^K7p#|c`9b2*< zL$4z%Fb_tE_t&rmAWf(p7DmAG4l&RJ%jhmT%o7U(383DnAaf`Xw@}DQ8k9t#ek0zK zOh7F$AgWYe@2}{Vw6aN?`qWu)JgXWe%NK#?iN;k&10X&uc=6EXuQ<3f9r}=kuGL4s zYi>MAM1*0=cd*ZQhzK7Xya-UWLgQz%_!DUmKN{~tBElO7uE0JOdE6`{kDngmZWd4t z;mHQhnC^ytHB^A0K}diy1fUrdkK)qaCU|%krDceKIEH~P5gL4`fJq!e4Fm1s(D)zL zl<{ct$Jy}Rr+^a}Xcp;3Bn|R}h(O?>c7@MO0PXK+j~?Qn5kv%shW<@$6r8*xV*ex) z(VAKVknt-;fU7!b=v^F~=P`dT9;^*OzQdQi!|^}E^8FP@M$jNd1jGemv*qhT0|fP4 zEr1@1bi+ZXC@sAd$VDo$kx>m=Ko)TCn)J41JgO4_KSOU7E!4adT|NPTAVLu?D(Dto zbbXCkxH8yX6ElQ(_>#awpuc=0jt+WWjKIU}Fi<->=mCxY3j+;Anvsk#?{IKyDs2ph zaAv^+5LF_T$Sf@QEP)Dfhn;u`TP2_cwT*=<6i3oflN=1x1c&e*uKbB94pzk=ox1E6!262%RI#wL-2E?c472gIvXBD4OndZd8@-IzZ~0TdZ?Z7l>NyDq zCeZl$38-a8iR6t@o(1|}CR%W=bp;F4#=xK8P^W@t_0c%6Y|9WBD7wG| zyWubs49F1%*pPqxYYRV}3AQ8gP2x-7hj<%l_x&w37jvyrkq>(@P+jZ`9t8XXf#*B{ z`FO}gl`1UOR`|CFau$auq(jf(pheg#JjQp8NBT93bq(IW(L{l1C@wg5nI z_1wbd{r<4I{oMtnt(^~Pya_D$Lp)#Z(YpW@Lgjn)rGTr? zdlHHiIx+VIfV8}Dca!)+O0q6@70J`aA8f!c@x3xjzy9&D>J}_=hl>7<%aJ&YXJOFs zC+c^YrO(q)P#tvIMMC65-B;Vo=|d(gEIKHlDAIatVkUE866IueYT~{Fn}r&xK|>Wk z`MaRm*!p**1Y{g5dFX(Tf=(vRfNt=7q>7TWq6-V0L>$#(wS95PG?Q^u)@tEUx z=Q%d$KVr2be?*d>DT)~1+n6o1Y}RxqmzBB~WLPt|cuR_c?ygXqN3X3$rj>0_bWaYg zy8m4MNi2c!3KYa$hj)0gi3nJ>CB_zGx;`Gxuce3bif^84!PZx#Bi8)=M0Lv(}Px478v z4blZ*&2JUwSr5*$oOsRn##y0%*0C}_<&1tRc>O#O_fzTKPnC|Jsvmx;bAIAverf%q zNA&uo8~01^-mjw_zYIS7I(|?7o6v@d(T17VhDF?l)x8ayjt$!n8+M!xg3P9a(Wax< zrgPk;>%C3)j!lmbn`b$j65z;>_$WWGEt@-(z_=~{j;#xETjy_4toyev--`%A|F${u zJNVS^5SiamAzRTMzi*t{y43Oesth~K>vvEHJMP|AOb9z+oSh`YzBSHHH~Pan%g*Uw z-;w!q;}$#Z2fHxjcX}K<)o43kWBazu_C1Y1RpWo6;}Oqsn!qrGLXy-#s_EBE%kbnLBt*!!r#zH{pLJve^Di?bESVc+9ycW`z-Z~&U8 znE3w?KFBTu{fF?uf38Oq{$_9Bc>1$lso{-1u(;z2q1-%E+Pu(l)#3ihlH*C@PG1~r zo$Al_7CJqgxOV3M(IYkCKt|6BMV^4olGk;{*N*CP&@CGg8w6zg5| z?#+}kN|tncVjsnN?p#{@N5vqf@Nbvz9Xst~ugcU;FZYLB_%bHGkY*=RxN&~Gk#oKF zd8UYTM_k*DzkQ>ZB=xT#0;h}X1?QW>*4%xUcmLiCy3%jd{v5R(<^Q!=(Rb_YonKAo z2J=fSJJ#NQ4=c5byxx#|H72K6xOy=$(`)_aTEkt-A9pXZ{v4FbzEU(MHx^x?VE~iK zxNz5~U1^DrPfe94KVr|GnQ7Q??cvLUA^8+(0b{N%TEiouUl^gG+KsZx`IBOFOYdv4 z=tb48bCSNLk5jSm6a}rixQsH4kVC#-PQfDGo{7F#%JZ!_{FVOLvzuq1+Q%~*>Kf#t z-q!S>0$KW&oe_0CTJl$Bgp{(iYCBU8$5>4O1YNA`74wYFDs>m^W?Yz*Q@bgj%;9z2 z&?Eq3@*j8a3%5P?Z8*G3C|BF0Q&mtS`e^1MF?F!)Iq5^Q7ab)br~dNGL@~c)%Dlzw zJUGNCKf!W}iq73v=#g3U`H04go+-T-IKgT;uf4k)l9xRuNc*mQGR7QPx>ABNhA0rQ zZ;1C6$^}C*ePJ#al;tSh5f6&?tE(BCe>IDm$l09oJGF)s_leQues{{`17cwwkSoRh zr8Vj^7c&-qi^sB*8^n1#SRaYewM(Ci{bR%e#G?1=SMFWhI{B$M4zX^<<0Yi`;7J@! zbBRBUefMCI-~DG7Uy%A2QVat1^+SroOIMR_nvHz@eVS7z4m$ciwA974pw@oO|{|W`w{zIIpDvQoa9`k7lM`K%A;hu( z9vhHl+&OZoW@0$bMA`R}@6nVZzGL~TpZHa?QptRWlZ~&69-~#yA)N*$&b_!G4s6NR zfQuxGUbxr%QEaMR`sMW>$9ybX+yz`3<$^prO(8M5Jo0qU^PB^;MZ zR#8et2d*vf->&Xai(c6`!o^c zlJ}>XZh`0p$(U4A0mUdDZM|~fDfT0gr_4ktqCF}`8^I^KU}oNR1j*a9D8t4K7?rLk z*{m$d=ZKS54;@;Zyu1+~@)lt?_;-J64y(Cv3f7P6uj&4cND zf>GHSP9{L@pC|SAXeq!l0q$qz!$-zb z$p1sM2quBAtf|iH&xBjQobVyyvtVa4MR>v<^fIB=N@tCpDC-cI z>Y55#2d|`QF_a|yNj(dgJNypF$0q(n6U$_Qq%OCssR*3u7mqS)h<3U=89!>FfXi5A z2S{$6nYHk_mhJBB2uv(V(bv-)`RQOLGm9}(vj1wI2?rZAw;?VG)ZGr-$viftd`Dau zP<{l<5bbGVCACf5me&N9b`!hQHd4`-@r!WXk+)jlb?{VUoEIwxe7l0-sAHqbt1Wtct08+}4Rwy!PnR8aaR1p zMTH8m)pMi~9cX&!YNh{r>wxFNdF-pYsH*+;=J9&S%D?5K!ixCS%JiohN^rSItN=Bv zrS*$!TDt$Y&CxS^Ko7Tva*)~?{`jGVn`bgA4lkVU#oc48C?5>F{<&D1PZ+?f&alF+ ziZ*Co8kD#=(v_2*1(JWTJ0?hC*nexg1tn&SJBS?6Y3aF?qk~DmIYnH*!CWDR+V{l-72k7eP)J_(WxKrf$3 z*pjze_cJe=U!V{m6CvQM*G;g$lG%+m2;jI1{IlvMcO z**?A61;lTCTb(#|f~xXQNPD^RO088<=VqzcQD0+_A_LD0eiVPEXhZ^R?$KQOIA!SM zEnZ4Bv}f&FmIZ*x&r{fc;@od;%i4@VPWg13oWP3e^0JT;fwEntU@|NE5QUeq=Gqn>WZs{&^eV(y-u| z{KAz)ku~G%JJ%9Ma$>-CuJ?Nc0~7T#TCZ-&C(BIHZynUrjQew)EV|0c;c&o7c&u^m^APZ8N-6QkRY3smJY9IbMmUNJgN6xN z3dkn39N;uj^IgB*ny2qiczbKFTi7F7c)ogn6Gr<^_U(CUw_mo3mdD|yP_b(dvt1`p z?#)&4t|Eo22+)MQz)zFcFRQAJi|2{5HVS&Ujh@!(jMDXiICQ!`QQFjf%A9U?mo?NEM zWAj%yT##E|JWqw2VJ^`X9y#DQ*%*{zu; z*oh~c2uI!bPnG;M@1>8Vj$s6|3I^0xdw2#@b20|<9IZd5@^X2EJ3AIfZ1c09StXcR z-O^Smsy z_}gf?Z*y#1cpY&tO9vu($%-k=BvHwUnVX z+u@y&5uwrH#FSC+$#JujqmH8^swYQxMy72?CmcuLERVe28JW@^ooyW%P8^91wY`4S zmh%Wa+@)am0AL%9JrNNKgH*#}8L&7eY$b2Z_535vjN7m2V`~OSwDM5%tdv!T-P-cl zcjP!r^3(^FQ{N26zZx9*u>-q7O=)k19Z?@t+B@>eM6Vea|X`P8<)C9a}l0Q7f*xiWF z-+{U^`~?HG9sof^K?g<2(xJdZ^$rTmSF+WwWSOsU{HHY-%FNvqjitd_RgrIRv)=@cI)@~=UQ*+slTp~B&QVd|EB1n$-E{iZ7n)$YQ^KENVdULOP`hcT6{jC^bnjSpm z3wh%W;g!LW#qiTI%+$tR;N`}5-c#=P^mN*K=WdD4h3}q`Pdy{A1gbNSpD+hrmU=JF z1m42B2xH&Zj>5gwK=LGVtT{QhF*V$9x*dWjADx?T^W@080)^NB3<;!!2V!WB;pW`W zk#Lm4a}YolBPN{W0;?=w<@;3W0gyh0N0$zq9);II;@8cA8FY7H(GTcU;0ON?6<8OM z6|(URw>F7e*p;YAjTd79H6Y2s@MJujq^Jjtg(n{yaLg(I3c!1u37ZA60T%R zSFj<8i{#GvY{n~!CL(k}{lOnFd%ShGJx$=y2z<&sJ|&n6!B@YQWykx_T`ckOiUY}U zdQeL$ykCthtqy862U-%K5zHhh09ks^c897f5-Ypg>G8JhsBl!ckL(>Mj_@ zLNI}prufFikeShx7OVu7VZ^tW0OefCA$qfcO`!BBS7zI5VLc{t|I$flnqNu0C?Ju@ z#5mIvR0BZrQ|paR5NNyH7YUKY9VVrQByA8$fpbe;%xh(9}}Y#S2Bf}JBKg*uaDKS2atLEce59z>vml5>XM ztXFFC6==Nh%C!3oG=L463j{%2$$AzkjVj6fWl5TBU?;@;#ia{kL?1(v%W2mH=eBr` zBPDnZKj03FVx zs{5(-0B8gN+GkEyr+ju7g*4ccRA&vX7^$Ab>ZjlGzT367vAz4i3Ci3x!)z$XZ#U`oRN zK(aCA6J80DPJ5+8bPZ?%?N{ z2~tXh#*#it9heqhA!{=daH5xPG5K$@;zij2Awv9S75uVmO)wx?5kUUYmRhw3Gb947 zLzA!U5B3gCRH#l>?c=%DkbD~Z`?3b)WD{97H8M}vd3-lX@KKWUF3H6lcsdm755K(F zo}`mZ{>FYPjJ-5lkBzGOS9=spU+uHmK%M$Ilibfb17mbQI!^;@0#Qk1(pVo zZzx{N%Lmr|K%Ucso~9)EhC*XkV5cz&54?V{8sG-0@e;HjetVyNXOiRC5OM0|bS6Ze z+ZPIl>Duv#kT$QFdqb>1N=;-5XOa(KGM(ZVxdl2J2KB^2P8UG&ZxTfrAD&pAmmXO3 zr2KN^q?{Lp9K@4P1tiA}Y-+iXsLnt^?)sfq_A@C-_-f$tsH*M$1P5lOt>xCo_x_Mn z9+X((0TKuknDkc~f^j7uPMJPH^t3Mc{!J*wfu3;oxXa}DFBzpR9W2;`m>j}L_M$`Z zGi1-LMSD8rn` zR3d~XmETD`3_33tan7P&uh~LBtQ^ND;n7>Dc;e$g(yd~tt3TIPe;s5{O;QBaf;N<1 zRodLq3jVU8{JPrVfkS=Jrpkoqamq8-!%#+vnzP5wN+3Axwt~r%5z1rpdQiQ^Wrf+x z=T7D;9Elw$$ey;@r+^nqw|;33vEe{&lpw8-^;D4$m=vZuGG@|2@)latw8hAiIjSmp zpw6Ie?JuuuU7lY0wym=^W3H&;p}E9!>778f66^8eZv+G%dr0-{HGSTLN%X8rtfo9Zj@ctCjfYtLeL;;I6S~scCxJ>xeYG*1BX8dEs2NdMe z0gvC(OR*5jeX6novQChm){bxmR9+p8Z^EqdKP z#u?pk|5#B|+oJNYzC2aA+A6H&bzQ^T=tB+7Us?`5YTMpEMC(KxQ+?bkeqHs+pvp_t zr{5Ics5)!mkEu0I9WWn1_9p11+Kcz@I^zaE{NA08pFf(E3Hn~}QvD^pe6qpmOBatu z+h)Ud1E?iJsJP8KzJhcVk?~HW6B6P!e(Iz6S}w9e2{3kiRn2COa!!!%jk*LjsMqn1^>%;EjFV`CTV~>4ndRKbv$IHJB$5?GJ z&P!IS{Q9*<)`pYL?E zZ-0Bh;rgMTqB%Q1Uxpa%a(+*Dbo_p~^C|<>Vw@GO1c)xGkOm1@p&_IbKE?@shtt<@ zdRc{%_t#+|8r7Y=KC}dh5iHDTr4y5bNjxCAz-wOJC0I@)D_!i z*E3w1SRyUci$H#GezCI+sSE=BV`5aMth#-gZH&*p3MDfIlk7BOk8+_BB{Mafur$Zz zMd24Sy$3HpPIqaA?!TF8b}^zN`7;4#@F^ZG^(s4@;Y$U*GNy+y>m_Dapx8E9s}PbY zB}sBw7JYueTrMX&!%;z2N^H>j_+?6NqMw}F-9Zb7pE-qj3VL+lfPL1_TLq^{`bR+x zN1wdP+5))HX)alutk;zDa`Gty0e4S8>Joxmd*(HUJGF`5pWJCtIIxv`&DL}KNx|US zfY!BHTR+6U!p^(^?eLnB3*x`-*cMfR24u&)3zsBUNw5j`8oOh)-I6uPf}`_R^pfI= z(yiq*!yne;F=J2Vch(+&_R>zpqO|WprXCpawwy{(7b*i*eKzGm5Uz||$okrG2nyS3Y&UsdOz);!dbnUC#Po7mNe1jkJscpViwXZ_AUUXvz*jAzf@IJDu zOvr7VEP3S{Z)~XIa3c~exj(deODV{qLdEG!{Ds@6+fx?D)zVE}>$x^mZ*|L;nEJ+A6_I(KvVUQ?fOGuiCYxWRc- zjF)ZJfk(-y-sTJ9xt3Q>(QTj2X$iD@HyiR^Y@U5NuOqW$#3aL?VJe>LlI`wYIIVl; z^&g3tBn^{4HH#+C^TduXtQZYny6NT^zhGnABd~a1!ji#DS1qP*JaL|kv^*SZ(P&d51ujzLcZyI;I>F8iU|Z49M7=6co~kw8&^?{ z3Ez8F4OC+gX?#JxRG!Y=EbrI=@ojfIgANx?{NTpZwSE@qVL+4$J4oPlrS-!c^A|F9 z+oTa2f+8}N8=sx@Uil8x=nz=wylsX^*}W=h6a|Z{S(1AbKc=P()nl7=v3z4lidnkL)t9d}ca87P1uxq^R-6K{u zxk@sNO*{x$E=S`*138np3mS}mKL8yia5*jdRq{$%Ssw$7V*4eL@5m3E7%l}~E-!jt zlpWaW92XPKv64K+i1Z0#AeVRJ(9^?^?iYDGxyDLq644&1s!;WOeevSv&=bO|E{a#4 zn23GeSY=b6B(r!1O1)aQvBDItE9u+mZjYXjvkbVWjrluL;2Ln z*ZUw(W*zPpAIPE>f*RL@t{0w{OnrRxf2>_7~CXqa4gZ7h}NC+PAmu)b@W0-m7Q?>{)o zV;D=*O!9w`A*}C{rbkZG!y>erM4UQ3_qNczLO9eAMRS*?zrZ>9j);bX4UcfDqExjN zUxOBNjBDeDZ<->Kh$7Z#i0CqcSPM}vFim0G47ClEbH#D}u{bIrYB#^pk6+_q9up5xF<6@E;ldX&kgTV_ zQ8WRxO%a)*Ivs&!<;-=mKWGjSRE=;liv-iV)X%oU>R75s5=8`WzVmL$K|s>9k`KWP z7Q}-xs=!KEs>Tu6q!1^Ar>Y-N#qku_5JjSxs3!!r(4dHHo5}d3`Ie-qY7tTFGO|KA z15Z&?A+YpMqB@@FcuY_Xqk~5QQWw21}ivSJV;<0D7*48*nQck2`pPikkvAm zIXa6h2Aw|v3CG$s88`ljs4aA{*&9o0ju9u{t zEX*_}L}gn7ojSMHyVB5QSkbW!rwJ*i5VByux#%iRBgqWqLo=OCldK@9hpg(g_{sq2 zcQ~l5C(_grX{zZ|^Wz}vco2!|3doRHj-tXU(MG+vnQ4&VGO_))+xN#n^-8eDd#WJ2 zxia35#Z&cv^BeXPA$VVXpDm-JEdd~&0puXgMNYpT0kv2DARP1z#);WKo)Fj zrQ7awoU3v=dKUA?VkQTNLf?4<&DiI$1Qb(u4Mg;`%%O`E@ud5|K;o^*H-j6L+FNg% z=LRNS{5;!)lMw}~!|w|!09teFB$p^3M?MZopO?Y=$O+X9wo(OKItB~B_8whCV$DT` z&%Nu!8I+~zi=A7&Jo4q7gdrBke3~SDfr6>#qrcP7Z>h*jD~%<9#x8zRsM;mZ%YV8m zY;r_l4U&FGsTOlz{>?M{h3Aq}6TpI#MZ<MUUMY1YrL;kLcO7;r z<-`SpO%c;nb7cPJM6xUwF%&?m=y%`z#K{@(m~xL*k#1G3S_-PtnEffN*1f*0`EyMZ z@)o(qquxT*n1V6eJ4&9S9}8)a<}LE~CH+{M8iJ$>$>&ud@6T>x;F5c{X%Y_YqN_^I zTE4o2)b~rccMB)2$y6BL++bABVQU$72;qMC?Nr;+#KlyOZlU`u-jMGW$k|U0S6dZ* zfl9IIFU`+EtnYzDKT6&8vMy^I38Y~2Ria|slagV5?a#;X%vv85x(B~LqXiRn4a}zjYTtLI%vKM zr;EV-ECDh0(#)Pv)bi8xq;Yad1UuG?szX4zVn2N>`1ABzX?GA`KT$Vc&ZuPtBb25W z&paNYLdWJG#aSGE{pmDu+rEOL>`S|Hm8P~$;Yp>2e!b6HCZ(TBb8656hf7O`kd;z# z5Jjv4EaNCH9g@Fk>#-y znp4My%l9+|oAcUw^plF@L=8o;&+E#w2(1?4+9^?RRt16kLfHpeLNz@eMH9JZ^7^Ksb@ttB*<~|i*c|0X9t5uE1c1JvQN zh|S$*yL|PKLlL$0FN7aFaK^`vWUxAdw8Be5!m&^?F;`c&7r&}m zOmuV%ILq4Xlk9^r(v$Z|Q|ycr{}^D95Giv=jpQxRTQ-*(q8KOC=urF7%S4$m9wV~3 zlqk=eX>+NUwVMa#m?`fn((*75PG-mq)g~o1;OZ4T&2S)6@Vma?*)d?V41YtAP-$@r!}HQQEpX;%wjG;=Z}m;XS>6kjwYl3SF2i z6|AO$(`~9A{LQ#4D&wsqZHTO(4Z3*hPZ@rM3Jg7`y=#gPHKSh|)i;=1)Ys#FJ58fJ zqJ0)WnkMWFNnc1U@YC_?l>jZ^E zUe6bI>eJ5ae;)b^*EjTpcHP{DujBd`uD^J?Jlw^J@7}z!C1P+UK-ZV1XY^)hWQmex z^k%eKzb)jHdy+`qqb`V1&ge>cxFfqjjgoBb>qqBBtNhx|O1!=!Ax?l5Tos$ms$S%Y zbsN>bIKA?a^kSJ$^x&z?GM~@P^tU&k&;$NT82=>j3>y5->&5f>cPV1s1vg*IniRM# zyuQ#5y3705n6WsUNLpUwp>|#C^fP{N_%C!p@%O;B-thMdzZJyg-M9C3yQej_pATD) zpWCt)`7NJe`7!)+W0(Jl(dESUUEO~&YxN3Ghi=Z9?DPzO&P~4mefTcK^dk1jk4HCu z{z^W*+?F_DvN68D|M0TQgvq|5se9Y-_o9^jJ5T=HH~stY$=@fYN8?Y9o}2!A{p8;V z)8kK1j=!CGkz$ISI$iI3&Mb|M=Y(s2u^%pr8)H>gS-gUc2df9Y>@NwhE|M_IMCz9Y z+FqA+X?7hbyM_E}eaJWp88Q(T#5o zaqsHS(oP6@`_Zy^WZj1uYT~2TPSE!q$0Pk?K0PN{-zan@Y(|lb zf?p5cO1$#u0Q;WLv^MGLk56-VJf75EOZ@e1ToLf?R`RvKzxGnLm333zXCAIl+MWP8 zlxE3b9#>m31Qj+*VZ-D*Q#s_@W~ngsDQ6m|{`M@5+YIh9!egs6$ILi6xQz0j37Z=g z^vib{Lxr}@jfq4trd-Cwu5QnbOAz3vCPe6dS*G#xbf+fCa?$yxvKIogZpAc}Mb}EI zuUgx0AO6m&EA5kRwUIX_22Y(JIh;NT0w0Y(Q(>Ukd!o95pG4yid9sAUhLKyUVad1{ z72T>ecJUb8Bz_MX{Qr9(=F4iRMzhBavu8zOAWM$ zO>=Q3ah?cP}*!3HqPJvEF2dmnS+7SJegct1#)B^nLO(%hlXrue; zYZ-z_-%oa$1@HAYuMd13yq%Jnv&!x~arH-CtdUD*?bY^8E45yf&p(2NI_$Z5~}rt{|+#5}zFg2n~o}m{z<4C6(uvQDJLHt|*&P+>cjio1+LjpcC88tDvkz>FmJ z-4EYSV;Kdia;eDkr+6RszHEwvTY#Y}XABhRU4i*&y3ZBT^^vm$#_*HC;X`wz%85IL zzJ91CIf9~^2Df9=ihxB=4(QMi4mco+ZlK4NE1ff$f=w@ppAApH0>wk*$o@iA&#~Jj zV~MdApqkmN`y+9ADVuBJ45l2(7jrXTs1fc`Icj{^WnPS3V^0wp7a_T1s%Fy!p^J<( zgTp;8DR+<~BV-&?h|g1vD7_S*1XM!KN@wIW5v=8CnunyqyJt_@lI;izKh?PvG9VH; zdc@;hU>EX<8w0stY%J^zf<67C>MSHeFYx;H>6hibWEWOWd_%BMmoUjDljr=@ zH{m7ltovX~D$;_$ArBbUXE!H<`k2K2nk?O8JY zu2>s=#dHvFl-Ng?uc&9cR&@r%TY_akVIS$b8%Q^zZZQ=v_^cTuekb+P5D>P2wu17S zak=l&L?fL6(wTFx^M~fmk3-JNaojvD7j;QMeub(gty|3cmBRHy)Mk)D{oQwg8HgJZ zn)o|bk{?)BknvE@dTG)ZuA*Xtea3!Up>QIH_ounH6U%Im9;F8tx+O7j>V_lzb5rmT zCEywP`d0m1_MBg1xYJZAXu>ax*VSCK{xn%>(wW29M9KS|oCWkal~W~I1$F+Axw)P_ zSxo2<3rt;($HTh$l9oWhb-iA`5B&jI>I7 zk4vx@FX!os5-#}DzN&rILU=&XJWy<~3?TL8Rhw_H%mC)X62XAtL!OF60@ z9Z_eywXA<}TD&B`{N0xjYs=Z0zJmu{x5C3CtKYsmICw}Ai-;Rk{a~t3`|!oLfy09Yy)lHFVA^hct|M zRE|>(^SI-1RF-QrF}qP1Y<)#PL8{QGsAgS8_xDqm+UWB8H6N9){C?(V5={;aaAh3C zckM)RzxN!_74G_;pHN#6)3&#GSPRpZMy2XWF$d9=dDeiDgqp4T2cc=&H8>f4|0SenSXUW?uYPZFKG?r>E1c(0@` z>7#1h@98VYKS&bSww&tzEId5k@2b1D6Iu87-LK)Y z7=P&!DZiiB9q&J6{M)Nb`S-1k@$VOd0aOF9-~k-P0NHPVVCva6E+9%xhKmHmAY_7M zK=Pf^lFv63@ZYhYfSR3PQ_1f}Y7ljho}M$rvRL9Xy`JGP3)v$ioY152 z=hH=dgQXWqqGOanB@hbe^46;>apN|k@Kw-5C-86y zrLu`G5mSGm&J`A4zith4FB>{bKN__>Cz|LSTuT~Lx+t15dv+{CqLajHL<%iT7v;2+ z0-Q=lGU2km-0xTLdMwzfD6gdpXlD3-k@b=sJMUuVP(EIybrgMTi{}xWQ@0sUVLflq zrsxPoNEjmn%j1b^c4oKcKDilrOyL_&6;fzF(bLJXaNGIk?nPp$zR72p-3s@RpV=Wv z#OGrAUDi9pog5q|Twk(iww-`!XZjeO4EVY0>_7``h*l_H=Zxr*>NZ0(pizS)-CC01 zpNZDv%o9CLPJeGtI=tvRn`S_{ZtG^>ED`m&sZOxBd{(&nJ}( zi7XLej6`W(%?2_ysBtRR{qbOaaACh%?7!y$eGgTUMb zI`^LmuH#fBGFL2<#LIY(zT%4!86J6&2^76f;Ct`O?PI2uN#cpN<{y-=R-jxJoich( zLQJC1P83Ou(FM|9!qFtbR1P#hg{ylLaRA_dPM5e#KyI(Vwo{Q*OD{4jZv{n2fdZeO z6!|P0c#~HELV|CO3mSzB?5}CP!FXiTiM{Kh!(9z!cu^yQ#S4-k#4kO}g@2GDc#L&s zG2=&0iYECvXd?y0Cv7&EvjimWLp^Uc-Fdx1IcIOm=#%6@XUsfvozdGc&v9o8Ba&$k ze5sC1-n!;W%4Y?|&sv@@zGHZe#M2VYjU-tamoae{2&CU*c9@PI9cDub7w-%Tq9|ef z&ZB{%4Czv-PBOn9^JTns^%U>`<;D^pLY@f^Y!zxmJ}gsIQkGc5=hQ^B)C_w z-|Pb1gjGBf!!yae*%bZ}KOru^^y8I)9Jo^>+LI6CsYmKu{{q9BA;uPXpOIUccJ$iv zkm#61qn*42Iy;(Rskl0S$ojgU?EUT|OHz(RH{GWcBQ`@9R=}h*kBFX#6LQA|XJX>B z&DQS{_!`j2?jN1zZGvRX-BPkb9kkE+@#9l(D`&2nj|`;$-J@%7mJ?3t6{lu z+AKZJ(sE=R~)_6I&T`ZIU6e(0rxX@txIa~!Y z;%x{LCR*~>lEOM|ZKKCLPL<^p1iBhyu5S`KY6UMx0R03*(8#H0;yV&S1db$vCKx%b9DFg)v-@uptP|+Ij`C;E~uUVKY&rPJx?W z2DzsyDyUpS)??*ocsB_S_0#v7er7whB^zo1Ci9~w zZzNxZu&fqtpa_nV(8258D-@9k0_+$YOVW_?xr@^#=4Gl$ZN^4=c%Y9dQD^cU|HfUv>0DS* zCDnkHX0=M&oFlkWRC`8*>Rk~n4*UwhVtvV01q>1kL>kfWnPEUdP(a7)VLjce!^>1&sKI!J=~ zz$_#nD2m6n43+y{+ARy%=SvdZq~ByC-uSR`XU86BPT&YK^ZKssKRO}>@kdeJfz1Nt z^=+a}Uj&*9g)~u8Nb9)W5kBd92)o#3%Q?=h=hfec=_5Ak(F5B?`YBbZ z#4&;@qgmvxpXihYu?u@SvBC|=_FSn%Xtl|%N*0<;=;PIWY)_0_q;qel3h{mk(r6G- zi%XA!B0;G~$ok8rvi*!Jr$K)%EA9po#z}d-ZzJ#0Ss=hHe2BR7DVfs1l+C4KyZ(|X z`n7Bf^dQwwmB@FF9HiL5yVx@b_|CoCZ}Xy*a=J_B+L*o3LX4W)xg?odEXnYl^wq9Q z`QksEd5$D1wv&RxxLseLL}Hu3cEF$$NUH^0*9!Oh%O$5zkt$JCb@Os8NIX{2Gd@~s z(hSjwjanWNY?7C%1;QrDA_rNazW}h@XD659xH~8b)fR%Mk^EOroWF5X8bW#9@G9y< zYR(=>&~7DBUd$xpsidAAzfyd>j~o9WBuhJI=ADJ84aT*0TT1PQ#3n&Bfq=9NzJ12a zVV7{XXyueG(2~*hOep%J9d-*QY<3=s;c2l#_kB6%O5sNWVGy9Ov_@FN3U}eCsCXaz z?!RQ}KYhiC7IpttmUIqRdJRAJ{f9fDBumjv5VFF{KIv(qEdgT;1Wb%F|BzU=u{?HJ zaV>Wc=0I!BP!n!@_q5Epw@~o|-7X_i-Ss!8jhpuF~~pc zupU#j3CBuf^e9TPi>r1<`Zosv(Hg)es+$-jP`Fs{~q2!!#zPrXq+&j-O2-A{7a9obqi z#LiNAqYgqau--+X&JOxq1{56ILV9WgN^pty~R z+ts?kKSn z8LHpC{)Ox@l(uJK)Q+U&5XlS!0mLw zPp!!lh7o=pUFGxQD*Aocp0?1s1J1+;-?LOtmMWA0;E4uq1*GdvrEL~*zM@Y(ar&8Z9*D_gdJx`zt_Fep*c6#r{S^o6?u=g;hT38>aCWx@ICuhAsvHX zCokO}K4va(s9g48U1Q>TVcnA|&%%0UOkm-?^N#l64_=+i3-4Qsc*Y2S_&ymH(Z5<~ zA2F~|n-?+ox#L;Hqpuh3xsAizJe?lzk9ePH`}Xx&JxeowsFdKY#A1%enu;0oNY8;11&~GPTHIeb_CW zFH4bidtW5(Oc&`^LwL>EMf6h1;4P_H@}JKSnfAV2(|R)a=i54yf6$5NDMz0f&xhH_ zkzf&appcSZ?lt(dxN$(<=YBQ{`|%escv9BvEKi~9uHTizM8J1ZJOGiamM*PSYbok$ zPN?5amoO3sbET#p@gVrf&TIym0;*qZ@mWSb9?wm5w9Y{MufVfOJVn_fQs!1U*2Jz{SD9s8L3hqdnox zw!|Aint(Vt^*x3+r*UXaob#zQ_HHQc`rN5;1C11{;5*p+2+sd(mL+Gp|06cc7p%b))br4eg2tUHcF>8cP=odW*u3U zxN%wPS_q5S90148G#z^S^W|E(0u+@SCZA#FG;GUcm2g|BtVUQ^k#m-bUd3Qqc?=1D zxtRR&=V0>gnowo-9f?oB9fHoepntCi8_VOI3TC<)W!+%_aAj6rcx7k-XLzeU&pI~a zK*=)gu!(IhYp!^eFK>Qi%}V`;bs;Fa?%z-g4@>K?VH+s?`)1|ybI^sBi(|&1*4J5m zdoZ5e!V0PB2Kkd`Y!pnQ>MGxSa>@{PRVe*gWGzis;%woJ?d=kGD!+U7+aUihZ0ot> zl`Ityk5h@j+?}4bPadX!TxR5=a!Xoe{Q^+Wj09Y&1@$sCDs#DpF2?m(E;+j+JF^jh z?|^$+TfT`8O)puMbmjirbfR5!Z?V%8K+Wa1vBJJ3Ay&TtA-YhKJMlFZ&etQ?6;JfU?VpIDgF zD~Dd&I&E;u1IVdI25lOCV3Ua|@o2-kRE3VJ2uPJ)dC`8A`^f(1pEQ9hHg%RFv#Bgf zfHE%6R9hZ-q8v0gC%&vRBRp@^g}0)xu|JH!W2D?(-|waWb6nCSbdseB$eHIksxX_H z$vVuW{%x?SF7FJ%X8t{)N9~=887gnFzBZ&UY z(iF*LS@jwpl?1!<-Fvv?=>B+~b^PZ8C)mBkOdSjKrN71i?t3fadgj>F|Ji1Dw&dPPcxO_PD^l1N`3v_L5%EEc2(-461Pnbn z%mC>Cs#srAQS1g^g2s6A4aq-1gZMGise%|*#ha1j5X6oWy+d2WvDSmT z?qA2qM$hnxzbkBdqdIXPuA2Ut$tmhMpZ>}jbs;R{Gg~}XZx#bTQ|ZtDf-z>QL&{K= zBzNm2b??MjmVWyn{)@Vh^>N`-Dz74q7v%7@nlQ|-shR!2e`ShgR;{42QEKDQ4gLH8 z_C&AKajVv;>%>H3K?WSV5l2Xkx&!cwvGU?BX8lP66bVFvFqh#CEZ2dolbxI?cL1(e zfZS@Fn|QsOsYJPWX#2Ry2{+gzTI-E_s-}?2x(D~ov1CMF;Kvj2&p59anXD8ntZa|K zDarb=!W?9lK=q9TQP>U|Ls~pcP78q^#kdZwz|}XeX|c<_p=G4_r-e4c?;xDFPhb3m zj=?ws)p`M`*vsNsS7NdVAYk;1Vzh`Hie3*0Yys@CCJpQ+Mr@dII|qcI!>wXt7W*>J z3t{$Co4G!1$07>X|~->MiTCW0vHH(A*S`p;tTT+4V6bWg_elyq2~ z`uX3Zp3Y6zmiTcVtiJ5U&@+qNu^$T~IjShkorz3l8^ZIJuF=yB8^u_sYqpUv^Rw=O zP6w_rH*%_&gi=mCP;!N!$5vXxQ9Yzlr8&yQ#3kmAn|$T>{JL-M`SbK#wq5%O`sJvd z<4cp{5%=Z&vw6GfcN#BtaonPP$L-g1F%Vwj>rTWA-nH_mg!HpzB%8Mj%`fb|=$Mc52&r`_*P$w(yXKsVy=pH=Pr| zw$=~xs$S^g9Nz^<;%go}aPN_J53qE94XN=iAw7>J%}aX{UY>=|ngD}wtovL=1NDjq za(nYuui03IN6#*Oyp>(~c9ZG$>tcO667E#d72L;7<-N z`&!#wX+5oXlk_LB(W!}~UtY<-3m8|6+gr)7R%j;9YhJoiIxgchnc;FKq0v2;q_cD* zN54MV^}KHT5oTBYDZ@(2q)XWU9hebzz?p(Q~29=mSnvsSf;e?UMD;E?7cB)te1hM z+s(%O&kh++&+@0TRwLj?v)taA#$WGta-PE2UgW-ikl3t70KFu}hj#rQwDgy;Y<*4L+237-8I-*6~(T652a$q{h^2ZtN{GyAbTjYkShb?S?U@4 z*kcCk4Mg{vUh1{-?zM&W`l1QFHl34rZpO;Zy%nrlH7djRK`oFWDgHy9-opGmz)!L7 z9-uGaQeSXl-vyDriz0o4sZnAa8n5HZ&e%VM5uK@(I>}=xiO(Kh`|>aa)=x;ph2r{u zp>-}lLaFBUSMTA(UucG;>7?F#7|N#?BBk|@%ypxBpyJZNnV5k(?}4(!&X6CSy9mhw z@1{IORPMdOn}kGPe{Gu>Ejy`4?l`T7_K*7W9x<^D)<3v16Z_lWqUt1vuKOAHdvNdO z7(cW3n0_|&{L9evJ-{67@w2zC`=Gj%A2&xuP%D(j##Ae)r7GW=T!)7Gr%P(hrKp=_ zgCCxWxBY!wHrM%Hw&zWd;t%I1zrQs6szzyuJYg8hg>#UJtBl9sF!B`-5>Pk|%W`6IS%Blc4xC$~qO;G-@|qo*B4 z-NHsa@<-3Kje1Xwp4}cj4&erPDUk`g)DEjn< z($ko>r`0u2Z{?+JnK$++IKYB zANI6&=vl+^Bsu9BQ>1!Zbh6ZeE0-*2S0!Au*)a{Do~uF4IZV$ep%#>;;i9PNFrJ8p zvL*P;EQlKj{O^_(-v66rh5kQSR@SWx-{{8v`EQmLF_!eZ3t#@rvVv@a3jUX6B}E~d z=f5l~D}DdRvSO3`-z+PuCMo}~TUHcOohtNZXdiF*I#!fwdY{^U z%ozRpA1o{OVxWEI`1~5L@z0gh4;EynrS|m$qLoiAdgmF>R|Hk3bDLhc!#TecQKZFf zisy)Z{x1Gg`>*#&zZg5eKBTg#9Im7bMjX3>xjQQ{hvDi{%_05Ph`%7&zByN|MnMy z@BcekzVhwgua&I-SXQn(IqHM1o<9Dw{qWoI-`#Ol#?jB$k&J)uuj2}_pQOtMaf|>P z086$3K%hAFj;1e&C&Yk7rxOEqwSmaQlQSGXtZ3Za%MWpA6n;H1rZc!#fX{Cf{bVz4 zu(VegKh-Es)8tll?<(?+%`$wy$Awklk@(Y@Wz3Wwm@4q7?ZjtcD=B&YasV}3$dvJ{ zIwJUIW44A~fWu8hwyKx8P^GBk5*HQ30tt|?@VUUhhA9>r-V=xJQU&_5(}mds#X195 zIg!rrSiqQgcMV1s$D7@ep3X@x&U#ktTkINSQ3@Jh7t2KRYV=EC1`%UV|5z8Fnx#ba zO-+ckp?O0T$f$}CbMsjYw{^4ilZpvMZTa%g-guV1&(4ZbFtDl&?}u#(c)wD5uw_ z;^lmAgQGx5h-7~F$a?jO>lvD?AeVwobM&!i;5*)K&NKLRp)0sIT6(DKCJ8*^hxPuF zFwhOWk90FAhwWVj)IH;9O=8P+f}dx=HFg(#L-x`5DK_2(!j#mlf4fqSZg!=X(R-yf z{N;*U~aWqk= zTedEIedYnvEBtujTk^NO^Pty)vR_xM<5(mOdH>8%9&7r6F3HkA zxGhrUj^2GjPd$R&D5i?Ox|JnWTSWT}pExPsC57J4*|9N-9@xJ=@7m zbCEx@*^aS4W?p}a$X=T(F6?cRRp#1s`7>WR6WgTRzU7!WIRE@_Z;Sf$mP@tp{B4u{ z*3<15U3vx=YLm6ww3WY{xo+^XFHXB7rv2ht3GU*CnwVkc$!&jbZyHInulo&QJ5cq} z;`H%y4@qn%l+SQ!xAUOuUVC_0@T0fOeL8&)rnm7+7jucuJ46Ud!3gtDRB zW#d&1B$!Pkus9vBJgd?}eoZfcaMe6l60S@e4*vGzwb_u~yyr#~~7j(^sxUfXg}P56(o zu<=9Im$RmSDtV(F((~KY^gd?0F17;L_o+@7m{*A6F~lE3FYKcY)Wv>qdpf8K~Z z+E8Ttd47L*?@mh6R-)yrvbVD z-1PW#7vuQ#2gcE_6i{{wL@1S|GUeBel-A-@;9@G^FclP%%Ilf>cRUpyl7iSw9B3zqsc&EFjFI*v{@k^FF$=|f1e>4{*x9_tLa1S(d zQmp_h2BL@+bKPVYD1iW@2XF{|gn}Bv!Wkjk3Wz3ytcuG_Ub3i=!AA9fms$v%{7GFN zu;FdZg4+P=9IjOe2#V)q&X0Vu5mwIEr6|yETAIOT4pRUwP&uo-He%8jaS35(fac?B z1SDeeByIkXH2<3V}(HpRwOSwVk4XB#ONi}dZF~KZnlj zmldQyU8rrOdjDVkJy((__FgnE2~lrfXq4TGKZ_CEA~)dj)JRD z?P6z6px_ZcPE@-LiWhJWL42FY22)tih9WB6T$E`4abhUegJ?fX1L^?*jC!zjE1*Ch z0m?vpskbESyFLMwkbPa0S0G*Th)8`GuwOBxq?WY{Hof9}@r;Hpx*Woh+0zQREst0j zKyW~LViwA{{2W7`s-IC~=W;94-31RWmRZf(+c?92;cLa{#hNSNR(+n!@`%ehAUq!a zmJA!(RM(L~psOmFnm9aTnWCV(A`qD5<5f=_@rGmO9=#Q#+HgkY{((zI?EyIF~&<8 zzh>(}7*_924o1DD<8Pn_xdvGRDfC6$Mr!W&J18(&ehiFbyB^{a*-?w96=rtYmJGTm zd`(!y|}+JbHNtbh#3W;AD>~t*!^;p{p>oe51Pnv^=X-F<8iqm0X2z zY(cyzZU6(}?H8LsK#(Hfp2+Fz9?qvP)9N@0Y!c4Q>%hZ&YuHL4_P&UQs?+|Ts~Bn? zmS^fj!0eA!5V80QtQi~PjLQRO=R;|PN+_au5$3*C?q-V!>_j};ZPp;)hG01SZ8fye zh})36P!dSfm&LspavMM1%HA5X)d(|@yPaEQ zb2d#b{dqE>h<8hQ+WH0Rir~Zn5NREZGSqm%&N4B0*JP!b6L`-8+w?>ZVKoc3n(c*{ zHCf!O(Dp8M_H6)>N-x<%LQy>ury;AkWqMoxi@o;>Xu{98eM2A+0wke#2#R!+-i6Ss z2ukk=2r4QdDn&4K5QI=fdT-LC_ue}J>Am+ZOue^k({Ib?} zt@R0prdHsxd>a8*0dcCl^8k_uxHgiNaH24zL*+f6N&KokH<2M}Y> zk4>y$rUAS`3W~E$#El1Fdk4_1Ga*seDmBw8ebtI&Xp@s_Q!r_h-vOZxz};F}%Sh-J zB5?eP{_z2H@;UVK9Z5TyxVnhQWagGG)o#Ji@l2}2+N9(8rw+S>j^_zP9a_YL4kSgd zpmCu4HfQ=9w_}v(PPe+wPcxmKSDh$^E^nzWUz09>`>sI?l1c0V$qLdeWTZ(2tUa#- zT>(HR(IgWNB-Y~53HjYts?jM7J&8O$8N@xwpL#N-dU8T~vUa))`+9P(dJ1Q5|K6Kg z*PYPUJ%J{fYU)}$XxqNzi3Y)T(a<%N^zs2o4-a%6-8V4Phq>w-X6PT0>K`-dpZL^2 zmC!#^*FQJYkLl~{yCV7aL3%v}x_i(v+hX(uuX#nWdksE#BsF+!GI;uF@H}DgqHgeN zX7J|I;Hnn%a7IQZdtlKCwx0s!FMmh$&=-1*fin(~JshGi9is9WqDdU0BN>wZXm3W= zH!cA4b#_lFrA_-iMEd=Ht)K8YxLs~UdB@i9{;a$|RzbzUN+n%bfhSQ9&+*sC_FuP4 zbt&-zTj#@&1v&Y|k(nnWaum*-PlxYPNkGfqP&%4YmWC4*zuR1eoEt$ai@pl&ZgrZJjPuT$KC43Kh2JNUXP;~C%hj{_?k}m zdrSl-PJF4KaC!utZGwlfVLJOJq8^Q}AvGrf(75`^gxSfY>&XW)Z=(bjNHy)kZy zRtFZLMh&a#!>iMd>z-!J-de!dmTP&~mNolB0%lQu#&!CKw!AhefHnZsV+g$Yj^bhE z^l*uqImWggXTwK&E5mFn%X2FyX)Cv3D?fB=?sThY&uSfLLvFTR;kjLvv<(t@p0>wh zg0@KSw3+R6c^)7_DyRjUtl=g7G$2kQ@% z%Oh!uAD+^=SixN*GaV=uII)Ebz%xam`7K(j72S;AT5Z2|S)pRg|BJHnU2a)r{(gND zJbdpE`RkYfhfuHVcvoPbQTC^}{=0R+x=H#G`QnKP9!w2Jnp7lD&vv4c0TxYG$V~yL z*`7GboH?7HefWIll6-c{SNSx5=7~K+y?raqd~WXziz7by<|U#PaNjx>YIx$5%>TUG zz;WFPHU}VCzKv=W{jvB-8~+(Pi4otFGs6`1PB>g-g z%N|EBrJVM7tFIqSSR0anaITWVNtPTOVPUWX#Li9%bQ8JL_jv%rbUiF{Jz{>{A3CG; z^?X=>O&nWjhFd(EP<(Id@%g_{R`#$req{CYe@vZ@x%YueyT`*cksPWbg)TkL;QRwy>Ao#{$lalijJl$CA0 zLeqbyth^eF7yAn7ij}0+-!rNCSIUY-i{IZUD+Y(pI{rpk*`XOHXdOeW_JOYL8om6J^V zIIZ<3$^aFg(>jKf~c*FWC@sk_u*jnj3POr2PT-i#G)%j@-P{S$8vCG z)?x+n$H$N4DfF$26{%q>8;Z2H8O2Jcz?ps}#*Zt-otw{&`Bhi~7|4|GgeeH9-urG{ zqRLK?v98LQo#BLZIqxo3mFYv8HH6V%|ZBy!LY98@5$aUHgPSLce_2~89Mg^&%1 z@AL4{OM%MXJ(kJbR;m#WcV8U5OcN5qYHw7<6mlps`w2Z!t)zDz7Cgg%0qWnboPOPx zJ=E!zmcLi7^YpQz@aTMxPPwi=EMrI4aMDNNt{&yN?btkgv|RsC&Z}d5ac)J|z^b-& zeawoo%E{0+*-ymiMRsO|(W{^BBF3*PS1XL)HiAS=96Rq-n!FoSJZt_q=0PAnH0&p; z@nM=bw9I9HHiF3`m~z1E6V@ie)Om%LhS7P3U(C{vTGIf>+0$L@Spa)<)w3@TD#WZp z7@t>J`HlJ8-F+aJaHJn>~Z`;{JE!fmTP6~>u5vK#Mg7xwn?8)#qClY z8>*kD2cNRPh!$4+W1ZdVPQdscqdJ96_Bb_Ue^pSqR`cp-Bfg}4aVJ~+cHZ@$PUeqr zwm&Z_vyJu5-FJr065TI0*>|l_ma7yR=Kv{(W&-v)hgO)flw&(JwF#NJX1E`%ZA8aq z;)f|cV~qbEoLA0)(TjktssU%Wa=pQQpI$5F@}QiV`D%ZV z{qyBf@4ED-v!Qiq_g!We01p2B2?QRW(oiPzX9|bTnzd8t3g;l|HSL1rRXEh636~}Y z-VE9Z0N`y5cvs*;cZG6LB+uYjN$R?k>y7M2ZH88x*4oa8YaftQFIl~KC6%}pioEdo zQan$rkhmOG@=T|2oRdXMW6vA_GgWwixIJq7_$=7r3YY28E6epKF)h>=xQu;)K2-V2 zvg7;<0AdRitQp*aAae|$<9|jsYNsHWH5777WuaLWQ|4n@2)0x}F`DYPUd+mpFQ&xF zENPc;NIxBPDU72k9ZVPg-gSmnY{G`B8qjcW3wt8QP8wB7riDl= z`z9Qd07AQ4Hcy4)Reg(KUf!J_xZQC;EW_LV)No432L#V*)X0LxwWK3&F z`d!W(KcN_0#)NJ5rYAIEE+(opF)jesPEJiXs;5zuqk)W@VC82LWr;%XtsGP)yO~d& z6O?(fG@8#*L?$Ve11_=BNV+F3nLBFh7$2&Q?BV1>q15FlYx;n$-sf?@vq-OV^_K~i z6Yzh3Ju0)(*gw~N0(>9UZ;iseu=|oxfc|kXtUp|F7!01;kCJQWP~h&CPxXJBKkCXU z-|gB_8u32qeHl9z#tios3S3VAP`_P027-M~&`I_5dqwi@mj0MgE?P#EC$27;Q09io zdiIFdP+z_0d5Lg35|q1bRQxrA6J-|5sQ+uHIqZ?j`{FW>=bR5{r}tx`#r<|4NtGHI z+nyf9S~8^L0#k`%4#_R_x1xSUeF=S=VTl{AxF+TmZ;3#a;OR#D}>IjE5SHZ6)kBXt0n{?p?YACGgOLf!$#V3PWZaR^#1tpucM+$#F{LDGsEmywEfr0i#O9Ii6Ljo$23x7j$LKRY4$8k!ri^LE3b{ zx&)e93W5BXsv+PIk_prg`zUy2^#1OGOx>r4A=C-=CstG6oj~|_qwgXgD>X6BT{-r} z?yMb>InC+e;MY-mel@#taClSo9xIkKX88%l=B%;WgR9YaK6MM#zyVjg%^l=rqSvffJh>icS5TJ|B)!8almB<&o6ci#y3zqP!-SM?R^3O{&If$28aDW)dnk4A5%C}Ot zB{<6O@TSU#A(u0lzhnnH{m6^BTMhK@J|t+^M!xON^K|gHI+xCK<8<80op)iUk_xjG z;8ur}v1G_fsWqAyr)Ew!zgm3YV~EEW$odVEpG(JsXPkY^(Re3~Q!uSCAdTY^$5;0} z0QVTpy0#71583Z+fK>G=$Ff*#%V{vZzi?R};re{@70KgT(fNc0^#L~Zi$LVn( zRCEpu;9L$!Gx1Zz_z1zhqMl@e9C|B#d#j>)t226Q%6eL zs}{gd3rhk13aIPzCNOht^_1vdJC5-qRSoB-2_FfB?`rw|(FzsUCgatnyv9)JYKH~U zd6TL}NcPvN^;4=NAopr}T_Sy(h?km({mzFLEx^m*_CE39zM4Ai5#qT8Vgw_}n%(en z5qDq9Aa?<*)r7yTZTNlx>>~zlj(gvwOY6aGn7|NPfP@n(FpKs&kc?k`!u0;hpdtB8 z(J#qzYW@=j^iiNAM}Q1y1W7p}dv8Qectl=tL_v2%(Pl*H{fM&Ph{`t|`FjCs79aCOl^K7iDGa`TH?jzcH&_d`B7rLQaAYO=Hd~1or)UuTRF_g2o*v#~tsD zI|+}!Qyh2J9e-~#{^9-jN565GZ{x0+<8I~S?(O5BM#nu?$3L`>eb6F!{hGi{rJp%b z%cniiS9ikCX2SpdM1bE!;J1mO%n7|OR=1nX4#d+H2b zqt%J8D8T=U+JFFxfTuu;|3lQqF@^LlrQpk%uHy90FogUU2Gx>`?nsWOxhCBunZ4in zta=huOSAgp#olerbeCoiCL?_yjA~^$L+L7!T&6u`KYnFvrK=^XmFJG;8I-=9?J3V2 z|7p?sg;BjCf3no>SFUMqMZt8X!*WledS&5kt;_GN+1|>Z^NlE6A|{QhqQ%xga&EJ} zs^aBN^j-BNjp~xs-Wb7GbA8pN>w_us!Ay^8$~J%HJk2xfuPNUiFS6=QdQ@AnJ6-i| zd#=B>a(}+bhlp9TuIg~PE0WuMpsxD&IwoB`S+l<8WP76Y)%-wx?b-f9YcQ7iaYNmo z-y6U3%m*9lFV7B^dy^kGHe6qx|K6S-Y;4400r(sXC_E~=1urmL&Vo0w$i{*XT!~}R zmqO2O(U0bN&Z0lVhmFMmgg?hpAZxVUQV>U0&e9j2ijAdUz7CG%5TP-<<*#CEIm@9^ zryI**NPNx=^DE*Pi&9FOfseygMK)I=wUjt*jII_0GrbS^Ty4Bn-fXUZZ+k(w_CHaZ zPM+WYPSi$AnfGKwNB{N7sDW+4$(YH<-IH;P0N&FH>+i2mC+)HePN(cEcTcAsI(g4# zoX20E{ku_{KdUjeg@4u(U{hg}1qo>YBFF~tlo)b5O%Lo8TMh#r`|=XYT!dW1B+5Vj zN7SZ?;K9{F8}+{#wfX+`=Fdj}(pap!`57KH0=TQv3^6+Jrs+$;7wu|>x*hl+h%G}_Qfb^*pv*+h zdJn-z)vXg&2-7rWoOnN|bK6}eT-R9{iUWz}6-^x0sMIp-R4U*jf|U|tp~wlntMFnn zJs{MwQ`|y7j7zRJke9WK3_lGBavplQ$rnh9Zi?}&T4tQA0V`3xgMQ90vcDux{pYC7 zSy$)nT7DRcI0HdYo#$}n1Gfssm35M>kSzj`TUxauRcya7ekmX{q`{Lp_X;fxw?wF- zfD~P9zS?_o!KTKE)cYxbN0>!i;18cs6d#-$gT%=p4}@#lqA5cn&|^k-`2tk?p3w&gLTZaD(cR&alG{Zux^EI6WjZXOP$T|Z=KIX{d48iH8cT%D6 zRI;eX(a|zjL(q5m%ZNsyK7o``Y@cm|7ULF2rx@5tt=%G>e%P&3azY$!FN9A&@?=AB za&f?s*ckyACKkg7hKUK}B|qp(26i75&uI^}G6z^5#_R@|Bae4nZ4__A$6JM`7n zUHXo50`VTl(9?cgW&_X{J(dor6LOik7txTQCH5oQZO5x!$o7B6&* zDnE+)>8aa9x+bC50$q*O^vG&m8yc&;5C#AY@(sEz^+5|GEMg=DcCy@4!(44e&^&u{ z9F$=@esn3`{nY16UwUa z`^oNGT*)UO)^g5OWQ=HGc*tml9wIi8Tds8I>sRmPy1zwj#(U>ZYtHJoul+wYhNB&Q zi!Ih@2%K>cIGbDuK;d@oU=XyoF}K;Wg<| zhZhSc<8l$t=j%&z5C8#r+h6E=5}=or=u^q26o?;q2%{{$TcCnl9C#^-2F%Fev}rZ* ztr_Wqh|gXSQ5}Bf_5#fhv_w!84pUs(4yW^to2!}?0Cf&wkIzLQ*s9y=rDce<6fXS= zAHlb9fo7DAE0z|3YKKOq;@n&;G22k72$$d(XE4NA82aOL-YkBto@%cAe7+T1did2b zX1PmKT|nxCSg0kYikeIdNf=G~+%c+^VI91j99gmO($|rpgU=sWbQs3Q-9(NBbcziW z>s)=EQ16I|w+H(OEQRbMaxG-LM~_O85$wzne7Sf-l|?{sJ_!#Jq&) z{F+In>u9~4GD)Q@XkZ$|F_Xq1EF$pq+wdAHQ9k7^NLW101DeYPU|!zn$RAIPGC5QK zlEM@y-gX%BW`u^W*Puh#B6vCLN12CGKfVwJn%IhChF)#;<0uCg)Luv)=XNiuf+bNH z6(-NHfbBX>e`^|bT261dqtZ!{4b~ZyUR@>ZO*S;vsPKPFQb4EwrLj~GmeA;IATLv6 z5K?%Y^%$%wqnG{bR&@SH)TVOaecGS8?b0pt56unSz7f|uc8_bP#s^L-YOi-4!fI#M zHP33MulHOAYv;}e&KfSS_ffFA1%k)7o2oYlfsgB!s0YtGB$J*)P0NuCbgsqirLQcd zIw=V5{J!&+q>^H8b6NTE#c=%1an9rVE&aiZvD%xHqOkfM+sBtv(>JG8pXq;-t6<#v$Ki9qVI9OeAq6@mK(EpKCOhhK_h8KG=G1zcgIe5M2j=fxfHDb>@ zAKx6&Dce=i^ua0%e6+ZV?NL}L0#1yezFF{Geg@mc zz_i$af3g9@2LLc1%JERHr<2!^6@D2&?Yp2^{?u#gnH-P_8qR6aiAhzxSzYD-|`(FGZ$*54FIkR5!S(L{74mY0N|crKh9=E z+R+Hc-~$ikCds_;7JX37pCJcCQW?A!E`U#98g-7_c^Wvr3$H?;@DBE4z-`UjkA}w6 zfaw?|x1eo3-V(4d8&|(E<8qjPMkvOU_ zem`ea5QdXY&`ci$^)Gq0^92Mo1L(DQ6OSdDnouD_02Z`oFAMNa(U&h?_^eUBzXV9^ zQUD|vK%^aw@UdK26_2h0Ooa@JE{1FrX)NdP=;8UjAor@bqX`t^jnIWZ6AN}<^gBC% zX6Nvu*s!ITFy8UKd5&D zLs)%1BXR)mV#3`Wl|ZVza%CFnfl=aOVd}K^H!x^S%(odURXZ&l%irP?9Pm?i6j76~ z!iu!RB8+MC{&`Wfo=*@k)n6}M5%MPjTOzli1$(4Q={otHYVrZXHB7IKQu4h#&bu&J zH)T-ugWwU2*fiJJbi+8X7b|s^ zpG#^SRTgQ6xN$0Be2yzTMKwN)Grl^O)L`@;(I%5BWkRzdRSRbV_}K?yuLOeB1d8Sa z!o>tUoW$O0(&5`|j3Ip7H4&Pch#Q^=0hrUb!xvgN;meco)oS>9P|`srU?w&JGL*FQ zCuyWQ@n{l$V3-WXNuK*bI`HDdTnc;#o&uCexuq83yQP5RQXn-c#8WBIixfCrDw#wo zg;6S%TPjUl>g~J$!&EBMMJj?W^)@}Wg@Lje#U}r-Bu-5uO0_&*PvefWyO|&LX_)Gea&Gd>N>Ee(Ke3lFuwG5DDhU}M&uJ#PRm5fw^%%ppnseW<=8!-lP znMO4;B*Cnpxd|?BPhRFG@a-n8y=o zaUc2qo=|=~rK*1f%MGx5_;VsvNk!zx!3=MutMmT9R0x0vqc+zam?{#Kad zoIF9ChXP~cjlyKMkkOhF3F>>oUN;=50CIHdU6_wFve`gl*SRnSh6FSl$m|@Gyp#<3 zZ*4VeBCE6IuY_?)wq5^msFvpshA`s|1!|#K1wB~9> zsuHI*T?2*rb4l@IaR8~=41Vwf6j&oAOb5yJ5xvE9mct;yPz5z5ZbM~0@q*yHa6!2a z9FB?-kstWDoY4b1r{@-qT-hyDH3xotA*sX!z_1S(T$fDm0C6hYQ0JmnrzEvbG3>%2 z>>c_p;{jkPYrzqE3nzN5B-II%$&|O>aiCGuX%ffy!|v&+1&s3%NC{zrdDOyRn?+Gb z-ToMV8Rf$aK%*YqXhWUs9UbG0tmx-Ca6nz*p+*VMvW_>DJda5MbTR4T9gdw+dqZdl z00kr?>=J~QFpMu)v4Z5foj3qNkfwlr8pTjYDIbP&u@$5QVW^|a(UXNPC4mkcRn93m=mibcz420F6s@hv{w${4 z7vXws&y&GLKn5TLq~IAy1&I8@hrN~HVhr1{l7D^}W`4@|^$WyS{7E%d6@-Vx$>8hY zqu>j%t|Lh@j?xk9#!&@PERjU4;GN?Mgh4Y~8S0-R$r#(A?{s`pJ?z_LKC!40T3a!+ z(%|z)9EQ9K!A;*=*r1#S~t@1Lk`32ErfpRKim{HiX*X?x=W8;kW<){fNJTfC4TMq z7gIANvAe>hQr7Yl-6Djl3)n=-c-xwGYlpszN~a%8xi{XiNaBbUir~zaClid^l>d-J zPB(t8EKyiY4AN<>@Xi>aqvQ)?&GKQGL@5bJTZY&GP6Fvom+qurhP<>${}#PE^5%Bi z*R15UBB6yqYSTjG3!{B4I(YYs zys7&Z@FmZi;h{yo>>7&@^sI0L>7JuHxp?M2!>sz9#J#Xg= zEe^5OSf-mk7nl?q71n$oYEy#S0Q|!*DEY18O+;6tsAfsT_r4W2$v@p%p(Rn-8mnB! ze|iiCN}>->g>}lw%M*dWquKEn_^0o^eMedv)H73T))Ls<|8~>g{RN(_;PjsXmx0ox zv%Yod%RhtvSs|FxCAI*_lJRmW!P5H+df%3wS{o8puDdSIL?S4D~?>wWwoY0Kk zmy3E0e=gcH3GxylVg6RpV>mt4XR}vc*)R9TTyi@6u%fEH;I)&!vFjWHEH>8v=7S9D zt>Y^yKlSMC$KFfC+36$XKfUS`0961A2lUsge#~B!((D5!=lbtob=l90C5lfw2h;z_ ztt9W{z>MUx_Wk8nvTM+CeEQ3+WWy!Qx5WL2Tj{rH{|~oP_x$ZYxs?Ui7m5ELaVyjN zePI4+&8?PpOrHO?Tlqh)I$W9Ou#H0B{;-|KHvh1L;p5I>CnA97sEhTx{ZThZcK%Th zd{2Ihv%n=BFGq=nwNK=NV__h>bLQP(_B00yDkD>Be>|kZUT{3DA-a3~>)&!KzmiMQ z`$NJWr48SmlA>8+q?@H^!J5)>PHoNX5_Zb6nMQ$Sc;{xkJ%^6a)Xmt^C+9 z`fz{33YML|Z4w6DcaAGX9)UAH=A1?CaY{m(o zcm3z9{@)h^_y4zIU>lpnq2PoTK%|5P&7tJ@bW}`*N-{IlIUyZkDit8XM_JkBco6h| zQw+4%-apFuHoaT?^n)=2GeNbCEPnUf3<)dKHvSBFP*1pTNCqprYPXuvQAA8%2AgPi zx2D@sWD4Fe4wR1z50Mg;O`NGs(*)41Av5`nSmd@R2siP%qG^MI^Y!g6lcyt zMWVl3(_w-Q@lW4@H~;`ZAIOCV0Am4^UeGNya-q$n!lsahP5ervLJU9`#GpUU%Z$bE?DKh z2O?|m!x7c5^b5_uxDn#(X;nU$^9~?|j!7C=EC>2w)lS6}WFymYAG4Zl3q6_2OyY#F z7`T@F<6=`#>>o^pYuJPkQ(YL&iMqr4C^+07J`a3dxo^vFrJy!zyd*cy$0U{H7SJM=ebU{I#6QI`5X zjnK4g_39caiSYUNVMk(-zyzQml4cPp*tdY|-pi7a{R{ zgAfDkKG03mE++WNiG|6h!+T0mU)xVCFrJdEBMC6P&6HMuMYxVa1mt4eCk+2;h+VXzBi%+V97Si4Ky4r`pB4@- zr))ID*DY{4kK;ZT?^QCapDtOxVtDIi;ZK3K?Eo2`Y~V9EnKfHJxcwWt1oBC%EeV%a zJUNcKBknmdWWz8S*jk9N%l=WEqQw?9@;pWU6^S*lid*=%D!F3{+|Y<%7iW)-o*L?zga3RO&;>=Mg>2QN)}LTSp&Wm-hM(P=`p&6fONTVGlt-b+e$)}7l+U_JH|wkLUf-=mObg+Oj4g97Mlnxzt3Q}@ph zHo`bpTAi1)_rm2_!|0{6Kf8*~d4Ek3i9z6xR5O;kS@ zG;}gK&0QIu>zioNh2LAWSz--@@dSQ5%M`q)urUQ0a6o$Dp#VTyJ@Obh76ptMMtG}z znE)eu?P?;V2VBSG6rP}4g{=+7K4m`&b%`=gTJXmgPiOtk=L>tH;CsF^%tqwxb9e1& zns~P?R3`<_dcGWEiR{*yz&p!X+I(upU_v9n6H{w^ORkbZ&OaqUmy~T;Yr|b&PHz4q=i^} zx%K+0&~AcIzY}eZe_nUpvhpNoLvX4fXjDHsrP%9}Hj8JuZNGx58n`(X(RU{hm(aV} zmw~7H!5yz1`-t3(&w!eI)Mz@`q6q-v8+}xEO9N2gz}ok`1H(dEaYaPi2z_Uc)I2S+ z?vs6S<}zp|b1{a0yf0f)@4 zNKmJ|kOv#Z%42+Awu-Xshc8(I)lJqlRATS7?06HW3J4us}C(TPsY4+Vkse_d=o@ZlHTUTiK^Eh10C${f|41|=sRfXH08Z!b2G!@}J}kN=bsM&CS~bc;w#fbj$l?>t z4%IR(KBE9D4Vsab*4>;6j#Jc0%8;@>XE%&R`l!&nDzMHyErP8Cm4HO7u~%&$ej+`YNxyNLZC)rgUa?QV?8DLq~JR|$ARQ31&~XPf~ve$v3U2n)hsUn-iCyNNC_oY zC?Zp|Vdq{N3t6O_7=@4}7{{}DBAH+{sKIEf1fpV~g zG^GO^RbD?Xp>sJGE53r7M#8z_I<8rOd~`6x5;wbugoNgEVe5;mW-fCaV#oq0(ZEO(83_LFoPKDQ zN)R5O<&9$(N`&bPKucY92(4z0Wk&&?vcPw+6Op=|u$z2MZ}f+!mof`P@+ zpIX=i#yvp%z*1R(1AIzUm$z>fNuvX9Yz{!e0oV5j;I$OHE3iwKv z8VSKV1S{!l#)>B-8o~w86xiqR9$$DoI#DDX5w!ZfNc9_gF>duHoT(h8-u({z1Wr)p zZ>B=zY=QUk8J<`L+#n0!h{2n@N6nq#_7TMki6vDi3J9^Kz9UGN#1W{MBa)N@x5waJ zKa17wmgFuD{H%-;`AAW;Xr|%vQI#VJ{R95o^$XWRgak`6UNeE?ki_QZ>x3M5SEskM z1Eo|CoTrD}(>2y=8FxoKBgim=($D1#?3>xmp6HYg(INn*61+N)h}-aEj?}%&0lych z4&(>rAbk{^Qt3)EWJnQ8Xqo$bxH-6ZauOM2vgw`@40IAKZ)tO~H(uWE89s^#3>6X`7B0q- z9UJ}RaQwO213xk%y>KJhj)Pyv!Lf8dNwkYjzZ6BLkwBV?pwmSp@g!4-VhYJ(D&t}r z_hP#EVoIW7*kuuG|c;zSeO84o? zPnVUbSC!t9Rlc=w|Gdh;_^NUwQ*gkdtI?QtcSkt_@Hu-yRJ>L{uonBcv#mP5AWKpo9eCW#uC+4y2BSQYe(Yi zr`#LBsr3V0_5HmK3)}VWk`4IU4Yls|t-%dr!S&mh^?R=x8|fRzxa)iJ8VH&jj)_PM zr)#38;Y4*caobHf+|ButHI#i#G3w1E2{q8erYgy1hWut)h89-)W_sdgFYXpnlNOq~ z7B;CC4&oY`=0--@Rtn2jcCXf-@r_KWt+!V*1Wp@_rHx9qjl{Bz!K;lZwM|m0RVsl@ zW2Zs(s!dd*-Q2z1Afer;uH8h6AqexY<>;4n9riOFZ>~C4*U}xNGMptlZB<})uR1-| zs?75{H)-oV8FE}1x)Qr#zcHP@pZpK7MW`?6E<^FI+qt#~6Llx4?&we5lfPcX+*Y1v zx()KWlQeu#3_TepJ-I^-Syx^;2|f8UJ%xRF0S7&RF4#Ao-fq#J3ZBp93B7eQy$x5r zO;WT~41Grp`UbB0CY5_JQvD+u@Zi3_(S-h~y8fA&{<*9E1%`no zseu)ffwfNq8wmqjbpu@?u#~=m1N+W>hCyB1$_b4@sgHx_Qtu9m2F(e&Z$3F+Fkmg2}s`mPQXYKz=-<)Do3k=F%*9VTFfpx<8Gm)sJY* zj%Z$wXfcjHc{r+LI;!U}YLGa}^Lp55b~Lg2m)UHEJmZ**(3tgC%a^uYTgw?gZMy z-Ggy5mwz(Kbn<)REYkY(fu7FiBpNsCi4?1Z~M`Im7_hT zs}iSc>Zj{wryH)Po32SS8E4uUpPgIuwI@>khEI1Vk{uUK_4iZ0V4O8!nHqUb9xOF8 zUO!tWG&_U6CZD>VSb?3Dj8NVyVEshK_w*pt8h32gpd67HRom=X?tko@7)>i>k!66WkSv z(GwSZOF;f5HqRxFq$RF~C7!vZ`!`E`Ov?h&%R*+$BA&})Ny`!q%Tja8(l^UUrWHBq z6$Q`bx7_ezdniK#=?-QEcX2@dhKwfAi*Y1P1N?d9B>o#&d}+?tN&8W+yGb12z|26C;NmA#pD&zp4=(}uV7hOgO%zvo6E zHfiHa!$!#5M(E83nrSmadNaywGum@ACTTOSVKYP;e)4dZoN1M85i`c~w{kRT)I`p0 zIeOs!mBT_oDCyUHz$xQ4g(I}WlXNd}yYBX1-1GabwGAZQ!Ve#tyWado0<%=#0c&q} zG~{Bgy9BQ{DTfBpGwWj}^SI4B(@8sH1JD-D+%Co+i*s;0?wyPVQgr_APScCkq{&-= z_u<^LbL7s{&E7LfDE`nh2y*V3WY@{ue%ah!e(shjxCrkM1a5}PQ+BgwXNM^=^IPJB7a`!<*c1T&K7@d! zVzY3E^linn%OkG(otMVIw+MKt!*A9HI~Qi~P1H6n=^>=);Pfl3hiT_AY%ii`7s^pV zG(iINB4NPpgK&D{?1$p6KsJ~`BD-<1>H@OU<2b3oM79bna_s;OC9vFuAUf$Ez{P%a z(84-yKjgI9sl5aMQX1Q-L6(x z2a_C1!#CkOEtmRWKP;D6lA3<8nRN!juZ$@&~j z99q%*RgP|p(Oy;xWqjy~H%ZE*pvdx{AtK!57ju!Fdj|q5$pUaUnVnY}+XC zb^W-&Kj_+=Ary|$V#7s>PNsrJnK{Yi@Pdc0HNuVx$k==I+y z#6n(DS&Qn(5}IQzl=}QB*(SU{i+XeAP`}jyX`QHQ5WJl;4PJwgNp3(MGR14qjeb8HP zE-?ihI|^i|;CwXhI`fKWghiUOQ*EF$uw3w`9FcZjrKXTnemhr~h~$sR;UdT@_W(pRA8 zTRyI~8uw58px{?_PZp>^I;ux0T^X$b3~ZDxR>CoEp9a#@yuAq(X$3DH)T~7ZfhDIz z=nfEvMR-COFz8;HRCh8+u#=uRL- z-y7~XlV6IsyP#6We=kQD9JB`6B@!e%3N8IeHzPbg4t8?n>S79hDa0WFDt!1eP3;G- zkFm#t{D5ToGmwjvSC96B$S9Kd8=sG7BD=|lkockdGMsq7)%87j?aEfAx~rBAlD#U5 zTrc|Wj|DPF+wrtFbcZgW%>Bim#|lop*I$%65$p8lNZ82Uq$?a4VP$;Q)$YG}sf^fk zj#ep_vGu3BZCna;AmyZYmL<;Gd9PFIUB6{R zLfU{Ra~&L`%wF$Yx6VJ~JgRSNI!(MuTK|61Hk%QX{pz+HJzHJt@p1k$fwaqF0DD90 z!QOpo*VXS~cHAqm0n!(X$=@5?wr$sWPPQx8lbm&H31mL?D+3ST9S$mESLc4&HeSan zznAg+gOl~i^K!pa=JWO0dgEv8?LHd7Mh}KVg+UQ0SO6(+cO&nFGUvUtz`GYn3f9DU zQ&Wsy@Kv$2-^;>!(nrzb$l4_l2SGe1|15xYX{6mJmKjf6l%?hl<($hf{(DEt1f{=e zg3HnwPY(zrodUzjxKaX1e*{Q^UD_xk0+=Z6@4PTNm;cPs#H@Q9ATg4P`dC$@xB>nS z#5BWP6SVFKGElm3WQTR?97^MIP+jEe_TM|(g!9E`^GchG7OU@0!)<%XRt$NWCGcjL+&gE}YAwIxR?QU5P z9P*w8R%*fHP;c;877w9i*%?Jz&k1?q->9W-nzQc8m53MzM}1z1fG=}f3J4_LAx+@` zGkVjEFviva$Bv$aciP#-=tXtGJ#<7tfh?3iCFhB`)Hx=`G%{2eAE9giq89+>c@}c?zOIcuRX4DuZwGjWXpA3Gh`+E!!<%B ztFn?iaNWc;vdMPMkV+_fBxEH!Dag=W2h$q+P%AGrE2x87rS0zpdDW4kPK(CF4DGL<^F5U{7OCT8EaQ|JFUx6G^{giYx*hi11l4eIHn$5%#rKl;$ zO1~P-`ZbiQ=i_87v?)==fct6N4~Zj(;@<6180D|}C52h?wTSp`64ZbnKFPQ>x;-t? z>8*;EkFw)WJe1euStJTUSKH_zy}|{z!BMUH%9?YA>bVqp2c#P-BLoq_(+(tq%}T!{ zP>K4SB2?xqc;Z?7^>^p(9_)Vz6~CGoS-*}h)$YBnVm!eCGu^?Cdn+PNCBN)qMwkPN zx`a8I?(&i$$#(5G0j=PRZq^^Oc-Cd;hG%6mtonOm!ow~Y{arrxWsa=Lm9|_cn^(=c z)52KvM^5<~prz$adSi5HS#BXDrb|tboB6Ey&z}<>E#3W*gK?q&Zo{)-6pX z7VPVV6kdBgQrua~@bFsWN9T`qR)AB*p2qXQwaK6STv!#5LPPj6ArlK%m+eJeJ=lD6T6Q~TvM?vaK*Q^UB$F2@nh+*mUSTLI2>&7`$&x8)v@~K zL=j>2i`aGmqbXaFx01gA6McNI-l|zgl;T`0XW!c|Ysnj=i6t@Bj7ClN;OPvi8nx-_z_JKZxxR8qpg@uV9~ohbcP=!r}tnB-Y$$I-ae= zzCE#m&nzk11bzTxw>(MN(it4VSHgeIrv>e(gsHRtGKF64N|X~a25-yK4a8;7j{OCYYFP+*zjb93(mZ4srDOr+)e0g z%;?YRcn+bs22y~5b^9$fu(i&>*wS~5+Hu$qB*icAQ;POlhE~_Tq&5*aw2dq#2F!*% zG=8f!0M`H07HicW?vu%?#|SiiOTd@&6_qls7V!n4mPqZO%SE6_Mk64{zu-dJK}u-Q z6&h9)xuEoupc;bE!JpQ_$|P5R86gt#KAP46LWVGjBz=DFE#^hLTa~ibui`AHhNB!gKOs zCmh2D)z+uU>e6iN((3Ngp3qO4?z+mI2H)>OAz*q4jPx`ajlrJf+%?~gym@2Px_q?*~uu?HdU+=cD?RlbJdLyJKb*KGiT8~4C zK{~k2vAgHmhaQ()lEG?^LqgAgkp?o5UaU$lmbKR-#9-UX&>=T&%D30CF~_IGU`iI$ zS=@WGn{l)-;f{8Xw6=h72;w!wC}4{e1nql;GSaw%4nY_NMj8nx7=_vP-Oue44`GQ= zc^cl%7@nDZpV+4l=*NW^;Sl|VZX<$Rp902M!L~nE+c+V*KfaX|PwYP@HyRVuj3Wk( zAF%c%()B;3`#_28Pi8fyh?%@H{?KS|(#YQ*IbrlH!6ZG`B%}JngI1H5J|?-&{o!)P z@jfi{?S@IzoFbKhV$49XS$v7-K$)k0YQO;1b|959P-$jBt{b2_4^-b7s97~F!^FSX zGOgtPSaLAXAUE(5^Ra3b^m(1(USv-)EmL5@|KaH7kS8q@*O~`EzH9yX{@_}x^ON?* zk8i}xI&7bGt$ysVHETzh^|6|D-5DGM#}&94N@XQpz|oz+_@M){;jO_>6N7KSL!*d_ zu`|h+sG*6F_|J4hNde|#&gRn?^BFnw*=qB65Qh)(<2BoCqFloHg0sN_w}q8T-?AKr z7GrT^0=(&9am^D+-!%9=7bB5vu^H0c7GSXz(ycgS@zb;W`LV?gru(&+#a?drZb)VD zR4UualYp=xlL^X?1UTG1E~Nbv<7o1!+cmQZ5Zsq!UM+N*CiTOI9F&>Lyp&LYN)Fy4 z)ochPVLpAXU=G&+-DwwmGZOEqt<1z`L5{Xms|Ibh=yBYC^)Eq8LYi=?pD$LOG0Ku( zRAcxlf84(k_RorMw`h`;eMXa_t+bXBJVRs4NY|$u49mmQ2*#k!V+y<`SBIKR_Zc({ zqTE(|yIGZaNt)!uG}1!_tz^;{#glItbBTUkii?Ctt^f5E;aeI=G zN|ruTyfYKmHub&PE*CvG50eZ6nKEYJY_3UX>DG`;EmQa$*z=BAx~KxNisqWk;^pKd z_U5DjTN>;RJ>yf*4JIoe{<2&47p_f?WkrxI54nv(Lpov76XqLkPjy@6FHoFl!BP0P z(+G;TT5PG6)CtK=BQN)Hx`t0QS8B!8fnS>xE`uS%O>A%1py;^AO*bTcSS{2i z@NScMe!ffeH)Gvyn8tv_l6lY8pRFVS{k=x<>Tv=?BbqW=<(i+Us6@@0B$sJgpQgMv zB>BdPEi~($z7?lj(~S)|Qt+dAW*{VL-7v@tbS@^qkp31_5*-ul%lzLek@I-uy5=Ng z`Agdl^S=_?-6j^i&kYiiR*(OS#hy)84>RXoVo}qZN)S)1SX>TZU`_1pH%p#Z@%(N& zKx-1oH2@M!!&TywS$+o&ud1a{2M$`&M44Y0N<=d=1*NZ$Qgt}G6lvq`f+G9J2yT44 zC{9Lc5K{m>A54RuN=!)xZ>wiS5aMs~Gj0kw(BP%Gg$rl<86uh#NbdDA^>G#I4x*f2 z;sf40#)GQzNWtrH5kD&@pi2Bm0*QpDSjkx|)%lpDhz4D?Fa|{!gZ$ZC{&X<~9y9hn z0|f_5xsfZS1ejE%Nmt#IMP6~=^CF!G9y76CA@O+O#reUw5u5l>8$#&E)OwE5Lf&}G zF9S0yPkorXyr2Sw&+L5{>eNXx0#CttmaSo6ns?(*#2A*r<0MNkJ!#qvrbVyL6^kNT zT!}r<;r=W(`{7x-f)}aAmyD-}E>gaPLlyuy1}!&-Im^`Do*d5to;-mvnQ3x~=2uJ| z>yfccW*+1t)lM91AAiiKn&J|>Gym^K^j{s)hL@X?Z>qRh^50M=&=RAzl8b}QSX(HA z|Mo&rJfBwJVk<6@k<%`!-6gi&nO=SQ{837|0CPAlPKU+?+8xJVlTy!C#t;uGVG}s< zB7J+7Y-baF>lmnz2l?#9dhWEGprf8K7m6&aXAd_hu+}cqsT)!9PnHk?(Feq|QyH!= zatALaw7Bu{YJukF7s8hu=+*f+Yd}8zqw%2(UBckdc9*v*v5zTZl8L0N8X3+5c3QZY z$gDJvJp-_EEOLZ~jb@sFa)j7Lqg`*1L$869D7`cTG8J@u6=XX*niq9CZk6$zG_xnq zNV0p zN&fau$P^FyhPZPlZOJ|>Atidu>G2cj$&*5vY~#=Ig_MNnR;*3(jt0++d)wnEKluv; zn49LyX#TRaE$a6gPwexMN&nVR5YpL!@7bMOA-mkTsWQfsq3~_~ziAm|me5tP6q8Z@ zYV{i?d5MgHB)Fbm^~k5(vWY*o*(N3+CP^^d+;-g!It}i>RHTY_Gfzl7%JNE1G*L>J3$2e!wGDdji(5>1@qwM`B#Y*6b~n4_aHvq6<<-|w z*VFuev@${S@|zTho9_5{C_vCN*|Ny%$9s$Kjk_J;$(=@yTRDk|d=5GGS$C5kbt9^; z9+xC-7AKyMMt!049>hL9d~h$$V<;IoH~qI`$hZ8Y>>ksT z4go<_EPp!)+RnggpwA*xr5r$STS?E+1H2Ug!3O}(bpaeQKr%|HVTbkc4qMv}`-fvi%2z|Fq72mQyqP+@0;ZwiPnZWmA5eUiB=_y#2O93jvLfDG13IEMLBW zfCZml7Ts6L2vUv%nG5!PKPovDff?Z$^INnDq-tw1iGCT7PEz&N>oK}<)u>A(z4PD% zWQ^XgV1t`9x_!ZD#sf@Jh#lzw^(I6&?m+)bF#Y1b`MnV1^APj6YHi&RjCFKcaa@P0 zoKm7Zf=gPP1~5~2h5k6!DW@t#rP}7G!Ec}X34 zJUqg?9eL`K+#Wvg`0qii+mWB{QGEY{yN@5x^FN@^#0j{O9z_?5%Li%sQHy0koQl9@ z8GMF5KFsKX5d0m{_b{UT_oMH>Gd}))EQOEy^)UL=LmXcyzV9KuVrZ1naRlEnoI*Me zj%G3^*F;q-go3UR3SKn>@pHa-A#t!-s=UjK;)f_kKE8)RUxdYv0j)0+60Sddx!Vc7 zNu!ww;5o+0jpy;JgHn@DTEiI079!@Fzn(K@7Tl!K!9VzF1>g>S^SwZ=m@kLQD3bq4 zJToKwt<@>My=BpavGP+m)dZf+m@iNl9!CGC?zw=Yb$HOP@HwRjC6kC(&jt8iRK0nT zCs3e5E&o$rFH_p~XFmQ<$ro|O%|G>eVLa`Bo?Ym?X@FurXCzYO)6g?Y=-J1%$hZ8F z0aJ_vI+1TR{!pfH!lA!=AOFVppY(k?d3gPi7!}9aMVkByn*4Io`{q%xHO=&YEa%VK z%07wayjF`JxCIhzZ^>1Aw9Nb<=sQ3l6VU(bnB0F7__(U)7O7A75uxet%J24|+f!0w>@MjZ*cv^mF=LMy`rCGgWbbJAVw<~&;B%ZqxzBDPGfr)abCL)oc1 zY+s7}?IStI^h1VPA@$-VlPsQ$IeufJad*!62;1O?2{?(QBVuO@3LHV5i)d44?12#9 zDFNqk>)Jaf%4>t!YH`)yhrcBVWOLtnVjsRp7BprMVd2&Xyv8M3Qr*J&m{M9|88x3! z!M|CVdJZQ2vdn<{4oT!}z);t}7YYkzNX z-dx-&Mj1|r9m7a4vN{&?JZ~Zub9P*e64M`193e9&zzEDkJ25lXR|mmRrUM)e5rt+8 z>0;Af1Vci9>xHba=^WSP0MC(%Lp=V{BXbxX=g=|DA9ech%yW0LhGdp}jTa~SYSR@5 z*D`685C(^=17ZoDkZe|f%uc_!@l*iDyO>13F0q;t-GmcugYAQy9BcBZl%FRK8jBIs`>Gru~i zz$Qt(^Nw8O7DkSj9QW5ZMw>nxn6p89|L87}EG}Yd-jU)=#Z0_w16?4CO2H#fMz#ItB(aooFbbqbGQnwSK4@Eq?nPn-_ z_*~}W{ZHgO69z=RRNg;HA||YeLE&>Pt>oZ$))pFA{}B!jN#gdzF(;~(bN%n3j9jz= z5Gm%A_z|rSlMTxW;ZNN`#1s-oW>6A|+ryDr%n0L2(IwR>!M~D>>*etLkB&DDb_Sd< z{~E|THKyhftDvRk687_19?p1TwS>ZTI4zX!sqooUtfB&s#C@b2+r;c#Zb(^l^VBeR zXYu4*Py-)5(H#VRqOV>?ALEBwWiY7gG&EBxeY`|tyr|@=FkUe%A(Db%H5*3-D6yT- zuk+V{@g>x9h)uf({H0z8YdlY~+uRau-$x#sScYWgA$dn;{yv{OrIbE4cKG7Rq~_(y z(Q=JIKg7wCt5TfV#^_b{0PASUNwA|b${AN#&3MNQ2z+BKOE5mMM5{TB zrBo(9x|1pRCMB;`!VAcJ8xLU&~5CH42p@MJWK4nZ@j2z(1*Pe36UwL&9x+UHPLBU1`6 zt4Zg(@20dZ2CZJ#tzM`yYAp(WAg&0wd!X6@xO4QPO3kJ;lR{_Qv`vQ4g@FS%J7cj| zbyIZ9&6QuZ)8&EnfAr7l7|DQoEF*PUK3G70g$znJ4Wi8V4>#%&N$B3zD~TX~HSYOe zQH0br3RVW*y`|i5b`R*3n@7j1KJC_dkU*GEh&a`5?=<@42aH}duo5RH?6YmMPO74Fjt9gG|;VUp8 z&tjnevinLML?GWz||Q^Nn`aqmtr@arSda zRU2CowyjurE?y)*>+{xwP^Yu18vzJPA$`Mg?Nx>gmrS%JTo{86Cf z1Ekv&^u=)GfB9Kq2m8=9CT{cP7TP|VV!;`HlIEiO?JTam_}Jh+4G{&158!5^2$ZBT zH~Oi_CNKUM)ktT|ot@sZxU@}uS0QRN!8^bP@ZBwLiQ6ry^5whe*!@9`*9%^^Q7eKR zSF{Xg=8xW88WuT1KD2F70=N7}D-^4%z0CFExaacw-NeV*tKyeV`n$Zvr<+bR&R>7~ z{c8W+e*AvK+u2d}`)T5EIX=cst8=!%>i37$kKg_9;P^BB@%>R_+q>=Hq(AdN-v4eD z?HlSV40-Tpe!ur7R6FI<1tg>oSPP8`DAY|Z6m2_=_vqUjU*g&JaIT#D`hKM5(!U;w zwlf)vf5+p`o7`KR|NeZe>oD~x>Ug~EpKS6uYUkd$viYOUKOD77bZ#{4n3=y{Gf6W` z2_zar3;<0$7Z9Uc0D;FW(pF``Wy;_(;Y69&Shn;c*-ETYH&$jCE?)~b znk$lSC{mcgURqneOapSgW@ry(@1a=G^7*sFF`ue2}+ho zy9z4EwBtaX^Ix8fb0_P0`#`B|u9&ya7+sqGRZrW{5?lza1#}v6@N?eUf@-5lD zEZIw~7Um40rB*>iYfcFpRSC=7sL|L=&|r=gX6Ma3x*@245nVU8Z@}(>GfE%E}A zgu&&%vVD?rO9J07xJ;#BV^uAPoM<}Lv-7!0mvxHjhKD)AsPVr{sPR+Hif2Xi$W!<7 z0QY#;ii}u;JI2JYgo3g~{fH=O-We*OlQ8Ei{!xe4AhS=KzdX)tKI_2(N0bTqzI42? zG)uOdvE|p1p^ckUj$AW>&kcP)mZmbk7fZtr;Nt)1{PP+`2TN zq}oKfyiQ_%%Rr#2ttza z!;Xc{N=}Fz+rO@FL2^{b^K1_pRJ!TiEKkh$AZH0hfI!sGgQv7=Sxe17^#rVm8fN9K znxcovg#5rCdoF@o3yHvh)SyIfcGK?vVnx;J1$F1%cel5q;hJH5+W0E1857ILA=de;X-Pm^0d1boca-zGjJB z7p171!JqA)*cQ7x8(hH{MFaNSHH-4a@98R6D{IN|or6=ky)N4c#i z>yJ;RFvcca{?M!_++Rb?P|*%5Gr%C>?n);ur}EEei^}{ODyAJjDtY~E;2xfNMdQwP z)9bE@(k{Vef_n8i6;8oR$=$`E@KVQU-Q6GWWqfoWbqvWw3n=1bFhpUfoo2xUpjA(;BvUG_!>|?qOQt<;!I#5g z88s)p-0D{p=GvoB$V8UGw9DFF0e+igY4v8&wXe$8nY+BxwG#F7W44SG5(PsLCSe3v zml&r18~-2CkMdo*CE{$3RA6;|b`+**mykc*fugH5nD~il_cx!sL|P{3P?SPN*p)W2 zSZ-C&0yi^lR(||A7%E( z=XXIf&g(HgsLAYkj$t(DN0vs&%gxs>F>ZiOc7;QnltD=sa{LxqdPW|sXx=QV5wU}c z^udL@^@O=j{mYrT8WcKA#Rpv$-ltV+xxB05sk2g({UCS5mbtqSFs`Ka- z<85zfs}}@)mo^xY*gu}V&e1J69@3hPP~4|Q+7TKJcwDt4rCMoh?rn~p=G6Z5)dZiv z;>9c8v*cJC$%g9LA_s6IEnK0owN-{%_L_jiM(OTPw#ymdG+Ii4+^-EeVc#@s{hjWi^f7)f-QV?HAiIsllvNgMf3mc2ge(m&H(KMu4OAwVWg1_j zbm*U2%pr4#vc+?LkkETV+iXY_D~ZN;zQIH)8z4t9-o!Unm%m8Ua80@Vd$4^OyLN9D zsWkFhQx@WF=ezH|M%eE%zj2H@#z%kOSumguRs>s^3hg^z!ejz?`DyR=$qK8T%WFV8 zg@`I_XgaR9J`#AFUYF@B6S$%(DRNvy}{16__b*zqI)eo1W zb@tFxUJp7%&tqI+QqT@w*}Ir%edRO2Xytx@6l=X{cb-ExKXz>B9SX?`BN|~Ov_rYF z^%osOlWn>)s+Y_8rHZJ+#&RdHg3N`iRMRM*#q6#U$SL=+NiMkVI=4`7w5kRzk<%uuMceYG((;? z<5^@6avu|m#y8Y$h?*X>BNrGXZSx|NR^yD`9qu5qrKsA|#d{gYrLXQ(4QSL&%GYH4 zW?tBZ(J?8K?0x~$DtI%al_%W9SMCb5;zTp<|GTlM zOWbHD`0GBrd{`4o%74SBN4$hcm^K;2DZDM%+S9CV@vB~@IEW0JbGBR{<1 z$WK%Gid=am_33P(p-VmziD~U5^J?~LaU6_wfv)OrV_)LOay7L7FxhOgYzn+23x+c1 zQDb~3G@oB7exX4P7QWc;@<>bG)hSFV&oAxkde*fhdY5d1$k9DN>FJ=I`_FUSKaUEm zRiDbUq1~MPy|@1%yy>pYRiv@KYwLIOTJa&-{hM@kI7dyH|5G*1ySvUa<_aGj+uK$zlq|m zAIAYROjA$B8a&}s@}5|yEEpz<>cw(vq^x%0!1T)=_B#kY+`b*$(+IqTN|)KKCpe6k zn1(9uZrc`EcU-(Xx8QRojj)z1#qUd(H97pOo@rH$m1u^X7fxjBhFO#delF=Mx%rIO zt3SkTq}J4d_f-YzJ1X?7XgS#Fa=Bh;cvd>Mc4mNkR~$sjuJsr@@XF8kA8Uf*cf0n*yK9~+tGU-dP}Ow5&g#vh zuTJk>cKaeu|5mAmUrhV}td{KnCb^MzT8NpVMx^FN1(^|+VA;teT|H9#L2l5pi%nx| zq>Dp#nWGzGA~)L2Wo2g7!{cygw1>~=l%-d|w|cZ!NZ`B++$S8iHEIOCe`aO;v{NXh zq_lZuxL+dc&e(_ZxjlI;f#=m@1CkpMq%i%U()WR+VP8_dl8|lm;H8LeBbZ8+88ghM z5@$24zL7gVthw82^GW+;Zv4|#z+amY6jL4-ED$MFCHrxzJ8;M_OM6Jj_zF-;h`u?{ z#>7-(d!qY-I-o*Z7lBu7`2@5-_scKYd@lTD8GK{XLA=!ncYCYw2K*6p`No(3a1tXE zZsX{6A#Ad_-LzNM-N|VY_eXX!z7;i-Gq>y6HtcsBwkKzO31@b5fjaWvZv>5+-<-cc zefPJ`!=lzt&{k`crR!iB!!0amAZ8E684s|1Ku5#GG%Tc zaD~;QeEO$S1zIp%ABW@~F?{}O5)pej!+R!0HP-%_NfDp5<>K>Vo{{Ly_Hle)MW!0I zdHX{~q%GivU{Ovj?j_U_OT4;3%~l4_i02iI*~wiVaQI~flcTO3l9H+CQE>RI#i_QS%;0IP~Yfx^!p$MA-bCZNEjVnB-V6!lS+nyBB_)1dp%xr{*oD zdHg%szo{*y@T&Rkn%^#D&!y%zG#nQ~Z2Hp9w-s~g0qpX78n%B|5VBw^!Bg;YX=BB* z=$7RtOJc*T7~^QJv;KIX=?+*w)C4eZLo@rXS z>HQ+F!x_*iUlJpxOaVvzpLc_%wkwfQ$e)17!j%++0PCE z#wST*gae$6YtcpB0_m8C9(0yI&UzUW!j!;$OXDr>c9{tYgiwSJiT*KMNdch`h_mm{ zF0xAx-hvTWAaMODz*|!FV8TdV80&Nde_5i+09fu=mR)vhn6Ts=Q0JxGG2FP zB(uGZRpO?QoKJzU&EtzI&a{l9Yj@cW;)esB;N^7)u3Yot0h5g6q!V9QiD0!y??>BFrYa^v+a$!d;UE?Vol-k;HWx3 zDx|{a6F177cI;cF(a0QUDW_!ulC$#u{b5BuYm!dC%2P3Yl9FIYY0Mq-OPUT@`m_Q@ z^qJT2ptlm*KQ^YqNVLSW%n!%t{=a%RqzAcjMB? zF&s7V;G3A2<`d^_@n;32V;9(ihs zbLZN-G>NSGztKHalIU*T=XtU?iAdKY>wMdDp&UPH+1|eHBT+Q>E-%ISM}4KqY6Smr zb4D9}`W`0s$9Xah*J>MZdocP>j+pREj(CyZ9XtoCKGSgr?E3g(f-NFObNhnk;%6<3F zPYR;(<>!OO9QkCEu-TbKg@>3r`JZ=ni8BP)Z)~DGdqBHDP5bLNMxBV!h+kUb+H1et z03tgn$5xBFo+WOu}ahx$h)*{%DX>+IPDF zvkK2_-@=ILo-=>;U^c3NLBvmcjWpTgA8P)%Erq+``uZKNp5t7tL}&^BE0QUEWn#T5WaseUgXbUAZ)3 z;0G+1z>n`ywJig-H_o^S9|qR+*wu4n@2?{NWeR_t)mJWomY(rRtCf~vfs&nc!y&-6 z9hpqAUdc=jhsDC+Juk`5O=k-x+fIoiF#Mcb?A$m8MhAPkMtZM}4Z{?37OlgKO&^_u zI}f>0}-*!du z40o)zu5WX;PShgYIs zFiHYUY{wNEhaKx@aHTa@MAf)-0)4>UR!h5ffVWU@)aOhf5Czs6Sif6*RW_$q+S| zl%LWKTQ`^dV+|#|A ze78VHurtC21F9#A*iM#0_X2gRb{+!D)xL7_y!~~XJNjAwQX?-gQL^WsW-?5WQxpZ` z&@WC%(33DTMhg^$+TMdX<4El0g>GoDG5L2l#D{J#dl2_&s*>hjzvd=Tw80uspcm1P zOFJln#G2N6+Dgf>z~(M{@xxQ1EO@r7FE;uGV_pM)yJEz_j z!&8`w#F!JWY%AOV)QM?2=>wb#%}+uU2HbfKUm^!!Ve4fNzr4`2DRSX!~G&x85T;(q%VG^D(T*fZppJ;EVO| zLePE%3zqz4X3;@FLnRi9;)JhnH@3sl8H$3>;iq=7gkHUHJ6fOhWwp){0W*ddyuf@K zdEtPESEk(Wr%ED2-XO=)ps{!PitouR!cy8{r$N3l1McNV1mRvB^Y`TI5T+mNHDdVq zZ*vWRR4wJ9B>At`x_g@$1cR$lKY^F$$lp|jLYH*;I{(m`7Jm!OBRi51wUlv)FyBSKl z8EF7ew|08xON9A@9AyseBfFO2O!M4;Bp$!<)2XD5rcPj363cXw z6dN-nESYVS!X_}*3+(3)tHm0Oz~81wz5TproN_r!hj&Ohn^qW%PIDoq!G;3gvJ!Yc zirQz1o^?EPKY8Y*k?tFoe)ny9;7R&@jf}9cj7J*jd_|&;aPu1p9&}GZ_dLxDWbz_yvnZ778_b5h?LmZPo@o3e#o{#G8Xld;xj@^db;S17k-i zDxd(%Vfo+Q=BEP3WcEF4SfP@oBV2pe`p2PSyD~Bi(ZJ&1NZY~F-<3`abECK`z z03cd`2nrx4SbRyd7(yuGgBRr2=RcM;ys1^peYI#CLbI)h(cE!No2P0Hy)l$p+-kl)0={2rT9)Wmn`i!>XmJ z@!v*D1YqqnFoo>OjPQyVr+FNU)uWm<71{6${f0nM&5~yAXf{0Ev6jQF;!pr^@%=B- zIfZmDiIkiOFBHZM*;jeRq#OVeFphvR!53d=YCmPy^UyYY4~O@jHuQzRICQ*tYJEob z^FzUMo<;spgSx`$I$wh{hcFmMtl~#@{V&0n9~>)voho6=4YzY(wc&8TmN$i`uhnMX z+-<28?yTl10PwdL78k~G(+F?6n_14@==IDQInlkQ%j45%;{!D&fJCgJ1fUqDla*`^qS3+j;PTUe7QeUFTdPY zq1hl>)FuRc!O>paMvYmSwV`6oPCIVKw$!pg8$|z9E6ugd3U&?6)VgbRoy$ga$qLm# zP~DKC=K`Ig69AEFxlXMfLb>USmOs_P?X^si9etXu9e>`41G}%}Hi<5`j7Gft?ey;3 z%*7w+m-p1;ymGCnVLhU#7ap^HeGx5Te=1&Tf2?oq{}l1YYqtK;+?!vsAI!CD+@1O% zSX%Byd$jt1);E4bM}WQai(5G_UpakzGdG+QUU@SYFajMEMm2qM?sz)aoUGj4lmCQuoc&vvo$ZG z>2s#!<|fD-9NgX^R8%2=r4@0jxkOW$>(HqCTCp%v}O@NjU=g+fx?` z3%J%NZ&9nZTPHuYj^@pM?Qp8d(*`5LVbJW4YMq~NJevI~SiBUD;78F_3R@SnRPj9; zzbTBE$?B2Ud+`Jy?4$SQ@n1#Hze@rIlk`#IJI#|kSxv3KBVXfZc3ZnL{=y&V0fO>h zRh_Z(yPQX~y3STGZlqS5r9dMp02!m>eAhVwfU;)i% z6SV(e3joePKfWbj`?vs|`ZCvc8T(dv237<7l4@_fB`VIqyx`y&NDa_A%O;DqfGMGtNOG$oW9Pri11^gmmxqdZa08+$9tAJ z$jsILEMr>%QCO!Q00=9V&fm|`LV#L-{Bo%~kzIozojaW7AV_8lC5NH`W>T=JitcA36jG~H)p>dv_jO^Ts>+y9r zs-D2O=fb!fI%tXi7v;(+bmw!Q-UyqwL{~@YV=-l2_af5 zXne#7>4I|o_XE20l*6Ro+pbqHy(apzDOfky{xV`@PvgB2J)D2_g|n>F`vi@p*1=q@ zh}z1eJiP`Lp61pm8fr%lYv`I8f74P7;iWt|kl(Chj-bP+?r$c)Rxv zyd=HYr`>$8!SG{g)|u6PW_#}1HMuihe|`BRjs|c3^ripk9o+=YR#@|ZUl}&UwQJf- z{~am_=StOn^8C-r$PJgScgqdW?EUR}IOE%I=Poxg%L}9xgTslHq~KBh2^yeUsgD({fJj;nZOi9U ziU^@l59h${&Y8^HNN1O$SAnEqbzq?9GEQfZehm)bcw3TkotYK>Rm=SXW6lkdX`Ie| zu;7q)|9;t0Dn+IvM%0!|W`umtRdPZEo!K2i(c%cBj;J%IDLaWJz(?8@n5)so4vg~n zi(#s980BhcKH0CblGjHZ%~5h6m2Cy9LxeKIM##zsA3Af;7}XH6-}xM~t^aF5Vy~Xk z4HTrh{xxsm)BYOMyRRl)wK#PSw)oHUZ6kHalo(beW=Kp`!T3Nj`D)XM>N+Sj*)&0b zu2*l?;>q3jnH?4P+VXf-7wZuxC%4Vn@1hE;xZJH3fiI-%CJGt0@lSv-M5L7mt35Ei zP2|^~zfNtp zduaHN(lj&3Gm1%#f(%vtOb(N>Rb9NDb!)-gj8^2OK{@V?xlN$%zvN)b^?%?G!b$1r zFkI9fR!@y@4WBF`jDDwWgtdZbdQz@=E0m0V zXMcw|bwaTTeDP!1RfzoPEsMH7^6L8aM~5iB?qo@@7Wj}l`wbfG+r|N1I%Y3DX*rR8 z@mcuK;{_F)MTSzTcZWw`b>Chc7A|h5zqT}&_bbrQ>(ig7G&YmkNAwh}U$oY={UtOh zLn}VV#dEVV>RL9wea7Z1i4Rn7%3r3h^Jm8x&no)pagQZBF!*)rfRt}Wq01DtngU?myw;79L zG0*TBVc_T z-KC~$k2aLEVY8!&o%qC#%%aCA>yrMuN$}&T^`zG&-tXbQ7Ree)zI*LudOo}P>BIyF zw$V6kyw6Zj*}mh5bobSzBc8wtc{N5o#)N;;4bG=rg}R7jeW^W50)`vT#l||1z#7nR zb%|Zr{q%L2$3BIAJ1^h}D+Zd8t;r<^B@9Zw7`tZc_{<5>?dZ5jf4;HYO_j_2zLfXS zRU7)ykaB&3q*Z-sP2eQ0Fwm=CYh=`_5PgGcUGr7Ee8#HU?htnUso%|t)6cQ?{fL9m zHLJe{N&2~m9ws$Lmui}2Y=8Dw-!`ZOa$0>!O5UmouSvbSZz>;Z2B|wet!iVvX79HV zR2P4@+C#dJ1Ex@t#!*;}mYW6tkG-?-YeP@dJx&Oc;I5^3TcEUPAxI%e3si6@v=lGJ zic28DEl6>9cXxMfi$jaMLvgt|=j_bR%%0hu+0V@0y?gghNIv;|^S;mX{+?$*OQsxm zVf#J(;*>vvf;pA`gE9NtSMW35%KSnelOINOUo1O?DhfY*V9f6l$$jKC@zz4hReQ4U z5f(%4BR|^!7vvxTMGc6!z&3enb`^nD_l?}bHqBgT%c#0;=O z-~9VRT68Tyv)G}ZdoCBC>Q%`)^@*x1%y?71`BWF`eu_Wub4A&5b#E7j$J2Ua#^wcZ z&+>X?n~1|c*+Lw(|Js69JA~=90@c(Y^L9q_D_cf8)ezACgCg-h7gJ-(YlyGzl>ue5 zMh7n&Uy!KHJdOkvv#{)b$Xu5`{_W%k@~C~}9SuV)(dZV*tUWOd{}~R&bL+`{=r*cR=cd(yEw8#$afc?QMoA|LQ#l=@Vw8^=*Nq1 z`R+fNeEGNDgx>3Ib3YmD6WRF~%9Xd|ep5j*F0-nfG zvNFAow8zCjtnW^4s2lRV$7S^BcvvmSJuyi9YI!)|G+OWG_+`iC=0^#6roEdp?T+2` z=;mv3*g5SFk6RK|@!MNv>zh-LlWuoR6Bsb;*5j=M4AapK-w`EOfH2l!o9r&6LNL8i z7)6fKSqw-MuY=li=GpK(t^41_-!#@gtcMqyBTn)XI5Pk#P@r|}Xm znyE9wwpK0OSHu4NBS&sDW_PsP#z!f<7%cT@c4=!m{;{#SvAulA_zhI`TpSL@=hRw76ZtsCpPt!x8fdw3PM=~6g`rt^@vE<_(}m-` zSmUdm6oYc&MKbTnPQ?dPC-~w$Y0r&`G)<^jLiF~kyz5Q4MI;Q%3%@yt`{FM#YMK}U zPn^P2xj@Fv%0Fu+e;F+QH@4hU_BGD27|os?eq5ctW`np+B~8_WjWv$8R^%2vn(E(uxpsKC$b?xV#LkC*s?Y>Zd^F${#s!2hVaavJA2VWZ?5qRXO5aN3p z5EXNpL#+0vUQZ_$gJ|kfzPupE2E!neqcvXx_wi&prOEjtJwu^~kG-%&!(U;_FuF%) zyyR)n2-AN`!-^L1k^u`6ZSKaYqN~p`g@KO~tFICTa#C51x9ZBJjK$8~$VzZb^3_Os zua*lzVoY@zD_s(rt*4TY?HlNtq~*ds%XgJvq(!R5P51(NxxfU-3n5IB7i!B046d?y zgh^CZ-ln`Vjp2Kw!tyP#iMB=56c-jysBW{UAx>s3{q>j#JstP)KCwULhZRh4<736# zG>{}ahy0s>4U!^^&V6thg>Kk9BvsE2u6ZkLem_Z&-kI3kW< zG!+f2!=4pEI{kRL9jwACaG!V}DZeB^Xnw>j>m8Ss6iMi!=oX~MLO_Z{O)Cu1{Y(Ru z5GwLMwS_`9#$+@DGnZi00hcCYw@sjZO1kB-vj!Lm%n{CLprKZQp;L`uQAj`3snUg! z?d)R`Nm$Vmlemmq{7ey=OyS7Flr-a$6zAjx$r^L;V#j#v6+TYtVtF-Djj=E@#ae=D zY8YT;wDZQ$)VWnH@iHyGCzRaG71>*Xvv35S#qC7H@PCLUcD5Y3Hr6&n&Q50k^bMm- zdxYS(d7G7t=o_-P0yU8Kl~1a(p z=V4bRMy>o+UC_qe2iM1jPb|RQ9xsZoPu@;3sqAABh8ELoF%MmzuTRLdgQck+tB{as z^O#>8PcXjB-;twpe|>VgC!z5DGHK|9GGh^yE)JlRAKJ`-i4OL=;-Si7`1mng2S5H& zZT(av6US3V8O}toAZ5YchANA3X8)}$hV-z=n^#OfU170Br*q$Dl_jD`1VfVU0_=8t zkqW+jxgw4;ROBnIw748cDeg+m>!%R3SW5xmdHx8=#Ha(1pyKzUR5%EV@WTIPY$XM0ThQ3L} ziZ1}r_e@tHgEcqeKKkZfaFwDm8;56y?>sj?EGC0vC4zQhN0r4U7Hd%nS*==UBkP6CbMb|WGlsU|cSW)C#fFj}F!2sEH6=`?ghlP&5SotJGyBN>`8zoa{af@<+?og0A!*DJ^fHZH(?I5K{Nfv&qa9mZz3}!SZnaGmm%mYX_^FY!OuKv zT7t2dS=DqlLahw%&}?cLNscf#*73iiTi}2af2n(ILWp<{3+gdm6~e(bNuzfDoO>MJ z>LWVqY1g6@{Zj{)0SoPMH@7EJHc}WplnF3yte`dPJ2C z2Dn&_YOG6g?m;+5yi8LWt3mO01?L)*-+ZUQdNhCD_ z9}knyTaTOtt|PP*R2cb1qqhtrOA5Pch#pEx2BXS+Zdnd)H^wH{e^!E*k*=V`CapCE zrcHQTqpc%d!;lJcCs0QhBF9l4hv0j;8rwZz=yoJ8@sfH<>A)L9l`+)y9M8#1c0rMOCdxQDUUA9r6&&M2~)}@ZGqe-H-5wLr>HS_ zER-rLR?~Vvfmt7W*;jjr%G>-WO8S}9FU;Y`Gr+U)Wem)u8ZhxiwXV#5LlV98*0w3g z=?J>B zI+B{@26J$CkX@AcSLw`{VS}~M%^&+a^0aMJai_F3J=})GK#?~gFDN`Y__b;a!KY=+ z_+nuEuU#~Lg>+7=z4EENAnq@4tjbW{#A2BqBzEtk6~?Xi&^pz{kEFntagWQ0JD%km| zj3a&|(cx%i05c4ZdfSFgGUbqH{we#egP-anf=Z-(>3Nkb(P#Gal-C?JATyH0FQMwX zJY5SVkdCWildmqu>dO7Yj@%_~xYi z_Ig*{AYT~oriJz-07FaizOt^@4a*n>#O zlhDx}4E4BmAOWs>kWG4GIeHSukkGDs(yu$SIeKx#cyZNu@l1N%Kl9?Hg7XW>A45O{ zs&D}>IDRVpUK<>50Zxs9z-2}dNFlHd5Rdpk3N;9&9t6QCLZt?wOy#X$0y;@Syo7pd z)PP?*dTYgaYt?uIiG7~;cx#z>zl{MK3OzRR^Lb<9V-D~!;P8F6?qdh=e!1@R%F$P~ z$JY_yt7_s4tMUD??u`)gG4Jv5qwDZgQbUMaLzosqKTni$;;b;5d4}}%{Z>=IkY9rD;5n|^NkXVYxRFN{8k+M#a&{{6G*huM) zaHaD|6;4t`>d$=3M6aAaYs7wj9UYhtbr0XyJoH~kEAj;4w$|N?*tTu`q9b{1} zWqBUOCId3!jAnWjZ6Axu$A~_LgB*LKVVaS4=h2>;F(@0=FE%EiHYR8)CgeN@NgW$5 z92=<_8|4&x-vIv7Keo0!Ho-|$`aHHp5l*J4xG4pQiT zskTltc1mE;N&{phvh~p(w}8BnY4_tKIWE%5iPQPD(yyh{A5T*W#ifh%rHfyrL+Zk6 zs54}=glV-hocJ=Jbs0+28EL*L&*LZ=Xfjc6(qB1e{#tFFsWY9acaf=2ll4|4%g`)N zMJr28GR*`?N?MmCXpm_cN1{NJ&CQo>mq%jdoP9Sn%XvE6Jue=J%=XwM_7cgV9nJEI z%L%B50^(7|?B}Agd;QnIrRw4?Q zQY!P(x3(nIGo=*f*`y1l^noNS@ujrdBzFT#*#pZs`-!*}N$y>i($SW)DwZ?d(h~D+ zl?eux-@7ck6IPx_L$Se)S&Ij5@R+-gTnb!MHqslR8tM})t26Fsu`m5}=f?^!2&Eu;V zb9`L$tK0(v?P+UlMQcU?)jokW{`fV4{WaHqRiXH`$|g0winTf>waClRINFM&%i0v$ zx-`+c4DGrsm%5zzy1e?jf|&+lGT#mxH^-&In%UH+k7b6e5~Dk;?jH;-+bXB+9z*X8(6j2+muaXg>gW%2Wi+v z3t6D8Ba8|v+QQO<5zRnaO7ZoMFNrLjT3Q0%ZbDkKM0F15GjW1Iv09|oU=57ak6&R# z>m@)XE>moR_7xg}OBK>SCa~eiOH`t{uo1RWp84K9(WVNxam5gxf|jlio|!j1EoqR< zH^-1{zwRTkm~X~t#jyszQD2L~*jDH>ZTPX#dXLYrIR(v7zZ1urpl!eNz8R=@9DHTf zq77D1C_q!0$Ee@ezr&2H#{_ns?Ow2Yhh3_)vYEcZ3s!_++TDtQqej46OqC4QnCbk4 zu5wMc6+J*JOj9QCRwsttHb|}j&C3;6i3}Gji`aPtE4u*AAO&oJq@7$%lR2XoXL=-! zXMMd7z-I0dDZx}YCC+(WBsPyFQz9tA)djRB7*c63$sEA+B>V&{!7F`wVwHFW0d<&xXi&{7Q$zuNZ4Bt314!Ja70CHDs9`gsOQY=p z^AI4_{5ek=u4{{eN#~DzwDpwMbh8$HQ#dYt-OVheM$SmXWj+wrbo8w=C3;w04pcu= zKd)4$R@+ic`z5n~_%i;Bd){bPz?VYqq~ZQAT=d!ZZ=Za9?DkbC@vBJVABqy_zezp$ zCZqdJ*6kZK@%M`oRHxE91M6G*$26W~FiWrRxeZ$o}zDKYX2(4Dop^y>FW>U5)WXn>%#^QAE{lnJT;=1ki~tt%$tEvV`6XV3ZPVSrOsi zWWq}TKz%GxUVENYjLemJRWnmOV%#BK9fW=>pXVZm>Nb;*nI)Q)dM14eVj`4(lSku2khDf))FIrHiE@5Pfjbjgt;&ue3?EvVmxLK zw!SSPyoCVr8^G^oh~G640b5q&1sWo8tyJ8>sRYE#Vx~-z3qaWXGiQQ@R4~r~=_cBm zLdB1mXly4vQuOu(H`dueIdkAX$g>ble48ZY{-)~k7V;Fo%F@7Spbf6iwUUk23| zs*^9lVj2Nr8fbG8Zvf^pvU!2Zhy9u(-E(8wSf$w3EnDQf8EX32>LK74|^2_`5ctoxhaWcIJb~4|EScfjb{n&aL-*4CV znB;#X^c|us)6?sxxH|2krbl>oE#WshQbl!YoEwED7{HI5DMpbvzT(d?)SMeAa;$rM6u#f>WJ z#P5((RIviKH6e`g%uC`7@#f6O(ol!9JT7aJFYB5w8-83? z+nzTir;U?bb-cOi^0?|rzUq6Eq4lgmZ?Jy2`HGBY{ENpGt4H0$o9pQxpA&9*2{!b5 z-JSt6R0-n;@jmWje42}A^&sj}p;2wY3wlCAGaUcw0b^m~wE)KP*{#D-aUL4qM+Q+x zAOV9+jLL$P4rkF<`zIVjF zTpL38IUXvVyj)j_KJsIDn)lVDKjWEXoUPeQ#;-ZA3-vnVezJ(=X*J3wIy^^b6-{dT zr6^%%IzVS?oa}O(sUhg?QeS7h`kr2*rSC=I^ylKI_GG3+vIPfLZ@WCmsb1p=Z-`Y# z;tPgwAoG`fBC+4$&}$tJ53>lf-&=R8kape2k|J|-{$vtfe)}OB%R=_f0A4ND|(84>%;t1KBMQuq%#c%=yi zmrJBU5?FjP#B!{qGNj5fd{4>M4NIR=zCrNGQX6NK%F=%9;FF_wST2=g^uXemu=Zjt zgWd_PC=p3$muF-Pkv)$5e<)6!Bukt%6JL5Yi8t)^x?KO>eXkRF=invv285VZhKdLKRQLE6Y$FAlxYrk8qV@sa! zQ|D8$%_m)lc##Kl4*r+2Do$&aWN+L~b^Ve)o?{E?d*aF}BtYaJA-LsD%3g7%9hAYZ##{EByYmx>4=>=wFKxjI(Nu;y-o?8z(xf z)*2^!;E0%{`m)uTq=(9im}W*B)tP1|`-qt3X5*CIg7fmp&&`a>$Lq{N@pG}}?t4G$ zl<&6Q7yVG#ODia*G43O3d7TkiZ&|mY`?+UULZdhnHi?&dCNG9B$#UYqj%n*Kk9}CWEE_||ay?<# zQ$=&|=csN}NS}7IsQ>PJT5i8sE^u?kb^F@=`A9sfC?P{D`leUMvsm1vsYEW$MNO{J zxlO&fN?iWYhZYtb1}C9@k+FzPkivp7h5d!x{o-0(&mjCX2@4wl*$H-J;VvwqQ=Z3q7&6dO*a>ggvzc+K)v- z0gf>I=ngdM=~cAFS_90t8ttuqVDagBW&{bVJr~Oh3P_nfXOwT&onRk%cFZ^RT^HM*JwZ zpe&jxa2DeR0Ck3AIPWg8C@z+v63n0nw~&~buR$8B;s?ehC}VauG;|G$f#Bn`-Ica8 zd_l$At8{|nL*$o%!OPc$)DP$I=E;11mJP$7A7v`J>S2B2k5sdGCt&r;@0y^k{_z2( zo3cXMvy>b#h>HnJ3vH0&ojjRHks&4C?Npb*{qUXwAsdDj?gasZwjco=G;~7L-=JD9 z%!mey(4EKl9YYGXK+h82$>e-|jsu(9{?O;gy>A4F4wa)TzOoYTGe6sw9C%#Gt9+Bz zeI!*jgg}t+aRe=}sk{d*_}SjYIEco8wxQXv7za)7r$hZ>`nnUc&h z0g@1Of2qFk79@E0D2D=%CLCN+=9Oj*;qnTIaAv@yWnsMX2jaqZv#PErlPO|5^x-)9A zT@%lCj?565uf$QdpmT?GacCjg?LCxL7QR?v?*5)sdcj^z(wq0g0lYx&dh8XBnr{)n z>BpWBtyWmc$JAY@>HQDwZ4L?S8J{=F%|CGyzo*Nn#yQ{lNX|4ne=%Ou^3>ACH(zIw z!J)SI-mYyX_w1a#F(XcG5k^_P?zX*p{r8^$hi1|5n^Bb7R>1&~%>}vs+~`K2)t>a? z%=e#Mu%^=YJ+2GdKQ7}Yns2eKVAuuXV_jV>`Sc~$HD&rZ56@aamX!N6Vhe+ivz8LP z?~)>$wD`0_59ukAq#<-~eS(DAS}_lN`4 z+b6mAy*;;=80#n7Laq72yl)>G0`3SuRB$JZh;N8gygS*a-enV2+3^0p!&Ltp9NU;q zF(dxysR3hI+qkg?qsP@#gCBit6IR5GMJA?(9J*|iel{43pH2;X;Mk>LKQWP_oF4I& zwM!#!T$iSe8tuYcOTX)uHS>J>OLUW_CEqojqm1*{ZsP6ir}XJg`u5+l)riHof;Sh1 z;>L>Y!}1M+sXB+I$M5I;EPM*r*Dde-)`(;8twwM0mU3pYTh_kpbEAck;LOypk9|ev zlMiOz<=Gv*;hFC) z=RX@o!_D1JX&?SPacF67`*`bFygZ97ccy-rXhrZ)j4kDpkRprtK?68pk+R#d>rs<+ zh{NpC5y?#VQ}M%Ujo@Wk`HtS#O*T>0vnvmLod({E+r~{K$ahsZ4So6^2H(3{p-6Tb zcKdFF(kxe>dI;AC?;bh0G%!iM5$Ub2w9Am2+vIz5HYTXInPaTGMRiK~ty$c@EP8I+ zSk7g7tjWHrdT!^VugmO;xI^8<+^$2n%lDs64o#liit8ZmZY@80i;|yJtYQGjN(C5)_@EaurJj^v)P`~^zKk5>40Co;$Sef z!qvf2Mt?N#yS@bZ@~mgEGJa&7EGlnX83f@#dWDLd(R7?o>rBwM1_aomcQ0fVD)Ywj zHOhgJ%wV7#qZZ05R;=QYCFdB()9tS+)J}QG-$f5#fg?P1<~Ha0tM~dFFz(L22B&BK zX!j#6uMD&HYsm_@qnM;rTei|4^U(bJKyCTjaEf#w!?U`IjjuT`^YsSnDz_#|-t{Lv ztFPLbsj=PqK3HG9_oD@l&-lEd=3uEOg8R)-L+#PpNV;P3^TxWLTa)GHKZY9XPxt2A z18*6Xn;OoK*1zVz8E$I4Jl$XFPgZVjy1qO++WIlv++^81EXM+ZOwDA$o60C>!H3R%eZiN>hhx!?H3~W-!RFHq5*~1chlq2!JNRNCUcFQf z`kp(F5i&anoqQ=~R6Xbk#p+S^^1(Ju8co9{KAtzJ$QoeeFaqUqYw_nOhZDu!Z= zQWWgBZ2=Q_8?nA}^R|7N3b-*%pZpyI3_zfeMemC<*Qye^rsY_w(B;^$$PCG>i*> zj_Ww={G8DDy>~Kc82#a7$|Sq+WZL4vE4vvh?Hrya(xrI2Sx4ob;yEYv+Y9?2Fx>lR z^9V}Ivjso)qO-*y!QHbZq}=`Ulx7@3v&l)mKU1^ z)w>s4CEfQgw<{(rFL!FziY|8>P+sv~3+{uf{SL~HR|h@p#aD*|g31LL>rl?1(A_3m z6<)iJ6pY3_I%+7s&8%WKMLe{=U+YaNP;37euNX%V^^(zfALSJrRNtHwS##(! z%+*jzobd%Yx3Xv{fm1zSd9t{e&g(tOSZEYTX?H$f^udfkdBwia4i=gNKd4d~Npw#K zo5+E`N>CbEHnfvV>mWd5AdRBBr}Mt^L7+ZCI#oBci$Crl$V4ffW}>I-aos_%RZu$J z8njzv`XIz{Af4f~r(68uAQVQB!GtT{BSmwF^i#@Uq3rFE6*&w;24%3a%l9g19frpY zWUvYL_C9w$j7TBKlAuf;WBGoq>BFd+fz103z5RL@ zhtVwrS-igT18-@LVtSOa_@jFVj6{xNM}o2hvgHTOw2tB?2eKYl_YPV*AH~lTWD9l6 z57`7@dmJm=ZMrZRvadTz+z-kYd*}$mBtW2_BxH*}J<*0CmTi;Ke)eEs9mbWI0{v263ivc`U>x+TBT^vh60^=r2!9uG!OCe$>>r0^!9L{B= z429`(7?dq{Ib7-S#&U#;Eayt(tA7k{je3;RA+4Cd@Yb0@Jjy7~)M8)1?my=3YTi~+ z!^!4WaSIOjc1Z^Xinl#%@wwS8_98su;TVdcWlj8wJC!9O+y#}*;sO6LZ}az>u1>a4 zsKw>kZ%KB#G|$EnRNQaVve`0kBOu*;-r+B$^tbc2L8~EO^lE*;yrNYks66_JVC!f^ zhavd*3p&@}-^SbOos$`>?t7=Rb{^ND5|V+mmbp)-w>zhQJ8y?;2TRt$h!Fl-5x#AT z)M}#7BSn7;Z}+Z_M&wYpIp5SjUjLjlPIi3Uej#N+M);W*DL5Um7Vvc?yZGi}yL#{D za=-h*?bY$b$J^_(|0Hiy0dmk^ZgUVEzuo3g)a`ro2Bi`hL)&Sl_kDy0Qi&XT+8HkP zeIW#CVB3E(Z+8!HOJxoG-wLB?fE-&Otg*R&&LLbBhXB9Bp;XB`MEDmf`WeuUzu-_f zD~N&kUX)JnA2{Ts>KhWsM@Gi^HiKOz4)WXFr|M1WA+qiCFE@hpLekz{Ec{u&a!B19 z0s|vRM>jz%vJgY2n4kGG)mBSgI-{yySe|_DJ*c^__=nHq`$WXh#o`6j-1py|LuxT| zAZN|LnEU>(bLf}3uVw+$RP_off|~n)#->@24}GReN$wXUPf`P>NuFe7^=ahh{pH;E zyBx~jE*p5fwOu|U`|I3?za}=E7EoB8BZ41_QNW^TRyDFnx?8%Yg_`>+zLf8jZ0|jlsLCKK?k45!R9R9~H)@XuvPxgE) z{>|Jcv{rC5BzC%eGz`JLcRV6P`QdmJ%3gSE`$I%Kv`4Wx_OOgzu8{59K!|ABm`PhZ zsN&_rExw6Anfv~gLlYlP=N#7xPrtkVC5NOhKP^g_q2d2~bD!nKMoxCopU!>I^l~0* zLxKuI$pxX8JS5MAME$^;BSWdY!}h4nV?gjPIE15^XNxXFmd#Nv_g=?aQNy7`)3*ch?NJU>K3oxLf1j4&AU5~nQ{#1i_2SdZKhR!M0lq{4# z;`sv3SuFW)JW2hV%{9&9CTKlTV!@C!SmY|EXO0SJ@W4 zBiP@*x&D!0jl}YQjbMLmbG_5Q@U&J?NV16GnMJD;ygL$KS?ny~Z{1w~NU*Je=RcSI zZ7sK!hP;$TP8IZva8?5(?n^WwLmM62V?GuYZT%NdQda+bf=OFGz3&i&&wxEDSAv1@ zuj|}z5W@Lg2>q{o_D`43o*};f(pr8KeFhgnpIJ7#~?%Qlv!Rj0R`@`55&d$!EVnC|l6Hc8P;mS#agB zeVBKtElrSg^lLUSVA)LN{`pdLzU0Ny#ar>ZufG4a>)gkGK7?2#;Ud;kT)NjBYLGt} zg#K4j`bS9k|BWT3K}=KSGqGP*IU_Cxi8B)}Qn4s!nuv_Fs0;O+tlyRJ|CUwm|CK@L z$u+zHtDIy0(ciVoIewnu2_%wS=O8U0?YFc(Tc-J>@H-Ozzg^}2j6wCIQ#@Pv<*EX& z+92PrEEBnNxc)c@{U#~>hpXIwp`@hnpJLEbz*TF3sz#b75o8>bffp=d_Gf$6G}`|v zMgIVY@V~QCl&iY0q!5{bQmi+!HWu1J+5Dq$&K$mAh0R>Q*nr=02>&PHMd$Rwbb<$^ z`249u_{TlV?yo3CLMiL4ia6AmAEZ@;h6n;>NC${mWGH+YIh4we9OM4z5dH^v`J+P^ z`Y|&>BA=`5=<4gXFr_K)h+v<>k8Ry92f-k$BG*Em)9=QAMJf6(#Ea2?3NL@nA^ham z@Pwg*5f#e7$%|fy$&-&xNCjn)BnSWHcJ;p!&p-G$;r}g(2RJTvR&$$2CRWDw)V#3f ze-wIt?>OO)=rJexhe$l7Nq@J*v-SsxXYuzXp8LW710^1rRRfg7v!#al7ZT6ko2C)_ z@26>mqtY}YyNty;Y#|tX+&`Sk|(b)p}B~7EB#9x#3mo$x-M!=mA1DLDjrJ`HbI)6c*? z@O)yoH~7#h{CI0J^F(hBW%KoOV-4NT-{UQ-kxy}MOGZ%JYDw(YO&PJ4g(1-;sl0k#l2Bq({BY%8rD7)J@>UPSB8hZJ2oXt4X@O%rJ3#7y@gU0) zb+NqYXm?Th=>Dvb^H(GS7k8;5fbYQ&q!tYsB-T8U6O3;n#fhbh?W8~AL(Vz6in@@B zr3}RhPJtyltdMJ*W#QwPg%{v8ohEw7b~`JRl5pA*IX8)p93+ z-R^vuMEXo)lpF|7fqe*Z|K&pJ?tvyaUJkg7ekZ^P+bBg4VAz^pL1E6LPy>uKEhY&- z@ARazb`A^3qc{JMEr{p?7YBxrvBuu7kt{pg5H0g&1gL5jDsFI~T{Mz;=nj8I^S=M@veXq6_E z8IYxSh{eK}Hw=>@Rhy0aN(C$!ZAX%OJ^~YyoKNUW3TSU1B_0B?;xK-a7#h0Sa?K4T+l-xyR;-H*|4-Z<+rgpe&o#AYQm4Z zSn(EYVL6g>3a^|br6*sv6FzZ3LFoB`5Efy%M-f_4ESF?r8k)9%$aV{E^Z1f8KI%eh zg7CvfNw%}xdWaAU%CUDg&4*>yh7eKxoOMW!`iz@e&@%KL<&?cT;!4?BiVi_rCyO=w za(R9{@#gDx#Y|i=M*pE1>Ov|AZ-`6 z;+NdR-i(jBkYX@Rf?VOE9QzR#=a=CaX%1~D$DXO#1?AXlAgR9m=GZHnWYAyi!=t#8 z{l*u+q6_j%u!@YjKXXkZ3w<9WPMiUMIq-JBL=H^K(8>7&I=Y{;@uuCC%cZ5$;C!_${R)HfmB?2-LwpOS zOrAaXgA08bNe#Ll0Kwyay?|BAG!kgz_egLW50phHZ+PCdSE;K9)i?JwihzK~iXV!&$a58vr7#scN#$j9Qqx4rzr^jn_pjrEQgw2mf@Ki^%vnE}%1GsNa)4ti z7c`S3+&7X%1}R|}Bb9=Npy%y&i6hk`j8dQsVld3cI!D}vM+jZ)q!ft9(@R>3uy1ih zMou-PaFXdWB&!wRK7rt8`sKD3pM*0m>vsu`q=FC~ubnTbYv2C4w~zTl9jNMXZ%`rF_212RF8YPUj5aW%x4 zufh)cstN?oF!cZ%_`xNdFmm75euU3UgDnnUpo`nkYQ7rLO+u4K*VD+yU|<`o zdvArh+*$e#&dYhSXwU5J0w7Mwhdr`H*Ftq~OQhwakz>Qz-;Q8QHhihey1LT@)bO&+ zWEa84moYsP7$nadoqWsFisK1^5@<1l?K%t~IOlTCxQ8Z@s^Tr3e53qLzhSbbYnTQP4U(9*(I^FUZ@9N=SXsWmx zEeQ9y@Jluzv2Upinr239-)B@2DmvcnCagyiAQZ#d@L9q7))g<^TQxihG||N!3HMbr zk;Gyq>ffjXUQ%n$ds-|}3JT?8*jd3JaKi{Sk)A|Uhx&0T-Ar~W=;6vX@ZqFDChyM- znX9uK-hKM`L{r(2f;!~0Z(3|A8(LAs&(uF}L%x7Fb{;)-Z5W>2WLny}dv9GIu}{_d zos{z`(%yOi+GE34gzgxM_26*C zj?oOc$XVZyu0c}9Ro#& z0BWBR@*fl`zwejR+X%odlTmek!XxT?It8yisj9!;Ij&c4S$KY0H*>w~I9&hzbm+9{ z5)}*tYM94WK5L^z!AH4ak#hK~OZ4wZ)2P4sSrYnWF;z9(eDda`ru&J4&9KXiU!*oLI z$lI$`L6653rN5j9U?EUHt@lwP4m7}-D zIs%oWp;H6aIkpbQ$2>gONo2(ESXFQ5u6I|~Fb z2PQrZ%!CHjm;@%)1mcVaMw|u21A>YGf$ffgUF$*7F+oK+0cjjTxROBw0Ae2vKg&t* zl8~Q`NeC<_1X1I=0}Zk230a}?BeD)b)`T2$gdW6%Uaf~5`Gsiagl06Ox3&^|ZVZKzs49sD~24PH|VW8A7iqyG{mMN#8GJ))R9uc|B|LbHfjy+RZ^;nOqT(PtVd3F zcnflVZi)<0%YCLA`?;wDbfofGM_ysy>RA9ds=VT}5h_iClSZL73KgYcmiop@INDA# z`ZIg9J)WFKY_#iCw6JQBd+t*hbqoTPrm|BU}+3;x7|S{V!=6F;m3I z*jT}e*o1SbcjvLf0Z%mk`Ch3B^YVBfY}=yos~$sBuoQFR_WAFh9@wizS^W z7T=a9EKUh`{vl069Fe$vp0rP$Ovx8>$ocqKGg+cM@vJsE1ognu>0XgMc=tTHGc6g* zIR!wIfEkz4=>@{+O9A&e;M1g%X{A!2(ljpAsV_Lu>rxX*;uvVsSVYoTwbIy}(>UVN zxa!h)rqk|Ur15G++)$?rn8}lBrGxoFpn&u*rRib;v}5P#!ZztrbqwNK8EIkus5Fg_ z0_jT5^tO#)e{BLF< z6LE#pb%nDc(x>}{^E5@L^Wa6Tq94=XRjywHHTuBYz@puYqJ5g;ZH1ykk)q?cq7$y- zEv@3~i=x}S;&WgLrg;%IcL{!LF?wJLFtr3%y9j@#2*h1Vh+lH1MSOuQrKvBan<-_u zETx_SGl`b5;+GMqqLPxz*yGE1%**gc%Xnu>S!l}zM9T$kY0J4?%6a3s+*SIDB=6&^%(f~mL`lqN3g7V&Ekmm9wX1=U=bYBnuJP4et<|3btDOT$mXKiY zdJ>poHPEVt-Lsm1q2@HKhNrcLKdi=Ui>xcQHm<%lVWu`Izn1Wz7L}%vL|d2PQkUHi z&Z)0U%dacAtc%~OD-o^F60I-RuCMB^D~qqsudi>2ufsp6uiL86=&NrS zm}waLHBIA-XyZ5S#&MU%Np10@I;Z!sjrizM-){rKbF@v%^^xORP3!$CnQ=|q`QWwq zhIXx{y?TeqlE$51(=<|yo4=b^U0gP=*XNCM`<JG>JyH?v(f+#5az@h;G2`!!sJrIJrOiKoMWb3{#A)76}fSK$GM-d%WPa zJT!GBLmnkkItoQp&FJ#JHXm+|x(;Zsq!ZHs4_E>M?gM}=UD%QxTHB9LQ;2|I0=tq1 z8%_dUI^s4kfTP5QN)qR;7}&Z6N8;ArUPP$15z&p)3i2&L^SBCgkimV1#Gy?k0Jh*4 zQxM@Z6LcdxjA-%*4?w!pSTi?)p!S% zT{~ZmF^bIu0bomN5v0~Id16%)6T&Dv%#AUt3(!V6uxw^QRt0EH1!(VJmKG`4yzRtr zCMp^xHP8+}#jjAsHLz*^8NTV^^C!7Ct>bI=uU5h|F&fowp@ zrL?4g_z2vJYXG`Hb{yP}M7nGuDP2exayrHCWhahlnu_&`x`Fq2dne-H>aLxSwi_Qm zqtM|PoQQ{OiUmIE9KApJjlvsbpw)6Vqp9|xk>OsW!M!%aXZazsh3^O(c?X+}b;qmY z#x3b5Y@STm=}y?YO*ke_I5$qX&P}*qPr&FWy`D@WbSHh>CjAm80~#lT<|ad~Cz141 z;e_ehZq4&EP0>%L(zK@HJ~-TnA`%-jCtz0nI>gH=MBUQ>An!C8U;9Yh6c`=<%8H1& z0DaU9hZFt2h4YB3!OZC;s6Ayy8+Rgg?#U_>P1F1gM;wu-O~RX!7b+j%WBWMVW8*ov zy}*48jh3wK{qU1p{cn1wQ^L&OaYyGIrsoC{n?z#ZtAymsy0iC>zmNCN?9=CtosVG> zw07wJaIE_=xb;KMu5(=l6#R4^2${!8n#aB|1iJs9_U`;2>cwB+_-KY1lNrMpO1A7v z35hz^vW$ISQ%GaaGK^wmjl=0gmX0I_b!17%u@(*46{4~?GZ_0WgqXR`x!=dR=YG%Q z-p9T7@wh+S`}q6~?;qdq_v=YJN}-`NX-8LRJZ2MI{uAiP34YQ9I(g!l&;$fYo1bsr z_5HG#Kae3lsXQN)R5fU|i>Sm+?k^YcE@dp68Yr3F(NLdKr%Y)wrnH6VmwKmW^V*l6 zBWV$h93PQ8jYZ!}Zz><=IcP}J-Xgs%ZpBH&_Y|a|eDVFjJ`0e5k|H>33VAiTP>n{I zYe4iDurFcIIC+$n*>rd}_-4Ex_%K+J$60p{d>x9WRd6m?Ogk^YdINo0nYMwjd{O*| z0hMN?r&%F6`pDfksAL9rvgovdSy2MxC<^a=E_FKAY|fcD$AzC)Iyr4(R`g{bl}AF) zqrTkez6M8malGv0!Lu5!u>_E~@R}%(vV_nd5X2f^NHg19H1bX!4so$w5U(0j21;e< z%4>!}J0_3jL%G*oe@)`D>V20a%hC4)wbh39NS-Plg4Fq=moUrs#22&defCi|$~U>G z$qQDH)q5RBWu%1QDCoo*Cou(LeC>8yAXu-$gfa%vKTPH*pq%=-KdiKW6e_HbX0O19 z!1^Js>L}@^E8tXCjUjF;5+yDR!pF-cUI;pNMC#467ip=eeWs=B5jW8TP41Z9>9|+I z9G1te&IwKB`^)Fg?@)@8*Ef{<7vt!o+4hhkJv7>UEQ@$twb}WbnSm@R-MZJn(Ivg# zdEKmaQ>PwzPq!qve(TPst2DZ4-*VHwIV_txsX{kJ748? zd$tLwlSJD3P|)!L^uZO8I=Kf2eIHsw+%sNy?@fn)Kpb0?R%M`rF*nV@`anszKJ;_o#L=hnVJluMeW=nxh8?peuZuKq@Y2n+X`R=3$w8PSFY)O1=YMwHgpnW7oqBZmUdJZn zhS9FWGzERDRyzfpY?`o@apFNI#hRaUcEvj^m0(XbZzveWKdVwQQS50+XjkmhwKP;7 zGO;pMp~jsxyWsfM&rGeW;cVaP_^02@wU`iPi;K`kcH!gfdIV;b4%)rS5-TiGVqzdw zP-SI&rcK$}RCT(_+FXnEoQ)+`qWbW|Rqvdwt-X7-t-VY9IXg${o`;=NK-)R{t4GJH z?em1x=dmsc5;ep32GMq62xn=pYMd%@(81*CR^nyv@-`Kx65h{tc8D95HBPn{xN67a zmg+mk^XhCLibPh9T+ibf?ZI@UR~?^&5rcD}!w;6$a8yxNJA)&!d?iXw?B}oXokVP^ z?TCbnJ0daJ-`pQvD8X3ns*@f$ zrv~$83T20>eDlnEhan!;G%~8M{aSsRIPVr=J?j0a)mxeAQ|x|s*XKp^^I+d{GMid8 zp2F@l=F4;b^^NMG$OnR<4cFED>t~<+qoz>=?|&UYX0oXVHbbQv0$Vt->i9N3&jx&l zaDsYJmsDXx(7Q7o>cKs#vkk$0T2Ku_KUS)d@X;Kbqs(H>48AaUKsX2)Y3cr9Y51pV z;!Rlki>tS&Q3-RxWDk}%p;KBxyP?w$J>P`A+vQRk8&6tk-#wd9#UMU=*ZwRo6eHd7 zmSUJgn%#P(nwVYtn^xd$hcE1}7h^Zwg)fEDnrj&^vUrO;%4QsM8I(y)mM3g#!+3*N z@M9z@Y&lZW$rWPy+gbL}glG&7$y7N16mipnd6R$B)qfED7L{S)_LJDP0&b71Vr!qbTad8o4((J~*lw4W8m8JXn{2c|Ae1fH{?3aj7Drp9(&n z0%>f--M=+43Emj)$cVO7V2I(IQ3?hb3QDObEoq_?p&+b~Ua~?lT}*ESR2+zx%>E>9 z#IegG=dmGf!BJqS&wkAO*?!Q;CeV%YAjSQZ3-Q~mW~XaF>ZjF z<>jGS#%!V`ZgiPyRR)V{^CZF!`#c2a*7O;11NrQHj01nGajehDr&bQB#{6*^mtoDe z0&Au*w2vfM%!J}jadc#?I3Mf91bvB1{W;3PB77z|Wr&h_dZ#r@6;Gm2O+HB3B2ShB z)+{o*lPrVuiI3Yz(H>AhpESEJ(yGpGk~8u?o-|(=TY|Nb67Nh7YAvv7fb&h%!3hmw zCEL=IdKlN1B3bQF_^_y9quV<#=|Hh4NQ?HI<>5zO_rsqmpIp{@!XC;?XL%dfrKvFh zVsp5}qJep?!*7&^u;G4edlAHx<9>}gK?!041xv(;xN#>8w~A>h>Kom2;|(8fv%92liPCS&n&Q{4Ql^-M37X=cJ=UR4 zQB3kXg%c(ZcVhK}(tcs87qanpbwRHx*@-K=%UbWo*taX`l!Xt--Z~!b!1gr*Q$hNU zpvOSi&t{%Tn~_tC>+u}ic-&^HwHA$J*LX7e`0~S=Ms9b_HD@kD-xX2T+Fc#e z<6zRa@mc%k-M)DFv@Fi6M*3Ky5sE~3CWV_5|06C#$}wZcb-DBHCi z5i23&aLTt3$~Q7JaxFfJ?;|I52g{~0A{MnD1uforpRoPaP@XtvPu&~ph}^CwN37gp zN+(0%J93ky>@j4TnmLz4g=&htpSS4KkSJ_x0PmuL^qJWT^3#noX$NBkOiCY*t_4I_ zMEkXNT&8qW@_Frh4%+v;cy?{1<2*8y-H0M`L<9RSw>a2){G0dO4v*8y-H z0M`L<9RSw>a2){G0dO4v*8y-H0M`L<9RSzi&rLMoIsmQ%;5q=V1K>IUt^?pY0Imbz zIsmQ%;5q=V!@r9{{aI}RTnE5)_=lqdMEL%nNB98O;qQ*lpQ#$abpTukz;*cF_GJLq s0dO7u>%I)&IsmT2Uu2s9ThYG-z;*bWO!FTl)dAPxe=ZXKlk1@NFDQI~A^-pY From c1444b40874b342082bfeea6d105d16adc0b661e Mon Sep 17 00:00:00 2001 From: Nolence Date: Mon, 25 Jan 2021 10:57:25 -0700 Subject: [PATCH 012/176] Move image to relative url --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5d5005c..4b927f3 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,10 @@ A builder that adds loading, disabled, errored and completed states on top of buttons that perform asynchronous tasks. It can be used with most any button or even on top of a custom Material button. It includes fluid animation between states as well using `AnimatedSize` as well as the possibility to define your own transition builder. -

+![An image of the various example loading buttons](/screenshots/ezgif-1-492fa074abc6.gif?raw=true) + ## Getting Started From 7ff42b74d54385fb36f3e698bb3a82fb0192cec6 Mon Sep 17 00:00:00 2001 From: Nolence Date: Mon, 25 Jan 2021 10:58:10 -0700 Subject: [PATCH 013/176] small type --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4b927f3..8db2869 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # async_button_builder -## This is a pre release and I'd like suggestions on naming, usability, further improvments. Thank you! +## This is a pre release and I'd like suggestions on naming, usability, further improvements. Thank you! A builder that adds loading, disabled, errored and completed states on top of buttons that perform asynchronous tasks. It can be used with most any button or even on top of a custom Material button. It includes fluid animation between states as well using `AnimatedSize` as well as the possibility to define your own transition builder. From 4a351ebcb8a334ff98bcf67934a12885d3adfa7b Mon Sep 17 00:00:00 2001 From: Nolence Date: Mon, 25 Jan 2021 21:25:20 -0700 Subject: [PATCH 014/176] Updated changelog --- CHANGELOG.md | 3 + README.md | 54 +-- example/lib/main.dart | 20 +- lib/src/async_button_builder.dart | 380 ++++++++++++------ lib/src/button_state/button_state.dart | 14 +- .../button_state/button_state.freezed.dart | 225 ++++++----- screenshots/ezgif-1-492fa074abc6.gif | Bin 449650 -> 0 bytes screenshots/ezgif-7-4088c909ba83.gif | Bin 0 -> 119599 bytes screenshots/ezgif-7-61c436edaec2.gif | Bin 0 -> 53098 bytes screenshots/ezgif-7-a971c6afaabf.gif | Bin 0 -> 80732 bytes screenshots/ezgif-7-b620d3def232.gif | Bin 0 -> 71945 bytes 11 files changed, 421 insertions(+), 275 deletions(-) delete mode 100644 screenshots/ezgif-1-492fa074abc6.gif create mode 100644 screenshots/ezgif-7-4088c909ba83.gif create mode 100644 screenshots/ezgif-7-61c436edaec2.gif create mode 100644 screenshots/ezgif-7-a971c6afaabf.gif create mode 100644 screenshots/ezgif-7-b620d3def232.gif diff --git a/CHANGELOG.md b/CHANGELOG.md index c466227..113e65f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## [2.0.1-nullsafety.2] - 2021-01-25 +Renames fields to better match standards of other buttons. + ## [2.0.0-dev.1] - 2021-01-25 Breaking. Replaces the fourth argument with a sealed union that better allows for directly managing states, removes unnecessary arguments such as padding, adds transition builders for custom transitions. Currently still includes AnimatedSize. diff --git a/README.md b/README.md index 8db2869..25f0ffe 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,6 @@ # async_button_builder -## This is a pre release and I'd like suggestions on naming, usability, further improvements. Thank you! - -A builder that adds loading, disabled, errored and completed states on top of buttons that perform asynchronous tasks. It can be used with most any button or even on top of a custom Material button. It includes fluid animation between states as well using `AnimatedSize` as well as the possibility to define your own transition builder. - -![An image of the various example loading buttons](/screenshots/ezgif-1-492fa074abc6.gif?raw=true) - +A builder that adds loading, disabled, errored and completed states on top of buttons that perform asynchronous tasks. It can be used with most any button or even on top of a custom Material button. It includes fluid animation between states as well using `AnimatedSize` in combination with `AnimatedSwitcher` which gives possibility to define your own transitions. ## Getting Started @@ -34,31 +27,45 @@ AsyncButtonBuilder( ), ``` +

+ +

+ The fourth value in the builder allows you listen to the loading state. This can be used to conditionally style the button. This package depends `freezed` in order to create a sealed union to better handle the possible states. ```dart AsyncButtonBuilder( child: Text('Click Me'), + loadingWidget: Text('Loading...'), onPressed: () async { await Future.delayed(Duration(seconds: 1)); + + throw 'shucks'; }, - builder: (context, child, callback, state) { - return ElevatedButton( + builder: (context, child, callback, buttonState) { + final buttonColor = buttonState.when( + idle: () => Colors.yellow[200], + loading: () => Colors.grey, + success: () => Colors.orangeAccent, + error: () => Colors.orange, + ); + + return OutlinedButton( child: child, onPressed: callback, - style: ElevatedButton.styleFrom( - primary: state.when( - idling: () => Colors.pink, - loading: () => Colors.grey, - completing: () => Colors.pinkAccent, - erroring: () => Colors.red[100], - ), + style: OutlinedButton.styleFrom( + primary: Colors.black, + backgroundColor: buttonColor, ), ); }, ), ``` +

+ +

+ You can also drive the state of the button yourself using the `buttonState` field: ```dart @@ -75,8 +82,7 @@ AsyncButtonBuilder( AsyncButtonBuilder( child: Padding( // Value keys are important as otherwise our custom transitions - // will have no way to differentiate between children. This is not - // specific to this library but Flutter's `AnimatedSwitcher`. + // will have no way to differentiate between children. key: ValueKey('foo'), padding: const EdgeInsets.symmetric( horizontal: 16.0, @@ -98,7 +104,7 @@ AsyncButtonBuilder( ), ), ), - completingWidget: Padding( + successWidget: Padding( key: ValueKey('foobar'), padding: const EdgeInsets.all(4.0), child: Icon( @@ -111,8 +117,6 @@ AsyncButtonBuilder( }, loadingSwitchInCurve: Curves.bounceInOut, loadingTransitionBuilder: (child, animation) { - // The loading indicator will come up from the button using a - // `bounceInOut` curve. return SlideTransition( position: Tween( begin: Offset(0, 1.0), @@ -124,7 +128,7 @@ AsyncButtonBuilder( builder: (context, child, callback, state) { return Material( color: state.maybeWhen( - completing: () => Colors.purple[100], + success: () => Colors.purple[100], orElse: () => Colors.blue, ), // This prevents the loading indicator showing below the @@ -140,4 +144,8 @@ AsyncButtonBuilder( ), ``` +

+ +

+ Issues and PR's welcome \ No newline at end of file diff --git a/example/lib/main.dart b/example/lib/main.dart index 7e397d9..2148024 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -22,9 +22,8 @@ class MyHomePage extends StatelessWidget { body: SizedBox.expand( child: Column( crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ - Spacer(), Divider(), Text('Text Button:'), AsyncButtonBuilder( @@ -65,10 +64,10 @@ class MyHomePage extends StatelessWidget { }, builder: (context, child, callback, buttonState) { final buttonColor = buttonState.when( - idling: () => Colors.yellow[200], + idle: () => Colors.yellow[200], loading: () => Colors.grey, - completing: () => Colors.orangeAccent, - erroring: () => Colors.orange, + success: () => Colors.orangeAccent, + error: () => Colors.orange, ); return OutlinedButton( @@ -88,7 +87,7 @@ class MyHomePage extends StatelessWidget { child: Padding( // Value keys are important as otherwise our custom transitions // will have no way to differentiate between children. - key: ValueKey('lust'), + key: ValueKey('foo'), padding: const EdgeInsets.symmetric( horizontal: 16.0, vertical: 8.0, @@ -99,7 +98,7 @@ class MyHomePage extends StatelessWidget { ), ), loadingWidget: Padding( - key: ValueKey('envy'), + key: ValueKey('bar'), padding: const EdgeInsets.all(8.0), child: SizedBox( height: 16.0, @@ -109,8 +108,8 @@ class MyHomePage extends StatelessWidget { ), ), ), - completingWidget: Padding( - key: ValueKey('sloth'), + successWidget: Padding( + key: ValueKey('foobar'), padding: const EdgeInsets.all(4.0), child: Icon( Icons.check, @@ -133,7 +132,7 @@ class MyHomePage extends StatelessWidget { builder: (context, child, callback, state) { return Material( color: state.maybeWhen( - completing: () => Colors.purple[100], + success: () => Colors.purple[100], orElse: () => Colors.blue, ), // This prevents the loading indicator showing below the @@ -148,7 +147,6 @@ class MyHomePage extends StatelessWidget { }, ), Divider(), - Spacer(), ], ), ), diff --git a/lib/src/async_button_builder.dart b/lib/src/async_button_builder.dart index 3234aee..d1b4e29 100644 --- a/lib/src/async_button_builder.dart +++ b/lib/src/async_button_builder.dart @@ -4,10 +4,47 @@ import 'package:async_button_builder/src/button_state/button_state.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -/// A `builder` that wraps a button automatically providing disabled and loading -/// states while retaining full access to a Button's API. Useful for any long -/// running operations or to prevent the user from clicking multiple times -/// while an asynchronous task is running. +/// A `builder` that wraps a button providing disabled, loading, success and +/// error states while retaining almost full access to the original Button's +/// API. This is useful for any long running operations and helps better +/// improve UX. +/// +/// {@tool dartpad --template=stateful_widget_material} +/// +/// ```dart +/// +/// @override +/// Widget build(BuildContext context) { +/// return AsyncButtonBuilder( +/// child: Text('Click Me'), +/// loadingWidget: Text('Loading...'), +/// onPressed: () async { +/// await Future.delayed(Duration(seconds: 1)); +/// +/// throw 'shucks'; +/// }, +/// builder: (context, child, callback, buttonState) { +/// final buttonColor = buttonState.when( +/// idle: () => Colors.yellow[200], +/// loading: () => Colors.grey, +/// success: () => Colors.orangeAccent, +/// error: () => Colors.orange, +/// ); +/// +/// return OutlinedButton( +/// child: child, +/// onPressed: callback, +/// style: OutlinedButton.styleFrom( +/// primary: Colors.black, +/// backgroundColor: buttonColor, +/// ), +/// ); +/// }, +/// ), +/// } +/// ``` +/// {@end-tool} +/// class AsyncButtonBuilder extends StatefulWidget { final Widget Function( BuildContext context, @@ -24,10 +61,16 @@ class AsyncButtonBuilder extends StatefulWidget { /// The animation will take place over [duration]. final Widget child; - /// The animation's duration between [child] and [loadingWidget] using - /// [AnimatedSize]. + /// The animation's duration between [child], [loadingWidget], + /// [successWidget] and [errorWidget]. This same value is used for both the + /// internal [AnimatedSize] and [TransitionBuilder]. final Duration duration; + /// The animation's reverse duration between [child], [loadingWidget], + /// [successWidget] and [errorWidget]. This same value is used for both the + /// internal [AnimatedSize] and [TransitionBuilder]. + final Duration reverseDuration; + /// A callback that runs the async task. This is wrapped in order to begin /// the button's internal `isLoading` before and after the operation /// completes. @@ -35,63 +78,117 @@ class AsyncButtonBuilder extends StatefulWidget { /// This is used to manually drive the state of the loading button thus /// initiating the corresponding animation and showing the correct button - /// child + /// child. final ButtonState buttonState; /// This is used to manually drive the disabled state of the button. final bool disabled; - /// The widget used to replace the [child] when the button is in a loading - /// state. If this is null the default widget is: + /// The widget replaces the [child] when the button is in the loading state. + /// If this is null the default widget is: /// /// SizedBox( /// height: 16.0, /// width: 16.0, - /// child: CircularProgressIndicator( - /// valueColor: valueColor, - /// ), + /// child: CircularProgressIndicator(), /// ) final Widget? loadingWidget; - /// The widget used to replace the [child] when the button is in a completing + /// The widget used to replace the [child] when the button is in a success /// state. If this is null the default widget is: /// - /// SizedBox( - /// height: 16.0, - /// width: 16.0, - /// child: Icons(Icon.check) + /// Icon( + /// Icons.check, + /// color: Theme.of(context).accentColor, + /// ); + final Widget? successWidget; + + /// The widget used to replace the [child] when the button is in a error + /// state. If this is null the default widget is: + /// + /// Icon( + /// Icons.error, + /// color: Theme.of(context).errorColor, /// ) - final Widget? completingWidget; + final Widget? errorWidget; + + /// Whether to show the [successWidget] on success. + final bool showSuccess; + + /// Whether to show the [errorWidget] on error. + final bool showError; + + /// Optional [EdgeInsets] that will wrap around the [errorWidget]. This is a + /// convenience field that can be replaced by defining your own [errorWidget] + /// and wrapping it in a [Padding]. + final EdgeInsets? errorPadding; - final Widget? erroringWidget; + /// Optional [EdgeInsets] that will wrap around the [successWidget]. This is a + /// convenience field that can be replaced by defining your own + /// [successWidget] and wrapping it in a [Padding]. + final EdgeInsets? successPadding; - final AnimatedSwitcherTransitionBuilder idlingTransitionBuilder; + /// Defines a custom transition when animating between any state and `idle` + final AnimatedSwitcherTransitionBuilder idleTransitionBuilder; + /// Defines a custom transition when animating between any state and `loading` final AnimatedSwitcherTransitionBuilder loadingTransitionBuilder; - final AnimatedSwitcherTransitionBuilder completingTransitionBuilder; + /// Defines a custom transition when animating between any state and `success` + final AnimatedSwitcherTransitionBuilder successTransitionBuilder; - final AnimatedSwitcherTransitionBuilder erroringTransitionBuilder; + /// Defines a custom transition when animating between any state and `error` + final AnimatedSwitcherTransitionBuilder errorTransitionBuilder; - final Duration completingIdleTime; + /// The amount of idle time the [successWidget] shows + final Duration successDuration; - final Duration erroringIdleTime; + /// The amount of idle time the [errorWidget] shows + final Duration errorDuration; - final Curve idlingSwitchInCurve; + /// Defines a curve for the custom transition. This used in in an + /// [AnimatedSwitcher] and only takes effect when animating to `idle` + final Curve idleSwitchInCurve; + /// Defines a curve for the custom transition. This used in in an + /// [AnimatedSwitcher] and only takes effect when animating to `loading` final Curve loadingSwitchInCurve; - final Curve completingSwitchInCurve; + /// Defines a curve for the custom transition. This used in in an + /// [AnimatedSwitcher] and only takes effect when animating to `success` + final Curve successSwitchInCurve; - final Curve erroringSwitchInCurve; + /// Defines a curve for the custom transition. This used in in an + /// [AnimatedSwitcher] and only takes effect when animating to `error` + final Curve errorSwitchInCurve; - final Curve idlingSwitchOutCurve; + /// Defines a curve for the custom transition. This used in in an + /// [AnimatedSwitcher] and only takes effect when animating out of `idle` + final Curve idleSwitchOutCurve; + /// Defines a curve for the custom transition. This used in in an + /// [AnimatedSwitcher] and only takes effect when animating out of `loading` final Curve loadingSwitchOutCurve; - final Curve completingSwitchOutCurve; + /// Defines a curve for the custom transition. This used in in an + /// [AnimatedSwitcher] and only takes effect when animating out of `success` + final Curve successSwitchOutCurve; + + /// Defines a curve for the custom transition. This used in in an + /// [AnimatedSwitcher] and only takes effect when animating out of `error` + final Curve errorSwitchOutCurve; + + /// Defines a curve for the internal [AnimatedSize] + final Curve sizeCurve; + + /// Defines the [Clip] for the internal [AnimatedSize] + final Clip sizeClipBehavior; - final Curve erroringSwitchOutCurve; + /// Defines the [Alignment] for the internal [AnimatedSize] + final Alignment sizeAlignment; + + /// Whether to animate the [Size] of the widget implicitly. + final bool animateSize; const AsyncButtonBuilder({ Key? key, @@ -99,33 +196,38 @@ class AsyncButtonBuilder extends StatefulWidget { required this.onPressed, required this.builder, this.loadingWidget, - this.completingWidget, - this.erroringWidget, + this.successWidget, + this.errorWidget, + this.showSuccess = true, + this.showError = true, + this.errorPadding, + this.successPadding, + this.buttonState = const ButtonState.idle(), this.duration = const Duration(milliseconds: 250), - this.buttonState = const ButtonState.idling(), + this.reverseDuration = const Duration(milliseconds: 250), this.disabled = false, - this.completingIdleTime = const Duration(seconds: 1), - this.erroringIdleTime = const Duration(seconds: 1), + this.successDuration = const Duration(seconds: 1), + this.errorDuration = const Duration(seconds: 1), this.loadingTransitionBuilder = AnimatedSwitcher.defaultTransitionBuilder, - this.idlingTransitionBuilder = AnimatedSwitcher.defaultTransitionBuilder, - this.completingTransitionBuilder = - AnimatedSwitcher.defaultTransitionBuilder, - this.erroringTransitionBuilder = AnimatedSwitcher.defaultTransitionBuilder, - this.idlingSwitchInCurve = Curves.linear, + this.idleTransitionBuilder = AnimatedSwitcher.defaultTransitionBuilder, + this.successTransitionBuilder = AnimatedSwitcher.defaultTransitionBuilder, + this.errorTransitionBuilder = AnimatedSwitcher.defaultTransitionBuilder, + this.idleSwitchInCurve = Curves.linear, this.loadingSwitchInCurve = Curves.linear, - this.completingSwitchInCurve = Curves.linear, - this.erroringSwitchInCurve = Curves.linear, - this.idlingSwitchOutCurve = Curves.linear, + this.successSwitchInCurve = Curves.linear, + this.errorSwitchInCurve = Curves.linear, + this.idleSwitchOutCurve = Curves.linear, this.loadingSwitchOutCurve = Curves.linear, - this.completingSwitchOutCurve = Curves.linear, - this.erroringSwitchOutCurve = Curves.linear, + this.successSwitchOutCurve = Curves.linear, + this.errorSwitchOutCurve = Curves.linear, + this.sizeCurve = Curves.linear, + this.sizeClipBehavior = Clip.hardEdge, + this.sizeAlignment = Alignment.center, + this.animateSize = true, }) : super(key: key); // TODO: I need asserts that will assert the keys are different for child, // loading, error, etc. because otherwise transitions won't work as expected - - // assert(widget.child.key != loadingWidget.key && - // loadingWidget.key != completingWidget.key && - // completingWidget.key != erroringWidget.key); + // and I'll get user issues @override _AsyncButtonBuilderState createState() => _AsyncButtonBuilderState(); @@ -163,104 +265,140 @@ class _AsyncButtonBuilderState extends State width: 16.0, child: CircularProgressIndicator(), ); - final completingWidget = widget.completingWidget ?? + final successPadding = widget.successPadding; + final errorPadding = widget.errorPadding; + var successWidget = widget.successWidget ?? Icon( Icons.check, color: theme.accentColor, ); - final erroringWidget = widget.erroringWidget ?? + var errorWidget = widget.errorWidget ?? Icon( Icons.error, color: theme.errorColor, ); + if (successPadding != null) { + successWidget = Padding( + padding: successPadding, + child: successWidget, + ); + } + if (errorPadding != null) { + errorWidget = Padding( + padding: errorPadding, + child: errorWidget, + ); + } + + final switcher = AnimatedSwitcher( + // TODO: This duration is same as size's duration. That's okay right? + duration: widget.duration, + reverseDuration: widget.reverseDuration, + switchInCurve: buttonState.when( + idle: () => widget.idleSwitchInCurve, + loading: () => widget.loadingSwitchInCurve, + success: () => widget.successSwitchInCurve, + error: () => widget.errorSwitchInCurve, + ), + switchOutCurve: buttonState.when( + idle: () => widget.idleSwitchOutCurve, + loading: () => widget.loadingSwitchOutCurve, + success: () => widget.successSwitchOutCurve, + error: () => widget.errorSwitchOutCurve, + ), + transitionBuilder: buttonState.when( + idle: () => widget.idleTransitionBuilder, + loading: () => widget.loadingTransitionBuilder, + success: () => widget.successTransitionBuilder, + error: () => widget.errorTransitionBuilder, + ), + child: buttonState.when( + idle: () => widget.child, + loading: () => loadingWidget, + success: () => successWidget, + error: () => errorWidget, + ), + ); return widget.builder( context, - AnimatedSize( - // TODO: Expose these fields - duration: widget.duration, - vsync: this, - child: AnimatedSwitcher( - duration: widget.duration, - switchInCurve: buttonState.when( - idling: () => widget.idlingSwitchInCurve, - loading: () => widget.loadingSwitchInCurve, - completing: () => widget.completingSwitchInCurve, - erroring: () => widget.erroringSwitchInCurve, - ), - switchOutCurve: buttonState.when( - idling: () => widget.idlingSwitchOutCurve, - loading: () => widget.loadingSwitchOutCurve, - completing: () => widget.completingSwitchOutCurve, - erroring: () => widget.erroringSwitchOutCurve, - ), - transitionBuilder: buttonState.when( - idling: () => widget.idlingTransitionBuilder, - loading: () => widget.loadingTransitionBuilder, - completing: () => widget.completingTransitionBuilder, - erroring: () => widget.erroringTransitionBuilder, - ), - child: buttonState.when( - idling: () => widget.child, - loading: () => loadingWidget, - completing: () => completingWidget, - erroring: () => erroringWidget, - ), - ), - ), + // TODO: I really just wanted an AnimatedSwitcher and the default + // transitionBuilder to be a SizedTransition but it was impossible + // to figure out how to reproduce the exact behaviour of AnimatedSize + widget.animateSize + ? AnimatedSize( + vsync: this, + child: switcher, + duration: widget.duration, + reverseDuration: widget.reverseDuration, + alignment: widget.sizeAlignment, + clipBehavior: widget.sizeClipBehavior, + curve: widget.sizeCurve, + ) + : switcher, widget.disabled ? null : buttonState.maybeWhen( - idling: () => () async { - // FIXME: I might not want to set buttonState if we're being + idle: () => () async { + // I might not want to set buttonState if we're being // driven by widget.buttonState... setState(() { buttonState = ButtonState.loading(); }); + timer?.cancel(); + try { await widget.onPressed(); - timer?.cancel(); - if (mounted) { - setState(() { - buttonState = ButtonState.completing(); - }); - - timer = Timer( - widget.completingIdleTime, - () { - timer?.cancel(); - - if (mounted) { - setState(() { - buttonState = ButtonState.idling(); - }); - } - }, - ); + if (widget.showSuccess) { + setState(() { + buttonState = ButtonState.success(); + }); + + timer = Timer( + widget.successDuration, + () { + timer?.cancel(); + + if (mounted) { + setState(() { + buttonState = ButtonState.idle(); + }); + } + }, + ); + } else { + setState(() { + buttonState = ButtonState.idle(); + }); + } } } catch (error) { - timer?.cancel(); - if (mounted) { - setState(() { - buttonState = ButtonState.erroring(); - }); - - timer = Timer( - widget.erroringIdleTime, - () { - timer?.cancel(); - - if (mounted) { - setState(() { - buttonState = ButtonState.idling(); - }); - } - }, - ); + if (widget.showError) { + setState(() { + buttonState = ButtonState.error(); + }); + + timer = Timer( + widget.errorDuration, + () { + timer?.cancel(); + + if (mounted) { + setState(() { + buttonState = ButtonState.idle(); + }); + } + }, + ); + } else { + setState(() { + buttonState = ButtonState.idle(); + }); + } } rethrow; diff --git a/lib/src/button_state/button_state.dart b/lib/src/button_state/button_state.dart index 7921989..00331f3 100644 --- a/lib/src/button_state/button_state.dart +++ b/lib/src/button_state/button_state.dart @@ -10,10 +10,10 @@ part 'button_state.freezed.dart'; /// /// ```dart /// final buttonColor = buttonState.when( -/// idling: () => Colors.pink, +/// idle: () => Colors.pink, /// loading: () => Colors.blue, -/// completing: () => Colors.green, -/// erroring: () => Colors.red, +/// success: () => Colors.green, +/// error: () => Colors.red, /// ); /// ``` /// {@end-tool} @@ -25,15 +25,15 @@ part 'button_state.freezed.dart'; /// /// ```dart /// final buttonColor = buttonState.maybeWhen( -/// idling: () => Colors.pink, +/// idle: () => Colors.pink, /// orElse: () => Colors.red, /// ); /// ``` /// {@end-tool} @freezed abstract class ButtonState with _$ButtonState { - const factory ButtonState.idling() = Idling; + const factory ButtonState.idle() = Idling; const factory ButtonState.loading() = Loading; - const factory ButtonState.completing() = Completing; - const factory ButtonState.erroring() = Erroring; + const factory ButtonState.success() = Succeding; + const factory ButtonState.error() = Failing; } diff --git a/lib/src/button_state/button_state.freezed.dart b/lib/src/button_state/button_state.freezed.dart index d40dd20..c37b4a1 100644 --- a/lib/src/button_state/button_state.freezed.dart +++ b/lib/src/button_state/button_state.freezed.dart @@ -13,7 +13,7 @@ T _$identity(T value) => value; class _$ButtonStateTearOff { const _$ButtonStateTearOff(); - Idling idling() { + Idling idle() { return const Idling(); } @@ -21,12 +21,12 @@ class _$ButtonStateTearOff { return const Loading(); } - Completing completing() { - return const Completing(); + Succeding success() { + return const Succeding(); } - Erroring erroring() { - return const Erroring(); + Failing error() { + return const Failing(); } } @@ -37,32 +37,32 @@ const $ButtonState = _$ButtonStateTearOff(); mixin _$ButtonState { @optionalTypeArgs TResult when({ - required TResult Function() idling, + required TResult Function() idle, required TResult Function() loading, - required TResult Function() completing, - required TResult Function() erroring, + required TResult Function() success, + required TResult Function() error, }); @optionalTypeArgs TResult maybeWhen({ - TResult Function()? idling, + TResult Function()? idle, TResult Function()? loading, - TResult Function()? completing, - TResult Function()? erroring, + TResult Function()? success, + TResult Function()? error, required TResult orElse(), }); @optionalTypeArgs TResult map({ - required TResult Function(Idling value) idling, + required TResult Function(Idling value) idle, required TResult Function(Loading value) loading, - required TResult Function(Completing value) completing, - required TResult Function(Erroring value) erroring, + required TResult Function(Succeding value) success, + required TResult Function(Failing value) error, }); @optionalTypeArgs TResult maybeMap({ - TResult Function(Idling value)? idling, + TResult Function(Idling value)? idle, TResult Function(Loading value)? loading, - TResult Function(Completing value)? completing, - TResult Function(Erroring value)? erroring, + TResult Function(Succeding value)? success, + TResult Function(Failing value)? error, required TResult orElse(), }); } @@ -105,7 +105,7 @@ class _$Idling implements Idling { @override String toString() { - return 'ButtonState.idling()'; + return 'ButtonState.idle()'; } @override @@ -119,25 +119,25 @@ class _$Idling implements Idling { @override @optionalTypeArgs TResult when({ - required TResult Function() idling, + required TResult Function() idle, required TResult Function() loading, - required TResult Function() completing, - required TResult Function() erroring, + required TResult Function() success, + required TResult Function() error, }) { - return idling(); + return idle(); } @override @optionalTypeArgs TResult maybeWhen({ - TResult Function()? idling, + TResult Function()? idle, TResult Function()? loading, - TResult Function()? completing, - TResult Function()? erroring, + TResult Function()? success, + TResult Function()? error, required TResult orElse(), }) { - if (idling != null) { - return idling(); + if (idle != null) { + return idle(); } return orElse(); } @@ -145,25 +145,25 @@ class _$Idling implements Idling { @override @optionalTypeArgs TResult map({ - required TResult Function(Idling value) idling, + required TResult Function(Idling value) idle, required TResult Function(Loading value) loading, - required TResult Function(Completing value) completing, - required TResult Function(Erroring value) erroring, + required TResult Function(Succeding value) success, + required TResult Function(Failing value) error, }) { - return idling(this); + return idle(this); } @override @optionalTypeArgs TResult maybeMap({ - TResult Function(Idling value)? idling, + TResult Function(Idling value)? idle, TResult Function(Loading value)? loading, - TResult Function(Completing value)? completing, - TResult Function(Erroring value)? erroring, + TResult Function(Succeding value)? success, + TResult Function(Failing value)? error, required TResult orElse(), }) { - if (idling != null) { - return idling(this); + if (idle != null) { + return idle(this); } return orElse(); } @@ -209,10 +209,10 @@ class _$Loading implements Loading { @override @optionalTypeArgs TResult when({ - required TResult Function() idling, + required TResult Function() idle, required TResult Function() loading, - required TResult Function() completing, - required TResult Function() erroring, + required TResult Function() success, + required TResult Function() error, }) { return loading(); } @@ -220,10 +220,10 @@ class _$Loading implements Loading { @override @optionalTypeArgs TResult maybeWhen({ - TResult Function()? idling, + TResult Function()? idle, TResult Function()? loading, - TResult Function()? completing, - TResult Function()? erroring, + TResult Function()? success, + TResult Function()? error, required TResult orElse(), }) { if (loading != null) { @@ -235,10 +235,10 @@ class _$Loading implements Loading { @override @optionalTypeArgs TResult map({ - required TResult Function(Idling value) idling, + required TResult Function(Idling value) idle, required TResult Function(Loading value) loading, - required TResult Function(Completing value) completing, - required TResult Function(Erroring value) erroring, + required TResult Function(Succeding value) success, + required TResult Function(Failing value) error, }) { return loading(this); } @@ -246,10 +246,10 @@ class _$Loading implements Loading { @override @optionalTypeArgs TResult maybeMap({ - TResult Function(Idling value)? idling, + TResult Function(Idling value)? idle, TResult Function(Loading value)? loading, - TResult Function(Completing value)? completing, - TResult Function(Erroring value)? erroring, + TResult Function(Succeding value)? success, + TResult Function(Failing value)? error, required TResult orElse(), }) { if (loading != null) { @@ -264,34 +264,33 @@ abstract class Loading implements ButtonState { } /// @nodoc -abstract class $CompletingCopyWith<$Res> { - factory $CompletingCopyWith( - Completing value, $Res Function(Completing) then) = - _$CompletingCopyWithImpl<$Res>; +abstract class $SuccedingCopyWith<$Res> { + factory $SuccedingCopyWith(Succeding value, $Res Function(Succeding) then) = + _$SuccedingCopyWithImpl<$Res>; } /// @nodoc -class _$CompletingCopyWithImpl<$Res> extends _$ButtonStateCopyWithImpl<$Res> - implements $CompletingCopyWith<$Res> { - _$CompletingCopyWithImpl(Completing _value, $Res Function(Completing) _then) - : super(_value, (v) => _then(v as Completing)); +class _$SuccedingCopyWithImpl<$Res> extends _$ButtonStateCopyWithImpl<$Res> + implements $SuccedingCopyWith<$Res> { + _$SuccedingCopyWithImpl(Succeding _value, $Res Function(Succeding) _then) + : super(_value, (v) => _then(v as Succeding)); @override - Completing get _value => super._value as Completing; + Succeding get _value => super._value as Succeding; } /// @nodoc -class _$Completing implements Completing { - const _$Completing(); +class _$Succeding implements Succeding { + const _$Succeding(); @override String toString() { - return 'ButtonState.completing()'; + return 'ButtonState.success()'; } @override bool operator ==(dynamic other) { - return identical(this, other) || (other is Completing); + return identical(this, other) || (other is Succeding); } @override @@ -300,25 +299,25 @@ class _$Completing implements Completing { @override @optionalTypeArgs TResult when({ - required TResult Function() idling, + required TResult Function() idle, required TResult Function() loading, - required TResult Function() completing, - required TResult Function() erroring, + required TResult Function() success, + required TResult Function() error, }) { - return completing(); + return success(); } @override @optionalTypeArgs TResult maybeWhen({ - TResult Function()? idling, + TResult Function()? idle, TResult Function()? loading, - TResult Function()? completing, - TResult Function()? erroring, + TResult Function()? success, + TResult Function()? error, required TResult orElse(), }) { - if (completing != null) { - return completing(); + if (success != null) { + return success(); } return orElse(); } @@ -326,62 +325,62 @@ class _$Completing implements Completing { @override @optionalTypeArgs TResult map({ - required TResult Function(Idling value) idling, + required TResult Function(Idling value) idle, required TResult Function(Loading value) loading, - required TResult Function(Completing value) completing, - required TResult Function(Erroring value) erroring, + required TResult Function(Succeding value) success, + required TResult Function(Failing value) error, }) { - return completing(this); + return success(this); } @override @optionalTypeArgs TResult maybeMap({ - TResult Function(Idling value)? idling, + TResult Function(Idling value)? idle, TResult Function(Loading value)? loading, - TResult Function(Completing value)? completing, - TResult Function(Erroring value)? erroring, + TResult Function(Succeding value)? success, + TResult Function(Failing value)? error, required TResult orElse(), }) { - if (completing != null) { - return completing(this); + if (success != null) { + return success(this); } return orElse(); } } -abstract class Completing implements ButtonState { - const factory Completing() = _$Completing; +abstract class Succeding implements ButtonState { + const factory Succeding() = _$Succeding; } /// @nodoc -abstract class $ErroringCopyWith<$Res> { - factory $ErroringCopyWith(Erroring value, $Res Function(Erroring) then) = - _$ErroringCopyWithImpl<$Res>; +abstract class $FailingCopyWith<$Res> { + factory $FailingCopyWith(Failing value, $Res Function(Failing) then) = + _$FailingCopyWithImpl<$Res>; } /// @nodoc -class _$ErroringCopyWithImpl<$Res> extends _$ButtonStateCopyWithImpl<$Res> - implements $ErroringCopyWith<$Res> { - _$ErroringCopyWithImpl(Erroring _value, $Res Function(Erroring) _then) - : super(_value, (v) => _then(v as Erroring)); +class _$FailingCopyWithImpl<$Res> extends _$ButtonStateCopyWithImpl<$Res> + implements $FailingCopyWith<$Res> { + _$FailingCopyWithImpl(Failing _value, $Res Function(Failing) _then) + : super(_value, (v) => _then(v as Failing)); @override - Erroring get _value => super._value as Erroring; + Failing get _value => super._value as Failing; } /// @nodoc -class _$Erroring implements Erroring { - const _$Erroring(); +class _$Failing implements Failing { + const _$Failing(); @override String toString() { - return 'ButtonState.erroring()'; + return 'ButtonState.error()'; } @override bool operator ==(dynamic other) { - return identical(this, other) || (other is Erroring); + return identical(this, other) || (other is Failing); } @override @@ -390,25 +389,25 @@ class _$Erroring implements Erroring { @override @optionalTypeArgs TResult when({ - required TResult Function() idling, + required TResult Function() idle, required TResult Function() loading, - required TResult Function() completing, - required TResult Function() erroring, + required TResult Function() success, + required TResult Function() error, }) { - return erroring(); + return error(); } @override @optionalTypeArgs TResult maybeWhen({ - TResult Function()? idling, + TResult Function()? idle, TResult Function()? loading, - TResult Function()? completing, - TResult Function()? erroring, + TResult Function()? success, + TResult Function()? error, required TResult orElse(), }) { - if (erroring != null) { - return erroring(); + if (error != null) { + return error(); } return orElse(); } @@ -416,30 +415,30 @@ class _$Erroring implements Erroring { @override @optionalTypeArgs TResult map({ - required TResult Function(Idling value) idling, + required TResult Function(Idling value) idle, required TResult Function(Loading value) loading, - required TResult Function(Completing value) completing, - required TResult Function(Erroring value) erroring, + required TResult Function(Succeding value) success, + required TResult Function(Failing value) error, }) { - return erroring(this); + return error(this); } @override @optionalTypeArgs TResult maybeMap({ - TResult Function(Idling value)? idling, + TResult Function(Idling value)? idle, TResult Function(Loading value)? loading, - TResult Function(Completing value)? completing, - TResult Function(Erroring value)? erroring, + TResult Function(Succeding value)? success, + TResult Function(Failing value)? error, required TResult orElse(), }) { - if (erroring != null) { - return erroring(this); + if (error != null) { + return error(this); } return orElse(); } } -abstract class Erroring implements ButtonState { - const factory Erroring() = _$Erroring; +abstract class Failing implements ButtonState { + const factory Failing() = _$Failing; } diff --git a/screenshots/ezgif-1-492fa074abc6.gif b/screenshots/ezgif-1-492fa074abc6.gif deleted file mode 100644 index 6ebb2cd6ac4603040ed01b38ada6b3ede451bcc9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 449650 zcmeF2_fu0}wDwOb9Re5(J@n8+uR^Gz0tN*I=}2#4L&QP~gd$+*RS2L+Hxv~WArui& zF)H{4rG#Dtq$(himv`=;aqpTrGwX*__UyBsz0Q30bB>>|H8k>d1uKL9fVBYI`@rdk z02=@S0EdEj@}wMdT&ScFjD@A ziSUUj8;FaFi(kl+5EGS1UXx7Ol!{G|N?Df{=aZI1OB7Ke=424iYBwx^OMIuBzojRS z($^Bw*VWh8(>K&NFvJHMy2cnOAdTbuO|%qDuRJt6W`^@6SQ_YA;w-HUb*vKJ+7Mc8 zDtB$Q#B4*7j~C6`Ssb;qwL4M1W$$>#;nYb-htrOfTaJ&mPscrRI%#tD-=OoiZkNK5 zbIva3Np&7>9-jL{-sjOiUOqmlPkkD9FZy1*crh^0KQJ(_Gl;Ct<+rR90FMQwiJm^s|?e*QZ2b?Dp2dn5mijQnH&Xqg)SdYg68jy2Aj87-d; z5S^WPF*`lCFu(Nk-@(et+OJ!{`W$t0eRFGlYkQHry;!`xRQmh(&dze#?n>(JDs?Xv z*n9nHZ?$M|XK!zJ?{AUx-<7QWUwQlMCHos$`+KwdfB*fL+W(&Tbf-w3dR8~m9Q?J$^Zm2>AJ3zv z`yZTo-Z1tmW^-xm{qrXi9RvuElzl6GvO7sw)$2oR?Ds_DQa{K3SbJ)bd>sNn%vAXZErBAoF?QSl7t@Zv?vYRetoZ44e z7iY5Y+;69|ozI2L=C}q{Kf2%)y*QiaLos6J`saqs6$DpS2VU}fwm4T5)vG*TeC=Dv z{DYXe>iH6M{o;Hn!ST&JEnXyaq0G07(0y8TmVt0QYE*+M&yGE^;0snZuC_c`PpfvM zeQv?vD`Jg9EAt}VLW+#2tX{?9DE3scQsaP%s-jOFKBL^sxpl$9D29<(-x#@(B<)
{MMsmBoy||?6O^ztNkzkx)T)Am3si1f(1o&wir;X;a-5vF73BFy`RRdd*!X@!n61a?6bTA^B=9k#?TgqS9awM=$%LSal z=vBz~v3#d8>neP*uh0$*=Vhj-D8DKa3kM@#>|g9-7*5_xF>klCQLQH+s@gJ=1=I-xeJS#U@ zC?s>ME>j^b#vjtU`4x59PMaT9ajGjgoiEk%8CjOAzdBXhial^i(N&NRuy3+Bp^uUVx+Hw^S-#*0_GfVh;RjNg@ zJkQUUVCljwkhOG~>E9@JI7edGH4w3F_yxVVDO?d9U{9!3uwGYgL(_A zSrw=88X%Ims|ef?R348O292v1pBfj_#erP|M6)OFACK`tj;~S7Tb$B^S|>xGFG`e5 z5yr?E0^eY8qBz^04wjCw5;qtm^4l>u;_NT-ieM<_{h!mrTc$;f*Q`z28Z|H3TM0<@ zm1_13rQiAN$1A@8;vL5G2gLY^jqe@Tx3qwIE&_e#RJ5f6Q01oU>hIq zDwlj}kZfK8f(vYQ3Rzs6kh;dA9N(FeuE+KO$D&}a`xU5cJE$UMz0I~kOME28R#iw) zD!Us1;}HqO-epH=*N)746K*9h1TzTSf@j+!zC~BRk+Hp zY>^D{-?a`b_`>p^w+;4DG^=o=7b`wj$NQ{8<||K!pSzDfw)0p?o<%(PP2k$=e={0b z#OG@EMMB___^euDHxeP!TANDNYqCiE-QbfG%k0%%ShLb>Dl5NwD&9O&5OR0C{*}Xb z4POcI@z3xq1SRQm>b4Iwx42DnPFL81Sr>rHnyIdMy^`6fyxs z5OSCs^Iv+T@sh7-z_3@f6aRE?{o8oVTiwWo(U9AQmsAj1$rcwikvwqr8{0h%qp_MN zv>HZ4+1CrgK2GT_rrpwnR-HTSXy4AsKc!`85byUn5H5c@M;-uQHsXa|HJg%d*($!E zv_#}EHhdo)Mv_(VCAO(M32%mzxQgFDl=zVxAA;w znk>-um-FfoIl=+H7v;=?NT1d_atzz)^6y16e$au#Y#79`7^EwWX}Ss&!zy8wy7M6L zt9$yE4_w9|0?t=Zf9_eV9a-cOsv`^q@oUu`9f~)jTYPV6*Q1WAq27+8s~v_5v~LF` z;)5$B@1P!tvoM@Ix)!5Vh-&^={JRid1n2XL6O+LioFKC<;THC=pDg0-W&1w@i25pz zN*5+HaL*FqjJ?1QKgD-4)t5^J4beFX&REL%>_#!%3Q*w^uch6BdeldSYWS*m^H!hm%Yy~Cf zNBH(@&f9jk(xi}Z4ma(-_eX16p^_A_EqpwfH-c=@Bh?shBkU`XiA(4@X@a=A+9{kr z9KWHr&S}Lg zGu$`Ah7e!kFm2gTL%hstx$}Z*#CO_znbq%7>5zhT5*F-J4Q2#z6Wb9UI7ZwrS%N$ZBxVP`5vX}}8sq@LO<2T*TxC@>!6Aw$;7Z&e>R{0k&H((KpI*Tg z5~K_~oI?&4iDKW7cr<_XyBtDO2a#@l%*N38e1&mypzh}@TG0v4w$pdjr}f?6#wpF| zfB16oxenrL1z7(PCjFZ6V?V!@u8SI0u@Ba;Q$Gx+4(y~dQE6Wc(*|ABzQv>s=cj!)Ono(+HolX_LZwd` zrqA>psfkHnuv40CO&`xsU)@PxL*3snyie~;{~dF0EC2o;O8(FA{im&IfG8DgM1{Ih z;Ww$A1yt@ARNfb0Xs>}a zeKOVQnd&~7n0J}#h%hamOvMpll@YKG+bIi6%QBeERN4g_DMKt?WE#KAlE0aKXEGCW zGfRCp%UT(tMKv%YWEv2ROfxdcx;d`zgjJJsPPqxI-UKVrGqv!3c8f^a5D9GpL>&iF zbpxvvK*EwCnB>fW0*Lt<*c=hYL(IJCmUlZF5s?hmMME4;ATBNDs-A#^jN~5#WuD!I znEF8U84%Mb1Ii1GF1K+NfRI!1ZWb%;JK@9|>( zGq*6x2v`*jdHn_I>;pCPff&&b?*?*QgGyterfVPf?fasD=ZX-0H4JJN(H?uZ9{`I2Lf2T8NaFW>>6R%NH8a{o|uaz4a>S;(UT zRc3)fcmPHPWT;?E7F2BwVnG0oM?nDu)O`UYx5`wlnE1N0N%0SlY`)s*DB1hxnPTj0X1TZDo2dna$H6V zVN9496$GVK8%F`s07#eyp)EJ-h zHx$B!hUy^zYdpC4CKzCWk5d6N1|;@ng$2FXlL?cK0;}SyJ{ZAJ?l8wFusOZfajo1T zCC?EL^P~g%G|25;uz^oCF9L?f=PMDwrCeY)T7x&6n^OA@>_})tslt);>>mYB9#~{q zySLchYOyP7Ir*x^{zr@B-xj?1(=#Sdo!y_}O@#fqF5m!=CE{V7Xim%?NSY47&@g=f z;Nu2PuqrN4VK7=A1_#qXz?1=y92Knly)d;9?2JF0=;xMr7?f&Y@S@P!7!1cljx!%B zxq;LObT}3q$wN`6Lv&T42*%S3QJ}LSPfPy3pozaMH+lKc{pGn^Ppmu36mU=k6?_&4 z)Q#lcOa}i-0XL1%LyMr@g)ra{NBY#t5dZ)Iz**(z5mnOfA1dH$WqknYD8PjFK*O!t zMGTO^KZequors0XAOK_T%6aw@)CK@?;sJmPoLXwW(VSWJqusT$tZT7V4i7yIyfSBk zAJ$m^R4wZ6e~hQSa$>wH%L2R@kC6m02Obpd-odk1E{%hEh=YAp@*Ip_JBz_U*t#b_ zDoRzLTmS&_0P0RWI*tI8@E}Y$;CTv2+RI-3+vQBm%zpQ1)4e09riS+Pi58=*K&LXkL*P_)aBP$oy)gLwV>8n_lapXI=1bDO zDqS2smc7`h8T;Ig05pf>V??vhet*V^15UGguI@h}oq80hnhU4G^suF-?hs3$uJK-0 zR9nBpdZFZnK4ofk3>So)oL7JIm2u%K^!_8H541k4+mv2Vzxen>?DHiRs05#}ma$+s3#NwvkMDm(0AL;lM6jm6?gPg1o~SV*t4I_AM}w!u zpnq#1nzUxIpKqOjz7u#r<~EpKTz%oTfdY=Mi~peP1AtiNr=v>$y!v2B&vmx%0%%~I z4`4$FPBSajeCQFX4^?ShdH?`j14R|q5-#K~-WHp$6UN?z=(1k-@j{zk7XD?6!nml; zoYZG*uCCI$k2Z*hClF9297OIXRDt@?5)1wm_POZPv7Nt6kvfG$86FRuMS#TC9$8?a!9SnLjrPQi722;s zg9v4mmziN7MMENln_?m9vPB-;AXx-VhFL5_gUJFQM;u^9dvzQE%jD~7k0^iwU~TSl zH2x6+s5-e{*JcbBLpQ23nE@fKXC#5Jd+&1jz%O5alKD_5$36y@1yVX|28_K(8l zqVJ}czvs(9$g$u^b+9a}T$TzFy3NQesJQX3!$@pYpVbOy9WLOYSw67vN+V?ap;;6J zgokkOL9JBs3=yAig^pP;Y7q$VCsi158_Fu`<8YtQ{Qeqan$!Jm9K)~FvkOkY)eiRo zy8gD+-!wSx0lbuiLUGTaKIb*DUqA>z%L`ODG8Mr4#_#~tbqXTr7=O$QIA2$(5Y=Og z2Peh$NaFw#*0?^S)|`LlyjekA;gsL1;3>MVw0u zmHo?o0|nOa>aU2lbd(4!eaz7snKvM08lso(NR$cnXS$AnT~6e=yem7YTzkttH*j&z z;4c?9HsN zuYaDb&IUJrujCtYQGR1{?}89VZW?!Nnoew<5MQ^<7*{p_ zwaB++t0`*uX+_N~SMT$h}}iRZGVBI zE=IzC95;PCeutaC3t;~a6Wk8zSi8QP6%qGGQs7VQB@zCP?<DWn~*hy#az$^->aY{+vyQ6x$`I`50J9djFc3tvzY0`V;=6hGCb}Qrds!I22 zI`--&_8QoGbm_m3EcRM{#WltK&35|xvg2>t#NS@xUxxI4m-&8=_kM4wR(t7wf5-j@ zZ_&5x{kh@&FKlC`_rK#>|AsqMGK2q(vQMjwu>U1$%S@Rc%y=Kn#T_h^9xQbnEKeM) znxkj=fXL-s@oRPaJNjS+j5?7@w4NK7P`Y!Y64Kk8+x_PC=@B_2fHE z+onq%iyr*ot7*ZtDd1y?P0_iP3(q3P+7rajuX?<^ zzB2x%==?9Q_B;O$U=prtK3xfX(zeB}>wdjylI9c%w+;XP9Ch#BVzHa(X`%`v=x%vb5Kau0F@31Rxx$i_xy-AZkUgEKPW$xnx z^F%4ny=zND^-7v5-&A-djIM-xkNq?0ZPMOJ3UI&h4m0<6*1-+Hza!lTxMutKi7gLze2P3+AiadlxZ zX+~=~htN>-n&r`B*s?0*=mvkgFagtHDn`f@Eo^rz zW25oYn`ksB)wfOgG2ZIqJ4JRnQq69r^xQ*d&3eiIUJ6-jj@b32A$yzee_4LHN#KjC zdO?bZT1aRgz1ko0wm7=2pfdmX?cpQ!s_)$`sTNiFTCWUwWiDDh#mRp=eeu4HzT49_ ziRt_}>bk;r-||NZd??g*P>w>ShXn`v+S;V;udT0T95SlvYaQ$>Q~{2w2_Hb50;aof zg@t4L9Ic~nC0#PFu!j0^NLxk(6`nCdo`A`v>>e+0yHfV%Xz0N@To`?h;hHFToiSV` z6-@wHU@HqK{K)8}8!+eZH{+p5o37!+D|Z$mtx?WCH(Gy3^}IIr+e+jOW^LG%>h zm#k3e6PpYXy?*3NxqYx8`_oZp=1oUoXS7oSPhz2q`y8Wa=Ph4R7EoCGMdbHPU1RbG137brRi;=r*Xer z|IoM$Hkfk!lD(*HAK0bwzolmKEYw|wPg-=VZ-g@qBA&AG0EzG9_h*1MIepW@O}qHQ z7eJy@jOX~)PBz~$MnTu$TSeZbM3Xmi-N~aq9LA`~v!gPd!+{1?V&B%Zo{B@X_a`Z) z%9~(>7~b<;@hfj8^3EANvT?OIB;4hOxO;`5sD}Cm2DCr z8>}?HW!epLb3BLLf0zrpzCk!N=|43zNWv!zp*T#0PKj{~7)El@caFzu%7c(tH31Pc z__Wg`1oSWc@q?L)ag?H`{F!cqGoC1*#$@_NMRSzgvAKO7fPeYY2`K^}IemyC|9W(~ z72`kOaon?$qcQ}>=@dzo$I|f)><3Gu0-_r44$lk@=NL6nXm@D{4oUS(*58Eu-|{r3VW0lQT{nRw9kwl~ftC_at#_MDxca1jFo3If56F1sFo@E|zpg+8Tkgb3yQ zLgbG5-Xxh%;QO`)7Z7j`wUE!|c2wceE<|Ye7-@@)|NZo>?wY^XpF+J)+Z>|3`j3rf zm1>3~NF4H?Yg|N^l2*|1c2xx4OA`5CzoH>`j{y`12{LKib*R)A_rXXmz2^X%Xv<|& z7571wgS^Edu14=u%m95h=feo@S0#R&Oy-RCL8%ae7TKbDA?5XeI64Zm_RmCU!MOpy6kgqMgr( z-oLfuLWn@MB z4^&MaWchlp>m7EtfCwk*ttoRU2;T{!L}9Fpph=&ur1gBGbw8GtTF0L)7Nf|G-C1S{ z1Vl+7W--0bdT0B7bMshOpWD3>Z@jxYyee&Kj(>6CXlcQ7Qh##rTdgYGR!pal<7;iA zc+=!P)eqqB^3?Ov{TX~_2qLF37EE}cv03$&oxz>COg?rCO*QgO z;0;|i2Yf*VPt&21JE}-|Ce!a)vggX}glzhMA=PX=tTrdU=R5-*n%(`i4kDB2y~5EW z4hk}|3wU)Z9rDkkaD&Z(>u-J#L(TxW5Cbxb%NM``N#u|h)Sa*;{Pfel|ihq#kWEYWbv97Q$=r@QWkzd zI2ZyoPS4`~zyhczA*d`x!Irorn9P~hpelV_iU1O)xtCetj&CA%c6>Xl{VMadAKg6T zYe(r9qN*!Nor|GkZ6)R>a`z;Zt-nU&*`O)z(5?G&BVN_alpya{Uml@dpX`vZ{tn(~hFgup!xM<#0D zs;WZ;ZmC@!jzO{$<#>>;q{%OozT{%L4G!m4FrpJGe}>|RI&S_7_V=n`iR`1Y>2%v& zj!=XW5+GUZ*Ivv=g#z)2P`v&}Hgu;}@ay$r&RibafaP;^PY`o*mc;9?@7>eBO zM6_Ob8z%<0Vha9Z+MJ4^gs;I3#K?Y#tWwz&wjH*nu0NmlJumyj2yJ~CTpZTvnH!@>*K^V zZuVcMXuhoDlm{_`3KFHKR9m18fcoiWO$?^H8?8t%S4>$%#%RFt zMM3{$w&UlF`fBEBt$SixpMDwUaPui{E+1KMm1=fi>g9kICgCaDLsO!-Agdx|Q zA-6|E7oHBezZvov8gh4V)Ut8m)*Je6=V*TnbpHB~r_DEimu~?9-~9g#qLPRXeBXZT zxCD$0O79S5nBO91zeR3;y9E0$3i;n-M1SF=R1e*gj*la-}!j{_R4>Ew$I;14igky33|hEHp9eYt_cpqq=?~!>#mfXVbYub*hgE5 zM|VJuY3Kb5z6~>o4o`{FQ6!ZrV&-+Cn4w#?x?7IkNRESBZo)`jj$7WNk=&;v`Sota zuSW{TMv7BimsgKBUg0y@F6n?Xb)7b zubAzW%J{I5Eg)F}VCJSYG(40=rUX_cR0sIv##4kG0k-0tuV&!15`0>w-CHO3;xVTw zu5n*v!`^yuR>wd0?gU?yqbI6?)%)6?Jp_0R1oQ^@n;*=EMy3my`J#F+g71#= z;yov9W;lHSI3vKm*FX5&Xpq#r`+;}wSYTJetVp20Sd@PlC57kB{Oxb^cjo5r{+^G6 zFAzi)h>8m&{ROh^0zq-YCD6NGGDsdry6))97K{nh%qJVIf#Lap<_;N$Al*p!;6s7r zTZ858K#sN^m%Zkr9o;)5=Py5-Jth)h=(te$Y_X_!vH08KgYl4CktxO^b6YF!f;g~g zRJ;=kcAPU_9TNl(jt_8!+o6KaR8c|+@$CU2UE3344025gS&(z|%|}9cFT@l_a#!@Q z)(C6v4WI^2g!~SvT9{?xr%sIfEj*a*%o#ODC4>eihVCTRd`mFu1JVWvj;@r@;P~o> zCC6dk`TBstH{)D}B=eo0MoizG?V0v854bDDvx*YHAPX|QzJ3H`^2t5l67+^Atwct_ zcjxL>{l7d2@hbWGIqByk*I@4UFm_);V211ofO-mi$Jt z+kvRBxlarM4R5^oqCoE(;2+v&ex?JCy)#y>l)DRwPCiqdtzP}n&`mG6H9F|h?}<9k z!0iX~u>&iQT30^V&2lyT8gX<-d6Av4zwCm^yeN?R4kUUZaVT=NXBFB_0XUiAUnN0l zCBT*6?)|;w_YEMcK!7vpQvCqI1oI2-P5z?b`RN<%PdmBn_snIpdHZL-zAH}s<4@an zOfjBYS^W2d3y}~IoG;rN1!n@B3-OHHgv-&ZZvp{L&UoA!>DOR&^gn6NVp|M~Q&#|=w%Z~f(|Fd1ou zIMlKR`^qm{Qov4_H7!`T6cGMX&a?&Be)N*xNeHFE_2brmmJsZiu*EM4cEMrhrBk*V zTc1!{6|8lWT(4yZqI#8_XDbAr1hm5<1ra3KzNj8Aio>ONrWrKtH_0hD@$OE7@7m*< zaq!9;NZdjsCl+$$)1hq+?Emej(D~~ZqPB2V#M*kIQE*~_PXe>#Hy4703r>vQNl3C- zU3DbVE4|p*-z=Ep@09y|v~S;S%su`S37OR3aOxw~*3Z^U&U2h!zI=D-Pp`ine%rT? zgfS%B8kRd5f*abGWp@&K_!BORT)O>);)qU&MkP@HgdeYhyBWqaDVN|lDDy5{(-5rg zO7`AKEIWELEiT~uc!2D)orW8HQtV3$D={7E@pAa}!7<-uy_=WL$8yrQkLN*5juIUg z;?4WOMNi=EkvT?&q*}ee(qGUGFSwGy`X5_p)!oZ*0yOIAWlj{)u?ij{9rP_{JVe9q zi9pK530`{8?83hr9ntZd4}u46W{w6D6p!ydn;?Z^5}lafP=Q}^`6NM~KOK(CrN{lV z=Ll@w)62F@QoADT-J?)XCaLTGmLP4Z;_ap#0(Shrgf{~}`=76iFmHci+%9$fJudQ> z3q@4#qtpbgB=;^^>2G{ZTpNtL#7X#F^9h_L0-9^Tz|Ri*Ba-m*S)`D`g7SHoNo$W z+)((CuO0NIE@V@2pxF4v#`5B(5|d_`D5TEaY;#Wt^)?##y@rA8|?5yU9!3a8-1@9J`}MV*I^RN4B)8X1+)G@0YMrUhRx%fn4UU!_u} z^;bt<-q>7S`D?Jo>Pi&WjNCWenCZwkU}d1WJq4@F0;@`Vuj)AoKZ^{&9?xrVx@b~= ztSCCdU4D=rD0(W!(O)K3$sqIMN@;^_%;~G9#W7k?!SLVrG{*bNL694?yiU%UMp!4O zo*gHVryvWl} zf5ImDDee<^|=~M;;3YPxe_qf=}65H-|D@%2R3rgTmB%(3qz~7mBiyM?znzKOYNy zU(E68^K6~7GcrToW(W_>(6r&y8uy>8cKIk{FQvtyC%mpFsx12ue`whHC}Yj7jMgc@ z+}k*sNgB$((IY+ABK%IUqrv48RPKn=hjyW-6{(_5YCn)K^eo?Zb4kU%(tgiYe>J-C zRO`KjP8rsg{-{|#Ox{xD>W-y@{x?&r_tI`Y*HE(MNoO=6iI_Xbugj)JC1U#VI$IKM zhS%doyQzM?uXy`pQZ(Dq8DL+J^w+vxmc=~DM=fbj^#?_RsYHnkwADx5ZtE+Qv6>kOSF(uRg#?v@Zjqiq$M#Rn=a^Qhso zSSLBD`>Svv(3N$m@(Eez;8|5Y z3fhgyj?3fI(eiROZu11m&u)LUNsI=cjC&Fp{6`gz_WoY650c`#DEg_-=4ZHI8YrPG6f~|@ zzxT8hynQECUY)G`!MyxTK%1$ec2@O=DF%>xRzgv?!l>eu?B#-QTVArw1$}SdB;Ee9 zuV{F$uPlp&E1I*O(fhin9Tclmyed(tKBWBV=9jBkdiO|}iR#n7z0D;D`${;izK;vb z&9qK=-Y|UN2ZFY)(fsYIDSxz+=%`L9{B^KG#I9JQn+8e}IG7~2 zigSg^Q1zLoHRqm&9&a{oM)j~b^f8Ph;Jm@c%u~kMWCjO610vqTrok@UQT3Qs`LDQ* z1+!};^6|5viaD24@BUNufv6653O%D!j;Z;9UOkY5vY-lBqGtg1zjtSzHC?vp=Q)Is z+)%=~J&5cLOV#h6GoQ6o9#aoJTl;;e=~>HR8=aku`M#+9tv(OHc=kOn6s(1Aum))Ah6TZxElK6NB{oc79KXNAiYPXOz(z_WUq zvF~fgx0-IeUX9SaJ)t_W^W{eS?|RLqTH_3OkwObww;&KGsP!g>@?B_Drlthx-V|dvcxjR~^7uBXk zzqa=3w`-+et(%sdj^VUGfxRBpf`uNp_Su?gmpYD;kZP^(WbSH{D`KFC@n+q;(e&;> z^!R4UV;&E!(ic7FkLi{R*Du)U>{VXBqx(?WVaV?6%Z9X);77`L79Fm>{91Cb<@{bP zv}g^^tT-nh=~y3Hc;w}fQb}^{MfIOZ>2)2Wc4J&HE~~SH)!8n5k{}Qnm9NxU_dn1h{A0wxVd4MaKl=HPTM4ZoMDfg z#(MJEwkeSg!(N?+^|Y(|6Sg~seO4M98Ch*JisnZBXB#$hn%ibI;*36A)YvTe+BT=( zVKi{HVe`Re+q@b3Mc=miR+;c?g^L=-U$PEXV|89HI!dR1snEE7&HVM!xenuR%?;Z@ zr(gf{VjB;4Yec6?T`6TdrkvWI) zFmY%0-%5qj1cw8PEVUe!pfE#w`Q+e)5h#zncmnth2oo%%WE^{=5i#onIN#ODTsT?6|@^)i)EH!9g1uBSFXlk{(hu@qgem;GL>idsMCtJ#2HOqUJ{yf`K!Y;UE{By#QGWHDA4R44k1*KCGdgUiKB zbzTAzQ|1!gva1v>LZ{BYl|G(qdx31Q-;HhUwzu`=TE{eP{fM`p%PAZXORD=spbb3jIxq8>sOP_F*PIfxK^P;DAn;{q6 zt)kl*LGSF0CrK__fHxE+)rj1@LDAs6wS@6Ym%aB!d}=<-L;^CcwLZOKI@Bzsfi~jeEn} z&TAsRJvgmhAz%*>?o+l_nIc3=qxNlNU4bOfu-wjJnW1?PJ)y&xx%J>QKV`vIqJb&o z5DBJ$J5j+8CASEIuHz9PBI0g{@E${Ghr!JX7FHvs@hg^zTBya4WvGBK_ag%YDO2B- ztoL|U&?0RPC<;{Ix2qONs>w?!sI2i3E|yJxCske(d|#W!z2j?wTFn2KdkrbGo-F~xl%9obo28ZnSu-9i9`3!d+o@)13Fo)c@+lK&wU8I-R;5+3W?4c^%jcxY zB{vLW-&X_G$-Mw5&X6SQYG=fnWe_eJ+XF@cnr?`U^?SvCpMg9vBXfE0Za0B zsoE{8ZGk-YL=e1|s>46A@g&8U-o9d;a?CD`0kEXJrL3cW%?cyppj++(COH<6gz|~z zGq_P*SoyB-b0u8aGCwjcR3)s8V!E+)GDz!kgBUBV8ImG3|NI%SItHRW)1{bdQE*PbcRtdcM4`=m=l0X+KA3zSzqFaJ|zgReZAzG((8tuK&S&qP9 zLGoY+Z@g8^5?ax}`=3UIW-F0*hQN!rG&$0Z4VJe#0#P_ZX3pHxTet|gdjS(=;vNYy zZ47I!HU1df+8MHB8$sX$czEF9Yykti5BU+=rK2V{fwq!hDlq9!IF>ufFQ@o-ET21e z4~-tz-y!nW5qR4GnYCX-!QJMg?5>%920x-x4j->)Z}o71WP~AeMEzP)Zsc~A=guN< z`-^ayc9|csYApnmuGK<=C-|v2%)S+dN)SKN9ZQ?lv0MF6NH+3tz+f(qKkJq}+ilg- zg{oul?-1nU*Hs=)>e}%h{@k_KRAM~~pyo+vuP1e4B;H}gqSplACqwKPUq*vvvIyDe zh?PF{qhcRUI2bH=*6R4dCFm)Vk!iOMqFUciQQV$EKL zB-ort&w!qb z98yRES5K#IHd(0$B+lE#RYBU$0HoJ0VP=Tpyd+K2c-e+3rE@bjp3v+hD^9vJl*;Yn% zD`ziRnhBGvo-6Q&U&rJFtbUcVwavcXAVl%%U5Fcqtbi?a zo~R}8$JA-+f{wc5q_VB_Ic537l~q`{YqtoJQ8P%!oOBmSFowYs!rmqaLaSp7L!zK)T2*#FT-6wodH zo@XKTg}6ZDDy0SeQ?AlVY={yqVk2Wd*&OmB+DL`7oIiXUTfCB3&p`e^iq11G$-j%k z44H!B-imuG?p>hfPBAS!gR};%^nwFXQuXudk z@rDn4xcS{2&bhwVVc}G8K*}{{G@GUv-4#7S)eiU-s=KS}u7e9HY4VvE(n>67>{ra^Ij_pD^(#bV-3&M)4i=c|WR#m3BDU ztsP4@H=(ESlv3ml`c($nxhlG7==aM`>3B-! zAq5f=qeW(KW!*S9;Rx2Qub3hBuRW|mG7VKs0XKs6#Ku;xN`6^*vM9j6{2J8zPWy{M z`%L}_I}(nrKJLQ!`Sz#lMvrtXSmV*Qluf(Z${VH{Auo~(r7brG~YeSt#Kn=x;WPl1&&JD6HTIx~}LmRTfo7LNEXOciC9q(m5 zQSmPWVBhP>x>O?rwp5!h)m4D_6nY$72&(YMnPrs@oJx=V>yTZ*@ipqHs{{JS8nMUD3CeQc%n~81up|?hot#ma`C3N`tw!Zht(%%6|W2t`q*wJ z7Aj|O9zVZ1=Q9*?9Y(A!rKOp&FX}nB$O?Jz8ATT*?1$%an7n5W51heZTog?Xi^i$j*bzgI=n zQ+D584`aApPSB~msxO_~(kiJfI(}U8AhX&C9jX3sTIf{raRz_Z_FIQ4%&K)mlOJbNjU1Jaw8#x}K*W9ySu% zsd^dQ2orFZNQWQxSU$KzR7o1RcjL_{)p%3X)CT5hHo?W%>9*xCGFnyRgY6ez*6jJs zrOmMMds%A#Ou#+VKZ|{CgW7{x{P8k>INdJ1=JN5cbDxrdT<$C?g5A^nVlG`8T=T${ z(u)bs_UTWR_f=l4``~KBF=u#gh>BE6{XwcWu+U23Q2D%Bq0P4zuOMb#)W7IggeDxI%ZzP*{IMj^l+oy7Dwf_Kgco7d3g|Om5 zEsgV~^;;tLF<0HgD;uWQ_l3CYJUsO+;CA7uHs~3;O_6s@*kYG84 zeLwk!=PbC)mAFdK3tLZBKkoUt1L6XNO%!^SE~+~_4gVfZVXzC%9j@0l_4F~$ku7eO z%sEry2d(gut{(+rNhcumWrmkS>qZy`~m^rq*}-pza8)#`U9V(#xiNQ$T&mo zBbw3;pJuQG7L>`oC`dXezt=iZh<}}eIO@3lGtVe#-GZQw^8503HZYkZ_Ao)%Y9NdR zJXwt6wwfpKNiL$hvo?%}T%aDAi^#5=YWjBSv)OuN=GZe0zPM7(tP z-3hLG@l@o0Ne~eV3ykB>LvuNw@hXIZr_7XKML0H0tqdS4K-%PyYLgQvV}Zw;2h}{O zy<00MAf9Lp+^h=(s`kmCD{%^xb>~{mH)9NzE-FROb4c|0n|W^+l|0+?Pi+OKS{}9F zhnO5#-XogwNE{GG9OII#$~!IB$M+)M3bc;tJ6TE-y}d@0KC_7S>ykFJ!p-Uuufebm z+CnQtD=5@aJpV2TyusGMLYvoRJ)f{>Wks2R2VX?)0ywayyC;H%oM`Gg?`7o{ zIsN^8H|d^0;+HNV_!n+N_IJ2Fhtf3sYEkzy;U=sb<9syui*vp_5(1Q7A$F;i zlH^3T2qZnH$(6crnTljI_6f~)IZ3lU+=cu}GCWPCFSW1ze4u)nN2Hu&(O*U^NzwO% zL=&w{vRe>#OEOd%(~-+v@6@>5rEBLrsbW<==Dh9OIsNW0R6HlLPj}1k|DFJLy=hNT zMfLmso7Yx zKjcf+;SV{QN|sWx0*`p#WkaY!{Q^eZi^?}Q{n9tGH$wuG#?{|^t?&_NF5xm+HO@EKUb0^@0X4ynu zZ1nwW7X-0|(mV|J6H2^`=?dc3N+-z{GWtGn?W3kgM1VPQybo#~@|hc6Ut*jjyt*#-6{m(iC(T{9!y)~i zS;QyJfx5cGq41TZZ(`~B(@dGQyMo>JtkMI6DMOq^X7XOVC_FOWd|0r)|S4_JM^8od174B6!-KNa` z)+@^Ix744fA`LPR3CwX=@(-jMeb)Vk+8s@m0J5(7y@OV-&P!irf>Hy%7>Bjzi ztV11&|0nUa;HtregYDDL_b&gAgPN=w3^Cov@!yuXW|#)PgBoA{41cra?G+{ZO!;xg z?sI<=ZU#y;Pk_`xfBlti`a+oIs->R|C1s8f7tKd2hASMpPvj>HEe3J8^Gi$h>|?~; z6}j{2GLSSG+egsSA~_>9a)XT~)M7`vC{^#kAAGIf;na>{^jFJhChYe&c+~iH@%s=l zKbW7t?M?H+1Ao^<46=pj*uAW6PDDo0VbNf)8Ez841Ag56mVdxLd&gM687Vf9fh5Lr zK{(f&;mU=2;+C8h{%13r7mW+|n5lxyk@#~6u>1~2@d!PQ;1R>UPIo%2#~3+skd-2i z%V+sQH&|jsM~`Xqmp}XVa9m zake%*+eI{_sWiWx?{85I_zuQgSBZ;AWte91+-ecIvn#^T5;f!5X2&{<+7%gdmNNJH)=>&xMhn+UVJVA+88TBQsmbR>3r0j=l0;|`4 z8*0m)h?KK!l{@)e&RJXjbfmmTtGxGjdGARX|44;un8I@{SfI9I3@<69RdGrS8#gJ< zIjNY{s+8BN6oH2ppMsvFE8qF9%+OYO5UEnzs?zXXrA1q{d+Vs4y>*@IL3Nn&LPw9k4DQfB%d})MuQlO4_B(Jo{6QI;S!|->n;k78Kd>5nZ zQAT&#j2PFA9{ez>)-kUAVcei&QWs^?a^2**i_uf6kajQ9m984|!*qFDe^A%ntclpeAI$+o_z4ox1S!|! zTLh^Cf`kJB>4{bHBbgbsTbS)xn4}scU56y>0JN`Cj@d8w&PXt&ARvmv-DU-`iq50o13wf?p!>8fkD#jtDG zvun|{?})a4+;0DD&%RgJ;YGCl7iq~QY4HPTk$DQtj}9s3wO!P8T#i<}F%3o%M88T) zZZIT=T~918Isx^FkQgGOgNXh~$#V=x?2bw z-)*yFM?1X!={2F}JtN><+wNM|0j97{88w}y#kg$!w7~004G2gMotB*ac^;@wf;_Sx znelG80sXjlPGHtzZN}yKjQh_U=NsBdut&b?`@Um0JmY3yOC3I&F+PM@^Y1ZUih@L~ zeLrV?|2o$Tivm76dVW6piKhFeQuQn`=poMVD# z&V(jCx-hsOx_DE5B=-D7tVDBc={@U%zazgk1aW+f*Dy+`6x&r4OQK37 z_XtuPC9Y5RtQqZg{&BIpKf<;aoz~A>N)kM)H4~-YrjgYdpZ6>NnnA*ixP)6J8iZdL z>n@2d1`?S*LS;blS)jz^oMf|sWEoXB z6DWo^JZ&561bGyECpL<0;FmV1x_X9ka@KygE&3ZnM0k;t{|Lpz1B)pv9q-LchCZ$hvyE$$8P)cTlomrQ14z5W*mbw>57IZbl;2v&9FEixJ^Qi(=EvzpwzU_u@_x8>gHm0b;NfVg8X=38Bpr#UP^;oTC%I? z{dhnRK=kVm$;n0Pb0Ak`Y0f<(yX5vn&V$G~fy}dKG9P>RbSx+q9N3iz+!ly)U6#(N zC`CaJC0RhJp`7J~l#M@)n35a5>$hNe2l?XpQ9$?JktS^;hF5Uz` z$=l-Nmn;{aCOlNX^-zEbWa5G2_`)s1@#V$FS1e%JLgLoVR1+-S1Y7LmW@l1%t?g$+ zgh}Tet;UF1`;qC`2_UDir)ae2iLD=EWzr&ap!hT)r}yo#2p<5mjJ6AG6JWyU0qFbl zcjgGSQ65so9zZ1k|97Co%U^b@@!6ULgc3c^{;Wh95XsNvS0Z)H5u`E+2q=J4!x3qj zB=&XxeDd727!w7H!*kCT?5sQOuN+8D`-tI402coII^hJTaQ7#m#2!IlY2jExZ%c&F zl?cLf_6NGiqzJzxsdQ%XW>kU{UYf46c-Q`^x28Lz<*-qNDwTUn>ZS-fo(fXJ7On$D zl@d|KVxp%ANGOE|erWw+&i>u$hV@^8+~R(mm*o>o5}!|JECYK?NB}{ql;pvUL3gh& z3&m#Q1LuD=-oT3vQSUzY;T;F?clACMz={AofkS7jTl5*#!b0)XY>C7nhPwb=nttb& zphQ_I_#ochGhJ*Qu;lC!`bGt#RU-F;JYH{x!^ z+)287{C)8~5wx7Cl$=@rW1v_wRlL}kF0|O8NEM&#J+}VVj?b8WT3U*3C?MyZ^X|3~ z``ptBq289$K0-l^w?d2_24Pa!>_XG;Nj(Yqy7%XD1hYEDJtV}%dM@`3{*l<%wQDGu zdGT)MK@zQn&?Q8rtNw9Kn!Xp20Fdzlo|2a6>m~D)%$teT{a_4^2o3(|T_{hG+FNW? zroglfX|~MyOaFC`%~Ti(R`y?UeEvaB(W6ns>)|J9@fr$)!RT7JbF-5n(!5w@a$EA; z6s+~()>em_E+!L z^+iVKVio}?@h>6!I#p^d34rXit`k{j-=={-G`EPxYTcuqUhHrI#_|aB2N5zL?i09iR5#Gb7e6o-(X zeCUrKyZ`2nscO$uNi7&7s_n-z%+{@)eBe-SdE z>Jx$Sq~dS)9TP&7_ooq>8m2Mx-=l@`gsdVi#22}Kn4?rn-CaA(DLdom^orGsHW!9O2oY^sjXDKCH~pTqqq(ywNU~t||Vevs=CA zoltbZM9V;q*ztVR$KRJn%T1np?uYaw?#w>fLK`%i1<+saJQxR}l>*j3_VU#)accG_ zUXO7taTE}Hw@A2_no&@C?lmK!cby0~{I=#g7Mr+ue=KNT?NsJPdBSz}-K4$geoyJ7 z80-n@?#k<2rjV7?4`+7)^8C(LW*NTODvd+FIT}4mXQBgY{U?k!n*}~Qu08{!HEL^$ zP`dLqF3vHZN)#lZD>f(PIX$`qaT1a!T;q7-(DFW6QGb{n+Bwz>2++Q-gxVoc##}rjUN{8zvCur5;X0rlp`XNA06t z>wn6PdSm=;G-~V^8x=jSKbNFg*>c7>aKujYb@Y^9>xQn=+%VD$c5Iy3H0~MxI%W=^ z#2Gt3U{=;-W~=F4-$Hb2SIZ3Dj9!1>a`x#XGco&T^)c~3_~Y7~zv=oC-MAHF7t@oL zV?JkVzB%Z!w7*ncIrsNu!t%}Y8Uc^A#@@%T-c9C8T)SWJ@%NX5m!9lvd8JKn5;xVK zo4U?cjyWc6;l%TkwohHld$Mr-Dc9wl2DX*b;uEQYKc^mPj&*;o5^Lz(nRNQLH%;yL zYC^pZAA2_YD!Iwzn{ln&VXM$}26r-i0E>*sv{bv#Q;=yX+q&g@ zQ0M~+hrdv=i%``rvU*pjz%3RSk>mCCzR+{{OI&tDuAf?k$cwe>act%#UWxf$R5jds zIVLK~|&#L&bBuuxN` zxw^hQcQl+&Vi7)wE65u4Q;E7Y8d9Zm5Aiy{ZtB*i@HJ8ou~_(hWchpXIW_59G(r9s z(DODg3ioy&x~*Th^EIT}46cG;=Eyh1| zPTO#;&7P?X(tCLJwTj#GjhW`yn0k_Yo%=}kY}><`dbhM7F5iSxRl_ljqPlj@o_Mgt zQcRQcR^5?)Y@UgXZBA9M_uI0o}-cCP^?WhlJ*urwYn;(vS)ZWk#8lLm+{YGqO_f|uAGN;%3$FW@l z>WvWvIq#QL;vSENHb&j!{IF&h_hh=EF{UZUdlC}&^gVlPJF=DY<4$&5_xJCO31c}Q z8!RKAeGP3&`o#I^U^uR4uc7J6x13LZj*#d-TTRJqP8Q&3+{~fTOy$l!0$b;wt%o+# zr0V&<+r{_sOKPTS<}Us?6W=esy%XuyoFb7KKOm>klI4{9nZGXng<4ok&Uw@q;gR^4 zx{WP);kjSLH{%CQw_6I5QA=3P#{*VMt=9^2m*i9vUO9xdUcZN0R1M*%?3Z8GjTjsqn*K>w`QrDIFTFHULl2Ex3N#0EN*OPKhS)3i90xP>b7HO`f>CIF(+}l zQlq2RDR0BIE^($ltfTJy-)D{^iL>pE9Sz}mo9O<;x$gAyjmhY*r0|Bh0ge6L)V!~L zs^u4-nBF?bB2GdTwfBpClS2W;8rycJJ)g21t z90eSy1A$8J01%%Wx;yWl{bXEN*?q4l^s;sQy8(|!ugT3I-gpXvgiU!C!3w|qLJX?n z-aC-d02b&v3xPlH>T)1{t7zsNSh(xfeQO*>&?S_w^~H$;w4i+M@5&XL@z27~h2Kj0 z<7J&y*%=Pgz|>)3*pH8U3$EH_{_;U^O#PeB5JXI?U^x40be zP^b75E(sx_qlanMseKsCy@Mm(Hs-+~C(L+?*Dx@oTtL}3-gi(%vWtA{%%XPAWh=w zFl!I$QdV-(>?VaHy4gw}ut?o(>RDCId~sY(nktd03OikL6nXxXAA3+C@m4rpl0*W{ zg#SI1*5^<;#Ds6o!0JeFJSFkXDm&I>HFk+Nv@DKXe-RXdLsbePY2&a09Op6}T~180 zZUL{|1pyqdtHHLl$DddA+ zx%!G(oA5l9om}H)(9l7~L2Ul?e9r8}t8Pl^Mb)6Fd88mEPk{v;8|Nxw0pY7*v+#($ zi$Kp+paKTDdMOH74JzHq)GJ9Y;xE)MNd_9`v?&$#$6b4^n633n=TbFniiIv{&cqC6 zKi=W48RwA1L(A~+j!U6<60E!sh6iY<0HEnCL{7L;WkeX2gLjijC(ir66*$$mxiicS&%E!sK_CV0SS`qZ9-KkB}roig347 znFU4|SP9@}DGO$a$+L7T6eJfO+$?18ASD4b87SCx4MFSVD8L?_`zXsx90faY5(Rt} zgDfyYl^5O)VnUL z0c!}O@N&f}_gFLRg$>A!jGApm4DDPs4}hoQ(BD_NmoZ2yY?duBb%lZ&V{xb8;;-0p z4AId&*iwb&D-k%5P&bQVSdFbTJ;I&7zrq`fP8^V z93uh4@aT^$=&vep0S;Xul)S(~s0|mi*=9bCD{mqJcW=h1j3e1(#CkkrjD(KB#b2_9 zOySTG6tJyu@=75imW+_ircaN<77d_Hxcl@HPRr5=za7*t2B~eF|B-^cED|0;3JV?PL1TeZ|KU(KDdqM6 z--0<98^?K<)tEfbk>rjl0>BH%C^q)8Bnw(Ve^7^qJ3qe8CZY;Ra0Us@#v=^kAFxU2 zX$rEm5Z-bL{T5TDf`wPiA+xaXyCn2-A^gT*)tk8THahqulj9^Al11bi!&E60Rwuo! zUbIC|v7oAWSQd`jumh)&A+AQ8Y%(WQEXr*h`Hxcj?ssWB4q6vb`w@qp+lUq@hnr@D zvjB-jcy|1?OAo!DYSaf@b$t@EdnQ6|4R{q>#}2%`lUUc%*${$@HX^|oJ8)MDSP%za zDdb#xRgg$Re=LNXQIg#-?M=<4ZuAHJ0O$b>I<&+6qc+B2JpFdz-NjRlJ1ptR&AuK+S16~cQ4(c?V^#2oe|U5qtGjK7(Zqr_w}Z4ss@JUAsG?Vok+Msf1=tmE$Ownv zD!2sG(7Fco97bF+fGQ@|@xwSIvXGV(unGn?OhNf6W}X{~s*W`=!anJtWO@j*ZRzt7 zF+z21!v!OUnXW8g1nGJarA~zel4IUgHiR#ar+Ah;>{{Ru{}mHULeJu1l}6Omoip&c z^tjym&a9#fcxRdhPan#3V5omDrAhtHRn6 z6Q31WL-fR|as#r<=*6oF^a7jbI1&fpDS})AUNJ#k02EJ=&ovVFigEW66a2 zje`Z<9{#CIsuyl&kP|f%@}d=eB@3BBPmjp&IFmhqUnzoExM=QO6+B1G zA>8I#gex8Oj|HprK&@b^EMefT(TW~}jJoD9Az11b1%+cl7j{q@YrwJ{?m8Br0Mpbo zm`x)ioPHzUvbZAvbesBtKSAh!<4Dr0H%V&<saWIB*Zbypmt7wOh}t|NahwDky;9_ad@se&M`>hO3a`c zvpT2nFhM+&B3hNY2760JJqQl1gI_Omm|Euzw;aD#hv%r=h!qve`|sAH_Uz#f6!caQ z7rh#F7k{tE8lLzx@{t248`r`fxxojA3sTr!Tg(@H86y*!qjRQ>ONUASh$#Fx2f?I; zL`N+b!UXBBkJsNQXr5hWq2CswcULo1Leh9yPTr5^G9bkqXv+%U^v^)(#9w~h8xjhlJOo9vI2Y63LlkjK@;k@cC?%KS> z`mI6i{=_mK{=_Ik#sS@FhJO4Z+=%&Zi1m&~=>1Aj(BwtX71kBnPR8bqvAa0*?Vama zm?`XAcO2*+J4L}*w>*K%kTPP!g+SoRXPvw0sb-I-R;@rGI}Z{7qpM~S8-L;Fwmy=c z@xS&$*)sp~9Cn2?-`#u+qU=1N z5aVS2pyq6QBbqZpN1)Lo9CG7f@yAm4ZuSncn6sDQGsCb0YtX>IE)rn$i+JApvyVpO zA76>jw$#J6h-*fer*A^gQ)I~LKeLCWsSGU8fEbbQ&Xw>C)P$!CqLOUaIQz@Vt}H|i z3%aBBTo4~G@~_h;5i&*Oa`S%fifQ*34=-uB9tE%V$QT1Uq2(PQquX26Co|^6o|_?( zI;YrRWFW`P5c35dx(<&u6+znPzVmqtUg+5hA%~l>pgPGE=evn@RiNmd(m^ED4cD3Q z7%9dbJH+B{!o&P_;QfWoog2VtOzCX^^dt+q@fYbz+D#(1++{*L<~VF?P^BzrA_Y0~ z76!NsnSD01{(+0NwX^-Q?!*!!f(I0QYYIa(#xK|VvGP2i)Q~*z=aJQjwsOdUq76221VlRJ>8_h!s z_}w+TVBu?>FMhdRK=y*~iMxTrhfB@!a$Q+XfK1lgmlmo6o~Xt08Qb+<~;&;|@u2HsgDmH}mtgtU6h_x#qOVp zRAU@(-~(aI5ByHOJn!OC_A&`Hz$fi9PE9p51uiMyip2V$9C?9#^#ZL9esvP2vfx)b#iH2xm@d`n}3=7kJmH>4XecSQZm|LF`qMEx0a@C#Gv|qcGir>HD6M1`Z-Nua=H8%L*tsTcN|10koOon|j z2Gr-egWDW0iO5XIugt{`xa&)3U5mkZ|B|@BS@V7Jg74$s5{a4Jk(rgNLy_BR;ocET zPw#F&PYW$@OcQQi6+f(97`z-m$6behIA~H7Gb@u7XLgTu(6p zkNhYIKhhCohlg7cQ}`-L5cPNh>f(`Fvi>~G?0|qtC#K5E`5;clo0o+U(^UO@IK2AkY?n%3 zfrvFrwTsRuAI^IgR$~iCCl_Br}enMo3C9h5gN;s3OO($9T ziKAa6|ISZ>PDTPzpD3dJNK8TZdQu>D@lJ(5gcMcbQ5|tw0@6>wmO$$a%C-j z@w5vY6sSIqp!9$QQNvFmrz$V%H6)x2x#&{~7-PQh?U{yDOn0($wY*kmXLdL)UJ4DH*I$qi_IRCmru8ryq-;ar&nKpFzi-RWH?7{n%)554oNoG+^TkN@s5CHLd?=F% zI0}IPdF0Nt3d+ zXr{iYeP#8CYsjQ|0;<=ab14l}fStP&tIN0bV3sSMXck1ugOM*f_Ae=kjIQ-Boml8K{^!9cOEot6wtgQRRNh+UR zp`*wj&v)w^KSe(!IcCx+Q0Yu_r#l}479z3Wjf?B#4}U+s?MwVHar04pa@o8FhJL?f zJNEhCI|JdJfMS8JKKL86bC(JZAD}Xs{)(h|`1sk*R=xUxxJ~afgJ&m7ujmz=f0zbc zYJ0&}NOLgT)(u+Rqq9t!EQkt|vt(7Po2AG`1G5-S1fdFd zT1Cv}lqicJbRV}L8d&}gh4tY)8({c!t1+&}?e_zCl{v(8b*Q#F;+=20pZNJg8YDn^ z5H8efZ`};>Ub`4C!&r+l~SJZb>!MpkEB#a?ljy` zJ%T;-{O|R4#7+thN4qg;xKNb#Iyl3KqP=VZ@~BAT_cLbZCU@otaI6tzOIWlgq`4RE0jdbC+ZZXEKg82l;f=}A|! zQ(c5lNy;5((=BYCUAhgBgWEX=(9|#>%Vt757@vB<%pV2h@6yldvy*Qd*2u1q8Uhmg z>q+k$PCtF+=nnN}y@D&*m!#CT$_@mfUdiyM1qr9=upV-4a(Eoj)M}^;*V7<-Fh3=b zQXR85HPysD-5;OAw*;`MfjSq`A}?FX*K-bdV|zkFk-GZ$>-_H5CIN)tnsj_-O51?8y6{mh_04vw zL-gMB?|rX=jzoFFFOGC;CBCCN@L?kgU@&%lZ#o(vXZc8cT-`lA76-NnHe=-s;CC{Dh)C-i z;7^mzlOY+$$yCwQLBxDYP$^Us1LAG~`qo3ESf*i1-9hfo86gu0lJTC`ZSkQOqR(7R zm+u)17)lsY6opL=+nJfShkB;8nub9iZd(D5IJ=a#^>C=~v&zDMM=t{ncTcym z8JuftQ2R?0J+Sc(NEHou?ufN!h*R@Sxts$|d)N%0IRS!Sp86E&Ec}{kHSFU3;WXK0 zsByGwYqKH7!T#Bj##>&X968l)9`vL5CBx)Yq}TA4oi$nsbdL{MQkr)-QGB(sa-Iol$@d25%SkhC5g<9wUSQ_8=w~i_kz@3}-+IeI$ zLI9*mc|(s*RU_$fOHf5wZ~W&$aAtk?I}V% z`T6c~FUJhOQi`)$hIIqb?}~@t4M>!5nvo6DNI1SNK;;C_!AEk)m zz!Rk5q^GaW2V~$4Q~Dk{4BFJ+dg^_7lwtxO{vh{k+mxff=)GqiMOleL{LFlj_mSpx zJ0Axq?;i~;r-;I7eYzRLYi}G$bp`C4RR1*_qr$YgJu{AA4v(Gm*GW)L$l!7J^b20S zvtH>|@g4o2XN`t>;9X!3rB4glXFbSPs(BPy9N3T5?H~`)tf8jJzgNZr#OCoPH_pk~ zdF5xzLc!`@Xn=*7*C!P%b$77kTB_AiX+G}VGD3mQfYgPJVU%OmgA%fX(sqo3(8_ikO9x#_lk6qWT7*9+gI}= zgX?35kP<+>>(p{v>%hkGJ9>KmMh&F}ECx27>+~2{o_*v#-H={PRP@umNNaQ7eD3zt z_pV9vk=nLRyx$Dn5n~W(6IJb5r#j+{;@y#3~ zpo7(Szcvn2-PapWonxPJ_!%~eHs9q1!AZdW{?iP9Kkxm{ioZY*8Ps341c-Vz$JhUE zV_L?qO}|2Ypw+}=d;0t5E~iIMKScFj*tNq~j82Zu0ZO?Xi(0&IN}sq{?PdHBNdj)( zQNPe=5Zl;F|KW-b_=rqzjyShOPG`KxI^uaLU#FI0w;M>1M#|N8o2VYqr>vx_j6{Xi zoD{!o*N@5h0T`DRV;#WR*rhbbhSaN!DA88%0RTQ^oFy4372GKcpzsySN_4%*6I{*x z_u$Dea1TYfnjTQZ?pgm9*^V0ed~OoxluZpu3M2&u=2uaPG89gd-tBWimm9M{?NxHt+pU#)l=b$&Cz65wD=HWz3SSphoYV}p*zCyurb_ixozb(seTu(0FOm8N1rRD#@7oRuv{3U%r9j3z zrMjrODqAb3Lhavf3I+ui3^hCb2LK;9wj^DAQ?oaTYin~*~F#o9ts8ygagb! zm*ErCc6kgUc#lU2I7J9rM+lwY6>{3;<^#gXR7?N`qC^45_h4(PtJ|ikTgj;VWYR-b z?@f8WgEi36_AWR;F*#DHAX52Wq)Jny>hnmovG0m73J6PqDgwm-^2dsT672$o3&}E0 zQF^fKDBot{B;G7&N8(yd$G-hA4&On}cM#u(dWCdr(-6?JKUCPf z-{l_4u3e)N*i@`=wG=(tK2E`*Y0u$#^vQ40j_kdY+%ZlRG9)se@+;LIIF)9MxOcoOj-N z|A5S7=AQXp>vOGZtreJI6_|N7Fv~kIJ3KHaHSl3UU@oOD@X=U+=wRUExxoByfd!O6 z0!vV#P*9OVP_a%>iB(YP)u1x(pz`pbiqxRWf}pCppz0SvHDf`KuYyHA6zV8JM3&%s zq2LCE;HNsljaI=;SA(0qgImIbTT_GE3WD3~f;(OWKN|~vJ{R1{6`Vi`CaqTBghIL} z3rIR4y;dQ8SC1kULI%Q*I-Ns?3POhKLPiQ~2FF5PIuJ&_g^W=`##usN3x!TlNH29l z-%8S}Tnc^f9Xc5vI+YqaT@X4`7y98v=jhyOR>w$_(9MD4iMg<^l20#Rconv#5aRVMY)66eaH?s`DtzFD z|95XnXkFMrYWUBB@WZz6a>I101b@am`Lb~g0ab59wZj_ z;1HswdB$nvlmu>-8?%G;#RI7*efi76gpIWGlK3=b5Mo$LDI?-IyIZ zhf2vuM==PPHdeeYHfGK>8*Z$8Q*K>s8oB}Me_QSN^v1{G%+HDZS9%fz%$jR1;O)n% zu8cH4`OxCCIQ-bGrS@Y-!0yJ!k(Ro-7gz|Rpm{5Cz9)`N)@ii0esKUVYL;)_*04O1 zqjK}pXxr1(F@k=gphbJ*`kRV#)lM(ln?6qxT}SdQI-0+HXubRS)60$)?;M3Nt7c&! z1}j8emBBA;ZNxMmYjzY6!5_3JkC6#!`sA3XyE4lbMbXs|??VfLBXN@>-DuiK(b1DkpQd}h(oXf(p{X!$I^t~NV+7urzlfQuRW&>as)Uau%L72>ZK zc0LC~b?ebG?9JkQuK~I+nmqJ;448xZ7hpv&E=IZ|qBQ^>#JFCTBp`a2b;P418N_~9 zETx;PtuH;WHk4k@u(S7E&UCz9xtw+R{`zt@CRTbS$1Tfq<)KGeTHtZkqjvAO6; ze{-{bP@;OXVN~t&=F@RQ*)NT6?Qec*nz~;7rFr)L=PxbfSlO?wOIbH-jY`3Zb5US2 zD>svD1wp@lp4v_Y_8FS>Sj=*;&H=p7aCNluN37iR4!sRg&-Mf#MbSANMJ2$GWf=A0 zV%FPZI@KhycTd-u8l{u`jMhrm`F)7#xVT19Yxc-_vMw7%EIqDQbFlg$tqco$9OtI5 zYFC`%GT*x%^CQ`MEFB^L`)@FG`m|zr?k6|by=2H|~fYgKl*e;6WBSeaPa*D0M{K7Ew zgedY|wiPyR*&h+wNM|y6Yk$&GMLTc|d_sI28XoRO)~Ukvs_Pb^ST$^uQZ2P)0w)h1 z>R5hE>zV;`=h=O2SATi4Z$m3K$nSSUXkusafEmqCH1tz)$50$xI9rgE6n)eDl5?&7OR6H%gj_#I8$I!4fzC}`m zVW^BAzPGJ0i?qaqaMcK?q;*899S|jVal=`)xKH(XK2`|Xb@R@_fT$exz=(^@d65q} z>T3i*$wQRg=^UV3<_uPANQk0t@Z}RkN7B`F3vq7E>+Fz0OivK!H3FtM8oFrdVS}K+ z@#0B-eDVcHG+n7nCVdullDUeUC1~BRf;3^Yy+4us&^CfzdkZY~(H0!Pg%jS~VhVq2 z4z@Ns&sX0Hmiv(gH9$@G+t1VSb()5iCS=oS&nH{pyP)vaq3X4>%^W#cm>rRtvYYD1 zN1Ub84A6b1jiG=;Yf%~+8SkvBE?9_(Z$AQ8tUPrItc}&$D?~go=94tFNzgJVgmtZ% zs@_1P*c+hl1w|MenNFlNmy}3xcp5m|co>E3EiE?9Hg{(@mo>9jrtz}U(tr3({^4FZ z`g$+#AM`?7q!zPCM1-HOj3&0)T>B(PwMV8%+Pxu*tZ}GFi9JeU zh+$eIf~T4y^ z0OD{VGUCY^h7RQCfcnJ$&Xw8sLqy&W1p`tS$F;jo(a}i57~!Ft4!dmX!z}d&FYChg zN3QCexL4-dkl+z$`x-o{Vt&Rn)y|DXrahI@bxq60(a)#gxVG$h*2CzS7zhh!93r@P z;1j1Sx4<&8At+^8pKxAIj(uRUPcdaX(MC>|=L2_tcREgcvujcCSI)q|VLkp!{k#a@ z&p~6$hV<-Fw`f4~qCu?PX=wK%S8z0UFM@P>VO#1R3=rI^7|56tM#u-d3AkBisM0Q6 zQ?j~10oJ&8>$h}MgEw1y1UUy!H_ld_W`XhY*V#YpiCJjz@Sv62?E88X2!`Zbhg@F(q~H8~Hs+bqncw2R7NQ#yp0n>FbY8P}Gbw zRIafEqQnHgs=?0eDQ#uC4$o}kaXHNCJ2$>R8$z?RkK-)&iuiu7MY;Gj4sOdi>U>@u zGgX}EQ+2xj)A;mguEJBS=J(p*-=8ro9a96AKN=qW-t@5Qn3;U_qq*bv7oXIQ*;UK^ z_7A_m2DmdiwaLp0knfU|c{aTxWqC+Z@%FLaOt)w-_OXO+wp1YMZTSR5wrw;d1Nfwe zEfcRH@K8PPcNHn^tpTH%k??m$#DksUSR6;O?Rtcqiq4Pl9TKv$T8L$1;)B@ z8SgJRtD^<#IlMuu&YkSBkTmGP{>Wj(9YPbz{d~d2A2&OHw2b}!8cg{`W_jUrFrX8{ zd>Mbi;}YuUZ;{S|8$Q1yJSpcfwBfZOnHOX_dK9{~GJ^&5xTek`xrlt|AqoX`t0fc5P9x2p-IX0@FxI9PP4u?1qi%MNX@8 zfk6K#!rlYTz&vp3-xXoHx8Q$@u==9DL~a%3w;<6)8PKq50>4Q^$Avm1PFBh-uKRgHw8i%)uwuMFPn!_eECPY6;cFZDa?eo z>U0=lvdYyjFwL)6P`1pYDd%%fJuzbj@2h;^>c1+Fs#hHBMsV@FjimdFrR zL+;nn4u|iI3q#yIc2iF(gh&kPL`qQ=O3bYi%%mz4f5nK>*Jr3XqrHfNok(97ubn}$_NtxXwIXxpA>Rp;CnGPryi{I_ePB{~mEZ8p zw_RlS*`rrljHd-(pXK|KH)c+$QN3f#_FMI>O}3oM<8wXl{obH)*DTa77}=eiP#&v! z0CRRwRhtGsOg=~Jd9LyMtlTLM-C5?>Py9zL3Mt9^dckjg`#arqIDK#>f-x-MQv9#k z?+Z!lPU=gyO=8WN!YN1#!zo5|y&}BZamMCF$n3#h39apT>!c#~a%1W$ zpX~&zXdL?MomBs4kk~^6`t-*9Sx|{S>gp&;mDZO96rhy6j>a**1F?j@T@?I|Fy=m4 z(HG%WoP5#TmFa`A{$&^z96Kv454(UrsYQ)8Xuvergt50_WJd4-t&SqMNz~wW;v6{^ zy(J8QB8ngkcoYqkz~TjSV?BVCplFCD5g0V83`?gW$UStLVTo^RtvH4OnF?!fK)GwL zplMOSd28Z>Uyjjw1l}K4snmP=DkfK&yPLkr{ih2kb~W-CT%x7yh2V1K;l!h~}f*T!Y z#-FM@wiIZyYte$;qzKJD4OshHcbA9t(Sv8fIV&CCEcX<+4)zZ&^=HquTZM`W)@00K zEtl^*-7K_LNj}LGbZ?YHM#G34&2}dn#*@*uZKc^K6*a2ZBlXn8l|3uK22N`$F{D$` z_+wN_OoNPta#DN4!4fORudUxQ5r=d>nM0u0j(^T$0hthzw%cVu zC*FER_tXuC4CJ5 z-`pNk$-xUpKxH&OKgm;U-G~yf8_f}WFc(%GNgoE^yV+hd(N>bas>Y~LEi4_s_zpjd3hmO&Ard$mG)c*xRGo6gNmV|@f!ZMzF9AF!bJT`qcQ39 z?{jy3OZ&WWe*n~+K$|Ckod{Mhu~%iEx7#&6(d+6U(k zFIhi^I8dJK8{FN0@?(x`{)*Z>8_!p@1q6-!0r{75K7Jv<>?>k9QT9e)Q4V!4;L>C2 z(Ouot?63Q4kcYKe8+o|=mX)k(C#}z4hK>W49(AOAf6>TNa;lZMTKntk^Omnc+qBbg z&7Hg`#*pPvitLxYak>|Q8B>hWzkkdcd5?R=2G?1?)l5@3qxX8^dg$KE%k2W=-}n2NavjQf>yUkB^me_x*JT2GHk?)7Ny8_Vh)J3ZnO@vU&lxR|P#-eMf2)uBK{V1{ zDAf5o_DE8($9C9?7ot=uqazLYjZcIf5C%?DV^;yNXu-V>I$feO3kbL?KzTDj2@nQo z6jh?00cE=B!dQ*hsbIPbIE5F&fGP~j_bWh1jTs3C!5;8UAz;*(5TKFMqlciK=%Cot zTd-)>BVgt9xGn_|!sM0@Ha@F0Jf!87tDLomm(WYHM%e#IAwYG@PSY0wpd68)#kT`u z>|o3LGT2-;n+jxq>?pD{Qh8^3zAjhYpz102BVR>46*8 z1E($r;{BuVhV5;YYQ|hZ1p4j#gQ`!u74paF{K`I`cYB}didgxhMa40VrOy;f4#0xe#rd9!^muABKJpQg~gK_4kI(~+kZ3>lb?9Gn_Y@R z-yt+NKP26vs7F9utRbDH7@yzjy0gbb0kC2ZOc`_8(7u=#JY;yBa|v%bD9mv9;fpVg zPuItl)Cg8b!aFedAENROkN_5eSN~2_(EM?a8s3G%lMHGZBn&c+{@Aq>r?TJLs1 zUEN}UhBiM&p<|@@d}K?!?A2G#+ICmRi_HowpSOSiJoWVE+^gpu``^eti4-BL&SyV& z*WOfL9qWAlYkzBTq`>M$=kH$!yPxOAUc8{zXtYv)l)-}>0h6d8M>46ck)sgQVex2o zdyn}T?&}rvvHbVf=5eT4sf9SPERThFsj`ZN1i9w5g+#^s*_V@iEmS9xRC7xnFAnCmG<57^8Cul~r_JpFI@x8= z*$m=Ut3~v`rw4S*n8;}Pm=%DvbnrseYAWV%om6JPM3z1gGegl_KMQ+!L%Iy=d1zH# zs|9?{vM$n+hWB#b^r~XAuNbg5^J)N}_`K1K)c)MXXe8+NrM0zc zc%%7481GFJ(Xv}x@Ujol=Dhl`Fg0(0-B89 zMALRKDx~koZ%WIhTbkeMTx!0s-OP|jj-Y|d6^`n}8xtZ^-}vTzt3gYQ)IF9tV#1>g2cHh(6h;s;jrc(sbNjZ#;AV z6#e6_tIydwBC&Mn6Coer?CDq>xH({sHE%mN5= zjiI0%a)gG>rjgs=SuWk%El?3-w4Vmy>Jv5GiT!)AQ1Yof279#hg2hraNX{t|5r-*7f~^c z&LB#?T_eDKiBSTZ;&fW$x(GhyWcnRgu<8UEeV;Ipttu=WJDf(LjeH;q@8xd{vQ053 zbS>fyA_eQQERGVu4U{b)hA=pVh0-FS-l#8IvF3s(Y_Hf&g-{ri@bQ5W$jeZ+(@`MN z4ioK&=mk5P7_gxh#Kf4DWzU<~W2~dtMKuh8LX_Sk5(?}4tVj;aJ(y1NQ`YIlqA`t{Sk? zDnBbn)0vJ(^6n8}78QD2!{dKhwaFC*lBWMVN}v^yFfYhq9+dK9jzdryFSOY3LPw~P- zU{e!uq2Iv%6Jpul?!n839Bi{98%dUWvvT;bQqI(d$!+-8UIgMW@-;7@Y~RAdAiF{2)q zPje?nSJXOwQeOI`Jk47*U)54z5Cpdkoc^?(61kxde6OG@puxi<_AVria}S<|l2-N0 zAp(%|blQ71sln7@C|po9pROVK?BdUH+ADjycZ2~3d{AL4;+`(@3s(6)8MQ>f0qw$A z1sIv{2)0DI9>oXl!U61xfVCeQbg2Xj>_sp~$bp3lXqy1v69^_)FZ&ii$9eU! zXG91@@R4DhCk>M2gjxqG=FI+IQ0#YS@-HYB_Ht2=5}oh2Z;>^H$1jNTGgjhG3+6K2 zlVTS-w8mAjFtA+s@N*uK+S)5=xt(z7Sz?S@#p%t$8%?k!8t}&hy-Ay|p##_^M`8(R zkd?t+BzSw2K6$&(-Eueg!_kVySlcWASG)PYj#mH4sx>aJ8hOx}7mwyDJnaY)XK(i_ zyYzd*ajgA)OMaoJm6{E545XhGlt1rVF<*cm)FM zUy(v$bH^>TTu>+EU75R4*lUf8LSHIqb=j=&hEfYKS`LuzaqW0fBsG5Y&qd5NY7vwA z?}`}xNIfW%W*o*j5%(WOOe%`aGOZOKkL4Hsd%roB=au<7K!eVbqAxJ#QNj<5{INPi z*Spc#H@vjiHHv5edXTsy3?_^(PmECT9poNvs-CQanAsuF*q1NdZ^N11rY-idfT185 z)6Qb=St7OH{Clb>2F{Bd{qb~#wkL&C{r0oLLl+DUpW5M%Tk)=S%Of&ejBDtXf^yHz zSw93pKNcOKcd8SE+NM3ZKxIhPG`Kfrgp4|6VV`M-N~I zX%rc;XkI$}@_CB!_RFf`eI0cODS+~{zdtIaQ#ETKOBfOx%q=tbV$4z}_&q1NKFw*gq_vm)kh)L^OKhtHoYQzv zC}y!O!Z}hma4jD|B}lnCXyB=Z&3v+h6U&=Bt;i7hVf974-aE&IFpVGn^Y9b2(qd`W zw%0||O(LCN#Z-WnmlBl>*Ts#`S?0I}IDiKitu8T4FK2t5aa&4um7yoFH2%&h%LPA~ zUdgA6;aLS3n8v5WxjV%^7RCt&J))zyL{kP`DrV1rO@^iI5LJ@$<9#(J?vH`Y|D zFzIkqCnMMBVOh=n4e4TU5sFD9Uqq1NOP$u^MJu&qZGBpLt=5^>k1e|oHmc9{D`BBe z8l%ABAx97B=r#8MD8d4G&29Fif#IXyfV`GC4`eA)R`_TcoveTiAj{K>RS*gv_tNsn z7Z~2pg307ByS$7qJc7{D%T^G(ySjtyzCGR#Td$zGer@p~wP5R^jai8n>0*`z0@sZ` z-tTbk@k*bX*2xJ#>9V~!@Lf=RtLm(0Ej*d0IK=XvdrBuY0Nu?9kDh>Y98GUqi6Gq$ zCb}>2CaPp;?5)H@x2wn??)=Bb7V?@kJ}SoM>c3SpWDFdd7-SsDBdSP8RQ$;aQ~WiY zbB9KAHZ3E$39#p*Bs0yfEbYjenyE0mW(&=I!KA)^0@Ns1#45+qsT5ym!6g_~R-k3@ z_yKWq4Gd^T*5iWzN?k1`k`5l=yJ5-G?0%wrS^V?F%;Zgu`QWIWjY98(vgm{iE*ZrsB=v-QtbCz@%2 zj-tNJDhli6(@XkjWG#$!7kh1Ol~e?IAo-Wo`7cEbm5jHOJj{!ECkOl0+P9N^l8X6P zjR*daalmNtf08j%35w2SP>**9A7@@7!ZkE#sP%8ic*rtn=K+DKRLaO?So8geaJ#;- z3|E6`RHL$RotUv4i}Hx=%ubfR@Z8{`hsx!{ooo_QnIg_))P;99XVAP%IeTdIy4LQ) z@uV`?jS!Wbm;d^Q{LS6w^nzDo>m-bw!C=R2tD>Qy$VHh4xyh?NAU)#Q0+BJ_@F`DU2n=zaVGT;z46dN>M=XQ+bzgG*j!2;$HM)e!6NQR#q z7daH)rHbh$89jH?x*YkYr`blJ@cW?C_p~GhDP8;t4zw1hEa1@tTM|6ITzq;d0`G@t zPIXJhY1`hw&-(7Q4qDXuW{=FSXk|y6ToKbm@_aDh-A|JX`byLHaPSMNp&(JN{QiL1 zr=8sWXKNO9L6ak&ezfmD-%73vSv8wGoZ0XETfcek_;CLP04HMU%rQss#Wea8ZjX^B zt>9A!U5FH7w50hw!=;06?pMTE_0f5F@Iem>ULVI*31SwT=migw;y}C+932O3{5~a! zXIn06p6EUiay;7Fe2^Z71?jA~p#MqN-UE)*7T&{u)is1OoS*q0ExiBCQT@GzCv{HZ znGzlcWXb%=Q9W=@;e?pU1I@ z_JWGzKX7@{+4CKLEe96?bw4x3IdI8tOS?Fl}W=;jn-=^%&`^V z6qI7cSxoxKb7#i=X+5>-@V8!!>|kmPDiQ?~;}P-szV-Q(zXtZZ!lRRFP=p@kzz1cV zzG4KO8jL842Dn7IOQdoZ6@L8U^VG;W|20AVrd9N69-!Ll05EeLk)p6ry^JWmtMihD zXJ=mSi~*R8-H*34we98@S^5wV>bF4kFe<~yxoGiGafbx9evP#I^#>|I?C+4t2o`m1 zDH4mqGlD*&&f1p#RYkM`J`((zSd?TfZ%~}99yxEJ*8J1Dz~RKGI3!*&PthS%Km9;N zSHQ6Hx~}>-72QvMa$L@Aj;Dn%>AqTi$8fF*TjU^LD=nq(-93?#cRu%Np@-ygUupi8 z?l_mr{_q=~y5~eLmd1KH5_%YtK1y#?WH{Z}(Dm;3ttjL6-H@&%CQyPlYQXb&>FOt8 zl4uqUMa~;Fnf+%!6Pml*WNI;uyN_v30cIP-@*D0_wZ18ZUgcUEr(_zlCj#V}j>X+U zbu+`mUvjm)_Mhaz8$XkPJB=#LJjlI^w~4F6F#UF-wI&wq8?-Y^3-Fp%*c35O6(O|=O>M~nQ%4T?C_k{mU z$nKl{(htL=!U{54b{e?jDnyyG@lJoCb^=RuV{yO#PAq_e0r63|eT(Ur8+V$XTX;X( zzjvy5A%adJ07X(7HufnNqg>YQ)_1|lq3aS^{L5+XAm*u;Txw7eC`!^DQ2|Q8!o5{d zT#A5!EFJ^i0N0Q~9B;qj$XI>H7rIb;xhWwCtC#~%+~Pg-ZUFVCBW zy<$LR$lPn`OR|ViiX7~Q+v>nJ5{2Oqfql8Sf=vMf6BJZ{?pry671)ivI;vAfmpXc=Af_*`%iXPAl*6rAz@(8BwFrE5t=YCBVSFHbiPur;j^ zk4R5E`*l2{v$-Kd{Qq6oY;$)qD$Gk|9EOJN+jlaFNu_e`CLHqUg==)IGq}_0Twd#y%vnEK`WvV=SUF# z996l?G&{@z2ZJ2KXencDRn3`5pQaWF4;HX{Z8G%Lm6bu)=sM^v2Zro z#+50a<|miZg`zi5O0n??PZ*+}eH?KpO6FI-c;G|u%*1gy(SfgK1alaSs2@skR0P5vH@=Aj!ZXoPXmkc?I)XpTuA5#` zZYqxkti1-vyiTL0S+&rO=NL8Vt-IlhD;bVBjoV@_QQ*@RB$=Ev48-7st{uDn;BrNY z!D&UQF0@2Z&ILx*JQSKyYZi}SRw^PcWi#FCLs9os`M4w~A!76yrO>M549Z@xl|05T z2V%N5w1N6?^ONG(JU`lYJlvAkO$7h&iBB;h$MmCV><*r&kk*fJ zbqYW2Q-5sF6b1DI%&5t9G6mf-8zJ-Ddq@$FHju4O(v76CxylqkP?!$AJM9{biAaz= z;@e*|Gra9PeckLyHv@Y|qvon<&~M~=v3uB^rHU~gpUUVDS9~`g2Fd?iZC&mBwfWq= zy|KP)_4eUX7tb7|sF~34>8$-$SF{FPlq_4=VPEmLJj;IrdH+i>WCw~%)jHZU0HCNG@oW-P{{Y!YMFfXX&7mf#pN(JLdO z3Q7vehSIH;|0^;4JLH{7jfT!nBK3bhF#B!w@Tzl}(jUm9PMy5}JLGjE+>JILFwOe) zW+Rr3KgkJcy&3v1d6t>o{Da;rr=czsmf&7d!LxQafDB3v+T0ZYgFIMDl@JlUeg$AO zok3I_OVF&o;14Vgy|&#GjDYg}KmbOQ5eA{Cv_HX8)9gXU6kahNFzNw|G&L;hvBw8S zM**$%EP@knQS%6_Q5)5a+$uI;aEwOMVtU{(Ks=N;(vCMu96&Sj)|tM5wmFC@(y3-_(FnN|^MN%tPr+od&pKU;)a`Iup9;sLo)wp$DZv@WY`l&f6fO9t_9tw8 z72R;dV7l3`IsP`f$YV$Z@(fYm22V^;$x;@m_xsQP1@g#Xz5~)9F~qIq)3jUz zGoM+2zOOJ~w$_N}$|6S9O~FAq&d?9jiYKaVm?PYx;)ErPC6^E}B5K^d;8xdY+*ChI zk&w*#&r4{~67^F`J`E_h&xlKe?_-HBg_N$Z}q!CeP$)nFUA@ z1KaaZj3aUCK-oR+{^2@a&qnq*(O42aPf9d#TaQG~EhFzC-0C7dQAhofNpYfu%ph@C z!c@Cn&4-qgcPruwqgJ~hI_ad3BmSky{92Z(AQ4xbo>VBCti;b^9K<9~u9ZE9rfXp& zM{{_P)dnaFkJW~0$oh0ej8>epdTV2k6$5=iI-_7{5{~yIL%uzAKE^p>?0ATio2H8y zMH`xjsGz~dS3NJ5{HlaEl^=%|!2pDqG4O@1#grlxKHUXzJ8m#%jYQEeAox}B1*sPz z(66;qPTX7qW1T=&9{31d@@sdpgCUdHG$1zUVkt_)#F_yJx1vZOef|pPt4y5dl11RK z-bnOY3rGAFzOn#YMwn8Z`KdyV*dFE+L@6v>X2mfB3RMbV@(>Kz)4xDn_@HrNvU-m+UsCZ?*Fpp0(c11CO?sVp;r#F%7AiwK68@${`7` zrjPllY-7D4@eD7KA*77Y#tl8;866ir&KL|6hn6_d zAIX=kz`uF=f_7y6X7!QE2y#qHbR4L5(~qT7Z_GV+Gtut6yZg%O(MTDuQ1+2GUC(zj5zLD;iNfe!% zwKJ$kFi99K0*;t}c>#-|Qe-O_4?s@5ZJm$Td1|ZMJ)GA~)U%Xr%zOY1wLTmb z_gWg~9810~gRO%Ejzg6PHoKx}kb8%!Z}QS*u?!N5^-)kxjSkgG(s32|kCm$TG~q^q z+Q>@=F;&aEbh46-cd{vu{EHWP^WMxwbKO3ekCUuDpr$gv9xURG(5mJPX2JMB%3Nx73H;u8#OIo4?hzJeb6!mLz=kVsGUw&u@6{ym!czv8;oXwhHugWld8BrGTN=Iw8@n!rzIwU zHZ6PmDeiPP4=zH{Hq^FhPD?}P4Y$U2sCChtFYMtNtM0l~ON;7@lf&i3K=V8pZ}^tD=-8%j*Ne^e~+E@18!-306`zi^lc3U+gSUzbb+{Ra&J z00M9XbA$hkSUUgP5zD`&`~S%rltPnI{*MvMr)4kyCEfqJSkjCd2L1bpWJl^mKWx4BbL)oJ>Hx-S@i$sh~>9AQWT?*<+Il9#lZ*vHMiryef6&6+^f?n_xZsj zS<1UkJHo+})gE;V>cK?#md2DrpRhG4;p@S!(fh);4*<(NDGmaVjireOPCvs5oI9dN zFi0N%Y_WqY;;PP&3vpcH9>MN81Dy`BLzC zM%ylW89Nw3fawg3XllO`T8QZ=^k;VguYCpN{;BAe@?3FGBLi8mv27UvpIa^rXLq7plwgvD zWq6p#u3(63hW?(^X=jNGk! zxP)S66g(ZTA;F!I!G7CBqU@2rpy{&jkSJ!#e@+y_fbM4|e=OhN2$t)MuHW9Cj4F8{ zk+e!|wQZH}5dYZSA32b*w2(i>E{j!LJ}R~_xqT2v1dgLcuuMOs&u%6QUOzVhf1agk ze(KY~ZoPuwp?-s!d{1zJg4S40A|L^~Xxk4)blfrd{xjl6DT7g{Bz?5hlgQdlnWrXI zeK2elgV>g{MLlzK`m${WcXy+md#cTZ%yuQBWJH3xLQqH|rCw6p)s-?rHwYmAtAG-t@4dFL6AQ`(E-w}TN-_`Tj<#HJ+9Em!bi0AKq7@e2qCh!O zhB9$1^tnEX8o#Aw?jQgGq!Ob`m)Y$d6+*zFJ9szL

SZGt1w0eemi^OirufN-3^$VTI?66roC70Jq|QG zldx}>@kyps$AkL~Ya>p(UK7O%Vjuhoc~+Nad1LeRu%xD`AD@yt>c_ilmRGA^_}n_Z zqpiebtD;^B$0@NWb2MCP&X+s#!a^|W9JXQj%#F!=i0qf07pIMnK4=&Vy!((xcv5LL z`jc(j@&-#@IG_>;U?~EyJMEL_rjEWj5bdci6?C^;O3C%-q78D|cQW-(Qm;6ncGYkW zJeScYUMBKhy-eG2NNJvb(_~|15B4vJR(pQ?OP*w8o`s;j=!x>l!C!kXe~>(bzbYMw zAoU{Vcc=G$XD%H5!Six3?V2-&Y+u^-`_Yt#_Ko;u*S9r&9Z$mS{gqs%#pfk>4DiGV z`$f4)NWHrM^b2jy@@-_xLT4~J-Ky=>o%c?AOwd{B2hF96HvW9-o)>@%i2DH>2@A#u zu=ZGopywdR(o>m-S$?Ha&zC3BJ#Myw z|HW9wzQP%)O9~4}RH42rmB#j83x*Z;Y^&-8 zw0_Hm8=n*iTd+(Qt3Ur-gn`KGZxRh%wDXmmR=btUCu<3q%OwN5&HKr!CN8(#PE}MK z2RN4JN>x&o%Rdf%t9~GAxjUgq`NUE(om8|%iS``>)j#fuNicMd@12|#OkAKxrhYy8 z>h|HCTS>MCA#cj$Vm`2oN1rRv8VcpZao_jlw?#_t2JI3dKZf44%jlc&y_Cz(*O;^#<@BgR!Y ze73l!t}rOCSlVr&L#uli>Z$%c&|}96h zyBO8e8^njB_4`RD-NUSw%uZAsT!4RUJS|ren4i-;^5x;d;8m*J?!lL>H9A@SJ6-Up z<xve77s9<8H8u0GceHVX7kYjvFSLyuV=DU$>y0ZT%nYs%O$PJ9jrVnmYjmZS zej;!x4lbvPwt}v!V7DR5uxNLsWb&DJs#G36JT8kpX(@4K@I+zFYb$y?H0h=}b2W2M z`KU_ZK_~juube#lL*92N=c85A!>|HTrwO>12ZyWk>zofGx%ZeHu~ zdt>q9RNs$jn?#ivRkh5^xzbuOiMQ$_T7L(mXv^qjN2_R=I(z7UPs-r!{`k&Nl5

$U+8fGkKT$S#H+ZAX=2X?m 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 &5GmD#=ci6)F0Qx*mq3@BP7AIn3qFYp?pX^S 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

eSy~gf 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�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

~7AIb0+(VM->z;^o8 z;3aei4A`!Me(ta#8DT`>OS$8e+@T4*n&LoMF%S+@2HFJZYr7=M$rzAv9b^nflH^I( z5acU}p;>)D#jLmPT*>LX(@9r70{Ct=Xz!LYd+D9`tYIwi-m}H4g!?G>HADFP9Z2#+ z8&q(UX9K$_16C@)XG2(w(F2ZQPQri%zdvkdH|d3ZNJeh?!noQ$`I6b!435ES#BTp3 ziI1$oO4jGE?8$31F*2X<^Xv?+h zeIjKqWPj=?r&|(Ul13%;CNy95O)O)D~| z*z0XNOkN@xWyL#V$c3c;dCegrELhj&Nu@goIigXo77jhvdlzYtg9e~do!Br=EFzh~GG3fk>w<6S=^WQB3Ufo}lhp1JOm5Lv3WPhj- zCzMuvIP+=|;nl*ois-!Y=AWLvq95muP~X41pWo*{c5PW6H?VXdYH1|s>EA056nv}b znIiFq>;sSYKNCu)t3Vm%;$JU-Of0pB$rBgeOnN;1VOfqO-SV`rc=k#5+o_K~GB1p2 zqkg=So%^)(qvx}#4AKcsn++1q+vaa23$NLu67C3PJ_;os<_jv`pES0_%gf21{qomu zDT7p6`cw8F+s{OmrIR%uJLSJ-skr~V*HbsU;Wp-vAh_V3h5Dl2!;G57e3TGCjJJ=9 z%bw1@Z2kJ%$c?OJOG9@$(qkEXrH`gZF6#WB?+#e#rSh5Y>Ns8I3e)_WucatS=x~^3fV+ z?tcR;Zs}UV)&Jdt_cdvY&Mndn?*EZ*w(TmUy#i_Srcq ze_!bJM$eHbw8l{ulLhG42 z43{JG_gScp_TOl-tvM7pH^UF$hCDIf5kKl`m=?Qs_nnUg!~P*6uweFR4!_WT^5*g@ z`iV!tA(3fM=bL@hiIDQ21&J4;=A|OkzW5NrmGaC|SyEp63s1U$(%{;97;QT2EbYgwFRgiyJR*;8+dWmaES#Xg>wO)ghcZrME0sjhx z{gu+k<-<-{jQ1k50=H3Q&vi9!=*9@aOb=4NHbn9t(hv&7+HtgtY z^w6xfBvEyY-|Pz4OPhw9Di1fW8}=#`YtOfG)?76UF5H;@;7(7sf8=cNRnfrpX0!fM z`=IQBrH&EpmZeMgEEbnK#~cklc0Jj7;N#`VeJvlmU&Jkbydp?9_|!9Ba^O?%LPN`^ zzNPNPPgjMv4L)C6esA^H8SUv4YMFMSy%W*B}Q(JVdq^?x9$hS9hCzwS*X@ZSC=H?z&h2MJDN*A_Fa z9#%e*Dt+r7Gae*EqOWUdeh#E@o<*1kZ^aMZrUc@z-BLOm!yGErURPd}9o@k8VIm`V zY`$kBGh=II3=vhl^WF9HfnLZpV31;pWI;GE6=phYyf))$TiM8bPQ6jF&1^av71TpX z6NWZHb=+Y+|fWkv?{w zeA6`;bZf7|JJannvyYTnrTso|sz1O(O` zf4P*X^ZQSNIji7a`Mmi*FSEj^8hqC%mGjw zV}0cqDZ{|8xz|5b-%-ZdhDMQ(pEUb0uHi%A6kkD=wiUCcAmQOL*pM^Lq78^v!)eo@ z)!)*eQ9Hdph1g&ygtcs@X=P@8`tbADVqTd1ljP5|w#49Nn>b_xflhQbo56n9VHpjE z9*bX`L0A{DuWWu3vkhB8$Cue_84&>S#&p}AnP$en=>a-Sw%xL>w5+98tk#p)*o_o? zi1M8LfPBW*PYrj{7 zc?WR_$$a8223FQ&4F0_twVxVH6SD?cp)sFit1!-o--NqdVH}>pf8G=7FMhpak{z ztQy-{Y&-;e>oIpDuunM?FK==OXdKWOY0PjmOWJ%T^NHF;I(rVL<4#&aDapd&4a&^4 zbfdhC!f*LANAab`r)|rr9#;v;!$WKbpjjWrg!4)*%vOd z=Jyi4(i|805Y}l>Dpw&(BAEw?5MzeV%t%b#IIsT}rwN)gLQa9q^#<}O8D%fWQ03y6 zfZvr-tZIoYElP|{FV+7@aXjTR>wPZQVO|HGZOdtm-09t#nfl%CTkO2;v~cvR%YDQRZU4-++io~{r6M2!mi>EkKMrHzh~hTj|698JZ$>by z%j3VL%PQYV$`~n)yoz<0H`yip{2pt}0{NcG#EnNJ+rOW?<6OMrkb8cd|-nq0D2ZDptHgaQ8p_@hdn53VP*Wtuir3cbANg>tz0TGd|qHWT@7NlH6yyxwga^GjU=!u>m zK(Lg5I6v=~sy12)=S`(C3hF@?|Dc5s1Mro;IsY*z#8fGT_dfhb-44*LrxcXwrQ zfstd5*B`s~A90y*^*b1Q5;-RBNMzB;q9T5CZP&iN3cVf)xg}Hy)^9Ya2UwWCZS`XMG^BH!-Y6$q7^0)cz-~6=}6HG=YNGV*|54(JX{p1uw z(_1%RDHje#b1GiSgTyGWv3p6%o#Q4sHXr??OOUf%79`@XViohmdB`GnEy7$>S)9Igc`?{lJE%M1xfj?q>qSR4p?%}V6v#;-n^NK_g0K>2sCaZ>(^M9So*{J7GlBuO zu6?{bJLrWrH1tJC1~dfn&COr(J+JkvT_jf^M#l4ut}!s-Po|uo^r$T!$_4LQzSaqH z&P{gi53dvscU4nvscq9l8ASVAtc+)gjsb{MLMISxPfJz~6|pU=RU>gYENm+WnR#1R zoq|wX_w_!ai2MTDaVJOEdZx-=T0=fAs)Zzgy*}+4*Pa4c3Z(uD5CF`?oqRzev zY3{d^JV++#3qZ}#dd?=khGNy^?O&(9a2O{J(LB~Azz`rUG6@|YZX8rlFL%u<{b!vEk;cCAfVOuN%jJ%Gef#Lm z{q+2=GD;uK-yVOAWuqY;h|z6GncDm|#I|v)Fdc<{6y*(!`lOa9qD3qzBa+!;x(gUH zz%S&U`^D((gJj*E+AlFBjKQ-1gy)xl6F>=I`G2pgFeg`8|A+7XzwvB6G?qEJe0VB9ae&pMxh&12X*t7ZxBk>mPf%w~ z;7LMx;z7-k!l5#S-!dzw?bGqG+VcHpHknS~5t}q#tUilQHb`MJa^$Pb^O~iCL>+WK~l#IONnB9r*{Nqbu*m3ez zs{W~Y5zSA7U;9NgGUvfOv@7?Wxke28j_Gw_U%*qvX5|5v08s}IoVrl27#$U z3&&DW4sA(DgSS>DG@i){DuzT61(FmM^Y9r79RRc4Q{Sn2jS_M8A)5jzpoFl4)Yjyr z@J59xVZS_Lh?lap3ShB}xX%Di?&$_DB#)riXs3d7f30?y;0)trkUT2J+=p!ltY10a zZE@-Y$|&~>bS6an4S5DqI&T*ZuE@F=z>&l-`ln_{+K@%&Mt-4U&Y~CwSlto7YCq}L z_I~$iSBxfi)nxv2E|f=RUP9Fwt&Rybcr$tf%v`^MfH)`iP$ z=MQ!7*#4yR7Fhhpb4*Jqmoi>Jll2XlonB*7#3w$ErUqAYTw|ZZ!MlgHY9e^wpWS$J z%MDT+8HGd@!s+Rt8RiQzdvjf^?5z0l)uqm(kGFKq<%`ap>pYal8W4eg33-Gq`)sV< z!&QI3&E|D}T6xx!e8>*)lU!y1TYpX4d=|T&_j|Uv(};z@F!KA2FTS%Fd$+;-bF$~y zvE<9QZkk>&hwT1v^SAz8Mcmx_X%z|pMCk+;OwF{t;rS*YbNP{+86ZuQ-^hGnuu8}a z)tqDBNpMt?=E-;{yv0gQ`vUiMxcfI7?s%tfZ?hVV8U9kE+B!lL9i&56eiRHjlh(cS zl2r41j~FHUk>|EOJ#Lj$weMrY#%tZra+02~AZ-i_rMt3O+w2Wy%Vxs21lo;3Wupu% zwMu3+3ZJlYOS)Akg2&y)o(!u+f%1Sjlb))@;99E{uqj0N!dEH}#80aKqf3IQ!cf^$ z(SQ}VgQbF`oHUxc<7jEY9Tl@jAJyEA31Og5zDSW|H1;D(#>GW+g=&QhEa_|_sYsfb zp)85l0+>4Eb#g@yFsyn73$%l5+6i zttd<;dW&=oq(|ASXe;V9<(EpLI_$knC7{UhE!Yks`pF|8%WO}M6U5gMAEY2 zkn66obw_bLor(;CS)>&fUBSWS#@DoqzzPek&tprZQ?@HNJkgBze@_YjkWwuk9KXpt zOImcch!ogSN=4nFi>h0xW&IC=?-P&%WCJGumxXwSCaJ0XKY~X>Z%GigtWRi})F@%_ zb`--q>oeFUis&FI%S`D@z|F8QczsD7f{|yX3C^jRck5(Bdr1pf_yJhQ2zp9j3}x#& zckaXMF~$1hKB3cv5mE2>8oM5Q2adMi&ckUym6=xKt!aQ?TI0*R^bD;N;3cs@ZA(CN zgA6TKe!M6IqXgbSl1lvRLgSSIV=CFi7jrZA@l-HBHDVRMed?SZ*O^Lv38`4 z>c%3D{c@EX>Gr5wA5rByMyzD2MbEu|$D}_HT*jMsmR{K02y~VVL_mu7BGjsD9ONUKZ17#kmRpz123pD^D-P!9u$HHe zo=tQa2r;}z8AF4ZGatRAf6Fg)bZY-;kgXnF(8YeA+Jq1dbXmWZqLSGkuWEW>!mo6y zyB)|Oy7x?C;PFHnM$v~#*DglYCFZ_%`IP8hAypJX?ihr(`Js=x zs6Sk6y8|Ja*=+>Vx29i+EnItHgrHU@vAako{$jV9CWWI$_E@({s$WsQ=y@%!rft|;b1jswPTm!j&fDs4j?0LXmqM6+TC`4`P}CBYoXwT~WZ zty(F%x1n$4=-myq;U<(>6Voqt5}^EdD>r2(%tywpXf$dpuSDNz4On>WCNA5`?ZYY6 zd!S@I<=4K>OGj)4*#MTw6 z*E5R(b!jlt(;7NEDaTSJZUih7`sG$hd5H^lgutR(t;%2WeHjdd^#U8AGGd`^M#XGv z$2>+pvP65g6CD!zl_+u&PDGa2GSTtYS}iqSL<9#DRax3D`kDNF|`IdBjYeX<=v z5MO^p@{EMy!TV}ee7;Po5UFm-jc|w}N;^oVTA*hz8@YBi7&co)z+czK4eKk)=7%>5 zc10L+yq^6SG>=Q&;Xc_fD;))@E(0Q#{PlY#cB{B%s9Mqb>Z|Hk>~Z5hS0(s494>@Z z%N`ZTkG#~kB}k0r%|hPH0G%vow9tmlwGpxj*>I|yGh2oC*vUwJJWa)r9kERs^E_h!fcK0Qb{m1;5BKlJUwnOowT2USPiTMHi}0$)6x4QzX+mORVIzfD z7mhZ*55o<)jh8i4eCSMIq*ETB^K9|BuXuU!>BWFs)f=wHEj@2>i#OT^Irxnv;jN@y zQZp&4$n9K#O<%`<#Wnr+Xr6U^jm=;<+X0eZQ`j?@S&-xQs3qTW0+sc4dhXw&dEXRb z5vh~@RV-i`2YWCmLH3*+3kEIwizr6&BU7C9xF+@3 z>sq8SoClpfCWX6Kj?6s-bKuxrNj*~5P|h?;!8u!WFzWh@1yuoE_8?z z3^>u#3se=KILsIL?JKXM=yhp%iy;ac-js#WhTnvMPpJK}%598ck;>ivZ!4o~0UBV1 z>9TjUWx5RP3z;shhr-*WGj@_xBK252HHGOdvkW@Cl9y@p#i?Tlc-c9TU0S@WR09-J^HUs!&*OSW%B* z2#485{hHkuZBF6h&*Ro&?yH%L7E@olT%vHd21~v;M?IXJR`Kfaal_uONmAUnl#g3$ zllAw(uOJ?-ojB@F8g*^&S4)*MP zpyLZDFGq~aE0DXH0VS+0M}eTUv>_w<{(GchLa!t+FO$YN){lx9Gn#vHb`L%LPes+s zFY@g7tH~A5I(~+GY^`zuto=>sn1sws>refs4lbk+BNQ^T(1n>eADnr!Zssd1nS%DR zVB!*Sc%txINA+%zSab)MqA3la{XqKH@!~hGw~S)^@1QMoGslp#TiE<2Vm>TT3~`24 zbZ>iq2-s7pf=Q)3v2pOtw@#qfxc$6m!$LaONWb3fpN z7i=<}BMl0x#T%ZTV)tll{t~hci7L$7RkzWbvO4hscs@ z0&JeO;5F6d$B(WD?K~aMy-#L=d{xns;M?s7-vud96tV z25GXX0k=)`GOAuZ5vvrLDnfmgW=REhRG{m&0S&|}b>l)}aU);MBD6C_F>H^E)matu zM~-Z~I*>S$lJlZerF)2h0(HZvn#dHO81Ed}GOF)V3Va|8o@!9SkkhhmJIaPh;PaeO zW!*{~(CU*}YcOkoFq2NMvlz&;-w>Ak^9L89y1~U{|V;s&n zG3|9Pr!bCtGbt-(lR#tAWZkmiBcp(bK<=>G3|}#t^{K+%w?Wl9an_I?#14MSD=6)HN6f;oMJ{WUwqWMZ42>5hRWBO6*KSTZt}$Zd+=20pr4vsG za^Kv8?Z$xRlL!~4$??cX-G&)K7!Nxc^LD~Kl1VT5XD2?2A=f_ViHuF6sbxg9%`bYx+3J{CV}EMH*nXcs~eU0 zdM-KwdWOxnF#isL;;6G7et?`VuV_k@lEuh`>BHYNQ`c^~(zYePHMe+8f0(?K{2+rd zU%j;kZS;J*Pf<$Glt*k-soM9#QmZg)`R-e4{qpt@QP^>wgFye%=2Fz6*6nUbkXts4p-CiE@d-URK(NSvoALI+l}2wKBDT{SC>;4A(rvNd6vekRy@1(vFihw8VgS*~lC|{| zX+6=DBKe(uTRMce=Ym4u!;mC@@0;ZW`CRie<7;s%y&7qY7rm~{0&pw<9T>Hfok%8xwN@>>2>VB+r-}Z*Uj|mq~QeH|+ zumB7#t|62Sn#lLxaAcb7%O~R;8k3wY7_#58T9zGL<6nX8zwgMMl!RWl^k?567UL6b z91{wo#Pk2;|CU=Ja#rsmxG^b~11h5{v1{Qk9?3#5QhnZ-7Nwm-xa(dutb8l)P`Jk0 z@5gI@zwH;xBz^jteend*k%*$vksFyf?!K+{dtDGP%5f}On}jqlfz_EnAX7j1i%iKA z8<5A2j?!1{VG}JaEllJzEjb)1j;=08tA}Gz$RWwEQ;6XCM*v=Eo+Jmzu>hAVV)dr* zI@5TPhhTUEa+2&wDs0I}-Pmam5(9Hdk>?R<@?TPYGmIY!uF*zVPr>!Tu8I#jIlHKH-a}kpZfid!goIcCk&dHoVO#DW&#Gf&- zFJz?a1a=h=x%Mv0hJun*&!~|nRF(vu)kS*85WJTWTZyM$hQm~t7~2T_0wi7vBr5rs zzdWpKJnA`%F3r6A_8ryE1@KXkIA*$n9b;SpXC)`d5hFNI^MK zknb|NvV@(=iK(LOge^SiN4rGD`YBBSoE1p0c`=!kEPa6OOUZs;utzPTXz8Dy1tBDw zJq5AE#}fDmOBNUjOAJ$zK`wq-h_q!CSu_>V6S?j%*Nu$K6+&hLge44!v(|qPTJL6e z3I2t9`nDrI6;4NP=DL%SwnAt+9QCfb&atd}n<+$>wPBX;W;!f_0&geAIQj13Gj^|(cwD+1Yp&^XebrR+6^ zT92aINJowYD}XK)U5Qd?1>jSLvKb#?(~gMt&#v`9GvKc<+hAiyK7QNy_^sZ`4eXNP zUq~!_^XQ$*ClQj{H^ZI&RnxsyFI>({>B;`5>1Gm$26zDVKPrO$6ewTUhV#E=42{fn zPzWj~8#faE9pGx@Piqfx&c~T68mrG|z$C;mq^|d1R=zrTc)GQzQ|IAX>qCxr?$m|T z&rb;i?oFSh6GQbyE`xhwEo zq`Jkkl6Qw(!AR&KIt5yjPK>j+{-0iA9%6DvN`MbkH$zRUERDUPvqSjBShC~YGUMQZ zGSZ=a?u$U%?)>26eV1jX_BG#AEq*u7bIM5;Q8T;Nb3`z5Qbeu#g=N&todQ#dQ!jq< zs9BOS`w*HMMQW9zCTqbf^LO5|cMiP35L1q4{shfN64p+f0Dgb^JTY-`&9P$b*lMXG z3ju`-R1aV*85~GGoWX|C&b$;c6HG7%c_FGQF1?jF5eViEDiAiJ1jt>ny6jX*(|W-G z-n56y!J9S+YDLZZoa^wLXZ`AO^tzliWZ}17yaMNjg8G7Eh6+42SMhL1mb-_-o5F~d z@v!26kg0QO4DDKx^$0pTsXC>IYY%aTqZRr!nMAXYS#v{WR^N6 zf~sTw1qw}~1spNIC)rJH{re*IdKbh+4_@?oko~6BKghr7!o*a;ElIB~Gw)8q7A1Rv z8!{>#o3#$(oHZG2{4mgFlG}zi(u@i#6z+WSsZDrcaq*h;!!uFW(r+&wzM3ZP?4ks& z@{t6pppC9^_ivY@S7RP3C%d(eT)10*9O*UldMh8HJt8uj8s1CTYT#lVEE}J zaYFPKoh%bH<{W2E4RM2J*gs~OU(1`P3PP=KJ?#GEYWC92SKQ>iYqUq~h|BAbe}+_b zdYu5y=J6yc#d3T4cPFkrSCqtSBYzTXwY_!nZP39lpR1IPoEW<+;%Rd6bB1mF=ltUF z%ZYJKpT?l0>KzFKmd65Dh?@|aBh8^7P0xN6rkmZne=(%w@#%|`S9-s`>GuYO^iht0 zTM!Sj5yXb=TU8(F zT!VOWLQEgaPj7U!k z!?JQNT^_XA?ByBKxg98MPuCmuJaIpIS~wqPBnZBjzYzUe#qM@Jl{q6COA1tUyL4J? zvLAiIsz!5L!oa4Anp4h?=6)T-jBFLp%-|iU{$1!q?amVQg$ihiJNG-Xg%r?Lny0is zqH~v(v2%!qTJ1fuZh+o4I_Our5vykt{j@!7;Lo{@&u=>f{~&lBA7e0LTZ-|a|bxlP=a9W;l(ce+tS!G}S+Wi+B zmhw)ChT|Y|+E;9$Zz2W|doy%T#G;r>oU20|D6_FWnk%`%8AI4(0VnTE-=e$l4tVX{ zeH$wsm~K_^q`3T1&|i-uBL=(h8q<$N)JJRTm3M{EK2qvT1qwLUW9nqQuX1vRJXxwfSNg-$T_!m^^6QR6m%4OLCgTh3O2+h>4?Ny8lkxET6N29_P@rpCqjKDd?QA*qXz04GOKd5i5Kh@*~8y{rb6egTT zM7@a0bHvZG8d@cFIRt=irn~(Z*-nE+$fe^$#Js-i>%RMGboZs1*aUUnUyLKg_G3F0 zT~-;q$H2z-q^Nz%%&`41bBbP1LV{x)%JdgC*Hv}kIvG)%)Tm_yCJ;boMxx&Sdx_6_8sLTJE6d_Bp zNqqgr{2RN&->#A|_Jv4oN7+pALK}binGtk&J38KhJ+F{VBs2+}wh)6+8`c9nd^Sjz zB_#Jdu=FH$s(WNlv}%#_76bRu9e|aY{GFItmsIs3^RIY3RTJZKLG`lxq2ImfG%UZf zX1{@`w?M!BeEr|~$GJAwBR2^%`*t|nS$qiIvv{Jns|Mq!pU|W^0of^x0O*5Y+S|BR z1!?|zqB!emz4^7xz_-Z^6Ed~ekYuO!W9(bo;zEYcn6Cmq)1g$dXIkf}7(W(f5*~zd z#bR8eq5@4Sne*v8g`o=DouNuDm+W2-NuFC{4_^66#4w(u$c5@oZ+t-wuDCiU_t360 zJF)I-(jX+YQ-3P*11OQugOFw6d^A3ci^m8+N#hgbCv# z{UIp}mhAL4Stk?No?O4mu1z|E=GsG&kl;<6rY^xKW1A{^=1bBNO{R4+Z9S@E&yI;Y zLMV`CVtblb$>h)ec^y@6$b9kLJ{?L2r4Bqm1UaHB$0jzADOx0u_KH0NNyoaNk7qFB7>dkT|-s8^_tV%9Hpb zOufX>8`yrlpMotG9KA|LbNR`!Le4P@Of@6>S$odJnE10X@s9$mwWCApj?Jo%MQ~(k zZ`Qi3SIV(*iv?3h;hkrAG(yEG(T|L%{_YP7MM{Jse!MK-$*jA4iGKc(13ax$wCw9+ zqJQZU)kJqW`{NZ(*mXSQnGmCT1<$EX%wp{NCEVLe#MRTesED9nsIW?n?T!0Hyo{xk zyS$LWa&2a)Nl6MfMPnB^=Q{&y1z4E!p#v=ZgaE6T!LG#Q{No%{&va=l!PWo)gVf+1 zKe9#vT=UvxqXP_7(M0wjDdKAT?s}qbx8(`!_r0ImF|mB5%WpRG9&fIHthtLJYe`LA z|5oD(fCQ8AoMW96irU_uHp<2NaX~B-abgU&BO^iSPE7o}qj$;Z2qI3Y2Y-@DJ;uU+ zg7J6Hha?hl&nSsI($YJ2O0?(e=JCvk0pqpJe! z@ra-lF7_8+;sSYJK_U9c?J`$&+=NhK4aTwjiW7Ok!$iRNnfNt&>G^J3F(12QYb+5- z7Q&KHfT0#l*8w3g)Py}WJ)o~kM8u9^UeaUDGuQ+2(5A7y@|k-Q-bq|1M%HG8?uZw= z4hMwCC8WT_qMxZZza|`M$S4MMFD^)YVFdlNAYm-;kF1H90*)J9-f?s9L03sYlqF^0 zwJmA9*1jFd3I+>?9B1dkb;&x#0PbNseoB~FOh)Y#R1Z4g*1llMc{sZ)O~(rSU0AG@ zxNqsLNHY(Y!wibx*0IhTuTi-?F2*6LzLlkSjEHNdu=nv%5D0+0s-q>?Sni&k<~Dt^ zA{k~EQ#A7TA-;v9cTzTln>tzW5UjOY-<%M14%~EY+(64t zZ+<}cVOPBR4|XCM9Y`!k8e`Xs+`+E~0U~=)8a`$n&dMFmrW$AsZbj3j4LRFeUTCP1 zSkU^6-jT2VeMyKJd)t6o;^#N}2O?X0j~WF{`fdp$rrX01uL_D1%Ymcsnr-h4LC3WN zJ|v$#<5V}m2N}gMA|A5X?hV>odpqlF_q#x-L*5Se+i$t)fu_xk=uJb#y6mq_Ag=*k zgU{y{c}UglzYQue&Py7f%-+7jdX=k$pI?^g{agH7?!Wsr#@3 z|2GK++z!ip?*MLt5J`^8&n0?EL0%fkA#sjr);2r6eocFy)bh(PIhgUt8Mify}#f4bKjr$Ki~(O%k_G_ zp3ldlUFI-BmkoQ+3d7$w&e2)J+;`ROvVH8%(&EmBxaV9Y(Z5E!jKQWul0cpex^Y`_k@2HpZpf6J^fW{n&{ncOd7m#cjd!f zKtu4?gtVO(OC%pVN*|J z(9)wJz|tm&Pyh*qBI!^A(tvC%l%5P_ghCm-ffyWei^kw)m%%vPV0`poV$fhz^ZoRz>G;?RWX3Hlu3!zf~Poq!V!Em zfGigW#?=4Wf~Z(F3UqxwW)@wAM#}`3X}TIPVLbrR8#P z?<$)o05yaUh9AKIbE#0yZS2vujh)oN-M<_t_vFbQl#?&Jne)SBPfi0yF!+e-kS&6v zH8Q0^j~P zi=paM%h|i3<|%GGCNFYiC=3#2E$p4hOU*w2ZM!^{sVtkbLH$lK`9 z=JM>{w9b{g{3zm-xgw3`xn47deG0b!>iQM7>#2#h~wIacQfcz``#06Ca5N-)I6=d0S>!?t!Wzj>kC6i`P;XsY`W1T}bl z4jpuj-1+*t^+HM89niNlx!n#)@&Gb+)J#yxe@XrP8{URz%9D@&-?~)iRxB5tjw4P=+kDG+yamNR<9I0zr1%U-NLy~#kK(gduWGW<DV@pjZ8SBsJM z;nx%0FVumWv&3(nw{jQWNC>yC*gxxxRfb_I=K&wzG5J4ucR%0d zURTRgvI|34^Vg>QA0*|nsaYEdfI4rXHGmHP{(jD-%__)0;31y0JR}D`VXLN3y5s8k zI|Az1cW+to^X4s>9Op(HeaZrb6k!6LhkftxU^0({oa?hZ>S`(J`X5EHE?vzNd;DlO zU@9rz9ydK(Bf8js8riG-hb4fuM^s~ca{4RvT)^1~6;++V;r0 z#~WG)%~Thc4($n>@4od-cY~=1sy+bv$IaVLf1we$dR>Wz+kV-N^qF%#NlPZ4*|PRi zppTzlu3~#inQb^ZKcA>yfjtYS;8<8XPlI+t1)hlQuf2Ewbt#vN^lR(EqE?iEYF>-V z6OAwye|D3+USqaWrzNB~jH5IABOehz-mLX0aX<%W+`QFsR|z&k z0Ritt9fHphwEe<#Rew?pI;-s+L~#oB{3f&B4s>{5pFAPTZL+QN^g$UPz(5Q1Mq4qvbf}GlY|4f2!pr()o_-5 z4c#2QRr?QM%AjM5x4vXlZ1YH_k?N6ttDkBLp0{mivh!nW%(KYB=y=a~UATb?#2mu( zY;#Cx%^n*re%@~|@~8+-hr_O}N>E$=s^NlK1l2!h>7~h``HT8609MJNjvq7B%TM*C z)U$CC5YRx!+R8wpJ-G+_+7~P<=?(2|tt!o_kZPZk;jeQCx1SjrG{)>z@v>+WZxA#+ z)x29bJ0;M2!RFb^LjV(Fb?2yFwvo?9m6#(g0Y@C=^ukD+dSTiWq-mB>=*Vw6poY=2 ze8`}yHLztF-*lskjeHJ&N%$HcS{M|ccPaZdYUc$(AaYN@20MOlP<1TVpSSLW_0*eP z4-=a$L6IFa?V$(UAG~(MU=@9#iMZCT zCmRp#6=D09L%WI#o+Szn?antbwM3esL@KgNsZP5{o84_6JUIDXN>!TNctNy?+TBQ$ zk#lL$KE|H0v6 z*}cO%$K0?+T#+pBP-p?XZAoe}2-%xjA9iIu{4CjBLlPLX7+JBe`tz^+eVXOMtn|q1b_ZTb|gA^rIJUx8W<37u}sz*gC$90V)yIWboZdZ|tLYL>X zzjJ+T!_~27Suq$pFfn4oZba?6`AYYC2=_b_2zAQ9`0U(rmrhI5 zY0YD;dD8DcrNEWfr+ra{)2mvp_gU(!VFu*svuLZ4kvg)Ux8HXDK`BsgArad}*kgj- zTZQP45?mPtEnRYa72xgjwYT=le4^m@7oy($*nzNAU)KaZ%iruIq}cPe$ul5Ym*I|H z`dn-EO@wfW1c>6nu^!sD(qX%W*zbHCS_!ZwZLw!z&HA$w-Gma*z>s10^4(E;tbF`4W~fUCTqD-R51yg z&43z&LZvVEvns&MLYWyA*+jwO1&}y?SvIMhAwi#EU?C*r4+m@$MMq?aJtHYQK*gK^ zP_u^RTA|Qg@lY)xYI+KFhKhk1fiKW1zYLN33}BTC{-c5tDrf@0TYGcIttf~5^ef{C zmDZq(07l`uneYL12~~+wbKPg;(PjNucybjH1D4dtGrIioWs6Yle@KM&T-SMT@SZ zD7tApfoM)MA}rM-Xo&8OT6i+WTX+N}29U8b5E4qIdV7v1+fIx?nlAQR8`|k(J`Q zC3vi(bk48TI?!bJKIyIWx3hm^Fm)q@hxtm9394+eJJ3w*F#o}6c6r_`PlG`O{%%e! zUQsPR2b#N%@&0>aNduaIfd86UpvMi9|G&F!9hW?CSfSRGoT*nN9bM`uJ${`n{-tV& z5|^YA`vJIwpjRZFVRDd&|C8kOtX7LCNk8}GOz1J`-Iirsp<{O% z{R@)T;+Joxe1jpM>~Fpj#T(GFnf$&zvNk2#p3zcQsLgC3IYyD?pkvq_f@$3|>(K1UHkHtV1 zhpIIFr&hVWwao=dA1-$1yz@9ij^}dZVBVuo{M8gw@=vRAxKNqvb|2a559-ZMe3?`Mv!_jq8$)l!WYZ0mlU`rN3DVjgLJ zC(hg$RHTdIIRq@51NtRBTLU7tnqnoFDJS_KYGp#Ew+(KVuVX72G_dphw%Dd5&|JS4 zt_SS+py80(ivyp^)K}Fncdr3T^k~5p@q3#72UWqrpEIQ&Za4qFd1+MhCZ9(Qf%E8H z@Q(>^<@KM^E$&{n(oAY1vsm7M4D!A0#gIbLAUwp2ppZ1V`&%?|tqVC6m%W{mG@78i zde4aM#1jV?>ejuq$2OP$-mI95fmcr>i(8n0jF2`jZY+OJg&l*>J+kF4Fi3A~s+hU5 zPQra#a?nfP@g_nvw2npX)HhRxKB&)#qvg8SF(V?pOguWU#3 zVercX_4gjEo07iA?&FhlkF=W#1uj>K`Fmc$wz5cv zesO*rgz68AhTQ(q1k(2;+^5)?gBokD6qLeI5FSg(XULuQeJ4CBvEOz4Z3V;_M#M~M zzXNRwP;daX*29lbQmctw&kZ$QrdqsT!XE-9YW!sZdl+RduUAsI`Ae+Isv*dd^%G|z z$bkwiOnY_GLVj*Q^dl-2^G;EyIn31rkMD(o(~J$)zpHZ3i_Fi-&d0-Io8UKIdl(+w z5iN5*&&0`3a3B&U{Ty}LXNY<3937;iGq+Y@+}YGoc$Ka@;k@xSU8G zq-o?yr>%UbN@NQ;kkMp(Q5bySz`N+%YMzEp-Of4jFqyAeO1by==tEgF;4xnd=3|>X zKp6GsdTs=lp?MmiJnZkwhSx(Fy6d(vz#e|AW-Xh;dB3z?ZsiMuX3 zgcJeTgGW!k)#*V!kSdeU?O_Q(PQPSg{h`(H_0oJ^+jn^h#43E-HaUn)j(`U#)%>13 z7XTg)La~vgAIg&?p82zc;+~u%7pt$D0nEcM(A4id1@U2_)zzn1>>j^jtbUv;p>&}A zbK5iO>m8o?B&*Pjn<-ZpqhCU>7KVVKVO3O+Z4+oP^-%^Fs&$!F=%}*mEVdDyzlOv{ z`b9P=3YdkT(*1phwgYgr3md4fN?xtpv%P#F6e73yW-`yTUk4>gy0VOFR+{KZ`xIJG zeyK6`$H$P?-+Yexoy(@IvT^+LfnCvGohJ|RW)WU|^@)=s1nqtw*bg=NvUQ>pzJ|KT z-OU+wt75r`AaaFT;QO%ZTk*ul6RX;5%VW1XrnXr{uy(-Y6BV}J?Q2LlV+=Aod8zZ5 zdFCc4P4R&Q9mMreJikgp7$Dg#n>QwJ`DBoZT>OA{1bD=oH$9?l#ZoG@0D@++ggY4U zvWCU@^C=#XC~jNO=)&u4Sj_-~(;~(3zt;veYcKstI$f|%_Q>*(%Qy1jZYMy>>hFoj z6mfI_?|_S6O`_KGQ$9=GoYIy@p2+&-U&6VaK^Hz+E)y!;q{0Fjl)(633I?Y@`?$MS z{({CBag9o2*xPaWf=3zcX&rxDho{A@@~_jId!l&%_&(Z7yuw52&}%l5Axm=!hl~^J z(Yr%{BxyyPvr80feCe#b?VQ>(G@UhB7wJj;nk?vn2E`58)nwrgf*uH^J?Jg%gS9Td zqSDc0FILCm{yk2-J?vxpaYbw_WU0mXs%1p>ATyZkbt`>@l#kE`3lieu^M60&8$mjV zkiKKWNDv$|L=Euq{F2I0FoUA>c^?x79Fp1s>tsSsNRN?ih_2w)bxLwCRp z8vy*A1Zl(cI;0pSPeUYCDg}t4~e7kC{-1^E@0lUXdK1Opae2C!m|N zdKBWK0(F@>sK$h;hQg+afH5DE{1)cSgWllckAz}>@d8VE(DYIHU@H6&8z!ZzW9pz* z6qpsIFg>y`BeO8GuJAzjf0CRzk%jh5sI~w=QGum&WmoCjF}KK*2Q68ZZ2iiRsbnJD z7zqZW+6_J+mYENsKp+ALZvnzfglbVsc$p=w=#o>z5CcI;`&0?PuB0=wq(kNKDV4*Q z9S&bzE@?L`(FlbSg;1SPK%NK4Q1e1O;94DUngl9ML@r7&d!*_YD$J9&Lyt|YTd)fy z+DfCLSRNo!DVJfCLioj^$nx3l;)TRgF}nP%VR=nj`Mc$^#qRRghTxl`iqDx9lBtUK zb>)D6xe~8jhA+(~!%EObK@0-osr0OrA0tF)3L(xQ(6uIkNwdl!gUfVy`enEmB`Rc= zD=$|6d$nm=QA>pwAe6TxgG zP-hC@ryYcm~>A=y5g29CjF(|M}(O-A*n92u4o3G2=rJAb{NFk09CtDbLE zOI>Gwbhy52|MB(2<2T;bUwd}^&PI6+)rMZjhTdPt2lqE1JC5JO9JeTHc=W3QMwZ_@ zr+3A%!5DI4s`$jSFLC`Fk3ai$;_*nsMKbi{{I3%|`%j$Pc=G+b<9;n_o!3uFR8M_z zJY_0AG4@|rxG7*e@C69|uc_g`$uV>?fvs%v|JmiD^uELw4*$PiLy@_jOZB@XD0L8aqhkk#9+?Ho0PDnM7KJmSm ztKI$QbIx;nz1m(}W1=>jeyAv@$oyk`E_2ql{ncH+cbg$h11)!+2gGD^@&x-?4{$@| zJ$#c!DC-Hd(QVpcXlM`!|-`Hc4SVE&?3;$aKnaP}# zi#_$p<=|L;tHxepP0r2ErT?heCd;$L(L?|2hE{!IGPiuJ&mNN7GZsH0|I&B2JweC2 zDEp85m(}h|t9PX0BcvgT^;@x3%7OVN?8{mF=zA*LTZPbga4{k=mUs>0rMdIfv8&H^ zkWLyL+fUmYK}cD=KD0%F9x9$a9DZd%=dkIZbZW4A<2P6C{Jd_il-gxD&$X2E*Dba7 zshpLUb~I!2@9a&8Dk7h>#P2$IT6r`yI^&r>(YyN^CwD{oQodSpW)D&`sndU`eseeG zZGGAuqq7YugP5}?GT!?a9?yC6Yz=Qur{$1(Omv4Q{!>S!7r}Gmf_`mS?i#Hl^A9~| ziQP24hWsDiVz1K8nGmGvwwgwS@`WVv;Q6-B)!#{N?Mb8WFYvqWAue8i8t|e0hE&LV z>Eg`2eD!UtQK+U;vSoAj4OdnD)O)c9o-0Y_bw>~?G@ExV!IV*sf@v?n(ahkA3*_un z;1D?CwmNX@YwylWx3QytKHd2$$FcDI_SAU~V*LUOrJ9ksgut2F(Ks!y1AUyKnO{%^j5cwwCuwf^0+jb8a(vtLp$sA%Q&^g=rk`k z)Cp^vHHr>Td~(am@J90r1~ObVI=j&(@bpRZV-T|q3I;3j;P*-V9^(-Od5l_&w(L&4L9 zke}xP+SfAxuguHhL2pYcB4`W(Y3Q(B==A9{W(QPtcHC z#~DLdOPy9me@tAqlk$}cJh%fEKxJfY=~LaGYk zN1qPiTWrqzt+ZFq_i>5cq&@pC_uzh$AWBP!tiPK!M;i_*91_3?(8vLIjTAMvsUZwxiFQLA*c$uJ_OqvgNq*s{sD7=32C6;ip`HhdQo`AR zX))A!iVfpbR#-Rq$o~_;gM;D+#V%ru!U3q4Q1tRsT}>UizeWQ>!(yB6 zi1xDSK~A}E+6=gI4!s09QmJksYA*{I#?Hhx4Dt*&4?^f6HB5`yWyOUtzhg-UQIUi-&XtxEH!NR+WLwa+> z7z)PYyn_PVH3_z*h^9ERpp+|pberthCVPj^HZ*0I7+t{~%(%<}m;}vVynNk65i2Iu zg4~Z$R8$ZJsZRx$o7px5(x4IR3q;3W;m(4+`Wh$J`;k2T=E=}e2ucVXRQ@QwHn@+Y zR7}OIvbIL_&4$%=!FhVgA96zd!W2UWToF4C<1=`@rdaX?iY9`*FqN z8nl^crm%Y0GAE)H0y2a{DH%s>UNz0r&imalG-b(|@*z}A*rtl$iS6~4V@IQOeeRs@BEx+)y$)C`;JEX|NH9_G*(EZD z-5}UKnH~)zF>f|>19CD_f&}<&#(%<+3@SV!HiQDMTxq+5c$(_j+3gM2RcS|i>+&i2 zFDt*?Ol{bLji%(=+UO`WM)si&9IooFVxqh=a|y_8XcOL*(hwbX0}D`7&VG zK1$ygt*dgFe_UNweomoO1lz&qnAD`mnj}cyAS>0iu!6jw-0{_6_OAQP@bNrMcVhzI zyZB|K1hTnXSNqR$p?mvMQMcOEO-RwR(J%?y+pt;d`|^<6G~_T|FTG!BJ#G8$#QYXS zZ$&br2e}-B!H%EJM@=PU(S)*<)d}%)Q#H>cGIav4{4LCoG&kpVc`0ga*u8VsEGJ4D zWB*40_FVHEf)v>Y#QEe7X;QHc=<3}Ld!rpTbkOOmye>txoT_js1773%klV^qp-Sr| zL9t!^?>GRHn~9SyNE`xkWO9u|MQHN1bI1QEC(%)7{a-^p?)#0TRxE0~L47uSm}j1z zx3G`2Vt8+lKjWJTXT^2E($SyZo_c-#ZC&`|p`IRDO#3N$#ODvkl%OJf?!w$lQ?bJ{ zycF(W__r#MaiI0@iBwW3<8{W(^e#_co^2#djM=hG^xf!?^k^5Z5%hc2CzrYZRTma7 z

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

VHNKN}q8pLwbU^d+dPsjHE$ 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

- +

Issues and PR's welcome \ No newline at end of file diff --git a/example/pubspec.lock b/example/pubspec.lock index 3b90ec6..4c46b6b 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -42,7 +42,7 @@ packages: path: ".." relative: true source: path - version: "2.0.0-dev.1" + version: "2.0.2-nullsafety.2" boolean_selector: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 9a7e1ec..2a8918a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_builder -description: A builder to wrap around buttons that handles loading and disabled state -version: 2.0.0-dev.1 +description: A builder to wrap around buttons that handles loading, disabled, error and succes states +version: 2.0.2-nullsafety.2 homepage: https://github.com/Nolence/async_button_builder environment: From 4c230fa81077cda987cdd0df9dc4209355546df9 Mon Sep 17 00:00:00 2001 From: Nolence Date: Wed, 27 Jan 2021 22:02:22 -0700 Subject: [PATCH 016/176] remove controller --- CHANGELOG.md | 3 +++ example/pubspec.lock | 9 ++++++++- lib/async_button_builder.dart | 2 ++ lib/src/async_button_builder.dart | 7 ++++--- pubspec.lock | 7 +++++++ pubspec.yaml | 3 ++- 6 files changed, 26 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b6f742..304c896 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## [2.0.2-nullsafety.3] - 2021-01-25 +Removes dangling controller and cleans up main code up a bit + ## [2.0.2-nullsafety.2] - 2021-01-25 Fixes wrong image path diff --git a/example/pubspec.lock b/example/pubspec.lock index 4c46b6b..0a5e980 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -42,7 +42,7 @@ packages: path: ".." relative: true source: path - version: "2.0.2-nullsafety.2" + version: "2.0.2-nullsafety.3" boolean_selector: dependency: transitive description: @@ -360,6 +360,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.0-nullsafety.5" + union: + dependency: transitive + description: + name: union + url: "https://pub.dartlang.org" + source: hosted + version: "0.0.4-nullsafety.1" vector_math: dependency: transitive description: diff --git a/lib/async_button_builder.dart b/lib/async_button_builder.dart index 9afabcc..2f7998d 100644 --- a/lib/async_button_builder.dart +++ b/lib/async_button_builder.dart @@ -1,2 +1,4 @@ +library async_button_builder; + export 'package:async_button_builder/src/async_button_builder.dart'; export 'package:async_button_builder/src/button_state/button_state.dart'; diff --git a/lib/src/async_button_builder.dart b/lib/src/async_button_builder.dart index d1b4e29..f046bd4 100644 --- a/lib/src/async_button_builder.dart +++ b/lib/src/async_button_builder.dart @@ -236,7 +236,6 @@ class AsyncButtonBuilder extends StatefulWidget { class _AsyncButtonBuilderState extends State with SingleTickerProviderStateMixin { late ButtonState buttonState; - late final AnimationController controller; Timer? timer; @override @@ -265,8 +264,6 @@ class _AsyncButtonBuilderState extends State width: 16.0, child: CircularProgressIndicator(), ); - final successPadding = widget.successPadding; - final errorPadding = widget.errorPadding; var successWidget = widget.successWidget ?? Icon( Icons.check, @@ -277,12 +274,16 @@ class _AsyncButtonBuilderState extends State Icons.error, color: theme.errorColor, ); + final successPadding = widget.successPadding; + final errorPadding = widget.errorPadding; + if (successPadding != null) { successWidget = Padding( padding: successPadding, child: successWidget, ); } + if (errorPadding != null) { errorWidget = Padding( padding: errorPadding, diff --git a/pubspec.lock b/pubspec.lock index c9a5973..3a1cfaf 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -443,6 +443,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.0-nullsafety.5" + union: + dependency: "direct main" + description: + name: union + url: "https://pub.dartlang.org" + source: hosted + version: "0.0.4-nullsafety.1" vector_math: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 2a8918a..a04a867 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_builder description: A builder to wrap around buttons that handles loading, disabled, error and succes states -version: 2.0.2-nullsafety.2 +version: 2.0.2-nullsafety.3 homepage: https://github.com/Nolence/async_button_builder environment: @@ -10,6 +10,7 @@ environment: dependencies: flutter: sdk: flutter + union: 0.0.4-nullsafety.1 freezed_annotation: ^0.13.0-nullsafety.0 dev_dependencies: From b942b28d9e33a4dbf5bb3bf7ebd266468846acac Mon Sep 17 00:00:00 2001 From: Nolence Date: Thu, 28 Jan 2021 08:42:14 -0700 Subject: [PATCH 017/176] Adds tests --- .github/workflows/dart.yaml | 42 +++++++++++ CHANGELOG.md | 3 + example/pubspec.lock | 2 +- lib/src/async_button_builder.dart | 7 ++ pubspec.yaml | 2 +- test/async_button_builder_test.dart | 107 +++++++++++++++++++++++++++- 6 files changed, 160 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/dart.yaml diff --git a/.github/workflows/dart.yaml b/.github/workflows/dart.yaml new file mode 100644 index 0000000..85273e2 --- /dev/null +++ b/.github/workflows/dart.yaml @@ -0,0 +1,42 @@ +name: Build + +on: + push: + pull_request: + schedule: + # runs the CI everyday at 10AM + - cron: '0 10 * * *' + +jobs: + flutter: + runs-on: ubuntu-latest + + strategy: + matrix: + channel: + - dev + - stable + + steps: + - uses: actions/checkout@v2 + + - uses: subosito/flutter-action@v1 + with: + channel: ${{ matrix.channel }} + + - name: Install dependencies + run: flutter pub get + + - name: Check format + run: flutter format --set-exit-if-changed . + + - name: Analyze + run: flutter analyze + + - name: Run tests + - run: flutter test --coverage + + - uses: codecov/codecov-action@v1.0.15 + with: + token: ${{secrets.CODECOV_TOKEN}} + file: ./coverage/lcov.info \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 304c896..7dc5899 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## [2.0.2-nullsafety.4] - 2021-01-26 +Adds tests and test coverage. Adds on dispose to cancel timer. + ## [2.0.2-nullsafety.3] - 2021-01-25 Removes dangling controller and cleans up main code up a bit diff --git a/example/pubspec.lock b/example/pubspec.lock index 0a5e980..d8e9297 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -42,7 +42,7 @@ packages: path: ".." relative: true source: path - version: "2.0.2-nullsafety.3" + version: "2.0.2-nullsafety.4" boolean_selector: dependency: transitive description: diff --git a/lib/src/async_button_builder.dart b/lib/src/async_button_builder.dart index f046bd4..c775057 100644 --- a/lib/src/async_button_builder.dart +++ b/lib/src/async_button_builder.dart @@ -255,6 +255,13 @@ class _AsyncButtonBuilderState extends State super.didUpdateWidget(oldWidget); } + @override + void dispose() { + timer?.cancel(); + + super.dispose(); + } + @override Widget build(BuildContext context) { final theme = Theme.of(context); diff --git a/pubspec.yaml b/pubspec.yaml index a04a867..2ddec82 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_builder description: A builder to wrap around buttons that handles loading, disabled, error and succes states -version: 2.0.2-nullsafety.3 +version: 2.0.2-nullsafety.4 homepage: https://github.com/Nolence/async_button_builder environment: diff --git a/test/async_button_builder_test.dart b/test/async_button_builder_test.dart index db8cee4..87c1f66 100644 --- a/test/async_button_builder_test.dart +++ b/test/async_button_builder_test.dart @@ -1,5 +1,110 @@ +import 'package:async_button_builder/async_button_builder.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { - test('TODO:', () {}); + testWidgets('displays child text', (WidgetTester tester) async { + final textButton = MaterialApp( + home: AsyncButtonBuilder( + child: Text('click me'), + onPressed: () async { + await Future.delayed(Duration(seconds: 1)); + }, + builder: (context, child, callback, state) { + return TextButton(onPressed: callback, child: child); + }, + ), + ); + + await tester.pumpWidget(textButton); + + expect(find.text('click me'), findsOneWidget); + }); + + testWidgets('shows loading widget', (WidgetTester tester) async { + final duration = Duration(milliseconds: 250); + final textButton = MaterialApp( + home: AsyncButtonBuilder( + duration: duration, + child: Text('click me'), + loadingWidget: Text('loading'), + onPressed: () async { + await Future.delayed(Duration(seconds: 1)); + }, + builder: (context, child, callback, state) { + return TextButton(onPressed: callback, child: child); + }, + ), + ); + + await tester.pumpWidget(textButton); + + await tester.tap(find.byType(TextButton)); + + // 1/10 of a second later, loading should be showing + await tester.pump(Duration(milliseconds: 100)); + + expect(find.text('loading'), findsOneWidget); + + // Let the widget continue to settle otherwise I won't dispose timers + // correctly. TODO: Explain why .900 is the magic number + await tester.pumpAndSettle(Duration(milliseconds: 900)); + }); + + testWidgets('shows error widget', (WidgetTester tester) async { + final duration = Duration(milliseconds: 250); + final textButton = MaterialApp( + home: AsyncButtonBuilder( + duration: duration, + child: Text('click me'), + errorWidget: Text('error'), + onPressed: () async { + throw ArgumentError(); + }, + builder: (context, child, callback, state) { + return TextButton(onPressed: callback, child: child); + }, + ), + ); + + await tester.pumpWidget(textButton); + final button = + find.byType(TextButton).evaluate().first.widget as TextButton; + + expect( + () => button.onPressed!.call(), + throwsA(isInstanceOf()), + ); + + await tester.pump(Duration(milliseconds: 200)); + + expect(find.text('error'), findsOneWidget); + }); + + testWidgets('Returns to child widget', (WidgetTester tester) async { + final duration = Duration(milliseconds: 250); + final textButton = MaterialApp( + home: AsyncButtonBuilder( + duration: duration, + child: Text('click me'), + loadingWidget: Text('loading'), + onPressed: () async { + await Future.delayed(Duration(seconds: 1)); + }, + builder: (context, child, callback, state) { + return TextButton(onPressed: callback, child: child); + }, + ), + ); + + await tester.pumpWidget(textButton); + + await tester.tap(find.byType(TextButton)); + + await tester.pump(Duration(milliseconds: 1000)); + + expect(find.text('loading'), findsNothing); + + expect(find.text('click me'), findsOneWidget); + }); } From d01544b2d2fcad5e2efdda52a95fbd243b532f39 Mon Sep 17 00:00:00 2001 From: Nolence Date: Thu, 28 Jan 2021 08:44:12 -0700 Subject: [PATCH 018/176] Added back uses --- .github/workflows/dart.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/dart.yaml b/.github/workflows/dart.yaml index 85273e2..8d1a963 100644 --- a/.github/workflows/dart.yaml +++ b/.github/workflows/dart.yaml @@ -35,7 +35,6 @@ jobs: - name: Run tests - run: flutter test --coverage - - uses: codecov/codecov-action@v1.0.15 with: token: ${{secrets.CODECOV_TOKEN}} From ad77b3ab17b5e28141c264a08c9418fa855d6e4f Mon Sep 17 00:00:00 2001 From: Nolence Date: Thu, 28 Jan 2021 08:45:53 -0700 Subject: [PATCH 019/176] Testing dart.yaml --- .github/workflows/dart.yaml | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/.github/workflows/dart.yaml b/.github/workflows/dart.yaml index 8d1a963..776895c 100644 --- a/.github/workflows/dart.yaml +++ b/.github/workflows/dart.yaml @@ -34,8 +34,33 @@ jobs: run: flutter analyze - name: Run tests - - run: flutter test --coverage - - uses: codecov/codecov-action@v1.0.15 - with: - token: ${{secrets.CODECOV_TOKEN}} - file: ./coverage/lcov.info \ No newline at end of file + run: flutter test + + + +# name: build + +# on: +# push: +# branches: [ master ] +# pull_request: +# branches: [ master ] + +# jobs: +# build-and-test: +# runs-on: ubuntu-latest +# steps: +# - uses: actions/checkout@v1 +# - uses: actions/setup-java@v1 +# with: +# java-version: '12.x' +# - uses: subosito/flutter-action@v1 +# with: +# channel: 'stable' +# - run: flutter pub get +# - run: flutter analyze +# - run: flutter test --coverage +# - uses: codecov/codecov-action@v1.0.15 +# with: +# token: ${{secrets.CODECOV_TOKEN}} +# file: ./coverage/lcov.info \ No newline at end of file From 0aca66847f051b604a49e66632bdb69184bf95dc Mon Sep 17 00:00:00 2001 From: Nolence Date: Thu, 28 Jan 2021 08:48:06 -0700 Subject: [PATCH 020/176] Removed stable --- .github/workflows/dart.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dart.yaml b/.github/workflows/dart.yaml index 776895c..f2fd135 100644 --- a/.github/workflows/dart.yaml +++ b/.github/workflows/dart.yaml @@ -15,7 +15,7 @@ jobs: matrix: channel: - dev - - stable + # - stable steps: - uses: actions/checkout@v2 From cd6065f0f20ef4d2402a5a05f4e16a1986cac52d Mon Sep 17 00:00:00 2001 From: Nolence Date: Thu, 28 Jan 2021 08:52:34 -0700 Subject: [PATCH 021/176] Removed fluff --- .github/workflows/dart.yaml | 31 +------------------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/.github/workflows/dart.yaml b/.github/workflows/dart.yaml index f2fd135..f4086c2 100644 --- a/.github/workflows/dart.yaml +++ b/.github/workflows/dart.yaml @@ -34,33 +34,4 @@ jobs: run: flutter analyze - name: Run tests - run: flutter test - - - -# name: build - -# on: -# push: -# branches: [ master ] -# pull_request: -# branches: [ master ] - -# jobs: -# build-and-test: -# runs-on: ubuntu-latest -# steps: -# - uses: actions/checkout@v1 -# - uses: actions/setup-java@v1 -# with: -# java-version: '12.x' -# - uses: subosito/flutter-action@v1 -# with: -# channel: 'stable' -# - run: flutter pub get -# - run: flutter analyze -# - run: flutter test --coverage -# - uses: codecov/codecov-action@v1.0.15 -# with: -# token: ${{secrets.CODECOV_TOKEN}} -# file: ./coverage/lcov.info \ No newline at end of file + run: flutter test \ No newline at end of file From ffb48a20846cb9e03d387ac257ed781a3e9215d2 Mon Sep 17 00:00:00 2001 From: Nolence Date: Thu, 28 Jan 2021 08:54:08 -0700 Subject: [PATCH 022/176] Removed danling union requirement --- example/pubspec.lock | 7 ------- pubspec.lock | 7 ------- pubspec.yaml | 1 - 3 files changed, 15 deletions(-) diff --git a/example/pubspec.lock b/example/pubspec.lock index d8e9297..1b48d70 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -360,13 +360,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.0-nullsafety.5" - union: - dependency: transitive - description: - name: union - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.4-nullsafety.1" vector_math: dependency: transitive description: diff --git a/pubspec.lock b/pubspec.lock index 3a1cfaf..c9a5973 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -443,13 +443,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.0-nullsafety.5" - union: - dependency: "direct main" - description: - name: union - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.4-nullsafety.1" vector_math: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 2ddec82..d09dc21 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -10,7 +10,6 @@ environment: dependencies: flutter: sdk: flutter - union: 0.0.4-nullsafety.1 freezed_annotation: ^0.13.0-nullsafety.0 dev_dependencies: From 04f376f92f3bb05dcf0572103561da343a545486 Mon Sep 17 00:00:00 2001 From: Nolence Date: Mon, 1 Feb 2021 18:06:09 -0700 Subject: [PATCH 023/176] Removed integration test --- CHANGELOG.md | 3 +++ example/integration_test/app_test.dart | 36 -------------------------- example/integration_test/driver.dart | 8 ------ example/pubspec.lock | 2 +- pubspec.yaml | 2 +- 5 files changed, 5 insertions(+), 46 deletions(-) delete mode 100644 example/integration_test/app_test.dart delete mode 100644 example/integration_test/driver.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index 7dc5899..927e5f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## [2.0.2-nullsafety.5] - 2021-02-01 +Removed example integration test + ## [2.0.2-nullsafety.4] - 2021-01-26 Adds tests and test coverage. Adds on dispose to cancel timer. diff --git a/example/integration_test/app_test.dart b/example/integration_test/app_test.dart deleted file mode 100644 index 3e01719..0000000 --- a/example/integration_test/app_test.dart +++ /dev/null @@ -1,36 +0,0 @@ -// This is a basic Flutter integration test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility that Flutter provides. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:integration_test/integration_test.dart'; - -import 'package:example/main.dart' as app; - -void main() => run(_testMain); - -void _testMain() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - app.main(); - - // Trigger a frame. - await tester.pumpAndSettle(); - - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); - - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); - }); -} diff --git a/example/integration_test/driver.dart b/example/integration_test/driver.dart deleted file mode 100644 index a03bca0..0000000 --- a/example/integration_test/driver.dart +++ /dev/null @@ -1,8 +0,0 @@ -// This file is provided as a convenience for running integration tests via the -// flutter drive command. -// -// flutter drive --driver integration_test/driver.dart --target integration_test/app_test.dart - -import 'package:integration_test/integration_test_driver.dart'; - -Future main() => integrationDriver(); diff --git a/example/pubspec.lock b/example/pubspec.lock index 1b48d70..b246c82 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -42,7 +42,7 @@ packages: path: ".." relative: true source: path - version: "2.0.2-nullsafety.4" + version: "2.0.2-nullsafety.5" boolean_selector: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index d09dc21..0f7f052 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_builder description: A builder to wrap around buttons that handles loading, disabled, error and succes states -version: 2.0.2-nullsafety.4 +version: 2.0.2-nullsafety.5 homepage: https://github.com/Nolence/async_button_builder environment: From a6f8ef5e2b17200ec661c916b6e5bb88372cd8b1 Mon Sep 17 00:00:00 2001 From: Nolence Date: Mon, 1 Feb 2021 18:21:58 -0700 Subject: [PATCH 024/176] Added more analysis options --- example/analysis_options.yaml | 1 + example/pubspec.lock | 227 +--------------------------------- example/pubspec.yaml | 3 +- pubspec.lock | 2 +- 4 files changed, 4 insertions(+), 229 deletions(-) create mode 100644 example/analysis_options.yaml diff --git a/example/analysis_options.yaml b/example/analysis_options.yaml new file mode 100644 index 0000000..108d105 --- /dev/null +++ b/example/analysis_options.yaml @@ -0,0 +1 @@ +include: package:pedantic/analysis_options.yaml diff --git a/example/pubspec.lock b/example/pubspec.lock index b246c82..0f33ba4 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -1,34 +1,6 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: - _fe_analyzer_shared: - dependency: transitive - description: - name: _fe_analyzer_shared - url: "https://pub.dartlang.org" - source: hosted - version: "12.0.0" - analyzer: - dependency: transitive - description: - name: analyzer - url: "https://pub.dartlang.org" - source: hosted - version: "0.40.6" - archive: - dependency: transitive - description: - name: archive - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.13" - args: - dependency: transitive - description: - name: args - url: "https://pub.dartlang.org" - source: hosted - version: "1.6.0" async: dependency: transitive description: @@ -64,13 +36,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.0-nullsafety.3" - cli_util: - dependency: transitive - description: - name: cli_util - url: "https://pub.dartlang.org" - source: hosted - version: "0.2.0" clock: dependency: transitive description: @@ -85,27 +50,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.15.0-nullsafety.5" - convert: - dependency: transitive - description: - name: convert - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.1" - coverage: - dependency: transitive - description: - name: coverage - url: "https://pub.dartlang.org" - source: hosted - version: "0.14.2" - crypto: - dependency: transitive - description: - name: crypto - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.5" cupertino_icons: dependency: "direct main" description: @@ -120,23 +64,11 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.0-nullsafety.3" - file: - dependency: transitive - description: - name: file - url: "https://pub.dartlang.org" - source: hosted - version: "6.0.0-nullsafety.4" flutter: dependency: "direct main" description: flutter source: sdk version: "0.0.0" - flutter_driver: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" flutter_test: dependency: "direct dev" description: flutter @@ -149,37 +81,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.13.0-nullsafety.0" - fuchsia_remote_debug_protocol: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - glob: - dependency: transitive - description: - name: glob - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - integration_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.9.2+2" - io: - dependency: transitive - description: - name: io - url: "https://pub.dartlang.org" - source: hosted - version: "0.3.4" - js: - dependency: transitive - description: - name: js - url: "https://pub.dartlang.org" - source: hosted - version: "0.6.3-nullsafety.3" json_annotation: dependency: transitive description: @@ -187,20 +88,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "4.0.0-nullsafety.0" - json_rpc_2: - dependency: transitive - description: - name: json_rpc_2 - url: "https://pub.dartlang.org" - source: hosted - version: "2.2.2" - logging: - dependency: transitive - description: - name: logging - url: "https://pub.dartlang.org" - source: hosted - version: "0.11.4" matcher: dependency: transitive description: @@ -215,27 +102,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.0-nullsafety.6" - node_interop: - dependency: transitive - description: - name: node_interop - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.1" - node_io: - dependency: transitive - description: - name: node_io - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.1" - package_config: - dependency: transitive - description: - name: package_config - url: "https://pub.dartlang.org" - source: hosted - version: "1.9.3" path: dependency: transitive description: @@ -244,59 +110,17 @@ packages: source: hosted version: "1.8.0-nullsafety.3" pedantic: - dependency: transitive + dependency: "direct dev" description: name: pedantic url: "https://pub.dartlang.org" source: hosted version: "1.10.0-nullsafety.3" - platform: - dependency: transitive - description: - name: platform - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.0-nullsafety.4" - pool: - dependency: transitive - description: - name: pool - url: "https://pub.dartlang.org" - source: hosted - version: "1.5.0-nullsafety.3" - process: - dependency: transitive - description: - name: process - url: "https://pub.dartlang.org" - source: hosted - version: "4.0.0-nullsafety.4" - pub_semver: - dependency: transitive - description: - name: pub_semver - url: "https://pub.dartlang.org" - source: hosted - version: "1.4.4" sky_engine: dependency: transitive description: flutter source: sdk version: "0.0.99" - source_map_stack_trace: - dependency: transitive - description: - name: source_map_stack_trace - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0-nullsafety.4" - source_maps: - dependency: transitive - description: - name: source_maps - url: "https://pub.dartlang.org" - source: hosted - version: "0.10.10-nullsafety.3" source_span: dependency: transitive description: @@ -325,13 +149,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.0-nullsafety.3" - sync_http: - dependency: transitive - description: - name: sync_http - url: "https://pub.dartlang.org" - source: hosted - version: "0.2.0" term_glyph: dependency: transitive description: @@ -346,13 +163,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.2.19-nullsafety.6" - test_core: - dependency: transitive - description: - name: test_core - url: "https://pub.dartlang.org" - source: hosted - version: "0.3.12-nullsafety.9" typed_data: dependency: transitive description: @@ -367,41 +177,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0-nullsafety.5" - vm_service: - dependency: transitive - description: - name: vm_service - url: "https://pub.dartlang.org" - source: hosted - version: "5.5.0" - watcher: - dependency: transitive - description: - name: watcher - url: "https://pub.dartlang.org" - source: hosted - version: "0.9.7+15" - web_socket_channel: - dependency: transitive - description: - name: web_socket_channel - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - webdriver: - dependency: transitive - description: - name: webdriver - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.2" - yaml: - dependency: transitive - description: - name: yaml - url: "https://pub.dartlang.org" - source: hosted - version: "2.2.1" sdks: dart: ">=2.12.0-0.0.dev <3.0.0" flutter: ">=1.17.0" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 904d70b..3e438cf 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -17,8 +17,7 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - integration_test: - sdk: flutter + pedantic: ^1.10.0-nullsafety.3 flutter: uses-material-design: true diff --git a/pubspec.lock b/pubspec.lock index c9a5973..a32ecb5 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -199,7 +199,7 @@ packages: name: freezed url: "https://pub.dartlang.org" source: hosted - version: "0.13.0-nullsafety.0" + version: "0.13.0-nullsafety.2" freezed_annotation: dependency: "direct main" description: From 7f4eccb416bdcdd8a1436ee64e63f385112cbca8 Mon Sep 17 00:00:00 2001 From: Nolence Date: Tue, 9 Feb 2021 11:13:19 -0700 Subject: [PATCH 025/176] Renamed classes in union. Should be non-breaking --- CHANGELOG.md | 3 + example/pubspec.lock | 2 +- lib/src/button_state/button_state.dart | 10 +- .../button_state/button_state.freezed.dart | 150 +++++++++--------- pubspec.yaml | 2 +- 5 files changed, 85 insertions(+), 82 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 927e5f9..1c481e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## [2.0.2-nullsafety.6] - 2021-02-09 +Renamed Union classes to match that of factory constructor name (Should not be breaking). + ## [2.0.2-nullsafety.5] - 2021-02-01 Removed example integration test diff --git a/example/pubspec.lock b/example/pubspec.lock index 0f33ba4..0bcd83d 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -14,7 +14,7 @@ packages: path: ".." relative: true source: path - version: "2.0.2-nullsafety.5" + version: "2.0.2-nullsafety.6" boolean_selector: dependency: transitive description: diff --git a/lib/src/button_state/button_state.dart b/lib/src/button_state/button_state.dart index 00331f3..6686549 100644 --- a/lib/src/button_state/button_state.dart +++ b/lib/src/button_state/button_state.dart @@ -2,8 +2,8 @@ import 'package:freezed_annotation/freezed_annotation.dart'; part 'button_state.freezed.dart'; -/// This union class represents the state of the button in either a [Normal], -/// [Loading] or [Completing] state. This can be considered a enum with extra +/// This union class represents the state of the button in either a [Idling], +/// [Loading], [Success] or [Error] state. This can be considered a enum with extra /// utilities for ease of use. /// /// {@tool snippet} @@ -32,8 +32,8 @@ part 'button_state.freezed.dart'; /// {@end-tool} @freezed abstract class ButtonState with _$ButtonState { - const factory ButtonState.idle() = Idling; + const factory ButtonState.idle() = Idle; const factory ButtonState.loading() = Loading; - const factory ButtonState.success() = Succeding; - const factory ButtonState.error() = Failing; + const factory ButtonState.success() = Success; + const factory ButtonState.error() = Error; } diff --git a/lib/src/button_state/button_state.freezed.dart b/lib/src/button_state/button_state.freezed.dart index c37b4a1..5efc4c4 100644 --- a/lib/src/button_state/button_state.freezed.dart +++ b/lib/src/button_state/button_state.freezed.dart @@ -13,20 +13,20 @@ T _$identity(T value) => value; class _$ButtonStateTearOff { const _$ButtonStateTearOff(); - Idling idle() { - return const Idling(); + Idle idle() { + return const Idle(); } Loading loading() { return const Loading(); } - Succeding success() { - return const Succeding(); + Success success() { + return const Success(); } - Failing error() { - return const Failing(); + Error error() { + return const Error(); } } @@ -52,17 +52,17 @@ mixin _$ButtonState { }); @optionalTypeArgs TResult map({ - required TResult Function(Idling value) idle, + required TResult Function(Idle value) idle, required TResult Function(Loading value) loading, - required TResult Function(Succeding value) success, - required TResult Function(Failing value) error, + required TResult Function(Success value) success, + required TResult Function(Error value) error, }); @optionalTypeArgs TResult maybeMap({ - TResult Function(Idling value)? idle, + TResult Function(Idle value)? idle, TResult Function(Loading value)? loading, - TResult Function(Succeding value)? success, - TResult Function(Failing value)? error, + TResult Function(Success value)? success, + TResult Function(Error value)? error, required TResult orElse(), }); } @@ -84,24 +84,24 @@ class _$ButtonStateCopyWithImpl<$Res> implements $ButtonStateCopyWith<$Res> { } /// @nodoc -abstract class $IdlingCopyWith<$Res> { - factory $IdlingCopyWith(Idling value, $Res Function(Idling) then) = - _$IdlingCopyWithImpl<$Res>; +abstract class $IdleCopyWith<$Res> { + factory $IdleCopyWith(Idle value, $Res Function(Idle) then) = + _$IdleCopyWithImpl<$Res>; } /// @nodoc -class _$IdlingCopyWithImpl<$Res> extends _$ButtonStateCopyWithImpl<$Res> - implements $IdlingCopyWith<$Res> { - _$IdlingCopyWithImpl(Idling _value, $Res Function(Idling) _then) - : super(_value, (v) => _then(v as Idling)); +class _$IdleCopyWithImpl<$Res> extends _$ButtonStateCopyWithImpl<$Res> + implements $IdleCopyWith<$Res> { + _$IdleCopyWithImpl(Idle _value, $Res Function(Idle) _then) + : super(_value, (v) => _then(v as Idle)); @override - Idling get _value => super._value as Idling; + Idle get _value => super._value as Idle; } /// @nodoc -class _$Idling implements Idling { - const _$Idling(); +class _$Idle implements Idle { + const _$Idle(); @override String toString() { @@ -110,7 +110,7 @@ class _$Idling implements Idling { @override bool operator ==(dynamic other) { - return identical(this, other) || (other is Idling); + return identical(this, other) || (other is Idle); } @override @@ -145,10 +145,10 @@ class _$Idling implements Idling { @override @optionalTypeArgs TResult map({ - required TResult Function(Idling value) idle, + required TResult Function(Idle value) idle, required TResult Function(Loading value) loading, - required TResult Function(Succeding value) success, - required TResult Function(Failing value) error, + required TResult Function(Success value) success, + required TResult Function(Error value) error, }) { return idle(this); } @@ -156,10 +156,10 @@ class _$Idling implements Idling { @override @optionalTypeArgs TResult maybeMap({ - TResult Function(Idling value)? idle, + TResult Function(Idle value)? idle, TResult Function(Loading value)? loading, - TResult Function(Succeding value)? success, - TResult Function(Failing value)? error, + TResult Function(Success value)? success, + TResult Function(Error value)? error, required TResult orElse(), }) { if (idle != null) { @@ -169,8 +169,8 @@ class _$Idling implements Idling { } } -abstract class Idling implements ButtonState { - const factory Idling() = _$Idling; +abstract class Idle implements ButtonState { + const factory Idle() = _$Idle; } /// @nodoc @@ -235,10 +235,10 @@ class _$Loading implements Loading { @override @optionalTypeArgs TResult map({ - required TResult Function(Idling value) idle, + required TResult Function(Idle value) idle, required TResult Function(Loading value) loading, - required TResult Function(Succeding value) success, - required TResult Function(Failing value) error, + required TResult Function(Success value) success, + required TResult Function(Error value) error, }) { return loading(this); } @@ -246,10 +246,10 @@ class _$Loading implements Loading { @override @optionalTypeArgs TResult maybeMap({ - TResult Function(Idling value)? idle, + TResult Function(Idle value)? idle, TResult Function(Loading value)? loading, - TResult Function(Succeding value)? success, - TResult Function(Failing value)? error, + TResult Function(Success value)? success, + TResult Function(Error value)? error, required TResult orElse(), }) { if (loading != null) { @@ -264,24 +264,24 @@ abstract class Loading implements ButtonState { } /// @nodoc -abstract class $SuccedingCopyWith<$Res> { - factory $SuccedingCopyWith(Succeding value, $Res Function(Succeding) then) = - _$SuccedingCopyWithImpl<$Res>; +abstract class $SuccessCopyWith<$Res> { + factory $SuccessCopyWith(Success value, $Res Function(Success) then) = + _$SuccessCopyWithImpl<$Res>; } /// @nodoc -class _$SuccedingCopyWithImpl<$Res> extends _$ButtonStateCopyWithImpl<$Res> - implements $SuccedingCopyWith<$Res> { - _$SuccedingCopyWithImpl(Succeding _value, $Res Function(Succeding) _then) - : super(_value, (v) => _then(v as Succeding)); +class _$SuccessCopyWithImpl<$Res> extends _$ButtonStateCopyWithImpl<$Res> + implements $SuccessCopyWith<$Res> { + _$SuccessCopyWithImpl(Success _value, $Res Function(Success) _then) + : super(_value, (v) => _then(v as Success)); @override - Succeding get _value => super._value as Succeding; + Success get _value => super._value as Success; } /// @nodoc -class _$Succeding implements Succeding { - const _$Succeding(); +class _$Success implements Success { + const _$Success(); @override String toString() { @@ -290,7 +290,7 @@ class _$Succeding implements Succeding { @override bool operator ==(dynamic other) { - return identical(this, other) || (other is Succeding); + return identical(this, other) || (other is Success); } @override @@ -325,10 +325,10 @@ class _$Succeding implements Succeding { @override @optionalTypeArgs TResult map({ - required TResult Function(Idling value) idle, + required TResult Function(Idle value) idle, required TResult Function(Loading value) loading, - required TResult Function(Succeding value) success, - required TResult Function(Failing value) error, + required TResult Function(Success value) success, + required TResult Function(Error value) error, }) { return success(this); } @@ -336,10 +336,10 @@ class _$Succeding implements Succeding { @override @optionalTypeArgs TResult maybeMap({ - TResult Function(Idling value)? idle, + TResult Function(Idle value)? idle, TResult Function(Loading value)? loading, - TResult Function(Succeding value)? success, - TResult Function(Failing value)? error, + TResult Function(Success value)? success, + TResult Function(Error value)? error, required TResult orElse(), }) { if (success != null) { @@ -349,29 +349,29 @@ class _$Succeding implements Succeding { } } -abstract class Succeding implements ButtonState { - const factory Succeding() = _$Succeding; +abstract class Success implements ButtonState { + const factory Success() = _$Success; } /// @nodoc -abstract class $FailingCopyWith<$Res> { - factory $FailingCopyWith(Failing value, $Res Function(Failing) then) = - _$FailingCopyWithImpl<$Res>; +abstract class $ErrorCopyWith<$Res> { + factory $ErrorCopyWith(Error value, $Res Function(Error) then) = + _$ErrorCopyWithImpl<$Res>; } /// @nodoc -class _$FailingCopyWithImpl<$Res> extends _$ButtonStateCopyWithImpl<$Res> - implements $FailingCopyWith<$Res> { - _$FailingCopyWithImpl(Failing _value, $Res Function(Failing) _then) - : super(_value, (v) => _then(v as Failing)); +class _$ErrorCopyWithImpl<$Res> extends _$ButtonStateCopyWithImpl<$Res> + implements $ErrorCopyWith<$Res> { + _$ErrorCopyWithImpl(Error _value, $Res Function(Error) _then) + : super(_value, (v) => _then(v as Error)); @override - Failing get _value => super._value as Failing; + Error get _value => super._value as Error; } /// @nodoc -class _$Failing implements Failing { - const _$Failing(); +class _$Error implements Error { + const _$Error(); @override String toString() { @@ -380,7 +380,7 @@ class _$Failing implements Failing { @override bool operator ==(dynamic other) { - return identical(this, other) || (other is Failing); + return identical(this, other) || (other is Error); } @override @@ -415,10 +415,10 @@ class _$Failing implements Failing { @override @optionalTypeArgs TResult map({ - required TResult Function(Idling value) idle, + required TResult Function(Idle value) idle, required TResult Function(Loading value) loading, - required TResult Function(Succeding value) success, - required TResult Function(Failing value) error, + required TResult Function(Success value) success, + required TResult Function(Error value) error, }) { return error(this); } @@ -426,10 +426,10 @@ class _$Failing implements Failing { @override @optionalTypeArgs TResult maybeMap({ - TResult Function(Idling value)? idle, + TResult Function(Idle value)? idle, TResult Function(Loading value)? loading, - TResult Function(Succeding value)? success, - TResult Function(Failing value)? error, + TResult Function(Success value)? success, + TResult Function(Error value)? error, required TResult orElse(), }) { if (error != null) { @@ -439,6 +439,6 @@ class _$Failing implements Failing { } } -abstract class Failing implements ButtonState { - const factory Failing() = _$Failing; +abstract class Error implements ButtonState { + const factory Error() = _$Error; } diff --git a/pubspec.yaml b/pubspec.yaml index 0f7f052..ef7c427 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_builder description: A builder to wrap around buttons that handles loading, disabled, error and succes states -version: 2.0.2-nullsafety.5 +version: 2.0.2-nullsafety.6 homepage: https://github.com/Nolence/async_button_builder environment: From f08fd5f9a5c021abce36fa1e3571b3b315b1d904 Mon Sep 17 00:00:00 2001 From: Nolence Date: Tue, 9 Feb 2021 11:14:37 -0700 Subject: [PATCH 026/176] Updated docs --- README.md | 3 ++- example/lib/main.dart | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 64f05b1..723fda8 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,8 @@ AsyncButtonBuilder( AsyncButtonBuilder( child: Padding( // Value keys are important as otherwise our custom transitions - // will have no way to differentiate between children. + // will have no way to differentiate between children. This is a + // Flutter framework requirement not a library one. key: ValueKey('foo'), padding: const EdgeInsets.symmetric( horizontal: 16.0, diff --git a/example/lib/main.dart b/example/lib/main.dart index 2148024..7734e57 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -86,7 +86,8 @@ class MyHomePage extends StatelessWidget { AsyncButtonBuilder( child: Padding( // Value keys are important as otherwise our custom transitions - // will have no way to differentiate between children. + // will have no way to differentiate between children. This is a + // Flutter framework requirement not a library one. key: ValueKey('foo'), padding: const EdgeInsets.symmetric( horizontal: 16.0, From 5ccc327e859c8436f82bf58063830f0c26af7ae8 Mon Sep 17 00:00:00 2001 From: Nolence Date: Fri, 12 Feb 2021 12:44:04 -0700 Subject: [PATCH 027/176] added typedef and doc over builder --- CHANGELOG.md | 3 ++ example/ios/Podfile | 2 +- example/ios/Podfile.lock | 8 +--- example/ios/Runner.xcodeproj/project.pbxproj | 18 --------- example/pubspec.lock | 38 +++++++++--------- lib/src/async_button_builder.dart | 17 +++++--- pubspec.lock | 36 ++++++++--------- pubspec.yaml | 2 +- test/async_button_builder_test.dart | 41 ++++++++++++++++++++ 9 files changed, 95 insertions(+), 70 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c481e8..8df38d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## [2.0.2-nullsafety.7] - 2021-02-12 +Added a typedef in place of inline type on function. Added doc to `builder` field + ## [2.0.2-nullsafety.6] - 2021-02-09 Renamed Union classes to match that of factory constructor name (Should not be breaking). diff --git a/example/ios/Podfile b/example/ios/Podfile index 1e8c3c9..b29247c 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -38,4 +38,4 @@ post_install do |installer| installer.pods_project.targets.each do |target| flutter_additional_ios_build_settings(target) end -end +end \ No newline at end of file diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index f0772ce..f11c132 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1,22 +1,16 @@ PODS: - Flutter (1.0.0) - - integration_test (0.0.1): - - Flutter DEPENDENCIES: - Flutter (from `Flutter`) - - integration_test (from `.symlinks/plugins/integration_test/ios`) EXTERNAL SOURCES: Flutter: :path: Flutter - integration_test: - :path: ".symlinks/plugins/integration_test/ios" SPEC CHECKSUMS: Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c - integration_test: 6eb66a19f7104200dcfdd62bc0077e1b09686e4f -PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c +PODFILE CHECKSUM: fc81e398f362bae88bdf55239bd5cf842faad39f COCOAPODS: 1.10.1 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 483ce5c..ad27a86 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -139,7 +139,6 @@ 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - 90F19155A8EB5CB4E9D778A3 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -234,23 +233,6 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; - 90F19155A8EB5CB4E9D778A3 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; diff --git a/example/pubspec.lock b/example/pubspec.lock index 0bcd83d..41ee0d5 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -7,49 +7,49 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.5.0-nullsafety.3" + version: "2.5.0" async_button_builder: dependency: "direct main" description: path: ".." relative: true source: path - version: "2.0.2-nullsafety.6" + version: "2.0.2-nullsafety.7" boolean_selector: dependency: transitive description: name: boolean_selector url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.3" + version: "2.1.0" characters: dependency: transitive description: name: characters url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.5" + version: "1.1.0" charcode: dependency: transitive description: name: charcode url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.3" + version: "1.2.0" clock: dependency: transitive description: name: clock url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.3" + version: "1.1.0" collection: dependency: transitive description: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.15.0-nullsafety.5" + version: "1.15.0" cupertino_icons: dependency: "direct main" description: @@ -63,7 +63,7 @@ packages: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.3" + version: "1.2.0" flutter: dependency: "direct main" description: flutter @@ -94,21 +94,21 @@ packages: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.10-nullsafety.3" + version: "0.12.10" meta: dependency: transitive description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.3.0-nullsafety.6" + version: "1.3.0" path: dependency: transitive description: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.0-nullsafety.3" + version: "1.8.0" pedantic: dependency: "direct dev" description: @@ -127,56 +127,56 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.0-nullsafety.4" + version: "1.8.0" stack_trace: dependency: transitive description: name: stack_trace url: "https://pub.dartlang.org" source: hosted - version: "1.10.0-nullsafety.6" + version: "1.10.0" stream_channel: dependency: transitive description: name: stream_channel url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.3" + version: "2.1.0" string_scanner: dependency: transitive description: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.3" + version: "1.1.0" term_glyph: dependency: transitive description: name: term_glyph url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.3" + version: "1.2.0" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.19-nullsafety.6" + version: "0.2.19" typed_data: dependency: transitive description: name: typed_data url: "https://pub.dartlang.org" source: hosted - version: "1.3.0-nullsafety.5" + version: "1.3.0" vector_math: dependency: transitive description: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.5" + version: "2.1.0" sdks: dart: ">=2.12.0-0.0.dev <3.0.0" flutter: ">=1.17.0" diff --git a/lib/src/async_button_builder.dart b/lib/src/async_button_builder.dart index c775057..ca7f27e 100644 --- a/lib/src/async_button_builder.dart +++ b/lib/src/async_button_builder.dart @@ -4,6 +4,13 @@ import 'package:async_button_builder/src/button_state/button_state.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +typedef AsyncButtonBuilderCallback = Widget Function( + BuildContext context, + Widget child, + AsyncCallback? callback, + ButtonState buttonState, +); + /// A `builder` that wraps a button providing disabled, loading, success and /// error states while retaining almost full access to the original Button's /// API. This is useful for any long running operations and helps better @@ -46,12 +53,10 @@ import 'package:flutter/material.dart'; /// {@end-tool} /// class AsyncButtonBuilder extends StatefulWidget { - final Widget Function( - BuildContext context, - Widget child, - AsyncCallback? callback, - ButtonState buttonState, - ) builder; + /// This builder provides the widget's [BuildContext], the variable [child] + /// based on button state as well as the [callback] that should be passed to + /// the button and the current [ButtonState] + final AsyncButtonBuilderCallback builder; /// The child of the button. In the case of an [IconButton], this can be a an /// [Icon]. For a [TextButton], a [Text]. diff --git a/pubspec.lock b/pubspec.lock index a32ecb5..79fee27 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -28,14 +28,14 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.5.0-nullsafety.3" + version: "2.5.0" boolean_selector: dependency: transitive description: name: boolean_selector url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.3" + version: "2.1.0" build: dependency: transitive description: @@ -98,14 +98,14 @@ packages: name: characters url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.5" + version: "1.1.0" charcode: dependency: transitive description: name: charcode url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.3" + version: "1.2.0" checked_yaml: dependency: transitive description: @@ -126,7 +126,7 @@ packages: name: clock url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.3" + version: "1.1.0" code_builder: dependency: transitive description: @@ -140,7 +140,7 @@ packages: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.15.0-nullsafety.5" + version: "1.15.0" convert: dependency: transitive description: @@ -168,7 +168,7 @@ packages: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.3" + version: "1.2.0" file: dependency: transitive description: @@ -276,14 +276,14 @@ packages: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.10-nullsafety.3" + version: "0.12.10" meta: dependency: transitive description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.3.0-nullsafety.6" + version: "1.3.0" mime: dependency: transitive description: @@ -318,7 +318,7 @@ packages: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.0-nullsafety.3" + version: "1.8.0" pedantic: dependency: "direct dev" description: @@ -386,21 +386,21 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.0-nullsafety.4" + version: "1.8.0" stack_trace: dependency: transitive description: name: stack_trace url: "https://pub.dartlang.org" source: hosted - version: "1.10.0-nullsafety.6" + version: "1.10.0" stream_channel: dependency: transitive description: name: stream_channel url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.3" + version: "2.1.0" stream_transform: dependency: transitive description: @@ -414,21 +414,21 @@ packages: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.3" + version: "1.1.0" term_glyph: dependency: transitive description: name: term_glyph url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.3" + version: "1.2.0" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.19-nullsafety.6" + version: "0.2.19" timing: dependency: transitive description: @@ -442,14 +442,14 @@ packages: name: typed_data url: "https://pub.dartlang.org" source: hosted - version: "1.3.0-nullsafety.5" + version: "1.3.0" vector_math: dependency: transitive description: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.5" + version: "2.1.0" watcher: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index ef7c427..90db352 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_builder description: A builder to wrap around buttons that handles loading, disabled, error and succes states -version: 2.0.2-nullsafety.6 +version: 2.0.2-nullsafety.7 homepage: https://github.com/Nolence/async_button_builder environment: diff --git a/test/async_button_builder_test.dart b/test/async_button_builder_test.dart index 87c1f66..4c7b789 100644 --- a/test/async_button_builder_test.dart +++ b/test/async_button_builder_test.dart @@ -107,4 +107,45 @@ void main() { expect(find.text('click me'), findsOneWidget); }); + + // TODO: Make it work on dropdown buttons + // AsyncButtonBuilder( + // child: Icon(Icons.arrow_upward), + // onPressed: (newValue) async { + // final oldValue = dropdownValue; + + // setState(() { + // dropdownValue = newValue; + // }); + + // await Future.delayed(Duration(seconds: 1)); + + // try { + // if (Random().nextBool()) { + // throw 'yikes'; + // } + // } catch (error) { + // setState(() { + // dropdownValue = oldValue; + // }); + // } + // }, + // builder: (context, child, callback, _) { + // return DropdownButton( + // // icon: SizedBox( + // // height: 16.0, + // // width: 16.0, + // // child: CircularProgressIndicator(), + // // ), + // onChanged: callback, + // items: ['one', 'two', 'three'] + // .map((value) => DropdownMenuItem( + // child: Text(value), + // value: value, + // )) + // .toList(), + // value: dropdownValue, + // ); + // }, + // ), } From 34e7730ef6543251eaef273f1db4fb793d741892 Mon Sep 17 00:00:00 2001 From: Nolence Date: Fri, 12 Feb 2021 13:31:03 -0700 Subject: [PATCH 028/176] Weird version bump. My mistake. --- CHANGELOG.md | 3 +++ example/pubspec.lock | 2 +- pubspec.yaml | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8df38d2..8d77bdf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## [2.0.7-nullsafety.8] - 2021-02-12 +Republish so current nullsafe becomes main. My mistake + ## [2.0.2-nullsafety.7] - 2021-02-12 Added a typedef in place of inline type on function. Added doc to `builder` field diff --git a/example/pubspec.lock b/example/pubspec.lock index 41ee0d5..0c0bea8 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -14,7 +14,7 @@ packages: path: ".." relative: true source: path - version: "2.0.2-nullsafety.7" + version: "2.0.7-nullsafety.8" boolean_selector: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 90db352..2be7672 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_builder description: A builder to wrap around buttons that handles loading, disabled, error and succes states -version: 2.0.2-nullsafety.7 +version: 2.0.7-nullsafety.8 homepage: https://github.com/Nolence/async_button_builder environment: From 1de4f4b2e919ff2f60e22099cd14daf8db48c69b Mon Sep 17 00:00:00 2001 From: Nolence Date: Fri, 12 Feb 2021 17:36:16 -0700 Subject: [PATCH 029/176] Update version so it's above stable --- CHANGELOG.md | 3 +++ example/pubspec.lock | 2 +- pubspec.yaml | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d77bdf..b725d29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## [2.0.8-nullsafety.0] - 2021-02-12 +Trying to bump version again to go over stable + ## [2.0.7-nullsafety.8] - 2021-02-12 Republish so current nullsafe becomes main. My mistake diff --git a/example/pubspec.lock b/example/pubspec.lock index 0c0bea8..025dbac 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -14,7 +14,7 @@ packages: path: ".." relative: true source: path - version: "2.0.7-nullsafety.8" + version: "2.0.8-nullsafety.0" boolean_selector: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 2be7672..2dc5344 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_builder description: A builder to wrap around buttons that handles loading, disabled, error and succes states -version: 2.0.7-nullsafety.8 +version: 2.0.8-nullsafety.0 homepage: https://github.com/Nolence/async_button_builder environment: From 2aea6bf2db25b2303668aeba4f0a3777cd976851 Mon Sep 17 00:00:00 2001 From: Nolence Date: Tue, 23 Feb 2021 10:29:59 -0700 Subject: [PATCH 030/176] Version bump over stable --- CHANGELOG.md | 3 +++ example/pubspec.lock | 2 +- pubspec.yaml | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b725d29..2af1524 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## [2.0.9-nullsafety.0] - 2021-02-12 +Trying to bump version again to go over stable + ## [2.0.8-nullsafety.0] - 2021-02-12 Trying to bump version again to go over stable diff --git a/example/pubspec.lock b/example/pubspec.lock index 025dbac..0ad82b1 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -14,7 +14,7 @@ packages: path: ".." relative: true source: path - version: "2.0.8-nullsafety.0" + version: "2.0.9-nullsafety.0" boolean_selector: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 2dc5344..ccc9c29 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_builder description: A builder to wrap around buttons that handles loading, disabled, error and succes states -version: 2.0.8-nullsafety.0 +version: 2.0.9-nullsafety.0 homepage: https://github.com/Nolence/async_button_builder environment: From e9fc350290dec15f298cfcaed02d368162baed63 Mon Sep 17 00:00:00 2001 From: Nolence Date: Thu, 11 Mar 2021 09:07:50 -0700 Subject: [PATCH 031/176] Remove null safety prefix and add stricter types --- CHANGELOG.md | 3 +++ analysis_options.yaml | 5 ++++ example/pubspec.lock | 8 +++--- lib/src/async_button_builder.dart | 2 +- pubspec.lock | 41 +++++++---------------------- pubspec.yaml | 10 +++---- test/async_button_builder_test.dart | 14 +++++----- 7 files changed, 35 insertions(+), 48 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2af1524..eb2d784 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## [2.0.10] - 2021-02-12 +Remove null-safety prefix as it's now in stable + ## [2.0.9-nullsafety.0] - 2021-02-12 Trying to bump version again to go over stable diff --git a/analysis_options.yaml b/analysis_options.yaml index 108d105..b0045a1 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1 +1,6 @@ include: package:pedantic/analysis_options.yaml + +analyzer: + strong-mode: + implicit-casts: false + implicit-dynamic: false \ No newline at end of file diff --git a/example/pubspec.lock b/example/pubspec.lock index 0ad82b1..652ab17 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -14,7 +14,7 @@ packages: path: ".." relative: true source: path - version: "2.0.9-nullsafety.0" + version: "2.0.10" boolean_selector: dependency: transitive description: @@ -80,14 +80,14 @@ packages: name: freezed_annotation url: "https://pub.dartlang.org" source: hosted - version: "0.13.0-nullsafety.0" + version: "0.14.0" json_annotation: dependency: transitive description: name: json_annotation url: "https://pub.dartlang.org" source: hosted - version: "4.0.0-nullsafety.0" + version: "4.0.0" matcher: dependency: transitive description: @@ -127,7 +127,7 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.0" + version: "1.8.1" stack_trace: dependency: transitive description: diff --git a/lib/src/async_button_builder.dart b/lib/src/async_button_builder.dart index ca7f27e..15e9f49 100644 --- a/lib/src/async_button_builder.dart +++ b/lib/src/async_button_builder.dart @@ -341,12 +341,12 @@ class _AsyncButtonBuilderState extends State widget.animateSize ? AnimatedSize( vsync: this, - child: switcher, duration: widget.duration, reverseDuration: widget.reverseDuration, alignment: widget.sizeAlignment, clipBehavior: widget.sizeClipBehavior, curve: widget.sizeCurve, + child: switcher, ) : switcher, widget.disabled diff --git a/pubspec.lock b/pubspec.lock index 79fee27..606eeae 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -70,14 +70,14 @@ packages: name: build_runner url: "https://pub.dartlang.org" source: hosted - version: "1.10.13" + version: "1.11.5" build_runner_core: dependency: transitive description: name: build_runner_core url: "https://pub.dartlang.org" source: hosted - version: "6.1.6" + version: "6.1.10" built_collection: dependency: transitive description: @@ -175,7 +175,7 @@ packages: name: file url: "https://pub.dartlang.org" source: hosted - version: "5.2.1" + version: "6.1.0" fixnum: dependency: transitive description: @@ -199,21 +199,21 @@ packages: name: freezed url: "https://pub.dartlang.org" source: hosted - version: "0.13.0-nullsafety.2" + version: "0.14.0+1" freezed_annotation: dependency: "direct main" description: name: freezed_annotation url: "https://pub.dartlang.org" source: hosted - version: "0.13.0-nullsafety.0" + version: "0.14.0" glob: dependency: transitive description: name: glob url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "2.0.0" graphs: dependency: transitive description: @@ -235,13 +235,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.1.4" - intl: - dependency: transitive - description: - name: intl - url: "https://pub.dartlang.org" - source: hosted - version: "0.16.1" io: dependency: transitive description: @@ -262,7 +255,7 @@ packages: name: json_annotation url: "https://pub.dartlang.org" source: hosted - version: "4.0.0-nullsafety.0" + version: "4.0.0" logging: dependency: transitive description: @@ -291,20 +284,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.9.7" - node_interop: - dependency: transitive - description: - name: node_interop - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.1" - node_io: - dependency: transitive - description: - name: node_io - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" package_config: dependency: transitive description: @@ -325,7 +304,7 @@ packages: name: pedantic url: "https://pub.dartlang.org" source: hosted - version: "1.10.0-nullsafety.3" + version: "1.11.0" pool: dependency: transitive description: @@ -379,14 +358,14 @@ packages: name: source_gen url: "https://pub.dartlang.org" source: hosted - version: "0.9.10+1" + version: "0.9.10+3" source_span: dependency: transitive description: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.0" + version: "1.8.1" stack_trace: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index ccc9c29..c364c2e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_builder description: A builder to wrap around buttons that handles loading, disabled, error and succes states -version: 2.0.9-nullsafety.0 +version: 2.0.10 homepage: https://github.com/Nolence/async_button_builder environment: @@ -10,13 +10,13 @@ environment: dependencies: flutter: sdk: flutter - freezed_annotation: ^0.13.0-nullsafety.0 + freezed_annotation: ^0.14.0 dev_dependencies: flutter_test: sdk: flutter - build_runner: ^1.10.13 - freezed: ^0.13.0-nullsafety.0 - pedantic: ^1.10.0-nullsafety.3 + build_runner: ^1.11.5 + freezed: ^0.14.0+1 + pedantic: ^1.11.0 flutter: \ No newline at end of file diff --git a/test/async_button_builder_test.dart b/test/async_button_builder_test.dart index 4c7b789..13b9c60 100644 --- a/test/async_button_builder_test.dart +++ b/test/async_button_builder_test.dart @@ -6,13 +6,13 @@ void main() { testWidgets('displays child text', (WidgetTester tester) async { final textButton = MaterialApp( home: AsyncButtonBuilder( - child: Text('click me'), onPressed: () async { - await Future.delayed(Duration(seconds: 1)); + await Future.delayed(Duration(seconds: 1)); }, builder: (context, child, callback, state) { return TextButton(onPressed: callback, child: child); }, + child: Text('click me'), ), ); @@ -26,14 +26,14 @@ void main() { final textButton = MaterialApp( home: AsyncButtonBuilder( duration: duration, - child: Text('click me'), loadingWidget: Text('loading'), onPressed: () async { - await Future.delayed(Duration(seconds: 1)); + await Future.delayed(Duration(seconds: 1)); }, builder: (context, child, callback, state) { return TextButton(onPressed: callback, child: child); }, + child: Text('click me'), ), ); @@ -56,7 +56,6 @@ void main() { final textButton = MaterialApp( home: AsyncButtonBuilder( duration: duration, - child: Text('click me'), errorWidget: Text('error'), onPressed: () async { throw ArgumentError(); @@ -64,6 +63,7 @@ void main() { builder: (context, child, callback, state) { return TextButton(onPressed: callback, child: child); }, + child: Text('click me'), ), ); @@ -86,14 +86,14 @@ void main() { final textButton = MaterialApp( home: AsyncButtonBuilder( duration: duration, - child: Text('click me'), loadingWidget: Text('loading'), onPressed: () async { - await Future.delayed(Duration(seconds: 1)); + await Future.delayed(Duration(seconds: 1)); }, builder: (context, child, callback, state) { return TextButton(onPressed: callback, child: child); }, + child: Text('click me'), ), ); From 6c609756aead72d8da9269ff9787f5a85e1df5cd Mon Sep 17 00:00:00 2001 From: Nolence Date: Thu, 11 Mar 2021 09:23:18 -0700 Subject: [PATCH 032/176] Bumped version --- example/pubspec.lock | 2 +- pubspec.yaml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/example/pubspec.lock b/example/pubspec.lock index 652ab17..84eb7ed 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -14,7 +14,7 @@ packages: path: ".." relative: true source: path - version: "2.0.10" + version: "2.1.0" boolean_selector: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index c364c2e..1535604 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,10 +1,10 @@ name: async_button_builder description: A builder to wrap around buttons that handles loading, disabled, error and succes states -version: 2.0.10 +version: 2.1.0 homepage: https://github.com/Nolence/async_button_builder environment: - sdk: ">=2.12.0-0 <3.0.0" + sdk: '>=2.12.0-0 <3.0.0' flutter: ">=1.17.0" dependencies: From dae85cc9ea9448e9638e3650c35b8a147e016d34 Mon Sep 17 00:00:00 2001 From: Nolence Date: Wed, 14 Apr 2021 12:52:17 -0600 Subject: [PATCH 033/176] Remove key necessity --- CHANGELOG.md | 5 +- README.md | 8 +- example/lib/main.dart | 6 -- example/pubspec.lock | 2 +- lib/src/async_button_builder.dart | 22 ++++- lib/src/button_state/button_state.dart | 2 +- .../button_state/button_state.freezed.dart | 17 +++- pubspec.lock | 91 +++++++++---------- pubspec.yaml | 6 +- 9 files changed, 81 insertions(+), 78 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb2d784..44da1f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,7 @@ -## [2.0.10] - 2021-02-12 +## [2.1.1] - 2021-02-12 +ValueKeys are now no longer required in order to differentiate children + +## [2.1.0] - 2021-02-12 Remove null-safety prefix as it's now in stable ## [2.0.9-nullsafety.0] - 2021-02-12 diff --git a/README.md b/README.md index 723fda8..97075a5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # async_button_builder -A builder that adds loading, disabled, errored and completed states on top of buttons that perform asynchronous tasks. It can be used with most any button or even on top of a custom Material button. It includes fluid animation between states as well using `AnimatedSize` in combination with `AnimatedSwitcher` which gives possibility to define your own transitions. +A builder that adds loading, disabled, errored and completed states (with fluid animation between each) on top of buttons that perform asynchronous tasks. ## Getting Started @@ -81,10 +81,6 @@ AsyncButtonBuilder( ```dart AsyncButtonBuilder( child: Padding( - // Value keys are important as otherwise our custom transitions - // will have no way to differentiate between children. This is a - // Flutter framework requirement not a library one. - key: ValueKey('foo'), padding: const EdgeInsets.symmetric( horizontal: 16.0, vertical: 8.0, @@ -95,7 +91,6 @@ AsyncButtonBuilder( ), ), loadingWidget: Padding( - key: ValueKey('bar'), padding: const EdgeInsets.all(8.0), child: SizedBox( height: 16.0, @@ -106,7 +101,6 @@ AsyncButtonBuilder( ), ), successWidget: Padding( - key: ValueKey('foobar'), padding: const EdgeInsets.all(4.0), child: Icon( Icons.check, diff --git a/example/lib/main.dart b/example/lib/main.dart index 7734e57..9fe13d5 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -85,10 +85,6 @@ class MyHomePage extends StatelessWidget { const SizedBox(height: 6.0), AsyncButtonBuilder( child: Padding( - // Value keys are important as otherwise our custom transitions - // will have no way to differentiate between children. This is a - // Flutter framework requirement not a library one. - key: ValueKey('foo'), padding: const EdgeInsets.symmetric( horizontal: 16.0, vertical: 8.0, @@ -99,7 +95,6 @@ class MyHomePage extends StatelessWidget { ), ), loadingWidget: Padding( - key: ValueKey('bar'), padding: const EdgeInsets.all(8.0), child: SizedBox( height: 16.0, @@ -110,7 +105,6 @@ class MyHomePage extends StatelessWidget { ), ), successWidget: Padding( - key: ValueKey('foobar'), padding: const EdgeInsets.all(4.0), child: Icon( Icons.check, diff --git a/example/pubspec.lock b/example/pubspec.lock index 84eb7ed..ec3b00c 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -80,7 +80,7 @@ packages: name: freezed_annotation url: "https://pub.dartlang.org" source: hosted - version: "0.14.0" + version: "0.14.1" json_annotation: dependency: transitive description: diff --git a/lib/src/async_button_builder.dart b/lib/src/async_button_builder.dart index 15e9f49..802dfb0 100644 --- a/lib/src/async_button_builder.dart +++ b/lib/src/async_button_builder.dart @@ -271,7 +271,7 @@ class _AsyncButtonBuilderState extends State Widget build(BuildContext context) { final theme = Theme.of(context); final loadingWidget = widget.loadingWidget ?? - const SizedBox( + SizedBox( height: 16.0, width: 16.0, child: CircularProgressIndicator(), @@ -326,10 +326,22 @@ class _AsyncButtonBuilderState extends State error: () => widget.errorTransitionBuilder, ), child: buttonState.when( - idle: () => widget.child, - loading: () => loadingWidget, - success: () => successWidget, - error: () => errorWidget, + idle: () => KeyedSubtree( + key: const ValueKey('__idle__'), + child: widget.child, + ), + loading: () => KeyedSubtree( + key: const ValueKey('__loading__'), + child: loadingWidget, + ), + success: () => KeyedSubtree( + key: const ValueKey('__success__'), + child: successWidget, + ), + error: () => KeyedSubtree( + key: const ValueKey('__error__'), + child: errorWidget, + ), ), ); diff --git a/lib/src/button_state/button_state.dart b/lib/src/button_state/button_state.dart index 6686549..c2a0a1a 100644 --- a/lib/src/button_state/button_state.dart +++ b/lib/src/button_state/button_state.dart @@ -31,7 +31,7 @@ part 'button_state.freezed.dart'; /// ``` /// {@end-tool} @freezed -abstract class ButtonState with _$ButtonState { +class ButtonState with _$ButtonState { const factory ButtonState.idle() = Idle; const factory ButtonState.loading() = Loading; const factory ButtonState.success() = Success; diff --git a/lib/src/button_state/button_state.freezed.dart b/lib/src/button_state/button_state.freezed.dart index 5efc4c4..148fcd6 100644 --- a/lib/src/button_state/button_state.freezed.dart +++ b/lib/src/button_state/button_state.freezed.dart @@ -1,5 +1,5 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides part of 'button_state.dart'; @@ -9,6 +9,9 @@ part of 'button_state.dart'; T _$identity(T value) => value; +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + /// @nodoc class _$ButtonStateTearOff { const _$ButtonStateTearOff(); @@ -41,7 +44,8 @@ mixin _$ButtonState { required TResult Function() loading, required TResult Function() success, required TResult Function() error, - }); + }) => + throw _privateConstructorUsedError; @optionalTypeArgs TResult maybeWhen({ TResult Function()? idle, @@ -49,14 +53,16 @@ mixin _$ButtonState { TResult Function()? success, TResult Function()? error, required TResult orElse(), - }); + }) => + throw _privateConstructorUsedError; @optionalTypeArgs TResult map({ required TResult Function(Idle value) idle, required TResult Function(Loading value) loading, required TResult Function(Success value) success, required TResult Function(Error value) error, - }); + }) => + throw _privateConstructorUsedError; @optionalTypeArgs TResult maybeMap({ TResult Function(Idle value)? idle, @@ -64,7 +70,8 @@ mixin _$ButtonState { TResult Function(Success value)? success, TResult Function(Error value)? error, required TResult orElse(), - }); + }) => + throw _privateConstructorUsedError; } /// @nodoc diff --git a/pubspec.lock b/pubspec.lock index 606eeae..301bf12 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,21 +7,21 @@ packages: name: _fe_analyzer_shared url: "https://pub.dartlang.org" source: hosted - version: "14.0.0" + version: "20.0.0" analyzer: dependency: transitive description: name: analyzer url: "https://pub.dartlang.org" source: hosted - version: "0.41.2" + version: "1.4.0" args: dependency: transitive description: name: args url: "https://pub.dartlang.org" source: hosted - version: "1.6.0" + version: "2.0.0" async: dependency: transitive description: @@ -42,56 +42,56 @@ packages: name: build url: "https://pub.dartlang.org" source: hosted - version: "1.6.1" + version: "2.0.0" build_config: dependency: transitive description: name: build_config url: "https://pub.dartlang.org" source: hosted - version: "0.4.5" + version: "0.4.7" build_daemon: dependency: transitive description: name: build_daemon url: "https://pub.dartlang.org" source: hosted - version: "2.1.6" + version: "2.1.10" build_resolvers: dependency: transitive description: name: build_resolvers url: "https://pub.dartlang.org" source: hosted - version: "1.5.2" + version: "2.0.0" build_runner: dependency: "direct dev" description: name: build_runner url: "https://pub.dartlang.org" source: hosted - version: "1.11.5" + version: "1.12.2" build_runner_core: dependency: transitive description: name: build_runner_core url: "https://pub.dartlang.org" source: hosted - version: "6.1.10" + version: "6.1.12" built_collection: dependency: transitive description: name: built_collection url: "https://pub.dartlang.org" source: hosted - version: "4.3.2" + version: "5.0.0" built_value: dependency: transitive description: name: built_value url: "https://pub.dartlang.org" source: hosted - version: "7.1.0" + version: "8.0.4" characters: dependency: transitive description: @@ -112,14 +112,14 @@ packages: name: checked_yaml url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "2.0.1" cli_util: dependency: transitive description: name: cli_util url: "https://pub.dartlang.org" source: hosted - version: "0.2.0" + version: "0.3.0" clock: dependency: transitive description: @@ -133,7 +133,7 @@ packages: name: code_builder url: "https://pub.dartlang.org" source: hosted - version: "3.6.0" + version: "3.7.0" collection: dependency: transitive description: @@ -147,21 +147,21 @@ packages: name: convert url: "https://pub.dartlang.org" source: hosted - version: "2.1.1" + version: "3.0.0" crypto: dependency: transitive description: name: crypto url: "https://pub.dartlang.org" source: hosted - version: "2.1.5" + version: "3.0.1" dart_style: dependency: transitive description: name: dart_style url: "https://pub.dartlang.org" source: hosted - version: "1.3.11" + version: "2.0.0" fake_async: dependency: transitive description: @@ -182,7 +182,7 @@ packages: name: fixnum url: "https://pub.dartlang.org" source: hosted - version: "0.10.11" + version: "1.0.0" flutter: dependency: "direct main" description: flutter @@ -199,70 +199,70 @@ packages: name: freezed url: "https://pub.dartlang.org" source: hosted - version: "0.14.0+1" + version: "0.14.1+2" freezed_annotation: dependency: "direct main" description: name: freezed_annotation url: "https://pub.dartlang.org" source: hosted - version: "0.14.0" + version: "0.14.1" glob: dependency: transitive description: name: glob url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.0.1" graphs: dependency: transitive description: name: graphs url: "https://pub.dartlang.org" source: hosted - version: "0.2.0" + version: "1.0.0" http_multi_server: dependency: transitive description: name: http_multi_server url: "https://pub.dartlang.org" source: hosted - version: "2.2.0" + version: "3.0.1" http_parser: dependency: transitive description: name: http_parser url: "https://pub.dartlang.org" source: hosted - version: "3.1.4" + version: "4.0.0" io: dependency: transitive description: name: io url: "https://pub.dartlang.org" source: hosted - version: "0.3.4" + version: "1.0.0" js: dependency: transitive description: name: js url: "https://pub.dartlang.org" source: hosted - version: "0.6.2" + version: "0.6.3" json_annotation: dependency: transitive description: name: json_annotation url: "https://pub.dartlang.org" source: hosted - version: "4.0.0" + version: "4.0.1" logging: dependency: transitive description: name: logging url: "https://pub.dartlang.org" source: hosted - version: "0.11.4" + version: "1.0.1" matcher: dependency: transitive description: @@ -283,14 +283,14 @@ packages: name: mime url: "https://pub.dartlang.org" source: hosted - version: "0.9.7" + version: "1.0.0" package_config: dependency: transitive description: name: package_config url: "https://pub.dartlang.org" source: hosted - version: "1.9.3" + version: "2.0.0" path: dependency: transitive description: @@ -311,42 +311,35 @@ packages: name: pool url: "https://pub.dartlang.org" source: hosted - version: "1.4.0" + version: "1.5.0" pub_semver: dependency: transitive description: name: pub_semver url: "https://pub.dartlang.org" source: hosted - version: "1.4.4" + version: "2.0.0" pubspec_parse: dependency: transitive description: name: pubspec_parse url: "https://pub.dartlang.org" source: hosted - version: "0.1.7" - quiver: - dependency: transitive - description: - name: quiver - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.5" + version: "1.0.0" shelf: dependency: transitive description: name: shelf url: "https://pub.dartlang.org" source: hosted - version: "0.7.9" + version: "1.1.0" shelf_web_socket: dependency: transitive description: name: shelf_web_socket url: "https://pub.dartlang.org" source: hosted - version: "0.2.3" + version: "1.0.1" sky_engine: dependency: transitive description: flutter @@ -358,7 +351,7 @@ packages: name: source_gen url: "https://pub.dartlang.org" source: hosted - version: "0.9.10+3" + version: "1.0.0" source_span: dependency: transitive description: @@ -386,7 +379,7 @@ packages: name: stream_transform url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "2.0.0" string_scanner: dependency: transitive description: @@ -414,7 +407,7 @@ packages: name: timing url: "https://pub.dartlang.org" source: hosted - version: "0.1.1+3" + version: "1.0.0" typed_data: dependency: transitive description: @@ -435,21 +428,21 @@ packages: name: watcher url: "https://pub.dartlang.org" source: hosted - version: "0.9.7+15" + version: "1.0.0" web_socket_channel: dependency: transitive description: name: web_socket_channel url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "2.0.0" yaml: dependency: transitive description: name: yaml url: "https://pub.dartlang.org" source: hosted - version: "2.2.1" + version: "3.1.0" sdks: - dart: ">=2.12.0-0.0.dev <3.0.0" + dart: ">=2.12.0 <3.0.0" flutter: ">=1.17.0" diff --git a/pubspec.yaml b/pubspec.yaml index 1535604..01c59e2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -10,13 +10,13 @@ environment: dependencies: flutter: sdk: flutter - freezed_annotation: ^0.14.0 + freezed_annotation: ^0.14.1 dev_dependencies: flutter_test: sdk: flutter - build_runner: ^1.11.5 - freezed: ^0.14.0+1 + build_runner: ^1.12.2 + freezed: ^0.14.1 pedantic: ^1.11.0 flutter: \ No newline at end of file From 9902715d5565f00ae5e3cebff88f5537ac326588 Mon Sep 17 00:00:00 2001 From: Nolence Date: Wed, 14 Apr 2021 12:52:39 -0600 Subject: [PATCH 034/176] bump version --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 01c59e2..e225f55 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_builder description: A builder to wrap around buttons that handles loading, disabled, error and succes states -version: 2.1.0 +version: 2.1.1 homepage: https://github.com/Nolence/async_button_builder environment: From cd9a629c8e9aab172abbeff6c5f025bc2ca9512f Mon Sep 17 00:00:00 2001 From: Nolence Date: Wed, 14 Apr 2021 12:54:34 -0600 Subject: [PATCH 035/176] Removed prerelease version of flutter sdk --- example/pubspec.lock | 4 ++-- pubspec.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/example/pubspec.lock b/example/pubspec.lock index ec3b00c..af90baa 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -14,7 +14,7 @@ packages: path: ".." relative: true source: path - version: "2.1.0" + version: "2.1.1" boolean_selector: dependency: transitive description: @@ -178,5 +178,5 @@ packages: source: hosted version: "2.1.0" sdks: - dart: ">=2.12.0-0.0.dev <3.0.0" + dart: ">=2.12.0 <3.0.0" flutter: ">=1.17.0" diff --git a/pubspec.yaml b/pubspec.yaml index e225f55..47f05c9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,7 +4,7 @@ version: 2.1.1 homepage: https://github.com/Nolence/async_button_builder environment: - sdk: '>=2.12.0-0 <3.0.0' + sdk: '>=2.12.0 <3.0.0' flutter: ">=1.17.0" dependencies: From 947a3401b13475e232d108079de220143f746445 Mon Sep 17 00:00:00 2001 From: Nolence Date: Wed, 14 Apr 2021 13:24:29 -0600 Subject: [PATCH 036/176] add information about timeuts --- CHANGELOG.md | 5 ++++- README.md | 1 + example/lib/main.dart | 16 ++++++++++++++++ example/pubspec.lock | 2 +- pubspec.yaml | 2 +- 5 files changed, 23 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 44da1f9..9f9b2a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,7 @@ -## [2.1.1] - 2021-02-12 +## [2.1.1+1] - 2021-04-14 +Add documentation on how to handle timeouts + +## [2.1.1] - 2021-04-14 ValueKeys are now no longer required in order to differentiate children ## [2.1.0] - 2021-02-12 diff --git a/README.md b/README.md index 97075a5..74fefd9 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,7 @@ AsyncButtonBuilder( onPressed: () async { await Future.delayed(Duration(seconds: 1)); + // See the examples file for a way to handle timeouts throw 'shucks'; }, builder: (context, child, callback, buttonState) { diff --git a/example/lib/main.dart b/example/lib/main.dart index 9fe13d5..27b04ce 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -61,6 +61,22 @@ class MyHomePage extends StatelessWidget { await Future.delayed(Duration(seconds: 1)); throw 'shucks'; + + // If you want to add a timeout, use something similar to + // + // try { + // await Future.delayed(Duration(seconds: 1)) + // .timeout(Duration(milliseconds: 500)); + // } on TimeoutException catch (_) { + // // Show a popup or something + // rethrow; + // } on Exception catch (_) { + // // Show a dialog or something + // rethrow; + // } + // + // We rethrow so that async_button_builder can handle the error + // state }, builder: (context, child, callback, buttonState) { final buttonColor = buttonState.when( diff --git a/example/pubspec.lock b/example/pubspec.lock index af90baa..eacef8b 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -14,7 +14,7 @@ packages: path: ".." relative: true source: path - version: "2.1.1" + version: "2.1.1+1" boolean_selector: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 47f05c9..2c04bc5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_builder description: A builder to wrap around buttons that handles loading, disabled, error and succes states -version: 2.1.1 +version: 2.1.1+1 homepage: https://github.com/Nolence/async_button_builder environment: From c7521b9da635e61627f80bd79744deaa26331b8c Mon Sep 17 00:00:00 2001 From: Nolence Date: Wed, 5 May 2021 13:36:37 -0600 Subject: [PATCH 037/176] Added null onpressed behaviour --- CHANGELOG.md | 3 + lib/src/async_button_builder.dart | 139 +++++++++++++++--------------- pubspec.yaml | 2 +- 3 files changed, 75 insertions(+), 69 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f9b2a3..890d992 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## [2.1.1+2] - 2021-04-14 +Makes onpressed nullable similar to other button's behaviour + ## [2.1.1+1] - 2021-04-14 Add documentation on how to handle timeouts diff --git a/lib/src/async_button_builder.dart b/lib/src/async_button_builder.dart index 802dfb0..0570e17 100644 --- a/lib/src/async_button_builder.dart +++ b/lib/src/async_button_builder.dart @@ -79,7 +79,7 @@ class AsyncButtonBuilder extends StatefulWidget { /// A callback that runs the async task. This is wrapped in order to begin /// the button's internal `isLoading` before and after the operation /// completes. - final AsyncCallback onPressed; + final AsyncCallback? onPressed; /// This is used to manually drive the state of the loading button thus /// initiating the corresponding animation and showing the correct button @@ -270,6 +270,7 @@ class _AsyncButtonBuilderState extends State @override Widget build(BuildContext context) { final theme = Theme.of(context); + final onPressed = widget.onPressed; final loadingWidget = widget.loadingWidget ?? SizedBox( height: 16.0, @@ -363,74 +364,76 @@ class _AsyncButtonBuilderState extends State : switcher, widget.disabled ? null - : buttonState.maybeWhen( - idle: () => () async { - // I might not want to set buttonState if we're being - // driven by widget.buttonState... - setState(() { - buttonState = ButtonState.loading(); - }); - - timer?.cancel(); - - try { - await widget.onPressed(); - - if (mounted) { - if (widget.showSuccess) { - setState(() { - buttonState = ButtonState.success(); - }); - - timer = Timer( - widget.successDuration, - () { - timer?.cancel(); - - if (mounted) { - setState(() { - buttonState = ButtonState.idle(); - }); - } - }, - ); - } else { - setState(() { - buttonState = ButtonState.idle(); - }); + : onPressed == null + ? null + : buttonState.maybeWhen( + idle: () => () async { + // I might not want to set buttonState if we're being + // driven by widget.buttonState... + setState(() { + buttonState = ButtonState.loading(); + }); + + timer?.cancel(); + + try { + await onPressed.call(); + + if (mounted) { + if (widget.showSuccess) { + setState(() { + buttonState = ButtonState.success(); + }); + + timer = Timer( + widget.successDuration, + () { + timer?.cancel(); + + if (mounted) { + setState(() { + buttonState = ButtonState.idle(); + }); + } + }, + ); + } else { + setState(() { + buttonState = ButtonState.idle(); + }); + } + } + } catch (error) { + if (mounted) { + if (widget.showError) { + setState(() { + buttonState = ButtonState.error(); + }); + + timer = Timer( + widget.errorDuration, + () { + timer?.cancel(); + + if (mounted) { + setState(() { + buttonState = ButtonState.idle(); + }); + } + }, + ); + } else { + setState(() { + buttonState = ButtonState.idle(); + }); + } + } + + rethrow; } - } - } catch (error) { - if (mounted) { - if (widget.showError) { - setState(() { - buttonState = ButtonState.error(); - }); - - timer = Timer( - widget.errorDuration, - () { - timer?.cancel(); - - if (mounted) { - setState(() { - buttonState = ButtonState.idle(); - }); - } - }, - ); - } else { - setState(() { - buttonState = ButtonState.idle(); - }); - } - } - - rethrow; - } - }, - orElse: () => null, - ), + }, + orElse: () => null, + ), buttonState, ); } diff --git a/pubspec.yaml b/pubspec.yaml index 2c04bc5..29cf813 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_builder description: A builder to wrap around buttons that handles loading, disabled, error and succes states -version: 2.1.1+1 +version: 2.1.1+2 homepage: https://github.com/Nolence/async_button_builder environment: From 6770aa887670d3e8283e1320a611cf187f12c6af Mon Sep 17 00:00:00 2001 From: Nolence Date: Wed, 5 May 2021 13:38:18 -0600 Subject: [PATCH 038/176] Updated dependencies --- example/pubspec.lock | 4 ++-- pubspec.lock | 41 ++++++++++++++++++++++++----------------- pubspec.yaml | 4 ++-- 3 files changed, 28 insertions(+), 21 deletions(-) diff --git a/example/pubspec.lock b/example/pubspec.lock index eacef8b..3f624c8 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -14,7 +14,7 @@ packages: path: ".." relative: true source: path - version: "2.1.1+1" + version: "2.1.1+2" boolean_selector: dependency: transitive description: @@ -162,7 +162,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.19" + version: "0.3.0" typed_data: dependency: transitive description: diff --git a/pubspec.lock b/pubspec.lock index 301bf12..c4d6655 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,21 +7,21 @@ packages: name: _fe_analyzer_shared url: "https://pub.dartlang.org" source: hosted - version: "20.0.0" + version: "21.0.0" analyzer: dependency: transitive description: name: analyzer url: "https://pub.dartlang.org" source: hosted - version: "1.4.0" + version: "1.5.0" args: dependency: transitive description: name: args url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.1.0" async: dependency: transitive description: @@ -42,42 +42,42 @@ packages: name: build url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.0.1" build_config: dependency: transitive description: name: build_config url: "https://pub.dartlang.org" source: hosted - version: "0.4.7" + version: "1.0.0" build_daemon: dependency: transitive description: name: build_daemon url: "https://pub.dartlang.org" source: hosted - version: "2.1.10" + version: "3.0.0" build_resolvers: dependency: transitive description: name: build_resolvers url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.0.1" build_runner: dependency: "direct dev" description: name: build_runner url: "https://pub.dartlang.org" source: hosted - version: "1.12.2" + version: "2.0.2" build_runner_core: dependency: transitive description: name: build_runner_core url: "https://pub.dartlang.org" source: hosted - version: "6.1.12" + version: "7.0.0" built_collection: dependency: transitive description: @@ -91,7 +91,7 @@ packages: name: built_value url: "https://pub.dartlang.org" source: hosted - version: "8.0.4" + version: "8.0.5" characters: dependency: transitive description: @@ -133,7 +133,7 @@ packages: name: code_builder url: "https://pub.dartlang.org" source: hosted - version: "3.7.0" + version: "4.0.0" collection: dependency: transitive description: @@ -161,7 +161,7 @@ packages: name: dart_style url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.0.1" fake_async: dependency: transitive description: @@ -199,7 +199,7 @@ packages: name: freezed url: "https://pub.dartlang.org" source: hosted - version: "0.14.1+2" + version: "0.14.1+3" freezed_annotation: dependency: "direct main" description: @@ -207,6 +207,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.14.1" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" glob: dependency: transitive description: @@ -220,7 +227,7 @@ packages: name: graphs url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "2.0.0" http_multi_server: dependency: transitive description: @@ -332,7 +339,7 @@ packages: name: shelf url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.1.1" shelf_web_socket: dependency: transitive description: @@ -400,7 +407,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.19" + version: "0.3.0" timing: dependency: transitive description: @@ -435,7 +442,7 @@ packages: name: web_socket_channel url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.1.0" yaml: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 29cf813..a438cdd 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,8 +15,8 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - build_runner: ^1.12.2 - freezed: ^0.14.1 + build_runner: ^2.0.2 + freezed: ^0.14.1+3 pedantic: ^1.11.0 flutter: \ No newline at end of file From e7a79b0dad169243cd576ad2566f270f379fbcfe Mon Sep 17 00:00:00 2001 From: Nolence Date: Mon, 24 May 2021 11:58:48 -0600 Subject: [PATCH 039/176] users completers for better error handling --- CHANGELOG.md | 3 + example/pubspec.lock | 8 +-- lib/src/async_button_builder.dart | 56 +++++++++---------- .../button_state/button_state.freezed.dart | 4 ++ pubspec.lock | 8 +-- pubspec.yaml | 8 +-- 6 files changed, 45 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 890d992..fe96437 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## [2.1.2] - 2021-05-24 +Errors from onpressed will throw with orignal call stack + ## [2.1.1+2] - 2021-04-14 Makes onpressed nullable similar to other button's behaviour diff --git a/example/pubspec.lock b/example/pubspec.lock index 3f624c8..767ebc9 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -7,14 +7,14 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.5.0" + version: "2.6.1" async_button_builder: dependency: "direct main" description: path: ".." relative: true source: path - version: "2.1.1+2" + version: "2.1.2" boolean_selector: dependency: transitive description: @@ -80,14 +80,14 @@ packages: name: freezed_annotation url: "https://pub.dartlang.org" source: hosted - version: "0.14.1" + version: "0.14.2" json_annotation: dependency: transitive description: name: json_annotation url: "https://pub.dartlang.org" source: hosted - version: "4.0.0" + version: "4.0.1" matcher: dependency: transitive description: diff --git a/lib/src/async_button_builder.dart b/lib/src/async_button_builder.dart index 0570e17..a662e9e 100644 --- a/lib/src/async_button_builder.dart +++ b/lib/src/async_button_builder.dart @@ -367,7 +367,8 @@ class _AsyncButtonBuilderState extends State : onPressed == null ? null : buttonState.maybeWhen( - idle: () => () async { + idle: () => () { + final completer = Completer(); // I might not want to set buttonState if we're being // driven by widget.buttonState... setState(() { @@ -376,8 +377,8 @@ class _AsyncButtonBuilderState extends State timer?.cancel(); - try { - await onPressed.call(); + onPressed.call().then((_) { + completer.complete(); if (mounted) { if (widget.showSuccess) { @@ -385,56 +386,51 @@ class _AsyncButtonBuilderState extends State buttonState = ButtonState.success(); }); - timer = Timer( - widget.successDuration, - () { - timer?.cancel(); - - if (mounted) { - setState(() { - buttonState = ButtonState.idle(); - }); - } - }, - ); + setTimer(widget.successDuration); } else { setState(() { buttonState = ButtonState.idle(); }); } } - } catch (error) { + }).catchError((Object error, StackTrace stackTrace) { + completer.completeError(error, stackTrace); + if (mounted) { if (widget.showError) { setState(() { buttonState = ButtonState.error(); }); - timer = Timer( - widget.errorDuration, - () { - timer?.cancel(); - - if (mounted) { - setState(() { - buttonState = ButtonState.idle(); - }); - } - }, - ); + setTimer(widget.errorDuration); } else { setState(() { buttonState = ButtonState.idle(); }); } } + }); - rethrow; - } + return completer.future; }, orElse: () => null, ), buttonState, ); } + + void setTimer(Duration duration) { + timer = Timer( + widget.errorDuration, + () { + timer?.cancel(); + + if (mounted) { + setState(() { + buttonState = ButtonState.idle(); + }); + } + }, + ); + } } diff --git a/lib/src/button_state/button_state.freezed.dart b/lib/src/button_state/button_state.freezed.dart index 148fcd6..b200140 100644 --- a/lib/src/button_state/button_state.freezed.dart +++ b/lib/src/button_state/button_state.freezed.dart @@ -107,6 +107,7 @@ class _$IdleCopyWithImpl<$Res> extends _$ButtonStateCopyWithImpl<$Res> } /// @nodoc + class _$Idle implements Idle { const _$Idle(); @@ -197,6 +198,7 @@ class _$LoadingCopyWithImpl<$Res> extends _$ButtonStateCopyWithImpl<$Res> } /// @nodoc + class _$Loading implements Loading { const _$Loading(); @@ -287,6 +289,7 @@ class _$SuccessCopyWithImpl<$Res> extends _$ButtonStateCopyWithImpl<$Res> } /// @nodoc + class _$Success implements Success { const _$Success(); @@ -377,6 +380,7 @@ class _$ErrorCopyWithImpl<$Res> extends _$ButtonStateCopyWithImpl<$Res> } /// @nodoc + class _$Error implements Error { const _$Error(); diff --git a/pubspec.lock b/pubspec.lock index c4d6655..d18c9ba 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -28,7 +28,7 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.5.0" + version: "2.6.1" boolean_selector: dependency: transitive description: @@ -70,7 +70,7 @@ packages: name: build_runner url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "2.0.3" build_runner_core: dependency: transitive description: @@ -199,14 +199,14 @@ packages: name: freezed url: "https://pub.dartlang.org" source: hosted - version: "0.14.1+3" + version: "0.14.2" freezed_annotation: dependency: "direct main" description: name: freezed_annotation url: "https://pub.dartlang.org" source: hosted - version: "0.14.1" + version: "0.14.2" frontend_server_client: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index a438cdd..70db0cb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_builder description: A builder to wrap around buttons that handles loading, disabled, error and succes states -version: 2.1.1+2 +version: 2.1.2 homepage: https://github.com/Nolence/async_button_builder environment: @@ -10,13 +10,13 @@ environment: dependencies: flutter: sdk: flutter - freezed_annotation: ^0.14.1 + freezed_annotation: ^0.14.2 dev_dependencies: flutter_test: sdk: flutter - build_runner: ^2.0.2 - freezed: ^0.14.1+3 + build_runner: ^2.0.3 + freezed: ^0.14.2 pedantic: ^1.11.0 flutter: \ No newline at end of file From f8057797e6d7c396b98267289098ac22dd29dc99 Mon Sep 17 00:00:00 2001 From: Nolence Date: Sat, 12 Jun 2021 11:31:35 -0600 Subject: [PATCH 040/176] analysis errors --- .github/workflows/dart.yaml | 1 - CHANGELOG.md | 3 +++ example/pubspec.lock | 2 +- lib/src/async_button_builder.dart | 3 +-- pubspec.yaml | 2 +- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/dart.yaml b/.github/workflows/dart.yaml index f4086c2..7b65877 100644 --- a/.github/workflows/dart.yaml +++ b/.github/workflows/dart.yaml @@ -19,7 +19,6 @@ jobs: steps: - uses: actions/checkout@v2 - - uses: subosito/flutter-action@v1 with: channel: ${{ matrix.channel }} diff --git a/CHANGELOG.md b/CHANGELOG.md index fe96437..115cae8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## [2.1.2+1] - 2021-06-12 +Fixes analysis errors so I stop getting annoying emails + ## [2.1.2] - 2021-05-24 Errors from onpressed will throw with orignal call stack diff --git a/example/pubspec.lock b/example/pubspec.lock index 767ebc9..778a91b 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -14,7 +14,7 @@ packages: path: ".." relative: true source: path - version: "2.1.2" + version: "2.1.2+1" boolean_selector: dependency: transitive description: diff --git a/lib/src/async_button_builder.dart b/lib/src/async_button_builder.dart index a662e9e..ffa73fe 100644 --- a/lib/src/async_button_builder.dart +++ b/lib/src/async_button_builder.dart @@ -280,7 +280,7 @@ class _AsyncButtonBuilderState extends State var successWidget = widget.successWidget ?? Icon( Icons.check, - color: theme.accentColor, + color: theme.colorScheme.secondary, ); var errorWidget = widget.errorWidget ?? Icon( @@ -353,7 +353,6 @@ class _AsyncButtonBuilderState extends State // to figure out how to reproduce the exact behaviour of AnimatedSize widget.animateSize ? AnimatedSize( - vsync: this, duration: widget.duration, reverseDuration: widget.reverseDuration, alignment: widget.sizeAlignment, diff --git a/pubspec.yaml b/pubspec.yaml index 70db0cb..92264eb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_builder description: A builder to wrap around buttons that handles loading, disabled, error and succes states -version: 2.1.2 +version: 2.1.2+1 homepage: https://github.com/Nolence/async_button_builder environment: From 1a9f08cf5d29f261170cb295067cd13350473a5d Mon Sep 17 00:00:00 2001 From: Nolence Date: Fri, 18 Jun 2021 09:51:03 -0600 Subject: [PATCH 041/176] Changed workflow and build against stable --- .github/workflows/dart.yaml | 5 +++-- .vscode/launch.json | 32 +++++++++++++++++++++++++++ CHANGELOG.md | 3 +++ analysis_options.yaml | 2 +- lib/src/async_button_builder.dart | 15 +++++++------ pubspec.lock | 16 +++++++++++++- pubspec.yaml | 2 +- test/async_button_builder_test.dart | 34 ++++++++++++++--------------- 8 files changed, 80 insertions(+), 29 deletions(-) create mode 100644 .vscode/launch.json diff --git a/.github/workflows/dart.yaml b/.github/workflows/dart.yaml index 7b65877..1c8d8da 100644 --- a/.github/workflows/dart.yaml +++ b/.github/workflows/dart.yaml @@ -14,8 +14,9 @@ jobs: strategy: matrix: channel: - - dev - # - stable + # Dev currently adds a breaking change on AnimatedContainer - so no + # - dev + - stable steps: - uses: actions/checkout@v2 diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..bf78b5a --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,32 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "async_button_builder", + "request": "launch", + "type": "dart", + }, + { + "name": "async_button_builder (profile mode)", + "request": "launch", + "type": "dart", + "flutterMode": "profile" + }, + { + "name": "example", + "cwd": "example", + "request": "launch", + "type": "dart" + }, + { + "name": "example (profile mode)", + "cwd": "example", + "request": "launch", + "type": "dart", + "flutterMode": "profile" + } + ] +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 115cae8..3e91c0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## [2.1.3] - 2021-06-18 +Tests and builds against stable. flutter_lints now used in place of pedantic + ## [2.1.2+1] - 2021-06-12 Fixes analysis errors so I stop getting annoying emails diff --git a/analysis_options.yaml b/analysis_options.yaml index b0045a1..0ffcdb2 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,4 +1,4 @@ -include: package:pedantic/analysis_options.yaml +include: package:flutter_lints/flutter.yaml analyzer: strong-mode: diff --git a/lib/src/async_button_builder.dart b/lib/src/async_button_builder.dart index ffa73fe..6ada9ac 100644 --- a/lib/src/async_button_builder.dart +++ b/lib/src/async_button_builder.dart @@ -272,7 +272,7 @@ class _AsyncButtonBuilderState extends State final theme = Theme.of(context); final onPressed = widget.onPressed; final loadingWidget = widget.loadingWidget ?? - SizedBox( + const SizedBox( height: 16.0, width: 16.0, child: CircularProgressIndicator(), @@ -353,6 +353,7 @@ class _AsyncButtonBuilderState extends State // to figure out how to reproduce the exact behaviour of AnimatedSize widget.animateSize ? AnimatedSize( + vsync: this, duration: widget.duration, reverseDuration: widget.reverseDuration, alignment: widget.sizeAlignment, @@ -371,7 +372,7 @@ class _AsyncButtonBuilderState extends State // I might not want to set buttonState if we're being // driven by widget.buttonState... setState(() { - buttonState = ButtonState.loading(); + buttonState = const ButtonState.loading(); }); timer?.cancel(); @@ -382,13 +383,13 @@ class _AsyncButtonBuilderState extends State if (mounted) { if (widget.showSuccess) { setState(() { - buttonState = ButtonState.success(); + buttonState = const ButtonState.success(); }); setTimer(widget.successDuration); } else { setState(() { - buttonState = ButtonState.idle(); + buttonState = const ButtonState.idle(); }); } } @@ -398,13 +399,13 @@ class _AsyncButtonBuilderState extends State if (mounted) { if (widget.showError) { setState(() { - buttonState = ButtonState.error(); + buttonState = const ButtonState.error(); }); setTimer(widget.errorDuration); } else { setState(() { - buttonState = ButtonState.idle(); + buttonState = const ButtonState.idle(); }); } } @@ -426,7 +427,7 @@ class _AsyncButtonBuilderState extends State if (mounted) { setState(() { - buttonState = ButtonState.idle(); + buttonState = const ButtonState.idle(); }); } }, diff --git a/pubspec.lock b/pubspec.lock index d18c9ba..1c27c7a 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -188,6 +188,13 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.3" flutter_test: dependency: "direct dev" description: flutter @@ -263,6 +270,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "4.0.1" + lints: + dependency: transitive + description: + name: lints + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" logging: dependency: transitive description: @@ -306,7 +320,7 @@ packages: source: hosted version: "1.8.0" pedantic: - dependency: "direct dev" + dependency: transitive description: name: pedantic url: "https://pub.dartlang.org" diff --git a/pubspec.yaml b/pubspec.yaml index 92264eb..20816af 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,6 +17,6 @@ dev_dependencies: sdk: flutter build_runner: ^2.0.3 freezed: ^0.14.2 - pedantic: ^1.11.0 + flutter_lints: flutter: \ No newline at end of file diff --git a/test/async_button_builder_test.dart b/test/async_button_builder_test.dart index 13b9c60..61a3968 100644 --- a/test/async_button_builder_test.dart +++ b/test/async_button_builder_test.dart @@ -7,12 +7,12 @@ void main() { final textButton = MaterialApp( home: AsyncButtonBuilder( onPressed: () async { - await Future.delayed(Duration(seconds: 1)); + await Future.delayed(const Duration(seconds: 1)); }, builder: (context, child, callback, state) { return TextButton(onPressed: callback, child: child); }, - child: Text('click me'), + child: const Text('click me'), ), ); @@ -22,18 +22,18 @@ void main() { }); testWidgets('shows loading widget', (WidgetTester tester) async { - final duration = Duration(milliseconds: 250); + const duration = Duration(milliseconds: 250); final textButton = MaterialApp( home: AsyncButtonBuilder( duration: duration, - loadingWidget: Text('loading'), + loadingWidget: const Text('loading'), onPressed: () async { - await Future.delayed(Duration(seconds: 1)); + await Future.delayed(const Duration(seconds: 1)); }, builder: (context, child, callback, state) { return TextButton(onPressed: callback, child: child); }, - child: Text('click me'), + child: const Text('click me'), ), ); @@ -42,28 +42,28 @@ void main() { await tester.tap(find.byType(TextButton)); // 1/10 of a second later, loading should be showing - await tester.pump(Duration(milliseconds: 100)); + await tester.pump(const Duration(milliseconds: 100)); expect(find.text('loading'), findsOneWidget); // Let the widget continue to settle otherwise I won't dispose timers // correctly. TODO: Explain why .900 is the magic number - await tester.pumpAndSettle(Duration(milliseconds: 900)); + await tester.pumpAndSettle(const Duration(milliseconds: 900)); }); testWidgets('shows error widget', (WidgetTester tester) async { - final duration = Duration(milliseconds: 250); + const duration = Duration(milliseconds: 250); final textButton = MaterialApp( home: AsyncButtonBuilder( duration: duration, - errorWidget: Text('error'), + errorWidget: const Text('error'), onPressed: () async { throw ArgumentError(); }, builder: (context, child, callback, state) { return TextButton(onPressed: callback, child: child); }, - child: Text('click me'), + child: const Text('click me'), ), ); @@ -76,24 +76,24 @@ void main() { throwsA(isInstanceOf()), ); - await tester.pump(Duration(milliseconds: 200)); + await tester.pump(const Duration(milliseconds: 200)); expect(find.text('error'), findsOneWidget); }); testWidgets('Returns to child widget', (WidgetTester tester) async { - final duration = Duration(milliseconds: 250); + const duration = Duration(milliseconds: 250); final textButton = MaterialApp( home: AsyncButtonBuilder( duration: duration, - loadingWidget: Text('loading'), + loadingWidget: const Text('loading'), onPressed: () async { - await Future.delayed(Duration(seconds: 1)); + await Future.delayed(const Duration(seconds: 1)); }, builder: (context, child, callback, state) { return TextButton(onPressed: callback, child: child); }, - child: Text('click me'), + child: const Text('click me'), ), ); @@ -101,7 +101,7 @@ void main() { await tester.tap(find.byType(TextButton)); - await tester.pump(Duration(milliseconds: 1000)); + await tester.pump(const Duration(milliseconds: 1000)); expect(find.text('loading'), findsNothing); From 5959123fddc94d5cfad2aa46f5cd58acc6720d8f Mon Sep 17 00:00:00 2001 From: Nolence Date: Fri, 18 Jun 2021 09:51:59 -0600 Subject: [PATCH 042/176] version bump and remove .vscode stuff --- .vscode/launch.json | 32 -------------------------------- example/pubspec.lock | 2 +- pubspec.yaml | 2 +- 3 files changed, 2 insertions(+), 34 deletions(-) delete mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index bf78b5a..0000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "async_button_builder", - "request": "launch", - "type": "dart", - }, - { - "name": "async_button_builder (profile mode)", - "request": "launch", - "type": "dart", - "flutterMode": "profile" - }, - { - "name": "example", - "cwd": "example", - "request": "launch", - "type": "dart" - }, - { - "name": "example (profile mode)", - "cwd": "example", - "request": "launch", - "type": "dart", - "flutterMode": "profile" - } - ] -} \ No newline at end of file diff --git a/example/pubspec.lock b/example/pubspec.lock index 778a91b..434da95 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -14,7 +14,7 @@ packages: path: ".." relative: true source: path - version: "2.1.2+1" + version: "2.1.3" boolean_selector: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 20816af..14aa79e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_builder description: A builder to wrap around buttons that handles loading, disabled, error and succes states -version: 2.1.2+1 +version: 2.1.3 homepage: https://github.com/Nolence/async_button_builder environment: From 351d9433e213a0cab08fcd19b1564eac0160b788 Mon Sep 17 00:00:00 2001 From: Nolence Date: Fri, 25 Jun 2021 08:00:26 -0600 Subject: [PATCH 043/176] use proper successDuration on setTimer --- CHANGELOG.md | 3 +++ example/pubspec.lock | 8 ++++---- lib/src/async_button_builder.dart | 2 +- pubspec.lock | 6 +++--- pubspec.yaml | 2 +- 5 files changed, 12 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e91c0f..a3c2934 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## [2.1.3+1] - 2021-06-25 +Was not using proper sucessDuration when setting timeouts (regression) + ## [2.1.3] - 2021-06-18 Tests and builds against stable. flutter_lints now used in place of pedantic diff --git a/example/pubspec.lock b/example/pubspec.lock index 434da95..734b152 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -7,14 +7,14 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.6.1" + version: "2.7.0" async_button_builder: dependency: "direct main" description: path: ".." relative: true source: path - version: "2.1.3" + version: "2.1.3+1" boolean_selector: dependency: transitive description: @@ -101,7 +101,7 @@ packages: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.4.0" path: dependency: transitive description: @@ -162,7 +162,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.3.0" + version: "0.4.0" typed_data: dependency: transitive description: diff --git a/lib/src/async_button_builder.dart b/lib/src/async_button_builder.dart index 6ada9ac..125e7b8 100644 --- a/lib/src/async_button_builder.dart +++ b/lib/src/async_button_builder.dart @@ -421,7 +421,7 @@ class _AsyncButtonBuilderState extends State void setTimer(Duration duration) { timer = Timer( - widget.errorDuration, + duration, () { timer?.cancel(); diff --git a/pubspec.lock b/pubspec.lock index 1c27c7a..83d0b9e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -28,7 +28,7 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.6.1" + version: "2.7.0" boolean_selector: dependency: transitive description: @@ -297,7 +297,7 @@ packages: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.4.0" mime: dependency: transitive description: @@ -421,7 +421,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.3.0" + version: "0.4.0" timing: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 14aa79e..3516671 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_builder description: A builder to wrap around buttons that handles loading, disabled, error and succes states -version: 2.1.3 +version: 2.1.3+1 homepage: https://github.com/Nolence/async_button_builder environment: From 86fff54aedecd3740fb866ad7a29a52042a93be9 Mon Sep 17 00:00:00 2001 From: Nolence Date: Thu, 12 Aug 2021 10:51:40 -0600 Subject: [PATCH 044/176] fix small possibility of keys interfering with one another --- CHANGELOG.md | 3 +++ example/pubspec.lock | 8 ++++---- lib/src/async_button_builder.dart | 18 ++++++++++++++---- pubspec.lock | 6 +++--- pubspec.yaml | 2 +- 5 files changed, 25 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3c2934..8c517a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## [2.1.3+1] - 2021-06-25 +Fix possibility of nested async button builders conflicting with each other due to matching keyed subtrees. In order to avoid this situation, the parent key of the async_button_builder is used in the creation of sub widgets. + ## [2.1.3+1] - 2021-06-25 Was not using proper sucessDuration when setting timeouts (regression) diff --git a/example/pubspec.lock b/example/pubspec.lock index 734b152..dd48e5f 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -14,7 +14,7 @@ packages: path: ".." relative: true source: path - version: "2.1.3+1" + version: "2.1.3+2" boolean_selector: dependency: transitive description: @@ -35,7 +35,7 @@ packages: name: charcode url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.3.1" clock: dependency: transitive description: @@ -101,7 +101,7 @@ packages: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.4.0" + version: "1.7.0" path: dependency: transitive description: @@ -162,7 +162,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.0" + version: "0.4.2" typed_data: dependency: transitive description: diff --git a/lib/src/async_button_builder.dart b/lib/src/async_button_builder.dart index 125e7b8..d81b32a 100644 --- a/lib/src/async_button_builder.dart +++ b/lib/src/async_button_builder.dart @@ -271,6 +271,7 @@ class _AsyncButtonBuilderState extends State Widget build(BuildContext context) { final theme = Theme.of(context); final onPressed = widget.onPressed; + final widgetKey = widget.key; final loadingWidget = widget.loadingWidget ?? const SizedBox( height: 16.0, @@ -290,6 +291,15 @@ class _AsyncButtonBuilderState extends State final successPadding = widget.successPadding; final errorPadding = widget.errorPadding; + // This is necessary in the case of nested async button builders. + // We cannot have the same __idle__, __loading__, etc. keys as they might + // conflict with one another. + String parentKeyValue = ''; + + if (widgetKey != null && widgetKey is ValueKey) { + parentKeyValue = widgetKey.value.toString(); + } + if (successPadding != null) { successWidget = Padding( padding: successPadding, @@ -328,19 +338,19 @@ class _AsyncButtonBuilderState extends State ), child: buttonState.when( idle: () => KeyedSubtree( - key: const ValueKey('__idle__'), + key: ValueKey('__idle__' + parentKeyValue), child: widget.child, ), loading: () => KeyedSubtree( - key: const ValueKey('__loading__'), + key: ValueKey('__loading__' + parentKeyValue), child: loadingWidget, ), success: () => KeyedSubtree( - key: const ValueKey('__success__'), + key: ValueKey('__success__' + parentKeyValue), child: successWidget, ), error: () => KeyedSubtree( - key: const ValueKey('__error__'), + key: ValueKey('__error__' + parentKeyValue), child: errorWidget, ), ), diff --git a/pubspec.lock b/pubspec.lock index 83d0b9e..2d57c56 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -105,7 +105,7 @@ packages: name: charcode url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.3.1" checked_yaml: dependency: transitive description: @@ -297,7 +297,7 @@ packages: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.4.0" + version: "1.7.0" mime: dependency: transitive description: @@ -421,7 +421,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.0" + version: "0.4.2" timing: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 3516671..440e40e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_builder description: A builder to wrap around buttons that handles loading, disabled, error and succes states -version: 2.1.3+1 +version: 2.1.3+2 homepage: https://github.com/Nolence/async_button_builder environment: From 132c7d059dfde23f4d9f4ed7fa24dd1156d7853c Mon Sep 17 00:00:00 2001 From: Nolence Date: Thu, 12 Aug 2021 10:52:43 -0600 Subject: [PATCH 045/176] Fix changelog not mentioning right dates --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c517a1..975d4ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## [2.1.3+1] - 2021-06-25 +## [2.1.3+2] - 2021-08-12 Fix possibility of nested async button builders conflicting with each other due to matching keyed subtrees. In order to avoid this situation, the parent key of the async_button_builder is used in the creation of sub widgets. ## [2.1.3+1] - 2021-06-25 From 6db729472e9003159c8aa16d8531ba9d37bceba6 Mon Sep 17 00:00:00 2001 From: Nolence Date: Wed, 18 Aug 2021 13:53:10 -0600 Subject: [PATCH 046/176] Moved to a multi repository thing --- packages/async_button_core/.gitignore | 75 +++ packages/async_button_core/.metadata | 10 + packages/async_button_core/CHANGELOG.md | 3 + packages/async_button_core/LICENSE | 1 + packages/async_button_core/README.md | 1 + .../async_button_core/analysis_options.yaml | 4 + .../lib/async_button_core.dart | 3 + .../lib/src/button_state/button_state.dart | 39 ++ .../button_state/button_state.freezed.dart | 455 ++++++++++++++++++ packages/async_button_core/pubspec.lock | 175 +++++++ packages/async_button_core/pubspec.yaml | 20 + .../test/async_button_core_test.dart | 7 + 12 files changed, 793 insertions(+) create mode 100644 packages/async_button_core/.gitignore create mode 100644 packages/async_button_core/.metadata create mode 100644 packages/async_button_core/CHANGELOG.md create mode 100644 packages/async_button_core/LICENSE create mode 100644 packages/async_button_core/README.md create mode 100644 packages/async_button_core/analysis_options.yaml create mode 100644 packages/async_button_core/lib/async_button_core.dart create mode 100644 packages/async_button_core/lib/src/button_state/button_state.dart create mode 100644 packages/async_button_core/lib/src/button_state/button_state.freezed.dart create mode 100644 packages/async_button_core/pubspec.lock create mode 100644 packages/async_button_core/pubspec.yaml create mode 100644 packages/async_button_core/test/async_button_core_test.dart diff --git a/packages/async_button_core/.gitignore b/packages/async_button_core/.gitignore new file mode 100644 index 0000000..a247422 --- /dev/null +++ b/packages/async_button_core/.gitignore @@ -0,0 +1,75 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +build/ + +# Android related +**/android/**/gradle-wrapper.jar +**/android/.gradle +**/android/captures/ +**/android/gradlew +**/android/gradlew.bat +**/android/local.properties +**/android/**/GeneratedPluginRegistrant.java + +# iOS/XCode related +**/ios/**/*.mode1v3 +**/ios/**/*.mode2v3 +**/ios/**/*.moved-aside +**/ios/**/*.pbxuser +**/ios/**/*.perspectivev3 +**/ios/**/*sync/ +**/ios/**/.sconsign.dblite +**/ios/**/.tags* +**/ios/**/.vagrant/ +**/ios/**/DerivedData/ +**/ios/**/Icon? +**/ios/**/Pods/ +**/ios/**/.symlinks/ +**/ios/**/profile +**/ios/**/xcuserdata +**/ios/.generated/ +**/ios/Flutter/App.framework +**/ios/Flutter/Flutter.framework +**/ios/Flutter/Flutter.podspec +**/ios/Flutter/Generated.xcconfig +**/ios/Flutter/ephemeral +**/ios/Flutter/app.flx +**/ios/Flutter/app.zip +**/ios/Flutter/flutter_assets/ +**/ios/Flutter/flutter_export_environment.sh +**/ios/ServiceDefinitions.json +**/ios/Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!**/ios/**/default.mode1v3 +!**/ios/**/default.mode2v3 +!**/ios/**/default.pbxuser +!**/ios/**/default.perspectivev3 diff --git a/packages/async_button_core/.metadata b/packages/async_button_core/.metadata new file mode 100644 index 0000000..b6da989 --- /dev/null +++ b/packages/async_button_core/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 225a43d941ddd1753765fec3682011e9ddffb11d + channel: dev + +project_type: package diff --git a/packages/async_button_core/CHANGELOG.md b/packages/async_button_core/CHANGELOG.md new file mode 100644 index 0000000..7ac4fa5 --- /dev/null +++ b/packages/async_button_core/CHANGELOG.md @@ -0,0 +1,3 @@ +## 0.0.1 - 2021-08-18 + +Initial release diff --git a/packages/async_button_core/LICENSE b/packages/async_button_core/LICENSE new file mode 100644 index 0000000..30cff74 --- /dev/null +++ b/packages/async_button_core/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/packages/async_button_core/README.md b/packages/async_button_core/README.md new file mode 100644 index 0000000..fe84005 --- /dev/null +++ b/packages/async_button_core/README.md @@ -0,0 +1 @@ +../../README.md \ No newline at end of file diff --git a/packages/async_button_core/analysis_options.yaml b/packages/async_button_core/analysis_options.yaml new file mode 100644 index 0000000..a5744c1 --- /dev/null +++ b/packages/async_button_core/analysis_options.yaml @@ -0,0 +1,4 @@ +include: package:flutter_lints/flutter.yaml + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/packages/async_button_core/lib/async_button_core.dart b/packages/async_button_core/lib/async_button_core.dart new file mode 100644 index 0000000..a892dfe --- /dev/null +++ b/packages/async_button_core/lib/async_button_core.dart @@ -0,0 +1,3 @@ +library async_button_core; + +export './async_button_core.dart'; diff --git a/packages/async_button_core/lib/src/button_state/button_state.dart b/packages/async_button_core/lib/src/button_state/button_state.dart new file mode 100644 index 0000000..c2a0a1a --- /dev/null +++ b/packages/async_button_core/lib/src/button_state/button_state.dart @@ -0,0 +1,39 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'button_state.freezed.dart'; + +/// This union class represents the state of the button in either a [Idling], +/// [Loading], [Success] or [Error] state. This can be considered a enum with extra +/// utilities for ease of use. +/// +/// {@tool snippet} +/// +/// ```dart +/// final buttonColor = buttonState.when( +/// idle: () => Colors.pink, +/// loading: () => Colors.blue, +/// success: () => Colors.green, +/// error: () => Colors.red, +/// ); +/// ``` +/// {@end-tool} +/// +/// You can also disregard other states and handle only those you'd like using +/// the `.maybeWhen` syntax. +/// +/// /// {@tool snippet} +/// +/// ```dart +/// final buttonColor = buttonState.maybeWhen( +/// idle: () => Colors.pink, +/// orElse: () => Colors.red, +/// ); +/// ``` +/// {@end-tool} +@freezed +class ButtonState with _$ButtonState { + const factory ButtonState.idle() = Idle; + const factory ButtonState.loading() = Loading; + const factory ButtonState.success() = Success; + const factory ButtonState.error() = Error; +} diff --git a/packages/async_button_core/lib/src/button_state/button_state.freezed.dart b/packages/async_button_core/lib/src/button_state/button_state.freezed.dart new file mode 100644 index 0000000..b200140 --- /dev/null +++ b/packages/async_button_core/lib/src/button_state/button_state.freezed.dart @@ -0,0 +1,455 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides + +part of 'button_state.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +/// @nodoc +class _$ButtonStateTearOff { + const _$ButtonStateTearOff(); + + Idle idle() { + return const Idle(); + } + + Loading loading() { + return const Loading(); + } + + Success success() { + return const Success(); + } + + Error error() { + return const Error(); + } +} + +/// @nodoc +const $ButtonState = _$ButtonStateTearOff(); + +/// @nodoc +mixin _$ButtonState { + @optionalTypeArgs + TResult when({ + required TResult Function() idle, + required TResult Function() loading, + required TResult Function() success, + required TResult Function() error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? idle, + TResult Function()? loading, + TResult Function()? success, + TResult Function()? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(Idle value) idle, + required TResult Function(Loading value) loading, + required TResult Function(Success value) success, + required TResult Function(Error value) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Idle value)? idle, + TResult Function(Loading value)? loading, + TResult Function(Success value)? success, + TResult Function(Error value)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ButtonStateCopyWith<$Res> { + factory $ButtonStateCopyWith( + ButtonState value, $Res Function(ButtonState) then) = + _$ButtonStateCopyWithImpl<$Res>; +} + +/// @nodoc +class _$ButtonStateCopyWithImpl<$Res> implements $ButtonStateCopyWith<$Res> { + _$ButtonStateCopyWithImpl(this._value, this._then); + + final ButtonState _value; + // ignore: unused_field + final $Res Function(ButtonState) _then; +} + +/// @nodoc +abstract class $IdleCopyWith<$Res> { + factory $IdleCopyWith(Idle value, $Res Function(Idle) then) = + _$IdleCopyWithImpl<$Res>; +} + +/// @nodoc +class _$IdleCopyWithImpl<$Res> extends _$ButtonStateCopyWithImpl<$Res> + implements $IdleCopyWith<$Res> { + _$IdleCopyWithImpl(Idle _value, $Res Function(Idle) _then) + : super(_value, (v) => _then(v as Idle)); + + @override + Idle get _value => super._value as Idle; +} + +/// @nodoc + +class _$Idle implements Idle { + const _$Idle(); + + @override + String toString() { + return 'ButtonState.idle()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || (other is Idle); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() idle, + required TResult Function() loading, + required TResult Function() success, + required TResult Function() error, + }) { + return idle(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? idle, + TResult Function()? loading, + TResult Function()? success, + TResult Function()? error, + required TResult orElse(), + }) { + if (idle != null) { + return idle(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(Idle value) idle, + required TResult Function(Loading value) loading, + required TResult Function(Success value) success, + required TResult Function(Error value) error, + }) { + return idle(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Idle value)? idle, + TResult Function(Loading value)? loading, + TResult Function(Success value)? success, + TResult Function(Error value)? error, + required TResult orElse(), + }) { + if (idle != null) { + return idle(this); + } + return orElse(); + } +} + +abstract class Idle implements ButtonState { + const factory Idle() = _$Idle; +} + +/// @nodoc +abstract class $LoadingCopyWith<$Res> { + factory $LoadingCopyWith(Loading value, $Res Function(Loading) then) = + _$LoadingCopyWithImpl<$Res>; +} + +/// @nodoc +class _$LoadingCopyWithImpl<$Res> extends _$ButtonStateCopyWithImpl<$Res> + implements $LoadingCopyWith<$Res> { + _$LoadingCopyWithImpl(Loading _value, $Res Function(Loading) _then) + : super(_value, (v) => _then(v as Loading)); + + @override + Loading get _value => super._value as Loading; +} + +/// @nodoc + +class _$Loading implements Loading { + const _$Loading(); + + @override + String toString() { + return 'ButtonState.loading()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || (other is Loading); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() idle, + required TResult Function() loading, + required TResult Function() success, + required TResult Function() error, + }) { + return loading(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? idle, + TResult Function()? loading, + TResult Function()? success, + TResult Function()? error, + required TResult orElse(), + }) { + if (loading != null) { + return loading(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(Idle value) idle, + required TResult Function(Loading value) loading, + required TResult Function(Success value) success, + required TResult Function(Error value) error, + }) { + return loading(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Idle value)? idle, + TResult Function(Loading value)? loading, + TResult Function(Success value)? success, + TResult Function(Error value)? error, + required TResult orElse(), + }) { + if (loading != null) { + return loading(this); + } + return orElse(); + } +} + +abstract class Loading implements ButtonState { + const factory Loading() = _$Loading; +} + +/// @nodoc +abstract class $SuccessCopyWith<$Res> { + factory $SuccessCopyWith(Success value, $Res Function(Success) then) = + _$SuccessCopyWithImpl<$Res>; +} + +/// @nodoc +class _$SuccessCopyWithImpl<$Res> extends _$ButtonStateCopyWithImpl<$Res> + implements $SuccessCopyWith<$Res> { + _$SuccessCopyWithImpl(Success _value, $Res Function(Success) _then) + : super(_value, (v) => _then(v as Success)); + + @override + Success get _value => super._value as Success; +} + +/// @nodoc + +class _$Success implements Success { + const _$Success(); + + @override + String toString() { + return 'ButtonState.success()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || (other is Success); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() idle, + required TResult Function() loading, + required TResult Function() success, + required TResult Function() error, + }) { + return success(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? idle, + TResult Function()? loading, + TResult Function()? success, + TResult Function()? error, + required TResult orElse(), + }) { + if (success != null) { + return success(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(Idle value) idle, + required TResult Function(Loading value) loading, + required TResult Function(Success value) success, + required TResult Function(Error value) error, + }) { + return success(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Idle value)? idle, + TResult Function(Loading value)? loading, + TResult Function(Success value)? success, + TResult Function(Error value)? error, + required TResult orElse(), + }) { + if (success != null) { + return success(this); + } + return orElse(); + } +} + +abstract class Success implements ButtonState { + const factory Success() = _$Success; +} + +/// @nodoc +abstract class $ErrorCopyWith<$Res> { + factory $ErrorCopyWith(Error value, $Res Function(Error) then) = + _$ErrorCopyWithImpl<$Res>; +} + +/// @nodoc +class _$ErrorCopyWithImpl<$Res> extends _$ButtonStateCopyWithImpl<$Res> + implements $ErrorCopyWith<$Res> { + _$ErrorCopyWithImpl(Error _value, $Res Function(Error) _then) + : super(_value, (v) => _then(v as Error)); + + @override + Error get _value => super._value as Error; +} + +/// @nodoc + +class _$Error implements Error { + const _$Error(); + + @override + String toString() { + return 'ButtonState.error()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || (other is Error); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() idle, + required TResult Function() loading, + required TResult Function() success, + required TResult Function() error, + }) { + return error(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? idle, + TResult Function()? loading, + TResult Function()? success, + TResult Function()? error, + required TResult orElse(), + }) { + if (error != null) { + return error(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(Idle value) idle, + required TResult Function(Loading value) loading, + required TResult Function(Success value) success, + required TResult Function(Error value) error, + }) { + return error(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Idle value)? idle, + TResult Function(Loading value)? loading, + TResult Function(Success value)? success, + TResult Function(Error value)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(this); + } + return orElse(); + } +} + +abstract class Error implements ButtonState { + const factory Error() = _$Error; +} diff --git a/packages/async_button_core/pubspec.lock b/packages/async_button_core/pubspec.lock new file mode 100644 index 0000000..904ddff --- /dev/null +++ b/packages/async_button_core/pubspec.lock @@ -0,0 +1,175 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + async: + dependency: transitive + description: + name: async + url: "https://pub.dartlang.org" + source: hosted + version: "2.8.1" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + characters: + dependency: transitive + description: + name: characters + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + charcode: + dependency: transitive + description: + name: charcode + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.1" + clock: + dependency: transitive + description: + name: clock + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + collection: + dependency: transitive + description: + name: collection + url: "https://pub.dartlang.org" + source: hosted + version: "1.15.0" + fake_async: + dependency: transitive + description: + name: fake_async + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.4" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + freezed_annotation: + dependency: "direct main" + description: + name: freezed_annotation + url: "https://pub.dartlang.org" + source: hosted + version: "0.14.3" + json_annotation: + dependency: transitive + description: + name: json_annotation + url: "https://pub.dartlang.org" + source: hosted + version: "4.1.0" + lints: + dependency: transitive + description: + name: lints + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + matcher: + dependency: transitive + description: + name: matcher + url: "https://pub.dartlang.org" + source: hosted + version: "0.12.10" + meta: + dependency: transitive + description: + name: meta + url: "https://pub.dartlang.org" + source: hosted + version: "1.7.0" + path: + dependency: transitive + description: + name: path + url: "https://pub.dartlang.org" + source: hosted + version: "1.8.0" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + url: "https://pub.dartlang.org" + source: hosted + version: "1.8.1" + stack_trace: + dependency: transitive + description: + name: stack_trace + url: "https://pub.dartlang.org" + source: hosted + version: "1.10.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + test_api: + dependency: transitive + description: + name: test_api + url: "https://pub.dartlang.org" + source: hosted + version: "0.4.2" + typed_data: + dependency: transitive + description: + name: typed_data + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.0" + vector_math: + dependency: transitive + description: + name: vector_math + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" +sdks: + dart: ">=2.12.0 <3.0.0" + flutter: ">=1.17.0" diff --git a/packages/async_button_core/pubspec.yaml b/packages/async_button_core/pubspec.yaml new file mode 100644 index 0000000..b3fd97f --- /dev/null +++ b/packages/async_button_core/pubspec.yaml @@ -0,0 +1,20 @@ +name: async_button_core +description: A new Flutter package project. +version: 0.0.1 +homepage: https://github.com/Nolence/async_button/packages/async_button_core + +environment: + sdk: ">=2.12.0 <3.0.0" + flutter: ">=1.17.0" + +dependencies: + flutter: + sdk: flutter + freezed_annotation: ^0.14.3 + +dev_dependencies: + flutter_lints: ^1.0.0 + flutter_test: + sdk: flutter + +flutter: null diff --git a/packages/async_button_core/test/async_button_core_test.dart b/packages/async_button_core/test/async_button_core_test.dart new file mode 100644 index 0000000..c989bbd --- /dev/null +++ b/packages/async_button_core/test/async_button_core_test.dart @@ -0,0 +1,7 @@ +import 'package:flutter_test/flutter_test.dart'; + +void main() { + test('adds one to input values', () { + throw UnimplementedError(); + }); +} From e91c7a0fcfdeaa8fc72cb45e58955979517a2381 Mon Sep 17 00:00:00 2001 From: Nolence Date: Wed, 18 Aug 2021 13:53:51 -0600 Subject: [PATCH 047/176] add other packages as well --- .../.github/workflows/dart.yaml | 37 ++ packages/async_button_builder/.gitignore | 74 +++ packages/async_button_builder/.metadata | 10 + packages/async_button_builder/CHANGELOG.md | 80 +++ packages/async_button_builder/LICENSE | 1 + packages/async_button_builder/README.md | 1 + .../async_button_builder/example/.gitignore | 46 ++ .../async_button_builder/example/.metadata | 10 + .../async_button_builder/example/README.md | 16 + .../example/analysis_options.yaml | 1 + .../example/android/.gitignore | 11 + .../example/android/app/build.gradle | 59 ++ .../android/app/src/debug/AndroidManifest.xml | 7 + .../android/app/src/main/AndroidManifest.xml | 41 ++ .../com/example/example/MainActivity.kt | 6 + .../res/drawable-v21/launch_background.xml | 12 + .../main/res/drawable/launch_background.xml | 12 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 544 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 442 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 721 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 1031 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 1443 bytes .../app/src/main/res/values-night/styles.xml | 18 + .../app/src/main/res/values/styles.xml | 18 + .../app/src/profile/AndroidManifest.xml | 7 + .../example/android/build.gradle | 31 ++ .../example/android/gradle.properties | 3 + .../gradle/wrapper/gradle-wrapper.properties | 6 + .../example/android/settings.gradle | 11 + .../example/ios/.gitignore | 32 ++ .../ios/Flutter/AppFrameworkInfo.plist | 26 + .../example/ios/Flutter/Debug.xcconfig | 3 + .../example/ios/Flutter/Release.xcconfig | 3 + .../async_button_builder/example/ios/Podfile | 41 ++ .../example/ios/Podfile.lock | 16 + .../ios/Runner.xcodeproj/project.pbxproj | 521 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../xcshareddata/xcschemes/Runner.xcscheme | 91 +++ .../contents.xcworkspacedata | 10 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../example/ios/Runner/AppDelegate.swift | 13 + .../AppIcon.appiconset/Contents.json | 122 ++++ .../Icon-App-1024x1024@1x.png | Bin 0 -> 10932 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 0 -> 564 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 0 -> 1283 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 0 -> 1588 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 0 -> 1025 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 0 -> 1716 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 0 -> 1920 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 0 -> 1283 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 0 -> 1895 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 0 -> 2665 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 0 -> 2665 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 0 -> 3831 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 0 -> 1888 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 0 -> 3294 bytes .../Icon-App-83.5x83.5@2x.png | Bin 0 -> 3612 bytes .../LaunchImage.imageset/Contents.json | 23 + .../LaunchImage.imageset/LaunchImage.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@2x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@3x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/README.md | 5 + .../Runner/Base.lproj/LaunchScreen.storyboard | 37 ++ .../ios/Runner/Base.lproj/Main.storyboard | 26 + .../example/ios/Runner/Info.plist | 45 ++ .../ios/Runner/Runner-Bridging-Header.h | 1 + .../example/lib/main.dart | 166 ++++++ .../async_button_builder/example/pubspec.lock | 189 +++++++ .../async_button_builder/example/pubspec.yaml | 23 + .../example/test/widget_test.dart | 30 + .../example/web/favicon.png | Bin 0 -> 917 bytes .../example/web/icons/Icon-192.png | Bin 0 -> 5292 bytes .../example/web/icons/Icon-512.png | Bin 0 -> 8252 bytes .../example/web/index.html | 45 ++ .../example/web/manifest.json | 23 + .../lib/async_button_builder.dart | 3 + .../lib/src/async_button_builder.dart | 445 +++++++++++++++ packages/async_button_builder/pubspec.lock | 476 ++++++++++++++++ packages/async_button_builder/pubspec.yaml | 23 + .../test/async_button_builder_test.dart | 151 +++++ packages/async_button_hook/.gitignore | 75 +++ packages/async_button_hook/.metadata | 10 + packages/async_button_hook/CHANGELOG.md | 3 + packages/async_button_hook/LICENSE | 1 + packages/async_button_hook/README.md | 1 + .../lib/async_button_hook.dart | 1 + packages/async_button_hook/pubspec.lock | 168 ++++++ packages/async_button_hook/pubspec.yaml | 20 + .../test/async_button_hook_test.dart | 7 + 92 files changed, 3432 insertions(+) create mode 100644 packages/async_button_builder/.github/workflows/dart.yaml create mode 100644 packages/async_button_builder/.gitignore create mode 100644 packages/async_button_builder/.metadata create mode 100644 packages/async_button_builder/CHANGELOG.md create mode 100644 packages/async_button_builder/LICENSE create mode 100644 packages/async_button_builder/README.md create mode 100644 packages/async_button_builder/example/.gitignore create mode 100644 packages/async_button_builder/example/.metadata create mode 100644 packages/async_button_builder/example/README.md create mode 100644 packages/async_button_builder/example/analysis_options.yaml create mode 100644 packages/async_button_builder/example/android/.gitignore create mode 100644 packages/async_button_builder/example/android/app/build.gradle create mode 100644 packages/async_button_builder/example/android/app/src/debug/AndroidManifest.xml create mode 100644 packages/async_button_builder/example/android/app/src/main/AndroidManifest.xml create mode 100644 packages/async_button_builder/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt create mode 100644 packages/async_button_builder/example/android/app/src/main/res/drawable-v21/launch_background.xml create mode 100644 packages/async_button_builder/example/android/app/src/main/res/drawable/launch_background.xml create mode 100644 packages/async_button_builder/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 packages/async_button_builder/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 packages/async_button_builder/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 packages/async_button_builder/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 packages/async_button_builder/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 packages/async_button_builder/example/android/app/src/main/res/values-night/styles.xml create mode 100644 packages/async_button_builder/example/android/app/src/main/res/values/styles.xml create mode 100644 packages/async_button_builder/example/android/app/src/profile/AndroidManifest.xml create mode 100644 packages/async_button_builder/example/android/build.gradle create mode 100644 packages/async_button_builder/example/android/gradle.properties create mode 100644 packages/async_button_builder/example/android/gradle/wrapper/gradle-wrapper.properties create mode 100644 packages/async_button_builder/example/android/settings.gradle create mode 100644 packages/async_button_builder/example/ios/.gitignore create mode 100644 packages/async_button_builder/example/ios/Flutter/AppFrameworkInfo.plist create mode 100644 packages/async_button_builder/example/ios/Flutter/Debug.xcconfig create mode 100644 packages/async_button_builder/example/ios/Flutter/Release.xcconfig create mode 100644 packages/async_button_builder/example/ios/Podfile create mode 100644 packages/async_button_builder/example/ios/Podfile.lock create mode 100644 packages/async_button_builder/example/ios/Runner.xcodeproj/project.pbxproj create mode 100644 packages/async_button_builder/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 packages/async_button_builder/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 packages/async_button_builder/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 packages/async_button_builder/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme create mode 100644 packages/async_button_builder/example/ios/Runner.xcworkspace/contents.xcworkspacedata create mode 100644 packages/async_button_builder/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 packages/async_button_builder/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 packages/async_button_builder/example/ios/Runner/AppDelegate.swift create mode 100644 packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png create mode 100644 packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png create mode 100644 packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png create mode 100644 packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png create mode 100644 packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png create mode 100644 packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png create mode 100644 packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png create mode 100644 packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png create mode 100644 packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png create mode 100644 packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png create mode 100644 packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png create mode 100644 packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png create mode 100644 packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png create mode 100644 packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png create mode 100644 packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png create mode 100644 packages/async_button_builder/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json create mode 100644 packages/async_button_builder/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png create mode 100644 packages/async_button_builder/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png create mode 100644 packages/async_button_builder/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png create mode 100644 packages/async_button_builder/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md create mode 100644 packages/async_button_builder/example/ios/Runner/Base.lproj/LaunchScreen.storyboard create mode 100644 packages/async_button_builder/example/ios/Runner/Base.lproj/Main.storyboard create mode 100644 packages/async_button_builder/example/ios/Runner/Info.plist create mode 100644 packages/async_button_builder/example/ios/Runner/Runner-Bridging-Header.h create mode 100644 packages/async_button_builder/example/lib/main.dart create mode 100644 packages/async_button_builder/example/pubspec.lock create mode 100644 packages/async_button_builder/example/pubspec.yaml create mode 100644 packages/async_button_builder/example/test/widget_test.dart create mode 100644 packages/async_button_builder/example/web/favicon.png create mode 100644 packages/async_button_builder/example/web/icons/Icon-192.png create mode 100644 packages/async_button_builder/example/web/icons/Icon-512.png create mode 100644 packages/async_button_builder/example/web/index.html create mode 100644 packages/async_button_builder/example/web/manifest.json create mode 100644 packages/async_button_builder/lib/async_button_builder.dart create mode 100644 packages/async_button_builder/lib/src/async_button_builder.dart create mode 100644 packages/async_button_builder/pubspec.lock create mode 100644 packages/async_button_builder/pubspec.yaml create mode 100644 packages/async_button_builder/test/async_button_builder_test.dart create mode 100644 packages/async_button_hook/.gitignore create mode 100644 packages/async_button_hook/.metadata create mode 100644 packages/async_button_hook/CHANGELOG.md create mode 100644 packages/async_button_hook/LICENSE create mode 100644 packages/async_button_hook/README.md create mode 100644 packages/async_button_hook/lib/async_button_hook.dart create mode 100644 packages/async_button_hook/pubspec.lock create mode 100644 packages/async_button_hook/pubspec.yaml create mode 100644 packages/async_button_hook/test/async_button_hook_test.dart diff --git a/packages/async_button_builder/.github/workflows/dart.yaml b/packages/async_button_builder/.github/workflows/dart.yaml new file mode 100644 index 0000000..1c8d8da --- /dev/null +++ b/packages/async_button_builder/.github/workflows/dart.yaml @@ -0,0 +1,37 @@ +name: Build + +on: + push: + pull_request: + schedule: + # runs the CI everyday at 10AM + - cron: '0 10 * * *' + +jobs: + flutter: + runs-on: ubuntu-latest + + strategy: + matrix: + channel: + # Dev currently adds a breaking change on AnimatedContainer - so no + # - dev + - stable + + steps: + - uses: actions/checkout@v2 + - uses: subosito/flutter-action@v1 + with: + channel: ${{ matrix.channel }} + + - name: Install dependencies + run: flutter pub get + + - name: Check format + run: flutter format --set-exit-if-changed . + + - name: Analyze + run: flutter analyze + + - name: Run tests + run: flutter test \ No newline at end of file diff --git a/packages/async_button_builder/.gitignore b/packages/async_button_builder/.gitignore new file mode 100644 index 0000000..1985397 --- /dev/null +++ b/packages/async_button_builder/.gitignore @@ -0,0 +1,74 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +build/ + +# Android related +**/android/**/gradle-wrapper.jar +**/android/.gradle +**/android/captures/ +**/android/gradlew +**/android/gradlew.bat +**/android/local.properties +**/android/**/GeneratedPluginRegistrant.java + +# iOS/XCode related +**/ios/**/*.mode1v3 +**/ios/**/*.mode2v3 +**/ios/**/*.moved-aside +**/ios/**/*.pbxuser +**/ios/**/*.perspectivev3 +**/ios/**/*sync/ +**/ios/**/.sconsign.dblite +**/ios/**/.tags* +**/ios/**/.vagrant/ +**/ios/**/DerivedData/ +**/ios/**/Icon? +**/ios/**/Pods/ +**/ios/**/.symlinks/ +**/ios/**/profile +**/ios/**/xcuserdata +**/ios/.generated/ +**/ios/Flutter/App.framework +**/ios/Flutter/Flutter.framework +**/ios/Flutter/Flutter.podspec +**/ios/Flutter/Generated.xcconfig +**/ios/Flutter/app.flx +**/ios/Flutter/app.zip +**/ios/Flutter/flutter_assets/ +**/ios/Flutter/flutter_export_environment.sh +**/ios/ServiceDefinitions.json +**/ios/Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!**/ios/**/default.mode1v3 +!**/ios/**/default.mode2v3 +!**/ios/**/default.pbxuser +!**/ios/**/default.perspectivev3 diff --git a/packages/async_button_builder/.metadata b/packages/async_button_builder/.metadata new file mode 100644 index 0000000..13a1909 --- /dev/null +++ b/packages/async_button_builder/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 63062a64432cce03315d6b5196fda7912866eb37 + channel: dev + +project_type: package diff --git a/packages/async_button_builder/CHANGELOG.md b/packages/async_button_builder/CHANGELOG.md new file mode 100644 index 0000000..975d4ea --- /dev/null +++ b/packages/async_button_builder/CHANGELOG.md @@ -0,0 +1,80 @@ +## [2.1.3+2] - 2021-08-12 +Fix possibility of nested async button builders conflicting with each other due to matching keyed subtrees. In order to avoid this situation, the parent key of the async_button_builder is used in the creation of sub widgets. + +## [2.1.3+1] - 2021-06-25 +Was not using proper sucessDuration when setting timeouts (regression) + +## [2.1.3] - 2021-06-18 +Tests and builds against stable. flutter_lints now used in place of pedantic + +## [2.1.2+1] - 2021-06-12 +Fixes analysis errors so I stop getting annoying emails + +## [2.1.2] - 2021-05-24 +Errors from onpressed will throw with orignal call stack + +## [2.1.1+2] - 2021-04-14 +Makes onpressed nullable similar to other button's behaviour + +## [2.1.1+1] - 2021-04-14 +Add documentation on how to handle timeouts + +## [2.1.1] - 2021-04-14 +ValueKeys are now no longer required in order to differentiate children + +## [2.1.0] - 2021-02-12 +Remove null-safety prefix as it's now in stable + +## [2.0.9-nullsafety.0] - 2021-02-12 +Trying to bump version again to go over stable + +## [2.0.8-nullsafety.0] - 2021-02-12 +Trying to bump version again to go over stable + +## [2.0.7-nullsafety.8] - 2021-02-12 +Republish so current nullsafe becomes main. My mistake + +## [2.0.2-nullsafety.7] - 2021-02-12 +Added a typedef in place of inline type on function. Added doc to `builder` field + +## [2.0.2-nullsafety.6] - 2021-02-09 +Renamed Union classes to match that of factory constructor name (Should not be breaking). + +## [2.0.2-nullsafety.5] - 2021-02-01 +Removed example integration test + +## [2.0.2-nullsafety.4] - 2021-01-26 +Adds tests and test coverage. Adds on dispose to cancel timer. + +## [2.0.2-nullsafety.3] - 2021-01-25 +Removes dangling controller and cleans up main code up a bit + +## [2.0.2-nullsafety.2] - 2021-01-25 +Fixes wrong image path + +## [2.0.1-nullsafety.2] - 2021-01-25 +Renames fields to better match standards of other buttons. + +## [2.0.0-dev.1] - 2021-01-25 + +Breaking. Replaces the fourth argument with a sealed union that better allows for directly managing states, removes unnecessary arguments such as padding, adds transition builders for custom transitions. Currently still includes AnimatedSize. + +## [1.0.0-nullsafety.0] - 2021-01-12 + +Breaking. Adds a fourth argument of loading to the builder. This removes the value notifier that was difficult or confusing to manage in actual usage in my use cases. The argument isLoading is now a `bool`. This also adds a `disabled` field in order to set that on construction. + +## [0.1.0-nullsafety.0] - 2021-01-12 + +Replaces the bool type of isLoading for a ValueNotifier. + +## [0.0.1-nullsafety.2] - 2021-01-12 + +Adds analysis options and removes unnecessary typedef + +## [0.0.1-nullsafety.1] - 2021-01-12 + +Adds docs to parameters and removes use of unnecessary undescore internal variables. + +## [0.0.1-nullsafety.0] - 2021-01-11 + +Holds basic builder AsyncButtonBuilder. No tests yet. NNBD is supported diff --git a/packages/async_button_builder/LICENSE b/packages/async_button_builder/LICENSE new file mode 100644 index 0000000..30cff74 --- /dev/null +++ b/packages/async_button_builder/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/packages/async_button_builder/README.md b/packages/async_button_builder/README.md new file mode 100644 index 0000000..fe84005 --- /dev/null +++ b/packages/async_button_builder/README.md @@ -0,0 +1 @@ +../../README.md \ No newline at end of file diff --git a/packages/async_button_builder/example/.gitignore b/packages/async_button_builder/example/.gitignore new file mode 100644 index 0000000..0fa6b67 --- /dev/null +++ b/packages/async_button_builder/example/.gitignore @@ -0,0 +1,46 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/packages/async_button_builder/example/.metadata b/packages/async_button_builder/example/.metadata new file mode 100644 index 0000000..36a4614 --- /dev/null +++ b/packages/async_button_builder/example/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 63062a64432cce03315d6b5196fda7912866eb37 + channel: dev + +project_type: app diff --git a/packages/async_button_builder/example/README.md b/packages/async_button_builder/example/README.md new file mode 100644 index 0000000..a135626 --- /dev/null +++ b/packages/async_button_builder/example/README.md @@ -0,0 +1,16 @@ +# example + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/packages/async_button_builder/example/analysis_options.yaml b/packages/async_button_builder/example/analysis_options.yaml new file mode 100644 index 0000000..108d105 --- /dev/null +++ b/packages/async_button_builder/example/analysis_options.yaml @@ -0,0 +1 @@ +include: package:pedantic/analysis_options.yaml diff --git a/packages/async_button_builder/example/android/.gitignore b/packages/async_button_builder/example/android/.gitignore new file mode 100644 index 0000000..0a741cb --- /dev/null +++ b/packages/async_button_builder/example/android/.gitignore @@ -0,0 +1,11 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties diff --git a/packages/async_button_builder/example/android/app/build.gradle b/packages/async_button_builder/example/android/app/build.gradle new file mode 100644 index 0000000..6ca2344 --- /dev/null +++ b/packages/async_button_builder/example/android/app/build.gradle @@ -0,0 +1,59 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 30 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.example" + minSdkVersion 16 + targetSdkVersion 30 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/packages/async_button_builder/example/android/app/src/debug/AndroidManifest.xml b/packages/async_button_builder/example/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..c208884 --- /dev/null +++ b/packages/async_button_builder/example/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/packages/async_button_builder/example/android/app/src/main/AndroidManifest.xml b/packages/async_button_builder/example/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..34dd77e --- /dev/null +++ b/packages/async_button_builder/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + diff --git a/packages/async_button_builder/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt b/packages/async_button_builder/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt new file mode 100644 index 0000000..e793a00 --- /dev/null +++ b/packages/async_button_builder/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.example + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} diff --git a/packages/async_button_builder/example/android/app/src/main/res/drawable-v21/launch_background.xml b/packages/async_button_builder/example/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 0000000..f74085f --- /dev/null +++ b/packages/async_button_builder/example/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/packages/async_button_builder/example/android/app/src/main/res/drawable/launch_background.xml b/packages/async_button_builder/example/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000..304732f --- /dev/null +++ b/packages/async_button_builder/example/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/packages/async_button_builder/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/packages/async_button_builder/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..db77bb4b7b0906d62b1847e87f15cdcacf6a4f29 GIT binary patch literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ literal 0 HcmV?d00001 diff --git a/packages/async_button_builder/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/packages/async_button_builder/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..17987b79bb8a35cc66c3c1fd44f5a5526c1b78be GIT binary patch literal 442 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xx&nMcT!A!W`0S9QKQy;}1Cl^CgaH=;G9cpY;r$Q>i*pfB zP2drbID<_#qf;rPZx^FqH)F_D#*k@@q03KywUtLX8Ua?`H+NMzkczFPK3lFz@i_kW%1NOn0|D2I9n9wzH8m|-tHjsw|9>@K=iMBhxvkv6m8Y-l zytQ?X=U+MF$@3 zt`~i=@j|6y)RWMK--}M|=T`o&^Ni>IoWKHEbBXz7?A@mgWoL>!*SXo`SZH-*HSdS+ yn*9;$7;m`l>wYBC5bq;=U}IMqLzqbYCidGC!)_gkIk_C@Uy!y&wkt5C($~2D>~)O*cj@FGjOCM)M>_ixfudOh)?xMu#Fs z#}Y=@YDTwOM)x{K_j*Q;dPdJ?Mz0n|pLRx{4n|)f>SXlmV)XB04CrSJn#dS5nK2lM zrZ9#~WelCp7&e13Y$jvaEXHskn$2V!!DN-nWS__6T*l;H&Fopn?A6HZ-6WRLFP=R` zqG+CE#d4|IbyAI+rJJ`&x9*T`+a=p|0O(+s{UBcyZdkhj=yS1>AirP+0R;mf2uMgM zC}@~JfByORAh4SyRgi&!(cja>F(l*O+nd+@4m$|6K6KDn_&uvCpV23&>G9HJp{xgg zoq1^2_p9@|WEo z*X_Uko@K)qYYv~>43eQGMdbiGbo>E~Q& zrYBH{QP^@Sti!`2)uG{irBBq@y*$B zi#&(U-*=fp74j)RyIw49+0MRPMRU)+a2r*PJ$L5roHt2$UjExCTZSbq%V!HeS7J$N zdG@vOZB4v_lF7Plrx+hxo7(fCV&}fHq)$ literal 0 HcmV?d00001 diff --git a/packages/async_button_builder/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/packages/async_button_builder/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..d5f1c8d34e7a88e3f88bea192c3a370d44689c3c GIT binary patch literal 1031 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof literal 0 HcmV?d00001 diff --git a/packages/async_button_builder/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/packages/async_button_builder/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..4d6372eebdb28e45604e46eeda8dd24651419bc0 GIT binary patch literal 1443 zcmb`G{WsKk6vsdJTdFg%tJav9_E4vzrOaqkWF|A724Nly!y+?N9`YV6wZ}5(X(D_N(?!*n3`|_r0Hc?=PQw&*vnU?QTFY zB_MsH|!j$PP;I}?dppoE_gA(4uc!jV&0!l7_;&p2^pxNo>PEcNJv za5_RT$o2Mf!<+r?&EbHH6nMoTsDOa;mN(wv8RNsHpG)`^ymG-S5By8=l9iVXzN_eG%Xg2@Xeq76tTZ*dGh~Lo9vl;Zfs+W#BydUw zCkZ$o1LqWQO$FC9aKlLl*7x9^0q%0}$OMlp@Kk_jHXOjofdePND+j!A{q!8~Jn+s3 z?~~w@4?egS02}8NuulUA=L~QQfm;MzCGd)XhiftT;+zFO&JVyp2mBww?;QByS_1w! zrQlx%{^cMj0|Bo1FjwY@Q8?Hx0cIPF*@-ZRFpPc#bBw{5@tD(5%sClzIfl8WU~V#u zm5Q;_F!wa$BSpqhN>W@2De?TKWR*!ujY;Yylk_X5#~V!L*Gw~;$%4Q8~Mad z@`-kG?yb$a9cHIApZDVZ^U6Xkp<*4rU82O7%}0jjHlK{id@?-wpN*fCHXyXh(bLt* zPc}H-x0e4E&nQ>y%B-(EL=9}RyC%MyX=upHuFhAk&MLbsF0LP-q`XnH78@fT+pKPW zu72MW`|?8ht^tz$iC}ZwLp4tB;Q49K!QCF3@!iB1qOI=?w z7In!}F~ij(18UYUjnbmC!qKhPo%24?8U1x{7o(+?^Zu0Hx81|FuS?bJ0jgBhEMzf< zCgUq7r2OCB(`XkKcN-TL>u5y#dD6D!)5W?`O5)V^>jb)P)GBdy%t$uUMpf$SNV31$ zb||OojAbvMP?T@$h_ZiFLFVHDmbyMhJF|-_)HX3%m=CDI+ID$0^C>kzxprBW)hw(v zr!Gmda);ICoQyhV_oP5+C%?jcG8v+D@9f?Dk*!BxY}dazmrT@64UrP3hlslANK)bq z$67n83eh}OeW&SV@HG95P|bjfqJ7gw$e+`Hxo!4cx`jdK1bJ>YDSpGKLPZ^1cv$ek zIB?0S<#tX?SJCLWdMd{-ME?$hc7A$zBOdIJ)4!KcAwb=VMov)nK;9z>x~rfT1>dS+ zZ6#`2v@`jgbqq)P22H)Tx2CpmM^o1$B+xT6`(v%5xJ(?j#>Q$+rx_R|7TzDZe{J6q zG1*EcU%tE?!kO%^M;3aM6JN*LAKUVb^xz8-Pxo#jR5(-KBeLJvA@-gxNHx0M-ZJLl z;#JwQoh~9V?`UVo#}{6ka@II>++D@%KqGpMdlQ}?9E*wFcf5(#XQnP$Dk5~%iX^>f z%$y;?M0BLp{O3a(-4A?ewryHrrD%cx#Q^%KY1H zNre$ve+vceSLZcNY4U(RBX&)oZn*Py()h)XkE?PL$!bNb{N5FVI2Y%LKEm%yvpyTP z(1P?z~7YxD~Rf<(a@_y` literal 0 HcmV?d00001 diff --git a/packages/async_button_builder/example/android/app/src/main/res/values-night/styles.xml b/packages/async_button_builder/example/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 0000000..449a9f9 --- /dev/null +++ b/packages/async_button_builder/example/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/packages/async_button_builder/example/android/app/src/main/res/values/styles.xml b/packages/async_button_builder/example/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..d74aa35 --- /dev/null +++ b/packages/async_button_builder/example/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/packages/async_button_builder/example/android/app/src/profile/AndroidManifest.xml b/packages/async_button_builder/example/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..c208884 --- /dev/null +++ b/packages/async_button_builder/example/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/packages/async_button_builder/example/android/build.gradle b/packages/async_button_builder/example/android/build.gradle new file mode 100644 index 0000000..c505a86 --- /dev/null +++ b/packages/async_button_builder/example/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:4.1.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/packages/async_button_builder/example/android/gradle.properties b/packages/async_button_builder/example/android/gradle.properties new file mode 100644 index 0000000..94adc3a --- /dev/null +++ b/packages/async_button_builder/example/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true diff --git a/packages/async_button_builder/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/async_button_builder/example/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..bc6a58a --- /dev/null +++ b/packages/async_button_builder/example/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip diff --git a/packages/async_button_builder/example/android/settings.gradle b/packages/async_button_builder/example/android/settings.gradle new file mode 100644 index 0000000..44e62bc --- /dev/null +++ b/packages/async_button_builder/example/android/settings.gradle @@ -0,0 +1,11 @@ +include ':app' + +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") +def properties = new Properties() + +assert localPropertiesFile.exists() +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + +def flutterSdkPath = properties.getProperty("flutter.sdk") +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/packages/async_button_builder/example/ios/.gitignore b/packages/async_button_builder/example/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/packages/async_button_builder/example/ios/.gitignore @@ -0,0 +1,32 @@ +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/packages/async_button_builder/example/ios/Flutter/AppFrameworkInfo.plist b/packages/async_button_builder/example/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 0000000..9367d48 --- /dev/null +++ b/packages/async_button_builder/example/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.0 + + diff --git a/packages/async_button_builder/example/ios/Flutter/Debug.xcconfig b/packages/async_button_builder/example/ios/Flutter/Debug.xcconfig new file mode 100644 index 0000000..b2f5fae --- /dev/null +++ b/packages/async_button_builder/example/ios/Flutter/Debug.xcconfig @@ -0,0 +1,3 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/packages/async_button_builder/example/ios/Flutter/Release.xcconfig b/packages/async_button_builder/example/ios/Flutter/Release.xcconfig new file mode 100644 index 0000000..88c2914 --- /dev/null +++ b/packages/async_button_builder/example/ios/Flutter/Release.xcconfig @@ -0,0 +1,3 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" diff --git a/packages/async_button_builder/example/ios/Podfile b/packages/async_button_builder/example/ios/Podfile new file mode 100644 index 0000000..b29247c --- /dev/null +++ b/packages/async_button_builder/example/ios/Podfile @@ -0,0 +1,41 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end \ No newline at end of file diff --git a/packages/async_button_builder/example/ios/Podfile.lock b/packages/async_button_builder/example/ios/Podfile.lock new file mode 100644 index 0000000..f11c132 --- /dev/null +++ b/packages/async_button_builder/example/ios/Podfile.lock @@ -0,0 +1,16 @@ +PODS: + - Flutter (1.0.0) + +DEPENDENCIES: + - Flutter (from `Flutter`) + +EXTERNAL SOURCES: + Flutter: + :path: Flutter + +SPEC CHECKSUMS: + Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c + +PODFILE CHECKSUM: fc81e398f362bae88bdf55239bd5cf842faad39f + +COCOAPODS: 1.10.1 diff --git a/packages/async_button_builder/example/ios/Runner.xcodeproj/project.pbxproj b/packages/async_button_builder/example/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..ad27a86 --- /dev/null +++ b/packages/async_button_builder/example/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,521 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 052090A8264F7CC7D59BAC4F /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 166593E2DDC1580301FBE4EB /* Pods_Runner.framework */; }; + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 166593E2DDC1580301FBE4EB /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 979288937DB54B7A8E167BFD /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + ABECF997BE9D843ACE309A51 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + BFE91A80E9CF01FB47297D69 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 052090A8264F7CC7D59BAC4F /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 421781B0B716E5E3F11A65B3 /* Pods */ = { + isa = PBXGroup; + children = ( + ABECF997BE9D843ACE309A51 /* Pods-Runner.debug.xcconfig */, + BFE91A80E9CF01FB47297D69 /* Pods-Runner.release.xcconfig */, + 979288937DB54B7A8E167BFD /* Pods-Runner.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + 421781B0B716E5E3F11A65B3 /* Pods */, + C21EF53B5D1A17BF8839457D /* Frameworks */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + C21EF53B5D1A17BF8839457D /* Frameworks */ = { + isa = PBXGroup; + children = ( + 166593E2DDC1580301FBE4EB /* Pods_Runner.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 0D390D42CD24A841DCDBE0FB /* [CP] Check Pods Manifest.lock */, + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 0D390D42CD24A841DCDBE0FB /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.example.example; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.example.example; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.example.example; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/packages/async_button_builder/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/async_button_builder/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/packages/async_button_builder/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/packages/async_button_builder/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/async_button_builder/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/packages/async_button_builder/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/async_button_builder/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/async_button_builder/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/packages/async_button_builder/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/packages/async_button_builder/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/async_button_builder/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..a28140c --- /dev/null +++ b/packages/async_button_builder/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/async_button_builder/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/async_button_builder/example/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..21a3cc1 --- /dev/null +++ b/packages/async_button_builder/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/packages/async_button_builder/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/async_button_builder/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/packages/async_button_builder/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/async_button_builder/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/async_button_builder/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/packages/async_button_builder/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/packages/async_button_builder/example/ios/Runner/AppDelegate.swift b/packages/async_button_builder/example/ios/Runner/AppDelegate.swift new file mode 100644 index 0000000..70693e4 --- /dev/null +++ b/packages/async_button_builder/example/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import UIKit +import Flutter + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d36b1fa --- /dev/null +++ b/packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..dc9ada4725e9b0ddb1deab583e5b5102493aa332 GIT binary patch literal 10932 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 literal 0 HcmV?d00001 diff --git a/packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..f091b6b0bca859a3f474b03065bef75ba58a9e4c GIT binary patch literal 1588 zcmV-42Fv-0P)C1SqPt}wig>|5Crh^=oyX$BK<}M8eLU3e2hGT;=G|!_SP)7zNI6fqUMB=)y zRAZ>eDe#*r`yDAVgB_R*LB*MAc)8(b{g{9McCXW!lq7r(btRoB9!8B-#AI6JMb~YFBEvdsV)`mEQO^&#eRKx@b&x- z5lZm*!WfD8oCLzfHGz#u7sT0^VLMI1MqGxF^v+`4YYnVYgk*=kU?HsSz{v({E3lb9 z>+xILjBN)t6`=g~IBOelGQ(O990@BfXf(DRI5I$qN$0Gkz-FSc$3a+2fX$AedL4u{ z4V+5Ong(9LiGcIKW?_352sR;LtDPmPJXI{YtT=O8=76o9;*n%_m|xo!i>7$IrZ-{l z-x3`7M}qzHsPV@$v#>H-TpjDh2UE$9g6sysUREDy_R(a)>=eHw-WAyfIN z*qb!_hW>G)Tu8nSw9yn#3wFMiLcfc4pY0ek1}8(NqkBR@t4{~oC>ryc-h_ByH(Cg5 z>ao-}771+xE3um9lWAY1FeQFxowa1(!J(;Jg*wrg!=6FdRX+t_<%z&d&?|Bn){>zm zZQj(aA_HeBY&OC^jj*)N`8fa^ePOU72VpInJoI1?`ty#lvlNzs(&MZX+R%2xS~5Kh zX*|AU4QE#~SgPzOXe9>tRj>hjU@c1k5Y_mW*Jp3fI;)1&g3j|zDgC+}2Q_v%YfDax z!?umcN^n}KYQ|a$Lr+51Nf9dkkYFSjZZjkma$0KOj+;aQ&721~t7QUKx61J3(P4P1 zstI~7-wOACnWP4=8oGOwz%vNDqD8w&Q`qcNGGrbbf&0s9L0De{4{mRS?o0MU+nR_! zrvshUau0G^DeMhM_v{5BuLjb#Hh@r23lDAk8oF(C+P0rsBpv85EP>4CVMx#04MOfG z;P%vktHcXwTj~+IE(~px)3*MY77e}p#|c>TD?sMatC0Tu4iKKJ0(X8jxQY*gYtxsC z(zYC$g|@+I+kY;dg_dE>scBf&bP1Nc@Hz<3R)V`=AGkc;8CXqdi=B4l2k|g;2%#m& z*jfX^%b!A8#bI!j9-0Fi0bOXl(-c^AB9|nQaE`*)Hw+o&jS9@7&Gov#HbD~#d{twV zXd^Tr^mWLfFh$@Dr$e;PBEz4(-2q1FF0}c;~B5sA}+Q>TOoP+t>wf)V9Iy=5ruQa;z)y zI9C9*oUga6=hxw6QasLPnee@3^Rr*M{CdaL5=R41nLs(AHk_=Y+A9$2&H(B7!_pURs&8aNw7?`&Z&xY_Ye z)~D5Bog^td-^QbUtkTirdyK^mTHAOuptDflut!#^lnKqU md>ggs(5nOWAqO?umG&QVYK#ibz}*4>0000U6E9hRK9^#O7(mu>ETqrXGsduA8$)?`v2seloOCza43C{NQ$$gAOH**MCn0Q?+L7dl7qnbRdqZ8LSVp1ItDxhxD?t@5_yHg6A8yI zC*%Wgg22K|8E#!~cTNYR~@Y9KepMPrrB8cABapAFa=`H+UGhkXUZV1GnwR1*lPyZ;*K(i~2gp|@bzp8}og7e*#% zEnr|^CWdVV!-4*Y_7rFvlww2Ze+>j*!Z!pQ?2l->4q#nqRu9`ELo6RMS5=br47g_X zRw}P9a7RRYQ%2Vsd0Me{_(EggTnuN6j=-?uFS6j^u69elMypu?t>op*wBx<=Wx8?( ztpe^(fwM6jJX7M-l*k3kEpWOl_Vk3@(_w4oc}4YF4|Rt=2V^XU?#Yz`8(e?aZ@#li0n*=g^qOcVpd-Wbok=@b#Yw zqn8u9a)z>l(1kEaPYZ6hwubN6i<8QHgsu0oE) ziJ(p;Wxm>sf!K+cw>R-(^Y2_bahB+&KI9y^);#0qt}t-$C|Bo71lHi{_+lg#f%RFy z0um=e3$K3i6K{U_4K!EX?F&rExl^W|G8Z8;`5z-k}OGNZ0#WVb$WCpQu-_YsiqKP?BB# vzVHS-CTUF4Ozn5G+mq_~Qqto~ahA+K`|lyv3(-e}00000NkvXXu0mjfd`9t{ literal 0 HcmV?d00001 diff --git a/packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..d0ef06e7edb86cdfe0d15b4b0d98334a86163658 GIT binary patch literal 1716 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 literal 0 HcmV?d00001 diff --git a/packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c8f9ed8f5cee1c98386d13b17e89f719e83555b2 GIT binary patch literal 1895 zcmV-t2blPYP)FQtfgmafE#=YDCq`qUBt#QpG%*H6QHY765~R=q zZ6iudfM}q!Pz#~9JgOi8QJ|DSu?1-*(kSi1K4#~5?#|rh?sS)(-JQqX*}ciXJ56_H zdw=^s_srbAdqxlvGyrgGet#6T7_|j;95sL%MtM;q86vOxKM$f#puR)Bjv9Zvz9-di zXOTSsZkM83)E9PYBXC<$6(|>lNLVBb&&6y{NByFCp%6+^ALR@NCTse_wqvNmSWI-m z!$%KlHFH2omF!>#%1l3LTZg(s7eof$7*xB)ZQ0h?ejh?Ta9fDv59+u#MokW+1t8Zb zgHv%K(u9G^Lv`lh#f3<6!JVTL3(dCpxHbnbA;kKqQyd1~^Xe0VIaYBSWm6nsr;dFj z4;G-RyL?cYgsN1{L4ZFFNa;8)Rv0fM0C(~Tkit94 zz#~A)59?QjD&pAPSEQ)p8gP|DS{ng)j=2ux)_EzzJ773GmQ_Cic%3JJhC0t2cx>|v zJcVusIB!%F90{+}8hG3QU4KNeKmK%T>mN57NnCZ^56=0?&3@!j>a>B43pi{!u z7JyDj7`6d)qVp^R=%j>UIY6f+3`+qzIc!Y_=+uN^3BYV|o+$vGo-j-Wm<10%A=(Yk^beI{t%ld@yhKjq0iNjqN4XMGgQtbKubPM$JWBz}YA65k%dm*awtC^+f;a-x4+ddbH^7iDWGg&N0n#MW{kA|=8iMUiFYvMoDY@sPC#t$55gn6ykUTPAr`a@!(;np824>2xJthS z*ZdmT`g5-`BuJs`0LVhz+D9NNa3<=6m;cQLaF?tCv8)zcRSh66*Z|vXhG@$I%U~2l z?`Q zykI#*+rQ=z6Jm=Bui-SfpDYLA=|vzGE(dYm=OC8XM&MDo7ux4UF1~0J1+i%aCUpRe zt3L_uNyQ*cE(38Uy03H%I*)*Bh=Lb^Xj3?I^Hnbeq72(EOK^Y93CNp*uAA{5Lc=ky zx=~RKa4{iTm{_>_vSCm?$Ej=i6@=m%@VvAITnigVg{&@!7CDgs908761meDK5azA} z4?=NOH|PdvabgJ&fW2{Mo$Q0CcD8Qc84%{JPYt5EiG{MdLIAeX%T=D7NIP4%Hw}p9 zg)==!2Lbp#j{u_}hMiao9=!VSyx0gHbeCS`;q&vzeq|fs`y&^X-lso(Ls@-706qmA z7u*T5PMo_w3{se1t2`zWeO^hOvTsohG_;>J0wVqVe+n)AbQCx)yh9;w+J6?NF5Lmo zecS@ieAKL8%bVd@+-KT{yI|S}O>pYckUFs;ry9Ow$CD@ztz5K-*D$^{i(_1llhSh^ zEkL$}tsQt5>QA^;QgjgIfBDmcOgi5YDyu?t6vSnbp=1+@6D& z5MJ}B8q;bRlVoxasyhcUF1+)o`&3r0colr}QJ3hcSdLu;9;td>kf@Tcn<@9sIx&=m z;AD;SCh95=&p;$r{Xz3iWCO^MX83AGJ(yH&eTXgv|0=34#-&WAmw{)U7OU9!Wz^!7 zZ%jZFi@JR;>Mhi7S>V7wQ176|FdW2m?&`qa(ScO^CFPR80HucLHOTy%5s*HR0^8)i h0WYBP*#0Ks^FNSabJA*5${_#%002ovPDHLkV1oKhTl@e3 literal 0 HcmV?d00001 diff --git a/packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..a6d6b8609df07bf62e5100a53a01510388bd2b22 GIT binary patch literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ literal 0 HcmV?d00001 diff --git a/packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a6d6b8609df07bf62e5100a53a01510388bd2b22 GIT binary patch literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ literal 0 HcmV?d00001 diff --git a/packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..75b2d164a5a98e212cca15ea7bf2ab5de5108680 GIT binary patch literal 3831 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 literal 0 HcmV?d00001 diff --git a/packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..c4df70d39da7941ef3f6dcb7f06a192d8dcb308d GIT binary patch literal 1888 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 iW8Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/packages/async_button_builder/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/packages/async_button_builder/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/packages/async_button_builder/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/packages/async_button_builder/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/packages/async_button_builder/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/async_button_builder/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 0000000..89c2725 --- /dev/null +++ b/packages/async_button_builder/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/packages/async_button_builder/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/async_button_builder/example/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..f2e259c --- /dev/null +++ b/packages/async_button_builder/example/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/async_button_builder/example/ios/Runner/Base.lproj/Main.storyboard b/packages/async_button_builder/example/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 0000000..f3c2851 --- /dev/null +++ b/packages/async_button_builder/example/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/async_button_builder/example/ios/Runner/Info.plist b/packages/async_button_builder/example/ios/Runner/Info.plist new file mode 100644 index 0000000..a060db6 --- /dev/null +++ b/packages/async_button_builder/example/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + example + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + + diff --git a/packages/async_button_builder/example/ios/Runner/Runner-Bridging-Header.h b/packages/async_button_builder/example/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 0000000..308a2a5 --- /dev/null +++ b/packages/async_button_builder/example/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/packages/async_button_builder/example/lib/main.dart b/packages/async_button_builder/example/lib/main.dart new file mode 100644 index 0000000..27b04ce --- /dev/null +++ b/packages/async_button_builder/example/lib/main.dart @@ -0,0 +1,166 @@ +import 'package:async_button_builder/async_button_builder.dart'; +import 'package:flutter/material.dart'; + +void main() => runApp(MyApp()); + +class MyApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Demo', + theme: ThemeData.dark(), + home: MyHomePage(), + ); + } +} + +class MyHomePage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: Text('Async Buttons')), + body: SizedBox.expand( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Divider(), + Text('Text Button:'), + AsyncButtonBuilder( + child: Text('Click Me'), + onPressed: () async { + await Future.delayed(Duration(seconds: 1)); + }, + builder: (context, child, callback, _) { + return TextButton( + child: child, + onPressed: callback, + ); + }, + ), + Divider(), + Text('Elevated Button:'), + AsyncButtonBuilder( + child: Text('Click Me'), + onPressed: () async { + await Future.delayed(Duration(seconds: 1)); + }, + builder: (context, child, callback, _) { + return ElevatedButton( + child: child, + onPressed: callback, + ); + }, + ), + Divider(), + Text('Custom Outlined Button (Error):'), + AsyncButtonBuilder( + child: Text('Click Me'), + loadingWidget: Text('Loading...'), + onPressed: () async { + await Future.delayed(Duration(seconds: 1)); + + throw 'shucks'; + + // If you want to add a timeout, use something similar to + // + // try { + // await Future.delayed(Duration(seconds: 1)) + // .timeout(Duration(milliseconds: 500)); + // } on TimeoutException catch (_) { + // // Show a popup or something + // rethrow; + // } on Exception catch (_) { + // // Show a dialog or something + // rethrow; + // } + // + // We rethrow so that async_button_builder can handle the error + // state + }, + builder: (context, child, callback, buttonState) { + final buttonColor = buttonState.when( + idle: () => Colors.yellow[200], + loading: () => Colors.grey, + success: () => Colors.orangeAccent, + error: () => Colors.orange, + ); + + return OutlinedButton( + child: child, + onPressed: callback, + style: OutlinedButton.styleFrom( + primary: Colors.black, + backgroundColor: buttonColor, + ), + ); + }, + ), + Divider(), + Text('Custom Material Button:'), + const SizedBox(height: 6.0), + AsyncButtonBuilder( + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16.0, + vertical: 8.0, + ), + child: Text( + 'Click Me', + style: TextStyle(color: Colors.white), + ), + ), + loadingWidget: Padding( + padding: const EdgeInsets.all(8.0), + child: SizedBox( + height: 16.0, + width: 16.0, + child: CircularProgressIndicator( + valueColor: AlwaysStoppedAnimation(Colors.white), + ), + ), + ), + successWidget: Padding( + padding: const EdgeInsets.all(4.0), + child: Icon( + Icons.check, + color: Colors.purpleAccent, + ), + ), + onPressed: () async { + await Future.delayed(Duration(seconds: 2)); + }, + loadingSwitchInCurve: Curves.bounceInOut, + loadingTransitionBuilder: (child, animation) { + return SlideTransition( + position: Tween( + begin: Offset(0, 1.0), + end: Offset(0, 0), + ).animate(animation), + child: child, + ); + }, + builder: (context, child, callback, state) { + return Material( + color: state.maybeWhen( + success: () => Colors.purple[100], + orElse: () => Colors.blue, + ), + // This prevents the loading indicator showing below the + // button + clipBehavior: Clip.hardEdge, + shape: StadiumBorder(), + child: InkWell( + child: child, + onTap: callback, + ), + ); + }, + ), + Divider(), + ], + ), + ), + ); + } +} diff --git a/packages/async_button_builder/example/pubspec.lock b/packages/async_button_builder/example/pubspec.lock new file mode 100644 index 0000000..ac9d930 --- /dev/null +++ b/packages/async_button_builder/example/pubspec.lock @@ -0,0 +1,189 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + async: + dependency: transitive + description: + name: async + url: "https://pub.dartlang.org" + source: hosted + version: "2.8.1" + async_button_builder: + dependency: "direct main" + description: + path: ".." + relative: true + source: path + version: "2.1.3+2" + async_button_core: + dependency: transitive + description: + path: "../../async_button_core" + relative: true + source: path + version: "0.0.1" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + characters: + dependency: transitive + description: + name: characters + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + charcode: + dependency: transitive + description: + name: charcode + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.1" + clock: + dependency: transitive + description: + name: clock + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + collection: + dependency: transitive + description: + name: collection + url: "https://pub.dartlang.org" + source: hosted + version: "1.15.0" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" + fake_async: + dependency: transitive + description: + name: fake_async + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + freezed_annotation: + dependency: transitive + description: + name: freezed_annotation + url: "https://pub.dartlang.org" + source: hosted + version: "0.14.3" + json_annotation: + dependency: transitive + description: + name: json_annotation + url: "https://pub.dartlang.org" + source: hosted + version: "4.1.0" + matcher: + dependency: transitive + description: + name: matcher + url: "https://pub.dartlang.org" + source: hosted + version: "0.12.10" + meta: + dependency: transitive + description: + name: meta + url: "https://pub.dartlang.org" + source: hosted + version: "1.7.0" + path: + dependency: transitive + description: + name: path + url: "https://pub.dartlang.org" + source: hosted + version: "1.8.0" + pedantic: + dependency: "direct dev" + description: + name: pedantic + url: "https://pub.dartlang.org" + source: hosted + version: "1.10.0-nullsafety.3" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + url: "https://pub.dartlang.org" + source: hosted + version: "1.8.1" + stack_trace: + dependency: transitive + description: + name: stack_trace + url: "https://pub.dartlang.org" + source: hosted + version: "1.10.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + test_api: + dependency: transitive + description: + name: test_api + url: "https://pub.dartlang.org" + source: hosted + version: "0.4.2" + typed_data: + dependency: transitive + description: + name: typed_data + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.0" + vector_math: + dependency: transitive + description: + name: vector_math + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" +sdks: + dart: ">=2.12.0 <3.0.0" + flutter: ">=1.17.0" diff --git a/packages/async_button_builder/example/pubspec.yaml b/packages/async_button_builder/example/pubspec.yaml new file mode 100644 index 0000000..3e438cf --- /dev/null +++ b/packages/async_button_builder/example/pubspec.yaml @@ -0,0 +1,23 @@ +name: example +description: A new Flutter project. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev +version: 1.0.0+1 + +environment: + sdk: ">=2.7.0 <3.0.0" + +dependencies: + flutter: + sdk: flutter + cupertino_icons: ^1.0.1 + + async_button_builder: + path: ../ + +dev_dependencies: + flutter_test: + sdk: flutter + pedantic: ^1.10.0-nullsafety.3 + +flutter: + uses-material-design: true diff --git a/packages/async_button_builder/example/test/widget_test.dart b/packages/async_button_builder/example/test/widget_test.dart new file mode 100644 index 0000000..747db1d --- /dev/null +++ b/packages/async_button_builder/example/test/widget_test.dart @@ -0,0 +1,30 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility that Flutter provides. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'package:example/main.dart'; + +void main() { + testWidgets('Counter increments smoke test', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget(MyApp()); + + // Verify that our counter starts at 0. + expect(find.text('0'), findsOneWidget); + expect(find.text('1'), findsNothing); + + // Tap the '+' icon and trigger a frame. + await tester.tap(find.byIcon(Icons.add)); + await tester.pump(); + + // Verify that our counter has incremented. + expect(find.text('0'), findsNothing); + expect(find.text('1'), findsOneWidget); + }); +} diff --git a/packages/async_button_builder/example/web/favicon.png b/packages/async_button_builder/example/web/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..8aaa46ac1ae21512746f852a42ba87e4165dfdd1 GIT binary patch literal 917 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|I14-?iy0X7 zltGxWVyS%@P(fs7NJL45ua8x7ey(0(N`6wRUPW#JP&EUCO@$SZnVVXYs8ErclUHn2 zVXFjIVFhG^g!Ppaz)DK8ZIvQ?0~DO|i&7O#^-S~(l1AfjnEK zjFOT9D}DX)@^Za$W4-*MbbUihOG|wNBYh(yU7!lx;>x^|#0uTKVr7USFmqf|i<65o z3raHc^AtelCMM;Vme?vOfh>Xph&xL%(-1c06+^uR^q@XSM&D4+Kp$>4P^%3{)XKjo zGZknv$b36P8?Z_gF{nK@`XI}Z90TzwSQO}0J1!f2c(B=V`5aP@1P1a|PZ!4!3&Gl8 zTYqUsf!gYFyJnXpu0!n&N*SYAX-%d(5gVjrHJWqXQshj@!Zm{!01WsQrH~9=kTxW#6SvuapgMqt>$=j#%eyGrQzr zP{L-3gsMA^$I1&gsBAEL+vxi1*Igl=8#8`5?A-T5=z-sk46WA1IUT)AIZHx1rdUrf zVJrJn<74DDw`j)Ki#gt}mIT-Q`XRa2-jQXQoI%w`nb|XblvzK${ZzlV)m-XcwC(od z71_OEC5Bt9GEXosOXaPTYOia#R4ID2TiU~`zVMl08TV_C%DnU4^+HE>9(CE4D6?Fz oujB08i7adh9xk7*FX66dWH6F5TM;?E2b5PlUHx3vIVCg!0Dx9vYXATM literal 0 HcmV?d00001 diff --git a/packages/async_button_builder/example/web/icons/Icon-192.png b/packages/async_button_builder/example/web/icons/Icon-192.png new file mode 100644 index 0000000000000000000000000000000000000000..b749bfef07473333cf1dd31e9eed89862a5d52aa GIT binary patch literal 5292 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 literal 0 HcmV?d00001 diff --git a/packages/async_button_builder/example/web/icons/Icon-512.png b/packages/async_button_builder/example/web/icons/Icon-512.png new file mode 100644 index 0000000000000000000000000000000000000000..88cfd48dff1169879ba46840804b412fe02fefd6 GIT binary patch literal 8252 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 literal 0 HcmV?d00001 diff --git a/packages/async_button_builder/example/web/index.html b/packages/async_button_builder/example/web/index.html new file mode 100644 index 0000000..1460b5e --- /dev/null +++ b/packages/async_button_builder/example/web/index.html @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + example + + + + + + + + diff --git a/packages/async_button_builder/example/web/manifest.json b/packages/async_button_builder/example/web/manifest.json new file mode 100644 index 0000000..8c01291 --- /dev/null +++ b/packages/async_button_builder/example/web/manifest.json @@ -0,0 +1,23 @@ +{ + "name": "example", + "short_name": "example", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + } + ] +} diff --git a/packages/async_button_builder/lib/async_button_builder.dart b/packages/async_button_builder/lib/async_button_builder.dart new file mode 100644 index 0000000..c7a5813 --- /dev/null +++ b/packages/async_button_builder/lib/async_button_builder.dart @@ -0,0 +1,3 @@ +library async_button_builder; + +export 'package:async_button_builder/src/async_button_builder.dart'; diff --git a/packages/async_button_builder/lib/src/async_button_builder.dart b/packages/async_button_builder/lib/src/async_button_builder.dart new file mode 100644 index 0000000..22333c2 --- /dev/null +++ b/packages/async_button_builder/lib/src/async_button_builder.dart @@ -0,0 +1,445 @@ +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +typedef AsyncButtonBuilderCallback = Widget Function( + BuildContext context, + Widget child, + AsyncCallback? callback, + ButtonState buttonState, +); + +/// A `builder` that wraps a button providing disabled, loading, success and +/// error states while retaining almost full access to the original Button's +/// API. This is useful for any long running operations and helps better +/// improve UX. +/// +/// {@tool dartpad --template=stateful_widget_material} +/// +/// ```dart +/// +/// @override +/// Widget build(BuildContext context) { +/// return AsyncButtonBuilder( +/// child: Text('Click Me'), +/// loadingWidget: Text('Loading...'), +/// onPressed: () async { +/// await Future.delayed(Duration(seconds: 1)); +/// +/// throw 'shucks'; +/// }, +/// builder: (context, child, callback, buttonState) { +/// final buttonColor = buttonState.when( +/// idle: () => Colors.yellow[200], +/// loading: () => Colors.grey, +/// success: () => Colors.orangeAccent, +/// error: () => Colors.orange, +/// ); +/// +/// return OutlinedButton( +/// child: child, +/// onPressed: callback, +/// style: OutlinedButton.styleFrom( +/// primary: Colors.black, +/// backgroundColor: buttonColor, +/// ), +/// ); +/// }, +/// ), +/// } +/// ``` +/// {@end-tool} +/// +class AsyncButtonBuilder extends StatefulWidget { + /// This builder provides the widget's [BuildContext], the variable [child] + /// based on button state as well as the [callback] that should be passed to + /// the button and the current [ButtonState] + final AsyncButtonBuilderCallback builder; + + /// The child of the button. In the case of an [IconButton], this can be a an + /// [Icon]. For a [TextButton], a [Text]. + /// + /// This child will be animated between for the [loadingWidget] or default + /// [CircularProgressIndicator] when the asynchronous [onPressed] is called. + /// The animation will take place over [duration]. + final Widget child; + + /// The animation's duration between [child], [loadingWidget], + /// [successWidget] and [errorWidget]. This same value is used for both the + /// internal [AnimatedSize] and [TransitionBuilder]. + final Duration duration; + + /// The animation's reverse duration between [child], [loadingWidget], + /// [successWidget] and [errorWidget]. This same value is used for both the + /// internal [AnimatedSize] and [TransitionBuilder]. + final Duration reverseDuration; + + /// A callback that runs the async task. This is wrapped in order to begin + /// the button's internal `isLoading` before and after the operation + /// completes. + final AsyncCallback? onPressed; + + /// This is used to manually drive the state of the loading button thus + /// initiating the corresponding animation and showing the correct button + /// child. + final ButtonState buttonState; + + /// This is used to manually drive the disabled state of the button. + final bool disabled; + + /// The widget replaces the [child] when the button is in the loading state. + /// If this is null the default widget is: + /// + /// SizedBox( + /// height: 16.0, + /// width: 16.0, + /// child: CircularProgressIndicator(), + /// ) + final Widget? loadingWidget; + + /// The widget used to replace the [child] when the button is in a success + /// state. If this is null the default widget is: + /// + /// Icon( + /// Icons.check, + /// color: Theme.of(context).accentColor, + /// ); + final Widget? successWidget; + + /// The widget used to replace the [child] when the button is in a error + /// state. If this is null the default widget is: + /// + /// Icon( + /// Icons.error, + /// color: Theme.of(context).errorColor, + /// ) + final Widget? errorWidget; + + /// Whether to show the [successWidget] on success. + final bool showSuccess; + + /// Whether to show the [errorWidget] on error. + final bool showError; + + /// Optional [EdgeInsets] that will wrap around the [errorWidget]. This is a + /// convenience field that can be replaced by defining your own [errorWidget] + /// and wrapping it in a [Padding]. + final EdgeInsets? errorPadding; + + /// Optional [EdgeInsets] that will wrap around the [successWidget]. This is a + /// convenience field that can be replaced by defining your own + /// [successWidget] and wrapping it in a [Padding]. + final EdgeInsets? successPadding; + + /// Defines a custom transition when animating between any state and `idle` + final AnimatedSwitcherTransitionBuilder idleTransitionBuilder; + + /// Defines a custom transition when animating between any state and `loading` + final AnimatedSwitcherTransitionBuilder loadingTransitionBuilder; + + /// Defines a custom transition when animating between any state and `success` + final AnimatedSwitcherTransitionBuilder successTransitionBuilder; + + /// Defines a custom transition when animating between any state and `error` + final AnimatedSwitcherTransitionBuilder errorTransitionBuilder; + + /// The amount of idle time the [successWidget] shows + final Duration successDuration; + + /// The amount of idle time the [errorWidget] shows + final Duration errorDuration; + + /// Defines a curve for the custom transition. This used in in an + /// [AnimatedSwitcher] and only takes effect when animating to `idle` + final Curve idleSwitchInCurve; + + /// Defines a curve for the custom transition. This used in in an + /// [AnimatedSwitcher] and only takes effect when animating to `loading` + final Curve loadingSwitchInCurve; + + /// Defines a curve for the custom transition. This used in in an + /// [AnimatedSwitcher] and only takes effect when animating to `success` + final Curve successSwitchInCurve; + + /// Defines a curve for the custom transition. This used in in an + /// [AnimatedSwitcher] and only takes effect when animating to `error` + final Curve errorSwitchInCurve; + + /// Defines a curve for the custom transition. This used in in an + /// [AnimatedSwitcher] and only takes effect when animating out of `idle` + final Curve idleSwitchOutCurve; + + /// Defines a curve for the custom transition. This used in in an + /// [AnimatedSwitcher] and only takes effect when animating out of `loading` + final Curve loadingSwitchOutCurve; + + /// Defines a curve for the custom transition. This used in in an + /// [AnimatedSwitcher] and only takes effect when animating out of `success` + final Curve successSwitchOutCurve; + + /// Defines a curve for the custom transition. This used in in an + /// [AnimatedSwitcher] and only takes effect when animating out of `error` + final Curve errorSwitchOutCurve; + + /// Defines a curve for the internal [AnimatedSize] + final Curve sizeCurve; + + /// Defines the [Clip] for the internal [AnimatedSize] + final Clip sizeClipBehavior; + + /// Defines the [Alignment] for the internal [AnimatedSize] + final Alignment sizeAlignment; + + /// Whether to animate the [Size] of the widget implicitly. + final bool animateSize; + + const AsyncButtonBuilder({ + Key? key, + required this.child, + required this.onPressed, + required this.builder, + this.loadingWidget, + this.successWidget, + this.errorWidget, + this.showSuccess = true, + this.showError = true, + this.errorPadding, + this.successPadding, + this.buttonState = const ButtonState.idle(), + this.duration = const Duration(milliseconds: 250), + this.reverseDuration = const Duration(milliseconds: 250), + this.disabled = false, + this.successDuration = const Duration(seconds: 1), + this.errorDuration = const Duration(seconds: 1), + this.loadingTransitionBuilder = AnimatedSwitcher.defaultTransitionBuilder, + this.idleTransitionBuilder = AnimatedSwitcher.defaultTransitionBuilder, + this.successTransitionBuilder = AnimatedSwitcher.defaultTransitionBuilder, + this.errorTransitionBuilder = AnimatedSwitcher.defaultTransitionBuilder, + this.idleSwitchInCurve = Curves.linear, + this.loadingSwitchInCurve = Curves.linear, + this.successSwitchInCurve = Curves.linear, + this.errorSwitchInCurve = Curves.linear, + this.idleSwitchOutCurve = Curves.linear, + this.loadingSwitchOutCurve = Curves.linear, + this.successSwitchOutCurve = Curves.linear, + this.errorSwitchOutCurve = Curves.linear, + this.sizeCurve = Curves.linear, + this.sizeClipBehavior = Clip.hardEdge, + this.sizeAlignment = Alignment.center, + this.animateSize = true, + }) : super(key: key); + // TODO: I need asserts that will assert the keys are different for child, + // loading, error, etc. because otherwise transitions won't work as expected + // and I'll get user issues + + @override + _AsyncButtonBuilderState createState() => _AsyncButtonBuilderState(); +} + +class _AsyncButtonBuilderState extends State + with SingleTickerProviderStateMixin { + late ButtonState buttonState; + Timer? timer; + + @override + void initState() { + buttonState = widget.buttonState; + super.initState(); + } + + @override + void didUpdateWidget(covariant AsyncButtonBuilder oldWidget) { + if (widget.buttonState != oldWidget.buttonState) { + setState(() { + buttonState = buttonState; + }); + } + + super.didUpdateWidget(oldWidget); + } + + @override + void dispose() { + timer?.cancel(); + + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + final onPressed = widget.onPressed; + final widgetKey = widget.key; + final loadingWidget = widget.loadingWidget ?? + const SizedBox( + height: 16.0, + width: 16.0, + child: CircularProgressIndicator(), + ); + var successWidget = widget.successWidget ?? + Icon( + Icons.check, + color: theme.colorScheme.secondary, + ); + var errorWidget = widget.errorWidget ?? + Icon( + Icons.error, + color: theme.errorColor, + ); + final successPadding = widget.successPadding; + final errorPadding = widget.errorPadding; + + // This is necessary in the case of nested async button builders. + // We cannot have the same __idle__, __loading__, etc. keys as they might + // conflict with one another. + String parentKeyValue = ''; + + if (widgetKey != null && widgetKey is ValueKey) { + parentKeyValue = widgetKey.value.toString(); + } + + if (successPadding != null) { + successWidget = Padding( + padding: successPadding, + child: successWidget, + ); + } + + if (errorPadding != null) { + errorWidget = Padding( + padding: errorPadding, + child: errorWidget, + ); + } + + final switcher = AnimatedSwitcher( + // TODO: This duration is same as size's duration. That's okay right? + duration: widget.duration, + reverseDuration: widget.reverseDuration, + switchInCurve: buttonState.when( + idle: () => widget.idleSwitchInCurve, + loading: () => widget.loadingSwitchInCurve, + success: () => widget.successSwitchInCurve, + error: () => widget.errorSwitchInCurve, + ), + switchOutCurve: buttonState.when( + idle: () => widget.idleSwitchOutCurve, + loading: () => widget.loadingSwitchOutCurve, + success: () => widget.successSwitchOutCurve, + error: () => widget.errorSwitchOutCurve, + ), + transitionBuilder: buttonState.when( + idle: () => widget.idleTransitionBuilder, + loading: () => widget.loadingTransitionBuilder, + success: () => widget.successTransitionBuilder, + error: () => widget.errorTransitionBuilder, + ), + child: buttonState.when( + idle: () => KeyedSubtree( + key: ValueKey('__idle__' + parentKeyValue), + child: widget.child, + ), + loading: () => KeyedSubtree( + key: ValueKey('__loading__' + parentKeyValue), + child: loadingWidget, + ), + success: () => KeyedSubtree( + key: ValueKey('__success__' + parentKeyValue), + child: successWidget, + ), + error: () => KeyedSubtree( + key: ValueKey('__error__' + parentKeyValue), + child: errorWidget, + ), + ), + ); + + return widget.builder( + context, + // TODO: I really just wanted an AnimatedSwitcher and the default + // transitionBuilder to be a SizedTransition but it was impossible + // to figure out how to reproduce the exact behaviour of AnimatedSize + widget.animateSize + ? AnimatedSize( + vsync: this, + duration: widget.duration, + reverseDuration: widget.reverseDuration, + alignment: widget.sizeAlignment, + clipBehavior: widget.sizeClipBehavior, + curve: widget.sizeCurve, + child: switcher, + ) + : switcher, + widget.disabled + ? null + : onPressed == null + ? null + : buttonState.maybeWhen( + idle: () => () { + final completer = Completer(); + // I might not want to set buttonState if we're being + // driven by widget.buttonState... + setState(() { + buttonState = const ButtonState.loading(); + }); + + timer?.cancel(); + + onPressed.call().then((_) { + completer.complete(); + + if (mounted) { + if (widget.showSuccess) { + setState(() { + buttonState = const ButtonState.success(); + }); + + setTimer(widget.successDuration); + } else { + setState(() { + buttonState = const ButtonState.idle(); + }); + } + } + }).catchError((Object error, StackTrace stackTrace) { + completer.completeError(error, stackTrace); + + if (mounted) { + if (widget.showError) { + setState(() { + buttonState = const ButtonState.error(); + }); + + setTimer(widget.errorDuration); + } else { + setState(() { + buttonState = const ButtonState.idle(); + }); + } + } + }); + + return completer.future; + }, + orElse: () => null, + ), + buttonState, + ); + } + + void setTimer(Duration duration) { + timer = Timer( + duration, + () { + timer?.cancel(); + + if (mounted) { + setState(() { + buttonState = const ButtonState.idle(); + }); + } + }, + ); + } +} diff --git a/packages/async_button_builder/pubspec.lock b/packages/async_button_builder/pubspec.lock new file mode 100644 index 0000000..d758aff --- /dev/null +++ b/packages/async_button_builder/pubspec.lock @@ -0,0 +1,476 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + url: "https://pub.dartlang.org" + source: hosted + version: "21.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + url: "https://pub.dartlang.org" + source: hosted + version: "1.5.0" + args: + dependency: transitive + description: + name: args + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + async: + dependency: transitive + description: + name: async + url: "https://pub.dartlang.org" + source: hosted + version: "2.8.1" + async_button_core: + dependency: "direct main" + description: + path: "../async_button_core" + relative: true + source: path + version: "0.0.1" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + build: + dependency: transitive + description: + name: build + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + build_config: + dependency: transitive + description: + name: build_config + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + build_daemon: + dependency: transitive + description: + name: build_daemon + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + build_runner: + dependency: "direct dev" + description: + name: build_runner + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.3" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + url: "https://pub.dartlang.org" + source: hosted + version: "7.0.0" + built_collection: + dependency: transitive + description: + name: built_collection + url: "https://pub.dartlang.org" + source: hosted + version: "5.0.0" + built_value: + dependency: transitive + description: + name: built_value + url: "https://pub.dartlang.org" + source: hosted + version: "8.0.5" + characters: + dependency: transitive + description: + name: characters + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + charcode: + dependency: transitive + description: + name: charcode + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.1" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + cli_util: + dependency: transitive + description: + name: cli_util + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.0" + clock: + dependency: transitive + description: + name: clock + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + code_builder: + dependency: transitive + description: + name: code_builder + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.0" + collection: + dependency: transitive + description: + name: collection + url: "https://pub.dartlang.org" + source: hosted + version: "1.15.0" + convert: + dependency: transitive + description: + name: convert + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" + crypto: + dependency: transitive + description: + name: crypto + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" + dart_style: + dependency: transitive + description: + name: dart_style + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + fake_async: + dependency: transitive + description: + name: fake_async + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + file: + dependency: transitive + description: + name: file + url: "https://pub.dartlang.org" + source: hosted + version: "6.1.0" + fixnum: + dependency: transitive + description: + name: fixnum + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.3" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + freezed: + dependency: "direct dev" + description: + name: freezed + url: "https://pub.dartlang.org" + source: hosted + version: "0.14.2" + freezed_annotation: + dependency: "direct main" + description: + name: freezed_annotation + url: "https://pub.dartlang.org" + source: hosted + version: "0.14.3" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + glob: + dependency: transitive + description: + name: glob + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + graphs: + dependency: transitive + description: + name: graphs + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" + http_parser: + dependency: transitive + description: + name: http_parser + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.0" + io: + dependency: transitive + description: + name: io + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + js: + dependency: transitive + description: + name: js + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.3" + json_annotation: + dependency: transitive + description: + name: json_annotation + url: "https://pub.dartlang.org" + source: hosted + version: "4.1.0" + lints: + dependency: transitive + description: + name: lints + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + logging: + dependency: transitive + description: + name: logging + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + matcher: + dependency: transitive + description: + name: matcher + url: "https://pub.dartlang.org" + source: hosted + version: "0.12.10" + meta: + dependency: transitive + description: + name: meta + url: "https://pub.dartlang.org" + source: hosted + version: "1.7.0" + mime: + dependency: transitive + description: + name: mime + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + package_config: + dependency: transitive + description: + name: package_config + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + path: + dependency: transitive + description: + name: path + url: "https://pub.dartlang.org" + source: hosted + version: "1.8.0" + pedantic: + dependency: transitive + description: + name: pedantic + url: "https://pub.dartlang.org" + source: hosted + version: "1.11.0" + pool: + dependency: transitive + description: + name: pool + url: "https://pub.dartlang.org" + source: hosted + version: "1.5.0" + pub_semver: + dependency: transitive + description: + name: pub_semver + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + shelf: + dependency: transitive + description: + name: shelf + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.1" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_gen: + dependency: transitive + description: + name: source_gen + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + source_span: + dependency: transitive + description: + name: source_span + url: "https://pub.dartlang.org" + source: hosted + version: "1.8.1" + stack_trace: + dependency: transitive + description: + name: stack_trace + url: "https://pub.dartlang.org" + source: hosted + version: "1.10.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + stream_transform: + dependency: transitive + description: + name: stream_transform + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + test_api: + dependency: transitive + description: + name: test_api + url: "https://pub.dartlang.org" + source: hosted + version: "0.4.2" + timing: + dependency: transitive + description: + name: timing + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + typed_data: + dependency: transitive + description: + name: typed_data + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.0" + vector_math: + dependency: transitive + description: + name: vector_math + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + watcher: + dependency: transitive + description: + name: watcher + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + yaml: + dependency: transitive + description: + name: yaml + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.0" +sdks: + dart: ">=2.12.0 <3.0.0" + flutter: ">=1.17.0" diff --git a/packages/async_button_builder/pubspec.yaml b/packages/async_button_builder/pubspec.yaml new file mode 100644 index 0000000..dfd86d9 --- /dev/null +++ b/packages/async_button_builder/pubspec.yaml @@ -0,0 +1,23 @@ +name: async_button_builder +description: A builder to wrap around buttons that handles loading, disabled, error and succes states +version: 2.1.3+2 +homepage: https://github.com/Nolence/async_button/packages/async_button_builder + +environment: + sdk: '>=2.12.0 <3.0.0' + flutter: ">=1.17.0" + +dependencies: + flutter: + sdk: flutter + freezed_annotation: ^0.14.2 + async_button_core: + +dev_dependencies: + flutter_test: + sdk: flutter + build_runner: ^2.0.3 + freezed: ^0.14.2 + flutter_lints: + +flutter: \ No newline at end of file diff --git a/packages/async_button_builder/test/async_button_builder_test.dart b/packages/async_button_builder/test/async_button_builder_test.dart new file mode 100644 index 0000000..61a3968 --- /dev/null +++ b/packages/async_button_builder/test/async_button_builder_test.dart @@ -0,0 +1,151 @@ +import 'package:async_button_builder/async_button_builder.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('displays child text', (WidgetTester tester) async { + final textButton = MaterialApp( + home: AsyncButtonBuilder( + onPressed: () async { + await Future.delayed(const Duration(seconds: 1)); + }, + builder: (context, child, callback, state) { + return TextButton(onPressed: callback, child: child); + }, + child: const Text('click me'), + ), + ); + + await tester.pumpWidget(textButton); + + expect(find.text('click me'), findsOneWidget); + }); + + testWidgets('shows loading widget', (WidgetTester tester) async { + const duration = Duration(milliseconds: 250); + final textButton = MaterialApp( + home: AsyncButtonBuilder( + duration: duration, + loadingWidget: const Text('loading'), + onPressed: () async { + await Future.delayed(const Duration(seconds: 1)); + }, + builder: (context, child, callback, state) { + return TextButton(onPressed: callback, child: child); + }, + child: const Text('click me'), + ), + ); + + await tester.pumpWidget(textButton); + + await tester.tap(find.byType(TextButton)); + + // 1/10 of a second later, loading should be showing + await tester.pump(const Duration(milliseconds: 100)); + + expect(find.text('loading'), findsOneWidget); + + // Let the widget continue to settle otherwise I won't dispose timers + // correctly. TODO: Explain why .900 is the magic number + await tester.pumpAndSettle(const Duration(milliseconds: 900)); + }); + + testWidgets('shows error widget', (WidgetTester tester) async { + const duration = Duration(milliseconds: 250); + final textButton = MaterialApp( + home: AsyncButtonBuilder( + duration: duration, + errorWidget: const Text('error'), + onPressed: () async { + throw ArgumentError(); + }, + builder: (context, child, callback, state) { + return TextButton(onPressed: callback, child: child); + }, + child: const Text('click me'), + ), + ); + + await tester.pumpWidget(textButton); + final button = + find.byType(TextButton).evaluate().first.widget as TextButton; + + expect( + () => button.onPressed!.call(), + throwsA(isInstanceOf()), + ); + + await tester.pump(const Duration(milliseconds: 200)); + + expect(find.text('error'), findsOneWidget); + }); + + testWidgets('Returns to child widget', (WidgetTester tester) async { + const duration = Duration(milliseconds: 250); + final textButton = MaterialApp( + home: AsyncButtonBuilder( + duration: duration, + loadingWidget: const Text('loading'), + onPressed: () async { + await Future.delayed(const Duration(seconds: 1)); + }, + builder: (context, child, callback, state) { + return TextButton(onPressed: callback, child: child); + }, + child: const Text('click me'), + ), + ); + + await tester.pumpWidget(textButton); + + await tester.tap(find.byType(TextButton)); + + await tester.pump(const Duration(milliseconds: 1000)); + + expect(find.text('loading'), findsNothing); + + expect(find.text('click me'), findsOneWidget); + }); + + // TODO: Make it work on dropdown buttons + // AsyncButtonBuilder( + // child: Icon(Icons.arrow_upward), + // onPressed: (newValue) async { + // final oldValue = dropdownValue; + + // setState(() { + // dropdownValue = newValue; + // }); + + // await Future.delayed(Duration(seconds: 1)); + + // try { + // if (Random().nextBool()) { + // throw 'yikes'; + // } + // } catch (error) { + // setState(() { + // dropdownValue = oldValue; + // }); + // } + // }, + // builder: (context, child, callback, _) { + // return DropdownButton( + // // icon: SizedBox( + // // height: 16.0, + // // width: 16.0, + // // child: CircularProgressIndicator(), + // // ), + // onChanged: callback, + // items: ['one', 'two', 'three'] + // .map((value) => DropdownMenuItem( + // child: Text(value), + // value: value, + // )) + // .toList(), + // value: dropdownValue, + // ); + // }, + // ), +} diff --git a/packages/async_button_hook/.gitignore b/packages/async_button_hook/.gitignore new file mode 100644 index 0000000..a247422 --- /dev/null +++ b/packages/async_button_hook/.gitignore @@ -0,0 +1,75 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +build/ + +# Android related +**/android/**/gradle-wrapper.jar +**/android/.gradle +**/android/captures/ +**/android/gradlew +**/android/gradlew.bat +**/android/local.properties +**/android/**/GeneratedPluginRegistrant.java + +# iOS/XCode related +**/ios/**/*.mode1v3 +**/ios/**/*.mode2v3 +**/ios/**/*.moved-aside +**/ios/**/*.pbxuser +**/ios/**/*.perspectivev3 +**/ios/**/*sync/ +**/ios/**/.sconsign.dblite +**/ios/**/.tags* +**/ios/**/.vagrant/ +**/ios/**/DerivedData/ +**/ios/**/Icon? +**/ios/**/Pods/ +**/ios/**/.symlinks/ +**/ios/**/profile +**/ios/**/xcuserdata +**/ios/.generated/ +**/ios/Flutter/App.framework +**/ios/Flutter/Flutter.framework +**/ios/Flutter/Flutter.podspec +**/ios/Flutter/Generated.xcconfig +**/ios/Flutter/ephemeral +**/ios/Flutter/app.flx +**/ios/Flutter/app.zip +**/ios/Flutter/flutter_assets/ +**/ios/Flutter/flutter_export_environment.sh +**/ios/ServiceDefinitions.json +**/ios/Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!**/ios/**/default.mode1v3 +!**/ios/**/default.mode2v3 +!**/ios/**/default.pbxuser +!**/ios/**/default.perspectivev3 diff --git a/packages/async_button_hook/.metadata b/packages/async_button_hook/.metadata new file mode 100644 index 0000000..b6da989 --- /dev/null +++ b/packages/async_button_hook/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 225a43d941ddd1753765fec3682011e9ddffb11d + channel: dev + +project_type: package diff --git a/packages/async_button_hook/CHANGELOG.md b/packages/async_button_hook/CHANGELOG.md new file mode 100644 index 0000000..41cc7d8 --- /dev/null +++ b/packages/async_button_hook/CHANGELOG.md @@ -0,0 +1,3 @@ +## 0.0.1 + +* TODO: Describe initial release. diff --git a/packages/async_button_hook/LICENSE b/packages/async_button_hook/LICENSE new file mode 100644 index 0000000..30cff74 --- /dev/null +++ b/packages/async_button_hook/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/packages/async_button_hook/README.md b/packages/async_button_hook/README.md new file mode 100644 index 0000000..fe84005 --- /dev/null +++ b/packages/async_button_hook/README.md @@ -0,0 +1 @@ +../../README.md \ No newline at end of file diff --git a/packages/async_button_hook/lib/async_button_hook.dart b/packages/async_button_hook/lib/async_button_hook.dart new file mode 100644 index 0000000..c2bc3e2 --- /dev/null +++ b/packages/async_button_hook/lib/async_button_hook.dart @@ -0,0 +1 @@ +library async_button_hook; diff --git a/packages/async_button_hook/pubspec.lock b/packages/async_button_hook/pubspec.lock new file mode 100644 index 0000000..51a022e --- /dev/null +++ b/packages/async_button_hook/pubspec.lock @@ -0,0 +1,168 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + async: + dependency: transitive + description: + name: async + url: "https://pub.dartlang.org" + source: hosted + version: "2.8.1" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + characters: + dependency: transitive + description: + name: characters + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + charcode: + dependency: transitive + description: + name: charcode + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.1" + clock: + dependency: transitive + description: + name: clock + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + collection: + dependency: transitive + description: + name: collection + url: "https://pub.dartlang.org" + source: hosted + version: "1.15.0" + fake_async: + dependency: transitive + description: + name: fake_async + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_hooks: + dependency: "direct main" + description: + name: flutter_hooks + url: "https://pub.dartlang.org" + source: hosted + version: "0.18.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.4" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + lints: + dependency: transitive + description: + name: lints + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + matcher: + dependency: transitive + description: + name: matcher + url: "https://pub.dartlang.org" + source: hosted + version: "0.12.10" + meta: + dependency: transitive + description: + name: meta + url: "https://pub.dartlang.org" + source: hosted + version: "1.7.0" + path: + dependency: transitive + description: + name: path + url: "https://pub.dartlang.org" + source: hosted + version: "1.8.0" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + url: "https://pub.dartlang.org" + source: hosted + version: "1.8.1" + stack_trace: + dependency: transitive + description: + name: stack_trace + url: "https://pub.dartlang.org" + source: hosted + version: "1.10.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + test_api: + dependency: transitive + description: + name: test_api + url: "https://pub.dartlang.org" + source: hosted + version: "0.4.2" + typed_data: + dependency: transitive + description: + name: typed_data + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.0" + vector_math: + dependency: transitive + description: + name: vector_math + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" +sdks: + dart: ">=2.12.0 <3.0.0" + flutter: ">=1.20.0" diff --git a/packages/async_button_hook/pubspec.yaml b/packages/async_button_hook/pubspec.yaml new file mode 100644 index 0000000..546520c --- /dev/null +++ b/packages/async_button_hook/pubspec.yaml @@ -0,0 +1,20 @@ +name: async_button_hook +description: A hook version of async_button_builder which depends on flutter_hooks +version: 0.0.1 +homepage: https://github.com/Nolence/async_button/packages/async_button_hook + +environment: + sdk: ">=2.12.0 <3.0.0" + flutter: ">=1.17.0" + +dependencies: + flutter: + sdk: flutter + flutter_hooks: ^0.18.0 + +dev_dependencies: + flutter_lints: ^1.0.0 + flutter_test: + sdk: flutter + +flutter: null diff --git a/packages/async_button_hook/test/async_button_hook_test.dart b/packages/async_button_hook/test/async_button_hook_test.dart new file mode 100644 index 0000000..c989bbd --- /dev/null +++ b/packages/async_button_hook/test/async_button_hook_test.dart @@ -0,0 +1,7 @@ +import 'package:flutter_test/flutter_test.dart'; + +void main() { + test('adds one to input values', () { + throw UnimplementedError(); + }); +} From f0437ae608ff665ad0b1e5b5781e1f1e3435a8cf Mon Sep 17 00:00:00 2001 From: Nolence Date: Wed, 18 Aug 2021 16:09:55 -0600 Subject: [PATCH 048/176] Added async_button_hook --- .github/workflows/dart.yaml | 37 -- .gitignore | 74 --- .idea/.name | 1 + .idea/modules.xml | 12 + .idea/runConfigurations/melos_bootstrap.xml | 11 + .idea/runConfigurations/melos_clean.xml | 11 + .../melos_flutter_run_example.xml | 6 + ...elos_flutter_test_async_button_builder.xml | 7 + .../melos_flutter_test_async_button_core.xml | 7 + .../melos_flutter_test_async_button_hook.xml | 7 + .idea/runConfigurations/melos_run_analyze.xml | 11 + .../runConfigurations/melos_run_generate.xml | 11 + .../melos_run_generate_dart.xml | 11 + .../melos_run_generate_flutter.xml | 11 + .idea/runConfigurations/melos_run_test.xml | 11 + .../runConfigurations/melos_run_test_dart.xml | 11 + .../melos_run_test_flutter.xml | 11 + .metadata | 10 - CHANGELOG.md | 80 --- README.md | 2 + example/.gitignore | 46 -- example/.metadata | 10 - example/README.md | 16 - example/analysis_options.yaml | 1 - example/android/.gitignore | 11 - example/android/app/build.gradle | 59 -- .../android/app/src/debug/AndroidManifest.xml | 7 - .../android/app/src/main/AndroidManifest.xml | 41 -- .../com/example/example/MainActivity.kt | 6 - .../res/drawable-v21/launch_background.xml | 12 - .../main/res/drawable/launch_background.xml | 12 - .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 544 -> 0 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 442 -> 0 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 721 -> 0 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 1031 -> 0 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 1443 -> 0 bytes .../app/src/main/res/values-night/styles.xml | 18 - .../app/src/main/res/values/styles.xml | 18 - .../app/src/profile/AndroidManifest.xml | 7 - example/android/build.gradle | 31 -- example/android/gradle.properties | 3 - .../gradle/wrapper/gradle-wrapper.properties | 6 - example/android/settings.gradle | 11 - example/ios/.gitignore | 32 -- example/ios/Flutter/AppFrameworkInfo.plist | 26 - example/ios/Flutter/Debug.xcconfig | 3 - example/ios/Flutter/Release.xcconfig | 3 - example/ios/Podfile | 41 -- example/ios/Podfile.lock | 16 - example/ios/Runner.xcodeproj/project.pbxproj | 521 ------------------ .../contents.xcworkspacedata | 7 - .../xcshareddata/IDEWorkspaceChecks.plist | 8 - .../xcshareddata/WorkspaceSettings.xcsettings | 8 - .../xcshareddata/xcschemes/Runner.xcscheme | 91 --- .../contents.xcworkspacedata | 10 - .../xcshareddata/IDEWorkspaceChecks.plist | 8 - .../xcshareddata/WorkspaceSettings.xcsettings | 8 - example/ios/Runner/AppDelegate.swift | 13 - .../AppIcon.appiconset/Contents.json | 122 ---- .../Icon-App-1024x1024@1x.png | Bin 10932 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 564 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 1283 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 1588 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 1025 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 1716 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 1920 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 1283 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 1895 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 2665 -> 0 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 2665 -> 0 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 3831 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 1888 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 3294 -> 0 bytes .../Icon-App-83.5x83.5@2x.png | Bin 3612 -> 0 bytes .../LaunchImage.imageset/Contents.json | 23 - .../LaunchImage.imageset/LaunchImage.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/LaunchImage@2x.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/LaunchImage@3x.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/README.md | 5 - .../Runner/Base.lproj/LaunchScreen.storyboard | 37 -- example/ios/Runner/Base.lproj/Main.storyboard | 26 - example/ios/Runner/Info.plist | 45 -- example/ios/Runner/Runner-Bridging-Header.h | 1 - example/lib/main.dart | 166 ------ example/pubspec.lock | 182 ------ example/pubspec.yaml | 23 - example/test/widget_test.dart | 30 - example/web/favicon.png | Bin 917 -> 0 bytes example/web/icons/Icon-192.png | Bin 5292 -> 0 bytes example/web/icons/Icon-512.png | Bin 8252 -> 0 bytes example/web/index.html | 45 -- example/web/manifest.json | 23 - lib/async_button_builder.dart | 4 - lib/src/async_button_builder.dart | 446 --------------- lib/src/button_state/button_state.dart | 39 -- .../button_state/button_state.freezed.dart | 455 --------------- melos.yaml | 42 ++ melos_async_button.iml | 10 + melos_my_project.iml | 10 + .../lib/src/async_button_builder.dart | 161 ++---- packages/async_button_builder/pubspec.yaml | 2 +- .../lib/async_button_core.dart | 3 +- packages/async_button_core/lib/src/types.dart | 200 +++++++ .../lib/async_button_hook.dart | 2 + .../lib/src/async_button_hook.dart | 210 +++++++ .../lib/src/models/async_button_result.dart | 22 + packages/async_button_hook/pubspec.lock | 21 + packages/async_button_hook/pubspec.yaml | 1 + pubspec.lock | 469 ---------------- pubspec.yaml | 22 - test/async_button_builder_test.dart | 151 ----- 111 files changed, 696 insertions(+), 3754 deletions(-) delete mode 100644 .github/workflows/dart.yaml delete mode 100644 .gitignore create mode 100644 .idea/.name create mode 100644 .idea/modules.xml create mode 100644 .idea/runConfigurations/melos_bootstrap.xml create mode 100644 .idea/runConfigurations/melos_clean.xml create mode 100644 .idea/runConfigurations/melos_flutter_run_example.xml create mode 100644 .idea/runConfigurations/melos_flutter_test_async_button_builder.xml create mode 100644 .idea/runConfigurations/melos_flutter_test_async_button_core.xml create mode 100644 .idea/runConfigurations/melos_flutter_test_async_button_hook.xml create mode 100644 .idea/runConfigurations/melos_run_analyze.xml create mode 100644 .idea/runConfigurations/melos_run_generate.xml create mode 100644 .idea/runConfigurations/melos_run_generate_dart.xml create mode 100644 .idea/runConfigurations/melos_run_generate_flutter.xml create mode 100644 .idea/runConfigurations/melos_run_test.xml create mode 100644 .idea/runConfigurations/melos_run_test_dart.xml create mode 100644 .idea/runConfigurations/melos_run_test_flutter.xml delete mode 100644 .metadata delete mode 100644 CHANGELOG.md delete mode 100644 example/.gitignore delete mode 100644 example/.metadata delete mode 100644 example/README.md delete mode 100644 example/analysis_options.yaml delete mode 100644 example/android/.gitignore delete mode 100644 example/android/app/build.gradle delete mode 100644 example/android/app/src/debug/AndroidManifest.xml delete mode 100644 example/android/app/src/main/AndroidManifest.xml delete mode 100644 example/android/app/src/main/kotlin/com/example/example/MainActivity.kt delete mode 100644 example/android/app/src/main/res/drawable-v21/launch_background.xml delete mode 100644 example/android/app/src/main/res/drawable/launch_background.xml delete mode 100644 example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png delete mode 100644 example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png delete mode 100644 example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png delete mode 100644 example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png delete mode 100644 example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png delete mode 100644 example/android/app/src/main/res/values-night/styles.xml delete mode 100644 example/android/app/src/main/res/values/styles.xml delete mode 100644 example/android/app/src/profile/AndroidManifest.xml delete mode 100644 example/android/build.gradle delete mode 100644 example/android/gradle.properties delete mode 100644 example/android/gradle/wrapper/gradle-wrapper.properties delete mode 100644 example/android/settings.gradle delete mode 100644 example/ios/.gitignore delete mode 100644 example/ios/Flutter/AppFrameworkInfo.plist delete mode 100644 example/ios/Flutter/Debug.xcconfig delete mode 100644 example/ios/Flutter/Release.xcconfig delete mode 100644 example/ios/Podfile delete mode 100644 example/ios/Podfile.lock delete mode 100644 example/ios/Runner.xcodeproj/project.pbxproj delete mode 100644 example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100644 example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings delete mode 100644 example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme delete mode 100644 example/ios/Runner.xcworkspace/contents.xcworkspacedata delete mode 100644 example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings delete mode 100644 example/ios/Runner/AppDelegate.swift delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png delete mode 100644 example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json delete mode 100644 example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png delete mode 100644 example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png delete mode 100644 example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png delete mode 100644 example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md delete mode 100644 example/ios/Runner/Base.lproj/LaunchScreen.storyboard delete mode 100644 example/ios/Runner/Base.lproj/Main.storyboard delete mode 100644 example/ios/Runner/Info.plist delete mode 100644 example/ios/Runner/Runner-Bridging-Header.h delete mode 100644 example/lib/main.dart delete mode 100644 example/pubspec.lock delete mode 100644 example/pubspec.yaml delete mode 100644 example/test/widget_test.dart delete mode 100644 example/web/favicon.png delete mode 100644 example/web/icons/Icon-192.png delete mode 100644 example/web/icons/Icon-512.png delete mode 100644 example/web/index.html delete mode 100644 example/web/manifest.json delete mode 100644 lib/async_button_builder.dart delete mode 100644 lib/src/async_button_builder.dart delete mode 100644 lib/src/button_state/button_state.dart delete mode 100644 lib/src/button_state/button_state.freezed.dart create mode 100644 melos.yaml create mode 100644 melos_async_button.iml create mode 100644 melos_my_project.iml create mode 100644 packages/async_button_core/lib/src/types.dart create mode 100644 packages/async_button_hook/lib/src/async_button_hook.dart create mode 100644 packages/async_button_hook/lib/src/models/async_button_result.dart delete mode 100644 pubspec.lock delete mode 100644 pubspec.yaml delete mode 100644 test/async_button_builder_test.dart diff --git a/.github/workflows/dart.yaml b/.github/workflows/dart.yaml deleted file mode 100644 index 1c8d8da..0000000 --- a/.github/workflows/dart.yaml +++ /dev/null @@ -1,37 +0,0 @@ -name: Build - -on: - push: - pull_request: - schedule: - # runs the CI everyday at 10AM - - cron: '0 10 * * *' - -jobs: - flutter: - runs-on: ubuntu-latest - - strategy: - matrix: - channel: - # Dev currently adds a breaking change on AnimatedContainer - so no - # - dev - - stable - - steps: - - uses: actions/checkout@v2 - - uses: subosito/flutter-action@v1 - with: - channel: ${{ matrix.channel }} - - - name: Install dependencies - run: flutter pub get - - - name: Check format - run: flutter format --set-exit-if-changed . - - - name: Analyze - run: flutter analyze - - - name: Run tests - run: flutter test \ No newline at end of file diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 1985397..0000000 --- a/.gitignore +++ /dev/null @@ -1,74 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -.dart_tool/ -.flutter-plugins -.flutter-plugins-dependencies -.packages -.pub-cache/ -.pub/ -build/ - -# Android related -**/android/**/gradle-wrapper.jar -**/android/.gradle -**/android/captures/ -**/android/gradlew -**/android/gradlew.bat -**/android/local.properties -**/android/**/GeneratedPluginRegistrant.java - -# iOS/XCode related -**/ios/**/*.mode1v3 -**/ios/**/*.mode2v3 -**/ios/**/*.moved-aside -**/ios/**/*.pbxuser -**/ios/**/*.perspectivev3 -**/ios/**/*sync/ -**/ios/**/.sconsign.dblite -**/ios/**/.tags* -**/ios/**/.vagrant/ -**/ios/**/DerivedData/ -**/ios/**/Icon? -**/ios/**/Pods/ -**/ios/**/.symlinks/ -**/ios/**/profile -**/ios/**/xcuserdata -**/ios/.generated/ -**/ios/Flutter/App.framework -**/ios/Flutter/Flutter.framework -**/ios/Flutter/Flutter.podspec -**/ios/Flutter/Generated.xcconfig -**/ios/Flutter/app.flx -**/ios/Flutter/app.zip -**/ios/Flutter/flutter_assets/ -**/ios/Flutter/flutter_export_environment.sh -**/ios/ServiceDefinitions.json -**/ios/Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!**/ios/**/default.mode1v3 -!**/ios/**/default.mode2v3 -!**/ios/**/default.pbxuser -!**/ios/**/default.perspectivev3 diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..132f597 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +async_button \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..e7beaf8 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/melos_bootstrap.xml b/.idea/runConfigurations/melos_bootstrap.xml new file mode 100644 index 0000000..d571530 --- /dev/null +++ b/.idea/runConfigurations/melos_bootstrap.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/.idea/runConfigurations/melos_clean.xml b/.idea/runConfigurations/melos_clean.xml new file mode 100644 index 0000000..f45d436 --- /dev/null +++ b/.idea/runConfigurations/melos_clean.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/.idea/runConfigurations/melos_flutter_run_example.xml b/.idea/runConfigurations/melos_flutter_run_example.xml new file mode 100644 index 0000000..d7a2aa2 --- /dev/null +++ b/.idea/runConfigurations/melos_flutter_run_example.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/melos_flutter_test_async_button_builder.xml b/.idea/runConfigurations/melos_flutter_test_async_button_builder.xml new file mode 100644 index 0000000..d9962a1 --- /dev/null +++ b/.idea/runConfigurations/melos_flutter_test_async_button_builder.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/melos_flutter_test_async_button_core.xml b/.idea/runConfigurations/melos_flutter_test_async_button_core.xml new file mode 100644 index 0000000..b649d6a --- /dev/null +++ b/.idea/runConfigurations/melos_flutter_test_async_button_core.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/melos_flutter_test_async_button_hook.xml b/.idea/runConfigurations/melos_flutter_test_async_button_hook.xml new file mode 100644 index 0000000..03a8548 --- /dev/null +++ b/.idea/runConfigurations/melos_flutter_test_async_button_hook.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/melos_run_analyze.xml b/.idea/runConfigurations/melos_run_analyze.xml new file mode 100644 index 0000000..4287f1c --- /dev/null +++ b/.idea/runConfigurations/melos_run_analyze.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/.idea/runConfigurations/melos_run_generate.xml b/.idea/runConfigurations/melos_run_generate.xml new file mode 100644 index 0000000..a697726 --- /dev/null +++ b/.idea/runConfigurations/melos_run_generate.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/.idea/runConfigurations/melos_run_generate_dart.xml b/.idea/runConfigurations/melos_run_generate_dart.xml new file mode 100644 index 0000000..3f84c12 --- /dev/null +++ b/.idea/runConfigurations/melos_run_generate_dart.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/.idea/runConfigurations/melos_run_generate_flutter.xml b/.idea/runConfigurations/melos_run_generate_flutter.xml new file mode 100644 index 0000000..2ffa709 --- /dev/null +++ b/.idea/runConfigurations/melos_run_generate_flutter.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/.idea/runConfigurations/melos_run_test.xml b/.idea/runConfigurations/melos_run_test.xml new file mode 100644 index 0000000..a4f0c21 --- /dev/null +++ b/.idea/runConfigurations/melos_run_test.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/.idea/runConfigurations/melos_run_test_dart.xml b/.idea/runConfigurations/melos_run_test_dart.xml new file mode 100644 index 0000000..c18e99d --- /dev/null +++ b/.idea/runConfigurations/melos_run_test_dart.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/.idea/runConfigurations/melos_run_test_flutter.xml b/.idea/runConfigurations/melos_run_test_flutter.xml new file mode 100644 index 0000000..beda0b0 --- /dev/null +++ b/.idea/runConfigurations/melos_run_test_flutter.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/.metadata b/.metadata deleted file mode 100644 index 13a1909..0000000 --- a/.metadata +++ /dev/null @@ -1,10 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled and should not be manually edited. - -version: - revision: 63062a64432cce03315d6b5196fda7912866eb37 - channel: dev - -project_type: package diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 975d4ea..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,80 +0,0 @@ -## [2.1.3+2] - 2021-08-12 -Fix possibility of nested async button builders conflicting with each other due to matching keyed subtrees. In order to avoid this situation, the parent key of the async_button_builder is used in the creation of sub widgets. - -## [2.1.3+1] - 2021-06-25 -Was not using proper sucessDuration when setting timeouts (regression) - -## [2.1.3] - 2021-06-18 -Tests and builds against stable. flutter_lints now used in place of pedantic - -## [2.1.2+1] - 2021-06-12 -Fixes analysis errors so I stop getting annoying emails - -## [2.1.2] - 2021-05-24 -Errors from onpressed will throw with orignal call stack - -## [2.1.1+2] - 2021-04-14 -Makes onpressed nullable similar to other button's behaviour - -## [2.1.1+1] - 2021-04-14 -Add documentation on how to handle timeouts - -## [2.1.1] - 2021-04-14 -ValueKeys are now no longer required in order to differentiate children - -## [2.1.0] - 2021-02-12 -Remove null-safety prefix as it's now in stable - -## [2.0.9-nullsafety.0] - 2021-02-12 -Trying to bump version again to go over stable - -## [2.0.8-nullsafety.0] - 2021-02-12 -Trying to bump version again to go over stable - -## [2.0.7-nullsafety.8] - 2021-02-12 -Republish so current nullsafe becomes main. My mistake - -## [2.0.2-nullsafety.7] - 2021-02-12 -Added a typedef in place of inline type on function. Added doc to `builder` field - -## [2.0.2-nullsafety.6] - 2021-02-09 -Renamed Union classes to match that of factory constructor name (Should not be breaking). - -## [2.0.2-nullsafety.5] - 2021-02-01 -Removed example integration test - -## [2.0.2-nullsafety.4] - 2021-01-26 -Adds tests and test coverage. Adds on dispose to cancel timer. - -## [2.0.2-nullsafety.3] - 2021-01-25 -Removes dangling controller and cleans up main code up a bit - -## [2.0.2-nullsafety.2] - 2021-01-25 -Fixes wrong image path - -## [2.0.1-nullsafety.2] - 2021-01-25 -Renames fields to better match standards of other buttons. - -## [2.0.0-dev.1] - 2021-01-25 - -Breaking. Replaces the fourth argument with a sealed union that better allows for directly managing states, removes unnecessary arguments such as padding, adds transition builders for custom transitions. Currently still includes AnimatedSize. - -## [1.0.0-nullsafety.0] - 2021-01-12 - -Breaking. Adds a fourth argument of loading to the builder. This removes the value notifier that was difficult or confusing to manage in actual usage in my use cases. The argument isLoading is now a `bool`. This also adds a `disabled` field in order to set that on construction. - -## [0.1.0-nullsafety.0] - 2021-01-12 - -Replaces the bool type of isLoading for a ValueNotifier. - -## [0.0.1-nullsafety.2] - 2021-01-12 - -Adds analysis options and removes unnecessary typedef - -## [0.0.1-nullsafety.1] - 2021-01-12 - -Adds docs to parameters and removes use of unnecessary undescore internal variables. - -## [0.0.1-nullsafety.0] - 2021-01-11 - -Holds basic builder AsyncButtonBuilder. No tests yet. NNBD is supported diff --git a/README.md b/README.md index 74fefd9..c230846 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # async_button_builder +[![melos](https://img.shields.io/badge/maintained%20with-melos-f700ff.svg?style=flat-square)](https://github.com/invertase/melos) + A builder that adds loading, disabled, errored and completed states (with fluid animation between each) on top of buttons that perform asynchronous tasks. ## Getting Started diff --git a/example/.gitignore b/example/.gitignore deleted file mode 100644 index 0fa6b67..0000000 --- a/example/.gitignore +++ /dev/null @@ -1,46 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -**/ios/Flutter/.last_build_id -.dart_tool/ -.flutter-plugins -.flutter-plugins-dependencies -.packages -.pub-cache/ -.pub/ -/build/ - -# Web related -lib/generated_plugin_registrant.dart - -# Symbolication related -app.*.symbols - -# Obfuscation related -app.*.map.json - -# Android Studio will place build artifacts here -/android/app/debug -/android/app/profile -/android/app/release diff --git a/example/.metadata b/example/.metadata deleted file mode 100644 index 36a4614..0000000 --- a/example/.metadata +++ /dev/null @@ -1,10 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled and should not be manually edited. - -version: - revision: 63062a64432cce03315d6b5196fda7912866eb37 - channel: dev - -project_type: app diff --git a/example/README.md b/example/README.md deleted file mode 100644 index a135626..0000000 --- a/example/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# example - -A new Flutter project. - -## Getting Started - -This project is a starting point for a Flutter application. - -A few resources to get you started if this is your first Flutter project: - -- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) -- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) - -For help getting started with Flutter, view our -[online documentation](https://flutter.dev/docs), which offers tutorials, -samples, guidance on mobile development, and a full API reference. diff --git a/example/analysis_options.yaml b/example/analysis_options.yaml deleted file mode 100644 index 108d105..0000000 --- a/example/analysis_options.yaml +++ /dev/null @@ -1 +0,0 @@ -include: package:pedantic/analysis_options.yaml diff --git a/example/android/.gitignore b/example/android/.gitignore deleted file mode 100644 index 0a741cb..0000000 --- a/example/android/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -gradle-wrapper.jar -/.gradle -/captures/ -/gradlew -/gradlew.bat -/local.properties -GeneratedPluginRegistrant.java - -# Remember to never publicly share your keystore. -# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app -key.properties diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle deleted file mode 100644 index 6ca2344..0000000 --- a/example/android/app/build.gradle +++ /dev/null @@ -1,59 +0,0 @@ -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - -android { - compileSdkVersion 30 - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.example.example" - minSdkVersion 16 - targetSdkVersion 30 - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } -} - -flutter { - source '../..' -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" -} diff --git a/example/android/app/src/debug/AndroidManifest.xml b/example/android/app/src/debug/AndroidManifest.xml deleted file mode 100644 index c208884..0000000 --- a/example/android/app/src/debug/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index 34dd77e..0000000 --- a/example/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt b/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt deleted file mode 100644 index e793a00..0000000 --- a/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.example.example - -import io.flutter.embedding.android.FlutterActivity - -class MainActivity: FlutterActivity() { -} diff --git a/example/android/app/src/main/res/drawable-v21/launch_background.xml b/example/android/app/src/main/res/drawable-v21/launch_background.xml deleted file mode 100644 index f74085f..0000000 --- a/example/android/app/src/main/res/drawable-v21/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/example/android/app/src/main/res/drawable/launch_background.xml b/example/android/app/src/main/res/drawable/launch_background.xml deleted file mode 100644 index 304732f..0000000 --- a/example/android/app/src/main/res/drawable/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index db77bb4b7b0906d62b1847e87f15cdcacf6a4f29..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ diff --git a/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 17987b79bb8a35cc66c3c1fd44f5a5526c1b78be..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 442 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xx&nMcT!A!W`0S9QKQy;}1Cl^CgaH=;G9cpY;r$Q>i*pfB zP2drbID<_#qf;rPZx^FqH)F_D#*k@@q03KywUtLX8Ua?`H+NMzkczFPK3lFz@i_kW%1NOn0|D2I9n9wzH8m|-tHjsw|9>@K=iMBhxvkv6m8Y-l zytQ?X=U+MF$@3 zt`~i=@j|6y)RWMK--}M|=T`o&^Ni>IoWKHEbBXz7?A@mgWoL>!*SXo`SZH-*HSdS+ yn*9;$7;m`l>wYBC5bq;=U}IMqLzqbYCidGC!)_gkIk_C@Uy!y&wkt5C($~2D>~)O*cj@FGjOCM)M>_ixfudOh)?xMu#Fs z#}Y=@YDTwOM)x{K_j*Q;dPdJ?Mz0n|pLRx{4n|)f>SXlmV)XB04CrSJn#dS5nK2lM zrZ9#~WelCp7&e13Y$jvaEXHskn$2V!!DN-nWS__6T*l;H&Fopn?A6HZ-6WRLFP=R` zqG+CE#d4|IbyAI+rJJ`&x9*T`+a=p|0O(+s{UBcyZdkhj=yS1>AirP+0R;mf2uMgM zC}@~JfByORAh4SyRgi&!(cja>F(l*O+nd+@4m$|6K6KDn_&uvCpV23&>G9HJp{xgg zoq1^2_p9@|WEo z*X_Uko@K)qYYv~>43eQGMdbiGbo>E~Q& zrYBH{QP^@Sti!`2)uG{irBBq@y*$B zi#&(U-*=fp74j)RyIw49+0MRPMRU)+a2r*PJ$L5roHt2$UjExCTZSbq%V!HeS7J$N zdG@vOZB4v_lF7Plrx+hxo7(fCV&}fHq)$ diff --git a/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index d5f1c8d34e7a88e3f88bea192c3a370d44689c3c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1031 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof diff --git a/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 4d6372eebdb28e45604e46eeda8dd24651419bc0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1443 zcmb`G{WsKk6vsdJTdFg%tJav9_E4vzrOaqkWF|A724Nly!y+?N9`YV6wZ}5(X(D_N(?!*n3`|_r0Hc?=PQw&*vnU?QTFY zB_MsH|!j$PP;I}?dppoE_gA(4uc!jV&0!l7_;&p2^pxNo>PEcNJv za5_RT$o2Mf!<+r?&EbHH6nMoTsDOa;mN(wv8RNsHpG)`^ymG-S5By8=l9iVXzN_eG%Xg2@Xeq76tTZ*dGh~Lo9vl;Zfs+W#BydUw zCkZ$o1LqWQO$FC9aKlLl*7x9^0q%0}$OMlp@Kk_jHXOjofdePND+j!A{q!8~Jn+s3 z?~~w@4?egS02}8NuulUA=L~QQfm;MzCGd)XhiftT;+zFO&JVyp2mBww?;QByS_1w! zrQlx%{^cMj0|Bo1FjwY@Q8?Hx0cIPF*@-ZRFpPc#bBw{5@tD(5%sClzIfl8WU~V#u zm5Q;_F!wa$BSpqhN>W@2De?TKWR*!ujY;Yylk_X5#~V!L*Gw~;$%4Q8~Mad z@`-kG?yb$a9cHIApZDVZ^U6Xkp<*4rU82O7%}0jjHlK{id@?-wpN*fCHXyXh(bLt* zPc}H-x0e4E&nQ>y%B-(EL=9}RyC%MyX=upHuFhAk&MLbsF0LP-q`XnH78@fT+pKPW zu72MW`|?8ht^tz$iC}ZwLp4tB;Q49K!QCF3@!iB1qOI=?w z7In!}F~ij(18UYUjnbmC!qKhPo%24?8U1x{7o(+?^Zu0Hx81|FuS?bJ0jgBhEMzf< zCgUq7r2OCB(`XkKcN-TL>u5y#dD6D!)5W?`O5)V^>jb)P)GBdy%t$uUMpf$SNV31$ zb||OojAbvMP?T@$h_ZiFLFVHDmbyMhJF|-_)HX3%m=CDI+ID$0^C>kzxprBW)hw(v zr!Gmda);ICoQyhV_oP5+C%?jcG8v+D@9f?Dk*!BxY}dazmrT@64UrP3hlslANK)bq z$67n83eh}OeW&SV@HG95P|bjfqJ7gw$e+`Hxo!4cx`jdK1bJ>YDSpGKLPZ^1cv$ek zIB?0S<#tX?SJCLWdMd{-ME?$hc7A$zBOdIJ)4!KcAwb=VMov)nK;9z>x~rfT1>dS+ zZ6#`2v@`jgbqq)P22H)Tx2CpmM^o1$B+xT6`(v%5xJ(?j#>Q$+rx_R|7TzDZe{J6q zG1*EcU%tE?!kO%^M;3aM6JN*LAKUVb^xz8-Pxo#jR5(-KBeLJvA@-gxNHx0M-ZJLl z;#JwQoh~9V?`UVo#}{6ka@II>++D@%KqGpMdlQ}?9E*wFcf5(#XQnP$Dk5~%iX^>f z%$y;?M0BLp{O3a(-4A?ewryHrrD%cx#Q^%KY1H zNre$ve+vceSLZcNY4U(RBX&)oZn*Py()h)XkE?PL$!bNb{N5FVI2Y%LKEm%yvpyTP z(1P?z~7YxD~Rf<(a@_y` diff --git a/example/android/app/src/main/res/values-night/styles.xml b/example/android/app/src/main/res/values-night/styles.xml deleted file mode 100644 index 449a9f9..0000000 --- a/example/android/app/src/main/res/values-night/styles.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - diff --git a/example/android/app/src/main/res/values/styles.xml b/example/android/app/src/main/res/values/styles.xml deleted file mode 100644 index d74aa35..0000000 --- a/example/android/app/src/main/res/values/styles.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - diff --git a/example/android/app/src/profile/AndroidManifest.xml b/example/android/app/src/profile/AndroidManifest.xml deleted file mode 100644 index c208884..0000000 --- a/example/android/app/src/profile/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/example/android/build.gradle b/example/android/build.gradle deleted file mode 100644 index c505a86..0000000 --- a/example/android/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -buildscript { - ext.kotlin_version = '1.3.50' - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:4.1.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -allprojects { - repositories { - google() - jcenter() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(':app') -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/example/android/gradle.properties b/example/android/gradle.properties deleted file mode 100644 index 94adc3a..0000000 --- a/example/android/gradle.properties +++ /dev/null @@ -1,3 +0,0 @@ -org.gradle.jvmargs=-Xmx1536M -android.useAndroidX=true -android.enableJetifier=true diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index bc6a58a..0000000 --- a/example/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Fri Jun 23 08:50:38 CEST 2017 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip diff --git a/example/android/settings.gradle b/example/android/settings.gradle deleted file mode 100644 index 44e62bc..0000000 --- a/example/android/settings.gradle +++ /dev/null @@ -1,11 +0,0 @@ -include ':app' - -def localPropertiesFile = new File(rootProject.projectDir, "local.properties") -def properties = new Properties() - -assert localPropertiesFile.exists() -localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } - -def flutterSdkPath = properties.getProperty("flutter.sdk") -assert flutterSdkPath != null, "flutter.sdk not set in local.properties" -apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/example/ios/.gitignore b/example/ios/.gitignore deleted file mode 100644 index e96ef60..0000000 --- a/example/ios/.gitignore +++ /dev/null @@ -1,32 +0,0 @@ -*.mode1v3 -*.mode2v3 -*.moved-aside -*.pbxuser -*.perspectivev3 -**/*sync/ -.sconsign.dblite -.tags* -**/.vagrant/ -**/DerivedData/ -Icon? -**/Pods/ -**/.symlinks/ -profile -xcuserdata -**/.generated/ -Flutter/App.framework -Flutter/Flutter.framework -Flutter/Flutter.podspec -Flutter/Generated.xcconfig -Flutter/app.flx -Flutter/app.zip -Flutter/flutter_assets/ -Flutter/flutter_export_environment.sh -ServiceDefinitions.json -Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!default.mode1v3 -!default.mode2v3 -!default.pbxuser -!default.perspectivev3 diff --git a/example/ios/Flutter/AppFrameworkInfo.plist b/example/ios/Flutter/AppFrameworkInfo.plist deleted file mode 100644 index 9367d48..0000000 --- a/example/ios/Flutter/AppFrameworkInfo.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - App - CFBundleIdentifier - io.flutter.flutter.app - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - App - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - MinimumOSVersion - 8.0 - - diff --git a/example/ios/Flutter/Debug.xcconfig b/example/ios/Flutter/Debug.xcconfig deleted file mode 100644 index b2f5fae..0000000 --- a/example/ios/Flutter/Debug.xcconfig +++ /dev/null @@ -1,3 +0,0 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" -#include "Generated.xcconfig" diff --git a/example/ios/Flutter/Release.xcconfig b/example/ios/Flutter/Release.xcconfig deleted file mode 100644 index 88c2914..0000000 --- a/example/ios/Flutter/Release.xcconfig +++ /dev/null @@ -1,3 +0,0 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" -#include "Generated.xcconfig" diff --git a/example/ios/Podfile b/example/ios/Podfile deleted file mode 100644 index b29247c..0000000 --- a/example/ios/Podfile +++ /dev/null @@ -1,41 +0,0 @@ -# Uncomment this line to define a global platform for your project -# platform :ios, '9.0' - -# CocoaPods analytics sends network stats synchronously affecting flutter build latency. -ENV['COCOAPODS_DISABLE_STATS'] = 'true' - -project 'Runner', { - 'Debug' => :debug, - 'Profile' => :release, - 'Release' => :release, -} - -def flutter_root - generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) - unless File.exist?(generated_xcode_build_settings_path) - raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" - end - - File.foreach(generated_xcode_build_settings_path) do |line| - matches = line.match(/FLUTTER_ROOT\=(.*)/) - return matches[1].strip if matches - end - raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" -end - -require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) - -flutter_ios_podfile_setup - -target 'Runner' do - use_frameworks! - use_modular_headers! - - flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) -end - -post_install do |installer| - installer.pods_project.targets.each do |target| - flutter_additional_ios_build_settings(target) - end -end \ No newline at end of file diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock deleted file mode 100644 index f11c132..0000000 --- a/example/ios/Podfile.lock +++ /dev/null @@ -1,16 +0,0 @@ -PODS: - - Flutter (1.0.0) - -DEPENDENCIES: - - Flutter (from `Flutter`) - -EXTERNAL SOURCES: - Flutter: - :path: Flutter - -SPEC CHECKSUMS: - Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c - -PODFILE CHECKSUM: fc81e398f362bae88bdf55239bd5cf842faad39f - -COCOAPODS: 1.10.1 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index ad27a86..0000000 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,521 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 052090A8264F7CC7D59BAC4F /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 166593E2DDC1580301FBE4EB /* Pods_Runner.framework */; }; - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; -/* End PBXBuildFile section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 9705A1C41CF9048500538489 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 166593E2DDC1580301FBE4EB /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; - 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 979288937DB54B7A8E167BFD /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; - 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - ABECF997BE9D843ACE309A51 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; - BFE91A80E9CF01FB47297D69 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 97C146EB1CF9000F007C117D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 052090A8264F7CC7D59BAC4F /* Pods_Runner.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 421781B0B716E5E3F11A65B3 /* Pods */ = { - isa = PBXGroup; - children = ( - ABECF997BE9D843ACE309A51 /* Pods-Runner.debug.xcconfig */, - BFE91A80E9CF01FB47297D69 /* Pods-Runner.release.xcconfig */, - 979288937DB54B7A8E167BFD /* Pods-Runner.profile.xcconfig */, - ); - name = Pods; - path = Pods; - sourceTree = ""; - }; - 9740EEB11CF90186004384FC /* Flutter */ = { - isa = PBXGroup; - children = ( - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 9740EEB31CF90195004384FC /* Generated.xcconfig */, - ); - name = Flutter; - sourceTree = ""; - }; - 97C146E51CF9000F007C117D = { - isa = PBXGroup; - children = ( - 9740EEB11CF90186004384FC /* Flutter */, - 97C146F01CF9000F007C117D /* Runner */, - 97C146EF1CF9000F007C117D /* Products */, - 421781B0B716E5E3F11A65B3 /* Pods */, - C21EF53B5D1A17BF8839457D /* Frameworks */, - ); - sourceTree = ""; - }; - 97C146EF1CF9000F007C117D /* Products */ = { - isa = PBXGroup; - children = ( - 97C146EE1CF9000F007C117D /* Runner.app */, - ); - name = Products; - sourceTree = ""; - }; - 97C146F01CF9000F007C117D /* Runner */ = { - isa = PBXGroup; - children = ( - 97C146FA1CF9000F007C117D /* Main.storyboard */, - 97C146FD1CF9000F007C117D /* Assets.xcassets */, - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, - 97C147021CF9000F007C117D /* Info.plist */, - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, - ); - path = Runner; - sourceTree = ""; - }; - C21EF53B5D1A17BF8839457D /* Frameworks */ = { - isa = PBXGroup; - children = ( - 166593E2DDC1580301FBE4EB /* Pods_Runner.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 97C146ED1CF9000F007C117D /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - 0D390D42CD24A841DCDBE0FB /* [CP] Check Pods Manifest.lock */, - 9740EEB61CF901F6004384FC /* Run Script */, - 97C146EA1CF9000F007C117D /* Sources */, - 97C146EB1CF9000F007C117D /* Frameworks */, - 97C146EC1CF9000F007C117D /* Resources */, - 9705A1C41CF9048500538489 /* Embed Frameworks */, - 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Runner; - productName = Runner; - productReference = 97C146EE1CF9000F007C117D /* Runner.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 97C146E61CF9000F007C117D /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 1020; - ORGANIZATIONNAME = ""; - TargetAttributes = { - 97C146ED1CF9000F007C117D = { - CreatedOnToolsVersion = 7.3.1; - LastSwiftMigration = 1100; - }; - }; - }; - buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 97C146E51CF9000F007C117D; - productRefGroup = 97C146EF1CF9000F007C117D /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 97C146ED1CF9000F007C117D /* Runner */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 97C146EC1CF9000F007C117D /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 0D390D42CD24A841DCDBE0FB /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Thin Binary"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; - }; - 9740EEB61CF901F6004384FC /* Run Script */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Run Script"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 97C146EA1CF9000F007C117D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 97C146FA1CF9000F007C117D /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C146FB1CF9000F007C117D /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C147001CF9000F007C117D /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 249021D3217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Profile; - }; - 249021D4217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.example.example; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Profile; - }; - 97C147031CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 97C147041CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 97C147061CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.example.example; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Debug; - }; - 97C147071CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.example.example; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147031CF9000F007C117D /* Debug */, - 97C147041CF9000F007C117D /* Release */, - 249021D3217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147061CF9000F007C117D /* Debug */, - 97C147071CF9000F007C117D /* Release */, - 249021D4217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 97C146E61CF9000F007C117D /* Project object */; -} diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a..0000000 --- a/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d9810..0000000 --- a/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c..0000000 --- a/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index a28140c..0000000 --- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/example/ios/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 21a3cc1..0000000 --- a/example/ios/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d9810..0000000 --- a/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c..0000000 --- a/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/example/ios/Runner/AppDelegate.swift b/example/ios/Runner/AppDelegate.swift deleted file mode 100644 index 70693e4..0000000 --- a/example/ios/Runner/AppDelegate.swift +++ /dev/null @@ -1,13 +0,0 @@ -import UIKit -import Flutter - -@UIApplicationMain -@objc class AppDelegate: FlutterAppDelegate { - override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - GeneratedPluginRegistrant.register(with: self) - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } -} diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index d36b1fa..0000000 --- a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,122 +0,0 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" - }, - { - "size" : "1024x1024", - "idiom" : "ios-marketing", - "filename" : "Icon-App-1024x1024@1x.png", - "scale" : "1x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png deleted file mode 100644 index dc9ada4725e9b0ddb1deab583e5b5102493aa332..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10932 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 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png deleted file mode 100644 index f091b6b0bca859a3f474b03065bef75ba58a9e4c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1588 zcmV-42Fv-0P)C1SqPt}wig>|5Crh^=oyX$BK<}M8eLU3e2hGT;=G|!_SP)7zNI6fqUMB=)y zRAZ>eDe#*r`yDAVgB_R*LB*MAc)8(b{g{9McCXW!lq7r(btRoB9!8B-#AI6JMb~YFBEvdsV)`mEQO^&#eRKx@b&x- z5lZm*!WfD8oCLzfHGz#u7sT0^VLMI1MqGxF^v+`4YYnVYgk*=kU?HsSz{v({E3lb9 z>+xILjBN)t6`=g~IBOelGQ(O990@BfXf(DRI5I$qN$0Gkz-FSc$3a+2fX$AedL4u{ z4V+5Ong(9LiGcIKW?_352sR;LtDPmPJXI{YtT=O8=76o9;*n%_m|xo!i>7$IrZ-{l z-x3`7M}qzHsPV@$v#>H-TpjDh2UE$9g6sysUREDy_R(a)>=eHw-WAyfIN z*qb!_hW>G)Tu8nSw9yn#3wFMiLcfc4pY0ek1}8(NqkBR@t4{~oC>ryc-h_ByH(Cg5 z>ao-}771+xE3um9lWAY1FeQFxowa1(!J(;Jg*wrg!=6FdRX+t_<%z&d&?|Bn){>zm zZQj(aA_HeBY&OC^jj*)N`8fa^ePOU72VpInJoI1?`ty#lvlNzs(&MZX+R%2xS~5Kh zX*|AU4QE#~SgPzOXe9>tRj>hjU@c1k5Y_mW*Jp3fI;)1&g3j|zDgC+}2Q_v%YfDax z!?umcN^n}KYQ|a$Lr+51Nf9dkkYFSjZZjkma$0KOj+;aQ&721~t7QUKx61J3(P4P1 zstI~7-wOACnWP4=8oGOwz%vNDqD8w&Q`qcNGGrbbf&0s9L0De{4{mRS?o0MU+nR_! zrvshUau0G^DeMhM_v{5BuLjb#Hh@r23lDAk8oF(C+P0rsBpv85EP>4CVMx#04MOfG z;P%vktHcXwTj~+IE(~px)3*MY77e}p#|c>TD?sMatC0Tu4iKKJ0(X8jxQY*gYtxsC z(zYC$g|@+I+kY;dg_dE>scBf&bP1Nc@Hz<3R)V`=AGkc;8CXqdi=B4l2k|g;2%#m& z*jfX^%b!A8#bI!j9-0Fi0bOXl(-c^AB9|nQaE`*)Hw+o&jS9@7&Gov#HbD~#d{twV zXd^Tr^mWLfFh$@Dr$e;PBEz4(-2q1FF0}c;~B5sA}+Q>TOoP+t>wf)V9Iy=5ruQa;z)y zI9C9*oUga6=hxw6QasLPnee@3^Rr*M{CdaL5=R41nLs(AHk_=Y+A9$2&H(B7!_pURs&8aNw7?`&Z&xY_Ye z)~D5Bog^td-^QbUtkTirdyK^mTHAOuptDflut!#^lnKqU md>ggs(5nOWAqO?umG&QVYK#ibz}*4>0000U6E9hRK9^#O7(mu>ETqrXGsduA8$)?`v2seloOCza43C{NQ$$gAOH**MCn0Q?+L7dl7qnbRdqZ8LSVp1ItDxhxD?t@5_yHg6A8yI zC*%Wgg22K|8E#!~cTNYR~@Y9KepMPrrB8cABapAFa=`H+UGhkXUZV1GnwR1*lPyZ;*K(i~2gp|@bzp8}og7e*#% zEnr|^CWdVV!-4*Y_7rFvlww2Ze+>j*!Z!pQ?2l->4q#nqRu9`ELo6RMS5=br47g_X zRw}P9a7RRYQ%2Vsd0Me{_(EggTnuN6j=-?uFS6j^u69elMypu?t>op*wBx<=Wx8?( ztpe^(fwM6jJX7M-l*k3kEpWOl_Vk3@(_w4oc}4YF4|Rt=2V^XU?#Yz`8(e?aZ@#li0n*=g^qOcVpd-Wbok=@b#Yw zqn8u9a)z>l(1kEaPYZ6hwubN6i<8QHgsu0oE) ziJ(p;Wxm>sf!K+cw>R-(^Y2_bahB+&KI9y^);#0qt}t-$C|Bo71lHi{_+lg#f%RFy z0um=e3$K3i6K{U_4K!EX?F&rExl^W|G8Z8;`5z-k}OGNZ0#WVb$WCpQu-_YsiqKP?BB# vzVHS-CTUF4Ozn5G+mq_~Qqto~ahA+K`|lyv3(-e}00000NkvXXu0mjfd`9t{ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png deleted file mode 100644 index d0ef06e7edb86cdfe0d15b4b0d98334a86163658..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1716 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 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png deleted file mode 100644 index c8f9ed8f5cee1c98386d13b17e89f719e83555b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1895 zcmV-t2blPYP)FQtfgmafE#=YDCq`qUBt#QpG%*H6QHY765~R=q zZ6iudfM}q!Pz#~9JgOi8QJ|DSu?1-*(kSi1K4#~5?#|rh?sS)(-JQqX*}ciXJ56_H zdw=^s_srbAdqxlvGyrgGet#6T7_|j;95sL%MtM;q86vOxKM$f#puR)Bjv9Zvz9-di zXOTSsZkM83)E9PYBXC<$6(|>lNLVBb&&6y{NByFCp%6+^ALR@NCTse_wqvNmSWI-m z!$%KlHFH2omF!>#%1l3LTZg(s7eof$7*xB)ZQ0h?ejh?Ta9fDv59+u#MokW+1t8Zb zgHv%K(u9G^Lv`lh#f3<6!JVTL3(dCpxHbnbA;kKqQyd1~^Xe0VIaYBSWm6nsr;dFj z4;G-RyL?cYgsN1{L4ZFFNa;8)Rv0fM0C(~Tkit94 zz#~A)59?QjD&pAPSEQ)p8gP|DS{ng)j=2ux)_EzzJ773GmQ_Cic%3JJhC0t2cx>|v zJcVusIB!%F90{+}8hG3QU4KNeKmK%T>mN57NnCZ^56=0?&3@!j>a>B43pi{!u z7JyDj7`6d)qVp^R=%j>UIY6f+3`+qzIc!Y_=+uN^3BYV|o+$vGo-j-Wm<10%A=(Yk^beI{t%ld@yhKjq0iNjqN4XMGgQtbKubPM$JWBz}YA65k%dm*awtC^+f;a-x4+ddbH^7iDWGg&N0n#MW{kA|=8iMUiFYvMoDY@sPC#t$55gn6ykUTPAr`a@!(;np824>2xJthS z*ZdmT`g5-`BuJs`0LVhz+D9NNa3<=6m;cQLaF?tCv8)zcRSh66*Z|vXhG@$I%U~2l z?`Q zykI#*+rQ=z6Jm=Bui-SfpDYLA=|vzGE(dYm=OC8XM&MDo7ux4UF1~0J1+i%aCUpRe zt3L_uNyQ*cE(38Uy03H%I*)*Bh=Lb^Xj3?I^Hnbeq72(EOK^Y93CNp*uAA{5Lc=ky zx=~RKa4{iTm{_>_vSCm?$Ej=i6@=m%@VvAITnigVg{&@!7CDgs908761meDK5azA} z4?=NOH|PdvabgJ&fW2{Mo$Q0CcD8Qc84%{JPYt5EiG{MdLIAeX%T=D7NIP4%Hw}p9 zg)==!2Lbp#j{u_}hMiao9=!VSyx0gHbeCS`;q&vzeq|fs`y&^X-lso(Ls@-706qmA z7u*T5PMo_w3{se1t2`zWeO^hOvTsohG_;>J0wVqVe+n)AbQCx)yh9;w+J6?NF5Lmo zecS@ieAKL8%bVd@+-KT{yI|S}O>pYckUFs;ry9Ow$CD@ztz5K-*D$^{i(_1llhSh^ zEkL$}tsQt5>QA^;QgjgIfBDmcOgi5YDyu?t6vSnbp=1+@6D& z5MJ}B8q;bRlVoxasyhcUF1+)o`&3r0colr}QJ3hcSdLu;9;td>kf@Tcn<@9sIx&=m z;AD;SCh95=&p;$r{Xz3iWCO^MX83AGJ(yH&eTXgv|0=34#-&WAmw{)U7OU9!Wz^!7 zZ%jZFi@JR;>Mhi7S>V7wQ176|FdW2m?&`qa(ScO^CFPR80HucLHOTy%5s*HR0^8)i h0WYBP*#0Ks^FNSabJA*5${_#%002ovPDHLkV1oKhTl@e3 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png deleted file mode 100644 index a6d6b8609df07bf62e5100a53a01510388bd2b22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index a6d6b8609df07bf62e5100a53a01510388bd2b22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index 75b2d164a5a98e212cca15ea7bf2ab5de5108680..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3831 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 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png deleted file mode 100644 index c4df70d39da7941ef3f6dcb7f06a192d8dcb308d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1888 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 iW8Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png deleted file mode 100644 index 9da19eacad3b03bb08bbddbbf4ac48dd78b3d838..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png deleted file mode 100644 index 9da19eacad3b03bb08bbddbbf4ac48dd78b3d838..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725..0000000 --- a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -You can customize the launch screen with your own desired assets by replacing the image files in this directory. - -You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/example/ios/Runner/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index f2e259c..0000000 --- a/example/ios/Runner/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/example/ios/Runner/Base.lproj/Main.storyboard b/example/ios/Runner/Base.lproj/Main.storyboard deleted file mode 100644 index f3c2851..0000000 --- a/example/ios/Runner/Base.lproj/Main.storyboard +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist deleted file mode 100644 index a060db6..0000000 --- a/example/ios/Runner/Info.plist +++ /dev/null @@ -1,45 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - example - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - - diff --git a/example/ios/Runner/Runner-Bridging-Header.h b/example/ios/Runner/Runner-Bridging-Header.h deleted file mode 100644 index 308a2a5..0000000 --- a/example/ios/Runner/Runner-Bridging-Header.h +++ /dev/null @@ -1 +0,0 @@ -#import "GeneratedPluginRegistrant.h" diff --git a/example/lib/main.dart b/example/lib/main.dart deleted file mode 100644 index 27b04ce..0000000 --- a/example/lib/main.dart +++ /dev/null @@ -1,166 +0,0 @@ -import 'package:async_button_builder/async_button_builder.dart'; -import 'package:flutter/material.dart'; - -void main() => runApp(MyApp()); - -class MyApp extends StatelessWidget { - @override - Widget build(BuildContext context) { - return MaterialApp( - title: 'Flutter Demo', - theme: ThemeData.dark(), - home: MyHomePage(), - ); - } -} - -class MyHomePage extends StatelessWidget { - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar(title: Text('Async Buttons')), - body: SizedBox.expand( - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - Divider(), - Text('Text Button:'), - AsyncButtonBuilder( - child: Text('Click Me'), - onPressed: () async { - await Future.delayed(Duration(seconds: 1)); - }, - builder: (context, child, callback, _) { - return TextButton( - child: child, - onPressed: callback, - ); - }, - ), - Divider(), - Text('Elevated Button:'), - AsyncButtonBuilder( - child: Text('Click Me'), - onPressed: () async { - await Future.delayed(Duration(seconds: 1)); - }, - builder: (context, child, callback, _) { - return ElevatedButton( - child: child, - onPressed: callback, - ); - }, - ), - Divider(), - Text('Custom Outlined Button (Error):'), - AsyncButtonBuilder( - child: Text('Click Me'), - loadingWidget: Text('Loading...'), - onPressed: () async { - await Future.delayed(Duration(seconds: 1)); - - throw 'shucks'; - - // If you want to add a timeout, use something similar to - // - // try { - // await Future.delayed(Duration(seconds: 1)) - // .timeout(Duration(milliseconds: 500)); - // } on TimeoutException catch (_) { - // // Show a popup or something - // rethrow; - // } on Exception catch (_) { - // // Show a dialog or something - // rethrow; - // } - // - // We rethrow so that async_button_builder can handle the error - // state - }, - builder: (context, child, callback, buttonState) { - final buttonColor = buttonState.when( - idle: () => Colors.yellow[200], - loading: () => Colors.grey, - success: () => Colors.orangeAccent, - error: () => Colors.orange, - ); - - return OutlinedButton( - child: child, - onPressed: callback, - style: OutlinedButton.styleFrom( - primary: Colors.black, - backgroundColor: buttonColor, - ), - ); - }, - ), - Divider(), - Text('Custom Material Button:'), - const SizedBox(height: 6.0), - AsyncButtonBuilder( - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 16.0, - vertical: 8.0, - ), - child: Text( - 'Click Me', - style: TextStyle(color: Colors.white), - ), - ), - loadingWidget: Padding( - padding: const EdgeInsets.all(8.0), - child: SizedBox( - height: 16.0, - width: 16.0, - child: CircularProgressIndicator( - valueColor: AlwaysStoppedAnimation(Colors.white), - ), - ), - ), - successWidget: Padding( - padding: const EdgeInsets.all(4.0), - child: Icon( - Icons.check, - color: Colors.purpleAccent, - ), - ), - onPressed: () async { - await Future.delayed(Duration(seconds: 2)); - }, - loadingSwitchInCurve: Curves.bounceInOut, - loadingTransitionBuilder: (child, animation) { - return SlideTransition( - position: Tween( - begin: Offset(0, 1.0), - end: Offset(0, 0), - ).animate(animation), - child: child, - ); - }, - builder: (context, child, callback, state) { - return Material( - color: state.maybeWhen( - success: () => Colors.purple[100], - orElse: () => Colors.blue, - ), - // This prevents the loading indicator showing below the - // button - clipBehavior: Clip.hardEdge, - shape: StadiumBorder(), - child: InkWell( - child: child, - onTap: callback, - ), - ); - }, - ), - Divider(), - ], - ), - ), - ); - } -} diff --git a/example/pubspec.lock b/example/pubspec.lock deleted file mode 100644 index dd48e5f..0000000 --- a/example/pubspec.lock +++ /dev/null @@ -1,182 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - async: - dependency: transitive - description: - name: async - url: "https://pub.dartlang.org" - source: hosted - version: "2.7.0" - async_button_builder: - dependency: "direct main" - description: - path: ".." - relative: true - source: path - version: "2.1.3+2" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - characters: - dependency: transitive - description: - name: characters - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.1" - clock: - dependency: transitive - description: - name: clock - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - collection: - dependency: transitive - description: - name: collection - url: "https://pub.dartlang.org" - source: hosted - version: "1.15.0" - cupertino_icons: - dependency: "direct main" - description: - name: cupertino_icons - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.2" - fake_async: - dependency: transitive - description: - name: fake_async - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - freezed_annotation: - dependency: transitive - description: - name: freezed_annotation - url: "https://pub.dartlang.org" - source: hosted - version: "0.14.2" - json_annotation: - dependency: transitive - description: - name: json_annotation - url: "https://pub.dartlang.org" - source: hosted - version: "4.0.1" - matcher: - dependency: transitive - description: - name: matcher - url: "https://pub.dartlang.org" - source: hosted - version: "0.12.10" - meta: - dependency: transitive - description: - name: meta - url: "https://pub.dartlang.org" - source: hosted - version: "1.7.0" - path: - dependency: transitive - description: - name: path - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.0" - pedantic: - dependency: "direct dev" - description: - name: pedantic - url: "https://pub.dartlang.org" - source: hosted - version: "1.10.0-nullsafety.3" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.99" - source_span: - dependency: transitive - description: - name: source_span - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.1" - stack_trace: - dependency: transitive - description: - name: stack_trace - url: "https://pub.dartlang.org" - source: hosted - version: "1.10.0" - stream_channel: - dependency: transitive - description: - name: stream_channel - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - string_scanner: - dependency: transitive - description: - name: string_scanner - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - term_glyph: - dependency: transitive - description: - name: term_glyph - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - test_api: - dependency: transitive - description: - name: test_api - url: "https://pub.dartlang.org" - source: hosted - version: "0.4.2" - typed_data: - dependency: transitive - description: - name: typed_data - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.0" - vector_math: - dependency: transitive - description: - name: vector_math - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" -sdks: - dart: ">=2.12.0 <3.0.0" - flutter: ">=1.17.0" diff --git a/example/pubspec.yaml b/example/pubspec.yaml deleted file mode 100644 index 3e438cf..0000000 --- a/example/pubspec.yaml +++ /dev/null @@ -1,23 +0,0 @@ -name: example -description: A new Flutter project. -publish_to: 'none' # Remove this line if you wish to publish to pub.dev -version: 1.0.0+1 - -environment: - sdk: ">=2.7.0 <3.0.0" - -dependencies: - flutter: - sdk: flutter - cupertino_icons: ^1.0.1 - - async_button_builder: - path: ../ - -dev_dependencies: - flutter_test: - sdk: flutter - pedantic: ^1.10.0-nullsafety.3 - -flutter: - uses-material-design: true diff --git a/example/test/widget_test.dart b/example/test/widget_test.dart deleted file mode 100644 index 747db1d..0000000 --- a/example/test/widget_test.dart +++ /dev/null @@ -1,30 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility that Flutter provides. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'package:example/main.dart'; - -void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(MyApp()); - - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); - - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); - }); -} diff --git a/example/web/favicon.png b/example/web/favicon.png deleted file mode 100644 index 8aaa46ac1ae21512746f852a42ba87e4165dfdd1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 917 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|I14-?iy0X7 zltGxWVyS%@P(fs7NJL45ua8x7ey(0(N`6wRUPW#JP&EUCO@$SZnVVXYs8ErclUHn2 zVXFjIVFhG^g!Ppaz)DK8ZIvQ?0~DO|i&7O#^-S~(l1AfjnEK zjFOT9D}DX)@^Za$W4-*MbbUihOG|wNBYh(yU7!lx;>x^|#0uTKVr7USFmqf|i<65o z3raHc^AtelCMM;Vme?vOfh>Xph&xL%(-1c06+^uR^q@XSM&D4+Kp$>4P^%3{)XKjo zGZknv$b36P8?Z_gF{nK@`XI}Z90TzwSQO}0J1!f2c(B=V`5aP@1P1a|PZ!4!3&Gl8 zTYqUsf!gYFyJnXpu0!n&N*SYAX-%d(5gVjrHJWqXQshj@!Zm{!01WsQrH~9=kTxW#6SvuapgMqt>$=j#%eyGrQzr zP{L-3gsMA^$I1&gsBAEL+vxi1*Igl=8#8`5?A-T5=z-sk46WA1IUT)AIZHx1rdUrf zVJrJn<74DDw`j)Ki#gt}mIT-Q`XRa2-jQXQoI%w`nb|XblvzK${ZzlV)m-XcwC(od z71_OEC5Bt9GEXosOXaPTYOia#R4ID2TiU~`zVMl08TV_C%DnU4^+HE>9(CE4D6?Fz oujB08i7adh9xk7*FX66dWH6F5TM;?E2b5PlUHx3vIVCg!0Dx9vYXATM diff --git a/example/web/icons/Icon-192.png b/example/web/icons/Icon-192.png deleted file mode 100644 index b749bfef07473333cf1dd31e9eed89862a5d52aa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5292 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 diff --git a/example/web/icons/Icon-512.png b/example/web/icons/Icon-512.png deleted file mode 100644 index 88cfd48dff1169879ba46840804b412fe02fefd6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8252 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 diff --git a/example/web/index.html b/example/web/index.html deleted file mode 100644 index 1460b5e..0000000 --- a/example/web/index.html +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - - - - - - - - - - - - example - - - - - - - - diff --git a/example/web/manifest.json b/example/web/manifest.json deleted file mode 100644 index 8c01291..0000000 --- a/example/web/manifest.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "example", - "short_name": "example", - "start_url": ".", - "display": "standalone", - "background_color": "#0175C2", - "theme_color": "#0175C2", - "description": "A new Flutter project.", - "orientation": "portrait-primary", - "prefer_related_applications": false, - "icons": [ - { - "src": "icons/Icon-192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "icons/Icon-512.png", - "sizes": "512x512", - "type": "image/png" - } - ] -} diff --git a/lib/async_button_builder.dart b/lib/async_button_builder.dart deleted file mode 100644 index 2f7998d..0000000 --- a/lib/async_button_builder.dart +++ /dev/null @@ -1,4 +0,0 @@ -library async_button_builder; - -export 'package:async_button_builder/src/async_button_builder.dart'; -export 'package:async_button_builder/src/button_state/button_state.dart'; diff --git a/lib/src/async_button_builder.dart b/lib/src/async_button_builder.dart deleted file mode 100644 index d81b32a..0000000 --- a/lib/src/async_button_builder.dart +++ /dev/null @@ -1,446 +0,0 @@ -import 'dart:async'; - -import 'package:async_button_builder/src/button_state/button_state.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; - -typedef AsyncButtonBuilderCallback = Widget Function( - BuildContext context, - Widget child, - AsyncCallback? callback, - ButtonState buttonState, -); - -/// A `builder` that wraps a button providing disabled, loading, success and -/// error states while retaining almost full access to the original Button's -/// API. This is useful for any long running operations and helps better -/// improve UX. -/// -/// {@tool dartpad --template=stateful_widget_material} -/// -/// ```dart -/// -/// @override -/// Widget build(BuildContext context) { -/// return AsyncButtonBuilder( -/// child: Text('Click Me'), -/// loadingWidget: Text('Loading...'), -/// onPressed: () async { -/// await Future.delayed(Duration(seconds: 1)); -/// -/// throw 'shucks'; -/// }, -/// builder: (context, child, callback, buttonState) { -/// final buttonColor = buttonState.when( -/// idle: () => Colors.yellow[200], -/// loading: () => Colors.grey, -/// success: () => Colors.orangeAccent, -/// error: () => Colors.orange, -/// ); -/// -/// return OutlinedButton( -/// child: child, -/// onPressed: callback, -/// style: OutlinedButton.styleFrom( -/// primary: Colors.black, -/// backgroundColor: buttonColor, -/// ), -/// ); -/// }, -/// ), -/// } -/// ``` -/// {@end-tool} -/// -class AsyncButtonBuilder extends StatefulWidget { - /// This builder provides the widget's [BuildContext], the variable [child] - /// based on button state as well as the [callback] that should be passed to - /// the button and the current [ButtonState] - final AsyncButtonBuilderCallback builder; - - /// The child of the button. In the case of an [IconButton], this can be a an - /// [Icon]. For a [TextButton], a [Text]. - /// - /// This child will be animated between for the [loadingWidget] or default - /// [CircularProgressIndicator] when the asynchronous [onPressed] is called. - /// The animation will take place over [duration]. - final Widget child; - - /// The animation's duration between [child], [loadingWidget], - /// [successWidget] and [errorWidget]. This same value is used for both the - /// internal [AnimatedSize] and [TransitionBuilder]. - final Duration duration; - - /// The animation's reverse duration between [child], [loadingWidget], - /// [successWidget] and [errorWidget]. This same value is used for both the - /// internal [AnimatedSize] and [TransitionBuilder]. - final Duration reverseDuration; - - /// A callback that runs the async task. This is wrapped in order to begin - /// the button's internal `isLoading` before and after the operation - /// completes. - final AsyncCallback? onPressed; - - /// This is used to manually drive the state of the loading button thus - /// initiating the corresponding animation and showing the correct button - /// child. - final ButtonState buttonState; - - /// This is used to manually drive the disabled state of the button. - final bool disabled; - - /// The widget replaces the [child] when the button is in the loading state. - /// If this is null the default widget is: - /// - /// SizedBox( - /// height: 16.0, - /// width: 16.0, - /// child: CircularProgressIndicator(), - /// ) - final Widget? loadingWidget; - - /// The widget used to replace the [child] when the button is in a success - /// state. If this is null the default widget is: - /// - /// Icon( - /// Icons.check, - /// color: Theme.of(context).accentColor, - /// ); - final Widget? successWidget; - - /// The widget used to replace the [child] when the button is in a error - /// state. If this is null the default widget is: - /// - /// Icon( - /// Icons.error, - /// color: Theme.of(context).errorColor, - /// ) - final Widget? errorWidget; - - /// Whether to show the [successWidget] on success. - final bool showSuccess; - - /// Whether to show the [errorWidget] on error. - final bool showError; - - /// Optional [EdgeInsets] that will wrap around the [errorWidget]. This is a - /// convenience field that can be replaced by defining your own [errorWidget] - /// and wrapping it in a [Padding]. - final EdgeInsets? errorPadding; - - /// Optional [EdgeInsets] that will wrap around the [successWidget]. This is a - /// convenience field that can be replaced by defining your own - /// [successWidget] and wrapping it in a [Padding]. - final EdgeInsets? successPadding; - - /// Defines a custom transition when animating between any state and `idle` - final AnimatedSwitcherTransitionBuilder idleTransitionBuilder; - - /// Defines a custom transition when animating between any state and `loading` - final AnimatedSwitcherTransitionBuilder loadingTransitionBuilder; - - /// Defines a custom transition when animating between any state and `success` - final AnimatedSwitcherTransitionBuilder successTransitionBuilder; - - /// Defines a custom transition when animating between any state and `error` - final AnimatedSwitcherTransitionBuilder errorTransitionBuilder; - - /// The amount of idle time the [successWidget] shows - final Duration successDuration; - - /// The amount of idle time the [errorWidget] shows - final Duration errorDuration; - - /// Defines a curve for the custom transition. This used in in an - /// [AnimatedSwitcher] and only takes effect when animating to `idle` - final Curve idleSwitchInCurve; - - /// Defines a curve for the custom transition. This used in in an - /// [AnimatedSwitcher] and only takes effect when animating to `loading` - final Curve loadingSwitchInCurve; - - /// Defines a curve for the custom transition. This used in in an - /// [AnimatedSwitcher] and only takes effect when animating to `success` - final Curve successSwitchInCurve; - - /// Defines a curve for the custom transition. This used in in an - /// [AnimatedSwitcher] and only takes effect when animating to `error` - final Curve errorSwitchInCurve; - - /// Defines a curve for the custom transition. This used in in an - /// [AnimatedSwitcher] and only takes effect when animating out of `idle` - final Curve idleSwitchOutCurve; - - /// Defines a curve for the custom transition. This used in in an - /// [AnimatedSwitcher] and only takes effect when animating out of `loading` - final Curve loadingSwitchOutCurve; - - /// Defines a curve for the custom transition. This used in in an - /// [AnimatedSwitcher] and only takes effect when animating out of `success` - final Curve successSwitchOutCurve; - - /// Defines a curve for the custom transition. This used in in an - /// [AnimatedSwitcher] and only takes effect when animating out of `error` - final Curve errorSwitchOutCurve; - - /// Defines a curve for the internal [AnimatedSize] - final Curve sizeCurve; - - /// Defines the [Clip] for the internal [AnimatedSize] - final Clip sizeClipBehavior; - - /// Defines the [Alignment] for the internal [AnimatedSize] - final Alignment sizeAlignment; - - /// Whether to animate the [Size] of the widget implicitly. - final bool animateSize; - - const AsyncButtonBuilder({ - Key? key, - required this.child, - required this.onPressed, - required this.builder, - this.loadingWidget, - this.successWidget, - this.errorWidget, - this.showSuccess = true, - this.showError = true, - this.errorPadding, - this.successPadding, - this.buttonState = const ButtonState.idle(), - this.duration = const Duration(milliseconds: 250), - this.reverseDuration = const Duration(milliseconds: 250), - this.disabled = false, - this.successDuration = const Duration(seconds: 1), - this.errorDuration = const Duration(seconds: 1), - this.loadingTransitionBuilder = AnimatedSwitcher.defaultTransitionBuilder, - this.idleTransitionBuilder = AnimatedSwitcher.defaultTransitionBuilder, - this.successTransitionBuilder = AnimatedSwitcher.defaultTransitionBuilder, - this.errorTransitionBuilder = AnimatedSwitcher.defaultTransitionBuilder, - this.idleSwitchInCurve = Curves.linear, - this.loadingSwitchInCurve = Curves.linear, - this.successSwitchInCurve = Curves.linear, - this.errorSwitchInCurve = Curves.linear, - this.idleSwitchOutCurve = Curves.linear, - this.loadingSwitchOutCurve = Curves.linear, - this.successSwitchOutCurve = Curves.linear, - this.errorSwitchOutCurve = Curves.linear, - this.sizeCurve = Curves.linear, - this.sizeClipBehavior = Clip.hardEdge, - this.sizeAlignment = Alignment.center, - this.animateSize = true, - }) : super(key: key); - // TODO: I need asserts that will assert the keys are different for child, - // loading, error, etc. because otherwise transitions won't work as expected - // and I'll get user issues - - @override - _AsyncButtonBuilderState createState() => _AsyncButtonBuilderState(); -} - -class _AsyncButtonBuilderState extends State - with SingleTickerProviderStateMixin { - late ButtonState buttonState; - Timer? timer; - - @override - void initState() { - buttonState = widget.buttonState; - super.initState(); - } - - @override - void didUpdateWidget(covariant AsyncButtonBuilder oldWidget) { - if (widget.buttonState != oldWidget.buttonState) { - setState(() { - buttonState = buttonState; - }); - } - - super.didUpdateWidget(oldWidget); - } - - @override - void dispose() { - timer?.cancel(); - - super.dispose(); - } - - @override - Widget build(BuildContext context) { - final theme = Theme.of(context); - final onPressed = widget.onPressed; - final widgetKey = widget.key; - final loadingWidget = widget.loadingWidget ?? - const SizedBox( - height: 16.0, - width: 16.0, - child: CircularProgressIndicator(), - ); - var successWidget = widget.successWidget ?? - Icon( - Icons.check, - color: theme.colorScheme.secondary, - ); - var errorWidget = widget.errorWidget ?? - Icon( - Icons.error, - color: theme.errorColor, - ); - final successPadding = widget.successPadding; - final errorPadding = widget.errorPadding; - - // This is necessary in the case of nested async button builders. - // We cannot have the same __idle__, __loading__, etc. keys as they might - // conflict with one another. - String parentKeyValue = ''; - - if (widgetKey != null && widgetKey is ValueKey) { - parentKeyValue = widgetKey.value.toString(); - } - - if (successPadding != null) { - successWidget = Padding( - padding: successPadding, - child: successWidget, - ); - } - - if (errorPadding != null) { - errorWidget = Padding( - padding: errorPadding, - child: errorWidget, - ); - } - - final switcher = AnimatedSwitcher( - // TODO: This duration is same as size's duration. That's okay right? - duration: widget.duration, - reverseDuration: widget.reverseDuration, - switchInCurve: buttonState.when( - idle: () => widget.idleSwitchInCurve, - loading: () => widget.loadingSwitchInCurve, - success: () => widget.successSwitchInCurve, - error: () => widget.errorSwitchInCurve, - ), - switchOutCurve: buttonState.when( - idle: () => widget.idleSwitchOutCurve, - loading: () => widget.loadingSwitchOutCurve, - success: () => widget.successSwitchOutCurve, - error: () => widget.errorSwitchOutCurve, - ), - transitionBuilder: buttonState.when( - idle: () => widget.idleTransitionBuilder, - loading: () => widget.loadingTransitionBuilder, - success: () => widget.successTransitionBuilder, - error: () => widget.errorTransitionBuilder, - ), - child: buttonState.when( - idle: () => KeyedSubtree( - key: ValueKey('__idle__' + parentKeyValue), - child: widget.child, - ), - loading: () => KeyedSubtree( - key: ValueKey('__loading__' + parentKeyValue), - child: loadingWidget, - ), - success: () => KeyedSubtree( - key: ValueKey('__success__' + parentKeyValue), - child: successWidget, - ), - error: () => KeyedSubtree( - key: ValueKey('__error__' + parentKeyValue), - child: errorWidget, - ), - ), - ); - - return widget.builder( - context, - // TODO: I really just wanted an AnimatedSwitcher and the default - // transitionBuilder to be a SizedTransition but it was impossible - // to figure out how to reproduce the exact behaviour of AnimatedSize - widget.animateSize - ? AnimatedSize( - vsync: this, - duration: widget.duration, - reverseDuration: widget.reverseDuration, - alignment: widget.sizeAlignment, - clipBehavior: widget.sizeClipBehavior, - curve: widget.sizeCurve, - child: switcher, - ) - : switcher, - widget.disabled - ? null - : onPressed == null - ? null - : buttonState.maybeWhen( - idle: () => () { - final completer = Completer(); - // I might not want to set buttonState if we're being - // driven by widget.buttonState... - setState(() { - buttonState = const ButtonState.loading(); - }); - - timer?.cancel(); - - onPressed.call().then((_) { - completer.complete(); - - if (mounted) { - if (widget.showSuccess) { - setState(() { - buttonState = const ButtonState.success(); - }); - - setTimer(widget.successDuration); - } else { - setState(() { - buttonState = const ButtonState.idle(); - }); - } - } - }).catchError((Object error, StackTrace stackTrace) { - completer.completeError(error, stackTrace); - - if (mounted) { - if (widget.showError) { - setState(() { - buttonState = const ButtonState.error(); - }); - - setTimer(widget.errorDuration); - } else { - setState(() { - buttonState = const ButtonState.idle(); - }); - } - } - }); - - return completer.future; - }, - orElse: () => null, - ), - buttonState, - ); - } - - void setTimer(Duration duration) { - timer = Timer( - duration, - () { - timer?.cancel(); - - if (mounted) { - setState(() { - buttonState = const ButtonState.idle(); - }); - } - }, - ); - } -} diff --git a/lib/src/button_state/button_state.dart b/lib/src/button_state/button_state.dart deleted file mode 100644 index c2a0a1a..0000000 --- a/lib/src/button_state/button_state.dart +++ /dev/null @@ -1,39 +0,0 @@ -import 'package:freezed_annotation/freezed_annotation.dart'; - -part 'button_state.freezed.dart'; - -/// This union class represents the state of the button in either a [Idling], -/// [Loading], [Success] or [Error] state. This can be considered a enum with extra -/// utilities for ease of use. -/// -/// {@tool snippet} -/// -/// ```dart -/// final buttonColor = buttonState.when( -/// idle: () => Colors.pink, -/// loading: () => Colors.blue, -/// success: () => Colors.green, -/// error: () => Colors.red, -/// ); -/// ``` -/// {@end-tool} -/// -/// You can also disregard other states and handle only those you'd like using -/// the `.maybeWhen` syntax. -/// -/// /// {@tool snippet} -/// -/// ```dart -/// final buttonColor = buttonState.maybeWhen( -/// idle: () => Colors.pink, -/// orElse: () => Colors.red, -/// ); -/// ``` -/// {@end-tool} -@freezed -class ButtonState with _$ButtonState { - const factory ButtonState.idle() = Idle; - const factory ButtonState.loading() = Loading; - const factory ButtonState.success() = Success; - const factory ButtonState.error() = Error; -} diff --git a/lib/src/button_state/button_state.freezed.dart b/lib/src/button_state/button_state.freezed.dart deleted file mode 100644 index b200140..0000000 --- a/lib/src/button_state/button_state.freezed.dart +++ /dev/null @@ -1,455 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides - -part of 'button_state.dart'; - -// ************************************************************************** -// FreezedGenerator -// ************************************************************************** - -T _$identity(T value) => value; - -final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); - -/// @nodoc -class _$ButtonStateTearOff { - const _$ButtonStateTearOff(); - - Idle idle() { - return const Idle(); - } - - Loading loading() { - return const Loading(); - } - - Success success() { - return const Success(); - } - - Error error() { - return const Error(); - } -} - -/// @nodoc -const $ButtonState = _$ButtonStateTearOff(); - -/// @nodoc -mixin _$ButtonState { - @optionalTypeArgs - TResult when({ - required TResult Function() idle, - required TResult Function() loading, - required TResult Function() success, - required TResult Function() error, - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult maybeWhen({ - TResult Function()? idle, - TResult Function()? loading, - TResult Function()? success, - TResult Function()? error, - required TResult orElse(), - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult map({ - required TResult Function(Idle value) idle, - required TResult Function(Loading value) loading, - required TResult Function(Success value) success, - required TResult Function(Error value) error, - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult maybeMap({ - TResult Function(Idle value)? idle, - TResult Function(Loading value)? loading, - TResult Function(Success value)? success, - TResult Function(Error value)? error, - required TResult orElse(), - }) => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $ButtonStateCopyWith<$Res> { - factory $ButtonStateCopyWith( - ButtonState value, $Res Function(ButtonState) then) = - _$ButtonStateCopyWithImpl<$Res>; -} - -/// @nodoc -class _$ButtonStateCopyWithImpl<$Res> implements $ButtonStateCopyWith<$Res> { - _$ButtonStateCopyWithImpl(this._value, this._then); - - final ButtonState _value; - // ignore: unused_field - final $Res Function(ButtonState) _then; -} - -/// @nodoc -abstract class $IdleCopyWith<$Res> { - factory $IdleCopyWith(Idle value, $Res Function(Idle) then) = - _$IdleCopyWithImpl<$Res>; -} - -/// @nodoc -class _$IdleCopyWithImpl<$Res> extends _$ButtonStateCopyWithImpl<$Res> - implements $IdleCopyWith<$Res> { - _$IdleCopyWithImpl(Idle _value, $Res Function(Idle) _then) - : super(_value, (v) => _then(v as Idle)); - - @override - Idle get _value => super._value as Idle; -} - -/// @nodoc - -class _$Idle implements Idle { - const _$Idle(); - - @override - String toString() { - return 'ButtonState.idle()'; - } - - @override - bool operator ==(dynamic other) { - return identical(this, other) || (other is Idle); - } - - @override - int get hashCode => runtimeType.hashCode; - - @override - @optionalTypeArgs - TResult when({ - required TResult Function() idle, - required TResult Function() loading, - required TResult Function() success, - required TResult Function() error, - }) { - return idle(); - } - - @override - @optionalTypeArgs - TResult maybeWhen({ - TResult Function()? idle, - TResult Function()? loading, - TResult Function()? success, - TResult Function()? error, - required TResult orElse(), - }) { - if (idle != null) { - return idle(); - } - return orElse(); - } - - @override - @optionalTypeArgs - TResult map({ - required TResult Function(Idle value) idle, - required TResult Function(Loading value) loading, - required TResult Function(Success value) success, - required TResult Function(Error value) error, - }) { - return idle(this); - } - - @override - @optionalTypeArgs - TResult maybeMap({ - TResult Function(Idle value)? idle, - TResult Function(Loading value)? loading, - TResult Function(Success value)? success, - TResult Function(Error value)? error, - required TResult orElse(), - }) { - if (idle != null) { - return idle(this); - } - return orElse(); - } -} - -abstract class Idle implements ButtonState { - const factory Idle() = _$Idle; -} - -/// @nodoc -abstract class $LoadingCopyWith<$Res> { - factory $LoadingCopyWith(Loading value, $Res Function(Loading) then) = - _$LoadingCopyWithImpl<$Res>; -} - -/// @nodoc -class _$LoadingCopyWithImpl<$Res> extends _$ButtonStateCopyWithImpl<$Res> - implements $LoadingCopyWith<$Res> { - _$LoadingCopyWithImpl(Loading _value, $Res Function(Loading) _then) - : super(_value, (v) => _then(v as Loading)); - - @override - Loading get _value => super._value as Loading; -} - -/// @nodoc - -class _$Loading implements Loading { - const _$Loading(); - - @override - String toString() { - return 'ButtonState.loading()'; - } - - @override - bool operator ==(dynamic other) { - return identical(this, other) || (other is Loading); - } - - @override - int get hashCode => runtimeType.hashCode; - - @override - @optionalTypeArgs - TResult when({ - required TResult Function() idle, - required TResult Function() loading, - required TResult Function() success, - required TResult Function() error, - }) { - return loading(); - } - - @override - @optionalTypeArgs - TResult maybeWhen({ - TResult Function()? idle, - TResult Function()? loading, - TResult Function()? success, - TResult Function()? error, - required TResult orElse(), - }) { - if (loading != null) { - return loading(); - } - return orElse(); - } - - @override - @optionalTypeArgs - TResult map({ - required TResult Function(Idle value) idle, - required TResult Function(Loading value) loading, - required TResult Function(Success value) success, - required TResult Function(Error value) error, - }) { - return loading(this); - } - - @override - @optionalTypeArgs - TResult maybeMap({ - TResult Function(Idle value)? idle, - TResult Function(Loading value)? loading, - TResult Function(Success value)? success, - TResult Function(Error value)? error, - required TResult orElse(), - }) { - if (loading != null) { - return loading(this); - } - return orElse(); - } -} - -abstract class Loading implements ButtonState { - const factory Loading() = _$Loading; -} - -/// @nodoc -abstract class $SuccessCopyWith<$Res> { - factory $SuccessCopyWith(Success value, $Res Function(Success) then) = - _$SuccessCopyWithImpl<$Res>; -} - -/// @nodoc -class _$SuccessCopyWithImpl<$Res> extends _$ButtonStateCopyWithImpl<$Res> - implements $SuccessCopyWith<$Res> { - _$SuccessCopyWithImpl(Success _value, $Res Function(Success) _then) - : super(_value, (v) => _then(v as Success)); - - @override - Success get _value => super._value as Success; -} - -/// @nodoc - -class _$Success implements Success { - const _$Success(); - - @override - String toString() { - return 'ButtonState.success()'; - } - - @override - bool operator ==(dynamic other) { - return identical(this, other) || (other is Success); - } - - @override - int get hashCode => runtimeType.hashCode; - - @override - @optionalTypeArgs - TResult when({ - required TResult Function() idle, - required TResult Function() loading, - required TResult Function() success, - required TResult Function() error, - }) { - return success(); - } - - @override - @optionalTypeArgs - TResult maybeWhen({ - TResult Function()? idle, - TResult Function()? loading, - TResult Function()? success, - TResult Function()? error, - required TResult orElse(), - }) { - if (success != null) { - return success(); - } - return orElse(); - } - - @override - @optionalTypeArgs - TResult map({ - required TResult Function(Idle value) idle, - required TResult Function(Loading value) loading, - required TResult Function(Success value) success, - required TResult Function(Error value) error, - }) { - return success(this); - } - - @override - @optionalTypeArgs - TResult maybeMap({ - TResult Function(Idle value)? idle, - TResult Function(Loading value)? loading, - TResult Function(Success value)? success, - TResult Function(Error value)? error, - required TResult orElse(), - }) { - if (success != null) { - return success(this); - } - return orElse(); - } -} - -abstract class Success implements ButtonState { - const factory Success() = _$Success; -} - -/// @nodoc -abstract class $ErrorCopyWith<$Res> { - factory $ErrorCopyWith(Error value, $Res Function(Error) then) = - _$ErrorCopyWithImpl<$Res>; -} - -/// @nodoc -class _$ErrorCopyWithImpl<$Res> extends _$ButtonStateCopyWithImpl<$Res> - implements $ErrorCopyWith<$Res> { - _$ErrorCopyWithImpl(Error _value, $Res Function(Error) _then) - : super(_value, (v) => _then(v as Error)); - - @override - Error get _value => super._value as Error; -} - -/// @nodoc - -class _$Error implements Error { - const _$Error(); - - @override - String toString() { - return 'ButtonState.error()'; - } - - @override - bool operator ==(dynamic other) { - return identical(this, other) || (other is Error); - } - - @override - int get hashCode => runtimeType.hashCode; - - @override - @optionalTypeArgs - TResult when({ - required TResult Function() idle, - required TResult Function() loading, - required TResult Function() success, - required TResult Function() error, - }) { - return error(); - } - - @override - @optionalTypeArgs - TResult maybeWhen({ - TResult Function()? idle, - TResult Function()? loading, - TResult Function()? success, - TResult Function()? error, - required TResult orElse(), - }) { - if (error != null) { - return error(); - } - return orElse(); - } - - @override - @optionalTypeArgs - TResult map({ - required TResult Function(Idle value) idle, - required TResult Function(Loading value) loading, - required TResult Function(Success value) success, - required TResult Function(Error value) error, - }) { - return error(this); - } - - @override - @optionalTypeArgs - TResult maybeMap({ - TResult Function(Idle value)? idle, - TResult Function(Loading value)? loading, - TResult Function(Success value)? success, - TResult Function(Error value)? error, - required TResult orElse(), - }) { - if (error != null) { - return error(this); - } - return orElse(); - } -} - -abstract class Error implements ButtonState { - const factory Error() = _$Error; -} diff --git a/melos.yaml b/melos.yaml new file mode 100644 index 0000000..b244638 --- /dev/null +++ b/melos.yaml @@ -0,0 +1,42 @@ +name: async_button + +packages: + - packages/** + +scripts: + analyze: + run: | + melos exec -c 1 -- \ + flutter analyze . + description: | + Run `dart analyze` in all packages. + - Note: you can also rely on your IDEs Dart Analysis / Issues window. + generate: + run: melos run generate:dart && melos run generate:flutter + description: Build all generated files for Dart & Flutter packages in this project. + + generate:dart: + run: melos exec -c 1 --depends-on="build_runner" --no-flutter -- "dart run build_runner build --delete-conflicting-outputs" + description: Build all generated files for Dart packages in this project. + + generate:flutter: + run: melos exec -c 1 --depends-on="build_runner" --flutter -- "flutter pub run build_runner build --delete-conflicting-outputs" + description: Build all generated files for Flutter packages in this project. + + test: + run: melos run test:dart --no-select && melos run test:flutter --no-select + description: Run all Dart & Flutter tests in this project. + + test:dart: + run: melos exec -c 1 --fail-fast -- "\$MELOS_ROOT_PATH/scripts/coverage.sh" + description: Run Dart tests for a specific package in this project. + select-package: + flutter: false + dir-exists: test + + test:flutter: + run: melos exec --dir-exists="test" -c 1 --fail-fast -- "flutter test --coverage" + description: Run Flutter tests for a specific package in this project. + select-package: + flutter: true + dir-exists: test \ No newline at end of file diff --git a/melos_async_button.iml b/melos_async_button.iml new file mode 100644 index 0000000..8be8bf8 --- /dev/null +++ b/melos_async_button.iml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/melos_my_project.iml b/melos_my_project.iml new file mode 100644 index 0000000..8be8bf8 --- /dev/null +++ b/melos_my_project.iml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/packages/async_button_builder/lib/src/async_button_builder.dart b/packages/async_button_builder/lib/src/async_button_builder.dart index 22333c2..0de4ab1 100644 --- a/packages/async_button_builder/lib/src/async_button_builder.dart +++ b/packages/async_button_builder/lib/src/async_button_builder.dart @@ -1,197 +1,104 @@ import 'dart:async'; +import 'package:async_button_core/async_button_core.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -typedef AsyncButtonBuilderCallback = Widget Function( - BuildContext context, - Widget child, - AsyncCallback? callback, - ButtonState buttonState, -); - -/// A `builder` that wraps a button providing disabled, loading, success and -/// error states while retaining almost full access to the original Button's -/// API. This is useful for any long running operations and helps better -/// improve UX. -/// -/// {@tool dartpad --template=stateful_widget_material} -/// -/// ```dart -/// -/// @override -/// Widget build(BuildContext context) { -/// return AsyncButtonBuilder( -/// child: Text('Click Me'), -/// loadingWidget: Text('Loading...'), -/// onPressed: () async { -/// await Future.delayed(Duration(seconds: 1)); -/// -/// throw 'shucks'; -/// }, -/// builder: (context, child, callback, buttonState) { -/// final buttonColor = buttonState.when( -/// idle: () => Colors.yellow[200], -/// loading: () => Colors.grey, -/// success: () => Colors.orangeAccent, -/// error: () => Colors.orange, -/// ); -/// -/// return OutlinedButton( -/// child: child, -/// onPressed: callback, -/// style: OutlinedButton.styleFrom( -/// primary: Colors.black, -/// backgroundColor: buttonColor, -/// ), -/// ); -/// }, -/// ), -/// } -/// ``` -/// {@end-tool} -/// -class AsyncButtonBuilder extends StatefulWidget { - /// This builder provides the widget's [BuildContext], the variable [child] - /// based on button state as well as the [callback] that should be passed to - /// the button and the current [ButtonState] +class AsyncButtonBuilder extends StatefulWidget implements AsyncButton { + @override final AsyncButtonBuilderCallback builder; - /// The child of the button. In the case of an [IconButton], this can be a an - /// [Icon]. For a [TextButton], a [Text]. - /// - /// This child will be animated between for the [loadingWidget] or default - /// [CircularProgressIndicator] when the asynchronous [onPressed] is called. - /// The animation will take place over [duration]. + @override final Widget child; - /// The animation's duration between [child], [loadingWidget], - /// [successWidget] and [errorWidget]. This same value is used for both the - /// internal [AnimatedSize] and [TransitionBuilder]. + @override final Duration duration; - /// The animation's reverse duration between [child], [loadingWidget], - /// [successWidget] and [errorWidget]. This same value is used for both the - /// internal [AnimatedSize] and [TransitionBuilder]. + @override final Duration reverseDuration; - /// A callback that runs the async task. This is wrapped in order to begin - /// the button's internal `isLoading` before and after the operation - /// completes. + @override final AsyncCallback? onPressed; - /// This is used to manually drive the state of the loading button thus - /// initiating the corresponding animation and showing the correct button - /// child. + @override final ButtonState buttonState; - /// This is used to manually drive the disabled state of the button. + @override final bool disabled; - /// The widget replaces the [child] when the button is in the loading state. - /// If this is null the default widget is: - /// - /// SizedBox( - /// height: 16.0, - /// width: 16.0, - /// child: CircularProgressIndicator(), - /// ) + @override final Widget? loadingWidget; - /// The widget used to replace the [child] when the button is in a success - /// state. If this is null the default widget is: - /// - /// Icon( - /// Icons.check, - /// color: Theme.of(context).accentColor, - /// ); + @override final Widget? successWidget; - /// The widget used to replace the [child] when the button is in a error - /// state. If this is null the default widget is: - /// - /// Icon( - /// Icons.error, - /// color: Theme.of(context).errorColor, - /// ) + @override final Widget? errorWidget; - /// Whether to show the [successWidget] on success. + @override final bool showSuccess; - /// Whether to show the [errorWidget] on error. + @override final bool showError; - /// Optional [EdgeInsets] that will wrap around the [errorWidget]. This is a - /// convenience field that can be replaced by defining your own [errorWidget] - /// and wrapping it in a [Padding]. + @override final EdgeInsets? errorPadding; - /// Optional [EdgeInsets] that will wrap around the [successWidget]. This is a - /// convenience field that can be replaced by defining your own - /// [successWidget] and wrapping it in a [Padding]. + @override final EdgeInsets? successPadding; - /// Defines a custom transition when animating between any state and `idle` + @override final AnimatedSwitcherTransitionBuilder idleTransitionBuilder; - /// Defines a custom transition when animating between any state and `loading` + @override final AnimatedSwitcherTransitionBuilder loadingTransitionBuilder; - /// Defines a custom transition when animating between any state and `success` + @override final AnimatedSwitcherTransitionBuilder successTransitionBuilder; - /// Defines a custom transition when animating between any state and `error` + @override final AnimatedSwitcherTransitionBuilder errorTransitionBuilder; - /// The amount of idle time the [successWidget] shows + @override final Duration successDuration; - /// The amount of idle time the [errorWidget] shows + @override final Duration errorDuration; - /// Defines a curve for the custom transition. This used in in an - /// [AnimatedSwitcher] and only takes effect when animating to `idle` + @override final Curve idleSwitchInCurve; - /// Defines a curve for the custom transition. This used in in an - /// [AnimatedSwitcher] and only takes effect when animating to `loading` + @override final Curve loadingSwitchInCurve; - /// Defines a curve for the custom transition. This used in in an - /// [AnimatedSwitcher] and only takes effect when animating to `success` + @override final Curve successSwitchInCurve; - /// Defines a curve for the custom transition. This used in in an - /// [AnimatedSwitcher] and only takes effect when animating to `error` + @override final Curve errorSwitchInCurve; - /// Defines a curve for the custom transition. This used in in an - /// [AnimatedSwitcher] and only takes effect when animating out of `idle` + @override final Curve idleSwitchOutCurve; - /// Defines a curve for the custom transition. This used in in an - /// [AnimatedSwitcher] and only takes effect when animating out of `loading` + @override final Curve loadingSwitchOutCurve; - /// Defines a curve for the custom transition. This used in in an - /// [AnimatedSwitcher] and only takes effect when animating out of `success` + @override final Curve successSwitchOutCurve; - /// Defines a curve for the custom transition. This used in in an - /// [AnimatedSwitcher] and only takes effect when animating out of `error` + @override final Curve errorSwitchOutCurve; - /// Defines a curve for the internal [AnimatedSize] + @override final Curve sizeCurve; - /// Defines the [Clip] for the internal [AnimatedSize] + @override final Clip sizeClipBehavior; - /// Defines the [Alignment] for the internal [AnimatedSize] + @override final Alignment sizeAlignment; - /// Whether to animate the [Size] of the widget implicitly. + @override final bool animateSize; const AsyncButtonBuilder({ diff --git a/packages/async_button_builder/pubspec.yaml b/packages/async_button_builder/pubspec.yaml index dfd86d9..484967f 100644 --- a/packages/async_button_builder/pubspec.yaml +++ b/packages/async_button_builder/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: flutter: sdk: flutter freezed_annotation: ^0.14.2 - async_button_core: + async_button_core: ^0.0.1 dev_dependencies: flutter_test: diff --git a/packages/async_button_core/lib/async_button_core.dart b/packages/async_button_core/lib/async_button_core.dart index a892dfe..b36931b 100644 --- a/packages/async_button_core/lib/async_button_core.dart +++ b/packages/async_button_core/lib/async_button_core.dart @@ -1,3 +1,4 @@ library async_button_core; -export './async_button_core.dart'; +export 'package:async_button_core/src/button_state/button_state.dart'; +export 'package:async_button_core/src/types.dart'; diff --git a/packages/async_button_core/lib/src/types.dart b/packages/async_button_core/lib/src/types.dart new file mode 100644 index 0000000..98e56c6 --- /dev/null +++ b/packages/async_button_core/lib/src/types.dart @@ -0,0 +1,200 @@ +import 'package:async_button_core/async_button_core.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +typedef AsyncButtonBuilderCallback = Widget Function( + BuildContext context, + Widget child, + AsyncCallback? callback, + ButtonState buttonState, +); + +// TODO: I created this class so I can do dartdoc stuff and use it in both +// the builder and the hook. Currently not paying off. + +/// A `builder` that wraps a button providing disabled, loading, success and +/// error states while retaining almost full access to the original Button's +/// API. This is useful for any long running operations and helps better +/// improve UX. +/// +/// {@tool dartpad --template=stateful_widget_material} +/// +/// ```dart +/// +/// @override +/// Widget build(BuildContext context) { +/// return AsyncButtonBuilder( +/// child: Text('Click Me'), +/// loadingWidget: Text('Loading...'), +/// onPressed: () async { +/// await Future.delayed(Duration(seconds: 1)); +/// +/// throw 'shucks'; +/// }, +/// builder: (context, child, callback, buttonState) { +/// final buttonColor = buttonState.when( +/// idle: () => Colors.yellow[200], +/// loading: () => Colors.grey, +/// success: () => Colors.orangeAccent, +/// error: () => Colors.orange, +/// ); +/// +/// return OutlinedButton( +/// child: child, +/// onPressed: callback, +/// style: OutlinedButton.styleFrom( +/// primary: Colors.black, +/// backgroundColor: buttonColor, +/// ), +/// ); +/// }, +/// ), +/// } +/// ``` +/// {@end-tool} +/// +abstract class AsyncButton { + /// This builder provides the widget's [BuildContext], the variable [child] + /// based on button state as well as the [callback] that should be passed to + /// the button and the current [ButtonState] + AsyncButtonBuilderCallback get builder; + + /// {@template asyncButton.interface.child} + /// The child of the button. In the case of an [IconButton], this can be a an + /// [Icon]. For a [TextButton], a [Text]. + /// + /// This child will be animated between for the [loadingWidget] or default + /// [CircularProgressIndicator] when the asynchronous [onPressed] is called. + /// The animation will take place over [duration]. + /// {@endtemplate} + Widget get child; + + /// The animation's duration between [child], [loadingWidget], + /// [successWidget] and [errorWidget]. This same value is used for both the + /// internal [AnimatedSize] and [TransitionBuilder]. + Duration get duration; + + /// The animation's reverse duration between [child], [loadingWidget], + /// [successWidget] and [errorWidget]. This same value is used for both the + /// internal [AnimatedSize] and [TransitionBuilder]. + Duration get reverseDuration; + + /// A callback that runs the async task. This is wrapped in order to begin + /// the button's internal `isLoading` before and after the operation + /// completes. + AsyncCallback? get onPressed; + + /// This is used to manually drive the state of the loading button thus + /// initiating the corresponding animation and showing the correct button + /// child. + ButtonState get buttonState; + + /// This is used to manually drive the disabled state of the button. + bool get disabled; + + /// The widget replaces the [child] when the button is in the loading state. + /// If this is null the default widget is: + /// + /// SizedBox( + /// height: 16.0, + /// width: 16.0, + /// child: CircularProgressIndicator(), + /// ) + Widget? get loadingWidget; + + /// The widget used to replace the [child] when the button is in a success + /// state. If this is null the default widget is: + /// + /// Icon( + /// Icons.check, + /// color: Theme.of(context).accentColor, + /// ); + Widget? get successWidget; + + /// The widget used to replace the [child] when the button is in a error + /// state. If this is null the default widget is: + /// + /// Icon( + /// Icons.error, + /// color: Theme.of(context).errorColor, + /// ) + Widget? get errorWidget; + + /// Whether to show the [successWidget] on success. + bool get showSuccess; + + /// Whether to show the [errorWidget] on error. + bool get showError; + + /// Optional [EdgeInsets] that will wrap around the [errorWidget]. This is a + /// convenience field that can be replaced by defining your own [errorWidget] + /// and wrapping it in a [Padding]. + EdgeInsets? get errorPadding; + + /// Optional [EdgeInsets] that will wrap around the [successWidget]. This is a + /// convenience field that can be replaced by defining your own + /// [successWidget] and wrapping it in a [Padding]. + EdgeInsets? get successPadding; + + /// Defines a custom transition when animating between any state and `idle` + AnimatedSwitcherTransitionBuilder get idleTransitionBuilder; + + /// Defines a custom transition when animating between any state and `loading` + AnimatedSwitcherTransitionBuilder get loadingTransitionBuilder; + + /// Defines a custom transition when animating between any state and `success` + AnimatedSwitcherTransitionBuilder get successTransitionBuilder; + + /// Defines a custom transition when animating between any state and `error` + AnimatedSwitcherTransitionBuilder get errorTransitionBuilder; + + /// The amount of idle time the [successWidget] shows + Duration get successDuration; + + /// The amount of idle time the [errorWidget] shows + Duration get errorDuration; + + /// Defines a curve for the custom transition. This used in in an + /// [AnimatedSwitcher] and only takes effect when animating to `idle` + Curve get idleSwitchInCurve; + + /// Defines a curve for the custom transition. This used in in an + /// [AnimatedSwitcher] and only takes effect when animating to `loading` + Curve get loadingSwitchInCurve; + + /// Defines a curve for the custom transition. This used in in an + /// [AnimatedSwitcher] and only takes effect when animating to `success` + Curve get successSwitchInCurve; + + /// Defines a curve for the custom transition. This used in in an + /// [AnimatedSwitcher] and only takes effect when animating to `error` + Curve get errorSwitchInCurve; + + /// Defines a curve for the custom transition. This used in in an + /// [AnimatedSwitcher] and only takes effect when animating out of `idle` + Curve get idleSwitchOutCurve; + + /// Defines a curve for the custom transition. This used in in an + /// [AnimatedSwitcher] and only takes effect when animating out of `loading` + Curve get loadingSwitchOutCurve; + + /// Defines a curve for the custom transition. This used in in an + /// [AnimatedSwitcher] and only takes effect when animating out of `success` + Curve get successSwitchOutCurve; + + /// Defines a curve for the custom transition. This used in in an + /// [AnimatedSwitcher] and only takes effect when animating out of `error` + Curve get errorSwitchOutCurve; + + /// Defines a curve for the internal [AnimatedSize] + Curve get sizeCurve; + + /// Defines the [Clip] for the internal [AnimatedSize] + Clip get sizeClipBehavior; + + /// Defines the [Alignment] for the internal [AnimatedSize] + Alignment get sizeAlignment; + + /// Whether to animate the [Size] of the widget implicitly. + bool get animateSize; +} diff --git a/packages/async_button_hook/lib/async_button_hook.dart b/packages/async_button_hook/lib/async_button_hook.dart index c2bc3e2..258cb5e 100644 --- a/packages/async_button_hook/lib/async_button_hook.dart +++ b/packages/async_button_hook/lib/async_button_hook.dart @@ -1 +1,3 @@ library async_button_hook; + +export 'package:async_button_hook/async_button_hook.dart'; diff --git a/packages/async_button_hook/lib/src/async_button_hook.dart b/packages/async_button_hook/lib/src/async_button_hook.dart new file mode 100644 index 0000000..de45be1 --- /dev/null +++ b/packages/async_button_hook/lib/src/async_button_hook.dart @@ -0,0 +1,210 @@ +import 'dart:async'; + +import 'package:async_button_core/async_button_core.dart'; +import 'package:async_button_hook/src/models/async_button_result.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; + +/// A button that can be used to perform an asynchronous operation. +AsyncButtonResult useAsyncButton({ + required Widget child, + required AsyncCallback? onPressed, + Widget? loadingWidget, + Widget? successWidget, + Widget? errorWidget, + bool showSuccess = true, + bool showError = true, + EdgeInsets? errorPadding, + EdgeInsets? successPadding, + ButtonState buttonState = const ButtonState.idle(), + Duration duration = const Duration(milliseconds: 250), + Duration reverseDuration = const Duration(milliseconds: 250), + bool disabled = false, + Duration successDuration = const Duration(seconds: 1), + Duration errorDuration = const Duration(seconds: 1), + AnimatedSwitcherTransitionBuilder loadingTransitionBuilder = + AnimatedSwitcher.defaultTransitionBuilder, + AnimatedSwitcherTransitionBuilder idleTransitionBuilder = + AnimatedSwitcher.defaultTransitionBuilder, + AnimatedSwitcherTransitionBuilder successTransitionBuilder = + AnimatedSwitcher.defaultTransitionBuilder, + AnimatedSwitcherTransitionBuilder errorTransitionBuilder = + AnimatedSwitcher.defaultTransitionBuilder, + Curve idleSwitchInCurve = Curves.linear, + Curve loadingSwitchInCurve = Curves.linear, + Curve successSwitchInCurve = Curves.linear, + Curve errorSwitchInCurve = Curves.linear, + Curve idleSwitchOutCurve = Curves.linear, + Curve loadingSwitchOutCurve = Curves.linear, + Curve successSwitchOutCurve = Curves.linear, + Curve errorSwitchOutCurve = Curves.linear, + Curve sizeCurve = Curves.linear, + Clip sizeClipBehavior = Clip.hardEdge, + Alignment sizeAlignment = Alignment.center, + bool animateSize = true, +}) { + final _buttonState = useState(buttonState); + Timer? timer; + + useEffect( + () { + if (_buttonState.value != buttonState) { + _buttonState.value = buttonState; + } + + return () { + timer?.cancel(); + }; + }, + [buttonState], + ); + + final ticker = useSingleTickerProvider(); + final isMounted = useIsMounted(); + final context = useContext(); + final theme = Theme.of(context); + final _loadingWidget = loadingWidget ?? + const SizedBox( + height: 16.0, + width: 16.0, + child: CircularProgressIndicator(), + ); + var _successWidget = successWidget ?? + Icon( + Icons.check, + color: theme.colorScheme.secondary, + ); + var _errorWidget = errorWidget ?? + Icon( + Icons.error, + color: theme.errorColor, + ); + + if (successPadding != null) { + _successWidget = Padding( + padding: successPadding, + child: successWidget, + ); + } + + if (errorPadding != null) { + _errorWidget = Padding( + padding: errorPadding, + child: errorWidget, + ); + } + + final switcher = AnimatedSwitcher( + // TODO: This duration is same as size's duration. That's okay right? + duration: duration, + reverseDuration: reverseDuration, + switchInCurve: buttonState.when( + idle: () => idleSwitchInCurve, + loading: () => loadingSwitchInCurve, + success: () => successSwitchInCurve, + error: () => errorSwitchInCurve, + ), + switchOutCurve: buttonState.when( + idle: () => idleSwitchOutCurve, + loading: () => loadingSwitchOutCurve, + success: () => successSwitchOutCurve, + error: () => errorSwitchOutCurve, + ), + transitionBuilder: buttonState.when( + idle: () => idleTransitionBuilder, + loading: () => loadingTransitionBuilder, + success: () => successTransitionBuilder, + error: () => errorTransitionBuilder, + ), + child: buttonState.when( + idle: () => KeyedSubtree( + key: const ValueKey('__idle__'), + child: child, + ), + loading: () => KeyedSubtree( + key: const ValueKey('__loading__'), + child: _loadingWidget, + ), + success: () => KeyedSubtree( + key: const ValueKey('__success__'), + child: _successWidget, + ), + error: () => KeyedSubtree( + key: const ValueKey('__error__'), + child: _errorWidget, + ), + ), + ); + + void setTimer(Duration duration) { + timer = Timer( + duration, + () { + timer?.cancel(); + + if (isMounted()) { + _buttonState.value = const ButtonState.idle(); + } + }, + ); + } + + return AsyncButtonResult( + child: animateSize + ? AnimatedSize( + vsync: ticker, + duration: duration, + reverseDuration: reverseDuration, + alignment: sizeAlignment, + clipBehavior: sizeClipBehavior, + curve: sizeCurve, + child: switcher, + ) + : switcher, + callback: disabled + ? null + : onPressed == null + ? null + : buttonState.maybeWhen( + idle: () => () { + final completer = Completer(); + // I might not want to set buttonState if we're being + // driven by buttonState... + _buttonState.value = const ButtonState.loading(); + + timer?.cancel(); + + onPressed.call().then((_) { + completer.complete(); + + if (isMounted()) { + if (showSuccess) { + _buttonState.value = const ButtonState.success(); + + setTimer(successDuration); + } else { + _buttonState.value = const ButtonState.idle(); + } + } + }).catchError((Object error, StackTrace stackTrace) { + completer.completeError(error, stackTrace); + + if (isMounted()) { + if (showError) { + _buttonState.value = const ButtonState.error(); + + setTimer(errorDuration); + } else { + _buttonState.value = const ButtonState.idle(); + } + } + }); + + return completer.future; + }, + orElse: () => null, + ), + buttonState: _buttonState.value, + ); +} diff --git a/packages/async_button_hook/lib/src/models/async_button_result.dart b/packages/async_button_hook/lib/src/models/async_button_result.dart new file mode 100644 index 0000000..5202c03 --- /dev/null +++ b/packages/async_button_hook/lib/src/models/async_button_result.dart @@ -0,0 +1,22 @@ +import 'package:async_button_core/async_button_core.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +/// The result of an asynchoous button +@immutable +class AsyncButtonResult { + /// The child of the button + final Widget child; + + /// Passed to the Button in place of the original onTap/onPressed variant + final AsyncCallback? callback; + + /// The state the button is currently in + final ButtonState buttonState; + + const AsyncButtonResult({ + required this.child, + required this.callback, + required this.buttonState, + }); +} diff --git a/packages/async_button_hook/pubspec.lock b/packages/async_button_hook/pubspec.lock index 51a022e..4ae4704 100644 --- a/packages/async_button_hook/pubspec.lock +++ b/packages/async_button_hook/pubspec.lock @@ -8,6 +8,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.8.1" + async_button_core: + dependency: "direct main" + description: + path: "../async_button_core" + relative: true + source: path + version: "0.0.1" boolean_selector: dependency: transitive description: @@ -74,6 +81,20 @@ packages: description: flutter source: sdk version: "0.0.0" + freezed_annotation: + dependency: transitive + description: + name: freezed_annotation + url: "https://pub.dartlang.org" + source: hosted + version: "0.14.3" + json_annotation: + dependency: transitive + description: + name: json_annotation + url: "https://pub.dartlang.org" + source: hosted + version: "4.1.0" lints: dependency: transitive description: diff --git a/packages/async_button_hook/pubspec.yaml b/packages/async_button_hook/pubspec.yaml index 546520c..89fa430 100644 --- a/packages/async_button_hook/pubspec.yaml +++ b/packages/async_button_hook/pubspec.yaml @@ -11,6 +11,7 @@ dependencies: flutter: sdk: flutter flutter_hooks: ^0.18.0 + async_button_core: ^0.0.1 dev_dependencies: flutter_lints: ^1.0.0 diff --git a/pubspec.lock b/pubspec.lock deleted file mode 100644 index 2d57c56..0000000 --- a/pubspec.lock +++ /dev/null @@ -1,469 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - _fe_analyzer_shared: - dependency: transitive - description: - name: _fe_analyzer_shared - url: "https://pub.dartlang.org" - source: hosted - version: "21.0.0" - analyzer: - dependency: transitive - description: - name: analyzer - url: "https://pub.dartlang.org" - source: hosted - version: "1.5.0" - args: - dependency: transitive - description: - name: args - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - async: - dependency: transitive - description: - name: async - url: "https://pub.dartlang.org" - source: hosted - version: "2.7.0" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - build: - dependency: transitive - description: - name: build - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.1" - build_config: - dependency: transitive - description: - name: build_config - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - build_daemon: - dependency: transitive - description: - name: build_daemon - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.0" - build_resolvers: - dependency: transitive - description: - name: build_resolvers - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.1" - build_runner: - dependency: "direct dev" - description: - name: build_runner - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.3" - build_runner_core: - dependency: transitive - description: - name: build_runner_core - url: "https://pub.dartlang.org" - source: hosted - version: "7.0.0" - built_collection: - dependency: transitive - description: - name: built_collection - url: "https://pub.dartlang.org" - source: hosted - version: "5.0.0" - built_value: - dependency: transitive - description: - name: built_value - url: "https://pub.dartlang.org" - source: hosted - version: "8.0.5" - characters: - dependency: transitive - description: - name: characters - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.1" - checked_yaml: - dependency: transitive - description: - name: checked_yaml - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.1" - cli_util: - dependency: transitive - description: - name: cli_util - url: "https://pub.dartlang.org" - source: hosted - version: "0.3.0" - clock: - dependency: transitive - description: - name: clock - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - code_builder: - dependency: transitive - description: - name: code_builder - url: "https://pub.dartlang.org" - source: hosted - version: "4.0.0" - collection: - dependency: transitive - description: - name: collection - url: "https://pub.dartlang.org" - source: hosted - version: "1.15.0" - convert: - dependency: transitive - description: - name: convert - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.0" - crypto: - dependency: transitive - description: - name: crypto - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.1" - dart_style: - dependency: transitive - description: - name: dart_style - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.1" - fake_async: - dependency: transitive - description: - name: fake_async - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - file: - dependency: transitive - description: - name: file - url: "https://pub.dartlang.org" - source: hosted - version: "6.1.0" - fixnum: - dependency: transitive - description: - name: fixnum - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.3" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - freezed: - dependency: "direct dev" - description: - name: freezed - url: "https://pub.dartlang.org" - source: hosted - version: "0.14.2" - freezed_annotation: - dependency: "direct main" - description: - name: freezed_annotation - url: "https://pub.dartlang.org" - source: hosted - version: "0.14.2" - frontend_server_client: - dependency: transitive - description: - name: frontend_server_client - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - glob: - dependency: transitive - description: - name: glob - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.1" - graphs: - dependency: transitive - description: - name: graphs - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - http_multi_server: - dependency: transitive - description: - name: http_multi_server - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.1" - http_parser: - dependency: transitive - description: - name: http_parser - url: "https://pub.dartlang.org" - source: hosted - version: "4.0.0" - io: - dependency: transitive - description: - name: io - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - js: - dependency: transitive - description: - name: js - url: "https://pub.dartlang.org" - source: hosted - version: "0.6.3" - json_annotation: - dependency: transitive - description: - name: json_annotation - url: "https://pub.dartlang.org" - source: hosted - version: "4.0.1" - lints: - dependency: transitive - description: - name: lints - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" - logging: - dependency: transitive - description: - name: logging - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" - matcher: - dependency: transitive - description: - name: matcher - url: "https://pub.dartlang.org" - source: hosted - version: "0.12.10" - meta: - dependency: transitive - description: - name: meta - url: "https://pub.dartlang.org" - source: hosted - version: "1.7.0" - mime: - dependency: transitive - description: - name: mime - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - package_config: - dependency: transitive - description: - name: package_config - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - path: - dependency: transitive - description: - name: path - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.0" - pedantic: - dependency: transitive - description: - name: pedantic - url: "https://pub.dartlang.org" - source: hosted - version: "1.11.0" - pool: - dependency: transitive - description: - name: pool - url: "https://pub.dartlang.org" - source: hosted - version: "1.5.0" - pub_semver: - dependency: transitive - description: - name: pub_semver - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - pubspec_parse: - dependency: transitive - description: - name: pubspec_parse - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - shelf: - dependency: transitive - description: - name: shelf - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.1" - shelf_web_socket: - dependency: transitive - description: - name: shelf_web_socket - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.99" - source_gen: - dependency: transitive - description: - name: source_gen - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - source_span: - dependency: transitive - description: - name: source_span - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.1" - stack_trace: - dependency: transitive - description: - name: stack_trace - url: "https://pub.dartlang.org" - source: hosted - version: "1.10.0" - stream_channel: - dependency: transitive - description: - name: stream_channel - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - stream_transform: - dependency: transitive - description: - name: stream_transform - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - string_scanner: - dependency: transitive - description: - name: string_scanner - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - term_glyph: - dependency: transitive - description: - name: term_glyph - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - test_api: - dependency: transitive - description: - name: test_api - url: "https://pub.dartlang.org" - source: hosted - version: "0.4.2" - timing: - dependency: transitive - description: - name: timing - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - typed_data: - dependency: transitive - description: - name: typed_data - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.0" - vector_math: - dependency: transitive - description: - name: vector_math - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - watcher: - dependency: transitive - description: - name: watcher - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - web_socket_channel: - dependency: transitive - description: - name: web_socket_channel - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - yaml: - dependency: transitive - description: - name: yaml - url: "https://pub.dartlang.org" - source: hosted - version: "3.1.0" -sdks: - dart: ">=2.12.0 <3.0.0" - flutter: ">=1.17.0" diff --git a/pubspec.yaml b/pubspec.yaml deleted file mode 100644 index 440e40e..0000000 --- a/pubspec.yaml +++ /dev/null @@ -1,22 +0,0 @@ -name: async_button_builder -description: A builder to wrap around buttons that handles loading, disabled, error and succes states -version: 2.1.3+2 -homepage: https://github.com/Nolence/async_button_builder - -environment: - sdk: '>=2.12.0 <3.0.0' - flutter: ">=1.17.0" - -dependencies: - flutter: - sdk: flutter - freezed_annotation: ^0.14.2 - -dev_dependencies: - flutter_test: - sdk: flutter - build_runner: ^2.0.3 - freezed: ^0.14.2 - flutter_lints: - -flutter: \ No newline at end of file diff --git a/test/async_button_builder_test.dart b/test/async_button_builder_test.dart deleted file mode 100644 index 61a3968..0000000 --- a/test/async_button_builder_test.dart +++ /dev/null @@ -1,151 +0,0 @@ -import 'package:async_button_builder/async_button_builder.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('displays child text', (WidgetTester tester) async { - final textButton = MaterialApp( - home: AsyncButtonBuilder( - onPressed: () async { - await Future.delayed(const Duration(seconds: 1)); - }, - builder: (context, child, callback, state) { - return TextButton(onPressed: callback, child: child); - }, - child: const Text('click me'), - ), - ); - - await tester.pumpWidget(textButton); - - expect(find.text('click me'), findsOneWidget); - }); - - testWidgets('shows loading widget', (WidgetTester tester) async { - const duration = Duration(milliseconds: 250); - final textButton = MaterialApp( - home: AsyncButtonBuilder( - duration: duration, - loadingWidget: const Text('loading'), - onPressed: () async { - await Future.delayed(const Duration(seconds: 1)); - }, - builder: (context, child, callback, state) { - return TextButton(onPressed: callback, child: child); - }, - child: const Text('click me'), - ), - ); - - await tester.pumpWidget(textButton); - - await tester.tap(find.byType(TextButton)); - - // 1/10 of a second later, loading should be showing - await tester.pump(const Duration(milliseconds: 100)); - - expect(find.text('loading'), findsOneWidget); - - // Let the widget continue to settle otherwise I won't dispose timers - // correctly. TODO: Explain why .900 is the magic number - await tester.pumpAndSettle(const Duration(milliseconds: 900)); - }); - - testWidgets('shows error widget', (WidgetTester tester) async { - const duration = Duration(milliseconds: 250); - final textButton = MaterialApp( - home: AsyncButtonBuilder( - duration: duration, - errorWidget: const Text('error'), - onPressed: () async { - throw ArgumentError(); - }, - builder: (context, child, callback, state) { - return TextButton(onPressed: callback, child: child); - }, - child: const Text('click me'), - ), - ); - - await tester.pumpWidget(textButton); - final button = - find.byType(TextButton).evaluate().first.widget as TextButton; - - expect( - () => button.onPressed!.call(), - throwsA(isInstanceOf()), - ); - - await tester.pump(const Duration(milliseconds: 200)); - - expect(find.text('error'), findsOneWidget); - }); - - testWidgets('Returns to child widget', (WidgetTester tester) async { - const duration = Duration(milliseconds: 250); - final textButton = MaterialApp( - home: AsyncButtonBuilder( - duration: duration, - loadingWidget: const Text('loading'), - onPressed: () async { - await Future.delayed(const Duration(seconds: 1)); - }, - builder: (context, child, callback, state) { - return TextButton(onPressed: callback, child: child); - }, - child: const Text('click me'), - ), - ); - - await tester.pumpWidget(textButton); - - await tester.tap(find.byType(TextButton)); - - await tester.pump(const Duration(milliseconds: 1000)); - - expect(find.text('loading'), findsNothing); - - expect(find.text('click me'), findsOneWidget); - }); - - // TODO: Make it work on dropdown buttons - // AsyncButtonBuilder( - // child: Icon(Icons.arrow_upward), - // onPressed: (newValue) async { - // final oldValue = dropdownValue; - - // setState(() { - // dropdownValue = newValue; - // }); - - // await Future.delayed(Duration(seconds: 1)); - - // try { - // if (Random().nextBool()) { - // throw 'yikes'; - // } - // } catch (error) { - // setState(() { - // dropdownValue = oldValue; - // }); - // } - // }, - // builder: (context, child, callback, _) { - // return DropdownButton( - // // icon: SizedBox( - // // height: 16.0, - // // width: 16.0, - // // child: CircularProgressIndicator(), - // // ), - // onChanged: callback, - // items: ['one', 'two', 'three'] - // .map((value) => DropdownMenuItem( - // child: Text(value), - // value: value, - // )) - // .toList(), - // value: dropdownValue, - // ); - // }, - // ), -} From 13a5cd1ce3723fe8aaf60bd511fb8a7ced9ca075 Mon Sep 17 00:00:00 2001 From: Nolence Date: Thu, 19 Aug 2021 08:43:48 -0600 Subject: [PATCH 049/176] Fix hook version not going into loading state correctly --- .idea/modules.xml | 1 + packages/async_button_hook/example/.gitignore | 46 ++ packages/async_button_hook/example/.metadata | 10 + packages/async_button_hook/example/README.md | 16 + .../example/analysis_options.yaml | 29 ++ .../example/android/.gitignore | 13 + .../example/android/app/build.gradle | 68 +++ .../android/app/src/debug/AndroidManifest.xml | 7 + .../android/app/src/main/AndroidManifest.xml | 32 ++ .../com/example/example/MainActivity.kt | 6 + .../res/drawable-v21/launch_background.xml | 12 + .../main/res/drawable/launch_background.xml | 12 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 544 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 442 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 721 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 1031 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 1443 bytes .../app/src/main/res/values-night/styles.xml | 18 + .../app/src/main/res/values/styles.xml | 18 + .../app/src/profile/AndroidManifest.xml | 7 + .../example/android/build.gradle | 29 ++ .../example/android/gradle.properties | 3 + .../gradle/wrapper/gradle-wrapper.properties | 6 + .../example/android/settings.gradle | 11 + .../async_button_hook/example/ios/.gitignore | 33 ++ .../ios/Flutter/AppFrameworkInfo.plist | 26 + .../example/ios/Flutter/Debug.xcconfig | 1 + .../example/ios/Flutter/Release.xcconfig | 1 + .../ios/Runner.xcodeproj/project.pbxproj | 471 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../xcshareddata/xcschemes/Runner.xcscheme | 91 ++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../example/ios/Runner/AppDelegate.swift | 13 + .../AppIcon.appiconset/Contents.json | 122 +++++ .../Icon-App-1024x1024@1x.png | Bin 0 -> 10932 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 0 -> 564 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 0 -> 1283 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 0 -> 1588 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 0 -> 1025 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 0 -> 1716 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 0 -> 1920 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 0 -> 1283 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 0 -> 1895 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 0 -> 2665 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 0 -> 2665 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 0 -> 3831 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 0 -> 1888 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 0 -> 3294 bytes .../Icon-App-83.5x83.5@2x.png | Bin 0 -> 3612 bytes .../LaunchImage.imageset/Contents.json | 23 + .../LaunchImage.imageset/LaunchImage.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@2x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@3x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/README.md | 5 + .../Runner/Base.lproj/LaunchScreen.storyboard | 37 ++ .../ios/Runner/Base.lproj/Main.storyboard | 26 + .../example/ios/Runner/Info.plist | 45 ++ .../ios/Runner/Runner-Bridging-Header.h | 1 + .../async_button_hook/example/lib/main.dart | 159 ++++++ .../async_button_hook/example/pubspec.lock | 203 ++++++++ .../async_button_hook/example/pubspec.yaml | 92 ++++ .../example/test/widget_test.dart | 30 ++ .../async_button_hook/example/web/favicon.png | Bin 0 -> 917 bytes .../example/web/icons/Icon-192.png | Bin 0 -> 5292 bytes .../example/web/icons/Icon-512.png | Bin 0 -> 8252 bytes .../example/web/icons/Icon-maskable-192.png | Bin 0 -> 5594 bytes .../example/web/icons/Icon-maskable-512.png | Bin 0 -> 20998 bytes .../async_button_hook/example/web/index.html | 101 ++++ .../example/web/manifest.json | 35 ++ .../lib/async_button_hook.dart | 3 +- .../lib/src/async_button_hook.dart | 28 +- 75 files changed, 1926 insertions(+), 10 deletions(-) create mode 100644 packages/async_button_hook/example/.gitignore create mode 100644 packages/async_button_hook/example/.metadata create mode 100644 packages/async_button_hook/example/README.md create mode 100644 packages/async_button_hook/example/analysis_options.yaml create mode 100644 packages/async_button_hook/example/android/.gitignore create mode 100644 packages/async_button_hook/example/android/app/build.gradle create mode 100644 packages/async_button_hook/example/android/app/src/debug/AndroidManifest.xml create mode 100644 packages/async_button_hook/example/android/app/src/main/AndroidManifest.xml create mode 100644 packages/async_button_hook/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt create mode 100644 packages/async_button_hook/example/android/app/src/main/res/drawable-v21/launch_background.xml create mode 100644 packages/async_button_hook/example/android/app/src/main/res/drawable/launch_background.xml create mode 100644 packages/async_button_hook/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 packages/async_button_hook/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 packages/async_button_hook/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 packages/async_button_hook/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 packages/async_button_hook/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 packages/async_button_hook/example/android/app/src/main/res/values-night/styles.xml create mode 100644 packages/async_button_hook/example/android/app/src/main/res/values/styles.xml create mode 100644 packages/async_button_hook/example/android/app/src/profile/AndroidManifest.xml create mode 100644 packages/async_button_hook/example/android/build.gradle create mode 100644 packages/async_button_hook/example/android/gradle.properties create mode 100644 packages/async_button_hook/example/android/gradle/wrapper/gradle-wrapper.properties create mode 100644 packages/async_button_hook/example/android/settings.gradle create mode 100644 packages/async_button_hook/example/ios/.gitignore create mode 100644 packages/async_button_hook/example/ios/Flutter/AppFrameworkInfo.plist create mode 100644 packages/async_button_hook/example/ios/Flutter/Debug.xcconfig create mode 100644 packages/async_button_hook/example/ios/Flutter/Release.xcconfig create mode 100644 packages/async_button_hook/example/ios/Runner.xcodeproj/project.pbxproj create mode 100644 packages/async_button_hook/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 packages/async_button_hook/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 packages/async_button_hook/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 packages/async_button_hook/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme create mode 100644 packages/async_button_hook/example/ios/Runner.xcworkspace/contents.xcworkspacedata create mode 100644 packages/async_button_hook/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 packages/async_button_hook/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 packages/async_button_hook/example/ios/Runner/AppDelegate.swift create mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png create mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png create mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png create mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png create mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png create mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png create mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png create mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png create mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png create mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png create mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png create mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png create mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png create mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png create mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png create mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json create mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png create mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png create mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png create mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md create mode 100644 packages/async_button_hook/example/ios/Runner/Base.lproj/LaunchScreen.storyboard create mode 100644 packages/async_button_hook/example/ios/Runner/Base.lproj/Main.storyboard create mode 100644 packages/async_button_hook/example/ios/Runner/Info.plist create mode 100644 packages/async_button_hook/example/ios/Runner/Runner-Bridging-Header.h create mode 100644 packages/async_button_hook/example/lib/main.dart create mode 100644 packages/async_button_hook/example/pubspec.lock create mode 100644 packages/async_button_hook/example/pubspec.yaml create mode 100644 packages/async_button_hook/example/test/widget_test.dart create mode 100644 packages/async_button_hook/example/web/favicon.png create mode 100644 packages/async_button_hook/example/web/icons/Icon-192.png create mode 100644 packages/async_button_hook/example/web/icons/Icon-512.png create mode 100644 packages/async_button_hook/example/web/icons/Icon-maskable-192.png create mode 100644 packages/async_button_hook/example/web/icons/Icon-maskable-512.png create mode 100644 packages/async_button_hook/example/web/index.html create mode 100644 packages/async_button_hook/example/web/manifest.json diff --git a/.idea/modules.xml b/.idea/modules.xml index e7beaf8..fb3a7d5 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -5,6 +5,7 @@ + diff --git a/packages/async_button_hook/example/.gitignore b/packages/async_button_hook/example/.gitignore new file mode 100644 index 0000000..0fa6b67 --- /dev/null +++ b/packages/async_button_hook/example/.gitignore @@ -0,0 +1,46 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/packages/async_button_hook/example/.metadata b/packages/async_button_hook/example/.metadata new file mode 100644 index 0000000..75f919a --- /dev/null +++ b/packages/async_button_hook/example/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 225a43d941ddd1753765fec3682011e9ddffb11d + channel: dev + +project_type: app diff --git a/packages/async_button_hook/example/README.md b/packages/async_button_hook/example/README.md new file mode 100644 index 0000000..a135626 --- /dev/null +++ b/packages/async_button_hook/example/README.md @@ -0,0 +1,16 @@ +# example + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/packages/async_button_hook/example/analysis_options.yaml b/packages/async_button_hook/example/analysis_options.yaml new file mode 100644 index 0000000..61b6c4d --- /dev/null +++ b/packages/async_button_hook/example/analysis_options.yaml @@ -0,0 +1,29 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at + # https://dart-lang.github.io/linter/lints/index.html. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/packages/async_button_hook/example/android/.gitignore b/packages/async_button_hook/example/android/.gitignore new file mode 100644 index 0000000..6f56801 --- /dev/null +++ b/packages/async_button_hook/example/android/.gitignore @@ -0,0 +1,13 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties +**/*.keystore +**/*.jks diff --git a/packages/async_button_hook/example/android/app/build.gradle b/packages/async_button_hook/example/android/app/build.gradle new file mode 100644 index 0000000..56bfa9b --- /dev/null +++ b/packages/async_button_hook/example/android/app/build.gradle @@ -0,0 +1,68 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 30 + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.example" + minSdkVersion 16 + targetSdkVersion 30 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/packages/async_button_hook/example/android/app/src/debug/AndroidManifest.xml b/packages/async_button_hook/example/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..c208884 --- /dev/null +++ b/packages/async_button_hook/example/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/packages/async_button_hook/example/android/app/src/main/AndroidManifest.xml b/packages/async_button_hook/example/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..6f325b4 --- /dev/null +++ b/packages/async_button_hook/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + diff --git a/packages/async_button_hook/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt b/packages/async_button_hook/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt new file mode 100644 index 0000000..e793a00 --- /dev/null +++ b/packages/async_button_hook/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.example + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} diff --git a/packages/async_button_hook/example/android/app/src/main/res/drawable-v21/launch_background.xml b/packages/async_button_hook/example/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 0000000..f74085f --- /dev/null +++ b/packages/async_button_hook/example/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/packages/async_button_hook/example/android/app/src/main/res/drawable/launch_background.xml b/packages/async_button_hook/example/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000..304732f --- /dev/null +++ b/packages/async_button_hook/example/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/packages/async_button_hook/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/packages/async_button_hook/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..db77bb4b7b0906d62b1847e87f15cdcacf6a4f29 GIT binary patch literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ literal 0 HcmV?d00001 diff --git a/packages/async_button_hook/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/packages/async_button_hook/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..17987b79bb8a35cc66c3c1fd44f5a5526c1b78be GIT binary patch literal 442 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xx&nMcT!A!W`0S9QKQy;}1Cl^CgaH=;G9cpY;r$Q>i*pfB zP2drbID<_#qf;rPZx^FqH)F_D#*k@@q03KywUtLX8Ua?`H+NMzkczFPK3lFz@i_kW%1NOn0|D2I9n9wzH8m|-tHjsw|9>@K=iMBhxvkv6m8Y-l zytQ?X=U+MF$@3 zt`~i=@j|6y)RWMK--}M|=T`o&^Ni>IoWKHEbBXz7?A@mgWoL>!*SXo`SZH-*HSdS+ yn*9;$7;m`l>wYBC5bq;=U}IMqLzqbYCidGC!)_gkIk_C@Uy!y&wkt5C($~2D>~)O*cj@FGjOCM)M>_ixfudOh)?xMu#Fs z#}Y=@YDTwOM)x{K_j*Q;dPdJ?Mz0n|pLRx{4n|)f>SXlmV)XB04CrSJn#dS5nK2lM zrZ9#~WelCp7&e13Y$jvaEXHskn$2V!!DN-nWS__6T*l;H&Fopn?A6HZ-6WRLFP=R` zqG+CE#d4|IbyAI+rJJ`&x9*T`+a=p|0O(+s{UBcyZdkhj=yS1>AirP+0R;mf2uMgM zC}@~JfByORAh4SyRgi&!(cja>F(l*O+nd+@4m$|6K6KDn_&uvCpV23&>G9HJp{xgg zoq1^2_p9@|WEo z*X_Uko@K)qYYv~>43eQGMdbiGbo>E~Q& zrYBH{QP^@Sti!`2)uG{irBBq@y*$B zi#&(U-*=fp74j)RyIw49+0MRPMRU)+a2r*PJ$L5roHt2$UjExCTZSbq%V!HeS7J$N zdG@vOZB4v_lF7Plrx+hxo7(fCV&}fHq)$ literal 0 HcmV?d00001 diff --git a/packages/async_button_hook/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/packages/async_button_hook/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..d5f1c8d34e7a88e3f88bea192c3a370d44689c3c GIT binary patch literal 1031 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof literal 0 HcmV?d00001 diff --git a/packages/async_button_hook/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/packages/async_button_hook/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..4d6372eebdb28e45604e46eeda8dd24651419bc0 GIT binary patch literal 1443 zcmb`G{WsKk6vsdJTdFg%tJav9_E4vzrOaqkWF|A724Nly!y+?N9`YV6wZ}5(X(D_N(?!*n3`|_r0Hc?=PQw&*vnU?QTFY zB_MsH|!j$PP;I}?dppoE_gA(4uc!jV&0!l7_;&p2^pxNo>PEcNJv za5_RT$o2Mf!<+r?&EbHH6nMoTsDOa;mN(wv8RNsHpG)`^ymG-S5By8=l9iVXzN_eG%Xg2@Xeq76tTZ*dGh~Lo9vl;Zfs+W#BydUw zCkZ$o1LqWQO$FC9aKlLl*7x9^0q%0}$OMlp@Kk_jHXOjofdePND+j!A{q!8~Jn+s3 z?~~w@4?egS02}8NuulUA=L~QQfm;MzCGd)XhiftT;+zFO&JVyp2mBww?;QByS_1w! zrQlx%{^cMj0|Bo1FjwY@Q8?Hx0cIPF*@-ZRFpPc#bBw{5@tD(5%sClzIfl8WU~V#u zm5Q;_F!wa$BSpqhN>W@2De?TKWR*!ujY;Yylk_X5#~V!L*Gw~;$%4Q8~Mad z@`-kG?yb$a9cHIApZDVZ^U6Xkp<*4rU82O7%}0jjHlK{id@?-wpN*fCHXyXh(bLt* zPc}H-x0e4E&nQ>y%B-(EL=9}RyC%MyX=upHuFhAk&MLbsF0LP-q`XnH78@fT+pKPW zu72MW`|?8ht^tz$iC}ZwLp4tB;Q49K!QCF3@!iB1qOI=?w z7In!}F~ij(18UYUjnbmC!qKhPo%24?8U1x{7o(+?^Zu0Hx81|FuS?bJ0jgBhEMzf< zCgUq7r2OCB(`XkKcN-TL>u5y#dD6D!)5W?`O5)V^>jb)P)GBdy%t$uUMpf$SNV31$ zb||OojAbvMP?T@$h_ZiFLFVHDmbyMhJF|-_)HX3%m=CDI+ID$0^C>kzxprBW)hw(v zr!Gmda);ICoQyhV_oP5+C%?jcG8v+D@9f?Dk*!BxY}dazmrT@64UrP3hlslANK)bq z$67n83eh}OeW&SV@HG95P|bjfqJ7gw$e+`Hxo!4cx`jdK1bJ>YDSpGKLPZ^1cv$ek zIB?0S<#tX?SJCLWdMd{-ME?$hc7A$zBOdIJ)4!KcAwb=VMov)nK;9z>x~rfT1>dS+ zZ6#`2v@`jgbqq)P22H)Tx2CpmM^o1$B+xT6`(v%5xJ(?j#>Q$+rx_R|7TzDZe{J6q zG1*EcU%tE?!kO%^M;3aM6JN*LAKUVb^xz8-Pxo#jR5(-KBeLJvA@-gxNHx0M-ZJLl z;#JwQoh~9V?`UVo#}{6ka@II>++D@%KqGpMdlQ}?9E*wFcf5(#XQnP$Dk5~%iX^>f z%$y;?M0BLp{O3a(-4A?ewryHrrD%cx#Q^%KY1H zNre$ve+vceSLZcNY4U(RBX&)oZn*Py()h)XkE?PL$!bNb{N5FVI2Y%LKEm%yvpyTP z(1P?z~7YxD~Rf<(a@_y` literal 0 HcmV?d00001 diff --git a/packages/async_button_hook/example/android/app/src/main/res/values-night/styles.xml b/packages/async_button_hook/example/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 0000000..449a9f9 --- /dev/null +++ b/packages/async_button_hook/example/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/packages/async_button_hook/example/android/app/src/main/res/values/styles.xml b/packages/async_button_hook/example/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..d74aa35 --- /dev/null +++ b/packages/async_button_hook/example/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/packages/async_button_hook/example/android/app/src/profile/AndroidManifest.xml b/packages/async_button_hook/example/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..c208884 --- /dev/null +++ b/packages/async_button_hook/example/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/packages/async_button_hook/example/android/build.gradle b/packages/async_button_hook/example/android/build.gradle new file mode 100644 index 0000000..ed45c65 --- /dev/null +++ b/packages/async_button_hook/example/android/build.gradle @@ -0,0 +1,29 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:4.1.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/packages/async_button_hook/example/android/gradle.properties b/packages/async_button_hook/example/android/gradle.properties new file mode 100644 index 0000000..94adc3a --- /dev/null +++ b/packages/async_button_hook/example/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true diff --git a/packages/async_button_hook/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/async_button_hook/example/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..bc6a58a --- /dev/null +++ b/packages/async_button_hook/example/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip diff --git a/packages/async_button_hook/example/android/settings.gradle b/packages/async_button_hook/example/android/settings.gradle new file mode 100644 index 0000000..44e62bc --- /dev/null +++ b/packages/async_button_hook/example/android/settings.gradle @@ -0,0 +1,11 @@ +include ':app' + +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") +def properties = new Properties() + +assert localPropertiesFile.exists() +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + +def flutterSdkPath = properties.getProperty("flutter.sdk") +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/packages/async_button_hook/example/ios/.gitignore b/packages/async_button_hook/example/ios/.gitignore new file mode 100644 index 0000000..151026b --- /dev/null +++ b/packages/async_button_hook/example/ios/.gitignore @@ -0,0 +1,33 @@ +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/ephemeral/ +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/packages/async_button_hook/example/ios/Flutter/AppFrameworkInfo.plist b/packages/async_button_hook/example/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 0000000..8d4492f --- /dev/null +++ b/packages/async_button_hook/example/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 9.0 + + diff --git a/packages/async_button_hook/example/ios/Flutter/Debug.xcconfig b/packages/async_button_hook/example/ios/Flutter/Debug.xcconfig new file mode 100644 index 0000000..592ceee --- /dev/null +++ b/packages/async_button_hook/example/ios/Flutter/Debug.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/packages/async_button_hook/example/ios/Flutter/Release.xcconfig b/packages/async_button_hook/example/ios/Flutter/Release.xcconfig new file mode 100644 index 0000000..592ceee --- /dev/null +++ b/packages/async_button_hook/example/ios/Flutter/Release.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/packages/async_button_hook/example/ios/Runner.xcodeproj/project.pbxproj b/packages/async_button_hook/example/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..c6759a6 --- /dev/null +++ b/packages/async_button_hook/example/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,471 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.example.example; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.example.example; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.example.example; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/packages/async_button_hook/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/async_button_hook/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/packages/async_button_hook/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/packages/async_button_hook/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/async_button_hook/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/packages/async_button_hook/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/async_button_hook/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/async_button_hook/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/packages/async_button_hook/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/packages/async_button_hook/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/async_button_hook/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..a28140c --- /dev/null +++ b/packages/async_button_hook/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/async_button_hook/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/async_button_hook/example/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /dev/null +++ b/packages/async_button_hook/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/packages/async_button_hook/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/async_button_hook/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/packages/async_button_hook/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/async_button_hook/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/async_button_hook/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/packages/async_button_hook/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/packages/async_button_hook/example/ios/Runner/AppDelegate.swift b/packages/async_button_hook/example/ios/Runner/AppDelegate.swift new file mode 100644 index 0000000..70693e4 --- /dev/null +++ b/packages/async_button_hook/example/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import UIKit +import Flutter + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d36b1fa --- /dev/null +++ b/packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..dc9ada4725e9b0ddb1deab583e5b5102493aa332 GIT binary patch literal 10932 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 literal 0 HcmV?d00001 diff --git a/packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..f091b6b0bca859a3f474b03065bef75ba58a9e4c GIT binary patch literal 1588 zcmV-42Fv-0P)C1SqPt}wig>|5Crh^=oyX$BK<}M8eLU3e2hGT;=G|!_SP)7zNI6fqUMB=)y zRAZ>eDe#*r`yDAVgB_R*LB*MAc)8(b{g{9McCXW!lq7r(btRoB9!8B-#AI6JMb~YFBEvdsV)`mEQO^&#eRKx@b&x- z5lZm*!WfD8oCLzfHGz#u7sT0^VLMI1MqGxF^v+`4YYnVYgk*=kU?HsSz{v({E3lb9 z>+xILjBN)t6`=g~IBOelGQ(O990@BfXf(DRI5I$qN$0Gkz-FSc$3a+2fX$AedL4u{ z4V+5Ong(9LiGcIKW?_352sR;LtDPmPJXI{YtT=O8=76o9;*n%_m|xo!i>7$IrZ-{l z-x3`7M}qzHsPV@$v#>H-TpjDh2UE$9g6sysUREDy_R(a)>=eHw-WAyfIN z*qb!_hW>G)Tu8nSw9yn#3wFMiLcfc4pY0ek1}8(NqkBR@t4{~oC>ryc-h_ByH(Cg5 z>ao-}771+xE3um9lWAY1FeQFxowa1(!J(;Jg*wrg!=6FdRX+t_<%z&d&?|Bn){>zm zZQj(aA_HeBY&OC^jj*)N`8fa^ePOU72VpInJoI1?`ty#lvlNzs(&MZX+R%2xS~5Kh zX*|AU4QE#~SgPzOXe9>tRj>hjU@c1k5Y_mW*Jp3fI;)1&g3j|zDgC+}2Q_v%YfDax z!?umcN^n}KYQ|a$Lr+51Nf9dkkYFSjZZjkma$0KOj+;aQ&721~t7QUKx61J3(P4P1 zstI~7-wOACnWP4=8oGOwz%vNDqD8w&Q`qcNGGrbbf&0s9L0De{4{mRS?o0MU+nR_! zrvshUau0G^DeMhM_v{5BuLjb#Hh@r23lDAk8oF(C+P0rsBpv85EP>4CVMx#04MOfG z;P%vktHcXwTj~+IE(~px)3*MY77e}p#|c>TD?sMatC0Tu4iKKJ0(X8jxQY*gYtxsC z(zYC$g|@+I+kY;dg_dE>scBf&bP1Nc@Hz<3R)V`=AGkc;8CXqdi=B4l2k|g;2%#m& z*jfX^%b!A8#bI!j9-0Fi0bOXl(-c^AB9|nQaE`*)Hw+o&jS9@7&Gov#HbD~#d{twV zXd^Tr^mWLfFh$@Dr$e;PBEz4(-2q1FF0}c;~B5sA}+Q>TOoP+t>wf)V9Iy=5ruQa;z)y zI9C9*oUga6=hxw6QasLPnee@3^Rr*M{CdaL5=R41nLs(AHk_=Y+A9$2&H(B7!_pURs&8aNw7?`&Z&xY_Ye z)~D5Bog^td-^QbUtkTirdyK^mTHAOuptDflut!#^lnKqU md>ggs(5nOWAqO?umG&QVYK#ibz}*4>0000U6E9hRK9^#O7(mu>ETqrXGsduA8$)?`v2seloOCza43C{NQ$$gAOH**MCn0Q?+L7dl7qnbRdqZ8LSVp1ItDxhxD?t@5_yHg6A8yI zC*%Wgg22K|8E#!~cTNYR~@Y9KepMPrrB8cABapAFa=`H+UGhkXUZV1GnwR1*lPyZ;*K(i~2gp|@bzp8}og7e*#% zEnr|^CWdVV!-4*Y_7rFvlww2Ze+>j*!Z!pQ?2l->4q#nqRu9`ELo6RMS5=br47g_X zRw}P9a7RRYQ%2Vsd0Me{_(EggTnuN6j=-?uFS6j^u69elMypu?t>op*wBx<=Wx8?( ztpe^(fwM6jJX7M-l*k3kEpWOl_Vk3@(_w4oc}4YF4|Rt=2V^XU?#Yz`8(e?aZ@#li0n*=g^qOcVpd-Wbok=@b#Yw zqn8u9a)z>l(1kEaPYZ6hwubN6i<8QHgsu0oE) ziJ(p;Wxm>sf!K+cw>R-(^Y2_bahB+&KI9y^);#0qt}t-$C|Bo71lHi{_+lg#f%RFy z0um=e3$K3i6K{U_4K!EX?F&rExl^W|G8Z8;`5z-k}OGNZ0#WVb$WCpQu-_YsiqKP?BB# vzVHS-CTUF4Ozn5G+mq_~Qqto~ahA+K`|lyv3(-e}00000NkvXXu0mjfd`9t{ literal 0 HcmV?d00001 diff --git a/packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..d0ef06e7edb86cdfe0d15b4b0d98334a86163658 GIT binary patch literal 1716 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 literal 0 HcmV?d00001 diff --git a/packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c8f9ed8f5cee1c98386d13b17e89f719e83555b2 GIT binary patch literal 1895 zcmV-t2blPYP)FQtfgmafE#=YDCq`qUBt#QpG%*H6QHY765~R=q zZ6iudfM}q!Pz#~9JgOi8QJ|DSu?1-*(kSi1K4#~5?#|rh?sS)(-JQqX*}ciXJ56_H zdw=^s_srbAdqxlvGyrgGet#6T7_|j;95sL%MtM;q86vOxKM$f#puR)Bjv9Zvz9-di zXOTSsZkM83)E9PYBXC<$6(|>lNLVBb&&6y{NByFCp%6+^ALR@NCTse_wqvNmSWI-m z!$%KlHFH2omF!>#%1l3LTZg(s7eof$7*xB)ZQ0h?ejh?Ta9fDv59+u#MokW+1t8Zb zgHv%K(u9G^Lv`lh#f3<6!JVTL3(dCpxHbnbA;kKqQyd1~^Xe0VIaYBSWm6nsr;dFj z4;G-RyL?cYgsN1{L4ZFFNa;8)Rv0fM0C(~Tkit94 zz#~A)59?QjD&pAPSEQ)p8gP|DS{ng)j=2ux)_EzzJ773GmQ_Cic%3JJhC0t2cx>|v zJcVusIB!%F90{+}8hG3QU4KNeKmK%T>mN57NnCZ^56=0?&3@!j>a>B43pi{!u z7JyDj7`6d)qVp^R=%j>UIY6f+3`+qzIc!Y_=+uN^3BYV|o+$vGo-j-Wm<10%A=(Yk^beI{t%ld@yhKjq0iNjqN4XMGgQtbKubPM$JWBz}YA65k%dm*awtC^+f;a-x4+ddbH^7iDWGg&N0n#MW{kA|=8iMUiFYvMoDY@sPC#t$55gn6ykUTPAr`a@!(;np824>2xJthS z*ZdmT`g5-`BuJs`0LVhz+D9NNa3<=6m;cQLaF?tCv8)zcRSh66*Z|vXhG@$I%U~2l z?`Q zykI#*+rQ=z6Jm=Bui-SfpDYLA=|vzGE(dYm=OC8XM&MDo7ux4UF1~0J1+i%aCUpRe zt3L_uNyQ*cE(38Uy03H%I*)*Bh=Lb^Xj3?I^Hnbeq72(EOK^Y93CNp*uAA{5Lc=ky zx=~RKa4{iTm{_>_vSCm?$Ej=i6@=m%@VvAITnigVg{&@!7CDgs908761meDK5azA} z4?=NOH|PdvabgJ&fW2{Mo$Q0CcD8Qc84%{JPYt5EiG{MdLIAeX%T=D7NIP4%Hw}p9 zg)==!2Lbp#j{u_}hMiao9=!VSyx0gHbeCS`;q&vzeq|fs`y&^X-lso(Ls@-706qmA z7u*T5PMo_w3{se1t2`zWeO^hOvTsohG_;>J0wVqVe+n)AbQCx)yh9;w+J6?NF5Lmo zecS@ieAKL8%bVd@+-KT{yI|S}O>pYckUFs;ry9Ow$CD@ztz5K-*D$^{i(_1llhSh^ zEkL$}tsQt5>QA^;QgjgIfBDmcOgi5YDyu?t6vSnbp=1+@6D& z5MJ}B8q;bRlVoxasyhcUF1+)o`&3r0colr}QJ3hcSdLu;9;td>kf@Tcn<@9sIx&=m z;AD;SCh95=&p;$r{Xz3iWCO^MX83AGJ(yH&eTXgv|0=34#-&WAmw{)U7OU9!Wz^!7 zZ%jZFi@JR;>Mhi7S>V7wQ176|FdW2m?&`qa(ScO^CFPR80HucLHOTy%5s*HR0^8)i h0WYBP*#0Ks^FNSabJA*5${_#%002ovPDHLkV1oKhTl@e3 literal 0 HcmV?d00001 diff --git a/packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..a6d6b8609df07bf62e5100a53a01510388bd2b22 GIT binary patch literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ literal 0 HcmV?d00001 diff --git a/packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a6d6b8609df07bf62e5100a53a01510388bd2b22 GIT binary patch literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ literal 0 HcmV?d00001 diff --git a/packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..75b2d164a5a98e212cca15ea7bf2ab5de5108680 GIT binary patch literal 3831 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 literal 0 HcmV?d00001 diff --git a/packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..c4df70d39da7941ef3f6dcb7f06a192d8dcb308d GIT binary patch literal 1888 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 iW8Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/packages/async_button_hook/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/packages/async_button_hook/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/packages/async_button_hook/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/packages/async_button_hook/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/packages/async_button_hook/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/async_button_hook/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 0000000..89c2725 --- /dev/null +++ b/packages/async_button_hook/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/packages/async_button_hook/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/async_button_hook/example/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..f2e259c --- /dev/null +++ b/packages/async_button_hook/example/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/async_button_hook/example/ios/Runner/Base.lproj/Main.storyboard b/packages/async_button_hook/example/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 0000000..f3c2851 --- /dev/null +++ b/packages/async_button_hook/example/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/async_button_hook/example/ios/Runner/Info.plist b/packages/async_button_hook/example/ios/Runner/Info.plist new file mode 100644 index 0000000..a060db6 --- /dev/null +++ b/packages/async_button_hook/example/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + example + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + + diff --git a/packages/async_button_hook/example/ios/Runner/Runner-Bridging-Header.h b/packages/async_button_hook/example/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 0000000..308a2a5 --- /dev/null +++ b/packages/async_button_hook/example/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/packages/async_button_hook/example/lib/main.dart b/packages/async_button_hook/example/lib/main.dart new file mode 100644 index 0000000..8354a96 --- /dev/null +++ b/packages/async_button_hook/example/lib/main.dart @@ -0,0 +1,159 @@ +import 'package:async_button_hook/async_button_hook.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; + +void main() => runApp(const MyApp()); + +class MyApp extends StatelessWidget { + const MyApp({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Demo', + theme: ThemeData.dark(), + home: const MyHomePage(), + ); + } +} + +class MyHomePage extends HookWidget { + const MyHomePage({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final textButtonResult = useAsyncButton( + child: const Text('Click Me'), + onPressed: () async { + await Future.delayed(const Duration(seconds: 1)); + }, + ); + final elevatedButtonResult = useAsyncButton( + child: const Text('Click Me'), + onPressed: () async { + await Future.delayed(const Duration(seconds: 1)); + }, + ); + final customButtonResult = useAsyncButton( + child: const Text('Click Me'), + loadingWidget: const Text('Loading...'), + onPressed: () async { + await Future.delayed(const Duration(seconds: 1)); + + throw 'shucks'; + + // If you want to add a timeout, use something similar to + // + // try { + // await Future.delayed(Duration(seconds: 1)) + // .timeout(Duration(milliseconds: 500)); + // } on TimeoutException catch (_) { + // // Show a popup or something + // rethrow; + // } on Exception catch (_) { + // // Show a dialog or something + // rethrow; + // } + // + // We rethrow so that async_button_builder can handle the error + // state + }, + ); + final buttonColor = customButtonResult.buttonState.when( + idle: () => Colors.yellow[200], + loading: () => Colors.grey, + success: () => Colors.orangeAccent, + error: () => Colors.orange, + ); + + return Scaffold( + appBar: AppBar(title: const Text('Async Buttons')), + body: SizedBox.expand( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + const Divider(), + const Text('Text Button:'), + TextButton( + child: textButtonResult.child, + onPressed: textButtonResult.callback, + ), + const Divider(), + const Text('Elevated Button:'), + ElevatedButton( + child: elevatedButtonResult.child, + onPressed: elevatedButtonResult.callback, + ), + const Divider(), + const Text('Custom Outlined Button (Error):'), + OutlinedButton( + child: customButtonResult.child, + onPressed: customButtonResult.callback, + style: OutlinedButton.styleFrom( + primary: Colors.black, + backgroundColor: buttonColor, + ), + ), + const Divider(), + const Text('Custom Material Button:'), + const SizedBox(height: 6.0), + HookBuilder( + builder: (context) { + final customButtonResult = useAsyncButton( + loadingSwitchInCurve: Curves.bounceInOut, + loadingTransitionBuilder: (child, animation) { + return SlideTransition( + position: Tween( + begin: const Offset(0, 1.0), + end: const Offset(0, 0), + ).animate(animation), + child: child, + ); + }, + child: const Text('Click Me'), + onPressed: () async { + await Future.delayed(const Duration(seconds: 2)); + }, + loadingWidget: const Padding( + padding: EdgeInsets.all(8.0), + child: SizedBox( + height: 16.0, + width: 16.0, + child: CircularProgressIndicator( + valueColor: AlwaysStoppedAnimation(Colors.white), + ), + ), + ), + successWidget: const Padding( + padding: EdgeInsets.all(4.0), + child: Icon( + Icons.check, + color: Colors.purpleAccent, + ), + ), + ); + + return Material( + color: customButtonResult.buttonState.maybeWhen( + success: () => Colors.purple[100], + orElse: () => Colors.blue, + ), + // This prevents the loading indicator showing below the + // button + clipBehavior: Clip.hardEdge, + shape: const StadiumBorder(), + child: InkWell( + child: customButtonResult.child, + onTap: customButtonResult.callback, + ), + ); + }, + ), + const Divider(), + ], + ), + ), + ); + } +} diff --git a/packages/async_button_hook/example/pubspec.lock b/packages/async_button_hook/example/pubspec.lock new file mode 100644 index 0000000..d5c4102 --- /dev/null +++ b/packages/async_button_hook/example/pubspec.lock @@ -0,0 +1,203 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + async: + dependency: transitive + description: + name: async + url: "https://pub.dartlang.org" + source: hosted + version: "2.8.1" + async_button_core: + dependency: transitive + description: + path: "../../async_button_core" + relative: true + source: path + version: "0.0.1" + async_button_hook: + dependency: "direct main" + description: + path: ".." + relative: true + source: path + version: "0.0.1" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + characters: + dependency: transitive + description: + name: characters + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + charcode: + dependency: transitive + description: + name: charcode + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.1" + clock: + dependency: transitive + description: + name: clock + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + collection: + dependency: transitive + description: + name: collection + url: "https://pub.dartlang.org" + source: hosted + version: "1.15.0" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.3" + fake_async: + dependency: transitive + description: + name: fake_async + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_hooks: + dependency: "direct main" + description: + name: flutter_hooks + url: "https://pub.dartlang.org" + source: hosted + version: "0.18.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.4" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + freezed_annotation: + dependency: transitive + description: + name: freezed_annotation + url: "https://pub.dartlang.org" + source: hosted + version: "0.14.3" + json_annotation: + dependency: transitive + description: + name: json_annotation + url: "https://pub.dartlang.org" + source: hosted + version: "4.1.0" + lints: + dependency: transitive + description: + name: lints + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + matcher: + dependency: transitive + description: + name: matcher + url: "https://pub.dartlang.org" + source: hosted + version: "0.12.10" + meta: + dependency: transitive + description: + name: meta + url: "https://pub.dartlang.org" + source: hosted + version: "1.7.0" + path: + dependency: transitive + description: + name: path + url: "https://pub.dartlang.org" + source: hosted + version: "1.8.0" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + url: "https://pub.dartlang.org" + source: hosted + version: "1.8.1" + stack_trace: + dependency: transitive + description: + name: stack_trace + url: "https://pub.dartlang.org" + source: hosted + version: "1.10.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + test_api: + dependency: transitive + description: + name: test_api + url: "https://pub.dartlang.org" + source: hosted + version: "0.4.2" + typed_data: + dependency: transitive + description: + name: typed_data + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.0" + vector_math: + dependency: transitive + description: + name: vector_math + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" +sdks: + dart: ">=2.12.0 <3.0.0" + flutter: ">=1.20.0" diff --git a/packages/async_button_hook/example/pubspec.yaml b/packages/async_button_hook/example/pubspec.yaml new file mode 100644 index 0000000..6dc4064 --- /dev/null +++ b/packages/async_button_hook/example/pubspec.yaml @@ -0,0 +1,92 @@ +name: example +description: A new Flutter project. + +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +version: 1.0.0+1 + +environment: + sdk: ">=2.12.0 <3.0.0" + +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. +dependencies: + flutter: + sdk: flutter + async_button_hook: + path: ../ + flutter_hooks: + + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^1.0.2 + +dev_dependencies: + flutter_test: + sdk: flutter + + # The "flutter_lints" package below contains a set of recommended lints to + # encourage good coding practices. The lint set provided by the package is + # activated in the `analysis_options.yaml` file located at the root of your + # package. See that file for information about deactivating specific lint + # rules and activating additional ones. + flutter_lints: ^1.0.0 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware. + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/assets-and-images/#from-packages + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/custom-fonts/#from-packages diff --git a/packages/async_button_hook/example/test/widget_test.dart b/packages/async_button_hook/example/test/widget_test.dart new file mode 100644 index 0000000..a19dabb --- /dev/null +++ b/packages/async_button_hook/example/test/widget_test.dart @@ -0,0 +1,30 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility that Flutter provides. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'package:example/main.dart'; + +void main() { + testWidgets('Counter increments smoke test', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget(const MyApp()); + + // Verify that our counter starts at 0. + expect(find.text('0'), findsOneWidget); + expect(find.text('1'), findsNothing); + + // Tap the '+' icon and trigger a frame. + await tester.tap(find.byIcon(Icons.add)); + await tester.pump(); + + // Verify that our counter has incremented. + expect(find.text('0'), findsNothing); + expect(find.text('1'), findsOneWidget); + }); +} diff --git a/packages/async_button_hook/example/web/favicon.png b/packages/async_button_hook/example/web/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..8aaa46ac1ae21512746f852a42ba87e4165dfdd1 GIT binary patch literal 917 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|I14-?iy0X7 zltGxWVyS%@P(fs7NJL45ua8x7ey(0(N`6wRUPW#JP&EUCO@$SZnVVXYs8ErclUHn2 zVXFjIVFhG^g!Ppaz)DK8ZIvQ?0~DO|i&7O#^-S~(l1AfjnEK zjFOT9D}DX)@^Za$W4-*MbbUihOG|wNBYh(yU7!lx;>x^|#0uTKVr7USFmqf|i<65o z3raHc^AtelCMM;Vme?vOfh>Xph&xL%(-1c06+^uR^q@XSM&D4+Kp$>4P^%3{)XKjo zGZknv$b36P8?Z_gF{nK@`XI}Z90TzwSQO}0J1!f2c(B=V`5aP@1P1a|PZ!4!3&Gl8 zTYqUsf!gYFyJnXpu0!n&N*SYAX-%d(5gVjrHJWqXQshj@!Zm{!01WsQrH~9=kTxW#6SvuapgMqt>$=j#%eyGrQzr zP{L-3gsMA^$I1&gsBAEL+vxi1*Igl=8#8`5?A-T5=z-sk46WA1IUT)AIZHx1rdUrf zVJrJn<74DDw`j)Ki#gt}mIT-Q`XRa2-jQXQoI%w`nb|XblvzK${ZzlV)m-XcwC(od z71_OEC5Bt9GEXosOXaPTYOia#R4ID2TiU~`zVMl08TV_C%DnU4^+HE>9(CE4D6?Fz oujB08i7adh9xk7*FX66dWH6F5TM;?E2b5PlUHx3vIVCg!0Dx9vYXATM literal 0 HcmV?d00001 diff --git a/packages/async_button_hook/example/web/icons/Icon-192.png b/packages/async_button_hook/example/web/icons/Icon-192.png new file mode 100644 index 0000000000000000000000000000000000000000..b749bfef07473333cf1dd31e9eed89862a5d52aa GIT binary patch literal 5292 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 literal 0 HcmV?d00001 diff --git a/packages/async_button_hook/example/web/icons/Icon-512.png b/packages/async_button_hook/example/web/icons/Icon-512.png new file mode 100644 index 0000000000000000000000000000000000000000..88cfd48dff1169879ba46840804b412fe02fefd6 GIT binary patch literal 8252 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 literal 0 HcmV?d00001 diff --git a/packages/async_button_hook/example/web/icons/Icon-maskable-192.png b/packages/async_button_hook/example/web/icons/Icon-maskable-192.png new file mode 100644 index 0000000000000000000000000000000000000000..eb9b4d76e525556d5d89141648c724331630325d GIT binary patch literal 5594 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 X>c!)3PgKfL&lX^$Z>Cpu&6)6jvi^Z! literal 0 HcmV?d00001 diff --git a/packages/async_button_hook/example/web/icons/Icon-maskable-512.png b/packages/async_button_hook/example/web/icons/Icon-maskable-512.png new file mode 100644 index 0000000000000000000000000000000000000000..d69c56691fbdb0b7efa65097c7cc1edac12a6d3e GIT binary patch literal 20998 zcmeFZ_gj-)&^4Nb2tlbLMU<{!p(#yjqEe+=0IA_oih%ScH9@5#MNp&}Y#;;(h=A0@ zh7{>lT2MkSQ344eAvrhici!td|HJuyvJm#Y_w1Q9Yu3!26dNlO-oxUDK_C#XnW^Co z5C{VN6#{~B0)K2j7}*1Xq(Nqemv23A-6&=ZpEijkVnSwVGqLv40?n0=p;k3-U5e5+ z+z3>aS`u9DS=!wg8ROu?X4TFoW6CFLL&{GzoVT)ldhLekLM|+j3tIxRd|*5=c{=s&*vfPdBr(Fyj(v@%eQj1Soy7m4^@VRl1~@-PV7y+c!xz$8436WBn$t{=}mEdK#k`aystimGgI{(IBx$!pAwFoE9Y`^t^;> zKAD)C(Dl^s%`?q5$P|fZf8Xymrtu^Pv(7D`rn>Z-w$Ahs!z9!94WNVxrJuXfHAaxg zC6s@|Z1$7R$(!#t%Jb{{s6(Y?NoQXDYq)!}X@jKPhe`{9KQ@sAU8y-5`xt?S9$jKH zoi}6m5PcG*^{kjvt+kwPpyQzVg4o)a>;LK`aaN2x4@itBD3Aq?yWTM20VRn1rrd+2 zKO=P0rMjEGq_UqpMa`~7B|p?xAN1SCoCp}QxAv8O`jLJ5CVh@umR%c%i^)6!o+~`F zaalSTQcl5iwOLC&H)efzd{8(88mo`GI(56T<(&p7>Qd^;R1hn1Y~jN~tApaL8>##U zd65bo8)79CplWxr#z4!6HvLz&N7_5AN#x;kLG?zQ(#p|lj<8VUlKY=Aw!ATqeL-VG z42gA!^cMNPj>(`ZMEbCrnkg*QTsn*u(nQPWI9pA{MQ=IsPTzd7q5E#7+z>Ch=fx$~ z;J|?(5jTo5UWGvsJa(Sx0?S#56+8SD!I^tftyeh_{5_31l6&Hywtn`bbqYDqGZXI( zCG7hBgvksX2ak8+)hB4jnxlO@A32C_RM&g&qDSb~3kM&)@A_j1*oTO@nicGUyv+%^ z=vB)4(q!ykzT==Z)3*3{atJ5}2PV*?Uw+HhN&+RvKvZL3p9E?gHjv{6zM!A|z|UHK z-r6jeLxbGn0D@q5aBzlco|nG2tr}N@m;CJX(4#Cn&p&sLKwzLFx1A5izu?X_X4x8r@K*d~7>t1~ zDW1Mv5O&WOxbzFC`DQ6yNJ(^u9vJdj$fl2dq`!Yba_0^vQHXV)vqv1gssZYzBct!j zHr9>ydtM8wIs}HI4=E}qAkv|BPWzh3^_yLH(|kdb?x56^BlDC)diWyPd*|f!`^12_U>TD^^94OCN0lVv~Sgvs94ecpE^}VY$w`qr_>Ue zTfH~;C<3H<0dS5Rkf_f@1x$Gms}gK#&k()IC0zb^QbR!YLoll)c$Agfi6MKI0dP_L z=Uou&u~~^2onea2%XZ@>`0x^L8CK6=I{ge;|HXMj)-@o~h&O{CuuwBX8pVqjJ*o}5 z#8&oF_p=uSo~8vn?R0!AMWvcbZmsrj{ZswRt(aEdbi~;HeVqIe)-6*1L%5u$Gbs}| zjFh?KL&U(rC2izSGtwP5FnsR@6$-1toz?RvLD^k~h9NfZgzHE7m!!7s6(;)RKo2z} zB$Ci@h({l?arO+vF;s35h=|WpefaOtKVx>l399}EsX@Oe3>>4MPy%h&^3N_`UTAHJ zI$u(|TYC~E4)|JwkWW3F!Tib=NzjHs5ii2uj0^m|Qlh-2VnB#+X~RZ|`SA*}}&8j9IDv?F;(Y^1=Z0?wWz;ikB zewU>MAXDi~O7a~?jx1x=&8GcR-fTp>{2Q`7#BE#N6D@FCp`?ht-<1|y(NArxE_WIu zP+GuG=Qq>SHWtS2M>34xwEw^uvo4|9)4s|Ac=ud?nHQ>ax@LvBqusFcjH0}{T3ZPQ zLO1l<@B_d-(IS682}5KA&qT1+{3jxKolW+1zL4inqBS-D>BohA!K5++41tM@ z@xe<-qz27}LnV#5lk&iC40M||JRmZ*A##K3+!j93eouU8@q-`W0r%7N`V$cR&JV;iX(@cS{#*5Q>~4BEDA)EikLSP@>Oo&Bt1Z~&0d5)COI%3$cLB_M?dK# z{yv2OqW!al-#AEs&QFd;WL5zCcp)JmCKJEdNsJlL9K@MnPegK23?G|O%v`@N{rIRa zi^7a}WBCD77@VQ-z_v{ZdRsWYrYgC$<^gRQwMCi6);%R~uIi31OMS}=gUTE(GKmCI z$zM>mytL{uNN+a&S38^ez(UT=iSw=l2f+a4)DyCA1Cs_N-r?Q@$3KTYosY!;pzQ0k zzh1G|kWCJjc(oZVBji@kN%)UBw(s{KaYGy=i{g3{)Z+&H8t2`^IuLLKWT6lL<-C(! zSF9K4xd-|VO;4}$s?Z7J_dYqD#Mt)WCDnsR{Kpjq275uUq6`v0y*!PHyS(}Zmv)_{>Vose9-$h8P0|y;YG)Bo}$(3Z%+Gs0RBmFiW!^5tBmDK-g zfe5%B*27ib+7|A*Fx5e)2%kIxh7xWoc3pZcXS2zik!63lAG1;sC1ja>BqH7D zODdi5lKW$$AFvxgC-l-)!c+9@YMC7a`w?G(P#MeEQ5xID#<}W$3bSmJ`8V*x2^3qz zVe<^^_8GHqYGF$nIQm0Xq2kAgYtm#UC1A(=&85w;rmg#v906 zT;RyMgbMpYOmS&S9c38^40oUp?!}#_84`aEVw;T;r%gTZkWeU;;FwM@0y0adt{-OK z(vGnPSlR=Nv2OUN!2=xazlnHPM9EWxXg2EKf0kI{iQb#FoP>xCB<)QY>OAM$Dcdbm zU6dU|%Mo(~avBYSjRc13@|s>axhrPl@Sr81{RSZUdz4(=|82XEbV*JAX6Lfbgqgz584lYgi0 z2-E{0XCVON$wHfvaLs;=dqhQJ&6aLn$D#0i(FkAVrXG9LGm3pSTf&f~RQb6|1_;W> z?n-;&hrq*~L=(;u#jS`*Yvh@3hU-33y_Kv1nxqrsf>pHVF&|OKkoC)4DWK%I!yq?P z=vXo8*_1iEWo8xCa{HJ4tzxOmqS0&$q+>LroMKI*V-rxhOc%3Y!)Y|N6p4PLE>Yek>Y(^KRECg8<|%g*nQib_Yc#A5q8Io z6Ig&V>k|~>B6KE%h4reAo*DfOH)_01tE0nWOxX0*YTJgyw7moaI^7gW*WBAeiLbD?FV9GSB zPv3`SX*^GRBM;zledO`!EbdBO_J@fEy)B{-XUTVQv}Qf~PSDpK9+@I`7G7|>Dgbbu z_7sX9%spVo$%qwRwgzq7!_N;#Td08m5HV#?^dF-EV1o)Q=Oa+rs2xH#g;ykLbwtCh znUnA^dW!XjspJ;otq$yV@I^s9Up(5k7rqhQd@OLMyyxVLj_+$#Vc*}Usevp^I(^vH zmDgHc0VMme|K&X?9&lkN{yq_(If)O`oUPW8X}1R5pSVBpfJe0t{sPA(F#`eONTh_) zxeLqHMfJX#?P(@6w4CqRE@Eiza; z;^5)Kk=^5)KDvd9Q<`=sJU8rjjxPmtWMTmzcH={o$U)j=QBuHarp?=}c??!`3d=H$nrJMyr3L-& zA#m?t(NqLM?I3mGgWA_C+0}BWy3-Gj7bR+d+U?n*mN$%5P`ugrB{PeV>jDUn;eVc- zzeMB1mI4?fVJatrNyq|+zn=!AiN~<}eoM#4uSx^K?Iw>P2*r=k`$<3kT00BE_1c(02MRz4(Hq`L^M&xt!pV2 zn+#U3@j~PUR>xIy+P>51iPayk-mqIK_5rlQMSe5&tDkKJk_$i(X&;K(11YGpEc-K= zq4Ln%^j>Zi_+Ae9eYEq_<`D+ddb8_aY!N;)(&EHFAk@Ekg&41ABmOXfWTo)Z&KotA zh*jgDGFYQ^y=m)<_LCWB+v48DTJw*5dwMm_YP0*_{@HANValf?kV-Ic3xsC}#x2h8 z`q5}d8IRmqWk%gR)s~M}(Qas5+`np^jW^oEd-pzERRPMXj$kS17g?H#4^trtKtq;C?;c ztd|%|WP2w2Nzg@)^V}!Gv++QF2!@FP9~DFVISRW6S?eP{H;;8EH;{>X_}NGj^0cg@ z!2@A>-CTcoN02^r6@c~^QUa={0xwK0v4i-tQ9wQq^=q*-{;zJ{Qe%7Qd!&X2>rV@4 z&wznCz*63_vw4>ZF8~%QCM?=vfzW0r_4O^>UA@otm_!N%mH)!ERy&b!n3*E*@?9d^ zu}s^By@FAhG(%?xgJMuMzuJw2&@$-oK>n z=UF}rt%vuaP9fzIFCYN-1&b#r^Cl6RDFIWsEsM|ROf`E?O(cy{BPO2Ie~kT+^kI^i zp>Kbc@C?}3vy-$ZFVX#-cx)Xj&G^ibX{pWggtr(%^?HeQL@Z( zM-430g<{>vT*)jK4aY9(a{lSy{8vxLbP~n1MXwM527ne#SHCC^F_2@o`>c>>KCq9c(4c$VSyMl*y3Nq1s+!DF| z^?d9PipQN(mw^j~{wJ^VOXDCaL$UtwwTpyv8IAwGOg<|NSghkAR1GSNLZ1JwdGJYm zP}t<=5=sNNUEjc=g(y)1n5)ynX(_$1-uGuDR*6Y^Wgg(LT)Jp><5X|}bt z_qMa&QP?l_n+iVS>v%s2Li_;AIeC=Ca^v1jX4*gvB$?H?2%ndnqOaK5-J%7a} zIF{qYa&NfVY}(fmS0OmXA70{znljBOiv5Yod!vFU{D~*3B3Ka{P8?^ zfhlF6o7aNT$qi8(w<}OPw5fqA7HUje*r*Oa(YV%*l0|9FP9KW@U&{VSW{&b0?@y)M zs%4k1Ax;TGYuZ9l;vP5@?3oQsp3)rjBeBvQQ>^B;z5pc=(yHhHtq6|0m(h4envn_j787fizY@V`o(!SSyE7vlMT zbo=Z1c=atz*G!kwzGB;*uPL$Ei|EbZLh8o+1BUMOpnU(uX&OG1MV@|!&HOOeU#t^x zr9=w2ow!SsTuJWT7%Wmt14U_M*3XiWBWHxqCVZI0_g0`}*^&yEG9RK9fHK8e+S^m? zfCNn$JTswUVbiC#>|=wS{t>-MI1aYPLtzO5y|LJ9nm>L6*wpr_m!)A2Fb1RceX&*|5|MwrvOk4+!0p99B9AgP*9D{Yt|x=X}O% zgIG$MrTB=n-!q%ROT|SzH#A$Xm;|ym)0>1KR}Yl0hr-KO&qMrV+0Ej3d@?FcgZ+B3 ztEk16g#2)@x=(ko8k7^Tq$*5pfZHC@O@}`SmzT1(V@x&NkZNM2F#Q-Go7-uf_zKC( zB(lHZ=3@dHaCOf6C!6i8rDL%~XM@rVTJbZL09?ht@r^Z_6x}}atLjvH^4Vk#Ibf(^LiBJFqorm?A=lE zzFmwvp4bT@Nv2V>YQT92X;t9<2s|Ru5#w?wCvlhcHLcsq0TaFLKy(?nzezJ>CECqj zggrI~Hd4LudM(m{L@ezfnpELsRFVFw>fx;CqZtie`$BXRn#Ns%AdoE$-Pf~{9A8rV zf7FbgpKmVzmvn-z(g+&+-ID=v`;6=)itq8oM*+Uz**SMm_{%eP_c0{<%1JGiZS19o z@Gj7$Se~0lsu}w!%;L%~mIAO;AY-2i`9A*ZfFs=X!LTd6nWOZ7BZH2M{l2*I>Xu)0 z`<=;ObglnXcVk!T>e$H?El}ra0WmPZ$YAN0#$?|1v26^(quQre8;k20*dpd4N{i=b zuN=y}_ew9SlE~R{2+Rh^7%PA1H5X(p8%0TpJ=cqa$65XL)$#ign-y!qij3;2>j}I; ziO@O|aYfn&up5F`YtjGw68rD3{OSGNYmBnl?zdwY$=RFsegTZ=kkzRQ`r7ZjQP!H( zp4>)&zf<*N!tI00xzm-ME_a{_I!TbDCr;8E;kCH4LlL-tqLxDuBn-+xgPk37S&S2^ z2QZumkIimwz!c@!r0)j3*(jPIs*V!iLTRl0Cpt_UVNUgGZzdvs0(-yUghJfKr7;=h zD~y?OJ-bWJg;VdZ^r@vlDoeGV&8^--!t1AsIMZ5S440HCVr%uk- z2wV>!W1WCvFB~p$P$$_}|H5>uBeAe>`N1FI8AxM|pq%oNs;ED8x+tb44E) zTj{^fbh@eLi%5AqT?;d>Es5D*Fi{Bpk)q$^iF!!U`r2hHAO_?#!aYmf>G+jHsES4W zgpTKY59d?hsb~F0WE&dUp6lPt;Pm zcbTUqRryw^%{ViNW%Z(o8}dd00H(H-MmQmOiTq{}_rnwOr*Ybo7*}3W-qBT!#s0Ie z-s<1rvvJx_W;ViUD`04%1pra*Yw0BcGe)fDKUK8aF#BwBwMPU;9`!6E(~!043?SZx z13K%z@$$#2%2ovVlgFIPp7Q6(vO)ud)=*%ZSucL2Dh~K4B|%q4KnSpj#n@(0B})!9 z8p*hY@5)NDn^&Pmo;|!>erSYg`LkO?0FB@PLqRvc>4IsUM5O&>rRv|IBRxi(RX(gJ ztQ2;??L~&Mv;aVr5Q@(?y^DGo%pO^~zijld41aA0KKsy_6FeHIn?fNHP-z>$OoWer zjZ5hFQTy*-f7KENRiCE$ZOp4|+Wah|2=n@|W=o}bFM}Y@0e62+_|#fND5cwa3;P{^pEzlJbF1Yq^}>=wy8^^^$I2M_MH(4Dw{F6hm+vrWV5!q;oX z;tTNhz5`-V={ew|bD$?qcF^WPR{L(E%~XG8eJx(DoGzt2G{l8r!QPJ>kpHeOvCv#w zr=SSwMDaUX^*~v%6K%O~i)<^6`{go>a3IdfZ8hFmz&;Y@P%ZygShQZ2DSHd`m5AR= zx$wWU06;GYwXOf(%MFyj{8rPFXD};JCe85Bdp4$YJ2$TzZ7Gr#+SwCvBI1o$QP0(c zy`P51FEBV2HTisM3bHqpmECT@H!Y2-bv2*SoSPoO?wLe{M#zDTy@ujAZ!Izzky~3k zRA1RQIIoC*Mej1PH!sUgtkR0VCNMX(_!b65mo66iM*KQ7xT8t2eev$v#&YdUXKwGm z7okYAqYF&bveHeu6M5p9xheRCTiU8PFeb1_Rht0VVSbm%|1cOVobc8mvqcw!RjrMRM#~=7xibH&Fa5Imc|lZ{eC|R__)OrFg4@X_ ze+kk*_sDNG5^ELmHnZ7Ue?)#6!O)#Nv*Dl2mr#2)w{#i-;}0*_h4A%HidnmclH#;Q zmQbq+P4DS%3}PpPm7K_K3d2s#k~x+PlTul7+kIKol0@`YN1NG=+&PYTS->AdzPv!> zQvzT=)9se*Jr1Yq+C{wbK82gAX`NkbXFZ)4==j4t51{|-v!!$H8@WKA={d>CWRW+g z*`L>9rRucS`vbXu0rzA1#AQ(W?6)}1+oJSF=80Kf_2r~Qm-EJ6bbB3k`80rCv(0d` zvCf3;L2ovYG_TES%6vSuoKfIHC6w;V31!oqHM8-I8AFzcd^+_86!EcCOX|Ta9k1!s z_Vh(EGIIsI3fb&dF$9V8v(sTBC%!#<&KIGF;R+;MyC0~}$gC}}= zR`DbUVc&Bx`lYykFZ4{R{xRaUQkWCGCQlEc;!mf=+nOk$RUg*7 z;kP7CVLEc$CA7@6VFpsp3_t~m)W0aPxjsA3e5U%SfY{tp5BV5jH-5n?YX7*+U+Zs%LGR>U- z!x4Y_|4{gx?ZPJobISy991O znrmrC3otC;#4^&Rg_iK}XH(XX+eUHN0@Oe06hJk}F?`$)KmH^eWz@@N%wEc)%>?Ft z#9QAroDeyfztQ5Qe{m*#R#T%-h*&XvSEn@N$hYRTCMXS|EPwzF3IIysD2waj`vQD{ zv_#^Pgr?s~I*NE=acf@dWVRNWTr(GN0wrL)Z2=`Dr>}&ZDNX|+^Anl{Di%v1Id$_p zK5_H5`RDjJx`BW7hc85|> zHMMsWJ4KTMRHGu+vy*kBEMjz*^K8VtU=bXJYdhdZ-?jTXa$&n)C?QQIZ7ln$qbGlr zS*TYE+ppOrI@AoPP=VI-OXm}FzgXRL)OPvR$a_=SsC<3Jb+>5makX|U!}3lx4tX&L z^C<{9TggZNoeX!P1jX_K5HkEVnQ#s2&c#umzV6s2U-Q;({l+j^?hi7JnQ7&&*oOy9 z(|0asVTWUCiCnjcOnB2pN0DpuTglKq;&SFOQ3pUdye*eT<2()7WKbXp1qq9=bhMWlF-7BHT|i3TEIT77AcjD(v=I207wi-=vyiw5mxgPdTVUC z&h^FEUrXwWs9en2C{ywZp;nvS(Mb$8sBEh-*_d-OEm%~p1b2EpcwUdf<~zmJmaSTO zSX&&GGCEz-M^)G$fBvLC2q@wM$;n4jp+mt0MJFLuJ%c`tSp8$xuP|G81GEd2ci$|M z4XmH{5$j?rqDWoL4vs!}W&!?!rtj=6WKJcE>)?NVske(p;|#>vL|M_$as=mi-n-()a*OU3Okmk0wC<9y7t^D(er-&jEEak2!NnDiOQ99Wx8{S8}=Ng!e0tzj*#T)+%7;aM$ z&H}|o|J1p{IK0Q7JggAwipvHvko6>Epmh4RFRUr}$*2K4dz85o7|3#Bec9SQ4Y*;> zXWjT~f+d)dp_J`sV*!w>B%)#GI_;USp7?0810&3S=WntGZ)+tzhZ+!|=XlQ&@G@~3 z-dw@I1>9n1{+!x^Hz|xC+P#Ab`E@=vY?3%Bc!Po~e&&&)Qp85!I|U<-fCXy*wMa&t zgDk!l;gk;$taOCV$&60z+}_$ykz=Ea*)wJQ3-M|p*EK(cvtIre0Pta~(95J7zoxBN zS(yE^3?>88AL0Wfuou$BM{lR1hkrRibz=+I9ccwd`ZC*{NNqL)3pCcw^ygMmrG^Yp zn5f}Xf>%gncC=Yq96;rnfp4FQL#{!Y*->e82rHgY4Zwy{`JH}b9*qr^VA{%~Z}jtp z_t$PlS6}5{NtTqXHN?uI8ut8rOaD#F1C^ls73S=b_yI#iZDOGz3#^L@YheGd>L;<( z)U=iYj;`{>VDNzIxcjbTk-X3keXR8Xbc`A$o5# zKGSk-7YcoBYuAFFSCjGi;7b<;n-*`USs)IX z=0q6WZ=L!)PkYtZE-6)azhXV|+?IVGTOmMCHjhkBjfy@k1>?yFO3u!)@cl{fFAXnRYsWk)kpT?X{_$J=|?g@Q}+kFw|%n!;Zo}|HE@j=SFMvT8v`6Y zNO;tXN^036nOB2%=KzxB?n~NQ1K8IO*UE{;Xy;N^ZNI#P+hRZOaHATz9(=)w=QwV# z`z3+P>9b?l-@$@P3<;w@O1BdKh+H;jo#_%rr!ute{|YX4g5}n?O7Mq^01S5;+lABE+7`&_?mR_z7k|Ja#8h{!~j)| zbBX;*fsbUak_!kXU%HfJ2J+G7;inu#uRjMb|8a){=^))y236LDZ$$q3LRlat1D)%7K0!q5hT5V1j3qHc7MG9 z_)Q=yQ>rs>3%l=vu$#VVd$&IgO}Za#?aN!xY>-<3PhzS&q!N<=1Q7VJBfHjug^4|) z*fW^;%3}P7X#W3d;tUs3;`O&>;NKZBMR8au6>7?QriJ@gBaorz-+`pUWOP73DJL=M z(33uT6Gz@Sv40F6bN|H=lpcO z^AJl}&=TIjdevuDQ!w0K*6oZ2JBOhb31q!XDArFyKpz!I$p4|;c}@^bX{>AXdt7Bm zaLTk?c%h@%xq02reu~;t@$bv`b3i(P=g}~ywgSFpM;}b$zAD+=I!7`V~}ARB(Wx0C(EAq@?GuxOL9X+ffbkn3+Op0*80TqmpAq~EXmv%cq36celXmRz z%0(!oMp&2?`W)ALA&#|fu)MFp{V~~zIIixOxY^YtO5^FSox8v$#d0*{qk0Z)pNTt0QVZ^$`4vImEB>;Lo2!7K05TpY-sl#sWBz_W-aDIV`Ksabi zvpa#93Svo!70W*Ydh)Qzm{0?CU`y;T^ITg-J9nfWeZ-sbw)G@W?$Eomf%Bg2frfh5 zRm1{|E0+(4zXy){$}uC3%Y-mSA2-^I>Tw|gQx|7TDli_hB>``)Q^aZ`LJC2V3U$SABP}T)%}9g2pF9dT}aC~!rFFgkl1J$ z`^z{Arn3On-m%}r}TGF8KQe*OjSJ=T|caa_E;v89A{t@$yT^(G9=N9F?^kT*#s3qhJq!IH5|AhnqFd z0B&^gm3w;YbMNUKU>naBAO@fbz zqw=n!@--}o5;k6DvTW9pw)IJVz;X}ncbPVrmH>4x);8cx;q3UyiML1PWp%bxSiS|^ zC5!kc4qw%NSOGQ*Kcd#&$30=lDvs#*4W4q0u8E02U)7d=!W7+NouEyuF1dyH$D@G& zaFaxo9Ex|ZXA5y{eZT*i*dP~INSMAi@mvEX@q5i<&o&#sM}Df?Og8n8Ku4vOux=T% zeuw~z1hR}ZNwTn8KsQHKLwe2>p^K`YWUJEdVEl|mO21Bov!D0D$qPoOv=vJJ`)|%_ z>l%`eexY7t{BlVKP!`a^U@nM?#9OC*t76My_E_<16vCz1x_#82qj2PkWiMWgF8bM9 z(1t4VdHcJ;B~;Q%x01k_gQ0>u2*OjuEWNOGX#4}+N?Gb5;+NQMqp}Puqw2HnkYuKA zzKFWGHc&K>gwVgI1Sc9OT1s6fq=>$gZU!!xsilA$fF`kLdGoX*^t}ao@+^WBpk>`8 z4v_~gK|c2rCq#DZ+H)$3v~Hoi=)=1D==e3P zpKrRQ+>O^cyTuWJ%2}__0Z9SM_z9rptd*;-9uC1tDw4+A!=+K%8~M&+Zk#13hY$Y$ zo-8$*8dD5@}XDi19RjK6T^J~DIXbF5w&l?JLHMrf0 zLv0{7*G!==o|B%$V!a=EtVHdMwXLtmO~vl}P6;S(R2Q>*kTJK~!}gloxj)m|_LYK{ zl(f1cB=EON&wVFwK?MGn^nWuh@f95SHatPs(jcwSY#Dnl1@_gkOJ5=f`%s$ZHljRH0 z+c%lrb=Gi&N&1>^L_}#m>=U=(oT^vTA&3!xXNyqi$pdW1BDJ#^{h|2tZc{t^vag3& zAD7*8C`chNF|27itjBUo^CCDyEpJLX3&u+(L;YeeMwnXEoyN(ytoEabcl$lSgx~Ltatn}b$@j_yyMrBb03)shJE*$;Mw=;mZd&8e>IzE+4WIoH zCSZE7WthNUL$|Y#m!Hn?x7V1CK}V`KwW2D$-7&ODy5Cj;!_tTOOo1Mm%(RUt)#$@3 zhurA)t<7qik%%1Et+N1?R#hdBB#LdQ7{%-C zn$(`5e0eFh(#c*hvF>WT*07fk$N_631?W>kfjySN8^XC9diiOd#s?4tybICF;wBjp zIPzilX3{j%4u7blhq)tnaOBZ_`h_JqHXuI7SuIlNTgBk9{HIS&3|SEPfrvcE<@}E` zKk$y*nzsqZ{J{uWW9;#n=de&&h>m#A#q)#zRonr(?mDOYU&h&aQWD;?Z(22wY?t$U3qo`?{+amA$^TkxL+Ex2dh`q7iR&TPd0Ymwzo#b? zP$#t=elB5?k$#uE$K>C$YZbYUX_JgnXA`oF_Ifz4H7LEOW~{Gww&3s=wH4+j8*TU| zSX%LtJWqhr-xGNSe{;(16kxnak6RnZ{0qZ^kJI5X*It_YuynSpi(^-}Lolr{)#z_~ zw!(J-8%7Ybo^c3(mED`Xz8xecP35a6M8HarxRn%+NJBE;dw>>Y2T&;jzRd4FSDO3T zt*y+zXCtZQ0bP0yf6HRpD|WmzP;DR^-g^}{z~0x~z4j8m zucTe%k&S9Nt-?Jb^gYW1w6!Y3AUZ0Jcq;pJ)Exz%7k+mUOm6%ApjjSmflfKwBo6`B zhNb@$NHTJ>guaj9S{@DX)!6)b-Shav=DNKWy(V00k(D!v?PAR0f0vDNq*#mYmUp6> z76KxbFDw5U{{qx{BRj(>?|C`82ICKbfLxoldov-M?4Xl+3;I4GzLHyPOzYw7{WQST zPNYcx5onA%MAO9??41Po*1zW(Y%Zzn06-lUp{s<3!_9vv9HBjT02On0Hf$}NP;wF) zP<`2p3}A^~1YbvOh{ePMx$!JGUPX-tbBzp3mDZMY;}h;sQ->!p97GA)9a|tF(Gh{1$xk7 zUw?ELkT({Xw!KIr);kTRb1b|UL`r2_`a+&UFVCdJ)1T#fdh;71EQl9790Br0m_`$x z9|ZANuchFci8GNZ{XbP=+uXSJRe(;V5laQz$u18#?X*9}x7cIEbnr%<=1cX3EIu7$ zhHW6pe5M(&qEtsqRa>?)*{O;OJT+YUhG5{km|YI7I@JL_3Hwao9aXneiSA~a* z|Lp@c-oMNyeAEuUz{F?kuou3x#C*gU?lon!RC1s37gW^0Frc`lqQWH&(J4NoZg3m8 z;Lin#8Q+cFPD7MCzj}#|ws7b@?D9Q4dVjS4dpco=4yX5SSH=A@U@yqPdp@?g?qeia zH=Tt_9)G=6C2QIPsi-QipnK(mc0xXIN;j$WLf@n8eYvMk;*H-Q4tK%(3$CN}NGgO8n}fD~+>?<3UzvsrMf*J~%i;VKQHbF%TPalFi=#sgj)(P#SM^0Q=Tr>4kJVw8X3iWsP|e8tj}NjlMdWp z@2+M4HQu~3!=bZpjh;;DIDk&X}=c8~kn)FWWH z2KL1w^rA5&1@@^X%MjZ7;u(kH=YhH2pJPFQe=hn>tZd5RC5cfGYis8s9PKaxi*}-s6*W zRA^PwR=y^5Z){!(4D9-KC;0~;b*ploznFOaU`bJ_7U?qAi#mTo!&rIECRL$_y@yI27x2?W+zqDBD5~KCVYKFZLK+>ABC(Kj zeAll)KMgIlAG`r^rS{loBrGLtzhHY8$)<_S<(Dpkr(Ym@@vnQ&rS@FC*>2@XCH}M+an74WcRDcoQ+a3@A z9tYhl5$z7bMdTvD2r&jztBuo37?*k~wcU9GK2-)MTFS-lux-mIRYUuGUCI~V$?s#< z?1qAWb(?ZLm(N>%S%y10COdaq_Tm5c^%ooIxpR=`3e4C|@O5wY+eLik&XVi5oT7oe zmxH)Jd*5eo@!7t`x8!K=-+zJ-Sz)B_V$)s1pW~CDU$=q^&ABvf6S|?TOMB-RIm@CoFg>mjIQE)?+A1_3s6zmFU_oW&BqyMz1mY*IcP_2knjq5 zqw~JK(cVsmzc7*EvTT2rvpeqhg)W=%TOZ^>f`rD4|7Z5fq*2D^lpCttIg#ictgqZ$P@ru6P#f$x#KfnfTZj~LG6U_d-kE~`;kU_X)`H5so@?C zWmb!7x|xk@0L~0JFall*@ltyiL^)@3m4MqC7(7H0sH!WidId1#f#6R{Q&A!XzO1IAcIx;$k66dumt6lpUw@nL2MvqJ5^kbOVZ<^2jt5-njy|2@`07}0w z;M%I1$FCoLy`8xp8Tk)bFr;7aJeQ9KK6p=O$U0-&JYYy8woV*>b+FB?xLX`=pirYM z5K$BA(u)+jR{?O2r$c_Qvl?M{=Ar{yQ!UVsVn4k@0!b?_lA;dVz9uaQUgBH8Oz(Sb zrEs;&Ey>_ex8&!N{PmQjp+-Hlh|OA&wvDai#GpU=^-B70V0*LF=^bi+Nhe_o|azZ%~ZZ1$}LTmWt4aoB1 zPgccm$EwYU+jrdBaQFxQfn5gd(gM`Y*Ro1n&Zi?j=(>T3kmf94vdhf?AuS8>$Va#P zGL5F+VHpxdsCUa}+RqavXCobI-@B;WJbMphpK2%6t=XvKWWE|ruvREgM+|V=i6;;O zx$g=7^`$XWn0fu!gF=Xe9cMB8Z_SelD>&o&{1XFS`|nInK3BXlaeD*rc;R-#osyIS zWv&>~^TLIyBB6oDX+#>3<_0+2C4u2zK^wmHXXDD9_)kmLYJ!0SzM|%G9{pi)`X$uf zW}|%%#LgyK7m(4{V&?x_0KEDq56tk|0YNY~B(Sr|>WVz-pO3A##}$JCT}5P7DY+@W z#gJv>pA5>$|E3WO2tV7G^SuymB?tY`ooKcN3!vaQMnBNk-WATF{-$#}FyzgtJ8M^; zUK6KWSG)}6**+rZ&?o@PK3??uN{Q)#+bDP9i1W&j)oaU5d0bIWJ_9T5ac!qc?x66Q z$KUSZ`nYY94qfN_dpTFr8OW~A?}LD;Yty-BA)-be5Z3S#t2Io%q+cAbnGj1t$|qFR z9o?8B7OA^KjCYL=-!p}w(dkC^G6Nd%_I=1))PC0w5}ZZGJxfK)jP4Fwa@b-SYBw?% zdz9B-<`*B2dOn(N;mcTm%Do)rIvfXRNFX&1h`?>Rzuj~Wx)$p13nrDlS8-jwq@e@n zNIj_|8or==8~1h*Ih?w*8K7rYkGlwlTWAwLKc5}~dfz3y`kM&^Q|@C%1VAp_$wnw6zG~W4O+^ z>i?NY?oXf^Puc~+fDM$VgRNBpOZj{2cMP~gCqWAX4 z7>%$ux8@a&_B(pt``KSt;r+sR-$N;jdpY>|pyvPiN)9ohd*>mVST3wMo)){`B(&eX z1?zZJ-4u9NZ|~j1rdZYq4R$?swf}<6(#ex%7r{kh%U@kT)&kWuAszS%oJts=*OcL9 zaZwK<5DZw%1IFHXgFplP6JiL^dk8+SgM$D?8X+gE4172hXh!WeqIO>}$I9?Nry$*S zQ#f)RuH{P7RwA3v9f<-w>{PSzom;>(i&^l{E0(&Xp4A-*q-@{W1oE3K;1zb{&n28dSC2$N+6auXe0}e4b z)KLJ?5c*>@9K#I^)W;uU_Z`enquTUxr>mNq z1{0_puF-M7j${rs!dxxo3EelGodF1TvjV;Zpo;s{5f1pyCuRp=HDZ?s#IA4f?h|-p zGd|Mq^4hDa@Bh!c4ZE?O&x&XZ_ptZGYK4$9F4~{%R!}G1leCBx`dtNUS|K zL-7J5s4W@%mhXg1!}a4PD%!t&Qn%f_oquRajn3@C*)`o&K9o7V6DwzVMEhjVdDJ1fjhr#@=lp#@4EBqi=CCQ>73>R(>QKPNM&_Jpe5G`n4wegeC`FYEPJ{|vwS>$-`fuRSp3927qOv|NC3T3G-0 zA{K`|+tQy1yqE$ShWt8ny&5~)%ITb@^+x$w0)f&om;P8B)@}=Wzy59BwUfZ1vqw87 za2lB8J(&*l#(V}Id8SyQ0C(2amzkz3EqG&Ed0Jq1)$|&>4_|NIe=5|n=3?siFV0fI z{As5DLW^gs|B-b4C;Hd(SM-S~GQhzb>HgF2|2Usww0nL^;x@1eaB)=+Clj+$fF@H( z-fqP??~QMT$KI-#m;QC*&6vkp&8699G3)Bq0*kFZXINw=b9OVaed(3(3kS|IZ)CM? zJdnW&%t8MveBuK21uiYj)_a{Fnw0OErMzMN?d$QoPwkhOwcP&p+t>P)4tHlYw-pPN z^oJ=uc$Sl>pv@fZH~ZqxSvdhF@F1s=oZawpr^-#l{IIOGG=T%QXjtwPhIg-F@k@uIlr?J->Ia zpEUQ*=4g|XYn4Gez&aHr*;t$u3oODPmc2Ku)2Og|xjc%w;q!Zz+zY)*3{7V8bK4;& zYV82FZ+8?v)`J|G1w4I0fWdKg|2b#iaazCv;|?(W-q}$o&Y}Q5d@BRk^jL7#{kbCK zSgkyu;=DV+or2)AxCBgq-nj5=@n^`%T#V+xBGEkW4lCqrE)LMv#f;AvD__cQ@Eg3`~x| zW+h9mofSXCq5|M)9|ez(#X?-sxB%Go8};sJ?2abp(Y!lyi>k)|{M*Z$c{e1-K4ky` MPgg&ebxsLQ025IeI{*Lx literal 0 HcmV?d00001 diff --git a/packages/async_button_hook/example/web/index.html b/packages/async_button_hook/example/web/index.html new file mode 100644 index 0000000..b829dda --- /dev/null +++ b/packages/async_button_hook/example/web/index.html @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + example + + + + + + + diff --git a/packages/async_button_hook/example/web/manifest.json b/packages/async_button_hook/example/web/manifest.json new file mode 100644 index 0000000..096edf8 --- /dev/null +++ b/packages/async_button_hook/example/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "example", + "short_name": "example", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/packages/async_button_hook/lib/async_button_hook.dart b/packages/async_button_hook/lib/async_button_hook.dart index 258cb5e..5e29b06 100644 --- a/packages/async_button_hook/lib/async_button_hook.dart +++ b/packages/async_button_hook/lib/async_button_hook.dart @@ -1,3 +1,4 @@ library async_button_hook; -export 'package:async_button_hook/async_button_hook.dart'; +export 'package:async_button_core/async_button_core.dart'; +export 'package:async_button_hook/src/async_button_hook.dart'; diff --git a/packages/async_button_hook/lib/src/async_button_hook.dart b/packages/async_button_hook/lib/src/async_button_hook.dart index de45be1..f26df7c 100644 --- a/packages/async_button_hook/lib/src/async_button_hook.dart +++ b/packages/async_button_hook/lib/src/async_button_hook.dart @@ -63,6 +63,7 @@ AsyncButtonResult useAsyncButton({ final ticker = useSingleTickerProvider(); final isMounted = useIsMounted(); final context = useContext(); + final childKey = child.key; final theme = Theme.of(context); final _loadingWidget = loadingWidget ?? const SizedBox( @@ -81,6 +82,15 @@ AsyncButtonResult useAsyncButton({ color: theme.errorColor, ); + // This is necessary in the case of nested async button builders. + // We cannot have the same __idle__, __loading__, etc. keys as they might + // conflict with one another. + String childKeyValue = ''; + + if (childKey != null && childKey is ValueKey) { + childKeyValue = childKey.value.toString(); + } + if (successPadding != null) { _successWidget = Padding( padding: successPadding, @@ -99,39 +109,39 @@ AsyncButtonResult useAsyncButton({ // TODO: This duration is same as size's duration. That's okay right? duration: duration, reverseDuration: reverseDuration, - switchInCurve: buttonState.when( + switchInCurve: _buttonState.value.when( idle: () => idleSwitchInCurve, loading: () => loadingSwitchInCurve, success: () => successSwitchInCurve, error: () => errorSwitchInCurve, ), - switchOutCurve: buttonState.when( + switchOutCurve: _buttonState.value.when( idle: () => idleSwitchOutCurve, loading: () => loadingSwitchOutCurve, success: () => successSwitchOutCurve, error: () => errorSwitchOutCurve, ), - transitionBuilder: buttonState.when( + transitionBuilder: _buttonState.value.when( idle: () => idleTransitionBuilder, loading: () => loadingTransitionBuilder, success: () => successTransitionBuilder, error: () => errorTransitionBuilder, ), - child: buttonState.when( + child: _buttonState.value.when( idle: () => KeyedSubtree( - key: const ValueKey('__idle__'), + key: ValueKey('__idle__' + childKeyValue), child: child, ), loading: () => KeyedSubtree( - key: const ValueKey('__loading__'), + key: ValueKey('__loading__' + childKeyValue), child: _loadingWidget, ), success: () => KeyedSubtree( - key: const ValueKey('__success__'), + key: ValueKey('__success__' + childKeyValue), child: _successWidget, ), error: () => KeyedSubtree( - key: const ValueKey('__error__'), + key: ValueKey('__error__' + childKeyValue), child: _errorWidget, ), ), @@ -166,7 +176,7 @@ AsyncButtonResult useAsyncButton({ ? null : onPressed == null ? null - : buttonState.maybeWhen( + : _buttonState.value.maybeWhen( idle: () => () { final completer = Completer(); // I might not want to set buttonState if we're being From 1d8a8a07847862bc2f55c23e2e8ab0f670078048 Mon Sep 17 00:00:00 2001 From: Nolence Date: Thu, 19 Aug 2021 08:45:48 -0600 Subject: [PATCH 050/176] Added padding to click me button in hook example --- packages/async_button_hook/example/lib/main.dart | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/async_button_hook/example/lib/main.dart b/packages/async_button_hook/example/lib/main.dart index 8354a96..4172d11 100644 --- a/packages/async_button_hook/example/lib/main.dart +++ b/packages/async_button_hook/example/lib/main.dart @@ -111,7 +111,16 @@ class MyHomePage extends HookWidget { child: child, ); }, - child: const Text('Click Me'), + child: const Padding( + padding: EdgeInsets.symmetric( + horizontal: 16.0, + vertical: 8.0, + ), + child: Text( + 'Click Me', + style: TextStyle(color: Colors.white), + ), + ), onPressed: () async { await Future.delayed(const Duration(seconds: 2)); }, From 2cc4b498626f670c29e0bc800ded938952b7f68e Mon Sep 17 00:00:00 2001 From: Nolence Date: Thu, 19 Aug 2021 09:24:50 -0600 Subject: [PATCH 051/176] updated docs of hook --- README.md | 148 +---------------- packages/async_button_builder/README.md | 150 +++++++++++++++++- packages/async_button_hook/README.md | 147 ++++++++++++++++- .../async_button_hook/example/lib/main.dart | 28 ++-- 4 files changed, 314 insertions(+), 159 deletions(-) diff --git a/README.md b/README.md index c230846..77f094b 100644 --- a/README.md +++ b/README.md @@ -1,149 +1,11 @@ -# async_button_builder +# async_button [![melos](https://img.shields.io/badge/maintained%20with-melos-f700ff.svg?style=flat-square)](https://github.com/invertase/melos) -A builder that adds loading, disabled, errored and completed states (with fluid animation between each) on top of buttons that perform asynchronous tasks. +AsyncButton offers a simple way to extend any type of button with an asynchronous aspect. It comes in two flavors that are independent (so no additional dependencies) of `builder` or `hook` pattern. Note, the hook version does rely on `flutter_hooks` for use. Either method allows adding loading, disabled, errored and completed states (with fluid animation between each) on top of buttons that perform asynchronous tasks. -## Getting Started +To see the respective guides see here: -Include the package: +### [async_button_builder](https://github.com/Nolence/async_button/tree/main/packages/async_button_builder) 🪝 -``` - async_button_builder: -``` - -Wrap the builder around a button, passing the onPressed and child element to builder instead of the button directly. These two are the only required fields. - -```dart -AsyncButtonBuilder( - child: Text('Click Me'), - onPressed: () async { - await Future.delayed(Duration(seconds: 1)); - }, - builder: (context, child, callback, _) { - return TextButton( - child: child, - onPressed: callback, - ); - }, -), -``` - -

- -

- -The fourth value in the builder allows you listen to the loading state. This can be used to conditionally style the button. This package depends `freezed` in order to create a sealed union to better handle the possible states. - -```dart -AsyncButtonBuilder( - child: Text('Click Me'), - loadingWidget: Text('Loading...'), - onPressed: () async { - await Future.delayed(Duration(seconds: 1)); - - // See the examples file for a way to handle timeouts - throw 'shucks'; - }, - builder: (context, child, callback, buttonState) { - final buttonColor = buttonState.when( - idle: () => Colors.yellow[200], - loading: () => Colors.grey, - success: () => Colors.orangeAccent, - error: () => Colors.orange, - ); - - return OutlinedButton( - child: child, - onPressed: callback, - style: OutlinedButton.styleFrom( - primary: Colors.black, - backgroundColor: buttonColor, - ), - ); - }, -), -``` - -

- -

- -You can also drive the state of the button yourself using the `buttonState` field: - -```dart -AsyncButtonBuilder( - buttonState: ButtonState.completing(), - // ... -), -``` - -`async_button_builder` even works for custom buttons. You can define your own widgets for loading, error, and completion as well as define the transitions between them. This example is a little verbose but shows some of what's possible. - - -```dart -AsyncButtonBuilder( - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 16.0, - vertical: 8.0, - ), - child: Text( - 'Click Me', - style: TextStyle(color: Colors.white), - ), - ), - loadingWidget: Padding( - padding: const EdgeInsets.all(8.0), - child: SizedBox( - height: 16.0, - width: 16.0, - child: CircularProgressIndicator( - valueColor: AlwaysStoppedAnimation(Colors.white), - ), - ), - ), - successWidget: Padding( - padding: const EdgeInsets.all(4.0), - child: Icon( - Icons.check, - color: Colors.purpleAccent, - ), - ), - onPressed: () async { - await Future.delayed(Duration(seconds: 2)); - }, - loadingSwitchInCurve: Curves.bounceInOut, - loadingTransitionBuilder: (child, animation) { - return SlideTransition( - position: Tween( - begin: Offset(0, 1.0), - end: Offset(0, 0), - ).animate(animation), - child: child, - ); - }, - builder: (context, child, callback, state) { - return Material( - color: state.maybeWhen( - success: () => Colors.purple[100], - orElse: () => Colors.blue, - ), - // This prevents the loading indicator showing below the - // button - clipBehavior: Clip.hardEdge, - shape: StadiumBorder(), - child: InkWell( - child: child, - onTap: callback, - ), - ); - }, -), -``` - -

- -

- -Issues and PR's welcome \ No newline at end of file +### [async_button_hook](https://github.com/Nolence/async_button/tree/main/packages/async_button_hook) 🏗️ \ No newline at end of file diff --git a/packages/async_button_builder/README.md b/packages/async_button_builder/README.md index fe84005..1cad3f2 100644 --- a/packages/async_button_builder/README.md +++ b/packages/async_button_builder/README.md @@ -1 +1,149 @@ -../../README.md \ No newline at end of file +# async_button + +[![melos](https://img.shields.io/badge/maintained%20with-melos-f700ff.svg?style=flat-square)](https://github.com/invertase/melos) + +AsyncButton offers a simple way to extend any type of button with an asynchronous aspect. It comes in two flavors that are independent (so no additional dependencies) of `builder` or `hook` pattern. Note, the hook version does rely on `flutter_hooks` for use. Either method allows adding loading, disabled, errored and completed states (with fluid animation between each) on top of buttons that perform asynchronous tasks. + +## Getting Started + +Include the package: + +```yaml + async_button_builder: +``` + +Wrap the builder around a button, passing the onPressed and child element to builder instead of the button directly. These two are the only required fields. + +```dart +AsyncButtonBuilder( + child: Text('Click Me'), + onPressed: () async { + await Future.delayed(Duration(seconds: 1)); + }, + builder: (context, child, callback, _) { + return TextButton( + child: child, + onPressed: callback, + ); + }, +), +``` + +

+ +

+ +The fourth value in the builder allows you listen to the loading state. This can be used to conditionally style the button. This package depends `freezed` in order to create a sealed union to better handle the possible states. + +```dart +AsyncButtonBuilder( + child: Text('Click Me'), + loadingWidget: Text('Loading...'), + onPressed: () async { + await Future.delayed(Duration(seconds: 1)); + + // See the examples file for a way to handle timeouts + throw 'shucks'; + }, + builder: (context, child, callback, buttonState) { + final buttonColor = buttonState.when( + idle: () => Colors.yellow[200], + loading: () => Colors.grey, + success: () => Colors.orangeAccent, + error: () => Colors.orange, + ); + + return OutlinedButton( + child: child, + onPressed: callback, + style: OutlinedButton.styleFrom( + primary: Colors.black, + backgroundColor: buttonColor, + ), + ); + }, +), +``` + +

+ +

+ +You can also drive the state of the button yourself using the `buttonState` field: + +```dart +AsyncButtonBuilder( + buttonState: ButtonState.completing(), + // ... +), +``` + +`async_button_builder` even works for custom buttons. You can define your own widgets for loading, error, and completion as well as define the transitions between them. This example is a little verbose but shows some of what's possible. + + +```dart +AsyncButtonBuilder( + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16.0, + vertical: 8.0, + ), + child: Text( + 'Click Me', + style: TextStyle(color: Colors.white), + ), + ), + loadingWidget: Padding( + padding: const EdgeInsets.all(8.0), + child: SizedBox( + height: 16.0, + width: 16.0, + child: CircularProgressIndicator( + valueColor: AlwaysStoppedAnimation(Colors.white), + ), + ), + ), + successWidget: Padding( + padding: const EdgeInsets.all(4.0), + child: Icon( + Icons.check, + color: Colors.purpleAccent, + ), + ), + onPressed: () async { + await Future.delayed(Duration(seconds: 2)); + }, + loadingSwitchInCurve: Curves.bounceInOut, + loadingTransitionBuilder: (child, animation) { + return SlideTransition( + position: Tween( + begin: Offset(0, 1.0), + end: Offset(0, 0), + ).animate(animation), + child: child, + ); + }, + builder: (context, child, callback, state) { + return Material( + color: state.maybeWhen( + success: () => Colors.purple[100], + orElse: () => Colors.blue, + ), + // This prevents the loading indicator showing below the + // button + clipBehavior: Clip.hardEdge, + shape: StadiumBorder(), + child: InkWell( + child: child, + onTap: callback, + ), + ); + }, +), +``` + +

+ +

+ +Issues and PR's welcome \ No newline at end of file diff --git a/packages/async_button_hook/README.md b/packages/async_button_hook/README.md index fe84005..0de041c 100644 --- a/packages/async_button_hook/README.md +++ b/packages/async_button_hook/README.md @@ -1 +1,146 @@ -../../README.md \ No newline at end of file +# async_button + +[![melos](https://img.shields.io/badge/maintained%20with-melos-f700ff.svg?style=flat-square)](https://github.com/invertase/melos) + +AsyncButton offers a simple way to extend any type of button with an asynchronous aspect. It comes in two flavors that are independent (so no additional dependencies) of `builder` or `hook` pattern. Note, the hook version does rely on `flutter_hooks` for use. Either method allows adding loading, disabled, errored and completed states (with fluid animation between each) on top of buttons that perform asynchronous tasks. + +## Getting Started + +Include the package: + +```yaml + async_button_hook: +``` + +To add a layer of async capabilities to your buttons, inside a `HookWidget` call `useAsyncButton` with its necessary fields. + +```dart +final asyncButton = useAsyncButton( + child: const Text('Click Me'), + onPressed: () async { + await Future.delayed(const Duration(seconds: 1)); + }, +); + +TextButton( + child: asyncButton.child, + onPressed: asyncButton.callback, +), +``` + +

+ +

+ +The value returned from `useAsyncButton` includes all the values necessary to switch the appearance of your buttons. The field `buttonState` on the value will show you the current state. This can be used to conditionally style the button. This package depends `freezed` in order to create a sealed union to better handle the possible states. + +```dart +final asyncButton = useAsyncButton( + child: const Text('Click Me'), + loadingWidget: const Text('Loading...'), + onPressed: () async { + await Future.delayed(Duration(seconds: 1)); + + // See the examples file for a way to handle timeouts + throw 'shucks'; + }, +); + +final buttonColor = asyncButton.buttonState.when( + idle: () => Colors.yellow[200], + loading: () => Colors.grey, + success: () => Colors.orangeAccent, + error: () => Colors.orange, +); + +return OutlinedButton( + child: asyncButton.child, + onPressed: asyncButton.callback, + style: OutlinedButton.styleFrom( + primary: Colors.black, + backgroundColor: buttonColor, + ), +) +``` + +

+ +

+ +You can also drive the state of the button yourself using the `buttonState` field: + +```dart +final asyncButton = useAsyncButton( + buttonState: ButtonState.completing(), + // ... +); +``` + +`async_button_hook` even works for custom buttons. You can define your own widgets for loading, error, and completion as well as define the transitions between them. This example is a little verbose but shows some of what's possible. + + +```dart +final asyncButton = useAsyncButton( + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16.0, + vertical: 8.0, + ), + child: Text( + 'Click Me', + style: TextStyle(color: Colors.white), + ), + ), + loadingWidget: Padding( + padding: const EdgeInsets.all(8.0), + child: SizedBox( + height: 16.0, + width: 16.0, + child: CircularProgressIndicator( + valueColor: AlwaysStoppedAnimation(Colors.white), + ), + ), + ), + successWidget: Padding( + padding: const EdgeInsets.all(4.0), + child: Icon( + Icons.check, + color: Colors.purpleAccent, + ), + ), + onPressed: () async { + await Future.delayed(Duration(seconds: 2)); + }, + loadingSwitchInCurve: Curves.bounceInOut, + loadingTransitionBuilder: (child, animation) { + return SlideTransition( + position: Tween( + begin: Offset(0, 1.0), + end: Offset(0, 0), + ).animate(animation), + child: child, + ); + }, +); + +return Material( + color: state.maybeWhen( + success: () => Colors.purple[100], + orElse: () => Colors.blue, + ), + // This prevents the loading indicator showing below the + // button + clipBehavior: Clip.hardEdge, + shape: StadiumBorder(), + child: InkWell( + child: asyncButton.child, + onTap: asyncButton.callback, + ), +); +``` + +

+ +

+ +Issues and PR's welcome \ No newline at end of file diff --git a/packages/async_button_hook/example/lib/main.dart b/packages/async_button_hook/example/lib/main.dart index 4172d11..985908b 100644 --- a/packages/async_button_hook/example/lib/main.dart +++ b/packages/async_button_hook/example/lib/main.dart @@ -22,19 +22,19 @@ class MyHomePage extends HookWidget { @override Widget build(BuildContext context) { - final textButtonResult = useAsyncButton( + final textAsyncButton = useAsyncButton( child: const Text('Click Me'), onPressed: () async { await Future.delayed(const Duration(seconds: 1)); }, ); - final elevatedButtonResult = useAsyncButton( + final elevatedAsyncButton = useAsyncButton( child: const Text('Click Me'), onPressed: () async { await Future.delayed(const Duration(seconds: 1)); }, ); - final customButtonResult = useAsyncButton( + final customAsyncButton = useAsyncButton( child: const Text('Click Me'), loadingWidget: const Text('Loading...'), onPressed: () async { @@ -59,7 +59,7 @@ class MyHomePage extends HookWidget { // state }, ); - final buttonColor = customButtonResult.buttonState.when( + final buttonColor = customAsyncButton.buttonState.when( idle: () => Colors.yellow[200], loading: () => Colors.grey, success: () => Colors.orangeAccent, @@ -76,20 +76,20 @@ class MyHomePage extends HookWidget { const Divider(), const Text('Text Button:'), TextButton( - child: textButtonResult.child, - onPressed: textButtonResult.callback, + child: textAsyncButton.child, + onPressed: textAsyncButton.callback, ), const Divider(), const Text('Elevated Button:'), ElevatedButton( - child: elevatedButtonResult.child, - onPressed: elevatedButtonResult.callback, + child: elevatedAsyncButton.child, + onPressed: elevatedAsyncButton.callback, ), const Divider(), const Text('Custom Outlined Button (Error):'), OutlinedButton( - child: customButtonResult.child, - onPressed: customButtonResult.callback, + child: customAsyncButton.child, + onPressed: customAsyncButton.callback, style: OutlinedButton.styleFrom( primary: Colors.black, backgroundColor: buttonColor, @@ -100,7 +100,7 @@ class MyHomePage extends HookWidget { const SizedBox(height: 6.0), HookBuilder( builder: (context) { - final customButtonResult = useAsyncButton( + final customAsyncButton = useAsyncButton( loadingSwitchInCurve: Curves.bounceInOut, loadingTransitionBuilder: (child, animation) { return SlideTransition( @@ -144,7 +144,7 @@ class MyHomePage extends HookWidget { ); return Material( - color: customButtonResult.buttonState.maybeWhen( + color: customAsyncButton.buttonState.maybeWhen( success: () => Colors.purple[100], orElse: () => Colors.blue, ), @@ -153,8 +153,8 @@ class MyHomePage extends HookWidget { clipBehavior: Clip.hardEdge, shape: const StadiumBorder(), child: InkWell( - child: customButtonResult.child, - onTap: customButtonResult.callback, + child: customAsyncButton.child, + onTap: customAsyncButton.callback, ), ); }, From 272b6a6227425036788eb0fbff721bfcfa2fba1f Mon Sep 17 00:00:00 2001 From: Nolence Date: Thu, 19 Aug 2021 09:51:15 -0600 Subject: [PATCH 052/176] Fixed weird dependency chain stuff --- packages/async_button_core/CHANGELOG.md | 4 ++++ packages/async_button_core/pubspec.yaml | 2 +- packages/async_button_hook/CHANGELOG.md | 6 +++++- packages/async_button_hook/example/pubspec.lock | 8 ++++---- packages/async_button_hook/lib/src/async_button_hook.dart | 1 - packages/async_button_hook/pubspec.lock | 8 ++++---- packages/async_button_hook/pubspec.yaml | 2 +- 7 files changed, 19 insertions(+), 12 deletions(-) diff --git a/packages/async_button_core/CHANGELOG.md b/packages/async_button_core/CHANGELOG.md index 7ac4fa5..700b7fb 100644 --- a/packages/async_button_core/CHANGELOG.md +++ b/packages/async_button_core/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.1+1 - 2021-08-19 + +Updated exports to include types + ## 0.0.1 - 2021-08-18 Initial release diff --git a/packages/async_button_core/pubspec.yaml b/packages/async_button_core/pubspec.yaml index b3fd97f..45af5ac 100644 --- a/packages/async_button_core/pubspec.yaml +++ b/packages/async_button_core/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_core description: A new Flutter package project. -version: 0.0.1 +version: 0.0.1+1 homepage: https://github.com/Nolence/async_button/packages/async_button_core environment: diff --git a/packages/async_button_hook/CHANGELOG.md b/packages/async_button_hook/CHANGELOG.md index 41cc7d8..3c2846d 100644 --- a/packages/async_button_hook/CHANGELOG.md +++ b/packages/async_button_hook/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.1+1 + +* Added better docs + ## 0.0.1 -* TODO: Describe initial release. +* Initial release diff --git a/packages/async_button_hook/example/pubspec.lock b/packages/async_button_hook/example/pubspec.lock index d5c4102..df5aa0c 100644 --- a/packages/async_button_hook/example/pubspec.lock +++ b/packages/async_button_hook/example/pubspec.lock @@ -11,9 +11,9 @@ packages: async_button_core: dependency: transitive description: - path: "../../async_button_core" - relative: true - source: path + name: async_button_core + url: "https://pub.dartlang.org" + source: hosted version: "0.0.1" async_button_hook: dependency: "direct main" @@ -21,7 +21,7 @@ packages: path: ".." relative: true source: path - version: "0.0.1" + version: "0.0.1+1" boolean_selector: dependency: transitive description: diff --git a/packages/async_button_hook/lib/src/async_button_hook.dart b/packages/async_button_hook/lib/src/async_button_hook.dart index f26df7c..68defc7 100644 --- a/packages/async_button_hook/lib/src/async_button_hook.dart +++ b/packages/async_button_hook/lib/src/async_button_hook.dart @@ -1,6 +1,5 @@ import 'dart:async'; -import 'package:async_button_core/async_button_core.dart'; import 'package:async_button_hook/src/models/async_button_result.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; diff --git a/packages/async_button_hook/pubspec.lock b/packages/async_button_hook/pubspec.lock index 4ae4704..168375c 100644 --- a/packages/async_button_hook/pubspec.lock +++ b/packages/async_button_hook/pubspec.lock @@ -11,10 +11,10 @@ packages: async_button_core: dependency: "direct main" description: - path: "../async_button_core" - relative: true - source: path - version: "0.0.1" + name: async_button_core + url: "https://pub.dartlang.org" + source: hosted + version: "0.0.1+1" boolean_selector: dependency: transitive description: diff --git a/packages/async_button_hook/pubspec.yaml b/packages/async_button_hook/pubspec.yaml index 89fa430..3fbf5de 100644 --- a/packages/async_button_hook/pubspec.yaml +++ b/packages/async_button_hook/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_hook description: A hook version of async_button_builder which depends on flutter_hooks -version: 0.0.1 +version: 0.0.1+1 homepage: https://github.com/Nolence/async_button/packages/async_button_hook environment: From 648bb823927fd42beb56907d30f37e75d7eb763f Mon Sep 17 00:00:00 2001 From: Nolence Date: Thu, 19 Aug 2021 09:51:48 -0600 Subject: [PATCH 053/176] bump version --- packages/async_button_hook/example/pubspec.lock | 2 +- packages/async_button_hook/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/async_button_hook/example/pubspec.lock b/packages/async_button_hook/example/pubspec.lock index df5aa0c..6126933 100644 --- a/packages/async_button_hook/example/pubspec.lock +++ b/packages/async_button_hook/example/pubspec.lock @@ -14,7 +14,7 @@ packages: name: async_button_core url: "https://pub.dartlang.org" source: hosted - version: "0.0.1" + version: "0.0.1+1" async_button_hook: dependency: "direct main" description: diff --git a/packages/async_button_hook/pubspec.yaml b/packages/async_button_hook/pubspec.yaml index 3fbf5de..af7258b 100644 --- a/packages/async_button_hook/pubspec.yaml +++ b/packages/async_button_hook/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: flutter: sdk: flutter flutter_hooks: ^0.18.0 - async_button_core: ^0.0.1 + async_button_core: ^0.0.1+1 dev_dependencies: flutter_lints: ^1.0.0 From 1c1c45264df51d8a34e7008595b9396dd981db1b Mon Sep 17 00:00:00 2001 From: Nolence Date: Thu, 19 Aug 2021 09:53:08 -0600 Subject: [PATCH 054/176] Fix export types in button builder --- packages/async_button_builder/CHANGELOG.md | 3 +++ packages/async_button_builder/example/pubspec.lock | 10 +++++----- .../async_button_builder/lib/async_button_builder.dart | 1 + packages/async_button_builder/pubspec.lock | 8 ++++---- packages/async_button_builder/pubspec.yaml | 4 ++-- 5 files changed, 15 insertions(+), 11 deletions(-) diff --git a/packages/async_button_builder/CHANGELOG.md b/packages/async_button_builder/CHANGELOG.md index 975d4ea..4dd692a 100644 --- a/packages/async_button_builder/CHANGELOG.md +++ b/packages/async_button_builder/CHANGELOG.md @@ -1,3 +1,6 @@ +## [2.1.3+3] - 2021-08-12 +Have proper types exported + ## [2.1.3+2] - 2021-08-12 Fix possibility of nested async button builders conflicting with each other due to matching keyed subtrees. In order to avoid this situation, the parent key of the async_button_builder is used in the creation of sub widgets. diff --git a/packages/async_button_builder/example/pubspec.lock b/packages/async_button_builder/example/pubspec.lock index ac9d930..345c950 100644 --- a/packages/async_button_builder/example/pubspec.lock +++ b/packages/async_button_builder/example/pubspec.lock @@ -14,14 +14,14 @@ packages: path: ".." relative: true source: path - version: "2.1.3+2" + version: "2.1.3+3" async_button_core: dependency: transitive description: - path: "../../async_button_core" - relative: true - source: path - version: "0.0.1" + name: async_button_core + url: "https://pub.dartlang.org" + source: hosted + version: "0.0.1+1" boolean_selector: dependency: transitive description: diff --git a/packages/async_button_builder/lib/async_button_builder.dart b/packages/async_button_builder/lib/async_button_builder.dart index c7a5813..58eb8e1 100644 --- a/packages/async_button_builder/lib/async_button_builder.dart +++ b/packages/async_button_builder/lib/async_button_builder.dart @@ -1,3 +1,4 @@ library async_button_builder; export 'package:async_button_builder/src/async_button_builder.dart'; +export 'package:async_button_core/async_button_core.dart'; diff --git a/packages/async_button_builder/pubspec.lock b/packages/async_button_builder/pubspec.lock index d758aff..a61173e 100644 --- a/packages/async_button_builder/pubspec.lock +++ b/packages/async_button_builder/pubspec.lock @@ -32,10 +32,10 @@ packages: async_button_core: dependency: "direct main" description: - path: "../async_button_core" - relative: true - source: path - version: "0.0.1" + name: async_button_core + url: "https://pub.dartlang.org" + source: hosted + version: "0.0.1+1" boolean_selector: dependency: transitive description: diff --git a/packages/async_button_builder/pubspec.yaml b/packages/async_button_builder/pubspec.yaml index 484967f..575ceea 100644 --- a/packages/async_button_builder/pubspec.yaml +++ b/packages/async_button_builder/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_builder description: A builder to wrap around buttons that handles loading, disabled, error and succes states -version: 2.1.3+2 +version: 2.1.3+3 homepage: https://github.com/Nolence/async_button/packages/async_button_builder environment: @@ -11,7 +11,7 @@ dependencies: flutter: sdk: flutter freezed_annotation: ^0.14.2 - async_button_core: ^0.0.1 + async_button_core: ^0.0.1+1 dev_dependencies: flutter_test: From f19e92417435de0592080c5a9951f7cb7145f0bf Mon Sep 17 00:00:00 2001 From: Nolence Date: Thu, 19 Aug 2021 09:55:10 -0600 Subject: [PATCH 055/176] Fix imports again --- packages/async_button_hook/CHANGELOG.md | 4 ++++ packages/async_button_hook/example/pubspec.lock | 2 +- packages/async_button_hook/lib/src/async_button_hook.dart | 1 + packages/async_button_hook/pubspec.yaml | 2 +- 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/async_button_hook/CHANGELOG.md b/packages/async_button_hook/CHANGELOG.md index 3c2846d..f7ffd79 100644 --- a/packages/async_button_hook/CHANGELOG.md +++ b/packages/async_button_hook/CHANGELOG.md @@ -1,5 +1,9 @@ ## 0.0.1+1 +* Fixed imports again + +## 0.0.1+1 + * Added better docs ## 0.0.1 diff --git a/packages/async_button_hook/example/pubspec.lock b/packages/async_button_hook/example/pubspec.lock index 6126933..ef8dbf0 100644 --- a/packages/async_button_hook/example/pubspec.lock +++ b/packages/async_button_hook/example/pubspec.lock @@ -21,7 +21,7 @@ packages: path: ".." relative: true source: path - version: "0.0.1+1" + version: "0.0.1+2" boolean_selector: dependency: transitive description: diff --git a/packages/async_button_hook/lib/src/async_button_hook.dart b/packages/async_button_hook/lib/src/async_button_hook.dart index 68defc7..f26df7c 100644 --- a/packages/async_button_hook/lib/src/async_button_hook.dart +++ b/packages/async_button_hook/lib/src/async_button_hook.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:async_button_core/async_button_core.dart'; import 'package:async_button_hook/src/models/async_button_result.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; diff --git a/packages/async_button_hook/pubspec.yaml b/packages/async_button_hook/pubspec.yaml index af7258b..ef7d26e 100644 --- a/packages/async_button_hook/pubspec.yaml +++ b/packages/async_button_hook/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_hook description: A hook version of async_button_builder which depends on flutter_hooks -version: 0.0.1+1 +version: 0.0.1+2 homepage: https://github.com/Nolence/async_button/packages/async_button_hook environment: From 86dce8606fd5534ee65cb9462ab8608ae8e2d764 Mon Sep 17 00:00:00 2001 From: Nolence Date: Fri, 27 Aug 2021 08:59:26 -0600 Subject: [PATCH 056/176] Fix home pages --- packages/async_button_builder/CHANGELOG.md | 3 +++ packages/async_button_builder/README.md | 4 +--- packages/async_button_builder/example/pubspec.lock | 2 +- packages/async_button_builder/pubspec.yaml | 4 ++-- packages/async_button_core/CHANGELOG.md | 5 +++-- packages/async_button_core/pubspec.yaml | 4 ++-- packages/async_button_hook/CHANGELOG.md | 14 ++++++++------ packages/async_button_hook/README.md | 6 +----- packages/async_button_hook/example/pubspec.lock | 2 +- packages/async_button_hook/pubspec.yaml | 4 ++-- 10 files changed, 24 insertions(+), 24 deletions(-) diff --git a/packages/async_button_builder/CHANGELOG.md b/packages/async_button_builder/CHANGELOG.md index 4dd692a..be5bdc5 100644 --- a/packages/async_button_builder/CHANGELOG.md +++ b/packages/async_button_builder/CHANGELOG.md @@ -1,3 +1,6 @@ +## [2.1.3+4] - 2021-08-27 +Fix home page + ## [2.1.3+3] - 2021-08-12 Have proper types exported diff --git a/packages/async_button_builder/README.md b/packages/async_button_builder/README.md index 1cad3f2..060b2d2 100644 --- a/packages/async_button_builder/README.md +++ b/packages/async_button_builder/README.md @@ -1,9 +1,7 @@ -# async_button +# async_button_builder [![melos](https://img.shields.io/badge/maintained%20with-melos-f700ff.svg?style=flat-square)](https://github.com/invertase/melos) -AsyncButton offers a simple way to extend any type of button with an asynchronous aspect. It comes in two flavors that are independent (so no additional dependencies) of `builder` or `hook` pattern. Note, the hook version does rely on `flutter_hooks` for use. Either method allows adding loading, disabled, errored and completed states (with fluid animation between each) on top of buttons that perform asynchronous tasks. - ## Getting Started Include the package: diff --git a/packages/async_button_builder/example/pubspec.lock b/packages/async_button_builder/example/pubspec.lock index 345c950..963c827 100644 --- a/packages/async_button_builder/example/pubspec.lock +++ b/packages/async_button_builder/example/pubspec.lock @@ -14,7 +14,7 @@ packages: path: ".." relative: true source: path - version: "2.1.3+3" + version: "2.1.3+4" async_button_core: dependency: transitive description: diff --git a/packages/async_button_builder/pubspec.yaml b/packages/async_button_builder/pubspec.yaml index 575ceea..ad362ee 100644 --- a/packages/async_button_builder/pubspec.yaml +++ b/packages/async_button_builder/pubspec.yaml @@ -1,7 +1,7 @@ name: async_button_builder description: A builder to wrap around buttons that handles loading, disabled, error and succes states -version: 2.1.3+3 -homepage: https://github.com/Nolence/async_button/packages/async_button_builder +version: 2.1.3+4 +homepage: https://github.com/Nolence/async_button/tree/main/packages/async_button_builder environment: sdk: '>=2.12.0 <3.0.0' diff --git a/packages/async_button_core/CHANGELOG.md b/packages/async_button_core/CHANGELOG.md index 700b7fb..8e89002 100644 --- a/packages/async_button_core/CHANGELOG.md +++ b/packages/async_button_core/CHANGELOG.md @@ -1,7 +1,8 @@ -## 0.0.1+1 - 2021-08-19 +## 0.0.1+2 - 2021-08-27 +Fixed home page +## 0.0.1+1 - 2021-08-19 Updated exports to include types ## 0.0.1 - 2021-08-18 - Initial release diff --git a/packages/async_button_core/pubspec.yaml b/packages/async_button_core/pubspec.yaml index 45af5ac..b00e204 100644 --- a/packages/async_button_core/pubspec.yaml +++ b/packages/async_button_core/pubspec.yaml @@ -1,7 +1,7 @@ name: async_button_core description: A new Flutter package project. -version: 0.0.1+1 -homepage: https://github.com/Nolence/async_button/packages/async_button_core +version: 0.0.1+2 +homepage: https://github.com/Nolence/async_button/tree/main/packages/async_button_core environment: sdk: ">=2.12.0 <3.0.0" diff --git a/packages/async_button_hook/CHANGELOG.md b/packages/async_button_hook/CHANGELOG.md index f7ffd79..e8f4b07 100644 --- a/packages/async_button_hook/CHANGELOG.md +++ b/packages/async_button_hook/CHANGELOG.md @@ -1,11 +1,13 @@ -## 0.0.1+1 +## 0.0.1+4 +Fixed home page -* Fixed imports again +## 0.0.1+3 -## 0.0.1+1 +## 0.0.1+2 +Fixed imports again -* Added better docs +## 0.0.1+1 +Added better docs ## 0.0.1 - -* Initial release +Initial release diff --git a/packages/async_button_hook/README.md b/packages/async_button_hook/README.md index 0de041c..b36bb26 100644 --- a/packages/async_button_hook/README.md +++ b/packages/async_button_hook/README.md @@ -1,11 +1,7 @@ -# async_button +# async_button_hook [![melos](https://img.shields.io/badge/maintained%20with-melos-f700ff.svg?style=flat-square)](https://github.com/invertase/melos) -AsyncButton offers a simple way to extend any type of button with an asynchronous aspect. It comes in two flavors that are independent (so no additional dependencies) of `builder` or `hook` pattern. Note, the hook version does rely on `flutter_hooks` for use. Either method allows adding loading, disabled, errored and completed states (with fluid animation between each) on top of buttons that perform asynchronous tasks. - -## Getting Started - Include the package: ```yaml diff --git a/packages/async_button_hook/example/pubspec.lock b/packages/async_button_hook/example/pubspec.lock index ef8dbf0..a1b1c54 100644 --- a/packages/async_button_hook/example/pubspec.lock +++ b/packages/async_button_hook/example/pubspec.lock @@ -21,7 +21,7 @@ packages: path: ".." relative: true source: path - version: "0.0.1+2" + version: "0.0.1+3" boolean_selector: dependency: transitive description: diff --git a/packages/async_button_hook/pubspec.yaml b/packages/async_button_hook/pubspec.yaml index ef7d26e..34cd3d5 100644 --- a/packages/async_button_hook/pubspec.yaml +++ b/packages/async_button_hook/pubspec.yaml @@ -1,7 +1,7 @@ name: async_button_hook description: A hook version of async_button_builder which depends on flutter_hooks -version: 0.0.1+2 -homepage: https://github.com/Nolence/async_button/packages/async_button_hook +version: 0.0.1+3 +homepage: https://github.com/Nolence/async_button/tree/main/packages/async_button_hook environment: sdk: ">=2.12.0 <3.0.0" From 51f3c0a5acaae32cacf5dc4bad048e23712388a6 Mon Sep 17 00:00:00 2001 From: Nolence Date: Fri, 27 Aug 2021 09:03:30 -0600 Subject: [PATCH 057/176] coverage files --- packages/async_button_builder/example/pubspec.lock | 8 ++++---- packages/async_button_builder/pubspec.lock | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/async_button_builder/example/pubspec.lock b/packages/async_button_builder/example/pubspec.lock index 963c827..d2b623e 100644 --- a/packages/async_button_builder/example/pubspec.lock +++ b/packages/async_button_builder/example/pubspec.lock @@ -18,10 +18,10 @@ packages: async_button_core: dependency: transitive description: - name: async_button_core - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.1+1" + path: "../../async_button_core" + relative: true + source: path + version: "0.0.1+2" boolean_selector: dependency: transitive description: diff --git a/packages/async_button_builder/pubspec.lock b/packages/async_button_builder/pubspec.lock index a61173e..82e9ad9 100644 --- a/packages/async_button_builder/pubspec.lock +++ b/packages/async_button_builder/pubspec.lock @@ -32,10 +32,10 @@ packages: async_button_core: dependency: "direct main" description: - name: async_button_core - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.1+1" + path: "../async_button_core" + relative: true + source: path + version: "0.0.1+2" boolean_selector: dependency: transitive description: From c47693b2336b4a98629f37394f404aad79d8b470 Mon Sep 17 00:00:00 2001 From: Nolence Date: Fri, 27 Aug 2021 09:03:41 -0600 Subject: [PATCH 058/176] coverage files --- packages/async_button_core/coverage/lcov.info | 0 packages/async_button_hook/example/pubspec.lock | 8 ++++---- packages/async_button_hook/pubspec.lock | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) create mode 100644 packages/async_button_core/coverage/lcov.info diff --git a/packages/async_button_core/coverage/lcov.info b/packages/async_button_core/coverage/lcov.info new file mode 100644 index 0000000..e69de29 diff --git a/packages/async_button_hook/example/pubspec.lock b/packages/async_button_hook/example/pubspec.lock index a1b1c54..a8a2fbf 100644 --- a/packages/async_button_hook/example/pubspec.lock +++ b/packages/async_button_hook/example/pubspec.lock @@ -11,10 +11,10 @@ packages: async_button_core: dependency: transitive description: - name: async_button_core - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.1+1" + path: "../../async_button_core" + relative: true + source: path + version: "0.0.1+2" async_button_hook: dependency: "direct main" description: diff --git a/packages/async_button_hook/pubspec.lock b/packages/async_button_hook/pubspec.lock index 168375c..a8fa2e2 100644 --- a/packages/async_button_hook/pubspec.lock +++ b/packages/async_button_hook/pubspec.lock @@ -11,10 +11,10 @@ packages: async_button_core: dependency: "direct main" description: - name: async_button_core - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.1+1" + path: "../async_button_core" + relative: true + source: path + version: "0.0.1+2" boolean_selector: dependency: transitive description: From 295200db52284b6cd671d5953f6eb27d470600dc Mon Sep 17 00:00:00 2001 From: Nolence Date: Fri, 27 Aug 2021 19:55:16 -0600 Subject: [PATCH 059/176] Trying to fix pub stuff --- packages/async_button_core/CHANGELOG.md | 3 +++ packages/async_button_core/pubspec.yaml | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/async_button_core/CHANGELOG.md b/packages/async_button_core/CHANGELOG.md index 8e89002..10ae3f9 100644 --- a/packages/async_button_core/CHANGELOG.md +++ b/packages/async_button_core/CHANGELOG.md @@ -1,3 +1,6 @@ +## 0.0.1+3 - 2021-08-27 +Trying to fix pub stuff + ## 0.0.1+2 - 2021-08-27 Fixed home page diff --git a/packages/async_button_core/pubspec.yaml b/packages/async_button_core/pubspec.yaml index b00e204..59ab107 100644 --- a/packages/async_button_core/pubspec.yaml +++ b/packages/async_button_core/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_core description: A new Flutter package project. -version: 0.0.1+2 +version: 0.0.1+3 homepage: https://github.com/Nolence/async_button/tree/main/packages/async_button_core environment: From 143882c006eb1fbb5cf6478f94fc67a027677455 Mon Sep 17 00:00:00 2001 From: Nolence Date: Fri, 27 Aug 2021 19:56:56 -0600 Subject: [PATCH 060/176] Trying to fix pub stuff --- packages/async_button_builder/CHANGELOG.md | 3 +++ .../example/ios/Flutter/AppFrameworkInfo.plist | 2 +- packages/async_button_builder/example/pubspec.lock | 8 ++++---- packages/async_button_builder/pubspec.lock | 6 +++--- packages/async_button_builder/pubspec.yaml | 6 +++--- packages/async_button_hook/CHANGELOG.md | 3 +++ packages/async_button_hook/example/pubspec.lock | 8 ++++---- packages/async_button_hook/pubspec.lock | 6 +++--- packages/async_button_hook/pubspec.yaml | 4 ++-- 9 files changed, 26 insertions(+), 20 deletions(-) diff --git a/packages/async_button_builder/CHANGELOG.md b/packages/async_button_builder/CHANGELOG.md index be5bdc5..e31e209 100644 --- a/packages/async_button_builder/CHANGELOG.md +++ b/packages/async_button_builder/CHANGELOG.md @@ -1,3 +1,6 @@ +## [2.1.3+5] - 2021-08-27 +Trying to fix pub stuff + ## [2.1.3+4] - 2021-08-27 Fix home page diff --git a/packages/async_button_builder/example/ios/Flutter/AppFrameworkInfo.plist b/packages/async_button_builder/example/ios/Flutter/AppFrameworkInfo.plist index 9367d48..8d4492f 100644 --- a/packages/async_button_builder/example/ios/Flutter/AppFrameworkInfo.plist +++ b/packages/async_button_builder/example/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 8.0 + 9.0 diff --git a/packages/async_button_builder/example/pubspec.lock b/packages/async_button_builder/example/pubspec.lock index d2b623e..811f7df 100644 --- a/packages/async_button_builder/example/pubspec.lock +++ b/packages/async_button_builder/example/pubspec.lock @@ -14,13 +14,13 @@ packages: path: ".." relative: true source: path - version: "2.1.3+4" + version: "2.1.3+5" async_button_core: dependency: transitive description: - path: "../../async_button_core" - relative: true - source: path + name: async_button_core + url: "https://pub.dartlang.org" + source: hosted version: "0.0.1+2" boolean_selector: dependency: transitive diff --git a/packages/async_button_builder/pubspec.lock b/packages/async_button_builder/pubspec.lock index 82e9ad9..5484345 100644 --- a/packages/async_button_builder/pubspec.lock +++ b/packages/async_button_builder/pubspec.lock @@ -32,9 +32,9 @@ packages: async_button_core: dependency: "direct main" description: - path: "../async_button_core" - relative: true - source: path + name: async_button_core + url: "https://pub.dartlang.org" + source: hosted version: "0.0.1+2" boolean_selector: dependency: transitive diff --git a/packages/async_button_builder/pubspec.yaml b/packages/async_button_builder/pubspec.yaml index ad362ee..3281c13 100644 --- a/packages/async_button_builder/pubspec.yaml +++ b/packages/async_button_builder/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_builder description: A builder to wrap around buttons that handles loading, disabled, error and succes states -version: 2.1.3+4 +version: 2.1.3+5 homepage: https://github.com/Nolence/async_button/tree/main/packages/async_button_builder environment: @@ -11,13 +11,13 @@ dependencies: flutter: sdk: flutter freezed_annotation: ^0.14.2 - async_button_core: ^0.0.1+1 + async_button_core: ^0.0.1+2 dev_dependencies: flutter_test: sdk: flutter build_runner: ^2.0.3 freezed: ^0.14.2 - flutter_lints: + flutter_lints: ^1.0.0 flutter: \ No newline at end of file diff --git a/packages/async_button_hook/CHANGELOG.md b/packages/async_button_hook/CHANGELOG.md index e8f4b07..566f9ab 100644 --- a/packages/async_button_hook/CHANGELOG.md +++ b/packages/async_button_hook/CHANGELOG.md @@ -1,3 +1,6 @@ +## 0.0.1+4 - 2021-08-27 +Trying to fix pub stuff + ## 0.0.1+4 Fixed home page diff --git a/packages/async_button_hook/example/pubspec.lock b/packages/async_button_hook/example/pubspec.lock index a8a2fbf..98945b9 100644 --- a/packages/async_button_hook/example/pubspec.lock +++ b/packages/async_button_hook/example/pubspec.lock @@ -11,9 +11,9 @@ packages: async_button_core: dependency: transitive description: - path: "../../async_button_core" - relative: true - source: path + name: async_button_core + url: "https://pub.dartlang.org" + source: hosted version: "0.0.1+2" async_button_hook: dependency: "direct main" @@ -21,7 +21,7 @@ packages: path: ".." relative: true source: path - version: "0.0.1+3" + version: "0.0.1+4" boolean_selector: dependency: transitive description: diff --git a/packages/async_button_hook/pubspec.lock b/packages/async_button_hook/pubspec.lock index a8fa2e2..4a86962 100644 --- a/packages/async_button_hook/pubspec.lock +++ b/packages/async_button_hook/pubspec.lock @@ -11,9 +11,9 @@ packages: async_button_core: dependency: "direct main" description: - path: "../async_button_core" - relative: true - source: path + name: async_button_core + url: "https://pub.dartlang.org" + source: hosted version: "0.0.1+2" boolean_selector: dependency: transitive diff --git a/packages/async_button_hook/pubspec.yaml b/packages/async_button_hook/pubspec.yaml index 34cd3d5..93f3c5a 100644 --- a/packages/async_button_hook/pubspec.yaml +++ b/packages/async_button_hook/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_hook description: A hook version of async_button_builder which depends on flutter_hooks -version: 0.0.1+3 +version: 0.0.1+4 homepage: https://github.com/Nolence/async_button/tree/main/packages/async_button_hook environment: @@ -11,7 +11,7 @@ dependencies: flutter: sdk: flutter flutter_hooks: ^0.18.0 - async_button_core: ^0.0.1+1 + async_button_core: ^0.0.1+2 dev_dependencies: flutter_lints: ^1.0.0 From 5818e16c596fb1206c531874cdc5458baa3ec349 Mon Sep 17 00:00:00 2001 From: Nolence Date: Tue, 31 Aug 2021 19:57:01 -0600 Subject: [PATCH 061/176] Added useless example and updated description --- .../async_button_core/example/example.dart | 33 +++++++++++++++++++ packages/async_button_core/pubspec.yaml | 4 +-- packages/async_button_hook/pubspec.yaml | 2 +- 3 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 packages/async_button_core/example/example.dart diff --git a/packages/async_button_core/example/example.dart b/packages/async_button_core/example/example.dart new file mode 100644 index 0000000..1ebdbe1 --- /dev/null +++ b/packages/async_button_core/example/example.dart @@ -0,0 +1,33 @@ +import 'package:flutter/material.dart'; + +void main() { + runApp(const MyApp()); +} + +class MyApp extends StatefulWidget { + const MyApp({Key? key}) : super(key: key); + + @override + _MyAppState createState() => _MyAppState(); +} + +class _MyAppState extends State { + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return MaterialApp( + home: Scaffold( + appBar: AppBar( + title: const Text('Plugin example app'), + ), + body: const Center( + child: Text('A simple flutter example\n'), + ), + ), + ); + } +} diff --git a/packages/async_button_core/pubspec.yaml b/packages/async_button_core/pubspec.yaml index 59ab107..aca3c00 100644 --- a/packages/async_button_core/pubspec.yaml +++ b/packages/async_button_core/pubspec.yaml @@ -1,5 +1,5 @@ name: async_button_core -description: A new Flutter package project. +description: Contains the core models and docs for the packages async_button_hook and async_button_builder version: 0.0.1+3 homepage: https://github.com/Nolence/async_button/tree/main/packages/async_button_core @@ -17,4 +17,4 @@ dev_dependencies: flutter_test: sdk: flutter -flutter: null +flutter: diff --git a/packages/async_button_hook/pubspec.yaml b/packages/async_button_hook/pubspec.yaml index 93f3c5a..803a664 100644 --- a/packages/async_button_hook/pubspec.yaml +++ b/packages/async_button_hook/pubspec.yaml @@ -18,4 +18,4 @@ dev_dependencies: flutter_test: sdk: flutter -flutter: null +flutter: From a0ca514970768e68d5882ea1c824dca7f7a5c693 Mon Sep 17 00:00:00 2001 From: Nolence Date: Tue, 31 Aug 2021 20:04:58 -0600 Subject: [PATCH 062/176] Updated versions and changelogs --- packages/async_button_builder/CHANGELOG.md | 3 +++ packages/async_button_builder/example/pubspec.lock | 10 +++++----- packages/async_button_builder/pubspec.lock | 8 ++++---- packages/async_button_builder/pubspec.yaml | 2 +- packages/async_button_core/CHANGELOG.md | 3 +++ packages/async_button_core/pubspec.yaml | 2 +- packages/async_button_hook/CHANGELOG.md | 3 +++ packages/async_button_hook/example/pubspec.lock | 10 +++++----- packages/async_button_hook/pubspec.lock | 8 ++++---- packages/async_button_hook/pubspec.yaml | 2 +- 10 files changed, 30 insertions(+), 21 deletions(-) diff --git a/packages/async_button_builder/CHANGELOG.md b/packages/async_button_builder/CHANGELOG.md index e31e209..b8cd6a0 100644 --- a/packages/async_button_builder/CHANGELOG.md +++ b/packages/async_button_builder/CHANGELOG.md @@ -1,3 +1,6 @@ +## [2.1.3+6] - 2021-08-31 +Trying to fix pub stuff + ## [2.1.3+5] - 2021-08-27 Trying to fix pub stuff diff --git a/packages/async_button_builder/example/pubspec.lock b/packages/async_button_builder/example/pubspec.lock index 811f7df..d3c33a4 100644 --- a/packages/async_button_builder/example/pubspec.lock +++ b/packages/async_button_builder/example/pubspec.lock @@ -14,14 +14,14 @@ packages: path: ".." relative: true source: path - version: "2.1.3+5" + version: "2.1.3+6" async_button_core: dependency: transitive description: - name: async_button_core - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.1+2" + path: "../../async_button_core" + relative: true + source: path + version: "0.0.1+4" boolean_selector: dependency: transitive description: diff --git a/packages/async_button_builder/pubspec.lock b/packages/async_button_builder/pubspec.lock index 5484345..ffd275e 100644 --- a/packages/async_button_builder/pubspec.lock +++ b/packages/async_button_builder/pubspec.lock @@ -32,10 +32,10 @@ packages: async_button_core: dependency: "direct main" description: - name: async_button_core - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.1+2" + path: "../async_button_core" + relative: true + source: path + version: "0.0.1+4" boolean_selector: dependency: transitive description: diff --git a/packages/async_button_builder/pubspec.yaml b/packages/async_button_builder/pubspec.yaml index 3281c13..21055a4 100644 --- a/packages/async_button_builder/pubspec.yaml +++ b/packages/async_button_builder/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_builder description: A builder to wrap around buttons that handles loading, disabled, error and succes states -version: 2.1.3+5 +version: 2.1.3+6 homepage: https://github.com/Nolence/async_button/tree/main/packages/async_button_builder environment: diff --git a/packages/async_button_core/CHANGELOG.md b/packages/async_button_core/CHANGELOG.md index 10ae3f9..e5bfdb9 100644 --- a/packages/async_button_core/CHANGELOG.md +++ b/packages/async_button_core/CHANGELOG.md @@ -1,3 +1,6 @@ +## 0.0.1+4 - 2021-08-27 +Trying to fix pub stuff + ## 0.0.1+3 - 2021-08-27 Trying to fix pub stuff diff --git a/packages/async_button_core/pubspec.yaml b/packages/async_button_core/pubspec.yaml index aca3c00..2e2eefd 100644 --- a/packages/async_button_core/pubspec.yaml +++ b/packages/async_button_core/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_core description: Contains the core models and docs for the packages async_button_hook and async_button_builder -version: 0.0.1+3 +version: 0.0.1+4 homepage: https://github.com/Nolence/async_button/tree/main/packages/async_button_core environment: diff --git a/packages/async_button_hook/CHANGELOG.md b/packages/async_button_hook/CHANGELOG.md index 566f9ab..1723011 100644 --- a/packages/async_button_hook/CHANGELOG.md +++ b/packages/async_button_hook/CHANGELOG.md @@ -1,3 +1,6 @@ +## 0.0.1+5 - 2021-08-31 +Trying to fix pub stuff + ## 0.0.1+4 - 2021-08-27 Trying to fix pub stuff diff --git a/packages/async_button_hook/example/pubspec.lock b/packages/async_button_hook/example/pubspec.lock index 98945b9..fa11603 100644 --- a/packages/async_button_hook/example/pubspec.lock +++ b/packages/async_button_hook/example/pubspec.lock @@ -11,17 +11,17 @@ packages: async_button_core: dependency: transitive description: - name: async_button_core - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.1+2" + path: "../../async_button_core" + relative: true + source: path + version: "0.0.1+4" async_button_hook: dependency: "direct main" description: path: ".." relative: true source: path - version: "0.0.1+4" + version: "0.0.1+5" boolean_selector: dependency: transitive description: diff --git a/packages/async_button_hook/pubspec.lock b/packages/async_button_hook/pubspec.lock index 4a86962..1fe3bcb 100644 --- a/packages/async_button_hook/pubspec.lock +++ b/packages/async_button_hook/pubspec.lock @@ -11,10 +11,10 @@ packages: async_button_core: dependency: "direct main" description: - name: async_button_core - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.1+2" + path: "../async_button_core" + relative: true + source: path + version: "0.0.1+4" boolean_selector: dependency: transitive description: diff --git a/packages/async_button_hook/pubspec.yaml b/packages/async_button_hook/pubspec.yaml index 803a664..295a0eb 100644 --- a/packages/async_button_hook/pubspec.yaml +++ b/packages/async_button_hook/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_hook description: A hook version of async_button_builder which depends on flutter_hooks -version: 0.0.1+4 +version: 0.0.1+5 homepage: https://github.com/Nolence/async_button/tree/main/packages/async_button_hook environment: From 49e2c944412c694645ad1f94e5a342708a96b643 Mon Sep 17 00:00:00 2001 From: Nolence Date: Thu, 9 Sep 2021 10:42:32 -0600 Subject: [PATCH 063/176] Updating workflows --- .../.github => .github}/workflows/dart.yaml | 24 ++++++ .gitignore | 75 +++++++++++++++++++ analysis_options.yaml | 20 ++++- melos.yaml | 12 ++- .../async_button_builder/example/pubspec.lock | 10 +-- .../lib/src/async_button_builder.dart | 1 - packages/async_button_builder/pubspec.lock | 48 ++++++------ .../async_button_core/analysis_options.yaml | 4 - .../async_button_hook/example/pubspec.lock | 6 +- .../lib/src/async_button_hook.dart | 2 - packages/async_button_hook/pubspec.lock | 6 +- 11 files changed, 158 insertions(+), 50 deletions(-) rename {packages/async_button_builder/.github => .github}/workflows/dart.yaml (54%) create mode 100644 .gitignore delete mode 100644 packages/async_button_core/analysis_options.yaml diff --git a/packages/async_button_builder/.github/workflows/dart.yaml b/.github/workflows/dart.yaml similarity index 54% rename from packages/async_button_builder/.github/workflows/dart.yaml rename to .github/workflows/dart.yaml index 1c8d8da..08ff7ad 100644 --- a/packages/async_button_builder/.github/workflows/dart.yaml +++ b/.github/workflows/dart.yaml @@ -8,6 +8,30 @@ on: - cron: '0 10 * * *' jobs: + analyze: + timeout-minutes: 15 + runs-on: ubuntu-latest + steps: + - name: "Git Checkout" + uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: "Install Flutter" + uses: subosito/flutter-action@v1 + with: + flutter-version: "2.2.1" + - name: "Install Tools" + run: | + flutter pub global activate melos + - name: "Bootstrap Workspace" + run: melos bootstrap + - name: "Dart Analyze" + run: | + melos run analyze + - name: "Pub Check" + run: | + melos run lint:pub + flutter: runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a247422 --- /dev/null +++ b/.gitignore @@ -0,0 +1,75 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +build/ + +# Android related +**/android/**/gradle-wrapper.jar +**/android/.gradle +**/android/captures/ +**/android/gradlew +**/android/gradlew.bat +**/android/local.properties +**/android/**/GeneratedPluginRegistrant.java + +# iOS/XCode related +**/ios/**/*.mode1v3 +**/ios/**/*.mode2v3 +**/ios/**/*.moved-aside +**/ios/**/*.pbxuser +**/ios/**/*.perspectivev3 +**/ios/**/*sync/ +**/ios/**/.sconsign.dblite +**/ios/**/.tags* +**/ios/**/.vagrant/ +**/ios/**/DerivedData/ +**/ios/**/Icon? +**/ios/**/Pods/ +**/ios/**/.symlinks/ +**/ios/**/profile +**/ios/**/xcuserdata +**/ios/.generated/ +**/ios/Flutter/App.framework +**/ios/Flutter/Flutter.framework +**/ios/Flutter/Flutter.podspec +**/ios/Flutter/Generated.xcconfig +**/ios/Flutter/ephemeral +**/ios/Flutter/app.flx +**/ios/Flutter/app.zip +**/ios/Flutter/flutter_assets/ +**/ios/Flutter/flutter_export_environment.sh +**/ios/ServiceDefinitions.json +**/ios/Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!**/ios/**/default.mode1v3 +!**/ios/**/default.mode2v3 +!**/ios/**/default.pbxuser +!**/ios/**/default.perspectivev3 diff --git a/analysis_options.yaml b/analysis_options.yaml index 0ffcdb2..fe58d4e 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -3,4 +3,22 @@ include: package:flutter_lints/flutter.yaml analyzer: strong-mode: implicit-casts: false - implicit-dynamic: false \ No newline at end of file + implicit-dynamic: false + exclude: + - "**/*.g.dart" + - "**/*.freezed.dart" + +linter: + rules: + # - public_member_api_docs + - require_trailing_commas + - parameter_assignments + - only_throw_errors + - always_use_package_imports + - avoid_dynamic_calls + - prefer_void_to_null + - always_declare_return_types + - avoid_classes_with_only_static_members + - unnecessary_lambdas + - unnecessary_const + - avoid_void_async \ No newline at end of file diff --git a/melos.yaml b/melos.yaml index b244638..d432f86 100644 --- a/melos.yaml +++ b/melos.yaml @@ -11,6 +11,11 @@ scripts: description: | Run `dart analyze` in all packages. - Note: you can also rely on your IDEs Dart Analysis / Issues window. + + lint:pub: > + melos exec -c 5 --fail-fast --no-private --ignore="*example*" -- \ + pub publish --dry-run + generate: run: melos run generate:dart && melos run generate:flutter description: Build all generated files for Dart & Flutter packages in this project. @@ -27,13 +32,6 @@ scripts: run: melos run test:dart --no-select && melos run test:flutter --no-select description: Run all Dart & Flutter tests in this project. - test:dart: - run: melos exec -c 1 --fail-fast -- "\$MELOS_ROOT_PATH/scripts/coverage.sh" - description: Run Dart tests for a specific package in this project. - select-package: - flutter: false - dir-exists: test - test:flutter: run: melos exec --dir-exists="test" -c 1 --fail-fast -- "flutter test --coverage" description: Run Flutter tests for a specific package in this project. diff --git a/packages/async_button_builder/example/pubspec.lock b/packages/async_button_builder/example/pubspec.lock index d3c33a4..492e192 100644 --- a/packages/async_button_builder/example/pubspec.lock +++ b/packages/async_button_builder/example/pubspec.lock @@ -18,9 +18,9 @@ packages: async_button_core: dependency: transitive description: - path: "../../async_button_core" - relative: true - source: path + name: async_button_core + url: "https://pub.dartlang.org" + source: hosted version: "0.0.1+4" boolean_selector: dependency: transitive @@ -63,7 +63,7 @@ packages: name: cupertino_icons url: "https://pub.dartlang.org" source: hosted - version: "1.0.2" + version: "1.0.3" fake_async: dependency: transitive description: @@ -122,7 +122,7 @@ packages: name: pedantic url: "https://pub.dartlang.org" source: hosted - version: "1.10.0-nullsafety.3" + version: "1.11.1" sky_engine: dependency: transitive description: flutter diff --git a/packages/async_button_builder/lib/src/async_button_builder.dart b/packages/async_button_builder/lib/src/async_button_builder.dart index 0de4ab1..ac30adf 100644 --- a/packages/async_button_builder/lib/src/async_button_builder.dart +++ b/packages/async_button_builder/lib/src/async_button_builder.dart @@ -269,7 +269,6 @@ class _AsyncButtonBuilderState extends State // to figure out how to reproduce the exact behaviour of AnimatedSize widget.animateSize ? AnimatedSize( - vsync: this, duration: widget.duration, reverseDuration: widget.reverseDuration, alignment: widget.sizeAlignment, diff --git a/packages/async_button_builder/pubspec.lock b/packages/async_button_builder/pubspec.lock index ffd275e..a714122 100644 --- a/packages/async_button_builder/pubspec.lock +++ b/packages/async_button_builder/pubspec.lock @@ -7,21 +7,21 @@ packages: name: _fe_analyzer_shared url: "https://pub.dartlang.org" source: hosted - version: "21.0.0" + version: "25.0.0" analyzer: dependency: transitive description: name: analyzer url: "https://pub.dartlang.org" source: hosted - version: "1.5.0" + version: "2.2.0" args: dependency: transitive description: name: args url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.2.0" async: dependency: transitive description: @@ -32,9 +32,9 @@ packages: async_button_core: dependency: "direct main" description: - path: "../async_button_core" - relative: true - source: path + name: async_button_core + url: "https://pub.dartlang.org" + source: hosted version: "0.0.1+4" boolean_selector: dependency: transitive @@ -49,7 +49,7 @@ packages: name: build url: "https://pub.dartlang.org" source: hosted - version: "2.0.1" + version: "2.1.0" build_config: dependency: transitive description: @@ -70,35 +70,35 @@ packages: name: build_resolvers url: "https://pub.dartlang.org" source: hosted - version: "2.0.1" + version: "2.0.4" build_runner: dependency: "direct dev" description: name: build_runner url: "https://pub.dartlang.org" source: hosted - version: "2.0.3" + version: "2.1.2" build_runner_core: dependency: transitive description: name: build_runner_core url: "https://pub.dartlang.org" source: hosted - version: "7.0.0" + version: "7.1.0" built_collection: dependency: transitive description: name: built_collection url: "https://pub.dartlang.org" source: hosted - version: "5.0.0" + version: "5.1.1" built_value: dependency: transitive description: name: built_value url: "https://pub.dartlang.org" source: hosted - version: "8.0.5" + version: "8.1.2" characters: dependency: transitive description: @@ -126,7 +126,7 @@ packages: name: cli_util url: "https://pub.dartlang.org" source: hosted - version: "0.3.0" + version: "0.3.3" clock: dependency: transitive description: @@ -140,7 +140,7 @@ packages: name: code_builder url: "https://pub.dartlang.org" source: hosted - version: "4.0.0" + version: "4.1.0" collection: dependency: transitive description: @@ -154,7 +154,7 @@ packages: name: convert url: "https://pub.dartlang.org" source: hosted - version: "3.0.0" + version: "3.0.1" crypto: dependency: transitive description: @@ -168,7 +168,7 @@ packages: name: dart_style url: "https://pub.dartlang.org" source: hosted - version: "2.0.1" + version: "2.1.0" fake_async: dependency: transitive description: @@ -182,7 +182,7 @@ packages: name: file url: "https://pub.dartlang.org" source: hosted - version: "6.1.0" + version: "6.1.2" fixnum: dependency: transitive description: @@ -201,7 +201,7 @@ packages: name: flutter_lints url: "https://pub.dartlang.org" source: hosted - version: "1.0.3" + version: "1.0.4" flutter_test: dependency: "direct dev" description: flutter @@ -213,7 +213,7 @@ packages: name: freezed url: "https://pub.dartlang.org" source: hosted - version: "0.14.2" + version: "0.14.5" freezed_annotation: dependency: "direct main" description: @@ -227,7 +227,7 @@ packages: name: frontend_server_client url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.1.2" glob: dependency: transitive description: @@ -262,7 +262,7 @@ packages: name: io url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.0.3" js: dependency: transitive description: @@ -332,7 +332,7 @@ packages: name: pedantic url: "https://pub.dartlang.org" source: hosted - version: "1.11.0" + version: "1.11.1" pool: dependency: transitive description: @@ -360,7 +360,7 @@ packages: name: shelf url: "https://pub.dartlang.org" source: hosted - version: "1.1.1" + version: "1.2.0" shelf_web_socket: dependency: transitive description: @@ -379,7 +379,7 @@ packages: name: source_gen url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.1.0" source_span: dependency: transitive description: diff --git a/packages/async_button_core/analysis_options.yaml b/packages/async_button_core/analysis_options.yaml deleted file mode 100644 index a5744c1..0000000 --- a/packages/async_button_core/analysis_options.yaml +++ /dev/null @@ -1,4 +0,0 @@ -include: package:flutter_lints/flutter.yaml - -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options diff --git a/packages/async_button_hook/example/pubspec.lock b/packages/async_button_hook/example/pubspec.lock index fa11603..8990592 100644 --- a/packages/async_button_hook/example/pubspec.lock +++ b/packages/async_button_hook/example/pubspec.lock @@ -11,9 +11,9 @@ packages: async_button_core: dependency: transitive description: - path: "../../async_button_core" - relative: true - source: path + name: async_button_core + url: "https://pub.dartlang.org" + source: hosted version: "0.0.1+4" async_button_hook: dependency: "direct main" diff --git a/packages/async_button_hook/lib/src/async_button_hook.dart b/packages/async_button_hook/lib/src/async_button_hook.dart index f26df7c..e535f5c 100644 --- a/packages/async_button_hook/lib/src/async_button_hook.dart +++ b/packages/async_button_hook/lib/src/async_button_hook.dart @@ -60,7 +60,6 @@ AsyncButtonResult useAsyncButton({ [buttonState], ); - final ticker = useSingleTickerProvider(); final isMounted = useIsMounted(); final context = useContext(); final childKey = child.key; @@ -163,7 +162,6 @@ AsyncButtonResult useAsyncButton({ return AsyncButtonResult( child: animateSize ? AnimatedSize( - vsync: ticker, duration: duration, reverseDuration: reverseDuration, alignment: sizeAlignment, diff --git a/packages/async_button_hook/pubspec.lock b/packages/async_button_hook/pubspec.lock index 1fe3bcb..7580bc7 100644 --- a/packages/async_button_hook/pubspec.lock +++ b/packages/async_button_hook/pubspec.lock @@ -11,9 +11,9 @@ packages: async_button_core: dependency: "direct main" description: - path: "../async_button_core" - relative: true - source: path + name: async_button_core + url: "https://pub.dartlang.org" + source: hosted version: "0.0.1+4" boolean_selector: dependency: transitive From 060b8a79e533b755a5509eff7eed7a9a48e5c2b1 Mon Sep 17 00:00:00 2001 From: Nolence Date: Thu, 9 Sep 2021 11:22:26 -0600 Subject: [PATCH 064/176] Updated workflow and moved build_runner --- .github/workflows/dart.yaml | 28 +- .gitignore | 4 + analysis_options.yaml | 1 + melos.yaml | 12 - .../example/lib/main.dart | 30 +- .../example/test/widget_test.dart | 20 +- packages/async_button_builder/pubspec.lock | 296 +----------------- packages/async_button_builder/pubspec.yaml | 3 - .../button_state/button_state.freezed.dart | 107 ++++++- packages/async_button_core/pubspec.lock | 294 +++++++++++++++++ packages/async_button_core/pubspec.yaml | 2 + .../test/async_button_core_test.dart | 4 +- packages/async_button_hook/coverage/lcov.info | 0 .../example/analysis_options.yaml | 28 -- .../test/async_button_hook_test.dart | 4 +- 15 files changed, 437 insertions(+), 396 deletions(-) create mode 100644 packages/async_button_hook/coverage/lcov.info diff --git a/.github/workflows/dart.yaml b/.github/workflows/dart.yaml index 08ff7ad..b7bd552 100644 --- a/.github/workflows/dart.yaml +++ b/.github/workflows/dart.yaml @@ -32,30 +32,24 @@ jobs: run: | melos run lint:pub - flutter: + test: runs-on: ubuntu-latest - + timeout-minutes: 15 strategy: matrix: channel: - # Dev currently adds a breaking change on AnimatedContainer - so no - # - dev + - dev - stable - steps: + - name: "Git Checkout" - uses: actions/checkout@v2 + - name: "Install Flutter" - uses: subosito/flutter-action@v1 with: channel: ${{ matrix.channel }} - - - name: Install dependencies - run: flutter pub get - - - name: Check format - run: flutter format --set-exit-if-changed . - - - name: Analyze - run: flutter analyze - - - name: Run tests - run: flutter test \ No newline at end of file + - name: "Install Tools" + run: flutter pub global activate melos + - name: "Bootstrap Workspace" + run: melos bootstrap + - name: "Flutter Test" + run: melos run test \ No newline at end of file diff --git a/.gitignore b/.gitignore index a247422..e59c66a 100644 --- a/.gitignore +++ b/.gitignore @@ -73,3 +73,7 @@ build/ !**/ios/**/default.mode2v3 !**/ios/**/default.pbxuser !**/ios/**/default.perspectivev3 + + +.melos_tool/ +*.iml \ No newline at end of file diff --git a/analysis_options.yaml b/analysis_options.yaml index fe58d4e..d93741b 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -11,6 +11,7 @@ analyzer: linter: rules: # - public_member_api_docs + - sort_child_properties_last - require_trailing_commas - parameter_assignments - only_throw_errors diff --git a/melos.yaml b/melos.yaml index d432f86..d8ab91f 100644 --- a/melos.yaml +++ b/melos.yaml @@ -17,22 +17,10 @@ scripts: pub publish --dry-run generate: - run: melos run generate:dart && melos run generate:flutter - description: Build all generated files for Dart & Flutter packages in this project. - - generate:dart: - run: melos exec -c 1 --depends-on="build_runner" --no-flutter -- "dart run build_runner build --delete-conflicting-outputs" - description: Build all generated files for Dart packages in this project. - - generate:flutter: run: melos exec -c 1 --depends-on="build_runner" --flutter -- "flutter pub run build_runner build --delete-conflicting-outputs" description: Build all generated files for Flutter packages in this project. test: - run: melos run test:dart --no-select && melos run test:flutter --no-select - description: Run all Dart & Flutter tests in this project. - - test:flutter: run: melos exec --dir-exists="test" -c 1 --fail-fast -- "flutter test --coverage" description: Run Flutter tests for a specific package in this project. select-package: diff --git a/packages/async_button_builder/example/lib/main.dart b/packages/async_button_builder/example/lib/main.dart index 27b04ce..f7bdb2c 100644 --- a/packages/async_button_builder/example/lib/main.dart +++ b/packages/async_button_builder/example/lib/main.dart @@ -33,8 +33,8 @@ class MyHomePage extends StatelessWidget { }, builder: (context, child, callback, _) { return TextButton( - child: child, onPressed: callback, + child: child, ); }, ), @@ -47,15 +47,14 @@ class MyHomePage extends StatelessWidget { }, builder: (context, child, callback, _) { return ElevatedButton( - child: child, onPressed: callback, + child: child, ); }, ), Divider(), Text('Custom Outlined Button (Error):'), AsyncButtonBuilder( - child: Text('Click Me'), loadingWidget: Text('Loading...'), onPressed: () async { await Future.delayed(Duration(seconds: 1)); @@ -87,29 +86,20 @@ class MyHomePage extends StatelessWidget { ); return OutlinedButton( - child: child, onPressed: callback, style: OutlinedButton.styleFrom( primary: Colors.black, backgroundColor: buttonColor, ), + child: child, ); }, + child: Text('Click Me'), ), Divider(), Text('Custom Material Button:'), const SizedBox(height: 6.0), AsyncButtonBuilder( - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 16.0, - vertical: 8.0, - ), - child: Text( - 'Click Me', - style: TextStyle(color: Colors.white), - ), - ), loadingWidget: Padding( padding: const EdgeInsets.all(8.0), child: SizedBox( @@ -151,11 +141,21 @@ class MyHomePage extends StatelessWidget { clipBehavior: Clip.hardEdge, shape: StadiumBorder(), child: InkWell( - child: child, onTap: callback, + child: child, ), ); }, + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16.0, + vertical: 8.0, + ), + child: Text( + 'Click Me', + style: TextStyle(color: Colors.white), + ), + ), ), Divider(), ], diff --git a/packages/async_button_builder/example/test/widget_test.dart b/packages/async_button_builder/example/test/widget_test.dart index 747db1d..ae40864 100644 --- a/packages/async_button_builder/example/test/widget_test.dart +++ b/packages/async_button_builder/example/test/widget_test.dart @@ -5,26 +5,8 @@ // gestures. You can also use WidgetTester to find child widgets in the widget // tree, read text, and verify that the values of widget properties are correct. -import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:example/main.dart'; - void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(MyApp()); - - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); - - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); - }); + testWidgets('Counter increments smoke test', (WidgetTester tester) async {}); } diff --git a/packages/async_button_builder/pubspec.lock b/packages/async_button_builder/pubspec.lock index a714122..2e556d6 100644 --- a/packages/async_button_builder/pubspec.lock +++ b/packages/async_button_builder/pubspec.lock @@ -1,27 +1,6 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: - _fe_analyzer_shared: - dependency: transitive - description: - name: _fe_analyzer_shared - url: "https://pub.dartlang.org" - source: hosted - version: "25.0.0" - analyzer: - dependency: transitive - description: - name: analyzer - url: "https://pub.dartlang.org" - source: hosted - version: "2.2.0" - args: - dependency: transitive - description: - name: args - url: "https://pub.dartlang.org" - source: hosted - version: "2.2.0" async: dependency: transitive description: @@ -43,62 +22,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" - build: - dependency: transitive - description: - name: build - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - build_config: - dependency: transitive - description: - name: build_config - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - build_daemon: - dependency: transitive - description: - name: build_daemon - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.0" - build_resolvers: - dependency: transitive - description: - name: build_resolvers - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.4" - build_runner: - dependency: "direct dev" - description: - name: build_runner - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.2" - build_runner_core: - dependency: transitive - description: - name: build_runner_core - url: "https://pub.dartlang.org" - source: hosted - version: "7.1.0" - built_collection: - dependency: transitive - description: - name: built_collection - url: "https://pub.dartlang.org" - source: hosted - version: "5.1.1" - built_value: - dependency: transitive - description: - name: built_value - url: "https://pub.dartlang.org" - source: hosted - version: "8.1.2" characters: dependency: transitive description: @@ -113,20 +36,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.1" - checked_yaml: - dependency: transitive - description: - name: checked_yaml - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.1" - cli_util: - dependency: transitive - description: - name: cli_util - url: "https://pub.dartlang.org" - source: hosted - version: "0.3.3" clock: dependency: transitive description: @@ -134,13 +43,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.0" - code_builder: - dependency: transitive - description: - name: code_builder - url: "https://pub.dartlang.org" - source: hosted - version: "4.1.0" collection: dependency: transitive description: @@ -148,27 +50,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.15.0" - convert: - dependency: transitive - description: - name: convert - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.1" - crypto: - dependency: transitive - description: - name: crypto - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.1" - dart_style: - dependency: transitive - description: - name: dart_style - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" fake_async: dependency: transitive description: @@ -176,20 +57,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.0" - file: - dependency: transitive - description: - name: file - url: "https://pub.dartlang.org" - source: hosted - version: "6.1.2" - fixnum: - dependency: transitive - description: - name: fixnum - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" flutter: dependency: "direct main" description: flutter @@ -207,69 +74,13 @@ packages: description: flutter source: sdk version: "0.0.0" - freezed: - dependency: "direct dev" - description: - name: freezed - url: "https://pub.dartlang.org" - source: hosted - version: "0.14.5" freezed_annotation: - dependency: "direct main" + dependency: transitive description: name: freezed_annotation url: "https://pub.dartlang.org" source: hosted version: "0.14.3" - frontend_server_client: - dependency: transitive - description: - name: frontend_server_client - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.2" - glob: - dependency: transitive - description: - name: glob - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.1" - graphs: - dependency: transitive - description: - name: graphs - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - http_multi_server: - dependency: transitive - description: - name: http_multi_server - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.1" - http_parser: - dependency: transitive - description: - name: http_parser - url: "https://pub.dartlang.org" - source: hosted - version: "4.0.0" - io: - dependency: transitive - description: - name: io - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.3" - js: - dependency: transitive - description: - name: js - url: "https://pub.dartlang.org" - source: hosted - version: "0.6.3" json_annotation: dependency: transitive description: @@ -284,13 +95,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.1" - logging: - dependency: transitive - description: - name: logging - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" matcher: dependency: transitive description: @@ -305,20 +109,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.7.0" - mime: - dependency: transitive - description: - name: mime - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - package_config: - dependency: transitive - description: - name: package_config - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" path: dependency: transitive description: @@ -326,60 +116,11 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.8.0" - pedantic: - dependency: transitive - description: - name: pedantic - url: "https://pub.dartlang.org" - source: hosted - version: "1.11.1" - pool: - dependency: transitive - description: - name: pool - url: "https://pub.dartlang.org" - source: hosted - version: "1.5.0" - pub_semver: - dependency: transitive - description: - name: pub_semver - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - pubspec_parse: - dependency: transitive - description: - name: pubspec_parse - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - shelf: - dependency: transitive - description: - name: shelf - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - shelf_web_socket: - dependency: transitive - description: - name: shelf_web_socket - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" sky_engine: dependency: transitive description: flutter source: sdk version: "0.0.99" - source_gen: - dependency: transitive - description: - name: source_gen - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" source_span: dependency: transitive description: @@ -401,13 +142,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" - stream_transform: - dependency: transitive - description: - name: stream_transform - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" string_scanner: dependency: transitive description: @@ -429,13 +163,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.4.2" - timing: - dependency: transitive - description: - name: timing - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" typed_data: dependency: transitive description: @@ -450,27 +177,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" - watcher: - dependency: transitive - description: - name: watcher - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - web_socket_channel: - dependency: transitive - description: - name: web_socket_channel - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - yaml: - dependency: transitive - description: - name: yaml - url: "https://pub.dartlang.org" - source: hosted - version: "3.1.0" sdks: dart: ">=2.12.0 <3.0.0" flutter: ">=1.17.0" diff --git a/packages/async_button_builder/pubspec.yaml b/packages/async_button_builder/pubspec.yaml index 21055a4..135fd1f 100644 --- a/packages/async_button_builder/pubspec.yaml +++ b/packages/async_button_builder/pubspec.yaml @@ -10,14 +10,11 @@ environment: dependencies: flutter: sdk: flutter - freezed_annotation: ^0.14.2 async_button_core: ^0.0.1+2 dev_dependencies: flutter_test: sdk: flutter - build_runner: ^2.0.3 - freezed: ^0.14.2 flutter_lints: ^1.0.0 flutter: \ No newline at end of file diff --git a/packages/async_button_core/lib/src/button_state/button_state.freezed.dart b/packages/async_button_core/lib/src/button_state/button_state.freezed.dart index b200140..690398a 100644 --- a/packages/async_button_core/lib/src/button_state/button_state.freezed.dart +++ b/packages/async_button_core/lib/src/button_state/button_state.freezed.dart @@ -1,5 +1,6 @@ +// coverage:ignore-file // GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target part of 'button_state.dart'; @@ -47,6 +48,14 @@ mixin _$ButtonState { }) => throw _privateConstructorUsedError; @optionalTypeArgs + TResult? whenOrNull({ + TResult Function()? idle, + TResult Function()? loading, + TResult Function()? success, + TResult Function()? error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs TResult maybeWhen({ TResult Function()? idle, TResult Function()? loading, @@ -64,6 +73,14 @@ mixin _$ButtonState { }) => throw _privateConstructorUsedError; @optionalTypeArgs + TResult? mapOrNull({ + TResult Function(Idle value)? idle, + TResult Function(Loading value)? loading, + TResult Function(Success value)? success, + TResult Function(Error value)? error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs TResult maybeMap({ TResult Function(Idle value)? idle, TResult Function(Loading value)? loading, @@ -135,6 +152,17 @@ class _$Idle implements Idle { return idle(); } + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult Function()? idle, + TResult Function()? loading, + TResult Function()? success, + TResult Function()? error, + }) { + return idle?.call(); + } + @override @optionalTypeArgs TResult maybeWhen({ @@ -161,6 +189,17 @@ class _$Idle implements Idle { return idle(this); } + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult Function(Idle value)? idle, + TResult Function(Loading value)? loading, + TResult Function(Success value)? success, + TResult Function(Error value)? error, + }) { + return idle?.call(this); + } + @override @optionalTypeArgs TResult maybeMap({ @@ -226,6 +265,17 @@ class _$Loading implements Loading { return loading(); } + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult Function()? idle, + TResult Function()? loading, + TResult Function()? success, + TResult Function()? error, + }) { + return loading?.call(); + } + @override @optionalTypeArgs TResult maybeWhen({ @@ -252,6 +302,17 @@ class _$Loading implements Loading { return loading(this); } + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult Function(Idle value)? idle, + TResult Function(Loading value)? loading, + TResult Function(Success value)? success, + TResult Function(Error value)? error, + }) { + return loading?.call(this); + } + @override @optionalTypeArgs TResult maybeMap({ @@ -317,6 +378,17 @@ class _$Success implements Success { return success(); } + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult Function()? idle, + TResult Function()? loading, + TResult Function()? success, + TResult Function()? error, + }) { + return success?.call(); + } + @override @optionalTypeArgs TResult maybeWhen({ @@ -343,6 +415,17 @@ class _$Success implements Success { return success(this); } + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult Function(Idle value)? idle, + TResult Function(Loading value)? loading, + TResult Function(Success value)? success, + TResult Function(Error value)? error, + }) { + return success?.call(this); + } + @override @optionalTypeArgs TResult maybeMap({ @@ -408,6 +491,17 @@ class _$Error implements Error { return error(); } + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult Function()? idle, + TResult Function()? loading, + TResult Function()? success, + TResult Function()? error, + }) { + return error?.call(); + } + @override @optionalTypeArgs TResult maybeWhen({ @@ -434,6 +528,17 @@ class _$Error implements Error { return error(this); } + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult Function(Idle value)? idle, + TResult Function(Loading value)? loading, + TResult Function(Success value)? success, + TResult Function(Error value)? error, + }) { + return error?.call(this); + } + @override @optionalTypeArgs TResult maybeMap({ diff --git a/packages/async_button_core/pubspec.lock b/packages/async_button_core/pubspec.lock index 904ddff..332f28a 100644 --- a/packages/async_button_core/pubspec.lock +++ b/packages/async_button_core/pubspec.lock @@ -1,6 +1,27 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + url: "https://pub.dartlang.org" + source: hosted + version: "25.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.0" + args: + dependency: transitive + description: + name: args + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.0" async: dependency: transitive description: @@ -15,6 +36,62 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" + build: + dependency: transitive + description: + name: build + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + build_config: + dependency: transitive + description: + name: build_config + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + build_daemon: + dependency: transitive + description: + name: build_daemon + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.4" + build_runner: + dependency: "direct dev" + description: + name: build_runner + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.2" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + url: "https://pub.dartlang.org" + source: hosted + version: "7.1.0" + built_collection: + dependency: transitive + description: + name: built_collection + url: "https://pub.dartlang.org" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + url: "https://pub.dartlang.org" + source: hosted + version: "8.1.2" characters: dependency: transitive description: @@ -29,6 +106,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.1" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + cli_util: + dependency: transitive + description: + name: cli_util + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.3" clock: dependency: transitive description: @@ -36,6 +127,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.0" + code_builder: + dependency: transitive + description: + name: code_builder + url: "https://pub.dartlang.org" + source: hosted + version: "4.1.0" collection: dependency: transitive description: @@ -43,6 +141,27 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.15.0" + convert: + dependency: transitive + description: + name: convert + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" + crypto: + dependency: transitive + description: + name: crypto + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" + dart_style: + dependency: transitive + description: + name: dart_style + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" fake_async: dependency: transitive description: @@ -50,6 +169,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.0" + file: + dependency: transitive + description: + name: file + url: "https://pub.dartlang.org" + source: hosted + version: "6.1.2" + fixnum: + dependency: transitive + description: + name: fixnum + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" flutter: dependency: "direct main" description: flutter @@ -67,6 +200,13 @@ packages: description: flutter source: sdk version: "0.0.0" + freezed: + dependency: "direct dev" + description: + name: freezed + url: "https://pub.dartlang.org" + source: hosted + version: "0.14.5" freezed_annotation: dependency: "direct main" description: @@ -74,6 +214,55 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.14.3" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.2" + glob: + dependency: transitive + description: + name: glob + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + graphs: + dependency: transitive + description: + name: graphs + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" + http_parser: + dependency: transitive + description: + name: http_parser + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.0" + io: + dependency: transitive + description: + name: io + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.3" + js: + dependency: transitive + description: + name: js + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.3" json_annotation: dependency: transitive description: @@ -88,6 +277,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.1" + logging: + dependency: transitive + description: + name: logging + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" matcher: dependency: transitive description: @@ -102,6 +298,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.7.0" + mime: + dependency: transitive + description: + name: mime + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + package_config: + dependency: transitive + description: + name: package_config + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" path: dependency: transitive description: @@ -109,11 +319,60 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.8.0" + pedantic: + dependency: transitive + description: + name: pedantic + url: "https://pub.dartlang.org" + source: hosted + version: "1.11.1" + pool: + dependency: transitive + description: + name: pool + url: "https://pub.dartlang.org" + source: hosted + version: "1.5.0" + pub_semver: + dependency: transitive + description: + name: pub_semver + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + shelf: + dependency: transitive + description: + name: shelf + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" sky_engine: dependency: transitive description: flutter source: sdk version: "0.0.99" + source_gen: + dependency: transitive + description: + name: source_gen + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" source_span: dependency: transitive description: @@ -135,6 +394,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" + stream_transform: + dependency: transitive + description: + name: stream_transform + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" string_scanner: dependency: transitive description: @@ -156,6 +422,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.4.2" + timing: + dependency: transitive + description: + name: timing + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" typed_data: dependency: transitive description: @@ -170,6 +443,27 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" + watcher: + dependency: transitive + description: + name: watcher + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + yaml: + dependency: transitive + description: + name: yaml + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.0" sdks: dart: ">=2.12.0 <3.0.0" flutter: ">=1.17.0" diff --git a/packages/async_button_core/pubspec.yaml b/packages/async_button_core/pubspec.yaml index 2e2eefd..25b22d4 100644 --- a/packages/async_button_core/pubspec.yaml +++ b/packages/async_button_core/pubspec.yaml @@ -14,6 +14,8 @@ dependencies: dev_dependencies: flutter_lints: ^1.0.0 + build_runner: ^2.0.3 + freezed: ^0.14.2 flutter_test: sdk: flutter diff --git a/packages/async_button_core/test/async_button_core_test.dart b/packages/async_button_core/test/async_button_core_test.dart index c989bbd..0da434d 100644 --- a/packages/async_button_core/test/async_button_core_test.dart +++ b/packages/async_button_core/test/async_button_core_test.dart @@ -1,7 +1,5 @@ import 'package:flutter_test/flutter_test.dart'; void main() { - test('adds one to input values', () { - throw UnimplementedError(); - }); + test('adds one to input values', () {}); } diff --git a/packages/async_button_hook/coverage/lcov.info b/packages/async_button_hook/coverage/lcov.info new file mode 100644 index 0000000..e69de29 diff --git a/packages/async_button_hook/example/analysis_options.yaml b/packages/async_button_hook/example/analysis_options.yaml index 61b6c4d..f9b3034 100644 --- a/packages/async_button_hook/example/analysis_options.yaml +++ b/packages/async_button_hook/example/analysis_options.yaml @@ -1,29 +1 @@ -# This file configures the analyzer, which statically analyzes Dart code to -# check for errors, warnings, and lints. -# -# The issues identified by the analyzer are surfaced in the UI of Dart-enabled -# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be -# invoked from the command line by running `flutter analyze`. - -# The following line activates a set of recommended lints for Flutter apps, -# packages, and plugins designed to encourage good coding practices. include: package:flutter_lints/flutter.yaml - -linter: - # The lint rules applied to this project can be customized in the - # section below to disable rules from the `package:flutter_lints/flutter.yaml` - # included above or to enable additional rules. A list of all available lints - # and their documentation is published at - # https://dart-lang.github.io/linter/lints/index.html. - # - # Instead of disabling a lint rule for the entire project in the - # section below, it can also be suppressed for a single line of code - # or a specific dart file by using the `// ignore: name_of_lint` and - # `// ignore_for_file: name_of_lint` syntax on the line or in the file - # producing the lint. - rules: - # avoid_print: false # Uncomment to disable the `avoid_print` rule - # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule - -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options diff --git a/packages/async_button_hook/test/async_button_hook_test.dart b/packages/async_button_hook/test/async_button_hook_test.dart index c989bbd..0da434d 100644 --- a/packages/async_button_hook/test/async_button_hook_test.dart +++ b/packages/async_button_hook/test/async_button_hook_test.dart @@ -1,7 +1,5 @@ import 'package:flutter_test/flutter_test.dart'; void main() { - test('adds one to input values', () { - throw UnimplementedError(); - }); + test('adds one to input values', () {}); } From d20756dada03fbf3aceeb6e94b3dee3cb01a8e4a Mon Sep 17 00:00:00 2001 From: Nolence Date: Thu, 9 Sep 2021 11:26:45 -0600 Subject: [PATCH 065/176] every step should include uses or run --- .github/workflows/dart.yaml | 41 +++++++++---------------------------- 1 file changed, 10 insertions(+), 31 deletions(-) diff --git a/.github/workflows/dart.yaml b/.github/workflows/dart.yaml index b7bd552..9fa611f 100644 --- a/.github/workflows/dart.yaml +++ b/.github/workflows/dart.yaml @@ -8,48 +8,27 @@ on: - cron: '0 10 * * *' jobs: - analyze: + flutter: timeout-minutes: 15 runs-on: ubuntu-latest steps: - name: "Git Checkout" uses: actions/checkout@v2 - with: - fetch-depth: 0 + - name: "Install Flutter" uses: subosito/flutter-action@v1 - with: - flutter-version: "2.2.1" + - name: "Install Tools" - run: | - flutter pub global activate melos + run: flutter pub global activate melos + - name: "Bootstrap Workspace" run: melos bootstrap + - name: "Dart Analyze" - run: | - melos run analyze + run: melos run analyze + - name: "Pub Check" - run: | - melos run lint:pub + run: melos run lint:pub - test: - runs-on: ubuntu-latest - timeout-minutes: 15 - strategy: - matrix: - channel: - - dev - - stable - steps: - - name: "Git Checkout" - - uses: actions/checkout@v2 - - name: "Install Flutter" - - uses: subosito/flutter-action@v1 - with: - channel: ${{ matrix.channel }} - - name: "Install Tools" - run: flutter pub global activate melos - - name: "Bootstrap Workspace" - run: melos bootstrap - name: "Flutter Test" - run: melos run test \ No newline at end of file + run: melos run test From 04eed9d691b45cbf60f3fe51b069a56db3dc6201 Mon Sep 17 00:00:00 2001 From: Nolence Date: Thu, 9 Sep 2021 11:34:55 -0600 Subject: [PATCH 066/176] Fixes test out of range --- .github/workflows/dart.yaml | 2 +- .../async_button_builder/coverage/lcov.info | 107 ++++++++++++++++++ .../example/test/widget_test.dart | 12 -- .../example/test/widget_test.dart | 30 ----- 4 files changed, 108 insertions(+), 43 deletions(-) create mode 100644 packages/async_button_builder/coverage/lcov.info delete mode 100644 packages/async_button_builder/example/test/widget_test.dart delete mode 100644 packages/async_button_hook/example/test/widget_test.dart diff --git a/.github/workflows/dart.yaml b/.github/workflows/dart.yaml index 9fa611f..8496493 100644 --- a/.github/workflows/dart.yaml +++ b/.github/workflows/dart.yaml @@ -31,4 +31,4 @@ jobs: run: melos run lint:pub - name: "Flutter Test" - run: melos run test + run: melos run test --no-select diff --git a/packages/async_button_builder/coverage/lcov.info b/packages/async_button_builder/coverage/lcov.info new file mode 100644 index 0000000..422cb7f --- /dev/null +++ b/packages/async_button_builder/coverage/lcov.info @@ -0,0 +1,107 @@ +SF:lib/src/async_button_builder.dart +DA:104,1 +DA:138,1 +DA:143,1 +DA:144,1 +DA:152,1 +DA:154,3 +DA:155,1 +DA:158,0 +DA:160,0 +DA:161,0 +DA:162,0 +DA:166,0 +DA:169,1 +DA:171,2 +DA:173,1 +DA:176,1 +DA:178,1 +DA:179,2 +DA:180,2 +DA:181,2 +DA:187,2 +DA:188,1 +DA:190,2 +DA:192,2 +DA:193,1 +DA:195,1 +DA:197,2 +DA:198,2 +DA:205,0 +DA:206,0 +DA:210,0 +DA:217,0 +DA:223,1 +DA:225,2 +DA:226,2 +DA:227,2 +DA:228,3 +DA:229,3 +DA:230,3 +DA:231,3 +DA:233,2 +DA:234,3 +DA:235,3 +DA:236,3 +DA:237,3 +DA:239,2 +DA:240,3 +DA:241,3 +DA:242,3 +DA:243,3 +DA:245,2 +DA:246,2 +DA:247,2 +DA:248,2 +DA:250,2 +DA:251,2 +DA:254,2 +DA:255,2 +DA:258,2 +DA:259,2 +DA:265,2 +DA:270,2 +DA:271,1 +DA:272,2 +DA:273,2 +DA:274,2 +DA:275,2 +DA:276,2 +DA:280,2 +DA:284,2 +DA:285,2 +DA:286,1 +DA:289,2 +DA:290,1 +DA:293,1 +DA:295,2 +DA:296,1 +DA:298,1 +DA:299,2 +DA:300,2 +DA:301,1 +DA:304,3 +DA:306,0 +DA:307,0 +DA:311,2 +DA:312,1 +DA:314,1 +DA:315,2 +DA:316,2 +DA:317,1 +DA:320,3 +DA:322,0 +DA:323,0 +DA:329,1 +DA:331,1 +DA:333,1 +DA:337,1 +DA:338,2 +DA:340,1 +DA:341,2 +DA:343,1 +DA:344,2 +DA:345,1 +LF:103 +LH:90 +end_of_record diff --git a/packages/async_button_builder/example/test/widget_test.dart b/packages/async_button_builder/example/test/widget_test.dart deleted file mode 100644 index ae40864..0000000 --- a/packages/async_button_builder/example/test/widget_test.dart +++ /dev/null @@ -1,12 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility that Flutter provides. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async {}); -} diff --git a/packages/async_button_hook/example/test/widget_test.dart b/packages/async_button_hook/example/test/widget_test.dart deleted file mode 100644 index a19dabb..0000000 --- a/packages/async_button_hook/example/test/widget_test.dart +++ /dev/null @@ -1,30 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility that Flutter provides. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'package:example/main.dart'; - -void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(const MyApp()); - - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); - - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); - }); -} From 35683c60007fc4aef88b859138f21dcfa114805c Mon Sep 17 00:00:00 2001 From: Nolence Date: Thu, 9 Sep 2021 11:42:01 -0600 Subject: [PATCH 067/176] Bumped version --- packages/async_button_builder/CHANGELOG.md | 3 +++ packages/async_button_builder/example/pubspec.lock | 2 +- packages/async_button_builder/pubspec.yaml | 2 +- packages/async_button_core/CHANGELOG.md | 3 +++ packages/async_button_core/pubspec.yaml | 2 +- packages/async_button_hook/CHANGELOG.md | 3 +++ packages/async_button_hook/example/pubspec.lock | 2 +- packages/async_button_hook/pubspec.yaml | 2 +- 8 files changed, 14 insertions(+), 5 deletions(-) diff --git a/packages/async_button_builder/CHANGELOG.md b/packages/async_button_builder/CHANGELOG.md index b8cd6a0..81508f4 100644 --- a/packages/async_button_builder/CHANGELOG.md +++ b/packages/async_button_builder/CHANGELOG.md @@ -1,3 +1,6 @@ +## [2.1.3+7] - 2021-09-08 +Fixed github actions + ## [2.1.3+6] - 2021-08-31 Trying to fix pub stuff diff --git a/packages/async_button_builder/example/pubspec.lock b/packages/async_button_builder/example/pubspec.lock index 492e192..6a0118f 100644 --- a/packages/async_button_builder/example/pubspec.lock +++ b/packages/async_button_builder/example/pubspec.lock @@ -14,7 +14,7 @@ packages: path: ".." relative: true source: path - version: "2.1.3+6" + version: "2.1.3+7" async_button_core: dependency: transitive description: diff --git a/packages/async_button_builder/pubspec.yaml b/packages/async_button_builder/pubspec.yaml index 135fd1f..09bde5a 100644 --- a/packages/async_button_builder/pubspec.yaml +++ b/packages/async_button_builder/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_builder description: A builder to wrap around buttons that handles loading, disabled, error and succes states -version: 2.1.3+6 +version: 2.1.3+7 homepage: https://github.com/Nolence/async_button/tree/main/packages/async_button_builder environment: diff --git a/packages/async_button_core/CHANGELOG.md b/packages/async_button_core/CHANGELOG.md index e5bfdb9..d740fd9 100644 --- a/packages/async_button_core/CHANGELOG.md +++ b/packages/async_button_core/CHANGELOG.md @@ -1,3 +1,6 @@ +## 0.0.1+5 - 2021-09-08 +Fixed github actions + ## 0.0.1+4 - 2021-08-27 Trying to fix pub stuff diff --git a/packages/async_button_core/pubspec.yaml b/packages/async_button_core/pubspec.yaml index 25b22d4..77f0da4 100644 --- a/packages/async_button_core/pubspec.yaml +++ b/packages/async_button_core/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_core description: Contains the core models and docs for the packages async_button_hook and async_button_builder -version: 0.0.1+4 +version: 0.0.1+5 homepage: https://github.com/Nolence/async_button/tree/main/packages/async_button_core environment: diff --git a/packages/async_button_hook/CHANGELOG.md b/packages/async_button_hook/CHANGELOG.md index 1723011..ae13201 100644 --- a/packages/async_button_hook/CHANGELOG.md +++ b/packages/async_button_hook/CHANGELOG.md @@ -1,3 +1,6 @@ +## 0.0.1+6 - 2021-09-08 +Fixed github actions + ## 0.0.1+5 - 2021-08-31 Trying to fix pub stuff diff --git a/packages/async_button_hook/example/pubspec.lock b/packages/async_button_hook/example/pubspec.lock index 8990592..d2b5bd7 100644 --- a/packages/async_button_hook/example/pubspec.lock +++ b/packages/async_button_hook/example/pubspec.lock @@ -21,7 +21,7 @@ packages: path: ".." relative: true source: path - version: "0.0.1+5" + version: "0.0.1+6" boolean_selector: dependency: transitive description: diff --git a/packages/async_button_hook/pubspec.yaml b/packages/async_button_hook/pubspec.yaml index 295a0eb..8a18cd3 100644 --- a/packages/async_button_hook/pubspec.yaml +++ b/packages/async_button_hook/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_hook description: A hook version of async_button_builder which depends on flutter_hooks -version: 0.0.1+5 +version: 0.0.1+6 homepage: https://github.com/Nolence/async_button/tree/main/packages/async_button_hook environment: From 4d9ea0c554543ac08fc9ceca3be0fad7f3d75154 Mon Sep 17 00:00:00 2001 From: Nolence Date: Tue, 28 Sep 2021 20:14:58 -0600 Subject: [PATCH 068/176] bumped versions --- packages/async_button_builder/CHANGELOG.md | 3 +++ .../async_button_builder/example/pubspec.lock | 4 ++-- packages/async_button_builder/pubspec.lock | 2 +- packages/async_button_builder/pubspec.yaml | 4 ++-- packages/async_button_core/CHANGELOG.md | 3 +++ packages/async_button_core/pubspec.lock | 20 +++++++++---------- packages/async_button_core/pubspec.yaml | 6 +++--- packages/async_button_hook/CHANGELOG.md | 3 +++ .../async_button_hook/example/pubspec.lock | 4 ++-- packages/async_button_hook/pubspec.lock | 2 +- packages/async_button_hook/pubspec.yaml | 4 ++-- 11 files changed, 32 insertions(+), 23 deletions(-) diff --git a/packages/async_button_builder/CHANGELOG.md b/packages/async_button_builder/CHANGELOG.md index 81508f4..bf171bd 100644 --- a/packages/async_button_builder/CHANGELOG.md +++ b/packages/async_button_builder/CHANGELOG.md @@ -1,3 +1,6 @@ +## [2.1.3+8] - 2021-09-28 +Upgraded deps + ## [2.1.3+7] - 2021-09-08 Fixed github actions diff --git a/packages/async_button_builder/example/pubspec.lock b/packages/async_button_builder/example/pubspec.lock index 6a0118f..02cb022 100644 --- a/packages/async_button_builder/example/pubspec.lock +++ b/packages/async_button_builder/example/pubspec.lock @@ -14,14 +14,14 @@ packages: path: ".." relative: true source: path - version: "2.1.3+7" + version: "2.1.3+8" async_button_core: dependency: transitive description: name: async_button_core url: "https://pub.dartlang.org" source: hosted - version: "0.0.1+4" + version: "0.0.1+6" boolean_selector: dependency: transitive description: diff --git a/packages/async_button_builder/pubspec.lock b/packages/async_button_builder/pubspec.lock index 2e556d6..e41fb74 100644 --- a/packages/async_button_builder/pubspec.lock +++ b/packages/async_button_builder/pubspec.lock @@ -14,7 +14,7 @@ packages: name: async_button_core url: "https://pub.dartlang.org" source: hosted - version: "0.0.1+4" + version: "0.0.1+6" boolean_selector: dependency: transitive description: diff --git a/packages/async_button_builder/pubspec.yaml b/packages/async_button_builder/pubspec.yaml index 09bde5a..6422a4b 100644 --- a/packages/async_button_builder/pubspec.yaml +++ b/packages/async_button_builder/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_builder description: A builder to wrap around buttons that handles loading, disabled, error and succes states -version: 2.1.3+7 +version: 2.1.3+8 homepage: https://github.com/Nolence/async_button/tree/main/packages/async_button_builder environment: @@ -10,7 +10,7 @@ environment: dependencies: flutter: sdk: flutter - async_button_core: ^0.0.1+2 + async_button_core: ^0.0.1+6 dev_dependencies: flutter_test: diff --git a/packages/async_button_core/CHANGELOG.md b/packages/async_button_core/CHANGELOG.md index d740fd9..ed3ac69 100644 --- a/packages/async_button_core/CHANGELOG.md +++ b/packages/async_button_core/CHANGELOG.md @@ -1,3 +1,6 @@ +## 0.0.1+6 - 2021-09-28 +Upgraded deps + ## 0.0.1+5 - 2021-09-08 Fixed github actions diff --git a/packages/async_button_core/pubspec.lock b/packages/async_button_core/pubspec.lock index 332f28a..d3c9b2b 100644 --- a/packages/async_button_core/pubspec.lock +++ b/packages/async_button_core/pubspec.lock @@ -7,21 +7,21 @@ packages: name: _fe_analyzer_shared url: "https://pub.dartlang.org" source: hosted - version: "25.0.0" + version: "26.0.0" analyzer: dependency: transitive description: name: analyzer url: "https://pub.dartlang.org" source: hosted - version: "2.2.0" + version: "2.3.0" args: dependency: transitive description: name: args url: "https://pub.dartlang.org" source: hosted - version: "2.2.0" + version: "2.3.0" async: dependency: transitive description: @@ -161,7 +161,7 @@ packages: name: dart_style url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.2.0" fake_async: dependency: transitive description: @@ -234,7 +234,7 @@ packages: name: graphs url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.1.0" http_multi_server: dependency: transitive description: @@ -283,7 +283,7 @@ packages: name: logging url: "https://pub.dartlang.org" source: hosted - version: "1.0.1" + version: "1.0.2" matcher: dependency: transitive description: @@ -311,7 +311,7 @@ packages: name: package_config url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.0.2" path: dependency: transitive description: @@ -339,14 +339,14 @@ packages: name: pub_semver url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.1.0" pubspec_parse: dependency: transitive description: name: pubspec_parse url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.1.0" shelf: dependency: transitive description: @@ -372,7 +372,7 @@ packages: name: source_gen url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.1.1" source_span: dependency: transitive description: diff --git a/packages/async_button_core/pubspec.yaml b/packages/async_button_core/pubspec.yaml index 77f0da4..7bd76e0 100644 --- a/packages/async_button_core/pubspec.yaml +++ b/packages/async_button_core/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_core description: Contains the core models and docs for the packages async_button_hook and async_button_builder -version: 0.0.1+5 +version: 0.0.1+6 homepage: https://github.com/Nolence/async_button/tree/main/packages/async_button_core environment: @@ -13,9 +13,9 @@ dependencies: freezed_annotation: ^0.14.3 dev_dependencies: - flutter_lints: ^1.0.0 + flutter_lints: ^1.0.4 build_runner: ^2.0.3 - freezed: ^0.14.2 + freezed: ^0.14.5 flutter_test: sdk: flutter diff --git a/packages/async_button_hook/CHANGELOG.md b/packages/async_button_hook/CHANGELOG.md index ae13201..34f1a86 100644 --- a/packages/async_button_hook/CHANGELOG.md +++ b/packages/async_button_hook/CHANGELOG.md @@ -1,3 +1,6 @@ +## 0.0.1+7 - 2021-09-28 +Upgraded deps + ## 0.0.1+6 - 2021-09-08 Fixed github actions diff --git a/packages/async_button_hook/example/pubspec.lock b/packages/async_button_hook/example/pubspec.lock index d2b5bd7..e3316aa 100644 --- a/packages/async_button_hook/example/pubspec.lock +++ b/packages/async_button_hook/example/pubspec.lock @@ -14,14 +14,14 @@ packages: name: async_button_core url: "https://pub.dartlang.org" source: hosted - version: "0.0.1+4" + version: "0.0.1+6" async_button_hook: dependency: "direct main" description: path: ".." relative: true source: path - version: "0.0.1+6" + version: "0.0.1+7" boolean_selector: dependency: transitive description: diff --git a/packages/async_button_hook/pubspec.lock b/packages/async_button_hook/pubspec.lock index 7580bc7..ddbd7de 100644 --- a/packages/async_button_hook/pubspec.lock +++ b/packages/async_button_hook/pubspec.lock @@ -14,7 +14,7 @@ packages: name: async_button_core url: "https://pub.dartlang.org" source: hosted - version: "0.0.1+4" + version: "0.0.1+6" boolean_selector: dependency: transitive description: diff --git a/packages/async_button_hook/pubspec.yaml b/packages/async_button_hook/pubspec.yaml index 8a18cd3..ce4bd2f 100644 --- a/packages/async_button_hook/pubspec.yaml +++ b/packages/async_button_hook/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_hook description: A hook version of async_button_builder which depends on flutter_hooks -version: 0.0.1+6 +version: 0.0.1+7 homepage: https://github.com/Nolence/async_button/tree/main/packages/async_button_hook environment: @@ -11,7 +11,7 @@ dependencies: flutter: sdk: flutter flutter_hooks: ^0.18.0 - async_button_core: ^0.0.1+2 + async_button_core: ^0.0.1+6 dev_dependencies: flutter_lints: ^1.0.0 From 5fed609de3ca9cbedbadc68581f1f2a807c0205d Mon Sep 17 00:00:00 2001 From: iliser Date: Tue, 9 Nov 2021 13:32:35 +0800 Subject: [PATCH 069/176] fix bug with manual buttonState change --- packages/async_button_builder/lib/src/async_button_builder.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/async_button_builder/lib/src/async_button_builder.dart b/packages/async_button_builder/lib/src/async_button_builder.dart index ac30adf..72b4dfe 100644 --- a/packages/async_button_builder/lib/src/async_button_builder.dart +++ b/packages/async_button_builder/lib/src/async_button_builder.dart @@ -159,7 +159,7 @@ class _AsyncButtonBuilderState extends State void didUpdateWidget(covariant AsyncButtonBuilder oldWidget) { if (widget.buttonState != oldWidget.buttonState) { setState(() { - buttonState = buttonState; + buttonState = widget.buttonState; }); } From 40d2a633ca3b2918634fd149c7ef5875f5fe8deb Mon Sep 17 00:00:00 2001 From: Nolence Date: Tue, 9 Nov 2021 11:17:20 -0700 Subject: [PATCH 070/176] version bumps and changelog updates --- packages/async_button_builder/CHANGELOG.md | 6 ++++++ packages/async_button_builder/example/pubspec.lock | 4 ++-- packages/async_button_builder/pubspec.lock | 2 +- packages/async_button_builder/pubspec.yaml | 4 ++-- packages/async_button_core/CHANGELOG.md | 6 ++++++ packages/async_button_core/pubspec.lock | 4 ++-- packages/async_button_core/pubspec.yaml | 4 ++-- packages/async_button_hook/CHANGELOG.md | 6 ++++++ packages/async_button_hook/example/pubspec.lock | 4 ++-- packages/async_button_hook/pubspec.lock | 2 +- packages/async_button_hook/pubspec.yaml | 4 ++-- 11 files changed, 32 insertions(+), 14 deletions(-) diff --git a/packages/async_button_builder/CHANGELOG.md b/packages/async_button_builder/CHANGELOG.md index bf171bd..897e78c 100644 --- a/packages/async_button_builder/CHANGELOG.md +++ b/packages/async_button_builder/CHANGELOG.md @@ -1,3 +1,9 @@ +## [2.1.4] - 2021-09-28 +Fix manual button state changes. Credit to @iliser + +## [2.1.3+9] - 2021-09-28 +Upgraded deps + ## [2.1.3+8] - 2021-09-28 Upgraded deps diff --git a/packages/async_button_builder/example/pubspec.lock b/packages/async_button_builder/example/pubspec.lock index 02cb022..ab22eae 100644 --- a/packages/async_button_builder/example/pubspec.lock +++ b/packages/async_button_builder/example/pubspec.lock @@ -14,14 +14,14 @@ packages: path: ".." relative: true source: path - version: "2.1.3+8" + version: "2.1.4" async_button_core: dependency: transitive description: name: async_button_core url: "https://pub.dartlang.org" source: hosted - version: "0.0.1+6" + version: "0.0.1+7" boolean_selector: dependency: transitive description: diff --git a/packages/async_button_builder/pubspec.lock b/packages/async_button_builder/pubspec.lock index e41fb74..7775898 100644 --- a/packages/async_button_builder/pubspec.lock +++ b/packages/async_button_builder/pubspec.lock @@ -14,7 +14,7 @@ packages: name: async_button_core url: "https://pub.dartlang.org" source: hosted - version: "0.0.1+6" + version: "0.0.1+7" boolean_selector: dependency: transitive description: diff --git a/packages/async_button_builder/pubspec.yaml b/packages/async_button_builder/pubspec.yaml index 6422a4b..a53fa9a 100644 --- a/packages/async_button_builder/pubspec.yaml +++ b/packages/async_button_builder/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_builder description: A builder to wrap around buttons that handles loading, disabled, error and succes states -version: 2.1.3+8 +version: 2.1.4 homepage: https://github.com/Nolence/async_button/tree/main/packages/async_button_builder environment: @@ -10,7 +10,7 @@ environment: dependencies: flutter: sdk: flutter - async_button_core: ^0.0.1+6 + async_button_core: ^0.0.1+7 dev_dependencies: flutter_test: diff --git a/packages/async_button_core/CHANGELOG.md b/packages/async_button_core/CHANGELOG.md index ed3ac69..0fe48f3 100644 --- a/packages/async_button_core/CHANGELOG.md +++ b/packages/async_button_core/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.0.1+8 - 2021-09-28 +Upgraded deps + +## 0.0.1+7 - 2021-09-28 +Upgraded deps + ## 0.0.1+6 - 2021-09-28 Upgraded deps diff --git a/packages/async_button_core/pubspec.lock b/packages/async_button_core/pubspec.lock index d3c9b2b..edf125d 100644 --- a/packages/async_button_core/pubspec.lock +++ b/packages/async_button_core/pubspec.lock @@ -213,7 +213,7 @@ packages: name: freezed_annotation url: "https://pub.dartlang.org" source: hosted - version: "0.14.3" + version: "0.15.0" frontend_server_client: dependency: transitive description: @@ -465,5 +465,5 @@ packages: source: hosted version: "3.1.0" sdks: - dart: ">=2.12.0 <3.0.0" + dart: ">=2.14.0 <3.0.0" flutter: ">=1.17.0" diff --git a/packages/async_button_core/pubspec.yaml b/packages/async_button_core/pubspec.yaml index 7bd76e0..5d1d4c6 100644 --- a/packages/async_button_core/pubspec.yaml +++ b/packages/async_button_core/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_core description: Contains the core models and docs for the packages async_button_hook and async_button_builder -version: 0.0.1+6 +version: 0.0.1+8 homepage: https://github.com/Nolence/async_button/tree/main/packages/async_button_core environment: @@ -10,7 +10,7 @@ environment: dependencies: flutter: sdk: flutter - freezed_annotation: ^0.14.3 + freezed_annotation: ">=0.14.0 <=0.16.0" dev_dependencies: flutter_lints: ^1.0.4 diff --git a/packages/async_button_hook/CHANGELOG.md b/packages/async_button_hook/CHANGELOG.md index 34f1a86..7ec29ac 100644 --- a/packages/async_button_hook/CHANGELOG.md +++ b/packages/async_button_hook/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.0.1+9 - 2021-09-28 +Upgraded deps + +## 0.0.1+8 - 2021-09-28 +Upgraded deps + ## 0.0.1+7 - 2021-09-28 Upgraded deps diff --git a/packages/async_button_hook/example/pubspec.lock b/packages/async_button_hook/example/pubspec.lock index e3316aa..9b0e11e 100644 --- a/packages/async_button_hook/example/pubspec.lock +++ b/packages/async_button_hook/example/pubspec.lock @@ -14,14 +14,14 @@ packages: name: async_button_core url: "https://pub.dartlang.org" source: hosted - version: "0.0.1+6" + version: "0.0.1+7" async_button_hook: dependency: "direct main" description: path: ".." relative: true source: path - version: "0.0.1+7" + version: "0.0.1+8" boolean_selector: dependency: transitive description: diff --git a/packages/async_button_hook/pubspec.lock b/packages/async_button_hook/pubspec.lock index ddbd7de..660bfa6 100644 --- a/packages/async_button_hook/pubspec.lock +++ b/packages/async_button_hook/pubspec.lock @@ -14,7 +14,7 @@ packages: name: async_button_core url: "https://pub.dartlang.org" source: hosted - version: "0.0.1+6" + version: "0.0.1+7" boolean_selector: dependency: transitive description: diff --git a/packages/async_button_hook/pubspec.yaml b/packages/async_button_hook/pubspec.yaml index ce4bd2f..c2516ac 100644 --- a/packages/async_button_hook/pubspec.yaml +++ b/packages/async_button_hook/pubspec.yaml @@ -1,6 +1,6 @@ name: async_button_hook description: A hook version of async_button_builder which depends on flutter_hooks -version: 0.0.1+7 +version: 0.0.1+8 homepage: https://github.com/Nolence/async_button/tree/main/packages/async_button_hook environment: @@ -11,7 +11,7 @@ dependencies: flutter: sdk: flutter flutter_hooks: ^0.18.0 - async_button_core: ^0.0.1+6 + async_button_core: ^0.0.1+7 dev_dependencies: flutter_lints: ^1.0.0 From d5d669b47aca8c92b55016a0f3e533d466efbb4f Mon Sep 17 00:00:00 2001 From: Nolence Date: Fri, 7 Jan 2022 12:33:30 -0700 Subject: [PATCH 071/176] removed hook version and simplified package structure --- .github/workflows/dart.yaml | 21 +- .../.metadata => .metadata | 0 .vscode/settings.json | 3 + .../CHANGELOG.md => CHANGELOG.md | 3 + README.md | 148 +++++- .../coverage => coverage}/lcov.info | 0 .../example => example}/.gitignore | 0 .../example => example}/.metadata | 0 .../example => example}/README.md | 0 .../example => example}/analysis_options.yaml | 0 .../example => example}/android/.gitignore | 0 .../android/app/build.gradle | 0 .../android/app/src/debug/AndroidManifest.xml | 0 .../android/app/src/main/AndroidManifest.xml | 0 .../com/example/example/MainActivity.kt | 0 .../res/drawable-v21/launch_background.xml | 0 .../main/res/drawable/launch_background.xml | 0 .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin .../app/src/main/res/values-night/styles.xml | 0 .../app/src/main/res/values/styles.xml | 0 .../app/src/profile/AndroidManifest.xml | 0 .../example => example}/android/build.gradle | 0 .../android/gradle.properties | 0 .../gradle/wrapper/gradle-wrapper.properties | 0 .../android/settings.gradle | 0 .../example => example}/ios/.gitignore | 0 .../ios/Flutter/AppFrameworkInfo.plist | 0 .../ios/Flutter/Debug.xcconfig | 0 .../ios/Flutter/Release.xcconfig | 0 .../example => example}/ios/Podfile | 0 .../example => example}/ios/Podfile.lock | 0 .../ios/Runner.xcodeproj/project.pbxproj | 0 .../contents.xcworkspacedata | 0 .../xcshareddata/IDEWorkspaceChecks.plist | 0 .../xcshareddata/WorkspaceSettings.xcsettings | 0 .../xcshareddata/xcschemes/Runner.xcscheme | 0 .../contents.xcworkspacedata | 0 .../xcshareddata/IDEWorkspaceChecks.plist | 0 .../xcshareddata/WorkspaceSettings.xcsettings | 0 .../ios/Runner/AppDelegate.swift | 0 .../AppIcon.appiconset/Contents.json | 0 .../Icon-App-1024x1024@1x.png | Bin .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin .../Icon-App-83.5x83.5@2x.png | Bin .../LaunchImage.imageset/Contents.json | 0 .../LaunchImage.imageset/LaunchImage.png | Bin .../LaunchImage.imageset/LaunchImage@2x.png | Bin .../LaunchImage.imageset/LaunchImage@3x.png | Bin .../LaunchImage.imageset/README.md | 0 .../Runner/Base.lproj/LaunchScreen.storyboard | 0 .../ios/Runner/Base.lproj/Main.storyboard | 0 .../example => example}/ios/Runner/Info.plist | 0 .../ios/Runner/Runner-Bridging-Header.h | 0 .../example => example}/lib/main.dart | 0 .../example => example}/pubspec.lock | 23 +- .../example => example}/pubspec.yaml | 0 .../example => example}/web/favicon.png | Bin .../web/icons/Icon-192.png | Bin .../web/icons/Icon-512.png | Bin .../example => example}/web/index.html | 0 .../example => example}/web/manifest.json | 0 .../lib => lib}/async_button_builder.dart | 2 +- .../lib => lib}/src/async_button_builder.dart | 165 ++++-- .../src/button_state/button_state.dart | 0 .../button_state/button_state.freezed.dart | 0 melos.yaml | 28 -- melos_async_button.iml | 10 - melos_my_project.iml | 10 - packages/async_button_builder/.gitignore | 74 --- packages/async_button_builder/LICENSE | 1 - packages/async_button_builder/README.md | 147 ------ packages/async_button_builder/pubspec.lock | 182 ------- packages/async_button_core/.gitignore | 75 --- packages/async_button_core/.metadata | 10 - packages/async_button_core/CHANGELOG.md | 26 - packages/async_button_core/LICENSE | 1 - packages/async_button_core/README.md | 1 - packages/async_button_core/coverage/lcov.info | 0 .../async_button_core/example/example.dart | 33 -- .../lib/async_button_core.dart | 4 - packages/async_button_core/lib/src/types.dart | 200 -------- packages/async_button_core/pubspec.yaml | 22 - .../test/async_button_core_test.dart | 5 - packages/async_button_hook/.gitignore | 75 --- packages/async_button_hook/.metadata | 10 - packages/async_button_hook/CHANGELOG.md | 31 -- packages/async_button_hook/LICENSE | 1 - packages/async_button_hook/README.md | 142 ------ packages/async_button_hook/coverage/lcov.info | 0 packages/async_button_hook/example/.gitignore | 46 -- packages/async_button_hook/example/.metadata | 10 - packages/async_button_hook/example/README.md | 16 - .../example/analysis_options.yaml | 1 - .../example/android/.gitignore | 13 - .../example/android/app/build.gradle | 68 --- .../android/app/src/debug/AndroidManifest.xml | 7 - .../android/app/src/main/AndroidManifest.xml | 32 -- .../com/example/example/MainActivity.kt | 6 - .../res/drawable-v21/launch_background.xml | 12 - .../main/res/drawable/launch_background.xml | 12 - .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 544 -> 0 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 442 -> 0 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 721 -> 0 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 1031 -> 0 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 1443 -> 0 bytes .../app/src/main/res/values-night/styles.xml | 18 - .../app/src/main/res/values/styles.xml | 18 - .../app/src/profile/AndroidManifest.xml | 7 - .../example/android/build.gradle | 29 -- .../example/android/gradle.properties | 3 - .../gradle/wrapper/gradle-wrapper.properties | 6 - .../example/android/settings.gradle | 11 - .../async_button_hook/example/ios/.gitignore | 33 -- .../ios/Flutter/AppFrameworkInfo.plist | 26 - .../example/ios/Flutter/Debug.xcconfig | 1 - .../example/ios/Flutter/Release.xcconfig | 1 - .../ios/Runner.xcodeproj/project.pbxproj | 471 ------------------ .../contents.xcworkspacedata | 7 - .../xcshareddata/IDEWorkspaceChecks.plist | 8 - .../xcshareddata/WorkspaceSettings.xcsettings | 8 - .../xcshareddata/xcschemes/Runner.xcscheme | 91 ---- .../contents.xcworkspacedata | 7 - .../xcshareddata/IDEWorkspaceChecks.plist | 8 - .../xcshareddata/WorkspaceSettings.xcsettings | 8 - .../example/ios/Runner/AppDelegate.swift | 13 - .../AppIcon.appiconset/Contents.json | 122 ----- .../Icon-App-1024x1024@1x.png | Bin 10932 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 564 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 1283 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 1588 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 1025 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 1716 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 1920 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 1283 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 1895 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 2665 -> 0 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 2665 -> 0 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 3831 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 1888 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 3294 -> 0 bytes .../Icon-App-83.5x83.5@2x.png | Bin 3612 -> 0 bytes .../LaunchImage.imageset/Contents.json | 23 - .../LaunchImage.imageset/LaunchImage.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/LaunchImage@2x.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/LaunchImage@3x.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/README.md | 5 - .../Runner/Base.lproj/LaunchScreen.storyboard | 37 -- .../ios/Runner/Base.lproj/Main.storyboard | 26 - .../example/ios/Runner/Info.plist | 45 -- .../ios/Runner/Runner-Bridging-Header.h | 1 - .../async_button_hook/example/lib/main.dart | 168 ------- .../async_button_hook/example/pubspec.lock | 203 -------- .../async_button_hook/example/pubspec.yaml | 92 ---- .../async_button_hook/example/web/favicon.png | Bin 917 -> 0 bytes .../example/web/icons/Icon-192.png | Bin 5292 -> 0 bytes .../example/web/icons/Icon-512.png | Bin 8252 -> 0 bytes .../example/web/icons/Icon-maskable-192.png | Bin 5594 -> 0 bytes .../example/web/icons/Icon-maskable-512.png | Bin 20998 -> 0 bytes .../async_button_hook/example/web/index.html | 101 ---- .../example/web/manifest.json | 35 -- .../lib/async_button_hook.dart | 4 - .../lib/src/async_button_hook.dart | 218 -------- .../lib/src/models/async_button_result.dart | 22 - packages/async_button_hook/pubspec.lock | 189 ------- packages/async_button_hook/pubspec.yaml | 21 - .../test/async_button_hook_test.dart | 5 - .../pubspec.lock => pubspec.lock | 53 +- .../pubspec.yaml => pubspec.yaml | 15 +- .../async_button_builder_test.dart | 0 185 files changed, 326 insertions(+), 3509 deletions(-) rename packages/async_button_builder/.metadata => .metadata (100%) create mode 100644 .vscode/settings.json rename packages/async_button_builder/CHANGELOG.md => CHANGELOG.md (96%) rename {packages/async_button_builder/coverage => coverage}/lcov.info (100%) rename {packages/async_button_builder/example => example}/.gitignore (100%) rename {packages/async_button_builder/example => example}/.metadata (100%) rename {packages/async_button_builder/example => example}/README.md (100%) rename {packages/async_button_builder/example => example}/analysis_options.yaml (100%) rename {packages/async_button_builder/example => example}/android/.gitignore (100%) rename {packages/async_button_builder/example => example}/android/app/build.gradle (100%) rename {packages/async_button_builder/example => example}/android/app/src/debug/AndroidManifest.xml (100%) rename {packages/async_button_builder/example => example}/android/app/src/main/AndroidManifest.xml (100%) rename {packages/async_button_builder/example => example}/android/app/src/main/kotlin/com/example/example/MainActivity.kt (100%) rename {packages/async_button_builder/example => example}/android/app/src/main/res/drawable-v21/launch_background.xml (100%) rename {packages/async_button_builder/example => example}/android/app/src/main/res/drawable/launch_background.xml (100%) rename {packages/async_button_builder/example => example}/android/app/src/main/res/mipmap-hdpi/ic_launcher.png (100%) rename {packages/async_button_builder/example => example}/android/app/src/main/res/mipmap-mdpi/ic_launcher.png (100%) rename {packages/async_button_builder/example => example}/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png (100%) rename {packages/async_button_builder/example => example}/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png (100%) rename {packages/async_button_builder/example => example}/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png (100%) rename {packages/async_button_builder/example => example}/android/app/src/main/res/values-night/styles.xml (100%) rename {packages/async_button_builder/example => example}/android/app/src/main/res/values/styles.xml (100%) rename {packages/async_button_builder/example => example}/android/app/src/profile/AndroidManifest.xml (100%) rename {packages/async_button_builder/example => example}/android/build.gradle (100%) rename {packages/async_button_builder/example => example}/android/gradle.properties (100%) rename {packages/async_button_builder/example => example}/android/gradle/wrapper/gradle-wrapper.properties (100%) rename {packages/async_button_builder/example => example}/android/settings.gradle (100%) rename {packages/async_button_builder/example => example}/ios/.gitignore (100%) rename {packages/async_button_builder/example => example}/ios/Flutter/AppFrameworkInfo.plist (100%) rename {packages/async_button_builder/example => example}/ios/Flutter/Debug.xcconfig (100%) rename {packages/async_button_builder/example => example}/ios/Flutter/Release.xcconfig (100%) rename {packages/async_button_builder/example => example}/ios/Podfile (100%) rename {packages/async_button_builder/example => example}/ios/Podfile.lock (100%) rename {packages/async_button_builder/example => example}/ios/Runner.xcodeproj/project.pbxproj (100%) rename {packages/async_button_builder/example => example}/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata (100%) rename {packages/async_button_builder/example => example}/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (100%) rename {packages/async_button_builder/example => example}/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings (100%) rename {packages/async_button_builder/example => example}/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme (100%) rename {packages/async_button_builder/example => example}/ios/Runner.xcworkspace/contents.xcworkspacedata (100%) rename {packages/async_button_builder/example => example}/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (100%) rename {packages/async_button_builder/example => example}/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings (100%) rename {packages/async_button_builder/example => example}/ios/Runner/AppDelegate.swift (100%) rename {packages/async_button_builder/example => example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) rename {packages/async_button_builder/example => example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png (100%) rename {packages/async_button_builder/example => example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png (100%) rename {packages/async_button_builder/example => example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png (100%) rename {packages/async_button_builder/example => example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png (100%) rename {packages/async_button_builder/example => example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png (100%) rename {packages/async_button_builder/example => example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png (100%) rename {packages/async_button_builder/example => example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png (100%) rename {packages/async_button_builder/example => example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png (100%) rename {packages/async_button_builder/example => example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png (100%) rename {packages/async_button_builder/example => example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png (100%) rename {packages/async_button_builder/example => example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png (100%) rename {packages/async_button_builder/example => example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png (100%) rename {packages/async_button_builder/example => example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png (100%) rename {packages/async_button_builder/example => example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png (100%) rename {packages/async_button_builder/example => example}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png (100%) rename {packages/async_button_builder/example => example}/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json (100%) rename {packages/async_button_builder/example => example}/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png (100%) rename {packages/async_button_builder/example => example}/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png (100%) rename {packages/async_button_builder/example => example}/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png (100%) rename {packages/async_button_builder/example => example}/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md (100%) rename {packages/async_button_builder/example => example}/ios/Runner/Base.lproj/LaunchScreen.storyboard (100%) rename {packages/async_button_builder/example => example}/ios/Runner/Base.lproj/Main.storyboard (100%) rename {packages/async_button_builder/example => example}/ios/Runner/Info.plist (100%) rename {packages/async_button_builder/example => example}/ios/Runner/Runner-Bridging-Header.h (100%) rename {packages/async_button_builder/example => example}/lib/main.dart (100%) rename {packages/async_button_builder/example => example}/pubspec.lock (92%) rename {packages/async_button_builder/example => example}/pubspec.yaml (100%) rename {packages/async_button_builder/example => example}/web/favicon.png (100%) rename {packages/async_button_builder/example => example}/web/icons/Icon-192.png (100%) rename {packages/async_button_builder/example => example}/web/icons/Icon-512.png (100%) rename {packages/async_button_builder/example => example}/web/index.html (100%) rename {packages/async_button_builder/example => example}/web/manifest.json (100%) rename {packages/async_button_builder/lib => lib}/async_button_builder.dart (60%) rename {packages/async_button_builder/lib => lib}/src/async_button_builder.dart (60%) rename {packages/async_button_core/lib => lib}/src/button_state/button_state.dart (100%) rename {packages/async_button_core/lib => lib}/src/button_state/button_state.freezed.dart (100%) delete mode 100644 melos.yaml delete mode 100644 melos_async_button.iml delete mode 100644 melos_my_project.iml delete mode 100644 packages/async_button_builder/.gitignore delete mode 100644 packages/async_button_builder/LICENSE delete mode 100644 packages/async_button_builder/README.md delete mode 100644 packages/async_button_builder/pubspec.lock delete mode 100644 packages/async_button_core/.gitignore delete mode 100644 packages/async_button_core/.metadata delete mode 100644 packages/async_button_core/CHANGELOG.md delete mode 100644 packages/async_button_core/LICENSE delete mode 100644 packages/async_button_core/README.md delete mode 100644 packages/async_button_core/coverage/lcov.info delete mode 100644 packages/async_button_core/example/example.dart delete mode 100644 packages/async_button_core/lib/async_button_core.dart delete mode 100644 packages/async_button_core/lib/src/types.dart delete mode 100644 packages/async_button_core/pubspec.yaml delete mode 100644 packages/async_button_core/test/async_button_core_test.dart delete mode 100644 packages/async_button_hook/.gitignore delete mode 100644 packages/async_button_hook/.metadata delete mode 100644 packages/async_button_hook/CHANGELOG.md delete mode 100644 packages/async_button_hook/LICENSE delete mode 100644 packages/async_button_hook/README.md delete mode 100644 packages/async_button_hook/coverage/lcov.info delete mode 100644 packages/async_button_hook/example/.gitignore delete mode 100644 packages/async_button_hook/example/.metadata delete mode 100644 packages/async_button_hook/example/README.md delete mode 100644 packages/async_button_hook/example/analysis_options.yaml delete mode 100644 packages/async_button_hook/example/android/.gitignore delete mode 100644 packages/async_button_hook/example/android/app/build.gradle delete mode 100644 packages/async_button_hook/example/android/app/src/debug/AndroidManifest.xml delete mode 100644 packages/async_button_hook/example/android/app/src/main/AndroidManifest.xml delete mode 100644 packages/async_button_hook/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt delete mode 100644 packages/async_button_hook/example/android/app/src/main/res/drawable-v21/launch_background.xml delete mode 100644 packages/async_button_hook/example/android/app/src/main/res/drawable/launch_background.xml delete mode 100644 packages/async_button_hook/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png delete mode 100644 packages/async_button_hook/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png delete mode 100644 packages/async_button_hook/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png delete mode 100644 packages/async_button_hook/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png delete mode 100644 packages/async_button_hook/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png delete mode 100644 packages/async_button_hook/example/android/app/src/main/res/values-night/styles.xml delete mode 100644 packages/async_button_hook/example/android/app/src/main/res/values/styles.xml delete mode 100644 packages/async_button_hook/example/android/app/src/profile/AndroidManifest.xml delete mode 100644 packages/async_button_hook/example/android/build.gradle delete mode 100644 packages/async_button_hook/example/android/gradle.properties delete mode 100644 packages/async_button_hook/example/android/gradle/wrapper/gradle-wrapper.properties delete mode 100644 packages/async_button_hook/example/android/settings.gradle delete mode 100644 packages/async_button_hook/example/ios/.gitignore delete mode 100644 packages/async_button_hook/example/ios/Flutter/AppFrameworkInfo.plist delete mode 100644 packages/async_button_hook/example/ios/Flutter/Debug.xcconfig delete mode 100644 packages/async_button_hook/example/ios/Flutter/Release.xcconfig delete mode 100644 packages/async_button_hook/example/ios/Runner.xcodeproj/project.pbxproj delete mode 100644 packages/async_button_hook/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100644 packages/async_button_hook/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 packages/async_button_hook/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings delete mode 100644 packages/async_button_hook/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme delete mode 100644 packages/async_button_hook/example/ios/Runner.xcworkspace/contents.xcworkspacedata delete mode 100644 packages/async_button_hook/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 packages/async_button_hook/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings delete mode 100644 packages/async_button_hook/example/ios/Runner/AppDelegate.swift delete mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png delete mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png delete mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png delete mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png delete mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png delete mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png delete mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png delete mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png delete mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png delete mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png delete mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png delete mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png delete mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png delete mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png delete mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png delete mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json delete mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png delete mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png delete mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png delete mode 100644 packages/async_button_hook/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md delete mode 100644 packages/async_button_hook/example/ios/Runner/Base.lproj/LaunchScreen.storyboard delete mode 100644 packages/async_button_hook/example/ios/Runner/Base.lproj/Main.storyboard delete mode 100644 packages/async_button_hook/example/ios/Runner/Info.plist delete mode 100644 packages/async_button_hook/example/ios/Runner/Runner-Bridging-Header.h delete mode 100644 packages/async_button_hook/example/lib/main.dart delete mode 100644 packages/async_button_hook/example/pubspec.lock delete mode 100644 packages/async_button_hook/example/pubspec.yaml delete mode 100644 packages/async_button_hook/example/web/favicon.png delete mode 100644 packages/async_button_hook/example/web/icons/Icon-192.png delete mode 100644 packages/async_button_hook/example/web/icons/Icon-512.png delete mode 100644 packages/async_button_hook/example/web/icons/Icon-maskable-192.png delete mode 100644 packages/async_button_hook/example/web/icons/Icon-maskable-512.png delete mode 100644 packages/async_button_hook/example/web/index.html delete mode 100644 packages/async_button_hook/example/web/manifest.json delete mode 100644 packages/async_button_hook/lib/async_button_hook.dart delete mode 100644 packages/async_button_hook/lib/src/async_button_hook.dart delete mode 100644 packages/async_button_hook/lib/src/models/async_button_result.dart delete mode 100644 packages/async_button_hook/pubspec.lock delete mode 100644 packages/async_button_hook/pubspec.yaml delete mode 100644 packages/async_button_hook/test/async_button_hook_test.dart rename packages/async_button_core/pubspec.lock => pubspec.lock (94%) rename packages/async_button_builder/pubspec.yaml => pubspec.yaml (68%) rename {packages/async_button_builder/test => test}/async_button_builder_test.dart (100%) diff --git a/.github/workflows/dart.yaml b/.github/workflows/dart.yaml index 8496493..b104a73 100644 --- a/.github/workflows/dart.yaml +++ b/.github/workflows/dart.yaml @@ -5,7 +5,7 @@ on: pull_request: schedule: # runs the CI everyday at 10AM - - cron: '0 10 * * *' + - cron: "0 10 * * *" jobs: flutter: @@ -18,17 +18,14 @@ jobs: - name: "Install Flutter" uses: subosito/flutter-action@v1 - - name: "Install Tools" - run: flutter pub global activate melos + - name: Install dependencies + run: flutter pub get - - name: "Bootstrap Workspace" - run: melos bootstrap + - name: Check format + run: flutter format --set-exit-if-changed . - - name: "Dart Analyze" - run: melos run analyze + - name: Analyze + run: flutter analyze - - name: "Pub Check" - run: melos run lint:pub - - - name: "Flutter Test" - run: melos run test --no-select + - name: Run tests + run: flutter test diff --git a/packages/async_button_builder/.metadata b/.metadata similarity index 100% rename from packages/async_button_builder/.metadata rename to .metadata diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..7f69797 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "dart.runPubGetOnPubspecChanges": false +} \ No newline at end of file diff --git a/packages/async_button_builder/CHANGELOG.md b/CHANGELOG.md similarity index 96% rename from packages/async_button_builder/CHANGELOG.md rename to CHANGELOG.md index 897e78c..b732b05 100644 --- a/packages/async_button_builder/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## [3.0.0] - 2022-01-07 +Got rid of hook version as it was complicating a simple package and likely discouraging possible contributors. + ## [2.1.4] - 2021-09-28 Fix manual button state changes. Credit to @iliser diff --git a/README.md b/README.md index 77f094b..f200ba1 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,147 @@ -# async_button +# async_button_builder -[![melos](https://img.shields.io/badge/maintained%20with-melos-f700ff.svg?style=flat-square)](https://github.com/invertase/melos) +AsyncButtonBuilder offers a simple way to extend any type of button with an asynchronous aspect. It allows adding loading, disabled, errored and completed states (with fluid animation between each) on top of buttons that perform asynchronous tasks. -AsyncButton offers a simple way to extend any type of button with an asynchronous aspect. It comes in two flavors that are independent (so no additional dependencies) of `builder` or `hook` pattern. Note, the hook version does rely on `flutter_hooks` for use. Either method allows adding loading, disabled, errored and completed states (with fluid animation between each) on top of buttons that perform asynchronous tasks. +## Getting Started -To see the respective guides see here: +Include the package: -### [async_button_builder](https://github.com/Nolence/async_button/tree/main/packages/async_button_builder) 🪝 +```yaml + async_button_builder: +``` -### [async_button_hook](https://github.com/Nolence/async_button/tree/main/packages/async_button_hook) 🏗️ \ No newline at end of file +Wrap the builder around a button, passing the onPressed and child element to builder instead of the button directly. These two are the only required fields. + +```dart +AsyncButtonBuilder( + child: Text('Click Me'), + onPressed: () async { + await Future.delayed(Duration(seconds: 1)); + }, + builder: (context, child, callback, _) { + return TextButton( + child: child, + onPressed: callback, + ); + }, +), +``` + +

+ +

+ +The fourth value in the builder allows you listen to the loading state. This can be used to conditionally style the button. This package depends `freezed` in order to create a sealed union to better handle the possible states. + +```dart +AsyncButtonBuilder( + child: Text('Click Me'), + loadingWidget: Text('Loading...'), + onPressed: () async { + await Future.delayed(Duration(seconds: 1)); + + // See the examples file for a way to handle timeouts + throw 'shucks'; + }, + builder: (context, child, callback, buttonState) { + final buttonColor = buttonState.when( + idle: () => Colors.yellow[200], + loading: () => Colors.grey, + success: () => Colors.orangeAccent, + error: () => Colors.orange, + ); + + return OutlinedButton( + child: child, + onPressed: callback, + style: OutlinedButton.styleFrom( + primary: Colors.black, + backgroundColor: buttonColor, + ), + ); + }, +), +``` + +

+ +

+ +You can also drive the state of the button yourself using the `buttonState` field: + +```dart +AsyncButtonBuilder( + buttonState: ButtonState.completing(), + // ... +), +``` + +`async_button_builder` even works for custom buttons. You can define your own widgets for loading, error, and completion as well as define the transitions between them. This example is a little verbose but shows some of what's possible. + + +```dart +AsyncButtonBuilder( + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16.0, + vertical: 8.0, + ), + child: Text( + 'Click Me', + style: TextStyle(color: Colors.white), + ), + ), + loadingWidget: Padding( + padding: const EdgeInsets.all(8.0), + child: SizedBox( + height: 16.0, + width: 16.0, + child: CircularProgressIndicator( + valueColor: AlwaysStoppedAnimation(Colors.white), + ), + ), + ), + successWidget: Padding( + padding: const EdgeInsets.all(4.0), + child: Icon( + Icons.check, + color: Colors.purpleAccent, + ), + ), + onPressed: () async { + await Future.delayed(Duration(seconds: 2)); + }, + loadingSwitchInCurve: Curves.bounceInOut, + loadingTransitionBuilder: (child, animation) { + return SlideTransition( + position: Tween( + begin: Offset(0, 1.0), + end: Offset(0, 0), + ).animate(animation), + child: child, + ); + }, + builder: (context, child, callback, state) { + return Material( + color: state.maybeWhen( + success: () => Colors.purple[100], + orElse: () => Colors.blue, + ), + // This prevents the loading indicator showing below the + // button + clipBehavior: Clip.hardEdge, + shape: StadiumBorder(), + child: InkWell( + child: child, + onTap: callback, + ), + ); + }, +), +``` + +

+ +

+ +Issues and PR's welcome \ No newline at end of file diff --git a/packages/async_button_builder/coverage/lcov.info b/coverage/lcov.info similarity index 100% rename from packages/async_button_builder/coverage/lcov.info rename to coverage/lcov.info diff --git a/packages/async_button_builder/example/.gitignore b/example/.gitignore similarity index 100% rename from packages/async_button_builder/example/.gitignore rename to example/.gitignore diff --git a/packages/async_button_builder/example/.metadata b/example/.metadata similarity index 100% rename from packages/async_button_builder/example/.metadata rename to example/.metadata diff --git a/packages/async_button_builder/example/README.md b/example/README.md similarity index 100% rename from packages/async_button_builder/example/README.md rename to example/README.md diff --git a/packages/async_button_builder/example/analysis_options.yaml b/example/analysis_options.yaml similarity index 100% rename from packages/async_button_builder/example/analysis_options.yaml rename to example/analysis_options.yaml diff --git a/packages/async_button_builder/example/android/.gitignore b/example/android/.gitignore similarity index 100% rename from packages/async_button_builder/example/android/.gitignore rename to example/android/.gitignore diff --git a/packages/async_button_builder/example/android/app/build.gradle b/example/android/app/build.gradle similarity index 100% rename from packages/async_button_builder/example/android/app/build.gradle rename to example/android/app/build.gradle diff --git a/packages/async_button_builder/example/android/app/src/debug/AndroidManifest.xml b/example/android/app/src/debug/AndroidManifest.xml similarity index 100% rename from packages/async_button_builder/example/android/app/src/debug/AndroidManifest.xml rename to example/android/app/src/debug/AndroidManifest.xml diff --git a/packages/async_button_builder/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml similarity index 100% rename from packages/async_button_builder/example/android/app/src/main/AndroidManifest.xml rename to example/android/app/src/main/AndroidManifest.xml diff --git a/packages/async_button_builder/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt b/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt similarity index 100% rename from packages/async_button_builder/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt rename to example/android/app/src/main/kotlin/com/example/example/MainActivity.kt diff --git a/packages/async_button_builder/example/android/app/src/main/res/drawable-v21/launch_background.xml b/example/android/app/src/main/res/drawable-v21/launch_background.xml similarity index 100% rename from packages/async_button_builder/example/android/app/src/main/res/drawable-v21/launch_background.xml rename to example/android/app/src/main/res/drawable-v21/launch_background.xml diff --git a/packages/async_button_builder/example/android/app/src/main/res/drawable/launch_background.xml b/example/android/app/src/main/res/drawable/launch_background.xml similarity index 100% rename from packages/async_button_builder/example/android/app/src/main/res/drawable/launch_background.xml rename to example/android/app/src/main/res/drawable/launch_background.xml diff --git a/packages/async_button_builder/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from packages/async_button_builder/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png rename to example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/packages/async_button_builder/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from packages/async_button_builder/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png rename to example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/packages/async_button_builder/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from packages/async_button_builder/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png rename to example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/packages/async_button_builder/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from packages/async_button_builder/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png rename to example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/packages/async_button_builder/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png similarity index 100% rename from packages/async_button_builder/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png rename to example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/packages/async_button_builder/example/android/app/src/main/res/values-night/styles.xml b/example/android/app/src/main/res/values-night/styles.xml similarity index 100% rename from packages/async_button_builder/example/android/app/src/main/res/values-night/styles.xml rename to example/android/app/src/main/res/values-night/styles.xml diff --git a/packages/async_button_builder/example/android/app/src/main/res/values/styles.xml b/example/android/app/src/main/res/values/styles.xml similarity index 100% rename from packages/async_button_builder/example/android/app/src/main/res/values/styles.xml rename to example/android/app/src/main/res/values/styles.xml diff --git a/packages/async_button_builder/example/android/app/src/profile/AndroidManifest.xml b/example/android/app/src/profile/AndroidManifest.xml similarity index 100% rename from packages/async_button_builder/example/android/app/src/profile/AndroidManifest.xml rename to example/android/app/src/profile/AndroidManifest.xml diff --git a/packages/async_button_builder/example/android/build.gradle b/example/android/build.gradle similarity index 100% rename from packages/async_button_builder/example/android/build.gradle rename to example/android/build.gradle diff --git a/packages/async_button_builder/example/android/gradle.properties b/example/android/gradle.properties similarity index 100% rename from packages/async_button_builder/example/android/gradle.properties rename to example/android/gradle.properties diff --git a/packages/async_button_builder/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from packages/async_button_builder/example/android/gradle/wrapper/gradle-wrapper.properties rename to example/android/gradle/wrapper/gradle-wrapper.properties diff --git a/packages/async_button_builder/example/android/settings.gradle b/example/android/settings.gradle similarity index 100% rename from packages/async_button_builder/example/android/settings.gradle rename to example/android/settings.gradle diff --git a/packages/async_button_builder/example/ios/.gitignore b/example/ios/.gitignore similarity index 100% rename from packages/async_button_builder/example/ios/.gitignore rename to example/ios/.gitignore diff --git a/packages/async_button_builder/example/ios/Flutter/AppFrameworkInfo.plist b/example/ios/Flutter/AppFrameworkInfo.plist similarity index 100% rename from packages/async_button_builder/example/ios/Flutter/AppFrameworkInfo.plist rename to example/ios/Flutter/AppFrameworkInfo.plist diff --git a/packages/async_button_builder/example/ios/Flutter/Debug.xcconfig b/example/ios/Flutter/Debug.xcconfig similarity index 100% rename from packages/async_button_builder/example/ios/Flutter/Debug.xcconfig rename to example/ios/Flutter/Debug.xcconfig diff --git a/packages/async_button_builder/example/ios/Flutter/Release.xcconfig b/example/ios/Flutter/Release.xcconfig similarity index 100% rename from packages/async_button_builder/example/ios/Flutter/Release.xcconfig rename to example/ios/Flutter/Release.xcconfig diff --git a/packages/async_button_builder/example/ios/Podfile b/example/ios/Podfile similarity index 100% rename from packages/async_button_builder/example/ios/Podfile rename to example/ios/Podfile diff --git a/packages/async_button_builder/example/ios/Podfile.lock b/example/ios/Podfile.lock similarity index 100% rename from packages/async_button_builder/example/ios/Podfile.lock rename to example/ios/Podfile.lock diff --git a/packages/async_button_builder/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj similarity index 100% rename from packages/async_button_builder/example/ios/Runner.xcodeproj/project.pbxproj rename to example/ios/Runner.xcodeproj/project.pbxproj diff --git a/packages/async_button_builder/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from packages/async_button_builder/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/packages/async_button_builder/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from packages/async_button_builder/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/packages/async_button_builder/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings similarity index 100% rename from packages/async_button_builder/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings rename to example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings diff --git a/packages/async_button_builder/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme similarity index 100% rename from packages/async_button_builder/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme rename to example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme diff --git a/packages/async_button_builder/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/example/ios/Runner.xcworkspace/contents.xcworkspacedata similarity index 100% rename from packages/async_button_builder/example/ios/Runner.xcworkspace/contents.xcworkspacedata rename to example/ios/Runner.xcworkspace/contents.xcworkspacedata diff --git a/packages/async_button_builder/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from packages/async_button_builder/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/packages/async_button_builder/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings similarity index 100% rename from packages/async_button_builder/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings rename to example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings diff --git a/packages/async_button_builder/example/ios/Runner/AppDelegate.swift b/example/ios/Runner/AppDelegate.swift similarity index 100% rename from packages/async_button_builder/example/ios/Runner/AppDelegate.swift rename to example/ios/Runner/AppDelegate.swift diff --git a/packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json rename to example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png similarity index 100% rename from packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png rename to example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png diff --git a/packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png similarity index 100% rename from packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png rename to example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png diff --git a/packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png similarity index 100% rename from packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png rename to example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png diff --git a/packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png similarity index 100% rename from packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png rename to example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png diff --git a/packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png similarity index 100% rename from packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png rename to example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png diff --git a/packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png similarity index 100% rename from packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png rename to example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png diff --git a/packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png similarity index 100% rename from packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png rename to example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png diff --git a/packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png similarity index 100% rename from packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png rename to example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png diff --git a/packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png similarity index 100% rename from packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png rename to example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png diff --git a/packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png similarity index 100% rename from packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png rename to example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png diff --git a/packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png similarity index 100% rename from packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png rename to example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png diff --git a/packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png similarity index 100% rename from packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png rename to example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png diff --git a/packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png similarity index 100% rename from packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png rename to example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png diff --git a/packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png similarity index 100% rename from packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png rename to example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png diff --git a/packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png similarity index 100% rename from packages/async_button_builder/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png rename to example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png diff --git a/packages/async_button_builder/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json similarity index 100% rename from packages/async_button_builder/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json rename to example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json diff --git a/packages/async_button_builder/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png similarity index 100% rename from packages/async_button_builder/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png rename to example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png diff --git a/packages/async_button_builder/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png similarity index 100% rename from packages/async_button_builder/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png rename to example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png diff --git a/packages/async_button_builder/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png similarity index 100% rename from packages/async_button_builder/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png rename to example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png diff --git a/packages/async_button_builder/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md similarity index 100% rename from packages/async_button_builder/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md rename to example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md diff --git a/packages/async_button_builder/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/example/ios/Runner/Base.lproj/LaunchScreen.storyboard similarity index 100% rename from packages/async_button_builder/example/ios/Runner/Base.lproj/LaunchScreen.storyboard rename to example/ios/Runner/Base.lproj/LaunchScreen.storyboard diff --git a/packages/async_button_builder/example/ios/Runner/Base.lproj/Main.storyboard b/example/ios/Runner/Base.lproj/Main.storyboard similarity index 100% rename from packages/async_button_builder/example/ios/Runner/Base.lproj/Main.storyboard rename to example/ios/Runner/Base.lproj/Main.storyboard diff --git a/packages/async_button_builder/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist similarity index 100% rename from packages/async_button_builder/example/ios/Runner/Info.plist rename to example/ios/Runner/Info.plist diff --git a/packages/async_button_builder/example/ios/Runner/Runner-Bridging-Header.h b/example/ios/Runner/Runner-Bridging-Header.h similarity index 100% rename from packages/async_button_builder/example/ios/Runner/Runner-Bridging-Header.h rename to example/ios/Runner/Runner-Bridging-Header.h diff --git a/packages/async_button_builder/example/lib/main.dart b/example/lib/main.dart similarity index 100% rename from packages/async_button_builder/example/lib/main.dart rename to example/lib/main.dart diff --git a/packages/async_button_builder/example/pubspec.lock b/example/pubspec.lock similarity index 92% rename from packages/async_button_builder/example/pubspec.lock rename to example/pubspec.lock index ab22eae..14e8a74 100644 --- a/packages/async_button_builder/example/pubspec.lock +++ b/example/pubspec.lock @@ -7,7 +7,7 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.8.1" + version: "2.8.2" async_button_builder: dependency: "direct main" description: @@ -15,13 +15,6 @@ packages: relative: true source: path version: "2.1.4" - async_button_core: - dependency: transitive - description: - name: async_button_core - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.1+7" boolean_selector: dependency: transitive description: @@ -35,7 +28,7 @@ packages: name: characters url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.2.0" charcode: dependency: transitive description: @@ -87,21 +80,21 @@ packages: name: freezed_annotation url: "https://pub.dartlang.org" source: hosted - version: "0.14.3" + version: "1.1.0" json_annotation: dependency: transitive description: name: json_annotation url: "https://pub.dartlang.org" source: hosted - version: "4.1.0" + version: "4.4.0" matcher: dependency: transitive description: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.10" + version: "0.12.11" meta: dependency: transitive description: @@ -169,7 +162,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.2" + version: "0.4.3" typed_data: dependency: transitive description: @@ -183,7 +176,7 @@ packages: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.1.1" sdks: - dart: ">=2.12.0 <3.0.0" + dart: ">=2.14.0 <3.0.0" flutter: ">=1.17.0" diff --git a/packages/async_button_builder/example/pubspec.yaml b/example/pubspec.yaml similarity index 100% rename from packages/async_button_builder/example/pubspec.yaml rename to example/pubspec.yaml diff --git a/packages/async_button_builder/example/web/favicon.png b/example/web/favicon.png similarity index 100% rename from packages/async_button_builder/example/web/favicon.png rename to example/web/favicon.png diff --git a/packages/async_button_builder/example/web/icons/Icon-192.png b/example/web/icons/Icon-192.png similarity index 100% rename from packages/async_button_builder/example/web/icons/Icon-192.png rename to example/web/icons/Icon-192.png diff --git a/packages/async_button_builder/example/web/icons/Icon-512.png b/example/web/icons/Icon-512.png similarity index 100% rename from packages/async_button_builder/example/web/icons/Icon-512.png rename to example/web/icons/Icon-512.png diff --git a/packages/async_button_builder/example/web/index.html b/example/web/index.html similarity index 100% rename from packages/async_button_builder/example/web/index.html rename to example/web/index.html diff --git a/packages/async_button_builder/example/web/manifest.json b/example/web/manifest.json similarity index 100% rename from packages/async_button_builder/example/web/manifest.json rename to example/web/manifest.json diff --git a/packages/async_button_builder/lib/async_button_builder.dart b/lib/async_button_builder.dart similarity index 60% rename from packages/async_button_builder/lib/async_button_builder.dart rename to lib/async_button_builder.dart index 58eb8e1..2548d3d 100644 --- a/packages/async_button_builder/lib/async_button_builder.dart +++ b/lib/async_button_builder.dart @@ -1,4 +1,4 @@ library async_button_builder; +export 'package:async_button_builder/async_button_builder.dart'; export 'package:async_button_builder/src/async_button_builder.dart'; -export 'package:async_button_core/async_button_core.dart'; diff --git a/packages/async_button_builder/lib/src/async_button_builder.dart b/lib/src/async_button_builder.dart similarity index 60% rename from packages/async_button_builder/lib/src/async_button_builder.dart rename to lib/src/async_button_builder.dart index 72b4dfe..d22ebcb 100644 --- a/packages/async_button_builder/lib/src/async_button_builder.dart +++ b/lib/src/async_button_builder.dart @@ -1,104 +1,198 @@ import 'dart:async'; -import 'package:async_button_core/async_button_core.dart'; +import 'package:async_button_builder/src/button_state/button_state.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -class AsyncButtonBuilder extends StatefulWidget implements AsyncButton { - @override +typedef AsyncButtonBuilderCallback = Widget Function( + BuildContext context, + Widget child, + AsyncCallback? callback, + ButtonState buttonState, +); + +/// A `builder` that wraps a button providing disabled, loading, success and +/// error states while retaining almost full access to the original Button's +/// API. This is useful for any long running operations and helps better +/// improve UX. +/// +/// {@tool dartpad --template=stateful_widget_material} +/// +/// ```dart +/// +/// @override +/// Widget build(BuildContext context) { +/// return AsyncButtonBuilder( +/// child: Text('Click Me'), +/// loadingWidget: Text('Loading...'), +/// onPressed: () async { +/// await Future.delayed(Duration(seconds: 1)); +/// +/// throw 'shucks'; +/// }, +/// builder: (context, child, callback, buttonState) { +/// final buttonColor = buttonState.when( +/// idle: () => Colors.yellow[200], +/// loading: () => Colors.grey, +/// success: () => Colors.orangeAccent, +/// error: () => Colors.orange, +/// ); +/// +/// return OutlinedButton( +/// child: child, +/// onPressed: callback, +/// style: OutlinedButton.styleFrom( +/// primary: Colors.black, +/// backgroundColor: buttonColor, +/// ), +/// ); +/// }, +/// ), +/// } +/// ``` +/// {@end-tool} +/// +class AsyncButtonBuilder extends StatefulWidget { + /// This builder provides the widget's [BuildContext], the variable [child] + /// based on button state as well as the [callback] that should be passed to + /// the button and the current [ButtonState] final AsyncButtonBuilderCallback builder; - @override + /// The child of the button. In the case of an [IconButton], this can be a an + /// [Icon]. For a [TextButton], a [Text]. + /// + /// This child will be animated between for the [loadingWidget] or default + /// [CircularProgressIndicator] when the asynchronous [onPressed] is called. + /// The animation will take place over [duration]. final Widget child; - @override + /// The animation's duration between [child], [loadingWidget], + /// [successWidget] and [errorWidget]. This same value is used for both the + /// internal [AnimatedSize] and [TransitionBuilder]. final Duration duration; - @override + /// The animation's reverse duration between [child], [loadingWidget], + /// [successWidget] and [errorWidget]. This same value is used for both the + /// internal [AnimatedSize] and [TransitionBuilder]. final Duration reverseDuration; - @override + /// A callback that runs the async task. This is wrapped in order to begin + /// the button's internal `isLoading` before and after the operation + /// completes. final AsyncCallback? onPressed; - @override + /// This is used to manually drive the state of the loading button thus + /// initiating the corresponding animation and showing the correct button + /// child. final ButtonState buttonState; - @override + /// This is used to manually drive the disabled state of the button. final bool disabled; - @override + /// The widget replaces the [child] when the button is in the loading state. + /// If this is null the default widget is: + /// + /// SizedBox( + /// height: 16.0, + /// width: 16.0, + /// child: CircularProgressIndicator(), + /// ) final Widget? loadingWidget; - @override + /// The widget used to replace the [child] when the button is in a success + /// state. If this is null the default widget is: + /// + /// Icon( + /// Icons.check, + /// color: Theme.of(context).accentColor, + /// ); final Widget? successWidget; - @override + /// The widget used to replace the [child] when the button is in a error + /// state. If this is null the default widget is: + /// + /// Icon( + /// Icons.error, + /// color: Theme.of(context).errorColor, + /// ) final Widget? errorWidget; - @override + /// Whether to show the [successWidget] on success. final bool showSuccess; - @override + /// Whether to show the [errorWidget] on error. final bool showError; - @override + /// Optional [EdgeInsets] that will wrap around the [errorWidget]. This is a + /// convenience field that can be replaced by defining your own [errorWidget] + /// and wrapping it in a [Padding]. final EdgeInsets? errorPadding; - @override + /// Optional [EdgeInsets] that will wrap around the [successWidget]. This is a + /// convenience field that can be replaced by defining your own + /// [successWidget] and wrapping it in a [Padding]. final EdgeInsets? successPadding; - @override + /// Defines a custom transition when animating between any state and `idle` final AnimatedSwitcherTransitionBuilder idleTransitionBuilder; - @override + /// Defines a custom transition when animating between any state and `loading` final AnimatedSwitcherTransitionBuilder loadingTransitionBuilder; - @override + /// Defines a custom transition when animating between any state and `success` final AnimatedSwitcherTransitionBuilder successTransitionBuilder; - @override + /// Defines a custom transition when animating between any state and `error` final AnimatedSwitcherTransitionBuilder errorTransitionBuilder; - @override + /// The amount of idle time the [successWidget] shows final Duration successDuration; - @override + /// The amount of idle time the [errorWidget] shows final Duration errorDuration; - @override + /// Defines a curve for the custom transition. This used in in an + /// [AnimatedSwitcher] and only takes effect when animating to `idle` final Curve idleSwitchInCurve; - @override + /// Defines a curve for the custom transition. This used in in an + /// [AnimatedSwitcher] and only takes effect when animating to `loading` final Curve loadingSwitchInCurve; - @override + /// Defines a curve for the custom transition. This used in in an + /// [AnimatedSwitcher] and only takes effect when animating to `success` final Curve successSwitchInCurve; - @override + /// Defines a curve for the custom transition. This used in in an + /// [AnimatedSwitcher] and only takes effect when animating to `error` final Curve errorSwitchInCurve; - @override + /// Defines a curve for the custom transition. This used in in an + /// [AnimatedSwitcher] and only takes effect when animating out of `idle` final Curve idleSwitchOutCurve; - @override + /// Defines a curve for the custom transition. This used in in an + /// [AnimatedSwitcher] and only takes effect when animating out of `loading` final Curve loadingSwitchOutCurve; - @override + /// Defines a curve for the custom transition. This used in in an + /// [AnimatedSwitcher] and only takes effect when animating out of `success` final Curve successSwitchOutCurve; - @override + /// Defines a curve for the custom transition. This used in in an + /// [AnimatedSwitcher] and only takes effect when animating out of `error` final Curve errorSwitchOutCurve; - @override + /// Defines a curve for the internal [AnimatedSize] final Curve sizeCurve; - @override + /// Defines the [Clip] for the internal [AnimatedSize] final Clip sizeClipBehavior; - @override + /// Defines the [Alignment] for the internal [AnimatedSize] final Alignment sizeAlignment; - @override + /// Whether to animate the [Size] of the widget implicitly. final bool animateSize; const AsyncButtonBuilder({ @@ -136,9 +230,6 @@ class AsyncButtonBuilder extends StatefulWidget implements AsyncButton { this.sizeAlignment = Alignment.center, this.animateSize = true, }) : super(key: key); - // TODO: I need asserts that will assert the keys are different for child, - // loading, error, etc. because otherwise transitions won't work as expected - // and I'll get user issues @override _AsyncButtonBuilderState createState() => _AsyncButtonBuilderState(); diff --git a/packages/async_button_core/lib/src/button_state/button_state.dart b/lib/src/button_state/button_state.dart similarity index 100% rename from packages/async_button_core/lib/src/button_state/button_state.dart rename to lib/src/button_state/button_state.dart diff --git a/packages/async_button_core/lib/src/button_state/button_state.freezed.dart b/lib/src/button_state/button_state.freezed.dart similarity index 100% rename from packages/async_button_core/lib/src/button_state/button_state.freezed.dart rename to lib/src/button_state/button_state.freezed.dart diff --git a/melos.yaml b/melos.yaml deleted file mode 100644 index d8ab91f..0000000 --- a/melos.yaml +++ /dev/null @@ -1,28 +0,0 @@ -name: async_button - -packages: - - packages/** - -scripts: - analyze: - run: | - melos exec -c 1 -- \ - flutter analyze . - description: | - Run `dart analyze` in all packages. - - Note: you can also rely on your IDEs Dart Analysis / Issues window. - - lint:pub: > - melos exec -c 5 --fail-fast --no-private --ignore="*example*" -- \ - pub publish --dry-run - - generate: - run: melos exec -c 1 --depends-on="build_runner" --flutter -- "flutter pub run build_runner build --delete-conflicting-outputs" - description: Build all generated files for Flutter packages in this project. - - test: - run: melos exec --dir-exists="test" -c 1 --fail-fast -- "flutter test --coverage" - description: Run Flutter tests for a specific package in this project. - select-package: - flutter: true - dir-exists: test \ No newline at end of file diff --git a/melos_async_button.iml b/melos_async_button.iml deleted file mode 100644 index 8be8bf8..0000000 --- a/melos_async_button.iml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/melos_my_project.iml b/melos_my_project.iml deleted file mode 100644 index 8be8bf8..0000000 --- a/melos_my_project.iml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/packages/async_button_builder/.gitignore b/packages/async_button_builder/.gitignore deleted file mode 100644 index 1985397..0000000 --- a/packages/async_button_builder/.gitignore +++ /dev/null @@ -1,74 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -.dart_tool/ -.flutter-plugins -.flutter-plugins-dependencies -.packages -.pub-cache/ -.pub/ -build/ - -# Android related -**/android/**/gradle-wrapper.jar -**/android/.gradle -**/android/captures/ -**/android/gradlew -**/android/gradlew.bat -**/android/local.properties -**/android/**/GeneratedPluginRegistrant.java - -# iOS/XCode related -**/ios/**/*.mode1v3 -**/ios/**/*.mode2v3 -**/ios/**/*.moved-aside -**/ios/**/*.pbxuser -**/ios/**/*.perspectivev3 -**/ios/**/*sync/ -**/ios/**/.sconsign.dblite -**/ios/**/.tags* -**/ios/**/.vagrant/ -**/ios/**/DerivedData/ -**/ios/**/Icon? -**/ios/**/Pods/ -**/ios/**/.symlinks/ -**/ios/**/profile -**/ios/**/xcuserdata -**/ios/.generated/ -**/ios/Flutter/App.framework -**/ios/Flutter/Flutter.framework -**/ios/Flutter/Flutter.podspec -**/ios/Flutter/Generated.xcconfig -**/ios/Flutter/app.flx -**/ios/Flutter/app.zip -**/ios/Flutter/flutter_assets/ -**/ios/Flutter/flutter_export_environment.sh -**/ios/ServiceDefinitions.json -**/ios/Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!**/ios/**/default.mode1v3 -!**/ios/**/default.mode2v3 -!**/ios/**/default.pbxuser -!**/ios/**/default.perspectivev3 diff --git a/packages/async_button_builder/LICENSE b/packages/async_button_builder/LICENSE deleted file mode 100644 index 30cff74..0000000 --- a/packages/async_button_builder/LICENSE +++ /dev/null @@ -1 +0,0 @@ -../../LICENSE \ No newline at end of file diff --git a/packages/async_button_builder/README.md b/packages/async_button_builder/README.md deleted file mode 100644 index 060b2d2..0000000 --- a/packages/async_button_builder/README.md +++ /dev/null @@ -1,147 +0,0 @@ -# async_button_builder - -[![melos](https://img.shields.io/badge/maintained%20with-melos-f700ff.svg?style=flat-square)](https://github.com/invertase/melos) - -## Getting Started - -Include the package: - -```yaml - async_button_builder: -``` - -Wrap the builder around a button, passing the onPressed and child element to builder instead of the button directly. These two are the only required fields. - -```dart -AsyncButtonBuilder( - child: Text('Click Me'), - onPressed: () async { - await Future.delayed(Duration(seconds: 1)); - }, - builder: (context, child, callback, _) { - return TextButton( - child: child, - onPressed: callback, - ); - }, -), -``` - -

- -

- -The fourth value in the builder allows you listen to the loading state. This can be used to conditionally style the button. This package depends `freezed` in order to create a sealed union to better handle the possible states. - -```dart -AsyncButtonBuilder( - child: Text('Click Me'), - loadingWidget: Text('Loading...'), - onPressed: () async { - await Future.delayed(Duration(seconds: 1)); - - // See the examples file for a way to handle timeouts - throw 'shucks'; - }, - builder: (context, child, callback, buttonState) { - final buttonColor = buttonState.when( - idle: () => Colors.yellow[200], - loading: () => Colors.grey, - success: () => Colors.orangeAccent, - error: () => Colors.orange, - ); - - return OutlinedButton( - child: child, - onPressed: callback, - style: OutlinedButton.styleFrom( - primary: Colors.black, - backgroundColor: buttonColor, - ), - ); - }, -), -``` - -

- -

- -You can also drive the state of the button yourself using the `buttonState` field: - -```dart -AsyncButtonBuilder( - buttonState: ButtonState.completing(), - // ... -), -``` - -`async_button_builder` even works for custom buttons. You can define your own widgets for loading, error, and completion as well as define the transitions between them. This example is a little verbose but shows some of what's possible. - - -```dart -AsyncButtonBuilder( - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 16.0, - vertical: 8.0, - ), - child: Text( - 'Click Me', - style: TextStyle(color: Colors.white), - ), - ), - loadingWidget: Padding( - padding: const EdgeInsets.all(8.0), - child: SizedBox( - height: 16.0, - width: 16.0, - child: CircularProgressIndicator( - valueColor: AlwaysStoppedAnimation(Colors.white), - ), - ), - ), - successWidget: Padding( - padding: const EdgeInsets.all(4.0), - child: Icon( - Icons.check, - color: Colors.purpleAccent, - ), - ), - onPressed: () async { - await Future.delayed(Duration(seconds: 2)); - }, - loadingSwitchInCurve: Curves.bounceInOut, - loadingTransitionBuilder: (child, animation) { - return SlideTransition( - position: Tween( - begin: Offset(0, 1.0), - end: Offset(0, 0), - ).animate(animation), - child: child, - ); - }, - builder: (context, child, callback, state) { - return Material( - color: state.maybeWhen( - success: () => Colors.purple[100], - orElse: () => Colors.blue, - ), - // This prevents the loading indicator showing below the - // button - clipBehavior: Clip.hardEdge, - shape: StadiumBorder(), - child: InkWell( - child: child, - onTap: callback, - ), - ); - }, -), -``` - -

- -

- -Issues and PR's welcome \ No newline at end of file diff --git a/packages/async_button_builder/pubspec.lock b/packages/async_button_builder/pubspec.lock deleted file mode 100644 index 7775898..0000000 --- a/packages/async_button_builder/pubspec.lock +++ /dev/null @@ -1,182 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - async: - dependency: transitive - description: - name: async - url: "https://pub.dartlang.org" - source: hosted - version: "2.8.1" - async_button_core: - dependency: "direct main" - description: - name: async_button_core - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.1+7" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - characters: - dependency: transitive - description: - name: characters - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.1" - clock: - dependency: transitive - description: - name: clock - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - collection: - dependency: transitive - description: - name: collection - url: "https://pub.dartlang.org" - source: hosted - version: "1.15.0" - fake_async: - dependency: transitive - description: - name: fake_async - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.4" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - freezed_annotation: - dependency: transitive - description: - name: freezed_annotation - url: "https://pub.dartlang.org" - source: hosted - version: "0.14.3" - json_annotation: - dependency: transitive - description: - name: json_annotation - url: "https://pub.dartlang.org" - source: hosted - version: "4.1.0" - lints: - dependency: transitive - description: - name: lints - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" - matcher: - dependency: transitive - description: - name: matcher - url: "https://pub.dartlang.org" - source: hosted - version: "0.12.10" - meta: - dependency: transitive - description: - name: meta - url: "https://pub.dartlang.org" - source: hosted - version: "1.7.0" - path: - dependency: transitive - description: - name: path - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.0" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.99" - source_span: - dependency: transitive - description: - name: source_span - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.1" - stack_trace: - dependency: transitive - description: - name: stack_trace - url: "https://pub.dartlang.org" - source: hosted - version: "1.10.0" - stream_channel: - dependency: transitive - description: - name: stream_channel - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - string_scanner: - dependency: transitive - description: - name: string_scanner - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - term_glyph: - dependency: transitive - description: - name: term_glyph - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - test_api: - dependency: transitive - description: - name: test_api - url: "https://pub.dartlang.org" - source: hosted - version: "0.4.2" - typed_data: - dependency: transitive - description: - name: typed_data - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.0" - vector_math: - dependency: transitive - description: - name: vector_math - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" -sdks: - dart: ">=2.12.0 <3.0.0" - flutter: ">=1.17.0" diff --git a/packages/async_button_core/.gitignore b/packages/async_button_core/.gitignore deleted file mode 100644 index a247422..0000000 --- a/packages/async_button_core/.gitignore +++ /dev/null @@ -1,75 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -.dart_tool/ -.flutter-plugins -.flutter-plugins-dependencies -.packages -.pub-cache/ -.pub/ -build/ - -# Android related -**/android/**/gradle-wrapper.jar -**/android/.gradle -**/android/captures/ -**/android/gradlew -**/android/gradlew.bat -**/android/local.properties -**/android/**/GeneratedPluginRegistrant.java - -# iOS/XCode related -**/ios/**/*.mode1v3 -**/ios/**/*.mode2v3 -**/ios/**/*.moved-aside -**/ios/**/*.pbxuser -**/ios/**/*.perspectivev3 -**/ios/**/*sync/ -**/ios/**/.sconsign.dblite -**/ios/**/.tags* -**/ios/**/.vagrant/ -**/ios/**/DerivedData/ -**/ios/**/Icon? -**/ios/**/Pods/ -**/ios/**/.symlinks/ -**/ios/**/profile -**/ios/**/xcuserdata -**/ios/.generated/ -**/ios/Flutter/App.framework -**/ios/Flutter/Flutter.framework -**/ios/Flutter/Flutter.podspec -**/ios/Flutter/Generated.xcconfig -**/ios/Flutter/ephemeral -**/ios/Flutter/app.flx -**/ios/Flutter/app.zip -**/ios/Flutter/flutter_assets/ -**/ios/Flutter/flutter_export_environment.sh -**/ios/ServiceDefinitions.json -**/ios/Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!**/ios/**/default.mode1v3 -!**/ios/**/default.mode2v3 -!**/ios/**/default.pbxuser -!**/ios/**/default.perspectivev3 diff --git a/packages/async_button_core/.metadata b/packages/async_button_core/.metadata deleted file mode 100644 index b6da989..0000000 --- a/packages/async_button_core/.metadata +++ /dev/null @@ -1,10 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled and should not be manually edited. - -version: - revision: 225a43d941ddd1753765fec3682011e9ddffb11d - channel: dev - -project_type: package diff --git a/packages/async_button_core/CHANGELOG.md b/packages/async_button_core/CHANGELOG.md deleted file mode 100644 index 0fe48f3..0000000 --- a/packages/async_button_core/CHANGELOG.md +++ /dev/null @@ -1,26 +0,0 @@ -## 0.0.1+8 - 2021-09-28 -Upgraded deps - -## 0.0.1+7 - 2021-09-28 -Upgraded deps - -## 0.0.1+6 - 2021-09-28 -Upgraded deps - -## 0.0.1+5 - 2021-09-08 -Fixed github actions - -## 0.0.1+4 - 2021-08-27 -Trying to fix pub stuff - -## 0.0.1+3 - 2021-08-27 -Trying to fix pub stuff - -## 0.0.1+2 - 2021-08-27 -Fixed home page - -## 0.0.1+1 - 2021-08-19 -Updated exports to include types - -## 0.0.1 - 2021-08-18 -Initial release diff --git a/packages/async_button_core/LICENSE b/packages/async_button_core/LICENSE deleted file mode 100644 index 30cff74..0000000 --- a/packages/async_button_core/LICENSE +++ /dev/null @@ -1 +0,0 @@ -../../LICENSE \ No newline at end of file diff --git a/packages/async_button_core/README.md b/packages/async_button_core/README.md deleted file mode 100644 index fe84005..0000000 --- a/packages/async_button_core/README.md +++ /dev/null @@ -1 +0,0 @@ -../../README.md \ No newline at end of file diff --git a/packages/async_button_core/coverage/lcov.info b/packages/async_button_core/coverage/lcov.info deleted file mode 100644 index e69de29..0000000 diff --git a/packages/async_button_core/example/example.dart b/packages/async_button_core/example/example.dart deleted file mode 100644 index 1ebdbe1..0000000 --- a/packages/async_button_core/example/example.dart +++ /dev/null @@ -1,33 +0,0 @@ -import 'package:flutter/material.dart'; - -void main() { - runApp(const MyApp()); -} - -class MyApp extends StatefulWidget { - const MyApp({Key? key}) : super(key: key); - - @override - _MyAppState createState() => _MyAppState(); -} - -class _MyAppState extends State { - @override - void initState() { - super.initState(); - } - - @override - Widget build(BuildContext context) { - return MaterialApp( - home: Scaffold( - appBar: AppBar( - title: const Text('Plugin example app'), - ), - body: const Center( - child: Text('A simple flutter example\n'), - ), - ), - ); - } -} diff --git a/packages/async_button_core/lib/async_button_core.dart b/packages/async_button_core/lib/async_button_core.dart deleted file mode 100644 index b36931b..0000000 --- a/packages/async_button_core/lib/async_button_core.dart +++ /dev/null @@ -1,4 +0,0 @@ -library async_button_core; - -export 'package:async_button_core/src/button_state/button_state.dart'; -export 'package:async_button_core/src/types.dart'; diff --git a/packages/async_button_core/lib/src/types.dart b/packages/async_button_core/lib/src/types.dart deleted file mode 100644 index 98e56c6..0000000 --- a/packages/async_button_core/lib/src/types.dart +++ /dev/null @@ -1,200 +0,0 @@ -import 'package:async_button_core/async_button_core.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; - -typedef AsyncButtonBuilderCallback = Widget Function( - BuildContext context, - Widget child, - AsyncCallback? callback, - ButtonState buttonState, -); - -// TODO: I created this class so I can do dartdoc stuff and use it in both -// the builder and the hook. Currently not paying off. - -/// A `builder` that wraps a button providing disabled, loading, success and -/// error states while retaining almost full access to the original Button's -/// API. This is useful for any long running operations and helps better -/// improve UX. -/// -/// {@tool dartpad --template=stateful_widget_material} -/// -/// ```dart -/// -/// @override -/// Widget build(BuildContext context) { -/// return AsyncButtonBuilder( -/// child: Text('Click Me'), -/// loadingWidget: Text('Loading...'), -/// onPressed: () async { -/// await Future.delayed(Duration(seconds: 1)); -/// -/// throw 'shucks'; -/// }, -/// builder: (context, child, callback, buttonState) { -/// final buttonColor = buttonState.when( -/// idle: () => Colors.yellow[200], -/// loading: () => Colors.grey, -/// success: () => Colors.orangeAccent, -/// error: () => Colors.orange, -/// ); -/// -/// return OutlinedButton( -/// child: child, -/// onPressed: callback, -/// style: OutlinedButton.styleFrom( -/// primary: Colors.black, -/// backgroundColor: buttonColor, -/// ), -/// ); -/// }, -/// ), -/// } -/// ``` -/// {@end-tool} -/// -abstract class AsyncButton { - /// This builder provides the widget's [BuildContext], the variable [child] - /// based on button state as well as the [callback] that should be passed to - /// the button and the current [ButtonState] - AsyncButtonBuilderCallback get builder; - - /// {@template asyncButton.interface.child} - /// The child of the button. In the case of an [IconButton], this can be a an - /// [Icon]. For a [TextButton], a [Text]. - /// - /// This child will be animated between for the [loadingWidget] or default - /// [CircularProgressIndicator] when the asynchronous [onPressed] is called. - /// The animation will take place over [duration]. - /// {@endtemplate} - Widget get child; - - /// The animation's duration between [child], [loadingWidget], - /// [successWidget] and [errorWidget]. This same value is used for both the - /// internal [AnimatedSize] and [TransitionBuilder]. - Duration get duration; - - /// The animation's reverse duration between [child], [loadingWidget], - /// [successWidget] and [errorWidget]. This same value is used for both the - /// internal [AnimatedSize] and [TransitionBuilder]. - Duration get reverseDuration; - - /// A callback that runs the async task. This is wrapped in order to begin - /// the button's internal `isLoading` before and after the operation - /// completes. - AsyncCallback? get onPressed; - - /// This is used to manually drive the state of the loading button thus - /// initiating the corresponding animation and showing the correct button - /// child. - ButtonState get buttonState; - - /// This is used to manually drive the disabled state of the button. - bool get disabled; - - /// The widget replaces the [child] when the button is in the loading state. - /// If this is null the default widget is: - /// - /// SizedBox( - /// height: 16.0, - /// width: 16.0, - /// child: CircularProgressIndicator(), - /// ) - Widget? get loadingWidget; - - /// The widget used to replace the [child] when the button is in a success - /// state. If this is null the default widget is: - /// - /// Icon( - /// Icons.check, - /// color: Theme.of(context).accentColor, - /// ); - Widget? get successWidget; - - /// The widget used to replace the [child] when the button is in a error - /// state. If this is null the default widget is: - /// - /// Icon( - /// Icons.error, - /// color: Theme.of(context).errorColor, - /// ) - Widget? get errorWidget; - - /// Whether to show the [successWidget] on success. - bool get showSuccess; - - /// Whether to show the [errorWidget] on error. - bool get showError; - - /// Optional [EdgeInsets] that will wrap around the [errorWidget]. This is a - /// convenience field that can be replaced by defining your own [errorWidget] - /// and wrapping it in a [Padding]. - EdgeInsets? get errorPadding; - - /// Optional [EdgeInsets] that will wrap around the [successWidget]. This is a - /// convenience field that can be replaced by defining your own - /// [successWidget] and wrapping it in a [Padding]. - EdgeInsets? get successPadding; - - /// Defines a custom transition when animating between any state and `idle` - AnimatedSwitcherTransitionBuilder get idleTransitionBuilder; - - /// Defines a custom transition when animating between any state and `loading` - AnimatedSwitcherTransitionBuilder get loadingTransitionBuilder; - - /// Defines a custom transition when animating between any state and `success` - AnimatedSwitcherTransitionBuilder get successTransitionBuilder; - - /// Defines a custom transition when animating between any state and `error` - AnimatedSwitcherTransitionBuilder get errorTransitionBuilder; - - /// The amount of idle time the [successWidget] shows - Duration get successDuration; - - /// The amount of idle time the [errorWidget] shows - Duration get errorDuration; - - /// Defines a curve for the custom transition. This used in in an - /// [AnimatedSwitcher] and only takes effect when animating to `idle` - Curve get idleSwitchInCurve; - - /// Defines a curve for the custom transition. This used in in an - /// [AnimatedSwitcher] and only takes effect when animating to `loading` - Curve get loadingSwitchInCurve; - - /// Defines a curve for the custom transition. This used in in an - /// [AnimatedSwitcher] and only takes effect when animating to `success` - Curve get successSwitchInCurve; - - /// Defines a curve for the custom transition. This used in in an - /// [AnimatedSwitcher] and only takes effect when animating to `error` - Curve get errorSwitchInCurve; - - /// Defines a curve for the custom transition. This used in in an - /// [AnimatedSwitcher] and only takes effect when animating out of `idle` - Curve get idleSwitchOutCurve; - - /// Defines a curve for the custom transition. This used in in an - /// [AnimatedSwitcher] and only takes effect when animating out of `loading` - Curve get loadingSwitchOutCurve; - - /// Defines a curve for the custom transition. This used in in an - /// [AnimatedSwitcher] and only takes effect when animating out of `success` - Curve get successSwitchOutCurve; - - /// Defines a curve for the custom transition. This used in in an - /// [AnimatedSwitcher] and only takes effect when animating out of `error` - Curve get errorSwitchOutCurve; - - /// Defines a curve for the internal [AnimatedSize] - Curve get sizeCurve; - - /// Defines the [Clip] for the internal [AnimatedSize] - Clip get sizeClipBehavior; - - /// Defines the [Alignment] for the internal [AnimatedSize] - Alignment get sizeAlignment; - - /// Whether to animate the [Size] of the widget implicitly. - bool get animateSize; -} diff --git a/packages/async_button_core/pubspec.yaml b/packages/async_button_core/pubspec.yaml deleted file mode 100644 index 5d1d4c6..0000000 --- a/packages/async_button_core/pubspec.yaml +++ /dev/null @@ -1,22 +0,0 @@ -name: async_button_core -description: Contains the core models and docs for the packages async_button_hook and async_button_builder -version: 0.0.1+8 -homepage: https://github.com/Nolence/async_button/tree/main/packages/async_button_core - -environment: - sdk: ">=2.12.0 <3.0.0" - flutter: ">=1.17.0" - -dependencies: - flutter: - sdk: flutter - freezed_annotation: ">=0.14.0 <=0.16.0" - -dev_dependencies: - flutter_lints: ^1.0.4 - build_runner: ^2.0.3 - freezed: ^0.14.5 - flutter_test: - sdk: flutter - -flutter: diff --git a/packages/async_button_core/test/async_button_core_test.dart b/packages/async_button_core/test/async_button_core_test.dart deleted file mode 100644 index 0da434d..0000000 --- a/packages/async_button_core/test/async_button_core_test.dart +++ /dev/null @@ -1,5 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; - -void main() { - test('adds one to input values', () {}); -} diff --git a/packages/async_button_hook/.gitignore b/packages/async_button_hook/.gitignore deleted file mode 100644 index a247422..0000000 --- a/packages/async_button_hook/.gitignore +++ /dev/null @@ -1,75 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -.dart_tool/ -.flutter-plugins -.flutter-plugins-dependencies -.packages -.pub-cache/ -.pub/ -build/ - -# Android related -**/android/**/gradle-wrapper.jar -**/android/.gradle -**/android/captures/ -**/android/gradlew -**/android/gradlew.bat -**/android/local.properties -**/android/**/GeneratedPluginRegistrant.java - -# iOS/XCode related -**/ios/**/*.mode1v3 -**/ios/**/*.mode2v3 -**/ios/**/*.moved-aside -**/ios/**/*.pbxuser -**/ios/**/*.perspectivev3 -**/ios/**/*sync/ -**/ios/**/.sconsign.dblite -**/ios/**/.tags* -**/ios/**/.vagrant/ -**/ios/**/DerivedData/ -**/ios/**/Icon? -**/ios/**/Pods/ -**/ios/**/.symlinks/ -**/ios/**/profile -**/ios/**/xcuserdata -**/ios/.generated/ -**/ios/Flutter/App.framework -**/ios/Flutter/Flutter.framework -**/ios/Flutter/Flutter.podspec -**/ios/Flutter/Generated.xcconfig -**/ios/Flutter/ephemeral -**/ios/Flutter/app.flx -**/ios/Flutter/app.zip -**/ios/Flutter/flutter_assets/ -**/ios/Flutter/flutter_export_environment.sh -**/ios/ServiceDefinitions.json -**/ios/Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!**/ios/**/default.mode1v3 -!**/ios/**/default.mode2v3 -!**/ios/**/default.pbxuser -!**/ios/**/default.perspectivev3 diff --git a/packages/async_button_hook/.metadata b/packages/async_button_hook/.metadata deleted file mode 100644 index b6da989..0000000 --- a/packages/async_button_hook/.metadata +++ /dev/null @@ -1,10 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled and should not be manually edited. - -version: - revision: 225a43d941ddd1753765fec3682011e9ddffb11d - channel: dev - -project_type: package diff --git a/packages/async_button_hook/CHANGELOG.md b/packages/async_button_hook/CHANGELOG.md deleted file mode 100644 index 7ec29ac..0000000 --- a/packages/async_button_hook/CHANGELOG.md +++ /dev/null @@ -1,31 +0,0 @@ -## 0.0.1+9 - 2021-09-28 -Upgraded deps - -## 0.0.1+8 - 2021-09-28 -Upgraded deps - -## 0.0.1+7 - 2021-09-28 -Upgraded deps - -## 0.0.1+6 - 2021-09-08 -Fixed github actions - -## 0.0.1+5 - 2021-08-31 -Trying to fix pub stuff - -## 0.0.1+4 - 2021-08-27 -Trying to fix pub stuff - -## 0.0.1+4 -Fixed home page - -## 0.0.1+3 - -## 0.0.1+2 -Fixed imports again - -## 0.0.1+1 -Added better docs - -## 0.0.1 -Initial release diff --git a/packages/async_button_hook/LICENSE b/packages/async_button_hook/LICENSE deleted file mode 100644 index 30cff74..0000000 --- a/packages/async_button_hook/LICENSE +++ /dev/null @@ -1 +0,0 @@ -../../LICENSE \ No newline at end of file diff --git a/packages/async_button_hook/README.md b/packages/async_button_hook/README.md deleted file mode 100644 index b36bb26..0000000 --- a/packages/async_button_hook/README.md +++ /dev/null @@ -1,142 +0,0 @@ -# async_button_hook - -[![melos](https://img.shields.io/badge/maintained%20with-melos-f700ff.svg?style=flat-square)](https://github.com/invertase/melos) - -Include the package: - -```yaml - async_button_hook: -``` - -To add a layer of async capabilities to your buttons, inside a `HookWidget` call `useAsyncButton` with its necessary fields. - -```dart -final asyncButton = useAsyncButton( - child: const Text('Click Me'), - onPressed: () async { - await Future.delayed(const Duration(seconds: 1)); - }, -); - -TextButton( - child: asyncButton.child, - onPressed: asyncButton.callback, -), -``` - -

- -

- -The value returned from `useAsyncButton` includes all the values necessary to switch the appearance of your buttons. The field `buttonState` on the value will show you the current state. This can be used to conditionally style the button. This package depends `freezed` in order to create a sealed union to better handle the possible states. - -```dart -final asyncButton = useAsyncButton( - child: const Text('Click Me'), - loadingWidget: const Text('Loading...'), - onPressed: () async { - await Future.delayed(Duration(seconds: 1)); - - // See the examples file for a way to handle timeouts - throw 'shucks'; - }, -); - -final buttonColor = asyncButton.buttonState.when( - idle: () => Colors.yellow[200], - loading: () => Colors.grey, - success: () => Colors.orangeAccent, - error: () => Colors.orange, -); - -return OutlinedButton( - child: asyncButton.child, - onPressed: asyncButton.callback, - style: OutlinedButton.styleFrom( - primary: Colors.black, - backgroundColor: buttonColor, - ), -) -``` - -

- -

- -You can also drive the state of the button yourself using the `buttonState` field: - -```dart -final asyncButton = useAsyncButton( - buttonState: ButtonState.completing(), - // ... -); -``` - -`async_button_hook` even works for custom buttons. You can define your own widgets for loading, error, and completion as well as define the transitions between them. This example is a little verbose but shows some of what's possible. - - -```dart -final asyncButton = useAsyncButton( - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 16.0, - vertical: 8.0, - ), - child: Text( - 'Click Me', - style: TextStyle(color: Colors.white), - ), - ), - loadingWidget: Padding( - padding: const EdgeInsets.all(8.0), - child: SizedBox( - height: 16.0, - width: 16.0, - child: CircularProgressIndicator( - valueColor: AlwaysStoppedAnimation(Colors.white), - ), - ), - ), - successWidget: Padding( - padding: const EdgeInsets.all(4.0), - child: Icon( - Icons.check, - color: Colors.purpleAccent, - ), - ), - onPressed: () async { - await Future.delayed(Duration(seconds: 2)); - }, - loadingSwitchInCurve: Curves.bounceInOut, - loadingTransitionBuilder: (child, animation) { - return SlideTransition( - position: Tween( - begin: Offset(0, 1.0), - end: Offset(0, 0), - ).animate(animation), - child: child, - ); - }, -); - -return Material( - color: state.maybeWhen( - success: () => Colors.purple[100], - orElse: () => Colors.blue, - ), - // This prevents the loading indicator showing below the - // button - clipBehavior: Clip.hardEdge, - shape: StadiumBorder(), - child: InkWell( - child: asyncButton.child, - onTap: asyncButton.callback, - ), -); -``` - -

- -

- -Issues and PR's welcome \ No newline at end of file diff --git a/packages/async_button_hook/coverage/lcov.info b/packages/async_button_hook/coverage/lcov.info deleted file mode 100644 index e69de29..0000000 diff --git a/packages/async_button_hook/example/.gitignore b/packages/async_button_hook/example/.gitignore deleted file mode 100644 index 0fa6b67..0000000 --- a/packages/async_button_hook/example/.gitignore +++ /dev/null @@ -1,46 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -**/ios/Flutter/.last_build_id -.dart_tool/ -.flutter-plugins -.flutter-plugins-dependencies -.packages -.pub-cache/ -.pub/ -/build/ - -# Web related -lib/generated_plugin_registrant.dart - -# Symbolication related -app.*.symbols - -# Obfuscation related -app.*.map.json - -# Android Studio will place build artifacts here -/android/app/debug -/android/app/profile -/android/app/release diff --git a/packages/async_button_hook/example/.metadata b/packages/async_button_hook/example/.metadata deleted file mode 100644 index 75f919a..0000000 --- a/packages/async_button_hook/example/.metadata +++ /dev/null @@ -1,10 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled and should not be manually edited. - -version: - revision: 225a43d941ddd1753765fec3682011e9ddffb11d - channel: dev - -project_type: app diff --git a/packages/async_button_hook/example/README.md b/packages/async_button_hook/example/README.md deleted file mode 100644 index a135626..0000000 --- a/packages/async_button_hook/example/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# example - -A new Flutter project. - -## Getting Started - -This project is a starting point for a Flutter application. - -A few resources to get you started if this is your first Flutter project: - -- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) -- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) - -For help getting started with Flutter, view our -[online documentation](https://flutter.dev/docs), which offers tutorials, -samples, guidance on mobile development, and a full API reference. diff --git a/packages/async_button_hook/example/analysis_options.yaml b/packages/async_button_hook/example/analysis_options.yaml deleted file mode 100644 index f9b3034..0000000 --- a/packages/async_button_hook/example/analysis_options.yaml +++ /dev/null @@ -1 +0,0 @@ -include: package:flutter_lints/flutter.yaml diff --git a/packages/async_button_hook/example/android/.gitignore b/packages/async_button_hook/example/android/.gitignore deleted file mode 100644 index 6f56801..0000000 --- a/packages/async_button_hook/example/android/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -gradle-wrapper.jar -/.gradle -/captures/ -/gradlew -/gradlew.bat -/local.properties -GeneratedPluginRegistrant.java - -# Remember to never publicly share your keystore. -# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app -key.properties -**/*.keystore -**/*.jks diff --git a/packages/async_button_hook/example/android/app/build.gradle b/packages/async_button_hook/example/android/app/build.gradle deleted file mode 100644 index 56bfa9b..0000000 --- a/packages/async_button_hook/example/android/app/build.gradle +++ /dev/null @@ -1,68 +0,0 @@ -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - -android { - compileSdkVersion 30 - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - - kotlinOptions { - jvmTarget = '1.8' - } - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.example.example" - minSdkVersion 16 - targetSdkVersion 30 - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } -} - -flutter { - source '../..' -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" -} diff --git a/packages/async_button_hook/example/android/app/src/debug/AndroidManifest.xml b/packages/async_button_hook/example/android/app/src/debug/AndroidManifest.xml deleted file mode 100644 index c208884..0000000 --- a/packages/async_button_hook/example/android/app/src/debug/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/packages/async_button_hook/example/android/app/src/main/AndroidManifest.xml b/packages/async_button_hook/example/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index 6f325b4..0000000 --- a/packages/async_button_hook/example/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - - - - - diff --git a/packages/async_button_hook/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt b/packages/async_button_hook/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt deleted file mode 100644 index e793a00..0000000 --- a/packages/async_button_hook/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.example.example - -import io.flutter.embedding.android.FlutterActivity - -class MainActivity: FlutterActivity() { -} diff --git a/packages/async_button_hook/example/android/app/src/main/res/drawable-v21/launch_background.xml b/packages/async_button_hook/example/android/app/src/main/res/drawable-v21/launch_background.xml deleted file mode 100644 index f74085f..0000000 --- a/packages/async_button_hook/example/android/app/src/main/res/drawable-v21/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/packages/async_button_hook/example/android/app/src/main/res/drawable/launch_background.xml b/packages/async_button_hook/example/android/app/src/main/res/drawable/launch_background.xml deleted file mode 100644 index 304732f..0000000 --- a/packages/async_button_hook/example/android/app/src/main/res/drawable/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/packages/async_button_hook/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/packages/async_button_hook/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index db77bb4b7b0906d62b1847e87f15cdcacf6a4f29..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ diff --git a/packages/async_button_hook/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/packages/async_button_hook/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 17987b79bb8a35cc66c3c1fd44f5a5526c1b78be..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 442 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xx&nMcT!A!W`0S9QKQy;}1Cl^CgaH=;G9cpY;r$Q>i*pfB zP2drbID<_#qf;rPZx^FqH)F_D#*k@@q03KywUtLX8Ua?`H+NMzkczFPK3lFz@i_kW%1NOn0|D2I9n9wzH8m|-tHjsw|9>@K=iMBhxvkv6m8Y-l zytQ?X=U+MF$@3 zt`~i=@j|6y)RWMK--}M|=T`o&^Ni>IoWKHEbBXz7?A@mgWoL>!*SXo`SZH-*HSdS+ yn*9;$7;m`l>wYBC5bq;=U}IMqLzqbYCidGC!)_gkIk_C@Uy!y&wkt5C($~2D>~)O*cj@FGjOCM)M>_ixfudOh)?xMu#Fs z#}Y=@YDTwOM)x{K_j*Q;dPdJ?Mz0n|pLRx{4n|)f>SXlmV)XB04CrSJn#dS5nK2lM zrZ9#~WelCp7&e13Y$jvaEXHskn$2V!!DN-nWS__6T*l;H&Fopn?A6HZ-6WRLFP=R` zqG+CE#d4|IbyAI+rJJ`&x9*T`+a=p|0O(+s{UBcyZdkhj=yS1>AirP+0R;mf2uMgM zC}@~JfByORAh4SyRgi&!(cja>F(l*O+nd+@4m$|6K6KDn_&uvCpV23&>G9HJp{xgg zoq1^2_p9@|WEo z*X_Uko@K)qYYv~>43eQGMdbiGbo>E~Q& zrYBH{QP^@Sti!`2)uG{irBBq@y*$B zi#&(U-*=fp74j)RyIw49+0MRPMRU)+a2r*PJ$L5roHt2$UjExCTZSbq%V!HeS7J$N zdG@vOZB4v_lF7Plrx+hxo7(fCV&}fHq)$ diff --git a/packages/async_button_hook/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/packages/async_button_hook/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index d5f1c8d34e7a88e3f88bea192c3a370d44689c3c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1031 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof diff --git a/packages/async_button_hook/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/packages/async_button_hook/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 4d6372eebdb28e45604e46eeda8dd24651419bc0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1443 zcmb`G{WsKk6vsdJTdFg%tJav9_E4vzrOaqkWF|A724Nly!y+?N9`YV6wZ}5(X(D_N(?!*n3`|_r0Hc?=PQw&*vnU?QTFY zB_MsH|!j$PP;I}?dppoE_gA(4uc!jV&0!l7_;&p2^pxNo>PEcNJv za5_RT$o2Mf!<+r?&EbHH6nMoTsDOa;mN(wv8RNsHpG)`^ymG-S5By8=l9iVXzN_eG%Xg2@Xeq76tTZ*dGh~Lo9vl;Zfs+W#BydUw zCkZ$o1LqWQO$FC9aKlLl*7x9^0q%0}$OMlp@Kk_jHXOjofdePND+j!A{q!8~Jn+s3 z?~~w@4?egS02}8NuulUA=L~QQfm;MzCGd)XhiftT;+zFO&JVyp2mBww?;QByS_1w! zrQlx%{^cMj0|Bo1FjwY@Q8?Hx0cIPF*@-ZRFpPc#bBw{5@tD(5%sClzIfl8WU~V#u zm5Q;_F!wa$BSpqhN>W@2De?TKWR*!ujY;Yylk_X5#~V!L*Gw~;$%4Q8~Mad z@`-kG?yb$a9cHIApZDVZ^U6Xkp<*4rU82O7%}0jjHlK{id@?-wpN*fCHXyXh(bLt* zPc}H-x0e4E&nQ>y%B-(EL=9}RyC%MyX=upHuFhAk&MLbsF0LP-q`XnH78@fT+pKPW zu72MW`|?8ht^tz$iC}ZwLp4tB;Q49K!QCF3@!iB1qOI=?w z7In!}F~ij(18UYUjnbmC!qKhPo%24?8U1x{7o(+?^Zu0Hx81|FuS?bJ0jgBhEMzf< zCgUq7r2OCB(`XkKcN-TL>u5y#dD6D!)5W?`O5)V^>jb)P)GBdy%t$uUMpf$SNV31$ zb||OojAbvMP?T@$h_ZiFLFVHDmbyMhJF|-_)HX3%m=CDI+ID$0^C>kzxprBW)hw(v zr!Gmda);ICoQyhV_oP5+C%?jcG8v+D@9f?Dk*!BxY}dazmrT@64UrP3hlslANK)bq z$67n83eh}OeW&SV@HG95P|bjfqJ7gw$e+`Hxo!4cx`jdK1bJ>YDSpGKLPZ^1cv$ek zIB?0S<#tX?SJCLWdMd{-ME?$hc7A$zBOdIJ)4!KcAwb=VMov)nK;9z>x~rfT1>dS+ zZ6#`2v@`jgbqq)P22H)Tx2CpmM^o1$B+xT6`(v%5xJ(?j#>Q$+rx_R|7TzDZe{J6q zG1*EcU%tE?!kO%^M;3aM6JN*LAKUVb^xz8-Pxo#jR5(-KBeLJvA@-gxNHx0M-ZJLl z;#JwQoh~9V?`UVo#}{6ka@II>++D@%KqGpMdlQ}?9E*wFcf5(#XQnP$Dk5~%iX^>f z%$y;?M0BLp{O3a(-4A?ewryHrrD%cx#Q^%KY1H zNre$ve+vceSLZcNY4U(RBX&)oZn*Py()h)XkE?PL$!bNb{N5FVI2Y%LKEm%yvpyTP z(1P?z~7YxD~Rf<(a@_y` diff --git a/packages/async_button_hook/example/android/app/src/main/res/values-night/styles.xml b/packages/async_button_hook/example/android/app/src/main/res/values-night/styles.xml deleted file mode 100644 index 449a9f9..0000000 --- a/packages/async_button_hook/example/android/app/src/main/res/values-night/styles.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - diff --git a/packages/async_button_hook/example/android/app/src/main/res/values/styles.xml b/packages/async_button_hook/example/android/app/src/main/res/values/styles.xml deleted file mode 100644 index d74aa35..0000000 --- a/packages/async_button_hook/example/android/app/src/main/res/values/styles.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - diff --git a/packages/async_button_hook/example/android/app/src/profile/AndroidManifest.xml b/packages/async_button_hook/example/android/app/src/profile/AndroidManifest.xml deleted file mode 100644 index c208884..0000000 --- a/packages/async_button_hook/example/android/app/src/profile/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/packages/async_button_hook/example/android/build.gradle b/packages/async_button_hook/example/android/build.gradle deleted file mode 100644 index ed45c65..0000000 --- a/packages/async_button_hook/example/android/build.gradle +++ /dev/null @@ -1,29 +0,0 @@ -buildscript { - ext.kotlin_version = '1.3.50' - repositories { - google() - mavenCentral() - } - - dependencies { - classpath 'com.android.tools.build:gradle:4.1.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -allprojects { - repositories { - google() - mavenCentral() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" - project.evaluationDependsOn(':app') -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/packages/async_button_hook/example/android/gradle.properties b/packages/async_button_hook/example/android/gradle.properties deleted file mode 100644 index 94adc3a..0000000 --- a/packages/async_button_hook/example/android/gradle.properties +++ /dev/null @@ -1,3 +0,0 @@ -org.gradle.jvmargs=-Xmx1536M -android.useAndroidX=true -android.enableJetifier=true diff --git a/packages/async_button_hook/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/async_button_hook/example/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index bc6a58a..0000000 --- a/packages/async_button_hook/example/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Fri Jun 23 08:50:38 CEST 2017 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip diff --git a/packages/async_button_hook/example/android/settings.gradle b/packages/async_button_hook/example/android/settings.gradle deleted file mode 100644 index 44e62bc..0000000 --- a/packages/async_button_hook/example/android/settings.gradle +++ /dev/null @@ -1,11 +0,0 @@ -include ':app' - -def localPropertiesFile = new File(rootProject.projectDir, "local.properties") -def properties = new Properties() - -assert localPropertiesFile.exists() -localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } - -def flutterSdkPath = properties.getProperty("flutter.sdk") -assert flutterSdkPath != null, "flutter.sdk not set in local.properties" -apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/packages/async_button_hook/example/ios/.gitignore b/packages/async_button_hook/example/ios/.gitignore deleted file mode 100644 index 151026b..0000000 --- a/packages/async_button_hook/example/ios/.gitignore +++ /dev/null @@ -1,33 +0,0 @@ -*.mode1v3 -*.mode2v3 -*.moved-aside -*.pbxuser -*.perspectivev3 -**/*sync/ -.sconsign.dblite -.tags* -**/.vagrant/ -**/DerivedData/ -Icon? -**/Pods/ -**/.symlinks/ -profile -xcuserdata -**/.generated/ -Flutter/App.framework -Flutter/Flutter.framework -Flutter/Flutter.podspec -Flutter/Generated.xcconfig -Flutter/ephemeral/ -Flutter/app.flx -Flutter/app.zip -Flutter/flutter_assets/ -Flutter/flutter_export_environment.sh -ServiceDefinitions.json -Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!default.mode1v3 -!default.mode2v3 -!default.pbxuser -!default.perspectivev3 diff --git a/packages/async_button_hook/example/ios/Flutter/AppFrameworkInfo.plist b/packages/async_button_hook/example/ios/Flutter/AppFrameworkInfo.plist deleted file mode 100644 index 8d4492f..0000000 --- a/packages/async_button_hook/example/ios/Flutter/AppFrameworkInfo.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - App - CFBundleIdentifier - io.flutter.flutter.app - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - App - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - MinimumOSVersion - 9.0 - - diff --git a/packages/async_button_hook/example/ios/Flutter/Debug.xcconfig b/packages/async_button_hook/example/ios/Flutter/Debug.xcconfig deleted file mode 100644 index 592ceee..0000000 --- a/packages/async_button_hook/example/ios/Flutter/Debug.xcconfig +++ /dev/null @@ -1 +0,0 @@ -#include "Generated.xcconfig" diff --git a/packages/async_button_hook/example/ios/Flutter/Release.xcconfig b/packages/async_button_hook/example/ios/Flutter/Release.xcconfig deleted file mode 100644 index 592ceee..0000000 --- a/packages/async_button_hook/example/ios/Flutter/Release.xcconfig +++ /dev/null @@ -1 +0,0 @@ -#include "Generated.xcconfig" diff --git a/packages/async_button_hook/example/ios/Runner.xcodeproj/project.pbxproj b/packages/async_button_hook/example/ios/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index c6759a6..0000000 --- a/packages/async_button_hook/example/ios/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,471 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; -/* End PBXBuildFile section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 9705A1C41CF9048500538489 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; - 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 97C146EB1CF9000F007C117D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 9740EEB11CF90186004384FC /* Flutter */ = { - isa = PBXGroup; - children = ( - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 9740EEB31CF90195004384FC /* Generated.xcconfig */, - ); - name = Flutter; - sourceTree = ""; - }; - 97C146E51CF9000F007C117D = { - isa = PBXGroup; - children = ( - 9740EEB11CF90186004384FC /* Flutter */, - 97C146F01CF9000F007C117D /* Runner */, - 97C146EF1CF9000F007C117D /* Products */, - ); - sourceTree = ""; - }; - 97C146EF1CF9000F007C117D /* Products */ = { - isa = PBXGroup; - children = ( - 97C146EE1CF9000F007C117D /* Runner.app */, - ); - name = Products; - sourceTree = ""; - }; - 97C146F01CF9000F007C117D /* Runner */ = { - isa = PBXGroup; - children = ( - 97C146FA1CF9000F007C117D /* Main.storyboard */, - 97C146FD1CF9000F007C117D /* Assets.xcassets */, - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, - 97C147021CF9000F007C117D /* Info.plist */, - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, - ); - path = Runner; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 97C146ED1CF9000F007C117D /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - 9740EEB61CF901F6004384FC /* Run Script */, - 97C146EA1CF9000F007C117D /* Sources */, - 97C146EB1CF9000F007C117D /* Frameworks */, - 97C146EC1CF9000F007C117D /* Resources */, - 9705A1C41CF9048500538489 /* Embed Frameworks */, - 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Runner; - productName = Runner; - productReference = 97C146EE1CF9000F007C117D /* Runner.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 97C146E61CF9000F007C117D /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 1020; - ORGANIZATIONNAME = ""; - TargetAttributes = { - 97C146ED1CF9000F007C117D = { - CreatedOnToolsVersion = 7.3.1; - LastSwiftMigration = 1100; - }; - }; - }; - buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 97C146E51CF9000F007C117D; - productRefGroup = 97C146EF1CF9000F007C117D /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 97C146ED1CF9000F007C117D /* Runner */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 97C146EC1CF9000F007C117D /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Thin Binary"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; - }; - 9740EEB61CF901F6004384FC /* Run Script */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Run Script"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 97C146EA1CF9000F007C117D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 97C146FA1CF9000F007C117D /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C146FB1CF9000F007C117D /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C147001CF9000F007C117D /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 249021D3217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Profile; - }; - 249021D4217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.example.example; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Profile; - }; - 97C147031CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 97C147041CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 97C147061CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.example.example; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Debug; - }; - 97C147071CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.example.example; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147031CF9000F007C117D /* Debug */, - 97C147041CF9000F007C117D /* Release */, - 249021D3217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147061CF9000F007C117D /* Debug */, - 97C147071CF9000F007C117D /* Release */, - 249021D4217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 97C146E61CF9000F007C117D /* Project object */; -} diff --git a/packages/async_button_hook/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/async_button_hook/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a..0000000 --- a/packages/async_button_hook/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/packages/async_button_hook/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/async_button_hook/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d9810..0000000 --- a/packages/async_button_hook/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/packages/async_button_hook/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/async_button_hook/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c..0000000 --- a/packages/async_button_hook/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/packages/async_button_hook/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/async_button_hook/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index a28140c..0000000 --- a/packages/async_button_hook/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/async_button_hook/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/async_button_hook/example/ios/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 1d526a1..0000000 --- a/packages/async_button_hook/example/ios/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/packages/async_button_hook/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/async_button_hook/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d9810..0000000 --- a/packages/async_button_hook/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/packages/async_button_hook/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/async_button_hook/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c..0000000 --- a/packages/async_button_hook/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/packages/async_button_hook/example/ios/Runner/AppDelegate.swift b/packages/async_button_hook/example/ios/Runner/AppDelegate.swift deleted file mode 100644 index 70693e4..0000000 --- a/packages/async_button_hook/example/ios/Runner/AppDelegate.swift +++ /dev/null @@ -1,13 +0,0 @@ -import UIKit -import Flutter - -@UIApplicationMain -@objc class AppDelegate: FlutterAppDelegate { - override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - GeneratedPluginRegistrant.register(with: self) - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } -} diff --git a/packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index d36b1fa..0000000 --- a/packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,122 +0,0 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" - }, - { - "size" : "1024x1024", - "idiom" : "ios-marketing", - "filename" : "Icon-App-1024x1024@1x.png", - "scale" : "1x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png deleted file mode 100644 index dc9ada4725e9b0ddb1deab583e5b5102493aa332..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10932 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 diff --git a/packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png deleted file mode 100644 index f091b6b0bca859a3f474b03065bef75ba58a9e4c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1588 zcmV-42Fv-0P)C1SqPt}wig>|5Crh^=oyX$BK<}M8eLU3e2hGT;=G|!_SP)7zNI6fqUMB=)y zRAZ>eDe#*r`yDAVgB_R*LB*MAc)8(b{g{9McCXW!lq7r(btRoB9!8B-#AI6JMb~YFBEvdsV)`mEQO^&#eRKx@b&x- z5lZm*!WfD8oCLzfHGz#u7sT0^VLMI1MqGxF^v+`4YYnVYgk*=kU?HsSz{v({E3lb9 z>+xILjBN)t6`=g~IBOelGQ(O990@BfXf(DRI5I$qN$0Gkz-FSc$3a+2fX$AedL4u{ z4V+5Ong(9LiGcIKW?_352sR;LtDPmPJXI{YtT=O8=76o9;*n%_m|xo!i>7$IrZ-{l z-x3`7M}qzHsPV@$v#>H-TpjDh2UE$9g6sysUREDy_R(a)>=eHw-WAyfIN z*qb!_hW>G)Tu8nSw9yn#3wFMiLcfc4pY0ek1}8(NqkBR@t4{~oC>ryc-h_ByH(Cg5 z>ao-}771+xE3um9lWAY1FeQFxowa1(!J(;Jg*wrg!=6FdRX+t_<%z&d&?|Bn){>zm zZQj(aA_HeBY&OC^jj*)N`8fa^ePOU72VpInJoI1?`ty#lvlNzs(&MZX+R%2xS~5Kh zX*|AU4QE#~SgPzOXe9>tRj>hjU@c1k5Y_mW*Jp3fI;)1&g3j|zDgC+}2Q_v%YfDax z!?umcN^n}KYQ|a$Lr+51Nf9dkkYFSjZZjkma$0KOj+;aQ&721~t7QUKx61J3(P4P1 zstI~7-wOACnWP4=8oGOwz%vNDqD8w&Q`qcNGGrbbf&0s9L0De{4{mRS?o0MU+nR_! zrvshUau0G^DeMhM_v{5BuLjb#Hh@r23lDAk8oF(C+P0rsBpv85EP>4CVMx#04MOfG z;P%vktHcXwTj~+IE(~px)3*MY77e}p#|c>TD?sMatC0Tu4iKKJ0(X8jxQY*gYtxsC z(zYC$g|@+I+kY;dg_dE>scBf&bP1Nc@Hz<3R)V`=AGkc;8CXqdi=B4l2k|g;2%#m& z*jfX^%b!A8#bI!j9-0Fi0bOXl(-c^AB9|nQaE`*)Hw+o&jS9@7&Gov#HbD~#d{twV zXd^Tr^mWLfFh$@Dr$e;PBEz4(-2q1FF0}c;~B5sA}+Q>TOoP+t>wf)V9Iy=5ruQa;z)y zI9C9*oUga6=hxw6QasLPnee@3^Rr*M{CdaL5=R41nLs(AHk_=Y+A9$2&H(B7!_pURs&8aNw7?`&Z&xY_Ye z)~D5Bog^td-^QbUtkTirdyK^mTHAOuptDflut!#^lnKqU md>ggs(5nOWAqO?umG&QVYK#ibz}*4>0000U6E9hRK9^#O7(mu>ETqrXGsduA8$)?`v2seloOCza43C{NQ$$gAOH**MCn0Q?+L7dl7qnbRdqZ8LSVp1ItDxhxD?t@5_yHg6A8yI zC*%Wgg22K|8E#!~cTNYR~@Y9KepMPrrB8cABapAFa=`H+UGhkXUZV1GnwR1*lPyZ;*K(i~2gp|@bzp8}og7e*#% zEnr|^CWdVV!-4*Y_7rFvlww2Ze+>j*!Z!pQ?2l->4q#nqRu9`ELo6RMS5=br47g_X zRw}P9a7RRYQ%2Vsd0Me{_(EggTnuN6j=-?uFS6j^u69elMypu?t>op*wBx<=Wx8?( ztpe^(fwM6jJX7M-l*k3kEpWOl_Vk3@(_w4oc}4YF4|Rt=2V^XU?#Yz`8(e?aZ@#li0n*=g^qOcVpd-Wbok=@b#Yw zqn8u9a)z>l(1kEaPYZ6hwubN6i<8QHgsu0oE) ziJ(p;Wxm>sf!K+cw>R-(^Y2_bahB+&KI9y^);#0qt}t-$C|Bo71lHi{_+lg#f%RFy z0um=e3$K3i6K{U_4K!EX?F&rExl^W|G8Z8;`5z-k}OGNZ0#WVb$WCpQu-_YsiqKP?BB# vzVHS-CTUF4Ozn5G+mq_~Qqto~ahA+K`|lyv3(-e}00000NkvXXu0mjfd`9t{ diff --git a/packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png deleted file mode 100644 index d0ef06e7edb86cdfe0d15b4b0d98334a86163658..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1716 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 diff --git a/packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png deleted file mode 100644 index c8f9ed8f5cee1c98386d13b17e89f719e83555b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1895 zcmV-t2blPYP)FQtfgmafE#=YDCq`qUBt#QpG%*H6QHY765~R=q zZ6iudfM}q!Pz#~9JgOi8QJ|DSu?1-*(kSi1K4#~5?#|rh?sS)(-JQqX*}ciXJ56_H zdw=^s_srbAdqxlvGyrgGet#6T7_|j;95sL%MtM;q86vOxKM$f#puR)Bjv9Zvz9-di zXOTSsZkM83)E9PYBXC<$6(|>lNLVBb&&6y{NByFCp%6+^ALR@NCTse_wqvNmSWI-m z!$%KlHFH2omF!>#%1l3LTZg(s7eof$7*xB)ZQ0h?ejh?Ta9fDv59+u#MokW+1t8Zb zgHv%K(u9G^Lv`lh#f3<6!JVTL3(dCpxHbnbA;kKqQyd1~^Xe0VIaYBSWm6nsr;dFj z4;G-RyL?cYgsN1{L4ZFFNa;8)Rv0fM0C(~Tkit94 zz#~A)59?QjD&pAPSEQ)p8gP|DS{ng)j=2ux)_EzzJ773GmQ_Cic%3JJhC0t2cx>|v zJcVusIB!%F90{+}8hG3QU4KNeKmK%T>mN57NnCZ^56=0?&3@!j>a>B43pi{!u z7JyDj7`6d)qVp^R=%j>UIY6f+3`+qzIc!Y_=+uN^3BYV|o+$vGo-j-Wm<10%A=(Yk^beI{t%ld@yhKjq0iNjqN4XMGgQtbKubPM$JWBz}YA65k%dm*awtC^+f;a-x4+ddbH^7iDWGg&N0n#MW{kA|=8iMUiFYvMoDY@sPC#t$55gn6ykUTPAr`a@!(;np824>2xJthS z*ZdmT`g5-`BuJs`0LVhz+D9NNa3<=6m;cQLaF?tCv8)zcRSh66*Z|vXhG@$I%U~2l z?`Q zykI#*+rQ=z6Jm=Bui-SfpDYLA=|vzGE(dYm=OC8XM&MDo7ux4UF1~0J1+i%aCUpRe zt3L_uNyQ*cE(38Uy03H%I*)*Bh=Lb^Xj3?I^Hnbeq72(EOK^Y93CNp*uAA{5Lc=ky zx=~RKa4{iTm{_>_vSCm?$Ej=i6@=m%@VvAITnigVg{&@!7CDgs908761meDK5azA} z4?=NOH|PdvabgJ&fW2{Mo$Q0CcD8Qc84%{JPYt5EiG{MdLIAeX%T=D7NIP4%Hw}p9 zg)==!2Lbp#j{u_}hMiao9=!VSyx0gHbeCS`;q&vzeq|fs`y&^X-lso(Ls@-706qmA z7u*T5PMo_w3{se1t2`zWeO^hOvTsohG_;>J0wVqVe+n)AbQCx)yh9;w+J6?NF5Lmo zecS@ieAKL8%bVd@+-KT{yI|S}O>pYckUFs;ry9Ow$CD@ztz5K-*D$^{i(_1llhSh^ zEkL$}tsQt5>QA^;QgjgIfBDmcOgi5YDyu?t6vSnbp=1+@6D& z5MJ}B8q;bRlVoxasyhcUF1+)o`&3r0colr}QJ3hcSdLu;9;td>kf@Tcn<@9sIx&=m z;AD;SCh95=&p;$r{Xz3iWCO^MX83AGJ(yH&eTXgv|0=34#-&WAmw{)U7OU9!Wz^!7 zZ%jZFi@JR;>Mhi7S>V7wQ176|FdW2m?&`qa(ScO^CFPR80HucLHOTy%5s*HR0^8)i h0WYBP*#0Ks^FNSabJA*5${_#%002ovPDHLkV1oKhTl@e3 diff --git a/packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png deleted file mode 100644 index a6d6b8609df07bf62e5100a53a01510388bd2b22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ diff --git a/packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index a6d6b8609df07bf62e5100a53a01510388bd2b22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ diff --git a/packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index 75b2d164a5a98e212cca15ea7bf2ab5de5108680..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3831 zcmVjJBgitF5mAp-i>4+KS_oR{|13AP->1TD4=w)g|)JHOx|a2Wk1Va z!k)vP$UcQ#mdj%wNQoaJ!w>jv_6&JPyutpQps?s5dmDQ>`%?Bvj>o<%kYG!YW6H-z zu`g$@mp`;qDR!51QaS}|ZToSuAGcJ7$2HF0z`ln4t!#Yg46>;vGG9N9{V@9z#}6v* zfP?}r6b{*-C*)(S>NECI_E~{QYzN5SXRmVnP<=gzP+_Sp(Aza_hKlZ{C1D&l*(7IKXxQC1Z9#6wx}YrGcn~g%;icdw>T0Rf^w0{ z$_wn1J+C0@!jCV<%Go5LA45e{5gY9PvZp8uM$=1}XDI+9m7!A95L>q>>oe0$nC->i zeexUIvq%Uk<-$>DiDb?!In)lAmtuMWxvWlk`2>4lNuhSsjAf2*2tjT`y;@d}($o)S zn(+W&hJ1p0xy@oxP%AM15->wPLp{H!k)BdBD$toBpJh+crWdsNV)qsHaqLg2_s|Ih z`8E9z{E3sA!}5aKu?T!#enD(wLw?IT?k-yWVHZ8Akz4k5(TZJN^zZgm&zM28sfTD2BYJ|Fde3Xzh;;S` z=GXTnY4Xc)8nYoz6&vF;P7{xRF-{|2Xs5>a5)@BrnQ}I(_x7Cgpx#5&Td^4Q9_FnQ zX5so*;#8-J8#c$OlA&JyPp$LKUhC~-e~Ij!L%uSMu!-VZG7Hx-L{m2DVR2i=GR(_% zCVD!4N`I)&Q5S`?P&fQZ=4#Dgt_v2-DzkT}K(9gF0L(owe-Id$Rc2qZVLqI_M_DyO z9@LC#U28_LU{;wGZ&))}0R2P4MhajKCd^K#D+JJ&JIXZ_p#@+7J9A&P<0kdRujtQ_ zOy>3=C$kgi6$0pW06KaLz!21oOryKM3ZUOWqppndxfH}QpgjEJ`j7Tzn5bk6K&@RA?vl##y z$?V~1E(!wB5rH`>3nc&@)|#<1dN2cMzzm=PGhQ|Yppne(C-Vlt450IXc`J4R0W@I7 zd1e5uW6juvO%ni(WX7BsKx3MLngO7rHO;^R5I~0^nE^9^E_eYLgiR9&KnJ)pBbfno zSVnW$0R+&6jOOsZ82}nJ126+c|%svPo;TeUku<2G7%?$oft zyaO;tVo}(W)VsTUhq^XmFi#2z%-W9a{7mXn{uzivYQ_d6b7VJG{77naW(vHt-uhnY zVN#d!JTqVh(7r-lhtXVU6o})aZbDt_;&wJVGl2FKYFBFpU-#9U)z#(A%=IVnqytR$SY-sO( z($oNE09{D^@OuYPz&w~?9>Fl5`g9u&ecFGhqX=^#fmR=we0CJw+5xna*@oHnkahk+ z9aWeE3v|An+O5%?4fA&$Fgu~H_YmqR!yIU!bFCk4!#pAj%(lI(A5n)n@Id#M)O9Yx zJU9oKy{sRAIV3=5>(s8n{8ryJ!;ho}%pn6hZKTKbqk=&m=f*UnK$zW3YQP*)pw$O* zIfLA^!-bmBl6%d_n$#tP8Zd_(XdA*z*WH|E_yILwjtI~;jK#v-6jMl^?<%Y%`gvpwv&cFb$||^v4D&V=aNy?NGo620jL3VZnA%s zH~I|qPzB~e(;p;b^gJr7Ure#7?8%F0m4vzzPy^^(q4q1OdthF}Fi*RmVZN1OwTsAP zn9CZP`FazX3^kG(KodIZ=Kty8DLTy--UKfa1$6XugS zk%6v$Kmxt6U!YMx0JQ)0qX*{CXwZZk$vEROidEc7=J-1;peNat!vS<3P-FT5po>iE z!l3R+<`#x|+_hw!HjQGV=8!q|76y8L7N8gP3$%0kfush|u0uU^?dKBaeRSBUpOZ0c z62;D&Mdn2}N}xHRFTRI?zRv=>=AjHgH}`2k4WK=#AHB)UFrR-J87GgX*x5fL^W2#d z=(%K8-oZfMO=i{aWRDg=FX}UubM4eotRDcn;OR#{3q=*?3mE3_oJ-~prjhxh%PgQT zyn)Qozaq0@o&|LEgS{Ind4Swsr;b`u185hZPOBLL<`d2%^Yp1?oL)=jnLi;Zo0ZDliTtQ^b5SmfIMe{T==zZkbvn$KTQGlbG8w}s@M3TZnde;1Am46P3juKb zl9GU&3F=q`>j!`?SyH#r@O59%@aMX^rx}Nxe<>NqpUp5=lX1ojGDIR*-D^SDuvCKF z?3$xG(gVUsBERef_YjPFl^rU9EtD{pt z0CXwpN7BN3!8>hajGaTVk-wl=9rxmfWtIhC{mheHgStLi^+Nz12a?4r(fz)?3A%at zMlvQmL<2-R)-@G1wJ0^zQK%mR=r4d{Y3fHp){nWXUL#|CqXl(+v+qDh>FkF9`eWrW zfr^D%LNfOcTNvtx0JXR35J0~Jpi2#P3Q&80w+nqNfc}&G0A~*)lGHKv=^FE+b(37|)zL;KLF>oiGfb(?&1 zV3XRu!Sw>@quKiab%g6jun#oZ%!>V#A%+lNc?q>6+VvyAn=kf_6z^(TZUa4Eelh{{ zqFX-#dY(EV@7l$NE&kv9u9BR8&Ojd#ZGJ6l8_BW}^r?DIS_rU2(XaGOK z225E@kH5Opf+CgD^{y29jD4gHbGf{1MD6ggQ&%>UG4WyPh5q_tb`{@_34B?xfSO*| zZv8!)q;^o-bz`MuxXk*G^}(6)ACb@=Lfs`Hxoh>`Y0NE8QRQ!*p|SH@{r8=%RKd4p z+#Ty^-0kb=-H-O`nAA3_6>2z(D=~Tbs(n8LHxD0`R0_ATFqp-SdY3(bZ3;VUM?J=O zKCNsxsgt@|&nKMC=*+ZqmLHhX1KHbAJs{nGVMs6~TiF%Q)P@>!koa$%oS zjXa=!5>P`vC-a}ln!uH1ooeI&v?=?v7?1n~P(wZ~0>xWxd_Aw;+}9#eULM7M8&E?Y zC-ZLhi3RoM92SXUb-5i-Lmt5_rfjE{6y^+24`y$1lywLyHO!)Boa7438K4#iLe?rh z2O~YGSgFUBH?og*6=r9rme=peP~ah`(8Zt7V)j5!V0KPFf_mebo3z95U8(up$-+EA^9dTRLq>Yl)YMBuch9%=e5B`Vnb>o zt03=kq;k2TgGe4|lGne&zJa~h(UGutjP_zr?a7~#b)@15XNA>Dj(m=gg2Q5V4-$)D|Q9}R#002ovPDHLkV1o7DH3k3x diff --git a/packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/async_button_hook/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png deleted file mode 100644 index c4df70d39da7941ef3f6dcb7f06a192d8dcb308d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1888 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 iW8Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v diff --git a/packages/async_button_hook/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/packages/async_button_hook/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png deleted file mode 100644 index 9da19eacad3b03bb08bbddbbf4ac48dd78b3d838..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v diff --git a/packages/async_button_hook/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/packages/async_button_hook/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png deleted file mode 100644 index 9da19eacad3b03bb08bbddbbf4ac48dd78b3d838..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v diff --git a/packages/async_button_hook/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/async_button_hook/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725..0000000 --- a/packages/async_button_hook/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -You can customize the launch screen with your own desired assets by replacing the image files in this directory. - -You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/packages/async_button_hook/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/async_button_hook/example/ios/Runner/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index f2e259c..0000000 --- a/packages/async_button_hook/example/ios/Runner/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/async_button_hook/example/ios/Runner/Base.lproj/Main.storyboard b/packages/async_button_hook/example/ios/Runner/Base.lproj/Main.storyboard deleted file mode 100644 index f3c2851..0000000 --- a/packages/async_button_hook/example/ios/Runner/Base.lproj/Main.storyboard +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/async_button_hook/example/ios/Runner/Info.plist b/packages/async_button_hook/example/ios/Runner/Info.plist deleted file mode 100644 index a060db6..0000000 --- a/packages/async_button_hook/example/ios/Runner/Info.plist +++ /dev/null @@ -1,45 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - example - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - - diff --git a/packages/async_button_hook/example/ios/Runner/Runner-Bridging-Header.h b/packages/async_button_hook/example/ios/Runner/Runner-Bridging-Header.h deleted file mode 100644 index 308a2a5..0000000 --- a/packages/async_button_hook/example/ios/Runner/Runner-Bridging-Header.h +++ /dev/null @@ -1 +0,0 @@ -#import "GeneratedPluginRegistrant.h" diff --git a/packages/async_button_hook/example/lib/main.dart b/packages/async_button_hook/example/lib/main.dart deleted file mode 100644 index 985908b..0000000 --- a/packages/async_button_hook/example/lib/main.dart +++ /dev/null @@ -1,168 +0,0 @@ -import 'package:async_button_hook/async_button_hook.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; - -void main() => runApp(const MyApp()); - -class MyApp extends StatelessWidget { - const MyApp({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return MaterialApp( - title: 'Flutter Demo', - theme: ThemeData.dark(), - home: const MyHomePage(), - ); - } -} - -class MyHomePage extends HookWidget { - const MyHomePage({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - final textAsyncButton = useAsyncButton( - child: const Text('Click Me'), - onPressed: () async { - await Future.delayed(const Duration(seconds: 1)); - }, - ); - final elevatedAsyncButton = useAsyncButton( - child: const Text('Click Me'), - onPressed: () async { - await Future.delayed(const Duration(seconds: 1)); - }, - ); - final customAsyncButton = useAsyncButton( - child: const Text('Click Me'), - loadingWidget: const Text('Loading...'), - onPressed: () async { - await Future.delayed(const Duration(seconds: 1)); - - throw 'shucks'; - - // If you want to add a timeout, use something similar to - // - // try { - // await Future.delayed(Duration(seconds: 1)) - // .timeout(Duration(milliseconds: 500)); - // } on TimeoutException catch (_) { - // // Show a popup or something - // rethrow; - // } on Exception catch (_) { - // // Show a dialog or something - // rethrow; - // } - // - // We rethrow so that async_button_builder can handle the error - // state - }, - ); - final buttonColor = customAsyncButton.buttonState.when( - idle: () => Colors.yellow[200], - loading: () => Colors.grey, - success: () => Colors.orangeAccent, - error: () => Colors.orange, - ); - - return Scaffold( - appBar: AppBar(title: const Text('Async Buttons')), - body: SizedBox.expand( - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - const Divider(), - const Text('Text Button:'), - TextButton( - child: textAsyncButton.child, - onPressed: textAsyncButton.callback, - ), - const Divider(), - const Text('Elevated Button:'), - ElevatedButton( - child: elevatedAsyncButton.child, - onPressed: elevatedAsyncButton.callback, - ), - const Divider(), - const Text('Custom Outlined Button (Error):'), - OutlinedButton( - child: customAsyncButton.child, - onPressed: customAsyncButton.callback, - style: OutlinedButton.styleFrom( - primary: Colors.black, - backgroundColor: buttonColor, - ), - ), - const Divider(), - const Text('Custom Material Button:'), - const SizedBox(height: 6.0), - HookBuilder( - builder: (context) { - final customAsyncButton = useAsyncButton( - loadingSwitchInCurve: Curves.bounceInOut, - loadingTransitionBuilder: (child, animation) { - return SlideTransition( - position: Tween( - begin: const Offset(0, 1.0), - end: const Offset(0, 0), - ).animate(animation), - child: child, - ); - }, - child: const Padding( - padding: EdgeInsets.symmetric( - horizontal: 16.0, - vertical: 8.0, - ), - child: Text( - 'Click Me', - style: TextStyle(color: Colors.white), - ), - ), - onPressed: () async { - await Future.delayed(const Duration(seconds: 2)); - }, - loadingWidget: const Padding( - padding: EdgeInsets.all(8.0), - child: SizedBox( - height: 16.0, - width: 16.0, - child: CircularProgressIndicator( - valueColor: AlwaysStoppedAnimation(Colors.white), - ), - ), - ), - successWidget: const Padding( - padding: EdgeInsets.all(4.0), - child: Icon( - Icons.check, - color: Colors.purpleAccent, - ), - ), - ); - - return Material( - color: customAsyncButton.buttonState.maybeWhen( - success: () => Colors.purple[100], - orElse: () => Colors.blue, - ), - // This prevents the loading indicator showing below the - // button - clipBehavior: Clip.hardEdge, - shape: const StadiumBorder(), - child: InkWell( - child: customAsyncButton.child, - onTap: customAsyncButton.callback, - ), - ); - }, - ), - const Divider(), - ], - ), - ), - ); - } -} diff --git a/packages/async_button_hook/example/pubspec.lock b/packages/async_button_hook/example/pubspec.lock deleted file mode 100644 index 9b0e11e..0000000 --- a/packages/async_button_hook/example/pubspec.lock +++ /dev/null @@ -1,203 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - async: - dependency: transitive - description: - name: async - url: "https://pub.dartlang.org" - source: hosted - version: "2.8.1" - async_button_core: - dependency: transitive - description: - name: async_button_core - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.1+7" - async_button_hook: - dependency: "direct main" - description: - path: ".." - relative: true - source: path - version: "0.0.1+8" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - characters: - dependency: transitive - description: - name: characters - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.1" - clock: - dependency: transitive - description: - name: clock - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - collection: - dependency: transitive - description: - name: collection - url: "https://pub.dartlang.org" - source: hosted - version: "1.15.0" - cupertino_icons: - dependency: "direct main" - description: - name: cupertino_icons - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.3" - fake_async: - dependency: transitive - description: - name: fake_async - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_hooks: - dependency: "direct main" - description: - name: flutter_hooks - url: "https://pub.dartlang.org" - source: hosted - version: "0.18.0" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.4" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - freezed_annotation: - dependency: transitive - description: - name: freezed_annotation - url: "https://pub.dartlang.org" - source: hosted - version: "0.14.3" - json_annotation: - dependency: transitive - description: - name: json_annotation - url: "https://pub.dartlang.org" - source: hosted - version: "4.1.0" - lints: - dependency: transitive - description: - name: lints - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" - matcher: - dependency: transitive - description: - name: matcher - url: "https://pub.dartlang.org" - source: hosted - version: "0.12.10" - meta: - dependency: transitive - description: - name: meta - url: "https://pub.dartlang.org" - source: hosted - version: "1.7.0" - path: - dependency: transitive - description: - name: path - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.0" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.99" - source_span: - dependency: transitive - description: - name: source_span - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.1" - stack_trace: - dependency: transitive - description: - name: stack_trace - url: "https://pub.dartlang.org" - source: hosted - version: "1.10.0" - stream_channel: - dependency: transitive - description: - name: stream_channel - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - string_scanner: - dependency: transitive - description: - name: string_scanner - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - term_glyph: - dependency: transitive - description: - name: term_glyph - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - test_api: - dependency: transitive - description: - name: test_api - url: "https://pub.dartlang.org" - source: hosted - version: "0.4.2" - typed_data: - dependency: transitive - description: - name: typed_data - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.0" - vector_math: - dependency: transitive - description: - name: vector_math - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" -sdks: - dart: ">=2.12.0 <3.0.0" - flutter: ">=1.20.0" diff --git a/packages/async_button_hook/example/pubspec.yaml b/packages/async_button_hook/example/pubspec.yaml deleted file mode 100644 index 6dc4064..0000000 --- a/packages/async_button_hook/example/pubspec.yaml +++ /dev/null @@ -1,92 +0,0 @@ -name: example -description: A new Flutter project. - -# The following line prevents the package from being accidentally published to -# pub.dev using `flutter pub publish`. This is preferred for private packages. -publish_to: 'none' # Remove this line if you wish to publish to pub.dev - -# The following defines the version and build number for your application. -# A version number is three numbers separated by dots, like 1.2.43 -# followed by an optional build number separated by a +. -# Both the version and the builder number may be overridden in flutter -# build by specifying --build-name and --build-number, respectively. -# In Android, build-name is used as versionName while build-number used as versionCode. -# Read more about Android versioning at https://developer.android.com/studio/publish/versioning -# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. -# Read more about iOS versioning at -# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.0.0+1 - -environment: - sdk: ">=2.12.0 <3.0.0" - -# Dependencies specify other packages that your package needs in order to work. -# To automatically upgrade your package dependencies to the latest versions -# consider running `flutter pub upgrade --major-versions`. Alternatively, -# dependencies can be manually updated by changing the version numbers below to -# the latest version available on pub.dev. To see which dependencies have newer -# versions available, run `flutter pub outdated`. -dependencies: - flutter: - sdk: flutter - async_button_hook: - path: ../ - flutter_hooks: - - - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^1.0.2 - -dev_dependencies: - flutter_test: - sdk: flutter - - # The "flutter_lints" package below contains a set of recommended lints to - # encourage good coding practices. The lint set provided by the package is - # activated in the `analysis_options.yaml` file located at the root of your - # package. See that file for information about deactivating specific lint - # rules and activating additional ones. - flutter_lints: ^1.0.0 - -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter. -flutter: - - # The following line ensures that the Material Icons font is - # included with your application, so that you can use the icons in - # the material Icons class. - uses-material-design: true - - # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware. - - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/assets-and-images/#from-packages - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.dev/custom-fonts/#from-packages diff --git a/packages/async_button_hook/example/web/favicon.png b/packages/async_button_hook/example/web/favicon.png deleted file mode 100644 index 8aaa46ac1ae21512746f852a42ba87e4165dfdd1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 917 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|I14-?iy0X7 zltGxWVyS%@P(fs7NJL45ua8x7ey(0(N`6wRUPW#JP&EUCO@$SZnVVXYs8ErclUHn2 zVXFjIVFhG^g!Ppaz)DK8ZIvQ?0~DO|i&7O#^-S~(l1AfjnEK zjFOT9D}DX)@^Za$W4-*MbbUihOG|wNBYh(yU7!lx;>x^|#0uTKVr7USFmqf|i<65o z3raHc^AtelCMM;Vme?vOfh>Xph&xL%(-1c06+^uR^q@XSM&D4+Kp$>4P^%3{)XKjo zGZknv$b36P8?Z_gF{nK@`XI}Z90TzwSQO}0J1!f2c(B=V`5aP@1P1a|PZ!4!3&Gl8 zTYqUsf!gYFyJnXpu0!n&N*SYAX-%d(5gVjrHJWqXQshj@!Zm{!01WsQrH~9=kTxW#6SvuapgMqt>$=j#%eyGrQzr zP{L-3gsMA^$I1&gsBAEL+vxi1*Igl=8#8`5?A-T5=z-sk46WA1IUT)AIZHx1rdUrf zVJrJn<74DDw`j)Ki#gt}mIT-Q`XRa2-jQXQoI%w`nb|XblvzK${ZzlV)m-XcwC(od z71_OEC5Bt9GEXosOXaPTYOia#R4ID2TiU~`zVMl08TV_C%DnU4^+HE>9(CE4D6?Fz oujB08i7adh9xk7*FX66dWH6F5TM;?E2b5PlUHx3vIVCg!0Dx9vYXATM diff --git a/packages/async_button_hook/example/web/icons/Icon-192.png b/packages/async_button_hook/example/web/icons/Icon-192.png deleted file mode 100644 index b749bfef07473333cf1dd31e9eed89862a5d52aa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5292 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 diff --git a/packages/async_button_hook/example/web/icons/Icon-512.png b/packages/async_button_hook/example/web/icons/Icon-512.png deleted file mode 100644 index 88cfd48dff1169879ba46840804b412fe02fefd6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8252 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 diff --git a/packages/async_button_hook/example/web/icons/Icon-maskable-192.png b/packages/async_button_hook/example/web/icons/Icon-maskable-192.png deleted file mode 100644 index eb9b4d76e525556d5d89141648c724331630325d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5594 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 X>c!)3PgKfL&lX^$Z>Cpu&6)6jvi^Z! diff --git a/packages/async_button_hook/example/web/icons/Icon-maskable-512.png b/packages/async_button_hook/example/web/icons/Icon-maskable-512.png deleted file mode 100644 index d69c56691fbdb0b7efa65097c7cc1edac12a6d3e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20998 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 MPgg&ebxsLQ025IeI{*Lx diff --git a/packages/async_button_hook/example/web/index.html b/packages/async_button_hook/example/web/index.html deleted file mode 100644 index b829dda..0000000 --- a/packages/async_button_hook/example/web/index.html +++ /dev/null @@ -1,101 +0,0 @@ - - - - - - - - - - - - - - - - - example - - - - - - - diff --git a/packages/async_button_hook/example/web/manifest.json b/packages/async_button_hook/example/web/manifest.json deleted file mode 100644 index 096edf8..0000000 --- a/packages/async_button_hook/example/web/manifest.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "example", - "short_name": "example", - "start_url": ".", - "display": "standalone", - "background_color": "#0175C2", - "theme_color": "#0175C2", - "description": "A new Flutter project.", - "orientation": "portrait-primary", - "prefer_related_applications": false, - "icons": [ - { - "src": "icons/Icon-192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "icons/Icon-512.png", - "sizes": "512x512", - "type": "image/png" - }, - { - "src": "icons/Icon-maskable-192.png", - "sizes": "192x192", - "type": "image/png", - "purpose": "maskable" - }, - { - "src": "icons/Icon-maskable-512.png", - "sizes": "512x512", - "type": "image/png", - "purpose": "maskable" - } - ] -} diff --git a/packages/async_button_hook/lib/async_button_hook.dart b/packages/async_button_hook/lib/async_button_hook.dart deleted file mode 100644 index 5e29b06..0000000 --- a/packages/async_button_hook/lib/async_button_hook.dart +++ /dev/null @@ -1,4 +0,0 @@ -library async_button_hook; - -export 'package:async_button_core/async_button_core.dart'; -export 'package:async_button_hook/src/async_button_hook.dart'; diff --git a/packages/async_button_hook/lib/src/async_button_hook.dart b/packages/async_button_hook/lib/src/async_button_hook.dart deleted file mode 100644 index e535f5c..0000000 --- a/packages/async_button_hook/lib/src/async_button_hook.dart +++ /dev/null @@ -1,218 +0,0 @@ -import 'dart:async'; - -import 'package:async_button_core/async_button_core.dart'; -import 'package:async_button_hook/src/models/async_button_result.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; - -/// A button that can be used to perform an asynchronous operation. -AsyncButtonResult useAsyncButton({ - required Widget child, - required AsyncCallback? onPressed, - Widget? loadingWidget, - Widget? successWidget, - Widget? errorWidget, - bool showSuccess = true, - bool showError = true, - EdgeInsets? errorPadding, - EdgeInsets? successPadding, - ButtonState buttonState = const ButtonState.idle(), - Duration duration = const Duration(milliseconds: 250), - Duration reverseDuration = const Duration(milliseconds: 250), - bool disabled = false, - Duration successDuration = const Duration(seconds: 1), - Duration errorDuration = const Duration(seconds: 1), - AnimatedSwitcherTransitionBuilder loadingTransitionBuilder = - AnimatedSwitcher.defaultTransitionBuilder, - AnimatedSwitcherTransitionBuilder idleTransitionBuilder = - AnimatedSwitcher.defaultTransitionBuilder, - AnimatedSwitcherTransitionBuilder successTransitionBuilder = - AnimatedSwitcher.defaultTransitionBuilder, - AnimatedSwitcherTransitionBuilder errorTransitionBuilder = - AnimatedSwitcher.defaultTransitionBuilder, - Curve idleSwitchInCurve = Curves.linear, - Curve loadingSwitchInCurve = Curves.linear, - Curve successSwitchInCurve = Curves.linear, - Curve errorSwitchInCurve = Curves.linear, - Curve idleSwitchOutCurve = Curves.linear, - Curve loadingSwitchOutCurve = Curves.linear, - Curve successSwitchOutCurve = Curves.linear, - Curve errorSwitchOutCurve = Curves.linear, - Curve sizeCurve = Curves.linear, - Clip sizeClipBehavior = Clip.hardEdge, - Alignment sizeAlignment = Alignment.center, - bool animateSize = true, -}) { - final _buttonState = useState(buttonState); - Timer? timer; - - useEffect( - () { - if (_buttonState.value != buttonState) { - _buttonState.value = buttonState; - } - - return () { - timer?.cancel(); - }; - }, - [buttonState], - ); - - final isMounted = useIsMounted(); - final context = useContext(); - final childKey = child.key; - final theme = Theme.of(context); - final _loadingWidget = loadingWidget ?? - const SizedBox( - height: 16.0, - width: 16.0, - child: CircularProgressIndicator(), - ); - var _successWidget = successWidget ?? - Icon( - Icons.check, - color: theme.colorScheme.secondary, - ); - var _errorWidget = errorWidget ?? - Icon( - Icons.error, - color: theme.errorColor, - ); - - // This is necessary in the case of nested async button builders. - // We cannot have the same __idle__, __loading__, etc. keys as they might - // conflict with one another. - String childKeyValue = ''; - - if (childKey != null && childKey is ValueKey) { - childKeyValue = childKey.value.toString(); - } - - if (successPadding != null) { - _successWidget = Padding( - padding: successPadding, - child: successWidget, - ); - } - - if (errorPadding != null) { - _errorWidget = Padding( - padding: errorPadding, - child: errorWidget, - ); - } - - final switcher = AnimatedSwitcher( - // TODO: This duration is same as size's duration. That's okay right? - duration: duration, - reverseDuration: reverseDuration, - switchInCurve: _buttonState.value.when( - idle: () => idleSwitchInCurve, - loading: () => loadingSwitchInCurve, - success: () => successSwitchInCurve, - error: () => errorSwitchInCurve, - ), - switchOutCurve: _buttonState.value.when( - idle: () => idleSwitchOutCurve, - loading: () => loadingSwitchOutCurve, - success: () => successSwitchOutCurve, - error: () => errorSwitchOutCurve, - ), - transitionBuilder: _buttonState.value.when( - idle: () => idleTransitionBuilder, - loading: () => loadingTransitionBuilder, - success: () => successTransitionBuilder, - error: () => errorTransitionBuilder, - ), - child: _buttonState.value.when( - idle: () => KeyedSubtree( - key: ValueKey('__idle__' + childKeyValue), - child: child, - ), - loading: () => KeyedSubtree( - key: ValueKey('__loading__' + childKeyValue), - child: _loadingWidget, - ), - success: () => KeyedSubtree( - key: ValueKey('__success__' + childKeyValue), - child: _successWidget, - ), - error: () => KeyedSubtree( - key: ValueKey('__error__' + childKeyValue), - child: _errorWidget, - ), - ), - ); - - void setTimer(Duration duration) { - timer = Timer( - duration, - () { - timer?.cancel(); - - if (isMounted()) { - _buttonState.value = const ButtonState.idle(); - } - }, - ); - } - - return AsyncButtonResult( - child: animateSize - ? AnimatedSize( - duration: duration, - reverseDuration: reverseDuration, - alignment: sizeAlignment, - clipBehavior: sizeClipBehavior, - curve: sizeCurve, - child: switcher, - ) - : switcher, - callback: disabled - ? null - : onPressed == null - ? null - : _buttonState.value.maybeWhen( - idle: () => () { - final completer = Completer(); - // I might not want to set buttonState if we're being - // driven by buttonState... - _buttonState.value = const ButtonState.loading(); - - timer?.cancel(); - - onPressed.call().then((_) { - completer.complete(); - - if (isMounted()) { - if (showSuccess) { - _buttonState.value = const ButtonState.success(); - - setTimer(successDuration); - } else { - _buttonState.value = const ButtonState.idle(); - } - } - }).catchError((Object error, StackTrace stackTrace) { - completer.completeError(error, stackTrace); - - if (isMounted()) { - if (showError) { - _buttonState.value = const ButtonState.error(); - - setTimer(errorDuration); - } else { - _buttonState.value = const ButtonState.idle(); - } - } - }); - - return completer.future; - }, - orElse: () => null, - ), - buttonState: _buttonState.value, - ); -} diff --git a/packages/async_button_hook/lib/src/models/async_button_result.dart b/packages/async_button_hook/lib/src/models/async_button_result.dart deleted file mode 100644 index 5202c03..0000000 --- a/packages/async_button_hook/lib/src/models/async_button_result.dart +++ /dev/null @@ -1,22 +0,0 @@ -import 'package:async_button_core/async_button_core.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; - -/// The result of an asynchoous button -@immutable -class AsyncButtonResult { - /// The child of the button - final Widget child; - - /// Passed to the Button in place of the original onTap/onPressed variant - final AsyncCallback? callback; - - /// The state the button is currently in - final ButtonState buttonState; - - const AsyncButtonResult({ - required this.child, - required this.callback, - required this.buttonState, - }); -} diff --git a/packages/async_button_hook/pubspec.lock b/packages/async_button_hook/pubspec.lock deleted file mode 100644 index 660bfa6..0000000 --- a/packages/async_button_hook/pubspec.lock +++ /dev/null @@ -1,189 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - async: - dependency: transitive - description: - name: async - url: "https://pub.dartlang.org" - source: hosted - version: "2.8.1" - async_button_core: - dependency: "direct main" - description: - name: async_button_core - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.1+7" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - characters: - dependency: transitive - description: - name: characters - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.1" - clock: - dependency: transitive - description: - name: clock - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - collection: - dependency: transitive - description: - name: collection - url: "https://pub.dartlang.org" - source: hosted - version: "1.15.0" - fake_async: - dependency: transitive - description: - name: fake_async - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_hooks: - dependency: "direct main" - description: - name: flutter_hooks - url: "https://pub.dartlang.org" - source: hosted - version: "0.18.0" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.4" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - freezed_annotation: - dependency: transitive - description: - name: freezed_annotation - url: "https://pub.dartlang.org" - source: hosted - version: "0.14.3" - json_annotation: - dependency: transitive - description: - name: json_annotation - url: "https://pub.dartlang.org" - source: hosted - version: "4.1.0" - lints: - dependency: transitive - description: - name: lints - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" - matcher: - dependency: transitive - description: - name: matcher - url: "https://pub.dartlang.org" - source: hosted - version: "0.12.10" - meta: - dependency: transitive - description: - name: meta - url: "https://pub.dartlang.org" - source: hosted - version: "1.7.0" - path: - dependency: transitive - description: - name: path - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.0" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.99" - source_span: - dependency: transitive - description: - name: source_span - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.1" - stack_trace: - dependency: transitive - description: - name: stack_trace - url: "https://pub.dartlang.org" - source: hosted - version: "1.10.0" - stream_channel: - dependency: transitive - description: - name: stream_channel - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - string_scanner: - dependency: transitive - description: - name: string_scanner - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - term_glyph: - dependency: transitive - description: - name: term_glyph - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - test_api: - dependency: transitive - description: - name: test_api - url: "https://pub.dartlang.org" - source: hosted - version: "0.4.2" - typed_data: - dependency: transitive - description: - name: typed_data - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.0" - vector_math: - dependency: transitive - description: - name: vector_math - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" -sdks: - dart: ">=2.12.0 <3.0.0" - flutter: ">=1.20.0" diff --git a/packages/async_button_hook/pubspec.yaml b/packages/async_button_hook/pubspec.yaml deleted file mode 100644 index c2516ac..0000000 --- a/packages/async_button_hook/pubspec.yaml +++ /dev/null @@ -1,21 +0,0 @@ -name: async_button_hook -description: A hook version of async_button_builder which depends on flutter_hooks -version: 0.0.1+8 -homepage: https://github.com/Nolence/async_button/tree/main/packages/async_button_hook - -environment: - sdk: ">=2.12.0 <3.0.0" - flutter: ">=1.17.0" - -dependencies: - flutter: - sdk: flutter - flutter_hooks: ^0.18.0 - async_button_core: ^0.0.1+7 - -dev_dependencies: - flutter_lints: ^1.0.0 - flutter_test: - sdk: flutter - -flutter: diff --git a/packages/async_button_hook/test/async_button_hook_test.dart b/packages/async_button_hook/test/async_button_hook_test.dart deleted file mode 100644 index 0da434d..0000000 --- a/packages/async_button_hook/test/async_button_hook_test.dart +++ /dev/null @@ -1,5 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; - -void main() { - test('adds one to input values', () {}); -} diff --git a/packages/async_button_core/pubspec.lock b/pubspec.lock similarity index 94% rename from packages/async_button_core/pubspec.lock rename to pubspec.lock index edf125d..9e7e5da 100644 --- a/packages/async_button_core/pubspec.lock +++ b/pubspec.lock @@ -7,14 +7,14 @@ packages: name: _fe_analyzer_shared url: "https://pub.dartlang.org" source: hosted - version: "26.0.0" + version: "32.0.0" analyzer: dependency: transitive description: name: analyzer url: "https://pub.dartlang.org" source: hosted - version: "2.3.0" + version: "3.0.0" args: dependency: transitive description: @@ -28,7 +28,7 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.8.1" + version: "2.8.2" boolean_selector: dependency: transitive description: @@ -42,7 +42,7 @@ packages: name: build url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.2.1" build_config: dependency: transitive description: @@ -56,28 +56,28 @@ packages: name: build_daemon url: "https://pub.dartlang.org" source: hosted - version: "3.0.0" + version: "3.0.1" build_resolvers: dependency: transitive description: name: build_resolvers url: "https://pub.dartlang.org" source: hosted - version: "2.0.4" + version: "2.0.6" build_runner: dependency: "direct dev" description: name: build_runner url: "https://pub.dartlang.org" source: hosted - version: "2.1.2" + version: "2.1.7" build_runner_core: dependency: transitive description: name: build_runner_core url: "https://pub.dartlang.org" source: hosted - version: "7.1.0" + version: "7.2.3" built_collection: dependency: transitive description: @@ -91,14 +91,14 @@ packages: name: built_value url: "https://pub.dartlang.org" source: hosted - version: "8.1.2" + version: "8.1.3" characters: dependency: transitive description: name: characters url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.2.0" charcode: dependency: transitive description: @@ -119,7 +119,7 @@ packages: name: cli_util url: "https://pub.dartlang.org" source: hosted - version: "0.3.3" + version: "0.3.5" clock: dependency: transitive description: @@ -161,7 +161,7 @@ packages: name: dart_style url: "https://pub.dartlang.org" source: hosted - version: "2.2.0" + version: "2.2.1" fake_async: dependency: transitive description: @@ -206,14 +206,14 @@ packages: name: freezed url: "https://pub.dartlang.org" source: hosted - version: "0.14.5" + version: "1.1.1" freezed_annotation: dependency: "direct main" description: name: freezed_annotation url: "https://pub.dartlang.org" source: hosted - version: "0.15.0" + version: "1.1.0" frontend_server_client: dependency: transitive description: @@ -227,7 +227,7 @@ packages: name: glob url: "https://pub.dartlang.org" source: hosted - version: "2.0.1" + version: "2.0.2" graphs: dependency: transitive description: @@ -269,7 +269,7 @@ packages: name: json_annotation url: "https://pub.dartlang.org" source: hosted - version: "4.1.0" + version: "4.4.0" lints: dependency: transitive description: @@ -290,7 +290,7 @@ packages: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.10" + version: "0.12.11" meta: dependency: transitive description: @@ -304,7 +304,7 @@ packages: name: mime url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.0.1" package_config: dependency: transitive description: @@ -319,13 +319,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.8.0" - pedantic: - dependency: transitive - description: - name: pedantic - url: "https://pub.dartlang.org" - source: hosted - version: "1.11.1" pool: dependency: transitive description: @@ -346,7 +339,7 @@ packages: name: pubspec_parse url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.2.0" shelf: dependency: transitive description: @@ -372,7 +365,7 @@ packages: name: source_gen url: "https://pub.dartlang.org" source: hosted - version: "1.1.1" + version: "1.2.1" source_span: dependency: transitive description: @@ -421,7 +414,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.2" + version: "0.4.3" timing: dependency: transitive description: @@ -442,14 +435,14 @@ packages: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.1.1" watcher: dependency: transitive description: name: watcher url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.0.1" web_socket_channel: dependency: transitive description: diff --git a/packages/async_button_builder/pubspec.yaml b/pubspec.yaml similarity index 68% rename from packages/async_button_builder/pubspec.yaml rename to pubspec.yaml index a53fa9a..ab1e8ad 100644 --- a/packages/async_button_builder/pubspec.yaml +++ b/pubspec.yaml @@ -1,20 +1,23 @@ name: async_button_builder -description: A builder to wrap around buttons that handles loading, disabled, error and succes states +description: A builder to wrap around buttons that handles loading, disabled, + error and succes states version: 2.1.4 homepage: https://github.com/Nolence/async_button/tree/main/packages/async_button_builder environment: - sdk: '>=2.12.0 <3.0.0' + sdk: ">=2.12.0 <3.0.0" flutter: ">=1.17.0" dependencies: flutter: sdk: flutter - async_button_core: ^0.0.1+7 - + freezed_annotation: ">=1.0.0 <2.0.0" + dev_dependencies: + build_runner: ^2.1.7 + freezed: ^1.1.1 + flutter_lints: ^1.0.0 flutter_test: sdk: flutter - flutter_lints: ^1.0.0 -flutter: \ No newline at end of file +flutter: null diff --git a/packages/async_button_builder/test/async_button_builder_test.dart b/test/async_button_builder_test.dart similarity index 100% rename from packages/async_button_builder/test/async_button_builder_test.dart rename to test/async_button_builder_test.dart From b7c6ca9814385a09ee4edeb0d7aee1fb4efc768f Mon Sep 17 00:00:00 2001 From: Nolence Date: Fri, 7 Jan 2022 12:37:20 -0700 Subject: [PATCH 072/176] renamed some stuff in examples --- README.md | 2 +- example/ios/Runner.xcodeproj/project.pbxproj | 4 ++-- .../Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme | 2 +- example/lib/main.dart | 2 +- lib/src/async_button_builder.dart | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index f200ba1..f0c715f 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ AsyncButtonBuilder( await Future.delayed(Duration(seconds: 1)); // See the examples file for a way to handle timeouts - throw 'shucks'; + throw 'yikes'; }, builder: (context, child, callback, buttonState) { final buttonColor = buttonState.when( diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index ad27a86..0ecf382 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 50; objects = { /* Begin PBXBuildFile section */ @@ -155,7 +155,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1020; + LastUpgradeCheck = 1300; ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index a28140c..3db53b6 100644 --- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ Date: Fri, 7 Jan 2022 12:45:31 -0700 Subject: [PATCH 073/176] updated versions --- CHANGELOG.md | 2 +- pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b732b05..07f3848 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## [3.0.0] - 2022-01-07 +## [2.2.0] - 2022-01-07 Got rid of hook version as it was complicating a simple package and likely discouraging possible contributors. ## [2.1.4] - 2021-09-28 diff --git a/pubspec.yaml b/pubspec.yaml index ab1e8ad..feae2cf 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: async_button_builder description: A builder to wrap around buttons that handles loading, disabled, error and succes states -version: 2.1.4 +version: 2.2.0 homepage: https://github.com/Nolence/async_button/tree/main/packages/async_button_builder environment: From b089c650853ed25d6ba7ed9971b73d4d0bebedb3 Mon Sep 17 00:00:00 2001 From: Nolence Date: Fri, 7 Jan 2022 13:11:57 -0700 Subject: [PATCH 074/176] removed idea stuff --- .gitignore | 1 + .idea/.name | 1 - .idea/modules.xml | 13 ------------- .idea/runConfigurations/melos_bootstrap.xml | 11 ----------- .idea/runConfigurations/melos_clean.xml | 11 ----------- .../runConfigurations/melos_flutter_run_example.xml | 6 ------ .../melos_flutter_test_async_button_builder.xml | 7 ------- .../melos_flutter_test_async_button_core.xml | 7 ------- .../melos_flutter_test_async_button_hook.xml | 7 ------- .idea/runConfigurations/melos_run_analyze.xml | 11 ----------- .idea/runConfigurations/melos_run_generate.xml | 11 ----------- .idea/runConfigurations/melos_run_generate_dart.xml | 11 ----------- .../melos_run_generate_flutter.xml | 11 ----------- .idea/runConfigurations/melos_run_test.xml | 11 ----------- .idea/runConfigurations/melos_run_test_dart.xml | 11 ----------- .idea/runConfigurations/melos_run_test_flutter.xml | 11 ----------- .pubignore | 4 ++++ 17 files changed, 5 insertions(+), 140 deletions(-) delete mode 100644 .idea/.name delete mode 100644 .idea/modules.xml delete mode 100644 .idea/runConfigurations/melos_bootstrap.xml delete mode 100644 .idea/runConfigurations/melos_clean.xml delete mode 100644 .idea/runConfigurations/melos_flutter_run_example.xml delete mode 100644 .idea/runConfigurations/melos_flutter_test_async_button_builder.xml delete mode 100644 .idea/runConfigurations/melos_flutter_test_async_button_core.xml delete mode 100644 .idea/runConfigurations/melos_flutter_test_async_button_hook.xml delete mode 100644 .idea/runConfigurations/melos_run_analyze.xml delete mode 100644 .idea/runConfigurations/melos_run_generate.xml delete mode 100644 .idea/runConfigurations/melos_run_generate_dart.xml delete mode 100644 .idea/runConfigurations/melos_run_generate_flutter.xml delete mode 100644 .idea/runConfigurations/melos_run_test.xml delete mode 100644 .idea/runConfigurations/melos_run_test_dart.xml delete mode 100644 .idea/runConfigurations/melos_run_test_flutter.xml create mode 100644 .pubignore diff --git a/.gitignore b/.gitignore index e59c66a..57b484f 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ *.ipr *.iws .idea/ +.idea # The .vscode folder contains launch configuration and tasks you configure in # VS Code which you may wish to be included in version control, so this line diff --git a/.idea/.name b/.idea/.name deleted file mode 100644 index 132f597..0000000 --- a/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -async_button \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index fb3a7d5..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/runConfigurations/melos_bootstrap.xml b/.idea/runConfigurations/melos_bootstrap.xml deleted file mode 100644 index d571530..0000000 --- a/.idea/runConfigurations/melos_bootstrap.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - diff --git a/.idea/runConfigurations/melos_clean.xml b/.idea/runConfigurations/melos_clean.xml deleted file mode 100644 index f45d436..0000000 --- a/.idea/runConfigurations/melos_clean.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - diff --git a/.idea/runConfigurations/melos_flutter_run_example.xml b/.idea/runConfigurations/melos_flutter_run_example.xml deleted file mode 100644 index d7a2aa2..0000000 --- a/.idea/runConfigurations/melos_flutter_run_example.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/runConfigurations/melos_flutter_test_async_button_builder.xml b/.idea/runConfigurations/melos_flutter_test_async_button_builder.xml deleted file mode 100644 index d9962a1..0000000 --- a/.idea/runConfigurations/melos_flutter_test_async_button_builder.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - \ No newline at end of file diff --git a/.idea/runConfigurations/melos_flutter_test_async_button_core.xml b/.idea/runConfigurations/melos_flutter_test_async_button_core.xml deleted file mode 100644 index b649d6a..0000000 --- a/.idea/runConfigurations/melos_flutter_test_async_button_core.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - \ No newline at end of file diff --git a/.idea/runConfigurations/melos_flutter_test_async_button_hook.xml b/.idea/runConfigurations/melos_flutter_test_async_button_hook.xml deleted file mode 100644 index 03a8548..0000000 --- a/.idea/runConfigurations/melos_flutter_test_async_button_hook.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - \ No newline at end of file diff --git a/.idea/runConfigurations/melos_run_analyze.xml b/.idea/runConfigurations/melos_run_analyze.xml deleted file mode 100644 index 4287f1c..0000000 --- a/.idea/runConfigurations/melos_run_analyze.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - diff --git a/.idea/runConfigurations/melos_run_generate.xml b/.idea/runConfigurations/melos_run_generate.xml deleted file mode 100644 index a697726..0000000 --- a/.idea/runConfigurations/melos_run_generate.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - diff --git a/.idea/runConfigurations/melos_run_generate_dart.xml b/.idea/runConfigurations/melos_run_generate_dart.xml deleted file mode 100644 index 3f84c12..0000000 --- a/.idea/runConfigurations/melos_run_generate_dart.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - diff --git a/.idea/runConfigurations/melos_run_generate_flutter.xml b/.idea/runConfigurations/melos_run_generate_flutter.xml deleted file mode 100644 index 2ffa709..0000000 --- a/.idea/runConfigurations/melos_run_generate_flutter.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - diff --git a/.idea/runConfigurations/melos_run_test.xml b/.idea/runConfigurations/melos_run_test.xml deleted file mode 100644 index a4f0c21..0000000 --- a/.idea/runConfigurations/melos_run_test.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - diff --git a/.idea/runConfigurations/melos_run_test_dart.xml b/.idea/runConfigurations/melos_run_test_dart.xml deleted file mode 100644 index c18e99d..0000000 --- a/.idea/runConfigurations/melos_run_test_dart.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - diff --git a/.idea/runConfigurations/melos_run_test_flutter.xml b/.idea/runConfigurations/melos_run_test_flutter.xml deleted file mode 100644 index beda0b0..0000000 --- a/.idea/runConfigurations/melos_run_test_flutter.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - diff --git a/.pubignore b/.pubignore new file mode 100644 index 0000000..fa3282a --- /dev/null +++ b/.pubignore @@ -0,0 +1,4 @@ +.idea/ +.vscode/ +screenshots/ +build/ \ No newline at end of file From 07f98f25962a28809316f55060f8345d659ebc5a Mon Sep 17 00:00:00 2001 From: softronaut Date: Tue, 25 Jan 2022 11:14:55 +0300 Subject: [PATCH 075/176] export fix, .gitignore fix, vscode folder delete --- .gitignore | 2 +- .vscode/settings.json | 3 --- example/pubspec.lock | 2 +- lib/async_button_builder.dart | 2 +- 4 files changed, 3 insertions(+), 6 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.gitignore b/.gitignore index 57b484f..7be8c83 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ *.iws .idea/ .idea +.vscode/ # The .vscode folder contains launch configuration and tasks you configure in # VS Code which you may wish to be included in version control, so this line @@ -77,4 +78,3 @@ build/ .melos_tool/ -*.iml \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 7f69797..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "dart.runPubGetOnPubspecChanges": false -} \ No newline at end of file diff --git a/example/pubspec.lock b/example/pubspec.lock index 14e8a74..56b355c 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -14,7 +14,7 @@ packages: path: ".." relative: true source: path - version: "2.1.4" + version: "2.2.0" boolean_selector: dependency: transitive description: diff --git a/lib/async_button_builder.dart b/lib/async_button_builder.dart index 2548d3d..2f7998d 100644 --- a/lib/async_button_builder.dart +++ b/lib/async_button_builder.dart @@ -1,4 +1,4 @@ library async_button_builder; -export 'package:async_button_builder/async_button_builder.dart'; export 'package:async_button_builder/src/async_button_builder.dart'; +export 'package:async_button_builder/src/button_state/button_state.dart'; From 7e36c71f6f98d9fc1a9388bd148595ae443dbd6f Mon Sep 17 00:00:00 2001 From: Nolence Date: Fri, 28 Jan 2022 09:27:16 -0700 Subject: [PATCH 076/176] version bump and changelog update --- CHANGELOG.md | 3 +++ example/pubspec.lock | 2 +- pubspec.yaml | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 07f3848..0b5e763 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## [2.2.0+1] - 2022-01-28 +Ignore .vscode, update versions and re-export button state. Credit @esenmx + ## [2.2.0] - 2022-01-07 Got rid of hook version as it was complicating a simple package and likely discouraging possible contributors. diff --git a/example/pubspec.lock b/example/pubspec.lock index 56b355c..3753fb9 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -14,7 +14,7 @@ packages: path: ".." relative: true source: path - version: "2.2.0" + version: "2.2.0+1" boolean_selector: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index feae2cf..9bc4444 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: async_button_builder description: A builder to wrap around buttons that handles loading, disabled, error and succes states -version: 2.2.0 +version: 2.2.0+1 homepage: https://github.com/Nolence/async_button/tree/main/packages/async_button_builder environment: From e631a956f62d2fd89afac6f713bfbb76a48b9238 Mon Sep 17 00:00:00 2001 From: mergehez Date: Wed, 30 Mar 2022 18:30:23 +0200 Subject: [PATCH 077/176] removed "freezed" until a new button state is needed As the generated codes are still available, it doesn't make sense to have "freezed_annotation" in the dependencies. If a new button state is needed which is not likely to happen, then it can be temporarily added and removed after generating the code. --- example/pubspec.lock | 21 +- lib/src/button_state/button_state.dart | 4 +- pubspec.lock | 308 +------------------------ pubspec.yaml | 3 - 4 files changed, 15 insertions(+), 321 deletions(-) diff --git a/example/pubspec.lock b/example/pubspec.lock index 3753fb9..75384c5 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -74,27 +74,20 @@ packages: description: flutter source: sdk version: "0.0.0" - freezed_annotation: - dependency: transitive - description: - name: freezed_annotation - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - json_annotation: + matcher: dependency: transitive description: - name: json_annotation + name: matcher url: "https://pub.dartlang.org" source: hosted - version: "4.4.0" - matcher: + version: "0.12.11" + material_color_utilities: dependency: transitive description: - name: matcher + name: material_color_utilities url: "https://pub.dartlang.org" source: hosted - version: "0.12.11" + version: "0.1.3" meta: dependency: transitive description: @@ -162,7 +155,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.3" + version: "0.4.8" typed_data: dependency: transitive description: diff --git a/lib/src/button_state/button_state.dart b/lib/src/button_state/button_state.dart index c2a0a1a..bfd4ffa 100644 --- a/lib/src/button_state/button_state.dart +++ b/lib/src/button_state/button_state.dart @@ -1,5 +1,3 @@ -import 'package:freezed_annotation/freezed_annotation.dart'; - part 'button_state.freezed.dart'; /// This union class represents the state of the button in either a [Idling], @@ -30,7 +28,7 @@ part 'button_state.freezed.dart'; /// ); /// ``` /// {@end-tool} -@freezed +// @freezed class ButtonState with _$ButtonState { const factory ButtonState.idle() = Idle; const factory ButtonState.loading() = Loading; diff --git a/pubspec.lock b/pubspec.lock index 9e7e5da..2485cb8 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,27 +1,6 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: - _fe_analyzer_shared: - dependency: transitive - description: - name: _fe_analyzer_shared - url: "https://pub.dartlang.org" - source: hosted - version: "32.0.0" - analyzer: - dependency: transitive - description: - name: analyzer - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.0" - args: - dependency: transitive - description: - name: args - url: "https://pub.dartlang.org" - source: hosted - version: "2.3.0" async: dependency: transitive description: @@ -36,62 +15,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" - build: - dependency: transitive - description: - name: build - url: "https://pub.dartlang.org" - source: hosted - version: "2.2.1" - build_config: - dependency: transitive - description: - name: build_config - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - build_daemon: - dependency: transitive - description: - name: build_daemon - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.1" - build_resolvers: - dependency: transitive - description: - name: build_resolvers - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.6" - build_runner: - dependency: "direct dev" - description: - name: build_runner - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.7" - build_runner_core: - dependency: transitive - description: - name: build_runner_core - url: "https://pub.dartlang.org" - source: hosted - version: "7.2.3" - built_collection: - dependency: transitive - description: - name: built_collection - url: "https://pub.dartlang.org" - source: hosted - version: "5.1.1" - built_value: - dependency: transitive - description: - name: built_value - url: "https://pub.dartlang.org" - source: hosted - version: "8.1.3" characters: dependency: transitive description: @@ -106,20 +29,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.1" - checked_yaml: - dependency: transitive - description: - name: checked_yaml - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.1" - cli_util: - dependency: transitive - description: - name: cli_util - url: "https://pub.dartlang.org" - source: hosted - version: "0.3.5" clock: dependency: transitive description: @@ -127,13 +36,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.0" - code_builder: - dependency: transitive - description: - name: code_builder - url: "https://pub.dartlang.org" - source: hosted - version: "4.1.0" collection: dependency: transitive description: @@ -141,27 +43,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.15.0" - convert: - dependency: transitive - description: - name: convert - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.1" - crypto: - dependency: transitive - description: - name: crypto - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.1" - dart_style: - dependency: transitive - description: - name: dart_style - url: "https://pub.dartlang.org" - source: hosted - version: "2.2.1" fake_async: dependency: transitive description: @@ -169,20 +50,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.0" - file: - dependency: transitive - description: - name: file - url: "https://pub.dartlang.org" - source: hosted - version: "6.1.2" - fixnum: - dependency: transitive - description: - name: fixnum - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" flutter: dependency: "direct main" description: flutter @@ -200,76 +67,6 @@ packages: description: flutter source: sdk version: "0.0.0" - freezed: - dependency: "direct dev" - description: - name: freezed - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.1" - freezed_annotation: - dependency: "direct main" - description: - name: freezed_annotation - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - frontend_server_client: - dependency: transitive - description: - name: frontend_server_client - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.2" - glob: - dependency: transitive - description: - name: glob - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.2" - graphs: - dependency: transitive - description: - name: graphs - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - http_multi_server: - dependency: transitive - description: - name: http_multi_server - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.1" - http_parser: - dependency: transitive - description: - name: http_parser - url: "https://pub.dartlang.org" - source: hosted - version: "4.0.0" - io: - dependency: transitive - description: - name: io - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.3" - js: - dependency: transitive - description: - name: js - url: "https://pub.dartlang.org" - source: hosted - version: "0.6.3" - json_annotation: - dependency: transitive - description: - name: json_annotation - url: "https://pub.dartlang.org" - source: hosted - version: "4.4.0" lints: dependency: transitive description: @@ -277,13 +74,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.1" - logging: - dependency: transitive - description: - name: logging - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.2" matcher: dependency: transitive description: @@ -291,27 +81,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.12.11" - meta: + material_color_utilities: dependency: transitive description: - name: meta + name: material_color_utilities url: "https://pub.dartlang.org" source: hosted - version: "1.7.0" - mime: - dependency: transitive - description: - name: mime - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" - package_config: + version: "0.1.3" + meta: dependency: transitive description: - name: package_config + name: meta url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "1.7.0" path: dependency: transitive description: @@ -319,53 +102,11 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.8.0" - pool: - dependency: transitive - description: - name: pool - url: "https://pub.dartlang.org" - source: hosted - version: "1.5.0" - pub_semver: - dependency: transitive - description: - name: pub_semver - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - pubspec_parse: - dependency: transitive - description: - name: pubspec_parse - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - shelf: - dependency: transitive - description: - name: shelf - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - shelf_web_socket: - dependency: transitive - description: - name: shelf_web_socket - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" sky_engine: dependency: transitive description: flutter source: sdk version: "0.0.99" - source_gen: - dependency: transitive - description: - name: source_gen - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.1" source_span: dependency: transitive description: @@ -387,13 +128,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" - stream_transform: - dependency: transitive - description: - name: stream_transform - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" string_scanner: dependency: transitive description: @@ -414,14 +148,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.3" - timing: - dependency: transitive - description: - name: timing - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" + version: "0.4.8" typed_data: dependency: transitive description: @@ -436,27 +163,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.1" - watcher: - dependency: transitive - description: - name: watcher - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" - web_socket_channel: - dependency: transitive - description: - name: web_socket_channel - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - yaml: - dependency: transitive - description: - name: yaml - url: "https://pub.dartlang.org" - source: hosted - version: "3.1.0" sdks: dart: ">=2.14.0 <3.0.0" flutter: ">=1.17.0" diff --git a/pubspec.yaml b/pubspec.yaml index 9bc4444..60c173b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,11 +11,8 @@ environment: dependencies: flutter: sdk: flutter - freezed_annotation: ">=1.0.0 <2.0.0" dev_dependencies: - build_runner: ^2.1.7 - freezed: ^1.1.1 flutter_lints: ^1.0.0 flutter_test: sdk: flutter From c5ca263f91a1078cabc1aa19e630edf1cfbb5bc2 Mon Sep 17 00:00:00 2001 From: mergehez Date: Wed, 30 Mar 2022 18:39:16 +0200 Subject: [PATCH 078/176] added new callbacks: "onSuccess" and "onError" --- lib/src/async_button_builder.dart | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/lib/src/async_button_builder.dart b/lib/src/async_button_builder.dart index 6a91693..da019c5 100644 --- a/lib/src/async_button_builder.dart +++ b/lib/src/async_button_builder.dart @@ -81,6 +81,12 @@ class AsyncButtonBuilder extends StatefulWidget { /// completes. final AsyncCallback? onPressed; + /// A callback that runs [buttonState] changes to [ButtonState.success] + final VoidCallback? onSuccess; + + /// A callback that runs [buttonState] changes to [ButtonState.error] + final VoidCallback? onError; + /// This is used to manually drive the state of the loading button thus /// initiating the corresponding animation and showing the correct button /// child. @@ -200,6 +206,8 @@ class AsyncButtonBuilder extends StatefulWidget { required this.child, required this.onPressed, required this.builder, + this.onSuccess, + this.onError, this.loadingWidget, this.successWidget, this.errorWidget, @@ -392,7 +400,7 @@ class _AsyncButtonBuilderState extends State buttonState = const ButtonState.success(); }); - setTimer(widget.successDuration); + setTimer(widget.successDuration, widget.onSuccess); } else { setState(() { buttonState = const ButtonState.idle(); @@ -408,7 +416,7 @@ class _AsyncButtonBuilderState extends State buttonState = const ButtonState.error(); }); - setTimer(widget.errorDuration); + setTimer(widget.errorDuration, widget.onSuccess); } else { setState(() { buttonState = const ButtonState.idle(); @@ -425,12 +433,14 @@ class _AsyncButtonBuilderState extends State ); } - void setTimer(Duration duration) { + void setTimer(Duration duration, [VoidCallback? then]) { timer = Timer( duration, () { timer?.cancel(); + then?.call(); + if (mounted) { setState(() { buttonState = const ButtonState.idle(); From 20e6c566d14b3d6a4f1daaca13ca9e3b87422ad6 Mon Sep 17 00:00:00 2001 From: esenmx Date: Tue, 19 Apr 2022 20:12:25 +0300 Subject: [PATCH 079/176] freezed 2.0.0 upgrade, unversion pubspec.lock --- .gitignore | 1 + example/pubspec.lock | 11 +- lib/src/async_button_builder.dart | 2 - .../button_state/button_state.freezed.dart | 39 +- pubspec.lock | 462 ------------------ pubspec.yaml | 8 +- 6 files changed, 24 insertions(+), 499 deletions(-) delete mode 100644 pubspec.lock diff --git a/.gitignore b/.gitignore index 7be8c83..a241674 100644 --- a/.gitignore +++ b/.gitignore @@ -78,3 +78,4 @@ build/ .melos_tool/ +/pubspec.lock diff --git a/example/pubspec.lock b/example/pubspec.lock index 3753fb9..6147300 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -80,7 +80,7 @@ packages: name: freezed_annotation url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "2.0.0" json_annotation: dependency: transitive description: @@ -95,6 +95,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.12.11" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.3" meta: dependency: transitive description: @@ -162,7 +169,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.3" + version: "0.4.8" typed_data: dependency: transitive description: diff --git a/lib/src/async_button_builder.dart b/lib/src/async_button_builder.dart index 6a91693..dc41085 100644 --- a/lib/src/async_button_builder.dart +++ b/lib/src/async_button_builder.dart @@ -253,14 +253,12 @@ class _AsyncButtonBuilderState extends State buttonState = widget.buttonState; }); } - super.didUpdateWidget(oldWidget); } @override void dispose() { timer?.cancel(); - super.dispose(); } diff --git a/lib/src/button_state/button_state.freezed.dart b/lib/src/button_state/button_state.freezed.dart index 690398a..9379850 100644 --- a/lib/src/button_state/button_state.freezed.dart +++ b/lib/src/button_state/button_state.freezed.dart @@ -1,5 +1,6 @@ // coverage:ignore-file // GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint // ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target part of 'button_state.dart'; @@ -11,31 +12,7 @@ part of 'button_state.dart'; T _$identity(T value) => value; final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); - -/// @nodoc -class _$ButtonStateTearOff { - const _$ButtonStateTearOff(); - - Idle idle() { - return const Idle(); - } - - Loading loading() { - return const Loading(); - } - - Success success() { - return const Success(); - } - - Error error() { - return const Error(); - } -} - -/// @nodoc -const $ButtonState = _$ButtonStateTearOff(); + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); /// @nodoc mixin _$ButtonState { @@ -135,7 +112,8 @@ class _$Idle implements Idle { @override bool operator ==(dynamic other) { - return identical(this, other) || (other is Idle); + return identical(this, other) || + (other.runtimeType == runtimeType && other is Idle); } @override @@ -248,7 +226,8 @@ class _$Loading implements Loading { @override bool operator ==(dynamic other) { - return identical(this, other) || (other is Loading); + return identical(this, other) || + (other.runtimeType == runtimeType && other is Loading); } @override @@ -361,7 +340,8 @@ class _$Success implements Success { @override bool operator ==(dynamic other) { - return identical(this, other) || (other is Success); + return identical(this, other) || + (other.runtimeType == runtimeType && other is Success); } @override @@ -474,7 +454,8 @@ class _$Error implements Error { @override bool operator ==(dynamic other) { - return identical(this, other) || (other is Error); + return identical(this, other) || + (other.runtimeType == runtimeType && other is Error); } @override diff --git a/pubspec.lock b/pubspec.lock deleted file mode 100644 index 9e7e5da..0000000 --- a/pubspec.lock +++ /dev/null @@ -1,462 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - _fe_analyzer_shared: - dependency: transitive - description: - name: _fe_analyzer_shared - url: "https://pub.dartlang.org" - source: hosted - version: "32.0.0" - analyzer: - dependency: transitive - description: - name: analyzer - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.0" - args: - dependency: transitive - description: - name: args - url: "https://pub.dartlang.org" - source: hosted - version: "2.3.0" - async: - dependency: transitive - description: - name: async - url: "https://pub.dartlang.org" - source: hosted - version: "2.8.2" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - build: - dependency: transitive - description: - name: build - url: "https://pub.dartlang.org" - source: hosted - version: "2.2.1" - build_config: - dependency: transitive - description: - name: build_config - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - build_daemon: - dependency: transitive - description: - name: build_daemon - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.1" - build_resolvers: - dependency: transitive - description: - name: build_resolvers - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.6" - build_runner: - dependency: "direct dev" - description: - name: build_runner - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.7" - build_runner_core: - dependency: transitive - description: - name: build_runner_core - url: "https://pub.dartlang.org" - source: hosted - version: "7.2.3" - built_collection: - dependency: transitive - description: - name: built_collection - url: "https://pub.dartlang.org" - source: hosted - version: "5.1.1" - built_value: - dependency: transitive - description: - name: built_value - url: "https://pub.dartlang.org" - source: hosted - version: "8.1.3" - characters: - dependency: transitive - description: - name: characters - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.1" - checked_yaml: - dependency: transitive - description: - name: checked_yaml - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.1" - cli_util: - dependency: transitive - description: - name: cli_util - url: "https://pub.dartlang.org" - source: hosted - version: "0.3.5" - clock: - dependency: transitive - description: - name: clock - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - code_builder: - dependency: transitive - description: - name: code_builder - url: "https://pub.dartlang.org" - source: hosted - version: "4.1.0" - collection: - dependency: transitive - description: - name: collection - url: "https://pub.dartlang.org" - source: hosted - version: "1.15.0" - convert: - dependency: transitive - description: - name: convert - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.1" - crypto: - dependency: transitive - description: - name: crypto - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.1" - dart_style: - dependency: transitive - description: - name: dart_style - url: "https://pub.dartlang.org" - source: hosted - version: "2.2.1" - fake_async: - dependency: transitive - description: - name: fake_async - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - file: - dependency: transitive - description: - name: file - url: "https://pub.dartlang.org" - source: hosted - version: "6.1.2" - fixnum: - dependency: transitive - description: - name: fixnum - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.4" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - freezed: - dependency: "direct dev" - description: - name: freezed - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.1" - freezed_annotation: - dependency: "direct main" - description: - name: freezed_annotation - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - frontend_server_client: - dependency: transitive - description: - name: frontend_server_client - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.2" - glob: - dependency: transitive - description: - name: glob - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.2" - graphs: - dependency: transitive - description: - name: graphs - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - http_multi_server: - dependency: transitive - description: - name: http_multi_server - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.1" - http_parser: - dependency: transitive - description: - name: http_parser - url: "https://pub.dartlang.org" - source: hosted - version: "4.0.0" - io: - dependency: transitive - description: - name: io - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.3" - js: - dependency: transitive - description: - name: js - url: "https://pub.dartlang.org" - source: hosted - version: "0.6.3" - json_annotation: - dependency: transitive - description: - name: json_annotation - url: "https://pub.dartlang.org" - source: hosted - version: "4.4.0" - lints: - dependency: transitive - description: - name: lints - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" - logging: - dependency: transitive - description: - name: logging - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.2" - matcher: - dependency: transitive - description: - name: matcher - url: "https://pub.dartlang.org" - source: hosted - version: "0.12.11" - meta: - dependency: transitive - description: - name: meta - url: "https://pub.dartlang.org" - source: hosted - version: "1.7.0" - mime: - dependency: transitive - description: - name: mime - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" - package_config: - dependency: transitive - description: - name: package_config - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.2" - path: - dependency: transitive - description: - name: path - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.0" - pool: - dependency: transitive - description: - name: pool - url: "https://pub.dartlang.org" - source: hosted - version: "1.5.0" - pub_semver: - dependency: transitive - description: - name: pub_semver - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - pubspec_parse: - dependency: transitive - description: - name: pubspec_parse - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - shelf: - dependency: transitive - description: - name: shelf - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - shelf_web_socket: - dependency: transitive - description: - name: shelf_web_socket - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.99" - source_gen: - dependency: transitive - description: - name: source_gen - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.1" - source_span: - dependency: transitive - description: - name: source_span - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.1" - stack_trace: - dependency: transitive - description: - name: stack_trace - url: "https://pub.dartlang.org" - source: hosted - version: "1.10.0" - stream_channel: - dependency: transitive - description: - name: stream_channel - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - stream_transform: - dependency: transitive - description: - name: stream_transform - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - string_scanner: - dependency: transitive - description: - name: string_scanner - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - term_glyph: - dependency: transitive - description: - name: term_glyph - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - test_api: - dependency: transitive - description: - name: test_api - url: "https://pub.dartlang.org" - source: hosted - version: "0.4.3" - timing: - dependency: transitive - description: - name: timing - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - typed_data: - dependency: transitive - description: - name: typed_data - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.0" - vector_math: - dependency: transitive - description: - name: vector_math - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.1" - watcher: - dependency: transitive - description: - name: watcher - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" - web_socket_channel: - dependency: transitive - description: - name: web_socket_channel - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - yaml: - dependency: transitive - description: - name: yaml - url: "https://pub.dartlang.org" - source: hosted - version: "3.1.0" -sdks: - dart: ">=2.14.0 <3.0.0" - flutter: ">=1.17.0" diff --git a/pubspec.yaml b/pubspec.yaml index 9bc4444..542b97a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,12 +11,12 @@ environment: dependencies: flutter: sdk: flutter - freezed_annotation: ">=1.0.0 <2.0.0" + freezed_annotation: ^2.0.0 dev_dependencies: - build_runner: ^2.1.7 - freezed: ^1.1.1 - flutter_lints: ^1.0.0 + build_runner: ^2.1.10 + freezed: ^2.0.0 + flutter_lints: ^1.0.4 flutter_test: sdk: flutter From 007421848e2810d834dd3c9aa9fd1b21cafff075 Mon Sep 17 00:00:00 2001 From: Nolence Date: Tue, 24 May 2022 20:42:24 -0600 Subject: [PATCH 080/176] added to gitignore --- .gitignore | 2 ++ example/.gitignore | 2 ++ example/pubspec.lock | 23 ++++++++--------------- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/.gitignore b/.gitignore index a241674..272c677 100644 --- a/.gitignore +++ b/.gitignore @@ -79,3 +79,5 @@ build/ .melos_tool/ /pubspec.lock +**/pubspec.lock +example/pubspec.lock diff --git a/example/.gitignore b/example/.gitignore index 0fa6b67..664a63d 100644 --- a/example/.gitignore +++ b/example/.gitignore @@ -44,3 +44,5 @@ app.*.map.json /android/app/debug /android/app/profile /android/app/release + +/pubspec.lock diff --git a/example/pubspec.lock b/example/pubspec.lock index 6147300..6ea7fa4 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -49,7 +49,7 @@ packages: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.15.0" + version: "1.16.0" cupertino_icons: dependency: "direct main" description: @@ -63,7 +63,7 @@ packages: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.3.0" flutter: dependency: "direct main" description: flutter @@ -101,7 +101,7 @@ packages: name: material_color_utilities url: "https://pub.dartlang.org" source: hosted - version: "0.1.3" + version: "0.1.4" meta: dependency: transitive description: @@ -115,7 +115,7 @@ packages: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.0" + version: "1.8.1" pedantic: dependency: "direct dev" description: @@ -134,7 +134,7 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.1" + version: "1.8.2" stack_trace: dependency: transitive description: @@ -169,21 +169,14 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.8" - typed_data: - dependency: transitive - description: - name: typed_data - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.0" + version: "0.4.9" vector_math: dependency: transitive description: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.1.1" + version: "2.1.2" sdks: - dart: ">=2.14.0 <3.0.0" + dart: ">=2.17.0-0 <3.0.0" flutter: ">=1.17.0" From e891ae7baea6cb5dcd76ffc3d4866eb15aa9ee4c Mon Sep 17 00:00:00 2001 From: Nolence Date: Tue, 24 May 2022 20:59:21 -0600 Subject: [PATCH 081/176] restore lock files although they shouldn't be there --- CHANGELOG.md | 4 ++++ example/pubspec.lock | 37 ++----------------------------------- pubspec.lock | 23 ++++++++--------------- pubspec.yaml | 2 +- 4 files changed, 15 insertions(+), 51 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b5e763..1bf2af1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## [2.3.0] - 2022-05-24 +- Removed freezed dependency and added new callbacks @mergehez +- Upgrade to freezed 2 (excluding user now) @quantosapplications @esenmx + ## [2.2.0+1] - 2022-01-28 Ignore .vscode, update versions and re-export button state. Credit @esenmx diff --git a/example/pubspec.lock b/example/pubspec.lock index b29eaba..158d270 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -14,7 +14,7 @@ packages: path: ".." relative: true source: path - version: "2.2.0+1" + version: "2.3.0" boolean_selector: dependency: transitive description: @@ -56,7 +56,7 @@ packages: name: cupertino_icons url: "https://pub.dartlang.org" source: hosted - version: "1.0.3" + version: "1.0.4" fake_async: dependency: transitive description: @@ -74,18 +74,7 @@ packages: description: flutter source: sdk version: "0.0.0" -<<<<<<< HEAD - freezed_annotation: - dependency: transitive - description: - name: freezed_annotation - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - json_annotation: -======= matcher: ->>>>>>> c5ca263f91a1078cabc1aa19e630edf1cfbb5bc2 dependency: transitive description: name: matcher @@ -98,18 +87,7 @@ packages: name: material_color_utilities url: "https://pub.dartlang.org" source: hosted -<<<<<<< HEAD - version: "0.12.11" - material_color_utilities: - dependency: transitive - description: - name: material_color_utilities - url: "https://pub.dartlang.org" - source: hosted version: "0.1.4" -======= - version: "0.1.3" ->>>>>>> c5ca263f91a1078cabc1aa19e630edf1cfbb5bc2 meta: dependency: transitive description: @@ -177,18 +155,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted -<<<<<<< HEAD version: "0.4.9" -======= - version: "0.4.8" - typed_data: - dependency: transitive - description: - name: typed_data - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.0" ->>>>>>> c5ca263f91a1078cabc1aa19e630edf1cfbb5bc2 vector_math: dependency: transitive description: diff --git a/pubspec.lock b/pubspec.lock index 2485cb8..bf6fc0e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -42,14 +42,14 @@ packages: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.15.0" + version: "1.16.0" fake_async: dependency: transitive description: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.3.0" flutter: dependency: "direct main" description: flutter @@ -87,7 +87,7 @@ packages: name: material_color_utilities url: "https://pub.dartlang.org" source: hosted - version: "0.1.3" + version: "0.1.4" meta: dependency: transitive description: @@ -101,7 +101,7 @@ packages: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.0" + version: "1.8.1" sky_engine: dependency: transitive description: flutter @@ -113,7 +113,7 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.1" + version: "1.8.2" stack_trace: dependency: transitive description: @@ -148,21 +148,14 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.8" - typed_data: - dependency: transitive - description: - name: typed_data - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.0" + version: "0.4.9" vector_math: dependency: transitive description: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.1.1" + version: "2.1.2" sdks: - dart: ">=2.14.0 <3.0.0" + dart: ">=2.17.0-0 <3.0.0" flutter: ">=1.17.0" diff --git a/pubspec.yaml b/pubspec.yaml index 60c173b..b346659 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: async_button_builder description: A builder to wrap around buttons that handles loading, disabled, error and succes states -version: 2.2.0+1 +version: 2.3.0 homepage: https://github.com/Nolence/async_button/tree/main/packages/async_button_builder environment: From 2922994484a9080819e83e07e7bb35c6c71bbb55 Mon Sep 17 00:00:00 2001 From: Nolence Date: Tue, 24 May 2022 21:13:04 -0600 Subject: [PATCH 082/176] added meta and moved to flutter lints 2.0 --- example/analysis_options.yaml | 2 +- example/lib/main.dart | 62 ++++++++++++++------------ example/pubspec.lock | 23 ++++++---- example/pubspec.yaml | 6 +-- lib/src/async_button_builder.dart | 9 ++-- lib/src/button_state/button_state.dart | 2 + pubspec.lock | 8 ++-- pubspec.yaml | 3 +- 8 files changed, 65 insertions(+), 50 deletions(-) diff --git a/example/analysis_options.yaml b/example/analysis_options.yaml index 108d105..f9b3034 100644 --- a/example/analysis_options.yaml +++ b/example/analysis_options.yaml @@ -1 +1 @@ -include: package:pedantic/analysis_options.yaml +include: package:flutter_lints/flutter.yaml diff --git a/example/lib/main.dart b/example/lib/main.dart index 7e35c40..da78b22 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,35 +1,39 @@ import 'package:async_button_builder/async_button_builder.dart'; import 'package:flutter/material.dart'; -void main() => runApp(MyApp()); +void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { + const MyApp({Key? key}) : super(key: key); + @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData.dark(), - home: MyHomePage(), + home: const MyHomePage(), ); } } class MyHomePage extends StatelessWidget { + const MyHomePage({Key? key}) : super(key: key); + @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: Text('Async Buttons')), + appBar: AppBar(title: const Text('Async Buttons')), body: SizedBox.expand( child: Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ - Divider(), - Text('Text Button:'), + const Divider(), + const Text('Text Button:'), AsyncButtonBuilder( - child: Text('Click Me'), + child: const Text('Click Me'), onPressed: () async { - await Future.delayed(Duration(seconds: 1)); + await Future.delayed(const Duration(seconds: 1)); }, builder: (context, child, callback, _) { return TextButton( @@ -38,12 +42,12 @@ class MyHomePage extends StatelessWidget { ); }, ), - Divider(), - Text('Elevated Button:'), + const Divider(), + const Text('Elevated Button:'), AsyncButtonBuilder( - child: Text('Click Me'), + child: const Text('Click Me'), onPressed: () async { - await Future.delayed(Duration(seconds: 1)); + await Future.delayed(const Duration(seconds: 1)); }, builder: (context, child, callback, _) { return ElevatedButton( @@ -52,12 +56,12 @@ class MyHomePage extends StatelessWidget { ); }, ), - Divider(), - Text('Custom Outlined Button (Error):'), + const Divider(), + const Text('Custom Outlined Button (Error):'), AsyncButtonBuilder( - loadingWidget: Text('Loading...'), + loadingWidget: const Text('Loading...'), onPressed: () async { - await Future.delayed(Duration(seconds: 1)); + await Future.delayed(const Duration(seconds: 1)); throw 'yikes'; @@ -94,14 +98,14 @@ class MyHomePage extends StatelessWidget { child: child, ); }, - child: Text('Click Me'), + child: const Text('Click Me'), ), - Divider(), - Text('Custom Material Button:'), + const Divider(), + const Text('Custom Material Button:'), const SizedBox(height: 6.0), AsyncButtonBuilder( - loadingWidget: Padding( - padding: const EdgeInsets.all(8.0), + loadingWidget: const Padding( + padding: EdgeInsets.all(8.0), child: SizedBox( height: 16.0, width: 16.0, @@ -110,22 +114,22 @@ class MyHomePage extends StatelessWidget { ), ), ), - successWidget: Padding( - padding: const EdgeInsets.all(4.0), + successWidget: const Padding( + padding: EdgeInsets.all(4.0), child: Icon( Icons.check, color: Colors.purpleAccent, ), ), onPressed: () async { - await Future.delayed(Duration(seconds: 2)); + await Future.delayed(const Duration(seconds: 2)); }, loadingSwitchInCurve: Curves.bounceInOut, loadingTransitionBuilder: (child, animation) { return SlideTransition( position: Tween( - begin: Offset(0, 1.0), - end: Offset(0, 0), + begin: const Offset(0, 1.0), + end: const Offset(0, 0), ).animate(animation), child: child, ); @@ -139,15 +143,15 @@ class MyHomePage extends StatelessWidget { // This prevents the loading indicator showing below the // button clipBehavior: Clip.hardEdge, - shape: StadiumBorder(), + shape: const StadiumBorder(), child: InkWell( onTap: callback, child: child, ), ); }, - child: Padding( - padding: const EdgeInsets.symmetric( + child: const Padding( + padding: EdgeInsets.symmetric( horizontal: 16.0, vertical: 8.0, ), @@ -157,7 +161,7 @@ class MyHomePage extends StatelessWidget { ), ), ), - Divider(), + const Divider(), ], ), ), diff --git a/example/pubspec.lock b/example/pubspec.lock index 158d270..bfb5dfa 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -69,11 +69,25 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" flutter_test: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" + lints: + dependency: transitive + description: + name: lints + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" matcher: dependency: transitive description: @@ -102,13 +116,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.8.1" - pedantic: - dependency: "direct dev" - description: - name: pedantic - url: "https://pub.dartlang.org" - source: hosted - version: "1.11.1" sky_engine: dependency: transitive description: flutter @@ -164,5 +171,5 @@ packages: source: hosted version: "2.1.2" sdks: - dart: ">=2.17.0-0 <3.0.0" + dart: ">=2.17.0-206.0.dev <3.0.0" flutter: ">=1.17.0" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 3e438cf..ace410c 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,10 +1,10 @@ name: example description: A new Flutter project. -publish_to: 'none' # Remove this line if you wish to publish to pub.dev +publish_to: "none" # Remove this line if you wish to publish to pub.dev version: 1.0.0+1 environment: - sdk: ">=2.7.0 <3.0.0" + sdk: ">=2.12.0 <3.0.0" dependencies: flutter: @@ -17,7 +17,7 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - pedantic: ^1.10.0-nullsafety.3 + flutter_lints: ^2.0.0 flutter: uses-material-design: true diff --git a/lib/src/async_button_builder.dart b/lib/src/async_button_builder.dart index 6fc1460..8a4bb4d 100644 --- a/lib/src/async_button_builder.dart +++ b/lib/src/async_button_builder.dart @@ -240,6 +240,7 @@ class AsyncButtonBuilder extends StatefulWidget { }) : super(key: key); @override + // ignore: library_private_types_in_public_api _AsyncButtonBuilderState createState() => _AsyncButtonBuilderState(); } @@ -341,19 +342,19 @@ class _AsyncButtonBuilderState extends State ), child: buttonState.when( idle: () => KeyedSubtree( - key: ValueKey('__idle__' + parentKeyValue), + key: ValueKey('__idle__$parentKeyValue'), child: widget.child, ), loading: () => KeyedSubtree( - key: ValueKey('__loading__' + parentKeyValue), + key: ValueKey('__loading__$parentKeyValue'), child: loadingWidget, ), success: () => KeyedSubtree( - key: ValueKey('__success__' + parentKeyValue), + key: ValueKey('__success__$parentKeyValue'), child: successWidget, ), error: () => KeyedSubtree( - key: ValueKey('__error__' + parentKeyValue), + key: ValueKey('__error__$parentKeyValue'), child: errorWidget, ), ), diff --git a/lib/src/button_state/button_state.dart b/lib/src/button_state/button_state.dart index bfd4ffa..deceeaf 100644 --- a/lib/src/button_state/button_state.dart +++ b/lib/src/button_state/button_state.dart @@ -1,3 +1,5 @@ +import 'package:meta/meta.dart'; + part 'button_state.freezed.dart'; /// This union class represents the state of the button in either a [Idling], diff --git a/pubspec.lock b/pubspec.lock index bf6fc0e..7e07bbd 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -61,7 +61,7 @@ packages: name: flutter_lints url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "2.0.1" flutter_test: dependency: "direct dev" description: flutter @@ -73,7 +73,7 @@ packages: name: lints url: "https://pub.dartlang.org" source: hosted - version: "1.0.1" + version: "2.0.0" matcher: dependency: transitive description: @@ -89,7 +89,7 @@ packages: source: hosted version: "0.1.4" meta: - dependency: transitive + dependency: "direct main" description: name: meta url: "https://pub.dartlang.org" @@ -157,5 +157,5 @@ packages: source: hosted version: "2.1.2" sdks: - dart: ">=2.17.0-0 <3.0.0" + dart: ">=2.17.0-206.0.dev <3.0.0" flutter: ">=1.17.0" diff --git a/pubspec.yaml b/pubspec.yaml index b346659..2447ad8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,9 +11,10 @@ environment: dependencies: flutter: sdk: flutter + meta: ^1.7.0 dev_dependencies: - flutter_lints: ^1.0.0 + flutter_lints: ^2.0.0 flutter_test: sdk: flutter From 7e8b9ae8366eafe8e5655b76ad85073d694f335e Mon Sep 17 00:00:00 2001 From: Nolence Date: Tue, 24 May 2022 21:17:21 -0600 Subject: [PATCH 083/176] remove unnecessary pubspec files --- example/pubspec.lock | 175 ------------------------------------------- pubspec.lock | 161 --------------------------------------- 2 files changed, 336 deletions(-) delete mode 100644 example/pubspec.lock delete mode 100644 pubspec.lock diff --git a/example/pubspec.lock b/example/pubspec.lock deleted file mode 100644 index bfb5dfa..0000000 --- a/example/pubspec.lock +++ /dev/null @@ -1,175 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - async: - dependency: transitive - description: - name: async - url: "https://pub.dartlang.org" - source: hosted - version: "2.8.2" - async_button_builder: - dependency: "direct main" - description: - path: ".." - relative: true - source: path - version: "2.3.0" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - characters: - dependency: transitive - description: - name: characters - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.1" - clock: - dependency: transitive - description: - name: clock - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - collection: - dependency: transitive - description: - name: collection - url: "https://pub.dartlang.org" - source: hosted - version: "1.16.0" - cupertino_icons: - dependency: "direct main" - description: - name: cupertino_icons - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.4" - fake_async: - dependency: transitive - description: - name: fake_async - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.0" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.1" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - lints: - dependency: transitive - description: - name: lints - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - matcher: - dependency: transitive - description: - name: matcher - url: "https://pub.dartlang.org" - source: hosted - version: "0.12.11" - material_color_utilities: - dependency: transitive - description: - name: material_color_utilities - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.4" - meta: - dependency: transitive - description: - name: meta - url: "https://pub.dartlang.org" - source: hosted - version: "1.7.0" - path: - dependency: transitive - description: - name: path - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.1" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.99" - source_span: - dependency: transitive - description: - name: source_span - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.2" - stack_trace: - dependency: transitive - description: - name: stack_trace - url: "https://pub.dartlang.org" - source: hosted - version: "1.10.0" - stream_channel: - dependency: transitive - description: - name: stream_channel - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - string_scanner: - dependency: transitive - description: - name: string_scanner - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - term_glyph: - dependency: transitive - description: - name: term_glyph - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - test_api: - dependency: transitive - description: - name: test_api - url: "https://pub.dartlang.org" - source: hosted - version: "0.4.9" - vector_math: - dependency: transitive - description: - name: vector_math - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.2" -sdks: - dart: ">=2.17.0-206.0.dev <3.0.0" - flutter: ">=1.17.0" diff --git a/pubspec.lock b/pubspec.lock deleted file mode 100644 index 7e07bbd..0000000 --- a/pubspec.lock +++ /dev/null @@ -1,161 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - async: - dependency: transitive - description: - name: async - url: "https://pub.dartlang.org" - source: hosted - version: "2.8.2" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - characters: - dependency: transitive - description: - name: characters - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.1" - clock: - dependency: transitive - description: - name: clock - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - collection: - dependency: transitive - description: - name: collection - url: "https://pub.dartlang.org" - source: hosted - version: "1.16.0" - fake_async: - dependency: transitive - description: - name: fake_async - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.0" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.1" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - lints: - dependency: transitive - description: - name: lints - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - matcher: - dependency: transitive - description: - name: matcher - url: "https://pub.dartlang.org" - source: hosted - version: "0.12.11" - material_color_utilities: - dependency: transitive - description: - name: material_color_utilities - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.4" - meta: - dependency: "direct main" - description: - name: meta - url: "https://pub.dartlang.org" - source: hosted - version: "1.7.0" - path: - dependency: transitive - description: - name: path - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.1" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.99" - source_span: - dependency: transitive - description: - name: source_span - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.2" - stack_trace: - dependency: transitive - description: - name: stack_trace - url: "https://pub.dartlang.org" - source: hosted - version: "1.10.0" - stream_channel: - dependency: transitive - description: - name: stream_channel - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - string_scanner: - dependency: transitive - description: - name: string_scanner - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - term_glyph: - dependency: transitive - description: - name: term_glyph - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - test_api: - dependency: transitive - description: - name: test_api - url: "https://pub.dartlang.org" - source: hosted - version: "0.4.9" - vector_math: - dependency: transitive - description: - name: vector_math - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.2" -sdks: - dart: ">=2.17.0-206.0.dev <3.0.0" - flutter: ">=1.17.0" From 6dd45a79c23a1ec2c55276a8d4383cc96f5a0984 Mon Sep 17 00:00:00 2001 From: Nolence Date: Tue, 24 May 2022 21:17:50 -0600 Subject: [PATCH 084/176] added pubspec lock to gitignore --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 272c677..7161313 100644 --- a/.gitignore +++ b/.gitignore @@ -78,6 +78,6 @@ build/ .melos_tool/ -/pubspec.lock +pubspec.lock **/pubspec.lock example/pubspec.lock From 127a889f7ce4cd827f651c4c9f3dde1e0b0dcaa1 Mon Sep 17 00:00:00 2001 From: Jonjo McKay Date: Tue, 14 Jun 2022 20:55:16 +0100 Subject: [PATCH 085/176] Fixed onError never being called when an error occurs --- lib/src/async_button_builder.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/async_button_builder.dart b/lib/src/async_button_builder.dart index 8a4bb4d..027c9a7 100644 --- a/lib/src/async_button_builder.dart +++ b/lib/src/async_button_builder.dart @@ -415,7 +415,7 @@ class _AsyncButtonBuilderState extends State buttonState = const ButtonState.error(); }); - setTimer(widget.errorDuration, widget.onSuccess); + setTimer(widget.errorDuration, widget.onError); } else { setState(() { buttonState = const ButtonState.idle(); From e73d35171e9eaf519e04ef79a84e5d760449d1f2 Mon Sep 17 00:00:00 2001 From: rexma Date: Tue, 14 Jun 2022 14:13:22 -0600 Subject: [PATCH 086/176] bump version --- CHANGELOG.md | 3 +++ pubspec.yaml | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1bf2af1..08e8628 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## [2.3.0+1] - 2022-05-24 +- Fixed onError never being called when an error occurs - Credit @jonjomckay + ## [2.3.0] - 2022-05-24 - Removed freezed dependency and added new callbacks @mergehez - Upgrade to freezed 2 (excluding user now) @quantosapplications @esenmx diff --git a/pubspec.yaml b/pubspec.yaml index 2447ad8..2f67986 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: async_button_builder description: A builder to wrap around buttons that handles loading, disabled, error and succes states -version: 2.3.0 +version: 2.3.0+1 homepage: https://github.com/Nolence/async_button/tree/main/packages/async_button_builder environment: From e7d714d14996facfd032fabc5282413da7d22e99 Mon Sep 17 00:00:00 2001 From: rexma Date: Tue, 14 Jun 2022 14:17:13 -0600 Subject: [PATCH 087/176] added beta to test ci --- .github/workflows/dart.yaml | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/.github/workflows/dart.yaml b/.github/workflows/dart.yaml index b104a73..18b6755 100644 --- a/.github/workflows/dart.yaml +++ b/.github/workflows/dart.yaml @@ -9,14 +9,24 @@ on: jobs: flutter: - timeout-minutes: 15 runs-on: ubuntu-latest + + strategy: + matrix: + channel: + - beta + - stable + steps: - name: "Git Checkout" - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: "Install Flutter" - uses: subosito/flutter-action@v1 + uses: subosito/flutter-action@v2 + with: + channel: ${{ matrix.channel }} + + - run: flutter --version - name: Install dependencies run: flutter pub get From a66cdb371c7fff519531166c77a84ea4f7aa207c Mon Sep 17 00:00:00 2001 From: rexma Date: Thu, 16 Jun 2022 14:41:32 -0600 Subject: [PATCH 088/176] testing an idea with run jobs --- .github/workflows/dart.yaml | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/.github/workflows/dart.yaml b/.github/workflows/dart.yaml index 18b6755..f0589a3 100644 --- a/.github/workflows/dart.yaml +++ b/.github/workflows/dart.yaml @@ -8,29 +8,24 @@ on: - cron: "0 10 * * *" jobs: - flutter: + setup: + timeout-minutes: 15 runs-on: ubuntu-latest - - strategy: - matrix: - channel: - - beta - - stable - steps: - name: "Git Checkout" - uses: actions/checkout@v3 + uses: actions/checkout@2v - name: "Install Flutter" - uses: subosito/flutter-action@v2 - with: - channel: ${{ matrix.channel }} - - - run: flutter --version + uses: subosito/flutter-action@v1 - name: Install dependencies run: flutter pub get + test: + timeout-minutes: 15 + needs: setup + runs-on: ubuntu-latest + steps: - name: Check format run: flutter format --set-exit-if-changed . From 2aaf2c8de7f9327348dd7aee005049d6ce34fbb4 Mon Sep 17 00:00:00 2001 From: rexma Date: Thu, 16 Jun 2022 14:46:32 -0600 Subject: [PATCH 089/176] updated checkout actions --- .github/workflows/dart.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dart.yaml b/.github/workflows/dart.yaml index f0589a3..aad08b9 100644 --- a/.github/workflows/dart.yaml +++ b/.github/workflows/dart.yaml @@ -13,10 +13,10 @@ jobs: runs-on: ubuntu-latest steps: - name: "Git Checkout" - uses: actions/checkout@2v + uses: actions/checkout@v3 - name: "Install Flutter" - uses: subosito/flutter-action@v1 + uses: subosito/flutter-action@v2 - name: Install dependencies run: flutter pub get From cdd2f1ab4a8a663bce90ae37254d31456394ab52 Mon Sep 17 00:00:00 2001 From: rexma Date: Thu, 16 Jun 2022 14:48:48 -0600 Subject: [PATCH 090/176] revert --- .github/workflows/dart.yaml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/dart.yaml b/.github/workflows/dart.yaml index aad08b9..336348f 100644 --- a/.github/workflows/dart.yaml +++ b/.github/workflows/dart.yaml @@ -21,11 +21,6 @@ jobs: - name: Install dependencies run: flutter pub get - test: - timeout-minutes: 15 - needs: setup - runs-on: ubuntu-latest - steps: - name: Check format run: flutter format --set-exit-if-changed . From 2307de5a79c11b30c2ccb267ebe5d63fe0913b0b Mon Sep 17 00:00:00 2001 From: Nollie Date: Mon, 13 Feb 2023 09:52:56 -0700 Subject: [PATCH 091/176] update versions and fix some lints --- example/lib/main.dart | 2 +- example/pubspec.yaml | 2 +- lib/src/async_button_builder.dart | 5 ++--- lib/src/button_state/button_state.dart | 2 -- pubspec.yaml | 5 ++--- test/async_button_builder_test.dart | 2 +- 6 files changed, 7 insertions(+), 11 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index da78b22..ee432e7 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -92,7 +92,7 @@ class MyHomePage extends StatelessWidget { return OutlinedButton( onPressed: callback, style: OutlinedButton.styleFrom( - primary: Colors.black, + foregroundColor: Colors.black, backgroundColor: buttonColor, ), child: child, diff --git a/example/pubspec.yaml b/example/pubspec.yaml index ace410c..50af5dc 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -4,7 +4,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev version: 1.0.0+1 environment: - sdk: ">=2.12.0 <3.0.0" + sdk: ">=2.17.0 <3.0.0" dependencies: flutter: diff --git a/lib/src/async_button_builder.dart b/lib/src/async_button_builder.dart index 027c9a7..6a2c202 100644 --- a/lib/src/async_button_builder.dart +++ b/lib/src/async_button_builder.dart @@ -240,8 +240,7 @@ class AsyncButtonBuilder extends StatefulWidget { }) : super(key: key); @override - // ignore: library_private_types_in_public_api - _AsyncButtonBuilderState createState() => _AsyncButtonBuilderState(); + State createState() => _AsyncButtonBuilderState(); } class _AsyncButtonBuilderState extends State @@ -290,7 +289,7 @@ class _AsyncButtonBuilderState extends State var errorWidget = widget.errorWidget ?? Icon( Icons.error, - color: theme.errorColor, + color: theme.colorScheme.error, ); final successPadding = widget.successPadding; final errorPadding = widget.errorPadding; diff --git a/lib/src/button_state/button_state.dart b/lib/src/button_state/button_state.dart index deceeaf..bfd4ffa 100644 --- a/lib/src/button_state/button_state.dart +++ b/lib/src/button_state/button_state.dart @@ -1,5 +1,3 @@ -import 'package:meta/meta.dart'; - part 'button_state.freezed.dart'; /// This union class represents the state of the button in either a [Idling], diff --git a/pubspec.yaml b/pubspec.yaml index 2f67986..b4450f6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -5,16 +5,15 @@ version: 2.3.0+1 homepage: https://github.com/Nolence/async_button/tree/main/packages/async_button_builder environment: - sdk: ">=2.12.0 <3.0.0" + sdk: ">=2.17.0 <3.0.0" flutter: ">=1.17.0" dependencies: flutter: sdk: flutter - meta: ^1.7.0 dev_dependencies: - flutter_lints: ^2.0.0 + flutter_lints: ^2.0.1 flutter_test: sdk: flutter diff --git a/test/async_button_builder_test.dart b/test/async_button_builder_test.dart index 61a3968..ee59255 100644 --- a/test/async_button_builder_test.dart +++ b/test/async_button_builder_test.dart @@ -73,7 +73,7 @@ void main() { expect( () => button.onPressed!.call(), - throwsA(isInstanceOf()), + throwsA(isA()), ); await tester.pump(const Duration(milliseconds: 200)); From d78d483180eafc77f625ca345b71c96ac8b8bf1c Mon Sep 17 00:00:00 2001 From: Nollie Date: Mon, 13 Feb 2023 10:47:13 -0700 Subject: [PATCH 092/176] notifications :) --- README.md | 47 +++- example/lib/main.dart | 2 +- lib/async_button_builder.dart | 1 + lib/src/async_button_builder.dart | 55 +++- lib/src/async_button_notification.dart | 10 + lib/src/button_state/button_state.dart | 5 +- .../button_state/button_state.freezed.dart | 240 ++++++++++-------- pubspec.yaml | 2 +- test/async_button_builder_test.dart | 51 ++++ 9 files changed, 299 insertions(+), 114 deletions(-) create mode 100644 lib/src/async_button_notification.dart diff --git a/README.md b/README.md index f0c715f..92322d4 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,8 @@ AsyncButtonBuilder( The fourth value in the builder allows you listen to the loading state. This can be used to conditionally style the button. This package depends `freezed` in order to create a sealed union to better handle the possible states. +> NOTE (Breaking change): As of v3.0.0, error now takes the error and stack trace as arguments. + ```dart AsyncButtonBuilder( child: Text('Click Me'), @@ -48,7 +50,7 @@ AsyncButtonBuilder( idle: () => Colors.yellow[200], loading: () => Colors.grey, success: () => Colors.orangeAccent, - error: () => Colors.orange, + error: (err, stack) => Colors.orange, ); return OutlinedButton( @@ -76,6 +78,49 @@ AsyncButtonBuilder( ), ``` +## Notifications + +As of v3.0.0, you can now wrap a higher level parent to handle notifications that come from buttons. Why not use something like `runZonedGuarded`? Notification bubbling handles not only the error but the state of the button. If you'd like, for example, to trigger a circular spinner in the center of the app notifiying the user that something is happening, you can do so by listening to the `AsyncButtonNotification` and then using the `buttonState` to determine what to do. + +It might also be a good idea to separate the errors that come from button presses and those that are not. An error wants to see why a button press silently failed but might not need to know why a background fetch failed. + +```dart +MaterialApp( + home: NotificationListener( + onNotification: (notification) { + notification.buttonState.when( + idle: () => // nothing -> you could use a maybeWhen as well + loading: () => // show circular loading widget? + success: () => // show success snackbar? + error: (_, __) => // show error snackbar? + ); + + // Tells the notification to stop bubbling + return true; + }, + // This async button can be nested arbitrarily deep* + child: AsyncButtonBuilder( + duration: duration, + errorDuration: const Duration(milliseconds: 100), + errorWidget: const Text('error'), + onPressed: () async { + throw ArgumentError(); + }, + builder: (context, child, callback, state) { + return TextButton(onPressed: callback, child: child); + }, + child: const Text('click me'), + ), + ), +) + +// See NotificationListener for more information +``` + +To disable the notifications, you can pass `false` to `notifications`. + +## Customization + `async_button_builder` even works for custom buttons. You can define your own widgets for loading, error, and completion as well as define the transitions between them. This example is a little verbose but shows some of what's possible. diff --git a/example/lib/main.dart b/example/lib/main.dart index ee432e7..79156c9 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -86,7 +86,7 @@ class MyHomePage extends StatelessWidget { idle: () => Colors.yellow[200], loading: () => Colors.grey, success: () => Colors.orangeAccent, - error: () => Colors.orange, + error: (_, __) => Colors.orange, ); return OutlinedButton( diff --git a/lib/async_button_builder.dart b/lib/async_button_builder.dart index 2f7998d..d97b5a7 100644 --- a/lib/async_button_builder.dart +++ b/lib/async_button_builder.dart @@ -1,4 +1,5 @@ library async_button_builder; export 'package:async_button_builder/src/async_button_builder.dart'; +export 'package:async_button_builder/src/async_button_notification.dart'; export 'package:async_button_builder/src/button_state/button_state.dart'; diff --git a/lib/src/async_button_builder.dart b/lib/src/async_button_builder.dart index 6a2c202..ba4e679 100644 --- a/lib/src/async_button_builder.dart +++ b/lib/src/async_button_builder.dart @@ -1,6 +1,6 @@ import 'dart:async'; -import 'package:async_button_builder/src/button_state/button_state.dart'; +import 'package:async_button_builder/async_button_builder.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -201,6 +201,11 @@ class AsyncButtonBuilder extends StatefulWidget { /// Whether to animate the [Size] of the widget implicitly. final bool animateSize; + /// Whether we should bubble up [AsyncButtonNotification]s up the widget tree. + /// This is useful if you want to listen to the state of the button from a + /// parent widget. + final bool notifications; + const AsyncButtonBuilder({ Key? key, required this.child, @@ -237,6 +242,7 @@ class AsyncButtonBuilder extends StatefulWidget { this.sizeClipBehavior = Clip.hardEdge, this.sizeAlignment = Alignment.center, this.animateSize = true, + this.notifications = true, }) : super(key: key); @override @@ -325,19 +331,19 @@ class _AsyncButtonBuilderState extends State idle: () => widget.idleSwitchInCurve, loading: () => widget.loadingSwitchInCurve, success: () => widget.successSwitchInCurve, - error: () => widget.errorSwitchInCurve, + error: (_, __) => widget.errorSwitchInCurve, ), switchOutCurve: buttonState.when( idle: () => widget.idleSwitchOutCurve, loading: () => widget.loadingSwitchOutCurve, success: () => widget.successSwitchOutCurve, - error: () => widget.errorSwitchOutCurve, + error: (_, __) => widget.errorSwitchOutCurve, ), transitionBuilder: buttonState.when( idle: () => widget.idleTransitionBuilder, loading: () => widget.loadingTransitionBuilder, success: () => widget.successTransitionBuilder, - error: () => widget.errorTransitionBuilder, + error: (_, __) => widget.errorTransitionBuilder, ), child: buttonState.when( idle: () => KeyedSubtree( @@ -352,7 +358,7 @@ class _AsyncButtonBuilderState extends State key: ValueKey('__success__$parentKeyValue'), child: successWidget, ), - error: () => KeyedSubtree( + error: (_, __) => KeyedSubtree( key: ValueKey('__error__$parentKeyValue'), child: errorWidget, ), @@ -381,12 +387,19 @@ class _AsyncButtonBuilderState extends State : buttonState.maybeWhen( idle: () => () { final completer = Completer(); + // I might not want to set buttonState if we're being // driven by widget.buttonState... setState(() { buttonState = const ButtonState.loading(); }); + if (widget.notifications) { + const AsyncButtonNotification( + buttonState: ButtonState.loading(), + ).dispatch(context); + } + timer?.cancel(); onPressed.call().then((_) { @@ -398,11 +411,23 @@ class _AsyncButtonBuilderState extends State buttonState = const ButtonState.success(); }); + if (widget.notifications) { + const AsyncButtonNotification( + buttonState: ButtonState.success(), + ).dispatch(context); + } + setTimer(widget.successDuration, widget.onSuccess); } else { setState(() { buttonState = const ButtonState.idle(); }); + + if (widget.notifications) { + const AsyncButtonNotification( + buttonState: ButtonState.idle(), + ).dispatch(context); + } } } }).catchError((Object error, StackTrace stackTrace) { @@ -411,14 +436,26 @@ class _AsyncButtonBuilderState extends State if (mounted) { if (widget.showError) { setState(() { - buttonState = const ButtonState.error(); + buttonState = ButtonState.error(error, stackTrace); }); + if (widget.notifications) { + AsyncButtonNotification( + buttonState: ButtonState.error(error, stackTrace), + ).dispatch(context); + } + setTimer(widget.errorDuration, widget.onError); } else { setState(() { buttonState = const ButtonState.idle(); }); + + if (widget.notifications) { + const AsyncButtonNotification( + buttonState: ButtonState.idle(), + ).dispatch(context); + } } } }); @@ -443,6 +480,12 @@ class _AsyncButtonBuilderState extends State setState(() { buttonState = const ButtonState.idle(); }); + + if (widget.notifications) { + const AsyncButtonNotification( + buttonState: ButtonState.idle(), + ).dispatch(context); + } } }, ); diff --git a/lib/src/async_button_notification.dart b/lib/src/async_button_notification.dart new file mode 100644 index 0000000..f99cce4 --- /dev/null +++ b/lib/src/async_button_notification.dart @@ -0,0 +1,10 @@ +import 'package:async_button_builder/async_button_builder.dart'; +import 'package:flutter/material.dart'; + +class AsyncButtonNotification extends Notification { + const AsyncButtonNotification({ + required this.buttonState, + }); + + final ButtonState buttonState; +} diff --git a/lib/src/button_state/button_state.dart b/lib/src/button_state/button_state.dart index bfd4ffa..46ae9e2 100644 --- a/lib/src/button_state/button_state.dart +++ b/lib/src/button_state/button_state.dart @@ -1,3 +1,5 @@ +// import 'package:freezed_annotation/freezed_annotation.dart'; + part 'button_state.freezed.dart'; /// This union class represents the state of the button in either a [Idling], @@ -33,5 +35,6 @@ class ButtonState with _$ButtonState { const factory ButtonState.idle() = Idle; const factory ButtonState.loading() = Loading; const factory ButtonState.success() = Success; - const factory ButtonState.error() = Error; + const factory ButtonState.error(Object error, [StackTrace? stackTrace]) = + Error; } diff --git a/lib/src/button_state/button_state.freezed.dart b/lib/src/button_state/button_state.freezed.dart index 9379850..daffece 100644 --- a/lib/src/button_state/button_state.freezed.dart +++ b/lib/src/button_state/button_state.freezed.dart @@ -1,7 +1,7 @@ // coverage:ignore-file // GENERATED CODE - DO NOT MODIFY BY HAND // ignore_for_file: type=lint -// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark part of 'button_state.dart'; @@ -21,15 +21,15 @@ mixin _$ButtonState { required TResult Function() idle, required TResult Function() loading, required TResult Function() success, - required TResult Function() error, + required TResult Function(Object error, StackTrace? stackTrace) error, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult? whenOrNull({ - TResult Function()? idle, - TResult Function()? loading, - TResult Function()? success, - TResult Function()? error, + TResult? Function()? idle, + TResult? Function()? loading, + TResult? Function()? success, + TResult? Function(Object error, StackTrace? stackTrace)? error, }) => throw _privateConstructorUsedError; @optionalTypeArgs @@ -37,7 +37,7 @@ mixin _$ButtonState { TResult Function()? idle, TResult Function()? loading, TResult Function()? success, - TResult Function()? error, + TResult Function(Object error, StackTrace? stackTrace)? error, required TResult orElse(), }) => throw _privateConstructorUsedError; @@ -51,10 +51,10 @@ mixin _$ButtonState { throw _privateConstructorUsedError; @optionalTypeArgs TResult? mapOrNull({ - TResult Function(Idle value)? idle, - TResult Function(Loading value)? loading, - TResult Function(Success value)? success, - TResult Function(Error value)? error, + TResult? Function(Idle value)? idle, + TResult? Function(Loading value)? loading, + TResult? Function(Success value)? success, + TResult? Function(Error value)? error, }) => throw _privateConstructorUsedError; @optionalTypeArgs @@ -72,32 +72,31 @@ mixin _$ButtonState { abstract class $ButtonStateCopyWith<$Res> { factory $ButtonStateCopyWith( ButtonState value, $Res Function(ButtonState) then) = - _$ButtonStateCopyWithImpl<$Res>; + _$ButtonStateCopyWithImpl<$Res, ButtonState>; } /// @nodoc -class _$ButtonStateCopyWithImpl<$Res> implements $ButtonStateCopyWith<$Res> { +class _$ButtonStateCopyWithImpl<$Res, $Val extends ButtonState> + implements $ButtonStateCopyWith<$Res> { _$ButtonStateCopyWithImpl(this._value, this._then); - final ButtonState _value; // ignore: unused_field - final $Res Function(ButtonState) _then; + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; } /// @nodoc -abstract class $IdleCopyWith<$Res> { - factory $IdleCopyWith(Idle value, $Res Function(Idle) then) = - _$IdleCopyWithImpl<$Res>; +abstract class _$$IdleCopyWith<$Res> { + factory _$$IdleCopyWith(_$Idle value, $Res Function(_$Idle) then) = + __$$IdleCopyWithImpl<$Res>; } /// @nodoc -class _$IdleCopyWithImpl<$Res> extends _$ButtonStateCopyWithImpl<$Res> - implements $IdleCopyWith<$Res> { - _$IdleCopyWithImpl(Idle _value, $Res Function(Idle) _then) - : super(_value, (v) => _then(v as Idle)); - - @override - Idle get _value => super._value as Idle; +class __$$IdleCopyWithImpl<$Res> extends _$ButtonStateCopyWithImpl<$Res, _$Idle> + implements _$$IdleCopyWith<$Res> { + __$$IdleCopyWithImpl(_$Idle _value, $Res Function(_$Idle) _then) + : super(_value, _then); } /// @nodoc @@ -113,7 +112,7 @@ class _$Idle implements Idle { @override bool operator ==(dynamic other) { return identical(this, other) || - (other.runtimeType == runtimeType && other is Idle); + (other.runtimeType == runtimeType && other is _$Idle); } @override @@ -125,7 +124,7 @@ class _$Idle implements Idle { required TResult Function() idle, required TResult Function() loading, required TResult Function() success, - required TResult Function() error, + required TResult Function(Object error, StackTrace? stackTrace) error, }) { return idle(); } @@ -133,10 +132,10 @@ class _$Idle implements Idle { @override @optionalTypeArgs TResult? whenOrNull({ - TResult Function()? idle, - TResult Function()? loading, - TResult Function()? success, - TResult Function()? error, + TResult? Function()? idle, + TResult? Function()? loading, + TResult? Function()? success, + TResult? Function(Object error, StackTrace? stackTrace)? error, }) { return idle?.call(); } @@ -147,7 +146,7 @@ class _$Idle implements Idle { TResult Function()? idle, TResult Function()? loading, TResult Function()? success, - TResult Function()? error, + TResult Function(Object error, StackTrace? stackTrace)? error, required TResult orElse(), }) { if (idle != null) { @@ -170,10 +169,10 @@ class _$Idle implements Idle { @override @optionalTypeArgs TResult? mapOrNull({ - TResult Function(Idle value)? idle, - TResult Function(Loading value)? loading, - TResult Function(Success value)? success, - TResult Function(Error value)? error, + TResult? Function(Idle value)? idle, + TResult? Function(Loading value)? loading, + TResult? Function(Success value)? success, + TResult? Function(Error value)? error, }) { return idle?.call(this); } @@ -199,19 +198,17 @@ abstract class Idle implements ButtonState { } /// @nodoc -abstract class $LoadingCopyWith<$Res> { - factory $LoadingCopyWith(Loading value, $Res Function(Loading) then) = - _$LoadingCopyWithImpl<$Res>; +abstract class _$$LoadingCopyWith<$Res> { + factory _$$LoadingCopyWith(_$Loading value, $Res Function(_$Loading) then) = + __$$LoadingCopyWithImpl<$Res>; } /// @nodoc -class _$LoadingCopyWithImpl<$Res> extends _$ButtonStateCopyWithImpl<$Res> - implements $LoadingCopyWith<$Res> { - _$LoadingCopyWithImpl(Loading _value, $Res Function(Loading) _then) - : super(_value, (v) => _then(v as Loading)); - - @override - Loading get _value => super._value as Loading; +class __$$LoadingCopyWithImpl<$Res> + extends _$ButtonStateCopyWithImpl<$Res, _$Loading> + implements _$$LoadingCopyWith<$Res> { + __$$LoadingCopyWithImpl(_$Loading _value, $Res Function(_$Loading) _then) + : super(_value, _then); } /// @nodoc @@ -227,7 +224,7 @@ class _$Loading implements Loading { @override bool operator ==(dynamic other) { return identical(this, other) || - (other.runtimeType == runtimeType && other is Loading); + (other.runtimeType == runtimeType && other is _$Loading); } @override @@ -239,7 +236,7 @@ class _$Loading implements Loading { required TResult Function() idle, required TResult Function() loading, required TResult Function() success, - required TResult Function() error, + required TResult Function(Object error, StackTrace? stackTrace) error, }) { return loading(); } @@ -247,10 +244,10 @@ class _$Loading implements Loading { @override @optionalTypeArgs TResult? whenOrNull({ - TResult Function()? idle, - TResult Function()? loading, - TResult Function()? success, - TResult Function()? error, + TResult? Function()? idle, + TResult? Function()? loading, + TResult? Function()? success, + TResult? Function(Object error, StackTrace? stackTrace)? error, }) { return loading?.call(); } @@ -261,7 +258,7 @@ class _$Loading implements Loading { TResult Function()? idle, TResult Function()? loading, TResult Function()? success, - TResult Function()? error, + TResult Function(Object error, StackTrace? stackTrace)? error, required TResult orElse(), }) { if (loading != null) { @@ -284,10 +281,10 @@ class _$Loading implements Loading { @override @optionalTypeArgs TResult? mapOrNull({ - TResult Function(Idle value)? idle, - TResult Function(Loading value)? loading, - TResult Function(Success value)? success, - TResult Function(Error value)? error, + TResult? Function(Idle value)? idle, + TResult? Function(Loading value)? loading, + TResult? Function(Success value)? success, + TResult? Function(Error value)? error, }) { return loading?.call(this); } @@ -313,19 +310,17 @@ abstract class Loading implements ButtonState { } /// @nodoc -abstract class $SuccessCopyWith<$Res> { - factory $SuccessCopyWith(Success value, $Res Function(Success) then) = - _$SuccessCopyWithImpl<$Res>; +abstract class _$$SuccessCopyWith<$Res> { + factory _$$SuccessCopyWith(_$Success value, $Res Function(_$Success) then) = + __$$SuccessCopyWithImpl<$Res>; } /// @nodoc -class _$SuccessCopyWithImpl<$Res> extends _$ButtonStateCopyWithImpl<$Res> - implements $SuccessCopyWith<$Res> { - _$SuccessCopyWithImpl(Success _value, $Res Function(Success) _then) - : super(_value, (v) => _then(v as Success)); - - @override - Success get _value => super._value as Success; +class __$$SuccessCopyWithImpl<$Res> + extends _$ButtonStateCopyWithImpl<$Res, _$Success> + implements _$$SuccessCopyWith<$Res> { + __$$SuccessCopyWithImpl(_$Success _value, $Res Function(_$Success) _then) + : super(_value, _then); } /// @nodoc @@ -341,7 +336,7 @@ class _$Success implements Success { @override bool operator ==(dynamic other) { return identical(this, other) || - (other.runtimeType == runtimeType && other is Success); + (other.runtimeType == runtimeType && other is _$Success); } @override @@ -353,7 +348,7 @@ class _$Success implements Success { required TResult Function() idle, required TResult Function() loading, required TResult Function() success, - required TResult Function() error, + required TResult Function(Object error, StackTrace? stackTrace) error, }) { return success(); } @@ -361,10 +356,10 @@ class _$Success implements Success { @override @optionalTypeArgs TResult? whenOrNull({ - TResult Function()? idle, - TResult Function()? loading, - TResult Function()? success, - TResult Function()? error, + TResult? Function()? idle, + TResult? Function()? loading, + TResult? Function()? success, + TResult? Function(Object error, StackTrace? stackTrace)? error, }) { return success?.call(); } @@ -375,7 +370,7 @@ class _$Success implements Success { TResult Function()? idle, TResult Function()? loading, TResult Function()? success, - TResult Function()? error, + TResult Function(Object error, StackTrace? stackTrace)? error, required TResult orElse(), }) { if (success != null) { @@ -398,10 +393,10 @@ class _$Success implements Success { @override @optionalTypeArgs TResult? mapOrNull({ - TResult Function(Idle value)? idle, - TResult Function(Loading value)? loading, - TResult Function(Success value)? success, - TResult Function(Error value)? error, + TResult? Function(Idle value)? idle, + TResult? Function(Loading value)? loading, + TResult? Function(Success value)? success, + TResult? Function(Error value)? error, }) { return success?.call(this); } @@ -427,39 +422,70 @@ abstract class Success implements ButtonState { } /// @nodoc -abstract class $ErrorCopyWith<$Res> { - factory $ErrorCopyWith(Error value, $Res Function(Error) then) = - _$ErrorCopyWithImpl<$Res>; +abstract class _$$ErrorCopyWith<$Res> { + factory _$$ErrorCopyWith(_$Error value, $Res Function(_$Error) then) = + __$$ErrorCopyWithImpl<$Res>; + @useResult + $Res call({Object error, StackTrace? stackTrace}); } /// @nodoc -class _$ErrorCopyWithImpl<$Res> extends _$ButtonStateCopyWithImpl<$Res> - implements $ErrorCopyWith<$Res> { - _$ErrorCopyWithImpl(Error _value, $Res Function(Error) _then) - : super(_value, (v) => _then(v as Error)); +class __$$ErrorCopyWithImpl<$Res> + extends _$ButtonStateCopyWithImpl<$Res, _$Error> + implements _$$ErrorCopyWith<$Res> { + __$$ErrorCopyWithImpl(_$Error _value, $Res Function(_$Error) _then) + : super(_value, _then); + @pragma('vm:prefer-inline') @override - Error get _value => super._value as Error; + $Res call({ + Object? error = null, + Object? stackTrace = freezed, + }) { + return _then(_$Error( + null == error ? _value.error : error, + freezed == stackTrace + ? _value.stackTrace + : stackTrace // ignore: cast_nullable_to_non_nullable + as StackTrace?, + )); + } } /// @nodoc class _$Error implements Error { - const _$Error(); + const _$Error(this.error, [this.stackTrace]); + + @override + final Object error; + @override + final StackTrace? stackTrace; @override String toString() { - return 'ButtonState.error()'; + return 'ButtonState.error(error: $error, stackTrace: $stackTrace)'; } @override bool operator ==(dynamic other) { return identical(this, other) || - (other.runtimeType == runtimeType && other is Error); + (other.runtimeType == runtimeType && + other is _$Error && + const DeepCollectionEquality().equals(other.error, error) && + (identical(other.stackTrace, stackTrace) || + other.stackTrace == stackTrace)); } @override - int get hashCode => runtimeType.hashCode; + int get hashCode => Object.hash( + runtimeType, const DeepCollectionEquality().hash(error), stackTrace); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ErrorCopyWith<_$Error> get copyWith => + __$$ErrorCopyWithImpl<_$Error>(this, _$identity); @override @optionalTypeArgs @@ -467,20 +493,20 @@ class _$Error implements Error { required TResult Function() idle, required TResult Function() loading, required TResult Function() success, - required TResult Function() error, + required TResult Function(Object error, StackTrace? stackTrace) error, }) { - return error(); + return error(this.error, stackTrace); } @override @optionalTypeArgs TResult? whenOrNull({ - TResult Function()? idle, - TResult Function()? loading, - TResult Function()? success, - TResult Function()? error, + TResult? Function()? idle, + TResult? Function()? loading, + TResult? Function()? success, + TResult? Function(Object error, StackTrace? stackTrace)? error, }) { - return error?.call(); + return error?.call(this.error, stackTrace); } @override @@ -489,11 +515,11 @@ class _$Error implements Error { TResult Function()? idle, TResult Function()? loading, TResult Function()? success, - TResult Function()? error, + TResult Function(Object error, StackTrace? stackTrace)? error, required TResult orElse(), }) { if (error != null) { - return error(); + return error(this.error, stackTrace); } return orElse(); } @@ -512,10 +538,10 @@ class _$Error implements Error { @override @optionalTypeArgs TResult? mapOrNull({ - TResult Function(Idle value)? idle, - TResult Function(Loading value)? loading, - TResult Function(Success value)? success, - TResult Function(Error value)? error, + TResult? Function(Idle value)? idle, + TResult? Function(Loading value)? loading, + TResult? Function(Success value)? success, + TResult? Function(Error value)? error, }) { return error?.call(this); } @@ -537,5 +563,11 @@ class _$Error implements Error { } abstract class Error implements ButtonState { - const factory Error() = _$Error; + const factory Error(final Object error, [final StackTrace? stackTrace]) = + _$Error; + + Object get error; + StackTrace? get stackTrace; + @JsonKey(ignore: true) + _$$ErrorCopyWith<_$Error> get copyWith => throw _privateConstructorUsedError; } diff --git a/pubspec.yaml b/pubspec.yaml index b4450f6..d9d7642 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: async_button_builder description: A builder to wrap around buttons that handles loading, disabled, error and succes states -version: 2.3.0+1 +version: 3.0.0 homepage: https://github.com/Nolence/async_button/tree/main/packages/async_button_builder environment: diff --git a/test/async_button_builder_test.dart b/test/async_button_builder_test.dart index ee59255..5e8e238 100644 --- a/test/async_button_builder_test.dart +++ b/test/async_button_builder_test.dart @@ -81,6 +81,57 @@ void main() { expect(find.text('error'), findsOneWidget); }); + testWidgets('error notification bubbles up', (WidgetTester tester) async { + const duration = Duration(milliseconds: 250); + var idleCount = 0; + var loadingCount = 0; + var successCount = 0; + var errorCount = 0; + + final textButton = MaterialApp( + home: NotificationListener( + onNotification: (notification) { + notification.buttonState.when( + idle: () => idleCount += 1, + loading: () => loadingCount += 1, + success: () => successCount += 1, + error: (_, __) => errorCount += 1, + ); + + return true; + }, + child: AsyncButtonBuilder( + duration: duration, + errorDuration: const Duration(milliseconds: 100), + errorWidget: const Text('error'), + onPressed: () async { + throw ArgumentError(); + }, + builder: (context, child, callback, state) { + return TextButton(onPressed: callback, child: child); + }, + child: const Text('click me'), + ), + ), + ); + + await tester.pumpWidget(textButton); + final button = + find.byType(TextButton).evaluate().first.widget as TextButton; + + expect( + () => button.onPressed!.call(), + throwsA(isA()), + ); + + await tester.pump(const Duration(milliseconds: 200)); + + expect(errorCount, 1); + expect(idleCount, 1); + expect(loadingCount, 1); + expect(successCount, 0); + }); + testWidgets('Returns to child widget', (WidgetTester tester) async { const duration = Duration(milliseconds: 250); final textButton = MaterialApp( From e4e4f27be81b6ad66f9877bf0e5c00d1fb076f66 Mon Sep 17 00:00:00 2001 From: Nollie Date: Mon, 13 Feb 2023 10:59:07 -0700 Subject: [PATCH 093/176] changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 08e8628..a57b35c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [3.0.0] - 2022-02-13 +- Added notification functionality. The error variant now passes through the error and stacktrace which would be needed for a notification to be useful. This is a breaking change as the error widget now takes an error and stacktrace as arguments. + +## [2.3.0+2] - 2023-02-13 +- Not pushed + ## [2.3.0+1] - 2022-05-24 - Fixed onError never being called when an error occurs - Credit @jonjomckay From 447772036d62634090175a709807124308c7da94 Mon Sep 17 00:00:00 2001 From: Rex Magana Date: Mon, 13 Feb 2023 11:29:31 -0700 Subject: [PATCH 094/176] Fix optional type args (#41) * added back freezed cause it's almost necessary now * changelog * changelog --- CHANGELOG.md | 6 ++++++ analysis_options.yaml | 5 ++--- lib/src/button_state/button_state.dart | 4 ++-- pubspec.yaml | 5 ++++- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a57b35c..dc0af4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,15 @@ +## [3.0.0+1] - 2022-02-13 +- Fix `Undefined name 'optionalTypeArgs'.` Also adds back the hard dep on freezed_annotation. + ## [3.0.0] - 2022-02-13 - Added notification functionality. The error variant now passes through the error and stacktrace which would be needed for a notification to be useful. This is a breaking change as the error widget now takes an error and stacktrace as arguments. ## [2.3.0+2] - 2023-02-13 - Not pushed +## [2.3.0+1] - 2022-05-24 +- Added back freezed_annotation as a hard dep. + ## [2.3.0+1] - 2022-05-24 - Fixed onError never being called when an error occurs - Credit @jonjomckay diff --git a/analysis_options.yaml b/analysis_options.yaml index d93741b..c34e8fd 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -5,8 +5,7 @@ analyzer: implicit-casts: false implicit-dynamic: false exclude: - - "**/*.g.dart" - - "**/*.freezed.dart" + # - "**/*.freezed.dart" linter: rules: @@ -22,4 +21,4 @@ linter: - avoid_classes_with_only_static_members - unnecessary_lambdas - unnecessary_const - - avoid_void_async \ No newline at end of file + - avoid_void_async diff --git a/lib/src/button_state/button_state.dart b/lib/src/button_state/button_state.dart index 46ae9e2..14fb042 100644 --- a/lib/src/button_state/button_state.dart +++ b/lib/src/button_state/button_state.dart @@ -1,4 +1,4 @@ -// import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; part 'button_state.freezed.dart'; @@ -30,7 +30,7 @@ part 'button_state.freezed.dart'; /// ); /// ``` /// {@end-tool} -// @freezed +@freezed class ButtonState with _$ButtonState { const factory ButtonState.idle() = Idle; const factory ButtonState.loading() = Loading; diff --git a/pubspec.yaml b/pubspec.yaml index d9d7642..e506cdb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: async_button_builder description: A builder to wrap around buttons that handles loading, disabled, error and succes states -version: 3.0.0 +version: 3.0.0+1 homepage: https://github.com/Nolence/async_button/tree/main/packages/async_button_builder environment: @@ -11,10 +11,13 @@ environment: dependencies: flutter: sdk: flutter + freezed_annotation: ^2.2.0 dev_dependencies: + build_runner: ^2.3.3 flutter_lints: ^2.0.1 flutter_test: sdk: flutter + freezed: ^2.3.2 flutter: null From 4e71d6f164f68bec733e580a00a1779c3f36142e Mon Sep 17 00:00:00 2001 From: "Esen, Mehmet" Date: Fri, 17 May 2024 16:07:49 +1000 Subject: [PATCH 095/176] refactor: package overhaul --- analysis_options.yaml | 20 +- example/lib/main.dart | 2 +- lib/async_button_builder.dart | 4 +- lib/src/async_button_builder.dart | 339 ++++------ lib/src/async_button_notification.dart | 6 +- lib/src/async_button_state.dart | 39 ++ lib/src/async_button_state.freezed.dart | 582 ++++++++++++++++++ lib/src/button_state/button_state.dart | 40 -- .../button_state/button_state.freezed.dart | 573 ----------------- pubspec.yaml | 5 +- test/async_button_builder_test.dart | 28 +- 11 files changed, 770 insertions(+), 868 deletions(-) create mode 100644 lib/src/async_button_state.dart create mode 100644 lib/src/async_button_state.freezed.dart delete mode 100644 lib/src/button_state/button_state.dart delete mode 100644 lib/src/button_state/button_state.freezed.dart diff --git a/analysis_options.yaml b/analysis_options.yaml index c34e8fd..8e99406 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,24 +1,8 @@ -include: package:flutter_lints/flutter.yaml +include: package:lint/package.yaml analyzer: - strong-mode: - implicit-casts: false - implicit-dynamic: false exclude: - # - "**/*.freezed.dart" + - "**/*.freezed.dart" linter: rules: - # - public_member_api_docs - - sort_child_properties_last - - require_trailing_commas - - parameter_assignments - - only_throw_errors - - always_use_package_imports - - avoid_dynamic_calls - - prefer_void_to_null - - always_declare_return_types - - avoid_classes_with_only_static_members - - unnecessary_lambdas - - unnecessary_const - - avoid_void_async diff --git a/example/lib/main.dart b/example/lib/main.dart index 79156c9..c96f74e 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -86,7 +86,7 @@ class MyHomePage extends StatelessWidget { idle: () => Colors.yellow[200], loading: () => Colors.grey, success: () => Colors.orangeAccent, - error: (_, __) => Colors.orange, + error: (_) => Colors.orange, ); return OutlinedButton( diff --git a/lib/async_button_builder.dart b/lib/async_button_builder.dart index d97b5a7..0ae7c8c 100644 --- a/lib/async_button_builder.dart +++ b/lib/async_button_builder.dart @@ -1,5 +1,3 @@ -library async_button_builder; - export 'package:async_button_builder/src/async_button_builder.dart'; export 'package:async_button_builder/src/async_button_notification.dart'; -export 'package:async_button_builder/src/button_state/button_state.dart'; +export 'package:async_button_builder/src/async_button_state.dart'; diff --git a/lib/src/async_button_builder.dart b/lib/src/async_button_builder.dart index ba4e679..20cfebd 100644 --- a/lib/src/async_button_builder.dart +++ b/lib/src/async_button_builder.dart @@ -8,7 +8,7 @@ typedef AsyncButtonBuilderCallback = Widget Function( BuildContext context, Widget child, AsyncCallback? callback, - ButtonState buttonState, + AsyncButtonState buttonState, ); /// A `builder` that wraps a button providing disabled, loading, success and @@ -51,8 +51,49 @@ typedef AsyncButtonBuilderCallback = Widget Function( /// } /// ``` /// {@end-tool} -/// class AsyncButtonBuilder extends StatefulWidget { + const AsyncButtonBuilder({ + super.key, + required this.child, + required this.onPressed, + required this.builder, + this.onSuccess, + this.onError, + this.loadingWidget = const SizedBox.square( + dimension: 16.0, + child: CircularProgressIndicator(), + ), + this.successWidget, + this.errorWidget, + this.showSuccess = true, + this.showError = true, + this.errorPadding, + this.successPadding, + this.buttonState = const AsyncButtonState.idle(), + this.duration = const Duration(milliseconds: 250), + this.reverseDuration = const Duration(milliseconds: 200), + this.disabled = false, + this.successDuration = const Duration(seconds: 1), + this.errorDuration = const Duration(seconds: 1), + this.loadingTransitionBuilder = AnimatedSwitcher.defaultTransitionBuilder, + this.idleTransitionBuilder = AnimatedSwitcher.defaultTransitionBuilder, + this.successTransitionBuilder = AnimatedSwitcher.defaultTransitionBuilder, + this.errorTransitionBuilder = AnimatedSwitcher.defaultTransitionBuilder, + this.idleSwitchInCurve = Curves.linear, + this.loadingSwitchInCurve = Curves.linear, + this.successSwitchInCurve = Curves.linear, + this.errorSwitchInCurve = Curves.linear, + this.idleSwitchOutCurve = Curves.linear, + this.loadingSwitchOutCurve = Curves.linear, + this.successSwitchOutCurve = Curves.linear, + this.errorSwitchOutCurve = Curves.linear, + this.sizeCurve = Curves.linear, + this.sizeClipBehavior = Clip.hardEdge, + this.sizeAlignment = Alignment.center, + this.animateSize = true, + this.notifications = false, + }); + /// This builder provides the widget's [BuildContext], the variable [child] /// based on button state as well as the [callback] that should be passed to /// the button and the current [ButtonState] @@ -81,16 +122,16 @@ class AsyncButtonBuilder extends StatefulWidget { /// completes. final AsyncCallback? onPressed; - /// A callback that runs [buttonState] changes to [ButtonState.success] + /// A callback that runs [buttonState] changes to [AsyncButtonState.success] final VoidCallback? onSuccess; - /// A callback that runs [buttonState] changes to [ButtonState.error] + /// A callback that runs [buttonState] changes to [AsyncButtonState.error] final VoidCallback? onError; /// This is used to manually drive the state of the loading button thus /// initiating the corresponding animation and showing the correct button /// child. - final ButtonState buttonState; + final AsyncButtonState buttonState; /// This is used to manually drive the disabled state of the button. final bool disabled; @@ -103,7 +144,7 @@ class AsyncButtonBuilder extends StatefulWidget { /// width: 16.0, /// child: CircularProgressIndicator(), /// ) - final Widget? loadingWidget; + final Widget loadingWidget; /// The widget used to replace the [child] when the button is in a success /// state. If this is null the default widget is: @@ -206,66 +247,20 @@ class AsyncButtonBuilder extends StatefulWidget { /// parent widget. final bool notifications; - const AsyncButtonBuilder({ - Key? key, - required this.child, - required this.onPressed, - required this.builder, - this.onSuccess, - this.onError, - this.loadingWidget, - this.successWidget, - this.errorWidget, - this.showSuccess = true, - this.showError = true, - this.errorPadding, - this.successPadding, - this.buttonState = const ButtonState.idle(), - this.duration = const Duration(milliseconds: 250), - this.reverseDuration = const Duration(milliseconds: 250), - this.disabled = false, - this.successDuration = const Duration(seconds: 1), - this.errorDuration = const Duration(seconds: 1), - this.loadingTransitionBuilder = AnimatedSwitcher.defaultTransitionBuilder, - this.idleTransitionBuilder = AnimatedSwitcher.defaultTransitionBuilder, - this.successTransitionBuilder = AnimatedSwitcher.defaultTransitionBuilder, - this.errorTransitionBuilder = AnimatedSwitcher.defaultTransitionBuilder, - this.idleSwitchInCurve = Curves.linear, - this.loadingSwitchInCurve = Curves.linear, - this.successSwitchInCurve = Curves.linear, - this.errorSwitchInCurve = Curves.linear, - this.idleSwitchOutCurve = Curves.linear, - this.loadingSwitchOutCurve = Curves.linear, - this.successSwitchOutCurve = Curves.linear, - this.errorSwitchOutCurve = Curves.linear, - this.sizeCurve = Curves.linear, - this.sizeClipBehavior = Clip.hardEdge, - this.sizeAlignment = Alignment.center, - this.animateSize = true, - this.notifications = true, - }) : super(key: key); - @override - State createState() => _AsyncButtonBuilderState(); + State createState() => AsyncButtonBuilderState(); } -class _AsyncButtonBuilderState extends State +class AsyncButtonBuilderState extends State with SingleTickerProviderStateMixin { - late ButtonState buttonState; + late AsyncButtonState _buttonState = widget.buttonState; + Key _switchKey = UniqueKey(); Timer? timer; - @override - void initState() { - buttonState = widget.buttonState; - super.initState(); - } - @override void didUpdateWidget(covariant AsyncButtonBuilder oldWidget) { if (widget.buttonState != oldWidget.buttonState) { - setState(() { - buttonState = widget.buttonState; - }); + _setButtonState(widget.buttonState); } super.didUpdateWidget(oldWidget); } @@ -279,46 +274,20 @@ class _AsyncButtonBuilderState extends State @override Widget build(BuildContext context) { final theme = Theme.of(context); - final onPressed = widget.onPressed; - final widgetKey = widget.key; - final loadingWidget = widget.loadingWidget ?? - const SizedBox( - height: 16.0, - width: 16.0, - child: CircularProgressIndicator(), - ); var successWidget = widget.successWidget ?? - Icon( - Icons.check, - color: theme.colorScheme.secondary, - ); - var errorWidget = widget.errorWidget ?? - Icon( - Icons.error, - color: theme.colorScheme.error, - ); - final successPadding = widget.successPadding; - final errorPadding = widget.errorPadding; - - // This is necessary in the case of nested async button builders. - // We cannot have the same __idle__, __loading__, etc. keys as they might - // conflict with one another. - String parentKeyValue = ''; - - if (widgetKey != null && widgetKey is ValueKey) { - parentKeyValue = widgetKey.value.toString(); - } - - if (successPadding != null) { + Icon(Icons.check, color: theme.colorScheme.secondary); + var errorWidget = + widget.errorWidget ?? Icon(Icons.error, color: theme.colorScheme.error); + if (widget.successPadding != null) { successWidget = Padding( - padding: successPadding, + padding: widget.successPadding!, child: successWidget, ); } - if (errorPadding != null) { + if (widget.errorPadding != null) { errorWidget = Padding( - padding: errorPadding, + padding: widget.errorPadding!, child: errorWidget, ); } @@ -327,40 +296,31 @@ class _AsyncButtonBuilderState extends State // TODO: This duration is same as size's duration. That's okay right? duration: widget.duration, reverseDuration: widget.reverseDuration, - switchInCurve: buttonState.when( + switchInCurve: _buttonState.when( idle: () => widget.idleSwitchInCurve, loading: () => widget.loadingSwitchInCurve, success: () => widget.successSwitchInCurve, - error: (_, __) => widget.errorSwitchInCurve, + error: (_) => widget.errorSwitchInCurve, ), - switchOutCurve: buttonState.when( + switchOutCurve: _buttonState.when( idle: () => widget.idleSwitchOutCurve, loading: () => widget.loadingSwitchOutCurve, success: () => widget.successSwitchOutCurve, - error: (_, __) => widget.errorSwitchOutCurve, + error: (_) => widget.errorSwitchOutCurve, ), - transitionBuilder: buttonState.when( + transitionBuilder: _buttonState.when( idle: () => widget.idleTransitionBuilder, loading: () => widget.loadingTransitionBuilder, success: () => widget.successTransitionBuilder, - error: (_, __) => widget.errorTransitionBuilder, + error: (_) => widget.errorTransitionBuilder, ), - child: buttonState.when( - idle: () => KeyedSubtree( - key: ValueKey('__idle__$parentKeyValue'), - child: widget.child, - ), - loading: () => KeyedSubtree( - key: ValueKey('__loading__$parentKeyValue'), - child: loadingWidget, - ), - success: () => KeyedSubtree( - key: ValueKey('__success__$parentKeyValue'), - child: successWidget, - ), - error: (_, __) => KeyedSubtree( - key: ValueKey('__error__$parentKeyValue'), - child: errorWidget, + child: KeyedSubtree( + key: _switchKey, + child: _buttonState.when( + idle: () => widget.child, + loading: () => widget.loadingWidget, + success: () => successWidget, + error: (_) => errorWidget, ), ), ); @@ -380,112 +340,73 @@ class _AsyncButtonBuilderState extends State child: switcher, ) : switcher, - widget.disabled - ? null - : onPressed == null - ? null - : buttonState.maybeWhen( - idle: () => () { - final completer = Completer(); - - // I might not want to set buttonState if we're being - // driven by widget.buttonState... - setState(() { - buttonState = const ButtonState.loading(); - }); - - if (widget.notifications) { - const AsyncButtonNotification( - buttonState: ButtonState.loading(), - ).dispatch(context); - } - - timer?.cancel(); - - onPressed.call().then((_) { - completer.complete(); - - if (mounted) { - if (widget.showSuccess) { - setState(() { - buttonState = const ButtonState.success(); - }); - - if (widget.notifications) { - const AsyncButtonNotification( - buttonState: ButtonState.success(), - ).dispatch(context); - } - - setTimer(widget.successDuration, widget.onSuccess); - } else { - setState(() { - buttonState = const ButtonState.idle(); - }); - - if (widget.notifications) { - const AsyncButtonNotification( - buttonState: ButtonState.idle(), - ).dispatch(context); - } - } - } - }).catchError((Object error, StackTrace stackTrace) { - completer.completeError(error, stackTrace); - - if (mounted) { - if (widget.showError) { - setState(() { - buttonState = ButtonState.error(error, stackTrace); - }); - - if (widget.notifications) { - AsyncButtonNotification( - buttonState: ButtonState.error(error, stackTrace), - ).dispatch(context); - } - - setTimer(widget.errorDuration, widget.onError); - } else { - setState(() { - buttonState = const ButtonState.idle(); - }); - - if (widget.notifications) { - const AsyncButtonNotification( - buttonState: ButtonState.idle(), - ).dispatch(context); - } - } - } - }); - - return completer.future; - }, - orElse: () => null, - ), - buttonState, + press(), + _buttonState, ); } - void setTimer(Duration duration, [VoidCallback? then]) { + AsyncCallback? press() { + if (widget.disabled || widget.onPressed == null) { + return null; + } + return _buttonState.maybeWhen( + orElse: () => null, + idle: () => () { + final completer = Completer(); + + // I might not want to set buttonState if we're being + // driven by widget.buttonState... + _setButtonState(const AsyncButtonState.loading()); + timer?.cancel(); + + widget.onPressed!.call().then((_) { + completer.complete(); + + if (mounted) { + if (widget.showSuccess) { + _setButtonState(const AsyncButtonState.success()); + _setTimer(widget.successDuration, widget.onSuccess); + } else { + _setButtonState(const AsyncButtonState.idle()); + } + } + }).onError((Object error, StackTrace stackTrace) { + completer.completeError(error, stackTrace); + + if (mounted) { + if (widget.showError) { + _setButtonState(AsyncButtonState.error(error)); + _setTimer(widget.errorDuration, widget.onError); + } else { + _setButtonState(const AsyncButtonState.idle()); + } + } + }); + + return completer.future; + }, + ); + } + + void _setButtonState(AsyncButtonState buttonState) { + setState(() { + _switchKey = UniqueKey(); + _buttonState = buttonState; + }); + + if (widget.notifications) { + AsyncButtonNotification(buttonState: buttonState).dispatch(context); + } + } + + void _setTimer(Duration duration, [VoidCallback? then]) { timer = Timer( duration, () { timer?.cancel(); - then?.call(); - if (mounted) { - setState(() { - buttonState = const ButtonState.idle(); - }); - - if (widget.notifications) { - const AsyncButtonNotification( - buttonState: ButtonState.idle(), - ).dispatch(context); - } + _setButtonState(const AsyncButtonState.idle()); } }, ); diff --git a/lib/src/async_button_notification.dart b/lib/src/async_button_notification.dart index f99cce4..d418060 100644 --- a/lib/src/async_button_notification.dart +++ b/lib/src/async_button_notification.dart @@ -2,9 +2,7 @@ import 'package:async_button_builder/async_button_builder.dart'; import 'package:flutter/material.dart'; class AsyncButtonNotification extends Notification { - const AsyncButtonNotification({ - required this.buttonState, - }); + const AsyncButtonNotification({required this.buttonState}); - final ButtonState buttonState; + final AsyncButtonState buttonState; } diff --git a/lib/src/async_button_state.dart b/lib/src/async_button_state.dart new file mode 100644 index 0000000..4d3999a --- /dev/null +++ b/lib/src/async_button_state.dart @@ -0,0 +1,39 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'async_button_state.freezed.dart'; + +/// This union class represents the state of the button in either a [Idling], +/// [AsyncButtonStateLoading], [AsyncButtonStateSuccess] or [AsyncButtonStateError] state. +/// This can be considered a enum with extra utilities for ease of use. +/// +/// {@tool snippet} +/// +/// ```dart +/// final buttonColor = AsyncbuttonState.when( +/// idle: () => Colors.pink, +/// loading: () => Colors.blue, +/// success: () => Colors.green, +/// error: () => Colors.red, +/// ); +/// ``` +/// {@end-tool} +/// +/// You can also disregard other states and handle only those you'd like using +/// the `.maybeWhen` syntax. +/// +/// {@tool snippet} +/// +/// ```dart +/// final buttonColor = AsyncbuttonState.maybeWhen( +/// idle: () => Colors.pink, +/// orElse: () => Colors.red, +/// ); +/// ``` +/// {@end-tool} +@freezed +class AsyncButtonState with _$AsyncButtonState { + const factory AsyncButtonState.idle() = AsyncButtonStateIdle; + const factory AsyncButtonState.loading() = AsyncButtonStateLoading; + const factory AsyncButtonState.success() = AsyncButtonStateSuccess; + const factory AsyncButtonState.error(Object error) = AsyncButtonStateError; +} diff --git a/lib/src/async_button_state.freezed.dart b/lib/src/async_button_state.freezed.dart new file mode 100644 index 0000000..ee47379 --- /dev/null +++ b/lib/src/async_button_state.freezed.dart @@ -0,0 +1,582 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'async_button_state.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$AsyncButtonState { + @optionalTypeArgs + TResult when({ + required TResult Function() idle, + required TResult Function() loading, + required TResult Function() success, + required TResult Function(Object error) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? idle, + TResult? Function()? loading, + TResult? Function()? success, + TResult? Function(Object error)? error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? idle, + TResult Function()? loading, + TResult Function()? success, + TResult Function(Object error)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(AsyncButtonStateIdle value) idle, + required TResult Function(AsyncButtonStateLoading value) loading, + required TResult Function(AsyncButtonStateSuccess value) success, + required TResult Function(AsyncButtonStateError value) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(AsyncButtonStateIdle value)? idle, + TResult? Function(AsyncButtonStateLoading value)? loading, + TResult? Function(AsyncButtonStateSuccess value)? success, + TResult? Function(AsyncButtonStateError value)? error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(AsyncButtonStateIdle value)? idle, + TResult Function(AsyncButtonStateLoading value)? loading, + TResult Function(AsyncButtonStateSuccess value)? success, + TResult Function(AsyncButtonStateError value)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $AsyncButtonStateCopyWith<$Res> { + factory $AsyncButtonStateCopyWith( + AsyncButtonState value, $Res Function(AsyncButtonState) then) = + _$AsyncButtonStateCopyWithImpl<$Res, AsyncButtonState>; +} + +/// @nodoc +class _$AsyncButtonStateCopyWithImpl<$Res, $Val extends AsyncButtonState> + implements $AsyncButtonStateCopyWith<$Res> { + _$AsyncButtonStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; +} + +/// @nodoc +abstract class _$$AsyncButtonStateIdleImplCopyWith<$Res> { + factory _$$AsyncButtonStateIdleImplCopyWith(_$AsyncButtonStateIdleImpl value, + $Res Function(_$AsyncButtonStateIdleImpl) then) = + __$$AsyncButtonStateIdleImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$AsyncButtonStateIdleImplCopyWithImpl<$Res> + extends _$AsyncButtonStateCopyWithImpl<$Res, _$AsyncButtonStateIdleImpl> + implements _$$AsyncButtonStateIdleImplCopyWith<$Res> { + __$$AsyncButtonStateIdleImplCopyWithImpl(_$AsyncButtonStateIdleImpl _value, + $Res Function(_$AsyncButtonStateIdleImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$AsyncButtonStateIdleImpl implements AsyncButtonStateIdle { + const _$AsyncButtonStateIdleImpl(); + + @override + String toString() { + return 'AsyncButtonState.idle()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$AsyncButtonStateIdleImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() idle, + required TResult Function() loading, + required TResult Function() success, + required TResult Function(Object error) error, + }) { + return idle(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? idle, + TResult? Function()? loading, + TResult? Function()? success, + TResult? Function(Object error)? error, + }) { + return idle?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? idle, + TResult Function()? loading, + TResult Function()? success, + TResult Function(Object error)? error, + required TResult orElse(), + }) { + if (idle != null) { + return idle(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(AsyncButtonStateIdle value) idle, + required TResult Function(AsyncButtonStateLoading value) loading, + required TResult Function(AsyncButtonStateSuccess value) success, + required TResult Function(AsyncButtonStateError value) error, + }) { + return idle(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(AsyncButtonStateIdle value)? idle, + TResult? Function(AsyncButtonStateLoading value)? loading, + TResult? Function(AsyncButtonStateSuccess value)? success, + TResult? Function(AsyncButtonStateError value)? error, + }) { + return idle?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(AsyncButtonStateIdle value)? idle, + TResult Function(AsyncButtonStateLoading value)? loading, + TResult Function(AsyncButtonStateSuccess value)? success, + TResult Function(AsyncButtonStateError value)? error, + required TResult orElse(), + }) { + if (idle != null) { + return idle(this); + } + return orElse(); + } +} + +abstract class AsyncButtonStateIdle implements AsyncButtonState { + const factory AsyncButtonStateIdle() = _$AsyncButtonStateIdleImpl; +} + +/// @nodoc +abstract class _$$AsyncButtonStateLoadingImplCopyWith<$Res> { + factory _$$AsyncButtonStateLoadingImplCopyWith( + _$AsyncButtonStateLoadingImpl value, + $Res Function(_$AsyncButtonStateLoadingImpl) then) = + __$$AsyncButtonStateLoadingImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$AsyncButtonStateLoadingImplCopyWithImpl<$Res> + extends _$AsyncButtonStateCopyWithImpl<$Res, _$AsyncButtonStateLoadingImpl> + implements _$$AsyncButtonStateLoadingImplCopyWith<$Res> { + __$$AsyncButtonStateLoadingImplCopyWithImpl( + _$AsyncButtonStateLoadingImpl _value, + $Res Function(_$AsyncButtonStateLoadingImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$AsyncButtonStateLoadingImpl implements AsyncButtonStateLoading { + const _$AsyncButtonStateLoadingImpl(); + + @override + String toString() { + return 'AsyncButtonState.loading()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$AsyncButtonStateLoadingImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() idle, + required TResult Function() loading, + required TResult Function() success, + required TResult Function(Object error) error, + }) { + return loading(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? idle, + TResult? Function()? loading, + TResult? Function()? success, + TResult? Function(Object error)? error, + }) { + return loading?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? idle, + TResult Function()? loading, + TResult Function()? success, + TResult Function(Object error)? error, + required TResult orElse(), + }) { + if (loading != null) { + return loading(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(AsyncButtonStateIdle value) idle, + required TResult Function(AsyncButtonStateLoading value) loading, + required TResult Function(AsyncButtonStateSuccess value) success, + required TResult Function(AsyncButtonStateError value) error, + }) { + return loading(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(AsyncButtonStateIdle value)? idle, + TResult? Function(AsyncButtonStateLoading value)? loading, + TResult? Function(AsyncButtonStateSuccess value)? success, + TResult? Function(AsyncButtonStateError value)? error, + }) { + return loading?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(AsyncButtonStateIdle value)? idle, + TResult Function(AsyncButtonStateLoading value)? loading, + TResult Function(AsyncButtonStateSuccess value)? success, + TResult Function(AsyncButtonStateError value)? error, + required TResult orElse(), + }) { + if (loading != null) { + return loading(this); + } + return orElse(); + } +} + +abstract class AsyncButtonStateLoading implements AsyncButtonState { + const factory AsyncButtonStateLoading() = _$AsyncButtonStateLoadingImpl; +} + +/// @nodoc +abstract class _$$AsyncButtonStateSuccessImplCopyWith<$Res> { + factory _$$AsyncButtonStateSuccessImplCopyWith( + _$AsyncButtonStateSuccessImpl value, + $Res Function(_$AsyncButtonStateSuccessImpl) then) = + __$$AsyncButtonStateSuccessImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$AsyncButtonStateSuccessImplCopyWithImpl<$Res> + extends _$AsyncButtonStateCopyWithImpl<$Res, _$AsyncButtonStateSuccessImpl> + implements _$$AsyncButtonStateSuccessImplCopyWith<$Res> { + __$$AsyncButtonStateSuccessImplCopyWithImpl( + _$AsyncButtonStateSuccessImpl _value, + $Res Function(_$AsyncButtonStateSuccessImpl) _then) + : super(_value, _then); +} + +/// @nodoc + +class _$AsyncButtonStateSuccessImpl implements AsyncButtonStateSuccess { + const _$AsyncButtonStateSuccessImpl(); + + @override + String toString() { + return 'AsyncButtonState.success()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$AsyncButtonStateSuccessImpl); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() idle, + required TResult Function() loading, + required TResult Function() success, + required TResult Function(Object error) error, + }) { + return success(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? idle, + TResult? Function()? loading, + TResult? Function()? success, + TResult? Function(Object error)? error, + }) { + return success?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? idle, + TResult Function()? loading, + TResult Function()? success, + TResult Function(Object error)? error, + required TResult orElse(), + }) { + if (success != null) { + return success(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(AsyncButtonStateIdle value) idle, + required TResult Function(AsyncButtonStateLoading value) loading, + required TResult Function(AsyncButtonStateSuccess value) success, + required TResult Function(AsyncButtonStateError value) error, + }) { + return success(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(AsyncButtonStateIdle value)? idle, + TResult? Function(AsyncButtonStateLoading value)? loading, + TResult? Function(AsyncButtonStateSuccess value)? success, + TResult? Function(AsyncButtonStateError value)? error, + }) { + return success?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(AsyncButtonStateIdle value)? idle, + TResult Function(AsyncButtonStateLoading value)? loading, + TResult Function(AsyncButtonStateSuccess value)? success, + TResult Function(AsyncButtonStateError value)? error, + required TResult orElse(), + }) { + if (success != null) { + return success(this); + } + return orElse(); + } +} + +abstract class AsyncButtonStateSuccess implements AsyncButtonState { + const factory AsyncButtonStateSuccess() = _$AsyncButtonStateSuccessImpl; +} + +/// @nodoc +abstract class _$$AsyncButtonStateErrorImplCopyWith<$Res> { + factory _$$AsyncButtonStateErrorImplCopyWith( + _$AsyncButtonStateErrorImpl value, + $Res Function(_$AsyncButtonStateErrorImpl) then) = + __$$AsyncButtonStateErrorImplCopyWithImpl<$Res>; + @useResult + $Res call({Object error}); +} + +/// @nodoc +class __$$AsyncButtonStateErrorImplCopyWithImpl<$Res> + extends _$AsyncButtonStateCopyWithImpl<$Res, _$AsyncButtonStateErrorImpl> + implements _$$AsyncButtonStateErrorImplCopyWith<$Res> { + __$$AsyncButtonStateErrorImplCopyWithImpl(_$AsyncButtonStateErrorImpl _value, + $Res Function(_$AsyncButtonStateErrorImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? error = null, + }) { + return _then(_$AsyncButtonStateErrorImpl( + null == error ? _value.error : error, + )); + } +} + +/// @nodoc + +class _$AsyncButtonStateErrorImpl implements AsyncButtonStateError { + const _$AsyncButtonStateErrorImpl(this.error); + + @override + final Object error; + + @override + String toString() { + return 'AsyncButtonState.error(error: $error)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$AsyncButtonStateErrorImpl && + const DeepCollectionEquality().equals(other.error, error)); + } + + @override + int get hashCode => + Object.hash(runtimeType, const DeepCollectionEquality().hash(error)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$AsyncButtonStateErrorImplCopyWith<_$AsyncButtonStateErrorImpl> + get copyWith => __$$AsyncButtonStateErrorImplCopyWithImpl< + _$AsyncButtonStateErrorImpl>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() idle, + required TResult Function() loading, + required TResult Function() success, + required TResult Function(Object error) error, + }) { + return error(this.error); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? idle, + TResult? Function()? loading, + TResult? Function()? success, + TResult? Function(Object error)? error, + }) { + return error?.call(this.error); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? idle, + TResult Function()? loading, + TResult Function()? success, + TResult Function(Object error)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(this.error); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(AsyncButtonStateIdle value) idle, + required TResult Function(AsyncButtonStateLoading value) loading, + required TResult Function(AsyncButtonStateSuccess value) success, + required TResult Function(AsyncButtonStateError value) error, + }) { + return error(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(AsyncButtonStateIdle value)? idle, + TResult? Function(AsyncButtonStateLoading value)? loading, + TResult? Function(AsyncButtonStateSuccess value)? success, + TResult? Function(AsyncButtonStateError value)? error, + }) { + return error?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(AsyncButtonStateIdle value)? idle, + TResult Function(AsyncButtonStateLoading value)? loading, + TResult Function(AsyncButtonStateSuccess value)? success, + TResult Function(AsyncButtonStateError value)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(this); + } + return orElse(); + } +} + +abstract class AsyncButtonStateError implements AsyncButtonState { + const factory AsyncButtonStateError(final Object error) = + _$AsyncButtonStateErrorImpl; + + Object get error; + @JsonKey(ignore: true) + _$$AsyncButtonStateErrorImplCopyWith<_$AsyncButtonStateErrorImpl> + get copyWith => throw _privateConstructorUsedError; +} diff --git a/lib/src/button_state/button_state.dart b/lib/src/button_state/button_state.dart deleted file mode 100644 index 14fb042..0000000 --- a/lib/src/button_state/button_state.dart +++ /dev/null @@ -1,40 +0,0 @@ -import 'package:freezed_annotation/freezed_annotation.dart'; - -part 'button_state.freezed.dart'; - -/// This union class represents the state of the button in either a [Idling], -/// [Loading], [Success] or [Error] state. This can be considered a enum with extra -/// utilities for ease of use. -/// -/// {@tool snippet} -/// -/// ```dart -/// final buttonColor = buttonState.when( -/// idle: () => Colors.pink, -/// loading: () => Colors.blue, -/// success: () => Colors.green, -/// error: () => Colors.red, -/// ); -/// ``` -/// {@end-tool} -/// -/// You can also disregard other states and handle only those you'd like using -/// the `.maybeWhen` syntax. -/// -/// /// {@tool snippet} -/// -/// ```dart -/// final buttonColor = buttonState.maybeWhen( -/// idle: () => Colors.pink, -/// orElse: () => Colors.red, -/// ); -/// ``` -/// {@end-tool} -@freezed -class ButtonState with _$ButtonState { - const factory ButtonState.idle() = Idle; - const factory ButtonState.loading() = Loading; - const factory ButtonState.success() = Success; - const factory ButtonState.error(Object error, [StackTrace? stackTrace]) = - Error; -} diff --git a/lib/src/button_state/button_state.freezed.dart b/lib/src/button_state/button_state.freezed.dart deleted file mode 100644 index daffece..0000000 --- a/lib/src/button_state/button_state.freezed.dart +++ /dev/null @@ -1,573 +0,0 @@ -// coverage:ignore-file -// GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: type=lint -// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark - -part of 'button_state.dart'; - -// ************************************************************************** -// FreezedGenerator -// ************************************************************************** - -T _$identity(T value) => value; - -final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); - -/// @nodoc -mixin _$ButtonState { - @optionalTypeArgs - TResult when({ - required TResult Function() idle, - required TResult Function() loading, - required TResult Function() success, - required TResult Function(Object error, StackTrace? stackTrace) error, - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult? whenOrNull({ - TResult? Function()? idle, - TResult? Function()? loading, - TResult? Function()? success, - TResult? Function(Object error, StackTrace? stackTrace)? error, - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult maybeWhen({ - TResult Function()? idle, - TResult Function()? loading, - TResult Function()? success, - TResult Function(Object error, StackTrace? stackTrace)? error, - required TResult orElse(), - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult map({ - required TResult Function(Idle value) idle, - required TResult Function(Loading value) loading, - required TResult Function(Success value) success, - required TResult Function(Error value) error, - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult? mapOrNull({ - TResult? Function(Idle value)? idle, - TResult? Function(Loading value)? loading, - TResult? Function(Success value)? success, - TResult? Function(Error value)? error, - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult maybeMap({ - TResult Function(Idle value)? idle, - TResult Function(Loading value)? loading, - TResult Function(Success value)? success, - TResult Function(Error value)? error, - required TResult orElse(), - }) => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $ButtonStateCopyWith<$Res> { - factory $ButtonStateCopyWith( - ButtonState value, $Res Function(ButtonState) then) = - _$ButtonStateCopyWithImpl<$Res, ButtonState>; -} - -/// @nodoc -class _$ButtonStateCopyWithImpl<$Res, $Val extends ButtonState> - implements $ButtonStateCopyWith<$Res> { - _$ButtonStateCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; -} - -/// @nodoc -abstract class _$$IdleCopyWith<$Res> { - factory _$$IdleCopyWith(_$Idle value, $Res Function(_$Idle) then) = - __$$IdleCopyWithImpl<$Res>; -} - -/// @nodoc -class __$$IdleCopyWithImpl<$Res> extends _$ButtonStateCopyWithImpl<$Res, _$Idle> - implements _$$IdleCopyWith<$Res> { - __$$IdleCopyWithImpl(_$Idle _value, $Res Function(_$Idle) _then) - : super(_value, _then); -} - -/// @nodoc - -class _$Idle implements Idle { - const _$Idle(); - - @override - String toString() { - return 'ButtonState.idle()'; - } - - @override - bool operator ==(dynamic other) { - return identical(this, other) || - (other.runtimeType == runtimeType && other is _$Idle); - } - - @override - int get hashCode => runtimeType.hashCode; - - @override - @optionalTypeArgs - TResult when({ - required TResult Function() idle, - required TResult Function() loading, - required TResult Function() success, - required TResult Function(Object error, StackTrace? stackTrace) error, - }) { - return idle(); - } - - @override - @optionalTypeArgs - TResult? whenOrNull({ - TResult? Function()? idle, - TResult? Function()? loading, - TResult? Function()? success, - TResult? Function(Object error, StackTrace? stackTrace)? error, - }) { - return idle?.call(); - } - - @override - @optionalTypeArgs - TResult maybeWhen({ - TResult Function()? idle, - TResult Function()? loading, - TResult Function()? success, - TResult Function(Object error, StackTrace? stackTrace)? error, - required TResult orElse(), - }) { - if (idle != null) { - return idle(); - } - return orElse(); - } - - @override - @optionalTypeArgs - TResult map({ - required TResult Function(Idle value) idle, - required TResult Function(Loading value) loading, - required TResult Function(Success value) success, - required TResult Function(Error value) error, - }) { - return idle(this); - } - - @override - @optionalTypeArgs - TResult? mapOrNull({ - TResult? Function(Idle value)? idle, - TResult? Function(Loading value)? loading, - TResult? Function(Success value)? success, - TResult? Function(Error value)? error, - }) { - return idle?.call(this); - } - - @override - @optionalTypeArgs - TResult maybeMap({ - TResult Function(Idle value)? idle, - TResult Function(Loading value)? loading, - TResult Function(Success value)? success, - TResult Function(Error value)? error, - required TResult orElse(), - }) { - if (idle != null) { - return idle(this); - } - return orElse(); - } -} - -abstract class Idle implements ButtonState { - const factory Idle() = _$Idle; -} - -/// @nodoc -abstract class _$$LoadingCopyWith<$Res> { - factory _$$LoadingCopyWith(_$Loading value, $Res Function(_$Loading) then) = - __$$LoadingCopyWithImpl<$Res>; -} - -/// @nodoc -class __$$LoadingCopyWithImpl<$Res> - extends _$ButtonStateCopyWithImpl<$Res, _$Loading> - implements _$$LoadingCopyWith<$Res> { - __$$LoadingCopyWithImpl(_$Loading _value, $Res Function(_$Loading) _then) - : super(_value, _then); -} - -/// @nodoc - -class _$Loading implements Loading { - const _$Loading(); - - @override - String toString() { - return 'ButtonState.loading()'; - } - - @override - bool operator ==(dynamic other) { - return identical(this, other) || - (other.runtimeType == runtimeType && other is _$Loading); - } - - @override - int get hashCode => runtimeType.hashCode; - - @override - @optionalTypeArgs - TResult when({ - required TResult Function() idle, - required TResult Function() loading, - required TResult Function() success, - required TResult Function(Object error, StackTrace? stackTrace) error, - }) { - return loading(); - } - - @override - @optionalTypeArgs - TResult? whenOrNull({ - TResult? Function()? idle, - TResult? Function()? loading, - TResult? Function()? success, - TResult? Function(Object error, StackTrace? stackTrace)? error, - }) { - return loading?.call(); - } - - @override - @optionalTypeArgs - TResult maybeWhen({ - TResult Function()? idle, - TResult Function()? loading, - TResult Function()? success, - TResult Function(Object error, StackTrace? stackTrace)? error, - required TResult orElse(), - }) { - if (loading != null) { - return loading(); - } - return orElse(); - } - - @override - @optionalTypeArgs - TResult map({ - required TResult Function(Idle value) idle, - required TResult Function(Loading value) loading, - required TResult Function(Success value) success, - required TResult Function(Error value) error, - }) { - return loading(this); - } - - @override - @optionalTypeArgs - TResult? mapOrNull({ - TResult? Function(Idle value)? idle, - TResult? Function(Loading value)? loading, - TResult? Function(Success value)? success, - TResult? Function(Error value)? error, - }) { - return loading?.call(this); - } - - @override - @optionalTypeArgs - TResult maybeMap({ - TResult Function(Idle value)? idle, - TResult Function(Loading value)? loading, - TResult Function(Success value)? success, - TResult Function(Error value)? error, - required TResult orElse(), - }) { - if (loading != null) { - return loading(this); - } - return orElse(); - } -} - -abstract class Loading implements ButtonState { - const factory Loading() = _$Loading; -} - -/// @nodoc -abstract class _$$SuccessCopyWith<$Res> { - factory _$$SuccessCopyWith(_$Success value, $Res Function(_$Success) then) = - __$$SuccessCopyWithImpl<$Res>; -} - -/// @nodoc -class __$$SuccessCopyWithImpl<$Res> - extends _$ButtonStateCopyWithImpl<$Res, _$Success> - implements _$$SuccessCopyWith<$Res> { - __$$SuccessCopyWithImpl(_$Success _value, $Res Function(_$Success) _then) - : super(_value, _then); -} - -/// @nodoc - -class _$Success implements Success { - const _$Success(); - - @override - String toString() { - return 'ButtonState.success()'; - } - - @override - bool operator ==(dynamic other) { - return identical(this, other) || - (other.runtimeType == runtimeType && other is _$Success); - } - - @override - int get hashCode => runtimeType.hashCode; - - @override - @optionalTypeArgs - TResult when({ - required TResult Function() idle, - required TResult Function() loading, - required TResult Function() success, - required TResult Function(Object error, StackTrace? stackTrace) error, - }) { - return success(); - } - - @override - @optionalTypeArgs - TResult? whenOrNull({ - TResult? Function()? idle, - TResult? Function()? loading, - TResult? Function()? success, - TResult? Function(Object error, StackTrace? stackTrace)? error, - }) { - return success?.call(); - } - - @override - @optionalTypeArgs - TResult maybeWhen({ - TResult Function()? idle, - TResult Function()? loading, - TResult Function()? success, - TResult Function(Object error, StackTrace? stackTrace)? error, - required TResult orElse(), - }) { - if (success != null) { - return success(); - } - return orElse(); - } - - @override - @optionalTypeArgs - TResult map({ - required TResult Function(Idle value) idle, - required TResult Function(Loading value) loading, - required TResult Function(Success value) success, - required TResult Function(Error value) error, - }) { - return success(this); - } - - @override - @optionalTypeArgs - TResult? mapOrNull({ - TResult? Function(Idle value)? idle, - TResult? Function(Loading value)? loading, - TResult? Function(Success value)? success, - TResult? Function(Error value)? error, - }) { - return success?.call(this); - } - - @override - @optionalTypeArgs - TResult maybeMap({ - TResult Function(Idle value)? idle, - TResult Function(Loading value)? loading, - TResult Function(Success value)? success, - TResult Function(Error value)? error, - required TResult orElse(), - }) { - if (success != null) { - return success(this); - } - return orElse(); - } -} - -abstract class Success implements ButtonState { - const factory Success() = _$Success; -} - -/// @nodoc -abstract class _$$ErrorCopyWith<$Res> { - factory _$$ErrorCopyWith(_$Error value, $Res Function(_$Error) then) = - __$$ErrorCopyWithImpl<$Res>; - @useResult - $Res call({Object error, StackTrace? stackTrace}); -} - -/// @nodoc -class __$$ErrorCopyWithImpl<$Res> - extends _$ButtonStateCopyWithImpl<$Res, _$Error> - implements _$$ErrorCopyWith<$Res> { - __$$ErrorCopyWithImpl(_$Error _value, $Res Function(_$Error) _then) - : super(_value, _then); - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? error = null, - Object? stackTrace = freezed, - }) { - return _then(_$Error( - null == error ? _value.error : error, - freezed == stackTrace - ? _value.stackTrace - : stackTrace // ignore: cast_nullable_to_non_nullable - as StackTrace?, - )); - } -} - -/// @nodoc - -class _$Error implements Error { - const _$Error(this.error, [this.stackTrace]); - - @override - final Object error; - @override - final StackTrace? stackTrace; - - @override - String toString() { - return 'ButtonState.error(error: $error, stackTrace: $stackTrace)'; - } - - @override - bool operator ==(dynamic other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$Error && - const DeepCollectionEquality().equals(other.error, error) && - (identical(other.stackTrace, stackTrace) || - other.stackTrace == stackTrace)); - } - - @override - int get hashCode => Object.hash( - runtimeType, const DeepCollectionEquality().hash(error), stackTrace); - - @JsonKey(ignore: true) - @override - @pragma('vm:prefer-inline') - _$$ErrorCopyWith<_$Error> get copyWith => - __$$ErrorCopyWithImpl<_$Error>(this, _$identity); - - @override - @optionalTypeArgs - TResult when({ - required TResult Function() idle, - required TResult Function() loading, - required TResult Function() success, - required TResult Function(Object error, StackTrace? stackTrace) error, - }) { - return error(this.error, stackTrace); - } - - @override - @optionalTypeArgs - TResult? whenOrNull({ - TResult? Function()? idle, - TResult? Function()? loading, - TResult? Function()? success, - TResult? Function(Object error, StackTrace? stackTrace)? error, - }) { - return error?.call(this.error, stackTrace); - } - - @override - @optionalTypeArgs - TResult maybeWhen({ - TResult Function()? idle, - TResult Function()? loading, - TResult Function()? success, - TResult Function(Object error, StackTrace? stackTrace)? error, - required TResult orElse(), - }) { - if (error != null) { - return error(this.error, stackTrace); - } - return orElse(); - } - - @override - @optionalTypeArgs - TResult map({ - required TResult Function(Idle value) idle, - required TResult Function(Loading value) loading, - required TResult Function(Success value) success, - required TResult Function(Error value) error, - }) { - return error(this); - } - - @override - @optionalTypeArgs - TResult? mapOrNull({ - TResult? Function(Idle value)? idle, - TResult? Function(Loading value)? loading, - TResult? Function(Success value)? success, - TResult? Function(Error value)? error, - }) { - return error?.call(this); - } - - @override - @optionalTypeArgs - TResult maybeMap({ - TResult Function(Idle value)? idle, - TResult Function(Loading value)? loading, - TResult Function(Success value)? success, - TResult Function(Error value)? error, - required TResult orElse(), - }) { - if (error != null) { - return error(this); - } - return orElse(); - } -} - -abstract class Error implements ButtonState { - const factory Error(final Object error, [final StackTrace? stackTrace]) = - _$Error; - - Object get error; - StackTrace? get stackTrace; - @JsonKey(ignore: true) - _$$ErrorCopyWith<_$Error> get copyWith => throw _privateConstructorUsedError; -} diff --git a/pubspec.yaml b/pubspec.yaml index e506cdb..a030073 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,11 +1,11 @@ name: async_button_builder description: A builder to wrap around buttons that handles loading, disabled, - error and succes states + error and success states version: 3.0.0+1 homepage: https://github.com/Nolence/async_button/tree/main/packages/async_button_builder environment: - sdk: ">=2.17.0 <3.0.0" + sdk: ">=2.17.0 <4.0.0" flutter: ">=1.17.0" dependencies: @@ -19,5 +19,6 @@ dev_dependencies: flutter_test: sdk: flutter freezed: ^2.3.2 + lint: ^2.3.0 flutter: null diff --git a/test/async_button_builder_test.dart b/test/async_button_builder_test.dart index 5e8e238..fc4098f 100644 --- a/test/async_button_builder_test.dart +++ b/test/async_button_builder_test.dart @@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { - testWidgets('displays child text', (WidgetTester tester) async { + testWidgets('displays child text', (tester) async { final textButton = MaterialApp( home: AsyncButtonBuilder( onPressed: () async { @@ -21,11 +21,9 @@ void main() { expect(find.text('click me'), findsOneWidget); }); - testWidgets('shows loading widget', (WidgetTester tester) async { - const duration = Duration(milliseconds: 250); + testWidgets('shows loading widget', (tester) async { final textButton = MaterialApp( home: AsyncButtonBuilder( - duration: duration, loadingWidget: const Text('loading'), onPressed: () async { await Future.delayed(const Duration(seconds: 1)); @@ -51,11 +49,9 @@ void main() { await tester.pumpAndSettle(const Duration(milliseconds: 900)); }); - testWidgets('shows error widget', (WidgetTester tester) async { - const duration = Duration(milliseconds: 250); + testWidgets('shows error widget', (tester) async { final textButton = MaterialApp( home: AsyncButtonBuilder( - duration: duration, errorWidget: const Text('error'), onPressed: () async { throw ArgumentError(); @@ -81,8 +77,7 @@ void main() { expect(find.text('error'), findsOneWidget); }); - testWidgets('error notification bubbles up', (WidgetTester tester) async { - const duration = Duration(milliseconds: 250); + testWidgets('error notification bubbles up', (tester) async { var idleCount = 0; var loadingCount = 0; var successCount = 0; @@ -95,17 +90,16 @@ void main() { idle: () => idleCount += 1, loading: () => loadingCount += 1, success: () => successCount += 1, - error: (_, __) => errorCount += 1, + error: (_) => errorCount += 1, ); - return true; }, child: AsyncButtonBuilder( - duration: duration, errorDuration: const Duration(milliseconds: 100), errorWidget: const Text('error'), + notifications: true, onPressed: () async { - throw ArgumentError(); + throw UnimplementedError(); }, builder: (context, child, callback, state) { return TextButton(onPressed: callback, child: child); @@ -120,8 +114,8 @@ void main() { find.byType(TextButton).evaluate().first.widget as TextButton; expect( - () => button.onPressed!.call(), - throwsA(isA()), + button.onPressed!.call, + throwsA(isA()), ); await tester.pump(const Duration(milliseconds: 200)); @@ -132,11 +126,9 @@ void main() { expect(successCount, 0); }); - testWidgets('Returns to child widget', (WidgetTester tester) async { - const duration = Duration(milliseconds: 250); + testWidgets('Returns to child widget', (tester) async { final textButton = MaterialApp( home: AsyncButtonBuilder( - duration: duration, loadingWidget: const Text('loading'), onPressed: () async { await Future.delayed(const Duration(seconds: 1)); From 45b4bd7b05ea61d758e8669546ea834586711168 Mon Sep 17 00:00:00 2001 From: "Esen, Mehmet" Date: Fri, 17 May 2024 16:39:06 +1000 Subject: [PATCH 096/176] refactor: removed example platform folders, pressCallback tweak --- example/.gitignore | 8 + example/.metadata | 24 +- example/android/.gitignore | 11 - example/android/app/build.gradle | 59 -- .../android/app/src/debug/AndroidManifest.xml | 7 - .../android/app/src/main/AndroidManifest.xml | 41 -- .../com/example/example/MainActivity.kt | 6 - .../res/drawable-v21/launch_background.xml | 12 - .../main/res/drawable/launch_background.xml | 12 - .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 544 -> 0 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 442 -> 0 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 721 -> 0 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 1031 -> 0 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 1443 -> 0 bytes .../app/src/main/res/values-night/styles.xml | 18 - .../app/src/main/res/values/styles.xml | 18 - .../app/src/profile/AndroidManifest.xml | 7 - example/android/build.gradle | 31 -- example/android/gradle.properties | 3 - .../gradle/wrapper/gradle-wrapper.properties | 6 - example/android/settings.gradle | 11 - example/ios/.gitignore | 32 -- example/ios/Flutter/AppFrameworkInfo.plist | 26 - example/ios/Flutter/Debug.xcconfig | 3 - example/ios/Flutter/Release.xcconfig | 3 - example/ios/Podfile | 41 -- example/ios/Podfile.lock | 16 - example/ios/Runner.xcodeproj/project.pbxproj | 521 ------------------ .../contents.xcworkspacedata | 7 - .../xcshareddata/IDEWorkspaceChecks.plist | 8 - .../xcshareddata/WorkspaceSettings.xcsettings | 8 - .../xcshareddata/xcschemes/Runner.xcscheme | 91 --- .../contents.xcworkspacedata | 10 - .../xcshareddata/IDEWorkspaceChecks.plist | 8 - .../xcshareddata/WorkspaceSettings.xcsettings | 8 - example/ios/Runner/AppDelegate.swift | 13 - .../AppIcon.appiconset/Contents.json | 122 ---- .../Icon-App-1024x1024@1x.png | Bin 10932 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 564 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 1283 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 1588 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 1025 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 1716 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 1920 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 1283 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 1895 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 2665 -> 0 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 2665 -> 0 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 3831 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 1888 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 3294 -> 0 bytes .../Icon-App-83.5x83.5@2x.png | Bin 3612 -> 0 bytes .../LaunchImage.imageset/Contents.json | 23 - .../LaunchImage.imageset/LaunchImage.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/LaunchImage@2x.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/LaunchImage@3x.png | Bin 68 -> 0 bytes .../LaunchImage.imageset/README.md | 5 - .../Runner/Base.lproj/LaunchScreen.storyboard | 37 -- example/ios/Runner/Base.lproj/Main.storyboard | 26 - example/ios/Runner/Info.plist | 45 -- example/ios/Runner/Runner-Bridging-Header.h | 1 - example/lib/main.dart | 14 +- example/web/favicon.png | Bin 917 -> 0 bytes example/web/icons/Icon-192.png | Bin 5292 -> 0 bytes example/web/icons/Icon-512.png | Bin 8252 -> 0 bytes example/web/index.html | 45 -- example/web/manifest.json | 23 - lib/src/async_button_builder.dart | 4 +- 68 files changed, 45 insertions(+), 1369 deletions(-) delete mode 100644 example/android/.gitignore delete mode 100644 example/android/app/build.gradle delete mode 100644 example/android/app/src/debug/AndroidManifest.xml delete mode 100644 example/android/app/src/main/AndroidManifest.xml delete mode 100644 example/android/app/src/main/kotlin/com/example/example/MainActivity.kt delete mode 100644 example/android/app/src/main/res/drawable-v21/launch_background.xml delete mode 100644 example/android/app/src/main/res/drawable/launch_background.xml delete mode 100644 example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png delete mode 100644 example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png delete mode 100644 example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png delete mode 100644 example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png delete mode 100644 example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png delete mode 100644 example/android/app/src/main/res/values-night/styles.xml delete mode 100644 example/android/app/src/main/res/values/styles.xml delete mode 100644 example/android/app/src/profile/AndroidManifest.xml delete mode 100644 example/android/build.gradle delete mode 100644 example/android/gradle.properties delete mode 100644 example/android/gradle/wrapper/gradle-wrapper.properties delete mode 100644 example/android/settings.gradle delete mode 100644 example/ios/.gitignore delete mode 100644 example/ios/Flutter/AppFrameworkInfo.plist delete mode 100644 example/ios/Flutter/Debug.xcconfig delete mode 100644 example/ios/Flutter/Release.xcconfig delete mode 100644 example/ios/Podfile delete mode 100644 example/ios/Podfile.lock delete mode 100644 example/ios/Runner.xcodeproj/project.pbxproj delete mode 100644 example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100644 example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings delete mode 100644 example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme delete mode 100644 example/ios/Runner.xcworkspace/contents.xcworkspacedata delete mode 100644 example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings delete mode 100644 example/ios/Runner/AppDelegate.swift delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png delete mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png delete mode 100644 example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json delete mode 100644 example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png delete mode 100644 example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png delete mode 100644 example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png delete mode 100644 example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md delete mode 100644 example/ios/Runner/Base.lproj/LaunchScreen.storyboard delete mode 100644 example/ios/Runner/Base.lproj/Main.storyboard delete mode 100644 example/ios/Runner/Info.plist delete mode 100644 example/ios/Runner/Runner-Bridging-Header.h delete mode 100644 example/web/favicon.png delete mode 100644 example/web/icons/Icon-192.png delete mode 100644 example/web/icons/Icon-512.png delete mode 100644 example/web/index.html delete mode 100644 example/web/manifest.json diff --git a/example/.gitignore b/example/.gitignore index 664a63d..80a9898 100644 --- a/example/.gitignore +++ b/example/.gitignore @@ -46,3 +46,11 @@ app.*.map.json /android/app/release /pubspec.lock + +# Platform Folders +android/ +ios/ +web/ +macos/ +windows/ +linux/ \ No newline at end of file diff --git a/example/.metadata b/example/.metadata index 36a4614..135a1da 100644 --- a/example/.metadata +++ b/example/.metadata @@ -4,7 +4,27 @@ # This file should be version controlled and should not be manually edited. version: - revision: 63062a64432cce03315d6b5196fda7912866eb37 - channel: dev + revision: "5dcb86f68f239346676ceb1ed1ea385bd215fba1" + channel: "stable" project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1 + base_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1 + - platform: macos + create_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1 + base_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/example/android/.gitignore b/example/android/.gitignore deleted file mode 100644 index 0a741cb..0000000 --- a/example/android/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -gradle-wrapper.jar -/.gradle -/captures/ -/gradlew -/gradlew.bat -/local.properties -GeneratedPluginRegistrant.java - -# Remember to never publicly share your keystore. -# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app -key.properties diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle deleted file mode 100644 index 6ca2344..0000000 --- a/example/android/app/build.gradle +++ /dev/null @@ -1,59 +0,0 @@ -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - -android { - compileSdkVersion 30 - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.example.example" - minSdkVersion 16 - targetSdkVersion 30 - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } -} - -flutter { - source '../..' -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" -} diff --git a/example/android/app/src/debug/AndroidManifest.xml b/example/android/app/src/debug/AndroidManifest.xml deleted file mode 100644 index c208884..0000000 --- a/example/android/app/src/debug/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index 34dd77e..0000000 --- a/example/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt b/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt deleted file mode 100644 index e793a00..0000000 --- a/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.example.example - -import io.flutter.embedding.android.FlutterActivity - -class MainActivity: FlutterActivity() { -} diff --git a/example/android/app/src/main/res/drawable-v21/launch_background.xml b/example/android/app/src/main/res/drawable-v21/launch_background.xml deleted file mode 100644 index f74085f..0000000 --- a/example/android/app/src/main/res/drawable-v21/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/example/android/app/src/main/res/drawable/launch_background.xml b/example/android/app/src/main/res/drawable/launch_background.xml deleted file mode 100644 index 304732f..0000000 --- a/example/android/app/src/main/res/drawable/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index db77bb4b7b0906d62b1847e87f15cdcacf6a4f29..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ diff --git a/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 17987b79bb8a35cc66c3c1fd44f5a5526c1b78be..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 442 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xx&nMcT!A!W`0S9QKQy;}1Cl^CgaH=;G9cpY;r$Q>i*pfB zP2drbID<_#qf;rPZx^FqH)F_D#*k@@q03KywUtLX8Ua?`H+NMzkczFPK3lFz@i_kW%1NOn0|D2I9n9wzH8m|-tHjsw|9>@K=iMBhxvkv6m8Y-l zytQ?X=U+MF$@3 zt`~i=@j|6y)RWMK--}M|=T`o&^Ni>IoWKHEbBXz7?A@mgWoL>!*SXo`SZH-*HSdS+ yn*9;$7;m`l>wYBC5bq;=U}IMqLzqbYCidGC!)_gkIk_C@Uy!y&wkt5C($~2D>~)O*cj@FGjOCM)M>_ixfudOh)?xMu#Fs z#}Y=@YDTwOM)x{K_j*Q;dPdJ?Mz0n|pLRx{4n|)f>SXlmV)XB04CrSJn#dS5nK2lM zrZ9#~WelCp7&e13Y$jvaEXHskn$2V!!DN-nWS__6T*l;H&Fopn?A6HZ-6WRLFP=R` zqG+CE#d4|IbyAI+rJJ`&x9*T`+a=p|0O(+s{UBcyZdkhj=yS1>AirP+0R;mf2uMgM zC}@~JfByORAh4SyRgi&!(cja>F(l*O+nd+@4m$|6K6KDn_&uvCpV23&>G9HJp{xgg zoq1^2_p9@|WEo z*X_Uko@K)qYYv~>43eQGMdbiGbo>E~Q& zrYBH{QP^@Sti!`2)uG{irBBq@y*$B zi#&(U-*=fp74j)RyIw49+0MRPMRU)+a2r*PJ$L5roHt2$UjExCTZSbq%V!HeS7J$N zdG@vOZB4v_lF7Plrx+hxo7(fCV&}fHq)$ diff --git a/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index d5f1c8d34e7a88e3f88bea192c3a370d44689c3c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1031 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof diff --git a/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 4d6372eebdb28e45604e46eeda8dd24651419bc0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1443 zcmb`G{WsKk6vsdJTdFg%tJav9_E4vzrOaqkWF|A724Nly!y+?N9`YV6wZ}5(X(D_N(?!*n3`|_r0Hc?=PQw&*vnU?QTFY zB_MsH|!j$PP;I}?dppoE_gA(4uc!jV&0!l7_;&p2^pxNo>PEcNJv za5_RT$o2Mf!<+r?&EbHH6nMoTsDOa;mN(wv8RNsHpG)`^ymG-S5By8=l9iVXzN_eG%Xg2@Xeq76tTZ*dGh~Lo9vl;Zfs+W#BydUw zCkZ$o1LqWQO$FC9aKlLl*7x9^0q%0}$OMlp@Kk_jHXOjofdePND+j!A{q!8~Jn+s3 z?~~w@4?egS02}8NuulUA=L~QQfm;MzCGd)XhiftT;+zFO&JVyp2mBww?;QByS_1w! zrQlx%{^cMj0|Bo1FjwY@Q8?Hx0cIPF*@-ZRFpPc#bBw{5@tD(5%sClzIfl8WU~V#u zm5Q;_F!wa$BSpqhN>W@2De?TKWR*!ujY;Yylk_X5#~V!L*Gw~;$%4Q8~Mad z@`-kG?yb$a9cHIApZDVZ^U6Xkp<*4rU82O7%}0jjHlK{id@?-wpN*fCHXyXh(bLt* zPc}H-x0e4E&nQ>y%B-(EL=9}RyC%MyX=upHuFhAk&MLbsF0LP-q`XnH78@fT+pKPW zu72MW`|?8ht^tz$iC}ZwLp4tB;Q49K!QCF3@!iB1qOI=?w z7In!}F~ij(18UYUjnbmC!qKhPo%24?8U1x{7o(+?^Zu0Hx81|FuS?bJ0jgBhEMzf< zCgUq7r2OCB(`XkKcN-TL>u5y#dD6D!)5W?`O5)V^>jb)P)GBdy%t$uUMpf$SNV31$ zb||OojAbvMP?T@$h_ZiFLFVHDmbyMhJF|-_)HX3%m=CDI+ID$0^C>kzxprBW)hw(v zr!Gmda);ICoQyhV_oP5+C%?jcG8v+D@9f?Dk*!BxY}dazmrT@64UrP3hlslANK)bq z$67n83eh}OeW&SV@HG95P|bjfqJ7gw$e+`Hxo!4cx`jdK1bJ>YDSpGKLPZ^1cv$ek zIB?0S<#tX?SJCLWdMd{-ME?$hc7A$zBOdIJ)4!KcAwb=VMov)nK;9z>x~rfT1>dS+ zZ6#`2v@`jgbqq)P22H)Tx2CpmM^o1$B+xT6`(v%5xJ(?j#>Q$+rx_R|7TzDZe{J6q zG1*EcU%tE?!kO%^M;3aM6JN*LAKUVb^xz8-Pxo#jR5(-KBeLJvA@-gxNHx0M-ZJLl z;#JwQoh~9V?`UVo#}{6ka@II>++D@%KqGpMdlQ}?9E*wFcf5(#XQnP$Dk5~%iX^>f z%$y;?M0BLp{O3a(-4A?ewryHrrD%cx#Q^%KY1H zNre$ve+vceSLZcNY4U(RBX&)oZn*Py()h)XkE?PL$!bNb{N5FVI2Y%LKEm%yvpyTP z(1P?z~7YxD~Rf<(a@_y` diff --git a/example/android/app/src/main/res/values-night/styles.xml b/example/android/app/src/main/res/values-night/styles.xml deleted file mode 100644 index 449a9f9..0000000 --- a/example/android/app/src/main/res/values-night/styles.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - diff --git a/example/android/app/src/main/res/values/styles.xml b/example/android/app/src/main/res/values/styles.xml deleted file mode 100644 index d74aa35..0000000 --- a/example/android/app/src/main/res/values/styles.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - diff --git a/example/android/app/src/profile/AndroidManifest.xml b/example/android/app/src/profile/AndroidManifest.xml deleted file mode 100644 index c208884..0000000 --- a/example/android/app/src/profile/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/example/android/build.gradle b/example/android/build.gradle deleted file mode 100644 index c505a86..0000000 --- a/example/android/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -buildscript { - ext.kotlin_version = '1.3.50' - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:4.1.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -allprojects { - repositories { - google() - jcenter() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(':app') -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/example/android/gradle.properties b/example/android/gradle.properties deleted file mode 100644 index 94adc3a..0000000 --- a/example/android/gradle.properties +++ /dev/null @@ -1,3 +0,0 @@ -org.gradle.jvmargs=-Xmx1536M -android.useAndroidX=true -android.enableJetifier=true diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index bc6a58a..0000000 --- a/example/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Fri Jun 23 08:50:38 CEST 2017 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip diff --git a/example/android/settings.gradle b/example/android/settings.gradle deleted file mode 100644 index 44e62bc..0000000 --- a/example/android/settings.gradle +++ /dev/null @@ -1,11 +0,0 @@ -include ':app' - -def localPropertiesFile = new File(rootProject.projectDir, "local.properties") -def properties = new Properties() - -assert localPropertiesFile.exists() -localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } - -def flutterSdkPath = properties.getProperty("flutter.sdk") -assert flutterSdkPath != null, "flutter.sdk not set in local.properties" -apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/example/ios/.gitignore b/example/ios/.gitignore deleted file mode 100644 index e96ef60..0000000 --- a/example/ios/.gitignore +++ /dev/null @@ -1,32 +0,0 @@ -*.mode1v3 -*.mode2v3 -*.moved-aside -*.pbxuser -*.perspectivev3 -**/*sync/ -.sconsign.dblite -.tags* -**/.vagrant/ -**/DerivedData/ -Icon? -**/Pods/ -**/.symlinks/ -profile -xcuserdata -**/.generated/ -Flutter/App.framework -Flutter/Flutter.framework -Flutter/Flutter.podspec -Flutter/Generated.xcconfig -Flutter/app.flx -Flutter/app.zip -Flutter/flutter_assets/ -Flutter/flutter_export_environment.sh -ServiceDefinitions.json -Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!default.mode1v3 -!default.mode2v3 -!default.pbxuser -!default.perspectivev3 diff --git a/example/ios/Flutter/AppFrameworkInfo.plist b/example/ios/Flutter/AppFrameworkInfo.plist deleted file mode 100644 index 8d4492f..0000000 --- a/example/ios/Flutter/AppFrameworkInfo.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - App - CFBundleIdentifier - io.flutter.flutter.app - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - App - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - MinimumOSVersion - 9.0 - - diff --git a/example/ios/Flutter/Debug.xcconfig b/example/ios/Flutter/Debug.xcconfig deleted file mode 100644 index b2f5fae..0000000 --- a/example/ios/Flutter/Debug.xcconfig +++ /dev/null @@ -1,3 +0,0 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" -#include "Generated.xcconfig" diff --git a/example/ios/Flutter/Release.xcconfig b/example/ios/Flutter/Release.xcconfig deleted file mode 100644 index 88c2914..0000000 --- a/example/ios/Flutter/Release.xcconfig +++ /dev/null @@ -1,3 +0,0 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" -#include "Generated.xcconfig" diff --git a/example/ios/Podfile b/example/ios/Podfile deleted file mode 100644 index b29247c..0000000 --- a/example/ios/Podfile +++ /dev/null @@ -1,41 +0,0 @@ -# Uncomment this line to define a global platform for your project -# platform :ios, '9.0' - -# CocoaPods analytics sends network stats synchronously affecting flutter build latency. -ENV['COCOAPODS_DISABLE_STATS'] = 'true' - -project 'Runner', { - 'Debug' => :debug, - 'Profile' => :release, - 'Release' => :release, -} - -def flutter_root - generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) - unless File.exist?(generated_xcode_build_settings_path) - raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" - end - - File.foreach(generated_xcode_build_settings_path) do |line| - matches = line.match(/FLUTTER_ROOT\=(.*)/) - return matches[1].strip if matches - end - raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" -end - -require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) - -flutter_ios_podfile_setup - -target 'Runner' do - use_frameworks! - use_modular_headers! - - flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) -end - -post_install do |installer| - installer.pods_project.targets.each do |target| - flutter_additional_ios_build_settings(target) - end -end \ No newline at end of file diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock deleted file mode 100644 index f11c132..0000000 --- a/example/ios/Podfile.lock +++ /dev/null @@ -1,16 +0,0 @@ -PODS: - - Flutter (1.0.0) - -DEPENDENCIES: - - Flutter (from `Flutter`) - -EXTERNAL SOURCES: - Flutter: - :path: Flutter - -SPEC CHECKSUMS: - Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c - -PODFILE CHECKSUM: fc81e398f362bae88bdf55239bd5cf842faad39f - -COCOAPODS: 1.10.1 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index 0ecf382..0000000 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,521 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 50; - objects = { - -/* Begin PBXBuildFile section */ - 052090A8264F7CC7D59BAC4F /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 166593E2DDC1580301FBE4EB /* Pods_Runner.framework */; }; - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; -/* End PBXBuildFile section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 9705A1C41CF9048500538489 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 166593E2DDC1580301FBE4EB /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; - 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 979288937DB54B7A8E167BFD /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; - 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - ABECF997BE9D843ACE309A51 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; - BFE91A80E9CF01FB47297D69 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 97C146EB1CF9000F007C117D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 052090A8264F7CC7D59BAC4F /* Pods_Runner.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 421781B0B716E5E3F11A65B3 /* Pods */ = { - isa = PBXGroup; - children = ( - ABECF997BE9D843ACE309A51 /* Pods-Runner.debug.xcconfig */, - BFE91A80E9CF01FB47297D69 /* Pods-Runner.release.xcconfig */, - 979288937DB54B7A8E167BFD /* Pods-Runner.profile.xcconfig */, - ); - name = Pods; - path = Pods; - sourceTree = ""; - }; - 9740EEB11CF90186004384FC /* Flutter */ = { - isa = PBXGroup; - children = ( - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 9740EEB31CF90195004384FC /* Generated.xcconfig */, - ); - name = Flutter; - sourceTree = ""; - }; - 97C146E51CF9000F007C117D = { - isa = PBXGroup; - children = ( - 9740EEB11CF90186004384FC /* Flutter */, - 97C146F01CF9000F007C117D /* Runner */, - 97C146EF1CF9000F007C117D /* Products */, - 421781B0B716E5E3F11A65B3 /* Pods */, - C21EF53B5D1A17BF8839457D /* Frameworks */, - ); - sourceTree = ""; - }; - 97C146EF1CF9000F007C117D /* Products */ = { - isa = PBXGroup; - children = ( - 97C146EE1CF9000F007C117D /* Runner.app */, - ); - name = Products; - sourceTree = ""; - }; - 97C146F01CF9000F007C117D /* Runner */ = { - isa = PBXGroup; - children = ( - 97C146FA1CF9000F007C117D /* Main.storyboard */, - 97C146FD1CF9000F007C117D /* Assets.xcassets */, - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, - 97C147021CF9000F007C117D /* Info.plist */, - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, - ); - path = Runner; - sourceTree = ""; - }; - C21EF53B5D1A17BF8839457D /* Frameworks */ = { - isa = PBXGroup; - children = ( - 166593E2DDC1580301FBE4EB /* Pods_Runner.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 97C146ED1CF9000F007C117D /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - 0D390D42CD24A841DCDBE0FB /* [CP] Check Pods Manifest.lock */, - 9740EEB61CF901F6004384FC /* Run Script */, - 97C146EA1CF9000F007C117D /* Sources */, - 97C146EB1CF9000F007C117D /* Frameworks */, - 97C146EC1CF9000F007C117D /* Resources */, - 9705A1C41CF9048500538489 /* Embed Frameworks */, - 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Runner; - productName = Runner; - productReference = 97C146EE1CF9000F007C117D /* Runner.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 97C146E61CF9000F007C117D /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 1300; - ORGANIZATIONNAME = ""; - TargetAttributes = { - 97C146ED1CF9000F007C117D = { - CreatedOnToolsVersion = 7.3.1; - LastSwiftMigration = 1100; - }; - }; - }; - buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 97C146E51CF9000F007C117D; - productRefGroup = 97C146EF1CF9000F007C117D /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 97C146ED1CF9000F007C117D /* Runner */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 97C146EC1CF9000F007C117D /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 0D390D42CD24A841DCDBE0FB /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Thin Binary"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; - }; - 9740EEB61CF901F6004384FC /* Run Script */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Run Script"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 97C146EA1CF9000F007C117D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 97C146FA1CF9000F007C117D /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C146FB1CF9000F007C117D /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C147001CF9000F007C117D /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 249021D3217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Profile; - }; - 249021D4217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.example.example; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Profile; - }; - 97C147031CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 97C147041CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 97C147061CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.example.example; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Debug; - }; - 97C147071CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.example.example; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147031CF9000F007C117D /* Debug */, - 97C147041CF9000F007C117D /* Release */, - 249021D3217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147061CF9000F007C117D /* Debug */, - 97C147071CF9000F007C117D /* Release */, - 249021D4217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 97C146E61CF9000F007C117D /* Project object */; -} diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a..0000000 --- a/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d9810..0000000 --- a/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c..0000000 --- a/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index 3db53b6..0000000 --- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/example/ios/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 21a3cc1..0000000 --- a/example/ios/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d9810..0000000 --- a/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c..0000000 --- a/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/example/ios/Runner/AppDelegate.swift b/example/ios/Runner/AppDelegate.swift deleted file mode 100644 index 70693e4..0000000 --- a/example/ios/Runner/AppDelegate.swift +++ /dev/null @@ -1,13 +0,0 @@ -import UIKit -import Flutter - -@UIApplicationMain -@objc class AppDelegate: FlutterAppDelegate { - override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - GeneratedPluginRegistrant.register(with: self) - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } -} diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index d36b1fa..0000000 --- a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,122 +0,0 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" - }, - { - "size" : "1024x1024", - "idiom" : "ios-marketing", - "filename" : "Icon-App-1024x1024@1x.png", - "scale" : "1x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png deleted file mode 100644 index dc9ada4725e9b0ddb1deab583e5b5102493aa332..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10932 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 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png deleted file mode 100644 index f091b6b0bca859a3f474b03065bef75ba58a9e4c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1588 zcmV-42Fv-0P)C1SqPt}wig>|5Crh^=oyX$BK<}M8eLU3e2hGT;=G|!_SP)7zNI6fqUMB=)y zRAZ>eDe#*r`yDAVgB_R*LB*MAc)8(b{g{9McCXW!lq7r(btRoB9!8B-#AI6JMb~YFBEvdsV)`mEQO^&#eRKx@b&x- z5lZm*!WfD8oCLzfHGz#u7sT0^VLMI1MqGxF^v+`4YYnVYgk*=kU?HsSz{v({E3lb9 z>+xILjBN)t6`=g~IBOelGQ(O990@BfXf(DRI5I$qN$0Gkz-FSc$3a+2fX$AedL4u{ z4V+5Ong(9LiGcIKW?_352sR;LtDPmPJXI{YtT=O8=76o9;*n%_m|xo!i>7$IrZ-{l z-x3`7M}qzHsPV@$v#>H-TpjDh2UE$9g6sysUREDy_R(a)>=eHw-WAyfIN z*qb!_hW>G)Tu8nSw9yn#3wFMiLcfc4pY0ek1}8(NqkBR@t4{~oC>ryc-h_ByH(Cg5 z>ao-}771+xE3um9lWAY1FeQFxowa1(!J(;Jg*wrg!=6FdRX+t_<%z&d&?|Bn){>zm zZQj(aA_HeBY&OC^jj*)N`8fa^ePOU72VpInJoI1?`ty#lvlNzs(&MZX+R%2xS~5Kh zX*|AU4QE#~SgPzOXe9>tRj>hjU@c1k5Y_mW*Jp3fI;)1&g3j|zDgC+}2Q_v%YfDax z!?umcN^n}KYQ|a$Lr+51Nf9dkkYFSjZZjkma$0KOj+;aQ&721~t7QUKx61J3(P4P1 zstI~7-wOACnWP4=8oGOwz%vNDqD8w&Q`qcNGGrbbf&0s9L0De{4{mRS?o0MU+nR_! zrvshUau0G^DeMhM_v{5BuLjb#Hh@r23lDAk8oF(C+P0rsBpv85EP>4CVMx#04MOfG z;P%vktHcXwTj~+IE(~px)3*MY77e}p#|c>TD?sMatC0Tu4iKKJ0(X8jxQY*gYtxsC z(zYC$g|@+I+kY;dg_dE>scBf&bP1Nc@Hz<3R)V`=AGkc;8CXqdi=B4l2k|g;2%#m& z*jfX^%b!A8#bI!j9-0Fi0bOXl(-c^AB9|nQaE`*)Hw+o&jS9@7&Gov#HbD~#d{twV zXd^Tr^mWLfFh$@Dr$e;PBEz4(-2q1FF0}c;~B5sA}+Q>TOoP+t>wf)V9Iy=5ruQa;z)y zI9C9*oUga6=hxw6QasLPnee@3^Rr*M{CdaL5=R41nLs(AHk_=Y+A9$2&H(B7!_pURs&8aNw7?`&Z&xY_Ye z)~D5Bog^td-^QbUtkTirdyK^mTHAOuptDflut!#^lnKqU md>ggs(5nOWAqO?umG&QVYK#ibz}*4>0000U6E9hRK9^#O7(mu>ETqrXGsduA8$)?`v2seloOCza43C{NQ$$gAOH**MCn0Q?+L7dl7qnbRdqZ8LSVp1ItDxhxD?t@5_yHg6A8yI zC*%Wgg22K|8E#!~cTNYR~@Y9KepMPrrB8cABapAFa=`H+UGhkXUZV1GnwR1*lPyZ;*K(i~2gp|@bzp8}og7e*#% zEnr|^CWdVV!-4*Y_7rFvlww2Ze+>j*!Z!pQ?2l->4q#nqRu9`ELo6RMS5=br47g_X zRw}P9a7RRYQ%2Vsd0Me{_(EggTnuN6j=-?uFS6j^u69elMypu?t>op*wBx<=Wx8?( ztpe^(fwM6jJX7M-l*k3kEpWOl_Vk3@(_w4oc}4YF4|Rt=2V^XU?#Yz`8(e?aZ@#li0n*=g^qOcVpd-Wbok=@b#Yw zqn8u9a)z>l(1kEaPYZ6hwubN6i<8QHgsu0oE) ziJ(p;Wxm>sf!K+cw>R-(^Y2_bahB+&KI9y^);#0qt}t-$C|Bo71lHi{_+lg#f%RFy z0um=e3$K3i6K{U_4K!EX?F&rExl^W|G8Z8;`5z-k}OGNZ0#WVb$WCpQu-_YsiqKP?BB# vzVHS-CTUF4Ozn5G+mq_~Qqto~ahA+K`|lyv3(-e}00000NkvXXu0mjfd`9t{ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png deleted file mode 100644 index d0ef06e7edb86cdfe0d15b4b0d98334a86163658..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1716 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 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png deleted file mode 100644 index c8f9ed8f5cee1c98386d13b17e89f719e83555b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1895 zcmV-t2blPYP)FQtfgmafE#=YDCq`qUBt#QpG%*H6QHY765~R=q zZ6iudfM}q!Pz#~9JgOi8QJ|DSu?1-*(kSi1K4#~5?#|rh?sS)(-JQqX*}ciXJ56_H zdw=^s_srbAdqxlvGyrgGet#6T7_|j;95sL%MtM;q86vOxKM$f#puR)Bjv9Zvz9-di zXOTSsZkM83)E9PYBXC<$6(|>lNLVBb&&6y{NByFCp%6+^ALR@NCTse_wqvNmSWI-m z!$%KlHFH2omF!>#%1l3LTZg(s7eof$7*xB)ZQ0h?ejh?Ta9fDv59+u#MokW+1t8Zb zgHv%K(u9G^Lv`lh#f3<6!JVTL3(dCpxHbnbA;kKqQyd1~^Xe0VIaYBSWm6nsr;dFj z4;G-RyL?cYgsN1{L4ZFFNa;8)Rv0fM0C(~Tkit94 zz#~A)59?QjD&pAPSEQ)p8gP|DS{ng)j=2ux)_EzzJ773GmQ_Cic%3JJhC0t2cx>|v zJcVusIB!%F90{+}8hG3QU4KNeKmK%T>mN57NnCZ^56=0?&3@!j>a>B43pi{!u z7JyDj7`6d)qVp^R=%j>UIY6f+3`+qzIc!Y_=+uN^3BYV|o+$vGo-j-Wm<10%A=(Yk^beI{t%ld@yhKjq0iNjqN4XMGgQtbKubPM$JWBz}YA65k%dm*awtC^+f;a-x4+ddbH^7iDWGg&N0n#MW{kA|=8iMUiFYvMoDY@sPC#t$55gn6ykUTPAr`a@!(;np824>2xJthS z*ZdmT`g5-`BuJs`0LVhz+D9NNa3<=6m;cQLaF?tCv8)zcRSh66*Z|vXhG@$I%U~2l z?`Q zykI#*+rQ=z6Jm=Bui-SfpDYLA=|vzGE(dYm=OC8XM&MDo7ux4UF1~0J1+i%aCUpRe zt3L_uNyQ*cE(38Uy03H%I*)*Bh=Lb^Xj3?I^Hnbeq72(EOK^Y93CNp*uAA{5Lc=ky zx=~RKa4{iTm{_>_vSCm?$Ej=i6@=m%@VvAITnigVg{&@!7CDgs908761meDK5azA} z4?=NOH|PdvabgJ&fW2{Mo$Q0CcD8Qc84%{JPYt5EiG{MdLIAeX%T=D7NIP4%Hw}p9 zg)==!2Lbp#j{u_}hMiao9=!VSyx0gHbeCS`;q&vzeq|fs`y&^X-lso(Ls@-706qmA z7u*T5PMo_w3{se1t2`zWeO^hOvTsohG_;>J0wVqVe+n)AbQCx)yh9;w+J6?NF5Lmo zecS@ieAKL8%bVd@+-KT{yI|S}O>pYckUFs;ry9Ow$CD@ztz5K-*D$^{i(_1llhSh^ zEkL$}tsQt5>QA^;QgjgIfBDmcOgi5YDyu?t6vSnbp=1+@6D& z5MJ}B8q;bRlVoxasyhcUF1+)o`&3r0colr}QJ3hcSdLu;9;td>kf@Tcn<@9sIx&=m z;AD;SCh95=&p;$r{Xz3iWCO^MX83AGJ(yH&eTXgv|0=34#-&WAmw{)U7OU9!Wz^!7 zZ%jZFi@JR;>Mhi7S>V7wQ176|FdW2m?&`qa(ScO^CFPR80HucLHOTy%5s*HR0^8)i h0WYBP*#0Ks^FNSabJA*5${_#%002ovPDHLkV1oKhTl@e3 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png deleted file mode 100644 index a6d6b8609df07bf62e5100a53a01510388bd2b22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index a6d6b8609df07bf62e5100a53a01510388bd2b22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index 75b2d164a5a98e212cca15ea7bf2ab5de5108680..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3831 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 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png deleted file mode 100644 index c4df70d39da7941ef3f6dcb7f06a192d8dcb308d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1888 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 iW8Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png deleted file mode 100644 index 9da19eacad3b03bb08bbddbbf4ac48dd78b3d838..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png deleted file mode 100644 index 9da19eacad3b03bb08bbddbbf4ac48dd78b3d838..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725..0000000 --- a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -You can customize the launch screen with your own desired assets by replacing the image files in this directory. - -You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/example/ios/Runner/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index f2e259c..0000000 --- a/example/ios/Runner/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/example/ios/Runner/Base.lproj/Main.storyboard b/example/ios/Runner/Base.lproj/Main.storyboard deleted file mode 100644 index f3c2851..0000000 --- a/example/ios/Runner/Base.lproj/Main.storyboard +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist deleted file mode 100644 index a060db6..0000000 --- a/example/ios/Runner/Info.plist +++ /dev/null @@ -1,45 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - example - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - - diff --git a/example/ios/Runner/Runner-Bridging-Header.h b/example/ios/Runner/Runner-Bridging-Header.h deleted file mode 100644 index 308a2a5..0000000 --- a/example/ios/Runner/Runner-Bridging-Header.h +++ /dev/null @@ -1 +0,0 @@ -#import "GeneratedPluginRegistrant.h" diff --git a/example/lib/main.dart b/example/lib/main.dart index c96f74e..ba3870b 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -16,13 +16,24 @@ class MyApp extends StatelessWidget { } } -class MyHomePage extends StatelessWidget { +class MyHomePage extends StatefulWidget { const MyHomePage({Key? key}) : super(key: key); + @override + State createState() => _MyHomePageState(); +} + +class _MyHomePageState extends State { + final textButtonState = GlobalKey(); + @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Async Buttons')), + floatingActionButton: FloatingActionButton.extended( + onPressed: textButtonState.currentState?.pressCallback, + label: const Text('You can trigger first button from here'), + ), body: SizedBox.expand( child: Column( crossAxisAlignment: CrossAxisAlignment.center, @@ -31,6 +42,7 @@ class MyHomePage extends StatelessWidget { const Divider(), const Text('Text Button:'), AsyncButtonBuilder( + key: textButtonState, child: const Text('Click Me'), onPressed: () async { await Future.delayed(const Duration(seconds: 1)); diff --git a/example/web/favicon.png b/example/web/favicon.png deleted file mode 100644 index 8aaa46ac1ae21512746f852a42ba87e4165dfdd1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 917 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|I14-?iy0X7 zltGxWVyS%@P(fs7NJL45ua8x7ey(0(N`6wRUPW#JP&EUCO@$SZnVVXYs8ErclUHn2 zVXFjIVFhG^g!Ppaz)DK8ZIvQ?0~DO|i&7O#^-S~(l1AfjnEK zjFOT9D}DX)@^Za$W4-*MbbUihOG|wNBYh(yU7!lx;>x^|#0uTKVr7USFmqf|i<65o z3raHc^AtelCMM;Vme?vOfh>Xph&xL%(-1c06+^uR^q@XSM&D4+Kp$>4P^%3{)XKjo zGZknv$b36P8?Z_gF{nK@`XI}Z90TzwSQO}0J1!f2c(B=V`5aP@1P1a|PZ!4!3&Gl8 zTYqUsf!gYFyJnXpu0!n&N*SYAX-%d(5gVjrHJWqXQshj@!Zm{!01WsQrH~9=kTxW#6SvuapgMqt>$=j#%eyGrQzr zP{L-3gsMA^$I1&gsBAEL+vxi1*Igl=8#8`5?A-T5=z-sk46WA1IUT)AIZHx1rdUrf zVJrJn<74DDw`j)Ki#gt}mIT-Q`XRa2-jQXQoI%w`nb|XblvzK${ZzlV)m-XcwC(od z71_OEC5Bt9GEXosOXaPTYOia#R4ID2TiU~`zVMl08TV_C%DnU4^+HE>9(CE4D6?Fz oujB08i7adh9xk7*FX66dWH6F5TM;?E2b5PlUHx3vIVCg!0Dx9vYXATM diff --git a/example/web/icons/Icon-192.png b/example/web/icons/Icon-192.png deleted file mode 100644 index b749bfef07473333cf1dd31e9eed89862a5d52aa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5292 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 diff --git a/example/web/icons/Icon-512.png b/example/web/icons/Icon-512.png deleted file mode 100644 index 88cfd48dff1169879ba46840804b412fe02fefd6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8252 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 diff --git a/example/web/index.html b/example/web/index.html deleted file mode 100644 index 1460b5e..0000000 --- a/example/web/index.html +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - - - - - - - - - - - - example - - - - - - - - diff --git a/example/web/manifest.json b/example/web/manifest.json deleted file mode 100644 index 8c01291..0000000 --- a/example/web/manifest.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "example", - "short_name": "example", - "start_url": ".", - "display": "standalone", - "background_color": "#0175C2", - "theme_color": "#0175C2", - "description": "A new Flutter project.", - "orientation": "portrait-primary", - "prefer_related_applications": false, - "icons": [ - { - "src": "icons/Icon-192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "icons/Icon-512.png", - "sizes": "512x512", - "type": "image/png" - } - ] -} diff --git a/lib/src/async_button_builder.dart b/lib/src/async_button_builder.dart index 20cfebd..3876035 100644 --- a/lib/src/async_button_builder.dart +++ b/lib/src/async_button_builder.dart @@ -340,12 +340,12 @@ class AsyncButtonBuilderState extends State child: switcher, ) : switcher, - press(), + pressCallback, _buttonState, ); } - AsyncCallback? press() { + AsyncCallback? get pressCallback { if (widget.disabled || widget.onPressed == null) { return null; } From 6ce2720d5769b10963160e3fa912af5698d39ab6 Mon Sep 17 00:00:00 2001 From: Mehmet Esen <43244505+esenmx@users.noreply.github.com> Date: Wed, 16 Apr 2025 12:36:06 +0300 Subject: [PATCH 097/176] refactor: removed freezed, code/doc tweaks --- CHANGELOG.md | 49 +- README.md | 3 +- analysis_options.yaml | 7 - example/.metadata | 12 +- example/lib/main.dart | 67 +-- example/pubspec.yaml | 2 +- example/test/widget_test.dart | 30 ++ lib/src/async_button_builder.dart | 149 +++--- lib/src/async_button_state.dart | 47 +- lib/src/async_button_state.freezed.dart | 582 ------------------------ pubspec.yaml | 12 +- test/async_button_builder_test.dart | 138 +++--- 12 files changed, 273 insertions(+), 825 deletions(-) create mode 100644 example/test/widget_test.dart delete mode 100644 lib/src/async_button_state.freezed.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index dc0af4b..93d93f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,112 +1,147 @@ -## [3.0.0+1] - 2022-02-13 +# [3.0.0+1] - 2022-02-13 + - Fix `Undefined name 'optionalTypeArgs'.` Also adds back the hard dep on freezed_annotation. ## [3.0.0] - 2022-02-13 + - Added notification functionality. The error variant now passes through the error and stacktrace which would be needed for a notification to be useful. This is a breaking change as the error widget now takes an error and stacktrace as arguments. -## [2.3.0+2] - 2023-02-13 +## [2.3.0+3] - 2023-02-13 + - Not pushed -## [2.3.0+1] - 2022-05-24 +## [2.3.0+2] - 2022-05-24 + - Added back freezed_annotation as a hard dep. ## [2.3.0+1] - 2022-05-24 + - Fixed onError never being called when an error occurs - Credit @jonjomckay ## [2.3.0] - 2022-05-24 + - Removed freezed dependency and added new callbacks @mergehez - Upgrade to freezed 2 (excluding user now) @quantosapplications @esenmx ## [2.2.0+1] - 2022-01-28 + Ignore .vscode, update versions and re-export button state. Credit @esenmx ## [2.2.0] - 2022-01-07 + Got rid of hook version as it was complicating a simple package and likely discouraging possible contributors. ## [2.1.4] - 2021-09-28 + Fix manual button state changes. Credit to @iliser ## [2.1.3+9] - 2021-09-28 + Upgraded deps ## [2.1.3+8] - 2021-09-28 + Upgraded deps ## [2.1.3+7] - 2021-09-08 + Fixed github actions ## [2.1.3+6] - 2021-08-31 + Trying to fix pub stuff ## [2.1.3+5] - 2021-08-27 + Trying to fix pub stuff ## [2.1.3+4] - 2021-08-27 + Fix home page ## [2.1.3+3] - 2021-08-12 + Have proper types exported ## [2.1.3+2] - 2021-08-12 + Fix possibility of nested async button builders conflicting with each other due to matching keyed subtrees. In order to avoid this situation, the parent key of the async_button_builder is used in the creation of sub widgets. ## [2.1.3+1] - 2021-06-25 + Was not using proper sucessDuration when setting timeouts (regression) ## [2.1.3] - 2021-06-18 + Tests and builds against stable. flutter_lints now used in place of pedantic ## [2.1.2+1] - 2021-06-12 + Fixes analysis errors so I stop getting annoying emails ## [2.1.2] - 2021-05-24 + Errors from onpressed will throw with orignal call stack ## [2.1.1+2] - 2021-04-14 + Makes onpressed nullable similar to other button's behaviour ## [2.1.1+1] - 2021-04-14 + Add documentation on how to handle timeouts ## [2.1.1] - 2021-04-14 + ValueKeys are now no longer required in order to differentiate children ## [2.1.0] - 2021-02-12 + Remove null-safety prefix as it's now in stable ## [2.0.9-nullsafety.0] - 2021-02-12 + Trying to bump version again to go over stable ## [2.0.8-nullsafety.0] - 2021-02-12 + Trying to bump version again to go over stable ## [2.0.7-nullsafety.8] - 2021-02-12 + Republish so current nullsafe becomes main. My mistake ## [2.0.2-nullsafety.7] - 2021-02-12 + Added a typedef in place of inline type on function. Added doc to `builder` field ## [2.0.2-nullsafety.6] - 2021-02-09 + Renamed Union classes to match that of factory constructor name (Should not be breaking). ## [2.0.2-nullsafety.5] - 2021-02-01 + Removed example integration test ## [2.0.2-nullsafety.4] - 2021-01-26 + Adds tests and test coverage. Adds on dispose to cancel timer. ## [2.0.2-nullsafety.3] - 2021-01-25 + Removes dangling controller and cleans up main code up a bit ## [2.0.2-nullsafety.2] - 2021-01-25 + Fixes wrong image path ## [2.0.1-nullsafety.2] - 2021-01-25 -Renames fields to better match standards of other buttons. + +Renames fields to better match standards of other buttons. ## [2.0.0-dev.1] - 2021-01-25 -Breaking. Replaces the fourth argument with a sealed union that better allows for directly managing states, removes unnecessary arguments such as padding, adds transition builders for custom transitions. Currently still includes AnimatedSize. +Breaking. Replaces the fourth argument with a sealed union that better allows for directly managing states, removes unnecessary arguments such as padding, adds transition builders for custom transitions. Currently still includes `AnimatedSize`. ## [1.0.0-nullsafety.0] - 2021-01-12 @@ -114,7 +149,7 @@ Breaking. Adds a fourth argument of loading to the builder. This removes the val ## [0.1.0-nullsafety.0] - 2021-01-12 -Replaces the bool type of isLoading for a ValueNotifier. +Replaces the bool type of isLoading for a `ValueNotifier`. ## [0.0.1-nullsafety.2] - 2021-01-12 @@ -126,4 +161,4 @@ Adds docs to parameters and removes use of unnecessary undescore internal variab ## [0.0.1-nullsafety.0] - 2021-01-11 -Holds basic builder AsyncButtonBuilder. No tests yet. NNBD is supported +Holds basic builder AsyncButtonBuilder. No tests yet. `NNBD` is supported diff --git a/README.md b/README.md index 92322d4..43aea9e 100644 --- a/README.md +++ b/README.md @@ -123,7 +123,6 @@ To disable the notifications, you can pass `false` to `notifications`. `async_button_builder` even works for custom buttons. You can define your own widgets for loading, error, and completion as well as define the transitions between them. This example is a little verbose but shows some of what's possible. - ```dart AsyncButtonBuilder( child: Padding( @@ -189,4 +188,4 @@ AsyncButtonBuilder(

-Issues and PR's welcome \ No newline at end of file +Issues and PR's welcome diff --git a/analysis_options.yaml b/analysis_options.yaml index 8e99406..38e6292 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,8 +1 @@ include: package:lint/package.yaml - -analyzer: - exclude: - - "**/*.freezed.dart" - -linter: - rules: diff --git a/example/.metadata b/example/.metadata index 135a1da..5c982c8 100644 --- a/example/.metadata +++ b/example/.metadata @@ -4,7 +4,7 @@ # This file should be version controlled and should not be manually edited. version: - revision: "5dcb86f68f239346676ceb1ed1ea385bd215fba1" + revision: "ea121f8859e4b13e47a8f845e4586164519588bc" channel: "stable" project_type: app @@ -13,11 +13,11 @@ project_type: app migration: platforms: - platform: root - create_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1 - base_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1 - - platform: macos - create_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1 - base_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1 + create_revision: ea121f8859e4b13e47a8f845e4586164519588bc + base_revision: ea121f8859e4b13e47a8f845e4586164519588bc + - platform: ios + create_revision: ea121f8859e4b13e47a8f845e4586164519588bc + base_revision: ea121f8859e4b13e47a8f845e4586164519588bc # User provided section diff --git a/example/lib/main.dart b/example/lib/main.dart index ba3870b..6210ff0 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -48,10 +48,7 @@ class _MyHomePageState extends State { await Future.delayed(const Duration(seconds: 1)); }, builder: (context, child, callback, _) { - return TextButton( - onPressed: callback, - child: child, - ); + return TextButton(onPressed: callback, child: child); }, ), const Divider(), @@ -62,10 +59,7 @@ class _MyHomePageState extends State { await Future.delayed(const Duration(seconds: 1)); }, builder: (context, child, callback, _) { - return ElevatedButton( - onPressed: callback, - child: child, - ); + return ElevatedButton(onPressed: callback, child: child); }, ), const Divider(), @@ -74,32 +68,15 @@ class _MyHomePageState extends State { loadingWidget: const Text('Loading...'), onPressed: () async { await Future.delayed(const Duration(seconds: 1)); - throw 'yikes'; - - // If you want to add a timeout, use something similar to - // - // try { - // await Future.delayed(Duration(seconds: 1)) - // .timeout(Duration(milliseconds: 500)); - // } on TimeoutException catch (_) { - // // Show a popup or something - // rethrow; - // } on Exception catch (_) { - // // Show a dialog or something - // rethrow; - // } - // - // We rethrow so that async_button_builder can handle the error - // state }, builder: (context, child, callback, buttonState) { - final buttonColor = buttonState.when( - idle: () => Colors.yellow[200], - loading: () => Colors.grey, - success: () => Colors.orangeAccent, - error: (_) => Colors.orange, - ); + final buttonColor = switch (buttonState) { + AsyncButtonStateIdle() => Colors.yellow[200], + AsyncButtonStateLoading() => Colors.grey, + AsyncButtonStateSuccess() => Colors.orangeAccent, + AsyncButtonStateError() => Colors.orange, + }; return OutlinedButton( onPressed: callback, @@ -128,10 +105,7 @@ class _MyHomePageState extends State { ), successWidget: const Padding( padding: EdgeInsets.all(4.0), - child: Icon( - Icons.check, - color: Colors.purpleAccent, - ), + child: Icon(Icons.check, color: Colors.purpleAccent), ), onPressed: () async { await Future.delayed(const Duration(seconds: 2)); @@ -148,29 +122,20 @@ class _MyHomePageState extends State { }, builder: (context, child, callback, state) { return Material( - color: state.maybeWhen( - success: () => Colors.purple[100], - orElse: () => Colors.blue, - ), + color: switch (state) { + AsyncButtonStateSuccess() => Colors.purple[100], + _ => Colors.blue, + }, // This prevents the loading indicator showing below the // button clipBehavior: Clip.hardEdge, shape: const StadiumBorder(), - child: InkWell( - onTap: callback, - child: child, - ), + child: InkWell(onTap: callback, child: child), ); }, child: const Padding( - padding: EdgeInsets.symmetric( - horizontal: 16.0, - vertical: 8.0, - ), - child: Text( - 'Click Me', - style: TextStyle(color: Colors.white), - ), + padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), + child: Text('Click Me', style: TextStyle(color: Colors.white)), ), ), const Divider(), diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 50af5dc..cf7e795 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -4,7 +4,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev version: 1.0.0+1 environment: - sdk: ">=2.17.0 <3.0.0" + sdk: ">=3.7.0 <4.0.0" dependencies: flutter: diff --git a/example/test/widget_test.dart b/example/test/widget_test.dart new file mode 100644 index 0000000..092d222 --- /dev/null +++ b/example/test/widget_test.dart @@ -0,0 +1,30 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility in the flutter_test package. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'package:example/main.dart'; + +void main() { + testWidgets('Counter increments smoke test', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget(const MyApp()); + + // Verify that our counter starts at 0. + expect(find.text('0'), findsOneWidget); + expect(find.text('1'), findsNothing); + + // Tap the '+' icon and trigger a frame. + await tester.tap(find.byIcon(Icons.add)); + await tester.pump(); + + // Verify that our counter has incremented. + expect(find.text('0'), findsNothing); + expect(find.text('1'), findsOneWidget); + }); +} diff --git a/lib/src/async_button_builder.dart b/lib/src/async_button_builder.dart index 3876035..d2562e1 100644 --- a/lib/src/async_button_builder.dart +++ b/lib/src/async_button_builder.dart @@ -274,9 +274,9 @@ class AsyncButtonBuilderState extends State @override Widget build(BuildContext context) { final theme = Theme.of(context); - var successWidget = widget.successWidget ?? + Widget successWidget = widget.successWidget ?? Icon(Icons.check, color: theme.colorScheme.secondary); - var errorWidget = + Widget errorWidget = widget.errorWidget ?? Icon(Icons.error, color: theme.colorScheme.error); if (widget.successPadding != null) { successWidget = Padding( @@ -292,100 +292,97 @@ class AsyncButtonBuilderState extends State ); } - final switcher = AnimatedSwitcher( + Widget content = AnimatedSwitcher( // TODO: This duration is same as size's duration. That's okay right? duration: widget.duration, reverseDuration: widget.reverseDuration, - switchInCurve: _buttonState.when( - idle: () => widget.idleSwitchInCurve, - loading: () => widget.loadingSwitchInCurve, - success: () => widget.successSwitchInCurve, - error: (_) => widget.errorSwitchInCurve, - ), - switchOutCurve: _buttonState.when( - idle: () => widget.idleSwitchOutCurve, - loading: () => widget.loadingSwitchOutCurve, - success: () => widget.successSwitchOutCurve, - error: (_) => widget.errorSwitchOutCurve, - ), - transitionBuilder: _buttonState.when( - idle: () => widget.idleTransitionBuilder, - loading: () => widget.loadingTransitionBuilder, - success: () => widget.successTransitionBuilder, - error: (_) => widget.errorTransitionBuilder, - ), + switchInCurve: switch (_buttonState) { + AsyncButtonStateIdle() => widget.idleSwitchInCurve, + AsyncButtonStateLoading() => widget.loadingSwitchInCurve, + AsyncButtonStateSuccess() => widget.successSwitchInCurve, + AsyncButtonStateError() => widget.errorSwitchInCurve, + }, + switchOutCurve: switch (_buttonState) { + AsyncButtonStateIdle() => widget.idleSwitchOutCurve, + AsyncButtonStateLoading() => widget.loadingSwitchOutCurve, + AsyncButtonStateSuccess() => widget.successSwitchOutCurve, + AsyncButtonStateError() => widget.errorSwitchOutCurve, + }, + transitionBuilder: switch (_buttonState) { + AsyncButtonStateIdle() => widget.idleTransitionBuilder, + AsyncButtonStateLoading() => widget.loadingTransitionBuilder, + AsyncButtonStateSuccess() => widget.successTransitionBuilder, + AsyncButtonStateError() => widget.errorTransitionBuilder, + }, child: KeyedSubtree( key: _switchKey, - child: _buttonState.when( - idle: () => widget.child, - loading: () => widget.loadingWidget, - success: () => successWidget, - error: (_) => errorWidget, - ), + child: switch (_buttonState) { + AsyncButtonStateIdle() => widget.child, + AsyncButtonStateLoading() => widget.loadingWidget, + AsyncButtonStateSuccess() => successWidget, + AsyncButtonStateError() => errorWidget, + }, ), ); - return widget.builder( - context, + if (widget.animateSize) { // TODO: I really just wanted an AnimatedSwitcher and the default // transitionBuilder to be a SizedTransition but it was impossible // to figure out how to reproduce the exact behaviour of AnimatedSize - widget.animateSize - ? AnimatedSize( - duration: widget.duration, - reverseDuration: widget.reverseDuration, - alignment: widget.sizeAlignment, - clipBehavior: widget.sizeClipBehavior, - curve: widget.sizeCurve, - child: switcher, - ) - : switcher, - pressCallback, - _buttonState, - ); + content = AnimatedSize( + duration: widget.duration, + reverseDuration: widget.reverseDuration, + alignment: widget.sizeAlignment, + clipBehavior: widget.sizeClipBehavior, + curve: widget.sizeCurve, + child: content, + ); + } + + return widget.builder(context, content, pressCallback, _buttonState); } AsyncCallback? get pressCallback { if (widget.disabled || widget.onPressed == null) { return null; } - return _buttonState.maybeWhen( - orElse: () => null, - idle: () => () { - final completer = Completer(); - - // I might not want to set buttonState if we're being - // driven by widget.buttonState... - _setButtonState(const AsyncButtonState.loading()); - timer?.cancel(); - - widget.onPressed!.call().then((_) { - completer.complete(); - - if (mounted) { - if (widget.showSuccess) { - _setButtonState(const AsyncButtonState.success()); - _setTimer(widget.successDuration, widget.onSuccess); - } else { - _setButtonState(const AsyncButtonState.idle()); + return switch (_buttonState) { + AsyncButtonStateIdle() => () { + final completer = Completer(); + + // I might not want to set buttonState if we're being + // driven by widget.buttonState... + _setButtonState(const AsyncButtonState.loading()); + timer?.cancel(); + + widget.onPressed!().then((_) { + completer.complete(); + + if (mounted) { + if (widget.showSuccess) { + _setButtonState(const AsyncButtonState.success()); + _setTimer(widget.successDuration, widget.onSuccess); + } else { + _setButtonState(const AsyncButtonState.idle()); + } } - } - }).onError((Object error, StackTrace stackTrace) { - completer.completeError(error, stackTrace); - - if (mounted) { - if (widget.showError) { - _setButtonState(AsyncButtonState.error(error)); - _setTimer(widget.errorDuration, widget.onError); - } else { - _setButtonState(const AsyncButtonState.idle()); + }).onError((Object error, StackTrace stackTrace) { + completer.completeError(error, stackTrace); + + if (mounted) { + if (widget.showError) { + _setButtonState(AsyncButtonState.error(error)); + _setTimer(widget.errorDuration, widget.onError); + } else { + _setButtonState(const AsyncButtonState.idle()); + } } - } - }); + }); - return completer.future; - }, - ); + return completer.future; + }, + _ => null, + }; } void _setButtonState(AsyncButtonState buttonState) { diff --git a/lib/src/async_button_state.dart b/lib/src/async_button_state.dart index 4d3999a..a4aa2a7 100644 --- a/lib/src/async_button_state.dart +++ b/lib/src/async_button_state.dart @@ -1,7 +1,3 @@ -import 'package:freezed_annotation/freezed_annotation.dart'; - -part 'async_button_state.freezed.dart'; - /// This union class represents the state of the button in either a [Idling], /// [AsyncButtonStateLoading], [AsyncButtonStateSuccess] or [AsyncButtonStateError] state. /// This can be considered a enum with extra utilities for ease of use. @@ -30,10 +26,49 @@ part 'async_button_state.freezed.dart'; /// ); /// ``` /// {@end-tool} -@freezed -class AsyncButtonState with _$AsyncButtonState { +sealed class AsyncButtonState { + const AsyncButtonState(); + const factory AsyncButtonState.idle() = AsyncButtonStateIdle; const factory AsyncButtonState.loading() = AsyncButtonStateLoading; const factory AsyncButtonState.success() = AsyncButtonStateSuccess; const factory AsyncButtonState.error(Object error) = AsyncButtonStateError; } + +class AsyncButtonStateIdle extends AsyncButtonState { + const AsyncButtonStateIdle(); + + @override + String toString() { + return 'AsyncButtonState.idle()'; + } +} + +class AsyncButtonStateLoading extends AsyncButtonState { + const AsyncButtonStateLoading(); + + @override + String toString() { + return 'AsyncButtonState.loading()'; + } +} + +class AsyncButtonStateSuccess extends AsyncButtonState { + const AsyncButtonStateSuccess(); + + @override + String toString() { + return 'AsyncButtonState.success()'; + } +} + +class AsyncButtonStateError extends AsyncButtonState { + const AsyncButtonStateError(this.error); + + final Object error; + + @override + String toString() { + return 'AsyncButtonState.error(error: $error)'; + } +} diff --git a/lib/src/async_button_state.freezed.dart b/lib/src/async_button_state.freezed.dart deleted file mode 100644 index ee47379..0000000 --- a/lib/src/async_button_state.freezed.dart +++ /dev/null @@ -1,582 +0,0 @@ -// coverage:ignore-file -// GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: type=lint -// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark - -part of 'async_button_state.dart'; - -// ************************************************************************** -// FreezedGenerator -// ************************************************************************** - -T _$identity(T value) => value; - -final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); - -/// @nodoc -mixin _$AsyncButtonState { - @optionalTypeArgs - TResult when({ - required TResult Function() idle, - required TResult Function() loading, - required TResult Function() success, - required TResult Function(Object error) error, - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult? whenOrNull({ - TResult? Function()? idle, - TResult? Function()? loading, - TResult? Function()? success, - TResult? Function(Object error)? error, - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult maybeWhen({ - TResult Function()? idle, - TResult Function()? loading, - TResult Function()? success, - TResult Function(Object error)? error, - required TResult orElse(), - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult map({ - required TResult Function(AsyncButtonStateIdle value) idle, - required TResult Function(AsyncButtonStateLoading value) loading, - required TResult Function(AsyncButtonStateSuccess value) success, - required TResult Function(AsyncButtonStateError value) error, - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult? mapOrNull({ - TResult? Function(AsyncButtonStateIdle value)? idle, - TResult? Function(AsyncButtonStateLoading value)? loading, - TResult? Function(AsyncButtonStateSuccess value)? success, - TResult? Function(AsyncButtonStateError value)? error, - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult maybeMap({ - TResult Function(AsyncButtonStateIdle value)? idle, - TResult Function(AsyncButtonStateLoading value)? loading, - TResult Function(AsyncButtonStateSuccess value)? success, - TResult Function(AsyncButtonStateError value)? error, - required TResult orElse(), - }) => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $AsyncButtonStateCopyWith<$Res> { - factory $AsyncButtonStateCopyWith( - AsyncButtonState value, $Res Function(AsyncButtonState) then) = - _$AsyncButtonStateCopyWithImpl<$Res, AsyncButtonState>; -} - -/// @nodoc -class _$AsyncButtonStateCopyWithImpl<$Res, $Val extends AsyncButtonState> - implements $AsyncButtonStateCopyWith<$Res> { - _$AsyncButtonStateCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; -} - -/// @nodoc -abstract class _$$AsyncButtonStateIdleImplCopyWith<$Res> { - factory _$$AsyncButtonStateIdleImplCopyWith(_$AsyncButtonStateIdleImpl value, - $Res Function(_$AsyncButtonStateIdleImpl) then) = - __$$AsyncButtonStateIdleImplCopyWithImpl<$Res>; -} - -/// @nodoc -class __$$AsyncButtonStateIdleImplCopyWithImpl<$Res> - extends _$AsyncButtonStateCopyWithImpl<$Res, _$AsyncButtonStateIdleImpl> - implements _$$AsyncButtonStateIdleImplCopyWith<$Res> { - __$$AsyncButtonStateIdleImplCopyWithImpl(_$AsyncButtonStateIdleImpl _value, - $Res Function(_$AsyncButtonStateIdleImpl) _then) - : super(_value, _then); -} - -/// @nodoc - -class _$AsyncButtonStateIdleImpl implements AsyncButtonStateIdle { - const _$AsyncButtonStateIdleImpl(); - - @override - String toString() { - return 'AsyncButtonState.idle()'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$AsyncButtonStateIdleImpl); - } - - @override - int get hashCode => runtimeType.hashCode; - - @override - @optionalTypeArgs - TResult when({ - required TResult Function() idle, - required TResult Function() loading, - required TResult Function() success, - required TResult Function(Object error) error, - }) { - return idle(); - } - - @override - @optionalTypeArgs - TResult? whenOrNull({ - TResult? Function()? idle, - TResult? Function()? loading, - TResult? Function()? success, - TResult? Function(Object error)? error, - }) { - return idle?.call(); - } - - @override - @optionalTypeArgs - TResult maybeWhen({ - TResult Function()? idle, - TResult Function()? loading, - TResult Function()? success, - TResult Function(Object error)? error, - required TResult orElse(), - }) { - if (idle != null) { - return idle(); - } - return orElse(); - } - - @override - @optionalTypeArgs - TResult map({ - required TResult Function(AsyncButtonStateIdle value) idle, - required TResult Function(AsyncButtonStateLoading value) loading, - required TResult Function(AsyncButtonStateSuccess value) success, - required TResult Function(AsyncButtonStateError value) error, - }) { - return idle(this); - } - - @override - @optionalTypeArgs - TResult? mapOrNull({ - TResult? Function(AsyncButtonStateIdle value)? idle, - TResult? Function(AsyncButtonStateLoading value)? loading, - TResult? Function(AsyncButtonStateSuccess value)? success, - TResult? Function(AsyncButtonStateError value)? error, - }) { - return idle?.call(this); - } - - @override - @optionalTypeArgs - TResult maybeMap({ - TResult Function(AsyncButtonStateIdle value)? idle, - TResult Function(AsyncButtonStateLoading value)? loading, - TResult Function(AsyncButtonStateSuccess value)? success, - TResult Function(AsyncButtonStateError value)? error, - required TResult orElse(), - }) { - if (idle != null) { - return idle(this); - } - return orElse(); - } -} - -abstract class AsyncButtonStateIdle implements AsyncButtonState { - const factory AsyncButtonStateIdle() = _$AsyncButtonStateIdleImpl; -} - -/// @nodoc -abstract class _$$AsyncButtonStateLoadingImplCopyWith<$Res> { - factory _$$AsyncButtonStateLoadingImplCopyWith( - _$AsyncButtonStateLoadingImpl value, - $Res Function(_$AsyncButtonStateLoadingImpl) then) = - __$$AsyncButtonStateLoadingImplCopyWithImpl<$Res>; -} - -/// @nodoc -class __$$AsyncButtonStateLoadingImplCopyWithImpl<$Res> - extends _$AsyncButtonStateCopyWithImpl<$Res, _$AsyncButtonStateLoadingImpl> - implements _$$AsyncButtonStateLoadingImplCopyWith<$Res> { - __$$AsyncButtonStateLoadingImplCopyWithImpl( - _$AsyncButtonStateLoadingImpl _value, - $Res Function(_$AsyncButtonStateLoadingImpl) _then) - : super(_value, _then); -} - -/// @nodoc - -class _$AsyncButtonStateLoadingImpl implements AsyncButtonStateLoading { - const _$AsyncButtonStateLoadingImpl(); - - @override - String toString() { - return 'AsyncButtonState.loading()'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$AsyncButtonStateLoadingImpl); - } - - @override - int get hashCode => runtimeType.hashCode; - - @override - @optionalTypeArgs - TResult when({ - required TResult Function() idle, - required TResult Function() loading, - required TResult Function() success, - required TResult Function(Object error) error, - }) { - return loading(); - } - - @override - @optionalTypeArgs - TResult? whenOrNull({ - TResult? Function()? idle, - TResult? Function()? loading, - TResult? Function()? success, - TResult? Function(Object error)? error, - }) { - return loading?.call(); - } - - @override - @optionalTypeArgs - TResult maybeWhen({ - TResult Function()? idle, - TResult Function()? loading, - TResult Function()? success, - TResult Function(Object error)? error, - required TResult orElse(), - }) { - if (loading != null) { - return loading(); - } - return orElse(); - } - - @override - @optionalTypeArgs - TResult map({ - required TResult Function(AsyncButtonStateIdle value) idle, - required TResult Function(AsyncButtonStateLoading value) loading, - required TResult Function(AsyncButtonStateSuccess value) success, - required TResult Function(AsyncButtonStateError value) error, - }) { - return loading(this); - } - - @override - @optionalTypeArgs - TResult? mapOrNull({ - TResult? Function(AsyncButtonStateIdle value)? idle, - TResult? Function(AsyncButtonStateLoading value)? loading, - TResult? Function(AsyncButtonStateSuccess value)? success, - TResult? Function(AsyncButtonStateError value)? error, - }) { - return loading?.call(this); - } - - @override - @optionalTypeArgs - TResult maybeMap({ - TResult Function(AsyncButtonStateIdle value)? idle, - TResult Function(AsyncButtonStateLoading value)? loading, - TResult Function(AsyncButtonStateSuccess value)? success, - TResult Function(AsyncButtonStateError value)? error, - required TResult orElse(), - }) { - if (loading != null) { - return loading(this); - } - return orElse(); - } -} - -abstract class AsyncButtonStateLoading implements AsyncButtonState { - const factory AsyncButtonStateLoading() = _$AsyncButtonStateLoadingImpl; -} - -/// @nodoc -abstract class _$$AsyncButtonStateSuccessImplCopyWith<$Res> { - factory _$$AsyncButtonStateSuccessImplCopyWith( - _$AsyncButtonStateSuccessImpl value, - $Res Function(_$AsyncButtonStateSuccessImpl) then) = - __$$AsyncButtonStateSuccessImplCopyWithImpl<$Res>; -} - -/// @nodoc -class __$$AsyncButtonStateSuccessImplCopyWithImpl<$Res> - extends _$AsyncButtonStateCopyWithImpl<$Res, _$AsyncButtonStateSuccessImpl> - implements _$$AsyncButtonStateSuccessImplCopyWith<$Res> { - __$$AsyncButtonStateSuccessImplCopyWithImpl( - _$AsyncButtonStateSuccessImpl _value, - $Res Function(_$AsyncButtonStateSuccessImpl) _then) - : super(_value, _then); -} - -/// @nodoc - -class _$AsyncButtonStateSuccessImpl implements AsyncButtonStateSuccess { - const _$AsyncButtonStateSuccessImpl(); - - @override - String toString() { - return 'AsyncButtonState.success()'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$AsyncButtonStateSuccessImpl); - } - - @override - int get hashCode => runtimeType.hashCode; - - @override - @optionalTypeArgs - TResult when({ - required TResult Function() idle, - required TResult Function() loading, - required TResult Function() success, - required TResult Function(Object error) error, - }) { - return success(); - } - - @override - @optionalTypeArgs - TResult? whenOrNull({ - TResult? Function()? idle, - TResult? Function()? loading, - TResult? Function()? success, - TResult? Function(Object error)? error, - }) { - return success?.call(); - } - - @override - @optionalTypeArgs - TResult maybeWhen({ - TResult Function()? idle, - TResult Function()? loading, - TResult Function()? success, - TResult Function(Object error)? error, - required TResult orElse(), - }) { - if (success != null) { - return success(); - } - return orElse(); - } - - @override - @optionalTypeArgs - TResult map({ - required TResult Function(AsyncButtonStateIdle value) idle, - required TResult Function(AsyncButtonStateLoading value) loading, - required TResult Function(AsyncButtonStateSuccess value) success, - required TResult Function(AsyncButtonStateError value) error, - }) { - return success(this); - } - - @override - @optionalTypeArgs - TResult? mapOrNull({ - TResult? Function(AsyncButtonStateIdle value)? idle, - TResult? Function(AsyncButtonStateLoading value)? loading, - TResult? Function(AsyncButtonStateSuccess value)? success, - TResult? Function(AsyncButtonStateError value)? error, - }) { - return success?.call(this); - } - - @override - @optionalTypeArgs - TResult maybeMap({ - TResult Function(AsyncButtonStateIdle value)? idle, - TResult Function(AsyncButtonStateLoading value)? loading, - TResult Function(AsyncButtonStateSuccess value)? success, - TResult Function(AsyncButtonStateError value)? error, - required TResult orElse(), - }) { - if (success != null) { - return success(this); - } - return orElse(); - } -} - -abstract class AsyncButtonStateSuccess implements AsyncButtonState { - const factory AsyncButtonStateSuccess() = _$AsyncButtonStateSuccessImpl; -} - -/// @nodoc -abstract class _$$AsyncButtonStateErrorImplCopyWith<$Res> { - factory _$$AsyncButtonStateErrorImplCopyWith( - _$AsyncButtonStateErrorImpl value, - $Res Function(_$AsyncButtonStateErrorImpl) then) = - __$$AsyncButtonStateErrorImplCopyWithImpl<$Res>; - @useResult - $Res call({Object error}); -} - -/// @nodoc -class __$$AsyncButtonStateErrorImplCopyWithImpl<$Res> - extends _$AsyncButtonStateCopyWithImpl<$Res, _$AsyncButtonStateErrorImpl> - implements _$$AsyncButtonStateErrorImplCopyWith<$Res> { - __$$AsyncButtonStateErrorImplCopyWithImpl(_$AsyncButtonStateErrorImpl _value, - $Res Function(_$AsyncButtonStateErrorImpl) _then) - : super(_value, _then); - - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? error = null, - }) { - return _then(_$AsyncButtonStateErrorImpl( - null == error ? _value.error : error, - )); - } -} - -/// @nodoc - -class _$AsyncButtonStateErrorImpl implements AsyncButtonStateError { - const _$AsyncButtonStateErrorImpl(this.error); - - @override - final Object error; - - @override - String toString() { - return 'AsyncButtonState.error(error: $error)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$AsyncButtonStateErrorImpl && - const DeepCollectionEquality().equals(other.error, error)); - } - - @override - int get hashCode => - Object.hash(runtimeType, const DeepCollectionEquality().hash(error)); - - @JsonKey(ignore: true) - @override - @pragma('vm:prefer-inline') - _$$AsyncButtonStateErrorImplCopyWith<_$AsyncButtonStateErrorImpl> - get copyWith => __$$AsyncButtonStateErrorImplCopyWithImpl< - _$AsyncButtonStateErrorImpl>(this, _$identity); - - @override - @optionalTypeArgs - TResult when({ - required TResult Function() idle, - required TResult Function() loading, - required TResult Function() success, - required TResult Function(Object error) error, - }) { - return error(this.error); - } - - @override - @optionalTypeArgs - TResult? whenOrNull({ - TResult? Function()? idle, - TResult? Function()? loading, - TResult? Function()? success, - TResult? Function(Object error)? error, - }) { - return error?.call(this.error); - } - - @override - @optionalTypeArgs - TResult maybeWhen({ - TResult Function()? idle, - TResult Function()? loading, - TResult Function()? success, - TResult Function(Object error)? error, - required TResult orElse(), - }) { - if (error != null) { - return error(this.error); - } - return orElse(); - } - - @override - @optionalTypeArgs - TResult map({ - required TResult Function(AsyncButtonStateIdle value) idle, - required TResult Function(AsyncButtonStateLoading value) loading, - required TResult Function(AsyncButtonStateSuccess value) success, - required TResult Function(AsyncButtonStateError value) error, - }) { - return error(this); - } - - @override - @optionalTypeArgs - TResult? mapOrNull({ - TResult? Function(AsyncButtonStateIdle value)? idle, - TResult? Function(AsyncButtonStateLoading value)? loading, - TResult? Function(AsyncButtonStateSuccess value)? success, - TResult? Function(AsyncButtonStateError value)? error, - }) { - return error?.call(this); - } - - @override - @optionalTypeArgs - TResult maybeMap({ - TResult Function(AsyncButtonStateIdle value)? idle, - TResult Function(AsyncButtonStateLoading value)? loading, - TResult Function(AsyncButtonStateSuccess value)? success, - TResult Function(AsyncButtonStateError value)? error, - required TResult orElse(), - }) { - if (error != null) { - return error(this); - } - return orElse(); - } -} - -abstract class AsyncButtonStateError implements AsyncButtonState { - const factory AsyncButtonStateError(final Object error) = - _$AsyncButtonStateErrorImpl; - - Object get error; - @JsonKey(ignore: true) - _$$AsyncButtonStateErrorImplCopyWith<_$AsyncButtonStateErrorImpl> - get copyWith => throw _privateConstructorUsedError; -} diff --git a/pubspec.yaml b/pubspec.yaml index a030073..71c15f1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -5,20 +5,14 @@ version: 3.0.0+1 homepage: https://github.com/Nolence/async_button/tree/main/packages/async_button_builder environment: - sdk: ">=2.17.0 <4.0.0" - flutter: ">=1.17.0" + sdk: ">=3.0.0 <4.0.0" + flutter: ">=2.0.0" dependencies: flutter: sdk: flutter - freezed_annotation: ^2.2.0 dev_dependencies: - build_runner: ^2.3.3 - flutter_lints: ^2.0.1 flutter_test: sdk: flutter - freezed: ^2.3.2 - lint: ^2.3.0 - -flutter: null + lint: ^2.8.0 diff --git a/test/async_button_builder_test.dart b/test/async_button_builder_test.dart index fc4098f..3b8b7af 100644 --- a/test/async_button_builder_test.dart +++ b/test/async_button_builder_test.dart @@ -4,7 +4,7 @@ import 'package:flutter_test/flutter_test.dart'; void main() { testWidgets('displays child text', (tester) async { - final textButton = MaterialApp( + await tester.pumpWidget(MaterialApp( home: AsyncButtonBuilder( onPressed: () async { await Future.delayed(const Duration(seconds: 1)); @@ -14,15 +14,12 @@ void main() { }, child: const Text('click me'), ), - ); - - await tester.pumpWidget(textButton); - + )); expect(find.text('click me'), findsOneWidget); }); testWidgets('shows loading widget', (tester) async { - final textButton = MaterialApp( + await tester.pumpWidget(MaterialApp( home: AsyncButtonBuilder( loadingWidget: const Text('loading'), onPressed: () async { @@ -33,9 +30,7 @@ void main() { }, child: const Text('click me'), ), - ); - - await tester.pumpWidget(textButton); + )); await tester.tap(find.byType(TextButton)); @@ -50,84 +45,75 @@ void main() { }); testWidgets('shows error widget', (tester) async { - final textButton = MaterialApp( + await tester.pumpWidget(MaterialApp( home: AsyncButtonBuilder( errorWidget: const Text('error'), - onPressed: () async { - throw ArgumentError(); - }, + onPressed: () async => throw Exception(), builder: (context, child, callback, state) { return TextButton(onPressed: callback, child: child); }, child: const Text('click me'), ), - ); + )); - await tester.pumpWidget(textButton); - final button = - find.byType(TextButton).evaluate().first.widget as TextButton; - - expect( - () => button.onPressed!.call(), - throwsA(isA()), - ); - - await tester.pump(const Duration(milliseconds: 200)); + await tester.tap(find.byType(TextButton)); + await tester.pump(const Duration(milliseconds: 100)); expect(find.text('error'), findsOneWidget); }); - testWidgets('error notification bubbles up', (tester) async { - var idleCount = 0; - var loadingCount = 0; - var successCount = 0; - var errorCount = 0; - - final textButton = MaterialApp( - home: NotificationListener( - onNotification: (notification) { - notification.buttonState.when( - idle: () => idleCount += 1, - loading: () => loadingCount += 1, - success: () => successCount += 1, - error: (_) => errorCount += 1, - ); - return true; - }, - child: AsyncButtonBuilder( - errorDuration: const Duration(milliseconds: 100), - errorWidget: const Text('error'), - notifications: true, - onPressed: () async { - throw UnimplementedError(); - }, - builder: (context, child, callback, state) { - return TextButton(onPressed: callback, child: child); - }, - child: const Text('click me'), - ), - ), - ); - - await tester.pumpWidget(textButton); - final button = - find.byType(TextButton).evaluate().first.widget as TextButton; - - expect( - button.onPressed!.call, - throwsA(isA()), - ); - - await tester.pump(const Duration(milliseconds: 200)); - - expect(errorCount, 1); - expect(idleCount, 1); - expect(loadingCount, 1); - expect(successCount, 0); - }); + // testWidgets('error notification bubbles up', (tester) async { + // var idleCount = 0; + // var loadingCount = 0; + // var successCount = 0; + // var errorCount = 0; + + // await tester.pumpWidget(MaterialApp( + // home: NotificationListener( + // onNotification: (notification) { + // tester.printToConsole(notification.buttonState.toString()); + // switch (notification.buttonState) { + // case AsyncButtonStateIdle(): + // idleCount += 1; + // case AsyncButtonStateLoading(): + // loadingCount += 1; + // case AsyncButtonStateSuccess(): + // successCount += 1; + // case AsyncButtonStateError(): + // errorCount += 1; + // } + // return true; + // }, + // child: AsyncButtonBuilder( + // errorDuration: const Duration(milliseconds: 100), + // errorWidget: const Text('error'), + // notifications: true, + // onPressed: () async => throw Exception(), + // builder: (context, child, callback, state) { + // return TextButton(onPressed: callback, child: child); + // }, + // child: const Text('click me'), + // ), + // ), + // )); + // final button = + // find.byType(TextButton).evaluate().first.widget as TextButton; + + // expect( + // button.onPressed!.call, + // throwsA(isA()), + // ); + + // await tester.pump(const Duration(milliseconds: 200)); + + // expect(errorCount, 1); + // expect(idleCount, 1); + // expect(loadingCount, 1); + // expect(successCount, 0); + // }); testWidgets('Returns to child widget', (tester) async { - final textButton = MaterialApp( + await tester.pumpWidget(MaterialApp( home: AsyncButtonBuilder( loadingWidget: const Text('loading'), onPressed: () async { @@ -138,16 +124,12 @@ void main() { }, child: const Text('click me'), ), - ); - - await tester.pumpWidget(textButton); + )); await tester.tap(find.byType(TextButton)); - await tester.pump(const Duration(milliseconds: 1000)); expect(find.text('loading'), findsNothing); - expect(find.text('click me'), findsOneWidget); }); From ae134a8b3e8b13dc55efdce433b806205706e6c2 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 25 May 2026 14:02:23 +0000 Subject: [PATCH 098/176] feat!: rename to material_async_button, add 1.0.0 redesign Renames the package from async_button_builder to material_async_button and ships a redesigned, theme-aware 1.0.0 API. * Five Material wrappers (Elevated/Filled/Outlined/Text/Icon) with full named-constructor parity (.icon, .tonal, .tonalIcon, .filled, etc.). * MaterialAsyncButtonTheme ThemeExtension replaces the need for a project- wide wrapper widget; .material() factory ships an opinionated baseline. * AsyncButtonController (ValueListenable) for external state control with trigger/reset/invalidate/markSuccess. * GlobalKey exposes the same operations on the low-level builder. * New params: confirmBeforePress, errorBuilder, onStateChanged, cooldownDuration, hapticOn, announceSemantics, rethrowErrors. * Unopinionated defaults: zero success/error display duration, no widget swap on success/error unless requested. Bug fixes from v3: * Timer race in success/error display path (B1). * AsyncButtonState now implements ==/hashCode (B3). * ValueKey instead of UniqueKey() per state change (B4). * StackTrace carried through error state (B7). * Switched to dart format in CI (B8). * Example test fixed (B9). * Lints upgraded to flutter_lints ^5.0.0 (B10). Other: * Dart ^3.10.0 / Flutter >=3.40.0 minimum. * Drops AsyncButtonNotification and the notifications flag. * Test suite expanded to cover state, controller, theme, builder, all five wrappers, regression cases for the timer race and controller swap. * Adds claude_code_skill/flutter-material-async-button/SKILL.md. https://claude.ai/code/session_01C5g1NbxvkgKbv7daca8Kvv --- .github/workflows/dart.yaml | 39 +- .metadata | 4 +- .pubignore | 5 +- CHANGELOG.md | 212 ++---- README.md | 322 +++++----- analysis_options.yaml | 19 +- .../flutter-material-async-button/SKILL.md | 118 ++++ coverage/lcov.info | 107 ---- example/lib/main.dart | 275 ++++---- example/pubspec.yaml | 13 +- example/test/widget_test.dart | 32 +- lib/async_button_builder.dart | 3 - lib/material_async_button.dart | 16 + lib/src/async_button_builder.dart | 603 ++++++++---------- lib/src/async_button_controller.dart | 164 +++++ lib/src/async_button_notification.dart | 8 - lib/src/async_button_state.dart | 87 +-- lib/src/buttons/elevated_async_button.dart | 174 +++++ lib/src/buttons/filled_async_button.dart | 279 ++++++++ lib/src/buttons/icon_async_button.dart | 366 +++++++++++ lib/src/buttons/outlined_async_button.dart | 169 +++++ lib/src/buttons/text_async_button.dart | 169 +++++ lib/src/material_async_button_theme.dart | 304 +++++++++ pubspec.yaml | 35 +- test/async_button_builder_test.dart | 473 +++++++++----- test/async_button_controller_test.dart | 286 +++++++++ test/async_button_state_test.dart | 76 +++ test/elevated_async_button_test.dart | 76 +++ test/filled_async_button_test.dart | 54 ++ test/icon_async_button_test.dart | 51 ++ test/material_async_button_theme_test.dart | 102 +++ test/outlined_async_button_test.dart | 44 ++ test/text_async_button_test.dart | 44 ++ 33 files changed, 3582 insertions(+), 1147 deletions(-) create mode 100644 claude_code_skill/flutter-material-async-button/SKILL.md delete mode 100644 coverage/lcov.info delete mode 100644 lib/async_button_builder.dart create mode 100644 lib/material_async_button.dart create mode 100644 lib/src/async_button_controller.dart delete mode 100644 lib/src/async_button_notification.dart create mode 100644 lib/src/buttons/elevated_async_button.dart create mode 100644 lib/src/buttons/filled_async_button.dart create mode 100644 lib/src/buttons/icon_async_button.dart create mode 100644 lib/src/buttons/outlined_async_button.dart create mode 100644 lib/src/buttons/text_async_button.dart create mode 100644 lib/src/material_async_button_theme.dart create mode 100644 test/async_button_controller_test.dart create mode 100644 test/async_button_state_test.dart create mode 100644 test/elevated_async_button_test.dart create mode 100644 test/filled_async_button_test.dart create mode 100644 test/icon_async_button_test.dart create mode 100644 test/material_async_button_theme_test.dart create mode 100644 test/outlined_async_button_test.dart create mode 100644 test/text_async_button_test.dart diff --git a/.github/workflows/dart.yaml b/.github/workflows/dart.yaml index 336348f..25d7068 100644 --- a/.github/workflows/dart.yaml +++ b/.github/workflows/dart.yaml @@ -1,31 +1,44 @@ -name: Build +name: CI on: push: + branches: [main] pull_request: - schedule: - # runs the CI everyday at 10AM - - cron: "0 10 * * *" jobs: - setup: + build: timeout-minutes: 15 runs-on: ubuntu-latest + strategy: + matrix: + channel: [stable, beta] + fail-fast: false steps: - - name: "Git Checkout" - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - - name: "Install Flutter" - uses: subosito/flutter-action@v2 + - uses: subosito/flutter-action@v2 + with: + channel: ${{ matrix.channel }} - name: Install dependencies run: flutter pub get - - name: Check format - run: flutter format --set-exit-if-changed . + - name: Check formatting + run: dart format --set-exit-if-changed . - name: Analyze run: flutter analyze - - name: Run tests - run: flutter test + - name: Test with coverage + run: flutter test --coverage + + - name: Upload coverage + if: matrix.channel == 'stable' + uses: actions/upload-artifact@v4 + with: + name: coverage + path: coverage/lcov.info + + - name: Validate publish (dry run) + if: matrix.channel == 'stable' + run: flutter pub publish --dry-run diff --git a/.metadata b/.metadata index 13a1909..3a40cbc 100644 --- a/.metadata +++ b/.metadata @@ -4,7 +4,7 @@ # This file should be version controlled and should not be manually edited. version: - revision: 63062a64432cce03315d6b5196fda7912866eb37 - channel: dev + revision: stable + channel: stable project_type: package diff --git a/.pubignore b/.pubignore index fa3282a..963e315 100644 --- a/.pubignore +++ b/.pubignore @@ -1,4 +1,5 @@ .idea/ .vscode/ -screenshots/ -build/ \ No newline at end of file +build/ +coverage/ +claude_code_skill/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 93d93f6..d9665e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,164 +1,48 @@ -# [3.0.0+1] - 2022-02-13 - -- Fix `Undefined name 'optionalTypeArgs'.` Also adds back the hard dep on freezed_annotation. - -## [3.0.0] - 2022-02-13 - -- Added notification functionality. The error variant now passes through the error and stacktrace which would be needed for a notification to be useful. This is a breaking change as the error widget now takes an error and stacktrace as arguments. - -## [2.3.0+3] - 2023-02-13 - -- Not pushed - -## [2.3.0+2] - 2022-05-24 - -- Added back freezed_annotation as a hard dep. - -## [2.3.0+1] - 2022-05-24 - -- Fixed onError never being called when an error occurs - Credit @jonjomckay - -## [2.3.0] - 2022-05-24 - -- Removed freezed dependency and added new callbacks @mergehez -- Upgrade to freezed 2 (excluding user now) @quantosapplications @esenmx - -## [2.2.0+1] - 2022-01-28 - -Ignore .vscode, update versions and re-export button state. Credit @esenmx - -## [2.2.0] - 2022-01-07 - -Got rid of hook version as it was complicating a simple package and likely discouraging possible contributors. - -## [2.1.4] - 2021-09-28 - -Fix manual button state changes. Credit to @iliser - -## [2.1.3+9] - 2021-09-28 - -Upgraded deps - -## [2.1.3+8] - 2021-09-28 - -Upgraded deps - -## [2.1.3+7] - 2021-09-08 - -Fixed github actions - -## [2.1.3+6] - 2021-08-31 - -Trying to fix pub stuff - -## [2.1.3+5] - 2021-08-27 - -Trying to fix pub stuff - -## [2.1.3+4] - 2021-08-27 - -Fix home page - -## [2.1.3+3] - 2021-08-12 - -Have proper types exported - -## [2.1.3+2] - 2021-08-12 - -Fix possibility of nested async button builders conflicting with each other due to matching keyed subtrees. In order to avoid this situation, the parent key of the async_button_builder is used in the creation of sub widgets. - -## [2.1.3+1] - 2021-06-25 - -Was not using proper sucessDuration when setting timeouts (regression) - -## [2.1.3] - 2021-06-18 - -Tests and builds against stable. flutter_lints now used in place of pedantic - -## [2.1.2+1] - 2021-06-12 - -Fixes analysis errors so I stop getting annoying emails - -## [2.1.2] - 2021-05-24 - -Errors from onpressed will throw with orignal call stack - -## [2.1.1+2] - 2021-04-14 - -Makes onpressed nullable similar to other button's behaviour - -## [2.1.1+1] - 2021-04-14 - -Add documentation on how to handle timeouts - -## [2.1.1] - 2021-04-14 - -ValueKeys are now no longer required in order to differentiate children - -## [2.1.0] - 2021-02-12 - -Remove null-safety prefix as it's now in stable - -## [2.0.9-nullsafety.0] - 2021-02-12 - -Trying to bump version again to go over stable - -## [2.0.8-nullsafety.0] - 2021-02-12 - -Trying to bump version again to go over stable - -## [2.0.7-nullsafety.8] - 2021-02-12 - -Republish so current nullsafe becomes main. My mistake - -## [2.0.2-nullsafety.7] - 2021-02-12 - -Added a typedef in place of inline type on function. Added doc to `builder` field - -## [2.0.2-nullsafety.6] - 2021-02-09 - -Renamed Union classes to match that of factory constructor name (Should not be breaking). - -## [2.0.2-nullsafety.5] - 2021-02-01 - -Removed example integration test - -## [2.0.2-nullsafety.4] - 2021-01-26 - -Adds tests and test coverage. Adds on dispose to cancel timer. - -## [2.0.2-nullsafety.3] - 2021-01-25 - -Removes dangling controller and cleans up main code up a bit - -## [2.0.2-nullsafety.2] - 2021-01-25 - -Fixes wrong image path - -## [2.0.1-nullsafety.2] - 2021-01-25 - -Renames fields to better match standards of other buttons. - -## [2.0.0-dev.1] - 2021-01-25 - -Breaking. Replaces the fourth argument with a sealed union that better allows for directly managing states, removes unnecessary arguments such as padding, adds transition builders for custom transitions. Currently still includes `AnimatedSize`. - -## [1.0.0-nullsafety.0] - 2021-01-12 - -Breaking. Adds a fourth argument of loading to the builder. This removes the value notifier that was difficult or confusing to manage in actual usage in my use cases. The argument isLoading is now a `bool`. This also adds a `disabled` field in order to set that on construction. - -## [0.1.0-nullsafety.0] - 2021-01-12 - -Replaces the bool type of isLoading for a `ValueNotifier`. - -## [0.0.1-nullsafety.2] - 2021-01-12 - -Adds analysis options and removes unnecessary typedef - -## [0.0.1-nullsafety.1] - 2021-01-12 - -Adds docs to parameters and removes use of unnecessary undescore internal variables. - -## [0.0.1-nullsafety.0] - 2021-01-11 - -Holds basic builder AsyncButtonBuilder. No tests yet. `NNBD` is supported +# 1.0.0 + +Initial release. Renamed from `async_button_builder` to `material_async_button` +with a redesigned, theme-aware API. + +### Added + +- Material wrapper widgets: `ElevatedAsyncButton`, `FilledAsyncButton` + (`+.tonal/.icon/.tonalIcon`), `OutlinedAsyncButton`, `TextAsyncButton`, + `IconAsyncButton` (`+.filled/.filledTonal/.outlined`). Each mirrors its + Material counterpart constructor-for-constructor. +- `MaterialAsyncButtonTheme` — a `ThemeExtension` for app-wide defaults + (loading/success/error widgets, durations, curves, haptics, semantics). + Includes `MaterialAsyncButtonTheme.material()` opinionated factory. +- `AsyncButtonController` — `ValueListenable` for + external state control. Methods: `trigger()`, `reset()`, + `invalidate(error)`, `markSuccess()`. +- `confirmBeforePress`, `errorBuilder`, `onStateChanged`, `cooldownDuration`, + `hapticOn`, `announceSemantics`, `rethrowErrors` parameters. +- `AsyncButtonBuilderState.trigger()`/`reset()`/`invalidate()`/`markSuccess()` + for `GlobalKey`-driven control (e.g. form keyboard "Done"). + +### Changed + +- `AsyncButtonState.error` now carries an optional `StackTrace`. +- `onSuccess` / `onError` fire on **entry** to their state, not after the + display duration elapses. +- Defaults are unopinionated: zero `successDisplayDuration`, + zero `errorDisplayDuration`, no success/error widget swap unless asked. + Use `MaterialAsyncButtonTheme.material()` for the v3-style baseline. +- Minimum Dart SDK is `^3.10.0`; minimum Flutter is `>=3.40.0`. + +### Fixed + +- Stale-timer race: timers from a previous success/error cycle no longer + overwrite a subsequent state set externally. +- `AsyncButtonState` variants now implement `==`/`hashCode`. +- `KeyedSubtree` switch key is `ValueKey(stateType)` instead of a + fresh `UniqueKey()` per state change. + +### Removed + +- `AsyncButtonNotification` and the `notifications: bool` flag. Use + `AsyncButtonController` or `onStateChanged` instead. +- `errorPadding` / `successPadding` convenience props — wrap your widgets + in `Padding` explicitly. +- Per-state transition curves and per-state transition builders. Use a + single `transitionBuilder` and `switchCurve`, override only when needed. diff --git a/README.md b/README.md index 43aea9e..bff6d60 100644 --- a/README.md +++ b/README.md @@ -1,191 +1,207 @@ -# async_button_builder +# material_async_button -AsyncButtonBuilder offers a simple way to extend any type of button with an asynchronous aspect. It allows adding loading, disabled, errored and completed states (with fluid animation between each) on top of buttons that perform asynchronous tasks. +Drop-in async wrappers for Flutter Material buttons. Adds **loading**, +**success**, and **error** states to `ElevatedButton`, `FilledButton`, +`OutlinedButton`, `TextButton`, and `IconButton` — without forcing you to +build a project-wide wrapper widget. -## Getting Started +```dart +ElevatedAsyncButton( + onPressed: () async => await api.save(), + child: const Text('Save'), +) +``` + +That's it. The button shows a spinner while `save()` runs and re-enables when +it returns or throws. -Include the package: +## Install ```yaml - async_button_builder: +dependencies: + material_async_button: ^1.0.0 ``` -Wrap the builder around a button, passing the onPressed and child element to builder instead of the button directly. These two are the only required fields. +Requires Dart `^3.10.0` and Flutter `>=3.40.0`. + +## Why + +Most apps end up writing their own `DefaultAsyncButton` wrapper to share +loading-spinner widgets, durations, and transition curves across screens. +This package gives you that wrapper as a [`ThemeExtension`][th]: ```dart -AsyncButtonBuilder( - child: Text('Click Me'), - onPressed: () async { - await Future.delayed(Duration(seconds: 1)); - }, - builder: (context, child, callback, _) { - return TextButton( - child: child, - onPressed: callback, - ); - }, -), +MaterialApp( + theme: ThemeData( + extensions: [MaterialAsyncButtonTheme.material()], + ), +) ``` -

- -

+Configure once, every `*AsyncButton` in the app picks it up. Override per +button when you need to. + +[th]: https://api.flutter.dev/flutter/material/ThemeExtension-class.html + +## Material wrappers + +| Material | Async counterpart | Variants | +| ---------------- | ---------------------- | --------------------------------------------------- | +| `ElevatedButton` | `ElevatedAsyncButton` | `.icon` | +| `FilledButton` | `FilledAsyncButton` | `.tonal`, `.icon`, `.tonalIcon` | +| `OutlinedButton` | `OutlinedAsyncButton` | `.icon` | +| `TextButton` | `TextAsyncButton` | `.icon` | +| `IconButton` | `IconAsyncButton` | `.filled`, `.filledTonal`, `.outlined` | + +Every Material constructor is mirrored. All Material parameters (`style`, +`focusNode`, `autofocus`, `clipBehavior`, `statesController`, etc.) are +forwarded verbatim. -The fourth value in the builder allows you listen to the loading state. This can be used to conditionally style the button. This package depends `freezed` in order to create a sealed union to better handle the possible states. +## Theming -> NOTE (Breaking change): As of v3.0.0, error now takes the error and stack trace as arguments. +`MaterialAsyncButtonTheme` is a `ThemeExtension`. Resolution order for any +field is **per-widget value → theme value → built-in fallback**. ```dart -AsyncButtonBuilder( - child: Text('Click Me'), - loadingWidget: Text('Loading...'), - onPressed: () async { - await Future.delayed(Duration(seconds: 1)); - - // See the examples file for a way to handle timeouts - throw 'yikes'; - }, - builder: (context, child, callback, buttonState) { - final buttonColor = buttonState.when( - idle: () => Colors.yellow[200], - loading: () => Colors.grey, - success: () => Colors.orangeAccent, - error: (err, stack) => Colors.orange, - ); - - return OutlinedButton( - child: child, - onPressed: callback, - style: OutlinedButton.styleFrom( - primary: Colors.black, - backgroundColor: buttonColor, - ), - ); - }, -), +ThemeData( + extensions: [ + MaterialAsyncButtonTheme( + switchDuration: const Duration(milliseconds: 200), + successDisplayDuration: const Duration(milliseconds: 800), + errorDisplayDuration: const Duration(milliseconds: 800), + successChild: const Icon(Icons.check), + errorChild: const Icon(Icons.error_outline), + animateSize: true, + hapticOn: HapticOn.both, + announceSemantics: true, + ), + ], +) ``` -

- -

- -You can also drive the state of the button yourself using the `buttonState` field: +Or grab the opinionated baseline: ```dart -AsyncButtonBuilder( - buttonState: ButtonState.completing(), - // ... -), +ThemeData(extensions: [MaterialAsyncButtonTheme.material()]) ``` -## Notifications +## Unopinionated defaults + +Without any theme set: + +| State | Default UI | +| ---------- | ------------------------------------------- | +| idle | your `child` | +| loading | 16×16 `CircularProgressIndicator` | +| success | your `child` (no swap), display duration 0 | +| error | your `child` (no swap), display duration 0 | -As of v3.0.0, you can now wrap a higher level parent to handle notifications that come from buttons. Why not use something like `runZonedGuarded`? Notification bubbling handles not only the error but the state of the button. If you'd like, for example, to trigger a circular spinner in the center of the app notifiying the user that something is happening, you can do so by listening to the `AsyncButtonNotification` and then using the `buttonState` to determine what to do. +Most apps want a flash of green check / red error. Either set the theme +extension once, or pass `successChild` / `errorChild` per button. -It might also be a good idea to separate the errors that come from button presses and those that are not. An error wants to see why a button press silently failed but might not need to know why a background fetch failed. +## External control + +### `AsyncButtonController` — recommended + +The Material wrappers expose state through an `AsyncButtonController`. This is +the pattern to use for **form keyboard "Done"**, parent-owned state, +cross-widget reactions, and tests. ```dart -MaterialApp( - home: NotificationListener( - onNotification: (notification) { - notification.buttonState.when( - idle: () => // nothing -> you could use a maybeWhen as well - loading: () => // show circular loading widget? - success: () => // show success snackbar? - error: (_, __) => // show error snackbar? - ); - - // Tells the notification to stop bubbling - return true; - }, - // This async button can be nested arbitrarily deep* - child: AsyncButtonBuilder( - duration: duration, - errorDuration: const Duration(milliseconds: 100), - errorWidget: const Text('error'), - onPressed: () async { - throw ArgumentError(); - }, - builder: (context, child, callback, state) { - return TextButton(onPressed: callback, child: child); - }, - child: const Text('click me'), - ), - ), +final controller = AsyncButtonController(); // dispose like any ChangeNotifier + +TextField( + textInputAction: TextInputAction.done, + onSubmitted: (_) => controller.trigger(), +) +ElevatedAsyncButton( + controller: controller, + onPressed: submit, + child: const Text('Submit'), ) -// See NotificationListener for more information +// any time: +controller.trigger(); // run onPressed from outside +controller.invalidate('server rejected'); // force error +controller.markSuccess(); // force success +controller.reset(); // back to idle ``` -To disable the notifications, you can pass `false` to `notifications`. +### `GlobalKey` — for the low-level builder only + +If you're using `AsyncButtonBuilder` directly (custom non-Material button), +the same operations are exposed on its `State`: + +```dart +final key = GlobalKey(); + +AsyncButtonBuilder( + key: key, + onPressed: submit, + child: const Text('Submit'), + builder: (c, child, cb, _) => MyButton(onTap: cb, child: child), +) + +key.currentState?.trigger(); +``` -## Customization +The controller is a `ValueListenable`. Pipe it to a +`ValueListenableBuilder` for cross-widget UI reactions. Dispose like any +`ChangeNotifier`. -`async_button_builder` even works for custom buttons. You can define your own widgets for loading, error, and completion as well as define the transitions between them. This example is a little verbose but shows some of what's possible. +## State pattern matching ```dart AsyncButtonBuilder( - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 16.0, - vertical: 8.0, - ), - child: Text( - 'Click Me', - style: TextStyle(color: Colors.white), - ), - ), - loadingWidget: Padding( - padding: const EdgeInsets.all(8.0), - child: SizedBox( - height: 16.0, - width: 16.0, - child: CircularProgressIndicator( - valueColor: AlwaysStoppedAnimation(Colors.white), - ), - ), - ), - successWidget: Padding( - padding: const EdgeInsets.all(4.0), - child: Icon( - Icons.check, - color: Colors.purpleAccent, - ), + onPressed: doWork, + child: const Text('Go'), + builder: (context, child, callback, state) => MyButton( + onTap: callback, + color: switch (state) { + AsyncButtonStateIdle() => Colors.blue, + AsyncButtonStateLoading() => Colors.grey, + AsyncButtonStateSuccess() => Colors.green, + AsyncButtonStateError() => Colors.red, + }, + child: child, ), - onPressed: () async { - await Future.delayed(Duration(seconds: 2)); - }, - loadingSwitchInCurve: Curves.bounceInOut, - loadingTransitionBuilder: (child, animation) { - return SlideTransition( - position: Tween( - begin: Offset(0, 1.0), - end: Offset(0, 0), - ).animate(animation), - child: child, - ); - }, - builder: (context, child, callback, state) { - return Material( - color: state.maybeWhen( - success: () => Colors.purple[100], - orElse: () => Colors.blue, - ), - // This prevents the loading indicator showing below the - // button - clipBehavior: Clip.hardEdge, - shape: StadiumBorder(), - child: InkWell( - child: child, - onTap: callback, - ), - ); - }, -), +) ``` -

- -

+`AsyncButtonBuilder` is the low-level escape hatch. Use it when none of the +Material wrappers fit. + +## Features + +- `confirmBeforePress` — gate `onPressed` behind a confirmation `Future` +- `errorBuilder` — render the thrown error with full context +- `onSuccess` / `onError` / `onStateChanged` — fire-and-forget callbacks +- `cooldownDuration` — disable the button briefly after success to prevent + double-submit +- `hapticOn` — light haptic on success/error +- `announceSemantics` — `SemanticsService.announce` for screen readers +- `rethrowErrors` — rethrow from `controller.trigger()` so callers can + `try/catch` while the UI also shows the error + +## Migrating from `async_button_builder` + +This package is a renamed continuation of `async_button_builder`. The +low-level `AsyncButtonBuilder` and `AsyncButtonState` types are preserved +(`error` now carries a `StackTrace`). Most v3 code keeps working after: + +1. `dependencies: async_button_builder: ^3.0.0` → `material_async_button: ^1.0.0` +2. `import 'package:async_button_builder/async_button_builder.dart'` + → `import 'package:material_async_button/material_async_button.dart'` + +The opinionated `notifications` flag and `AsyncButtonNotification` are gone; +use `AsyncButtonController` or `onStateChanged` instead. + +## Claude Code skill + +A skill that teaches Claude Code to use this package idiomatically ships at +`claude_code_skill/flutter-material-async-button/SKILL.md`. Copy it into +`.claude/skills/` in your project. + +## License -Issues and PR's welcome +MIT diff --git a/analysis_options.yaml b/analysis_options.yaml index 38e6292..8ba7847 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1 +1,18 @@ -include: package:lint/package.yaml +include: package:flutter_lints/flutter.yaml + +analyzer: + language: + strict-casts: true + strict-inference: true + strict-raw-types: true + +linter: + rules: + - always_declare_return_types + - prefer_const_constructors + - prefer_const_constructors_in_immutables + - prefer_const_declarations + - prefer_const_literals_to_create_immutables + - prefer_final_locals + - sort_constructors_first + - use_super_parameters diff --git a/claude_code_skill/flutter-material-async-button/SKILL.md b/claude_code_skill/flutter-material-async-button/SKILL.md new file mode 100644 index 0000000..4d6cc40 --- /dev/null +++ b/claude_code_skill/flutter-material-async-button/SKILL.md @@ -0,0 +1,118 @@ +--- +name: flutter-material-async-button +description: Use this skill when working in a Flutter project that depends on + the material_async_button package, or when the user wants to add + loading/success/error UI to a Material button (ElevatedButton, FilledButton, + OutlinedButton, TextButton, IconButton) whose onPressed is async. Triggers on + "async button", "loading button", or any handler the user writes as + `() async {}` and passes to a Material button. +--- + +# material_async_button + +## Default mapping + +Replace the Material button with its async counterpart whenever `onPressed` +is async. The wrapper handles loading state, the post-press display, and +disables the button while running. + +| Material | Use | Variants | +| ---------------- | ---------------------- | ------------------------------------------------- | +| `ElevatedButton` | `ElevatedAsyncButton` | `.icon` | +| `FilledButton` | `FilledAsyncButton` | `.tonal` `.icon` `.tonalIcon` | +| `OutlinedButton` | `OutlinedAsyncButton` | `.icon` | +| `TextButton` | `TextAsyncButton` | `.icon` | +| `IconButton` | `IconAsyncButton` | `.filled` `.filledTonal` `.outlined` | + +## Minimal use + +```dart +ElevatedAsyncButton( + onPressed: () async => api.save(), + child: const Text('Save'), +) +``` + +## Theming — do this once + +```dart +ThemeData(extensions: [MaterialAsyncButtonTheme.material()]) +``` + +Or, with overrides: + +```dart +ThemeData(extensions: [ + MaterialAsyncButtonTheme( + successChild: const Icon(Icons.check), + errorChild: const Icon(Icons.error_outline), + switchDuration: const Duration(milliseconds: 200), + successDisplayDuration:const Duration(milliseconds: 800), + errorDisplayDuration: const Duration(milliseconds: 800), + animateSize: true, + hapticOn: HapticOn.both, + ), +]) +``` + +Per-button props always win over the theme. + +## External control — `AsyncButtonController` + +Use this for form "Done" keyboard action, parent-owned state, and +cross-widget reactions: + +```dart +final controller = AsyncButtonController(); // dispose like any ChangeNotifier + +TextField( + textInputAction: TextInputAction.done, + onSubmitted: (_) => controller.trigger(), +) +ElevatedAsyncButton( + controller: controller, + onPressed: submit, + child: const Text('Submit'), +) + +controller.trigger(); // run onPressed from outside +controller.invalidate('server rejected'); // force error from outside +controller.markSuccess(); // force success from outside +controller.reset(); // back to idle +``` + +It's a `ValueListenable` — pipe into +`ValueListenableBuilder` for cross-widget reactions. + +`GlobalKey` exposes the same methods, but is only +useful with the low-level `AsyncButtonBuilder` (the Material wrappers are +`StatelessWidget`). + +## Custom buttons — `AsyncButtonBuilder` + +Only when no Material wrapper fits: + +```dart +AsyncButtonBuilder( + onPressed: doWork, + child: const Text('Go'), + builder: (context, child, callback, state) => MyButton( + onTap: callback, + color: switch (state) { + AsyncButtonStateLoading() => Colors.grey, + AsyncButtonStateError() => Colors.red, + _ => Colors.indigo, + }, + child: child, + ), +) +``` + +## Don't + +- Don't wrap an already-async-aware button (no nested `…AsyncButton`s). +- Don't pass `disabled: true` to "pause" — pass `null` to `onPressed` instead. +- Don't call `setState` in `onSuccess` / `onError` for state the button + already reflects. +- Don't create a project-wide wrapper widget for default loading/success + spinners — that's exactly what `MaterialAsyncButtonTheme` is for. diff --git a/coverage/lcov.info b/coverage/lcov.info deleted file mode 100644 index 422cb7f..0000000 --- a/coverage/lcov.info +++ /dev/null @@ -1,107 +0,0 @@ -SF:lib/src/async_button_builder.dart -DA:104,1 -DA:138,1 -DA:143,1 -DA:144,1 -DA:152,1 -DA:154,3 -DA:155,1 -DA:158,0 -DA:160,0 -DA:161,0 -DA:162,0 -DA:166,0 -DA:169,1 -DA:171,2 -DA:173,1 -DA:176,1 -DA:178,1 -DA:179,2 -DA:180,2 -DA:181,2 -DA:187,2 -DA:188,1 -DA:190,2 -DA:192,2 -DA:193,1 -DA:195,1 -DA:197,2 -DA:198,2 -DA:205,0 -DA:206,0 -DA:210,0 -DA:217,0 -DA:223,1 -DA:225,2 -DA:226,2 -DA:227,2 -DA:228,3 -DA:229,3 -DA:230,3 -DA:231,3 -DA:233,2 -DA:234,3 -DA:235,3 -DA:236,3 -DA:237,3 -DA:239,2 -DA:240,3 -DA:241,3 -DA:242,3 -DA:243,3 -DA:245,2 -DA:246,2 -DA:247,2 -DA:248,2 -DA:250,2 -DA:251,2 -DA:254,2 -DA:255,2 -DA:258,2 -DA:259,2 -DA:265,2 -DA:270,2 -DA:271,1 -DA:272,2 -DA:273,2 -DA:274,2 -DA:275,2 -DA:276,2 -DA:280,2 -DA:284,2 -DA:285,2 -DA:286,1 -DA:289,2 -DA:290,1 -DA:293,1 -DA:295,2 -DA:296,1 -DA:298,1 -DA:299,2 -DA:300,2 -DA:301,1 -DA:304,3 -DA:306,0 -DA:307,0 -DA:311,2 -DA:312,1 -DA:314,1 -DA:315,2 -DA:316,2 -DA:317,1 -DA:320,3 -DA:322,0 -DA:323,0 -DA:329,1 -DA:331,1 -DA:333,1 -DA:337,1 -DA:338,2 -DA:340,1 -DA:341,2 -DA:343,1 -DA:344,2 -DA:345,1 -LF:103 -LH:90 -end_of_record diff --git a/example/lib/main.dart b/example/lib/main.dart index 6210ff0..f7a6208 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,147 +1,182 @@ -import 'package:async_button_builder/async_button_builder.dart'; import 'package:flutter/material.dart'; +import 'package:material_async_button/material_async_button.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { - const MyApp({Key? key}) : super(key: key); + const MyApp({super.key}); @override - Widget build(BuildContext context) { - return MaterialApp( - title: 'Flutter Demo', - theme: ThemeData.dark(), - home: const MyHomePage(), - ); - } + Widget build(BuildContext context) => MaterialApp( + title: 'material_async_button demo', + theme: ThemeData( + colorSchemeSeed: Colors.indigo, + useMaterial3: true, + extensions: [MaterialAsyncButtonTheme.material()], + ), + home: const HomePage(), + ); } -class MyHomePage extends StatefulWidget { - const MyHomePage({Key? key}) : super(key: key); +class HomePage extends StatefulWidget { + const HomePage({super.key}); @override - State createState() => _MyHomePageState(); + State createState() => _HomePageState(); } -class _MyHomePageState extends State { - final textButtonState = GlobalKey(); +class _HomePageState extends State { + final _formController = AsyncButtonController(); + final _externalController = AsyncButtonController(); + final _textController = TextEditingController(); @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar(title: const Text('Async Buttons')), - floatingActionButton: FloatingActionButton.extended( - onPressed: textButtonState.currentState?.pressCallback, - label: const Text('You can trigger first button from here'), - ), - body: SizedBox.expand( - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - const Divider(), - const Text('Text Button:'), - AsyncButtonBuilder( - key: textButtonState, - child: const Text('Click Me'), - onPressed: () async { - await Future.delayed(const Duration(seconds: 1)); - }, - builder: (context, child, callback, _) { - return TextButton(onPressed: callback, child: child); - }, - ), - const Divider(), - const Text('Elevated Button:'), - AsyncButtonBuilder( - child: const Text('Click Me'), - onPressed: () async { - await Future.delayed(const Duration(seconds: 1)); - }, - builder: (context, child, callback, _) { - return ElevatedButton(onPressed: callback, child: child); - }, - ), - const Divider(), - const Text('Custom Outlined Button (Error):'), - AsyncButtonBuilder( - loadingWidget: const Text('Loading...'), - onPressed: () async { - await Future.delayed(const Duration(seconds: 1)); - throw 'yikes'; - }, - builder: (context, child, callback, buttonState) { - final buttonColor = switch (buttonState) { - AsyncButtonStateIdle() => Colors.yellow[200], - AsyncButtonStateLoading() => Colors.grey, - AsyncButtonStateSuccess() => Colors.orangeAccent, - AsyncButtonStateError() => Colors.orange, - }; + void dispose() { + _formController.dispose(); + _externalController.dispose(); + _textController.dispose(); + super.dispose(); + } - return OutlinedButton( - onPressed: callback, - style: OutlinedButton.styleFrom( - foregroundColor: Colors.black, - backgroundColor: buttonColor, + Future _simulateWork({bool fail = false}) async { + await Future.delayed(const Duration(milliseconds: 800)); + if (fail) throw StateError('simulated failure'); + } + + @override + Widget build(BuildContext context) => Scaffold( + appBar: AppBar(title: const Text('material_async_button')), + body: SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + const _SectionLabel('Material wrappers'), + ElevatedAsyncButton( + onPressed: _simulateWork, + child: const Text('ElevatedAsyncButton'), + ), + const SizedBox(height: 8), + ElevatedAsyncButton.icon( + onPressed: _simulateWork, + icon: const Icon(Icons.send), + label: const Text('ElevatedAsyncButton.icon'), + ), + const SizedBox(height: 8), + FilledAsyncButton( + onPressed: _simulateWork, + child: const Text('FilledAsyncButton'), + ), + const SizedBox(height: 8), + FilledAsyncButton.tonal( + onPressed: _simulateWork, + child: const Text('FilledAsyncButton.tonal'), + ), + const SizedBox(height: 8), + OutlinedAsyncButton( + onPressed: () => _simulateWork(fail: true), + child: const Text('OutlinedAsyncButton (fails)'), + ), + const SizedBox(height: 8), + TextAsyncButton( + onPressed: _simulateWork, + child: const Text('TextAsyncButton'), + ), + const SizedBox(height: 8), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + IconAsyncButton( + onPressed: _simulateWork, + icon: const Icon(Icons.refresh)), + IconAsyncButton.filled( + onPressed: _simulateWork, icon: const Icon(Icons.add)), + IconAsyncButton.filledTonal( + onPressed: _simulateWork, icon: const Icon(Icons.edit)), + IconAsyncButton.outlined( + onPressed: _simulateWork, + icon: const Icon(Icons.delete)), + ], + ), + const Divider(height: 32), + const _SectionLabel('Form "Done" → controller.trigger()'), + TextField( + controller: _textController, + textInputAction: TextInputAction.done, + decoration: const InputDecoration(labelText: 'Name'), + onSubmitted: (_) => _formController.trigger(), + ), + const SizedBox(height: 8), + ElevatedAsyncButton( + controller: _formController, + onPressed: () => _simulateWork(), + child: const Text('Submit'), + ), + const Divider(height: 32), + const _SectionLabel('External controller'), + ElevatedAsyncButton( + controller: _externalController, + onPressed: _simulateWork, + child: const Text('Submit (driven by controller)'), + ), + const SizedBox(height: 8), + Wrap( + spacing: 8, + children: [ + OutlinedButton( + onPressed: () => _externalController.trigger(), + child: const Text('trigger()'), ), - child: child, - ); - }, - child: const Text('Click Me'), - ), - const Divider(), - const Text('Custom Material Button:'), - const SizedBox(height: 6.0), - AsyncButtonBuilder( - loadingWidget: const Padding( - padding: EdgeInsets.all(8.0), - child: SizedBox( - height: 16.0, - width: 16.0, - child: CircularProgressIndicator( - valueColor: AlwaysStoppedAnimation(Colors.white), + OutlinedButton( + onPressed: () => + _externalController.invalidate('server rejected'), + child: const Text('invalidate()'), ), - ), - ), - successWidget: const Padding( - padding: EdgeInsets.all(4.0), - child: Icon(Icons.check, color: Colors.purpleAccent), + OutlinedButton( + onPressed: _externalController.markSuccess, + child: const Text('markSuccess()'), + ), + OutlinedButton( + onPressed: _externalController.reset, + child: const Text('reset()'), + ), + ], ), - onPressed: () async { - await Future.delayed(const Duration(seconds: 2)); - }, - loadingSwitchInCurve: Curves.bounceInOut, - loadingTransitionBuilder: (child, animation) { - return SlideTransition( - position: Tween( - begin: const Offset(0, 1.0), - end: const Offset(0, 0), - ).animate(animation), - child: child, - ); - }, - builder: (context, child, callback, state) { - return Material( + const Divider(height: 32), + const _SectionLabel('Custom button via AsyncButtonBuilder'), + AsyncButtonBuilder( + onPressed: _simulateWork, + animateSize: true, + child: const Padding( + padding: + EdgeInsets.symmetric(horizontal: 16, vertical: 12), + child: + Text('Custom', style: TextStyle(color: Colors.white)), + ), + builder: (ctx, child, callback, state) => Material( color: switch (state) { - AsyncButtonStateSuccess() => Colors.purple[100], - _ => Colors.blue, + AsyncButtonStateSuccess() => Colors.green, + AsyncButtonStateError() => Colors.red, + _ => Colors.indigo, }, - // This prevents the loading indicator showing below the - // button clipBehavior: Clip.hardEdge, shape: const StadiumBorder(), child: InkWell(onTap: callback, child: child), - ); - }, - child: const Padding( - padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), - child: Text('Click Me', style: TextStyle(color: Colors.white)), + ), ), - ), - const Divider(), - ], + ], + ), ), - ), - ); - } + ); +} + +class _SectionLabel extends StatelessWidget { + const _SectionLabel(this.text); + final String text; + + @override + Widget build(BuildContext context) => Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: Text(text, style: Theme.of(context).textTheme.titleMedium), + ); } diff --git a/example/pubspec.yaml b/example/pubspec.yaml index cf7e795..7fbb51b 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,23 +1,22 @@ name: example -description: A new Flutter project. -publish_to: "none" # Remove this line if you wish to publish to pub.dev +description: Showcase for material_async_button. +publish_to: "none" version: 1.0.0+1 environment: - sdk: ">=3.7.0 <4.0.0" + sdk: ^3.10.0 + flutter: ">=3.40.0" dependencies: flutter: sdk: flutter - cupertino_icons: ^1.0.1 - - async_button_builder: + material_async_button: path: ../ dev_dependencies: flutter_test: sdk: flutter - flutter_lints: ^2.0.0 + flutter_lints: ^5.0.0 flutter: uses-material-design: true diff --git a/example/test/widget_test.dart b/example/test/widget_test.dart index 092d222..7b8922f 100644 --- a/example/test/widget_test.dart +++ b/example/test/widget_test.dart @@ -1,30 +1,14 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility in the flutter_test package. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - import 'package:example/main.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:material_async_button/material_async_button.dart'; void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. + testWidgets('example app builds and shows the Material wrappers section', + (tester) async { await tester.pumpWidget(const MyApp()); - - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); - - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); + await tester.pumpAndSettle(); + expect(find.text('Material wrappers'), findsOneWidget); + expect(find.byType(ElevatedAsyncButton), findsWidgets); + expect(find.byType(FilledAsyncButton), findsWidgets); }); } diff --git a/lib/async_button_builder.dart b/lib/async_button_builder.dart deleted file mode 100644 index 0ae7c8c..0000000 --- a/lib/async_button_builder.dart +++ /dev/null @@ -1,3 +0,0 @@ -export 'package:async_button_builder/src/async_button_builder.dart'; -export 'package:async_button_builder/src/async_button_notification.dart'; -export 'package:async_button_builder/src/async_button_state.dart'; diff --git a/lib/material_async_button.dart b/lib/material_async_button.dart new file mode 100644 index 0000000..642eadc --- /dev/null +++ b/lib/material_async_button.dart @@ -0,0 +1,16 @@ +/// Drop-in async wrappers for Flutter Material buttons. +/// +/// See [ElevatedAsyncButton], [FilledAsyncButton], [OutlinedAsyncButton], +/// [TextAsyncButton], and [IconAsyncButton] for the named-constructor +/// variants. Use [AsyncButtonBuilder] when you need a custom button. +library; + +export 'src/async_button_builder.dart'; +export 'src/async_button_controller.dart'; +export 'src/async_button_state.dart'; +export 'src/buttons/elevated_async_button.dart'; +export 'src/buttons/filled_async_button.dart'; +export 'src/buttons/icon_async_button.dart'; +export 'src/buttons/outlined_async_button.dart'; +export 'src/buttons/text_async_button.dart'; +export 'src/material_async_button_theme.dart'; diff --git a/lib/src/async_button_builder.dart b/lib/src/async_button_builder.dart index d2562e1..dbd1cea 100644 --- a/lib/src/async_button_builder.dart +++ b/lib/src/async_button_builder.dart @@ -1,54 +1,42 @@ import 'dart:async'; -import 'package:async_button_builder/async_button_builder.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/semantics.dart'; +import 'package:flutter/services.dart'; -typedef AsyncButtonBuilderCallback = Widget Function( +import 'async_button_controller.dart'; +import 'async_button_state.dart'; +import 'material_async_button_theme.dart'; + +/// Signature for the [AsyncButtonBuilder.builder]. +/// +/// `callback` is `null` when the button should appear disabled (already +/// loading, in cooldown, or `onPressed`/`disabled` make it ineligible). +typedef AsyncButtonWidgetBuilder = Widget Function( BuildContext context, Widget child, AsyncCallback? callback, - AsyncButtonState buttonState, + AsyncButtonState state, ); -/// A `builder` that wraps a button providing disabled, loading, success and -/// error states while retaining almost full access to the original Button's -/// API. This is useful for any long running operations and helps better -/// improve UX. +/// Builder for an arbitrary button with async loading/success/error states. /// -/// {@tool dartpad --template=stateful_widget_material} +/// You almost always want one of the named Material wrappers (e.g. +/// [ElevatedAsyncButton], [FilledAsyncButton], [OutlinedAsyncButton], +/// [TextAsyncButton], [IconAsyncButton]). Reach for [AsyncButtonBuilder] +/// directly only when you need to render a non-Material button. /// +/// {@tool snippet} /// ```dart -/// -/// @override -/// Widget build(BuildContext context) { -/// return AsyncButtonBuilder( -/// child: Text('Click Me'), -/// loadingWidget: Text('Loading...'), -/// onPressed: () async { -/// await Future.delayed(Duration(seconds: 1)); -/// -/// throw 'yikes'; -/// }, -/// builder: (context, child, callback, buttonState) { -/// final buttonColor = buttonState.when( -/// idle: () => Colors.yellow[200], -/// loading: () => Colors.grey, -/// success: () => Colors.orangeAccent, -/// error: () => Colors.orange, -/// ); -/// -/// return OutlinedButton( -/// child: child, -/// onPressed: callback, -/// style: OutlinedButton.styleFrom( -/// primary: Colors.black, -/// backgroundColor: buttonColor, -/// ), -/// ); -/// }, +/// AsyncButtonBuilder( +/// onPressed: () async => doWork(), +/// child: const Text('Go'), +/// builder: (context, child, callback, state) => MyCustomButton( +/// onTap: callback, +/// child: child, /// ), -/// } +/// ) /// ``` /// {@end-tool} class AsyncButtonBuilder extends StatefulWidget { @@ -57,355 +45,296 @@ class AsyncButtonBuilder extends StatefulWidget { required this.child, required this.onPressed, required this.builder, + this.controller, this.onSuccess, this.onError, - this.loadingWidget = const SizedBox.square( - dimension: 16.0, - child: CircularProgressIndicator(), - ), - this.successWidget, - this.errorWidget, - this.showSuccess = true, - this.showError = true, - this.errorPadding, - this.successPadding, - this.buttonState = const AsyncButtonState.idle(), - this.duration = const Duration(milliseconds: 250), - this.reverseDuration = const Duration(milliseconds: 200), + this.onStateChanged, + this.confirmBeforePress, + this.errorBuilder, + this.loadingChild, + this.successChild, + this.errorChild, this.disabled = false, - this.successDuration = const Duration(seconds: 1), - this.errorDuration = const Duration(seconds: 1), - this.loadingTransitionBuilder = AnimatedSwitcher.defaultTransitionBuilder, - this.idleTransitionBuilder = AnimatedSwitcher.defaultTransitionBuilder, - this.successTransitionBuilder = AnimatedSwitcher.defaultTransitionBuilder, - this.errorTransitionBuilder = AnimatedSwitcher.defaultTransitionBuilder, - this.idleSwitchInCurve = Curves.linear, - this.loadingSwitchInCurve = Curves.linear, - this.successSwitchInCurve = Curves.linear, - this.errorSwitchInCurve = Curves.linear, - this.idleSwitchOutCurve = Curves.linear, - this.loadingSwitchOutCurve = Curves.linear, - this.successSwitchOutCurve = Curves.linear, - this.errorSwitchOutCurve = Curves.linear, - this.sizeCurve = Curves.linear, - this.sizeClipBehavior = Clip.hardEdge, - this.sizeAlignment = Alignment.center, - this.animateSize = true, - this.notifications = false, + this.switchDuration, + this.switchReverseDuration, + this.switchCurve, + this.switchInCurve, + this.switchOutCurve, + this.transitionBuilder, + this.successDisplayDuration, + this.errorDisplayDuration, + this.cooldownDuration, + this.animateSize, + this.sizeCurve, + this.sizeAlignment, + this.sizeClipBehavior, + this.hapticOn, + this.announceSemantics, + this.rethrowErrors, }); - /// This builder provides the widget's [BuildContext], the variable [child] - /// based on button state as well as the [callback] that should be passed to - /// the button and the current [ButtonState] - final AsyncButtonBuilderCallback builder; - - /// The child of the button. In the case of an [IconButton], this can be a an - /// [Icon]. For a [TextButton], a [Text]. - /// - /// This child will be animated between for the [loadingWidget] or default - /// [CircularProgressIndicator] when the asynchronous [onPressed] is called. - /// The animation will take place over [duration]. final Widget child; + final AsyncCallback? onPressed; + final AsyncButtonWidgetBuilder builder; - /// The animation's duration between [child], [loadingWidget], - /// [successWidget] and [errorWidget]. This same value is used for both the - /// internal [AnimatedSize] and [TransitionBuilder]. - final Duration duration; + /// External controller. When null, the widget creates and owns its own. + final AsyncButtonController? controller; - /// The animation's reverse duration between [child], [loadingWidget], - /// [successWidget] and [errorWidget]. This same value is used for both the - /// internal [AnimatedSize] and [TransitionBuilder]. - final Duration reverseDuration; + /// Called after success display completes. + final VoidCallback? onSuccess; - /// A callback that runs the async task. This is wrapped in order to begin - /// the button's internal `isLoading` before and after the operation - /// completes. - final AsyncCallback? onPressed; + /// Called after error display completes (or immediately if the display + /// duration is zero). Receives the thrown error and stack trace. + final void Function(Object error, StackTrace stackTrace)? onError; - /// A callback that runs [buttonState] changes to [AsyncButtonState.success] - final VoidCallback? onSuccess; + /// Fired on every state change. + final ValueChanged? onStateChanged; - /// A callback that runs [buttonState] changes to [AsyncButtonState.error] - final VoidCallback? onError; + /// If provided, runs before [onPressed]. If it returns `false`, the press + /// is cancelled and no state change happens. + final Future Function(BuildContext context)? confirmBeforePress; - /// This is used to manually drive the state of the loading button thus - /// initiating the corresponding animation and showing the correct button - /// child. - final AsyncButtonState buttonState; + /// Renders the error state. When non-null, takes precedence over + /// [errorChild] and the theme's `errorChild`. + final Widget Function(BuildContext context, Object error, StackTrace? stackTrace)? + errorBuilder; - /// This is used to manually drive the disabled state of the button. - final bool disabled; + final Widget? loadingChild; + final Widget? successChild; + final Widget? errorChild; - /// The widget replaces the [child] when the button is in the loading state. - /// If this is null the default widget is: - /// - /// SizedBox( - /// height: 16.0, - /// width: 16.0, - /// child: CircularProgressIndicator(), - /// ) - final Widget loadingWidget; - - /// The widget used to replace the [child] when the button is in a success - /// state. If this is null the default widget is: - /// - /// Icon( - /// Icons.check, - /// color: Theme.of(context).accentColor, - /// ); - final Widget? successWidget; - - /// The widget used to replace the [child] when the button is in a error - /// state. If this is null the default widget is: - /// - /// Icon( - /// Icons.error, - /// color: Theme.of(context).errorColor, - /// ) - final Widget? errorWidget; - - /// Whether to show the [successWidget] on success. - final bool showSuccess; - - /// Whether to show the [errorWidget] on error. - final bool showError; - - /// Optional [EdgeInsets] that will wrap around the [errorWidget]. This is a - /// convenience field that can be replaced by defining your own [errorWidget] - /// and wrapping it in a [Padding]. - final EdgeInsets? errorPadding; - - /// Optional [EdgeInsets] that will wrap around the [successWidget]. This is a - /// convenience field that can be replaced by defining your own - /// [successWidget] and wrapping it in a [Padding]. - final EdgeInsets? successPadding; - - /// Defines a custom transition when animating between any state and `idle` - final AnimatedSwitcherTransitionBuilder idleTransitionBuilder; - - /// Defines a custom transition when animating between any state and `loading` - final AnimatedSwitcherTransitionBuilder loadingTransitionBuilder; - - /// Defines a custom transition when animating between any state and `success` - final AnimatedSwitcherTransitionBuilder successTransitionBuilder; - - /// Defines a custom transition when animating between any state and `error` - final AnimatedSwitcherTransitionBuilder errorTransitionBuilder; - - /// The amount of idle time the [successWidget] shows - final Duration successDuration; - - /// The amount of idle time the [errorWidget] shows - final Duration errorDuration; - - /// Defines a curve for the custom transition. This used in in an - /// [AnimatedSwitcher] and only takes effect when animating to `idle` - final Curve idleSwitchInCurve; - - /// Defines a curve for the custom transition. This used in in an - /// [AnimatedSwitcher] and only takes effect when animating to `loading` - final Curve loadingSwitchInCurve; - - /// Defines a curve for the custom transition. This used in in an - /// [AnimatedSwitcher] and only takes effect when animating to `success` - final Curve successSwitchInCurve; - - /// Defines a curve for the custom transition. This used in in an - /// [AnimatedSwitcher] and only takes effect when animating to `error` - final Curve errorSwitchInCurve; - - /// Defines a curve for the custom transition. This used in in an - /// [AnimatedSwitcher] and only takes effect when animating out of `idle` - final Curve idleSwitchOutCurve; - - /// Defines a curve for the custom transition. This used in in an - /// [AnimatedSwitcher] and only takes effect when animating out of `loading` - final Curve loadingSwitchOutCurve; - - /// Defines a curve for the custom transition. This used in in an - /// [AnimatedSwitcher] and only takes effect when animating out of `success` - final Curve successSwitchOutCurve; - - /// Defines a curve for the custom transition. This used in in an - /// [AnimatedSwitcher] and only takes effect when animating out of `error` - final Curve errorSwitchOutCurve; - - /// Defines a curve for the internal [AnimatedSize] - final Curve sizeCurve; - - /// Defines the [Clip] for the internal [AnimatedSize] - final Clip sizeClipBehavior; - - /// Defines the [Alignment] for the internal [AnimatedSize] - final Alignment sizeAlignment; - - /// Whether to animate the [Size] of the widget implicitly. - final bool animateSize; + /// Forces the button to appear disabled regardless of state. + final bool disabled; - /// Whether we should bubble up [AsyncButtonNotification]s up the widget tree. - /// This is useful if you want to listen to the state of the button from a - /// parent widget. - final bool notifications; + // Per-widget overrides of the theme. Null means "use theme, then default". + final Duration? switchDuration; + final Duration? switchReverseDuration; + final Curve? switchCurve; + final Curve? switchInCurve; + final Curve? switchOutCurve; + final AnimatedSwitcherTransitionBuilder? transitionBuilder; + final Duration? successDisplayDuration; + final Duration? errorDisplayDuration; + final Duration? cooldownDuration; + final bool? animateSize; + final Curve? sizeCurve; + final AlignmentGeometry? sizeAlignment; + final Clip? sizeClipBehavior; + final HapticOn? hapticOn; + final bool? announceSemantics; + final bool? rethrowErrors; @override State createState() => AsyncButtonBuilderState(); } -class AsyncButtonBuilderState extends State - with SingleTickerProviderStateMixin { - late AsyncButtonState _buttonState = widget.buttonState; - Key _switchKey = UniqueKey(); - Timer? timer; +class AsyncButtonBuilderState extends State { + AsyncButtonController? _internalController; + AsyncButtonController get _controller => + widget.controller ?? _internalController!; + + AsyncButtonState _lastNotifiedState = const AsyncButtonState.idle(); @override - void didUpdateWidget(covariant AsyncButtonBuilder oldWidget) { - if (widget.buttonState != oldWidget.buttonState) { - _setButtonState(widget.buttonState); + void initState() { + super.initState(); + if (widget.controller == null) { + _internalController = AsyncButtonController(); } + _controller.addListener(_handleControllerChange); + _lastNotifiedState = _controller.value; + } + + @override + void didUpdateWidget(covariant AsyncButtonBuilder oldWidget) { super.didUpdateWidget(oldWidget); + if (widget.controller != oldWidget.controller) { + final previous = oldWidget.controller ?? _internalController; + previous?.removeListener(_handleControllerChange); + if (widget.controller != null) { + _internalController?.dispose(); + _internalController = null; + } else { + _internalController = AsyncButtonController(); + } + _controller.addListener(_handleControllerChange); + _lastNotifiedState = _controller.value; + } } @override void dispose() { - timer?.cancel(); + _controller.removeListener(_handleControllerChange); + _internalController?.dispose(); super.dispose(); } - @override - Widget build(BuildContext context) { - final theme = Theme.of(context); - Widget successWidget = widget.successWidget ?? - Icon(Icons.check, color: theme.colorScheme.secondary); - Widget errorWidget = - widget.errorWidget ?? Icon(Icons.error, color: theme.colorScheme.error); - if (widget.successPadding != null) { - successWidget = Padding( - padding: widget.successPadding!, - child: successWidget, - ); + void _handleControllerChange() { + final newState = _controller.value; + if (newState != _lastNotifiedState) { + widget.onStateChanged?.call(newState); + _fireHaptic(_lastNotifiedState, newState); + _announceSemantics(newState); + if (newState is AsyncButtonStateSuccess && _lastNotifiedState is! AsyncButtonStateSuccess) { + widget.onSuccess?.call(); + } else if (newState is AsyncButtonStateError && _lastNotifiedState is! AsyncButtonStateError) { + widget.onError?.call(newState.error, newState.stackTrace ?? StackTrace.empty); + } + _lastNotifiedState = newState; } + if (mounted) setState(() {}); + } - if (widget.errorPadding != null) { - errorWidget = Padding( - padding: widget.errorPadding!, - child: errorWidget, - ); + void _fireHaptic(AsyncButtonState from, AsyncButtonState to) { + final theme = MaterialAsyncButtonTheme.of(context); + final mode = widget.hapticOn ?? theme.hapticOn ?? HapticOn.none; + if (mode == HapticOn.none) return; + if (to is AsyncButtonStateSuccess && (mode == HapticOn.success || mode == HapticOn.both)) { + HapticFeedback.lightImpact(); + } else if (to is AsyncButtonStateError && (mode == HapticOn.error || mode == HapticOn.both)) { + HapticFeedback.mediumImpact(); + } + } + + void _announceSemantics(AsyncButtonState state) { + final theme = MaterialAsyncButtonTheme.of(context); + final on = widget.announceSemantics ?? theme.announceSemantics ?? false; + if (!on) return; + final direction = Directionality.maybeOf(context) ?? TextDirection.ltr; + final message = switch (state) { + AsyncButtonStateIdle() => null, + AsyncButtonStateLoading() => 'Loading', + AsyncButtonStateSuccess() => 'Success', + AsyncButtonStateError() => 'Error', + }; + if (message != null) { + SemanticsService.announce(message, direction); } + } + + /// Trigger the attached `onPressed` programmatically. Equivalent to + /// [AsyncButtonController.trigger] on the active controller. Safe to call + /// from outside the widget tree (e.g. via a [GlobalKey]). + Future trigger() => _controller.trigger(); + + /// Force the button back to idle. + void reset() => _controller.reset(); + + /// Force the error state from outside. + void invalidate(Object error, [StackTrace? stackTrace]) => + _controller.invalidate(error, stackTrace); + + /// Force the success state from outside. + void markSuccess() => _controller.markSuccess(); + + /// The current state. Exposed for callers using a [GlobalKey]. + AsyncButtonState get value => _controller.value; + + @override + Widget build(BuildContext context) { + final theme = MaterialAsyncButtonTheme.of(context); + + final successDuration = + widget.successDisplayDuration ?? theme.successDisplayDuration ?? Duration.zero; + final errorDuration = + widget.errorDisplayDuration ?? theme.errorDisplayDuration ?? Duration.zero; + final cooldown = + widget.cooldownDuration ?? theme.cooldownDuration ?? Duration.zero; + final rethrowErrors = widget.rethrowErrors ?? theme.rethrowErrors ?? false; + + _controller.attach( + onPressed: _gatedOnPressed(), + successDuration: successDuration, + errorDuration: errorDuration, + cooldownDuration: cooldown, + rethrowErrors: rethrowErrors, + ); + + final state = _controller.value; + + final loadingChild = widget.loadingChild ?? + theme.loadingChild ?? + const _BuiltinLoadingChild(); + final successChild = widget.successChild ?? theme.successChild; + final errorChild = widget.errorChild ?? theme.errorChild; + final switchDuration = + widget.switchDuration ?? theme.switchDuration ?? const Duration(milliseconds: 200); + final switchReverseDuration = widget.switchReverseDuration ?? theme.switchReverseDuration; + final switchInCurve = + widget.switchInCurve ?? theme.switchInCurve ?? widget.switchCurve ?? theme.switchCurve ?? Curves.linear; + final switchOutCurve = + widget.switchOutCurve ?? theme.switchOutCurve ?? widget.switchCurve ?? theme.switchCurve ?? Curves.linear; + final transitionBuilder = widget.transitionBuilder ?? + theme.transitionBuilder ?? + AnimatedSwitcher.defaultTransitionBuilder; + final animateSize = widget.animateSize ?? theme.animateSize ?? false; + + Widget visible = switch (state) { + AsyncButtonStateIdle() => widget.child, + AsyncButtonStateLoading() => loadingChild, + AsyncButtonStateSuccess() => successChild ?? widget.child, + AsyncButtonStateError(:final error, :final stackTrace) => + widget.errorBuilder?.call(context, error, stackTrace) ?? + errorChild ?? + widget.child, + }; Widget content = AnimatedSwitcher( - // TODO: This duration is same as size's duration. That's okay right? - duration: widget.duration, - reverseDuration: widget.reverseDuration, - switchInCurve: switch (_buttonState) { - AsyncButtonStateIdle() => widget.idleSwitchInCurve, - AsyncButtonStateLoading() => widget.loadingSwitchInCurve, - AsyncButtonStateSuccess() => widget.successSwitchInCurve, - AsyncButtonStateError() => widget.errorSwitchInCurve, - }, - switchOutCurve: switch (_buttonState) { - AsyncButtonStateIdle() => widget.idleSwitchOutCurve, - AsyncButtonStateLoading() => widget.loadingSwitchOutCurve, - AsyncButtonStateSuccess() => widget.successSwitchOutCurve, - AsyncButtonStateError() => widget.errorSwitchOutCurve, - }, - transitionBuilder: switch (_buttonState) { - AsyncButtonStateIdle() => widget.idleTransitionBuilder, - AsyncButtonStateLoading() => widget.loadingTransitionBuilder, - AsyncButtonStateSuccess() => widget.successTransitionBuilder, - AsyncButtonStateError() => widget.errorTransitionBuilder, - }, + duration: switchDuration, + reverseDuration: switchReverseDuration, + switchInCurve: switchInCurve, + switchOutCurve: switchOutCurve, + transitionBuilder: transitionBuilder, child: KeyedSubtree( - key: _switchKey, - child: switch (_buttonState) { - AsyncButtonStateIdle() => widget.child, - AsyncButtonStateLoading() => widget.loadingWidget, - AsyncButtonStateSuccess() => successWidget, - AsyncButtonStateError() => errorWidget, - }, + key: ValueKey(state.runtimeType), + child: visible, ), ); - if (widget.animateSize) { - // TODO: I really just wanted an AnimatedSwitcher and the default - // transitionBuilder to be a SizedTransition but it was impossible - // to figure out how to reproduce the exact behaviour of AnimatedSize + if (animateSize) { content = AnimatedSize( - duration: widget.duration, - reverseDuration: widget.reverseDuration, - alignment: widget.sizeAlignment, - clipBehavior: widget.sizeClipBehavior, - curve: widget.sizeCurve, + duration: switchDuration, + reverseDuration: switchReverseDuration, + alignment: widget.sizeAlignment ?? theme.sizeAlignment ?? Alignment.center, + clipBehavior: widget.sizeClipBehavior ?? theme.sizeClipBehavior ?? Clip.hardEdge, + curve: widget.sizeCurve ?? theme.sizeCurve ?? Curves.linear, child: content, ); } - return widget.builder(context, content, pressCallback, _buttonState); + return widget.builder(context, content, _builderCallback(), state); } - AsyncCallback? get pressCallback { - if (widget.disabled || widget.onPressed == null) { - return null; - } - return switch (_buttonState) { - AsyncButtonStateIdle() => () { - final completer = Completer(); - - // I might not want to set buttonState if we're being - // driven by widget.buttonState... - _setButtonState(const AsyncButtonState.loading()); - timer?.cancel(); - - widget.onPressed!().then((_) { - completer.complete(); - - if (mounted) { - if (widget.showSuccess) { - _setButtonState(const AsyncButtonState.success()); - _setTimer(widget.successDuration, widget.onSuccess); - } else { - _setButtonState(const AsyncButtonState.idle()); - } - } - }).onError((Object error, StackTrace stackTrace) { - completer.completeError(error, stackTrace); - - if (mounted) { - if (widget.showError) { - _setButtonState(AsyncButtonState.error(error)); - _setTimer(widget.errorDuration, widget.onError); - } else { - _setButtonState(const AsyncButtonState.idle()); - } - } - }); - - return completer.future; - }, - _ => null, - }; + /// The callback passed back through the builder. Null when the button is + /// in a state that should appear disabled. + AsyncCallback? _builderCallback() { + if (widget.disabled || widget.onPressed == null) return null; + if (!_controller.canTrigger) return null; + return _controller.trigger; } - void _setButtonState(AsyncButtonState buttonState) { - setState(() { - _switchKey = UniqueKey(); - _buttonState = buttonState; - }); - - if (widget.notifications) { - AsyncButtonNotification(buttonState: buttonState).dispatch(context); - } + /// The `onPressed` that `controller.trigger` will actually run, wrapped + /// with `confirmBeforePress` and only invoked when not disabled. + AsyncCallback? _gatedOnPressed() { + if (widget.disabled || widget.onPressed == null) return null; + final confirm = widget.confirmBeforePress; + final raw = widget.onPressed!; + if (confirm == null) return raw; + return () async { + if (!mounted) return; + final ok = await confirm(context); + if (!mounted || !ok) return; + await raw(); + }; } +} - void _setTimer(Duration duration, [VoidCallback? then]) { - timer = Timer( - duration, - () { - timer?.cancel(); - then?.call(); - if (mounted) { - _setButtonState(const AsyncButtonState.idle()); - } - }, - ); - } +class _BuiltinLoadingChild extends StatelessWidget { + const _BuiltinLoadingChild(); + + @override + Widget build(BuildContext context) => const SizedBox.square( + dimension: 16, + child: CircularProgressIndicator(strokeWidth: 2), + ); } diff --git a/lib/src/async_button_controller.dart b/lib/src/async_button_controller.dart new file mode 100644 index 0000000..4dcfeba --- /dev/null +++ b/lib/src/async_button_controller.dart @@ -0,0 +1,164 @@ +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:meta/meta.dart'; + +import 'async_button_state.dart'; + +/// Imperative controller for an [AsyncButtonBuilder] or any of the Material +/// wrappers. Listens like a [ValueListenable] of [AsyncButtonState]. +/// +/// Use it to: +/// - trigger the attached `onPressed` from outside the button +/// (e.g. a form keyboard "Done" action), +/// - reset to idle, +/// - mark the button as errored from an out-of-band source +/// (e.g. a WebSocket message), +/// - mark the button as succeeded from outside. +/// +/// Dispose like any [ChangeNotifier]. +class AsyncButtonController extends ChangeNotifier + implements ValueListenable { + AsyncButtonController({AsyncButtonState initial = const AsyncButtonState.idle()}) + : _value = initial; + + AsyncButtonState _value; + @override + AsyncButtonState get value => _value; + + bool get isIdle => _value is AsyncButtonStateIdle; + bool get isLoading => _value is AsyncButtonStateLoading; + bool get isSuccess => _value is AsyncButtonStateSuccess; + bool get isError => _value is AsyncButtonStateError; + + Object? get error => switch (_value) { + AsyncButtonStateError(:final error) => error, + _ => null, + }; + + StackTrace? get stackTrace => switch (_value) { + AsyncButtonStateError(:final stackTrace) => stackTrace, + _ => null, + }; + + bool get isInCooldown => _cooldownActive; + + /// True when [trigger] would actually run the attached callback. + bool get canTrigger => isIdle && !_cooldownActive && _onPressed != null; + + // Widget-owned configuration. Refreshed on every build. + Future Function()? _onPressed; + Duration _successDuration = Duration.zero; + Duration _errorDuration = Duration.zero; + Duration _cooldownDuration = Duration.zero; + bool _rethrowErrors = false; + + Timer? _timer; + bool _cooldownActive = false; + bool _disposed = false; + + /// Internal: called by the widget on each build to keep config fresh. + @internal + void attach({ + required Future Function()? onPressed, + required Duration successDuration, + required Duration errorDuration, + required Duration cooldownDuration, + required bool rethrowErrors, + }) { + _onPressed = onPressed; + _successDuration = successDuration; + _errorDuration = errorDuration; + _cooldownDuration = cooldownDuration; + _rethrowErrors = rethrowErrors; + } + + /// Run the attached `onPressed`. No-op if already loading, in cooldown, + /// or if no callback is attached. + Future trigger() async { + if (!canTrigger) return; + _cancelTimer(); + _setValue(const AsyncButtonState.loading()); + try { + await _onPressed!(); + // External resets (e.g. controller.reset()) may have moved us off + // loading mid-await. Only continue the success cycle if we're still + // the one driving. + if (!_disposed && _value is AsyncButtonStateLoading) { + _setValue(const AsyncButtonState.success()); + _scheduleReturnToIdle(_successDuration); + } + } catch (error, stack) { + if (!_disposed && _value is AsyncButtonStateLoading) { + _setValue(AsyncButtonState.error(error, stack)); + _scheduleReturnToIdle(_errorDuration); + } + if (_rethrowErrors) rethrow; + } + } + + /// Force the button back to idle. Cancels any pending display/cooldown. + void reset() { + _cancelTimer(); + _cooldownActive = false; + _setValue(const AsyncButtonState.idle()); + } + + /// Force the error state from outside. Runs the same display/callback + /// cycle as if `onPressed` had thrown. + void invalidate(Object error, [StackTrace? stackTrace]) { + _cancelTimer(); + _setValue(AsyncButtonState.error(error, stackTrace ?? StackTrace.current)); + _scheduleReturnToIdle(_errorDuration); + } + + /// Force the success state from outside. Runs the same display cycle as + /// a completed `onPressed`. + void markSuccess() { + _cancelTimer(); + _setValue(const AsyncButtonState.success()); + _scheduleReturnToIdle(_successDuration); + } + + void _setValue(AsyncButtonState v) { + if (_value == v) return; + _value = v; + notifyListeners(); + } + + void _cancelTimer() { + _timer?.cancel(); + _timer = null; + } + + void _scheduleReturnToIdle(Duration displayDuration) { + if (displayDuration <= Duration.zero) { + _enterIdleThenCooldown(); + return; + } + _timer = Timer(displayDuration, _enterIdleThenCooldown); + } + + void _enterIdleThenCooldown() { + if (_disposed) return; + _timer = null; + _setValue(const AsyncButtonState.idle()); + if (_cooldownDuration > Duration.zero) { + _cooldownActive = true; + notifyListeners(); + _timer = Timer(_cooldownDuration, () { + if (_disposed) return; + _timer = null; + _cooldownActive = false; + notifyListeners(); + }); + } + } + + @override + void dispose() { + _disposed = true; + _cancelTimer(); + super.dispose(); + } +} diff --git a/lib/src/async_button_notification.dart b/lib/src/async_button_notification.dart deleted file mode 100644 index d418060..0000000 --- a/lib/src/async_button_notification.dart +++ /dev/null @@ -1,8 +0,0 @@ -import 'package:async_button_builder/async_button_builder.dart'; -import 'package:flutter/material.dart'; - -class AsyncButtonNotification extends Notification { - const AsyncButtonNotification({required this.buttonState}); - - final AsyncButtonState buttonState; -} diff --git a/lib/src/async_button_state.dart b/lib/src/async_button_state.dart index a4aa2a7..e1a6f26 100644 --- a/lib/src/async_button_state.dart +++ b/lib/src/async_button_state.dart @@ -1,74 +1,77 @@ -/// This union class represents the state of the button in either a [Idling], -/// [AsyncButtonStateLoading], [AsyncButtonStateSuccess] or [AsyncButtonStateError] state. -/// This can be considered a enum with extra utilities for ease of use. +/// State of an async button. /// -/// {@tool snippet} +/// Pattern-match with `switch` to react to each state: /// /// ```dart -/// final buttonColor = AsyncbuttonState.when( -/// idle: () => Colors.pink, -/// loading: () => Colors.blue, -/// success: () => Colors.green, -/// error: () => Colors.red, -/// ); +/// final color = switch (state) { +/// AsyncButtonStateIdle() => Colors.blue, +/// AsyncButtonStateLoading() => Colors.grey, +/// AsyncButtonStateSuccess() => Colors.green, +/// AsyncButtonStateError() => Colors.red, +/// }; /// ``` -/// {@end-tool} -/// -/// You can also disregard other states and handle only those you'd like using -/// the `.maybeWhen` syntax. -/// -/// {@tool snippet} -/// -/// ```dart -/// final buttonColor = AsyncbuttonState.maybeWhen( -/// idle: () => Colors.pink, -/// orElse: () => Colors.red, -/// ); -/// ``` -/// {@end-tool} sealed class AsyncButtonState { const AsyncButtonState(); const factory AsyncButtonState.idle() = AsyncButtonStateIdle; const factory AsyncButtonState.loading() = AsyncButtonStateLoading; const factory AsyncButtonState.success() = AsyncButtonStateSuccess; - const factory AsyncButtonState.error(Object error) = AsyncButtonStateError; + const factory AsyncButtonState.error(Object error, [StackTrace? stackTrace]) = + AsyncButtonStateError; } -class AsyncButtonStateIdle extends AsyncButtonState { +final class AsyncButtonStateIdle extends AsyncButtonState { const AsyncButtonStateIdle(); @override - String toString() { - return 'AsyncButtonState.idle()'; - } + bool operator ==(Object other) => other is AsyncButtonStateIdle; + + @override + int get hashCode => (AsyncButtonStateIdle).hashCode; + + @override + String toString() => 'AsyncButtonState.idle()'; } -class AsyncButtonStateLoading extends AsyncButtonState { +final class AsyncButtonStateLoading extends AsyncButtonState { const AsyncButtonStateLoading(); @override - String toString() { - return 'AsyncButtonState.loading()'; - } + bool operator ==(Object other) => other is AsyncButtonStateLoading; + + @override + int get hashCode => (AsyncButtonStateLoading).hashCode; + + @override + String toString() => 'AsyncButtonState.loading()'; } -class AsyncButtonStateSuccess extends AsyncButtonState { +final class AsyncButtonStateSuccess extends AsyncButtonState { const AsyncButtonStateSuccess(); @override - String toString() { - return 'AsyncButtonState.success()'; - } + bool operator ==(Object other) => other is AsyncButtonStateSuccess; + + @override + int get hashCode => (AsyncButtonStateSuccess).hashCode; + + @override + String toString() => 'AsyncButtonState.success()'; } -class AsyncButtonStateError extends AsyncButtonState { - const AsyncButtonStateError(this.error); +final class AsyncButtonStateError extends AsyncButtonState { + const AsyncButtonStateError(this.error, [this.stackTrace]); final Object error; + final StackTrace? stackTrace; + + @override + bool operator ==(Object other) => + other is AsyncButtonStateError && other.error == error; + + @override + int get hashCode => Object.hash(AsyncButtonStateError, error); @override - String toString() { - return 'AsyncButtonState.error(error: $error)'; - } + String toString() => 'AsyncButtonState.error($error)'; } diff --git a/lib/src/buttons/elevated_async_button.dart b/lib/src/buttons/elevated_async_button.dart new file mode 100644 index 0000000..7fbba0a --- /dev/null +++ b/lib/src/buttons/elevated_async_button.dart @@ -0,0 +1,174 @@ +import 'package:flutter/material.dart'; + +import '../async_button_builder.dart'; +import '../async_button_controller.dart'; +import '../async_button_state.dart'; +import '../material_async_button_theme.dart'; + +/// Async-aware [ElevatedButton]. While `onPressed` is running the label is +/// swapped for a loading widget; success/error are shown afterwards if +/// configured via prop or theme. +class ElevatedAsyncButton extends StatelessWidget { + const ElevatedAsyncButton({ + super.key, + required this.onPressed, + required this.child, + this.onLongPress, + this.onHover, + this.onFocusChange, + this.style, + this.focusNode, + this.autofocus = false, + this.clipBehavior, + this.statesController, + // async + this.controller, + this.onSuccess, + this.onError, + this.onStateChanged, + this.confirmBeforePress, + this.errorBuilder, + this.loadingChild, + this.successChild, + this.errorChild, + this.disabled = false, + this.switchDuration, + this.transitionBuilder, + this.successDisplayDuration, + this.errorDisplayDuration, + this.cooldownDuration, + this.animateSize, + this.hapticOn, + this.announceSemantics, + this.rethrowErrors, + }) : _icon = null, + _iconAlignment = null; + + /// Mirrors [ElevatedButton.icon]. The loading/success/error children + /// replace the `label` while [icon] stays put. + const ElevatedAsyncButton.icon({ + super.key, + required this.onPressed, + required Widget icon, + required Widget label, + this.onLongPress, + this.onHover, + this.onFocusChange, + this.style, + this.focusNode, + this.autofocus = false, + this.clipBehavior, + this.statesController, + IconAlignment? iconAlignment, + this.controller, + this.onSuccess, + this.onError, + this.onStateChanged, + this.confirmBeforePress, + this.errorBuilder, + this.loadingChild, + this.successChild, + this.errorChild, + this.disabled = false, + this.switchDuration, + this.transitionBuilder, + this.successDisplayDuration, + this.errorDisplayDuration, + this.cooldownDuration, + this.animateSize, + this.hapticOn, + this.announceSemantics, + this.rethrowErrors, + }) : _icon = icon, + _iconAlignment = iconAlignment, + child = label; + + final Future Function()? onPressed; + final Widget child; + final VoidCallback? onLongPress; + final ValueChanged? onHover; + final ValueChanged? onFocusChange; + final ButtonStyle? style; + final FocusNode? focusNode; + final bool autofocus; + final Clip? clipBehavior; + final WidgetStatesController? statesController; + final Widget? _icon; + final IconAlignment? _iconAlignment; + + final AsyncButtonController? controller; + final VoidCallback? onSuccess; + final void Function(Object error, StackTrace stackTrace)? onError; + final ValueChanged? onStateChanged; + final Future Function(BuildContext context)? confirmBeforePress; + final Widget Function(BuildContext context, Object error, StackTrace? stackTrace)? + errorBuilder; + final Widget? loadingChild; + final Widget? successChild; + final Widget? errorChild; + final bool disabled; + final Duration? switchDuration; + final AnimatedSwitcherTransitionBuilder? transitionBuilder; + final Duration? successDisplayDuration; + final Duration? errorDisplayDuration; + final Duration? cooldownDuration; + final bool? animateSize; + final HapticOn? hapticOn; + final bool? announceSemantics; + final bool? rethrowErrors; + + @override + Widget build(BuildContext context) => AsyncButtonBuilder( + onPressed: onPressed, + controller: controller, + onSuccess: onSuccess, + onError: onError, + onStateChanged: onStateChanged, + confirmBeforePress: confirmBeforePress, + errorBuilder: errorBuilder, + loadingChild: loadingChild, + successChild: successChild, + errorChild: errorChild, + disabled: disabled, + switchDuration: switchDuration, + transitionBuilder: transitionBuilder, + successDisplayDuration: successDisplayDuration, + errorDisplayDuration: errorDisplayDuration, + cooldownDuration: cooldownDuration, + animateSize: animateSize, + hapticOn: hapticOn, + announceSemantics: announceSemantics, + rethrowErrors: rethrowErrors, + child: child, + builder: (context, animatedChild, callback, _) { + if (_icon != null) { + return ElevatedButton.icon( + onPressed: callback, + onLongPress: callback == null ? null : onLongPress, + onHover: onHover, + onFocusChange: onFocusChange, + style: style, + focusNode: focusNode, + autofocus: autofocus, + clipBehavior: clipBehavior ?? Clip.none, + statesController: statesController, + iconAlignment: _iconAlignment, + icon: _icon, + label: animatedChild, + ); + } + return ElevatedButton( + onPressed: callback, + onLongPress: callback == null ? null : onLongPress, + onHover: onHover, + onFocusChange: onFocusChange, + style: style, + focusNode: focusNode, + autofocus: autofocus, + clipBehavior: clipBehavior ?? Clip.none, + statesController: statesController, + child: animatedChild, + ); + }, + ); +} diff --git a/lib/src/buttons/filled_async_button.dart b/lib/src/buttons/filled_async_button.dart new file mode 100644 index 0000000..378c482 --- /dev/null +++ b/lib/src/buttons/filled_async_button.dart @@ -0,0 +1,279 @@ +import 'package:flutter/material.dart'; + +import '../async_button_builder.dart'; +import '../async_button_controller.dart'; +import '../async_button_state.dart'; +import '../material_async_button_theme.dart'; + +enum _FilledVariant { primary, tonal } + +/// Async-aware [FilledButton] with all four Material 3 flavors: +/// [FilledAsyncButton.new], [FilledAsyncButton.tonal], +/// [FilledAsyncButton.icon], [FilledAsyncButton.tonalIcon]. +class FilledAsyncButton extends StatelessWidget { + const FilledAsyncButton({ + super.key, + required this.onPressed, + required this.child, + this.onLongPress, + this.onHover, + this.onFocusChange, + this.style, + this.focusNode, + this.autofocus = false, + this.clipBehavior, + this.statesController, + this.controller, + this.onSuccess, + this.onError, + this.onStateChanged, + this.confirmBeforePress, + this.errorBuilder, + this.loadingChild, + this.successChild, + this.errorChild, + this.disabled = false, + this.switchDuration, + this.transitionBuilder, + this.successDisplayDuration, + this.errorDisplayDuration, + this.cooldownDuration, + this.animateSize, + this.hapticOn, + this.announceSemantics, + this.rethrowErrors, + }) : _variant = _FilledVariant.primary, + _icon = null, + _iconAlignment = null; + + const FilledAsyncButton.tonal({ + super.key, + required this.onPressed, + required this.child, + this.onLongPress, + this.onHover, + this.onFocusChange, + this.style, + this.focusNode, + this.autofocus = false, + this.clipBehavior, + this.statesController, + this.controller, + this.onSuccess, + this.onError, + this.onStateChanged, + this.confirmBeforePress, + this.errorBuilder, + this.loadingChild, + this.successChild, + this.errorChild, + this.disabled = false, + this.switchDuration, + this.transitionBuilder, + this.successDisplayDuration, + this.errorDisplayDuration, + this.cooldownDuration, + this.animateSize, + this.hapticOn, + this.announceSemantics, + this.rethrowErrors, + }) : _variant = _FilledVariant.tonal, + _icon = null, + _iconAlignment = null; + + const FilledAsyncButton.icon({ + super.key, + required this.onPressed, + required Widget icon, + required Widget label, + this.onLongPress, + this.onHover, + this.onFocusChange, + this.style, + this.focusNode, + this.autofocus = false, + this.clipBehavior, + this.statesController, + IconAlignment? iconAlignment, + this.controller, + this.onSuccess, + this.onError, + this.onStateChanged, + this.confirmBeforePress, + this.errorBuilder, + this.loadingChild, + this.successChild, + this.errorChild, + this.disabled = false, + this.switchDuration, + this.transitionBuilder, + this.successDisplayDuration, + this.errorDisplayDuration, + this.cooldownDuration, + this.animateSize, + this.hapticOn, + this.announceSemantics, + this.rethrowErrors, + }) : _variant = _FilledVariant.primary, + _icon = icon, + _iconAlignment = iconAlignment, + child = label; + + const FilledAsyncButton.tonalIcon({ + super.key, + required this.onPressed, + required Widget icon, + required Widget label, + this.onLongPress, + this.onHover, + this.onFocusChange, + this.style, + this.focusNode, + this.autofocus = false, + this.clipBehavior, + this.statesController, + IconAlignment? iconAlignment, + this.controller, + this.onSuccess, + this.onError, + this.onStateChanged, + this.confirmBeforePress, + this.errorBuilder, + this.loadingChild, + this.successChild, + this.errorChild, + this.disabled = false, + this.switchDuration, + this.transitionBuilder, + this.successDisplayDuration, + this.errorDisplayDuration, + this.cooldownDuration, + this.animateSize, + this.hapticOn, + this.announceSemantics, + this.rethrowErrors, + }) : _variant = _FilledVariant.tonal, + _icon = icon, + _iconAlignment = iconAlignment, + child = label; + + final Future Function()? onPressed; + final Widget child; + final VoidCallback? onLongPress; + final ValueChanged? onHover; + final ValueChanged? onFocusChange; + final ButtonStyle? style; + final FocusNode? focusNode; + final bool autofocus; + final Clip? clipBehavior; + final WidgetStatesController? statesController; + final _FilledVariant _variant; + final Widget? _icon; + final IconAlignment? _iconAlignment; + + final AsyncButtonController? controller; + final VoidCallback? onSuccess; + final void Function(Object error, StackTrace stackTrace)? onError; + final ValueChanged? onStateChanged; + final Future Function(BuildContext context)? confirmBeforePress; + final Widget Function(BuildContext context, Object error, StackTrace? stackTrace)? + errorBuilder; + final Widget? loadingChild; + final Widget? successChild; + final Widget? errorChild; + final bool disabled; + final Duration? switchDuration; + final AnimatedSwitcherTransitionBuilder? transitionBuilder; + final Duration? successDisplayDuration; + final Duration? errorDisplayDuration; + final Duration? cooldownDuration; + final bool? animateSize; + final HapticOn? hapticOn; + final bool? announceSemantics; + final bool? rethrowErrors; + + @override + Widget build(BuildContext context) => AsyncButtonBuilder( + onPressed: onPressed, + controller: controller, + onSuccess: onSuccess, + onError: onError, + onStateChanged: onStateChanged, + confirmBeforePress: confirmBeforePress, + errorBuilder: errorBuilder, + loadingChild: loadingChild, + successChild: successChild, + errorChild: errorChild, + disabled: disabled, + switchDuration: switchDuration, + transitionBuilder: transitionBuilder, + successDisplayDuration: successDisplayDuration, + errorDisplayDuration: errorDisplayDuration, + cooldownDuration: cooldownDuration, + animateSize: animateSize, + hapticOn: hapticOn, + announceSemantics: announceSemantics, + rethrowErrors: rethrowErrors, + child: child, + builder: (context, animatedChild, callback, _) { + if (_icon != null) { + return switch (_variant) { + _FilledVariant.primary => FilledButton.icon( + onPressed: callback, + onLongPress: callback == null ? null : onLongPress, + onHover: onHover, + onFocusChange: onFocusChange, + style: style, + focusNode: focusNode, + autofocus: autofocus, + clipBehavior: clipBehavior ?? Clip.none, + statesController: statesController, + iconAlignment: _iconAlignment, + icon: _icon, + label: animatedChild, + ), + _FilledVariant.tonal => FilledButton.tonalIcon( + onPressed: callback, + onLongPress: callback == null ? null : onLongPress, + onHover: onHover, + onFocusChange: onFocusChange, + style: style, + focusNode: focusNode, + autofocus: autofocus, + clipBehavior: clipBehavior ?? Clip.none, + statesController: statesController, + iconAlignment: _iconAlignment, + icon: _icon, + label: animatedChild, + ), + }; + } + return switch (_variant) { + _FilledVariant.primary => FilledButton( + onPressed: callback, + onLongPress: callback == null ? null : onLongPress, + onHover: onHover, + onFocusChange: onFocusChange, + style: style, + focusNode: focusNode, + autofocus: autofocus, + clipBehavior: clipBehavior ?? Clip.none, + statesController: statesController, + child: animatedChild, + ), + _FilledVariant.tonal => FilledButton.tonal( + onPressed: callback, + onLongPress: callback == null ? null : onLongPress, + onHover: onHover, + onFocusChange: onFocusChange, + style: style, + focusNode: focusNode, + autofocus: autofocus, + clipBehavior: clipBehavior ?? Clip.none, + statesController: statesController, + child: animatedChild, + ), + }; + }, + ); +} diff --git a/lib/src/buttons/icon_async_button.dart b/lib/src/buttons/icon_async_button.dart new file mode 100644 index 0000000..03e8328 --- /dev/null +++ b/lib/src/buttons/icon_async_button.dart @@ -0,0 +1,366 @@ +import 'package:flutter/material.dart'; + +import '../async_button_builder.dart'; +import '../async_button_controller.dart'; +import '../async_button_state.dart'; +import '../material_async_button_theme.dart'; + +enum _IconVariant { standard, filled, filledTonal, outlined } + +/// Async-aware [IconButton]. Includes all four Material 3 flavors: +/// [IconAsyncButton.new], [IconAsyncButton.filled], +/// [IconAsyncButton.filledTonal], [IconAsyncButton.outlined]. +/// +/// The [icon] is swapped with [loadingChild]/[successChild]/[errorChild] +/// during the corresponding state. +class IconAsyncButton extends StatelessWidget { + const IconAsyncButton({ + super.key, + required this.onPressed, + required this.icon, + this.iconSize, + this.visualDensity, + this.padding, + this.alignment, + this.splashRadius, + this.color, + this.focusColor, + this.hoverColor, + this.highlightColor, + this.splashColor, + this.disabledColor, + this.mouseCursor, + this.focusNode, + this.autofocus = false, + this.tooltip, + this.enableFeedback, + this.constraints, + this.style, + this.isSelected, + this.selectedIcon, + this.controller, + this.onSuccess, + this.onError, + this.onStateChanged, + this.confirmBeforePress, + this.errorBuilder, + this.loadingChild, + this.successChild, + this.errorChild, + this.disabled = false, + this.switchDuration, + this.transitionBuilder, + this.successDisplayDuration, + this.errorDisplayDuration, + this.cooldownDuration, + this.animateSize, + this.hapticOn, + this.announceSemantics, + this.rethrowErrors, + }) : _variant = _IconVariant.standard; + + const IconAsyncButton.filled({ + super.key, + required this.onPressed, + required this.icon, + this.iconSize, + this.visualDensity, + this.padding, + this.alignment, + this.splashRadius, + this.color, + this.focusColor, + this.hoverColor, + this.highlightColor, + this.splashColor, + this.disabledColor, + this.mouseCursor, + this.focusNode, + this.autofocus = false, + this.tooltip, + this.enableFeedback, + this.constraints, + this.style, + this.isSelected, + this.selectedIcon, + this.controller, + this.onSuccess, + this.onError, + this.onStateChanged, + this.confirmBeforePress, + this.errorBuilder, + this.loadingChild, + this.successChild, + this.errorChild, + this.disabled = false, + this.switchDuration, + this.transitionBuilder, + this.successDisplayDuration, + this.errorDisplayDuration, + this.cooldownDuration, + this.animateSize, + this.hapticOn, + this.announceSemantics, + this.rethrowErrors, + }) : _variant = _IconVariant.filled; + + const IconAsyncButton.filledTonal({ + super.key, + required this.onPressed, + required this.icon, + this.iconSize, + this.visualDensity, + this.padding, + this.alignment, + this.splashRadius, + this.color, + this.focusColor, + this.hoverColor, + this.highlightColor, + this.splashColor, + this.disabledColor, + this.mouseCursor, + this.focusNode, + this.autofocus = false, + this.tooltip, + this.enableFeedback, + this.constraints, + this.style, + this.isSelected, + this.selectedIcon, + this.controller, + this.onSuccess, + this.onError, + this.onStateChanged, + this.confirmBeforePress, + this.errorBuilder, + this.loadingChild, + this.successChild, + this.errorChild, + this.disabled = false, + this.switchDuration, + this.transitionBuilder, + this.successDisplayDuration, + this.errorDisplayDuration, + this.cooldownDuration, + this.animateSize, + this.hapticOn, + this.announceSemantics, + this.rethrowErrors, + }) : _variant = _IconVariant.filledTonal; + + const IconAsyncButton.outlined({ + super.key, + required this.onPressed, + required this.icon, + this.iconSize, + this.visualDensity, + this.padding, + this.alignment, + this.splashRadius, + this.color, + this.focusColor, + this.hoverColor, + this.highlightColor, + this.splashColor, + this.disabledColor, + this.mouseCursor, + this.focusNode, + this.autofocus = false, + this.tooltip, + this.enableFeedback, + this.constraints, + this.style, + this.isSelected, + this.selectedIcon, + this.controller, + this.onSuccess, + this.onError, + this.onStateChanged, + this.confirmBeforePress, + this.errorBuilder, + this.loadingChild, + this.successChild, + this.errorChild, + this.disabled = false, + this.switchDuration, + this.transitionBuilder, + this.successDisplayDuration, + this.errorDisplayDuration, + this.cooldownDuration, + this.animateSize, + this.hapticOn, + this.announceSemantics, + this.rethrowErrors, + }) : _variant = _IconVariant.outlined; + + final Future Function()? onPressed; + final Widget icon; + final double? iconSize; + final VisualDensity? visualDensity; + final EdgeInsetsGeometry? padding; + final AlignmentGeometry? alignment; + final double? splashRadius; + final Color? color; + final Color? focusColor; + final Color? hoverColor; + final Color? highlightColor; + final Color? splashColor; + final Color? disabledColor; + final MouseCursor? mouseCursor; + final FocusNode? focusNode; + final bool autofocus; + final String? tooltip; + final bool? enableFeedback; + final BoxConstraints? constraints; + final ButtonStyle? style; + final bool? isSelected; + final Widget? selectedIcon; + final _IconVariant _variant; + + final AsyncButtonController? controller; + final VoidCallback? onSuccess; + final void Function(Object error, StackTrace stackTrace)? onError; + final ValueChanged? onStateChanged; + final Future Function(BuildContext context)? confirmBeforePress; + final Widget Function(BuildContext context, Object error, StackTrace? stackTrace)? + errorBuilder; + final Widget? loadingChild; + final Widget? successChild; + final Widget? errorChild; + final bool disabled; + final Duration? switchDuration; + final AnimatedSwitcherTransitionBuilder? transitionBuilder; + final Duration? successDisplayDuration; + final Duration? errorDisplayDuration; + final Duration? cooldownDuration; + final bool? animateSize; + final HapticOn? hapticOn; + final bool? announceSemantics; + final bool? rethrowErrors; + + @override + Widget build(BuildContext context) => AsyncButtonBuilder( + onPressed: onPressed, + controller: controller, + onSuccess: onSuccess, + onError: onError, + onStateChanged: onStateChanged, + confirmBeforePress: confirmBeforePress, + errorBuilder: errorBuilder, + loadingChild: loadingChild, + successChild: successChild, + errorChild: errorChild, + disabled: disabled, + switchDuration: switchDuration, + transitionBuilder: transitionBuilder, + successDisplayDuration: successDisplayDuration, + errorDisplayDuration: errorDisplayDuration, + cooldownDuration: cooldownDuration, + animateSize: animateSize, + hapticOn: hapticOn, + announceSemantics: announceSemantics, + rethrowErrors: rethrowErrors, + child: icon, + builder: (context, animatedChild, callback, _) { + return switch (_variant) { + _IconVariant.standard => IconButton( + onPressed: callback, + icon: animatedChild, + iconSize: iconSize, + visualDensity: visualDensity, + padding: padding, + alignment: alignment, + splashRadius: splashRadius, + color: color, + focusColor: focusColor, + hoverColor: hoverColor, + highlightColor: highlightColor, + splashColor: splashColor, + disabledColor: disabledColor, + mouseCursor: mouseCursor, + focusNode: focusNode, + autofocus: autofocus, + tooltip: tooltip, + enableFeedback: enableFeedback, + constraints: constraints, + style: style, + isSelected: isSelected, + selectedIcon: selectedIcon, + ), + _IconVariant.filled => IconButton.filled( + onPressed: callback, + icon: animatedChild, + iconSize: iconSize, + visualDensity: visualDensity, + padding: padding, + alignment: alignment, + splashRadius: splashRadius, + color: color, + focusColor: focusColor, + hoverColor: hoverColor, + highlightColor: highlightColor, + splashColor: splashColor, + disabledColor: disabledColor, + mouseCursor: mouseCursor, + focusNode: focusNode, + autofocus: autofocus, + tooltip: tooltip, + enableFeedback: enableFeedback, + constraints: constraints, + style: style, + isSelected: isSelected, + selectedIcon: selectedIcon, + ), + _IconVariant.filledTonal => IconButton.filledTonal( + onPressed: callback, + icon: animatedChild, + iconSize: iconSize, + visualDensity: visualDensity, + padding: padding, + alignment: alignment, + splashRadius: splashRadius, + color: color, + focusColor: focusColor, + hoverColor: hoverColor, + highlightColor: highlightColor, + splashColor: splashColor, + disabledColor: disabledColor, + mouseCursor: mouseCursor, + focusNode: focusNode, + autofocus: autofocus, + tooltip: tooltip, + enableFeedback: enableFeedback, + constraints: constraints, + style: style, + isSelected: isSelected, + selectedIcon: selectedIcon, + ), + _IconVariant.outlined => IconButton.outlined( + onPressed: callback, + icon: animatedChild, + iconSize: iconSize, + visualDensity: visualDensity, + padding: padding, + alignment: alignment, + splashRadius: splashRadius, + color: color, + focusColor: focusColor, + hoverColor: hoverColor, + highlightColor: highlightColor, + splashColor: splashColor, + disabledColor: disabledColor, + mouseCursor: mouseCursor, + focusNode: focusNode, + autofocus: autofocus, + tooltip: tooltip, + enableFeedback: enableFeedback, + constraints: constraints, + style: style, + isSelected: isSelected, + selectedIcon: selectedIcon, + ), + }; + }, + ); +} diff --git a/lib/src/buttons/outlined_async_button.dart b/lib/src/buttons/outlined_async_button.dart new file mode 100644 index 0000000..a7dfd2a --- /dev/null +++ b/lib/src/buttons/outlined_async_button.dart @@ -0,0 +1,169 @@ +import 'package:flutter/material.dart'; + +import '../async_button_builder.dart'; +import '../async_button_controller.dart'; +import '../async_button_state.dart'; +import '../material_async_button_theme.dart'; + +/// Async-aware [OutlinedButton]. +class OutlinedAsyncButton extends StatelessWidget { + const OutlinedAsyncButton({ + super.key, + required this.onPressed, + required this.child, + this.onLongPress, + this.onHover, + this.onFocusChange, + this.style, + this.focusNode, + this.autofocus = false, + this.clipBehavior, + this.statesController, + this.controller, + this.onSuccess, + this.onError, + this.onStateChanged, + this.confirmBeforePress, + this.errorBuilder, + this.loadingChild, + this.successChild, + this.errorChild, + this.disabled = false, + this.switchDuration, + this.transitionBuilder, + this.successDisplayDuration, + this.errorDisplayDuration, + this.cooldownDuration, + this.animateSize, + this.hapticOn, + this.announceSemantics, + this.rethrowErrors, + }) : _icon = null, + _iconAlignment = null; + + const OutlinedAsyncButton.icon({ + super.key, + required this.onPressed, + required Widget icon, + required Widget label, + this.onLongPress, + this.onHover, + this.onFocusChange, + this.style, + this.focusNode, + this.autofocus = false, + this.clipBehavior, + this.statesController, + IconAlignment? iconAlignment, + this.controller, + this.onSuccess, + this.onError, + this.onStateChanged, + this.confirmBeforePress, + this.errorBuilder, + this.loadingChild, + this.successChild, + this.errorChild, + this.disabled = false, + this.switchDuration, + this.transitionBuilder, + this.successDisplayDuration, + this.errorDisplayDuration, + this.cooldownDuration, + this.animateSize, + this.hapticOn, + this.announceSemantics, + this.rethrowErrors, + }) : _icon = icon, + _iconAlignment = iconAlignment, + child = label; + + final Future Function()? onPressed; + final Widget child; + final VoidCallback? onLongPress; + final ValueChanged? onHover; + final ValueChanged? onFocusChange; + final ButtonStyle? style; + final FocusNode? focusNode; + final bool autofocus; + final Clip? clipBehavior; + final WidgetStatesController? statesController; + final Widget? _icon; + final IconAlignment? _iconAlignment; + + final AsyncButtonController? controller; + final VoidCallback? onSuccess; + final void Function(Object error, StackTrace stackTrace)? onError; + final ValueChanged? onStateChanged; + final Future Function(BuildContext context)? confirmBeforePress; + final Widget Function(BuildContext context, Object error, StackTrace? stackTrace)? + errorBuilder; + final Widget? loadingChild; + final Widget? successChild; + final Widget? errorChild; + final bool disabled; + final Duration? switchDuration; + final AnimatedSwitcherTransitionBuilder? transitionBuilder; + final Duration? successDisplayDuration; + final Duration? errorDisplayDuration; + final Duration? cooldownDuration; + final bool? animateSize; + final HapticOn? hapticOn; + final bool? announceSemantics; + final bool? rethrowErrors; + + @override + Widget build(BuildContext context) => AsyncButtonBuilder( + onPressed: onPressed, + controller: controller, + onSuccess: onSuccess, + onError: onError, + onStateChanged: onStateChanged, + confirmBeforePress: confirmBeforePress, + errorBuilder: errorBuilder, + loadingChild: loadingChild, + successChild: successChild, + errorChild: errorChild, + disabled: disabled, + switchDuration: switchDuration, + transitionBuilder: transitionBuilder, + successDisplayDuration: successDisplayDuration, + errorDisplayDuration: errorDisplayDuration, + cooldownDuration: cooldownDuration, + animateSize: animateSize, + hapticOn: hapticOn, + announceSemantics: announceSemantics, + rethrowErrors: rethrowErrors, + child: child, + builder: (context, animatedChild, callback, _) { + if (_icon != null) { + return OutlinedButton.icon( + onPressed: callback, + onLongPress: callback == null ? null : onLongPress, + onHover: onHover, + onFocusChange: onFocusChange, + style: style, + focusNode: focusNode, + autofocus: autofocus, + clipBehavior: clipBehavior ?? Clip.none, + statesController: statesController, + iconAlignment: _iconAlignment, + icon: _icon, + label: animatedChild, + ); + } + return OutlinedButton( + onPressed: callback, + onLongPress: callback == null ? null : onLongPress, + onHover: onHover, + onFocusChange: onFocusChange, + style: style, + focusNode: focusNode, + autofocus: autofocus, + clipBehavior: clipBehavior ?? Clip.none, + statesController: statesController, + child: animatedChild, + ); + }, + ); +} diff --git a/lib/src/buttons/text_async_button.dart b/lib/src/buttons/text_async_button.dart new file mode 100644 index 0000000..39a1722 --- /dev/null +++ b/lib/src/buttons/text_async_button.dart @@ -0,0 +1,169 @@ +import 'package:flutter/material.dart'; + +import '../async_button_builder.dart'; +import '../async_button_controller.dart'; +import '../async_button_state.dart'; +import '../material_async_button_theme.dart'; + +/// Async-aware [TextButton]. +class TextAsyncButton extends StatelessWidget { + const TextAsyncButton({ + super.key, + required this.onPressed, + required this.child, + this.onLongPress, + this.onHover, + this.onFocusChange, + this.style, + this.focusNode, + this.autofocus = false, + this.clipBehavior, + this.statesController, + this.controller, + this.onSuccess, + this.onError, + this.onStateChanged, + this.confirmBeforePress, + this.errorBuilder, + this.loadingChild, + this.successChild, + this.errorChild, + this.disabled = false, + this.switchDuration, + this.transitionBuilder, + this.successDisplayDuration, + this.errorDisplayDuration, + this.cooldownDuration, + this.animateSize, + this.hapticOn, + this.announceSemantics, + this.rethrowErrors, + }) : _icon = null, + _iconAlignment = null; + + const TextAsyncButton.icon({ + super.key, + required this.onPressed, + required Widget icon, + required Widget label, + this.onLongPress, + this.onHover, + this.onFocusChange, + this.style, + this.focusNode, + this.autofocus = false, + this.clipBehavior, + this.statesController, + IconAlignment? iconAlignment, + this.controller, + this.onSuccess, + this.onError, + this.onStateChanged, + this.confirmBeforePress, + this.errorBuilder, + this.loadingChild, + this.successChild, + this.errorChild, + this.disabled = false, + this.switchDuration, + this.transitionBuilder, + this.successDisplayDuration, + this.errorDisplayDuration, + this.cooldownDuration, + this.animateSize, + this.hapticOn, + this.announceSemantics, + this.rethrowErrors, + }) : _icon = icon, + _iconAlignment = iconAlignment, + child = label; + + final Future Function()? onPressed; + final Widget child; + final VoidCallback? onLongPress; + final ValueChanged? onHover; + final ValueChanged? onFocusChange; + final ButtonStyle? style; + final FocusNode? focusNode; + final bool autofocus; + final Clip? clipBehavior; + final WidgetStatesController? statesController; + final Widget? _icon; + final IconAlignment? _iconAlignment; + + final AsyncButtonController? controller; + final VoidCallback? onSuccess; + final void Function(Object error, StackTrace stackTrace)? onError; + final ValueChanged? onStateChanged; + final Future Function(BuildContext context)? confirmBeforePress; + final Widget Function(BuildContext context, Object error, StackTrace? stackTrace)? + errorBuilder; + final Widget? loadingChild; + final Widget? successChild; + final Widget? errorChild; + final bool disabled; + final Duration? switchDuration; + final AnimatedSwitcherTransitionBuilder? transitionBuilder; + final Duration? successDisplayDuration; + final Duration? errorDisplayDuration; + final Duration? cooldownDuration; + final bool? animateSize; + final HapticOn? hapticOn; + final bool? announceSemantics; + final bool? rethrowErrors; + + @override + Widget build(BuildContext context) => AsyncButtonBuilder( + onPressed: onPressed, + controller: controller, + onSuccess: onSuccess, + onError: onError, + onStateChanged: onStateChanged, + confirmBeforePress: confirmBeforePress, + errorBuilder: errorBuilder, + loadingChild: loadingChild, + successChild: successChild, + errorChild: errorChild, + disabled: disabled, + switchDuration: switchDuration, + transitionBuilder: transitionBuilder, + successDisplayDuration: successDisplayDuration, + errorDisplayDuration: errorDisplayDuration, + cooldownDuration: cooldownDuration, + animateSize: animateSize, + hapticOn: hapticOn, + announceSemantics: announceSemantics, + rethrowErrors: rethrowErrors, + child: child, + builder: (context, animatedChild, callback, _) { + if (_icon != null) { + return TextButton.icon( + onPressed: callback, + onLongPress: callback == null ? null : onLongPress, + onHover: onHover, + onFocusChange: onFocusChange, + style: style, + focusNode: focusNode, + autofocus: autofocus, + clipBehavior: clipBehavior ?? Clip.none, + statesController: statesController, + iconAlignment: _iconAlignment, + icon: _icon, + label: animatedChild, + ); + } + return TextButton( + onPressed: callback, + onLongPress: callback == null ? null : onLongPress, + onHover: onHover, + onFocusChange: onFocusChange, + style: style, + focusNode: focusNode, + autofocus: autofocus, + clipBehavior: clipBehavior ?? Clip.none, + statesController: statesController, + child: animatedChild, + ); + }, + ); +} diff --git a/lib/src/material_async_button_theme.dart b/lib/src/material_async_button_theme.dart new file mode 100644 index 0000000..7cb28f3 --- /dev/null +++ b/lib/src/material_async_button_theme.dart @@ -0,0 +1,304 @@ +import 'package:flutter/material.dart'; + +/// Which haptic event, if any, to fire on state transitions. +enum HapticOn { none, success, error, both } + +/// App-wide defaults for `material_async_button` widgets, attached as a +/// [ThemeExtension] on [ThemeData]. +/// +/// Resolution order for any field: per-widget value, then theme value, then +/// the hard-coded fallback documented on each field. +/// +/// Use [MaterialAsyncButtonTheme.material] for an opinionated baseline that +/// mirrors what most apps want; otherwise build the extension yourself with +/// only the fields you care about. +/// +/// ```dart +/// MaterialApp( +/// theme: ThemeData(extensions: [MaterialAsyncButtonTheme.material()]), +/// ) +/// ``` +@immutable +class MaterialAsyncButtonTheme extends ThemeExtension { + const MaterialAsyncButtonTheme({ + this.loadingChild, + this.successChild, + this.errorChild, + this.switchDuration, + this.switchReverseDuration, + this.switchCurve, + this.switchInCurve, + this.switchOutCurve, + this.transitionBuilder, + this.successDisplayDuration, + this.errorDisplayDuration, + this.cooldownDuration, + this.animateSize, + this.sizeCurve, + this.sizeAlignment, + this.sizeClipBehavior, + this.hapticOn, + this.announceSemantics, + this.rethrowErrors, + }); + + /// Convenience: an opinionated baseline. + /// + /// - 16x16 indeterminate spinner during loading + /// - check icon for 800ms after success + /// - error icon for 800ms after error + /// - 200ms cross-fade between states + /// - light haptic on success and error + /// - announces state changes to assistive tech + factory MaterialAsyncButtonTheme.material({ + Color? loadingColor, + Color? successColor, + Color? errorColor, + }) => + MaterialAsyncButtonTheme( + loadingChild: _DefaultLoadingChild(color: loadingColor), + successChild: _DefaultSuccessIcon(color: successColor), + errorChild: _DefaultErrorIcon(color: errorColor), + switchDuration: const Duration(milliseconds: 200), + switchReverseDuration: const Duration(milliseconds: 200), + successDisplayDuration: const Duration(milliseconds: 800), + errorDisplayDuration: const Duration(milliseconds: 800), + animateSize: true, + hapticOn: HapticOn.both, + announceSemantics: true, + ); + + /// Shown in place of [child] while the future is in flight. + /// Falls back to a 16x16 [CircularProgressIndicator] when null. + final Widget? loadingChild; + + /// Shown after success for [successDisplayDuration]. Null = keep the + /// original child visible (no visual swap, only the idle delay applies). + final Widget? successChild; + + /// Shown after error for [errorDisplayDuration]. Null = keep the + /// original child visible. + final Widget? errorChild; + + /// Cross-fade duration between state widgets. + /// Falls back to 200ms when null. + final Duration? switchDuration; + final Duration? switchReverseDuration; + + /// Convenience: applied to both [switchInCurve] and [switchOutCurve] + /// unless one of those is set explicitly. + final Curve? switchCurve; + final Curve? switchInCurve; + final Curve? switchOutCurve; + + final AnimatedSwitcherTransitionBuilder? transitionBuilder; + + /// How long [successChild] is shown before returning to idle. Defaults to + /// [Duration.zero] (immediate return). + final Duration? successDisplayDuration; + + /// How long [errorChild] is shown before returning to idle. Defaults to + /// [Duration.zero]. + final Duration? errorDisplayDuration; + + /// After a success/error display, keep the button disabled for this long + /// to prevent accidental double-submits. Defaults to [Duration.zero]. + final Duration? cooldownDuration; + + /// Whether to animate the implicit size between state widgets of differing + /// dimensions. Falls back to `false`. + final bool? animateSize; + final Curve? sizeCurve; + final AlignmentGeometry? sizeAlignment; + final Clip? sizeClipBehavior; + + /// Whether to fire a [HapticFeedback] on success / error transitions. + /// Defaults to [HapticOn.none]. + final HapticOn? hapticOn; + + /// Whether to announce state changes via [SemanticsService.announce]. + /// Defaults to `false`. + final bool? announceSemantics; + + /// If true, errors from `onPressed` are rethrown after the error state is + /// displayed. Useful when a caller awaits the future. Defaults to `false`. + final bool? rethrowErrors; + + static const MaterialAsyncButtonTheme empty = MaterialAsyncButtonTheme(); + + static MaterialAsyncButtonTheme of(BuildContext context) => + Theme.of(context).extension() ?? empty; + + @override + MaterialAsyncButtonTheme copyWith({ + Widget? loadingChild, + Widget? successChild, + Widget? errorChild, + Duration? switchDuration, + Duration? switchReverseDuration, + Curve? switchCurve, + Curve? switchInCurve, + Curve? switchOutCurve, + AnimatedSwitcherTransitionBuilder? transitionBuilder, + Duration? successDisplayDuration, + Duration? errorDisplayDuration, + Duration? cooldownDuration, + bool? animateSize, + Curve? sizeCurve, + AlignmentGeometry? sizeAlignment, + Clip? sizeClipBehavior, + HapticOn? hapticOn, + bool? announceSemantics, + bool? rethrowErrors, + }) => + MaterialAsyncButtonTheme( + loadingChild: loadingChild ?? this.loadingChild, + successChild: successChild ?? this.successChild, + errorChild: errorChild ?? this.errorChild, + switchDuration: switchDuration ?? this.switchDuration, + switchReverseDuration: + switchReverseDuration ?? this.switchReverseDuration, + switchCurve: switchCurve ?? this.switchCurve, + switchInCurve: switchInCurve ?? this.switchInCurve, + switchOutCurve: switchOutCurve ?? this.switchOutCurve, + transitionBuilder: transitionBuilder ?? this.transitionBuilder, + successDisplayDuration: + successDisplayDuration ?? this.successDisplayDuration, + errorDisplayDuration: + errorDisplayDuration ?? this.errorDisplayDuration, + cooldownDuration: cooldownDuration ?? this.cooldownDuration, + animateSize: animateSize ?? this.animateSize, + sizeCurve: sizeCurve ?? this.sizeCurve, + sizeAlignment: sizeAlignment ?? this.sizeAlignment, + sizeClipBehavior: sizeClipBehavior ?? this.sizeClipBehavior, + hapticOn: hapticOn ?? this.hapticOn, + announceSemantics: announceSemantics ?? this.announceSemantics, + rethrowErrors: rethrowErrors ?? this.rethrowErrors, + ); + + @override + MaterialAsyncButtonTheme lerp( + covariant ThemeExtension? other, + double t, + ) { + if (other is! MaterialAsyncButtonTheme) return this; + // Widgets and enums don't lerp meaningfully; snap at the halfway point. + final snap = t < 0.5; + return MaterialAsyncButtonTheme( + loadingChild: snap ? loadingChild : other.loadingChild, + successChild: snap ? successChild : other.successChild, + errorChild: snap ? errorChild : other.errorChild, + switchDuration: _lerpDuration(switchDuration, other.switchDuration, t), + switchReverseDuration: + _lerpDuration(switchReverseDuration, other.switchReverseDuration, t), + switchCurve: snap ? switchCurve : other.switchCurve, + switchInCurve: snap ? switchInCurve : other.switchInCurve, + switchOutCurve: snap ? switchOutCurve : other.switchOutCurve, + transitionBuilder: snap ? transitionBuilder : other.transitionBuilder, + successDisplayDuration: + _lerpDuration(successDisplayDuration, other.successDisplayDuration, t), + errorDisplayDuration: + _lerpDuration(errorDisplayDuration, other.errorDisplayDuration, t), + cooldownDuration: + _lerpDuration(cooldownDuration, other.cooldownDuration, t), + animateSize: snap ? animateSize : other.animateSize, + sizeCurve: snap ? sizeCurve : other.sizeCurve, + sizeAlignment: AlignmentGeometry.lerp(sizeAlignment, other.sizeAlignment, t), + sizeClipBehavior: snap ? sizeClipBehavior : other.sizeClipBehavior, + hapticOn: snap ? hapticOn : other.hapticOn, + announceSemantics: snap ? announceSemantics : other.announceSemantics, + rethrowErrors: snap ? rethrowErrors : other.rethrowErrors, + ); + } + + static Duration? _lerpDuration(Duration? a, Duration? b, double t) { + if (a == null && b == null) return null; + final aMs = (a ?? Duration.zero).inMicroseconds; + final bMs = (b ?? Duration.zero).inMicroseconds; + return Duration(microseconds: (aMs + (bMs - aMs) * t).round()); + } + + @override + bool operator ==(Object other) => + identical(this, other) || + other is MaterialAsyncButtonTheme && + loadingChild == other.loadingChild && + successChild == other.successChild && + errorChild == other.errorChild && + switchDuration == other.switchDuration && + switchReverseDuration == other.switchReverseDuration && + switchCurve == other.switchCurve && + switchInCurve == other.switchInCurve && + switchOutCurve == other.switchOutCurve && + transitionBuilder == other.transitionBuilder && + successDisplayDuration == other.successDisplayDuration && + errorDisplayDuration == other.errorDisplayDuration && + cooldownDuration == other.cooldownDuration && + animateSize == other.animateSize && + sizeCurve == other.sizeCurve && + sizeAlignment == other.sizeAlignment && + sizeClipBehavior == other.sizeClipBehavior && + hapticOn == other.hapticOn && + announceSemantics == other.announceSemantics && + rethrowErrors == other.rethrowErrors; + + @override + int get hashCode => Object.hashAll([ + loadingChild, + successChild, + errorChild, + switchDuration, + switchReverseDuration, + switchCurve, + switchInCurve, + switchOutCurve, + transitionBuilder, + successDisplayDuration, + errorDisplayDuration, + cooldownDuration, + animateSize, + sizeCurve, + sizeAlignment, + sizeClipBehavior, + hapticOn, + announceSemantics, + rethrowErrors, + ]); +} + +class _DefaultLoadingChild extends StatelessWidget { + const _DefaultLoadingChild({this.color}); + + final Color? color; + + @override + Widget build(BuildContext context) { + return SizedBox.square( + dimension: 16, + child: CircularProgressIndicator( + strokeWidth: 2, + valueColor: color == null ? null : AlwaysStoppedAnimation(color!), + ), + ); + } +} + +class _DefaultSuccessIcon extends StatelessWidget { + const _DefaultSuccessIcon({this.color}); + + final Color? color; + + @override + Widget build(BuildContext context) => + Icon(Icons.check, color: color ?? Theme.of(context).colorScheme.primary); +} + +class _DefaultErrorIcon extends StatelessWidget { + const _DefaultErrorIcon({this.color}); + + final Color? color; + + @override + Widget build(BuildContext context) => + Icon(Icons.error, color: color ?? Theme.of(context).colorScheme.error); +} diff --git a/pubspec.yaml b/pubspec.yaml index 71c15f1..b9cfbf0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,18 +1,37 @@ -name: async_button_builder -description: A builder to wrap around buttons that handles loading, disabled, - error and success states -version: 3.0.0+1 -homepage: https://github.com/Nolence/async_button/tree/main/packages/async_button_builder +name: material_async_button +description: >- + Drop-in async wrappers for Flutter Material buttons. Adds loading, success, + and error states with theming via ThemeExtension and external control via a + controller. +version: 1.0.0 +repository: https://github.com/esenmx/async_button_builder +issue_tracker: https://github.com/esenmx/async_button_builder/issues + +topics: + - button + - async + - material + - loading + - form environment: - sdk: ">=3.0.0 <4.0.0" - flutter: ">=2.0.0" + sdk: ^3.10.0 + flutter: ">=3.40.0" dependencies: flutter: sdk: flutter + meta: ^1.16.0 dev_dependencies: flutter_test: sdk: flutter - lint: ^2.8.0 + flutter_lints: ^5.0.0 + +screenshots: + - description: Elevated button cycling through loading, success, and error. + path: screenshots/ezgif-7-61c436edaec2.gif + - description: State-driven background color via the builder. + path: screenshots/ezgif-7-a971c6afaabf.gif + - description: Custom Material button with bounce-in loading transition. + path: screenshots/ezgif-7-4088c909ba83.gif diff --git a/test/async_button_builder_test.dart b/test/async_button_builder_test.dart index 3b8b7af..166479e 100644 --- a/test/async_button_builder_test.dart +++ b/test/async_button_builder_test.dart @@ -1,176 +1,337 @@ -import 'package:async_button_builder/async_button_builder.dart'; +import 'dart:async'; + import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:material_async_button/material_async_button.dart'; -void main() { - testWidgets('displays child text', (tester) async { - await tester.pumpWidget(MaterialApp( - home: AsyncButtonBuilder( - onPressed: () async { - await Future.delayed(const Duration(seconds: 1)); - }, - builder: (context, child, callback, state) { - return TextButton(onPressed: callback, child: child); - }, - child: const Text('click me'), - ), - )); - expect(find.text('click me'), findsOneWidget); - }); +Widget _wrap(Widget child) => + MaterialApp(home: Scaffold(body: Center(child: child))); - testWidgets('shows loading widget', (tester) async { - await tester.pumpWidget(MaterialApp( - home: AsyncButtonBuilder( - loadingWidget: const Text('loading'), - onPressed: () async { - await Future.delayed(const Duration(seconds: 1)); - }, - builder: (context, child, callback, state) { - return TextButton(onPressed: callback, child: child); - }, - child: const Text('click me'), - ), - )); +void main() { + group('AsyncButtonBuilder rendering', () { + testWidgets('shows child in idle state', (tester) async { + await tester.pumpWidget(_wrap(AsyncButtonBuilder( + onPressed: () async {}, + child: const Text('hello'), + builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + ))); + expect(find.text('hello'), findsOneWidget); + }); - await tester.tap(find.byType(TextButton)); + testWidgets('falls back to built-in spinner when no loadingChild', + (tester) async { + final completer = Completer(); + await tester.pumpWidget(_wrap(AsyncButtonBuilder( + onPressed: () => completer.future, + child: const Text('go'), + builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + ))); + await tester.tap(find.byType(TextButton)); + await tester.pump(); + expect(find.byType(CircularProgressIndicator), findsOneWidget); + completer.complete(); + await tester.pumpAndSettle(); + }); - // 1/10 of a second later, loading should be showing - await tester.pump(const Duration(milliseconds: 100)); + testWidgets('uses per-widget loadingChild when given', (tester) async { + final completer = Completer(); + await tester.pumpWidget(_wrap(AsyncButtonBuilder( + onPressed: () => completer.future, + child: const Text('go'), + loadingChild: const Text('spinning'), + builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + ))); + await tester.tap(find.byType(TextButton)); + await tester.pump(); + expect(find.text('spinning'), findsOneWidget); + completer.complete(); + await tester.pumpAndSettle(); + }); - expect(find.text('loading'), findsOneWidget); + testWidgets('theme loadingChild used when no per-widget override', + (tester) async { + final completer = Completer(); + await tester.pumpWidget(MaterialApp( + theme: ThemeData(extensions: const [ + MaterialAsyncButtonTheme(loadingChild: Text('themed-loading')), + ]), + home: Scaffold( + body: AsyncButtonBuilder( + onPressed: () => completer.future, + child: const Text('go'), + builder: (c, child, cb, _) => + TextButton(onPressed: cb, child: child), + ), + ), + )); + await tester.tap(find.byType(TextButton)); + await tester.pump(); + expect(find.text('themed-loading'), findsOneWidget); + completer.complete(); + await tester.pumpAndSettle(); + }); - // Let the widget continue to settle otherwise I won't dispose timers - // correctly. TODO: Explain why .900 is the magic number - await tester.pumpAndSettle(const Duration(milliseconds: 900)); + testWidgets('widget loadingChild beats theme', (tester) async { + final completer = Completer(); + await tester.pumpWidget(MaterialApp( + theme: ThemeData(extensions: const [ + MaterialAsyncButtonTheme(loadingChild: Text('themed')), + ]), + home: Scaffold( + body: AsyncButtonBuilder( + onPressed: () => completer.future, + child: const Text('go'), + loadingChild: const Text('widget'), + builder: (c, child, cb, _) => + TextButton(onPressed: cb, child: child), + ), + ), + )); + await tester.tap(find.byType(TextButton)); + await tester.pump(); + expect(find.text('widget'), findsOneWidget); + expect(find.text('themed'), findsNothing); + completer.complete(); + await tester.pumpAndSettle(); + }); }); - testWidgets('shows error widget', (tester) async { - await tester.pumpWidget(MaterialApp( - home: AsyncButtonBuilder( - errorWidget: const Text('error'), - onPressed: () async => throw Exception(), - builder: (context, child, callback, state) { - return TextButton(onPressed: callback, child: child); + group('AsyncButtonBuilder transitions', () { + testWidgets('returns to child after success with zero display duration', + (tester) async { + await tester.pumpWidget(_wrap(AsyncButtonBuilder( + onPressed: () async {}, + child: const Text('label'), + builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + ))); + await tester.tap(find.byType(TextButton)); + await tester.pumpAndSettle(); + expect(find.text('label'), findsOneWidget); + }); + + testWidgets('shows successChild for successDisplayDuration', + (tester) async { + await tester.pumpWidget(_wrap(AsyncButtonBuilder( + onPressed: () async {}, + child: const Text('label'), + successChild: const Text('done!'), + successDisplayDuration: const Duration(milliseconds: 200), + builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + ))); + await tester.tap(find.byType(TextButton)); + await tester.pump(); + await tester.pump(); + expect(find.text('done!'), findsOneWidget); + await tester.pump(const Duration(milliseconds: 250)); + await tester.pumpAndSettle(); + expect(find.text('done!'), findsNothing); + expect(find.text('label'), findsOneWidget); + }); + + testWidgets('shows errorChild and exposes error to errorBuilder', + (tester) async { + Object? observed; + await tester.pumpWidget(_wrap(AsyncButtonBuilder( + onPressed: () async => throw StateError('boom'), + child: const Text('label'), + errorDisplayDuration: const Duration(milliseconds: 100), + errorBuilder: (c, err, st) { + observed = err; + return Text('err: ${err.toString().split(":").last.trim()}'); }, - child: const Text('click me'), - ), - )); + builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + ))); + await tester.tap(find.byType(TextButton)); + await tester.pump(); + await tester.pump(); + expect(observed, isA()); + expect(find.textContaining('err:'), findsOneWidget); + await tester.pump(const Duration(milliseconds: 200)); + await tester.pumpAndSettle(); + }); + }); + + group('AsyncButtonBuilder callbacks', () { + testWidgets('callback null when disabled', (tester) async { + await tester.pumpWidget(_wrap(AsyncButtonBuilder( + onPressed: () async {}, + disabled: true, + child: const Text('label'), + builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + ))); + final btn = tester.widget(find.byType(TextButton)); + expect(btn.onPressed, isNull); + }); + + testWidgets('callback null when onPressed is null', (tester) async { + await tester.pumpWidget(_wrap(AsyncButtonBuilder( + onPressed: null, + child: const Text('label'), + builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + ))); + final btn = tester.widget(find.byType(TextButton)); + expect(btn.onPressed, isNull); + }); + + testWidgets('onSuccess and onStateChanged fire', (tester) async { + var successCount = 0; + final changes = []; + await tester.pumpWidget(_wrap(AsyncButtonBuilder( + onPressed: () async {}, + onSuccess: () => successCount++, + onStateChanged: changes.add, + child: const Text('label'), + builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + ))); + await tester.tap(find.byType(TextButton)); + await tester.pumpAndSettle(); + expect(successCount, 1); + expect(changes.map((s) => s.runtimeType), + containsAllInOrder([ + AsyncButtonStateLoading, + AsyncButtonStateSuccess, + AsyncButtonStateIdle, + ])); + }); - await tester.tap(find.byType(TextButton)); - await tester.pump(const Duration(milliseconds: 100)); + testWidgets('onError fires with the thrown error', (tester) async { + Object? captured; + await tester.pumpWidget(_wrap(AsyncButtonBuilder( + onPressed: () async => throw StateError('x'), + onError: (e, _) => captured = e, + child: const Text('label'), + builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + ))); + await tester.tap(find.byType(TextButton)); + await tester.pumpAndSettle(); + expect(captured, isA()); + }); - expect(find.text('error'), findsOneWidget); + testWidgets('confirmBeforePress can cancel the press', (tester) async { + var ran = 0; + await tester.pumpWidget(_wrap(AsyncButtonBuilder( + onPressed: () async => ran++, + confirmBeforePress: (_) async => false, + child: const Text('label'), + builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + ))); + await tester.tap(find.byType(TextButton)); + await tester.pumpAndSettle(); + expect(ran, 0, + reason: 'onPressed should not run when confirm returns false.'); + }); }); - // testWidgets('error notification bubbles up', (tester) async { - // var idleCount = 0; - // var loadingCount = 0; - // var successCount = 0; - // var errorCount = 0; - - // await tester.pumpWidget(MaterialApp( - // home: NotificationListener( - // onNotification: (notification) { - // tester.printToConsole(notification.buttonState.toString()); - // switch (notification.buttonState) { - // case AsyncButtonStateIdle(): - // idleCount += 1; - // case AsyncButtonStateLoading(): - // loadingCount += 1; - // case AsyncButtonStateSuccess(): - // successCount += 1; - // case AsyncButtonStateError(): - // errorCount += 1; - // } - // return true; - // }, - // child: AsyncButtonBuilder( - // errorDuration: const Duration(milliseconds: 100), - // errorWidget: const Text('error'), - // notifications: true, - // onPressed: () async => throw Exception(), - // builder: (context, child, callback, state) { - // return TextButton(onPressed: callback, child: child); - // }, - // child: const Text('click me'), - // ), - // ), - // )); - // final button = - // find.byType(TextButton).evaluate().first.widget as TextButton; - - // expect( - // button.onPressed!.call, - // throwsA(isA()), - // ); - - // await tester.pump(const Duration(milliseconds: 200)); - - // expect(errorCount, 1); - // expect(idleCount, 1); - // expect(loadingCount, 1); - // expect(successCount, 0); - // }); - - testWidgets('Returns to child widget', (tester) async { - await tester.pumpWidget(MaterialApp( - home: AsyncButtonBuilder( - loadingWidget: const Text('loading'), - onPressed: () async { - await Future.delayed(const Duration(seconds: 1)); - }, - builder: (context, child, callback, state) { - return TextButton(onPressed: callback, child: child); - }, - child: const Text('click me'), - ), - )); + group('AsyncButtonBuilder external control', () { + testWidgets('GlobalKey.trigger() runs onPressed', (tester) async { + final key = GlobalKey(); + var ran = 0; + await tester.pumpWidget(_wrap(AsyncButtonBuilder( + key: key, + onPressed: () async => ran++, + child: const Text('label'), + builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + ))); + await key.currentState!.trigger(); + await tester.pumpAndSettle(); + expect(ran, 1); + }); - await tester.tap(find.byType(TextButton)); - await tester.pump(const Duration(milliseconds: 1000)); + testWidgets('AsyncButtonController.invalidate flips to error', + (tester) async { + final controller = AsyncButtonController(); + addTearDown(controller.dispose); + await tester.pumpWidget(_wrap(AsyncButtonBuilder( + controller: controller, + onPressed: () async {}, + child: const Text('label'), + errorChild: const Text('errored'), + errorDisplayDuration: const Duration(milliseconds: 100), + builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + ))); + controller.invalidate('bad'); + await tester.pump(); + expect(find.text('errored'), findsOneWidget); + await tester.pump(const Duration(milliseconds: 200)); + await tester.pumpAndSettle(); + }); - expect(find.text('loading'), findsNothing); - expect(find.text('click me'), findsOneWidget); + testWidgets('AsyncButtonController.reset clears mid-display', + (tester) async { + final controller = AsyncButtonController(); + addTearDown(controller.dispose); + await tester.pumpWidget(_wrap(AsyncButtonBuilder( + controller: controller, + onPressed: () async {}, + child: const Text('label'), + successChild: const Text('yay'), + successDisplayDuration: const Duration(seconds: 5), + builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + ))); + controller.markSuccess(); + await tester.pump(); + expect(find.text('yay'), findsOneWidget); + controller.reset(); + await tester.pump(); + expect(find.text('label'), findsOneWidget); + }); + + testWidgets( + 'swapping the external controller transfers listening without leak', + (tester) async { + final a = AsyncButtonController(); + final b = AsyncButtonController(); + addTearDown(() { + a.dispose(); + b.dispose(); + }); + final builder = (AsyncButtonController c) => AsyncButtonBuilder( + controller: c, + onPressed: () async {}, + successChild: const Text('done'), + successDisplayDuration: const Duration(milliseconds: 100), + child: const Text('child'), + builder: (ctx, child, cb, _) => + TextButton(onPressed: cb, child: child), + ); + await tester.pumpWidget(_wrap(builder(a))); + await tester.pumpWidget(_wrap(builder(b))); + // Mutating the OLD controller must not change the UI. + a.markSuccess(); + await tester.pump(); + expect(find.text('done'), findsNothing); + // New controller drives the UI. + b.markSuccess(); + await tester.pump(); + expect(find.text('done'), findsOneWidget); + await tester.pump(const Duration(milliseconds: 200)); + await tester.pumpAndSettle(); + }); }); - // TODO: Make it work on dropdown buttons - // AsyncButtonBuilder( - // child: Icon(Icons.arrow_upward), - // onPressed: (newValue) async { - // final oldValue = dropdownValue; - - // setState(() { - // dropdownValue = newValue; - // }); - - // await Future.delayed(Duration(seconds: 1)); - - // try { - // if (Random().nextBool()) { - // throw 'yikes'; - // } - // } catch (error) { - // setState(() { - // dropdownValue = oldValue; - // }); - // } - // }, - // builder: (context, child, callback, _) { - // return DropdownButton( - // // icon: SizedBox( - // // height: 16.0, - // // width: 16.0, - // // child: CircularProgressIndicator(), - // // ), - // onChanged: callback, - // items: ['one', 'two', 'three'] - // .map((value) => DropdownMenuItem( - // child: Text(value), - // value: value, - // )) - // .toList(), - // value: dropdownValue, - // ); - // }, - // ), + group('AsyncButtonBuilder timer hygiene (regression for old timer race)', () { + testWidgets('rapid invalidate then reset does not later re-flip to idle', + (tester) async { + final controller = AsyncButtonController(); + addTearDown(controller.dispose); + await tester.pumpWidget(_wrap(AsyncButtonBuilder( + controller: controller, + onPressed: () async {}, + child: const Text('child'), + errorChild: const Text('e'), + errorDisplayDuration: const Duration(milliseconds: 200), + builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + ))); + controller.invalidate('1'); + await tester.pump(); + // While in error display, manually mark success. The previous error + // timer must NOT fire and overwrite the new success state. + controller.markSuccess(); + await tester.pump(); + // Wait beyond the original error timer, less than success timer. + await tester.pump(const Duration(milliseconds: 250)); + // Default success duration is zero, so we should be back to idle. + expect(find.text('child'), findsOneWidget); + }); + }); } diff --git a/test/async_button_controller_test.dart b/test/async_button_controller_test.dart new file mode 100644 index 0000000..437435c --- /dev/null +++ b/test/async_button_controller_test.dart @@ -0,0 +1,286 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:material_async_button/material_async_button.dart'; + +void main() { + group('AsyncButtonController', () { + test('starts in idle by default', () { + final c = AsyncButtonController(); + expect(c.value, const AsyncButtonState.idle()); + expect(c.isIdle, isTrue); + expect(c.isLoading, isFalse); + expect(c.canTrigger, isFalse, + reason: 'No onPressed attached yet, cannot trigger.'); + c.dispose(); + }); + + test('honors initial state', () { + final c = AsyncButtonController(initial: const AsyncButtonState.loading()); + expect(c.isLoading, isTrue); + c.dispose(); + }); + + test('trigger no-ops when no onPressed is attached', () async { + final c = AsyncButtonController(); + await c.trigger(); + expect(c.isIdle, isTrue); + c.dispose(); + }); + + test('reset moves to idle and cancels timer', () async { + final c = AsyncButtonController() + ..attach( + onPressed: () async {}, + successDuration: const Duration(seconds: 5), + errorDuration: Duration.zero, + cooldownDuration: Duration.zero, + rethrowErrors: false, + ); + await c.trigger(); + // We're now in success state for 5s. Reset short-circuits. + expect(c.isSuccess, isTrue); + c.reset(); + expect(c.isIdle, isTrue); + c.dispose(); + }); + + test('invalidate forces error and reaches idle when duration zero', + () async { + final c = AsyncButtonController() + ..attach( + onPressed: null, + successDuration: Duration.zero, + errorDuration: Duration.zero, + cooldownDuration: Duration.zero, + rethrowErrors: false, + ); + c.invalidate('bad'); + expect(c.value, const AsyncButtonState.idle(), + reason: 'Zero error duration returns straight to idle.'); + c.dispose(); + }); + + test('invalidate forces error and stays there for errorDuration', + () async { + final c = AsyncButtonController() + ..attach( + onPressed: null, + successDuration: Duration.zero, + errorDuration: const Duration(milliseconds: 50), + cooldownDuration: Duration.zero, + rethrowErrors: false, + ); + c.invalidate('bad'); + expect(c.isError, isTrue); + expect(c.error, 'bad'); + await Future.delayed(const Duration(milliseconds: 70)); + expect(c.isIdle, isTrue); + c.dispose(); + }); + + test('markSuccess forces success state', () { + final c = AsyncButtonController() + ..attach( + onPressed: null, + successDuration: const Duration(seconds: 5), + errorDuration: Duration.zero, + cooldownDuration: Duration.zero, + rethrowErrors: false, + ); + c.markSuccess(); + expect(c.isSuccess, isTrue); + c.dispose(); + }); + + test('successful trigger transitions idle -> loading -> success -> idle', + () async { + final transitions = []; + final c = AsyncButtonController() + ..attach( + onPressed: () async => Future.delayed( + const Duration(milliseconds: 20)), + successDuration: const Duration(milliseconds: 20), + errorDuration: Duration.zero, + cooldownDuration: Duration.zero, + rethrowErrors: false, + ); + c.addListener(() => transitions.add(c.value)); + await c.trigger(); + // trigger awaited onPressed. Success has fired; idle is scheduled in 20ms. + await Future.delayed(const Duration(milliseconds: 50)); + expect( + transitions.map((s) => s.runtimeType).toList(), + containsAllInOrder([ + AsyncButtonStateLoading, + AsyncButtonStateSuccess, + AsyncButtonStateIdle, + ])); + c.dispose(); + }); + + test('failing trigger transitions idle -> loading -> error -> idle', + () async { + final transitions = []; + final c = AsyncButtonController() + ..attach( + onPressed: () async => throw StateError('oops'), + successDuration: Duration.zero, + errorDuration: const Duration(milliseconds: 20), + cooldownDuration: Duration.zero, + rethrowErrors: false, + ); + c.addListener(() => transitions.add(c.value)); + await c.trigger(); + await Future.delayed(const Duration(milliseconds: 50)); + expect( + transitions.map((s) => s.runtimeType).toList(), + containsAllInOrder([ + AsyncButtonStateLoading, + AsyncButtonStateError, + AsyncButtonStateIdle, + ])); + c.dispose(); + }); + + test('rethrowErrors=true bubbles the error to the caller', () async { + final c = AsyncButtonController() + ..attach( + onPressed: () async => throw StateError('oops'), + successDuration: Duration.zero, + errorDuration: Duration.zero, + cooldownDuration: Duration.zero, + rethrowErrors: true, + ); + await expectLater(c.trigger(), throwsA(isA())); + c.dispose(); + }); + + test('cooldown keeps canTrigger false after idle returns', () async { + final c = AsyncButtonController() + ..attach( + onPressed: () async {}, + successDuration: Duration.zero, + errorDuration: Duration.zero, + cooldownDuration: const Duration(milliseconds: 40), + rethrowErrors: false, + ); + await c.trigger(); + expect(c.isIdle, isTrue); + expect(c.isInCooldown, isTrue); + expect(c.canTrigger, isFalse); + await Future.delayed(const Duration(milliseconds: 60)); + expect(c.isInCooldown, isFalse); + expect(c.canTrigger, isTrue); + c.dispose(); + }); + + test('disposes cleanly without throwing for pending timers', () async { + final c = AsyncButtonController() + ..attach( + onPressed: null, + successDuration: const Duration(seconds: 5), + errorDuration: Duration.zero, + cooldownDuration: Duration.zero, + rethrowErrors: false, + ); + c.markSuccess(); + c.dispose(); + // Wait beyond the timer schedule; the disposed flag should suppress + // notifyListeners on the post-dispose callback. + await Future.delayed(const Duration(milliseconds: 10)); + }); + }); + + group('AsyncButtonController concurrent calls', () { + test('trigger is a no-op while already loading', () async { + var calls = 0; + final completer = Completer(); + final c = AsyncButtonController() + ..attach( + onPressed: () async { + calls++; + await completer.future; + }, + successDuration: Duration.zero, + errorDuration: Duration.zero, + cooldownDuration: Duration.zero, + rethrowErrors: false, + ); + // First trigger starts loading. + final f1 = c.trigger(); + // Second trigger should no-op because state is loading. + final f2 = c.trigger(); + expect(c.isLoading, isTrue); + completer.complete(); + await Future.wait([f1, f2]); + expect(calls, 1); + c.dispose(); + }); + + test('reset mid-onPressed stops the success transition', () async { + final completer = Completer(); + final c = AsyncButtonController() + ..attach( + onPressed: () async => completer.future, + successDuration: Duration.zero, + errorDuration: Duration.zero, + cooldownDuration: Duration.zero, + rethrowErrors: false, + ); + final f = c.trigger(); + expect(c.isLoading, isTrue); + c.reset(); + completer.complete(); + await f; + // Should remain idle; trigger's post-await branch sees non-loading and bails. + expect(c.isIdle, isTrue); + c.dispose(); + }); + }); + + group('AsyncButtonController utility getters', () { + test('error/stackTrace getters return null off-error', () { + final c = AsyncButtonController(); + expect(c.error, isNull); + expect(c.stackTrace, isNull); + c.dispose(); + }); + + test('error/stackTrace getters expose the error variant payload', () { + final st = StackTrace.current; + final c = AsyncButtonController( + initial: AsyncButtonState.error('boom', st)); + expect(c.error, 'boom'); + expect(c.stackTrace, st); + c.dispose(); + }); + }); + + testWidgets('value listenable interop with ValueListenableBuilder', + (tester) async { + final c = AsyncButtonController(); + addTearDown(c.dispose); + + String label(AsyncButtonState s) => switch (s) { + AsyncButtonStateIdle() => 'idle', + AsyncButtonStateLoading() => 'loading', + AsyncButtonStateSuccess() => 'success', + AsyncButtonStateError() => 'error', + }; + + await tester.pumpWidget(MaterialApp( + home: ValueListenableBuilder( + valueListenable: c, + builder: (_, state, __) => Text(label(state), + textDirection: TextDirection.ltr), + ), + )); + expect(find.text('idle'), findsOneWidget); + + c.markSuccess(); + await tester.pump(); + expect(find.text('success'), findsOneWidget); + }); +} diff --git a/test/async_button_state_test.dart b/test/async_button_state_test.dart new file mode 100644 index 0000000..b6cd364 --- /dev/null +++ b/test/async_button_state_test.dart @@ -0,0 +1,76 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:material_async_button/material_async_button.dart'; + +void main() { + group('AsyncButtonState equality', () { + test('idle equals idle', () { + expect(const AsyncButtonState.idle(), const AsyncButtonState.idle()); + expect(const AsyncButtonState.idle().hashCode, + const AsyncButtonState.idle().hashCode); + }); + + test('loading equals loading', () { + expect( + const AsyncButtonState.loading(), const AsyncButtonState.loading()); + }); + + test('success equals success', () { + expect( + const AsyncButtonState.success(), const AsyncButtonState.success()); + }); + + test('error equals error by error object', () { + final e = Exception('boom'); + expect(AsyncButtonState.error(e), AsyncButtonState.error(e)); + // Different errors are not equal. + expect(AsyncButtonState.error(Exception('a')) == + AsyncButtonState.error(Exception('a')), + isFalse, + reason: 'Two distinct Exception instances are not equal in Dart.'); + }); + + test('different variants are not equal', () { + expect( + const AsyncButtonState.idle() == const AsyncButtonState.loading(), + isFalse); + expect( + const AsyncButtonState.success() == const AsyncButtonState.idle(), + isFalse); + }); + }); + + group('AsyncButtonState toString', () { + test('readable identifiers', () { + expect(const AsyncButtonState.idle().toString(), + 'AsyncButtonState.idle()'); + expect(const AsyncButtonState.loading().toString(), + 'AsyncButtonState.loading()'); + expect(const AsyncButtonState.success().toString(), + 'AsyncButtonState.success()'); + expect(AsyncButtonState.error('boom').toString(), + 'AsyncButtonState.error(boom)'); + }); + }); + + group('AsyncButtonState pattern matching', () { + test('exhaustive switch compiles and dispatches', () { + String describe(AsyncButtonState s) => switch (s) { + AsyncButtonStateIdle() => 'idle', + AsyncButtonStateLoading() => 'loading', + AsyncButtonStateSuccess() => 'success', + AsyncButtonStateError() => 'error', + }; + expect(describe(const AsyncButtonState.idle()), 'idle'); + expect(describe(const AsyncButtonState.loading()), 'loading'); + expect(describe(const AsyncButtonState.success()), 'success'); + expect(describe(AsyncButtonState.error('x')), 'error'); + }); + + test('error variant exposes error and stack trace', () { + final st = StackTrace.current; + final s = AsyncButtonState.error('boom', st); + expect(s.error, 'boom'); + expect(s.stackTrace, st); + }); + }); +} diff --git a/test/elevated_async_button_test.dart b/test/elevated_async_button_test.dart new file mode 100644 index 0000000..700909c --- /dev/null +++ b/test/elevated_async_button_test.dart @@ -0,0 +1,76 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:material_async_button/material_async_button.dart'; + +Widget _wrap(Widget child) => + MaterialApp(home: Scaffold(body: Center(child: child))); + +void main() { + group('ElevatedAsyncButton', () { + testWidgets('renders an ElevatedButton with the child', (tester) async { + await tester.pumpWidget(_wrap(ElevatedAsyncButton( + onPressed: () async {}, + child: const Text('go'), + ))); + expect(find.byType(ElevatedButton), findsOneWidget); + expect(find.text('go'), findsOneWidget); + }); + + testWidgets('shows loading then returns to idle', (tester) async { + final completer = Completer(); + await tester.pumpWidget(_wrap(ElevatedAsyncButton( + onPressed: () => completer.future, + child: const Text('go'), + ))); + await tester.tap(find.byType(ElevatedButton)); + await tester.pump(); + expect(find.byType(CircularProgressIndicator), findsOneWidget); + completer.complete(); + await tester.pumpAndSettle(); + expect(find.text('go'), findsOneWidget); + }); + + testWidgets('is disabled when onPressed is null', (tester) async { + await tester.pumpWidget(_wrap(const ElevatedAsyncButton( + onPressed: null, + child: Text('go'), + ))); + final btn = tester.widget(find.byType(ElevatedButton)); + expect(btn.onPressed, isNull); + }); + + testWidgets('is disabled when disabled=true', (tester) async { + await tester.pumpWidget(_wrap(ElevatedAsyncButton( + onPressed: () async {}, + disabled: true, + child: const Text('go'), + ))); + final btn = tester.widget(find.byType(ElevatedButton)); + expect(btn.onPressed, isNull); + }); + }); + + group('ElevatedAsyncButton.icon', () { + testWidgets('icon stays put while the label animates', (tester) async { + final completer = Completer(); + await tester.pumpWidget(_wrap(ElevatedAsyncButton.icon( + onPressed: () => completer.future, + icon: const Icon(Icons.send), + label: const Text('send'), + ))); + // Idle: icon + label. + expect(find.byIcon(Icons.send), findsOneWidget); + expect(find.text('send'), findsOneWidget); + await tester.tap(find.byType(ElevatedButton)); + await tester.pump(); + // Loading: icon stays, label gone, spinner present. + expect(find.byIcon(Icons.send), findsOneWidget); + expect(find.byType(CircularProgressIndicator), findsOneWidget); + completer.complete(); + await tester.pumpAndSettle(); + expect(find.text('send'), findsOneWidget); + }); + }); +} diff --git a/test/filled_async_button_test.dart b/test/filled_async_button_test.dart new file mode 100644 index 0000000..2c1f7ee --- /dev/null +++ b/test/filled_async_button_test.dart @@ -0,0 +1,54 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:material_async_button/material_async_button.dart'; + +Widget _wrap(Widget child) => + MaterialApp(home: Scaffold(body: Center(child: child))); + +void main() { + group('FilledAsyncButton', () { + testWidgets('renders FilledButton', (tester) async { + await tester.pumpWidget(_wrap(FilledAsyncButton( + onPressed: () async {}, + child: const Text('go'), + ))); + expect(find.byType(FilledButton), findsOneWidget); + }); + + testWidgets('FilledAsyncButton.tonal renders FilledButton in tonal style', + (tester) async { + await tester.pumpWidget(_wrap(FilledAsyncButton.tonal( + onPressed: () async {}, + child: const Text('go'), + ))); + expect(find.byType(FilledButton), findsOneWidget); + }); + + testWidgets('FilledAsyncButton.icon swaps label during loading', + (tester) async { + final completer = Completer(); + await tester.pumpWidget(_wrap(FilledAsyncButton.icon( + onPressed: () => completer.future, + icon: const Icon(Icons.save), + label: const Text('save'), + ))); + await tester.tap(find.byType(FilledButton)); + await tester.pump(); + expect(find.byIcon(Icons.save), findsOneWidget); + expect(find.text('save'), findsNothing); + completer.complete(); + await tester.pumpAndSettle(); + }); + + testWidgets('FilledAsyncButton.tonalIcon renders', (tester) async { + await tester.pumpWidget(_wrap(FilledAsyncButton.tonalIcon( + onPressed: () async {}, + icon: const Icon(Icons.save), + label: const Text('save'), + ))); + expect(find.byType(FilledButton), findsOneWidget); + }); + }); +} diff --git a/test/icon_async_button_test.dart b/test/icon_async_button_test.dart new file mode 100644 index 0000000..d43665c --- /dev/null +++ b/test/icon_async_button_test.dart @@ -0,0 +1,51 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:material_async_button/material_async_button.dart'; + +Widget _wrap(Widget child) => + MaterialApp(home: Scaffold(body: Center(child: child))); + +void main() { + group('IconAsyncButton', () { + testWidgets('renders IconButton with the icon', (tester) async { + await tester.pumpWidget(_wrap(IconAsyncButton( + onPressed: () async {}, + icon: const Icon(Icons.refresh), + ))); + expect(find.byIcon(Icons.refresh), findsOneWidget); + expect(find.byType(IconButton), findsOneWidget); + }); + + testWidgets('filled, filledTonal, outlined variants all render', + (tester) async { + for (final ctor in [ + () => IconAsyncButton.filled( + onPressed: () async {}, icon: const Icon(Icons.add)), + () => IconAsyncButton.filledTonal( + onPressed: () async {}, icon: const Icon(Icons.add)), + () => IconAsyncButton.outlined( + onPressed: () async {}, icon: const Icon(Icons.add)), + ]) { + await tester.pumpWidget(_wrap(ctor())); + expect(find.byType(IconButton), findsOneWidget); + } + }); + + testWidgets('swaps icon for loading widget during press', (tester) async { + final completer = Completer(); + await tester.pumpWidget(_wrap(IconAsyncButton( + onPressed: () => completer.future, + icon: const Icon(Icons.refresh), + ))); + await tester.tap(find.byType(IconButton)); + await tester.pump(); + expect(find.byType(CircularProgressIndicator), findsOneWidget); + // Icon may animate out via AnimatedSwitcher; allow both possibilities. + completer.complete(); + await tester.pumpAndSettle(); + expect(find.byIcon(Icons.refresh), findsOneWidget); + }); + }); +} diff --git a/test/material_async_button_theme_test.dart b/test/material_async_button_theme_test.dart new file mode 100644 index 0000000..d560950 --- /dev/null +++ b/test/material_async_button_theme_test.dart @@ -0,0 +1,102 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:material_async_button/material_async_button.dart'; + +void main() { + group('MaterialAsyncButtonTheme', () { + test('empty default has all null fields', () { + const t = MaterialAsyncButtonTheme.empty; + expect(t.loadingChild, isNull); + expect(t.successChild, isNull); + expect(t.errorChild, isNull); + expect(t.switchDuration, isNull); + expect(t.hapticOn, isNull); + }); + + test('material() supplies opinionated baseline', () { + final t = MaterialAsyncButtonTheme.material(); + expect(t.loadingChild, isNotNull); + expect(t.successChild, isNotNull); + expect(t.errorChild, isNotNull); + expect(t.switchDuration, const Duration(milliseconds: 200)); + expect(t.successDisplayDuration, const Duration(milliseconds: 800)); + expect(t.errorDisplayDuration, const Duration(milliseconds: 800)); + expect(t.animateSize, isTrue); + expect(t.hapticOn, HapticOn.both); + expect(t.announceSemantics, isTrue); + }); + + test('copyWith overrides only specified fields', () { + final base = MaterialAsyncButtonTheme.material(); + final overridden = + base.copyWith(switchDuration: const Duration(milliseconds: 500)); + expect(overridden.switchDuration, const Duration(milliseconds: 500)); + expect(overridden.successDisplayDuration, base.successDisplayDuration); + expect(overridden.hapticOn, base.hapticOn); + }); + + test('lerp snaps non-numeric fields and interpolates durations', () { + const a = MaterialAsyncButtonTheme( + switchDuration: Duration(milliseconds: 100), + successDisplayDuration: Duration(milliseconds: 200), + hapticOn: HapticOn.success, + ); + const b = MaterialAsyncButtonTheme( + switchDuration: Duration(milliseconds: 300), + successDisplayDuration: Duration(milliseconds: 600), + hapticOn: HapticOn.error, + ); + final mid = a.lerp(b, 0.5); + expect(mid.switchDuration, const Duration(milliseconds: 200)); + expect(mid.successDisplayDuration, const Duration(milliseconds: 400)); + // Non-interpolable fields snap at 0.5 to the second value. + expect(mid.hapticOn, HapticOn.error); + }); + + test('lerp with non-MaterialAsyncButtonTheme returns self', () { + const a = MaterialAsyncButtonTheme( + switchDuration: Duration(milliseconds: 100)); + final result = a.lerp(null, 0.5); + expect(result.switchDuration, a.switchDuration); + }); + + testWidgets('of(context) returns the registered extension', (tester) async { + const ext = MaterialAsyncButtonTheme( + switchDuration: Duration(milliseconds: 123)); + MaterialAsyncButtonTheme? captured; + await tester.pumpWidget(MaterialApp( + theme: ThemeData(extensions: const [ext]), + home: Builder( + builder: (ctx) { + captured = MaterialAsyncButtonTheme.of(ctx); + return const SizedBox.shrink(); + }, + ), + )); + expect(captured?.switchDuration, const Duration(milliseconds: 123)); + }); + + testWidgets('of(context) returns empty when extension absent', + (tester) async { + MaterialAsyncButtonTheme? captured; + await tester.pumpWidget(MaterialApp( + home: Builder( + builder: (ctx) { + captured = MaterialAsyncButtonTheme.of(ctx); + return const SizedBox.shrink(); + }, + ), + )); + expect(captured?.switchDuration, isNull); + }); + + test('equality is value-based', () { + const a = MaterialAsyncButtonTheme( + switchDuration: Duration(milliseconds: 100), hapticOn: HapticOn.both); + const b = MaterialAsyncButtonTheme( + switchDuration: Duration(milliseconds: 100), hapticOn: HapticOn.both); + expect(a, b); + expect(a.hashCode, b.hashCode); + }); + }); +} diff --git a/test/outlined_async_button_test.dart b/test/outlined_async_button_test.dart new file mode 100644 index 0000000..f5b5e47 --- /dev/null +++ b/test/outlined_async_button_test.dart @@ -0,0 +1,44 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:material_async_button/material_async_button.dart'; + +Widget _wrap(Widget child) => + MaterialApp(home: Scaffold(body: Center(child: child))); + +void main() { + group('OutlinedAsyncButton', () { + testWidgets('renders OutlinedButton', (tester) async { + await tester.pumpWidget(_wrap(OutlinedAsyncButton( + onPressed: () async {}, + child: const Text('go'), + ))); + expect(find.byType(OutlinedButton), findsOneWidget); + }); + + testWidgets('.icon variant renders with icon + label', (tester) async { + await tester.pumpWidget(_wrap(OutlinedAsyncButton.icon( + onPressed: () async {}, + icon: const Icon(Icons.share), + label: const Text('share'), + ))); + expect(find.byType(OutlinedButton), findsOneWidget); + expect(find.byIcon(Icons.share), findsOneWidget); + expect(find.text('share'), findsOneWidget); + }); + + testWidgets('cycles through loading', (tester) async { + final completer = Completer(); + await tester.pumpWidget(_wrap(OutlinedAsyncButton( + onPressed: () => completer.future, + child: const Text('go'), + ))); + await tester.tap(find.byType(OutlinedButton)); + await tester.pump(); + expect(find.byType(CircularProgressIndicator), findsOneWidget); + completer.complete(); + await tester.pumpAndSettle(); + }); + }); +} diff --git a/test/text_async_button_test.dart b/test/text_async_button_test.dart new file mode 100644 index 0000000..6680744 --- /dev/null +++ b/test/text_async_button_test.dart @@ -0,0 +1,44 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:material_async_button/material_async_button.dart'; + +Widget _wrap(Widget child) => + MaterialApp(home: Scaffold(body: Center(child: child))); + +void main() { + group('TextAsyncButton', () { + testWidgets('renders TextButton', (tester) async { + await tester.pumpWidget(_wrap(TextAsyncButton( + onPressed: () async {}, + child: const Text('go'), + ))); + expect(find.byType(TextButton), findsOneWidget); + }); + + testWidgets('.icon variant renders with icon + label', (tester) async { + await tester.pumpWidget(_wrap(TextAsyncButton.icon( + onPressed: () async {}, + icon: const Icon(Icons.copy), + label: const Text('copy'), + ))); + expect(find.byType(TextButton), findsOneWidget); + expect(find.byIcon(Icons.copy), findsOneWidget); + }); + + testWidgets('state.trigger() works for "Done" keyboard pattern', + (tester) async { + var ran = 0; + await tester.pumpWidget(_wrap(TextAsyncButton( + onPressed: () async => ran++, + child: const Text('go'), + ))); + final state = tester.state( + find.byType(AsyncButtonBuilder)); + await state.trigger(); + await tester.pumpAndSettle(); + expect(ran, 1); + }); + }); +} From 3afea8ab5262b5ef4d95108365ebd0dfe54adbab Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 25 May 2026 14:12:52 +0000 Subject: [PATCH 099/176] fix(ci): reformat with dart format and loosen SDK constraints * dart format --line-length 100 applied across lib/test/example. * Bumped CI format step to --line-length 100 (was 80 default). * Hoisted repeated Widget Function/error-callback types to AsyncButtonErrorBuilder / AsyncButtonErrorCallback typedefs. * Removed strict-inference (overly aggressive for Flutter test idioms like `(tester) async {}`); kept strict-casts + strict-raw-types. * Loosened pubspec flutter constraint to >=3.0.0; the sdk ^3.10.0 constraint is the real gate. Flutter 3.40 wasn't a real release yet when CI ran. * Fixed value-listenable interop test to attach a non-zero success duration so the success state is observable before idle. https://claude.ai/code/session_01C5g1NbxvkgKbv7daca8Kvv --- .github/workflows/dart.yaml | 2 +- CHANGELOG.md | 2 +- README.md | 2 +- analysis_options.yaml | 1 - example/lib/main.dart | 235 ++++++------- example/pubspec.yaml | 2 +- example/test/widget_test.dart | 3 +- lib/src/async_button_builder.dart | 75 +++-- lib/src/async_button_controller.dart | 17 +- lib/src/async_button_state.dart | 3 +- lib/src/buttons/elevated_async_button.dart | 117 ++++--- lib/src/buttons/filled_async_button.dart | 197 ++++++----- lib/src/buttons/icon_async_button.dart | 249 +++++++------- lib/src/buttons/outlined_async_button.dart | 117 ++++--- lib/src/buttons/text_async_button.dart | 117 ++++--- lib/src/material_async_button_theme.dart | 127 ++++--- pubspec.yaml | 2 +- test/async_button_builder_test.dart | 371 ++++++++++++--------- test/async_button_controller_test.dart | 90 ++--- test/async_button_state_test.dart | 48 ++- test/elevated_async_button_test.dart | 46 ++- test/filled_async_button_test.dart | 53 +-- test/icon_async_button_test.dart | 31 +- test/material_async_button_theme_test.dart | 54 +-- test/outlined_async_button_test.dart | 33 +- test/text_async_button_test.dart | 39 +-- 26 files changed, 1028 insertions(+), 1005 deletions(-) diff --git a/.github/workflows/dart.yaml b/.github/workflows/dart.yaml index 25d7068..0432ec5 100644 --- a/.github/workflows/dart.yaml +++ b/.github/workflows/dart.yaml @@ -24,7 +24,7 @@ jobs: run: flutter pub get - name: Check formatting - run: dart format --set-exit-if-changed . + run: dart format --line-length 100 --set-exit-if-changed . - name: Analyze run: flutter analyze diff --git a/CHANGELOG.md b/CHANGELOG.md index d9665e6..29e89b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,7 +28,7 @@ with a redesigned, theme-aware API. - Defaults are unopinionated: zero `successDisplayDuration`, zero `errorDisplayDuration`, no success/error widget swap unless asked. Use `MaterialAsyncButtonTheme.material()` for the v3-style baseline. -- Minimum Dart SDK is `^3.10.0`; minimum Flutter is `>=3.40.0`. +- Minimum Dart SDK is `^3.10.0` (any Flutter SDK shipping Dart 3.10+). ### Fixed diff --git a/README.md b/README.md index bff6d60..fdf0a19 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ dependencies: material_async_button: ^1.0.0 ``` -Requires Dart `^3.10.0` and Flutter `>=3.40.0`. +Requires Dart `^3.10.0` (any Flutter SDK shipping Dart 3.10+). ## Why diff --git a/analysis_options.yaml b/analysis_options.yaml index 8ba7847..72d8d1b 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -3,7 +3,6 @@ include: package:flutter_lints/flutter.yaml analyzer: language: strict-casts: true - strict-inference: true strict-raw-types: true linter: diff --git a/example/lib/main.dart b/example/lib/main.dart index f7a6208..f62a54b 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -8,14 +8,14 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) => MaterialApp( - title: 'material_async_button demo', - theme: ThemeData( - colorSchemeSeed: Colors.indigo, - useMaterial3: true, - extensions: [MaterialAsyncButtonTheme.material()], - ), - home: const HomePage(), - ); + title: 'material_async_button demo', + theme: ThemeData( + colorSchemeSeed: Colors.indigo, + useMaterial3: true, + extensions: [MaterialAsyncButtonTheme.material()], + ), + home: const HomePage(), + ); } class HomePage extends StatefulWidget { @@ -45,129 +45,108 @@ class _HomePageState extends State { @override Widget build(BuildContext context) => Scaffold( - appBar: AppBar(title: const Text('material_async_button')), - body: SingleChildScrollView( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, + appBar: AppBar(title: const Text('material_async_button')), + body: SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + const _SectionLabel('Material wrappers'), + ElevatedAsyncButton(onPressed: _simulateWork, child: const Text('ElevatedAsyncButton')), + const SizedBox(height: 8), + ElevatedAsyncButton.icon( + onPressed: _simulateWork, + icon: const Icon(Icons.send), + label: const Text('ElevatedAsyncButton.icon'), + ), + const SizedBox(height: 8), + FilledAsyncButton(onPressed: _simulateWork, child: const Text('FilledAsyncButton')), + const SizedBox(height: 8), + FilledAsyncButton.tonal( + onPressed: _simulateWork, + child: const Text('FilledAsyncButton.tonal'), + ), + const SizedBox(height: 8), + OutlinedAsyncButton( + onPressed: () => _simulateWork(fail: true), + child: const Text('OutlinedAsyncButton (fails)'), + ), + const SizedBox(height: 8), + TextAsyncButton(onPressed: _simulateWork, child: const Text('TextAsyncButton')), + const SizedBox(height: 8), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ - const _SectionLabel('Material wrappers'), - ElevatedAsyncButton( - onPressed: _simulateWork, - child: const Text('ElevatedAsyncButton'), - ), - const SizedBox(height: 8), - ElevatedAsyncButton.icon( - onPressed: _simulateWork, - icon: const Icon(Icons.send), - label: const Text('ElevatedAsyncButton.icon'), - ), - const SizedBox(height: 8), - FilledAsyncButton( - onPressed: _simulateWork, - child: const Text('FilledAsyncButton'), - ), - const SizedBox(height: 8), - FilledAsyncButton.tonal( - onPressed: _simulateWork, - child: const Text('FilledAsyncButton.tonal'), - ), - const SizedBox(height: 8), - OutlinedAsyncButton( - onPressed: () => _simulateWork(fail: true), - child: const Text('OutlinedAsyncButton (fails)'), - ), - const SizedBox(height: 8), - TextAsyncButton( - onPressed: _simulateWork, - child: const Text('TextAsyncButton'), - ), - const SizedBox(height: 8), - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - IconAsyncButton( - onPressed: _simulateWork, - icon: const Icon(Icons.refresh)), - IconAsyncButton.filled( - onPressed: _simulateWork, icon: const Icon(Icons.add)), - IconAsyncButton.filledTonal( - onPressed: _simulateWork, icon: const Icon(Icons.edit)), - IconAsyncButton.outlined( - onPressed: _simulateWork, - icon: const Icon(Icons.delete)), - ], - ), - const Divider(height: 32), - const _SectionLabel('Form "Done" → controller.trigger()'), - TextField( - controller: _textController, - textInputAction: TextInputAction.done, - decoration: const InputDecoration(labelText: 'Name'), - onSubmitted: (_) => _formController.trigger(), - ), - const SizedBox(height: 8), - ElevatedAsyncButton( - controller: _formController, - onPressed: () => _simulateWork(), - child: const Text('Submit'), - ), - const Divider(height: 32), - const _SectionLabel('External controller'), - ElevatedAsyncButton( - controller: _externalController, - onPressed: _simulateWork, - child: const Text('Submit (driven by controller)'), + IconAsyncButton(onPressed: _simulateWork, icon: const Icon(Icons.refresh)), + IconAsyncButton.filled(onPressed: _simulateWork, icon: const Icon(Icons.add)), + IconAsyncButton.filledTonal(onPressed: _simulateWork, icon: const Icon(Icons.edit)), + IconAsyncButton.outlined(onPressed: _simulateWork, icon: const Icon(Icons.delete)), + ], + ), + const Divider(height: 32), + const _SectionLabel('Form "Done" → controller.trigger()'), + TextField( + controller: _textController, + textInputAction: TextInputAction.done, + decoration: const InputDecoration(labelText: 'Name'), + onSubmitted: (_) => _formController.trigger(), + ), + const SizedBox(height: 8), + ElevatedAsyncButton( + controller: _formController, + onPressed: () => _simulateWork(), + child: const Text('Submit'), + ), + const Divider(height: 32), + const _SectionLabel('External controller'), + ElevatedAsyncButton( + controller: _externalController, + onPressed: _simulateWork, + child: const Text('Submit (driven by controller)'), + ), + const SizedBox(height: 8), + Wrap( + spacing: 8, + children: [ + OutlinedButton( + onPressed: () => _externalController.trigger(), + child: const Text('trigger()'), ), - const SizedBox(height: 8), - Wrap( - spacing: 8, - children: [ - OutlinedButton( - onPressed: () => _externalController.trigger(), - child: const Text('trigger()'), - ), - OutlinedButton( - onPressed: () => - _externalController.invalidate('server rejected'), - child: const Text('invalidate()'), - ), - OutlinedButton( - onPressed: _externalController.markSuccess, - child: const Text('markSuccess()'), - ), - OutlinedButton( - onPressed: _externalController.reset, - child: const Text('reset()'), - ), - ], + OutlinedButton( + onPressed: () => _externalController.invalidate('server rejected'), + child: const Text('invalidate()'), ), - const Divider(height: 32), - const _SectionLabel('Custom button via AsyncButtonBuilder'), - AsyncButtonBuilder( - onPressed: _simulateWork, - animateSize: true, - child: const Padding( - padding: - EdgeInsets.symmetric(horizontal: 16, vertical: 12), - child: - Text('Custom', style: TextStyle(color: Colors.white)), - ), - builder: (ctx, child, callback, state) => Material( - color: switch (state) { - AsyncButtonStateSuccess() => Colors.green, - AsyncButtonStateError() => Colors.red, - _ => Colors.indigo, - }, - clipBehavior: Clip.hardEdge, - shape: const StadiumBorder(), - child: InkWell(onTap: callback, child: child), - ), + OutlinedButton( + onPressed: _externalController.markSuccess, + child: const Text('markSuccess()'), ), + OutlinedButton(onPressed: _externalController.reset, child: const Text('reset()')), ], ), - ), - ); + const Divider(height: 32), + const _SectionLabel('Custom button via AsyncButtonBuilder'), + AsyncButtonBuilder( + onPressed: _simulateWork, + animateSize: true, + child: const Padding( + padding: EdgeInsets.symmetric(horizontal: 16, vertical: 12), + child: Text('Custom', style: TextStyle(color: Colors.white)), + ), + builder: (ctx, child, callback, state) => Material( + color: switch (state) { + AsyncButtonStateSuccess() => Colors.green, + AsyncButtonStateError() => Colors.red, + _ => Colors.indigo, + }, + clipBehavior: Clip.hardEdge, + shape: const StadiumBorder(), + child: InkWell(onTap: callback, child: child), + ), + ), + ], + ), + ), + ); } class _SectionLabel extends StatelessWidget { @@ -176,7 +155,7 @@ class _SectionLabel extends StatelessWidget { @override Widget build(BuildContext context) => Padding( - padding: const EdgeInsets.symmetric(vertical: 8), - child: Text(text, style: Theme.of(context).textTheme.titleMedium), - ); + padding: const EdgeInsets.symmetric(vertical: 8), + child: Text(text, style: Theme.of(context).textTheme.titleMedium), + ); } diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 7fbb51b..a240141 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -5,7 +5,7 @@ version: 1.0.0+1 environment: sdk: ^3.10.0 - flutter: ">=3.40.0" + flutter: ">=3.0.0" dependencies: flutter: diff --git a/example/test/widget_test.dart b/example/test/widget_test.dart index 7b8922f..aa6b683 100644 --- a/example/test/widget_test.dart +++ b/example/test/widget_test.dart @@ -3,8 +3,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:material_async_button/material_async_button.dart'; void main() { - testWidgets('example app builds and shows the Material wrappers section', - (tester) async { + testWidgets('example app builds and shows the Material wrappers section', (tester) async { await tester.pumpWidget(const MyApp()); await tester.pumpAndSettle(); expect(find.text('Material wrappers'), findsOneWidget); diff --git a/lib/src/async_button_builder.dart b/lib/src/async_button_builder.dart index dbd1cea..82fb406 100644 --- a/lib/src/async_button_builder.dart +++ b/lib/src/async_button_builder.dart @@ -13,12 +13,21 @@ import 'material_async_button_theme.dart'; /// /// `callback` is `null` when the button should appear disabled (already /// loading, in cooldown, or `onPressed`/`disabled` make it ineligible). -typedef AsyncButtonWidgetBuilder = Widget Function( - BuildContext context, - Widget child, - AsyncCallback? callback, - AsyncButtonState state, -); +typedef AsyncButtonWidgetBuilder = + Widget Function( + BuildContext context, + Widget child, + AsyncCallback? callback, + AsyncButtonState state, + ); + +/// Signature for [AsyncButtonBuilder.errorBuilder]. +typedef AsyncButtonErrorBuilder = + Widget Function(BuildContext context, Object error, StackTrace? stackTrace); + +/// Signature for the `onError` callback. Receives the thrown error plus the +/// captured stack trace. +typedef AsyncButtonErrorCallback = void Function(Object error, StackTrace stackTrace); /// Builder for an arbitrary button with async loading/success/error states. /// @@ -85,7 +94,7 @@ class AsyncButtonBuilder extends StatefulWidget { /// Called after error display completes (or immediately if the display /// duration is zero). Receives the thrown error and stack trace. - final void Function(Object error, StackTrace stackTrace)? onError; + final AsyncButtonErrorCallback? onError; /// Fired on every state change. final ValueChanged? onStateChanged; @@ -96,8 +105,7 @@ class AsyncButtonBuilder extends StatefulWidget { /// Renders the error state. When non-null, takes precedence over /// [errorChild] and the theme's `errorChild`. - final Widget Function(BuildContext context, Object error, StackTrace? stackTrace)? - errorBuilder; + final AsyncButtonErrorBuilder? errorBuilder; final Widget? loadingChild; final Widget? successChild; @@ -130,8 +138,7 @@ class AsyncButtonBuilder extends StatefulWidget { class AsyncButtonBuilderState extends State { AsyncButtonController? _internalController; - AsyncButtonController get _controller => - widget.controller ?? _internalController!; + AsyncButtonController get _controller => widget.controller ?? _internalController!; AsyncButtonState _lastNotifiedState = const AsyncButtonState.idle(); @@ -175,9 +182,11 @@ class AsyncButtonBuilderState extends State { widget.onStateChanged?.call(newState); _fireHaptic(_lastNotifiedState, newState); _announceSemantics(newState); - if (newState is AsyncButtonStateSuccess && _lastNotifiedState is! AsyncButtonStateSuccess) { + final wasSuccess = _lastNotifiedState is AsyncButtonStateSuccess; + final wasError = _lastNotifiedState is AsyncButtonStateError; + if (newState is AsyncButtonStateSuccess && !wasSuccess) { widget.onSuccess?.call(); - } else if (newState is AsyncButtonStateError && _lastNotifiedState is! AsyncButtonStateError) { + } else if (newState is AsyncButtonStateError && !wasError) { widget.onError?.call(newState.error, newState.stackTrace ?? StackTrace.empty); } _lastNotifiedState = newState; @@ -189,9 +198,11 @@ class AsyncButtonBuilderState extends State { final theme = MaterialAsyncButtonTheme.of(context); final mode = widget.hapticOn ?? theme.hapticOn ?? HapticOn.none; if (mode == HapticOn.none) return; - if (to is AsyncButtonStateSuccess && (mode == HapticOn.success || mode == HapticOn.both)) { + final wantSuccess = mode == HapticOn.success || mode == HapticOn.both; + final wantError = mode == HapticOn.error || mode == HapticOn.both; + if (to is AsyncButtonStateSuccess && wantSuccess) { HapticFeedback.lightImpact(); - } else if (to is AsyncButtonStateError && (mode == HapticOn.error || mode == HapticOn.both)) { + } else if (to is AsyncButtonStateError && wantError) { HapticFeedback.mediumImpact(); } } @@ -238,8 +249,7 @@ class AsyncButtonBuilderState extends State { widget.successDisplayDuration ?? theme.successDisplayDuration ?? Duration.zero; final errorDuration = widget.errorDisplayDuration ?? theme.errorDisplayDuration ?? Duration.zero; - final cooldown = - widget.cooldownDuration ?? theme.cooldownDuration ?? Duration.zero; + final cooldown = widget.cooldownDuration ?? theme.cooldownDuration ?? Duration.zero; final rethrowErrors = widget.rethrowErrors ?? theme.rethrowErrors ?? false; _controller.attach( @@ -252,31 +262,27 @@ class AsyncButtonBuilderState extends State { final state = _controller.value; - final loadingChild = widget.loadingChild ?? - theme.loadingChild ?? - const _BuiltinLoadingChild(); + final loadingChild = widget.loadingChild ?? theme.loadingChild ?? const _BuiltinLoadingChild(); final successChild = widget.successChild ?? theme.successChild; final errorChild = widget.errorChild ?? theme.errorChild; final switchDuration = widget.switchDuration ?? theme.switchDuration ?? const Duration(milliseconds: 200); final switchReverseDuration = widget.switchReverseDuration ?? theme.switchReverseDuration; - final switchInCurve = - widget.switchInCurve ?? theme.switchInCurve ?? widget.switchCurve ?? theme.switchCurve ?? Curves.linear; - final switchOutCurve = - widget.switchOutCurve ?? theme.switchOutCurve ?? widget.switchCurve ?? theme.switchCurve ?? Curves.linear; - final transitionBuilder = widget.transitionBuilder ?? + final fallbackCurve = widget.switchCurve ?? theme.switchCurve ?? Curves.linear; + final switchInCurve = widget.switchInCurve ?? theme.switchInCurve ?? fallbackCurve; + final switchOutCurve = widget.switchOutCurve ?? theme.switchOutCurve ?? fallbackCurve; + final transitionBuilder = + widget.transitionBuilder ?? theme.transitionBuilder ?? AnimatedSwitcher.defaultTransitionBuilder; final animateSize = widget.animateSize ?? theme.animateSize ?? false; - Widget visible = switch (state) { + final Widget visible = switch (state) { AsyncButtonStateIdle() => widget.child, AsyncButtonStateLoading() => loadingChild, AsyncButtonStateSuccess() => successChild ?? widget.child, AsyncButtonStateError(:final error, :final stackTrace) => - widget.errorBuilder?.call(context, error, stackTrace) ?? - errorChild ?? - widget.child, + widget.errorBuilder?.call(context, error, stackTrace) ?? errorChild ?? widget.child, }; Widget content = AnimatedSwitcher( @@ -285,10 +291,7 @@ class AsyncButtonBuilderState extends State { switchInCurve: switchInCurve, switchOutCurve: switchOutCurve, transitionBuilder: transitionBuilder, - child: KeyedSubtree( - key: ValueKey(state.runtimeType), - child: visible, - ), + child: KeyedSubtree(key: ValueKey(state.runtimeType), child: visible), ); if (animateSize) { @@ -333,8 +336,6 @@ class _BuiltinLoadingChild extends StatelessWidget { const _BuiltinLoadingChild(); @override - Widget build(BuildContext context) => const SizedBox.square( - dimension: 16, - child: CircularProgressIndicator(strokeWidth: 2), - ); + Widget build(BuildContext context) => + const SizedBox.square(dimension: 16, child: CircularProgressIndicator(strokeWidth: 2)); } diff --git a/lib/src/async_button_controller.dart b/lib/src/async_button_controller.dart index 4dcfeba..224a47a 100644 --- a/lib/src/async_button_controller.dart +++ b/lib/src/async_button_controller.dart @@ -17,10 +17,9 @@ import 'async_button_state.dart'; /// - mark the button as succeeded from outside. /// /// Dispose like any [ChangeNotifier]. -class AsyncButtonController extends ChangeNotifier - implements ValueListenable { +class AsyncButtonController extends ChangeNotifier implements ValueListenable { AsyncButtonController({AsyncButtonState initial = const AsyncButtonState.idle()}) - : _value = initial; + : _value = initial; AsyncButtonState _value; @override @@ -32,14 +31,14 @@ class AsyncButtonController extends ChangeNotifier bool get isError => _value is AsyncButtonStateError; Object? get error => switch (_value) { - AsyncButtonStateError(:final error) => error, - _ => null, - }; + AsyncButtonStateError(:final error) => error, + _ => null, + }; StackTrace? get stackTrace => switch (_value) { - AsyncButtonStateError(:final stackTrace) => stackTrace, - _ => null, - }; + AsyncButtonStateError(:final stackTrace) => stackTrace, + _ => null, + }; bool get isInCooldown => _cooldownActive; diff --git a/lib/src/async_button_state.dart b/lib/src/async_button_state.dart index e1a6f26..137023b 100644 --- a/lib/src/async_button_state.dart +++ b/lib/src/async_button_state.dart @@ -66,8 +66,7 @@ final class AsyncButtonStateError extends AsyncButtonState { final StackTrace? stackTrace; @override - bool operator ==(Object other) => - other is AsyncButtonStateError && other.error == error; + bool operator ==(Object other) => other is AsyncButtonStateError && other.error == error; @override int get hashCode => Object.hash(AsyncButtonStateError, error); diff --git a/lib/src/buttons/elevated_async_button.dart b/lib/src/buttons/elevated_async_button.dart index 7fbba0a..acae1c1 100644 --- a/lib/src/buttons/elevated_async_button.dart +++ b/lib/src/buttons/elevated_async_button.dart @@ -41,8 +41,8 @@ class ElevatedAsyncButton extends StatelessWidget { this.hapticOn, this.announceSemantics, this.rethrowErrors, - }) : _icon = null, - _iconAlignment = null; + }) : _icon = null, + _iconAlignment = null; /// Mirrors [ElevatedButton.icon]. The loading/success/error children /// replace the `label` while [icon] stays put. @@ -79,9 +79,9 @@ class ElevatedAsyncButton extends StatelessWidget { this.hapticOn, this.announceSemantics, this.rethrowErrors, - }) : _icon = icon, - _iconAlignment = iconAlignment, - child = label; + }) : _icon = icon, + _iconAlignment = iconAlignment, + child = label; final Future Function()? onPressed; final Widget child; @@ -98,11 +98,10 @@ class ElevatedAsyncButton extends StatelessWidget { final AsyncButtonController? controller; final VoidCallback? onSuccess; - final void Function(Object error, StackTrace stackTrace)? onError; + final AsyncButtonErrorCallback? onError; final ValueChanged? onStateChanged; final Future Function(BuildContext context)? confirmBeforePress; - final Widget Function(BuildContext context, Object error, StackTrace? stackTrace)? - errorBuilder; + final AsyncButtonErrorBuilder? errorBuilder; final Widget? loadingChild; final Widget? successChild; final Widget? errorChild; @@ -119,56 +118,56 @@ class ElevatedAsyncButton extends StatelessWidget { @override Widget build(BuildContext context) => AsyncButtonBuilder( - onPressed: onPressed, - controller: controller, - onSuccess: onSuccess, - onError: onError, - onStateChanged: onStateChanged, - confirmBeforePress: confirmBeforePress, - errorBuilder: errorBuilder, - loadingChild: loadingChild, - successChild: successChild, - errorChild: errorChild, - disabled: disabled, - switchDuration: switchDuration, - transitionBuilder: transitionBuilder, - successDisplayDuration: successDisplayDuration, - errorDisplayDuration: errorDisplayDuration, - cooldownDuration: cooldownDuration, - animateSize: animateSize, - hapticOn: hapticOn, - announceSemantics: announceSemantics, - rethrowErrors: rethrowErrors, - child: child, - builder: (context, animatedChild, callback, _) { - if (_icon != null) { - return ElevatedButton.icon( - onPressed: callback, - onLongPress: callback == null ? null : onLongPress, - onHover: onHover, - onFocusChange: onFocusChange, - style: style, - focusNode: focusNode, - autofocus: autofocus, - clipBehavior: clipBehavior ?? Clip.none, - statesController: statesController, - iconAlignment: _iconAlignment, - icon: _icon, - label: animatedChild, - ); - } - return ElevatedButton( - onPressed: callback, - onLongPress: callback == null ? null : onLongPress, - onHover: onHover, - onFocusChange: onFocusChange, - style: style, - focusNode: focusNode, - autofocus: autofocus, - clipBehavior: clipBehavior ?? Clip.none, - statesController: statesController, - child: animatedChild, - ); - }, + onPressed: onPressed, + controller: controller, + onSuccess: onSuccess, + onError: onError, + onStateChanged: onStateChanged, + confirmBeforePress: confirmBeforePress, + errorBuilder: errorBuilder, + loadingChild: loadingChild, + successChild: successChild, + errorChild: errorChild, + disabled: disabled, + switchDuration: switchDuration, + transitionBuilder: transitionBuilder, + successDisplayDuration: successDisplayDuration, + errorDisplayDuration: errorDisplayDuration, + cooldownDuration: cooldownDuration, + animateSize: animateSize, + hapticOn: hapticOn, + announceSemantics: announceSemantics, + rethrowErrors: rethrowErrors, + child: child, + builder: (context, animatedChild, callback, _) { + if (_icon != null) { + return ElevatedButton.icon( + onPressed: callback, + onLongPress: callback == null ? null : onLongPress, + onHover: onHover, + onFocusChange: onFocusChange, + style: style, + focusNode: focusNode, + autofocus: autofocus, + clipBehavior: clipBehavior ?? Clip.none, + statesController: statesController, + iconAlignment: _iconAlignment, + icon: _icon, + label: animatedChild, + ); + } + return ElevatedButton( + onPressed: callback, + onLongPress: callback == null ? null : onLongPress, + onHover: onHover, + onFocusChange: onFocusChange, + style: style, + focusNode: focusNode, + autofocus: autofocus, + clipBehavior: clipBehavior ?? Clip.none, + statesController: statesController, + child: animatedChild, ); + }, + ); } diff --git a/lib/src/buttons/filled_async_button.dart b/lib/src/buttons/filled_async_button.dart index 378c482..62bfac4 100644 --- a/lib/src/buttons/filled_async_button.dart +++ b/lib/src/buttons/filled_async_button.dart @@ -42,9 +42,9 @@ class FilledAsyncButton extends StatelessWidget { this.hapticOn, this.announceSemantics, this.rethrowErrors, - }) : _variant = _FilledVariant.primary, - _icon = null, - _iconAlignment = null; + }) : _variant = _FilledVariant.primary, + _icon = null, + _iconAlignment = null; const FilledAsyncButton.tonal({ super.key, @@ -77,9 +77,9 @@ class FilledAsyncButton extends StatelessWidget { this.hapticOn, this.announceSemantics, this.rethrowErrors, - }) : _variant = _FilledVariant.tonal, - _icon = null, - _iconAlignment = null; + }) : _variant = _FilledVariant.tonal, + _icon = null, + _iconAlignment = null; const FilledAsyncButton.icon({ super.key, @@ -114,10 +114,10 @@ class FilledAsyncButton extends StatelessWidget { this.hapticOn, this.announceSemantics, this.rethrowErrors, - }) : _variant = _FilledVariant.primary, - _icon = icon, - _iconAlignment = iconAlignment, - child = label; + }) : _variant = _FilledVariant.primary, + _icon = icon, + _iconAlignment = iconAlignment, + child = label; const FilledAsyncButton.tonalIcon({ super.key, @@ -152,10 +152,10 @@ class FilledAsyncButton extends StatelessWidget { this.hapticOn, this.announceSemantics, this.rethrowErrors, - }) : _variant = _FilledVariant.tonal, - _icon = icon, - _iconAlignment = iconAlignment, - child = label; + }) : _variant = _FilledVariant.tonal, + _icon = icon, + _iconAlignment = iconAlignment, + child = label; final Future Function()? onPressed; final Widget child; @@ -173,11 +173,10 @@ class FilledAsyncButton extends StatelessWidget { final AsyncButtonController? controller; final VoidCallback? onSuccess; - final void Function(Object error, StackTrace stackTrace)? onError; + final AsyncButtonErrorCallback? onError; final ValueChanged? onStateChanged; final Future Function(BuildContext context)? confirmBeforePress; - final Widget Function(BuildContext context, Object error, StackTrace? stackTrace)? - errorBuilder; + final AsyncButtonErrorBuilder? errorBuilder; final Widget? loadingChild; final Widget? successChild; final Widget? errorChild; @@ -194,86 +193,86 @@ class FilledAsyncButton extends StatelessWidget { @override Widget build(BuildContext context) => AsyncButtonBuilder( - onPressed: onPressed, - controller: controller, - onSuccess: onSuccess, - onError: onError, - onStateChanged: onStateChanged, - confirmBeforePress: confirmBeforePress, - errorBuilder: errorBuilder, - loadingChild: loadingChild, - successChild: successChild, - errorChild: errorChild, - disabled: disabled, - switchDuration: switchDuration, - transitionBuilder: transitionBuilder, - successDisplayDuration: successDisplayDuration, - errorDisplayDuration: errorDisplayDuration, - cooldownDuration: cooldownDuration, - animateSize: animateSize, - hapticOn: hapticOn, - announceSemantics: announceSemantics, - rethrowErrors: rethrowErrors, - child: child, - builder: (context, animatedChild, callback, _) { - if (_icon != null) { - return switch (_variant) { - _FilledVariant.primary => FilledButton.icon( - onPressed: callback, - onLongPress: callback == null ? null : onLongPress, - onHover: onHover, - onFocusChange: onFocusChange, - style: style, - focusNode: focusNode, - autofocus: autofocus, - clipBehavior: clipBehavior ?? Clip.none, - statesController: statesController, - iconAlignment: _iconAlignment, - icon: _icon, - label: animatedChild, - ), - _FilledVariant.tonal => FilledButton.tonalIcon( - onPressed: callback, - onLongPress: callback == null ? null : onLongPress, - onHover: onHover, - onFocusChange: onFocusChange, - style: style, - focusNode: focusNode, - autofocus: autofocus, - clipBehavior: clipBehavior ?? Clip.none, - statesController: statesController, - iconAlignment: _iconAlignment, - icon: _icon, - label: animatedChild, - ), - }; - } - return switch (_variant) { - _FilledVariant.primary => FilledButton( - onPressed: callback, - onLongPress: callback == null ? null : onLongPress, - onHover: onHover, - onFocusChange: onFocusChange, - style: style, - focusNode: focusNode, - autofocus: autofocus, - clipBehavior: clipBehavior ?? Clip.none, - statesController: statesController, - child: animatedChild, - ), - _FilledVariant.tonal => FilledButton.tonal( - onPressed: callback, - onLongPress: callback == null ? null : onLongPress, - onHover: onHover, - onFocusChange: onFocusChange, - style: style, - focusNode: focusNode, - autofocus: autofocus, - clipBehavior: clipBehavior ?? Clip.none, - statesController: statesController, - child: animatedChild, - ), - }; - }, - ); + onPressed: onPressed, + controller: controller, + onSuccess: onSuccess, + onError: onError, + onStateChanged: onStateChanged, + confirmBeforePress: confirmBeforePress, + errorBuilder: errorBuilder, + loadingChild: loadingChild, + successChild: successChild, + errorChild: errorChild, + disabled: disabled, + switchDuration: switchDuration, + transitionBuilder: transitionBuilder, + successDisplayDuration: successDisplayDuration, + errorDisplayDuration: errorDisplayDuration, + cooldownDuration: cooldownDuration, + animateSize: animateSize, + hapticOn: hapticOn, + announceSemantics: announceSemantics, + rethrowErrors: rethrowErrors, + child: child, + builder: (context, animatedChild, callback, _) { + if (_icon != null) { + return switch (_variant) { + _FilledVariant.primary => FilledButton.icon( + onPressed: callback, + onLongPress: callback == null ? null : onLongPress, + onHover: onHover, + onFocusChange: onFocusChange, + style: style, + focusNode: focusNode, + autofocus: autofocus, + clipBehavior: clipBehavior ?? Clip.none, + statesController: statesController, + iconAlignment: _iconAlignment, + icon: _icon, + label: animatedChild, + ), + _FilledVariant.tonal => FilledButton.tonalIcon( + onPressed: callback, + onLongPress: callback == null ? null : onLongPress, + onHover: onHover, + onFocusChange: onFocusChange, + style: style, + focusNode: focusNode, + autofocus: autofocus, + clipBehavior: clipBehavior ?? Clip.none, + statesController: statesController, + iconAlignment: _iconAlignment, + icon: _icon, + label: animatedChild, + ), + }; + } + return switch (_variant) { + _FilledVariant.primary => FilledButton( + onPressed: callback, + onLongPress: callback == null ? null : onLongPress, + onHover: onHover, + onFocusChange: onFocusChange, + style: style, + focusNode: focusNode, + autofocus: autofocus, + clipBehavior: clipBehavior ?? Clip.none, + statesController: statesController, + child: animatedChild, + ), + _FilledVariant.tonal => FilledButton.tonal( + onPressed: callback, + onLongPress: callback == null ? null : onLongPress, + onHover: onHover, + onFocusChange: onFocusChange, + style: style, + focusNode: focusNode, + autofocus: autofocus, + clipBehavior: clipBehavior ?? Clip.none, + statesController: statesController, + child: animatedChild, + ), + }; + }, + ); } diff --git a/lib/src/buttons/icon_async_button.dart b/lib/src/buttons/icon_async_button.dart index 03e8328..d4de872 100644 --- a/lib/src/buttons/icon_async_button.dart +++ b/lib/src/buttons/icon_async_button.dart @@ -220,11 +220,10 @@ class IconAsyncButton extends StatelessWidget { final AsyncButtonController? controller; final VoidCallback? onSuccess; - final void Function(Object error, StackTrace stackTrace)? onError; + final AsyncButtonErrorCallback? onError; final ValueChanged? onStateChanged; final Future Function(BuildContext context)? confirmBeforePress; - final Widget Function(BuildContext context, Object error, StackTrace? stackTrace)? - errorBuilder; + final AsyncButtonErrorBuilder? errorBuilder; final Widget? loadingChild; final Widget? successChild; final Widget? errorChild; @@ -241,126 +240,126 @@ class IconAsyncButton extends StatelessWidget { @override Widget build(BuildContext context) => AsyncButtonBuilder( - onPressed: onPressed, - controller: controller, - onSuccess: onSuccess, - onError: onError, - onStateChanged: onStateChanged, - confirmBeforePress: confirmBeforePress, - errorBuilder: errorBuilder, - loadingChild: loadingChild, - successChild: successChild, - errorChild: errorChild, - disabled: disabled, - switchDuration: switchDuration, - transitionBuilder: transitionBuilder, - successDisplayDuration: successDisplayDuration, - errorDisplayDuration: errorDisplayDuration, - cooldownDuration: cooldownDuration, - animateSize: animateSize, - hapticOn: hapticOn, - announceSemantics: announceSemantics, - rethrowErrors: rethrowErrors, - child: icon, - builder: (context, animatedChild, callback, _) { - return switch (_variant) { - _IconVariant.standard => IconButton( - onPressed: callback, - icon: animatedChild, - iconSize: iconSize, - visualDensity: visualDensity, - padding: padding, - alignment: alignment, - splashRadius: splashRadius, - color: color, - focusColor: focusColor, - hoverColor: hoverColor, - highlightColor: highlightColor, - splashColor: splashColor, - disabledColor: disabledColor, - mouseCursor: mouseCursor, - focusNode: focusNode, - autofocus: autofocus, - tooltip: tooltip, - enableFeedback: enableFeedback, - constraints: constraints, - style: style, - isSelected: isSelected, - selectedIcon: selectedIcon, - ), - _IconVariant.filled => IconButton.filled( - onPressed: callback, - icon: animatedChild, - iconSize: iconSize, - visualDensity: visualDensity, - padding: padding, - alignment: alignment, - splashRadius: splashRadius, - color: color, - focusColor: focusColor, - hoverColor: hoverColor, - highlightColor: highlightColor, - splashColor: splashColor, - disabledColor: disabledColor, - mouseCursor: mouseCursor, - focusNode: focusNode, - autofocus: autofocus, - tooltip: tooltip, - enableFeedback: enableFeedback, - constraints: constraints, - style: style, - isSelected: isSelected, - selectedIcon: selectedIcon, - ), - _IconVariant.filledTonal => IconButton.filledTonal( - onPressed: callback, - icon: animatedChild, - iconSize: iconSize, - visualDensity: visualDensity, - padding: padding, - alignment: alignment, - splashRadius: splashRadius, - color: color, - focusColor: focusColor, - hoverColor: hoverColor, - highlightColor: highlightColor, - splashColor: splashColor, - disabledColor: disabledColor, - mouseCursor: mouseCursor, - focusNode: focusNode, - autofocus: autofocus, - tooltip: tooltip, - enableFeedback: enableFeedback, - constraints: constraints, - style: style, - isSelected: isSelected, - selectedIcon: selectedIcon, - ), - _IconVariant.outlined => IconButton.outlined( - onPressed: callback, - icon: animatedChild, - iconSize: iconSize, - visualDensity: visualDensity, - padding: padding, - alignment: alignment, - splashRadius: splashRadius, - color: color, - focusColor: focusColor, - hoverColor: hoverColor, - highlightColor: highlightColor, - splashColor: splashColor, - disabledColor: disabledColor, - mouseCursor: mouseCursor, - focusNode: focusNode, - autofocus: autofocus, - tooltip: tooltip, - enableFeedback: enableFeedback, - constraints: constraints, - style: style, - isSelected: isSelected, - selectedIcon: selectedIcon, - ), - }; - }, - ); + onPressed: onPressed, + controller: controller, + onSuccess: onSuccess, + onError: onError, + onStateChanged: onStateChanged, + confirmBeforePress: confirmBeforePress, + errorBuilder: errorBuilder, + loadingChild: loadingChild, + successChild: successChild, + errorChild: errorChild, + disabled: disabled, + switchDuration: switchDuration, + transitionBuilder: transitionBuilder, + successDisplayDuration: successDisplayDuration, + errorDisplayDuration: errorDisplayDuration, + cooldownDuration: cooldownDuration, + animateSize: animateSize, + hapticOn: hapticOn, + announceSemantics: announceSemantics, + rethrowErrors: rethrowErrors, + child: icon, + builder: (context, animatedChild, callback, _) { + return switch (_variant) { + _IconVariant.standard => IconButton( + onPressed: callback, + icon: animatedChild, + iconSize: iconSize, + visualDensity: visualDensity, + padding: padding, + alignment: alignment, + splashRadius: splashRadius, + color: color, + focusColor: focusColor, + hoverColor: hoverColor, + highlightColor: highlightColor, + splashColor: splashColor, + disabledColor: disabledColor, + mouseCursor: mouseCursor, + focusNode: focusNode, + autofocus: autofocus, + tooltip: tooltip, + enableFeedback: enableFeedback, + constraints: constraints, + style: style, + isSelected: isSelected, + selectedIcon: selectedIcon, + ), + _IconVariant.filled => IconButton.filled( + onPressed: callback, + icon: animatedChild, + iconSize: iconSize, + visualDensity: visualDensity, + padding: padding, + alignment: alignment, + splashRadius: splashRadius, + color: color, + focusColor: focusColor, + hoverColor: hoverColor, + highlightColor: highlightColor, + splashColor: splashColor, + disabledColor: disabledColor, + mouseCursor: mouseCursor, + focusNode: focusNode, + autofocus: autofocus, + tooltip: tooltip, + enableFeedback: enableFeedback, + constraints: constraints, + style: style, + isSelected: isSelected, + selectedIcon: selectedIcon, + ), + _IconVariant.filledTonal => IconButton.filledTonal( + onPressed: callback, + icon: animatedChild, + iconSize: iconSize, + visualDensity: visualDensity, + padding: padding, + alignment: alignment, + splashRadius: splashRadius, + color: color, + focusColor: focusColor, + hoverColor: hoverColor, + highlightColor: highlightColor, + splashColor: splashColor, + disabledColor: disabledColor, + mouseCursor: mouseCursor, + focusNode: focusNode, + autofocus: autofocus, + tooltip: tooltip, + enableFeedback: enableFeedback, + constraints: constraints, + style: style, + isSelected: isSelected, + selectedIcon: selectedIcon, + ), + _IconVariant.outlined => IconButton.outlined( + onPressed: callback, + icon: animatedChild, + iconSize: iconSize, + visualDensity: visualDensity, + padding: padding, + alignment: alignment, + splashRadius: splashRadius, + color: color, + focusColor: focusColor, + hoverColor: hoverColor, + highlightColor: highlightColor, + splashColor: splashColor, + disabledColor: disabledColor, + mouseCursor: mouseCursor, + focusNode: focusNode, + autofocus: autofocus, + tooltip: tooltip, + enableFeedback: enableFeedback, + constraints: constraints, + style: style, + isSelected: isSelected, + selectedIcon: selectedIcon, + ), + }; + }, + ); } diff --git a/lib/src/buttons/outlined_async_button.dart b/lib/src/buttons/outlined_async_button.dart index a7dfd2a..6b18185 100644 --- a/lib/src/buttons/outlined_async_button.dart +++ b/lib/src/buttons/outlined_async_button.dart @@ -38,8 +38,8 @@ class OutlinedAsyncButton extends StatelessWidget { this.hapticOn, this.announceSemantics, this.rethrowErrors, - }) : _icon = null, - _iconAlignment = null; + }) : _icon = null, + _iconAlignment = null; const OutlinedAsyncButton.icon({ super.key, @@ -74,9 +74,9 @@ class OutlinedAsyncButton extends StatelessWidget { this.hapticOn, this.announceSemantics, this.rethrowErrors, - }) : _icon = icon, - _iconAlignment = iconAlignment, - child = label; + }) : _icon = icon, + _iconAlignment = iconAlignment, + child = label; final Future Function()? onPressed; final Widget child; @@ -93,11 +93,10 @@ class OutlinedAsyncButton extends StatelessWidget { final AsyncButtonController? controller; final VoidCallback? onSuccess; - final void Function(Object error, StackTrace stackTrace)? onError; + final AsyncButtonErrorCallback? onError; final ValueChanged? onStateChanged; final Future Function(BuildContext context)? confirmBeforePress; - final Widget Function(BuildContext context, Object error, StackTrace? stackTrace)? - errorBuilder; + final AsyncButtonErrorBuilder? errorBuilder; final Widget? loadingChild; final Widget? successChild; final Widget? errorChild; @@ -114,56 +113,56 @@ class OutlinedAsyncButton extends StatelessWidget { @override Widget build(BuildContext context) => AsyncButtonBuilder( - onPressed: onPressed, - controller: controller, - onSuccess: onSuccess, - onError: onError, - onStateChanged: onStateChanged, - confirmBeforePress: confirmBeforePress, - errorBuilder: errorBuilder, - loadingChild: loadingChild, - successChild: successChild, - errorChild: errorChild, - disabled: disabled, - switchDuration: switchDuration, - transitionBuilder: transitionBuilder, - successDisplayDuration: successDisplayDuration, - errorDisplayDuration: errorDisplayDuration, - cooldownDuration: cooldownDuration, - animateSize: animateSize, - hapticOn: hapticOn, - announceSemantics: announceSemantics, - rethrowErrors: rethrowErrors, - child: child, - builder: (context, animatedChild, callback, _) { - if (_icon != null) { - return OutlinedButton.icon( - onPressed: callback, - onLongPress: callback == null ? null : onLongPress, - onHover: onHover, - onFocusChange: onFocusChange, - style: style, - focusNode: focusNode, - autofocus: autofocus, - clipBehavior: clipBehavior ?? Clip.none, - statesController: statesController, - iconAlignment: _iconAlignment, - icon: _icon, - label: animatedChild, - ); - } - return OutlinedButton( - onPressed: callback, - onLongPress: callback == null ? null : onLongPress, - onHover: onHover, - onFocusChange: onFocusChange, - style: style, - focusNode: focusNode, - autofocus: autofocus, - clipBehavior: clipBehavior ?? Clip.none, - statesController: statesController, - child: animatedChild, - ); - }, + onPressed: onPressed, + controller: controller, + onSuccess: onSuccess, + onError: onError, + onStateChanged: onStateChanged, + confirmBeforePress: confirmBeforePress, + errorBuilder: errorBuilder, + loadingChild: loadingChild, + successChild: successChild, + errorChild: errorChild, + disabled: disabled, + switchDuration: switchDuration, + transitionBuilder: transitionBuilder, + successDisplayDuration: successDisplayDuration, + errorDisplayDuration: errorDisplayDuration, + cooldownDuration: cooldownDuration, + animateSize: animateSize, + hapticOn: hapticOn, + announceSemantics: announceSemantics, + rethrowErrors: rethrowErrors, + child: child, + builder: (context, animatedChild, callback, _) { + if (_icon != null) { + return OutlinedButton.icon( + onPressed: callback, + onLongPress: callback == null ? null : onLongPress, + onHover: onHover, + onFocusChange: onFocusChange, + style: style, + focusNode: focusNode, + autofocus: autofocus, + clipBehavior: clipBehavior ?? Clip.none, + statesController: statesController, + iconAlignment: _iconAlignment, + icon: _icon, + label: animatedChild, + ); + } + return OutlinedButton( + onPressed: callback, + onLongPress: callback == null ? null : onLongPress, + onHover: onHover, + onFocusChange: onFocusChange, + style: style, + focusNode: focusNode, + autofocus: autofocus, + clipBehavior: clipBehavior ?? Clip.none, + statesController: statesController, + child: animatedChild, ); + }, + ); } diff --git a/lib/src/buttons/text_async_button.dart b/lib/src/buttons/text_async_button.dart index 39a1722..282b524 100644 --- a/lib/src/buttons/text_async_button.dart +++ b/lib/src/buttons/text_async_button.dart @@ -38,8 +38,8 @@ class TextAsyncButton extends StatelessWidget { this.hapticOn, this.announceSemantics, this.rethrowErrors, - }) : _icon = null, - _iconAlignment = null; + }) : _icon = null, + _iconAlignment = null; const TextAsyncButton.icon({ super.key, @@ -74,9 +74,9 @@ class TextAsyncButton extends StatelessWidget { this.hapticOn, this.announceSemantics, this.rethrowErrors, - }) : _icon = icon, - _iconAlignment = iconAlignment, - child = label; + }) : _icon = icon, + _iconAlignment = iconAlignment, + child = label; final Future Function()? onPressed; final Widget child; @@ -93,11 +93,10 @@ class TextAsyncButton extends StatelessWidget { final AsyncButtonController? controller; final VoidCallback? onSuccess; - final void Function(Object error, StackTrace stackTrace)? onError; + final AsyncButtonErrorCallback? onError; final ValueChanged? onStateChanged; final Future Function(BuildContext context)? confirmBeforePress; - final Widget Function(BuildContext context, Object error, StackTrace? stackTrace)? - errorBuilder; + final AsyncButtonErrorBuilder? errorBuilder; final Widget? loadingChild; final Widget? successChild; final Widget? errorChild; @@ -114,56 +113,56 @@ class TextAsyncButton extends StatelessWidget { @override Widget build(BuildContext context) => AsyncButtonBuilder( - onPressed: onPressed, - controller: controller, - onSuccess: onSuccess, - onError: onError, - onStateChanged: onStateChanged, - confirmBeforePress: confirmBeforePress, - errorBuilder: errorBuilder, - loadingChild: loadingChild, - successChild: successChild, - errorChild: errorChild, - disabled: disabled, - switchDuration: switchDuration, - transitionBuilder: transitionBuilder, - successDisplayDuration: successDisplayDuration, - errorDisplayDuration: errorDisplayDuration, - cooldownDuration: cooldownDuration, - animateSize: animateSize, - hapticOn: hapticOn, - announceSemantics: announceSemantics, - rethrowErrors: rethrowErrors, - child: child, - builder: (context, animatedChild, callback, _) { - if (_icon != null) { - return TextButton.icon( - onPressed: callback, - onLongPress: callback == null ? null : onLongPress, - onHover: onHover, - onFocusChange: onFocusChange, - style: style, - focusNode: focusNode, - autofocus: autofocus, - clipBehavior: clipBehavior ?? Clip.none, - statesController: statesController, - iconAlignment: _iconAlignment, - icon: _icon, - label: animatedChild, - ); - } - return TextButton( - onPressed: callback, - onLongPress: callback == null ? null : onLongPress, - onHover: onHover, - onFocusChange: onFocusChange, - style: style, - focusNode: focusNode, - autofocus: autofocus, - clipBehavior: clipBehavior ?? Clip.none, - statesController: statesController, - child: animatedChild, - ); - }, + onPressed: onPressed, + controller: controller, + onSuccess: onSuccess, + onError: onError, + onStateChanged: onStateChanged, + confirmBeforePress: confirmBeforePress, + errorBuilder: errorBuilder, + loadingChild: loadingChild, + successChild: successChild, + errorChild: errorChild, + disabled: disabled, + switchDuration: switchDuration, + transitionBuilder: transitionBuilder, + successDisplayDuration: successDisplayDuration, + errorDisplayDuration: errorDisplayDuration, + cooldownDuration: cooldownDuration, + animateSize: animateSize, + hapticOn: hapticOn, + announceSemantics: announceSemantics, + rethrowErrors: rethrowErrors, + child: child, + builder: (context, animatedChild, callback, _) { + if (_icon != null) { + return TextButton.icon( + onPressed: callback, + onLongPress: callback == null ? null : onLongPress, + onHover: onHover, + onFocusChange: onFocusChange, + style: style, + focusNode: focusNode, + autofocus: autofocus, + clipBehavior: clipBehavior ?? Clip.none, + statesController: statesController, + iconAlignment: _iconAlignment, + icon: _icon, + label: animatedChild, + ); + } + return TextButton( + onPressed: callback, + onLongPress: callback == null ? null : onLongPress, + onHover: onHover, + onFocusChange: onFocusChange, + style: style, + focusNode: focusNode, + autofocus: autofocus, + clipBehavior: clipBehavior ?? Clip.none, + statesController: statesController, + child: animatedChild, ); + }, + ); } diff --git a/lib/src/material_async_button_theme.dart b/lib/src/material_async_button_theme.dart index 7cb28f3..157be79 100644 --- a/lib/src/material_async_button_theme.dart +++ b/lib/src/material_async_button_theme.dart @@ -54,19 +54,18 @@ class MaterialAsyncButtonTheme extends ThemeExtension Color? loadingColor, Color? successColor, Color? errorColor, - }) => - MaterialAsyncButtonTheme( - loadingChild: _DefaultLoadingChild(color: loadingColor), - successChild: _DefaultSuccessIcon(color: successColor), - errorChild: _DefaultErrorIcon(color: errorColor), - switchDuration: const Duration(milliseconds: 200), - switchReverseDuration: const Duration(milliseconds: 200), - successDisplayDuration: const Duration(milliseconds: 800), - errorDisplayDuration: const Duration(milliseconds: 800), - animateSize: true, - hapticOn: HapticOn.both, - announceSemantics: true, - ); + }) => MaterialAsyncButtonTheme( + loadingChild: _DefaultLoadingChild(color: loadingColor), + successChild: _DefaultSuccessIcon(color: successColor), + errorChild: _DefaultErrorIcon(color: errorColor), + switchDuration: const Duration(milliseconds: 200), + switchReverseDuration: const Duration(milliseconds: 200), + successDisplayDuration: const Duration(milliseconds: 800), + errorDisplayDuration: const Duration(milliseconds: 800), + animateSize: true, + hapticOn: HapticOn.both, + announceSemantics: true, + ); /// Shown in place of [child] while the future is in flight. /// Falls back to a 16x16 [CircularProgressIndicator] when null. @@ -150,31 +149,27 @@ class MaterialAsyncButtonTheme extends ThemeExtension HapticOn? hapticOn, bool? announceSemantics, bool? rethrowErrors, - }) => - MaterialAsyncButtonTheme( - loadingChild: loadingChild ?? this.loadingChild, - successChild: successChild ?? this.successChild, - errorChild: errorChild ?? this.errorChild, - switchDuration: switchDuration ?? this.switchDuration, - switchReverseDuration: - switchReverseDuration ?? this.switchReverseDuration, - switchCurve: switchCurve ?? this.switchCurve, - switchInCurve: switchInCurve ?? this.switchInCurve, - switchOutCurve: switchOutCurve ?? this.switchOutCurve, - transitionBuilder: transitionBuilder ?? this.transitionBuilder, - successDisplayDuration: - successDisplayDuration ?? this.successDisplayDuration, - errorDisplayDuration: - errorDisplayDuration ?? this.errorDisplayDuration, - cooldownDuration: cooldownDuration ?? this.cooldownDuration, - animateSize: animateSize ?? this.animateSize, - sizeCurve: sizeCurve ?? this.sizeCurve, - sizeAlignment: sizeAlignment ?? this.sizeAlignment, - sizeClipBehavior: sizeClipBehavior ?? this.sizeClipBehavior, - hapticOn: hapticOn ?? this.hapticOn, - announceSemantics: announceSemantics ?? this.announceSemantics, - rethrowErrors: rethrowErrors ?? this.rethrowErrors, - ); + }) => MaterialAsyncButtonTheme( + loadingChild: loadingChild ?? this.loadingChild, + successChild: successChild ?? this.successChild, + errorChild: errorChild ?? this.errorChild, + switchDuration: switchDuration ?? this.switchDuration, + switchReverseDuration: switchReverseDuration ?? this.switchReverseDuration, + switchCurve: switchCurve ?? this.switchCurve, + switchInCurve: switchInCurve ?? this.switchInCurve, + switchOutCurve: switchOutCurve ?? this.switchOutCurve, + transitionBuilder: transitionBuilder ?? this.transitionBuilder, + successDisplayDuration: successDisplayDuration ?? this.successDisplayDuration, + errorDisplayDuration: errorDisplayDuration ?? this.errorDisplayDuration, + cooldownDuration: cooldownDuration ?? this.cooldownDuration, + animateSize: animateSize ?? this.animateSize, + sizeCurve: sizeCurve ?? this.sizeCurve, + sizeAlignment: sizeAlignment ?? this.sizeAlignment, + sizeClipBehavior: sizeClipBehavior ?? this.sizeClipBehavior, + hapticOn: hapticOn ?? this.hapticOn, + announceSemantics: announceSemantics ?? this.announceSemantics, + rethrowErrors: rethrowErrors ?? this.rethrowErrors, + ); @override MaterialAsyncButtonTheme lerp( @@ -189,18 +184,18 @@ class MaterialAsyncButtonTheme extends ThemeExtension successChild: snap ? successChild : other.successChild, errorChild: snap ? errorChild : other.errorChild, switchDuration: _lerpDuration(switchDuration, other.switchDuration, t), - switchReverseDuration: - _lerpDuration(switchReverseDuration, other.switchReverseDuration, t), + switchReverseDuration: _lerpDuration(switchReverseDuration, other.switchReverseDuration, t), switchCurve: snap ? switchCurve : other.switchCurve, switchInCurve: snap ? switchInCurve : other.switchInCurve, switchOutCurve: snap ? switchOutCurve : other.switchOutCurve, transitionBuilder: snap ? transitionBuilder : other.transitionBuilder, - successDisplayDuration: - _lerpDuration(successDisplayDuration, other.successDisplayDuration, t), - errorDisplayDuration: - _lerpDuration(errorDisplayDuration, other.errorDisplayDuration, t), - cooldownDuration: - _lerpDuration(cooldownDuration, other.cooldownDuration, t), + successDisplayDuration: _lerpDuration( + successDisplayDuration, + other.successDisplayDuration, + t, + ), + errorDisplayDuration: _lerpDuration(errorDisplayDuration, other.errorDisplayDuration, t), + cooldownDuration: _lerpDuration(cooldownDuration, other.cooldownDuration, t), animateSize: snap ? animateSize : other.animateSize, sizeCurve: snap ? sizeCurve : other.sizeCurve, sizeAlignment: AlignmentGeometry.lerp(sizeAlignment, other.sizeAlignment, t), @@ -244,26 +239,26 @@ class MaterialAsyncButtonTheme extends ThemeExtension @override int get hashCode => Object.hashAll([ - loadingChild, - successChild, - errorChild, - switchDuration, - switchReverseDuration, - switchCurve, - switchInCurve, - switchOutCurve, - transitionBuilder, - successDisplayDuration, - errorDisplayDuration, - cooldownDuration, - animateSize, - sizeCurve, - sizeAlignment, - sizeClipBehavior, - hapticOn, - announceSemantics, - rethrowErrors, - ]); + loadingChild, + successChild, + errorChild, + switchDuration, + switchReverseDuration, + switchCurve, + switchInCurve, + switchOutCurve, + transitionBuilder, + successDisplayDuration, + errorDisplayDuration, + cooldownDuration, + animateSize, + sizeCurve, + sizeAlignment, + sizeClipBehavior, + hapticOn, + announceSemantics, + rethrowErrors, + ]); } class _DefaultLoadingChild extends StatelessWidget { diff --git a/pubspec.yaml b/pubspec.yaml index b9cfbf0..9b1bc61 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,7 +16,7 @@ topics: environment: sdk: ^3.10.0 - flutter: ">=3.40.0" + flutter: ">=3.0.0" dependencies: flutter: diff --git a/test/async_button_builder_test.dart b/test/async_button_builder_test.dart index 166479e..98a6e02 100644 --- a/test/async_button_builder_test.dart +++ b/test/async_button_builder_test.dart @@ -4,28 +4,36 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:material_async_button/material_async_button.dart'; -Widget _wrap(Widget child) => - MaterialApp(home: Scaffold(body: Center(child: child))); +Widget _wrap(Widget child) => MaterialApp( + home: Scaffold(body: Center(child: child)), +); void main() { group('AsyncButtonBuilder rendering', () { testWidgets('shows child in idle state', (tester) async { - await tester.pumpWidget(_wrap(AsyncButtonBuilder( - onPressed: () async {}, - child: const Text('hello'), - builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), - ))); + await tester.pumpWidget( + _wrap( + AsyncButtonBuilder( + onPressed: () async {}, + child: const Text('hello'), + builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + ), + ), + ); expect(find.text('hello'), findsOneWidget); }); - testWidgets('falls back to built-in spinner when no loadingChild', - (tester) async { + testWidgets('falls back to built-in spinner when no loadingChild', (tester) async { final completer = Completer(); - await tester.pumpWidget(_wrap(AsyncButtonBuilder( - onPressed: () => completer.future, - child: const Text('go'), - builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), - ))); + await tester.pumpWidget( + _wrap( + AsyncButtonBuilder( + onPressed: () => completer.future, + child: const Text('go'), + builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + ), + ), + ); await tester.tap(find.byType(TextButton)); await tester.pump(); expect(find.byType(CircularProgressIndicator), findsOneWidget); @@ -35,12 +43,16 @@ void main() { testWidgets('uses per-widget loadingChild when given', (tester) async { final completer = Completer(); - await tester.pumpWidget(_wrap(AsyncButtonBuilder( - onPressed: () => completer.future, - child: const Text('go'), - loadingChild: const Text('spinning'), - builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), - ))); + await tester.pumpWidget( + _wrap( + AsyncButtonBuilder( + onPressed: () => completer.future, + child: const Text('go'), + loadingChild: const Text('spinning'), + builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + ), + ), + ); await tester.tap(find.byType(TextButton)); await tester.pump(); expect(find.text('spinning'), findsOneWidget); @@ -48,22 +60,22 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('theme loadingChild used when no per-widget override', - (tester) async { + testWidgets('theme loadingChild used when no per-widget override', (tester) async { final completer = Completer(); - await tester.pumpWidget(MaterialApp( - theme: ThemeData(extensions: const [ - MaterialAsyncButtonTheme(loadingChild: Text('themed-loading')), - ]), - home: Scaffold( - body: AsyncButtonBuilder( - onPressed: () => completer.future, - child: const Text('go'), - builder: (c, child, cb, _) => - TextButton(onPressed: cb, child: child), + await tester.pumpWidget( + MaterialApp( + theme: ThemeData( + extensions: const [MaterialAsyncButtonTheme(loadingChild: Text('themed-loading'))], + ), + home: Scaffold( + body: AsyncButtonBuilder( + onPressed: () => completer.future, + child: const Text('go'), + builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + ), ), ), - )); + ); await tester.tap(find.byType(TextButton)); await tester.pump(); expect(find.text('themed-loading'), findsOneWidget); @@ -73,20 +85,21 @@ void main() { testWidgets('widget loadingChild beats theme', (tester) async { final completer = Completer(); - await tester.pumpWidget(MaterialApp( - theme: ThemeData(extensions: const [ - MaterialAsyncButtonTheme(loadingChild: Text('themed')), - ]), - home: Scaffold( - body: AsyncButtonBuilder( - onPressed: () => completer.future, - child: const Text('go'), - loadingChild: const Text('widget'), - builder: (c, child, cb, _) => - TextButton(onPressed: cb, child: child), + await tester.pumpWidget( + MaterialApp( + theme: ThemeData( + extensions: const [MaterialAsyncButtonTheme(loadingChild: Text('themed'))], + ), + home: Scaffold( + body: AsyncButtonBuilder( + onPressed: () => completer.future, + child: const Text('go'), + loadingChild: const Text('widget'), + builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + ), ), ), - )); + ); await tester.tap(find.byType(TextButton)); await tester.pump(); expect(find.text('widget'), findsOneWidget); @@ -97,27 +110,33 @@ void main() { }); group('AsyncButtonBuilder transitions', () { - testWidgets('returns to child after success with zero display duration', - (tester) async { - await tester.pumpWidget(_wrap(AsyncButtonBuilder( - onPressed: () async {}, - child: const Text('label'), - builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), - ))); + testWidgets('returns to child after success with zero display duration', (tester) async { + await tester.pumpWidget( + _wrap( + AsyncButtonBuilder( + onPressed: () async {}, + child: const Text('label'), + builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + ), + ), + ); await tester.tap(find.byType(TextButton)); await tester.pumpAndSettle(); expect(find.text('label'), findsOneWidget); }); - testWidgets('shows successChild for successDisplayDuration', - (tester) async { - await tester.pumpWidget(_wrap(AsyncButtonBuilder( - onPressed: () async {}, - child: const Text('label'), - successChild: const Text('done!'), - successDisplayDuration: const Duration(milliseconds: 200), - builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), - ))); + testWidgets('shows successChild for successDisplayDuration', (tester) async { + await tester.pumpWidget( + _wrap( + AsyncButtonBuilder( + onPressed: () async {}, + child: const Text('label'), + successChild: const Text('done!'), + successDisplayDuration: const Duration(milliseconds: 200), + builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + ), + ), + ); await tester.tap(find.byType(TextButton)); await tester.pump(); await tester.pump(); @@ -128,19 +147,22 @@ void main() { expect(find.text('label'), findsOneWidget); }); - testWidgets('shows errorChild and exposes error to errorBuilder', - (tester) async { + testWidgets('shows errorChild and exposes error to errorBuilder', (tester) async { Object? observed; - await tester.pumpWidget(_wrap(AsyncButtonBuilder( - onPressed: () async => throw StateError('boom'), - child: const Text('label'), - errorDisplayDuration: const Duration(milliseconds: 100), - errorBuilder: (c, err, st) { - observed = err; - return Text('err: ${err.toString().split(":").last.trim()}'); - }, - builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), - ))); + await tester.pumpWidget( + _wrap( + AsyncButtonBuilder( + onPressed: () async => throw StateError('boom'), + child: const Text('label'), + errorDisplayDuration: const Duration(milliseconds: 100), + errorBuilder: (c, err, st) { + observed = err; + return Text('err: ${err.toString().split(":").last.trim()}'); + }, + builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + ), + ), + ); await tester.tap(find.byType(TextButton)); await tester.pump(); await tester.pump(); @@ -153,22 +175,30 @@ void main() { group('AsyncButtonBuilder callbacks', () { testWidgets('callback null when disabled', (tester) async { - await tester.pumpWidget(_wrap(AsyncButtonBuilder( - onPressed: () async {}, - disabled: true, - child: const Text('label'), - builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), - ))); + await tester.pumpWidget( + _wrap( + AsyncButtonBuilder( + onPressed: () async {}, + disabled: true, + child: const Text('label'), + builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + ), + ), + ); final btn = tester.widget(find.byType(TextButton)); expect(btn.onPressed, isNull); }); testWidgets('callback null when onPressed is null', (tester) async { - await tester.pumpWidget(_wrap(AsyncButtonBuilder( - onPressed: null, - child: const Text('label'), - builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), - ))); + await tester.pumpWidget( + _wrap( + AsyncButtonBuilder( + onPressed: null, + child: const Text('label'), + builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + ), + ), + ); final btn = tester.widget(find.byType(TextButton)); expect(btn.onPressed, isNull); }); @@ -176,32 +206,42 @@ void main() { testWidgets('onSuccess and onStateChanged fire', (tester) async { var successCount = 0; final changes = []; - await tester.pumpWidget(_wrap(AsyncButtonBuilder( - onPressed: () async {}, - onSuccess: () => successCount++, - onStateChanged: changes.add, - child: const Text('label'), - builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), - ))); + await tester.pumpWidget( + _wrap( + AsyncButtonBuilder( + onPressed: () async {}, + onSuccess: () => successCount++, + onStateChanged: changes.add, + child: const Text('label'), + builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + ), + ), + ); await tester.tap(find.byType(TextButton)); await tester.pumpAndSettle(); expect(successCount, 1); - expect(changes.map((s) => s.runtimeType), - containsAllInOrder([ - AsyncButtonStateLoading, - AsyncButtonStateSuccess, - AsyncButtonStateIdle, - ])); + expect( + changes.map((s) => s.runtimeType), + containsAllInOrder([ + AsyncButtonStateLoading, + AsyncButtonStateSuccess, + AsyncButtonStateIdle, + ]), + ); }); testWidgets('onError fires with the thrown error', (tester) async { Object? captured; - await tester.pumpWidget(_wrap(AsyncButtonBuilder( - onPressed: () async => throw StateError('x'), - onError: (e, _) => captured = e, - child: const Text('label'), - builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), - ))); + await tester.pumpWidget( + _wrap( + AsyncButtonBuilder( + onPressed: () async => throw StateError('x'), + onError: (e, _) => captured = e, + child: const Text('label'), + builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + ), + ), + ); await tester.tap(find.byType(TextButton)); await tester.pumpAndSettle(); expect(captured, isA()); @@ -209,16 +249,19 @@ void main() { testWidgets('confirmBeforePress can cancel the press', (tester) async { var ran = 0; - await tester.pumpWidget(_wrap(AsyncButtonBuilder( - onPressed: () async => ran++, - confirmBeforePress: (_) async => false, - child: const Text('label'), - builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), - ))); + await tester.pumpWidget( + _wrap( + AsyncButtonBuilder( + onPressed: () async => ran++, + confirmBeforePress: (_) async => false, + child: const Text('label'), + builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + ), + ), + ); await tester.tap(find.byType(TextButton)); await tester.pumpAndSettle(); - expect(ran, 0, - reason: 'onPressed should not run when confirm returns false.'); + expect(ran, 0, reason: 'onPressed should not run when confirm returns false.'); }); }); @@ -226,29 +269,36 @@ void main() { testWidgets('GlobalKey.trigger() runs onPressed', (tester) async { final key = GlobalKey(); var ran = 0; - await tester.pumpWidget(_wrap(AsyncButtonBuilder( - key: key, - onPressed: () async => ran++, - child: const Text('label'), - builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), - ))); + await tester.pumpWidget( + _wrap( + AsyncButtonBuilder( + key: key, + onPressed: () async => ran++, + child: const Text('label'), + builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + ), + ), + ); await key.currentState!.trigger(); await tester.pumpAndSettle(); expect(ran, 1); }); - testWidgets('AsyncButtonController.invalidate flips to error', - (tester) async { + testWidgets('AsyncButtonController.invalidate flips to error', (tester) async { final controller = AsyncButtonController(); addTearDown(controller.dispose); - await tester.pumpWidget(_wrap(AsyncButtonBuilder( - controller: controller, - onPressed: () async {}, - child: const Text('label'), - errorChild: const Text('errored'), - errorDisplayDuration: const Duration(milliseconds: 100), - builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), - ))); + await tester.pumpWidget( + _wrap( + AsyncButtonBuilder( + controller: controller, + onPressed: () async {}, + child: const Text('label'), + errorChild: const Text('errored'), + errorDisplayDuration: const Duration(milliseconds: 100), + builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + ), + ), + ); controller.invalidate('bad'); await tester.pump(); expect(find.text('errored'), findsOneWidget); @@ -256,18 +306,21 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('AsyncButtonController.reset clears mid-display', - (tester) async { + testWidgets('AsyncButtonController.reset clears mid-display', (tester) async { final controller = AsyncButtonController(); addTearDown(controller.dispose); - await tester.pumpWidget(_wrap(AsyncButtonBuilder( - controller: controller, - onPressed: () async {}, - child: const Text('label'), - successChild: const Text('yay'), - successDisplayDuration: const Duration(seconds: 5), - builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), - ))); + await tester.pumpWidget( + _wrap( + AsyncButtonBuilder( + controller: controller, + onPressed: () async {}, + child: const Text('label'), + successChild: const Text('yay'), + successDisplayDuration: const Duration(seconds: 5), + builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + ), + ), + ); controller.markSuccess(); await tester.pump(); expect(find.text('yay'), findsOneWidget); @@ -276,9 +329,9 @@ void main() { expect(find.text('label'), findsOneWidget); }); - testWidgets( - 'swapping the external controller transfers listening without leak', - (tester) async { + testWidgets('swapping the external controller transfers listening without leak', ( + tester, + ) async { final a = AsyncButtonController(); final b = AsyncButtonController(); addTearDown(() { @@ -286,14 +339,13 @@ void main() { b.dispose(); }); final builder = (AsyncButtonController c) => AsyncButtonBuilder( - controller: c, - onPressed: () async {}, - successChild: const Text('done'), - successDisplayDuration: const Duration(milliseconds: 100), - child: const Text('child'), - builder: (ctx, child, cb, _) => - TextButton(onPressed: cb, child: child), - ); + controller: c, + onPressed: () async {}, + successChild: const Text('done'), + successDisplayDuration: const Duration(milliseconds: 100), + child: const Text('child'), + builder: (ctx, child, cb, _) => TextButton(onPressed: cb, child: child), + ); await tester.pumpWidget(_wrap(builder(a))); await tester.pumpWidget(_wrap(builder(b))); // Mutating the OLD controller must not change the UI. @@ -310,18 +362,21 @@ void main() { }); group('AsyncButtonBuilder timer hygiene (regression for old timer race)', () { - testWidgets('rapid invalidate then reset does not later re-flip to idle', - (tester) async { + testWidgets('rapid invalidate then reset does not later re-flip to idle', (tester) async { final controller = AsyncButtonController(); addTearDown(controller.dispose); - await tester.pumpWidget(_wrap(AsyncButtonBuilder( - controller: controller, - onPressed: () async {}, - child: const Text('child'), - errorChild: const Text('e'), - errorDisplayDuration: const Duration(milliseconds: 200), - builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), - ))); + await tester.pumpWidget( + _wrap( + AsyncButtonBuilder( + controller: controller, + onPressed: () async {}, + child: const Text('child'), + errorChild: const Text('e'), + errorDisplayDuration: const Duration(milliseconds: 200), + builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + ), + ), + ); controller.invalidate('1'); await tester.pump(); // While in error display, manually mark success. The previous error diff --git a/test/async_button_controller_test.dart b/test/async_button_controller_test.dart index 437435c..f372175 100644 --- a/test/async_button_controller_test.dart +++ b/test/async_button_controller_test.dart @@ -11,8 +11,7 @@ void main() { expect(c.value, const AsyncButtonState.idle()); expect(c.isIdle, isTrue); expect(c.isLoading, isFalse); - expect(c.canTrigger, isFalse, - reason: 'No onPressed attached yet, cannot trigger.'); + expect(c.canTrigger, isFalse, reason: 'No onPressed attached yet, cannot trigger.'); c.dispose(); }); @@ -46,8 +45,7 @@ void main() { c.dispose(); }); - test('invalidate forces error and reaches idle when duration zero', - () async { + test('invalidate forces error and reaches idle when duration zero', () async { final c = AsyncButtonController() ..attach( onPressed: null, @@ -57,13 +55,15 @@ void main() { rethrowErrors: false, ); c.invalidate('bad'); - expect(c.value, const AsyncButtonState.idle(), - reason: 'Zero error duration returns straight to idle.'); + expect( + c.value, + const AsyncButtonState.idle(), + reason: 'Zero error duration returns straight to idle.', + ); c.dispose(); }); - test('invalidate forces error and stays there for errorDuration', - () async { + test('invalidate forces error and stays there for errorDuration', () async { final c = AsyncButtonController() ..attach( onPressed: null, @@ -94,13 +94,11 @@ void main() { c.dispose(); }); - test('successful trigger transitions idle -> loading -> success -> idle', - () async { + test('successful trigger transitions idle -> loading -> success -> idle', () async { final transitions = []; final c = AsyncButtonController() ..attach( - onPressed: () async => Future.delayed( - const Duration(milliseconds: 20)), + onPressed: () async => Future.delayed(const Duration(milliseconds: 20)), successDuration: const Duration(milliseconds: 20), errorDuration: Duration.zero, cooldownDuration: Duration.zero, @@ -111,17 +109,17 @@ void main() { // trigger awaited onPressed. Success has fired; idle is scheduled in 20ms. await Future.delayed(const Duration(milliseconds: 50)); expect( - transitions.map((s) => s.runtimeType).toList(), - containsAllInOrder([ - AsyncButtonStateLoading, - AsyncButtonStateSuccess, - AsyncButtonStateIdle, - ])); + transitions.map((s) => s.runtimeType).toList(), + containsAllInOrder([ + AsyncButtonStateLoading, + AsyncButtonStateSuccess, + AsyncButtonStateIdle, + ]), + ); c.dispose(); }); - test('failing trigger transitions idle -> loading -> error -> idle', - () async { + test('failing trigger transitions idle -> loading -> error -> idle', () async { final transitions = []; final c = AsyncButtonController() ..attach( @@ -135,12 +133,13 @@ void main() { await c.trigger(); await Future.delayed(const Duration(milliseconds: 50)); expect( - transitions.map((s) => s.runtimeType).toList(), - containsAllInOrder([ - AsyncButtonStateLoading, - AsyncButtonStateError, - AsyncButtonStateIdle, - ])); + transitions.map((s) => s.runtimeType).toList(), + containsAllInOrder([ + AsyncButtonStateLoading, + AsyncButtonStateError, + AsyncButtonStateIdle, + ]), + ); c.dispose(); }); @@ -250,37 +249,44 @@ void main() { test('error/stackTrace getters expose the error variant payload', () { final st = StackTrace.current; - final c = AsyncButtonController( - initial: AsyncButtonState.error('boom', st)); + final c = AsyncButtonController(initial: AsyncButtonState.error('boom', st)); expect(c.error, 'boom'); expect(c.stackTrace, st); c.dispose(); }); }); - testWidgets('value listenable interop with ValueListenableBuilder', - (tester) async { - final c = AsyncButtonController(); + testWidgets('value listenable interop with ValueListenableBuilder', (tester) async { + final c = AsyncButtonController() + ..attach( + onPressed: null, + successDuration: const Duration(seconds: 5), + errorDuration: Duration.zero, + cooldownDuration: Duration.zero, + rethrowErrors: false, + ); addTearDown(c.dispose); String label(AsyncButtonState s) => switch (s) { - AsyncButtonStateIdle() => 'idle', - AsyncButtonStateLoading() => 'loading', - AsyncButtonStateSuccess() => 'success', - AsyncButtonStateError() => 'error', - }; + AsyncButtonStateIdle() => 'idle', + AsyncButtonStateLoading() => 'loading', + AsyncButtonStateSuccess() => 'success', + AsyncButtonStateError() => 'error', + }; - await tester.pumpWidget(MaterialApp( - home: ValueListenableBuilder( - valueListenable: c, - builder: (_, state, __) => Text(label(state), - textDirection: TextDirection.ltr), + await tester.pumpWidget( + MaterialApp( + home: ValueListenableBuilder( + valueListenable: c, + builder: (_, state, __) => Text(label(state), textDirection: TextDirection.ltr), + ), ), - )); + ); expect(find.text('idle'), findsOneWidget); c.markSuccess(); await tester.pump(); expect(find.text('success'), findsOneWidget); + c.reset(); }); } diff --git a/test/async_button_state_test.dart b/test/async_button_state_test.dart index b6cd364..c5eca0b 100644 --- a/test/async_button_state_test.dart +++ b/test/async_button_state_test.dart @@ -5,61 +5,51 @@ void main() { group('AsyncButtonState equality', () { test('idle equals idle', () { expect(const AsyncButtonState.idle(), const AsyncButtonState.idle()); - expect(const AsyncButtonState.idle().hashCode, - const AsyncButtonState.idle().hashCode); + expect(const AsyncButtonState.idle().hashCode, const AsyncButtonState.idle().hashCode); }); test('loading equals loading', () { - expect( - const AsyncButtonState.loading(), const AsyncButtonState.loading()); + expect(const AsyncButtonState.loading(), const AsyncButtonState.loading()); }); test('success equals success', () { - expect( - const AsyncButtonState.success(), const AsyncButtonState.success()); + expect(const AsyncButtonState.success(), const AsyncButtonState.success()); }); test('error equals error by error object', () { final e = Exception('boom'); expect(AsyncButtonState.error(e), AsyncButtonState.error(e)); // Different errors are not equal. - expect(AsyncButtonState.error(Exception('a')) == - AsyncButtonState.error(Exception('a')), - isFalse, - reason: 'Two distinct Exception instances are not equal in Dart.'); + expect( + AsyncButtonState.error(Exception('a')) == AsyncButtonState.error(Exception('a')), + isFalse, + reason: 'Two distinct Exception instances are not equal in Dart.', + ); }); test('different variants are not equal', () { - expect( - const AsyncButtonState.idle() == const AsyncButtonState.loading(), - isFalse); - expect( - const AsyncButtonState.success() == const AsyncButtonState.idle(), - isFalse); + expect(const AsyncButtonState.idle() == const AsyncButtonState.loading(), isFalse); + expect(const AsyncButtonState.success() == const AsyncButtonState.idle(), isFalse); }); }); group('AsyncButtonState toString', () { test('readable identifiers', () { - expect(const AsyncButtonState.idle().toString(), - 'AsyncButtonState.idle()'); - expect(const AsyncButtonState.loading().toString(), - 'AsyncButtonState.loading()'); - expect(const AsyncButtonState.success().toString(), - 'AsyncButtonState.success()'); - expect(AsyncButtonState.error('boom').toString(), - 'AsyncButtonState.error(boom)'); + expect(const AsyncButtonState.idle().toString(), 'AsyncButtonState.idle()'); + expect(const AsyncButtonState.loading().toString(), 'AsyncButtonState.loading()'); + expect(const AsyncButtonState.success().toString(), 'AsyncButtonState.success()'); + expect(AsyncButtonState.error('boom').toString(), 'AsyncButtonState.error(boom)'); }); }); group('AsyncButtonState pattern matching', () { test('exhaustive switch compiles and dispatches', () { String describe(AsyncButtonState s) => switch (s) { - AsyncButtonStateIdle() => 'idle', - AsyncButtonStateLoading() => 'loading', - AsyncButtonStateSuccess() => 'success', - AsyncButtonStateError() => 'error', - }; + AsyncButtonStateIdle() => 'idle', + AsyncButtonStateLoading() => 'loading', + AsyncButtonStateSuccess() => 'success', + AsyncButtonStateError() => 'error', + }; expect(describe(const AsyncButtonState.idle()), 'idle'); expect(describe(const AsyncButtonState.loading()), 'loading'); expect(describe(const AsyncButtonState.success()), 'success'); diff --git a/test/elevated_async_button_test.dart b/test/elevated_async_button_test.dart index 700909c..790887c 100644 --- a/test/elevated_async_button_test.dart +++ b/test/elevated_async_button_test.dart @@ -4,26 +4,25 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:material_async_button/material_async_button.dart'; -Widget _wrap(Widget child) => - MaterialApp(home: Scaffold(body: Center(child: child))); +Widget _wrap(Widget child) => MaterialApp( + home: Scaffold(body: Center(child: child)), +); void main() { group('ElevatedAsyncButton', () { testWidgets('renders an ElevatedButton with the child', (tester) async { - await tester.pumpWidget(_wrap(ElevatedAsyncButton( - onPressed: () async {}, - child: const Text('go'), - ))); + await tester.pumpWidget( + _wrap(ElevatedAsyncButton(onPressed: () async {}, child: const Text('go'))), + ); expect(find.byType(ElevatedButton), findsOneWidget); expect(find.text('go'), findsOneWidget); }); testWidgets('shows loading then returns to idle', (tester) async { final completer = Completer(); - await tester.pumpWidget(_wrap(ElevatedAsyncButton( - onPressed: () => completer.future, - child: const Text('go'), - ))); + await tester.pumpWidget( + _wrap(ElevatedAsyncButton(onPressed: () => completer.future, child: const Text('go'))), + ); await tester.tap(find.byType(ElevatedButton)); await tester.pump(); expect(find.byType(CircularProgressIndicator), findsOneWidget); @@ -33,20 +32,15 @@ void main() { }); testWidgets('is disabled when onPressed is null', (tester) async { - await tester.pumpWidget(_wrap(const ElevatedAsyncButton( - onPressed: null, - child: Text('go'), - ))); + await tester.pumpWidget(_wrap(const ElevatedAsyncButton(onPressed: null, child: Text('go')))); final btn = tester.widget(find.byType(ElevatedButton)); expect(btn.onPressed, isNull); }); testWidgets('is disabled when disabled=true', (tester) async { - await tester.pumpWidget(_wrap(ElevatedAsyncButton( - onPressed: () async {}, - disabled: true, - child: const Text('go'), - ))); + await tester.pumpWidget( + _wrap(ElevatedAsyncButton(onPressed: () async {}, disabled: true, child: const Text('go'))), + ); final btn = tester.widget(find.byType(ElevatedButton)); expect(btn.onPressed, isNull); }); @@ -55,11 +49,15 @@ void main() { group('ElevatedAsyncButton.icon', () { testWidgets('icon stays put while the label animates', (tester) async { final completer = Completer(); - await tester.pumpWidget(_wrap(ElevatedAsyncButton.icon( - onPressed: () => completer.future, - icon: const Icon(Icons.send), - label: const Text('send'), - ))); + await tester.pumpWidget( + _wrap( + ElevatedAsyncButton.icon( + onPressed: () => completer.future, + icon: const Icon(Icons.send), + label: const Text('send'), + ), + ), + ); // Idle: icon + label. expect(find.byIcon(Icons.send), findsOneWidget); expect(find.text('send'), findsOneWidget); diff --git a/test/filled_async_button_test.dart b/test/filled_async_button_test.dart index 2c1f7ee..56e2bd5 100644 --- a/test/filled_async_button_test.dart +++ b/test/filled_async_button_test.dart @@ -4,36 +4,37 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:material_async_button/material_async_button.dart'; -Widget _wrap(Widget child) => - MaterialApp(home: Scaffold(body: Center(child: child))); +Widget _wrap(Widget child) => MaterialApp( + home: Scaffold(body: Center(child: child)), +); void main() { group('FilledAsyncButton', () { testWidgets('renders FilledButton', (tester) async { - await tester.pumpWidget(_wrap(FilledAsyncButton( - onPressed: () async {}, - child: const Text('go'), - ))); + await tester.pumpWidget( + _wrap(FilledAsyncButton(onPressed: () async {}, child: const Text('go'))), + ); expect(find.byType(FilledButton), findsOneWidget); }); - testWidgets('FilledAsyncButton.tonal renders FilledButton in tonal style', - (tester) async { - await tester.pumpWidget(_wrap(FilledAsyncButton.tonal( - onPressed: () async {}, - child: const Text('go'), - ))); + testWidgets('FilledAsyncButton.tonal renders FilledButton in tonal style', (tester) async { + await tester.pumpWidget( + _wrap(FilledAsyncButton.tonal(onPressed: () async {}, child: const Text('go'))), + ); expect(find.byType(FilledButton), findsOneWidget); }); - testWidgets('FilledAsyncButton.icon swaps label during loading', - (tester) async { + testWidgets('FilledAsyncButton.icon swaps label during loading', (tester) async { final completer = Completer(); - await tester.pumpWidget(_wrap(FilledAsyncButton.icon( - onPressed: () => completer.future, - icon: const Icon(Icons.save), - label: const Text('save'), - ))); + await tester.pumpWidget( + _wrap( + FilledAsyncButton.icon( + onPressed: () => completer.future, + icon: const Icon(Icons.save), + label: const Text('save'), + ), + ), + ); await tester.tap(find.byType(FilledButton)); await tester.pump(); expect(find.byIcon(Icons.save), findsOneWidget); @@ -43,11 +44,15 @@ void main() { }); testWidgets('FilledAsyncButton.tonalIcon renders', (tester) async { - await tester.pumpWidget(_wrap(FilledAsyncButton.tonalIcon( - onPressed: () async {}, - icon: const Icon(Icons.save), - label: const Text('save'), - ))); + await tester.pumpWidget( + _wrap( + FilledAsyncButton.tonalIcon( + onPressed: () async {}, + icon: const Icon(Icons.save), + label: const Text('save'), + ), + ), + ); expect(find.byType(FilledButton), findsOneWidget); }); }); diff --git a/test/icon_async_button_test.dart b/test/icon_async_button_test.dart index d43665c..7a46fe0 100644 --- a/test/icon_async_button_test.dart +++ b/test/icon_async_button_test.dart @@ -4,29 +4,25 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:material_async_button/material_async_button.dart'; -Widget _wrap(Widget child) => - MaterialApp(home: Scaffold(body: Center(child: child))); +Widget _wrap(Widget child) => MaterialApp( + home: Scaffold(body: Center(child: child)), +); void main() { group('IconAsyncButton', () { testWidgets('renders IconButton with the icon', (tester) async { - await tester.pumpWidget(_wrap(IconAsyncButton( - onPressed: () async {}, - icon: const Icon(Icons.refresh), - ))); + await tester.pumpWidget( + _wrap(IconAsyncButton(onPressed: () async {}, icon: const Icon(Icons.refresh))), + ); expect(find.byIcon(Icons.refresh), findsOneWidget); expect(find.byType(IconButton), findsOneWidget); }); - testWidgets('filled, filledTonal, outlined variants all render', - (tester) async { + testWidgets('filled, filledTonal, outlined variants all render', (tester) async { for (final ctor in [ - () => IconAsyncButton.filled( - onPressed: () async {}, icon: const Icon(Icons.add)), - () => IconAsyncButton.filledTonal( - onPressed: () async {}, icon: const Icon(Icons.add)), - () => IconAsyncButton.outlined( - onPressed: () async {}, icon: const Icon(Icons.add)), + () => IconAsyncButton.filled(onPressed: () async {}, icon: const Icon(Icons.add)), + () => IconAsyncButton.filledTonal(onPressed: () async {}, icon: const Icon(Icons.add)), + () => IconAsyncButton.outlined(onPressed: () async {}, icon: const Icon(Icons.add)), ]) { await tester.pumpWidget(_wrap(ctor())); expect(find.byType(IconButton), findsOneWidget); @@ -35,10 +31,9 @@ void main() { testWidgets('swaps icon for loading widget during press', (tester) async { final completer = Completer(); - await tester.pumpWidget(_wrap(IconAsyncButton( - onPressed: () => completer.future, - icon: const Icon(Icons.refresh), - ))); + await tester.pumpWidget( + _wrap(IconAsyncButton(onPressed: () => completer.future, icon: const Icon(Icons.refresh))), + ); await tester.tap(find.byType(IconButton)); await tester.pump(); expect(find.byType(CircularProgressIndicator), findsOneWidget); diff --git a/test/material_async_button_theme_test.dart b/test/material_async_button_theme_test.dart index d560950..7f8722a 100644 --- a/test/material_async_button_theme_test.dart +++ b/test/material_async_button_theme_test.dart @@ -28,8 +28,7 @@ void main() { test('copyWith overrides only specified fields', () { final base = MaterialAsyncButtonTheme.material(); - final overridden = - base.copyWith(switchDuration: const Duration(milliseconds: 500)); + final overridden = base.copyWith(switchDuration: const Duration(milliseconds: 500)); expect(overridden.switchDuration, const Duration(milliseconds: 500)); expect(overridden.successDisplayDuration, base.successDisplayDuration); expect(overridden.hapticOn, base.hapticOn); @@ -54,47 +53,52 @@ void main() { }); test('lerp with non-MaterialAsyncButtonTheme returns self', () { - const a = MaterialAsyncButtonTheme( - switchDuration: Duration(milliseconds: 100)); + const a = MaterialAsyncButtonTheme(switchDuration: Duration(milliseconds: 100)); final result = a.lerp(null, 0.5); expect(result.switchDuration, a.switchDuration); }); testWidgets('of(context) returns the registered extension', (tester) async { - const ext = MaterialAsyncButtonTheme( - switchDuration: Duration(milliseconds: 123)); + const ext = MaterialAsyncButtonTheme(switchDuration: Duration(milliseconds: 123)); MaterialAsyncButtonTheme? captured; - await tester.pumpWidget(MaterialApp( - theme: ThemeData(extensions: const [ext]), - home: Builder( - builder: (ctx) { - captured = MaterialAsyncButtonTheme.of(ctx); - return const SizedBox.shrink(); - }, + await tester.pumpWidget( + MaterialApp( + theme: ThemeData(extensions: const [ext]), + home: Builder( + builder: (ctx) { + captured = MaterialAsyncButtonTheme.of(ctx); + return const SizedBox.shrink(); + }, + ), ), - )); + ); expect(captured?.switchDuration, const Duration(milliseconds: 123)); }); - testWidgets('of(context) returns empty when extension absent', - (tester) async { + testWidgets('of(context) returns empty when extension absent', (tester) async { MaterialAsyncButtonTheme? captured; - await tester.pumpWidget(MaterialApp( - home: Builder( - builder: (ctx) { - captured = MaterialAsyncButtonTheme.of(ctx); - return const SizedBox.shrink(); - }, + await tester.pumpWidget( + MaterialApp( + home: Builder( + builder: (ctx) { + captured = MaterialAsyncButtonTheme.of(ctx); + return const SizedBox.shrink(); + }, + ), ), - )); + ); expect(captured?.switchDuration, isNull); }); test('equality is value-based', () { const a = MaterialAsyncButtonTheme( - switchDuration: Duration(milliseconds: 100), hapticOn: HapticOn.both); + switchDuration: Duration(milliseconds: 100), + hapticOn: HapticOn.both, + ); const b = MaterialAsyncButtonTheme( - switchDuration: Duration(milliseconds: 100), hapticOn: HapticOn.both); + switchDuration: Duration(milliseconds: 100), + hapticOn: HapticOn.both, + ); expect(a, b); expect(a.hashCode, b.hashCode); }); diff --git a/test/outlined_async_button_test.dart b/test/outlined_async_button_test.dart index f5b5e47..891645d 100644 --- a/test/outlined_async_button_test.dart +++ b/test/outlined_async_button_test.dart @@ -4,25 +4,29 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:material_async_button/material_async_button.dart'; -Widget _wrap(Widget child) => - MaterialApp(home: Scaffold(body: Center(child: child))); +Widget _wrap(Widget child) => MaterialApp( + home: Scaffold(body: Center(child: child)), +); void main() { group('OutlinedAsyncButton', () { testWidgets('renders OutlinedButton', (tester) async { - await tester.pumpWidget(_wrap(OutlinedAsyncButton( - onPressed: () async {}, - child: const Text('go'), - ))); + await tester.pumpWidget( + _wrap(OutlinedAsyncButton(onPressed: () async {}, child: const Text('go'))), + ); expect(find.byType(OutlinedButton), findsOneWidget); }); testWidgets('.icon variant renders with icon + label', (tester) async { - await tester.pumpWidget(_wrap(OutlinedAsyncButton.icon( - onPressed: () async {}, - icon: const Icon(Icons.share), - label: const Text('share'), - ))); + await tester.pumpWidget( + _wrap( + OutlinedAsyncButton.icon( + onPressed: () async {}, + icon: const Icon(Icons.share), + label: const Text('share'), + ), + ), + ); expect(find.byType(OutlinedButton), findsOneWidget); expect(find.byIcon(Icons.share), findsOneWidget); expect(find.text('share'), findsOneWidget); @@ -30,10 +34,9 @@ void main() { testWidgets('cycles through loading', (tester) async { final completer = Completer(); - await tester.pumpWidget(_wrap(OutlinedAsyncButton( - onPressed: () => completer.future, - child: const Text('go'), - ))); + await tester.pumpWidget( + _wrap(OutlinedAsyncButton(onPressed: () => completer.future, child: const Text('go'))), + ); await tester.tap(find.byType(OutlinedButton)); await tester.pump(); expect(find.byType(CircularProgressIndicator), findsOneWidget); diff --git a/test/text_async_button_test.dart b/test/text_async_button_test.dart index 6680744..cf8a00e 100644 --- a/test/text_async_button_test.dart +++ b/test/text_async_button_test.dart @@ -4,38 +4,39 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:material_async_button/material_async_button.dart'; -Widget _wrap(Widget child) => - MaterialApp(home: Scaffold(body: Center(child: child))); +Widget _wrap(Widget child) => MaterialApp( + home: Scaffold(body: Center(child: child)), +); void main() { group('TextAsyncButton', () { testWidgets('renders TextButton', (tester) async { - await tester.pumpWidget(_wrap(TextAsyncButton( - onPressed: () async {}, - child: const Text('go'), - ))); + await tester.pumpWidget( + _wrap(TextAsyncButton(onPressed: () async {}, child: const Text('go'))), + ); expect(find.byType(TextButton), findsOneWidget); }); testWidgets('.icon variant renders with icon + label', (tester) async { - await tester.pumpWidget(_wrap(TextAsyncButton.icon( - onPressed: () async {}, - icon: const Icon(Icons.copy), - label: const Text('copy'), - ))); + await tester.pumpWidget( + _wrap( + TextAsyncButton.icon( + onPressed: () async {}, + icon: const Icon(Icons.copy), + label: const Text('copy'), + ), + ), + ); expect(find.byType(TextButton), findsOneWidget); expect(find.byIcon(Icons.copy), findsOneWidget); }); - testWidgets('state.trigger() works for "Done" keyboard pattern', - (tester) async { + testWidgets('state.trigger() works for "Done" keyboard pattern', (tester) async { var ran = 0; - await tester.pumpWidget(_wrap(TextAsyncButton( - onPressed: () async => ran++, - child: const Text('go'), - ))); - final state = tester.state( - find.byType(AsyncButtonBuilder)); + await tester.pumpWidget( + _wrap(TextAsyncButton(onPressed: () async => ran++, child: const Text('go'))), + ); + final state = tester.state(find.byType(AsyncButtonBuilder)); await state.trigger(); await tester.pumpAndSettle(); expect(ran, 1); From bf27187dc318cb2505c0958a389ae28e260d239d Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 25 May 2026 14:20:15 +0000 Subject: [PATCH 100/176] fix(ci): resolve flutter analyze errors and one test failure * test/async_button_state_test.dart: typed the variant as AsyncButtonStateError so .error / .stackTrace getters resolve. (Previously accessed on the base sealed type.) * test/text_async_button_test.dart: drop unused dart:async import. * lib/src/async_button_controller.dart: drop @internal import from package:meta; foundation re-exports it. Removed meta from pubspec. * lib/src/async_button_builder.dart: SemanticsService.announce is deprecated in Flutter 3.41; switched to sendAnnouncement with the current FlutterView. * test/filled_async_button_test.dart: FilledAsyncButton.icon test was asserting "save" label is gone after a single pump, but the AnimatedSwitcher cross-fade keeps both widgets in the tree mid- animation. Wait past the switch duration. * test/async_button_builder_test.dart: switch the controller-swap test's local builder var to a function declaration (prefer_function_declarations_over_variables); also reorder its named args so child: is last. Verified locally with Flutter 3.41.0 stable: dart format clean at line-length 100, flutter analyze exits 0 (7 cosmetic info-level lints remain in tests, not fatal), all 69 tests pass. https://claude.ai/code/session_01C5g1NbxvkgKbv7daca8Kvv --- lib/src/async_button_builder.dart | 5 ++++- lib/src/async_button_controller.dart | 1 - pubspec.yaml | 1 - test/async_button_builder_test.dart | 4 ++-- test/async_button_state_test.dart | 6 +++--- test/filled_async_button_test.dart | 3 +++ test/text_async_button_test.dart | 2 -- 7 files changed, 12 insertions(+), 10 deletions(-) diff --git a/lib/src/async_button_builder.dart b/lib/src/async_button_builder.dart index 82fb406..68bb95c 100644 --- a/lib/src/async_button_builder.dart +++ b/lib/src/async_button_builder.dart @@ -219,7 +219,10 @@ class AsyncButtonBuilderState extends State { AsyncButtonStateError() => 'Error', }; if (message != null) { - SemanticsService.announce(message, direction); + final view = View.maybeOf(context); + if (view != null) { + SemanticsService.sendAnnouncement(view, message, direction); + } } } diff --git a/lib/src/async_button_controller.dart b/lib/src/async_button_controller.dart index 224a47a..e5840ee 100644 --- a/lib/src/async_button_controller.dart +++ b/lib/src/async_button_controller.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; -import 'package:meta/meta.dart'; import 'async_button_state.dart'; diff --git a/pubspec.yaml b/pubspec.yaml index 9b1bc61..c4e9da8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -21,7 +21,6 @@ environment: dependencies: flutter: sdk: flutter - meta: ^1.16.0 dev_dependencies: flutter_test: diff --git a/test/async_button_builder_test.dart b/test/async_button_builder_test.dart index 98a6e02..b2b94b2 100644 --- a/test/async_button_builder_test.dart +++ b/test/async_button_builder_test.dart @@ -338,13 +338,13 @@ void main() { a.dispose(); b.dispose(); }); - final builder = (AsyncButtonController c) => AsyncButtonBuilder( + AsyncButtonBuilder builder(AsyncButtonController c) => AsyncButtonBuilder( controller: c, onPressed: () async {}, successChild: const Text('done'), successDisplayDuration: const Duration(milliseconds: 100), - child: const Text('child'), builder: (ctx, child, cb, _) => TextButton(onPressed: cb, child: child), + child: const Text('child'), ); await tester.pumpWidget(_wrap(builder(a))); await tester.pumpWidget(_wrap(builder(b))); diff --git a/test/async_button_state_test.dart b/test/async_button_state_test.dart index c5eca0b..857ded4 100644 --- a/test/async_button_state_test.dart +++ b/test/async_button_state_test.dart @@ -38,7 +38,7 @@ void main() { expect(const AsyncButtonState.idle().toString(), 'AsyncButtonState.idle()'); expect(const AsyncButtonState.loading().toString(), 'AsyncButtonState.loading()'); expect(const AsyncButtonState.success().toString(), 'AsyncButtonState.success()'); - expect(AsyncButtonState.error('boom').toString(), 'AsyncButtonState.error(boom)'); + expect(const AsyncButtonState.error('boom').toString(), 'AsyncButtonState.error(boom)'); }); }); @@ -53,12 +53,12 @@ void main() { expect(describe(const AsyncButtonState.idle()), 'idle'); expect(describe(const AsyncButtonState.loading()), 'loading'); expect(describe(const AsyncButtonState.success()), 'success'); - expect(describe(AsyncButtonState.error('x')), 'error'); + expect(describe(const AsyncButtonState.error('x')), 'error'); }); test('error variant exposes error and stack trace', () { final st = StackTrace.current; - final s = AsyncButtonState.error('boom', st); + final s = AsyncButtonStateError('boom', st); expect(s.error, 'boom'); expect(s.stackTrace, st); }); diff --git a/test/filled_async_button_test.dart b/test/filled_async_button_test.dart index 56e2bd5..4870a0a 100644 --- a/test/filled_async_button_test.dart +++ b/test/filled_async_button_test.dart @@ -36,9 +36,12 @@ void main() { ), ); await tester.tap(find.byType(FilledButton)); + // Wait for the AnimatedSwitcher cross-fade to settle. await tester.pump(); + await tester.pump(const Duration(milliseconds: 250)); expect(find.byIcon(Icons.save), findsOneWidget); expect(find.text('save'), findsNothing); + expect(find.byType(CircularProgressIndicator), findsOneWidget); completer.complete(); await tester.pumpAndSettle(); }); diff --git a/test/text_async_button_test.dart b/test/text_async_button_test.dart index cf8a00e..382464a 100644 --- a/test/text_async_button_test.dart +++ b/test/text_async_button_test.dart @@ -1,5 +1,3 @@ -import 'dart:async'; - import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:material_async_button/material_async_button.dart'; From c2d9fba3ca55131b49caa03f57bba2fdbc8861ef Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 25 May 2026 14:25:14 +0000 Subject: [PATCH 101/176] fix(ci): reorder named args so child: comes last (sort_child_properties_last) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit flutter analyze in Flutter 3.41+ exits non-zero on info-level lints (behavior change from earlier versions). Fix the 7 sort_child_properties_last hits in test files by moving the outer `child:` named arg after `builder:` / other named args in each AsyncButtonBuilder call. Verified locally: `flutter analyze` → "No issues found!" (exit 0), and all 69 tests still pass. https://claude.ai/code/session_01C5g1NbxvkgKbv7daca8Kvv --- coverage/lcov.info | 680 ++++++++++++++++++++++++++++ test/async_button_builder_test.dart | 14 +- 2 files changed, 687 insertions(+), 7 deletions(-) create mode 100644 coverage/lcov.info diff --git a/coverage/lcov.info b/coverage/lcov.info new file mode 100644 index 0000000..ecdcfeb --- /dev/null +++ b/coverage/lcov.info @@ -0,0 +1,680 @@ +SF:lib/src/async_button_builder.dart +DA:52,6 +DA:135,6 +DA:136,6 +DA:141,24 +DA:145,6 +DA:147,6 +DA:148,12 +DA:149,12 +DA:151,18 +DA:152,18 +DA:155,2 +DA:157,2 +DA:158,8 +DA:159,1 +DA:160,2 +DA:161,2 +DA:162,1 +DA:163,1 +DA:165,0 +DA:167,3 +DA:168,3 +DA:172,6 +DA:174,18 +DA:175,12 +DA:176,6 +DA:179,6 +DA:180,12 +DA:181,12 +DA:182,13 +DA:183,12 +DA:184,6 +DA:185,12 +DA:186,12 +DA:187,6 +DA:188,13 +DA:189,6 +DA:190,5 +DA:192,6 +DA:194,18 +DA:197,6 +DA:198,12 +DA:199,18 +DA:200,6 +DA:201,0 +DA:202,0 +DA:203,0 +DA:204,0 +DA:205,0 +DA:206,0 +DA:210,6 +DA:211,12 +DA:212,18 +DA:214,0 +DA:216,0 +DA:217,0 +DA:218,0 +DA:219,0 +DA:222,0 +DA:224,0 +DA:232,6 +DA:235,0 +DA:238,0 +DA:239,0 +DA:242,0 +DA:245,0 +DA:247,6 +DA:249,6 +DA:252,18 +DA:254,18 +DA:255,18 +DA:256,18 +DA:258,12 +DA:259,6 +DA:266,12 +DA:268,18 +DA:269,18 +DA:270,18 +DA:272,18 +DA:273,18 +DA:274,18 +DA:275,18 +DA:276,18 +DA:278,12 +DA:279,6 +DA:281,18 +DA:284,18 +DA:285,5 +DA:286,1 +DA:287,3 +DA:288,3 +DA:291,6 +DA:297,18 +DA:301,0 +DA:304,0 +DA:305,0 +DA:306,0 +DA:311,24 +DA:316,6 +DA:317,24 +DA:318,12 +DA:319,12 +DA:324,6 +DA:325,24 +DA:326,12 +DA:327,12 +DA:329,1 +DA:330,1 +DA:331,2 +DA:332,1 +DA:333,0 +DA:339,1 +DA:341,5 +LF:112 +LH:88 +end_of_record +SF:lib/src/async_button_controller.dart +DA:20,7 +DA:24,7 +DA:25,7 +DA:27,21 +DA:28,3 +DA:29,3 +DA:30,3 +DA:32,2 +DA:33,2 +DA:37,2 +DA:38,2 +DA:42,2 +DA:45,28 +DA:59,7 +DA:67,7 +DA:68,7 +DA:69,7 +DA:70,7 +DA:71,7 +DA:76,7 +DA:77,7 +DA:78,7 +DA:79,7 +DA:81,14 +DA:85,21 +DA:86,7 +DA:87,14 +DA:90,6 +DA:91,4 +DA:92,4 +DA:94,2 +DA:99,2 +DA:100,2 +DA:101,2 +DA:102,2 +DA:107,2 +DA:108,2 +DA:109,6 +DA:110,4 +DA:115,2 +DA:116,2 +DA:117,2 +DA:118,4 +DA:121,7 +DA:122,14 +DA:123,7 +DA:124,7 +DA:127,7 +DA:128,9 +DA:129,7 +DA:132,7 +DA:133,7 +DA:134,7 +DA:137,6 +DA:140,7 +DA:141,7 +DA:142,7 +DA:143,7 +DA:144,14 +DA:145,1 +DA:146,1 +DA:147,4 +DA:148,1 +DA:149,1 +DA:150,1 +DA:151,1 +DA:156,7 +DA:158,7 +DA:159,7 +DA:160,7 +LF:70 +LH:70 +end_of_record +SF:lib/src/async_button_state.dart +DA:14,3 +DA:24,1 +DA:26,8 +DA:27,8 +DA:29,1 +DA:30,1 +DA:32,1 +DA:37,1 +DA:39,8 +DA:40,8 +DA:42,0 +DA:43,0 +DA:45,1 +DA:50,1 +DA:52,8 +DA:53,8 +DA:55,0 +DA:56,0 +DA:58,1 +DA:63,3 +DA:68,3 +DA:69,6 +DA:71,0 +DA:72,0 +DA:74,1 +DA:75,2 +LF:26 +LH:20 +end_of_record +SF:lib/src/buttons/elevated_async_button.dart +DA:12,1 +DA:49,1 +DA:119,1 +DA:120,1 +DA:121,1 +DA:122,1 +DA:123,1 +DA:124,1 +DA:125,1 +DA:126,1 +DA:127,1 +DA:128,1 +DA:129,1 +DA:130,1 +DA:131,1 +DA:132,1 +DA:133,1 +DA:134,1 +DA:135,1 +DA:136,1 +DA:137,1 +DA:138,1 +DA:139,1 +DA:140,1 +DA:141,1 +DA:142,1 +DA:143,1 +DA:144,1 +DA:146,1 +DA:147,1 +DA:148,1 +DA:149,1 +DA:150,1 +DA:151,1 +DA:152,1 +DA:153,1 +DA:154,1 +DA:155,1 +DA:159,1 +DA:161,1 +DA:162,1 +DA:163,1 +DA:164,1 +DA:165,1 +DA:166,1 +DA:167,1 +DA:168,1 +LF:47 +LH:47 +end_of_record +SF:lib/src/buttons/filled_async_button.dart +DA:14,1 +DA:49,1 +DA:84,1 +DA:122,1 +DA:194,1 +DA:195,1 +DA:196,1 +DA:197,1 +DA:198,1 +DA:199,1 +DA:200,1 +DA:201,1 +DA:202,1 +DA:203,1 +DA:204,1 +DA:205,1 +DA:206,1 +DA:207,1 +DA:208,1 +DA:209,1 +DA:210,1 +DA:211,1 +DA:212,1 +DA:213,1 +DA:214,1 +DA:215,1 +DA:216,1 +DA:217,1 +DA:218,1 +DA:219,1 +DA:220,2 +DA:222,1 +DA:223,1 +DA:224,1 +DA:225,1 +DA:226,1 +DA:227,1 +DA:228,1 +DA:229,1 +DA:230,1 +DA:231,1 +DA:234,2 +DA:236,1 +DA:237,1 +DA:238,1 +DA:239,1 +DA:240,1 +DA:241,1 +DA:242,1 +DA:243,1 +DA:244,1 +DA:245,1 +DA:250,1 +DA:251,2 +DA:253,1 +DA:254,1 +DA:255,1 +DA:256,1 +DA:257,1 +DA:258,1 +DA:259,1 +DA:260,1 +DA:263,2 +DA:265,1 +DA:266,1 +DA:267,1 +DA:268,1 +DA:269,1 +DA:270,1 +DA:271,1 +DA:272,1 +LF:71 +LH:71 +end_of_record +SF:lib/src/buttons/icon_async_button.dart +DA:17,1 +DA:62,1 +DA:107,1 +DA:152,1 +DA:241,1 +DA:242,1 +DA:243,1 +DA:244,1 +DA:245,1 +DA:246,1 +DA:247,1 +DA:248,1 +DA:249,1 +DA:250,1 +DA:251,1 +DA:252,1 +DA:253,1 +DA:254,1 +DA:255,1 +DA:256,1 +DA:257,1 +DA:258,1 +DA:259,1 +DA:260,1 +DA:261,1 +DA:262,1 +DA:263,1 +DA:264,1 +DA:265,1 +DA:266,2 +DA:269,1 +DA:270,1 +DA:271,1 +DA:272,1 +DA:273,1 +DA:274,1 +DA:275,1 +DA:276,1 +DA:277,1 +DA:278,1 +DA:279,1 +DA:280,1 +DA:281,1 +DA:282,1 +DA:283,1 +DA:284,1 +DA:285,1 +DA:286,1 +DA:287,1 +DA:288,1 +DA:290,2 +DA:293,1 +DA:294,1 +DA:295,1 +DA:296,1 +DA:297,1 +DA:298,1 +DA:299,1 +DA:300,1 +DA:301,1 +DA:302,1 +DA:303,1 +DA:304,1 +DA:305,1 +DA:306,1 +DA:307,1 +DA:308,1 +DA:309,1 +DA:310,1 +DA:311,1 +DA:312,1 +DA:314,2 +DA:317,1 +DA:318,1 +DA:319,1 +DA:320,1 +DA:321,1 +DA:322,1 +DA:323,1 +DA:324,1 +DA:325,1 +DA:326,1 +DA:327,1 +DA:328,1 +DA:329,1 +DA:330,1 +DA:331,1 +DA:332,1 +DA:333,1 +DA:334,1 +DA:335,1 +DA:336,1 +DA:338,2 +DA:341,1 +DA:342,1 +DA:343,1 +DA:344,1 +DA:345,1 +DA:346,1 +DA:347,1 +DA:348,1 +DA:349,1 +DA:350,1 +DA:351,1 +DA:352,1 +DA:353,1 +DA:354,1 +DA:355,1 +DA:356,1 +DA:357,1 +DA:358,1 +DA:359,1 +DA:360,1 +LF:113 +LH:113 +end_of_record +SF:lib/src/buttons/outlined_async_button.dart +DA:10,1 +DA:44,1 +DA:114,1 +DA:115,1 +DA:116,1 +DA:117,1 +DA:118,1 +DA:119,1 +DA:120,1 +DA:121,1 +DA:122,1 +DA:123,1 +DA:124,1 +DA:125,1 +DA:126,1 +DA:127,1 +DA:128,1 +DA:129,1 +DA:130,1 +DA:131,1 +DA:132,1 +DA:133,1 +DA:134,1 +DA:135,1 +DA:136,1 +DA:137,1 +DA:138,1 +DA:139,1 +DA:141,1 +DA:142,1 +DA:143,1 +DA:144,1 +DA:145,1 +DA:146,1 +DA:147,1 +DA:148,1 +DA:149,1 +DA:150,1 +DA:154,1 +DA:156,1 +DA:157,1 +DA:158,1 +DA:159,1 +DA:160,1 +DA:161,1 +DA:162,1 +DA:163,1 +LF:47 +LH:47 +end_of_record +SF:lib/src/buttons/text_async_button.dart +DA:10,1 +DA:44,1 +DA:114,1 +DA:115,1 +DA:116,1 +DA:117,1 +DA:118,1 +DA:119,1 +DA:120,1 +DA:121,1 +DA:122,1 +DA:123,1 +DA:124,1 +DA:125,1 +DA:126,1 +DA:127,1 +DA:128,1 +DA:129,1 +DA:130,1 +DA:131,1 +DA:132,1 +DA:133,1 +DA:134,1 +DA:135,1 +DA:136,1 +DA:137,1 +DA:138,1 +DA:139,1 +DA:141,1 +DA:142,1 +DA:143,1 +DA:144,1 +DA:145,1 +DA:146,1 +DA:147,1 +DA:148,1 +DA:149,1 +DA:150,1 +DA:154,1 +DA:156,1 +DA:157,1 +DA:158,1 +DA:159,1 +DA:160,1 +DA:161,1 +DA:162,1 +DA:163,1 +LF:47 +LH:47 +end_of_record +SF:lib/src/material_async_button_theme.dart +DA:23,3 +DA:53,1 +DA:57,1 +DA:58,1 +DA:59,1 +DA:60,1 +DA:128,7 +DA:129,14 +DA:131,1 +DA:152,1 +DA:153,1 +DA:154,1 +DA:155,1 +DA:156,0 +DA:157,1 +DA:158,1 +DA:159,1 +DA:160,1 +DA:161,1 +DA:162,1 +DA:163,1 +DA:164,1 +DA:165,1 +DA:166,1 +DA:167,1 +DA:168,1 +DA:169,1 +DA:170,1 +DA:171,1 +DA:174,2 +DA:179,2 +DA:181,2 +DA:182,2 +DA:183,2 +DA:184,2 +DA:185,2 +DA:186,6 +DA:187,6 +DA:188,2 +DA:189,2 +DA:190,2 +DA:191,2 +DA:192,2 +DA:193,2 +DA:194,2 +DA:197,6 +DA:198,6 +DA:199,2 +DA:200,2 +DA:201,6 +DA:202,2 +DA:203,2 +DA:204,2 +DA:205,2 +DA:209,2 +DA:211,1 +DA:212,1 +DA:213,5 +DA:216,2 +DA:219,1 +DA:220,3 +DA:221,3 +DA:222,3 +DA:223,3 +DA:224,3 +DA:225,3 +DA:226,3 +DA:227,3 +DA:228,3 +DA:229,3 +DA:230,3 +DA:231,3 +DA:232,3 +DA:233,3 +DA:234,3 +DA:235,3 +DA:236,3 +DA:237,3 +DA:238,3 +DA:240,1 +DA:241,2 +DA:242,1 +DA:243,1 +DA:244,1 +DA:245,1 +DA:246,1 +DA:247,1 +DA:248,1 +DA:249,1 +DA:250,1 +DA:251,1 +DA:252,1 +DA:253,1 +DA:254,1 +DA:255,1 +DA:256,1 +DA:257,1 +DA:258,1 +DA:259,1 +DA:260,1 +DA:265,1 +DA:269,0 +DA:271,0 +DA:273,0 +DA:275,0 +DA:282,1 +DA:286,0 +DA:288,0 +DA:292,1 +DA:296,0 +DA:298,0 +LF:111 +LH:102 +end_of_record diff --git a/test/async_button_builder_test.dart b/test/async_button_builder_test.dart index b2b94b2..629ce6e 100644 --- a/test/async_button_builder_test.dart +++ b/test/async_button_builder_test.dart @@ -47,9 +47,9 @@ void main() { _wrap( AsyncButtonBuilder( onPressed: () => completer.future, - child: const Text('go'), loadingChild: const Text('spinning'), builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + child: const Text('go'), ), ), ); @@ -93,9 +93,9 @@ void main() { home: Scaffold( body: AsyncButtonBuilder( onPressed: () => completer.future, - child: const Text('go'), loadingChild: const Text('widget'), builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + child: const Text('go'), ), ), ), @@ -130,10 +130,10 @@ void main() { _wrap( AsyncButtonBuilder( onPressed: () async {}, - child: const Text('label'), successChild: const Text('done!'), successDisplayDuration: const Duration(milliseconds: 200), builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + child: const Text('label'), ), ), ); @@ -153,13 +153,13 @@ void main() { _wrap( AsyncButtonBuilder( onPressed: () async => throw StateError('boom'), - child: const Text('label'), errorDisplayDuration: const Duration(milliseconds: 100), errorBuilder: (c, err, st) { observed = err; return Text('err: ${err.toString().split(":").last.trim()}'); }, builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + child: const Text('label'), ), ), ); @@ -292,10 +292,10 @@ void main() { AsyncButtonBuilder( controller: controller, onPressed: () async {}, - child: const Text('label'), errorChild: const Text('errored'), errorDisplayDuration: const Duration(milliseconds: 100), builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + child: const Text('label'), ), ), ); @@ -314,10 +314,10 @@ void main() { AsyncButtonBuilder( controller: controller, onPressed: () async {}, - child: const Text('label'), successChild: const Text('yay'), successDisplayDuration: const Duration(seconds: 5), builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + child: const Text('label'), ), ), ); @@ -370,10 +370,10 @@ void main() { AsyncButtonBuilder( controller: controller, onPressed: () async {}, - child: const Text('child'), errorChild: const Text('e'), errorDisplayDuration: const Duration(milliseconds: 200), builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), + child: const Text('child'), ), ), ); From d88f5c9e437eec8d34639ad979bb4647e846ccb7 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 25 May 2026 14:25:46 +0000 Subject: [PATCH 102/176] chore: untrack coverage/lcov.info and add to .gitignore Accidentally committed in the previous commit; CI generates this fresh each run and uploads as an artifact. https://claude.ai/code/session_01C5g1NbxvkgKbv7daca8Kvv --- .gitignore | 3 + coverage/lcov.info | 680 --------------------------------------------- 2 files changed, 3 insertions(+), 680 deletions(-) delete mode 100644 coverage/lcov.info diff --git a/.gitignore b/.gitignore index 7161313..5c5d214 100644 --- a/.gitignore +++ b/.gitignore @@ -81,3 +81,6 @@ build/ pubspec.lock **/pubspec.lock example/pubspec.lock + +# Coverage output +coverage/ diff --git a/coverage/lcov.info b/coverage/lcov.info deleted file mode 100644 index ecdcfeb..0000000 --- a/coverage/lcov.info +++ /dev/null @@ -1,680 +0,0 @@ -SF:lib/src/async_button_builder.dart -DA:52,6 -DA:135,6 -DA:136,6 -DA:141,24 -DA:145,6 -DA:147,6 -DA:148,12 -DA:149,12 -DA:151,18 -DA:152,18 -DA:155,2 -DA:157,2 -DA:158,8 -DA:159,1 -DA:160,2 -DA:161,2 -DA:162,1 -DA:163,1 -DA:165,0 -DA:167,3 -DA:168,3 -DA:172,6 -DA:174,18 -DA:175,12 -DA:176,6 -DA:179,6 -DA:180,12 -DA:181,12 -DA:182,13 -DA:183,12 -DA:184,6 -DA:185,12 -DA:186,12 -DA:187,6 -DA:188,13 -DA:189,6 -DA:190,5 -DA:192,6 -DA:194,18 -DA:197,6 -DA:198,12 -DA:199,18 -DA:200,6 -DA:201,0 -DA:202,0 -DA:203,0 -DA:204,0 -DA:205,0 -DA:206,0 -DA:210,6 -DA:211,12 -DA:212,18 -DA:214,0 -DA:216,0 -DA:217,0 -DA:218,0 -DA:219,0 -DA:222,0 -DA:224,0 -DA:232,6 -DA:235,0 -DA:238,0 -DA:239,0 -DA:242,0 -DA:245,0 -DA:247,6 -DA:249,6 -DA:252,18 -DA:254,18 -DA:255,18 -DA:256,18 -DA:258,12 -DA:259,6 -DA:266,12 -DA:268,18 -DA:269,18 -DA:270,18 -DA:272,18 -DA:273,18 -DA:274,18 -DA:275,18 -DA:276,18 -DA:278,12 -DA:279,6 -DA:281,18 -DA:284,18 -DA:285,5 -DA:286,1 -DA:287,3 -DA:288,3 -DA:291,6 -DA:297,18 -DA:301,0 -DA:304,0 -DA:305,0 -DA:306,0 -DA:311,24 -DA:316,6 -DA:317,24 -DA:318,12 -DA:319,12 -DA:324,6 -DA:325,24 -DA:326,12 -DA:327,12 -DA:329,1 -DA:330,1 -DA:331,2 -DA:332,1 -DA:333,0 -DA:339,1 -DA:341,5 -LF:112 -LH:88 -end_of_record -SF:lib/src/async_button_controller.dart -DA:20,7 -DA:24,7 -DA:25,7 -DA:27,21 -DA:28,3 -DA:29,3 -DA:30,3 -DA:32,2 -DA:33,2 -DA:37,2 -DA:38,2 -DA:42,2 -DA:45,28 -DA:59,7 -DA:67,7 -DA:68,7 -DA:69,7 -DA:70,7 -DA:71,7 -DA:76,7 -DA:77,7 -DA:78,7 -DA:79,7 -DA:81,14 -DA:85,21 -DA:86,7 -DA:87,14 -DA:90,6 -DA:91,4 -DA:92,4 -DA:94,2 -DA:99,2 -DA:100,2 -DA:101,2 -DA:102,2 -DA:107,2 -DA:108,2 -DA:109,6 -DA:110,4 -DA:115,2 -DA:116,2 -DA:117,2 -DA:118,4 -DA:121,7 -DA:122,14 -DA:123,7 -DA:124,7 -DA:127,7 -DA:128,9 -DA:129,7 -DA:132,7 -DA:133,7 -DA:134,7 -DA:137,6 -DA:140,7 -DA:141,7 -DA:142,7 -DA:143,7 -DA:144,14 -DA:145,1 -DA:146,1 -DA:147,4 -DA:148,1 -DA:149,1 -DA:150,1 -DA:151,1 -DA:156,7 -DA:158,7 -DA:159,7 -DA:160,7 -LF:70 -LH:70 -end_of_record -SF:lib/src/async_button_state.dart -DA:14,3 -DA:24,1 -DA:26,8 -DA:27,8 -DA:29,1 -DA:30,1 -DA:32,1 -DA:37,1 -DA:39,8 -DA:40,8 -DA:42,0 -DA:43,0 -DA:45,1 -DA:50,1 -DA:52,8 -DA:53,8 -DA:55,0 -DA:56,0 -DA:58,1 -DA:63,3 -DA:68,3 -DA:69,6 -DA:71,0 -DA:72,0 -DA:74,1 -DA:75,2 -LF:26 -LH:20 -end_of_record -SF:lib/src/buttons/elevated_async_button.dart -DA:12,1 -DA:49,1 -DA:119,1 -DA:120,1 -DA:121,1 -DA:122,1 -DA:123,1 -DA:124,1 -DA:125,1 -DA:126,1 -DA:127,1 -DA:128,1 -DA:129,1 -DA:130,1 -DA:131,1 -DA:132,1 -DA:133,1 -DA:134,1 -DA:135,1 -DA:136,1 -DA:137,1 -DA:138,1 -DA:139,1 -DA:140,1 -DA:141,1 -DA:142,1 -DA:143,1 -DA:144,1 -DA:146,1 -DA:147,1 -DA:148,1 -DA:149,1 -DA:150,1 -DA:151,1 -DA:152,1 -DA:153,1 -DA:154,1 -DA:155,1 -DA:159,1 -DA:161,1 -DA:162,1 -DA:163,1 -DA:164,1 -DA:165,1 -DA:166,1 -DA:167,1 -DA:168,1 -LF:47 -LH:47 -end_of_record -SF:lib/src/buttons/filled_async_button.dart -DA:14,1 -DA:49,1 -DA:84,1 -DA:122,1 -DA:194,1 -DA:195,1 -DA:196,1 -DA:197,1 -DA:198,1 -DA:199,1 -DA:200,1 -DA:201,1 -DA:202,1 -DA:203,1 -DA:204,1 -DA:205,1 -DA:206,1 -DA:207,1 -DA:208,1 -DA:209,1 -DA:210,1 -DA:211,1 -DA:212,1 -DA:213,1 -DA:214,1 -DA:215,1 -DA:216,1 -DA:217,1 -DA:218,1 -DA:219,1 -DA:220,2 -DA:222,1 -DA:223,1 -DA:224,1 -DA:225,1 -DA:226,1 -DA:227,1 -DA:228,1 -DA:229,1 -DA:230,1 -DA:231,1 -DA:234,2 -DA:236,1 -DA:237,1 -DA:238,1 -DA:239,1 -DA:240,1 -DA:241,1 -DA:242,1 -DA:243,1 -DA:244,1 -DA:245,1 -DA:250,1 -DA:251,2 -DA:253,1 -DA:254,1 -DA:255,1 -DA:256,1 -DA:257,1 -DA:258,1 -DA:259,1 -DA:260,1 -DA:263,2 -DA:265,1 -DA:266,1 -DA:267,1 -DA:268,1 -DA:269,1 -DA:270,1 -DA:271,1 -DA:272,1 -LF:71 -LH:71 -end_of_record -SF:lib/src/buttons/icon_async_button.dart -DA:17,1 -DA:62,1 -DA:107,1 -DA:152,1 -DA:241,1 -DA:242,1 -DA:243,1 -DA:244,1 -DA:245,1 -DA:246,1 -DA:247,1 -DA:248,1 -DA:249,1 -DA:250,1 -DA:251,1 -DA:252,1 -DA:253,1 -DA:254,1 -DA:255,1 -DA:256,1 -DA:257,1 -DA:258,1 -DA:259,1 -DA:260,1 -DA:261,1 -DA:262,1 -DA:263,1 -DA:264,1 -DA:265,1 -DA:266,2 -DA:269,1 -DA:270,1 -DA:271,1 -DA:272,1 -DA:273,1 -DA:274,1 -DA:275,1 -DA:276,1 -DA:277,1 -DA:278,1 -DA:279,1 -DA:280,1 -DA:281,1 -DA:282,1 -DA:283,1 -DA:284,1 -DA:285,1 -DA:286,1 -DA:287,1 -DA:288,1 -DA:290,2 -DA:293,1 -DA:294,1 -DA:295,1 -DA:296,1 -DA:297,1 -DA:298,1 -DA:299,1 -DA:300,1 -DA:301,1 -DA:302,1 -DA:303,1 -DA:304,1 -DA:305,1 -DA:306,1 -DA:307,1 -DA:308,1 -DA:309,1 -DA:310,1 -DA:311,1 -DA:312,1 -DA:314,2 -DA:317,1 -DA:318,1 -DA:319,1 -DA:320,1 -DA:321,1 -DA:322,1 -DA:323,1 -DA:324,1 -DA:325,1 -DA:326,1 -DA:327,1 -DA:328,1 -DA:329,1 -DA:330,1 -DA:331,1 -DA:332,1 -DA:333,1 -DA:334,1 -DA:335,1 -DA:336,1 -DA:338,2 -DA:341,1 -DA:342,1 -DA:343,1 -DA:344,1 -DA:345,1 -DA:346,1 -DA:347,1 -DA:348,1 -DA:349,1 -DA:350,1 -DA:351,1 -DA:352,1 -DA:353,1 -DA:354,1 -DA:355,1 -DA:356,1 -DA:357,1 -DA:358,1 -DA:359,1 -DA:360,1 -LF:113 -LH:113 -end_of_record -SF:lib/src/buttons/outlined_async_button.dart -DA:10,1 -DA:44,1 -DA:114,1 -DA:115,1 -DA:116,1 -DA:117,1 -DA:118,1 -DA:119,1 -DA:120,1 -DA:121,1 -DA:122,1 -DA:123,1 -DA:124,1 -DA:125,1 -DA:126,1 -DA:127,1 -DA:128,1 -DA:129,1 -DA:130,1 -DA:131,1 -DA:132,1 -DA:133,1 -DA:134,1 -DA:135,1 -DA:136,1 -DA:137,1 -DA:138,1 -DA:139,1 -DA:141,1 -DA:142,1 -DA:143,1 -DA:144,1 -DA:145,1 -DA:146,1 -DA:147,1 -DA:148,1 -DA:149,1 -DA:150,1 -DA:154,1 -DA:156,1 -DA:157,1 -DA:158,1 -DA:159,1 -DA:160,1 -DA:161,1 -DA:162,1 -DA:163,1 -LF:47 -LH:47 -end_of_record -SF:lib/src/buttons/text_async_button.dart -DA:10,1 -DA:44,1 -DA:114,1 -DA:115,1 -DA:116,1 -DA:117,1 -DA:118,1 -DA:119,1 -DA:120,1 -DA:121,1 -DA:122,1 -DA:123,1 -DA:124,1 -DA:125,1 -DA:126,1 -DA:127,1 -DA:128,1 -DA:129,1 -DA:130,1 -DA:131,1 -DA:132,1 -DA:133,1 -DA:134,1 -DA:135,1 -DA:136,1 -DA:137,1 -DA:138,1 -DA:139,1 -DA:141,1 -DA:142,1 -DA:143,1 -DA:144,1 -DA:145,1 -DA:146,1 -DA:147,1 -DA:148,1 -DA:149,1 -DA:150,1 -DA:154,1 -DA:156,1 -DA:157,1 -DA:158,1 -DA:159,1 -DA:160,1 -DA:161,1 -DA:162,1 -DA:163,1 -LF:47 -LH:47 -end_of_record -SF:lib/src/material_async_button_theme.dart -DA:23,3 -DA:53,1 -DA:57,1 -DA:58,1 -DA:59,1 -DA:60,1 -DA:128,7 -DA:129,14 -DA:131,1 -DA:152,1 -DA:153,1 -DA:154,1 -DA:155,1 -DA:156,0 -DA:157,1 -DA:158,1 -DA:159,1 -DA:160,1 -DA:161,1 -DA:162,1 -DA:163,1 -DA:164,1 -DA:165,1 -DA:166,1 -DA:167,1 -DA:168,1 -DA:169,1 -DA:170,1 -DA:171,1 -DA:174,2 -DA:179,2 -DA:181,2 -DA:182,2 -DA:183,2 -DA:184,2 -DA:185,2 -DA:186,6 -DA:187,6 -DA:188,2 -DA:189,2 -DA:190,2 -DA:191,2 -DA:192,2 -DA:193,2 -DA:194,2 -DA:197,6 -DA:198,6 -DA:199,2 -DA:200,2 -DA:201,6 -DA:202,2 -DA:203,2 -DA:204,2 -DA:205,2 -DA:209,2 -DA:211,1 -DA:212,1 -DA:213,5 -DA:216,2 -DA:219,1 -DA:220,3 -DA:221,3 -DA:222,3 -DA:223,3 -DA:224,3 -DA:225,3 -DA:226,3 -DA:227,3 -DA:228,3 -DA:229,3 -DA:230,3 -DA:231,3 -DA:232,3 -DA:233,3 -DA:234,3 -DA:235,3 -DA:236,3 -DA:237,3 -DA:238,3 -DA:240,1 -DA:241,2 -DA:242,1 -DA:243,1 -DA:244,1 -DA:245,1 -DA:246,1 -DA:247,1 -DA:248,1 -DA:249,1 -DA:250,1 -DA:251,1 -DA:252,1 -DA:253,1 -DA:254,1 -DA:255,1 -DA:256,1 -DA:257,1 -DA:258,1 -DA:259,1 -DA:260,1 -DA:265,1 -DA:269,0 -DA:271,0 -DA:273,0 -DA:275,0 -DA:282,1 -DA:286,0 -DA:288,0 -DA:292,1 -DA:296,0 -DA:298,0 -LF:111 -LH:102 -end_of_record From 83075e1413f0c2b2fbf46d406f78a8bc60fb4ea1 Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Tue, 26 May 2026 12:50:08 +0300 Subject: [PATCH 103/176] chore(release): polish 1.0.0 - Refactor AsyncButtonController to extend ValueNotifier. - Reorder constructor parameters: all super.X before this.X and locals. - Remove stale pre-rename files (async_button_builder, async_button_state, screenshots, claude_code_skill). - Ship Claude Code skill at tool/claude/flutter-material-async-button/SKILL.md with corrected type names. - Expand example with FilledAsyncButton.icon/.tonalIcon and per-button override demo (successChild/errorChild/cooldownDuration). - Adopt package:checks across example tests. - README + SKILL.md fixes for renamed types and current skill path. Co-Authored-By: Claude Opus 4.7 --- .pubignore | 2 +- CHANGELOG.md | 44 -- LICENSE | 2 +- README.md | 179 ++++--- analysis_options.yaml | 15 +- example/analysis_options.yaml | 1 - example/lib/main.dart | 126 +++-- example/pubspec.yaml | 2 +- example/test/widget_test.dart | 33 +- lib/material_async_button.dart | 32 +- lib/src/async_button.dart | 397 ++++++++++++++++ lib/src/async_button_builder.dart | 344 -------------- lib/src/async_button_controller.dart | 117 +++-- lib/src/async_button_state.dart | 76 --- lib/src/async_button_status.dart | 95 ++++ lib/src/buttons/async_material_button.dart | 112 +++++ lib/src/buttons/elevated_async_button.dart | 259 +++++----- lib/src/buttons/filled_async_button.dart | 422 ++++++++--------- lib/src/buttons/icon_async_button.dart | 447 +++++++++--------- lib/src/buttons/outlined_async_button.dart | 256 +++++----- lib/src/buttons/text_async_button.dart | 256 +++++----- lib/src/material_async_button_theme.dart | 274 ++++++----- pubspec.yaml | 15 +- screenshots/ezgif-7-4088c909ba83.gif | Bin 119599 -> 0 bytes screenshots/ezgif-7-61c436edaec2.gif | Bin 53098 -> 0 bytes screenshots/ezgif-7-a971c6afaabf.gif | Bin 80732 -> 0 bytes screenshots/ezgif-7-b620d3def232.gif | Bin 71945 -> 0 bytes test/_helpers.dart | 71 +++ test/async_button_builder_test.dart | 392 --------------- test/async_button_controller_test.dart | 362 ++++++-------- test/async_button_state_test.dart | 66 --- test/async_button_test.dart | 401 ++++++++++++++++ test/elevated_async_button_test.dart | 67 ++- test/filled_async_button_test.dart | 48 +- test/icon_async_button_test.dart | 60 ++- test/material_async_button_theme_test.dart | 149 ++++-- test/outlined_async_button_test.dart | 37 +- test/text_async_button_test.dart | 41 +- .../flutter-material-async-button/SKILL.md | 60 ++- 39 files changed, 2717 insertions(+), 2543 deletions(-) delete mode 100644 example/analysis_options.yaml create mode 100644 lib/src/async_button.dart delete mode 100644 lib/src/async_button_builder.dart delete mode 100644 lib/src/async_button_state.dart create mode 100644 lib/src/async_button_status.dart create mode 100644 lib/src/buttons/async_material_button.dart delete mode 100644 screenshots/ezgif-7-4088c909ba83.gif delete mode 100644 screenshots/ezgif-7-61c436edaec2.gif delete mode 100644 screenshots/ezgif-7-a971c6afaabf.gif delete mode 100644 screenshots/ezgif-7-b620d3def232.gif create mode 100644 test/_helpers.dart delete mode 100644 test/async_button_builder_test.dart delete mode 100644 test/async_button_state_test.dart create mode 100644 test/async_button_test.dart rename {claude_code_skill => tool/claude}/flutter-material-async-button/SKILL.md (56%) diff --git a/.pubignore b/.pubignore index 963e315..2c3be47 100644 --- a/.pubignore +++ b/.pubignore @@ -2,4 +2,4 @@ .vscode/ build/ coverage/ -claude_code_skill/ +tool/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 29e89b1..f48b724 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,47 +2,3 @@ Initial release. Renamed from `async_button_builder` to `material_async_button` with a redesigned, theme-aware API. - -### Added - -- Material wrapper widgets: `ElevatedAsyncButton`, `FilledAsyncButton` - (`+.tonal/.icon/.tonalIcon`), `OutlinedAsyncButton`, `TextAsyncButton`, - `IconAsyncButton` (`+.filled/.filledTonal/.outlined`). Each mirrors its - Material counterpart constructor-for-constructor. -- `MaterialAsyncButtonTheme` — a `ThemeExtension` for app-wide defaults - (loading/success/error widgets, durations, curves, haptics, semantics). - Includes `MaterialAsyncButtonTheme.material()` opinionated factory. -- `AsyncButtonController` — `ValueListenable` for - external state control. Methods: `trigger()`, `reset()`, - `invalidate(error)`, `markSuccess()`. -- `confirmBeforePress`, `errorBuilder`, `onStateChanged`, `cooldownDuration`, - `hapticOn`, `announceSemantics`, `rethrowErrors` parameters. -- `AsyncButtonBuilderState.trigger()`/`reset()`/`invalidate()`/`markSuccess()` - for `GlobalKey`-driven control (e.g. form keyboard "Done"). - -### Changed - -- `AsyncButtonState.error` now carries an optional `StackTrace`. -- `onSuccess` / `onError` fire on **entry** to their state, not after the - display duration elapses. -- Defaults are unopinionated: zero `successDisplayDuration`, - zero `errorDisplayDuration`, no success/error widget swap unless asked. - Use `MaterialAsyncButtonTheme.material()` for the v3-style baseline. -- Minimum Dart SDK is `^3.10.0` (any Flutter SDK shipping Dart 3.10+). - -### Fixed - -- Stale-timer race: timers from a previous success/error cycle no longer - overwrite a subsequent state set externally. -- `AsyncButtonState` variants now implement `==`/`hashCode`. -- `KeyedSubtree` switch key is `ValueKey(stateType)` instead of a - fresh `UniqueKey()` per state change. - -### Removed - -- `AsyncButtonNotification` and the `notifications: bool` flag. Use - `AsyncButtonController` or `onStateChanged` instead. -- `errorPadding` / `successPadding` convenience props — wrap your widgets - in `Padding` explicitly. -- Per-state transition curves and per-state transition builders. Use a - single `transitionBuilder` and `switchCurve`, override only when needed. diff --git a/LICENSE b/LICENSE index 8da5f16..4c996a4 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2021 Rex Magana +Copyright (c) 2026 Mehmet Esen Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index fdf0a19..8fa3f44 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,19 @@ # material_async_button Drop-in async wrappers for Flutter Material buttons. Adds **loading**, -**success**, and **error** states to `ElevatedButton`, `FilledButton`, +**success**, and **error** statuses to `ElevatedButton`, `FilledButton`, `OutlinedButton`, `TextButton`, and `IconButton` — without forcing you to build a project-wide wrapper widget. ```dart ElevatedAsyncButton( - onPressed: () async => await api.save(), + onPressed: () async => api.save(), child: const Text('Save'), ) ``` -That's it. The button shows a spinner while `save()` runs and re-enables when -it returns or throws. +That's it. The button shows a spinner while `save()` runs and re-enables +when it returns or throws. ## Install @@ -33,7 +33,7 @@ This package gives you that wrapper as a [`ThemeExtension`][th]: ```dart MaterialApp( theme: ThemeData( - extensions: [MaterialAsyncButtonTheme.material()], + extensions: [AsyncButtonTheme.material()], ), ) ``` @@ -59,13 +59,13 @@ forwarded verbatim. ## Theming -`MaterialAsyncButtonTheme` is a `ThemeExtension`. Resolution order for any +`AsyncButtonTheme` is a `ThemeExtension`. Resolution order for any field is **per-widget value → theme value → built-in fallback**. ```dart ThemeData( extensions: [ - MaterialAsyncButtonTheme( + AsyncButtonTheme( switchDuration: const Duration(milliseconds: 200), successDisplayDuration: const Duration(milliseconds: 800), errorDisplayDuration: const Duration(milliseconds: 800), @@ -82,30 +82,78 @@ ThemeData( Or grab the opinionated baseline: ```dart -ThemeData(extensions: [MaterialAsyncButtonTheme.material()]) +ThemeData(extensions: [AsyncButtonTheme.material()]) ``` -## Unopinionated defaults +## Status pattern matching -Without any theme set: +`AsyncButtonStatus` is sealed. The error variant carries the error and +stack trace as fields — destructure them inline: -| State | Default UI | -| ---------- | ------------------------------------------- | -| idle | your `child` | -| loading | 16×16 `CircularProgressIndicator` | -| success | your `child` (no swap), display duration 0 | -| error | your `child` (no swap), display duration 0 | +```dart +AsyncButton( + onPressed: doWork, + child: const Text('Go'), + builder: (context, child, callback, status) => MyButton( + onTap: callback, + color: switch (status) { + AsyncButtonStatusIdle() => Colors.blue, + AsyncButtonStatusLoading() => Colors.grey, + AsyncButtonStatusSuccess() => Colors.green, + AsyncButtonStatusError() => Colors.red, + }, + child: child, + ), +) +``` + +`AsyncButton` is the low-level escape hatch. Use it when none of the +Material wrappers fit. -Most apps want a flash of green check / red error. Either set the theme -extension once, or pass `successChild` / `errorChild` per button. +## Error payload -## External control +The error variant owns its thrown payload. Render it inline in the builder: + +```dart +AsyncButton( + onPressed: () async => repo.submit(), + builder: (context, child, callback, status) => switch (status) { + AsyncButtonStatusError(:final error) => + Text('failed: $error'), + _ => MyButton(onTap: callback, child: child), + }, + child: const Text('Submit'), +) +``` + +Or react externally: + +```dart +ValueListenableBuilder( + valueListenable: controller, + builder: (_, status, _) => switch (status) { + AsyncButtonStatusError(:final error) => Text('$error'), + _ => const SizedBox.shrink(), + }, +) +``` + +For one-shot notifications (snackbar, log), `onError`: + +```dart +ElevatedAsyncButton( + onPressed: () async => repo.submit(), + onError: (error, stackTrace) => log.warn('$error'), + errorChild: const Icon(Icons.error_outline), + child: const Text('Submit'), +) +``` -### `AsyncButtonController` — recommended +## External control -The Material wrappers expose state through an `AsyncButtonController`. This is -the pattern to use for **form keyboard "Done"**, parent-owned state, -cross-widget reactions, and tests. +`AsyncButtonController` is a `ValueListenable` plus +imperative methods. Use it for **form keyboard "Done"**, parent-owned +state, cross-widget reactions, and tests. ```dart final controller = AsyncButtonController(); // dispose like any ChangeNotifier @@ -125,82 +173,69 @@ controller.trigger(); // run onPressed from outside controller.invalidate('server rejected'); // force error controller.markSuccess(); // force success controller.reset(); // back to idle -``` - -### `GlobalKey` — for the low-level builder only -If you're using `AsyncButtonBuilder` directly (custom non-Material button), -the same operations are exposed on its `State`: - -```dart -final key = GlobalKey(); - -AsyncButtonBuilder( - key: key, - onPressed: submit, - child: const Text('Submit'), - builder: (c, child, cb, _) => MyButton(onTap: cb, child: child), -) - -key.currentState?.trigger(); +// inspect: +controller.value; // AsyncButtonStatus (sealed) +// Pattern-match value for the error payload: +if (controller.value case AsyncButtonStatusError(:final error)) { + log.warn('$error'); +} ``` -The controller is a `ValueListenable`. Pipe it to a -`ValueListenableBuilder` for cross-widget UI reactions. Dispose like any -`ChangeNotifier`. +## Defaults -## State pattern matching +When no `AsyncButtonTheme` extension is registered, `AsyncButtonTheme.of` +falls back to `AsyncButtonTheme.material()`: -```dart -AsyncButtonBuilder( - onPressed: doWork, - child: const Text('Go'), - builder: (context, child, callback, state) => MyButton( - onTap: callback, - color: switch (state) { - AsyncButtonStateIdle() => Colors.blue, - AsyncButtonStateLoading() => Colors.grey, - AsyncButtonStateSuccess() => Colors.green, - AsyncButtonStateError() => Colors.red, - }, - child: child, - ), -) -``` +| Status | Default UI | +| ---------- | ------------------------------------------------------- | +| idle | your `child` | +| loading | 16×16 `CircularProgressIndicator` | +| success | `Icons.check`, displayed for 800ms | +| error | `Icons.error`, displayed for 800ms | -`AsyncButtonBuilder` is the low-level escape hatch. Use it when none of the -Material wrappers fit. +Opt out of the baseline by registering `AsyncButtonTheme.empty` on the +theme, then set only the fields you care about. Per-widget overrides +(e.g. `successChild:` on a single button) always win. ## Features - `confirmBeforePress` — gate `onPressed` behind a confirmation `Future` -- `errorBuilder` — render the thrown error with full context - `onSuccess` / `onError` / `onStateChanged` — fire-and-forget callbacks +- `errorChild` — static widget shown during error status - `cooldownDuration` — disable the button briefly after success to prevent double-submit - `hapticOn` — light haptic on success/error -- `announceSemantics` — `SemanticsService.announce` for screen readers +- `announceSemantics` — `SemanticsService.sendAnnouncement` for screen readers - `rethrowErrors` — rethrow from `controller.trigger()` so callers can `try/catch` while the UI also shows the error ## Migrating from `async_button_builder` -This package is a renamed continuation of `async_button_builder`. The -low-level `AsyncButtonBuilder` and `AsyncButtonState` types are preserved -(`error` now carries a `StackTrace`). Most v3 code keeps working after: +After: 1. `dependencies: async_button_builder: ^3.0.0` → `material_async_button: ^1.0.0` 2. `import 'package:async_button_builder/async_button_builder.dart'` → `import 'package:material_async_button/material_async_button.dart'` -The opinionated `notifications` flag and `AsyncButtonNotification` are gone; -use `AsyncButtonController` or `onStateChanged` instead. +Then: + +- `AsyncButtonBuilder` → `AsyncButton` +- `AsyncButtonState` (sealed) → `AsyncButtonStatus` (still sealed; renamed + for clarity and re-prefixed variants `AsyncButtonStatusIdle`, + `AsyncButtonStatusLoading`, `AsyncButtonStatusSuccess`, + `AsyncButtonStatusError(error, stackTrace)`). +- `state.error` → destructure the error variant: + `AsyncButtonStatusError(:final error)`. +- The previous `errorBuilder` is gone — pattern-match the status in your + `builder` callback, or render `errorChild`. ## Claude Code skill -A skill that teaches Claude Code to use this package idiomatically ships at -`claude_code_skill/flutter-material-async-button/SKILL.md`. Copy it into -`.claude/skills/` in your project. +A Claude Code skill that teaches Claude to use this package idiomatically +lives in the GitHub repo at +[`tool/claude/flutter-material-async-button/SKILL.md`](https://github.com/esenmx/material_async_button/blob/main/tool/claude/flutter-material-async-button/SKILL.md). +Copy it into `.claude/skills/` in your project. ## License diff --git a/analysis_options.yaml b/analysis_options.yaml index 72d8d1b..da187d6 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,17 +1,14 @@ -include: package:flutter_lints/flutter.yaml +include: package:very_good_analysis/analysis_options.yaml analyzer: language: strict-casts: true + strict-inference: true strict-raw-types: true linter: rules: - - always_declare_return_types - - prefer_const_constructors - - prefer_const_constructors_in_immutables - - prefer_const_declarations - - prefer_const_literals_to_create_immutables - - prefer_final_locals - - sort_constructors_first - - use_super_parameters + always_put_required_named_parameters_first: false + sort_constructors_first: true + public_member_api_docs: false + diagnostic_describe_all_properties: false diff --git a/example/analysis_options.yaml b/example/analysis_options.yaml deleted file mode 100644 index f9b3034..0000000 --- a/example/analysis_options.yaml +++ /dev/null @@ -1 +0,0 @@ -include: package:flutter_lints/flutter.yaml diff --git a/example/lib/main.dart b/example/lib/main.dart index f62a54b..ea858a1 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -7,15 +7,17 @@ class MyApp extends StatelessWidget { const MyApp({super.key}); @override - Widget build(BuildContext context) => MaterialApp( - title: 'material_async_button demo', - theme: ThemeData( - colorSchemeSeed: Colors.indigo, - useMaterial3: true, - extensions: [MaterialAsyncButtonTheme.material()], - ), - home: const HomePage(), - ); + Widget build(BuildContext context) { + return MaterialApp( + title: 'material_async_button demo', + theme: ThemeData( + colorSchemeSeed: Colors.indigo, + useMaterial3: true, + extensions: [AsyncButtonTheme.material()], + ), + home: const HomePage(), + ); + } } class HomePage extends StatefulWidget { @@ -49,10 +51,13 @@ class _HomePageState extends State { body: SingleChildScrollView( padding: const EdgeInsets.all(16), child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, + crossAxisAlignment: .stretch, children: [ const _SectionLabel('Material wrappers'), - ElevatedAsyncButton(onPressed: _simulateWork, child: const Text('ElevatedAsyncButton')), + ElevatedAsyncButton( + onPressed: _simulateWork, + child: const Text('ElevatedAsyncButton'), + ), const SizedBox(height: 8), ElevatedAsyncButton.icon( onPressed: _simulateWork, @@ -60,30 +65,77 @@ class _HomePageState extends State { label: const Text('ElevatedAsyncButton.icon'), ), const SizedBox(height: 8), - FilledAsyncButton(onPressed: _simulateWork, child: const Text('FilledAsyncButton')), + FilledAsyncButton( + onPressed: _simulateWork, + child: const Text('FilledAsyncButton'), + ), const SizedBox(height: 8), FilledAsyncButton.tonal( onPressed: _simulateWork, child: const Text('FilledAsyncButton.tonal'), ), const SizedBox(height: 8), + FilledAsyncButton.icon( + onPressed: _simulateWork, + icon: const Icon(Icons.save), + label: const Text('FilledAsyncButton.icon'), + ), + const SizedBox(height: 8), + FilledAsyncButton.tonalIcon( + onPressed: _simulateWork, + icon: const Icon(Icons.cloud_upload), + label: const Text('FilledAsyncButton.tonalIcon'), + ), + const SizedBox(height: 8), OutlinedAsyncButton( onPressed: () => _simulateWork(fail: true), child: const Text('OutlinedAsyncButton (fails)'), ), const SizedBox(height: 8), - TextAsyncButton(onPressed: _simulateWork, child: const Text('TextAsyncButton')), + TextAsyncButton( + onPressed: _simulateWork, + child: const Text('TextAsyncButton'), + ), const SizedBox(height: 8), Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, + mainAxisAlignment: .spaceEvenly, children: [ - IconAsyncButton(onPressed: _simulateWork, icon: const Icon(Icons.refresh)), - IconAsyncButton.filled(onPressed: _simulateWork, icon: const Icon(Icons.add)), - IconAsyncButton.filledTonal(onPressed: _simulateWork, icon: const Icon(Icons.edit)), - IconAsyncButton.outlined(onPressed: _simulateWork, icon: const Icon(Icons.delete)), + IconAsyncButton( + onPressed: _simulateWork, + icon: const Icon(Icons.refresh), + ), + IconAsyncButton.filled( + onPressed: _simulateWork, + icon: const Icon(Icons.add), + ), + IconAsyncButton.filledTonal( + onPressed: _simulateWork, + icon: const Icon(Icons.edit), + ), + IconAsyncButton.outlined( + onPressed: _simulateWork, + icon: const Icon(Icons.delete), + ), ], ), const Divider(height: 32), + const _SectionLabel('Per-button overrides'), + ElevatedAsyncButton( + onPressed: _simulateWork, + successChild: const Text('Saved!'), + successDisplayDuration: const Duration(milliseconds: 1200), + cooldownDuration: const Duration(seconds: 1), + child: const Text('Custom successChild + 1s cooldown'), + ), + const SizedBox(height: 8), + OutlinedAsyncButton( + onPressed: () => _simulateWork(fail: true), + errorChild: const Text('Failed — try again'), + errorDisplayDuration: const Duration(milliseconds: 1200), + onError: (error, _) => debugPrint('error: $error'), + child: const Text('Custom errorChild + onError'), + ), + const Divider(height: 32), const _SectionLabel('Form "Done" → controller.trigger()'), TextField( controller: _textController, @@ -94,7 +146,7 @@ class _HomePageState extends State { const SizedBox(height: 8), ElevatedAsyncButton( controller: _formController, - onPressed: () => _simulateWork(), + onPressed: _simulateWork, child: const Text('Submit'), ), const Divider(height: 32), @@ -109,39 +161,44 @@ class _HomePageState extends State { spacing: 8, children: [ OutlinedButton( - onPressed: () => _externalController.trigger(), + onPressed: _externalController.trigger, child: const Text('trigger()'), ), OutlinedButton( - onPressed: () => _externalController.invalidate('server rejected'), + onPressed: () => + _externalController.invalidate('server rejected'), child: const Text('invalidate()'), ), OutlinedButton( onPressed: _externalController.markSuccess, child: const Text('markSuccess()'), ), - OutlinedButton(onPressed: _externalController.reset, child: const Text('reset()')), + OutlinedButton( + onPressed: _externalController.reset, + child: const Text('reset()'), + ), ], ), const Divider(height: 32), - const _SectionLabel('Custom button via AsyncButtonBuilder'), - AsyncButtonBuilder( + const _SectionLabel('Custom button via AsyncButton'), + AsyncButton( onPressed: _simulateWork, animateSize: true, - child: const Padding( - padding: EdgeInsets.symmetric(horizontal: 16, vertical: 12), - child: Text('Custom', style: TextStyle(color: Colors.white)), - ), - builder: (ctx, child, callback, state) => Material( - color: switch (state) { - AsyncButtonStateSuccess() => Colors.green, - AsyncButtonStateError() => Colors.red, - _ => Colors.indigo, + builder: (ctx, child, callback, status) => Material( + color: switch (status) { + AsyncButtonStatusIdle() || + AsyncButtonStatusLoading() => Colors.indigo, + AsyncButtonStatusSuccess() => Colors.green, + AsyncButtonStatusError() => Colors.red, }, - clipBehavior: Clip.hardEdge, + clipBehavior: .hardEdge, shape: const StadiumBorder(), child: InkWell(onTap: callback, child: child), ), + child: const Padding( + padding: EdgeInsets.symmetric(horizontal: 16, vertical: 12), + child: Text('Custom', style: TextStyle(color: Colors.white)), + ), ), ], ), @@ -151,6 +208,7 @@ class _HomePageState extends State { class _SectionLabel extends StatelessWidget { const _SectionLabel(this.text); + final String text; @override diff --git a/example/pubspec.yaml b/example/pubspec.yaml index a240141..b76c652 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -14,9 +14,9 @@ dependencies: path: ../ dev_dependencies: + checks: ^0.3.1 flutter_test: sdk: flutter - flutter_lints: ^5.0.0 flutter: uses-material-design: true diff --git a/example/test/widget_test.dart b/example/test/widget_test.dart index aa6b683..763fb11 100644 --- a/example/test/widget_test.dart +++ b/example/test/widget_test.dart @@ -1,13 +1,38 @@ +import 'package:checks/checks.dart'; import 'package:example/main.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:material_async_button/material_async_button.dart'; +extension on Subject { + void findsOne() => has((f) => f.evaluate().length, 'matches').equals(1); + void findsNone() => has((f) => f.evaluate(), 'matches').isEmpty(); + void findsMany([int min = 1]) => + has((f) => f.evaluate().length, 'matches').isGreaterOrEqual(min); +} + void main() { - testWidgets('example app builds and shows the Material wrappers section', (tester) async { + testWidgets('builds and shows the Material wrappers section', (tester) async { await tester.pumpWidget(const MyApp()); await tester.pumpAndSettle(); - expect(find.text('Material wrappers'), findsOneWidget); - expect(find.byType(ElevatedAsyncButton), findsWidgets); - expect(find.byType(FilledAsyncButton), findsWidgets); + + check(find.text('Material wrappers')).findsOne(); + check(find.byType(ElevatedAsyncButton)).findsMany(); + check(find.byType(FilledAsyncButton)).findsMany(); + }); + + testWidgets('tapping an ElevatedAsyncButton shows the loading spinner', ( + tester, + ) async { + await tester.pumpWidget(const MyApp()); + await tester.pumpAndSettle(); + + await tester.tap(find.text('ElevatedAsyncButton')); + await tester.pump(); + + check(find.byType(CircularProgressIndicator)).findsOne(); + + await tester.pumpAndSettle(); + check(find.byType(CircularProgressIndicator)).findsNone(); }); } diff --git a/lib/material_async_button.dart b/lib/material_async_button.dart index 642eadc..7ff0856 100644 --- a/lib/material_async_button.dart +++ b/lib/material_async_button.dart @@ -1,16 +1,24 @@ /// Drop-in async wrappers for Flutter Material buttons. /// -/// See [ElevatedAsyncButton], [FilledAsyncButton], [OutlinedAsyncButton], -/// [TextAsyncButton], and [IconAsyncButton] for the named-constructor -/// variants. Use [AsyncButtonBuilder] when you need a custom button. +/// See `ElevatedAsyncButton`, `FilledAsyncButton`, `OutlinedAsyncButton`, +/// `TextAsyncButton`, and `IconAsyncButton` for the named-constructor +/// variants. Use `AsyncButton` when you need a custom non-Material button. library; -export 'src/async_button_builder.dart'; -export 'src/async_button_controller.dart'; -export 'src/async_button_state.dart'; -export 'src/buttons/elevated_async_button.dart'; -export 'src/buttons/filled_async_button.dart'; -export 'src/buttons/icon_async_button.dart'; -export 'src/buttons/outlined_async_button.dart'; -export 'src/buttons/text_async_button.dart'; -export 'src/material_async_button_theme.dart'; +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/semantics.dart'; +import 'package:flutter/services.dart'; + +part 'src/async_button.dart'; +part 'src/async_button_controller.dart'; +part 'src/async_button_status.dart'; +part 'src/buttons/async_material_button.dart'; +part 'src/buttons/elevated_async_button.dart'; +part 'src/buttons/filled_async_button.dart'; +part 'src/buttons/icon_async_button.dart'; +part 'src/buttons/outlined_async_button.dart'; +part 'src/buttons/text_async_button.dart'; +part 'src/material_async_button_theme.dart'; diff --git a/lib/src/async_button.dart b/lib/src/async_button.dart new file mode 100644 index 0000000..c02fed1 --- /dev/null +++ b/lib/src/async_button.dart @@ -0,0 +1,397 @@ +part of '../material_async_button.dart'; + +/// Signature for [AsyncButton.builder]. +/// +/// `callback` is `null` when the button should appear disabled (already +/// loading, in cooldown, or `onPressed`/`disabled` make it ineligible). +typedef AsyncButtonWidgetBuilder = + Widget Function( + BuildContext context, + Widget child, + AsyncCallback? callback, + AsyncButtonStatus status, + ); + +/// Signature for `onError`. Receives the thrown error plus the captured +/// stack trace. The error is delivered informationally — the button itself +/// only reacts to [AsyncButtonStatus]. +typedef AsyncButtonErrorCallback = + void Function( + Object error, + StackTrace stackTrace, + ); + +/// Low-level async-status shell for arbitrary buttons. +/// +/// Prefer the named Material wrappers ([ElevatedAsyncButton], +/// [FilledAsyncButton], [OutlinedAsyncButton], [TextAsyncButton], +/// [IconAsyncButton]). Reach for [AsyncButton] directly only when you need +/// to render a non-Material button. +/// +/// The builder receives the current [AsyncButtonStatus] — destructure the +/// error variant to render the error inline: +/// +/// ```dart +/// builder: (context, child, callback, status) => switch (status) { +/// AsyncButtonStatusError(:final error) => Text('failed: $error'), +/// _ => MyButton(onTap: callback, child: child), +/// } +/// ``` +/// +/// ```dart +/// AsyncButton( +/// onPressed: () async => doWork(), +/// child: const Text('Go'), +/// builder: (context, child, callback, status) => MyCustomButton( +/// onTap: callback, +/// child: child, +/// ), +/// ) +/// ``` +class AsyncButton extends StatefulWidget { + const AsyncButton({ + super.key, + required this.child, + required this.onPressed, + required this.builder, + this.controller, + this.onSuccess, + this.onError, + this.onStateChanged, + this.confirmBeforePress, + this.loadingChild, + this.successChild, + this.errorChild, + this.disabled = false, + this.switchDuration, + this.switchReverseDuration, + this.switchCurve, + this.switchInCurve, + this.switchOutCurve, + this.transitionBuilder, + this.successDisplayDuration, + this.errorDisplayDuration, + this.cooldownDuration, + this.animateSize, + this.sizeCurve, + this.sizeAlignment, + this.sizeClipBehavior, + this.hapticOn, + this.announceSemantics, + this.rethrowErrors, + }); + + final Widget child; + final AsyncCallback? onPressed; + final AsyncButtonWidgetBuilder builder; + + /// External controller. When null, the widget creates and owns its own. + final AsyncButtonController? controller; + + /// Called when the button enters [.success]. + final VoidCallback? onSuccess; + + /// Called when the button enters [.error]. + final AsyncButtonErrorCallback? onError; + + /// Fired on every status change. Use [onError] or read [controller] when + /// you also need the error payload. + final ValueChanged? onStateChanged; + + /// Runs before [onPressed]. If it returns `false` the press is cancelled + /// and no status change happens. + final Future Function(BuildContext context)? confirmBeforePress; + + final Widget? loadingChild; + final Widget? successChild; + final Widget? errorChild; + + /// Forces the button to appear disabled regardless of status. + final bool disabled; + + // Per-widget overrides of the theme. Null means "use theme, then default". + final Duration? switchDuration; + final Duration? switchReverseDuration; + final Curve? switchCurve; + final Curve? switchInCurve; + final Curve? switchOutCurve; + final AnimatedSwitcherTransitionBuilder? transitionBuilder; + final Duration? successDisplayDuration; + final Duration? errorDisplayDuration; + final Duration? cooldownDuration; + final bool? animateSize; + final Curve? sizeCurve; + final AlignmentGeometry? sizeAlignment; + final Clip? sizeClipBehavior; + final HapticOn? hapticOn; + final bool? announceSemantics; + final bool? rethrowErrors; + + @override + State createState() { + return _AsyncButtonState(); + } +} + +class _AsyncButtonState extends State { + AsyncButtonController? _internalController; + AsyncButtonController get _controller => + widget.controller ?? _internalController!; + + AsyncButtonStatus _lastStatus = const .idle(); + + @override + void initState() { + super.initState(); + if (widget.controller == null) { + _internalController = AsyncButtonController(); + } + _controller.addListener(_handleControllerChange); + _lastStatus = _controller.value; + } + + @override + void didUpdateWidget(covariant AsyncButton oldWidget) { + super.didUpdateWidget(oldWidget); + if (widget.controller == oldWidget.controller) { + return; + } + final previous = oldWidget.controller ?? _internalController; + previous?.removeListener(_handleControllerChange); + if (widget.controller != null) { + _internalController?.dispose(); + _internalController = null; + } else { + _internalController = AsyncButtonController(); + } + _controller.addListener(_handleControllerChange); + _lastStatus = _controller.value; + } + + @override + void dispose() { + _controller.removeListener(_handleControllerChange); + _internalController?.dispose(); + super.dispose(); + } + + void _handleControllerChange() { + final newStatus = _controller.value; + if (newStatus != _lastStatus) { + widget.onStateChanged?.call(newStatus); + _fireHaptic(newStatus); + _announceSemantics(newStatus); + if (newStatus is AsyncButtonStatusSuccess && + _lastStatus is! AsyncButtonStatusSuccess) { + widget.onSuccess?.call(); + } else if (newStatus is AsyncButtonStatusError && + _lastStatus is! AsyncButtonStatusError) { + widget.onError?.call( + newStatus.error, + newStatus.stackTrace ?? StackTrace.empty, + ); + } + _lastStatus = newStatus; + } + if (mounted) { + setState(() {}); + } + } + + void _fireHaptic(AsyncButtonStatus to) { + final mode = + widget.hapticOn ?? AsyncButtonTheme.of(context).hapticOn ?? .none; + if (mode == .none) { + return; + } + final wantSuccess = mode == .success || mode == .both; + final wantError = mode == .error || mode == .both; + if (to is AsyncButtonStatusSuccess && wantSuccess) { + unawaited(HapticFeedback.lightImpact()); + } else if (to is AsyncButtonStatusError && wantError) { + unawaited(HapticFeedback.mediumImpact()); + } + } + + void _announceSemantics(AsyncButtonStatus status) { + final on = + widget.announceSemantics ?? + AsyncButtonTheme.of(context).announceSemantics ?? + false; + if (!on) { + return; + } + final message = switch (status) { + AsyncButtonStatusIdle() => null, + AsyncButtonStatusLoading() => 'Loading', + AsyncButtonStatusSuccess() => 'Success', + AsyncButtonStatusError() => 'Error', + }; + if (message == null) { + return; + } + final view = View.maybeOf(context); + if (view == null) { + return; + } + final direction = Directionality.maybeOf(context) ?? .ltr; + unawaited(SemanticsService.sendAnnouncement(view, message, direction)); + } + + @override + Widget build(BuildContext context) { + final config = _resolveConfig(AsyncButtonTheme.of(context)); + + _controller.attach( + onPressed: _gatedOnPressed(), + successDuration: config.successDisplayDuration, + errorDuration: config.errorDisplayDuration, + cooldownDuration: config.cooldownDuration, + rethrowErrors: config.rethrowErrors, + ); + + final status = _controller.value; + final visible = switch (status) { + AsyncButtonStatusIdle() => widget.child, + AsyncButtonStatusLoading() => config.loadingChild, + AsyncButtonStatusSuccess() => config.successChild ?? widget.child, + AsyncButtonStatusError() => config.errorChild ?? widget.child, + }; + + Widget content = AnimatedSwitcher( + duration: config.switchDuration, + reverseDuration: config.switchReverseDuration, + switchInCurve: config.switchInCurve, + switchOutCurve: config.switchOutCurve, + transitionBuilder: config.transitionBuilder, + child: KeyedSubtree( + key: ValueKey(status), + child: visible, + ), + ); + + if (config.animateSize) { + content = AnimatedSize( + duration: config.switchDuration, + reverseDuration: config.switchReverseDuration, + alignment: config.sizeAlignment, + clipBehavior: config.sizeClipBehavior, + curve: config.sizeCurve, + child: content, + ); + } + + return widget.builder(context, content, _builderCallback(), status); + } + + /// Callback passed back through the builder. Null when the button is in a + /// status that should appear disabled. + AsyncCallback? _builderCallback() { + if (widget.disabled || widget.onPressed == null) { + return null; + } + if (!_controller.canTrigger) { + return null; + } + return _controller.trigger; + } + + /// The `onPressed` that `controller.trigger` will actually run, wrapped + /// with `confirmBeforePress` and only invoked when not disabled. + AsyncCallback? _gatedOnPressed() { + if (widget.disabled || widget.onPressed == null) { + return null; + } + final confirm = widget.confirmBeforePress; + final raw = widget.onPressed!; + if (confirm == null) { + return raw; + } + return () async { + if (!mounted) { + return; + } + final ok = await confirm(context); + if (!mounted || !ok) { + return; + } + await raw(); + }; + } + + _ResolvedConfig _resolveConfig(AsyncButtonTheme t) { + final w = widget; + final fallbackCurve = w.switchCurve ?? t.switchCurve ?? Curves.linear; + return _ResolvedConfig( + loadingChild: w.loadingChild ?? t.loadingChild ?? _defaultLoadingChild, + successChild: w.successChild ?? t.successChild, + errorChild: w.errorChild ?? t.errorChild, + switchDuration: + w.switchDuration ?? + t.switchDuration ?? + const Duration(milliseconds: 200), + switchReverseDuration: w.switchReverseDuration ?? t.switchReverseDuration, + switchInCurve: w.switchInCurve ?? t.switchInCurve ?? fallbackCurve, + switchOutCurve: w.switchOutCurve ?? t.switchOutCurve ?? fallbackCurve, + transitionBuilder: + w.transitionBuilder ?? + t.transitionBuilder ?? + AnimatedSwitcher.defaultTransitionBuilder, + successDisplayDuration: + w.successDisplayDuration ?? t.successDisplayDuration ?? .zero, + errorDisplayDuration: + w.errorDisplayDuration ?? t.errorDisplayDuration ?? .zero, + cooldownDuration: w.cooldownDuration ?? t.cooldownDuration ?? .zero, + animateSize: w.animateSize ?? t.animateSize ?? false, + sizeCurve: w.sizeCurve ?? t.sizeCurve ?? Curves.linear, + sizeAlignment: w.sizeAlignment ?? t.sizeAlignment ?? .center, + sizeClipBehavior: w.sizeClipBehavior ?? t.sizeClipBehavior ?? .hardEdge, + rethrowErrors: w.rethrowErrors ?? t.rethrowErrors ?? false, + ); + } +} + +/// Per-build resolution of widget props ▶ theme ▶ defaults. +@immutable +class _ResolvedConfig { + const _ResolvedConfig({ + required this.loadingChild, + required this.successChild, + required this.errorChild, + required this.switchDuration, + required this.switchReverseDuration, + required this.switchInCurve, + required this.switchOutCurve, + required this.transitionBuilder, + required this.successDisplayDuration, + required this.errorDisplayDuration, + required this.cooldownDuration, + required this.animateSize, + required this.sizeCurve, + required this.sizeAlignment, + required this.sizeClipBehavior, + required this.rethrowErrors, + }); + + final Widget loadingChild; + final Widget? successChild; + final Widget? errorChild; + final Duration switchDuration; + final Duration? switchReverseDuration; + final Curve switchInCurve; + final Curve switchOutCurve; + final AnimatedSwitcherTransitionBuilder transitionBuilder; + final Duration successDisplayDuration; + final Duration errorDisplayDuration; + final Duration cooldownDuration; + final bool animateSize; + final Curve sizeCurve; + final AlignmentGeometry sizeAlignment; + final Clip sizeClipBehavior; + final bool rethrowErrors; +} + +const _defaultLoadingChild = SizedBox.square( + dimension: 16, + child: CircularProgressIndicator(strokeWidth: 2), +); diff --git a/lib/src/async_button_builder.dart b/lib/src/async_button_builder.dart deleted file mode 100644 index 68bb95c..0000000 --- a/lib/src/async_button_builder.dart +++ /dev/null @@ -1,344 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/semantics.dart'; -import 'package:flutter/services.dart'; - -import 'async_button_controller.dart'; -import 'async_button_state.dart'; -import 'material_async_button_theme.dart'; - -/// Signature for the [AsyncButtonBuilder.builder]. -/// -/// `callback` is `null` when the button should appear disabled (already -/// loading, in cooldown, or `onPressed`/`disabled` make it ineligible). -typedef AsyncButtonWidgetBuilder = - Widget Function( - BuildContext context, - Widget child, - AsyncCallback? callback, - AsyncButtonState state, - ); - -/// Signature for [AsyncButtonBuilder.errorBuilder]. -typedef AsyncButtonErrorBuilder = - Widget Function(BuildContext context, Object error, StackTrace? stackTrace); - -/// Signature for the `onError` callback. Receives the thrown error plus the -/// captured stack trace. -typedef AsyncButtonErrorCallback = void Function(Object error, StackTrace stackTrace); - -/// Builder for an arbitrary button with async loading/success/error states. -/// -/// You almost always want one of the named Material wrappers (e.g. -/// [ElevatedAsyncButton], [FilledAsyncButton], [OutlinedAsyncButton], -/// [TextAsyncButton], [IconAsyncButton]). Reach for [AsyncButtonBuilder] -/// directly only when you need to render a non-Material button. -/// -/// {@tool snippet} -/// ```dart -/// AsyncButtonBuilder( -/// onPressed: () async => doWork(), -/// child: const Text('Go'), -/// builder: (context, child, callback, state) => MyCustomButton( -/// onTap: callback, -/// child: child, -/// ), -/// ) -/// ``` -/// {@end-tool} -class AsyncButtonBuilder extends StatefulWidget { - const AsyncButtonBuilder({ - super.key, - required this.child, - required this.onPressed, - required this.builder, - this.controller, - this.onSuccess, - this.onError, - this.onStateChanged, - this.confirmBeforePress, - this.errorBuilder, - this.loadingChild, - this.successChild, - this.errorChild, - this.disabled = false, - this.switchDuration, - this.switchReverseDuration, - this.switchCurve, - this.switchInCurve, - this.switchOutCurve, - this.transitionBuilder, - this.successDisplayDuration, - this.errorDisplayDuration, - this.cooldownDuration, - this.animateSize, - this.sizeCurve, - this.sizeAlignment, - this.sizeClipBehavior, - this.hapticOn, - this.announceSemantics, - this.rethrowErrors, - }); - - final Widget child; - final AsyncCallback? onPressed; - final AsyncButtonWidgetBuilder builder; - - /// External controller. When null, the widget creates and owns its own. - final AsyncButtonController? controller; - - /// Called after success display completes. - final VoidCallback? onSuccess; - - /// Called after error display completes (or immediately if the display - /// duration is zero). Receives the thrown error and stack trace. - final AsyncButtonErrorCallback? onError; - - /// Fired on every state change. - final ValueChanged? onStateChanged; - - /// If provided, runs before [onPressed]. If it returns `false`, the press - /// is cancelled and no state change happens. - final Future Function(BuildContext context)? confirmBeforePress; - - /// Renders the error state. When non-null, takes precedence over - /// [errorChild] and the theme's `errorChild`. - final AsyncButtonErrorBuilder? errorBuilder; - - final Widget? loadingChild; - final Widget? successChild; - final Widget? errorChild; - - /// Forces the button to appear disabled regardless of state. - final bool disabled; - - // Per-widget overrides of the theme. Null means "use theme, then default". - final Duration? switchDuration; - final Duration? switchReverseDuration; - final Curve? switchCurve; - final Curve? switchInCurve; - final Curve? switchOutCurve; - final AnimatedSwitcherTransitionBuilder? transitionBuilder; - final Duration? successDisplayDuration; - final Duration? errorDisplayDuration; - final Duration? cooldownDuration; - final bool? animateSize; - final Curve? sizeCurve; - final AlignmentGeometry? sizeAlignment; - final Clip? sizeClipBehavior; - final HapticOn? hapticOn; - final bool? announceSemantics; - final bool? rethrowErrors; - - @override - State createState() => AsyncButtonBuilderState(); -} - -class AsyncButtonBuilderState extends State { - AsyncButtonController? _internalController; - AsyncButtonController get _controller => widget.controller ?? _internalController!; - - AsyncButtonState _lastNotifiedState = const AsyncButtonState.idle(); - - @override - void initState() { - super.initState(); - if (widget.controller == null) { - _internalController = AsyncButtonController(); - } - _controller.addListener(_handleControllerChange); - _lastNotifiedState = _controller.value; - } - - @override - void didUpdateWidget(covariant AsyncButtonBuilder oldWidget) { - super.didUpdateWidget(oldWidget); - if (widget.controller != oldWidget.controller) { - final previous = oldWidget.controller ?? _internalController; - previous?.removeListener(_handleControllerChange); - if (widget.controller != null) { - _internalController?.dispose(); - _internalController = null; - } else { - _internalController = AsyncButtonController(); - } - _controller.addListener(_handleControllerChange); - _lastNotifiedState = _controller.value; - } - } - - @override - void dispose() { - _controller.removeListener(_handleControllerChange); - _internalController?.dispose(); - super.dispose(); - } - - void _handleControllerChange() { - final newState = _controller.value; - if (newState != _lastNotifiedState) { - widget.onStateChanged?.call(newState); - _fireHaptic(_lastNotifiedState, newState); - _announceSemantics(newState); - final wasSuccess = _lastNotifiedState is AsyncButtonStateSuccess; - final wasError = _lastNotifiedState is AsyncButtonStateError; - if (newState is AsyncButtonStateSuccess && !wasSuccess) { - widget.onSuccess?.call(); - } else if (newState is AsyncButtonStateError && !wasError) { - widget.onError?.call(newState.error, newState.stackTrace ?? StackTrace.empty); - } - _lastNotifiedState = newState; - } - if (mounted) setState(() {}); - } - - void _fireHaptic(AsyncButtonState from, AsyncButtonState to) { - final theme = MaterialAsyncButtonTheme.of(context); - final mode = widget.hapticOn ?? theme.hapticOn ?? HapticOn.none; - if (mode == HapticOn.none) return; - final wantSuccess = mode == HapticOn.success || mode == HapticOn.both; - final wantError = mode == HapticOn.error || mode == HapticOn.both; - if (to is AsyncButtonStateSuccess && wantSuccess) { - HapticFeedback.lightImpact(); - } else if (to is AsyncButtonStateError && wantError) { - HapticFeedback.mediumImpact(); - } - } - - void _announceSemantics(AsyncButtonState state) { - final theme = MaterialAsyncButtonTheme.of(context); - final on = widget.announceSemantics ?? theme.announceSemantics ?? false; - if (!on) return; - final direction = Directionality.maybeOf(context) ?? TextDirection.ltr; - final message = switch (state) { - AsyncButtonStateIdle() => null, - AsyncButtonStateLoading() => 'Loading', - AsyncButtonStateSuccess() => 'Success', - AsyncButtonStateError() => 'Error', - }; - if (message != null) { - final view = View.maybeOf(context); - if (view != null) { - SemanticsService.sendAnnouncement(view, message, direction); - } - } - } - - /// Trigger the attached `onPressed` programmatically. Equivalent to - /// [AsyncButtonController.trigger] on the active controller. Safe to call - /// from outside the widget tree (e.g. via a [GlobalKey]). - Future trigger() => _controller.trigger(); - - /// Force the button back to idle. - void reset() => _controller.reset(); - - /// Force the error state from outside. - void invalidate(Object error, [StackTrace? stackTrace]) => - _controller.invalidate(error, stackTrace); - - /// Force the success state from outside. - void markSuccess() => _controller.markSuccess(); - - /// The current state. Exposed for callers using a [GlobalKey]. - AsyncButtonState get value => _controller.value; - - @override - Widget build(BuildContext context) { - final theme = MaterialAsyncButtonTheme.of(context); - - final successDuration = - widget.successDisplayDuration ?? theme.successDisplayDuration ?? Duration.zero; - final errorDuration = - widget.errorDisplayDuration ?? theme.errorDisplayDuration ?? Duration.zero; - final cooldown = widget.cooldownDuration ?? theme.cooldownDuration ?? Duration.zero; - final rethrowErrors = widget.rethrowErrors ?? theme.rethrowErrors ?? false; - - _controller.attach( - onPressed: _gatedOnPressed(), - successDuration: successDuration, - errorDuration: errorDuration, - cooldownDuration: cooldown, - rethrowErrors: rethrowErrors, - ); - - final state = _controller.value; - - final loadingChild = widget.loadingChild ?? theme.loadingChild ?? const _BuiltinLoadingChild(); - final successChild = widget.successChild ?? theme.successChild; - final errorChild = widget.errorChild ?? theme.errorChild; - final switchDuration = - widget.switchDuration ?? theme.switchDuration ?? const Duration(milliseconds: 200); - final switchReverseDuration = widget.switchReverseDuration ?? theme.switchReverseDuration; - final fallbackCurve = widget.switchCurve ?? theme.switchCurve ?? Curves.linear; - final switchInCurve = widget.switchInCurve ?? theme.switchInCurve ?? fallbackCurve; - final switchOutCurve = widget.switchOutCurve ?? theme.switchOutCurve ?? fallbackCurve; - final transitionBuilder = - widget.transitionBuilder ?? - theme.transitionBuilder ?? - AnimatedSwitcher.defaultTransitionBuilder; - final animateSize = widget.animateSize ?? theme.animateSize ?? false; - - final Widget visible = switch (state) { - AsyncButtonStateIdle() => widget.child, - AsyncButtonStateLoading() => loadingChild, - AsyncButtonStateSuccess() => successChild ?? widget.child, - AsyncButtonStateError(:final error, :final stackTrace) => - widget.errorBuilder?.call(context, error, stackTrace) ?? errorChild ?? widget.child, - }; - - Widget content = AnimatedSwitcher( - duration: switchDuration, - reverseDuration: switchReverseDuration, - switchInCurve: switchInCurve, - switchOutCurve: switchOutCurve, - transitionBuilder: transitionBuilder, - child: KeyedSubtree(key: ValueKey(state.runtimeType), child: visible), - ); - - if (animateSize) { - content = AnimatedSize( - duration: switchDuration, - reverseDuration: switchReverseDuration, - alignment: widget.sizeAlignment ?? theme.sizeAlignment ?? Alignment.center, - clipBehavior: widget.sizeClipBehavior ?? theme.sizeClipBehavior ?? Clip.hardEdge, - curve: widget.sizeCurve ?? theme.sizeCurve ?? Curves.linear, - child: content, - ); - } - - return widget.builder(context, content, _builderCallback(), state); - } - - /// The callback passed back through the builder. Null when the button is - /// in a state that should appear disabled. - AsyncCallback? _builderCallback() { - if (widget.disabled || widget.onPressed == null) return null; - if (!_controller.canTrigger) return null; - return _controller.trigger; - } - - /// The `onPressed` that `controller.trigger` will actually run, wrapped - /// with `confirmBeforePress` and only invoked when not disabled. - AsyncCallback? _gatedOnPressed() { - if (widget.disabled || widget.onPressed == null) return null; - final confirm = widget.confirmBeforePress; - final raw = widget.onPressed!; - if (confirm == null) return raw; - return () async { - if (!mounted) return; - final ok = await confirm(context); - if (!mounted || !ok) return; - await raw(); - }; - } -} - -class _BuiltinLoadingChild extends StatelessWidget { - const _BuiltinLoadingChild(); - - @override - Widget build(BuildContext context) => - const SizedBox.square(dimension: 16, child: CircularProgressIndicator(strokeWidth: 2)); -} diff --git a/lib/src/async_button_controller.dart b/lib/src/async_button_controller.dart index e5840ee..1eb0a9a 100644 --- a/lib/src/async_button_controller.dart +++ b/lib/src/async_button_controller.dart @@ -1,64 +1,55 @@ -import 'dart:async'; +part of '../material_async_button.dart'; -import 'package:flutter/foundation.dart'; - -import 'async_button_state.dart'; - -/// Imperative controller for an [AsyncButtonBuilder] or any of the Material -/// wrappers. Listens like a [ValueListenable] of [AsyncButtonState]. +/// [ValueNotifier] of [AsyncButtonStatus] for an [AsyncButton] or any of +/// the Material wrappers. Pipe it directly into a +/// `ValueListenableBuilder` for reactive UI outside the +/// button — pattern-match the [value] for the error payload on error. /// /// Use it to: /// - trigger the attached `onPressed` from outside the button /// (e.g. a form keyboard "Done" action), /// - reset to idle, -/// - mark the button as errored from an out-of-band source -/// (e.g. a WebSocket message), -/// - mark the button as succeeded from outside. +/// - mark the button as failed from an out-of-band source +/// (e.g. a WebSocket message) via [invalidate], +/// - mark the button as succeeded from outside via [markSuccess]. +/// +/// Prefer [reset], [invalidate], [markSuccess], or [trigger] over assigning +/// to [value] directly — the imperative methods keep the display-duration +/// timers and cooldown machinery coherent. /// /// Dispose like any [ChangeNotifier]. -class AsyncButtonController extends ChangeNotifier implements ValueListenable { - AsyncButtonController({AsyncButtonState initial = const AsyncButtonState.idle()}) - : _value = initial; - - AsyncButtonState _value; - @override - AsyncButtonState get value => _value; - - bool get isIdle => _value is AsyncButtonStateIdle; - bool get isLoading => _value is AsyncButtonStateLoading; - bool get isSuccess => _value is AsyncButtonStateSuccess; - bool get isError => _value is AsyncButtonStateError; - - Object? get error => switch (_value) { - AsyncButtonStateError(:final error) => error, - _ => null, - }; +class AsyncButtonController extends ValueNotifier { + AsyncButtonController([super.initial = const .idle()]); - StackTrace? get stackTrace => switch (_value) { - AsyncButtonStateError(:final stackTrace) => stackTrace, - _ => null, - }; + bool get isIdle => value is AsyncButtonStatusIdle; + bool get isLoading => value is AsyncButtonStatusLoading; + bool get isSuccess => value is AsyncButtonStatusSuccess; + bool get isError => value is AsyncButtonStatusError; + @visibleForTesting bool get isInCooldown => _cooldownActive; /// True when [trigger] would actually run the attached callback. bool get canTrigger => isIdle && !_cooldownActive && _onPressed != null; // Widget-owned configuration. Refreshed on every build. - Future Function()? _onPressed; - Duration _successDuration = Duration.zero; - Duration _errorDuration = Duration.zero; - Duration _cooldownDuration = Duration.zero; + AsyncCallback? _onPressed; + Duration _successDuration = .zero; + Duration _errorDuration = .zero; + Duration _cooldownDuration = .zero; bool _rethrowErrors = false; Timer? _timer; bool _cooldownActive = false; bool _disposed = false; - /// Internal: called by the widget on each build to keep config fresh. - @internal + /// Internal hook used by [AsyncButton] to push the host widget's current + /// configuration into the controller on every build. Calling this from + /// outside the package is supported (tests drive a detached controller + /// this way), but the values you set will be overwritten on the next + /// build if the controller is also bound to an [AsyncButton]. void attach({ - required Future Function()? onPressed, + required AsyncCallback? onPressed, required Duration successDuration, required Duration errorDuration, required Duration cooldownDuration, @@ -74,24 +65,28 @@ class AsyncButtonController extends ChangeNotifier implements ValueListenable trigger() async { - if (!canTrigger) return; + if (!canTrigger) { + return; + } _cancelTimer(); - _setValue(const AsyncButtonState.loading()); + value = const .loading(); try { await _onPressed!(); // External resets (e.g. controller.reset()) may have moved us off // loading mid-await. Only continue the success cycle if we're still // the one driving. - if (!_disposed && _value is AsyncButtonStateLoading) { - _setValue(const AsyncButtonState.success()); + if (!_disposed && value is AsyncButtonStatusLoading) { + value = const .success(); _scheduleReturnToIdle(_successDuration); } } catch (error, stack) { - if (!_disposed && _value is AsyncButtonStateLoading) { - _setValue(AsyncButtonState.error(error, stack)); + if (!_disposed && value is AsyncButtonStatusLoading) { + value = .error(error, stack); _scheduleReturnToIdle(_errorDuration); } - if (_rethrowErrors) rethrow; + if (_rethrowErrors) { + rethrow; + } } } @@ -99,38 +94,32 @@ class AsyncButtonController extends ChangeNotifier implements ValueListenable Duration.zero) { + value = const .idle(); + if (_cooldownDuration > .zero) { _cooldownActive = true; notifyListeners(); _timer = Timer(_cooldownDuration, () { - if (_disposed) return; + if (_disposed) { + return; + } _timer = null; _cooldownActive = false; notifyListeners(); diff --git a/lib/src/async_button_state.dart b/lib/src/async_button_state.dart deleted file mode 100644 index 137023b..0000000 --- a/lib/src/async_button_state.dart +++ /dev/null @@ -1,76 +0,0 @@ -/// State of an async button. -/// -/// Pattern-match with `switch` to react to each state: -/// -/// ```dart -/// final color = switch (state) { -/// AsyncButtonStateIdle() => Colors.blue, -/// AsyncButtonStateLoading() => Colors.grey, -/// AsyncButtonStateSuccess() => Colors.green, -/// AsyncButtonStateError() => Colors.red, -/// }; -/// ``` -sealed class AsyncButtonState { - const AsyncButtonState(); - - const factory AsyncButtonState.idle() = AsyncButtonStateIdle; - const factory AsyncButtonState.loading() = AsyncButtonStateLoading; - const factory AsyncButtonState.success() = AsyncButtonStateSuccess; - const factory AsyncButtonState.error(Object error, [StackTrace? stackTrace]) = - AsyncButtonStateError; -} - -final class AsyncButtonStateIdle extends AsyncButtonState { - const AsyncButtonStateIdle(); - - @override - bool operator ==(Object other) => other is AsyncButtonStateIdle; - - @override - int get hashCode => (AsyncButtonStateIdle).hashCode; - - @override - String toString() => 'AsyncButtonState.idle()'; -} - -final class AsyncButtonStateLoading extends AsyncButtonState { - const AsyncButtonStateLoading(); - - @override - bool operator ==(Object other) => other is AsyncButtonStateLoading; - - @override - int get hashCode => (AsyncButtonStateLoading).hashCode; - - @override - String toString() => 'AsyncButtonState.loading()'; -} - -final class AsyncButtonStateSuccess extends AsyncButtonState { - const AsyncButtonStateSuccess(); - - @override - bool operator ==(Object other) => other is AsyncButtonStateSuccess; - - @override - int get hashCode => (AsyncButtonStateSuccess).hashCode; - - @override - String toString() => 'AsyncButtonState.success()'; -} - -final class AsyncButtonStateError extends AsyncButtonState { - const AsyncButtonStateError(this.error, [this.stackTrace]); - - final Object error; - final StackTrace? stackTrace; - - @override - bool operator ==(Object other) => other is AsyncButtonStateError && other.error == error; - - @override - int get hashCode => Object.hash(AsyncButtonStateError, error); - - @override - String toString() => 'AsyncButtonState.error($error)'; -} diff --git a/lib/src/async_button_status.dart b/lib/src/async_button_status.dart new file mode 100644 index 0000000..20c1d35 --- /dev/null +++ b/lib/src/async_button_status.dart @@ -0,0 +1,95 @@ +part of '../material_async_button.dart'; + +/// Status of an async button. Sealed — pattern-match exhaustively, and pull +/// the [AsyncButtonStatusError.error] / [AsyncButtonStatusError.stackTrace] +/// payload directly from the error variant. +/// +/// ```dart +/// final color = switch (status) { +/// AsyncButtonStatusIdle() => Colors.blue, +/// AsyncButtonStatusLoading() => Colors.grey, +/// AsyncButtonStatusSuccess() => Colors.green, +/// AsyncButtonStatusError() => Colors.red, +/// }; +/// ``` +/// +/// The three singleton variants rely on `const` canonicalisation for +/// equality — always construct them via `const` or the factory ctors. +@immutable +sealed class AsyncButtonStatus { + const AsyncButtonStatus(); + + const factory AsyncButtonStatus.idle() = AsyncButtonStatusIdle; + const factory AsyncButtonStatus.loading() = AsyncButtonStatusLoading; + const factory AsyncButtonStatus.success() = AsyncButtonStatusSuccess; + const factory AsyncButtonStatus.error( + Object error, [ + StackTrace? stackTrace, + ]) = AsyncButtonStatusError; +} + +final class AsyncButtonStatusIdle extends AsyncButtonStatus { + const AsyncButtonStatusIdle(); + + @override + String toString() { + return '.idle()'; + } +} + +final class AsyncButtonStatusLoading extends AsyncButtonStatus { + const AsyncButtonStatusLoading(); + + @override + String toString() { + return '.loading()'; + } +} + +final class AsyncButtonStatusSuccess extends AsyncButtonStatus { + const AsyncButtonStatusSuccess(); + + @override + String toString() { + return '.success()'; + } +} + +final class AsyncButtonStatusError extends AsyncButtonStatus { + const AsyncButtonStatusError(this.error, [this.stackTrace]); + + final Object error; + final StackTrace? stackTrace; + + /// Equality compares [error] by runtime type and `toString()` payload — + /// most thrown errors (Exceptions, Errors, custom error objects) do not + /// override `operator ==`, so a raw `error == other.error` collapses to + /// identity. Two `invalidate('bad')` calls or two `StateError('oops')` + /// throws are treated as the same error for listener-dedup purposes. + /// [stackTrace] is informational and excluded from equality. + @override + bool operator ==(Object other) { + if (identical(this, other)) { + return true; + } + if (other is! AsyncButtonStatusError) { + return false; + } + return error.runtimeType == other.error.runtimeType && + error.toString() == other.error.toString(); + } + + @override + int get hashCode { + return Object.hash( + AsyncButtonStatusError, + error.runtimeType, + error.toString(), + ); + } + + @override + String toString() { + return '.error($error)'; + } +} diff --git a/lib/src/buttons/async_material_button.dart b/lib/src/buttons/async_material_button.dart new file mode 100644 index 0000000..146bc24 --- /dev/null +++ b/lib/src/buttons/async_material_button.dart @@ -0,0 +1,112 @@ +part of '../../material_async_button.dart'; + +/// Abstract base for the Material wrapper widgets shipped with this package +/// ([ElevatedAsyncButton], [FilledAsyncButton], [OutlinedAsyncButton], +/// [TextAsyncButton], [IconAsyncButton]). +/// +/// Owns the shared async-status surface — [onPressed], [controller], and +/// the theme-override knobs. Subclasses implement [build] and forward these +/// fields to an [AsyncButton]. For custom non-Material buttons reach for +/// [AsyncButton] directly. +abstract class AsyncMaterialButton extends StatelessWidget { + const AsyncMaterialButton({ + super.key, + required this.child, + required this.onPressed, + this.controller, + this.onSuccess, + this.onError, + this.onStateChanged, + this.confirmBeforePress, + this.loadingChild, + this.successChild, + this.errorChild, + this.disabled = false, + this.switchDuration, + this.transitionBuilder, + this.successDisplayDuration, + this.errorDisplayDuration, + this.cooldownDuration, + this.animateSize, + this.hapticOn, + this.announceSemantics, + this.rethrowErrors, + }); + + final Widget child; + final AsyncCallback? onPressed; + final AsyncButtonController? controller; + final VoidCallback? onSuccess; + final AsyncButtonErrorCallback? onError; + final ValueChanged? onStateChanged; + final Future Function(BuildContext context)? confirmBeforePress; + final Widget? loadingChild; + final Widget? successChild; + final Widget? errorChild; + final bool disabled; + final Duration? switchDuration; + final AnimatedSwitcherTransitionBuilder? transitionBuilder; + final Duration? successDisplayDuration; + final Duration? errorDisplayDuration; + final Duration? cooldownDuration; + final bool? animateSize; + final HapticOn? hapticOn; + final bool? announceSemantics; + final bool? rethrowErrors; +} + +/// Sub-base for the four [AsyncMaterialButton]s that share the standard +/// [ButtonStyleButton] surface ([ElevatedAsyncButton], [FilledAsyncButton], +/// [OutlinedAsyncButton], [TextAsyncButton]). Centralises the common +/// Material parameters and the `.icon` constructor pieces so each concrete +/// subclass only has to render its specific button widget. +/// +/// [IconAsyncButton] does not extend this — it carries a different field +/// set ([IconButton]'s API). +abstract class AsyncStandardMaterialButton extends AsyncMaterialButton { + const AsyncStandardMaterialButton({ + super.key, + required super.child, + required super.onPressed, + super.controller, + super.onSuccess, + super.onError, + super.onStateChanged, + super.confirmBeforePress, + super.loadingChild, + super.successChild, + super.errorChild, + super.disabled, + super.switchDuration, + super.transitionBuilder, + super.successDisplayDuration, + super.errorDisplayDuration, + super.cooldownDuration, + super.animateSize, + super.hapticOn, + super.announceSemantics, + super.rethrowErrors, + this.onLongPress, + this.onHover, + this.onFocusChange, + this.style, + this.focusNode, + this.autofocus = false, + this.clipBehavior, + this.statesController, + Widget? icon, + IconAlignment? iconAlignment, + }) : _icon = icon, + _iconAlignment = iconAlignment; + + final VoidCallback? onLongPress; + final ValueChanged? onHover; + final ValueChanged? onFocusChange; + final ButtonStyle? style; + final FocusNode? focusNode; + final bool autofocus; + final Clip? clipBehavior; + final WidgetStatesController? statesController; + final Widget? _icon; + final IconAlignment? _iconAlignment; +} diff --git a/lib/src/buttons/elevated_async_button.dart b/lib/src/buttons/elevated_async_button.dart index acae1c1..2b73d99 100644 --- a/lib/src/buttons/elevated_async_button.dart +++ b/lib/src/buttons/elevated_async_button.dart @@ -1,173 +1,132 @@ -import 'package:flutter/material.dart'; - -import '../async_button_builder.dart'; -import '../async_button_controller.dart'; -import '../async_button_state.dart'; -import '../material_async_button_theme.dart'; +part of '../../material_async_button.dart'; /// Async-aware [ElevatedButton]. While `onPressed` is running the label is /// swapped for a loading widget; success/error are shown afterwards if /// configured via prop or theme. -class ElevatedAsyncButton extends StatelessWidget { +class ElevatedAsyncButton extends AsyncStandardMaterialButton { const ElevatedAsyncButton({ super.key, - required this.onPressed, - required this.child, - this.onLongPress, - this.onHover, - this.onFocusChange, - this.style, - this.focusNode, - this.autofocus = false, - this.clipBehavior, - this.statesController, - // async - this.controller, - this.onSuccess, - this.onError, - this.onStateChanged, - this.confirmBeforePress, - this.errorBuilder, - this.loadingChild, - this.successChild, - this.errorChild, - this.disabled = false, - this.switchDuration, - this.transitionBuilder, - this.successDisplayDuration, - this.errorDisplayDuration, - this.cooldownDuration, - this.animateSize, - this.hapticOn, - this.announceSemantics, - this.rethrowErrors, - }) : _icon = null, - _iconAlignment = null; + required super.onPressed, + required super.child, + super.onLongPress, + super.onHover, + super.onFocusChange, + super.style, + super.focusNode, + super.autofocus, + super.clipBehavior, + super.statesController, + super.controller, + super.onSuccess, + super.onError, + super.onStateChanged, + super.confirmBeforePress, + super.loadingChild, + super.successChild, + super.errorChild, + super.disabled, + super.switchDuration, + super.transitionBuilder, + super.successDisplayDuration, + super.errorDisplayDuration, + super.cooldownDuration, + super.animateSize, + super.hapticOn, + super.announceSemantics, + super.rethrowErrors, + }); /// Mirrors [ElevatedButton.icon]. The loading/success/error children - /// replace the `label` while [icon] stays put. + /// replace `label` while `icon` stays put. const ElevatedAsyncButton.icon({ super.key, - required this.onPressed, + required super.onPressed, + super.onLongPress, + super.onHover, + super.onFocusChange, + super.style, + super.focusNode, + super.autofocus, + super.clipBehavior, + super.statesController, + super.iconAlignment, + super.controller, + super.onSuccess, + super.onError, + super.onStateChanged, + super.confirmBeforePress, + super.loadingChild, + super.successChild, + super.errorChild, + super.disabled, + super.switchDuration, + super.transitionBuilder, + super.successDisplayDuration, + super.errorDisplayDuration, + super.cooldownDuration, + super.animateSize, + super.hapticOn, + super.announceSemantics, + super.rethrowErrors, required Widget icon, required Widget label, - this.onLongPress, - this.onHover, - this.onFocusChange, - this.style, - this.focusNode, - this.autofocus = false, - this.clipBehavior, - this.statesController, - IconAlignment? iconAlignment, - this.controller, - this.onSuccess, - this.onError, - this.onStateChanged, - this.confirmBeforePress, - this.errorBuilder, - this.loadingChild, - this.successChild, - this.errorChild, - this.disabled = false, - this.switchDuration, - this.transitionBuilder, - this.successDisplayDuration, - this.errorDisplayDuration, - this.cooldownDuration, - this.animateSize, - this.hapticOn, - this.announceSemantics, - this.rethrowErrors, - }) : _icon = icon, - _iconAlignment = iconAlignment, - child = label; - - final Future Function()? onPressed; - final Widget child; - final VoidCallback? onLongPress; - final ValueChanged? onHover; - final ValueChanged? onFocusChange; - final ButtonStyle? style; - final FocusNode? focusNode; - final bool autofocus; - final Clip? clipBehavior; - final WidgetStatesController? statesController; - final Widget? _icon; - final IconAlignment? _iconAlignment; - - final AsyncButtonController? controller; - final VoidCallback? onSuccess; - final AsyncButtonErrorCallback? onError; - final ValueChanged? onStateChanged; - final Future Function(BuildContext context)? confirmBeforePress; - final AsyncButtonErrorBuilder? errorBuilder; - final Widget? loadingChild; - final Widget? successChild; - final Widget? errorChild; - final bool disabled; - final Duration? switchDuration; - final AnimatedSwitcherTransitionBuilder? transitionBuilder; - final Duration? successDisplayDuration; - final Duration? errorDisplayDuration; - final Duration? cooldownDuration; - final bool? animateSize; - final HapticOn? hapticOn; - final bool? announceSemantics; - final bool? rethrowErrors; + }) : super(icon: icon, child: label); @override - Widget build(BuildContext context) => AsyncButtonBuilder( - onPressed: onPressed, - controller: controller, - onSuccess: onSuccess, - onError: onError, - onStateChanged: onStateChanged, - confirmBeforePress: confirmBeforePress, - errorBuilder: errorBuilder, - loadingChild: loadingChild, - successChild: successChild, - errorChild: errorChild, - disabled: disabled, - switchDuration: switchDuration, - transitionBuilder: transitionBuilder, - successDisplayDuration: successDisplayDuration, - errorDisplayDuration: errorDisplayDuration, - cooldownDuration: cooldownDuration, - animateSize: animateSize, - hapticOn: hapticOn, - announceSemantics: announceSemantics, - rethrowErrors: rethrowErrors, - child: child, - builder: (context, animatedChild, callback, _) { - if (_icon != null) { - return ElevatedButton.icon( + Widget build(BuildContext context) { + return AsyncButton( + onPressed: onPressed, + controller: controller, + onSuccess: onSuccess, + onError: onError, + onStateChanged: onStateChanged, + confirmBeforePress: confirmBeforePress, + loadingChild: loadingChild, + successChild: successChild, + errorChild: errorChild, + disabled: disabled, + switchDuration: switchDuration, + transitionBuilder: transitionBuilder, + successDisplayDuration: successDisplayDuration, + errorDisplayDuration: errorDisplayDuration, + cooldownDuration: cooldownDuration, + animateSize: animateSize, + hapticOn: hapticOn, + announceSemantics: announceSemantics, + rethrowErrors: rethrowErrors, + builder: (context, animatedChild, callback, status) { + final clip = clipBehavior ?? .none; + final longPress = callback == null ? null : onLongPress; + if (_icon != null) { + return ElevatedButton.icon( + onPressed: callback, + onLongPress: longPress, + onHover: onHover, + onFocusChange: onFocusChange, + style: style, + focusNode: focusNode, + autofocus: autofocus, + clipBehavior: clip, + statesController: statesController, + iconAlignment: _iconAlignment, + icon: _icon, + label: animatedChild, + ); + } + return ElevatedButton( onPressed: callback, - onLongPress: callback == null ? null : onLongPress, + onLongPress: longPress, onHover: onHover, onFocusChange: onFocusChange, style: style, focusNode: focusNode, autofocus: autofocus, - clipBehavior: clipBehavior ?? Clip.none, + clipBehavior: clip, statesController: statesController, - iconAlignment: _iconAlignment, - icon: _icon, - label: animatedChild, + child: animatedChild, ); - } - return ElevatedButton( - onPressed: callback, - onLongPress: callback == null ? null : onLongPress, - onHover: onHover, - onFocusChange: onFocusChange, - style: style, - focusNode: focusNode, - autofocus: autofocus, - clipBehavior: clipBehavior ?? Clip.none, - statesController: statesController, - child: animatedChild, - ); - }, - ); + }, + child: child, + ); + } } diff --git a/lib/src/buttons/filled_async_button.dart b/lib/src/buttons/filled_async_button.dart index 62bfac4..bccc8df 100644 --- a/lib/src/buttons/filled_async_button.dart +++ b/lib/src/buttons/filled_async_button.dart @@ -1,278 +1,232 @@ -import 'package:flutter/material.dart'; - -import '../async_button_builder.dart'; -import '../async_button_controller.dart'; -import '../async_button_state.dart'; -import '../material_async_button_theme.dart'; +part of '../../material_async_button.dart'; enum _FilledVariant { primary, tonal } /// Async-aware [FilledButton] with all four Material 3 flavors: /// [FilledAsyncButton.new], [FilledAsyncButton.tonal], /// [FilledAsyncButton.icon], [FilledAsyncButton.tonalIcon]. -class FilledAsyncButton extends StatelessWidget { +class FilledAsyncButton extends AsyncStandardMaterialButton { const FilledAsyncButton({ super.key, - required this.onPressed, - required this.child, - this.onLongPress, - this.onHover, - this.onFocusChange, - this.style, - this.focusNode, - this.autofocus = false, - this.clipBehavior, - this.statesController, - this.controller, - this.onSuccess, - this.onError, - this.onStateChanged, - this.confirmBeforePress, - this.errorBuilder, - this.loadingChild, - this.successChild, - this.errorChild, - this.disabled = false, - this.switchDuration, - this.transitionBuilder, - this.successDisplayDuration, - this.errorDisplayDuration, - this.cooldownDuration, - this.animateSize, - this.hapticOn, - this.announceSemantics, - this.rethrowErrors, - }) : _variant = _FilledVariant.primary, - _icon = null, - _iconAlignment = null; + required super.onPressed, + required super.child, + super.onLongPress, + super.onHover, + super.onFocusChange, + super.style, + super.focusNode, + super.autofocus, + super.clipBehavior, + super.statesController, + super.controller, + super.onSuccess, + super.onError, + super.onStateChanged, + super.confirmBeforePress, + super.loadingChild, + super.successChild, + super.errorChild, + super.disabled, + super.switchDuration, + super.transitionBuilder, + super.successDisplayDuration, + super.errorDisplayDuration, + super.cooldownDuration, + super.animateSize, + super.hapticOn, + super.announceSemantics, + super.rethrowErrors, + }) : _variant = .primary; const FilledAsyncButton.tonal({ super.key, - required this.onPressed, - required this.child, - this.onLongPress, - this.onHover, - this.onFocusChange, - this.style, - this.focusNode, - this.autofocus = false, - this.clipBehavior, - this.statesController, - this.controller, - this.onSuccess, - this.onError, - this.onStateChanged, - this.confirmBeforePress, - this.errorBuilder, - this.loadingChild, - this.successChild, - this.errorChild, - this.disabled = false, - this.switchDuration, - this.transitionBuilder, - this.successDisplayDuration, - this.errorDisplayDuration, - this.cooldownDuration, - this.animateSize, - this.hapticOn, - this.announceSemantics, - this.rethrowErrors, - }) : _variant = _FilledVariant.tonal, - _icon = null, - _iconAlignment = null; + required super.onPressed, + required super.child, + super.onLongPress, + super.onHover, + super.onFocusChange, + super.style, + super.focusNode, + super.autofocus, + super.clipBehavior, + super.statesController, + super.controller, + super.onSuccess, + super.onError, + super.onStateChanged, + super.confirmBeforePress, + super.loadingChild, + super.successChild, + super.errorChild, + super.disabled, + super.switchDuration, + super.transitionBuilder, + super.successDisplayDuration, + super.errorDisplayDuration, + super.cooldownDuration, + super.animateSize, + super.hapticOn, + super.announceSemantics, + super.rethrowErrors, + }) : _variant = .tonal; const FilledAsyncButton.icon({ super.key, - required this.onPressed, + required super.onPressed, + super.onLongPress, + super.onHover, + super.onFocusChange, + super.style, + super.focusNode, + super.autofocus, + super.clipBehavior, + super.statesController, + super.iconAlignment, + super.controller, + super.onSuccess, + super.onError, + super.onStateChanged, + super.confirmBeforePress, + super.loadingChild, + super.successChild, + super.errorChild, + super.disabled, + super.switchDuration, + super.transitionBuilder, + super.successDisplayDuration, + super.errorDisplayDuration, + super.cooldownDuration, + super.animateSize, + super.hapticOn, + super.announceSemantics, + super.rethrowErrors, required Widget icon, required Widget label, - this.onLongPress, - this.onHover, - this.onFocusChange, - this.style, - this.focusNode, - this.autofocus = false, - this.clipBehavior, - this.statesController, - IconAlignment? iconAlignment, - this.controller, - this.onSuccess, - this.onError, - this.onStateChanged, - this.confirmBeforePress, - this.errorBuilder, - this.loadingChild, - this.successChild, - this.errorChild, - this.disabled = false, - this.switchDuration, - this.transitionBuilder, - this.successDisplayDuration, - this.errorDisplayDuration, - this.cooldownDuration, - this.animateSize, - this.hapticOn, - this.announceSemantics, - this.rethrowErrors, - }) : _variant = _FilledVariant.primary, - _icon = icon, - _iconAlignment = iconAlignment, - child = label; + }) : _variant = .primary, + super(icon: icon, child: label); const FilledAsyncButton.tonalIcon({ super.key, - required this.onPressed, + required super.onPressed, + super.onLongPress, + super.onHover, + super.onFocusChange, + super.style, + super.focusNode, + super.autofocus, + super.clipBehavior, + super.statesController, + super.iconAlignment, + super.controller, + super.onSuccess, + super.onError, + super.onStateChanged, + super.confirmBeforePress, + super.loadingChild, + super.successChild, + super.errorChild, + super.disabled, + super.switchDuration, + super.transitionBuilder, + super.successDisplayDuration, + super.errorDisplayDuration, + super.cooldownDuration, + super.animateSize, + super.hapticOn, + super.announceSemantics, + super.rethrowErrors, required Widget icon, required Widget label, - this.onLongPress, - this.onHover, - this.onFocusChange, - this.style, - this.focusNode, - this.autofocus = false, - this.clipBehavior, - this.statesController, - IconAlignment? iconAlignment, - this.controller, - this.onSuccess, - this.onError, - this.onStateChanged, - this.confirmBeforePress, - this.errorBuilder, - this.loadingChild, - this.successChild, - this.errorChild, - this.disabled = false, - this.switchDuration, - this.transitionBuilder, - this.successDisplayDuration, - this.errorDisplayDuration, - this.cooldownDuration, - this.animateSize, - this.hapticOn, - this.announceSemantics, - this.rethrowErrors, - }) : _variant = _FilledVariant.tonal, - _icon = icon, - _iconAlignment = iconAlignment, - child = label; + }) : _variant = .tonal, + super(icon: icon, child: label); - final Future Function()? onPressed; - final Widget child; - final VoidCallback? onLongPress; - final ValueChanged? onHover; - final ValueChanged? onFocusChange; - final ButtonStyle? style; - final FocusNode? focusNode; - final bool autofocus; - final Clip? clipBehavior; - final WidgetStatesController? statesController; final _FilledVariant _variant; - final Widget? _icon; - final IconAlignment? _iconAlignment; - - final AsyncButtonController? controller; - final VoidCallback? onSuccess; - final AsyncButtonErrorCallback? onError; - final ValueChanged? onStateChanged; - final Future Function(BuildContext context)? confirmBeforePress; - final AsyncButtonErrorBuilder? errorBuilder; - final Widget? loadingChild; - final Widget? successChild; - final Widget? errorChild; - final bool disabled; - final Duration? switchDuration; - final AnimatedSwitcherTransitionBuilder? transitionBuilder; - final Duration? successDisplayDuration; - final Duration? errorDisplayDuration; - final Duration? cooldownDuration; - final bool? animateSize; - final HapticOn? hapticOn; - final bool? announceSemantics; - final bool? rethrowErrors; @override - Widget build(BuildContext context) => AsyncButtonBuilder( - onPressed: onPressed, - controller: controller, - onSuccess: onSuccess, - onError: onError, - onStateChanged: onStateChanged, - confirmBeforePress: confirmBeforePress, - errorBuilder: errorBuilder, - loadingChild: loadingChild, - successChild: successChild, - errorChild: errorChild, - disabled: disabled, - switchDuration: switchDuration, - transitionBuilder: transitionBuilder, - successDisplayDuration: successDisplayDuration, - errorDisplayDuration: errorDisplayDuration, - cooldownDuration: cooldownDuration, - animateSize: animateSize, - hapticOn: hapticOn, - announceSemantics: announceSemantics, - rethrowErrors: rethrowErrors, - child: child, - builder: (context, animatedChild, callback, _) { - if (_icon != null) { + Widget build(BuildContext context) { + return AsyncButton( + onPressed: onPressed, + controller: controller, + onSuccess: onSuccess, + onError: onError, + onStateChanged: onStateChanged, + confirmBeforePress: confirmBeforePress, + loadingChild: loadingChild, + successChild: successChild, + errorChild: errorChild, + disabled: disabled, + switchDuration: switchDuration, + transitionBuilder: transitionBuilder, + successDisplayDuration: successDisplayDuration, + errorDisplayDuration: errorDisplayDuration, + cooldownDuration: cooldownDuration, + animateSize: animateSize, + hapticOn: hapticOn, + announceSemantics: announceSemantics, + rethrowErrors: rethrowErrors, + builder: (context, animatedChild, callback, status) { + final clip = clipBehavior ?? .none; + final longPress = callback == null ? null : onLongPress; + if (_icon != null) { + return switch (_variant) { + .primary => FilledButton.icon( + onPressed: callback, + onLongPress: longPress, + onHover: onHover, + onFocusChange: onFocusChange, + style: style, + focusNode: focusNode, + autofocus: autofocus, + clipBehavior: clip, + statesController: statesController, + iconAlignment: _iconAlignment, + icon: _icon, + label: animatedChild, + ), + .tonal => FilledButton.tonalIcon( + onPressed: callback, + onLongPress: longPress, + onHover: onHover, + onFocusChange: onFocusChange, + style: style, + focusNode: focusNode, + autofocus: autofocus, + clipBehavior: clip, + statesController: statesController, + iconAlignment: _iconAlignment, + icon: _icon, + label: animatedChild, + ), + }; + } return switch (_variant) { - _FilledVariant.primary => FilledButton.icon( + .primary => FilledButton( onPressed: callback, - onLongPress: callback == null ? null : onLongPress, + onLongPress: longPress, onHover: onHover, onFocusChange: onFocusChange, style: style, focusNode: focusNode, autofocus: autofocus, - clipBehavior: clipBehavior ?? Clip.none, + clipBehavior: clip, statesController: statesController, - iconAlignment: _iconAlignment, - icon: _icon, - label: animatedChild, + child: animatedChild, ), - _FilledVariant.tonal => FilledButton.tonalIcon( + .tonal => FilledButton.tonal( onPressed: callback, - onLongPress: callback == null ? null : onLongPress, + onLongPress: longPress, onHover: onHover, onFocusChange: onFocusChange, style: style, focusNode: focusNode, autofocus: autofocus, - clipBehavior: clipBehavior ?? Clip.none, + clipBehavior: clip, statesController: statesController, - iconAlignment: _iconAlignment, - icon: _icon, - label: animatedChild, + child: animatedChild, ), }; - } - return switch (_variant) { - _FilledVariant.primary => FilledButton( - onPressed: callback, - onLongPress: callback == null ? null : onLongPress, - onHover: onHover, - onFocusChange: onFocusChange, - style: style, - focusNode: focusNode, - autofocus: autofocus, - clipBehavior: clipBehavior ?? Clip.none, - statesController: statesController, - child: animatedChild, - ), - _FilledVariant.tonal => FilledButton.tonal( - onPressed: callback, - onLongPress: callback == null ? null : onLongPress, - onHover: onHover, - onFocusChange: onFocusChange, - style: style, - focusNode: focusNode, - autofocus: autofocus, - clipBehavior: clipBehavior ?? Clip.none, - statesController: statesController, - child: animatedChild, - ), - }; - }, - ); + }, + child: child, + ); + } } diff --git a/lib/src/buttons/icon_async_button.dart b/lib/src/buttons/icon_async_button.dart index d4de872..ee15ac5 100644 --- a/lib/src/buttons/icon_async_button.dart +++ b/lib/src/buttons/icon_async_button.dart @@ -1,9 +1,4 @@ -import 'package:flutter/material.dart'; - -import '../async_button_builder.dart'; -import '../async_button_controller.dart'; -import '../async_button_state.dart'; -import '../material_async_button_theme.dart'; +part of '../../material_async_button.dart'; enum _IconVariant { standard, filled, filledTonal, outlined } @@ -11,12 +6,30 @@ enum _IconVariant { standard, filled, filledTonal, outlined } /// [IconAsyncButton.new], [IconAsyncButton.filled], /// [IconAsyncButton.filledTonal], [IconAsyncButton.outlined]. /// -/// The [icon] is swapped with [loadingChild]/[successChild]/[errorChild] +/// The [icon] is swapped with `loadingChild`/`successChild`/`errorChild` /// during the corresponding state. -class IconAsyncButton extends StatelessWidget { +class IconAsyncButton extends AsyncMaterialButton { const IconAsyncButton({ super.key, - required this.onPressed, + required super.onPressed, + super.controller, + super.onSuccess, + super.onError, + super.onStateChanged, + super.confirmBeforePress, + super.loadingChild, + super.successChild, + super.errorChild, + super.disabled, + super.switchDuration, + super.transitionBuilder, + super.successDisplayDuration, + super.errorDisplayDuration, + super.cooldownDuration, + super.animateSize, + super.hapticOn, + super.announceSemantics, + super.rethrowErrors, required this.icon, this.iconSize, this.visualDensity, @@ -38,30 +51,30 @@ class IconAsyncButton extends StatelessWidget { this.style, this.isSelected, this.selectedIcon, - this.controller, - this.onSuccess, - this.onError, - this.onStateChanged, - this.confirmBeforePress, - this.errorBuilder, - this.loadingChild, - this.successChild, - this.errorChild, - this.disabled = false, - this.switchDuration, - this.transitionBuilder, - this.successDisplayDuration, - this.errorDisplayDuration, - this.cooldownDuration, - this.animateSize, - this.hapticOn, - this.announceSemantics, - this.rethrowErrors, - }) : _variant = _IconVariant.standard; + }) : _variant = .standard, + super(child: icon); const IconAsyncButton.filled({ super.key, - required this.onPressed, + required super.onPressed, + super.controller, + super.onSuccess, + super.onError, + super.onStateChanged, + super.confirmBeforePress, + super.loadingChild, + super.successChild, + super.errorChild, + super.disabled, + super.switchDuration, + super.transitionBuilder, + super.successDisplayDuration, + super.errorDisplayDuration, + super.cooldownDuration, + super.animateSize, + super.hapticOn, + super.announceSemantics, + super.rethrowErrors, required this.icon, this.iconSize, this.visualDensity, @@ -83,30 +96,30 @@ class IconAsyncButton extends StatelessWidget { this.style, this.isSelected, this.selectedIcon, - this.controller, - this.onSuccess, - this.onError, - this.onStateChanged, - this.confirmBeforePress, - this.errorBuilder, - this.loadingChild, - this.successChild, - this.errorChild, - this.disabled = false, - this.switchDuration, - this.transitionBuilder, - this.successDisplayDuration, - this.errorDisplayDuration, - this.cooldownDuration, - this.animateSize, - this.hapticOn, - this.announceSemantics, - this.rethrowErrors, - }) : _variant = _IconVariant.filled; + }) : _variant = .filled, + super(child: icon); const IconAsyncButton.filledTonal({ super.key, - required this.onPressed, + required super.onPressed, + super.controller, + super.onSuccess, + super.onError, + super.onStateChanged, + super.confirmBeforePress, + super.loadingChild, + super.successChild, + super.errorChild, + super.disabled, + super.switchDuration, + super.transitionBuilder, + super.successDisplayDuration, + super.errorDisplayDuration, + super.cooldownDuration, + super.animateSize, + super.hapticOn, + super.announceSemantics, + super.rethrowErrors, required this.icon, this.iconSize, this.visualDensity, @@ -128,30 +141,30 @@ class IconAsyncButton extends StatelessWidget { this.style, this.isSelected, this.selectedIcon, - this.controller, - this.onSuccess, - this.onError, - this.onStateChanged, - this.confirmBeforePress, - this.errorBuilder, - this.loadingChild, - this.successChild, - this.errorChild, - this.disabled = false, - this.switchDuration, - this.transitionBuilder, - this.successDisplayDuration, - this.errorDisplayDuration, - this.cooldownDuration, - this.animateSize, - this.hapticOn, - this.announceSemantics, - this.rethrowErrors, - }) : _variant = _IconVariant.filledTonal; + }) : _variant = .filledTonal, + super(child: icon); const IconAsyncButton.outlined({ super.key, - required this.onPressed, + required super.onPressed, + super.controller, + super.onSuccess, + super.onError, + super.onStateChanged, + super.confirmBeforePress, + super.loadingChild, + super.successChild, + super.errorChild, + super.disabled, + super.switchDuration, + super.transitionBuilder, + super.successDisplayDuration, + super.errorDisplayDuration, + super.cooldownDuration, + super.animateSize, + super.hapticOn, + super.announceSemantics, + super.rethrowErrors, required this.icon, this.iconSize, this.visualDensity, @@ -173,28 +186,9 @@ class IconAsyncButton extends StatelessWidget { this.style, this.isSelected, this.selectedIcon, - this.controller, - this.onSuccess, - this.onError, - this.onStateChanged, - this.confirmBeforePress, - this.errorBuilder, - this.loadingChild, - this.successChild, - this.errorChild, - this.disabled = false, - this.switchDuration, - this.transitionBuilder, - this.successDisplayDuration, - this.errorDisplayDuration, - this.cooldownDuration, - this.animateSize, - this.hapticOn, - this.announceSemantics, - this.rethrowErrors, - }) : _variant = _IconVariant.outlined; + }) : _variant = .outlined, + super(child: icon); - final Future Function()? onPressed; final Widget icon; final double? iconSize; final VisualDensity? visualDensity; @@ -218,148 +212,129 @@ class IconAsyncButton extends StatelessWidget { final Widget? selectedIcon; final _IconVariant _variant; - final AsyncButtonController? controller; - final VoidCallback? onSuccess; - final AsyncButtonErrorCallback? onError; - final ValueChanged? onStateChanged; - final Future Function(BuildContext context)? confirmBeforePress; - final AsyncButtonErrorBuilder? errorBuilder; - final Widget? loadingChild; - final Widget? successChild; - final Widget? errorChild; - final bool disabled; - final Duration? switchDuration; - final AnimatedSwitcherTransitionBuilder? transitionBuilder; - final Duration? successDisplayDuration; - final Duration? errorDisplayDuration; - final Duration? cooldownDuration; - final bool? animateSize; - final HapticOn? hapticOn; - final bool? announceSemantics; - final bool? rethrowErrors; - @override - Widget build(BuildContext context) => AsyncButtonBuilder( - onPressed: onPressed, - controller: controller, - onSuccess: onSuccess, - onError: onError, - onStateChanged: onStateChanged, - confirmBeforePress: confirmBeforePress, - errorBuilder: errorBuilder, - loadingChild: loadingChild, - successChild: successChild, - errorChild: errorChild, - disabled: disabled, - switchDuration: switchDuration, - transitionBuilder: transitionBuilder, - successDisplayDuration: successDisplayDuration, - errorDisplayDuration: errorDisplayDuration, - cooldownDuration: cooldownDuration, - animateSize: animateSize, - hapticOn: hapticOn, - announceSemantics: announceSemantics, - rethrowErrors: rethrowErrors, - child: icon, - builder: (context, animatedChild, callback, _) { - return switch (_variant) { - _IconVariant.standard => IconButton( - onPressed: callback, - icon: animatedChild, - iconSize: iconSize, - visualDensity: visualDensity, - padding: padding, - alignment: alignment, - splashRadius: splashRadius, - color: color, - focusColor: focusColor, - hoverColor: hoverColor, - highlightColor: highlightColor, - splashColor: splashColor, - disabledColor: disabledColor, - mouseCursor: mouseCursor, - focusNode: focusNode, - autofocus: autofocus, - tooltip: tooltip, - enableFeedback: enableFeedback, - constraints: constraints, - style: style, - isSelected: isSelected, - selectedIcon: selectedIcon, - ), - _IconVariant.filled => IconButton.filled( - onPressed: callback, - icon: animatedChild, - iconSize: iconSize, - visualDensity: visualDensity, - padding: padding, - alignment: alignment, - splashRadius: splashRadius, - color: color, - focusColor: focusColor, - hoverColor: hoverColor, - highlightColor: highlightColor, - splashColor: splashColor, - disabledColor: disabledColor, - mouseCursor: mouseCursor, - focusNode: focusNode, - autofocus: autofocus, - tooltip: tooltip, - enableFeedback: enableFeedback, - constraints: constraints, - style: style, - isSelected: isSelected, - selectedIcon: selectedIcon, - ), - _IconVariant.filledTonal => IconButton.filledTonal( - onPressed: callback, - icon: animatedChild, - iconSize: iconSize, - visualDensity: visualDensity, - padding: padding, - alignment: alignment, - splashRadius: splashRadius, - color: color, - focusColor: focusColor, - hoverColor: hoverColor, - highlightColor: highlightColor, - splashColor: splashColor, - disabledColor: disabledColor, - mouseCursor: mouseCursor, - focusNode: focusNode, - autofocus: autofocus, - tooltip: tooltip, - enableFeedback: enableFeedback, - constraints: constraints, - style: style, - isSelected: isSelected, - selectedIcon: selectedIcon, - ), - _IconVariant.outlined => IconButton.outlined( - onPressed: callback, - icon: animatedChild, - iconSize: iconSize, - visualDensity: visualDensity, - padding: padding, - alignment: alignment, - splashRadius: splashRadius, - color: color, - focusColor: focusColor, - hoverColor: hoverColor, - highlightColor: highlightColor, - splashColor: splashColor, - disabledColor: disabledColor, - mouseCursor: mouseCursor, - focusNode: focusNode, - autofocus: autofocus, - tooltip: tooltip, - enableFeedback: enableFeedback, - constraints: constraints, - style: style, - isSelected: isSelected, - selectedIcon: selectedIcon, - ), - }; - }, - ); + Widget build(BuildContext context) { + return AsyncButton( + onPressed: onPressed, + controller: controller, + onSuccess: onSuccess, + onError: onError, + onStateChanged: onStateChanged, + confirmBeforePress: confirmBeforePress, + loadingChild: loadingChild, + successChild: successChild, + errorChild: errorChild, + disabled: disabled, + switchDuration: switchDuration, + transitionBuilder: transitionBuilder, + successDisplayDuration: successDisplayDuration, + errorDisplayDuration: errorDisplayDuration, + cooldownDuration: cooldownDuration, + animateSize: animateSize, + hapticOn: hapticOn, + announceSemantics: announceSemantics, + rethrowErrors: rethrowErrors, + builder: (context, child, callback, status) { + return switch (_variant) { + .standard => IconButton( + onPressed: callback, + icon: child, + iconSize: iconSize, + visualDensity: visualDensity, + padding: padding, + alignment: alignment, + splashRadius: splashRadius, + color: color, + focusColor: focusColor, + hoverColor: hoverColor, + highlightColor: highlightColor, + splashColor: splashColor, + disabledColor: disabledColor, + mouseCursor: mouseCursor, + focusNode: focusNode, + autofocus: autofocus, + tooltip: tooltip, + enableFeedback: enableFeedback, + constraints: constraints, + style: style, + isSelected: isSelected, + selectedIcon: selectedIcon, + ), + .filled => IconButton.filled( + onPressed: callback, + icon: child, + iconSize: iconSize, + visualDensity: visualDensity, + padding: padding, + alignment: alignment, + splashRadius: splashRadius, + color: color, + focusColor: focusColor, + hoverColor: hoverColor, + highlightColor: highlightColor, + splashColor: splashColor, + disabledColor: disabledColor, + mouseCursor: mouseCursor, + focusNode: focusNode, + autofocus: autofocus, + tooltip: tooltip, + enableFeedback: enableFeedback, + constraints: constraints, + style: style, + isSelected: isSelected, + selectedIcon: selectedIcon, + ), + .filledTonal => IconButton.filledTonal( + onPressed: callback, + icon: child, + iconSize: iconSize, + visualDensity: visualDensity, + padding: padding, + alignment: alignment, + splashRadius: splashRadius, + color: color, + focusColor: focusColor, + hoverColor: hoverColor, + highlightColor: highlightColor, + splashColor: splashColor, + disabledColor: disabledColor, + mouseCursor: mouseCursor, + focusNode: focusNode, + autofocus: autofocus, + tooltip: tooltip, + enableFeedback: enableFeedback, + constraints: constraints, + style: style, + isSelected: isSelected, + selectedIcon: selectedIcon, + ), + .outlined => IconButton.outlined( + onPressed: callback, + icon: child, + iconSize: iconSize, + visualDensity: visualDensity, + padding: padding, + alignment: alignment, + splashRadius: splashRadius, + color: color, + focusColor: focusColor, + hoverColor: hoverColor, + highlightColor: highlightColor, + splashColor: splashColor, + disabledColor: disabledColor, + mouseCursor: mouseCursor, + focusNode: focusNode, + autofocus: autofocus, + tooltip: tooltip, + enableFeedback: enableFeedback, + constraints: constraints, + style: style, + isSelected: isSelected, + selectedIcon: selectedIcon, + ), + }; + }, + child: icon, + ); + } } diff --git a/lib/src/buttons/outlined_async_button.dart b/lib/src/buttons/outlined_async_button.dart index 6b18185..d2a8eab 100644 --- a/lib/src/buttons/outlined_async_button.dart +++ b/lib/src/buttons/outlined_async_button.dart @@ -1,168 +1,128 @@ -import 'package:flutter/material.dart'; - -import '../async_button_builder.dart'; -import '../async_button_controller.dart'; -import '../async_button_state.dart'; -import '../material_async_button_theme.dart'; +part of '../../material_async_button.dart'; /// Async-aware [OutlinedButton]. -class OutlinedAsyncButton extends StatelessWidget { +class OutlinedAsyncButton extends AsyncStandardMaterialButton { const OutlinedAsyncButton({ super.key, - required this.onPressed, - required this.child, - this.onLongPress, - this.onHover, - this.onFocusChange, - this.style, - this.focusNode, - this.autofocus = false, - this.clipBehavior, - this.statesController, - this.controller, - this.onSuccess, - this.onError, - this.onStateChanged, - this.confirmBeforePress, - this.errorBuilder, - this.loadingChild, - this.successChild, - this.errorChild, - this.disabled = false, - this.switchDuration, - this.transitionBuilder, - this.successDisplayDuration, - this.errorDisplayDuration, - this.cooldownDuration, - this.animateSize, - this.hapticOn, - this.announceSemantics, - this.rethrowErrors, - }) : _icon = null, - _iconAlignment = null; + required super.onPressed, + required super.child, + super.onLongPress, + super.onHover, + super.onFocusChange, + super.style, + super.focusNode, + super.autofocus, + super.clipBehavior, + super.statesController, + super.controller, + super.onSuccess, + super.onError, + super.onStateChanged, + super.confirmBeforePress, + super.loadingChild, + super.successChild, + super.errorChild, + super.disabled, + super.switchDuration, + super.transitionBuilder, + super.successDisplayDuration, + super.errorDisplayDuration, + super.cooldownDuration, + super.animateSize, + super.hapticOn, + super.announceSemantics, + super.rethrowErrors, + }); const OutlinedAsyncButton.icon({ super.key, - required this.onPressed, + required super.onPressed, + super.onLongPress, + super.onHover, + super.onFocusChange, + super.style, + super.focusNode, + super.autofocus, + super.clipBehavior, + super.statesController, + super.iconAlignment, + super.controller, + super.onSuccess, + super.onError, + super.onStateChanged, + super.confirmBeforePress, + super.loadingChild, + super.successChild, + super.errorChild, + super.disabled, + super.switchDuration, + super.transitionBuilder, + super.successDisplayDuration, + super.errorDisplayDuration, + super.cooldownDuration, + super.animateSize, + super.hapticOn, + super.announceSemantics, + super.rethrowErrors, required Widget icon, required Widget label, - this.onLongPress, - this.onHover, - this.onFocusChange, - this.style, - this.focusNode, - this.autofocus = false, - this.clipBehavior, - this.statesController, - IconAlignment? iconAlignment, - this.controller, - this.onSuccess, - this.onError, - this.onStateChanged, - this.confirmBeforePress, - this.errorBuilder, - this.loadingChild, - this.successChild, - this.errorChild, - this.disabled = false, - this.switchDuration, - this.transitionBuilder, - this.successDisplayDuration, - this.errorDisplayDuration, - this.cooldownDuration, - this.animateSize, - this.hapticOn, - this.announceSemantics, - this.rethrowErrors, - }) : _icon = icon, - _iconAlignment = iconAlignment, - child = label; - - final Future Function()? onPressed; - final Widget child; - final VoidCallback? onLongPress; - final ValueChanged? onHover; - final ValueChanged? onFocusChange; - final ButtonStyle? style; - final FocusNode? focusNode; - final bool autofocus; - final Clip? clipBehavior; - final WidgetStatesController? statesController; - final Widget? _icon; - final IconAlignment? _iconAlignment; - - final AsyncButtonController? controller; - final VoidCallback? onSuccess; - final AsyncButtonErrorCallback? onError; - final ValueChanged? onStateChanged; - final Future Function(BuildContext context)? confirmBeforePress; - final AsyncButtonErrorBuilder? errorBuilder; - final Widget? loadingChild; - final Widget? successChild; - final Widget? errorChild; - final bool disabled; - final Duration? switchDuration; - final AnimatedSwitcherTransitionBuilder? transitionBuilder; - final Duration? successDisplayDuration; - final Duration? errorDisplayDuration; - final Duration? cooldownDuration; - final bool? animateSize; - final HapticOn? hapticOn; - final bool? announceSemantics; - final bool? rethrowErrors; + }) : super(icon: icon, child: label); @override - Widget build(BuildContext context) => AsyncButtonBuilder( - onPressed: onPressed, - controller: controller, - onSuccess: onSuccess, - onError: onError, - onStateChanged: onStateChanged, - confirmBeforePress: confirmBeforePress, - errorBuilder: errorBuilder, - loadingChild: loadingChild, - successChild: successChild, - errorChild: errorChild, - disabled: disabled, - switchDuration: switchDuration, - transitionBuilder: transitionBuilder, - successDisplayDuration: successDisplayDuration, - errorDisplayDuration: errorDisplayDuration, - cooldownDuration: cooldownDuration, - animateSize: animateSize, - hapticOn: hapticOn, - announceSemantics: announceSemantics, - rethrowErrors: rethrowErrors, - child: child, - builder: (context, animatedChild, callback, _) { - if (_icon != null) { - return OutlinedButton.icon( + Widget build(BuildContext context) { + return AsyncButton( + onPressed: onPressed, + controller: controller, + onSuccess: onSuccess, + onError: onError, + onStateChanged: onStateChanged, + confirmBeforePress: confirmBeforePress, + loadingChild: loadingChild, + successChild: successChild, + errorChild: errorChild, + disabled: disabled, + switchDuration: switchDuration, + transitionBuilder: transitionBuilder, + successDisplayDuration: successDisplayDuration, + errorDisplayDuration: errorDisplayDuration, + cooldownDuration: cooldownDuration, + animateSize: animateSize, + hapticOn: hapticOn, + announceSemantics: announceSemantics, + rethrowErrors: rethrowErrors, + builder: (context, animatedChild, callback, status) { + final clip = clipBehavior ?? .none; + final longPress = callback == null ? null : onLongPress; + if (_icon != null) { + return OutlinedButton.icon( + onPressed: callback, + onLongPress: longPress, + onHover: onHover, + onFocusChange: onFocusChange, + style: style, + focusNode: focusNode, + autofocus: autofocus, + clipBehavior: clip, + statesController: statesController, + iconAlignment: _iconAlignment, + icon: _icon, + label: animatedChild, + ); + } + return OutlinedButton( onPressed: callback, - onLongPress: callback == null ? null : onLongPress, + onLongPress: longPress, onHover: onHover, onFocusChange: onFocusChange, style: style, focusNode: focusNode, autofocus: autofocus, - clipBehavior: clipBehavior ?? Clip.none, + clipBehavior: clip, statesController: statesController, - iconAlignment: _iconAlignment, - icon: _icon, - label: animatedChild, + child: animatedChild, ); - } - return OutlinedButton( - onPressed: callback, - onLongPress: callback == null ? null : onLongPress, - onHover: onHover, - onFocusChange: onFocusChange, - style: style, - focusNode: focusNode, - autofocus: autofocus, - clipBehavior: clipBehavior ?? Clip.none, - statesController: statesController, - child: animatedChild, - ); - }, - ); + }, + child: child, + ); + } } diff --git a/lib/src/buttons/text_async_button.dart b/lib/src/buttons/text_async_button.dart index 282b524..15a4bc7 100644 --- a/lib/src/buttons/text_async_button.dart +++ b/lib/src/buttons/text_async_button.dart @@ -1,168 +1,128 @@ -import 'package:flutter/material.dart'; - -import '../async_button_builder.dart'; -import '../async_button_controller.dart'; -import '../async_button_state.dart'; -import '../material_async_button_theme.dart'; +part of '../../material_async_button.dart'; /// Async-aware [TextButton]. -class TextAsyncButton extends StatelessWidget { +class TextAsyncButton extends AsyncStandardMaterialButton { const TextAsyncButton({ super.key, - required this.onPressed, - required this.child, - this.onLongPress, - this.onHover, - this.onFocusChange, - this.style, - this.focusNode, - this.autofocus = false, - this.clipBehavior, - this.statesController, - this.controller, - this.onSuccess, - this.onError, - this.onStateChanged, - this.confirmBeforePress, - this.errorBuilder, - this.loadingChild, - this.successChild, - this.errorChild, - this.disabled = false, - this.switchDuration, - this.transitionBuilder, - this.successDisplayDuration, - this.errorDisplayDuration, - this.cooldownDuration, - this.animateSize, - this.hapticOn, - this.announceSemantics, - this.rethrowErrors, - }) : _icon = null, - _iconAlignment = null; + required super.onPressed, + required super.child, + super.onLongPress, + super.onHover, + super.onFocusChange, + super.style, + super.focusNode, + super.autofocus, + super.clipBehavior, + super.statesController, + super.controller, + super.onSuccess, + super.onError, + super.onStateChanged, + super.confirmBeforePress, + super.loadingChild, + super.successChild, + super.errorChild, + super.disabled, + super.switchDuration, + super.transitionBuilder, + super.successDisplayDuration, + super.errorDisplayDuration, + super.cooldownDuration, + super.animateSize, + super.hapticOn, + super.announceSemantics, + super.rethrowErrors, + }); const TextAsyncButton.icon({ super.key, - required this.onPressed, + required super.onPressed, + super.onLongPress, + super.onHover, + super.onFocusChange, + super.style, + super.focusNode, + super.autofocus, + super.clipBehavior, + super.statesController, + super.iconAlignment, + super.controller, + super.onSuccess, + super.onError, + super.onStateChanged, + super.confirmBeforePress, + super.loadingChild, + super.successChild, + super.errorChild, + super.disabled, + super.switchDuration, + super.transitionBuilder, + super.successDisplayDuration, + super.errorDisplayDuration, + super.cooldownDuration, + super.animateSize, + super.hapticOn, + super.announceSemantics, + super.rethrowErrors, required Widget icon, required Widget label, - this.onLongPress, - this.onHover, - this.onFocusChange, - this.style, - this.focusNode, - this.autofocus = false, - this.clipBehavior, - this.statesController, - IconAlignment? iconAlignment, - this.controller, - this.onSuccess, - this.onError, - this.onStateChanged, - this.confirmBeforePress, - this.errorBuilder, - this.loadingChild, - this.successChild, - this.errorChild, - this.disabled = false, - this.switchDuration, - this.transitionBuilder, - this.successDisplayDuration, - this.errorDisplayDuration, - this.cooldownDuration, - this.animateSize, - this.hapticOn, - this.announceSemantics, - this.rethrowErrors, - }) : _icon = icon, - _iconAlignment = iconAlignment, - child = label; - - final Future Function()? onPressed; - final Widget child; - final VoidCallback? onLongPress; - final ValueChanged? onHover; - final ValueChanged? onFocusChange; - final ButtonStyle? style; - final FocusNode? focusNode; - final bool autofocus; - final Clip? clipBehavior; - final WidgetStatesController? statesController; - final Widget? _icon; - final IconAlignment? _iconAlignment; - - final AsyncButtonController? controller; - final VoidCallback? onSuccess; - final AsyncButtonErrorCallback? onError; - final ValueChanged? onStateChanged; - final Future Function(BuildContext context)? confirmBeforePress; - final AsyncButtonErrorBuilder? errorBuilder; - final Widget? loadingChild; - final Widget? successChild; - final Widget? errorChild; - final bool disabled; - final Duration? switchDuration; - final AnimatedSwitcherTransitionBuilder? transitionBuilder; - final Duration? successDisplayDuration; - final Duration? errorDisplayDuration; - final Duration? cooldownDuration; - final bool? animateSize; - final HapticOn? hapticOn; - final bool? announceSemantics; - final bool? rethrowErrors; + }) : super(icon: icon, child: label); @override - Widget build(BuildContext context) => AsyncButtonBuilder( - onPressed: onPressed, - controller: controller, - onSuccess: onSuccess, - onError: onError, - onStateChanged: onStateChanged, - confirmBeforePress: confirmBeforePress, - errorBuilder: errorBuilder, - loadingChild: loadingChild, - successChild: successChild, - errorChild: errorChild, - disabled: disabled, - switchDuration: switchDuration, - transitionBuilder: transitionBuilder, - successDisplayDuration: successDisplayDuration, - errorDisplayDuration: errorDisplayDuration, - cooldownDuration: cooldownDuration, - animateSize: animateSize, - hapticOn: hapticOn, - announceSemantics: announceSemantics, - rethrowErrors: rethrowErrors, - child: child, - builder: (context, animatedChild, callback, _) { - if (_icon != null) { - return TextButton.icon( + Widget build(BuildContext context) { + return AsyncButton( + onPressed: onPressed, + controller: controller, + onSuccess: onSuccess, + onError: onError, + onStateChanged: onStateChanged, + confirmBeforePress: confirmBeforePress, + loadingChild: loadingChild, + successChild: successChild, + errorChild: errorChild, + disabled: disabled, + switchDuration: switchDuration, + transitionBuilder: transitionBuilder, + successDisplayDuration: successDisplayDuration, + errorDisplayDuration: errorDisplayDuration, + cooldownDuration: cooldownDuration, + animateSize: animateSize, + hapticOn: hapticOn, + announceSemantics: announceSemantics, + rethrowErrors: rethrowErrors, + builder: (context, animatedChild, callback, status) { + final clip = clipBehavior ?? .none; + final longPress = callback == null ? null : onLongPress; + if (_icon != null) { + return TextButton.icon( + onPressed: callback, + onLongPress: longPress, + onHover: onHover, + onFocusChange: onFocusChange, + style: style, + focusNode: focusNode, + autofocus: autofocus, + clipBehavior: clip, + statesController: statesController, + iconAlignment: _iconAlignment, + icon: _icon, + label: animatedChild, + ); + } + return TextButton( onPressed: callback, - onLongPress: callback == null ? null : onLongPress, + onLongPress: longPress, onHover: onHover, onFocusChange: onFocusChange, style: style, focusNode: focusNode, autofocus: autofocus, - clipBehavior: clipBehavior ?? Clip.none, + clipBehavior: clip, statesController: statesController, - iconAlignment: _iconAlignment, - icon: _icon, - label: animatedChild, + child: animatedChild, ); - } - return TextButton( - onPressed: callback, - onLongPress: callback == null ? null : onLongPress, - onHover: onHover, - onFocusChange: onFocusChange, - style: style, - focusNode: focusNode, - autofocus: autofocus, - clipBehavior: clipBehavior ?? Clip.none, - statesController: statesController, - child: animatedChild, - ); - }, - ); + }, + child: child, + ); + } } diff --git a/lib/src/material_async_button_theme.dart b/lib/src/material_async_button_theme.dart index 157be79..a16ead4 100644 --- a/lib/src/material_async_button_theme.dart +++ b/lib/src/material_async_button_theme.dart @@ -1,4 +1,4 @@ -import 'package:flutter/material.dart'; +part of '../material_async_button.dart'; /// Which haptic event, if any, to fire on state transitions. enum HapticOn { none, success, error, both } @@ -9,18 +9,18 @@ enum HapticOn { none, success, error, both } /// Resolution order for any field: per-widget value, then theme value, then /// the hard-coded fallback documented on each field. /// -/// Use [MaterialAsyncButtonTheme.material] for an opinionated baseline that +/// Use [AsyncButtonTheme.material] for an opinionated baseline that /// mirrors what most apps want; otherwise build the extension yourself with /// only the fields you care about. /// /// ```dart /// MaterialApp( -/// theme: ThemeData(extensions: [MaterialAsyncButtonTheme.material()]), +/// theme: ThemeData(extensions: [AsyncButtonTheme.material()]), /// ) /// ``` @immutable -class MaterialAsyncButtonTheme extends ThemeExtension { - const MaterialAsyncButtonTheme({ +class AsyncButtonTheme extends ThemeExtension { + const AsyncButtonTheme({ this.loadingChild, this.successChild, this.errorChild, @@ -50,24 +50,26 @@ class MaterialAsyncButtonTheme extends ThemeExtension /// - 200ms cross-fade between states /// - light haptic on success and error /// - announces state changes to assistive tech - factory MaterialAsyncButtonTheme.material({ + factory AsyncButtonTheme.material({ Color? loadingColor, Color? successColor, Color? errorColor, - }) => MaterialAsyncButtonTheme( - loadingChild: _DefaultLoadingChild(color: loadingColor), - successChild: _DefaultSuccessIcon(color: successColor), - errorChild: _DefaultErrorIcon(color: errorColor), - switchDuration: const Duration(milliseconds: 200), - switchReverseDuration: const Duration(milliseconds: 200), - successDisplayDuration: const Duration(milliseconds: 800), - errorDisplayDuration: const Duration(milliseconds: 800), - animateSize: true, - hapticOn: HapticOn.both, - announceSemantics: true, - ); - - /// Shown in place of [child] while the future is in flight. + }) { + return AsyncButtonTheme( + loadingChild: _DefaultLoadingChild(color: loadingColor), + successChild: _DefaultSuccessIcon(color: successColor), + errorChild: _DefaultErrorIcon(color: errorColor), + switchDuration: const Duration(milliseconds: 200), + switchReverseDuration: const Duration(milliseconds: 200), + successDisplayDuration: const Duration(milliseconds: 800), + errorDisplayDuration: const Duration(milliseconds: 800), + animateSize: true, + hapticOn: .both, + announceSemantics: true, + ); + } + + /// Shown in place of the button's child while the future is in flight. /// Falls back to a 16x16 [CircularProgressIndicator] when null. final Widget? loadingChild; @@ -93,15 +95,15 @@ class MaterialAsyncButtonTheme extends ThemeExtension final AnimatedSwitcherTransitionBuilder? transitionBuilder; /// How long [successChild] is shown before returning to idle. Defaults to - /// [Duration.zero] (immediate return). + /// [.zero] (immediate return). final Duration? successDisplayDuration; /// How long [errorChild] is shown before returning to idle. Defaults to - /// [Duration.zero]. + /// [.zero]. final Duration? errorDisplayDuration; /// After a success/error display, keep the button disabled for this long - /// to prevent accidental double-submits. Defaults to [Duration.zero]. + /// to prevent accidental double-submits. Defaults to [.zero]. final Duration? cooldownDuration; /// Whether to animate the implicit size between state widgets of differing @@ -115,21 +117,32 @@ class MaterialAsyncButtonTheme extends ThemeExtension /// Defaults to [HapticOn.none]. final HapticOn? hapticOn; - /// Whether to announce state changes via [SemanticsService.announce]. - /// Defaults to `false`. + /// Whether to announce state changes via + /// [SemanticsService.sendAnnouncement]. Defaults to `false`. final bool? announceSemantics; /// If true, errors from `onPressed` are rethrown after the error state is /// displayed. Useful when a caller awaits the future. Defaults to `false`. final bool? rethrowErrors; - static const MaterialAsyncButtonTheme empty = MaterialAsyncButtonTheme(); + /// An extension with every field left null. Use this to opt out of the + /// opinionated [AsyncButtonTheme.material] baseline returned by [of] when + /// no extension is registered on the surrounding [ThemeData]. + static const AsyncButtonTheme empty = AsyncButtonTheme(); - static MaterialAsyncButtonTheme of(BuildContext context) => - Theme.of(context).extension() ?? empty; + static final AsyncButtonTheme _materialDefaults = AsyncButtonTheme.material(); + + /// Resolves the [AsyncButtonTheme] visible at [context]. Returns the + /// extension registered on the surrounding [ThemeData] when one exists; + /// otherwise falls back to [AsyncButtonTheme.material] so that apps + /// without explicit theming still get the spinner / check / error UX + /// out of the box. Pass [empty] to opt out. + static AsyncButtonTheme of(BuildContext context) { + return Theme.of(context).extension() ?? _materialDefaults; + } @override - MaterialAsyncButtonTheme copyWith({ + AsyncButtonTheme copyWith({ Widget? loadingChild, Widget? successChild, Widget? errorChild, @@ -149,42 +162,56 @@ class MaterialAsyncButtonTheme extends ThemeExtension HapticOn? hapticOn, bool? announceSemantics, bool? rethrowErrors, - }) => MaterialAsyncButtonTheme( - loadingChild: loadingChild ?? this.loadingChild, - successChild: successChild ?? this.successChild, - errorChild: errorChild ?? this.errorChild, - switchDuration: switchDuration ?? this.switchDuration, - switchReverseDuration: switchReverseDuration ?? this.switchReverseDuration, - switchCurve: switchCurve ?? this.switchCurve, - switchInCurve: switchInCurve ?? this.switchInCurve, - switchOutCurve: switchOutCurve ?? this.switchOutCurve, - transitionBuilder: transitionBuilder ?? this.transitionBuilder, - successDisplayDuration: successDisplayDuration ?? this.successDisplayDuration, - errorDisplayDuration: errorDisplayDuration ?? this.errorDisplayDuration, - cooldownDuration: cooldownDuration ?? this.cooldownDuration, - animateSize: animateSize ?? this.animateSize, - sizeCurve: sizeCurve ?? this.sizeCurve, - sizeAlignment: sizeAlignment ?? this.sizeAlignment, - sizeClipBehavior: sizeClipBehavior ?? this.sizeClipBehavior, - hapticOn: hapticOn ?? this.hapticOn, - announceSemantics: announceSemantics ?? this.announceSemantics, - rethrowErrors: rethrowErrors ?? this.rethrowErrors, - ); + }) { + return AsyncButtonTheme( + loadingChild: loadingChild ?? this.loadingChild, + successChild: successChild ?? this.successChild, + errorChild: errorChild ?? this.errorChild, + switchDuration: switchDuration ?? this.switchDuration, + switchReverseDuration: + switchReverseDuration ?? this.switchReverseDuration, + switchCurve: switchCurve ?? this.switchCurve, + switchInCurve: switchInCurve ?? this.switchInCurve, + switchOutCurve: switchOutCurve ?? this.switchOutCurve, + transitionBuilder: transitionBuilder ?? this.transitionBuilder, + successDisplayDuration: + successDisplayDuration ?? this.successDisplayDuration, + errorDisplayDuration: errorDisplayDuration ?? this.errorDisplayDuration, + cooldownDuration: cooldownDuration ?? this.cooldownDuration, + animateSize: animateSize ?? this.animateSize, + sizeCurve: sizeCurve ?? this.sizeCurve, + sizeAlignment: sizeAlignment ?? this.sizeAlignment, + sizeClipBehavior: sizeClipBehavior ?? this.sizeClipBehavior, + hapticOn: hapticOn ?? this.hapticOn, + announceSemantics: announceSemantics ?? this.announceSemantics, + rethrowErrors: rethrowErrors ?? this.rethrowErrors, + ); + } @override - MaterialAsyncButtonTheme lerp( - covariant ThemeExtension? other, + AsyncButtonTheme lerp( + covariant ThemeExtension? other, double t, ) { - if (other is! MaterialAsyncButtonTheme) return this; + if (other is! AsyncButtonTheme) { + return this; + } // Widgets and enums don't lerp meaningfully; snap at the halfway point. final snap = t < 0.5; - return MaterialAsyncButtonTheme( + return AsyncButtonTheme( loadingChild: snap ? loadingChild : other.loadingChild, successChild: snap ? successChild : other.successChild, errorChild: snap ? errorChild : other.errorChild, - switchDuration: _lerpDuration(switchDuration, other.switchDuration, t), - switchReverseDuration: _lerpDuration(switchReverseDuration, other.switchReverseDuration, t), + switchDuration: _lerpDuration( + switchDuration, + other.switchDuration, + t, + ), + switchReverseDuration: _lerpDuration( + switchReverseDuration, + other.switchReverseDuration, + t, + ), switchCurve: snap ? switchCurve : other.switchCurve, switchInCurve: snap ? switchInCurve : other.switchInCurve, switchOutCurve: snap ? switchOutCurve : other.switchOutCurve, @@ -194,11 +221,23 @@ class MaterialAsyncButtonTheme extends ThemeExtension other.successDisplayDuration, t, ), - errorDisplayDuration: _lerpDuration(errorDisplayDuration, other.errorDisplayDuration, t), - cooldownDuration: _lerpDuration(cooldownDuration, other.cooldownDuration, t), + errorDisplayDuration: _lerpDuration( + errorDisplayDuration, + other.errorDisplayDuration, + t, + ), + cooldownDuration: _lerpDuration( + cooldownDuration, + other.cooldownDuration, + t, + ), animateSize: snap ? animateSize : other.animateSize, sizeCurve: snap ? sizeCurve : other.sizeCurve, - sizeAlignment: AlignmentGeometry.lerp(sizeAlignment, other.sizeAlignment, t), + sizeAlignment: .lerp( + sizeAlignment, + other.sizeAlignment, + t, + ), sizeClipBehavior: snap ? sizeClipBehavior : other.sizeClipBehavior, hapticOn: snap ? hapticOn : other.hapticOn, announceSemantics: snap ? announceSemantics : other.announceSemantics, @@ -207,58 +246,63 @@ class MaterialAsyncButtonTheme extends ThemeExtension } static Duration? _lerpDuration(Duration? a, Duration? b, double t) { - if (a == null && b == null) return null; - final aMs = (a ?? Duration.zero).inMicroseconds; - final bMs = (b ?? Duration.zero).inMicroseconds; + if (a == null && b == null) { + return null; + } + final aMs = (a ?? .zero).inMicroseconds; + final bMs = (b ?? .zero).inMicroseconds; return Duration(microseconds: (aMs + (bMs - aMs) * t).round()); } @override - bool operator ==(Object other) => - identical(this, other) || - other is MaterialAsyncButtonTheme && - loadingChild == other.loadingChild && - successChild == other.successChild && - errorChild == other.errorChild && - switchDuration == other.switchDuration && - switchReverseDuration == other.switchReverseDuration && - switchCurve == other.switchCurve && - switchInCurve == other.switchInCurve && - switchOutCurve == other.switchOutCurve && - transitionBuilder == other.transitionBuilder && - successDisplayDuration == other.successDisplayDuration && - errorDisplayDuration == other.errorDisplayDuration && - cooldownDuration == other.cooldownDuration && - animateSize == other.animateSize && - sizeCurve == other.sizeCurve && - sizeAlignment == other.sizeAlignment && - sizeClipBehavior == other.sizeClipBehavior && - hapticOn == other.hapticOn && - announceSemantics == other.announceSemantics && - rethrowErrors == other.rethrowErrors; + bool operator ==(Object other) { + return identical(this, other) || + other is AsyncButtonTheme && + loadingChild == other.loadingChild && + successChild == other.successChild && + errorChild == other.errorChild && + switchDuration == other.switchDuration && + switchReverseDuration == other.switchReverseDuration && + switchCurve == other.switchCurve && + switchInCurve == other.switchInCurve && + switchOutCurve == other.switchOutCurve && + transitionBuilder == other.transitionBuilder && + successDisplayDuration == other.successDisplayDuration && + errorDisplayDuration == other.errorDisplayDuration && + cooldownDuration == other.cooldownDuration && + animateSize == other.animateSize && + sizeCurve == other.sizeCurve && + sizeAlignment == other.sizeAlignment && + sizeClipBehavior == other.sizeClipBehavior && + hapticOn == other.hapticOn && + announceSemantics == other.announceSemantics && + rethrowErrors == other.rethrowErrors; + } @override - int get hashCode => Object.hashAll([ - loadingChild, - successChild, - errorChild, - switchDuration, - switchReverseDuration, - switchCurve, - switchInCurve, - switchOutCurve, - transitionBuilder, - successDisplayDuration, - errorDisplayDuration, - cooldownDuration, - animateSize, - sizeCurve, - sizeAlignment, - sizeClipBehavior, - hapticOn, - announceSemantics, - rethrowErrors, - ]); + int get hashCode { + return Object.hashAll([ + loadingChild, + successChild, + errorChild, + switchDuration, + switchReverseDuration, + switchCurve, + switchInCurve, + switchOutCurve, + transitionBuilder, + successDisplayDuration, + errorDisplayDuration, + cooldownDuration, + animateSize, + sizeCurve, + sizeAlignment, + sizeClipBehavior, + hapticOn, + announceSemantics, + rethrowErrors, + ]); + } } class _DefaultLoadingChild extends StatelessWidget { @@ -272,7 +316,9 @@ class _DefaultLoadingChild extends StatelessWidget { dimension: 16, child: CircularProgressIndicator( strokeWidth: 2, - valueColor: color == null ? null : AlwaysStoppedAnimation(color!), + valueColor: color == null + ? null + : AlwaysStoppedAnimation(color!), ), ); } @@ -284,8 +330,12 @@ class _DefaultSuccessIcon extends StatelessWidget { final Color? color; @override - Widget build(BuildContext context) => - Icon(Icons.check, color: color ?? Theme.of(context).colorScheme.primary); + Widget build(BuildContext context) { + return Icon( + Icons.check, + color: color ?? Theme.of(context).colorScheme.primary, + ); + } } class _DefaultErrorIcon extends StatelessWidget { @@ -294,6 +344,10 @@ class _DefaultErrorIcon extends StatelessWidget { final Color? color; @override - Widget build(BuildContext context) => - Icon(Icons.error, color: color ?? Theme.of(context).colorScheme.error); + Widget build(BuildContext context) { + return Icon( + Icons.error, + color: color ?? Theme.of(context).colorScheme.error, + ); + } } diff --git a/pubspec.yaml b/pubspec.yaml index c4e9da8..f2c57cc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,8 +4,8 @@ description: >- and error states with theming via ThemeExtension and external control via a controller. version: 1.0.0 -repository: https://github.com/esenmx/async_button_builder -issue_tracker: https://github.com/esenmx/async_button_builder/issues +repository: https://github.com/esenmx/material_async_button +issue_tracker: https://github.com/esenmx/material_async_button/issues topics: - button @@ -23,14 +23,7 @@ dependencies: sdk: flutter dev_dependencies: + checks: ^0.3.1 flutter_test: sdk: flutter - flutter_lints: ^5.0.0 - -screenshots: - - description: Elevated button cycling through loading, success, and error. - path: screenshots/ezgif-7-61c436edaec2.gif - - description: State-driven background color via the builder. - path: screenshots/ezgif-7-a971c6afaabf.gif - - description: Custom Material button with bounce-in loading transition. - path: screenshots/ezgif-7-4088c909ba83.gif + very_good_analysis: ^10.2.0 diff --git a/screenshots/ezgif-7-4088c909ba83.gif b/screenshots/ezgif-7-4088c909ba83.gif deleted file mode 100644 index 6b6f42efdf03883c847f8dc026cbebd45d9ef6f0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 119599 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

+y0HQ%F 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 Q?vy32bz*NQ8L;~Q0J_7Ca{vGU literal 0 HcmV?d00001 diff --git a/screenshots/ezgif-7-61c436edaec2.gif b/screenshots/ezgif-7-61c436edaec2.gif new file mode 100644 index 0000000000000000000000000000000000000000..d2dce9ddc68231c765294ab2ac27adf6245a9d79 GIT binary patch literal 53098 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 literal 0 HcmV?d00001 diff --git a/screenshots/ezgif-7-a971c6afaabf.gif b/screenshots/ezgif-7-a971c6afaabf.gif new file mode 100644 index 0000000000000000000000000000000000000000..bf0cb619ace04c33bc18ef53e1be74ab6ee33ee1 GIT binary patch literal 80732 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 q$2UkDUh@ykg_i%AS9IfOPCWO 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 z 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 literal 0 HcmV?d00001 From 836fd72bdd865352764f311cc302d097f77fa5c1 Mon Sep 17 00:00:00 2001 From: Nolence Date: Mon, 25 Jan 2021 21:30:14 -0700 Subject: [PATCH 015/176] Fixed wrong path --- CHANGELOG.md | 3 +++ README.md | 2 +- example/pubspec.lock | 2 +- pubspec.yaml | 4 ++-- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 113e65f..5b6f742 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## [2.0.2-nullsafety.2] - 2021-01-25 +Fixes wrong image path + ## [2.0.1-nullsafety.2] - 2021-01-25 Renames fields to better match standards of other buttons. diff --git a/README.md b/README.md index 25f0ffe..64f05b1 100644 --- a/README.md +++ b/README.md @@ -145,7 +145,7 @@ AsyncButtonBuilder( ```

~7AIb0+(VM->z;^o8 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 z

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

VHNKN}q8pLwbU^d+dPsjHE$ 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

+y0HQ%F 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 Q?vy32bz*NQ8L;~Q0J_7Ca{vGU diff --git a/screenshots/ezgif-7-61c436edaec2.gif b/screenshots/ezgif-7-61c436edaec2.gif deleted file mode 100644 index d2dce9ddc68231c765294ab2ac27adf6245a9d79..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53098 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 diff --git a/screenshots/ezgif-7-a971c6afaabf.gif b/screenshots/ezgif-7-a971c6afaabf.gif deleted file mode 100644 index bf0cb619ace04c33bc18ef53e1be74ab6ee33ee1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 80732 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 q$2UkDUh@ykg_i%AS9IfOPCWO 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 z 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 diff --git a/test/_helpers.dart b/test/_helpers.dart new file mode 100644 index 0000000..594226c --- /dev/null +++ b/test/_helpers.dart @@ -0,0 +1,71 @@ +import 'dart:async'; + +import 'package:checks/checks.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:material_async_button/material_async_button.dart'; + +/// Wraps a widget in a minimal MaterialApp + Scaffold for testing. +/// +/// Defaults to a [ThemeData] carrying [AsyncButtonTheme.empty] so the tests +/// see the per-widget / hard-coded fallbacks instead of the opinionated +/// [AsyncButtonTheme.material] baseline that `AsyncButtonTheme.of` returns +/// when no extension is registered. +Widget pumpHost(Widget child, {ThemeData? theme}) { + return MaterialApp( + theme: theme ?? ThemeData(extensions: const [AsyncButtonTheme.empty]), + home: Scaffold( + body: Center(child: child), + ), + ); +} + +/// Returns an `(onPressed, completer)` pair. Caller drives the button into +/// loading and decides when to complete or fail. +({AsyncCallback onPressed, Completer completer}) pendingPress() { + final completer = Completer(); + return (onPressed: () => completer.future, completer: completer); +} + +/// Controller pre-attached with `onPressed`/durations. Auto-disposes. +AsyncButtonController attachedController({ + AsyncCallback? onPressed, + Duration successDuration = .zero, + Duration errorDuration = .zero, + Duration cooldownDuration = .zero, + bool rethrowErrors = false, +}) { + final c = AsyncButtonController() + ..attach( + onPressed: onPressed, + successDuration: successDuration, + errorDuration: errorDuration, + cooldownDuration: cooldownDuration, + rethrowErrors: rethrowErrors, + ); + addTearDown(c.dispose); + return c; +} + +/// Builder that renders a [TextButton] driven by the AsyncButton callback. +Widget textBuilder(_, Widget child, AsyncCallback? cb, _) { + return TextButton(onPressed: cb, child: child); +} + +/// `checks`-style assertions for [Finder]. +extension FinderChecks on Subject { + void findsOne() => has((f) => f.evaluate().length, 'matches').equals(1); + void findsNone() => has((f) => f.evaluate(), 'matches').isEmpty(); + void findsMany([int min = 1]) => + has((f) => f.evaluate().length, 'matches').isGreaterOrEqual(min); +} + +/// `checks`-style assertions for [AsyncButtonController]. +extension AsyncButtonControllerChecks on Subject { + void hasStatus(AsyncButtonStatus expected) => + has((c) => c.value, 'value').equals(expected); + void isIdle() => hasStatus(const .idle()); + void isLoading() => hasStatus(const .loading()); + void isSuccess() => hasStatus(const .success()); +} diff --git a/test/async_button_builder_test.dart b/test/async_button_builder_test.dart deleted file mode 100644 index 629ce6e..0000000 --- a/test/async_button_builder_test.dart +++ /dev/null @@ -1,392 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:material_async_button/material_async_button.dart'; - -Widget _wrap(Widget child) => MaterialApp( - home: Scaffold(body: Center(child: child)), -); - -void main() { - group('AsyncButtonBuilder rendering', () { - testWidgets('shows child in idle state', (tester) async { - await tester.pumpWidget( - _wrap( - AsyncButtonBuilder( - onPressed: () async {}, - child: const Text('hello'), - builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), - ), - ), - ); - expect(find.text('hello'), findsOneWidget); - }); - - testWidgets('falls back to built-in spinner when no loadingChild', (tester) async { - final completer = Completer(); - await tester.pumpWidget( - _wrap( - AsyncButtonBuilder( - onPressed: () => completer.future, - child: const Text('go'), - builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), - ), - ), - ); - await tester.tap(find.byType(TextButton)); - await tester.pump(); - expect(find.byType(CircularProgressIndicator), findsOneWidget); - completer.complete(); - await tester.pumpAndSettle(); - }); - - testWidgets('uses per-widget loadingChild when given', (tester) async { - final completer = Completer(); - await tester.pumpWidget( - _wrap( - AsyncButtonBuilder( - onPressed: () => completer.future, - loadingChild: const Text('spinning'), - builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), - child: const Text('go'), - ), - ), - ); - await tester.tap(find.byType(TextButton)); - await tester.pump(); - expect(find.text('spinning'), findsOneWidget); - completer.complete(); - await tester.pumpAndSettle(); - }); - - testWidgets('theme loadingChild used when no per-widget override', (tester) async { - final completer = Completer(); - await tester.pumpWidget( - MaterialApp( - theme: ThemeData( - extensions: const [MaterialAsyncButtonTheme(loadingChild: Text('themed-loading'))], - ), - home: Scaffold( - body: AsyncButtonBuilder( - onPressed: () => completer.future, - child: const Text('go'), - builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), - ), - ), - ), - ); - await tester.tap(find.byType(TextButton)); - await tester.pump(); - expect(find.text('themed-loading'), findsOneWidget); - completer.complete(); - await tester.pumpAndSettle(); - }); - - testWidgets('widget loadingChild beats theme', (tester) async { - final completer = Completer(); - await tester.pumpWidget( - MaterialApp( - theme: ThemeData( - extensions: const [MaterialAsyncButtonTheme(loadingChild: Text('themed'))], - ), - home: Scaffold( - body: AsyncButtonBuilder( - onPressed: () => completer.future, - loadingChild: const Text('widget'), - builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), - child: const Text('go'), - ), - ), - ), - ); - await tester.tap(find.byType(TextButton)); - await tester.pump(); - expect(find.text('widget'), findsOneWidget); - expect(find.text('themed'), findsNothing); - completer.complete(); - await tester.pumpAndSettle(); - }); - }); - - group('AsyncButtonBuilder transitions', () { - testWidgets('returns to child after success with zero display duration', (tester) async { - await tester.pumpWidget( - _wrap( - AsyncButtonBuilder( - onPressed: () async {}, - child: const Text('label'), - builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), - ), - ), - ); - await tester.tap(find.byType(TextButton)); - await tester.pumpAndSettle(); - expect(find.text('label'), findsOneWidget); - }); - - testWidgets('shows successChild for successDisplayDuration', (tester) async { - await tester.pumpWidget( - _wrap( - AsyncButtonBuilder( - onPressed: () async {}, - successChild: const Text('done!'), - successDisplayDuration: const Duration(milliseconds: 200), - builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), - child: const Text('label'), - ), - ), - ); - await tester.tap(find.byType(TextButton)); - await tester.pump(); - await tester.pump(); - expect(find.text('done!'), findsOneWidget); - await tester.pump(const Duration(milliseconds: 250)); - await tester.pumpAndSettle(); - expect(find.text('done!'), findsNothing); - expect(find.text('label'), findsOneWidget); - }); - - testWidgets('shows errorChild and exposes error to errorBuilder', (tester) async { - Object? observed; - await tester.pumpWidget( - _wrap( - AsyncButtonBuilder( - onPressed: () async => throw StateError('boom'), - errorDisplayDuration: const Duration(milliseconds: 100), - errorBuilder: (c, err, st) { - observed = err; - return Text('err: ${err.toString().split(":").last.trim()}'); - }, - builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), - child: const Text('label'), - ), - ), - ); - await tester.tap(find.byType(TextButton)); - await tester.pump(); - await tester.pump(); - expect(observed, isA()); - expect(find.textContaining('err:'), findsOneWidget); - await tester.pump(const Duration(milliseconds: 200)); - await tester.pumpAndSettle(); - }); - }); - - group('AsyncButtonBuilder callbacks', () { - testWidgets('callback null when disabled', (tester) async { - await tester.pumpWidget( - _wrap( - AsyncButtonBuilder( - onPressed: () async {}, - disabled: true, - child: const Text('label'), - builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), - ), - ), - ); - final btn = tester.widget(find.byType(TextButton)); - expect(btn.onPressed, isNull); - }); - - testWidgets('callback null when onPressed is null', (tester) async { - await tester.pumpWidget( - _wrap( - AsyncButtonBuilder( - onPressed: null, - child: const Text('label'), - builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), - ), - ), - ); - final btn = tester.widget(find.byType(TextButton)); - expect(btn.onPressed, isNull); - }); - - testWidgets('onSuccess and onStateChanged fire', (tester) async { - var successCount = 0; - final changes = []; - await tester.pumpWidget( - _wrap( - AsyncButtonBuilder( - onPressed: () async {}, - onSuccess: () => successCount++, - onStateChanged: changes.add, - child: const Text('label'), - builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), - ), - ), - ); - await tester.tap(find.byType(TextButton)); - await tester.pumpAndSettle(); - expect(successCount, 1); - expect( - changes.map((s) => s.runtimeType), - containsAllInOrder([ - AsyncButtonStateLoading, - AsyncButtonStateSuccess, - AsyncButtonStateIdle, - ]), - ); - }); - - testWidgets('onError fires with the thrown error', (tester) async { - Object? captured; - await tester.pumpWidget( - _wrap( - AsyncButtonBuilder( - onPressed: () async => throw StateError('x'), - onError: (e, _) => captured = e, - child: const Text('label'), - builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), - ), - ), - ); - await tester.tap(find.byType(TextButton)); - await tester.pumpAndSettle(); - expect(captured, isA()); - }); - - testWidgets('confirmBeforePress can cancel the press', (tester) async { - var ran = 0; - await tester.pumpWidget( - _wrap( - AsyncButtonBuilder( - onPressed: () async => ran++, - confirmBeforePress: (_) async => false, - child: const Text('label'), - builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), - ), - ), - ); - await tester.tap(find.byType(TextButton)); - await tester.pumpAndSettle(); - expect(ran, 0, reason: 'onPressed should not run when confirm returns false.'); - }); - }); - - group('AsyncButtonBuilder external control', () { - testWidgets('GlobalKey.trigger() runs onPressed', (tester) async { - final key = GlobalKey(); - var ran = 0; - await tester.pumpWidget( - _wrap( - AsyncButtonBuilder( - key: key, - onPressed: () async => ran++, - child: const Text('label'), - builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), - ), - ), - ); - await key.currentState!.trigger(); - await tester.pumpAndSettle(); - expect(ran, 1); - }); - - testWidgets('AsyncButtonController.invalidate flips to error', (tester) async { - final controller = AsyncButtonController(); - addTearDown(controller.dispose); - await tester.pumpWidget( - _wrap( - AsyncButtonBuilder( - controller: controller, - onPressed: () async {}, - errorChild: const Text('errored'), - errorDisplayDuration: const Duration(milliseconds: 100), - builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), - child: const Text('label'), - ), - ), - ); - controller.invalidate('bad'); - await tester.pump(); - expect(find.text('errored'), findsOneWidget); - await tester.pump(const Duration(milliseconds: 200)); - await tester.pumpAndSettle(); - }); - - testWidgets('AsyncButtonController.reset clears mid-display', (tester) async { - final controller = AsyncButtonController(); - addTearDown(controller.dispose); - await tester.pumpWidget( - _wrap( - AsyncButtonBuilder( - controller: controller, - onPressed: () async {}, - successChild: const Text('yay'), - successDisplayDuration: const Duration(seconds: 5), - builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), - child: const Text('label'), - ), - ), - ); - controller.markSuccess(); - await tester.pump(); - expect(find.text('yay'), findsOneWidget); - controller.reset(); - await tester.pump(); - expect(find.text('label'), findsOneWidget); - }); - - testWidgets('swapping the external controller transfers listening without leak', ( - tester, - ) async { - final a = AsyncButtonController(); - final b = AsyncButtonController(); - addTearDown(() { - a.dispose(); - b.dispose(); - }); - AsyncButtonBuilder builder(AsyncButtonController c) => AsyncButtonBuilder( - controller: c, - onPressed: () async {}, - successChild: const Text('done'), - successDisplayDuration: const Duration(milliseconds: 100), - builder: (ctx, child, cb, _) => TextButton(onPressed: cb, child: child), - child: const Text('child'), - ); - await tester.pumpWidget(_wrap(builder(a))); - await tester.pumpWidget(_wrap(builder(b))); - // Mutating the OLD controller must not change the UI. - a.markSuccess(); - await tester.pump(); - expect(find.text('done'), findsNothing); - // New controller drives the UI. - b.markSuccess(); - await tester.pump(); - expect(find.text('done'), findsOneWidget); - await tester.pump(const Duration(milliseconds: 200)); - await tester.pumpAndSettle(); - }); - }); - - group('AsyncButtonBuilder timer hygiene (regression for old timer race)', () { - testWidgets('rapid invalidate then reset does not later re-flip to idle', (tester) async { - final controller = AsyncButtonController(); - addTearDown(controller.dispose); - await tester.pumpWidget( - _wrap( - AsyncButtonBuilder( - controller: controller, - onPressed: () async {}, - errorChild: const Text('e'), - errorDisplayDuration: const Duration(milliseconds: 200), - builder: (c, child, cb, _) => TextButton(onPressed: cb, child: child), - child: const Text('child'), - ), - ), - ); - controller.invalidate('1'); - await tester.pump(); - // While in error display, manually mark success. The previous error - // timer must NOT fire and overwrite the new success state. - controller.markSuccess(); - await tester.pump(); - // Wait beyond the original error timer, less than success timer. - await tester.pump(const Duration(milliseconds: 250)); - // Default success duration is zero, so we should be back to idle. - expect(find.text('child'), findsOneWidget); - }); - }); -} diff --git a/test/async_button_controller_test.dart b/test/async_button_controller_test.dart index f372175..9b402a7 100644 --- a/test/async_button_controller_test.dart +++ b/test/async_button_controller_test.dart @@ -1,292 +1,224 @@ import 'dart:async'; +import 'package:checks/checks.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:material_async_button/material_async_button.dart'; +import '_helpers.dart'; + +/// Subscribes a status-recording listener to [c]; returns the recording list. +List recordStatuses(AsyncButtonController c) { + final out = []; + c.addListener(() => out.add(c.value)); + return out; +} + void main() { - group('AsyncButtonController', () { - test('starts in idle by default', () { + group('AsyncButtonController basics', () { + test('starts idle by default with no onPressed', () { final c = AsyncButtonController(); - expect(c.value, const AsyncButtonState.idle()); - expect(c.isIdle, isTrue); - expect(c.isLoading, isFalse); - expect(c.canTrigger, isFalse, reason: 'No onPressed attached yet, cannot trigger.'); - c.dispose(); + addTearDown(c.dispose); + check(c) + ..isIdle() + ..has((it) => it.canTrigger, 'canTrigger').isFalse(); }); - test('honors initial state', () { - final c = AsyncButtonController(initial: const AsyncButtonState.loading()); - expect(c.isLoading, isTrue); - c.dispose(); + test('honors initial status', () { + final c = AsyncButtonController(const .loading()); + addTearDown(c.dispose); + check(c).isLoading(); }); test('trigger no-ops when no onPressed is attached', () async { final c = AsyncButtonController(); + addTearDown(c.dispose); await c.trigger(); - expect(c.isIdle, isTrue); - c.dispose(); + check(c).isIdle(); }); + }); - test('reset moves to idle and cancels timer', () async { - final c = AsyncButtonController() - ..attach( - onPressed: () async {}, - successDuration: const Duration(seconds: 5), - errorDuration: Duration.zero, - cooldownDuration: Duration.zero, - rethrowErrors: false, - ); + group('AsyncButtonController forced transitions', () { + test('reset returns to idle and cancels pending display', () async { + final c = attachedController( + onPressed: () async {}, + successDuration: const Duration(seconds: 5), + ); await c.trigger(); - // We're now in success state for 5s. Reset short-circuits. - expect(c.isSuccess, isTrue); + check(c).isSuccess(); c.reset(); - expect(c.isIdle, isTrue); - c.dispose(); + check(c).isIdle(); }); - test('invalidate forces error and reaches idle when duration zero', () async { - final c = AsyncButtonController() - ..attach( - onPressed: null, - successDuration: Duration.zero, - errorDuration: Duration.zero, - cooldownDuration: Duration.zero, - rethrowErrors: false, - ); - c.invalidate('bad'); - expect( - c.value, - const AsyncButtonState.idle(), - reason: 'Zero error duration returns straight to idle.', - ); - c.dispose(); + test('invalidate with zero duration returns straight to idle', () { + final c = attachedController()..invalidate('bad'); + check(c).isIdle(); }); - test('invalidate forces error and stays there for errorDuration', () async { - final c = AsyncButtonController() - ..attach( - onPressed: null, - successDuration: Duration.zero, - errorDuration: const Duration(milliseconds: 50), - cooldownDuration: Duration.zero, - rethrowErrors: false, - ); - c.invalidate('bad'); - expect(c.isError, isTrue); - expect(c.error, 'bad'); + test('invalidate holds error until errorDuration elapses', () async { + final c = attachedController( + errorDuration: const Duration(milliseconds: 50), + )..invalidate('bad'); + check(c.value) + .isA() + .has((f) => f.error, 'error') + .equals('bad'); await Future.delayed(const Duration(milliseconds: 70)); - expect(c.isIdle, isTrue); - c.dispose(); + check(c).isIdle(); }); - test('markSuccess forces success state', () { - final c = AsyncButtonController() - ..attach( - onPressed: null, - successDuration: const Duration(seconds: 5), - errorDuration: Duration.zero, - cooldownDuration: Duration.zero, - rethrowErrors: false, - ); - c.markSuccess(); - expect(c.isSuccess, isTrue); - c.dispose(); + test('markSuccess forces success', () { + final c = attachedController( + successDuration: const Duration(seconds: 5), + )..markSuccess(); + check(c).isSuccess(); }); + }); - test('successful trigger transitions idle -> loading -> success -> idle', () async { - final transitions = []; - final c = AsyncButtonController() - ..attach( - onPressed: () async => Future.delayed(const Duration(milliseconds: 20)), - successDuration: const Duration(milliseconds: 20), - errorDuration: Duration.zero, - cooldownDuration: Duration.zero, - rethrowErrors: false, - ); - c.addListener(() => transitions.add(c.value)); + group('AsyncButtonController.trigger', () { + test('successful run traces loading -> success -> idle', () async { + final c = attachedController( + onPressed: () => Future.delayed(const Duration(milliseconds: 20)), + successDuration: const Duration(milliseconds: 20), + ); + final transitions = recordStatuses(c); await c.trigger(); - // trigger awaited onPressed. Success has fired; idle is scheduled in 20ms. await Future.delayed(const Duration(milliseconds: 50)); - expect( - transitions.map((s) => s.runtimeType).toList(), - containsAllInOrder([ - AsyncButtonStateLoading, - AsyncButtonStateSuccess, - AsyncButtonStateIdle, - ]), - ); - c.dispose(); + check(transitions.map((s) => s.runtimeType).toList()) + ..contains(AsyncButtonStatusLoading) + ..contains(AsyncButtonStatusSuccess) + ..contains(AsyncButtonStatusIdle); }); - test('failing trigger transitions idle -> loading -> error -> idle', () async { - final transitions = []; - final c = AsyncButtonController() - ..attach( - onPressed: () async => throw StateError('oops'), - successDuration: Duration.zero, - errorDuration: const Duration(milliseconds: 20), - cooldownDuration: Duration.zero, - rethrowErrors: false, - ); - c.addListener(() => transitions.add(c.value)); + test('failing run traces loading -> error -> idle', () async { + final c = attachedController( + onPressed: () async => throw StateError('oops'), + errorDuration: const Duration(milliseconds: 20), + ); + final transitions = recordStatuses(c); await c.trigger(); await Future.delayed(const Duration(milliseconds: 50)); - expect( - transitions.map((s) => s.runtimeType).toList(), - containsAllInOrder([ - AsyncButtonStateLoading, - AsyncButtonStateError, - AsyncButtonStateIdle, - ]), + check(transitions.map((s) => s.runtimeType).toList()) + ..contains(AsyncButtonStatusLoading) + ..contains(AsyncButtonStatusError) + ..contains(AsyncButtonStatusIdle); + }); + + test('error variant carries the thrown error and stack trace', () async { + final c = attachedController( + onPressed: () async => throw StateError('oops'), + errorDuration: const Duration(milliseconds: 50), ); - c.dispose(); + await c.trigger(); + check(c.value) + .isA() + .has((f) => f.error, 'error') + .isA(); + check(c.value) + .isA() + .has((f) => f.stackTrace, 'stackTrace') + .isNotNull(); + await Future.delayed(const Duration(milliseconds: 70)); + check(c).isIdle(); }); test('rethrowErrors=true bubbles the error to the caller', () async { - final c = AsyncButtonController() - ..attach( - onPressed: () async => throw StateError('oops'), - successDuration: Duration.zero, - errorDuration: Duration.zero, - cooldownDuration: Duration.zero, - rethrowErrors: true, - ); - await expectLater(c.trigger(), throwsA(isA())); - c.dispose(); + final c = attachedController( + onPressed: () async => throw StateError('oops'), + rethrowErrors: true, + ); + await check(c.trigger()).throws(); }); - test('cooldown keeps canTrigger false after idle returns', () async { - final c = AsyncButtonController() - ..attach( - onPressed: () async {}, - successDuration: Duration.zero, - errorDuration: Duration.zero, - cooldownDuration: const Duration(milliseconds: 40), - rethrowErrors: false, - ); + test('cooldown keeps canTrigger false after returning to idle', () async { + final c = attachedController( + onPressed: () async {}, + cooldownDuration: const Duration(milliseconds: 40), + ); await c.trigger(); - expect(c.isIdle, isTrue); - expect(c.isInCooldown, isTrue); - expect(c.canTrigger, isFalse); + check(c) + ..isIdle() + ..has((it) => it.isInCooldown, 'isInCooldown').isTrue() + ..has((it) => it.canTrigger, 'canTrigger').isFalse(); await Future.delayed(const Duration(milliseconds: 60)); - expect(c.isInCooldown, isFalse); - expect(c.canTrigger, isTrue); - c.dispose(); + check(c) + ..has((it) => it.isInCooldown, 'isInCooldown').isFalse() + ..has((it) => it.canTrigger, 'canTrigger').isTrue(); }); - test('disposes cleanly without throwing for pending timers', () async { - final c = AsyncButtonController() + test('dispose does not throw for pending timers', () async { + AsyncButtonController() ..attach( onPressed: null, successDuration: const Duration(seconds: 5), - errorDuration: Duration.zero, - cooldownDuration: Duration.zero, + errorDuration: .zero, + cooldownDuration: .zero, rethrowErrors: false, - ); - c.markSuccess(); - c.dispose(); - // Wait beyond the timer schedule; the disposed flag should suppress - // notifyListeners on the post-dispose callback. + ) + ..markSuccess() + ..dispose(); await Future.delayed(const Duration(milliseconds: 10)); }); }); - group('AsyncButtonController concurrent calls', () { + group('AsyncButtonController concurrency', () { test('trigger is a no-op while already loading', () async { var calls = 0; final completer = Completer(); - final c = AsyncButtonController() - ..attach( - onPressed: () async { - calls++; - await completer.future; - }, - successDuration: Duration.zero, - errorDuration: Duration.zero, - cooldownDuration: Duration.zero, - rethrowErrors: false, - ); - // First trigger starts loading. + final c = attachedController( + onPressed: () async { + calls++; + await completer.future; + }, + ); final f1 = c.trigger(); - // Second trigger should no-op because state is loading. final f2 = c.trigger(); - expect(c.isLoading, isTrue); + check(c).isLoading(); completer.complete(); await Future.wait([f1, f2]); - expect(calls, 1); - c.dispose(); + check(calls).equals(1); }); test('reset mid-onPressed stops the success transition', () async { final completer = Completer(); - final c = AsyncButtonController() - ..attach( - onPressed: () async => completer.future, - successDuration: Duration.zero, - errorDuration: Duration.zero, - cooldownDuration: Duration.zero, - rethrowErrors: false, - ); + final c = attachedController(onPressed: () => completer.future); final f = c.trigger(); - expect(c.isLoading, isTrue); + check(c).isLoading(); c.reset(); completer.complete(); await f; - // Should remain idle; trigger's post-await branch sees non-loading and bails. - expect(c.isIdle, isTrue); - c.dispose(); - }); - }); - - group('AsyncButtonController utility getters', () { - test('error/stackTrace getters return null off-error', () { - final c = AsyncButtonController(); - expect(c.error, isNull); - expect(c.stackTrace, isNull); - c.dispose(); - }); - - test('error/stackTrace getters expose the error variant payload', () { - final st = StackTrace.current; - final c = AsyncButtonController(initial: AsyncButtonState.error('boom', st)); - expect(c.error, 'boom'); - expect(c.stackTrace, st); - c.dispose(); + check(c).isIdle(); }); }); - testWidgets('value listenable interop with ValueListenableBuilder', (tester) async { - final c = AsyncButtonController() - ..attach( - onPressed: null, + group('AsyncButtonController interop', () { + testWidgets('exposes a ValueListenable', (tester) async { + final c = attachedController( successDuration: const Duration(seconds: 5), - errorDuration: Duration.zero, - cooldownDuration: Duration.zero, - rethrowErrors: false, ); - addTearDown(c.dispose); - String label(AsyncButtonState s) => switch (s) { - AsyncButtonStateIdle() => 'idle', - AsyncButtonStateLoading() => 'loading', - AsyncButtonStateSuccess() => 'success', - AsyncButtonStateError() => 'error', - }; - - await tester.pumpWidget( - MaterialApp( - home: ValueListenableBuilder( - valueListenable: c, - builder: (_, state, __) => Text(label(state), textDirection: TextDirection.ltr), + await tester.pumpWidget( + MaterialApp( + home: ValueListenableBuilder( + valueListenable: c, + builder: (context, status, child) => Text( + switch (status) { + AsyncButtonStatusIdle() => 'idle', + AsyncButtonStatusLoading() => 'loading', + AsyncButtonStatusSuccess() => 'success', + AsyncButtonStatusError() => 'error', + }, + textDirection: .ltr, + ), + ), ), - ), - ); - expect(find.text('idle'), findsOneWidget); + ); + check(find.text('idle')).findsOne(); - c.markSuccess(); - await tester.pump(); - expect(find.text('success'), findsOneWidget); - c.reset(); + c.markSuccess(); + await tester.pump(); + check(find.text('success')).findsOne(); + c.reset(); + }); }); } diff --git a/test/async_button_state_test.dart b/test/async_button_state_test.dart deleted file mode 100644 index 857ded4..0000000 --- a/test/async_button_state_test.dart +++ /dev/null @@ -1,66 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:material_async_button/material_async_button.dart'; - -void main() { - group('AsyncButtonState equality', () { - test('idle equals idle', () { - expect(const AsyncButtonState.idle(), const AsyncButtonState.idle()); - expect(const AsyncButtonState.idle().hashCode, const AsyncButtonState.idle().hashCode); - }); - - test('loading equals loading', () { - expect(const AsyncButtonState.loading(), const AsyncButtonState.loading()); - }); - - test('success equals success', () { - expect(const AsyncButtonState.success(), const AsyncButtonState.success()); - }); - - test('error equals error by error object', () { - final e = Exception('boom'); - expect(AsyncButtonState.error(e), AsyncButtonState.error(e)); - // Different errors are not equal. - expect( - AsyncButtonState.error(Exception('a')) == AsyncButtonState.error(Exception('a')), - isFalse, - reason: 'Two distinct Exception instances are not equal in Dart.', - ); - }); - - test('different variants are not equal', () { - expect(const AsyncButtonState.idle() == const AsyncButtonState.loading(), isFalse); - expect(const AsyncButtonState.success() == const AsyncButtonState.idle(), isFalse); - }); - }); - - group('AsyncButtonState toString', () { - test('readable identifiers', () { - expect(const AsyncButtonState.idle().toString(), 'AsyncButtonState.idle()'); - expect(const AsyncButtonState.loading().toString(), 'AsyncButtonState.loading()'); - expect(const AsyncButtonState.success().toString(), 'AsyncButtonState.success()'); - expect(const AsyncButtonState.error('boom').toString(), 'AsyncButtonState.error(boom)'); - }); - }); - - group('AsyncButtonState pattern matching', () { - test('exhaustive switch compiles and dispatches', () { - String describe(AsyncButtonState s) => switch (s) { - AsyncButtonStateIdle() => 'idle', - AsyncButtonStateLoading() => 'loading', - AsyncButtonStateSuccess() => 'success', - AsyncButtonStateError() => 'error', - }; - expect(describe(const AsyncButtonState.idle()), 'idle'); - expect(describe(const AsyncButtonState.loading()), 'loading'); - expect(describe(const AsyncButtonState.success()), 'success'); - expect(describe(const AsyncButtonState.error('x')), 'error'); - }); - - test('error variant exposes error and stack trace', () { - final st = StackTrace.current; - final s = AsyncButtonStateError('boom', st); - expect(s.error, 'boom'); - expect(s.stackTrace, st); - }); - }); -} diff --git a/test/async_button_test.dart b/test/async_button_test.dart new file mode 100644 index 0000000..757359f --- /dev/null +++ b/test/async_button_test.dart @@ -0,0 +1,401 @@ +import 'package:checks/checks.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:material_async_button/material_async_button.dart'; + +import '_helpers.dart'; + +void main() { + group('AsyncButton rendering', () { + testWidgets('shows child in idle state', (tester) async { + await tester.pumpWidget( + pumpHost( + AsyncButton( + onPressed: () async {}, + builder: textBuilder, + child: const Text('hello'), + ), + ), + ); + check(find.text('hello')).findsOne(); + }); + + testWidgets('falls back to built-in spinner when no loadingChild', ( + tester, + ) async { + final (:onPressed, :completer) = pendingPress(); + await tester.pumpWidget( + pumpHost( + AsyncButton( + onPressed: onPressed, + builder: textBuilder, + child: const Text('go'), + ), + ), + ); + await tester.tap(find.byType(TextButton)); + await tester.pump(); + check(find.byType(CircularProgressIndicator)).findsOne(); + completer.complete(); + await tester.pumpAndSettle(); + }); + + testWidgets('uses per-widget loadingChild when given', (tester) async { + final (:onPressed, :completer) = pendingPress(); + await tester.pumpWidget( + pumpHost( + AsyncButton( + onPressed: onPressed, + loadingChild: const Text('spinning'), + builder: textBuilder, + child: const Text('go'), + ), + ), + ); + await tester.tap(find.byType(TextButton)); + await tester.pump(); + check(find.text('spinning')).findsOne(); + completer.complete(); + await tester.pumpAndSettle(); + }); + + testWidgets('theme loadingChild used when no per-widget override', ( + tester, + ) async { + final (:onPressed, :completer) = pendingPress(); + await tester.pumpWidget( + pumpHost( + AsyncButton( + onPressed: onPressed, + builder: textBuilder, + child: const Text('go'), + ), + theme: ThemeData( + extensions: const [ + AsyncButtonTheme(loadingChild: Text('themed-loading')), + ], + ), + ), + ); + await tester.tap(find.byType(TextButton)); + await tester.pump(); + check(find.text('themed-loading')).findsOne(); + completer.complete(); + await tester.pumpAndSettle(); + }); + + testWidgets('widget loadingChild beats theme', (tester) async { + final (:onPressed, :completer) = pendingPress(); + await tester.pumpWidget( + pumpHost( + AsyncButton( + onPressed: onPressed, + loadingChild: const Text('widget'), + builder: textBuilder, + child: const Text('go'), + ), + theme: ThemeData( + extensions: const [ + AsyncButtonTheme(loadingChild: Text('themed')), + ], + ), + ), + ); + await tester.tap(find.byType(TextButton)); + await tester.pump(); + check(find.text('widget')).findsOne(); + check(find.text('themed')).findsNone(); + completer.complete(); + await tester.pumpAndSettle(); + }); + }); + + group('AsyncButton transitions', () { + testWidgets('returns to child after success with zero display duration', ( + tester, + ) async { + await tester.pumpWidget( + pumpHost( + AsyncButton( + onPressed: () async {}, + builder: textBuilder, + child: const Text('label'), + ), + ), + ); + await tester.tap(find.byType(TextButton)); + await tester.pumpAndSettle(); + check(find.text('label')).findsOne(); + }); + + testWidgets('shows successChild for successDisplayDuration', ( + tester, + ) async { + await tester.pumpWidget( + pumpHost( + AsyncButton( + onPressed: () async {}, + successChild: const Text('done!'), + successDisplayDuration: const Duration(milliseconds: 200), + builder: textBuilder, + child: const Text('label'), + ), + ), + ); + await tester.tap(find.byType(TextButton)); + await tester.pump(); + await tester.pump(); + check(find.text('done!')).findsOne(); + await tester.pump(const Duration(milliseconds: 250)); + await tester.pumpAndSettle(); + check(find.text('done!')).findsNone(); + check(find.text('label')).findsOne(); + }); + + testWidgets('shows errorChild during error status', (tester) async { + await tester.pumpWidget( + pumpHost( + AsyncButton( + onPressed: () async => throw StateError('boom'), + errorChild: const Text('errored'), + errorDisplayDuration: const Duration(milliseconds: 100), + builder: textBuilder, + child: const Text('label'), + ), + ), + ); + await tester.tap(find.byType(TextButton)); + await tester.pump(); + await tester.pump(); + check(find.text('errored')).findsOne(); + await tester.pump(const Duration(milliseconds: 200)); + await tester.pumpAndSettle(); + }); + + testWidgets('onError carries the thrown error payload', (tester) async { + Object? captured; + await tester.pumpWidget( + pumpHost( + AsyncButton( + onPressed: () async => throw StateError('x'), + onError: (e, _) => captured = e, + builder: textBuilder, + child: const Text('label'), + ), + ), + ); + await tester.tap(find.byType(TextButton)); + await tester.pumpAndSettle(); + check(captured).isA(); + }); + }); + + group('AsyncButton callbacks', () { + testWidgets('callback null when disabled', (tester) async { + await tester.pumpWidget( + pumpHost( + AsyncButton( + onPressed: () async {}, + disabled: true, + builder: textBuilder, + child: const Text('label'), + ), + ), + ); + final btn = tester.widget(find.byType(TextButton)); + check(btn.onPressed).isNull(); + }); + + testWidgets('callback null when onPressed is null', (tester) async { + await tester.pumpWidget( + pumpHost( + const AsyncButton( + onPressed: null, + builder: textBuilder, + child: Text('label'), + ), + ), + ); + final btn = tester.widget(find.byType(TextButton)); + check(btn.onPressed).isNull(); + }); + + testWidgets('onSuccess and onStateChanged fire', (tester) async { + var successCount = 0; + final statuses = []; + await tester.pumpWidget( + pumpHost( + AsyncButton( + onPressed: () async {}, + onSuccess: () => successCount++, + onStateChanged: statuses.add, + builder: textBuilder, + child: const Text('label'), + ), + ), + ); + await tester.tap(find.byType(TextButton)); + await tester.pumpAndSettle(); + check(successCount).equals(1); + check(statuses.map((s) => s.runtimeType).toList()) + ..contains(AsyncButtonStatusLoading) + ..contains(AsyncButtonStatusSuccess) + ..contains(AsyncButtonStatusIdle); + }); + + testWidgets('onError fires with the thrown error', (tester) async { + Object? captured; + await tester.pumpWidget( + pumpHost( + AsyncButton( + onPressed: () async => throw StateError('x'), + onError: (e, _) => captured = e, + builder: textBuilder, + child: const Text('label'), + ), + ), + ); + await tester.tap(find.byType(TextButton)); + await tester.pumpAndSettle(); + check(captured).isA(); + }); + + testWidgets('confirmBeforePress can cancel the press', (tester) async { + var ran = 0; + await tester.pumpWidget( + pumpHost( + AsyncButton( + onPressed: () async => ran++, + confirmBeforePress: (_) async => false, + builder: textBuilder, + child: const Text('label'), + ), + ), + ); + await tester.tap(find.byType(TextButton)); + await tester.pumpAndSettle(); + check(ran).equals(0); + }); + }); + + group('AsyncButton external control', () { + testWidgets('controller.trigger() runs onPressed', (tester) async { + final controller = AsyncButtonController(); + addTearDown(controller.dispose); + var ran = 0; + await tester.pumpWidget( + pumpHost( + AsyncButton( + controller: controller, + onPressed: () async => ran++, + builder: textBuilder, + child: const Text('label'), + ), + ), + ); + await controller.trigger(); + await tester.pumpAndSettle(); + check(ran).equals(1); + }); + + testWidgets('controller.invalidate flips to error', (tester) async { + final controller = AsyncButtonController(); + addTearDown(controller.dispose); + await tester.pumpWidget( + pumpHost( + AsyncButton( + controller: controller, + onPressed: () async {}, + errorChild: const Text('errored'), + errorDisplayDuration: const Duration(milliseconds: 100), + builder: textBuilder, + child: const Text('label'), + ), + ), + ); + controller.invalidate('bad'); + await tester.pump(); + check(find.text('errored')).findsOne(); + await tester.pump(const Duration(milliseconds: 200)); + await tester.pumpAndSettle(); + }); + + testWidgets('controller.reset clears mid-display', (tester) async { + final controller = AsyncButtonController(); + addTearDown(controller.dispose); + await tester.pumpWidget( + pumpHost( + AsyncButton( + controller: controller, + onPressed: () async {}, + successChild: const Text('yay'), + successDisplayDuration: const Duration(seconds: 5), + builder: textBuilder, + child: const Text('label'), + ), + ), + ); + controller.markSuccess(); + await tester.pump(); + check(find.text('yay')).findsOne(); + controller.reset(); + await tester.pump(); + check(find.text('label')).findsOne(); + }); + + testWidgets( + 'swapping the external controller transfers listening without leak', + (tester) async { + final a = AsyncButtonController(); + final b = AsyncButtonController(); + addTearDown(() { + a.dispose(); + b.dispose(); + }); + AsyncButton button(AsyncButtonController c) => AsyncButton( + controller: c, + onPressed: () async {}, + successChild: const Text('done'), + successDisplayDuration: const Duration(milliseconds: 100), + builder: textBuilder, + child: const Text('child'), + ); + await tester.pumpWidget(pumpHost(button(a))); + await tester.pumpWidget(pumpHost(button(b))); + a.markSuccess(); + await tester.pump(); + check(find.text('done')).findsNone(); + b.markSuccess(); + await tester.pump(); + check(find.text('done')).findsOne(); + await tester.pump(const Duration(milliseconds: 200)); + await tester.pumpAndSettle(); + }, + ); + }); + + group('AsyncButton timer hygiene', () { + testWidgets('invalidate then markSuccess does not race', (tester) async { + final controller = AsyncButtonController(); + addTearDown(controller.dispose); + await tester.pumpWidget( + pumpHost( + AsyncButton( + controller: controller, + onPressed: () async {}, + errorChild: const Text('e'), + errorDisplayDuration: const Duration(milliseconds: 200), + builder: textBuilder, + child: const Text('child'), + ), + ), + ); + controller.invalidate('1'); + await tester.pump(); + controller.markSuccess(); + await tester.pump(); + await tester.pump(const Duration(milliseconds: 250)); + check(find.text('child')).findsOne(); + }); + }); +} diff --git a/test/elevated_async_button_test.dart b/test/elevated_async_button_test.dart index 790887c..ec5237c 100644 --- a/test/elevated_async_button_test.dart +++ b/test/elevated_async_button_test.dart @@ -1,74 +1,89 @@ -import 'dart:async'; - +import 'package:checks/checks.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:material_async_button/material_async_button.dart'; -Widget _wrap(Widget child) => MaterialApp( - home: Scaffold(body: Center(child: child)), -); +import '_helpers.dart'; void main() { group('ElevatedAsyncButton', () { testWidgets('renders an ElevatedButton with the child', (tester) async { await tester.pumpWidget( - _wrap(ElevatedAsyncButton(onPressed: () async {}, child: const Text('go'))), + pumpHost( + ElevatedAsyncButton( + onPressed: () async {}, + child: const Text('go'), + ), + ), ); - expect(find.byType(ElevatedButton), findsOneWidget); - expect(find.text('go'), findsOneWidget); + check(find.byType(ElevatedButton)).findsOne(); + check(find.text('go')).findsOne(); }); testWidgets('shows loading then returns to idle', (tester) async { - final completer = Completer(); + final (:onPressed, :completer) = pendingPress(); await tester.pumpWidget( - _wrap(ElevatedAsyncButton(onPressed: () => completer.future, child: const Text('go'))), + pumpHost( + ElevatedAsyncButton( + onPressed: onPressed, + child: const Text('go'), + ), + ), ); await tester.tap(find.byType(ElevatedButton)); await tester.pump(); - expect(find.byType(CircularProgressIndicator), findsOneWidget); + check(find.byType(CircularProgressIndicator)).findsOne(); completer.complete(); await tester.pumpAndSettle(); - expect(find.text('go'), findsOneWidget); + check(find.text('go')).findsOne(); }); testWidgets('is disabled when onPressed is null', (tester) async { - await tester.pumpWidget(_wrap(const ElevatedAsyncButton(onPressed: null, child: Text('go')))); + await tester.pumpWidget( + pumpHost( + const ElevatedAsyncButton(onPressed: null, child: Text('go')), + ), + ); final btn = tester.widget(find.byType(ElevatedButton)); - expect(btn.onPressed, isNull); + check(btn.onPressed).isNull(); }); testWidgets('is disabled when disabled=true', (tester) async { await tester.pumpWidget( - _wrap(ElevatedAsyncButton(onPressed: () async {}, disabled: true, child: const Text('go'))), + pumpHost( + ElevatedAsyncButton( + onPressed: () async {}, + disabled: true, + child: const Text('go'), + ), + ), ); final btn = tester.widget(find.byType(ElevatedButton)); - expect(btn.onPressed, isNull); + check(btn.onPressed).isNull(); }); }); group('ElevatedAsyncButton.icon', () { testWidgets('icon stays put while the label animates', (tester) async { - final completer = Completer(); + final (:onPressed, :completer) = pendingPress(); await tester.pumpWidget( - _wrap( + pumpHost( ElevatedAsyncButton.icon( - onPressed: () => completer.future, + onPressed: onPressed, icon: const Icon(Icons.send), label: const Text('send'), ), ), ); - // Idle: icon + label. - expect(find.byIcon(Icons.send), findsOneWidget); - expect(find.text('send'), findsOneWidget); + check(find.byIcon(Icons.send)).findsOne(); + check(find.text('send')).findsOne(); await tester.tap(find.byType(ElevatedButton)); await tester.pump(); - // Loading: icon stays, label gone, spinner present. - expect(find.byIcon(Icons.send), findsOneWidget); - expect(find.byType(CircularProgressIndicator), findsOneWidget); + check(find.byIcon(Icons.send)).findsOne(); + check(find.byType(CircularProgressIndicator)).findsOne(); completer.complete(); await tester.pumpAndSettle(); - expect(find.text('send'), findsOneWidget); + check(find.text('send')).findsOne(); }); }); } diff --git a/test/filled_async_button_test.dart b/test/filled_async_button_test.dart index 4870a0a..eefa1e5 100644 --- a/test/filled_async_button_test.dart +++ b/test/filled_async_button_test.dart @@ -1,54 +1,60 @@ -import 'dart:async'; - +import 'package:checks/checks.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:material_async_button/material_async_button.dart'; -Widget _wrap(Widget child) => MaterialApp( - home: Scaffold(body: Center(child: child)), -); +import '_helpers.dart'; void main() { group('FilledAsyncButton', () { testWidgets('renders FilledButton', (tester) async { await tester.pumpWidget( - _wrap(FilledAsyncButton(onPressed: () async {}, child: const Text('go'))), + pumpHost( + FilledAsyncButton( + onPressed: () async {}, + child: const Text('go'), + ), + ), ); - expect(find.byType(FilledButton), findsOneWidget); + check(find.byType(FilledButton)).findsOne(); }); - testWidgets('FilledAsyncButton.tonal renders FilledButton in tonal style', (tester) async { + testWidgets('.tonal renders FilledButton in tonal style', (tester) async { await tester.pumpWidget( - _wrap(FilledAsyncButton.tonal(onPressed: () async {}, child: const Text('go'))), + pumpHost( + FilledAsyncButton.tonal( + onPressed: () async {}, + child: const Text('go'), + ), + ), ); - expect(find.byType(FilledButton), findsOneWidget); + check(find.byType(FilledButton)).findsOne(); }); - testWidgets('FilledAsyncButton.icon swaps label during loading', (tester) async { - final completer = Completer(); + testWidgets('.icon swaps label during loading', (tester) async { + final (:onPressed, :completer) = pendingPress(); await tester.pumpWidget( - _wrap( + pumpHost( FilledAsyncButton.icon( - onPressed: () => completer.future, + onPressed: onPressed, icon: const Icon(Icons.save), label: const Text('save'), ), ), ); await tester.tap(find.byType(FilledButton)); - // Wait for the AnimatedSwitcher cross-fade to settle. await tester.pump(); await tester.pump(const Duration(milliseconds: 250)); - expect(find.byIcon(Icons.save), findsOneWidget); - expect(find.text('save'), findsNothing); - expect(find.byType(CircularProgressIndicator), findsOneWidget); + check(find.byIcon(Icons.save)).findsOne(); + check(find.text('save')).findsNone(); + check(find.byType(CircularProgressIndicator)).findsOne(); completer.complete(); await tester.pumpAndSettle(); }); - testWidgets('FilledAsyncButton.tonalIcon renders', (tester) async { + testWidgets('.tonalIcon renders', (tester) async { await tester.pumpWidget( - _wrap( + pumpHost( FilledAsyncButton.tonalIcon( onPressed: () async {}, icon: const Icon(Icons.save), @@ -56,7 +62,7 @@ void main() { ), ), ); - expect(find.byType(FilledButton), findsOneWidget); + check(find.byType(FilledButton)).findsOne(); }); }); } diff --git a/test/icon_async_button_test.dart b/test/icon_async_button_test.dart index 7a46fe0..2998f13 100644 --- a/test/icon_async_button_test.dart +++ b/test/icon_async_button_test.dart @@ -1,46 +1,64 @@ -import 'dart:async'; - +import 'package:checks/checks.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:material_async_button/material_async_button.dart'; -Widget _wrap(Widget child) => MaterialApp( - home: Scaffold(body: Center(child: child)), -); +import '_helpers.dart'; void main() { group('IconAsyncButton', () { testWidgets('renders IconButton with the icon', (tester) async { await tester.pumpWidget( - _wrap(IconAsyncButton(onPressed: () async {}, icon: const Icon(Icons.refresh))), + pumpHost( + IconAsyncButton( + onPressed: () async {}, + icon: const Icon(Icons.refresh), + ), + ), ); - expect(find.byIcon(Icons.refresh), findsOneWidget); - expect(find.byType(IconButton), findsOneWidget); + check(find.byIcon(Icons.refresh)).findsOne(); + check(find.byType(IconButton)).findsOne(); }); - testWidgets('filled, filledTonal, outlined variants all render', (tester) async { - for (final ctor in [ - () => IconAsyncButton.filled(onPressed: () async {}, icon: const Icon(Icons.add)), - () => IconAsyncButton.filledTonal(onPressed: () async {}, icon: const Icon(Icons.add)), - () => IconAsyncButton.outlined(onPressed: () async {}, icon: const Icon(Icons.add)), - ]) { - await tester.pumpWidget(_wrap(ctor())); - expect(find.byType(IconButton), findsOneWidget); + testWidgets('filled, filledTonal, outlined variants all render', ( + tester, + ) async { + final ctors = [ + () => IconAsyncButton.filled( + onPressed: () async {}, + icon: const Icon(Icons.add), + ), + () => IconAsyncButton.filledTonal( + onPressed: () async {}, + icon: const Icon(Icons.add), + ), + () => IconAsyncButton.outlined( + onPressed: () async {}, + icon: const Icon(Icons.add), + ), + ]; + for (final ctor in ctors) { + await tester.pumpWidget(pumpHost(ctor())); + check(find.byType(IconButton)).findsOne(); } }); testWidgets('swaps icon for loading widget during press', (tester) async { - final completer = Completer(); + final (:onPressed, :completer) = pendingPress(); await tester.pumpWidget( - _wrap(IconAsyncButton(onPressed: () => completer.future, icon: const Icon(Icons.refresh))), + pumpHost( + IconAsyncButton( + onPressed: onPressed, + icon: const Icon(Icons.refresh), + ), + ), ); await tester.tap(find.byType(IconButton)); await tester.pump(); - expect(find.byType(CircularProgressIndicator), findsOneWidget); - // Icon may animate out via AnimatedSwitcher; allow both possibilities. + check(find.byType(CircularProgressIndicator)).findsOne(); completer.complete(); await tester.pumpAndSettle(); - expect(find.byIcon(Icons.refresh), findsOneWidget); + check(find.byIcon(Icons.refresh)).findsOne(); }); }); } diff --git a/test/material_async_button_theme_test.dart b/test/material_async_button_theme_test.dart index 7f8722a..12fdb9b 100644 --- a/test/material_async_button_theme_test.dart +++ b/test/material_async_button_theme_test.dart @@ -1,106 +1,167 @@ +import 'package:checks/checks.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:material_async_button/material_async_button.dart'; void main() { - group('MaterialAsyncButtonTheme', () { + group('AsyncButtonTheme', () { test('empty default has all null fields', () { - const t = MaterialAsyncButtonTheme.empty; - expect(t.loadingChild, isNull); - expect(t.successChild, isNull); - expect(t.errorChild, isNull); - expect(t.switchDuration, isNull); - expect(t.hapticOn, isNull); + const t = AsyncButtonTheme.empty; + check(t) + ..has((it) => it.loadingChild, 'loadingChild').isNull() + ..has((it) => it.successChild, 'successChild').isNull() + ..has((it) => it.errorChild, 'errorChild').isNull() + ..has((it) => it.switchDuration, 'switchDuration').isNull() + ..has((it) => it.hapticOn, 'hapticOn').isNull(); }); test('material() supplies opinionated baseline', () { - final t = MaterialAsyncButtonTheme.material(); - expect(t.loadingChild, isNotNull); - expect(t.successChild, isNotNull); - expect(t.errorChild, isNotNull); - expect(t.switchDuration, const Duration(milliseconds: 200)); - expect(t.successDisplayDuration, const Duration(milliseconds: 800)); - expect(t.errorDisplayDuration, const Duration(milliseconds: 800)); - expect(t.animateSize, isTrue); - expect(t.hapticOn, HapticOn.both); - expect(t.announceSemantics, isTrue); + final t = AsyncButtonTheme.material(); + check(t) + ..has((it) => it.loadingChild, 'loadingChild').isNotNull() + ..has((it) => it.successChild, 'successChild').isNotNull() + ..has((it) => it.errorChild, 'errorChild').isNotNull() + ..has( + (it) => it.switchDuration, + 'switchDuration', + ).equals(const Duration(milliseconds: 200)) + ..has( + (it) => it.successDisplayDuration, + 'successDisplayDuration', + ).equals(const Duration(milliseconds: 800)) + ..has( + (it) => it.errorDisplayDuration, + 'errorDisplayDuration', + ).equals(const Duration(milliseconds: 800)) + ..has((it) => it.animateSize, 'animateSize').equals(true) + ..has((it) => it.hapticOn, 'hapticOn').equals(HapticOn.both) + ..has((it) => it.announceSemantics, 'announceSemantics').equals(true); }); test('copyWith overrides only specified fields', () { - final base = MaterialAsyncButtonTheme.material(); - final overridden = base.copyWith(switchDuration: const Duration(milliseconds: 500)); - expect(overridden.switchDuration, const Duration(milliseconds: 500)); - expect(overridden.successDisplayDuration, base.successDisplayDuration); - expect(overridden.hapticOn, base.hapticOn); + final base = AsyncButtonTheme.material(); + final overridden = base.copyWith( + switchDuration: const Duration(milliseconds: 500), + ); + check(overridden) + ..has( + (it) => it.switchDuration, + 'switchDuration', + ).equals(const Duration(milliseconds: 500)) + ..has( + (it) => it.successDisplayDuration, + 'successDisplayDuration', + ).equals(base.successDisplayDuration) + ..has((it) => it.hapticOn, 'hapticOn').equals(base.hapticOn); }); test('lerp snaps non-numeric fields and interpolates durations', () { - const a = MaterialAsyncButtonTheme( + const a = AsyncButtonTheme( switchDuration: Duration(milliseconds: 100), successDisplayDuration: Duration(milliseconds: 200), hapticOn: HapticOn.success, ); - const b = MaterialAsyncButtonTheme( + const b = AsyncButtonTheme( switchDuration: Duration(milliseconds: 300), successDisplayDuration: Duration(milliseconds: 600), hapticOn: HapticOn.error, ); final mid = a.lerp(b, 0.5); - expect(mid.switchDuration, const Duration(milliseconds: 200)); - expect(mid.successDisplayDuration, const Duration(milliseconds: 400)); - // Non-interpolable fields snap at 0.5 to the second value. - expect(mid.hapticOn, HapticOn.error); + check(mid) + ..has( + (it) => it.switchDuration, + 'switchDuration', + ).equals(const Duration(milliseconds: 200)) + ..has( + (it) => it.successDisplayDuration, + 'successDisplayDuration', + ).equals(const Duration(milliseconds: 400)) + ..has((it) => it.hapticOn, 'hapticOn').equals(HapticOn.error); }); - test('lerp with non-MaterialAsyncButtonTheme returns self', () { - const a = MaterialAsyncButtonTheme(switchDuration: Duration(milliseconds: 100)); - final result = a.lerp(null, 0.5); - expect(result.switchDuration, a.switchDuration); + test('lerp with non-AsyncButtonTheme returns self', () { + const a = AsyncButtonTheme( + switchDuration: Duration(milliseconds: 100), + ); + check(a.lerp(null, 0.5)) + .has((it) => it.switchDuration, 'switchDuration') + .equals(a.switchDuration); }); testWidgets('of(context) returns the registered extension', (tester) async { - const ext = MaterialAsyncButtonTheme(switchDuration: Duration(milliseconds: 123)); - MaterialAsyncButtonTheme? captured; + const ext = AsyncButtonTheme( + switchDuration: Duration(milliseconds: 123), + ); + AsyncButtonTheme? captured; await tester.pumpWidget( MaterialApp( theme: ThemeData(extensions: const [ext]), home: Builder( builder: (ctx) { - captured = MaterialAsyncButtonTheme.of(ctx); + captured = AsyncButtonTheme.of(ctx); return const SizedBox.shrink(); }, ), ), ); - expect(captured?.switchDuration, const Duration(milliseconds: 123)); + check(captured) + .isNotNull() + .has((it) => it.switchDuration, 'switchDuration') + .equals(const Duration(milliseconds: 123)); }); - testWidgets('of(context) returns empty when extension absent', (tester) async { - MaterialAsyncButtonTheme? captured; + testWidgets('of(context) falls back to material defaults when absent', ( + tester, + ) async { + AsyncButtonTheme? captured; await tester.pumpWidget( MaterialApp( home: Builder( builder: (ctx) { - captured = MaterialAsyncButtonTheme.of(ctx); + captured = AsyncButtonTheme.of(ctx); return const SizedBox.shrink(); }, ), ), ); - expect(captured?.switchDuration, isNull); + check(captured) + .isNotNull() + .has((it) => it.switchDuration, 'switchDuration') + .equals(const Duration(milliseconds: 200)); }); + testWidgets( + 'of(context) returns registered empty extension when explicitly set', + (tester) async { + AsyncButtonTheme? captured; + await tester.pumpWidget( + MaterialApp( + theme: ThemeData(extensions: const [AsyncButtonTheme.empty]), + home: Builder( + builder: (ctx) { + captured = AsyncButtonTheme.of(ctx); + return const SizedBox.shrink(); + }, + ), + ), + ); + check( + captured, + ).isNotNull().has((it) => it.switchDuration, 'switchDuration').isNull(); + }, + ); + test('equality is value-based', () { - const a = MaterialAsyncButtonTheme( + const a = AsyncButtonTheme( switchDuration: Duration(milliseconds: 100), hapticOn: HapticOn.both, ); - const b = MaterialAsyncButtonTheme( + const b = AsyncButtonTheme( switchDuration: Duration(milliseconds: 100), hapticOn: HapticOn.both, ); - expect(a, b); - expect(a.hashCode, b.hashCode); + check(a).equals(b); + check(a.hashCode).equals(b.hashCode); }); }); } diff --git a/test/outlined_async_button_test.dart b/test/outlined_async_button_test.dart index 891645d..370a1b6 100644 --- a/test/outlined_async_button_test.dart +++ b/test/outlined_async_button_test.dart @@ -1,25 +1,27 @@ -import 'dart:async'; - +import 'package:checks/checks.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:material_async_button/material_async_button.dart'; -Widget _wrap(Widget child) => MaterialApp( - home: Scaffold(body: Center(child: child)), -); +import '_helpers.dart'; void main() { group('OutlinedAsyncButton', () { testWidgets('renders OutlinedButton', (tester) async { await tester.pumpWidget( - _wrap(OutlinedAsyncButton(onPressed: () async {}, child: const Text('go'))), + pumpHost( + OutlinedAsyncButton( + onPressed: () async {}, + child: const Text('go'), + ), + ), ); - expect(find.byType(OutlinedButton), findsOneWidget); + check(find.byType(OutlinedButton)).findsOne(); }); - testWidgets('.icon variant renders with icon + label', (tester) async { + testWidgets('.icon renders with icon + label', (tester) async { await tester.pumpWidget( - _wrap( + pumpHost( OutlinedAsyncButton.icon( onPressed: () async {}, icon: const Icon(Icons.share), @@ -27,19 +29,24 @@ void main() { ), ), ); - expect(find.byType(OutlinedButton), findsOneWidget); - expect(find.byIcon(Icons.share), findsOneWidget); - expect(find.text('share'), findsOneWidget); + check(find.byType(OutlinedButton)).findsOne(); + check(find.byIcon(Icons.share)).findsOne(); + check(find.text('share')).findsOne(); }); testWidgets('cycles through loading', (tester) async { - final completer = Completer(); + final (:onPressed, :completer) = pendingPress(); await tester.pumpWidget( - _wrap(OutlinedAsyncButton(onPressed: () => completer.future, child: const Text('go'))), + pumpHost( + OutlinedAsyncButton( + onPressed: onPressed, + child: const Text('go'), + ), + ), ); await tester.tap(find.byType(OutlinedButton)); await tester.pump(); - expect(find.byType(CircularProgressIndicator), findsOneWidget); + check(find.byType(CircularProgressIndicator)).findsOne(); completer.complete(); await tester.pumpAndSettle(); }); diff --git a/test/text_async_button_test.dart b/test/text_async_button_test.dart index 382464a..baa0a01 100644 --- a/test/text_async_button_test.dart +++ b/test/text_async_button_test.dart @@ -1,23 +1,27 @@ +import 'package:checks/checks.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:material_async_button/material_async_button.dart'; -Widget _wrap(Widget child) => MaterialApp( - home: Scaffold(body: Center(child: child)), -); +import '_helpers.dart'; void main() { group('TextAsyncButton', () { testWidgets('renders TextButton', (tester) async { await tester.pumpWidget( - _wrap(TextAsyncButton(onPressed: () async {}, child: const Text('go'))), + pumpHost( + TextAsyncButton( + onPressed: () async {}, + child: const Text('go'), + ), + ), ); - expect(find.byType(TextButton), findsOneWidget); + check(find.byType(TextButton)).findsOne(); }); - testWidgets('.icon variant renders with icon + label', (tester) async { + testWidgets('.icon renders with icon + label', (tester) async { await tester.pumpWidget( - _wrap( + pumpHost( TextAsyncButton.icon( onPressed: () async {}, icon: const Icon(Icons.copy), @@ -25,19 +29,28 @@ void main() { ), ), ); - expect(find.byType(TextButton), findsOneWidget); - expect(find.byIcon(Icons.copy), findsOneWidget); + check(find.byType(TextButton)).findsOne(); + check(find.byIcon(Icons.copy)).findsOne(); }); - testWidgets('state.trigger() works for "Done" keyboard pattern', (tester) async { + testWidgets('controller.trigger() works for "Done" keyboard pattern', ( + tester, + ) async { + final controller = AsyncButtonController(); + addTearDown(controller.dispose); var ran = 0; await tester.pumpWidget( - _wrap(TextAsyncButton(onPressed: () async => ran++, child: const Text('go'))), + pumpHost( + TextAsyncButton( + controller: controller, + onPressed: () async => ran++, + child: const Text('go'), + ), + ), ); - final state = tester.state(find.byType(AsyncButtonBuilder)); - await state.trigger(); + await controller.trigger(); await tester.pumpAndSettle(); - expect(ran, 1); + check(ran).equals(1); }); }); } diff --git a/claude_code_skill/flutter-material-async-button/SKILL.md b/tool/claude/flutter-material-async-button/SKILL.md similarity index 56% rename from claude_code_skill/flutter-material-async-button/SKILL.md rename to tool/claude/flutter-material-async-button/SKILL.md index 4d6cc40..efc886c 100644 --- a/claude_code_skill/flutter-material-async-button/SKILL.md +++ b/tool/claude/flutter-material-async-button/SKILL.md @@ -16,19 +16,19 @@ Replace the Material button with its async counterpart whenever `onPressed` is async. The wrapper handles loading state, the post-press display, and disables the button while running. -| Material | Use | Variants | -| ---------------- | ---------------------- | ------------------------------------------------- | -| `ElevatedButton` | `ElevatedAsyncButton` | `.icon` | -| `FilledButton` | `FilledAsyncButton` | `.tonal` `.icon` `.tonalIcon` | -| `OutlinedButton` | `OutlinedAsyncButton` | `.icon` | -| `TextButton` | `TextAsyncButton` | `.icon` | -| `IconButton` | `IconAsyncButton` | `.filled` `.filledTonal` `.outlined` | +|Material|Use|Variants| +|--|--|--| +|`ElevatedButton`|`ElevatedAsyncButton`|`.icon`| +|`FilledButton`|`FilledAsyncButton`|`.tonal` `.icon` `.tonalIcon`| +|`OutlinedButton`|`OutlinedAsyncButton`|`.icon`| +|`TextButton`|`TextAsyncButton`|`.icon`| +|`IconButton`|`IconAsyncButton`|`.filled` `.filledTonal` `.outlined`| ## Minimal use ```dart ElevatedAsyncButton( - onPressed: () async => api.save(), + onPressed: notifier.save, child: const Text('Save'), ) ``` @@ -36,22 +36,24 @@ ElevatedAsyncButton( ## Theming — do this once ```dart -ThemeData(extensions: [MaterialAsyncButtonTheme.material()]) +ThemeData(extensions: [AsyncButtonTheme.material()]) ``` Or, with overrides: ```dart -ThemeData(extensions: [ - MaterialAsyncButtonTheme( - successChild: const Icon(Icons.check), - errorChild: const Icon(Icons.error_outline), - switchDuration: const Duration(milliseconds: 200), - successDisplayDuration:const Duration(milliseconds: 800), - errorDisplayDuration: const Duration(milliseconds: 800), - animateSize: true, - hapticOn: HapticOn.both, - ), +ThemeData( + extensions: [ + AsyncButtonTheme( + successChild: const Icon(Icons.check), + errorChild: const Icon(Icons.error_outline), + switchDuration: const Duration(milliseconds: 200), + successDisplayDuration:const Duration(milliseconds: 800), + errorDisplayDuration: const Duration(milliseconds: 800), + animateSize: true, + hapticOn: HapticOn.both, + ), + ], ]) ``` @@ -81,26 +83,22 @@ controller.markSuccess(); // force success from outside controller.reset(); // back to idle ``` -It's a `ValueListenable` — pipe into +It's a `ValueListenable` — pipe into `ValueListenableBuilder` for cross-widget reactions. -`GlobalKey` exposes the same methods, but is only -useful with the low-level `AsyncButtonBuilder` (the Material wrappers are -`StatelessWidget`). - -## Custom buttons — `AsyncButtonBuilder` +## Custom buttons — `AsyncButton` Only when no Material wrapper fits: ```dart -AsyncButtonBuilder( +AsyncButton( onPressed: doWork, child: const Text('Go'), - builder: (context, child, callback, state) => MyButton( + builder: (context, child, callback, status) => MyButton( onTap: callback, - color: switch (state) { - AsyncButtonStateLoading() => Colors.grey, - AsyncButtonStateError() => Colors.red, + color: switch (status) { + AsyncButtonStatusLoading() => Colors.grey, + AsyncButtonStatusError() => Colors.red, _ => Colors.indigo, }, child: child, @@ -115,4 +113,4 @@ AsyncButtonBuilder( - Don't call `setState` in `onSuccess` / `onError` for state the button already reflects. - Don't create a project-wide wrapper widget for default loading/success - spinners — that's exactly what `MaterialAsyncButtonTheme` is for. + spinners — that's exactly what `AsyncButtonTheme` is for. From 1b5889f2732aba4e193d05192ecab42020195e24 Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Tue, 26 May 2026 13:04:11 +0300 Subject: [PATCH 104/176] docs: add public_member_api_docs comments across lib/ - Exclude example/ from analyzer. - Add concise /// docs to AsyncButton, AsyncMaterialButton, AsyncStandardMaterialButton, IconAsyncButton and the five Material wrappers. Most field docs reference the underlying [AsyncButton.X] or [Material*Button.X] property. - Doc the four AsyncButtonStatus variants and their factory ctors. - Doc AsyncButtonController bool getters and the HapticOn enum members. Co-Authored-By: Claude Opus 4.7 --- analysis_options.yaml | 15 ++---- lib/src/async_button.dart | 46 ++++++++++++++++- lib/src/async_button_controller.dart | 9 ++++ lib/src/async_button_status.dart | 12 +++++ lib/src/buttons/async_material_button.dart | 59 ++++++++++++++++++++++ lib/src/buttons/elevated_async_button.dart | 1 + lib/src/buttons/filled_async_button.dart | 4 ++ lib/src/buttons/icon_async_button.dart | 46 +++++++++++++++++ lib/src/buttons/outlined_async_button.dart | 2 + lib/src/buttons/text_async_button.dart | 2 + lib/src/material_async_button_theme.dart | 30 ++++++++++- 11 files changed, 213 insertions(+), 13 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index da187d6..fb902e3 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,14 +1,7 @@ include: package:very_good_analysis/analysis_options.yaml analyzer: - language: - strict-casts: true - strict-inference: true - strict-raw-types: true - -linter: - rules: - always_put_required_named_parameters_first: false - sort_constructors_first: true - public_member_api_docs: false - diagnostic_describe_all_properties: false + exclude: + - example/** + errors: + always_put_required_named_parameters_first: ignore diff --git a/lib/src/async_button.dart b/lib/src/async_button.dart index c02fed1..d9be886 100644 --- a/lib/src/async_button.dart +++ b/lib/src/async_button.dart @@ -49,6 +49,7 @@ typedef AsyncButtonErrorCallback = /// ) /// ``` class AsyncButton extends StatefulWidget { + /// Creates an [AsyncButton]. See the class doc for usage. const AsyncButton({ super.key, required this.child, @@ -81,8 +82,14 @@ class AsyncButton extends StatefulWidget { this.rethrowErrors, }); + /// Idle widget. Replaced by [loadingChild] / [successChild] / [errorChild] + /// during the matching [AsyncButtonStatus]. final Widget child; + + /// Async callback. `null` makes the button appear disabled. final AsyncCallback? onPressed; + + /// Renders the button chrome. See [AsyncButtonWidgetBuilder]. final AsyncButtonWidgetBuilder builder; /// External controller. When null, the widget creates and owns its own. @@ -102,29 +109,66 @@ class AsyncButton extends StatefulWidget { /// and no status change happens. final Future Function(BuildContext context)? confirmBeforePress; + /// Widget shown while loading. Falls back to [AsyncButtonTheme.loadingChild]. final Widget? loadingChild; + + /// Widget shown briefly after success. Falls back to + /// [AsyncButtonTheme.successChild]. final Widget? successChild; + + /// Widget shown briefly after error. Falls back to + /// [AsyncButtonTheme.errorChild]. final Widget? errorChild; /// Forces the button to appear disabled regardless of status. final bool disabled; - // Per-widget overrides of the theme. Null means "use theme, then default". + /// Per-widget override of [AsyncButtonTheme.switchDuration]. final Duration? switchDuration; + + /// Per-widget override of [AsyncButtonTheme.switchReverseDuration]. final Duration? switchReverseDuration; + + /// Per-widget override of [AsyncButtonTheme.switchCurve]. final Curve? switchCurve; + + /// Per-widget override of [AsyncButtonTheme.switchInCurve]. final Curve? switchInCurve; + + /// Per-widget override of [AsyncButtonTheme.switchOutCurve]. final Curve? switchOutCurve; + + /// Per-widget override of [AsyncButtonTheme.transitionBuilder]. final AnimatedSwitcherTransitionBuilder? transitionBuilder; + + /// Per-widget override of [AsyncButtonTheme.successDisplayDuration]. final Duration? successDisplayDuration; + + /// Per-widget override of [AsyncButtonTheme.errorDisplayDuration]. final Duration? errorDisplayDuration; + + /// Per-widget override of [AsyncButtonTheme.cooldownDuration]. final Duration? cooldownDuration; + + /// Per-widget override of [AsyncButtonTheme.animateSize]. final bool? animateSize; + + /// Per-widget override of [AsyncButtonTheme.sizeCurve]. final Curve? sizeCurve; + + /// Per-widget override of [AsyncButtonTheme.sizeAlignment]. final AlignmentGeometry? sizeAlignment; + + /// Per-widget override of [AsyncButtonTheme.sizeClipBehavior]. final Clip? sizeClipBehavior; + + /// Per-widget override of [AsyncButtonTheme.hapticOn]. final HapticOn? hapticOn; + + /// Per-widget override of [AsyncButtonTheme.announceSemantics]. final bool? announceSemantics; + + /// Per-widget override of [AsyncButtonTheme.rethrowErrors]. final bool? rethrowErrors; @override diff --git a/lib/src/async_button_controller.dart b/lib/src/async_button_controller.dart index 1eb0a9a..4068496 100644 --- a/lib/src/async_button_controller.dart +++ b/lib/src/async_button_controller.dart @@ -19,13 +19,22 @@ part of '../material_async_button.dart'; /// /// Dispose like any [ChangeNotifier]. class AsyncButtonController extends ValueNotifier { + /// Creates a controller with an optional initial status (defaults to idle). AsyncButtonController([super.initial = const .idle()]); + /// True when [value] is [AsyncButtonStatusIdle]. bool get isIdle => value is AsyncButtonStatusIdle; + + /// True when [value] is [AsyncButtonStatusLoading]. bool get isLoading => value is AsyncButtonStatusLoading; + + /// True when [value] is [AsyncButtonStatusSuccess]. bool get isSuccess => value is AsyncButtonStatusSuccess; + + /// True when [value] is [AsyncButtonStatusError]. bool get isError => value is AsyncButtonStatusError; + /// True while the post-success/error cooldown is blocking [trigger]. @visibleForTesting bool get isInCooldown => _cooldownActive; diff --git a/lib/src/async_button_status.dart b/lib/src/async_button_status.dart index 20c1d35..2a4bf28 100644 --- a/lib/src/async_button_status.dart +++ b/lib/src/async_button_status.dart @@ -28,7 +28,9 @@ sealed class AsyncButtonStatus { ]) = AsyncButtonStatusError; } +/// Idle variant of [AsyncButtonStatus] — no async work in flight. final class AsyncButtonStatusIdle extends AsyncButtonStatus { + /// Const constructor; prefer the [AsyncButtonStatus.idle] factory. const AsyncButtonStatusIdle(); @override @@ -37,7 +39,9 @@ final class AsyncButtonStatusIdle extends AsyncButtonStatus { } } +/// Loading variant of [AsyncButtonStatus] — `onPressed` is in flight. final class AsyncButtonStatusLoading extends AsyncButtonStatus { + /// Const constructor; prefer the [AsyncButtonStatus.loading] factory. const AsyncButtonStatusLoading(); @override @@ -46,7 +50,9 @@ final class AsyncButtonStatusLoading extends AsyncButtonStatus { } } +/// Success variant of [AsyncButtonStatus] — `onPressed` completed. final class AsyncButtonStatusSuccess extends AsyncButtonStatus { + /// Const constructor; prefer the [AsyncButtonStatus.success] factory. const AsyncButtonStatusSuccess(); @override @@ -55,10 +61,16 @@ final class AsyncButtonStatusSuccess extends AsyncButtonStatus { } } +/// Error variant of [AsyncButtonStatus]. Produced when `onPressed` throws or +/// [AsyncButtonController.invalidate] is called. final class AsyncButtonStatusError extends AsyncButtonStatus { + /// Const constructor; prefer the [AsyncButtonStatus.error] factory. const AsyncButtonStatusError(this.error, [this.stackTrace]); + /// The thrown error. final Object error; + + /// Captured stack trace, when available. final StackTrace? stackTrace; /// Equality compares [error] by runtime type and `toString()` payload — diff --git a/lib/src/buttons/async_material_button.dart b/lib/src/buttons/async_material_button.dart index 146bc24..7cd536c 100644 --- a/lib/src/buttons/async_material_button.dart +++ b/lib/src/buttons/async_material_button.dart @@ -9,6 +9,8 @@ part of '../../material_async_button.dart'; /// fields to an [AsyncButton]. For custom non-Material buttons reach for /// [AsyncButton] directly. abstract class AsyncMaterialButton extends StatelessWidget { + /// Subclass-only constructor. Forwards every field to [AsyncButton]. See + /// [AsyncButton] for the semantics of each parameter. const AsyncMaterialButton({ super.key, required this.child, @@ -33,25 +35,64 @@ abstract class AsyncMaterialButton extends StatelessWidget { this.rethrowErrors, }); + /// See [AsyncButton.child]. final Widget child; + + /// See [AsyncButton.onPressed]. final AsyncCallback? onPressed; + + /// See [AsyncButton.controller]. final AsyncButtonController? controller; + + /// See [AsyncButton.onSuccess]. final VoidCallback? onSuccess; + + /// See [AsyncButton.onError]. final AsyncButtonErrorCallback? onError; + + /// See [AsyncButton.onStateChanged]. final ValueChanged? onStateChanged; + + /// See [AsyncButton.confirmBeforePress]. final Future Function(BuildContext context)? confirmBeforePress; + + /// See [AsyncButton.loadingChild]. final Widget? loadingChild; + + /// See [AsyncButton.successChild]. final Widget? successChild; + + /// See [AsyncButton.errorChild]. final Widget? errorChild; + + /// See [AsyncButton.disabled]. final bool disabled; + + /// See [AsyncButton.switchDuration]. final Duration? switchDuration; + + /// See [AsyncButton.transitionBuilder]. final AnimatedSwitcherTransitionBuilder? transitionBuilder; + + /// See [AsyncButton.successDisplayDuration]. final Duration? successDisplayDuration; + + /// See [AsyncButton.errorDisplayDuration]. final Duration? errorDisplayDuration; + + /// See [AsyncButton.cooldownDuration]. final Duration? cooldownDuration; + + /// See [AsyncButton.animateSize]. final bool? animateSize; + + /// See [AsyncButton.hapticOn]. final HapticOn? hapticOn; + + /// See [AsyncButton.announceSemantics]. final bool? announceSemantics; + + /// See [AsyncButton.rethrowErrors]. final bool? rethrowErrors; } @@ -64,6 +105,8 @@ abstract class AsyncMaterialButton extends StatelessWidget { /// [IconAsyncButton] does not extend this — it carries a different field /// set ([IconButton]'s API). abstract class AsyncStandardMaterialButton extends AsyncMaterialButton { + /// Subclass-only constructor. Adds Material parameters common to + /// [ElevatedButton]/[FilledButton]/[OutlinedButton]/[TextButton]. const AsyncStandardMaterialButton({ super.key, required super.child, @@ -99,14 +142,30 @@ abstract class AsyncStandardMaterialButton extends AsyncMaterialButton { }) : _icon = icon, _iconAlignment = iconAlignment; + /// Forwarded to the underlying Material button. final VoidCallback? onLongPress; + + /// Forwarded to the underlying Material button. final ValueChanged? onHover; + + /// Forwarded to the underlying Material button. final ValueChanged? onFocusChange; + + /// Forwarded to the underlying Material button. final ButtonStyle? style; + + /// Forwarded to the underlying Material button. final FocusNode? focusNode; + + /// Forwarded to the underlying Material button. final bool autofocus; + + /// Forwarded to the underlying Material button. final Clip? clipBehavior; + + /// Forwarded to the underlying Material button. final WidgetStatesController? statesController; + final Widget? _icon; final IconAlignment? _iconAlignment; } diff --git a/lib/src/buttons/elevated_async_button.dart b/lib/src/buttons/elevated_async_button.dart index 2b73d99..974457f 100644 --- a/lib/src/buttons/elevated_async_button.dart +++ b/lib/src/buttons/elevated_async_button.dart @@ -4,6 +4,7 @@ part of '../../material_async_button.dart'; /// swapped for a loading widget; success/error are shown afterwards if /// configured via prop or theme. class ElevatedAsyncButton extends AsyncStandardMaterialButton { + /// Mirrors [ElevatedButton.new]. const ElevatedAsyncButton({ super.key, required super.onPressed, diff --git a/lib/src/buttons/filled_async_button.dart b/lib/src/buttons/filled_async_button.dart index bccc8df..2b4ee58 100644 --- a/lib/src/buttons/filled_async_button.dart +++ b/lib/src/buttons/filled_async_button.dart @@ -6,6 +6,7 @@ enum _FilledVariant { primary, tonal } /// [FilledAsyncButton.new], [FilledAsyncButton.tonal], /// [FilledAsyncButton.icon], [FilledAsyncButton.tonalIcon]. class FilledAsyncButton extends AsyncStandardMaterialButton { + /// Mirrors [FilledButton.new]. const FilledAsyncButton({ super.key, required super.onPressed, @@ -38,6 +39,7 @@ class FilledAsyncButton extends AsyncStandardMaterialButton { super.rethrowErrors, }) : _variant = .primary; + /// Mirrors [FilledButton.tonal]. const FilledAsyncButton.tonal({ super.key, required super.onPressed, @@ -70,6 +72,7 @@ class FilledAsyncButton extends AsyncStandardMaterialButton { super.rethrowErrors, }) : _variant = .tonal; + /// Mirrors [FilledButton.icon]. const FilledAsyncButton.icon({ super.key, required super.onPressed, @@ -105,6 +108,7 @@ class FilledAsyncButton extends AsyncStandardMaterialButton { }) : _variant = .primary, super(icon: icon, child: label); + /// Mirrors [FilledButton.tonalIcon]. const FilledAsyncButton.tonalIcon({ super.key, required super.onPressed, diff --git a/lib/src/buttons/icon_async_button.dart b/lib/src/buttons/icon_async_button.dart index ee15ac5..b30ffca 100644 --- a/lib/src/buttons/icon_async_button.dart +++ b/lib/src/buttons/icon_async_button.dart @@ -9,6 +9,7 @@ enum _IconVariant { standard, filled, filledTonal, outlined } /// The [icon] is swapped with `loadingChild`/`successChild`/`errorChild` /// during the corresponding state. class IconAsyncButton extends AsyncMaterialButton { + /// Mirrors [IconButton.new]. const IconAsyncButton({ super.key, required super.onPressed, @@ -54,6 +55,7 @@ class IconAsyncButton extends AsyncMaterialButton { }) : _variant = .standard, super(child: icon); + /// Mirrors [IconButton.filled]. const IconAsyncButton.filled({ super.key, required super.onPressed, @@ -99,6 +101,7 @@ class IconAsyncButton extends AsyncMaterialButton { }) : _variant = .filled, super(child: icon); + /// Mirrors [IconButton.filledTonal]. const IconAsyncButton.filledTonal({ super.key, required super.onPressed, @@ -144,6 +147,7 @@ class IconAsyncButton extends AsyncMaterialButton { }) : _variant = .filledTonal, super(child: icon); + /// Mirrors [IconButton.outlined]. const IconAsyncButton.outlined({ super.key, required super.onPressed, @@ -189,27 +193,69 @@ class IconAsyncButton extends AsyncMaterialButton { }) : _variant = .outlined, super(child: icon); + /// Idle icon. Swapped with `loadingChild`/`successChild`/`errorChild`. final Widget icon; + + /// Forwarded to the underlying [IconButton]. final double? iconSize; + + /// Forwarded to the underlying [IconButton]. final VisualDensity? visualDensity; + + /// Forwarded to the underlying [IconButton]. final EdgeInsetsGeometry? padding; + + /// Forwarded to the underlying [IconButton]. final AlignmentGeometry? alignment; + + /// Forwarded to the underlying [IconButton]. final double? splashRadius; + + /// Forwarded to the underlying [IconButton]. final Color? color; + + /// Forwarded to the underlying [IconButton]. final Color? focusColor; + + /// Forwarded to the underlying [IconButton]. final Color? hoverColor; + + /// Forwarded to the underlying [IconButton]. final Color? highlightColor; + + /// Forwarded to the underlying [IconButton]. final Color? splashColor; + + /// Forwarded to the underlying [IconButton]. final Color? disabledColor; + + /// Forwarded to the underlying [IconButton]. final MouseCursor? mouseCursor; + + /// Forwarded to the underlying [IconButton]. final FocusNode? focusNode; + + /// Forwarded to the underlying [IconButton]. final bool autofocus; + + /// Forwarded to the underlying [IconButton]. final String? tooltip; + + /// Forwarded to the underlying [IconButton]. final bool? enableFeedback; + + /// Forwarded to the underlying [IconButton]. final BoxConstraints? constraints; + + /// Forwarded to the underlying [IconButton]. final ButtonStyle? style; + + /// Forwarded to the underlying [IconButton]. final bool? isSelected; + + /// Forwarded to the underlying [IconButton]. final Widget? selectedIcon; + final _IconVariant _variant; @override diff --git a/lib/src/buttons/outlined_async_button.dart b/lib/src/buttons/outlined_async_button.dart index d2a8eab..2c21cf8 100644 --- a/lib/src/buttons/outlined_async_button.dart +++ b/lib/src/buttons/outlined_async_button.dart @@ -2,6 +2,7 @@ part of '../../material_async_button.dart'; /// Async-aware [OutlinedButton]. class OutlinedAsyncButton extends AsyncStandardMaterialButton { + /// Mirrors [OutlinedButton.new]. const OutlinedAsyncButton({ super.key, required super.onPressed, @@ -34,6 +35,7 @@ class OutlinedAsyncButton extends AsyncStandardMaterialButton { super.rethrowErrors, }); + /// Mirrors [OutlinedButton.icon]. const OutlinedAsyncButton.icon({ super.key, required super.onPressed, diff --git a/lib/src/buttons/text_async_button.dart b/lib/src/buttons/text_async_button.dart index 15a4bc7..3238db8 100644 --- a/lib/src/buttons/text_async_button.dart +++ b/lib/src/buttons/text_async_button.dart @@ -2,6 +2,7 @@ part of '../../material_async_button.dart'; /// Async-aware [TextButton]. class TextAsyncButton extends AsyncStandardMaterialButton { + /// Mirrors [TextButton.new]. const TextAsyncButton({ super.key, required super.onPressed, @@ -34,6 +35,7 @@ class TextAsyncButton extends AsyncStandardMaterialButton { super.rethrowErrors, }); + /// Mirrors [TextButton.icon]. const TextAsyncButton.icon({ super.key, required super.onPressed, diff --git a/lib/src/material_async_button_theme.dart b/lib/src/material_async_button_theme.dart index a16ead4..18e27d0 100644 --- a/lib/src/material_async_button_theme.dart +++ b/lib/src/material_async_button_theme.dart @@ -1,7 +1,19 @@ part of '../material_async_button.dart'; /// Which haptic event, if any, to fire on state transitions. -enum HapticOn { none, success, error, both } +enum HapticOn { + /// Fire no haptic on state transitions. + none, + + /// Fire a light haptic on success only. + success, + + /// Fire a light haptic on error only. + error, + + /// Fire a light haptic on both success and error. + both, +} /// App-wide defaults for `material_async_button` widgets, attached as a /// [ThemeExtension] on [ThemeData]. @@ -20,6 +32,8 @@ enum HapticOn { none, success, error, both } /// ``` @immutable class AsyncButtonTheme extends ThemeExtension { + /// Builds an [AsyncButtonTheme]. Every field is nullable so callers only + /// set the ones they want. const AsyncButtonTheme({ this.loadingChild, this.successChild, @@ -84,14 +98,22 @@ class AsyncButtonTheme extends ThemeExtension { /// Cross-fade duration between state widgets. /// Falls back to 200ms when null. final Duration? switchDuration; + + /// Reverse cross-fade duration. Falls back to [switchDuration] when null. final Duration? switchReverseDuration; /// Convenience: applied to both [switchInCurve] and [switchOutCurve] /// unless one of those is set explicitly. final Curve? switchCurve; + + /// Curve for the incoming widget during the cross-fade. final Curve? switchInCurve; + + /// Curve for the outgoing widget during the cross-fade. final Curve? switchOutCurve; + /// Custom transition for the underlying [AnimatedSwitcher]. Defaults to a + /// fade transition. final AnimatedSwitcherTransitionBuilder? transitionBuilder; /// How long [successChild] is shown before returning to idle. Defaults to @@ -109,8 +131,14 @@ class AsyncButtonTheme extends ThemeExtension { /// Whether to animate the implicit size between state widgets of differing /// dimensions. Falls back to `false`. final bool? animateSize; + + /// Curve used by the [AnimatedSize] when [animateSize] is true. final Curve? sizeCurve; + + /// Alignment used by the [AnimatedSize] when [animateSize] is true. final AlignmentGeometry? sizeAlignment; + + /// Clip behavior used by the [AnimatedSize] when [animateSize] is true. final Clip? sizeClipBehavior; /// Whether to fire a [HapticFeedback] on success / error transitions. From 9dbf57150441221908d3e9093cf32ac986d31dda Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Tue, 26 May 2026 13:13:13 +0300 Subject: [PATCH 105/176] docs(readme): drop migration-from-async_button_builder section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Treating material_async_button as a clean v1.0.0 — no migration story needed in the README. Co-Authored-By: Claude Opus 4.7 --- README.md | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/README.md b/README.md index 8fa3f44..028c460 100644 --- a/README.md +++ b/README.md @@ -210,26 +210,6 @@ theme, then set only the fields you care about. Per-widget overrides - `rethrowErrors` — rethrow from `controller.trigger()` so callers can `try/catch` while the UI also shows the error -## Migrating from `async_button_builder` - -After: - -1. `dependencies: async_button_builder: ^3.0.0` → `material_async_button: ^1.0.0` -2. `import 'package:async_button_builder/async_button_builder.dart'` - → `import 'package:material_async_button/material_async_button.dart'` - -Then: - -- `AsyncButtonBuilder` → `AsyncButton` -- `AsyncButtonState` (sealed) → `AsyncButtonStatus` (still sealed; renamed - for clarity and re-prefixed variants `AsyncButtonStatusIdle`, - `AsyncButtonStatusLoading`, `AsyncButtonStatusSuccess`, - `AsyncButtonStatusError(error, stackTrace)`). -- `state.error` → destructure the error variant: - `AsyncButtonStatusError(:final error)`. -- The previous `errorBuilder` is gone — pattern-match the status in your - `builder` callback, or render `errorChild`. - ## Claude Code skill A Claude Code skill that teaches Claude to use this package idiomatically From aaefb1850829d86add6cd71679cf65e41d19dfb5 Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Tue, 26 May 2026 13:19:08 +0300 Subject: [PATCH 106/176] ci: split CI into format/analyze/test/pana/example, add tag-triggered pub.dev publish Match the workflow shape used in the other esenmx pub.dev packages (fluiver, rand): one job per concern, default dart format (no --line-length override), pana score informational, separate example analyze. Add publish.yaml that fires on v* tags and uses pub.dev OIDC trusted publishing. Also fill in homepage and documentation URLs in pubspec.yaml. --- .github/workflows/ci.yaml | 87 ++++++++++++++++++++++++++++++++++ .github/workflows/dart.yaml | 44 ----------------- .github/workflows/publish.yaml | 42 ++++++++++++++++ pubspec.yaml | 2 + 4 files changed, 131 insertions(+), 44 deletions(-) create mode 100644 .github/workflows/ci.yaml delete mode 100644 .github/workflows/dart.yaml create mode 100644 .github/workflows/publish.yaml diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..23f93b0 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,87 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + format: + name: Format + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - uses: subosito/flutter-action@v2 + with: + channel: stable + cache: true + - run: flutter pub get + - run: dart format --output=none --set-exit-if-changed . + + analyze: + name: Analyze + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - uses: subosito/flutter-action@v2 + with: + channel: stable + cache: true + - run: flutter pub get + - run: flutter analyze --fatal-infos --fatal-warnings + + test: + name: Test (Flutter ${{ matrix.flutter }}) + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + flutter: [stable, beta] + steps: + - uses: actions/checkout@v6 + - uses: subosito/flutter-action@v2 + with: + channel: ${{ matrix.flutter }} + cache: true + - run: flutter pub get + - run: flutter test --coverage + - name: Upload coverage + if: matrix.flutter == 'stable' + uses: actions/upload-artifact@v4 + with: + name: coverage + path: coverage/lcov.info + + pana: + name: Pana score + runs-on: ubuntu-latest + continue-on-error: true + steps: + - uses: actions/checkout@v6 + - uses: subosito/flutter-action@v2 + with: + channel: stable + cache: true + - run: flutter pub get + - run: dart pub global activate pana + - run: pana --no-warning + + example: + name: Example analyze + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - uses: subosito/flutter-action@v2 + with: + channel: stable + cache: true + - run: flutter pub get + working-directory: example + - run: flutter analyze + working-directory: example diff --git a/.github/workflows/dart.yaml b/.github/workflows/dart.yaml deleted file mode 100644 index 0432ec5..0000000 --- a/.github/workflows/dart.yaml +++ /dev/null @@ -1,44 +0,0 @@ -name: CI - -on: - push: - branches: [main] - pull_request: - -jobs: - build: - timeout-minutes: 15 - runs-on: ubuntu-latest - strategy: - matrix: - channel: [stable, beta] - fail-fast: false - steps: - - uses: actions/checkout@v4 - - - uses: subosito/flutter-action@v2 - with: - channel: ${{ matrix.channel }} - - - name: Install dependencies - run: flutter pub get - - - name: Check formatting - run: dart format --line-length 100 --set-exit-if-changed . - - - name: Analyze - run: flutter analyze - - - name: Test with coverage - run: flutter test --coverage - - - name: Upload coverage - if: matrix.channel == 'stable' - uses: actions/upload-artifact@v4 - with: - name: coverage - path: coverage/lcov.info - - - name: Validate publish (dry run) - if: matrix.channel == 'stable' - run: flutter pub publish --dry-run diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml new file mode 100644 index 0000000..b7fedd1 --- /dev/null +++ b/.github/workflows/publish.yaml @@ -0,0 +1,42 @@ +name: Publish + +on: + push: + tags: + - 'v[0-9]+.[0-9]+.[0-9]+*' + +permissions: + id-token: write + contents: read + +jobs: + verify: + name: Verify tag matches pubspec + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - name: Check tag matches pubspec version + run: | + TAG="${GITHUB_REF#refs/tags/v}" + PUBSPEC=$(grep '^version:' pubspec.yaml | awk '{print $2}') + if [ "$TAG" != "$PUBSPEC" ]; then + echo "::error::Tag v$TAG does not match pubspec.yaml version $PUBSPEC" + exit 1 + fi + + publish: + name: Publish to pub.dev + needs: verify + runs-on: ubuntu-latest + environment: pub.dev + permissions: + id-token: write + contents: read + steps: + - uses: actions/checkout@v6 + - uses: dart-lang/setup-dart@v1 + - uses: subosito/flutter-action@v2 + with: + channel: stable + - run: flutter pub get + - run: flutter pub publish --force diff --git a/pubspec.yaml b/pubspec.yaml index f2c57cc..3044687 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,8 +4,10 @@ description: >- and error states with theming via ThemeExtension and external control via a controller. version: 1.0.0 +homepage: https://mehmetesen.com repository: https://github.com/esenmx/material_async_button issue_tracker: https://github.com/esenmx/material_async_button/issues +documentation: https://pub.dev/documentation/material_async_button/latest/ topics: - button From 693ad9b2c6ab0d5e4f2a58a24fdca2f7ffec3cf3 Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Tue, 26 May 2026 13:24:21 +0300 Subject: [PATCH 107/176] docs(readme): use tear-off form for onPressed examples --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 028c460..f176695 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ build a project-wide wrapper widget. ```dart ElevatedAsyncButton( - onPressed: () async => api.save(), + onPressed: api.save, child: const Text('Save'), ) ``` @@ -116,7 +116,7 @@ The error variant owns its thrown payload. Render it inline in the builder: ```dart AsyncButton( - onPressed: () async => repo.submit(), + onPressed: repo.submit, builder: (context, child, callback, status) => switch (status) { AsyncButtonStatusError(:final error) => Text('failed: $error'), @@ -142,7 +142,7 @@ For one-shot notifications (snackbar, log), `onError`: ```dart ElevatedAsyncButton( - onPressed: () async => repo.submit(), + onPressed: repo.submit, onError: (error, stackTrace) => log.warn('$error'), errorChild: const Icon(Icons.error_outline), child: const Text('Submit'), From 0c4c5228c3756d36be6fd10209cdf02c9c1897f2 Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Tue, 26 May 2026 13:26:53 +0300 Subject: [PATCH 108/176] chore(release): 1.0.1 --- CHANGELOG.md | 6 ++++++ pubspec.yaml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f48b724..0726620 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# 1.0.1 + +- Docs: use tear-off form (`onPressed: api.save`) in README examples. +- CI: split workflow into format/analyze/test/pana/example, add + tag-triggered pub.dev publish via OIDC trusted publishing. + # 1.0.0 Initial release. Renamed from `async_button_builder` to `material_async_button` diff --git a/pubspec.yaml b/pubspec.yaml index 3044687..0dad0c5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -3,7 +3,7 @@ description: >- Drop-in async wrappers for Flutter Material buttons. Adds loading, success, and error states with theming via ThemeExtension and external control via a controller. -version: 1.0.0 +version: 1.0.1 homepage: https://mehmetesen.com repository: https://github.com/esenmx/material_async_button issue_tracker: https://github.com/esenmx/material_async_button/issues From aec3cb0908aa8c2beacff297fb4be8b6a780dc11 Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Sun, 31 May 2026 10:23:39 +0300 Subject: [PATCH 109/176] feat!: redesign as loading-only async button (v2.0.0) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Breaking redesign: the button does one job — show a spinner while onPressed is in flight — and stays out of error handling, success feedback, and styling. State collapses to a single bool (isLoading); the theme becomes a pure complement to ButtonStyle. See CHANGELOG for the full breaking-change list. Co-Authored-By: Claude Opus 4.8 --- CHANGELOG.md | 59 ++- README.md | 234 ++++----- example/.metadata | 12 +- example/analysis_options.yaml | 1 + example/lib/main.dart | 114 +++-- example/pubspec.yaml | 1 + lib/material_async_button.dart | 5 - lib/src/async_button.dart | 458 +++++------------- lib/src/async_button_controller.dart | 159 ++---- lib/src/async_button_status.dart | 107 ---- lib/src/buttons/async_material_button.dart | 98 +--- lib/src/buttons/elevated_async_button.dart | 73 +-- lib/src/buttons/filled_async_button.dart | 108 +---- lib/src/buttons/icon_async_button.dart | 97 +--- lib/src/buttons/outlined_async_button.dart | 65 +-- lib/src/buttons/text_async_button.dart | 65 +-- lib/src/material_async_button_theme.dart | 398 ++++----------- pubspec.yaml | 9 +- test/_helpers.dart | 53 +- test/async_button_controller_test.dart | 159 ++---- test/async_button_test.dart | 314 ++++++------ test/elevated_async_button_test.dart | 63 +-- test/filled_async_button_test.dart | 92 +++- test/icon_async_button_test.dart | 41 ++ test/material_async_button_theme_test.dart | 156 ++---- test/outlined_async_button_test.dart | 16 +- test/text_async_button_test.dart | 26 +- .../flutter-material-async-button/SKILL.md | 106 ++-- 28 files changed, 1003 insertions(+), 2086 deletions(-) create mode 100644 example/analysis_options.yaml delete mode 100644 lib/src/async_button_status.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index 0726620..c4fce20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,65 @@ -# 1.0.1 +# CHANGELOG + +## 2.0.0 + +Breaking redesign. The button now does exactly one job — show a spinner while +`onPressed` is in flight — and stays out of error handling, success feedback, +and styling. State collapses to a single `bool` (loading), and the theme becomes +a pure complement to `ButtonStyle`. + +### Breaking + +- **Loading-only: no success or error state.** Removed `AsyncButtonStatus` + entirely (the state is now a plain `bool isLoading`), along with `onSuccess`, + `onError`, `successBuilder`, `errorBuilder`, `feedbackDuration`, + `cooldownDuration`, `markSuccess`, `markError`, `haptic` / `HapticOn`, and + `announce` / `AsyncButtonAnnouncer` / `defaultAsyncButtonAnnouncer`. An + in-button error view is a Material anti-pattern; success is handled by what + your action already does (navigate away, flip the label). Both belong to your + state management, not the button. +- **`onPressed` throws now re-propagate.** When `onPressed` throws, the button + returns to idle and **re-throws** so the error reaches `FlutterError.onError` + / your `runZonedGuarded` zone. `controller.trigger()` rethrows instead of + completing normally. +- **`AsyncButtonController` is now a `ValueListenable`** (`isLoading`). + Builders receive `bool isLoading` instead of an `AsyncButtonStatus`; observe + it with `addListener` / `ValueListenableBuilder`. +- **`AsyncButtonTheme` carries only `loadingBuilder` + `transitionBuilder`.** + `AsyncButtonTheme.empty` (spinner-only) is the sole baseline; removed + `AsyncButtonTheme.material()`. It complements `ButtonStyle` — no styling. +- **`disabled` flag → `enabled` (defaults to `true`).** Affirmative naming that + pairs with a tear-off `onPressed`. Either `enabled: false` or `onPressed: null` + disables — both also no-op an external `controller.trigger()`. +- **`loadingChild` (a `Widget`) → `loadingBuilder` (a `WidgetBuilder`)** on both + the widgets and `AsyncButtonTheme`. +- **Removed the loading-colour knobs** (`loadingForegroundColor`, + `material(loadingColor:)`). The spinner inherits each button variant's + foreground; recolour a single button via `AsyncButtonSpinner(color: ...)`. + +### Fixed + +- **Loading never disables the button.** It keeps the button's themed enabled + colours — being loading and being *disabled* are different things. The spinner + inherits the enabled foreground for free (no more greyed indicator); taps that + can't run are silently swallowed, and `onLongPress` is gated off while busy. + The button shows the disabled look **only** when explicitly disabled via + `onPressed: null`. +- **`.icon` buttons drop the icon while loading**, rendering the spinner alone. + +### Improved + +- The default `AsyncButtonSpinner` derives its size from the ambient font size, + so it matches the button's label instead of a fixed 16px. +- Guarded against state changes on an unmounted button. +- Corrected the `flutter` SDK constraint. + +## 1.0.1 - Docs: use tear-off form (`onPressed: api.save`) in README examples. - CI: split workflow into format/analyze/test/pana/example, add tag-triggered pub.dev publish via OIDC trusted publishing. -# 1.0.0 +## 1.0.0 Initial release. Renamed from `async_button_builder` to `material_async_button` with a redesigned, theme-aware API. diff --git a/README.md b/README.md index f176695..8508842 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,8 @@ # material_async_button -Drop-in async wrappers for Flutter Material buttons. Adds **loading**, -**success**, and **error** statuses to `ElevatedButton`, `FilledButton`, -`OutlinedButton`, `TextButton`, and `IconButton` — without forcing you to -build a project-wide wrapper widget. +Drop-in async wrappers for Flutter Material buttons. Adds a **loading** state to +`ElevatedButton`, `FilledButton`, `OutlinedButton`, `TextButton`, and +`IconButton` — without forcing you to build a project-wide wrapper widget. ```dart ElevatedAsyncButton( @@ -12,34 +11,24 @@ ElevatedAsyncButton( ) ``` -That's it. The button shows a spinner while `save()` runs and re-enables -when it returns or throws. +That's it. The button shows a spinner while `save()` runs and returns to its +label when it completes. ## Install ```yaml dependencies: - material_async_button: ^1.0.0 + material_async_button: ^2.0.0 ``` Requires Dart `^3.10.0` (any Flutter SDK shipping Dart 3.10+). ## Why -Most apps end up writing their own `DefaultAsyncButton` wrapper to share -loading-spinner widgets, durations, and transition curves across screens. -This package gives you that wrapper as a [`ThemeExtension`][th]: - -```dart -MaterialApp( - theme: ThemeData( - extensions: [AsyncButtonTheme.material()], - ), -) -``` - -Configure once, every `*AsyncButton` in the app picks it up. Override per -button when you need to. +Most apps end up writing their own `DefaultAsyncButton` wrapper to share a +loading widget and its transition across screens. This package gives you that +wrapper as a [`ThemeExtension`][th] — configure once, every `*AsyncButton` picks +it up; override per button when you need to. [th]: https://api.flutter.dev/flutter/material/ThemeExtension-class.html @@ -55,111 +44,93 @@ button when you need to. Every Material constructor is mirrored. All Material parameters (`style`, `focusNode`, `autofocus`, `clipBehavior`, `statesController`, etc.) are -forwarded verbatim. +forwarded verbatim. `AsyncButtonTheme` complements `ButtonStyle` / +`ButtonThemeData` — it carries only the loading view, never styling. + +## Loading only — by design + +The button does one job: show a spinner while `onPressed` is in flight. It has +no success or error state. + +- **No error state.** An in-button error view is a Material anti-pattern, and + error handling belongs to your state management. When `onPressed` throws, the + button returns to idle and **re-throws** — the error reaches + `FlutterError.onError` / your `runZonedGuarded` zone, like any other uncaught + error. Handle it where it belongs: + + ```dart + // Typical: your notifier/repository absorbs the failure internally + // (e.g. AsyncValue.guard), so onPressed never throws. + ElevatedAsyncButton( + onPressed: () => ref.read(saveProvider.notifier).save(), + child: const Text('Save'), + ) + + // Or handle it inline and surface it your way: + ElevatedAsyncButton( + onPressed: () async { + try { + await repo.submit(); + } on Exception catch (error) { + messenger.showSnackBar(SnackBar(content: Text('$error'))); + } + }, + child: const Text('Submit'), + ) + ``` + +- **No success state.** Success is handled by what your action already does — + navigate away, flip the label (Save → Unsave), update a list. An in-button + "Saved ✓" is usually redundant. Surface it the same way you surface any state + change. ## Theming -`AsyncButtonTheme` is a `ThemeExtension`. Resolution order for any -field is **per-widget value → theme value → built-in fallback**. +`AsyncButtonTheme` is a `ThemeExtension`. Resolution order for any field is +**per-widget value → theme value → built-in fallback**. ```dart ThemeData( extensions: [ AsyncButtonTheme( - switchDuration: const Duration(milliseconds: 200), - successDisplayDuration: const Duration(milliseconds: 800), - errorDisplayDuration: const Duration(milliseconds: 800), - successChild: const Icon(Icons.check), - errorChild: const Icon(Icons.error_outline), - animateSize: true, - hapticOn: HapticOn.both, - announceSemantics: true, + loadingBuilder: (_) => const AsyncButtonSpinner(strokeWidth: 3), + // transitionBuilder: animate every button's swap — see Defaults below. ), ], ) ``` -Or grab the opinionated baseline: - -```dart -ThemeData(extensions: [AsyncButtonTheme.material()]) -``` +With no extension registered, `AsyncButtonTheme.of` falls back to +`AsyncButtonTheme.empty` — the default spinner and nothing else. -## Status pattern matching +## Custom buttons — `AsyncButton` -`AsyncButtonStatus` is sealed. The error variant carries the error and -stack trace as fields — destructure them inline: +`AsyncButton` is the low-level escape hatch. Use it when none of the Material +wrappers fit. The builder receives whether the button is loading: ```dart AsyncButton( onPressed: doWork, child: const Text('Go'), - builder: (context, child, callback, status) => MyButton( + builder: (context, child, callback, isLoading) => MyButton( onTap: callback, - color: switch (status) { - AsyncButtonStatusIdle() => Colors.blue, - AsyncButtonStatusLoading() => Colors.grey, - AsyncButtonStatusSuccess() => Colors.green, - AsyncButtonStatusError() => Colors.red, - }, + color: isLoading ? Colors.grey : Colors.indigo, child: child, ), ) ``` -`AsyncButton` is the low-level escape hatch. Use it when none of the -Material wrappers fit. - -## Error payload - -The error variant owns its thrown payload. Render it inline in the builder: - -```dart -AsyncButton( - onPressed: repo.submit, - builder: (context, child, callback, status) => switch (status) { - AsyncButtonStatusError(:final error) => - Text('failed: $error'), - _ => MyButton(onTap: callback, child: child), - }, - child: const Text('Submit'), -) -``` - -Or react externally: - -```dart -ValueListenableBuilder( - valueListenable: controller, - builder: (_, status, _) => switch (status) { - AsyncButtonStatusError(:final error) => Text('$error'), - _ => const SizedBox.shrink(), - }, -) -``` - -For one-shot notifications (snackbar, log), `onError`: - -```dart -ElevatedAsyncButton( - onPressed: repo.submit, - onError: (error, stackTrace) => log.warn('$error'), - errorChild: const Icon(Icons.error_outline), - child: const Text('Submit'), -) -``` - ## External control -`AsyncButtonController` is a `ValueListenable` plus -imperative methods. Use it for **form keyboard "Done"**, parent-owned -state, cross-widget reactions, and tests. +`AsyncButtonController` is a `ValueListenable` (loading) plus imperative +methods. Use it for **form keyboard "Done"**, parent-owned state, cross-widget +reactions, and tests. ```dart final controller = AsyncButtonController(); // dispose like any ChangeNotifier TextField( - textInputAction: TextInputAction.done, + textInputAction: .done, onSubmitted: (_) => controller.trigger(), ) ElevatedAsyncButton( @@ -168,47 +139,50 @@ ElevatedAsyncButton( child: const Text('Submit'), ) -// any time: -controller.trigger(); // run onPressed from outside -controller.invalidate('server rejected'); // force error -controller.markSuccess(); // force success -controller.reset(); // back to idle - -// inspect: -controller.value; // AsyncButtonStatus (sealed) -// Pattern-match value for the error payload: -if (controller.value case AsyncButtonStatusError(:final error)) { - log.warn('$error'); -} +controller.trigger(); // run onPressed from outside (rethrows on failure) +controller.reset(); // force back to idle +controller.isLoading; // bool ``` ## Defaults -When no `AsyncButtonTheme` extension is registered, `AsyncButtonTheme.of` -falls back to `AsyncButtonTheme.material()`: - -| Status | Default UI | -| ---------- | ------------------------------------------------------- | -| idle | your `child` | -| loading | 16×16 `CircularProgressIndicator` | -| success | `Icons.check`, displayed for 800ms | -| error | `Icons.error`, displayed for 800ms | - -Opt out of the baseline by registering `AsyncButtonTheme.empty` on the -theme, then set only the fields you care about. Per-widget overrides -(e.g. `successChild:` on a single button) always win. - -## Features - -- `confirmBeforePress` — gate `onPressed` behind a confirmation `Future` -- `onSuccess` / `onError` / `onStateChanged` — fire-and-forget callbacks -- `errorChild` — static widget shown during error status -- `cooldownDuration` — disable the button briefly after success to prevent - double-submit -- `hapticOn` — light haptic on success/error -- `announceSemantics` — `SemanticsService.sendAnnouncement` for screen readers -- `rethrowErrors` — rethrow from `controller.trigger()` so callers can - `try/catch` while the UI also shows the error +| State | UI | +| -------- | ------------------------------------------- | +| idle | your `child` | +| loading | `AsyncButtonSpinner` (sized to the label) | + +`.icon` constructors drop the icon while loading and show the spinner alone. + +**Loading never disables the button.** Being loading and being *disabled* are +different things — the spinner is the indicator, the button keeps its themed +enabled colours, and taps that can't run are silently swallowed (`onLongPress` +is gated off while busy). The button shows the disabled look **only** when you +disable it explicitly — pass `enabled: false` (defaults to `true`) or +`onPressed: null`. Either path also no-ops an external `controller.trigger()`. + +**The swap is instant; the button resizes to fit the loading widget.** The +button does no animation of its own. To smooth the swap — and the size change +when the spinner differs from the child — pass a `transitionBuilder`. The child +is already keyed by loading state, so an `AnimatedSwitcher` inside an +`AnimatedSize` is all it takes: + +```dart +ElevatedAsyncButton( + onPressed: api.save, + transitionBuilder: (context, child, isLoading) => AnimatedSize( + duration: const Duration(milliseconds: 200), + child: AnimatedSwitcher( + duration: const Duration(milliseconds: 200), + child: child, + ), + ), + child: const Text('Save'), +) +``` + +Set `transitionBuilder` on `AsyncButtonTheme` to animate every button at once. +`AsyncButtonSpinner` is public and inherits the button's foreground — customise +its `color` / `strokeWidth` / `size` and return it from `loadingBuilder`. ## Claude Code skill diff --git a/example/.metadata b/example/.metadata index 5c982c8..c24b9a1 100644 --- a/example/.metadata +++ b/example/.metadata @@ -4,7 +4,7 @@ # This file should be version controlled and should not be manually edited. version: - revision: "ea121f8859e4b13e47a8f845e4586164519588bc" + revision: "00b0c91f06209d9e4a41f71b7a512d6eb3b9c694" channel: "stable" project_type: app @@ -13,11 +13,11 @@ project_type: app migration: platforms: - platform: root - create_revision: ea121f8859e4b13e47a8f845e4586164519588bc - base_revision: ea121f8859e4b13e47a8f845e4586164519588bc - - platform: ios - create_revision: ea121f8859e4b13e47a8f845e4586164519588bc - base_revision: ea121f8859e4b13e47a8f845e4586164519588bc + create_revision: 00b0c91f06209d9e4a41f71b7a512d6eb3b9c694 + base_revision: 00b0c91f06209d9e4a41f71b7a512d6eb3b9c694 + - platform: macos + create_revision: 00b0c91f06209d9e4a41f71b7a512d6eb3b9c694 + base_revision: 00b0c91f06209d9e4a41f71b7a512d6eb3b9c694 # User provided section diff --git a/example/analysis_options.yaml b/example/analysis_options.yaml new file mode 100644 index 0000000..f9b3034 --- /dev/null +++ b/example/analysis_options.yaml @@ -0,0 +1 @@ +include: package:flutter_lints/flutter.yaml diff --git a/example/lib/main.dart b/example/lib/main.dart index ea858a1..7bc2b1f 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -10,11 +10,7 @@ class MyApp extends StatelessWidget { Widget build(BuildContext context) { return MaterialApp( title: 'material_async_button demo', - theme: ThemeData( - colorSchemeSeed: Colors.indigo, - useMaterial3: true, - extensions: [AsyncButtonTheme.material()], - ), + theme: ThemeData(colorSchemeSeed: Colors.indigo), home: const HomePage(), ); } @@ -41,15 +37,32 @@ class _HomePageState extends State { } Future _simulateWork({bool fail = false}) async { - await Future.delayed(const Duration(milliseconds: 800)); - if (fail) throw StateError('simulated failure'); + await Future.delayed(const Duration(seconds: 1)); + if (fail) { + throw Exception('simulated failure'); + } + } + + /// A button is not the place to surface errors. A throw from `onPressed` + /// returns the button to idle and re-propagates — so handle it here (in real + /// apps, in your state management) and surface it your way. + Future _submit(BuildContext context, {bool fail = false}) async { + try { + await _simulateWork(fail: fail); + } on Exception catch (error) { + if (context.mounted) { + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text('Failed: $error'))); + } + } } @override Widget build(BuildContext context) => Scaffold( appBar: AppBar(title: const Text('material_async_button')), body: SingleChildScrollView( - padding: const EdgeInsets.all(16), + padding: const .all(16), child: Column( crossAxisAlignment: .stretch, children: [ @@ -88,8 +101,8 @@ class _HomePageState extends State { ), const SizedBox(height: 8), OutlinedAsyncButton( - onPressed: () => _simulateWork(fail: true), - child: const Text('OutlinedAsyncButton (fails)'), + onPressed: () => _submit(context, fail: true), + child: const Text('OutlinedAsyncButton (handles failure)'), ), const SizedBox(height: 8), TextAsyncButton( @@ -97,6 +110,12 @@ class _HomePageState extends State { child: const Text('TextAsyncButton'), ), const SizedBox(height: 8), + FilledAsyncButton( + onPressed: _simulateWork, + enabled: false, + child: const Text('Disabled (enabled: false)'), + ), + const SizedBox(height: 8), Row( mainAxisAlignment: .spaceEvenly, children: [ @@ -119,21 +138,18 @@ class _HomePageState extends State { ], ), const Divider(height: 32), - const _SectionLabel('Per-button overrides'), - ElevatedAsyncButton( + const _SectionLabel('Animated spinner swap'), + FilledAsyncButton( onPressed: _simulateWork, - successChild: const Text('Saved!'), - successDisplayDuration: const Duration(milliseconds: 1200), - cooldownDuration: const Duration(seconds: 1), - child: const Text('Custom successChild + 1s cooldown'), + transitionBuilder: _animatedSwitchSize, + child: const Text('Save (animated)'), ), - const SizedBox(height: 8), - OutlinedAsyncButton( - onPressed: () => _simulateWork(fail: true), - errorChild: const Text('Failed — try again'), - errorDisplayDuration: const Duration(milliseconds: 1200), - onError: (error, _) => debugPrint('error: $error'), - child: const Text('Custom errorChild + onError'), + const Divider(height: 32), + const _SectionLabel('Custom loading widget'), + ElevatedAsyncButton( + onPressed: _simulateWork, + loadingBuilder: (_) => const AsyncButtonSpinner(strokeWidth: 3), + child: const Text('Thicker spinner'), ), const Divider(height: 32), const _SectionLabel('Form "Done" → controller.trigger()'), @@ -164,15 +180,6 @@ class _HomePageState extends State { onPressed: _externalController.trigger, child: const Text('trigger()'), ), - OutlinedButton( - onPressed: () => - _externalController.invalidate('server rejected'), - child: const Text('invalidate()'), - ), - OutlinedButton( - onPressed: _externalController.markSuccess, - child: const Text('markSuccess()'), - ), OutlinedButton( onPressed: _externalController.reset, child: const Text('reset()'), @@ -183,18 +190,23 @@ class _HomePageState extends State { const _SectionLabel('Custom button via AsyncButton'), AsyncButton( onPressed: _simulateWork, - animateSize: true, - builder: (ctx, child, callback, status) => Material( - color: switch (status) { - AsyncButtonStatusIdle() || - AsyncButtonStatusLoading() => Colors.indigo, - AsyncButtonStatusSuccess() => Colors.green, - AsyncButtonStatusError() => Colors.red, - }, - clipBehavior: .hardEdge, - shape: const StadiumBorder(), - child: InkWell(onTap: callback, child: child), - ), + loadingBuilder: (context) { + return Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 12, + ), + child: const AsyncButtonSpinner(strokeWidth: 3), + ); + }, + builder: (context, child, callback, isLoading) { + return Material( + color: isLoading ? Colors.indigo.shade200 : Colors.indigo, + clipBehavior: .hardEdge, + shape: const StadiumBorder(), + child: InkWell(onTap: callback, child: child), + ); + }, child: const Padding( padding: EdgeInsets.symmetric(horizontal: 16, vertical: 12), child: Text('Custom', style: TextStyle(color: Colors.white)), @@ -206,6 +218,20 @@ class _HomePageState extends State { ); } +/// Animates the spinner swap: [AnimatedSwitcher] cross-fades between the idle +/// child and the loading spinner (already keyed by loading state), and +/// [AnimatedSize] tweens the button's width as they differ in size. +Widget _animatedSwitchSize(BuildContext context, Widget child, bool isLoading) { + return AnimatedSize( + duration: const Duration(milliseconds: 250), + curve: Curves.easeOut, + child: AnimatedSwitcher( + duration: const Duration(milliseconds: 250), + child: child, + ), + ); +} + class _SectionLabel extends StatelessWidget { const _SectionLabel(this.text); diff --git a/example/pubspec.yaml b/example/pubspec.yaml index b76c652..e151c78 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -15,6 +15,7 @@ dependencies: dev_dependencies: checks: ^0.3.1 + flutter_lints: ^6.0.0 flutter_test: sdk: flutter diff --git a/lib/material_async_button.dart b/lib/material_async_button.dart index 7ff0856..d319b72 100644 --- a/lib/material_async_button.dart +++ b/lib/material_async_button.dart @@ -5,16 +5,11 @@ /// variants. Use `AsyncButton` when you need a custom non-Material button. library; -import 'dart:async'; - import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/semantics.dart'; -import 'package:flutter/services.dart'; part 'src/async_button.dart'; part 'src/async_button_controller.dart'; -part 'src/async_button_status.dart'; part 'src/buttons/async_material_button.dart'; part 'src/buttons/elevated_async_button.dart'; part 'src/buttons/filled_async_button.dart'; diff --git a/lib/src/async_button.dart b/lib/src/async_button.dart index d9be886..ff138df 100644 --- a/lib/src/async_button.dart +++ b/lib/src/async_button.dart @@ -2,48 +2,55 @@ part of '../material_async_button.dart'; /// Signature for [AsyncButton.builder]. /// -/// `callback` is `null` when the button should appear disabled (already -/// loading, in cooldown, or `onPressed`/`disabled` make it ineligible). +/// `callback` is `null` **only** when the button is explicitly disabled +/// (`enabled: false` or `onPressed == null`). Loading never disables the +/// button: while loading, `callback` stays non-null so the button keeps its +/// enabled look (the spinner is the state indicator). Taps that can't run are +/// silently swallowed by the controller, so they never double-submit. typedef AsyncButtonWidgetBuilder = Widget Function( BuildContext context, Widget child, AsyncCallback? callback, - AsyncButtonStatus status, + // Builder callbacks are positional by Flutter convention (cf. + // ValueWidgetBuilder); a named bool here would be un-idiomatic. + // ignore: avoid_positional_boolean_parameters + bool isLoading, ); -/// Signature for `onError`. Receives the thrown error plus the captured -/// stack trace. The error is delivered informationally — the button itself -/// only reacts to [AsyncButtonStatus]. -typedef AsyncButtonErrorCallback = - void Function( - Object error, - StackTrace stackTrace, +/// Signature for [AsyncButton.transitionBuilder]. +/// +/// Wraps the current state's [child] (already keyed by loading state) to +/// animate the idle ⇄ loading swap — e.g. an [AnimatedSwitcher] inside an +/// [AnimatedSize]. The button does no animation of its own; return [child] +/// unchanged for an instant swap. See the README for a worked example. +typedef AsyncButtonTransitionBuilder = + Widget Function( + BuildContext context, + Widget child, + // Builder callbacks are positional by Flutter convention (cf. + // ValueWidgetBuilder); a named bool here would be un-idiomatic. + // ignore: avoid_positional_boolean_parameters + bool isLoading, ); -/// Low-level async-status shell for arbitrary buttons. +/// Low-level async-loading shell for arbitrary buttons. /// /// Prefer the named Material wrappers ([ElevatedAsyncButton], /// [FilledAsyncButton], [OutlinedAsyncButton], [TextAsyncButton], /// [IconAsyncButton]). Reach for [AsyncButton] directly only when you need /// to render a non-Material button. /// -/// The builder receives the current [AsyncButtonStatus] — destructure the -/// error variant to render the error inline: -/// -/// ```dart -/// builder: (context, child, callback, status) => switch (status) { -/// AsyncButtonStatusError(:final error) => Text('failed: $error'), -/// _ => MyButton(onTap: callback, child: child), -/// } -/// ``` +/// The builder receives whether the button is loading — switch the chrome on +/// it: /// /// ```dart /// AsyncButton( /// onPressed: () async => doWork(), /// child: const Text('Go'), -/// builder: (context, child, callback, status) => MyCustomButton( +/// builder: (context, child, callback, isLoading) => MyCustomButton( /// onTap: callback, +/// color: isLoading ? Colors.grey : Colors.indigo, /// child: child, /// ), /// ) @@ -55,121 +62,40 @@ class AsyncButton extends StatefulWidget { required this.child, required this.onPressed, required this.builder, + this.enabled = true, this.controller, - this.onSuccess, - this.onError, - this.onStateChanged, - this.confirmBeforePress, - this.loadingChild, - this.successChild, - this.errorChild, - this.disabled = false, - this.switchDuration, - this.switchReverseDuration, - this.switchCurve, - this.switchInCurve, - this.switchOutCurve, + this.loadingBuilder, this.transitionBuilder, - this.successDisplayDuration, - this.errorDisplayDuration, - this.cooldownDuration, - this.animateSize, - this.sizeCurve, - this.sizeAlignment, - this.sizeClipBehavior, - this.hapticOn, - this.announceSemantics, - this.rethrowErrors, }); - /// Idle widget. Replaced by [loadingChild] / [successChild] / [errorChild] - /// during the matching [AsyncButtonStatus]. + /// Idle widget. Replaced by [loadingBuilder] while loading. final Widget child; /// Async callback. `null` makes the button appear disabled. final AsyncCallback? onPressed; + /// Whether the button is interactive. When `false` it renders the disabled + /// look, ignores taps, and no-ops an external [AsyncButtonController.trigger] + /// — same as `onPressed: null`, but the affirmative form that pairs with a + /// tear-off `onPressed`. Defaults to `true`. + final bool enabled; + /// Renders the button chrome. See [AsyncButtonWidgetBuilder]. final AsyncButtonWidgetBuilder builder; /// External controller. When null, the widget creates and owns its own. final AsyncButtonController? controller; - /// Called when the button enters [.success]. - final VoidCallback? onSuccess; - - /// Called when the button enters [.error]. - final AsyncButtonErrorCallback? onError; - - /// Fired on every status change. Use [onError] or read [controller] when - /// you also need the error payload. - final ValueChanged? onStateChanged; - - /// Runs before [onPressed]. If it returns `false` the press is cancelled - /// and no status change happens. - final Future Function(BuildContext context)? confirmBeforePress; - - /// Widget shown while loading. Falls back to [AsyncButtonTheme.loadingChild]. - final Widget? loadingChild; - - /// Widget shown briefly after success. Falls back to - /// [AsyncButtonTheme.successChild]. - final Widget? successChild; - - /// Widget shown briefly after error. Falls back to - /// [AsyncButtonTheme.errorChild]. - final Widget? errorChild; - - /// Forces the button to appear disabled regardless of status. - final bool disabled; - - /// Per-widget override of [AsyncButtonTheme.switchDuration]. - final Duration? switchDuration; - - /// Per-widget override of [AsyncButtonTheme.switchReverseDuration]. - final Duration? switchReverseDuration; - - /// Per-widget override of [AsyncButtonTheme.switchCurve]. - final Curve? switchCurve; + /// Builds the widget shown while loading, with the [AsyncButton]'s own + /// [BuildContext]. Falls back to [AsyncButtonTheme.loadingBuilder], then to + /// an [AsyncButtonSpinner]. The spinner inherits the button's foreground + /// colour automatically — to recolour it, return + /// `AsyncButtonSpinner(color: ...)`. + final WidgetBuilder? loadingBuilder; - /// Per-widget override of [AsyncButtonTheme.switchInCurve]. - final Curve? switchInCurve; - - /// Per-widget override of [AsyncButtonTheme.switchOutCurve]. - final Curve? switchOutCurve; - - /// Per-widget override of [AsyncButtonTheme.transitionBuilder]. - final AnimatedSwitcherTransitionBuilder? transitionBuilder; - - /// Per-widget override of [AsyncButtonTheme.successDisplayDuration]. - final Duration? successDisplayDuration; - - /// Per-widget override of [AsyncButtonTheme.errorDisplayDuration]. - final Duration? errorDisplayDuration; - - /// Per-widget override of [AsyncButtonTheme.cooldownDuration]. - final Duration? cooldownDuration; - - /// Per-widget override of [AsyncButtonTheme.animateSize]. - final bool? animateSize; - - /// Per-widget override of [AsyncButtonTheme.sizeCurve]. - final Curve? sizeCurve; - - /// Per-widget override of [AsyncButtonTheme.sizeAlignment]. - final AlignmentGeometry? sizeAlignment; - - /// Per-widget override of [AsyncButtonTheme.sizeClipBehavior]. - final Clip? sizeClipBehavior; - - /// Per-widget override of [AsyncButtonTheme.hapticOn]. - final HapticOn? hapticOn; - - /// Per-widget override of [AsyncButtonTheme.announceSemantics]. - final bool? announceSemantics; - - /// Per-widget override of [AsyncButtonTheme.rethrowErrors]. - final bool? rethrowErrors; + /// Per-widget override of [AsyncButtonTheme.transitionBuilder]. The button + /// performs no animation unless this (or the theme's) builder adds one. + final AsyncButtonTransitionBuilder? transitionBuilder; @override State createState() { @@ -178,264 +104,96 @@ class AsyncButton extends StatefulWidget { } class _AsyncButtonState extends State { - AsyncButtonController? _internalController; - AsyncButtonController get _controller => - widget.controller ?? _internalController!; - - AsyncButtonStatus _lastStatus = const .idle(); + late AsyncButtonController controller; + + /// The widget's `onPressed` once [AsyncButton.enabled] is applied — `null` + /// (disabled) when `enabled: false` or `onPressed == null`. Both disable + /// paths collapse here, so the controller and the builder callback stay in + /// agreement. + AsyncCallback? get effectiveOnPressed => + widget.enabled ? widget.onPressed : null; + + /// Handed to the builder. `null` when disabled (see [effectiveOnPressed]); + /// otherwise [AsyncButtonController.trigger]. Loading never disables the + /// button — trigger just no-ops while busy, so taps that can't run are + /// swallowed and the button keeps its enabled look. + AsyncCallback? get callback => + effectiveOnPressed == null ? null : controller.trigger; @override void initState() { super.initState(); - if (widget.controller == null) { - _internalController = AsyncButtonController(); - } - _controller.addListener(_handleControllerChange); - _lastStatus = _controller.value; + controller = widget.controller ?? AsyncButtonController(); + controller + ..addListener(listener) + ..attach(onPressed: effectiveOnPressed); } @override void didUpdateWidget(covariant AsyncButton oldWidget) { super.didUpdateWidget(oldWidget); - if (widget.controller == oldWidget.controller) { - return; - } - final previous = oldWidget.controller ?? _internalController; - previous?.removeListener(_handleControllerChange); - if (widget.controller != null) { - _internalController?.dispose(); - _internalController = null; - } else { - _internalController = AsyncButtonController(); + if (widget.controller != oldWidget.controller) { + controller.removeListener(listener); + // Dispose only a controller we created ourselves — never one the caller + // owns. + if (oldWidget.controller == null) { + controller.dispose(); + } + controller = widget.controller ?? AsyncButtonController(); + controller.addListener(listener); } - _controller.addListener(_handleControllerChange); - _lastStatus = _controller.value; + // onPressed (and enabled) can change on every parent rebuild — keep the + // controller's copy current. + controller.attach(onPressed: effectiveOnPressed); } @override void dispose() { - _controller.removeListener(_handleControllerChange); - _internalController?.dispose(); + controller.removeListener(listener); + // Dispose only an internally-owned controller. + if (widget.controller == null) { + controller.dispose(); + } super.dispose(); } - void _handleControllerChange() { - final newStatus = _controller.value; - if (newStatus != _lastStatus) { - widget.onStateChanged?.call(newStatus); - _fireHaptic(newStatus); - _announceSemantics(newStatus); - if (newStatus is AsyncButtonStatusSuccess && - _lastStatus is! AsyncButtonStatusSuccess) { - widget.onSuccess?.call(); - } else if (newStatus is AsyncButtonStatusError && - _lastStatus is! AsyncButtonStatusError) { - widget.onError?.call( - newStatus.error, - newStatus.stackTrace ?? StackTrace.empty, - ); - } - _lastStatus = newStatus; - } + void listener() { if (mounted) { setState(() {}); } } - void _fireHaptic(AsyncButtonStatus to) { - final mode = - widget.hapticOn ?? AsyncButtonTheme.of(context).hapticOn ?? .none; - if (mode == .none) { - return; - } - final wantSuccess = mode == .success || mode == .both; - final wantError = mode == .error || mode == .both; - if (to is AsyncButtonStatusSuccess && wantSuccess) { - unawaited(HapticFeedback.lightImpact()); - } else if (to is AsyncButtonStatusError && wantError) { - unawaited(HapticFeedback.mediumImpact()); - } - } - - void _announceSemantics(AsyncButtonStatus status) { - final on = - widget.announceSemantics ?? - AsyncButtonTheme.of(context).announceSemantics ?? - false; - if (!on) { - return; - } - final message = switch (status) { - AsyncButtonStatusIdle() => null, - AsyncButtonStatusLoading() => 'Loading', - AsyncButtonStatusSuccess() => 'Success', - AsyncButtonStatusError() => 'Error', - }; - if (message == null) { - return; - } - final view = View.maybeOf(context); - if (view == null) { - return; - } - final direction = Directionality.maybeOf(context) ?? .ltr; - unawaited(SemanticsService.sendAnnouncement(view, message, direction)); - } - @override Widget build(BuildContext context) { - final config = _resolveConfig(AsyncButtonTheme.of(context)); - - _controller.attach( - onPressed: _gatedOnPressed(), - successDuration: config.successDisplayDuration, - errorDuration: config.errorDisplayDuration, - cooldownDuration: config.cooldownDuration, - rethrowErrors: config.rethrowErrors, - ); - - final status = _controller.value; - final visible = switch (status) { - AsyncButtonStatusIdle() => widget.child, - AsyncButtonStatusLoading() => config.loadingChild, - AsyncButtonStatusSuccess() => config.successChild ?? widget.child, - AsyncButtonStatusError() => config.errorChild ?? widget.child, - }; - - Widget content = AnimatedSwitcher( - duration: config.switchDuration, - reverseDuration: config.switchReverseDuration, - switchInCurve: config.switchInCurve, - switchOutCurve: config.switchOutCurve, - transitionBuilder: config.transitionBuilder, - child: KeyedSubtree( - key: ValueKey(status), - child: visible, - ), + final theme = AsyncButtonTheme.of(context); + final loadingBuilder = + widget.loadingBuilder ?? theme.loadingBuilder ?? _defaultLoadingBuilder; + final transitionBuilder = + widget.transitionBuilder ?? theme.transitionBuilder; + + final isLoading = controller.value; + // The idle child is replaced outright by the loading widget; the button + // may resize to fit it (wrap a transitionBuilder in AnimatedSize to smooth + // that). + var content = isLoading ? loadingBuilder(context) : widget.child; + + // Keyed by loading state so a user-supplied transitionBuilder can animate + // the swap (e.g. via AnimatedSwitcher / AnimatedSize). With no builder it + // is an instant swap. + content = KeyedSubtree( + key: ValueKey(isLoading), + child: content, ); - - if (config.animateSize) { - content = AnimatedSize( - duration: config.switchDuration, - reverseDuration: config.switchReverseDuration, - alignment: config.sizeAlignment, - clipBehavior: config.sizeClipBehavior, - curve: config.sizeCurve, - child: content, - ); + if (transitionBuilder != null) { + content = transitionBuilder(context, content, isLoading); } - return widget.builder(context, content, _builderCallback(), status); - } - - /// Callback passed back through the builder. Null when the button is in a - /// status that should appear disabled. - AsyncCallback? _builderCallback() { - if (widget.disabled || widget.onPressed == null) { - return null; - } - if (!_controller.canTrigger) { - return null; - } - return _controller.trigger; - } - - /// The `onPressed` that `controller.trigger` will actually run, wrapped - /// with `confirmBeforePress` and only invoked when not disabled. - AsyncCallback? _gatedOnPressed() { - if (widget.disabled || widget.onPressed == null) { - return null; - } - final confirm = widget.confirmBeforePress; - final raw = widget.onPressed!; - if (confirm == null) { - return raw; - } - return () async { - if (!mounted) { - return; - } - final ok = await confirm(context); - if (!mounted || !ok) { - return; - } - await raw(); - }; - } - - _ResolvedConfig _resolveConfig(AsyncButtonTheme t) { - final w = widget; - final fallbackCurve = w.switchCurve ?? t.switchCurve ?? Curves.linear; - return _ResolvedConfig( - loadingChild: w.loadingChild ?? t.loadingChild ?? _defaultLoadingChild, - successChild: w.successChild ?? t.successChild, - errorChild: w.errorChild ?? t.errorChild, - switchDuration: - w.switchDuration ?? - t.switchDuration ?? - const Duration(milliseconds: 200), - switchReverseDuration: w.switchReverseDuration ?? t.switchReverseDuration, - switchInCurve: w.switchInCurve ?? t.switchInCurve ?? fallbackCurve, - switchOutCurve: w.switchOutCurve ?? t.switchOutCurve ?? fallbackCurve, - transitionBuilder: - w.transitionBuilder ?? - t.transitionBuilder ?? - AnimatedSwitcher.defaultTransitionBuilder, - successDisplayDuration: - w.successDisplayDuration ?? t.successDisplayDuration ?? .zero, - errorDisplayDuration: - w.errorDisplayDuration ?? t.errorDisplayDuration ?? .zero, - cooldownDuration: w.cooldownDuration ?? t.cooldownDuration ?? .zero, - animateSize: w.animateSize ?? t.animateSize ?? false, - sizeCurve: w.sizeCurve ?? t.sizeCurve ?? Curves.linear, - sizeAlignment: w.sizeAlignment ?? t.sizeAlignment ?? .center, - sizeClipBehavior: w.sizeClipBehavior ?? t.sizeClipBehavior ?? .hardEdge, - rethrowErrors: w.rethrowErrors ?? t.rethrowErrors ?? false, - ); + return widget.builder(context, content, callback, isLoading); } } -/// Per-build resolution of widget props ▶ theme ▶ defaults. -@immutable -class _ResolvedConfig { - const _ResolvedConfig({ - required this.loadingChild, - required this.successChild, - required this.errorChild, - required this.switchDuration, - required this.switchReverseDuration, - required this.switchInCurve, - required this.switchOutCurve, - required this.transitionBuilder, - required this.successDisplayDuration, - required this.errorDisplayDuration, - required this.cooldownDuration, - required this.animateSize, - required this.sizeCurve, - required this.sizeAlignment, - required this.sizeClipBehavior, - required this.rethrowErrors, - }); - - final Widget loadingChild; - final Widget? successChild; - final Widget? errorChild; - final Duration switchDuration; - final Duration? switchReverseDuration; - final Curve switchInCurve; - final Curve switchOutCurve; - final AnimatedSwitcherTransitionBuilder transitionBuilder; - final Duration successDisplayDuration; - final Duration errorDisplayDuration; - final Duration cooldownDuration; - final bool animateSize; - final Curve sizeCurve; - final AlignmentGeometry sizeAlignment; - final Clip sizeClipBehavior; - final bool rethrowErrors; +/// The loading view used when neither the widget nor the theme supplies a +/// [AsyncButton.loadingBuilder]: the default [AsyncButtonSpinner]. +Widget _defaultLoadingBuilder(BuildContext context) { + return const AsyncButtonSpinner(); } - -const _defaultLoadingChild = SizedBox.square( - dimension: 16, - child: CircularProgressIndicator(strokeWidth: 2), -); diff --git a/lib/src/async_button_controller.dart b/lib/src/async_button_controller.dart index 4068496..a4f4356 100644 --- a/lib/src/async_button_controller.dart +++ b/lib/src/async_button_controller.dart @@ -1,164 +1,71 @@ part of '../material_async_button.dart'; -/// [ValueNotifier] of [AsyncButtonStatus] for an [AsyncButton] or any of -/// the Material wrappers. Pipe it directly into a -/// `ValueListenableBuilder` for reactive UI outside the -/// button — pattern-match the [value] for the error payload on error. +/// `ValueNotifier` of an [AsyncButton]'s loading state (`true` while +/// `onPressed` is in flight). Pipe it into a `ValueListenableBuilder` for +/// reactive UI outside the button. /// /// Use it to: /// - trigger the attached `onPressed` from outside the button /// (e.g. a form keyboard "Done" action), -/// - reset to idle, -/// - mark the button as failed from an out-of-band source -/// (e.g. a WebSocket message) via [invalidate], -/// - mark the button as succeeded from outside via [markSuccess]. -/// -/// Prefer [reset], [invalidate], [markSuccess], or [trigger] over assigning -/// to [value] directly — the imperative methods keep the display-duration -/// timers and cooldown machinery coherent. +/// - reset to idle. /// /// Dispose like any [ChangeNotifier]. -class AsyncButtonController extends ValueNotifier { - /// Creates a controller with an optional initial status (defaults to idle). - AsyncButtonController([super.initial = const .idle()]); - - /// True when [value] is [AsyncButtonStatusIdle]. - bool get isIdle => value is AsyncButtonStatusIdle; - - /// True when [value] is [AsyncButtonStatusLoading]. - bool get isLoading => value is AsyncButtonStatusLoading; +class AsyncButtonController extends ValueNotifier { + /// Creates a controller in the idle (not-loading) state. + AsyncButtonController() : super(false); - /// True when [value] is [AsyncButtonStatusSuccess]. - bool get isSuccess => value is AsyncButtonStatusSuccess; - - /// True when [value] is [AsyncButtonStatusError]. - bool get isError => value is AsyncButtonStatusError; - - /// True while the post-success/error cooldown is blocking [trigger]. - @visibleForTesting - bool get isInCooldown => _cooldownActive; + /// Whether `onPressed` is currently in flight. + bool get isLoading => value; /// True when [trigger] would actually run the attached callback. - bool get canTrigger => isIdle && !_cooldownActive && _onPressed != null; + bool get canTrigger => !value && _onPressed != null; - // Widget-owned configuration. Refreshed on every build. + // Widget-owned configuration. Refreshed whenever the bound [AsyncButton] + // updates. AsyncCallback? _onPressed; - Duration _successDuration = .zero; - Duration _errorDuration = .zero; - Duration _cooldownDuration = .zero; - bool _rethrowErrors = false; - Timer? _timer; - bool _cooldownActive = false; bool _disposed = false; - /// Internal hook used by [AsyncButton] to push the host widget's current - /// configuration into the controller on every build. Calling this from - /// outside the package is supported (tests drive a detached controller - /// this way), but the values you set will be overwritten on the next - /// build if the controller is also bound to an [AsyncButton]. - void attach({ - required AsyncCallback? onPressed, - required Duration successDuration, - required Duration errorDuration, - required Duration cooldownDuration, - required bool rethrowErrors, - }) { + /// Binds the host widget's current `onPressed` to the controller. + /// [AsyncButton] calls this; you can too (tests drive a detached controller + /// this way), but a bound button overwrites it on its next update. + // A named binding hook, not a property setter — tests drive this seam. + // ignore: use_setters_to_change_properties + void attach({required AsyncCallback? onPressed}) { _onPressed = onPressed; - _successDuration = successDuration; - _errorDuration = errorDuration; - _cooldownDuration = cooldownDuration; - _rethrowErrors = rethrowErrors; } - /// Run the attached `onPressed`. No-op if already loading, in cooldown, - /// or if no callback is attached. + /// Run the attached `onPressed`. No-op if already loading or if no callback + /// is attached. + /// + /// If `onPressed` throws, the button returns to idle and the error + /// **re-propagates** — a button is not the place to surface errors, so handle + /// them in your state management. Future trigger() async { if (!canTrigger) { return; } - _cancelTimer(); - value = const .loading(); + value = true; try { await _onPressed!(); - // External resets (e.g. controller.reset()) may have moved us off - // loading mid-await. Only continue the success cycle if we're still - // the one driving. - if (!_disposed && value is AsyncButtonStatusLoading) { - value = const .success(); - _scheduleReturnToIdle(_successDuration); - } - } catch (error, stack) { - if (!_disposed && value is AsyncButtonStatusLoading) { - value = .error(error, stack); - _scheduleReturnToIdle(_errorDuration); - } - if (_rethrowErrors) { - rethrow; + } finally { + // Reset the UI whether onPressed completed or threw; a throw propagates + // through finally (trigger rethrows) so the error reaches the surrounding + // zone / FlutterError.onError. + if (!_disposed) { + value = false; } } } - /// Force the button back to idle. Cancels any pending display/cooldown. + /// Force the button back to idle. void reset() { - _cancelTimer(); - _cooldownActive = false; - value = const .idle(); - } - - /// Force the error status from outside. Runs the same display cycle as - /// if `onPressed` had thrown. - void invalidate(Object error, [StackTrace? stackTrace]) { - _cancelTimer(); - value = .error(error, stackTrace); - _scheduleReturnToIdle(_errorDuration); - } - - /// Force the success status from outside. Runs the same display cycle as - /// a completed `onPressed`. - void markSuccess() { - _cancelTimer(); - value = const .success(); - _scheduleReturnToIdle(_successDuration); - } - - void _cancelTimer() { - _timer?.cancel(); - _timer = null; - } - - void _scheduleReturnToIdle(Duration displayDuration) { - if (displayDuration <= .zero) { - _enterIdleThenCooldown(); - return; - } - _timer = Timer(displayDuration, _enterIdleThenCooldown); - } - - void _enterIdleThenCooldown() { - if (_disposed) { - return; - } - _timer = null; - value = const .idle(); - if (_cooldownDuration > .zero) { - _cooldownActive = true; - notifyListeners(); - _timer = Timer(_cooldownDuration, () { - if (_disposed) { - return; - } - _timer = null; - _cooldownActive = false; - notifyListeners(); - }); - } + value = false; } @override void dispose() { _disposed = true; - _cancelTimer(); super.dispose(); } } diff --git a/lib/src/async_button_status.dart b/lib/src/async_button_status.dart deleted file mode 100644 index 2a4bf28..0000000 --- a/lib/src/async_button_status.dart +++ /dev/null @@ -1,107 +0,0 @@ -part of '../material_async_button.dart'; - -/// Status of an async button. Sealed — pattern-match exhaustively, and pull -/// the [AsyncButtonStatusError.error] / [AsyncButtonStatusError.stackTrace] -/// payload directly from the error variant. -/// -/// ```dart -/// final color = switch (status) { -/// AsyncButtonStatusIdle() => Colors.blue, -/// AsyncButtonStatusLoading() => Colors.grey, -/// AsyncButtonStatusSuccess() => Colors.green, -/// AsyncButtonStatusError() => Colors.red, -/// }; -/// ``` -/// -/// The three singleton variants rely on `const` canonicalisation for -/// equality — always construct them via `const` or the factory ctors. -@immutable -sealed class AsyncButtonStatus { - const AsyncButtonStatus(); - - const factory AsyncButtonStatus.idle() = AsyncButtonStatusIdle; - const factory AsyncButtonStatus.loading() = AsyncButtonStatusLoading; - const factory AsyncButtonStatus.success() = AsyncButtonStatusSuccess; - const factory AsyncButtonStatus.error( - Object error, [ - StackTrace? stackTrace, - ]) = AsyncButtonStatusError; -} - -/// Idle variant of [AsyncButtonStatus] — no async work in flight. -final class AsyncButtonStatusIdle extends AsyncButtonStatus { - /// Const constructor; prefer the [AsyncButtonStatus.idle] factory. - const AsyncButtonStatusIdle(); - - @override - String toString() { - return '.idle()'; - } -} - -/// Loading variant of [AsyncButtonStatus] — `onPressed` is in flight. -final class AsyncButtonStatusLoading extends AsyncButtonStatus { - /// Const constructor; prefer the [AsyncButtonStatus.loading] factory. - const AsyncButtonStatusLoading(); - - @override - String toString() { - return '.loading()'; - } -} - -/// Success variant of [AsyncButtonStatus] — `onPressed` completed. -final class AsyncButtonStatusSuccess extends AsyncButtonStatus { - /// Const constructor; prefer the [AsyncButtonStatus.success] factory. - const AsyncButtonStatusSuccess(); - - @override - String toString() { - return '.success()'; - } -} - -/// Error variant of [AsyncButtonStatus]. Produced when `onPressed` throws or -/// [AsyncButtonController.invalidate] is called. -final class AsyncButtonStatusError extends AsyncButtonStatus { - /// Const constructor; prefer the [AsyncButtonStatus.error] factory. - const AsyncButtonStatusError(this.error, [this.stackTrace]); - - /// The thrown error. - final Object error; - - /// Captured stack trace, when available. - final StackTrace? stackTrace; - - /// Equality compares [error] by runtime type and `toString()` payload — - /// most thrown errors (Exceptions, Errors, custom error objects) do not - /// override `operator ==`, so a raw `error == other.error` collapses to - /// identity. Two `invalidate('bad')` calls or two `StateError('oops')` - /// throws are treated as the same error for listener-dedup purposes. - /// [stackTrace] is informational and excluded from equality. - @override - bool operator ==(Object other) { - if (identical(this, other)) { - return true; - } - if (other is! AsyncButtonStatusError) { - return false; - } - return error.runtimeType == other.error.runtimeType && - error.toString() == other.error.toString(); - } - - @override - int get hashCode { - return Object.hash( - AsyncButtonStatusError, - error.runtimeType, - error.toString(), - ); - } - - @override - String toString() { - return '.error($error)'; - } -} diff --git a/lib/src/buttons/async_material_button.dart b/lib/src/buttons/async_material_button.dart index 7cd536c..d1faa3b 100644 --- a/lib/src/buttons/async_material_button.dart +++ b/lib/src/buttons/async_material_button.dart @@ -4,10 +4,10 @@ part of '../../material_async_button.dart'; /// ([ElevatedAsyncButton], [FilledAsyncButton], [OutlinedAsyncButton], /// [TextAsyncButton], [IconAsyncButton]). /// -/// Owns the shared async-status surface — [onPressed], [controller], and -/// the theme-override knobs. Subclasses implement [build] and forward these -/// fields to an [AsyncButton]. For custom non-Material buttons reach for -/// [AsyncButton] directly. +/// Owns the shared async surface — [onPressed], [controller], and the +/// theme-override knobs. Subclasses implement [build] and forward these fields +/// to an [AsyncButton]. For custom non-Material buttons reach for [AsyncButton] +/// directly. abstract class AsyncMaterialButton extends StatelessWidget { /// Subclass-only constructor. Forwards every field to [AsyncButton]. See /// [AsyncButton] for the semantics of each parameter. @@ -15,24 +15,10 @@ abstract class AsyncMaterialButton extends StatelessWidget { super.key, required this.child, required this.onPressed, + this.enabled = true, this.controller, - this.onSuccess, - this.onError, - this.onStateChanged, - this.confirmBeforePress, - this.loadingChild, - this.successChild, - this.errorChild, - this.disabled = false, - this.switchDuration, + this.loadingBuilder, this.transitionBuilder, - this.successDisplayDuration, - this.errorDisplayDuration, - this.cooldownDuration, - this.animateSize, - this.hapticOn, - this.announceSemantics, - this.rethrowErrors, }); /// See [AsyncButton.child]. @@ -41,59 +27,17 @@ abstract class AsyncMaterialButton extends StatelessWidget { /// See [AsyncButton.onPressed]. final AsyncCallback? onPressed; + /// See [AsyncButton.enabled]. + final bool enabled; + /// See [AsyncButton.controller]. final AsyncButtonController? controller; - /// See [AsyncButton.onSuccess]. - final VoidCallback? onSuccess; - - /// See [AsyncButton.onError]. - final AsyncButtonErrorCallback? onError; - - /// See [AsyncButton.onStateChanged]. - final ValueChanged? onStateChanged; - - /// See [AsyncButton.confirmBeforePress]. - final Future Function(BuildContext context)? confirmBeforePress; - - /// See [AsyncButton.loadingChild]. - final Widget? loadingChild; - - /// See [AsyncButton.successChild]. - final Widget? successChild; - - /// See [AsyncButton.errorChild]. - final Widget? errorChild; - - /// See [AsyncButton.disabled]. - final bool disabled; - - /// See [AsyncButton.switchDuration]. - final Duration? switchDuration; + /// See [AsyncButton.loadingBuilder]. + final WidgetBuilder? loadingBuilder; /// See [AsyncButton.transitionBuilder]. - final AnimatedSwitcherTransitionBuilder? transitionBuilder; - - /// See [AsyncButton.successDisplayDuration]. - final Duration? successDisplayDuration; - - /// See [AsyncButton.errorDisplayDuration]. - final Duration? errorDisplayDuration; - - /// See [AsyncButton.cooldownDuration]. - final Duration? cooldownDuration; - - /// See [AsyncButton.animateSize]. - final bool? animateSize; - - /// See [AsyncButton.hapticOn]. - final HapticOn? hapticOn; - - /// See [AsyncButton.announceSemantics]. - final bool? announceSemantics; - - /// See [AsyncButton.rethrowErrors]. - final bool? rethrowErrors; + final AsyncButtonTransitionBuilder? transitionBuilder; } /// Sub-base for the four [AsyncMaterialButton]s that share the standard @@ -111,24 +55,10 @@ abstract class AsyncStandardMaterialButton extends AsyncMaterialButton { super.key, required super.child, required super.onPressed, + super.enabled, super.controller, - super.onSuccess, - super.onError, - super.onStateChanged, - super.confirmBeforePress, - super.loadingChild, - super.successChild, - super.errorChild, - super.disabled, - super.switchDuration, + super.loadingBuilder, super.transitionBuilder, - super.successDisplayDuration, - super.errorDisplayDuration, - super.cooldownDuration, - super.animateSize, - super.hapticOn, - super.announceSemantics, - super.rethrowErrors, this.onLongPress, this.onHover, this.onFocusChange, diff --git a/lib/src/buttons/elevated_async_button.dart b/lib/src/buttons/elevated_async_button.dart index 974457f..958fb95 100644 --- a/lib/src/buttons/elevated_async_button.dart +++ b/lib/src/buttons/elevated_async_button.dart @@ -1,8 +1,8 @@ part of '../../material_async_button.dart'; /// Async-aware [ElevatedButton]. While `onPressed` is running the label is -/// swapped for a loading widget; success/error are shown afterwards if -/// configured via prop or theme. +/// swapped for a loading widget; an optional success view is shown afterwards +/// if configured via prop or theme. class ElevatedAsyncButton extends AsyncStandardMaterialButton { /// Mirrors [ElevatedButton.new]. const ElevatedAsyncButton({ @@ -17,28 +17,14 @@ class ElevatedAsyncButton extends AsyncStandardMaterialButton { super.autofocus, super.clipBehavior, super.statesController, + super.enabled, super.controller, - super.onSuccess, - super.onError, - super.onStateChanged, - super.confirmBeforePress, - super.loadingChild, - super.successChild, - super.errorChild, - super.disabled, - super.switchDuration, + super.loadingBuilder, super.transitionBuilder, - super.successDisplayDuration, - super.errorDisplayDuration, - super.cooldownDuration, - super.animateSize, - super.hapticOn, - super.announceSemantics, - super.rethrowErrors, }); - /// Mirrors [ElevatedButton.icon]. The loading/success/error children - /// replace `label` while `icon` stays put. + /// Mirrors [ElevatedButton.icon]. The loading/success children replace + /// `label` while `icon` stays put. const ElevatedAsyncButton.icon({ super.key, required super.onPressed, @@ -52,52 +38,23 @@ class ElevatedAsyncButton extends AsyncStandardMaterialButton { super.statesController, super.iconAlignment, super.controller, - super.onSuccess, - super.onError, - super.onStateChanged, - super.confirmBeforePress, - super.loadingChild, - super.successChild, - super.errorChild, - super.disabled, - super.switchDuration, + super.loadingBuilder, super.transitionBuilder, - super.successDisplayDuration, - super.errorDisplayDuration, - super.cooldownDuration, - super.animateSize, - super.hapticOn, - super.announceSemantics, - super.rethrowErrors, - required Widget icon, + required super.icon, required Widget label, - }) : super(icon: icon, child: label); + }) : super(child: label); @override Widget build(BuildContext context) { + final clip = clipBehavior ?? .none; return AsyncButton( onPressed: onPressed, + enabled: enabled, controller: controller, - onSuccess: onSuccess, - onError: onError, - onStateChanged: onStateChanged, - confirmBeforePress: confirmBeforePress, - loadingChild: loadingChild, - successChild: successChild, - errorChild: errorChild, - disabled: disabled, - switchDuration: switchDuration, + loadingBuilder: loadingBuilder, transitionBuilder: transitionBuilder, - successDisplayDuration: successDisplayDuration, - errorDisplayDuration: errorDisplayDuration, - cooldownDuration: cooldownDuration, - animateSize: animateSize, - hapticOn: hapticOn, - announceSemantics: announceSemantics, - rethrowErrors: rethrowErrors, - builder: (context, animatedChild, callback, status) { - final clip = clipBehavior ?? .none; - final longPress = callback == null ? null : onLongPress; + builder: (context, animatedChild, callback, isLoading) { + final longPress = (callback != null && !isLoading) ? onLongPress : null; if (_icon != null) { return ElevatedButton.icon( onPressed: callback, @@ -110,7 +67,7 @@ class ElevatedAsyncButton extends AsyncStandardMaterialButton { clipBehavior: clip, statesController: statesController, iconAlignment: _iconAlignment, - icon: _icon, + icon: isLoading ? null : _icon, label: animatedChild, ); } diff --git a/lib/src/buttons/filled_async_button.dart b/lib/src/buttons/filled_async_button.dart index 2b4ee58..db2ebd2 100644 --- a/lib/src/buttons/filled_async_button.dart +++ b/lib/src/buttons/filled_async_button.dart @@ -19,31 +19,16 @@ class FilledAsyncButton extends AsyncStandardMaterialButton { super.autofocus, super.clipBehavior, super.statesController, + super.enabled, super.controller, - super.onSuccess, - super.onError, - super.onStateChanged, - super.confirmBeforePress, - super.loadingChild, - super.successChild, - super.errorChild, - super.disabled, - super.switchDuration, + super.loadingBuilder, super.transitionBuilder, - super.successDisplayDuration, - super.errorDisplayDuration, - super.cooldownDuration, - super.animateSize, - super.hapticOn, - super.announceSemantics, - super.rethrowErrors, }) : _variant = .primary; /// Mirrors [FilledButton.tonal]. const FilledAsyncButton.tonal({ super.key, required super.onPressed, - required super.child, super.onLongPress, super.onHover, super.onFocusChange, @@ -52,24 +37,11 @@ class FilledAsyncButton extends AsyncStandardMaterialButton { super.autofocus, super.clipBehavior, super.statesController, + super.enabled, super.controller, - super.onSuccess, - super.onError, - super.onStateChanged, - super.confirmBeforePress, - super.loadingChild, - super.successChild, - super.errorChild, - super.disabled, - super.switchDuration, + super.loadingBuilder, super.transitionBuilder, - super.successDisplayDuration, - super.errorDisplayDuration, - super.cooldownDuration, - super.animateSize, - super.hapticOn, - super.announceSemantics, - super.rethrowErrors, + required super.child, }) : _variant = .tonal; /// Mirrors [FilledButton.icon]. @@ -86,27 +58,12 @@ class FilledAsyncButton extends AsyncStandardMaterialButton { super.statesController, super.iconAlignment, super.controller, - super.onSuccess, - super.onError, - super.onStateChanged, - super.confirmBeforePress, - super.loadingChild, - super.successChild, - super.errorChild, - super.disabled, - super.switchDuration, + super.loadingBuilder, super.transitionBuilder, - super.successDisplayDuration, - super.errorDisplayDuration, - super.cooldownDuration, - super.animateSize, - super.hapticOn, - super.announceSemantics, - super.rethrowErrors, - required Widget icon, + required super.icon, required Widget label, }) : _variant = .primary, - super(icon: icon, child: label); + super(child: label); /// Mirrors [FilledButton.tonalIcon]. const FilledAsyncButton.tonalIcon({ @@ -122,55 +79,26 @@ class FilledAsyncButton extends AsyncStandardMaterialButton { super.statesController, super.iconAlignment, super.controller, - super.onSuccess, - super.onError, - super.onStateChanged, - super.confirmBeforePress, - super.loadingChild, - super.successChild, - super.errorChild, - super.disabled, - super.switchDuration, + super.loadingBuilder, super.transitionBuilder, - super.successDisplayDuration, - super.errorDisplayDuration, - super.cooldownDuration, - super.animateSize, - super.hapticOn, - super.announceSemantics, - super.rethrowErrors, - required Widget icon, + required super.icon, required Widget label, }) : _variant = .tonal, - super(icon: icon, child: label); + super(child: label); final _FilledVariant _variant; @override Widget build(BuildContext context) { + final clip = clipBehavior ?? .none; return AsyncButton( onPressed: onPressed, + enabled: enabled, controller: controller, - onSuccess: onSuccess, - onError: onError, - onStateChanged: onStateChanged, - confirmBeforePress: confirmBeforePress, - loadingChild: loadingChild, - successChild: successChild, - errorChild: errorChild, - disabled: disabled, - switchDuration: switchDuration, + loadingBuilder: loadingBuilder, transitionBuilder: transitionBuilder, - successDisplayDuration: successDisplayDuration, - errorDisplayDuration: errorDisplayDuration, - cooldownDuration: cooldownDuration, - animateSize: animateSize, - hapticOn: hapticOn, - announceSemantics: announceSemantics, - rethrowErrors: rethrowErrors, - builder: (context, animatedChild, callback, status) { - final clip = clipBehavior ?? .none; - final longPress = callback == null ? null : onLongPress; + builder: (context, animatedChild, callback, isLoading) { + final longPress = (callback != null && !isLoading) ? onLongPress : null; if (_icon != null) { return switch (_variant) { .primary => FilledButton.icon( @@ -184,7 +112,7 @@ class FilledAsyncButton extends AsyncStandardMaterialButton { clipBehavior: clip, statesController: statesController, iconAlignment: _iconAlignment, - icon: _icon, + icon: isLoading ? null : _icon, label: animatedChild, ), .tonal => FilledButton.tonalIcon( @@ -198,7 +126,7 @@ class FilledAsyncButton extends AsyncStandardMaterialButton { clipBehavior: clip, statesController: statesController, iconAlignment: _iconAlignment, - icon: _icon, + icon: isLoading ? null : _icon, label: animatedChild, ), }; diff --git a/lib/src/buttons/icon_async_button.dart b/lib/src/buttons/icon_async_button.dart index b30ffca..5c04068 100644 --- a/lib/src/buttons/icon_async_button.dart +++ b/lib/src/buttons/icon_async_button.dart @@ -6,31 +6,16 @@ enum _IconVariant { standard, filled, filledTonal, outlined } /// [IconAsyncButton.new], [IconAsyncButton.filled], /// [IconAsyncButton.filledTonal], [IconAsyncButton.outlined]. /// -/// The [icon] is swapped with `loadingChild`/`successChild`/`errorChild` -/// during the corresponding state. +/// The [icon] is swapped with the `loadingBuilder` output while loading. class IconAsyncButton extends AsyncMaterialButton { /// Mirrors [IconButton.new]. const IconAsyncButton({ super.key, required super.onPressed, + super.enabled, super.controller, - super.onSuccess, - super.onError, - super.onStateChanged, - super.confirmBeforePress, - super.loadingChild, - super.successChild, - super.errorChild, - super.disabled, - super.switchDuration, + super.loadingBuilder, super.transitionBuilder, - super.successDisplayDuration, - super.errorDisplayDuration, - super.cooldownDuration, - super.animateSize, - super.hapticOn, - super.announceSemantics, - super.rethrowErrors, required this.icon, this.iconSize, this.visualDensity, @@ -59,24 +44,10 @@ class IconAsyncButton extends AsyncMaterialButton { const IconAsyncButton.filled({ super.key, required super.onPressed, + super.enabled, super.controller, - super.onSuccess, - super.onError, - super.onStateChanged, - super.confirmBeforePress, - super.loadingChild, - super.successChild, - super.errorChild, - super.disabled, - super.switchDuration, + super.loadingBuilder, super.transitionBuilder, - super.successDisplayDuration, - super.errorDisplayDuration, - super.cooldownDuration, - super.animateSize, - super.hapticOn, - super.announceSemantics, - super.rethrowErrors, required this.icon, this.iconSize, this.visualDensity, @@ -105,24 +76,10 @@ class IconAsyncButton extends AsyncMaterialButton { const IconAsyncButton.filledTonal({ super.key, required super.onPressed, + super.enabled, super.controller, - super.onSuccess, - super.onError, - super.onStateChanged, - super.confirmBeforePress, - super.loadingChild, - super.successChild, - super.errorChild, - super.disabled, - super.switchDuration, + super.loadingBuilder, super.transitionBuilder, - super.successDisplayDuration, - super.errorDisplayDuration, - super.cooldownDuration, - super.animateSize, - super.hapticOn, - super.announceSemantics, - super.rethrowErrors, required this.icon, this.iconSize, this.visualDensity, @@ -151,24 +108,10 @@ class IconAsyncButton extends AsyncMaterialButton { const IconAsyncButton.outlined({ super.key, required super.onPressed, + super.enabled, super.controller, - super.onSuccess, - super.onError, - super.onStateChanged, - super.confirmBeforePress, - super.loadingChild, - super.successChild, - super.errorChild, - super.disabled, - super.switchDuration, + super.loadingBuilder, super.transitionBuilder, - super.successDisplayDuration, - super.errorDisplayDuration, - super.cooldownDuration, - super.animateSize, - super.hapticOn, - super.announceSemantics, - super.rethrowErrors, required this.icon, this.iconSize, this.visualDensity, @@ -193,7 +136,7 @@ class IconAsyncButton extends AsyncMaterialButton { }) : _variant = .outlined, super(child: icon); - /// Idle icon. Swapped with `loadingChild`/`successChild`/`errorChild`. + /// Idle icon. Swapped with the `loadingBuilder` output while loading. final Widget icon; /// Forwarded to the underlying [IconButton]. @@ -262,25 +205,11 @@ class IconAsyncButton extends AsyncMaterialButton { Widget build(BuildContext context) { return AsyncButton( onPressed: onPressed, + enabled: enabled, controller: controller, - onSuccess: onSuccess, - onError: onError, - onStateChanged: onStateChanged, - confirmBeforePress: confirmBeforePress, - loadingChild: loadingChild, - successChild: successChild, - errorChild: errorChild, - disabled: disabled, - switchDuration: switchDuration, + loadingBuilder: loadingBuilder, transitionBuilder: transitionBuilder, - successDisplayDuration: successDisplayDuration, - errorDisplayDuration: errorDisplayDuration, - cooldownDuration: cooldownDuration, - animateSize: animateSize, - hapticOn: hapticOn, - announceSemantics: announceSemantics, - rethrowErrors: rethrowErrors, - builder: (context, child, callback, status) { + builder: (context, child, callback, isLoading) { return switch (_variant) { .standard => IconButton( onPressed: callback, diff --git a/lib/src/buttons/outlined_async_button.dart b/lib/src/buttons/outlined_async_button.dart index 2c21cf8..9167122 100644 --- a/lib/src/buttons/outlined_async_button.dart +++ b/lib/src/buttons/outlined_async_button.dart @@ -15,24 +15,10 @@ class OutlinedAsyncButton extends AsyncStandardMaterialButton { super.autofocus, super.clipBehavior, super.statesController, + super.enabled, super.controller, - super.onSuccess, - super.onError, - super.onStateChanged, - super.confirmBeforePress, - super.loadingChild, - super.successChild, - super.errorChild, - super.disabled, - super.switchDuration, + super.loadingBuilder, super.transitionBuilder, - super.successDisplayDuration, - super.errorDisplayDuration, - super.cooldownDuration, - super.animateSize, - super.hapticOn, - super.announceSemantics, - super.rethrowErrors, }); /// Mirrors [OutlinedButton.icon]. @@ -49,52 +35,23 @@ class OutlinedAsyncButton extends AsyncStandardMaterialButton { super.statesController, super.iconAlignment, super.controller, - super.onSuccess, - super.onError, - super.onStateChanged, - super.confirmBeforePress, - super.loadingChild, - super.successChild, - super.errorChild, - super.disabled, - super.switchDuration, + super.loadingBuilder, super.transitionBuilder, - super.successDisplayDuration, - super.errorDisplayDuration, - super.cooldownDuration, - super.animateSize, - super.hapticOn, - super.announceSemantics, - super.rethrowErrors, - required Widget icon, + required super.icon, required Widget label, - }) : super(icon: icon, child: label); + }) : super(child: label); @override Widget build(BuildContext context) { + final clip = clipBehavior ?? .none; return AsyncButton( onPressed: onPressed, + enabled: enabled, controller: controller, - onSuccess: onSuccess, - onError: onError, - onStateChanged: onStateChanged, - confirmBeforePress: confirmBeforePress, - loadingChild: loadingChild, - successChild: successChild, - errorChild: errorChild, - disabled: disabled, - switchDuration: switchDuration, + loadingBuilder: loadingBuilder, transitionBuilder: transitionBuilder, - successDisplayDuration: successDisplayDuration, - errorDisplayDuration: errorDisplayDuration, - cooldownDuration: cooldownDuration, - animateSize: animateSize, - hapticOn: hapticOn, - announceSemantics: announceSemantics, - rethrowErrors: rethrowErrors, - builder: (context, animatedChild, callback, status) { - final clip = clipBehavior ?? .none; - final longPress = callback == null ? null : onLongPress; + builder: (context, animatedChild, callback, isLoading) { + final longPress = (callback != null && !isLoading) ? onLongPress : null; if (_icon != null) { return OutlinedButton.icon( onPressed: callback, @@ -107,7 +64,7 @@ class OutlinedAsyncButton extends AsyncStandardMaterialButton { clipBehavior: clip, statesController: statesController, iconAlignment: _iconAlignment, - icon: _icon, + icon: isLoading ? null : _icon, label: animatedChild, ); } diff --git a/lib/src/buttons/text_async_button.dart b/lib/src/buttons/text_async_button.dart index 3238db8..4060c26 100644 --- a/lib/src/buttons/text_async_button.dart +++ b/lib/src/buttons/text_async_button.dart @@ -15,24 +15,10 @@ class TextAsyncButton extends AsyncStandardMaterialButton { super.autofocus, super.clipBehavior, super.statesController, + super.enabled, super.controller, - super.onSuccess, - super.onError, - super.onStateChanged, - super.confirmBeforePress, - super.loadingChild, - super.successChild, - super.errorChild, - super.disabled, - super.switchDuration, + super.loadingBuilder, super.transitionBuilder, - super.successDisplayDuration, - super.errorDisplayDuration, - super.cooldownDuration, - super.animateSize, - super.hapticOn, - super.announceSemantics, - super.rethrowErrors, }); /// Mirrors [TextButton.icon]. @@ -49,52 +35,23 @@ class TextAsyncButton extends AsyncStandardMaterialButton { super.statesController, super.iconAlignment, super.controller, - super.onSuccess, - super.onError, - super.onStateChanged, - super.confirmBeforePress, - super.loadingChild, - super.successChild, - super.errorChild, - super.disabled, - super.switchDuration, + super.loadingBuilder, super.transitionBuilder, - super.successDisplayDuration, - super.errorDisplayDuration, - super.cooldownDuration, - super.animateSize, - super.hapticOn, - super.announceSemantics, - super.rethrowErrors, - required Widget icon, + required super.icon, required Widget label, - }) : super(icon: icon, child: label); + }) : super(child: label); @override Widget build(BuildContext context) { + final clip = clipBehavior ?? .none; return AsyncButton( onPressed: onPressed, + enabled: enabled, controller: controller, - onSuccess: onSuccess, - onError: onError, - onStateChanged: onStateChanged, - confirmBeforePress: confirmBeforePress, - loadingChild: loadingChild, - successChild: successChild, - errorChild: errorChild, - disabled: disabled, - switchDuration: switchDuration, + loadingBuilder: loadingBuilder, transitionBuilder: transitionBuilder, - successDisplayDuration: successDisplayDuration, - errorDisplayDuration: errorDisplayDuration, - cooldownDuration: cooldownDuration, - animateSize: animateSize, - hapticOn: hapticOn, - announceSemantics: announceSemantics, - rethrowErrors: rethrowErrors, - builder: (context, animatedChild, callback, status) { - final clip = clipBehavior ?? .none; - final longPress = callback == null ? null : onLongPress; + builder: (context, animatedChild, callback, isLoading) { + final longPress = (callback != null && !isLoading) ? onLongPress : null; if (_icon != null) { return TextButton.icon( onPressed: callback, @@ -107,7 +64,7 @@ class TextAsyncButton extends AsyncStandardMaterialButton { clipBehavior: clip, statesController: statesController, iconAlignment: _iconAlignment, - icon: _icon, + icon: isLoading ? null : _icon, label: animatedChild, ); } diff --git a/lib/src/material_async_button_theme.dart b/lib/src/material_async_button_theme.dart index 18e27d0..4d72137 100644 --- a/lib/src/material_async_button_theme.dart +++ b/lib/src/material_async_button_theme.dart @@ -1,33 +1,23 @@ part of '../material_async_button.dart'; -/// Which haptic event, if any, to fire on state transitions. -enum HapticOn { - /// Fire no haptic on state transitions. - none, - - /// Fire a light haptic on success only. - success, - - /// Fire a light haptic on error only. - error, - - /// Fire a light haptic on both success and error. - both, -} - /// App-wide defaults for `material_async_button` widgets, attached as a -/// [ThemeExtension] on [ThemeData]. +/// [ThemeExtension] on [ThemeData]. Complements [ButtonStyle] / `ButtonThemeData` +/// — it carries only async behaviour (the loading view and its transition), +/// never styling knobs. /// /// Resolution order for any field: per-widget value, then theme value, then -/// the hard-coded fallback documented on each field. -/// -/// Use [AsyncButtonTheme.material] for an opinionated baseline that -/// mirrors what most apps want; otherwise build the extension yourself with -/// only the fields you care about. +/// the hard-coded fallback. With no extension registered the zero-config +/// fallback ([empty]) shows the default spinner and nothing else. /// /// ```dart /// MaterialApp( -/// theme: ThemeData(extensions: [AsyncButtonTheme.material()]), +/// theme: ThemeData( +/// extensions: [ +/// AsyncButtonTheme( +/// loadingBuilder: (_) => const AsyncButtonSpinner(strokeWidth: 3), +/// ), +/// ], +/// ), /// ) /// ``` @immutable @@ -35,184 +25,43 @@ class AsyncButtonTheme extends ThemeExtension { /// Builds an [AsyncButtonTheme]. Every field is nullable so callers only /// set the ones they want. const AsyncButtonTheme({ - this.loadingChild, - this.successChild, - this.errorChild, - this.switchDuration, - this.switchReverseDuration, - this.switchCurve, - this.switchInCurve, - this.switchOutCurve, + this.loadingBuilder, this.transitionBuilder, - this.successDisplayDuration, - this.errorDisplayDuration, - this.cooldownDuration, - this.animateSize, - this.sizeCurve, - this.sizeAlignment, - this.sizeClipBehavior, - this.hapticOn, - this.announceSemantics, - this.rethrowErrors, }); - /// Convenience: an opinionated baseline. - /// - /// - 16x16 indeterminate spinner during loading - /// - check icon for 800ms after success - /// - error icon for 800ms after error - /// - 200ms cross-fade between states - /// - light haptic on success and error - /// - announces state changes to assistive tech - factory AsyncButtonTheme.material({ - Color? loadingColor, - Color? successColor, - Color? errorColor, - }) { - return AsyncButtonTheme( - loadingChild: _DefaultLoadingChild(color: loadingColor), - successChild: _DefaultSuccessIcon(color: successColor), - errorChild: _DefaultErrorIcon(color: errorColor), - switchDuration: const Duration(milliseconds: 200), - switchReverseDuration: const Duration(milliseconds: 200), - successDisplayDuration: const Duration(milliseconds: 800), - errorDisplayDuration: const Duration(milliseconds: 800), - animateSize: true, - hapticOn: .both, - announceSemantics: true, - ); - } - - /// Shown in place of the button's child while the future is in flight. - /// Falls back to a 16x16 [CircularProgressIndicator] when null. - final Widget? loadingChild; - - /// Shown after success for [successDisplayDuration]. Null = keep the - /// original child visible (no visual swap, only the idle delay applies). - final Widget? successChild; - - /// Shown after error for [errorDisplayDuration]. Null = keep the - /// original child visible. - final Widget? errorChild; - - /// Cross-fade duration between state widgets. - /// Falls back to 200ms when null. - final Duration? switchDuration; - - /// Reverse cross-fade duration. Falls back to [switchDuration] when null. - final Duration? switchReverseDuration; - - /// Convenience: applied to both [switchInCurve] and [switchOutCurve] - /// unless one of those is set explicitly. - final Curve? switchCurve; - - /// Curve for the incoming widget during the cross-fade. - final Curve? switchInCurve; - - /// Curve for the outgoing widget during the cross-fade. - final Curve? switchOutCurve; - - /// Custom transition for the underlying [AnimatedSwitcher]. Defaults to a - /// fade transition. - final AnimatedSwitcherTransitionBuilder? transitionBuilder; - - /// How long [successChild] is shown before returning to idle. Defaults to - /// [.zero] (immediate return). - final Duration? successDisplayDuration; - - /// How long [errorChild] is shown before returning to idle. Defaults to - /// [.zero]. - final Duration? errorDisplayDuration; - - /// After a success/error display, keep the button disabled for this long - /// to prevent accidental double-submits. Defaults to [.zero]. - final Duration? cooldownDuration; - - /// Whether to animate the implicit size between state widgets of differing - /// dimensions. Falls back to `false`. - final bool? animateSize; - - /// Curve used by the [AnimatedSize] when [animateSize] is true. - final Curve? sizeCurve; - - /// Alignment used by the [AnimatedSize] when [animateSize] is true. - final AlignmentGeometry? sizeAlignment; - - /// Clip behavior used by the [AnimatedSize] when [animateSize] is true. - final Clip? sizeClipBehavior; - - /// Whether to fire a [HapticFeedback] on success / error transitions. - /// Defaults to [HapticOn.none]. - final HapticOn? hapticOn; - - /// Whether to announce state changes via - /// [SemanticsService.sendAnnouncement]. Defaults to `false`. - final bool? announceSemantics; - - /// If true, errors from `onPressed` are rethrown after the error state is - /// displayed. Useful when a caller awaits the future. Defaults to `false`. - final bool? rethrowErrors; - - /// An extension with every field left null. Use this to opt out of the - /// opinionated [AsyncButtonTheme.material] baseline returned by [of] when - /// no extension is registered on the surrounding [ThemeData]. + /// Builds the widget shown in place of the button's child while the future is + /// in flight. Falls back to an [AsyncButtonSpinner] when null. The spinner + /// inherits the button's foreground; return `AsyncButtonSpinner(color: ...)` + /// to recolour it. + final WidgetBuilder? loadingBuilder; + + /// Wraps the state widget to animate the idle ⇄ loading swap. `null` by + /// default — the button performs no animation of its own. See + /// [AsyncButtonTransitionBuilder] for plugging in an [AnimatedSwitcher] / + /// [AnimatedSize]. + final AsyncButtonTransitionBuilder? transitionBuilder; + + /// An extension with every field left null — also the zero-config fallback + /// returned by [of] when no extension is registered. Renders the default + /// spinner on loading and nothing else. static const AsyncButtonTheme empty = AsyncButtonTheme(); - static final AsyncButtonTheme _materialDefaults = AsyncButtonTheme.material(); - /// Resolves the [AsyncButtonTheme] visible at [context]. Returns the /// extension registered on the surrounding [ThemeData] when one exists; - /// otherwise falls back to [AsyncButtonTheme.material] so that apps - /// without explicit theming still get the spinner / check / error UX - /// out of the box. Pass [empty] to opt out. + /// otherwise falls back to [empty] — apps without explicit theming still get + /// the loading spinner (via the built-in fallback). static AsyncButtonTheme of(BuildContext context) { - return Theme.of(context).extension() ?? _materialDefaults; + return Theme.of(context).extension() ?? empty; } @override AsyncButtonTheme copyWith({ - Widget? loadingChild, - Widget? successChild, - Widget? errorChild, - Duration? switchDuration, - Duration? switchReverseDuration, - Curve? switchCurve, - Curve? switchInCurve, - Curve? switchOutCurve, - AnimatedSwitcherTransitionBuilder? transitionBuilder, - Duration? successDisplayDuration, - Duration? errorDisplayDuration, - Duration? cooldownDuration, - bool? animateSize, - Curve? sizeCurve, - AlignmentGeometry? sizeAlignment, - Clip? sizeClipBehavior, - HapticOn? hapticOn, - bool? announceSemantics, - bool? rethrowErrors, + WidgetBuilder? loadingBuilder, + AsyncButtonTransitionBuilder? transitionBuilder, }) { return AsyncButtonTheme( - loadingChild: loadingChild ?? this.loadingChild, - successChild: successChild ?? this.successChild, - errorChild: errorChild ?? this.errorChild, - switchDuration: switchDuration ?? this.switchDuration, - switchReverseDuration: - switchReverseDuration ?? this.switchReverseDuration, - switchCurve: switchCurve ?? this.switchCurve, - switchInCurve: switchInCurve ?? this.switchInCurve, - switchOutCurve: switchOutCurve ?? this.switchOutCurve, + loadingBuilder: loadingBuilder ?? this.loadingBuilder, transitionBuilder: transitionBuilder ?? this.transitionBuilder, - successDisplayDuration: - successDisplayDuration ?? this.successDisplayDuration, - errorDisplayDuration: errorDisplayDuration ?? this.errorDisplayDuration, - cooldownDuration: cooldownDuration ?? this.cooldownDuration, - animateSize: animateSize ?? this.animateSize, - sizeCurve: sizeCurve ?? this.sizeCurve, - sizeAlignment: sizeAlignment ?? this.sizeAlignment, - sizeClipBehavior: sizeClipBehavior ?? this.sizeClipBehavior, - hapticOn: hapticOn ?? this.hapticOn, - announceSemantics: announceSemantics ?? this.announceSemantics, - rethrowErrors: rethrowErrors ?? this.rethrowErrors, ); } @@ -224,158 +73,81 @@ class AsyncButtonTheme extends ThemeExtension { if (other is! AsyncButtonTheme) { return this; } - // Widgets and enums don't lerp meaningfully; snap at the halfway point. + // Widgets and callbacks don't lerp; snap at the halfway point. final snap = t < 0.5; return AsyncButtonTheme( - loadingChild: snap ? loadingChild : other.loadingChild, - successChild: snap ? successChild : other.successChild, - errorChild: snap ? errorChild : other.errorChild, - switchDuration: _lerpDuration( - switchDuration, - other.switchDuration, - t, - ), - switchReverseDuration: _lerpDuration( - switchReverseDuration, - other.switchReverseDuration, - t, - ), - switchCurve: snap ? switchCurve : other.switchCurve, - switchInCurve: snap ? switchInCurve : other.switchInCurve, - switchOutCurve: snap ? switchOutCurve : other.switchOutCurve, + loadingBuilder: snap ? loadingBuilder : other.loadingBuilder, transitionBuilder: snap ? transitionBuilder : other.transitionBuilder, - successDisplayDuration: _lerpDuration( - successDisplayDuration, - other.successDisplayDuration, - t, - ), - errorDisplayDuration: _lerpDuration( - errorDisplayDuration, - other.errorDisplayDuration, - t, - ), - cooldownDuration: _lerpDuration( - cooldownDuration, - other.cooldownDuration, - t, - ), - animateSize: snap ? animateSize : other.animateSize, - sizeCurve: snap ? sizeCurve : other.sizeCurve, - sizeAlignment: .lerp( - sizeAlignment, - other.sizeAlignment, - t, - ), - sizeClipBehavior: snap ? sizeClipBehavior : other.sizeClipBehavior, - hapticOn: snap ? hapticOn : other.hapticOn, - announceSemantics: snap ? announceSemantics : other.announceSemantics, - rethrowErrors: snap ? rethrowErrors : other.rethrowErrors, ); } - static Duration? _lerpDuration(Duration? a, Duration? b, double t) { - if (a == null && b == null) { - return null; - } - final aMs = (a ?? .zero).inMicroseconds; - final bMs = (b ?? .zero).inMicroseconds; - return Duration(microseconds: (aMs + (bMs - aMs) * t).round()); - } - @override bool operator ==(Object other) { return identical(this, other) || other is AsyncButtonTheme && - loadingChild == other.loadingChild && - successChild == other.successChild && - errorChild == other.errorChild && - switchDuration == other.switchDuration && - switchReverseDuration == other.switchReverseDuration && - switchCurve == other.switchCurve && - switchInCurve == other.switchInCurve && - switchOutCurve == other.switchOutCurve && - transitionBuilder == other.transitionBuilder && - successDisplayDuration == other.successDisplayDuration && - errorDisplayDuration == other.errorDisplayDuration && - cooldownDuration == other.cooldownDuration && - animateSize == other.animateSize && - sizeCurve == other.sizeCurve && - sizeAlignment == other.sizeAlignment && - sizeClipBehavior == other.sizeClipBehavior && - hapticOn == other.hapticOn && - announceSemantics == other.announceSemantics && - rethrowErrors == other.rethrowErrors; + loadingBuilder == other.loadingBuilder && + transitionBuilder == other.transitionBuilder; } @override int get hashCode { - return Object.hashAll([ - loadingChild, - successChild, - errorChild, - switchDuration, - switchReverseDuration, - switchCurve, - switchInCurve, - switchOutCurve, - transitionBuilder, - successDisplayDuration, - errorDisplayDuration, - cooldownDuration, - animateSize, - sizeCurve, - sizeAlignment, - sizeClipBehavior, - hapticOn, - announceSemantics, - rethrowErrors, - ]); + return Object.hash(loadingBuilder, transitionBuilder); } } -class _DefaultLoadingChild extends StatelessWidget { - const _DefaultLoadingChild({this.color}); - - final Color? color; - - @override - Widget build(BuildContext context) { - return SizedBox.square( - dimension: 16, - child: CircularProgressIndicator( - strokeWidth: 2, - valueColor: color == null - ? null - : AlwaysStoppedAnimation(color!), - ), - ); - } -} - -class _DefaultSuccessIcon extends StatelessWidget { - const _DefaultSuccessIcon({this.color}); +/// The default loading indicator — a sized, indeterminate +/// [CircularProgressIndicator]. Used as the fallback loading view, and exposed +/// so you can tweak it and return it from a `loadingBuilder`: +/// +/// ```dart +/// FilledAsyncButton( +/// onPressed: api.save, +/// loadingBuilder: (_) => const AsyncButtonSpinner(strokeWidth: 3), +/// child: const Text('Save'), +/// ) +/// ``` +class AsyncButtonSpinner extends StatelessWidget { + /// Creates a spinner. [color] defaults to the button's foreground and + /// otherwise the primary colour; [strokeWidth] sets the line weight; [size] + /// sets the square the indicator occupies — when null it tracks the ambient + /// font size so the spinner matches the button's label. + const AsyncButtonSpinner({ + super.key, + this.color, + this.strokeWidth = 2, + this.size, + }); + /// Indicator colour. When null, inherits the button's foreground (its + /// enabled foreground while loading), falling back to [ColorScheme.primary] + /// outside any button. final Color? color; - @override - Widget build(BuildContext context) { - return Icon( - Icons.check, - color: color ?? Theme.of(context).colorScheme.primary, - ); - } -} + /// Stroke width of the [CircularProgressIndicator]. + final double strokeWidth; -class _DefaultErrorIcon extends StatelessWidget { - const _DefaultErrorIcon({this.color}); - - final Color? color; + /// Side length of the square the indicator is laid out in. When null it is + /// derived from the ambient [DefaultTextStyle] font size (matching a text + /// button's label), falling back to `16`. [IconThemeData.size] is + /// intentionally not used — it is typically 24 and would oversize the spinner + /// on text buttons. + final double? size; @override Widget build(BuildContext context) { - return Icon( - Icons.error, - color: color ?? Theme.of(context).colorScheme.error, + final resolved = + color ?? + IconTheme.of(context).color ?? + Theme.of(context).colorScheme.primary; + final dimension = size ?? DefaultTextStyle.of(context).style.fontSize ?? 16; + return Center( + child: SizedBox.square( + dimension: dimension, + child: CircularProgressIndicator( + strokeWidth: strokeWidth, + valueColor: AlwaysStoppedAnimation(resolved), + ), + ), ); } } diff --git a/pubspec.yaml b/pubspec.yaml index 0dad0c5..46b44d8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,9 +1,8 @@ name: material_async_button description: >- - Drop-in async wrappers for Flutter Material buttons. Adds loading, success, - and error states with theming via ThemeExtension and external control via a - controller. -version: 1.0.1 + Drop-in async wrappers for Flutter Material buttons. Adds a loading state, + with theming via ThemeExtension and external control via a controller. +version: 2.0.0 homepage: https://mehmetesen.com repository: https://github.com/esenmx/material_async_button issue_tracker: https://github.com/esenmx/material_async_button/issues @@ -18,7 +17,7 @@ topics: environment: sdk: ^3.10.0 - flutter: ">=3.0.0" + flutter: ">=3.38.0" dependencies: flutter: diff --git a/test/_helpers.dart b/test/_helpers.dart index 594226c..98c9389 100644 --- a/test/_helpers.dart +++ b/test/_helpers.dart @@ -9,9 +9,7 @@ import 'package:material_async_button/material_async_button.dart'; /// Wraps a widget in a minimal MaterialApp + Scaffold for testing. /// /// Defaults to a [ThemeData] carrying [AsyncButtonTheme.empty] so the tests -/// see the per-widget / hard-coded fallbacks instead of the opinionated -/// [AsyncButtonTheme.material] baseline that `AsyncButtonTheme.of` returns -/// when no extension is registered. +/// see the per-widget / hard-coded fallbacks. Widget pumpHost(Widget child, {ThemeData? theme}) { return MaterialApp( theme: theme ?? ThemeData(extensions: const [AsyncButtonTheme.empty]), @@ -28,22 +26,9 @@ Widget pumpHost(Widget child, {ThemeData? theme}) { return (onPressed: () => completer.future, completer: completer); } -/// Controller pre-attached with `onPressed`/durations. Auto-disposes. -AsyncButtonController attachedController({ - AsyncCallback? onPressed, - Duration successDuration = .zero, - Duration errorDuration = .zero, - Duration cooldownDuration = .zero, - bool rethrowErrors = false, -}) { - final c = AsyncButtonController() - ..attach( - onPressed: onPressed, - successDuration: successDuration, - errorDuration: errorDuration, - cooldownDuration: cooldownDuration, - rethrowErrors: rethrowErrors, - ); +/// Controller pre-attached with `onPressed`. Auto-disposes. +AsyncButtonController attachedController({AsyncCallback? onPressed}) { + final c = AsyncButtonController()..attach(onPressed: onPressed); addTearDown(c.dispose); return c; } @@ -53,6 +38,29 @@ Widget textBuilder(_, Widget child, AsyncCallback? cb, _) { return TextButton(onPressed: cb, child: child); } +/// The colour the loading [CircularProgressIndicator] resolved to — i.e. the +/// spinner foreground inherited from the enabled button while loading. +Color? spinnerColor(WidgetTester tester) { + final cpi = tester.widget( + find.byType(CircularProgressIndicator), + ); + return cpi.valueColor?.value; +} + +/// The colour of the nearest [IconTheme] above the spinner — the scope any +/// `Icon` / spinner loading child inherits. +Color? spinnerIconThemeColor(WidgetTester tester) { + final iconTheme = tester.widget( + find + .ancestor( + of: find.byType(CircularProgressIndicator), + matching: find.byType(IconTheme), + ) + .first, + ); + return iconTheme.data.color; +} + /// `checks`-style assertions for [Finder]. extension FinderChecks on Subject { void findsOne() => has((f) => f.evaluate().length, 'matches').equals(1); @@ -63,9 +71,6 @@ extension FinderChecks on Subject { /// `checks`-style assertions for [AsyncButtonController]. extension AsyncButtonControllerChecks on Subject { - void hasStatus(AsyncButtonStatus expected) => - has((c) => c.value, 'value').equals(expected); - void isIdle() => hasStatus(const .idle()); - void isLoading() => hasStatus(const .loading()); - void isSuccess() => hasStatus(const .success()); + void isIdle() => has((c) => c.value, 'isLoading').isFalse(); + void isLoading() => has((c) => c.value, 'isLoading').isTrue(); } diff --git a/test/async_button_controller_test.dart b/test/async_button_controller_test.dart index 9b402a7..3b793d5 100644 --- a/test/async_button_controller_test.dart +++ b/test/async_button_controller_test.dart @@ -7,9 +7,9 @@ import 'package:material_async_button/material_async_button.dart'; import '_helpers.dart'; -/// Subscribes a status-recording listener to [c]; returns the recording list. -List recordStatuses(AsyncButtonController c) { - final out = []; +/// Subscribes a loading-recording listener to [c]; returns the recording list. +List recordStates(AsyncButtonController c) { + final out = []; c.addListener(() => out.add(c.value)); return out; } @@ -24,140 +24,43 @@ void main() { ..has((it) => it.canTrigger, 'canTrigger').isFalse(); }); - test('honors initial status', () { - final c = AsyncButtonController(const .loading()); - addTearDown(c.dispose); - check(c).isLoading(); - }); - test('trigger no-ops when no onPressed is attached', () async { final c = AsyncButtonController(); addTearDown(c.dispose); await c.trigger(); check(c).isIdle(); }); - }); - group('AsyncButtonController forced transitions', () { - test('reset returns to idle and cancels pending display', () async { - final c = attachedController( - onPressed: () async {}, - successDuration: const Duration(seconds: 5), - ); - await c.trigger(); - check(c).isSuccess(); + test('reset returns to idle', () async { + final completer = Completer(); + final c = attachedController(onPressed: () => completer.future); + unawaited(c.trigger()); + check(c).isLoading(); c.reset(); check(c).isIdle(); - }); - - test('invalidate with zero duration returns straight to idle', () { - final c = attachedController()..invalidate('bad'); - check(c).isIdle(); - }); - - test('invalidate holds error until errorDuration elapses', () async { - final c = attachedController( - errorDuration: const Duration(milliseconds: 50), - )..invalidate('bad'); - check(c.value) - .isA() - .has((f) => f.error, 'error') - .equals('bad'); - await Future.delayed(const Duration(milliseconds: 70)); - check(c).isIdle(); - }); - - test('markSuccess forces success', () { - final c = attachedController( - successDuration: const Duration(seconds: 5), - )..markSuccess(); - check(c).isSuccess(); + completer.complete(); }); }); group('AsyncButtonController.trigger', () { - test('successful run traces loading -> success -> idle', () async { + test('successful run traces loading -> idle', () async { final c = attachedController( onPressed: () => Future.delayed(const Duration(milliseconds: 20)), - successDuration: const Duration(milliseconds: 20), - ); - final transitions = recordStatuses(c); - await c.trigger(); - await Future.delayed(const Duration(milliseconds: 50)); - check(transitions.map((s) => s.runtimeType).toList()) - ..contains(AsyncButtonStatusLoading) - ..contains(AsyncButtonStatusSuccess) - ..contains(AsyncButtonStatusIdle); - }); - - test('failing run traces loading -> error -> idle', () async { - final c = attachedController( - onPressed: () async => throw StateError('oops'), - errorDuration: const Duration(milliseconds: 20), - ); - final transitions = recordStatuses(c); - await c.trigger(); - await Future.delayed(const Duration(milliseconds: 50)); - check(transitions.map((s) => s.runtimeType).toList()) - ..contains(AsyncButtonStatusLoading) - ..contains(AsyncButtonStatusError) - ..contains(AsyncButtonStatusIdle); - }); - - test('error variant carries the thrown error and stack trace', () async { - final c = attachedController( - onPressed: () async => throw StateError('oops'), - errorDuration: const Duration(milliseconds: 50), ); + final states = recordStates(c); await c.trigger(); - check(c.value) - .isA() - .has((f) => f.error, 'error') - .isA(); - check(c.value) - .isA() - .has((f) => f.stackTrace, 'stackTrace') - .isNotNull(); - await Future.delayed(const Duration(milliseconds: 70)); + check(states).deepEquals([true, false]); check(c).isIdle(); }); - test('rethrowErrors=true bubbles the error to the caller', () async { + test('failing run resets to idle and rethrows', () async { final c = attachedController( onPressed: () async => throw StateError('oops'), - rethrowErrors: true, ); + final states = recordStates(c); await check(c.trigger()).throws(); - }); - - test('cooldown keeps canTrigger false after returning to idle', () async { - final c = attachedController( - onPressed: () async {}, - cooldownDuration: const Duration(milliseconds: 40), - ); - await c.trigger(); - check(c) - ..isIdle() - ..has((it) => it.isInCooldown, 'isInCooldown').isTrue() - ..has((it) => it.canTrigger, 'canTrigger').isFalse(); - await Future.delayed(const Duration(milliseconds: 60)); - check(c) - ..has((it) => it.isInCooldown, 'isInCooldown').isFalse() - ..has((it) => it.canTrigger, 'canTrigger').isTrue(); - }); - - test('dispose does not throw for pending timers', () async { - AsyncButtonController() - ..attach( - onPressed: null, - successDuration: const Duration(seconds: 5), - errorDuration: .zero, - cooldownDuration: .zero, - rethrowErrors: false, - ) - ..markSuccess() - ..dispose(); - await Future.delayed(const Duration(milliseconds: 10)); + check(states).deepEquals([true, false]); + check(c).isIdle(); }); }); @@ -179,7 +82,7 @@ void main() { check(calls).equals(1); }); - test('reset mid-onPressed stops the success transition', () async { + test('reset mid-onPressed leaves the button idle', () async { final completer = Completer(); final c = attachedController(onPressed: () => completer.future); final f = c.trigger(); @@ -192,22 +95,16 @@ void main() { }); group('AsyncButtonController interop', () { - testWidgets('exposes a ValueListenable', (tester) async { - final c = attachedController( - successDuration: const Duration(seconds: 5), - ); + testWidgets('exposes a ValueListenable', (tester) async { + final completer = Completer(); + final c = attachedController(onPressed: () => completer.future); await tester.pumpWidget( MaterialApp( - home: ValueListenableBuilder( + home: ValueListenableBuilder( valueListenable: c, - builder: (context, status, child) => Text( - switch (status) { - AsyncButtonStatusIdle() => 'idle', - AsyncButtonStatusLoading() => 'loading', - AsyncButtonStatusSuccess() => 'success', - AsyncButtonStatusError() => 'error', - }, + builder: (context, isLoading, child) => Text( + isLoading ? 'loading' : 'idle', textDirection: .ltr, ), ), @@ -215,10 +112,14 @@ void main() { ); check(find.text('idle')).findsOne(); - c.markSuccess(); + unawaited(c.trigger()); await tester.pump(); - check(find.text('success')).findsOne(); - c.reset(); + check(find.text('loading')).findsOne(); + + completer.complete(); + await tester.pump(); // drain the completion microtask + await tester.pump(); // rebuild with the idle state + check(find.text('idle')).findsOne(); }); }); } diff --git a/test/async_button_test.dart b/test/async_button_test.dart index 757359f..07dbbe6 100644 --- a/test/async_button_test.dart +++ b/test/async_button_test.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:checks/checks.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -20,7 +22,7 @@ void main() { check(find.text('hello')).findsOne(); }); - testWidgets('falls back to built-in spinner when no loadingChild', ( + testWidgets('falls back to built-in spinner when no loadingBuilder', ( tester, ) async { final (:onPressed, :completer) = pendingPress(); @@ -40,13 +42,36 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('uses per-widget loadingChild when given', (tester) async { + testWidgets('stays enabled while loading (taps are no-ops)', ( + tester, + ) async { final (:onPressed, :completer) = pendingPress(); await tester.pumpWidget( pumpHost( AsyncButton( onPressed: onPressed, - loadingChild: const Text('spinning'), + builder: textBuilder, + child: const Text('go'), + ), + ), + ); + await tester.tap(find.byType(TextButton)); + await tester.pump(); + // Loading never disables the button — the callback stays wired; the + // controller swallows the tap (still loading), so it doesn't re-run. + final btn = tester.widget(find.byType(TextButton)); + check(btn.onPressed).isNotNull(); + completer.complete(); + await tester.pumpAndSettle(); + }); + + testWidgets('uses per-widget loadingBuilder when given', (tester) async { + final (:onPressed, :completer) = pendingPress(); + await tester.pumpWidget( + pumpHost( + AsyncButton( + onPressed: onPressed, + loadingBuilder: (_) => const Text('spinning'), builder: textBuilder, child: const Text('go'), ), @@ -59,7 +84,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('theme loadingChild used when no per-widget override', ( + testWidgets('theme loadingBuilder used when no per-widget override', ( tester, ) async { final (:onPressed, :completer) = pendingPress(); @@ -71,8 +96,10 @@ void main() { child: const Text('go'), ), theme: ThemeData( - extensions: const [ - AsyncButtonTheme(loadingChild: Text('themed-loading')), + extensions: [ + AsyncButtonTheme( + loadingBuilder: (_) => const Text('themed-loading'), + ), ], ), ), @@ -84,19 +111,19 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('widget loadingChild beats theme', (tester) async { + testWidgets('widget loadingBuilder beats theme', (tester) async { final (:onPressed, :completer) = pendingPress(); await tester.pumpWidget( pumpHost( AsyncButton( onPressed: onPressed, - loadingChild: const Text('widget'), + loadingBuilder: (_) => const Text('widget'), builder: textBuilder, child: const Text('go'), ), theme: ThemeData( - extensions: const [ - AsyncButtonTheme(loadingChild: Text('themed')), + extensions: [ + AsyncButtonTheme(loadingBuilder: (_) => const Text('themed')), ], ), ), @@ -111,7 +138,7 @@ void main() { }); group('AsyncButton transitions', () { - testWidgets('returns to child after success with zero display duration', ( + testWidgets('returns to its child after onPressed completes', ( tester, ) async { await tester.pumpWidget( @@ -128,84 +155,31 @@ void main() { check(find.text('label')).findsOne(); }); - testWidgets('shows successChild for successDisplayDuration', ( + testWidgets('a throwing onPressed returns to idle and rethrows', ( tester, ) async { + final controller = AsyncButtonController(); + addTearDown(controller.dispose); await tester.pumpWidget( pumpHost( AsyncButton( - onPressed: () async {}, - successChild: const Text('done!'), - successDisplayDuration: const Duration(milliseconds: 200), - builder: textBuilder, - child: const Text('label'), - ), - ), - ); - await tester.tap(find.byType(TextButton)); - await tester.pump(); - await tester.pump(); - check(find.text('done!')).findsOne(); - await tester.pump(const Duration(milliseconds: 250)); - await tester.pumpAndSettle(); - check(find.text('done!')).findsNone(); - check(find.text('label')).findsOne(); - }); - - testWidgets('shows errorChild during error status', (tester) async { - await tester.pumpWidget( - pumpHost( - AsyncButton( + controller: controller, onPressed: () async => throw StateError('boom'), - errorChild: const Text('errored'), - errorDisplayDuration: const Duration(milliseconds: 100), builder: textBuilder, child: const Text('label'), ), ), ); - await tester.tap(find.byType(TextButton)); + // The error is not swallowed — trigger() rethrows so the caller (state + // management / the surrounding zone) sees it. + await check(controller.trigger()).throws(); await tester.pump(); - await tester.pump(); - check(find.text('errored')).findsOne(); - await tester.pump(const Duration(milliseconds: 200)); - await tester.pumpAndSettle(); - }); - - testWidgets('onError carries the thrown error payload', (tester) async { - Object? captured; - await tester.pumpWidget( - pumpHost( - AsyncButton( - onPressed: () async => throw StateError('x'), - onError: (e, _) => captured = e, - builder: textBuilder, - child: const Text('label'), - ), - ), - ); - await tester.tap(find.byType(TextButton)); - await tester.pumpAndSettle(); - check(captured).isA(); + // The button is back to its idle child — there is no error view. + check(find.text('label')).findsOne(); }); }); group('AsyncButton callbacks', () { - testWidgets('callback null when disabled', (tester) async { - await tester.pumpWidget( - pumpHost( - AsyncButton( - onPressed: () async {}, - disabled: true, - builder: textBuilder, - child: const Text('label'), - ), - ), - ); - final btn = tester.widget(find.byType(TextButton)); - check(btn.onPressed).isNull(); - }); - testWidgets('callback null when onPressed is null', (tester) async { await tester.pumpWidget( pumpHost( @@ -220,127 +194,104 @@ void main() { check(btn.onPressed).isNull(); }); - testWidgets('onSuccess and onStateChanged fire', (tester) async { - var successCount = 0; - final statuses = []; + testWidgets('callback null when enabled is false', (tester) async { await tester.pumpWidget( pumpHost( AsyncButton( onPressed: () async {}, - onSuccess: () => successCount++, - onStateChanged: statuses.add, - builder: textBuilder, - child: const Text('label'), - ), - ), - ); - await tester.tap(find.byType(TextButton)); - await tester.pumpAndSettle(); - check(successCount).equals(1); - check(statuses.map((s) => s.runtimeType).toList()) - ..contains(AsyncButtonStatusLoading) - ..contains(AsyncButtonStatusSuccess) - ..contains(AsyncButtonStatusIdle); - }); - - testWidgets('onError fires with the thrown error', (tester) async { - Object? captured; - await tester.pumpWidget( - pumpHost( - AsyncButton( - onPressed: () async => throw StateError('x'), - onError: (e, _) => captured = e, + enabled: false, builder: textBuilder, child: const Text('label'), ), ), ); - await tester.tap(find.byType(TextButton)); - await tester.pumpAndSettle(); - check(captured).isA(); + final btn = tester.widget(find.byType(TextButton)); + check(btn.onPressed).isNull(); }); - testWidgets('confirmBeforePress can cancel the press', (tester) async { + testWidgets('enabled:false no-ops external controller.trigger', ( + tester, + ) async { var ran = 0; - await tester.pumpWidget( - pumpHost( - AsyncButton( - onPressed: () async => ran++, - confirmBeforePress: (_) async => false, - builder: textBuilder, - child: const Text('label'), - ), - ), - ); - await tester.tap(find.byType(TextButton)); - await tester.pumpAndSettle(); - check(ran).equals(0); - }); - }); - - group('AsyncButton external control', () { - testWidgets('controller.trigger() runs onPressed', (tester) async { final controller = AsyncButtonController(); addTearDown(controller.dispose); - var ran = 0; await tester.pumpWidget( pumpHost( AsyncButton( controller: controller, onPressed: () async => ran++, + enabled: false, builder: textBuilder, child: const Text('label'), ), ), ); + // enabled:false collapses to onPressed:null at the controller seam, so an + // external trigger can't run either. await controller.trigger(); - await tester.pumpAndSettle(); - check(ran).equals(1); + await tester.pump(); + check(ran).equals(0); + check(controller).isIdle(); + check(find.byType(CircularProgressIndicator)).findsNone(); }); + }); - testWidgets('controller.invalidate flips to error', (tester) async { + group('AsyncButton external control', () { + testWidgets('controller.trigger drives loading; stays enabled', ( + tester, + ) async { final controller = AsyncButtonController(); addTearDown(controller.dispose); + final completer = Completer(); await tester.pumpWidget( pumpHost( AsyncButton( controller: controller, - onPressed: () async {}, - errorChild: const Text('errored'), - errorDisplayDuration: const Duration(milliseconds: 100), + onPressed: () => completer.future, builder: textBuilder, child: const Text('label'), ), ), ); - controller.invalidate('bad'); + // Idle: interactive. + check( + tester.widget(find.byType(TextButton)).onPressed, + ).isNotNull(); + + unawaited(controller.trigger()); await tester.pump(); - check(find.text('errored')).findsOne(); - await tester.pump(const Duration(milliseconds: 200)); + // Loading: spinner shows and the button keeps its enabled look. + check(find.byType(CircularProgressIndicator)).findsOne(); + check( + tester.widget(find.byType(TextButton)).onPressed, + ).isNotNull(); + + completer.complete(); await tester.pumpAndSettle(); + check(find.text('label')).findsOne(); }); - testWidgets('controller.reset clears mid-display', (tester) async { + testWidgets('controller.reset clears the loading state', (tester) async { final controller = AsyncButtonController(); addTearDown(controller.dispose); + final completer = Completer(); await tester.pumpWidget( pumpHost( AsyncButton( controller: controller, - onPressed: () async {}, - successChild: const Text('yay'), - successDisplayDuration: const Duration(seconds: 5), + onPressed: () => completer.future, builder: textBuilder, child: const Text('label'), ), ), ); - controller.markSuccess(); + unawaited(controller.trigger()); await tester.pump(); - check(find.text('yay')).findsOne(); + check(find.byType(CircularProgressIndicator)).findsOne(); controller.reset(); await tester.pump(); check(find.text('label')).findsOne(); + completer.complete(); }); testWidgets( @@ -348,54 +299,81 @@ void main() { (tester) async { final a = AsyncButtonController(); final b = AsyncButtonController(); + final aCompleter = Completer(); + final bCompleter = Completer(); addTearDown(() { a.dispose(); b.dispose(); }); - AsyncButton button(AsyncButtonController c) => AsyncButton( - controller: c, - onPressed: () async {}, - successChild: const Text('done'), - successDisplayDuration: const Duration(milliseconds: 100), - builder: textBuilder, - child: const Text('child'), - ); - await tester.pumpWidget(pumpHost(button(a))); - await tester.pumpWidget(pumpHost(button(b))); - a.markSuccess(); + AsyncButton button(AsyncButtonController c, Completer done) => + AsyncButton( + controller: c, + onPressed: () => done.future, + builder: textBuilder, + child: const Text('child'), + ); + await tester.pumpWidget(pumpHost(button(a, aCompleter))); + await tester.pumpWidget(pumpHost(button(b, bCompleter))); + // The widget now listens to b: driving a must not show loading. + unawaited(a.trigger()); await tester.pump(); - check(find.text('done')).findsNone(); - b.markSuccess(); + check(find.byType(CircularProgressIndicator)).findsNone(); + // Driving b does. + unawaited(b.trigger()); await tester.pump(); - check(find.text('done')).findsOne(); - await tester.pump(const Duration(milliseconds: 200)); + check(find.byType(CircularProgressIndicator)).findsOne(); + aCompleter.complete(); + bCompleter.complete(); await tester.pumpAndSettle(); }, ); }); - group('AsyncButton timer hygiene', () { - testWidgets('invalidate then markSuccess does not race', (tester) async { - final controller = AsyncButtonController(); - addTearDown(controller.dispose); + group('AsyncButton transition builder', () { + testWidgets('no transition by default — the swap is instant', ( + tester, + ) async { + final (:onPressed, :completer) = pendingPress(); await tester.pumpWidget( pumpHost( - AsyncButton( - controller: controller, - onPressed: () async {}, - errorChild: const Text('e'), - errorDisplayDuration: const Duration(milliseconds: 200), - builder: textBuilder, - child: const Text('child'), - ), + FilledAsyncButton(onPressed: onPressed, child: const Text('go')), ), ); - controller.invalidate('1'); + await tester.tap(find.byType(FilledButton)); await tester.pump(); - controller.markSuccess(); + // No AnimatedSwitcher/AnimatedSize is inserted by the package. + check(find.byType(AnimatedSwitcher)).findsNone(); + check(find.byType(CircularProgressIndicator)).findsOne(); + completer.complete(); + await tester.pumpAndSettle(); + }); + + testWidgets('wraps the keyed state child with the supplied builder', ( + tester, + ) async { + final (:onPressed, :completer) = pendingPress(); + final seenLoading = []; + await tester.pumpWidget( + pumpHost( + FilledAsyncButton( + onPressed: onPressed, + transitionBuilder: (context, child, isLoading) { + seenLoading.add(isLoading); + return AnimatedSwitcher( + duration: const Duration(milliseconds: 100), + child: child, + ); + }, + child: const Text('go'), + ), + ), + ); + await tester.tap(find.byType(FilledButton)); await tester.pump(); - await tester.pump(const Duration(milliseconds: 250)); - check(find.text('child')).findsOne(); + check(find.byType(AnimatedSwitcher)).findsOne(); + check(seenLoading).contains(true); + completer.complete(); + await tester.pumpAndSettle(); }); }); } diff --git a/test/elevated_async_button_test.dart b/test/elevated_async_button_test.dart index ec5237c..fb7e7b8 100644 --- a/test/elevated_async_button_test.dart +++ b/test/elevated_async_button_test.dart @@ -10,61 +10,64 @@ void main() { testWidgets('renders an ElevatedButton with the child', (tester) async { await tester.pumpWidget( pumpHost( - ElevatedAsyncButton( - onPressed: () async {}, - child: const Text('go'), - ), + ElevatedAsyncButton(onPressed: () async {}, child: const Text('go')), ), ); check(find.byType(ElevatedButton)).findsOne(); check(find.text('go')).findsOne(); }); - testWidgets('shows loading then returns to idle', (tester) async { + testWidgets('loading spinner uses primary, not the disabled grey', ( + tester, + ) async { final (:onPressed, :completer) = pendingPress(); + final theme = ThemeData(extensions: const [AsyncButtonTheme.empty]); await tester.pumpWidget( pumpHost( - ElevatedAsyncButton( - onPressed: onPressed, - child: const Text('go'), - ), + ElevatedAsyncButton(onPressed: onPressed, child: const Text('go')), + theme: theme, ), ); await tester.tap(find.byType(ElevatedButton)); await tester.pump(); - check(find.byType(CircularProgressIndicator)).findsOne(); + await tester.pump(const Duration(milliseconds: 250)); + check(spinnerColor(tester)).equals(theme.colorScheme.primary); completer.complete(); await tester.pumpAndSettle(); - check(find.text('go')).findsOne(); }); - testWidgets('is disabled when onPressed is null', (tester) async { - await tester.pumpWidget( - pumpHost( - const ElevatedAsyncButton(onPressed: null, child: Text('go')), - ), - ); - final btn = tester.widget(find.byType(ElevatedButton)); - check(btn.onPressed).isNull(); - }); - - testWidgets('is disabled when disabled=true', (tester) async { + testWidgets('onLongPress is gated off while loading', (tester) async { + final (:onPressed, :completer) = pendingPress(); await tester.pumpWidget( pumpHost( ElevatedAsyncButton( - onPressed: () async {}, - disabled: true, + onPressed: onPressed, + onLongPress: () {}, child: const Text('go'), ), ), ); - final btn = tester.widget(find.byType(ElevatedButton)); - check(btn.onPressed).isNull(); + // Idle: long-press is wired. + check( + tester.widget(find.byType(ElevatedButton)).onLongPress, + ).isNotNull(); + + await tester.tap(find.byType(ElevatedButton)); + await tester.pump(); + // Loading: the button looks enabled, but long-press is gated off. + check( + tester.widget(find.byType(ElevatedButton)).onLongPress, + ).isNull(); + + completer.complete(); + await tester.pumpAndSettle(); }); }); group('ElevatedAsyncButton.icon', () { - testWidgets('icon stays put while the label animates', (tester) async { + testWidgets('spinner replaces icon and label, both restored after', ( + tester, + ) async { final (:onPressed, :completer) = pendingPress(); await tester.pumpWidget( pumpHost( @@ -79,10 +82,14 @@ void main() { check(find.text('send')).findsOne(); await tester.tap(find.byType(ElevatedButton)); await tester.pump(); - check(find.byIcon(Icons.send)).findsOne(); + await tester.pump(const Duration(milliseconds: 250)); + // Loading drops the icon and shows the spinner alone. check(find.byType(CircularProgressIndicator)).findsOne(); + check(find.byIcon(Icons.send)).findsNone(); completer.complete(); await tester.pumpAndSettle(); + // Icon and label both return once the work completes. + check(find.byIcon(Icons.send)).findsOne(); check(find.text('send')).findsOne(); }); }); diff --git a/test/filled_async_button_test.dart b/test/filled_async_button_test.dart index eefa1e5..8f9adbe 100644 --- a/test/filled_async_button_test.dart +++ b/test/filled_async_button_test.dart @@ -10,10 +10,7 @@ void main() { testWidgets('renders FilledButton', (tester) async { await tester.pumpWidget( pumpHost( - FilledAsyncButton( - onPressed: () async {}, - child: const Text('go'), - ), + FilledAsyncButton(onPressed: () async {}, child: const Text('go')), ), ); check(find.byType(FilledButton)).findsOne(); @@ -31,7 +28,22 @@ void main() { check(find.byType(FilledButton)).findsOne(); }); - testWidgets('.icon swaps label during loading', (tester) async { + testWidgets('.tonalIcon renders', (tester) async { + await tester.pumpWidget( + pumpHost( + FilledAsyncButton.tonalIcon( + onPressed: () async {}, + icon: const Icon(Icons.save), + label: const Text('save'), + ), + ), + ); + check(find.byType(FilledButton)).findsOne(); + }); + + testWidgets('.icon shows the spinner while loading, restores after', ( + tester, + ) async { final (:onPressed, :completer) = pendingPress(); await tester.pumpWidget( pumpHost( @@ -45,24 +57,78 @@ void main() { await tester.tap(find.byType(FilledButton)); await tester.pump(); await tester.pump(const Duration(milliseconds: 250)); - check(find.byIcon(Icons.save)).findsOne(); - check(find.text('save')).findsNone(); + // Loading drops the icon and shows the spinner alone. check(find.byType(CircularProgressIndicator)).findsOne(); + check(find.byIcon(Icons.save)).findsNone(); completer.complete(); await tester.pumpAndSettle(); + // Label and icon return once the work completes. + check(find.text('save')).findsOne(); + check(find.byIcon(Icons.save)).findsOne(); }); + }); - testWidgets('.tonalIcon renders', (tester) async { + group('FilledAsyncButton loading foreground', () { + testWidgets('spinner uses onPrimary, not the disabled grey', ( + tester, + ) async { + final (:onPressed, :completer) = pendingPress(); + final theme = ThemeData(extensions: const [AsyncButtonTheme.empty]); await tester.pumpWidget( pumpHost( - FilledAsyncButton.tonalIcon( - onPressed: () async {}, - icon: const Icon(Icons.save), - label: const Text('save'), + FilledAsyncButton(onPressed: onPressed, child: const Text('go')), + theme: theme, + ), + ); + await tester.tap(find.byType(FilledButton)); + await tester.pump(); + await tester.pump(const Duration(milliseconds: 250)); + check(spinnerColor(tester)).equals(theme.colorScheme.onPrimary); + completer.complete(); + await tester.pumpAndSettle(); + }); + + testWidgets('.tonal spinner uses onSecondaryContainer', (tester) async { + final (:onPressed, :completer) = pendingPress(); + final theme = ThemeData(extensions: const [AsyncButtonTheme.empty]); + await tester.pumpWidget( + pumpHost( + FilledAsyncButton.tonal( + onPressed: onPressed, + child: const Text('go'), ), + theme: theme, ), ); - check(find.byType(FilledButton)).findsOne(); + await tester.tap(find.byType(FilledButton)); + await tester.pump(); + await tester.pump(const Duration(milliseconds: 250)); + check( + spinnerColor(tester), + ).equals(theme.colorScheme.onSecondaryContainer); + completer.complete(); + await tester.pumpAndSettle(); + }); + + testWidgets('a custom spinner colour overrides the inherited one', ( + tester, + ) async { + final (:onPressed, :completer) = pendingPress(); + await tester.pumpWidget( + pumpHost( + FilledAsyncButton( + onPressed: onPressed, + loadingBuilder: (_) => const AsyncButtonSpinner(color: Colors.teal), + child: const Text('go'), + ), + ), + ); + await tester.tap(find.byType(FilledButton)); + await tester.pump(); + await tester.pump(const Duration(milliseconds: 250)); + check(spinnerColor(tester)).equals(Colors.teal); + completer.complete(); + await tester.pumpAndSettle(); }); }); } diff --git a/test/icon_async_button_test.dart b/test/icon_async_button_test.dart index 2998f13..98f200e 100644 --- a/test/icon_async_button_test.dart +++ b/test/icon_async_button_test.dart @@ -61,4 +61,45 @@ void main() { check(find.byIcon(Icons.refresh)).findsOne(); }); }); + + group('IconAsyncButton loading foreground', () { + testWidgets('.filled spinner uses onPrimary', (tester) async { + final (:onPressed, :completer) = pendingPress(); + final theme = ThemeData(extensions: const [AsyncButtonTheme.empty]); + await tester.pumpWidget( + pumpHost( + IconAsyncButton.filled( + onPressed: onPressed, + icon: const Icon(Icons.add), + ), + theme: theme, + ), + ); + await tester.tap(find.byType(IconButton)); + await tester.pump(); + await tester.pump(const Duration(milliseconds: 250)); + check(spinnerColor(tester)).equals(theme.colorScheme.onPrimary); + completer.complete(); + await tester.pumpAndSettle(); + }); + + testWidgets('honours the color property', (tester) async { + final (:onPressed, :completer) = pendingPress(); + await tester.pumpWidget( + pumpHost( + IconAsyncButton( + onPressed: onPressed, + color: Colors.purple, + icon: const Icon(Icons.refresh), + ), + ), + ); + await tester.tap(find.byType(IconButton)); + await tester.pump(); + await tester.pump(const Duration(milliseconds: 250)); + check(spinnerColor(tester)).equals(Colors.purple); + completer.complete(); + await tester.pumpAndSettle(); + }); + }); } diff --git a/test/material_async_button_theme_test.dart b/test/material_async_button_theme_test.dart index 12fdb9b..0d059e5 100644 --- a/test/material_async_button_theme_test.dart +++ b/test/material_async_button_theme_test.dart @@ -3,99 +3,64 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:material_async_button/material_async_button.dart'; +// A no-op transition builder for theme-field tests. +Widget _noopTransition(BuildContext context, Widget child, bool isLoading) { + return child; +} + void main() { group('AsyncButtonTheme', () { test('empty default has all null fields', () { const t = AsyncButtonTheme.empty; check(t) - ..has((it) => it.loadingChild, 'loadingChild').isNull() - ..has((it) => it.successChild, 'successChild').isNull() - ..has((it) => it.errorChild, 'errorChild').isNull() - ..has((it) => it.switchDuration, 'switchDuration').isNull() - ..has((it) => it.hapticOn, 'hapticOn').isNull(); - }); - - test('material() supplies opinionated baseline', () { - final t = AsyncButtonTheme.material(); - check(t) - ..has((it) => it.loadingChild, 'loadingChild').isNotNull() - ..has((it) => it.successChild, 'successChild').isNotNull() - ..has((it) => it.errorChild, 'errorChild').isNotNull() - ..has( - (it) => it.switchDuration, - 'switchDuration', - ).equals(const Duration(milliseconds: 200)) - ..has( - (it) => it.successDisplayDuration, - 'successDisplayDuration', - ).equals(const Duration(milliseconds: 800)) - ..has( - (it) => it.errorDisplayDuration, - 'errorDisplayDuration', - ).equals(const Duration(milliseconds: 800)) - ..has((it) => it.animateSize, 'animateSize').equals(true) - ..has((it) => it.hapticOn, 'hapticOn').equals(HapticOn.both) - ..has((it) => it.announceSemantics, 'announceSemantics').equals(true); + ..has((it) => it.loadingBuilder, 'loadingBuilder').isNull() + ..has((it) => it.transitionBuilder, 'transitionBuilder').isNull(); }); - test('copyWith overrides only specified fields', () { - final base = AsyncButtonTheme.material(); - final overridden = base.copyWith( - switchDuration: const Duration(milliseconds: 500), + test('copyWith overrides only specified fields, preserving the rest', () { + Widget loadingA(BuildContext _) => const SizedBox.shrink(); + Widget loadingB(BuildContext _) => const SizedBox.shrink(); + final base = AsyncButtonTheme( + loadingBuilder: loadingA, + transitionBuilder: _noopTransition, ); + final overridden = base.copyWith(loadingBuilder: loadingB); check(overridden) + ..has((it) => it.loadingBuilder, 'loadingBuilder').equals(loadingB) ..has( - (it) => it.switchDuration, - 'switchDuration', - ).equals(const Duration(milliseconds: 500)) - ..has( - (it) => it.successDisplayDuration, - 'successDisplayDuration', - ).equals(base.successDisplayDuration) - ..has((it) => it.hapticOn, 'hapticOn').equals(base.hapticOn); + (it) => it.transitionBuilder, + 'transitionBuilder', + ).equals(_noopTransition); }); - test('lerp snaps non-numeric fields and interpolates durations', () { - const a = AsyncButtonTheme( - switchDuration: Duration(milliseconds: 100), - successDisplayDuration: Duration(milliseconds: 200), - hapticOn: HapticOn.success, - ); - const b = AsyncButtonTheme( - switchDuration: Duration(milliseconds: 300), - successDisplayDuration: Duration(milliseconds: 600), - hapticOn: HapticOn.error, - ); - final mid = a.lerp(b, 0.5); - check(mid) - ..has( - (it) => it.switchDuration, - 'switchDuration', - ).equals(const Duration(milliseconds: 200)) - ..has( - (it) => it.successDisplayDuration, - 'successDisplayDuration', - ).equals(const Duration(milliseconds: 400)) - ..has((it) => it.hapticOn, 'hapticOn').equals(HapticOn.error); + test('lerp snaps fields at the halfway point', () { + Widget loadingA(BuildContext _) => const SizedBox.shrink(); + Widget loadingB(BuildContext _) => const SizedBox.shrink(); + final from = AsyncButtonTheme(loadingBuilder: loadingA); + final to = AsyncButtonTheme(loadingBuilder: loadingB); + check( + from.lerp(to, 0.4), + ).has((it) => it.loadingBuilder, 'loadingBuilder').equals(loadingA); + check( + from.lerp(to, 0.6), + ).has((it) => it.loadingBuilder, 'loadingBuilder').equals(loadingB); }); test('lerp with non-AsyncButtonTheme returns self', () { - const a = AsyncButtonTheme( - switchDuration: Duration(milliseconds: 100), - ); - check(a.lerp(null, 0.5)) - .has((it) => it.switchDuration, 'switchDuration') - .equals(a.switchDuration); + Widget loadingA(BuildContext _) => const SizedBox.shrink(); + final a = AsyncButtonTheme(loadingBuilder: loadingA); + check( + a.lerp(null, 0.5), + ).has((it) => it.loadingBuilder, 'loadingBuilder').equals(loadingA); }); testWidgets('of(context) returns the registered extension', (tester) async { - const ext = AsyncButtonTheme( - switchDuration: Duration(milliseconds: 123), - ); + Widget loadingA(BuildContext _) => const SizedBox.shrink(); + final ext = AsyncButtonTheme(loadingBuilder: loadingA); AsyncButtonTheme? captured; await tester.pumpWidget( MaterialApp( - theme: ThemeData(extensions: const [ext]), + theme: ThemeData(extensions: [ext]), home: Builder( builder: (ctx) { captured = AsyncButtonTheme.of(ctx); @@ -106,11 +71,11 @@ void main() { ); check(captured) .isNotNull() - .has((it) => it.switchDuration, 'switchDuration') - .equals(const Duration(milliseconds: 123)); + .has((it) => it.loadingBuilder, 'loadingBuilder') + .equals(loadingA); }); - testWidgets('of(context) falls back to material defaults when absent', ( + testWidgets('of(context) falls back to empty when no extension is set', ( tester, ) async { AsyncButtonTheme? captured; @@ -124,41 +89,20 @@ void main() { ), ), ); - check(captured) - .isNotNull() - .has((it) => it.switchDuration, 'switchDuration') - .equals(const Duration(milliseconds: 200)); + check(captured).isNotNull() + ..has((it) => it.loadingBuilder, 'loadingBuilder').isNull() + ..has((it) => it.transitionBuilder, 'transitionBuilder').isNull(); }); - testWidgets( - 'of(context) returns registered empty extension when explicitly set', - (tester) async { - AsyncButtonTheme? captured; - await tester.pumpWidget( - MaterialApp( - theme: ThemeData(extensions: const [AsyncButtonTheme.empty]), - home: Builder( - builder: (ctx) { - captured = AsyncButtonTheme.of(ctx); - return const SizedBox.shrink(); - }, - ), - ), - ); - check( - captured, - ).isNotNull().has((it) => it.switchDuration, 'switchDuration').isNull(); - }, - ); - test('equality is value-based', () { - const a = AsyncButtonTheme( - switchDuration: Duration(milliseconds: 100), - hapticOn: HapticOn.both, + Widget loadingA(BuildContext _) => const SizedBox.shrink(); + final a = AsyncButtonTheme( + loadingBuilder: loadingA, + transitionBuilder: _noopTransition, ); - const b = AsyncButtonTheme( - switchDuration: Duration(milliseconds: 100), - hapticOn: HapticOn.both, + final b = AsyncButtonTheme( + loadingBuilder: loadingA, + transitionBuilder: _noopTransition, ); check(a).equals(b); check(a.hashCode).equals(b.hashCode); diff --git a/test/outlined_async_button_test.dart b/test/outlined_async_button_test.dart index 370a1b6..7647b9a 100644 --- a/test/outlined_async_button_test.dart +++ b/test/outlined_async_button_test.dart @@ -10,10 +10,7 @@ void main() { testWidgets('renders OutlinedButton', (tester) async { await tester.pumpWidget( pumpHost( - OutlinedAsyncButton( - onPressed: () async {}, - child: const Text('go'), - ), + OutlinedAsyncButton(onPressed: () async {}, child: const Text('go')), ), ); check(find.byType(OutlinedButton)).findsOne(); @@ -34,19 +31,24 @@ void main() { check(find.text('share')).findsOne(); }); - testWidgets('cycles through loading', (tester) async { + testWidgets('loading spinner honours style.foregroundColor', ( + tester, + ) async { final (:onPressed, :completer) = pendingPress(); await tester.pumpWidget( pumpHost( OutlinedAsyncButton( onPressed: onPressed, - child: const Text('go'), + style: OutlinedButton.styleFrom(foregroundColor: Colors.red), + child: const Text('delete'), ), ), ); await tester.tap(find.byType(OutlinedButton)); await tester.pump(); - check(find.byType(CircularProgressIndicator)).findsOne(); + await tester.pump(const Duration(milliseconds: 250)); + check(spinnerColor(tester)).equals(Colors.red); + check(spinnerIconThemeColor(tester)).equals(Colors.red); completer.complete(); await tester.pumpAndSettle(); }); diff --git a/test/text_async_button_test.dart b/test/text_async_button_test.dart index baa0a01..6db8588 100644 --- a/test/text_async_button_test.dart +++ b/test/text_async_button_test.dart @@ -10,10 +10,7 @@ void main() { testWidgets('renders TextButton', (tester) async { await tester.pumpWidget( pumpHost( - TextAsyncButton( - onPressed: () async {}, - child: const Text('go'), - ), + TextAsyncButton(onPressed: () async {}, child: const Text('go')), ), ); check(find.byType(TextButton)).findsOne(); @@ -31,26 +28,7 @@ void main() { ); check(find.byType(TextButton)).findsOne(); check(find.byIcon(Icons.copy)).findsOne(); - }); - - testWidgets('controller.trigger() works for "Done" keyboard pattern', ( - tester, - ) async { - final controller = AsyncButtonController(); - addTearDown(controller.dispose); - var ran = 0; - await tester.pumpWidget( - pumpHost( - TextAsyncButton( - controller: controller, - onPressed: () async => ran++, - child: const Text('go'), - ), - ), - ); - await controller.trigger(); - await tester.pumpAndSettle(); - check(ran).equals(1); + check(find.text('copy')).findsOne(); }); }); } diff --git a/tool/claude/flutter-material-async-button/SKILL.md b/tool/claude/flutter-material-async-button/SKILL.md index efc886c..1aa6d24 100644 --- a/tool/claude/flutter-material-async-button/SKILL.md +++ b/tool/claude/flutter-material-async-button/SKILL.md @@ -1,22 +1,19 @@ --- name: flutter-material-async-button description: Use this skill when working in a Flutter project that depends on - the material_async_button package, or when the user wants to add - loading/success/error UI to a Material button (ElevatedButton, FilledButton, - OutlinedButton, TextButton, IconButton) whose onPressed is async. Triggers on - "async button", "loading button", or any handler the user writes as - `() async {}` and passes to a Material button. + the material_async_button package, or when the user wants to add a loading + state to a Material button (ElevatedButton, FilledButton, OutlinedButton, + TextButton, IconButton) whose onPressed is async. Triggers on "async button", + "loading button", or any handler the user writes as `() async {}` and passes + to a Material button. --- # material_async_button -## Default mapping +Replace a Material button with its async counterpart when `onPressed` is async — +it shows a spinner while the future runs. Every Material param is forwarded. -Replace the Material button with its async counterpart whenever `onPressed` -is async. The wrapper handles loading state, the post-press display, and -disables the button while running. - -|Material|Use|Variants| +|Material|Async|Variants| |--|--|--| |`ElevatedButton`|`ElevatedAsyncButton`|`.icon`| |`FilledButton`|`FilledAsyncButton`|`.tonal` `.icon` `.tonalIcon`| @@ -24,93 +21,52 @@ disables the button while running. |`TextButton`|`TextAsyncButton`|`.icon`| |`IconButton`|`IconAsyncButton`|`.filled` `.filledTonal` `.outlined`| -## Minimal use - ```dart -ElevatedAsyncButton( - onPressed: notifier.save, - child: const Text('Save'), -) +ElevatedAsyncButton(onPressed: notifier.save, child: const Text('Save')) ``` -## Theming — do this once - -```dart -ThemeData(extensions: [AsyncButtonTheme.material()]) -``` +Loading-only — no success/error state. Loading never disables the button; +`enabled: false` or `onPressed: null` does. A throw rethrows (reaches +`FlutterError.onError`) — handle failures in your state management, not the +button. -Or, with overrides: +## Theme (once) ```dart -ThemeData( - extensions: [ - AsyncButtonTheme( - successChild: const Icon(Icons.check), - errorChild: const Icon(Icons.error_outline), - switchDuration: const Duration(milliseconds: 200), - successDisplayDuration:const Duration(milliseconds: 800), - errorDisplayDuration: const Duration(milliseconds: 800), - animateSize: true, - hapticOn: HapticOn.both, - ), - ], -]) +AsyncButtonTheme(loadingBuilder: (_) => const AsyncButtonSpinner(strokeWidth: 3)) ``` -Per-button props always win over the theme. - -## External control — `AsyncButtonController` +Per-button props win. No styling knobs — that's `ButtonStyle`'s job. Animate the +swap with `transitionBuilder` (wrap `child` in `AnimatedSwitcher` + `AnimatedSize`). -Use this for form "Done" keyboard action, parent-owned state, and -cross-widget reactions: +## Controller — drive from outside ```dart -final controller = AsyncButtonController(); // dispose like any ChangeNotifier - -TextField( - textInputAction: TextInputAction.done, - onSubmitted: (_) => controller.trigger(), -) -ElevatedAsyncButton( - controller: controller, - onPressed: submit, - child: const Text('Submit'), -) +final controller = AsyncButtonController(); // dispose like a ChangeNotifier +ElevatedAsyncButton(controller: controller, onPressed: submit, child: ...) -controller.trigger(); // run onPressed from outside -controller.invalidate('server rejected'); // force error from outside -controller.markSuccess(); // force success from outside -controller.reset(); // back to idle +controller.trigger(); // run onPressed externally (e.g. form "Done") +controller.reset(); ``` -It's a `ValueListenable` — pipe into -`ValueListenableBuilder` for cross-widget reactions. +`ValueListenable` (`isLoading`). -## Custom buttons — `AsyncButton` +## Custom button — `AsyncButton` -Only when no Material wrapper fits: +Only when no wrapper fits: ```dart AsyncButton( onPressed: doWork, child: const Text('Go'), - builder: (context, child, callback, status) => MyButton( - onTap: callback, - color: switch (status) { - AsyncButtonStatusLoading() => Colors.grey, - AsyncButtonStatusError() => Colors.red, - _ => Colors.indigo, - }, - child: child, - ), + builder: (context, child, callback, isLoading) => + MyButton(onTap: callback, child: child), ) ``` ## Don't -- Don't wrap an already-async-aware button (no nested `…AsyncButton`s). -- Don't pass `disabled: true` to "pause" — pass `null` to `onPressed` instead. -- Don't call `setState` in `onSuccess` / `onError` for state the button - already reflects. -- Don't create a project-wide wrapper widget for default loading/success - spinners — that's exactly what `AsyncButtonTheme` is for. +- No nested `…AsyncButton`s. +- Disable with `enabled: false` or `onPressed: null` — no `disabled` flag. +- Don't show success/error in the button (loading-only; throws rethrow). +- Don't hand-roll a wrapper for a default spinner — that's `AsyncButtonTheme`. From 16c00329616eb27ebb40d35b19dddf0dc6768186 Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Sun, 31 May 2026 10:35:42 +0300 Subject: [PATCH 110/176] fix: address v2.0.0 review findings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Post-rewrite review of the unreleased v2.0.0 surface: - Drop stale "success view" wording from ElevatedAsyncButton dartdoc (the success state was removed in this release; docs ship to pub.dev). - Document that IconAsyncButton needs `tooltip` for an accessible loading state — the spinner that replaces the icon carries no semantic label. - Reword AsyncButtonController doc to its advertised `ValueListenable` surface (drive via trigger/reset, not value=); document canTrigger. - Guard reset() with `if (!_disposed)`, matching trigger()'s finally. - createState() as an expression body. - Disclose the Flutter >=3.38.0 floor in README; align example/pubspec. - Note default spinner sizes from font size, not IconTheme.size (README, SKILL); clarify IconAsyncButton has no .icon variant. - example: loadingBuilder as an expression-body closure. No behavior change beyond the reset() guard; analyze clean, 53 tests pass. Co-Authored-By: Claude Opus 4.8 --- README.md | 12 ++++++++++-- example/lib/main.dart | 13 ++++--------- example/pubspec.yaml | 2 +- lib/src/async_button.dart | 4 +--- lib/src/async_button_controller.dart | 12 ++++++++---- lib/src/buttons/elevated_async_button.dart | 7 +++---- lib/src/buttons/icon_async_button.dart | 9 ++++++++- tool/claude/flutter-material-async-button/SKILL.md | 2 ++ 8 files changed, 37 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 8508842..f767c9c 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ dependencies: material_async_button: ^2.0.0 ``` -Requires Dart `^3.10.0` (any Flutter SDK shipping Dart 3.10+). +Requires Dart `^3.10.0` and Flutter `>=3.38.0`. ## Why @@ -103,6 +103,10 @@ ThemeData( With no extension registered, `AsyncButtonTheme.of` falls back to `AsyncButtonTheme.empty` — the default spinner and nothing else. +The default spinner sizes itself from the ambient font size, not `IconTheme.size`, +so inside an `IconAsyncButton` pass `loadingBuilder: (_) => AsyncButtonSpinner(size: ...)` +to match the icon's footprint. + ## Custom buttons — `AsyncButton` `AsyncButton` is the low-level escape hatch. Use it when none of the Material @@ -142,6 +146,7 @@ ElevatedAsyncButton( controller.trigger(); // run onPressed from outside (rethrows on failure) controller.reset(); // force back to idle controller.isLoading; // bool +controller.canTrigger; // bool — true when trigger() would run (not loading, callback attached) ``` ## Defaults @@ -151,7 +156,10 @@ controller.isLoading; // bool | idle | your `child` | | loading | `AsyncButtonSpinner` (sized to the label) | -`.icon` constructors drop the icon while loading and show the spinner alone. +The label-button `.icon` constructors (`ElevatedAsyncButton.icon`, +`FilledAsyncButton.icon`, etc.) drop the icon while loading and show the spinner +alone. (`IconAsyncButton` has no `.icon` variant — it swaps its sole icon for the +spinner.) **Loading never disables the button.** Being loading and being *disabled* are different things — the spinner is the indicator, the button keeps its themed diff --git a/example/lib/main.dart b/example/lib/main.dart index 7bc2b1f..f32ad56 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -190,15 +190,10 @@ class _HomePageState extends State { const _SectionLabel('Custom button via AsyncButton'), AsyncButton( onPressed: _simulateWork, - loadingBuilder: (context) { - return Padding( - padding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 12, - ), - child: const AsyncButtonSpinner(strokeWidth: 3), - ); - }, + loadingBuilder: (context) => Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + child: const AsyncButtonSpinner(strokeWidth: 3), + ), builder: (context, child, callback, isLoading) { return Material( color: isLoading ? Colors.indigo.shade200 : Colors.indigo, diff --git a/example/pubspec.yaml b/example/pubspec.yaml index e151c78..62c1a51 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -5,7 +5,7 @@ version: 1.0.0+1 environment: sdk: ^3.10.0 - flutter: ">=3.0.0" + flutter: ">=3.38.0" dependencies: flutter: diff --git a/lib/src/async_button.dart b/lib/src/async_button.dart index ff138df..b4a7b9c 100644 --- a/lib/src/async_button.dart +++ b/lib/src/async_button.dart @@ -98,9 +98,7 @@ class AsyncButton extends StatefulWidget { final AsyncButtonTransitionBuilder? transitionBuilder; @override - State createState() { - return _AsyncButtonState(); - } + State createState() => _AsyncButtonState(); } class _AsyncButtonState extends State { diff --git a/lib/src/async_button_controller.dart b/lib/src/async_button_controller.dart index a4f4356..27264e5 100644 --- a/lib/src/async_button_controller.dart +++ b/lib/src/async_button_controller.dart @@ -1,13 +1,15 @@ part of '../material_async_button.dart'; -/// `ValueNotifier` of an [AsyncButton]'s loading state (`true` while +/// A `ValueListenable` of an [AsyncButton]'s loading state (`true` while /// `onPressed` is in flight). Pipe it into a `ValueListenableBuilder` for -/// reactive UI outside the button. +/// reactive UI outside the button; drive the button with [trigger] / [reset] +/// rather than mutating `value` directly. /// /// Use it to: /// - trigger the attached `onPressed` from outside the button /// (e.g. a form keyboard "Done" action), -/// - reset to idle. +/// - reset to idle, +/// - read [isLoading] / [canTrigger] to gate surrounding UI. /// /// Dispose like any [ChangeNotifier]. class AsyncButtonController extends ValueNotifier { @@ -60,7 +62,9 @@ class AsyncButtonController extends ValueNotifier { /// Force the button back to idle. void reset() { - value = false; + if (!_disposed) { + value = false; + } } @override diff --git a/lib/src/buttons/elevated_async_button.dart b/lib/src/buttons/elevated_async_button.dart index 958fb95..d6c2a37 100644 --- a/lib/src/buttons/elevated_async_button.dart +++ b/lib/src/buttons/elevated_async_button.dart @@ -1,8 +1,7 @@ part of '../../material_async_button.dart'; /// Async-aware [ElevatedButton]. While `onPressed` is running the label is -/// swapped for a loading widget; an optional success view is shown afterwards -/// if configured via prop or theme. +/// swapped for the loading widget. class ElevatedAsyncButton extends AsyncStandardMaterialButton { /// Mirrors [ElevatedButton.new]. const ElevatedAsyncButton({ @@ -23,8 +22,8 @@ class ElevatedAsyncButton extends AsyncStandardMaterialButton { super.transitionBuilder, }); - /// Mirrors [ElevatedButton.icon]. The loading/success children replace - /// `label` while `icon` stays put. + /// Mirrors [ElevatedButton.icon]. The loading widget replaces `label` + /// while `icon` stays put. const ElevatedAsyncButton.icon({ super.key, required super.onPressed, diff --git a/lib/src/buttons/icon_async_button.dart b/lib/src/buttons/icon_async_button.dart index 5c04068..e10b108 100644 --- a/lib/src/buttons/icon_async_button.dart +++ b/lib/src/buttons/icon_async_button.dart @@ -7,6 +7,11 @@ enum _IconVariant { standard, filled, filledTonal, outlined } /// [IconAsyncButton.filledTonal], [IconAsyncButton.outlined]. /// /// The [icon] is swapped with the `loadingBuilder` output while loading. +/// +/// Pass a [tooltip] for an accessible loading state: while loading the [icon] +/// (often the button's only implicit label) is replaced by the spinner, which +/// carries no semantic label, so without a tooltip a screen reader announces an +/// unlabeled button. class IconAsyncButton extends AsyncMaterialButton { /// Mirrors [IconButton.new]. const IconAsyncButton({ @@ -181,7 +186,9 @@ class IconAsyncButton extends AsyncMaterialButton { /// Forwarded to the underlying [IconButton]. final bool autofocus; - /// Forwarded to the underlying [IconButton]. + /// Forwarded to the underlying [IconButton]. Doubles as the button's + /// accessible label — recommended, since the spinner that replaces [icon] + /// while loading has no label of its own. final String? tooltip; /// Forwarded to the underlying [IconButton]. diff --git a/tool/claude/flutter-material-async-button/SKILL.md b/tool/claude/flutter-material-async-button/SKILL.md index 1aa6d24..a75ab79 100644 --- a/tool/claude/flutter-material-async-button/SKILL.md +++ b/tool/claude/flutter-material-async-button/SKILL.md @@ -38,6 +38,8 @@ AsyncButtonTheme(loadingBuilder: (_) => const AsyncButtonSpinner(strokeWidth: 3) Per-button props win. No styling knobs — that's `ButtonStyle`'s job. Animate the swap with `transitionBuilder` (wrap `child` in `AnimatedSwitcher` + `AnimatedSize`). +The default spinner sizes from the ambient font size, not `IconTheme.size`; inside an +`IconAsyncButton` pass `loadingBuilder: (_) => AsyncButtonSpinner(size: ...)` to match the icon. ## Controller — drive from outside From ec026828d2aff99d7f233fb6735c8fe1dc789812 Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Sun, 31 May 2026 10:44:12 +0300 Subject: [PATCH 111/176] refactor!: make AsyncButtonController a read-only ValueListenable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Was `extends ValueNotifier`, which leaked a public `value` setter — external code could set `controller.value = true` and desync the displayed state from the actual running future. Now `ChangeNotifier implements ValueListenable`: `value` is a getter only, backed by a private `_isLoading` mutated through a single deduping `_setLoading` (preserving ValueNotifier's change-only notification and the post-dispose guard). The binding seam `attach()` is now `@visibleForTesting` — the widget reaches it via same-library access, tests via the seam, and external consumers get an analyzer warning. Public surface is now just value/isLoading/canTrigger/trigger/reset/dispose + the listener API. No behavior change; analyze clean (package + example), 53 tests pass. Co-Authored-By: Claude Opus 4.8 --- CHANGELOG.md | 8 ++-- lib/src/async_button_controller.dart | 60 +++++++++++++++++++--------- 2 files changed, 46 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c4fce20..6c13e44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,9 +21,11 @@ a pure complement to `ButtonStyle`. returns to idle and **re-throws** so the error reaches `FlutterError.onError` / your `runZonedGuarded` zone. `controller.trigger()` rethrows instead of completing normally. -- **`AsyncButtonController` is now a `ValueListenable`** (`isLoading`). - Builders receive `bool isLoading` instead of an `AsyncButtonStatus`; observe - it with `addListener` / `ValueListenableBuilder`. +- **`AsyncButtonController` is now a read-only `ValueListenable`** + (`ChangeNotifier implements ValueListenable`, `isLoading`). There is no + public `value` setter — drive it with `trigger()` / `reset()` and observe with + `addListener` / `ValueListenableBuilder`. Builders receive `bool + isLoading` instead of an `AsyncButtonStatus`. - **`AsyncButtonTheme` carries only `loadingBuilder` + `transitionBuilder`.** `AsyncButtonTheme.empty` (spinner-only) is the sole baseline; removed `AsyncButtonTheme.material()`. It complements `ButtonStyle` — no styling. diff --git a/lib/src/async_button_controller.dart b/lib/src/async_button_controller.dart index 27264e5..4c498d8 100644 --- a/lib/src/async_button_controller.dart +++ b/lib/src/async_button_controller.dart @@ -1,9 +1,12 @@ part of '../material_async_button.dart'; -/// A `ValueListenable` of an [AsyncButton]'s loading state (`true` while -/// `onPressed` is in flight). Pipe it into a `ValueListenableBuilder` for -/// reactive UI outside the button; drive the button with [trigger] / [reset] -/// rather than mutating `value` directly. +/// A read-only [ValueListenable] of an [AsyncButton]'s loading state (`true` +/// while `onPressed` is in flight), plus imperative [trigger] / [reset]. +/// +/// Pipe it into a `ValueListenableBuilder` for reactive UI outside the +/// button. The loading [value] is observe-only — drive the button with +/// [trigger] / [reset]; there is no public setter, so external code can't +/// desync the displayed state from the running future. /// /// Use it to: /// - trigger the attached `onPressed` from outside the button @@ -12,15 +15,24 @@ part of '../material_async_button.dart'; /// - read [isLoading] / [canTrigger] to gate surrounding UI. /// /// Dispose like any [ChangeNotifier]. -class AsyncButtonController extends ValueNotifier { +class AsyncButtonController extends ChangeNotifier + implements ValueListenable { /// Creates a controller in the idle (not-loading) state. - AsyncButtonController() : super(false); + AsyncButtonController(); + + bool _isLoading = false; + + /// Whether `onPressed` is currently in flight. Observe-only — mutated by + /// [trigger] / [reset], never from outside. + @override + bool get value => _isLoading; - /// Whether `onPressed` is currently in flight. - bool get isLoading => value; + /// Alias for [value] — whether `onPressed` is currently in flight. + bool get isLoading => _isLoading; - /// True when [trigger] would actually run the attached callback. - bool get canTrigger => !value && _onPressed != null; + /// True when [trigger] would actually run the attached callback (not loading + /// and a callback is attached). Use it to gate surrounding UI. + bool get canTrigger => !_isLoading && _onPressed != null; // Widget-owned configuration. Refreshed whenever the bound [AsyncButton] // updates. @@ -29,9 +41,13 @@ class AsyncButtonController extends ValueNotifier { bool _disposed = false; /// Binds the host widget's current `onPressed` to the controller. - /// [AsyncButton] calls this; you can too (tests drive a detached controller - /// this way), but a bound button overwrites it on its next update. - // A named binding hook, not a property setter — tests drive this seam. + /// + /// [AsyncButton] calls this on every update via same-library access; it is + /// exposed only so tests can drive a detached controller. Not part of the + /// consumer-facing API. + @visibleForTesting + // A named binding hook, not a property setter — the widget refreshes it on + // every rebuild, so this stays a method. // ignore: use_setters_to_change_properties void attach({required AsyncCallback? onPressed}) { _onPressed = onPressed; @@ -47,24 +63,30 @@ class AsyncButtonController extends ValueNotifier { if (!canTrigger) { return; } - value = true; + _setLoading(true); try { await _onPressed!(); } finally { // Reset the UI whether onPressed completed or threw; a throw propagates // through finally (trigger rethrows) so the error reaches the surrounding // zone / FlutterError.onError. - if (!_disposed) { - value = false; - } + _setLoading(false); } } /// Force the button back to idle. void reset() { - if (!_disposed) { - value = false; + _setLoading(false); + } + + /// Single mutation point. Dedupes (like the former [ValueNotifier]) so + /// listeners fire only on a real change, and never notifies after [dispose]. + void _setLoading(bool value) { + if (_disposed || _isLoading == value) { + return; } + _isLoading = value; + notifyListeners(); } @override From b233952f5b01a656c138411c1f6249db6f44464a Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Sun, 31 May 2026 11:52:00 +0300 Subject: [PATCH 112/176] chore: tidy controller/button internals and reusable test helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Non-behavioural cleanup on the unreleased 2.0.0 surface: - Rename variant enums to the _[Type]ButtonVariant convention (_FilledVariant -> _FilledButtonVariant, _IconVariant -> _IconButtonVariant). - _disposed -> _isDisposed (is/can/has prefix for booleans). - clipBehavior: drop the per-build `?? .none` and make the field a non-null `Clip` defaulting to .none. Verified equivalent: the old code never passed null to the Material button (it collapsed to .none first), and ButtonStyleButton only auto-promotes a *null* clipBehavior to antiAlias, so identical clip reaches the button — the change just rejects a meaningless `clipBehavior: null` at the call site. - Tests: extract reusable helpers — emptyAsyncButtonTheme / asyncButtonTheme() for the ThemeData(extensions:[AsyncButtonTheme]) boilerplate, tapIntoLoading() for the tap+pump-into-spinner dance, newController() for the auto-disposing controller pattern, and top-level _loadingA/_loadingB so identity-based theme tests stop redeclaring closures. analyze clean (package + example), 52 tests pass. Co-Authored-By: Claude Opus 4.8 --- lib/src/async_button_controller.dart | 6 +-- lib/src/buttons/async_material_button.dart | 4 +- lib/src/buttons/elevated_async_button.dart | 5 +-- lib/src/buttons/filled_async_button.dart | 13 +++--- lib/src/buttons/icon_async_button.dart | 4 +- lib/src/buttons/outlined_async_button.dart | 5 +-- lib/src/buttons/text_async_button.dart | 5 +-- test/_helpers.dart | 46 ++++++++++++++++++++- test/async_button_controller_test.dart | 8 ++-- test/async_button_test.dart | 34 +++++----------- test/elevated_async_button_test.dart | 10 ++--- test/filled_async_button_test.dart | 20 +++------ test/icon_async_button_test.dart | 10 ++--- test/material_async_button_theme_test.dart | 47 +++++++++++----------- test/outlined_async_button_test.dart | 4 +- 15 files changed, 111 insertions(+), 110 deletions(-) diff --git a/lib/src/async_button_controller.dart b/lib/src/async_button_controller.dart index 4c498d8..df24d2f 100644 --- a/lib/src/async_button_controller.dart +++ b/lib/src/async_button_controller.dart @@ -38,7 +38,7 @@ class AsyncButtonController extends ChangeNotifier // updates. AsyncCallback? _onPressed; - bool _disposed = false; + bool _isDisposed = false; /// Binds the host widget's current `onPressed` to the controller. /// @@ -82,7 +82,7 @@ class AsyncButtonController extends ChangeNotifier /// Single mutation point. Dedupes (like the former [ValueNotifier]) so /// listeners fire only on a real change, and never notifies after [dispose]. void _setLoading(bool value) { - if (_disposed || _isLoading == value) { + if (_isDisposed || _isLoading == value) { return; } _isLoading = value; @@ -91,7 +91,7 @@ class AsyncButtonController extends ChangeNotifier @override void dispose() { - _disposed = true; + _isDisposed = true; super.dispose(); } } diff --git a/lib/src/buttons/async_material_button.dart b/lib/src/buttons/async_material_button.dart index d1faa3b..a262671 100644 --- a/lib/src/buttons/async_material_button.dart +++ b/lib/src/buttons/async_material_button.dart @@ -65,7 +65,7 @@ abstract class AsyncStandardMaterialButton extends AsyncMaterialButton { this.style, this.focusNode, this.autofocus = false, - this.clipBehavior, + this.clipBehavior = .none, this.statesController, Widget? icon, IconAlignment? iconAlignment, @@ -91,7 +91,7 @@ abstract class AsyncStandardMaterialButton extends AsyncMaterialButton { final bool autofocus; /// Forwarded to the underlying Material button. - final Clip? clipBehavior; + final Clip clipBehavior; /// Forwarded to the underlying Material button. final WidgetStatesController? statesController; diff --git a/lib/src/buttons/elevated_async_button.dart b/lib/src/buttons/elevated_async_button.dart index d6c2a37..25e1139 100644 --- a/lib/src/buttons/elevated_async_button.dart +++ b/lib/src/buttons/elevated_async_button.dart @@ -45,7 +45,6 @@ class ElevatedAsyncButton extends AsyncStandardMaterialButton { @override Widget build(BuildContext context) { - final clip = clipBehavior ?? .none; return AsyncButton( onPressed: onPressed, enabled: enabled, @@ -63,7 +62,7 @@ class ElevatedAsyncButton extends AsyncStandardMaterialButton { style: style, focusNode: focusNode, autofocus: autofocus, - clipBehavior: clip, + clipBehavior: clipBehavior, statesController: statesController, iconAlignment: _iconAlignment, icon: isLoading ? null : _icon, @@ -78,7 +77,7 @@ class ElevatedAsyncButton extends AsyncStandardMaterialButton { style: style, focusNode: focusNode, autofocus: autofocus, - clipBehavior: clip, + clipBehavior: clipBehavior, statesController: statesController, child: animatedChild, ); diff --git a/lib/src/buttons/filled_async_button.dart b/lib/src/buttons/filled_async_button.dart index db2ebd2..a64ec7d 100644 --- a/lib/src/buttons/filled_async_button.dart +++ b/lib/src/buttons/filled_async_button.dart @@ -1,6 +1,6 @@ part of '../../material_async_button.dart'; -enum _FilledVariant { primary, tonal } +enum _FilledButtonVariant { primary, tonal } /// Async-aware [FilledButton] with all four Material 3 flavors: /// [FilledAsyncButton.new], [FilledAsyncButton.tonal], @@ -86,11 +86,10 @@ class FilledAsyncButton extends AsyncStandardMaterialButton { }) : _variant = .tonal, super(child: label); - final _FilledVariant _variant; + final _FilledButtonVariant _variant; @override Widget build(BuildContext context) { - final clip = clipBehavior ?? .none; return AsyncButton( onPressed: onPressed, enabled: enabled, @@ -109,7 +108,7 @@ class FilledAsyncButton extends AsyncStandardMaterialButton { style: style, focusNode: focusNode, autofocus: autofocus, - clipBehavior: clip, + clipBehavior: clipBehavior, statesController: statesController, iconAlignment: _iconAlignment, icon: isLoading ? null : _icon, @@ -123,7 +122,7 @@ class FilledAsyncButton extends AsyncStandardMaterialButton { style: style, focusNode: focusNode, autofocus: autofocus, - clipBehavior: clip, + clipBehavior: clipBehavior, statesController: statesController, iconAlignment: _iconAlignment, icon: isLoading ? null : _icon, @@ -140,7 +139,7 @@ class FilledAsyncButton extends AsyncStandardMaterialButton { style: style, focusNode: focusNode, autofocus: autofocus, - clipBehavior: clip, + clipBehavior: clipBehavior, statesController: statesController, child: animatedChild, ), @@ -152,7 +151,7 @@ class FilledAsyncButton extends AsyncStandardMaterialButton { style: style, focusNode: focusNode, autofocus: autofocus, - clipBehavior: clip, + clipBehavior: clipBehavior, statesController: statesController, child: animatedChild, ), diff --git a/lib/src/buttons/icon_async_button.dart b/lib/src/buttons/icon_async_button.dart index e10b108..494bab1 100644 --- a/lib/src/buttons/icon_async_button.dart +++ b/lib/src/buttons/icon_async_button.dart @@ -1,6 +1,6 @@ part of '../../material_async_button.dart'; -enum _IconVariant { standard, filled, filledTonal, outlined } +enum _IconButtonVariant { standard, filled, filledTonal, outlined } /// Async-aware [IconButton]. Includes all four Material 3 flavors: /// [IconAsyncButton.new], [IconAsyncButton.filled], @@ -206,7 +206,7 @@ class IconAsyncButton extends AsyncMaterialButton { /// Forwarded to the underlying [IconButton]. final Widget? selectedIcon; - final _IconVariant _variant; + final _IconButtonVariant _variant; @override Widget build(BuildContext context) { diff --git a/lib/src/buttons/outlined_async_button.dart b/lib/src/buttons/outlined_async_button.dart index 9167122..3cd9f35 100644 --- a/lib/src/buttons/outlined_async_button.dart +++ b/lib/src/buttons/outlined_async_button.dart @@ -43,7 +43,6 @@ class OutlinedAsyncButton extends AsyncStandardMaterialButton { @override Widget build(BuildContext context) { - final clip = clipBehavior ?? .none; return AsyncButton( onPressed: onPressed, enabled: enabled, @@ -61,7 +60,7 @@ class OutlinedAsyncButton extends AsyncStandardMaterialButton { style: style, focusNode: focusNode, autofocus: autofocus, - clipBehavior: clip, + clipBehavior: clipBehavior, statesController: statesController, iconAlignment: _iconAlignment, icon: isLoading ? null : _icon, @@ -76,7 +75,7 @@ class OutlinedAsyncButton extends AsyncStandardMaterialButton { style: style, focusNode: focusNode, autofocus: autofocus, - clipBehavior: clip, + clipBehavior: clipBehavior, statesController: statesController, child: animatedChild, ); diff --git a/lib/src/buttons/text_async_button.dart b/lib/src/buttons/text_async_button.dart index 4060c26..2b5f3ad 100644 --- a/lib/src/buttons/text_async_button.dart +++ b/lib/src/buttons/text_async_button.dart @@ -43,7 +43,6 @@ class TextAsyncButton extends AsyncStandardMaterialButton { @override Widget build(BuildContext context) { - final clip = clipBehavior ?? .none; return AsyncButton( onPressed: onPressed, enabled: enabled, @@ -61,7 +60,7 @@ class TextAsyncButton extends AsyncStandardMaterialButton { style: style, focusNode: focusNode, autofocus: autofocus, - clipBehavior: clip, + clipBehavior: clipBehavior, statesController: statesController, iconAlignment: _iconAlignment, icon: isLoading ? null : _icon, @@ -76,7 +75,7 @@ class TextAsyncButton extends AsyncStandardMaterialButton { style: style, focusNode: focusNode, autofocus: autofocus, - clipBehavior: clip, + clipBehavior: clipBehavior, statesController: statesController, child: animatedChild, ); diff --git a/test/_helpers.dart b/test/_helpers.dart index 98c9389..dd1def7 100644 --- a/test/_helpers.dart +++ b/test/_helpers.dart @@ -12,13 +12,35 @@ import 'package:material_async_button/material_async_button.dart'; /// see the per-widget / hard-coded fallbacks. Widget pumpHost(Widget child, {ThemeData? theme}) { return MaterialApp( - theme: theme ?? ThemeData(extensions: const [AsyncButtonTheme.empty]), + theme: theme ?? emptyAsyncButtonTheme, home: Scaffold( body: Center(child: child), ), ); } +/// A [ThemeData] whose only extension is [AsyncButtonTheme.empty] — the +/// zero-config baseline, used to assert the per-widget / hard-coded fallbacks. +final ThemeData emptyAsyncButtonTheme = ThemeData( + extensions: const [AsyncButtonTheme.empty], +); + +/// A [ThemeData] carrying an [AsyncButtonTheme] from the given fields — for +/// asserting that theme values flow through when no per-widget override is set. +ThemeData asyncButtonTheme({ + WidgetBuilder? loadingBuilder, + AsyncButtonTransitionBuilder? transitionBuilder, +}) { + return ThemeData( + extensions: [ + AsyncButtonTheme( + loadingBuilder: loadingBuilder, + transitionBuilder: transitionBuilder, + ), + ], + ); +} + /// Returns an `(onPressed, completer)` pair. Caller drives the button into /// loading and decides when to complete or fail. ({AsyncCallback onPressed, Completer completer}) pendingPress() { @@ -26,7 +48,27 @@ Widget pumpHost(Widget child, {ThemeData? theme}) { return (onPressed: () => completer.future, completer: completer); } -/// Controller pre-attached with `onPressed`. Auto-disposes. +/// Taps [finder] and pumps into the loading frame: the spinner is mounted and +/// its indeterminate animation has advanced far enough for `valueColor` to +/// resolve (so [spinnerColor] reads the inherited foreground, not a null +/// first-frame value). +Future tapIntoLoading(WidgetTester tester, Finder finder) async { + await tester.tap(finder); + await tester.pump(); // kick off the future → first loading frame + await tester.pump(const Duration(milliseconds: 250)); // advance the spinner +} + +/// A fresh [AsyncButtonController] that auto-disposes at test teardown — for +/// tests that hand the controller to a widget (which attaches `onPressed` +/// itself). Use [attachedController] when driving a detached controller. +AsyncButtonController newController() { + final c = AsyncButtonController(); + addTearDown(c.dispose); + return c; +} + +/// Controller pre-attached with `onPressed`, for driving it detached from any +/// widget. Auto-disposes. AsyncButtonController attachedController({AsyncCallback? onPressed}) { final c = AsyncButtonController()..attach(onPressed: onPressed); addTearDown(c.dispose); diff --git a/test/async_button_controller_test.dart b/test/async_button_controller_test.dart index 3b793d5..76bb78d 100644 --- a/test/async_button_controller_test.dart +++ b/test/async_button_controller_test.dart @@ -7,7 +7,7 @@ import 'package:material_async_button/material_async_button.dart'; import '_helpers.dart'; -/// Subscribes a loading-recording listener to [c]; returns the recording list. +/// Subscribes a loading-recording listener to [c]; returns the recorded list. List recordStates(AsyncButtonController c) { final out = []; c.addListener(() => out.add(c.value)); @@ -17,16 +17,14 @@ List recordStates(AsyncButtonController c) { void main() { group('AsyncButtonController basics', () { test('starts idle by default with no onPressed', () { - final c = AsyncButtonController(); - addTearDown(c.dispose); + final c = newController(); check(c) ..isIdle() ..has((it) => it.canTrigger, 'canTrigger').isFalse(); }); test('trigger no-ops when no onPressed is attached', () async { - final c = AsyncButtonController(); - addTearDown(c.dispose); + final c = newController(); await c.trigger(); check(c).isIdle(); }); diff --git a/test/async_button_test.dart b/test/async_button_test.dart index 07dbbe6..3ff21bb 100644 --- a/test/async_button_test.dart +++ b/test/async_button_test.dart @@ -95,12 +95,8 @@ void main() { builder: textBuilder, child: const Text('go'), ), - theme: ThemeData( - extensions: [ - AsyncButtonTheme( - loadingBuilder: (_) => const Text('themed-loading'), - ), - ], + theme: asyncButtonTheme( + loadingBuilder: (_) => const Text('themed-loading'), ), ), ); @@ -121,11 +117,7 @@ void main() { builder: textBuilder, child: const Text('go'), ), - theme: ThemeData( - extensions: [ - AsyncButtonTheme(loadingBuilder: (_) => const Text('themed')), - ], - ), + theme: asyncButtonTheme(loadingBuilder: (_) => const Text('themed')), ), ); await tester.tap(find.byType(TextButton)); @@ -158,8 +150,7 @@ void main() { testWidgets('a throwing onPressed returns to idle and rethrows', ( tester, ) async { - final controller = AsyncButtonController(); - addTearDown(controller.dispose); + final controller = newController(); await tester.pumpWidget( pumpHost( AsyncButton( @@ -213,8 +204,7 @@ void main() { tester, ) async { var ran = 0; - final controller = AsyncButtonController(); - addTearDown(controller.dispose); + final controller = newController(); await tester.pumpWidget( pumpHost( AsyncButton( @@ -240,8 +230,7 @@ void main() { testWidgets('controller.trigger drives loading; stays enabled', ( tester, ) async { - final controller = AsyncButtonController(); - addTearDown(controller.dispose); + final controller = newController(); final completer = Completer(); await tester.pumpWidget( pumpHost( @@ -272,8 +261,7 @@ void main() { }); testWidgets('controller.reset clears the loading state', (tester) async { - final controller = AsyncButtonController(); - addTearDown(controller.dispose); + final controller = newController(); final completer = Completer(); await tester.pumpWidget( pumpHost( @@ -297,14 +285,10 @@ void main() { testWidgets( 'swapping the external controller transfers listening without leak', (tester) async { - final a = AsyncButtonController(); - final b = AsyncButtonController(); + final a = newController(); + final b = newController(); final aCompleter = Completer(); final bCompleter = Completer(); - addTearDown(() { - a.dispose(); - b.dispose(); - }); AsyncButton button(AsyncButtonController c, Completer done) => AsyncButton( controller: c, diff --git a/test/elevated_async_button_test.dart b/test/elevated_async_button_test.dart index fb7e7b8..fd164ab 100644 --- a/test/elevated_async_button_test.dart +++ b/test/elevated_async_button_test.dart @@ -21,16 +21,14 @@ void main() { tester, ) async { final (:onPressed, :completer) = pendingPress(); - final theme = ThemeData(extensions: const [AsyncButtonTheme.empty]); + final theme = emptyAsyncButtonTheme; await tester.pumpWidget( pumpHost( ElevatedAsyncButton(onPressed: onPressed, child: const Text('go')), theme: theme, ), ); - await tester.tap(find.byType(ElevatedButton)); - await tester.pump(); - await tester.pump(const Duration(milliseconds: 250)); + await tapIntoLoading(tester, find.byType(ElevatedButton)); check(spinnerColor(tester)).equals(theme.colorScheme.primary); completer.complete(); await tester.pumpAndSettle(); @@ -80,9 +78,7 @@ void main() { ); check(find.byIcon(Icons.send)).findsOne(); check(find.text('send')).findsOne(); - await tester.tap(find.byType(ElevatedButton)); - await tester.pump(); - await tester.pump(const Duration(milliseconds: 250)); + await tapIntoLoading(tester, find.byType(ElevatedButton)); // Loading drops the icon and shows the spinner alone. check(find.byType(CircularProgressIndicator)).findsOne(); check(find.byIcon(Icons.send)).findsNone(); diff --git a/test/filled_async_button_test.dart b/test/filled_async_button_test.dart index 8f9adbe..65a0f3a 100644 --- a/test/filled_async_button_test.dart +++ b/test/filled_async_button_test.dart @@ -54,9 +54,7 @@ void main() { ), ), ); - await tester.tap(find.byType(FilledButton)); - await tester.pump(); - await tester.pump(const Duration(milliseconds: 250)); + await tapIntoLoading(tester, find.byType(FilledButton)); // Loading drops the icon and shows the spinner alone. check(find.byType(CircularProgressIndicator)).findsOne(); check(find.byIcon(Icons.save)).findsNone(); @@ -73,16 +71,14 @@ void main() { tester, ) async { final (:onPressed, :completer) = pendingPress(); - final theme = ThemeData(extensions: const [AsyncButtonTheme.empty]); + final theme = emptyAsyncButtonTheme; await tester.pumpWidget( pumpHost( FilledAsyncButton(onPressed: onPressed, child: const Text('go')), theme: theme, ), ); - await tester.tap(find.byType(FilledButton)); - await tester.pump(); - await tester.pump(const Duration(milliseconds: 250)); + await tapIntoLoading(tester, find.byType(FilledButton)); check(spinnerColor(tester)).equals(theme.colorScheme.onPrimary); completer.complete(); await tester.pumpAndSettle(); @@ -90,7 +86,7 @@ void main() { testWidgets('.tonal spinner uses onSecondaryContainer', (tester) async { final (:onPressed, :completer) = pendingPress(); - final theme = ThemeData(extensions: const [AsyncButtonTheme.empty]); + final theme = emptyAsyncButtonTheme; await tester.pumpWidget( pumpHost( FilledAsyncButton.tonal( @@ -100,9 +96,7 @@ void main() { theme: theme, ), ); - await tester.tap(find.byType(FilledButton)); - await tester.pump(); - await tester.pump(const Duration(milliseconds: 250)); + await tapIntoLoading(tester, find.byType(FilledButton)); check( spinnerColor(tester), ).equals(theme.colorScheme.onSecondaryContainer); @@ -123,9 +117,7 @@ void main() { ), ), ); - await tester.tap(find.byType(FilledButton)); - await tester.pump(); - await tester.pump(const Duration(milliseconds: 250)); + await tapIntoLoading(tester, find.byType(FilledButton)); check(spinnerColor(tester)).equals(Colors.teal); completer.complete(); await tester.pumpAndSettle(); diff --git a/test/icon_async_button_test.dart b/test/icon_async_button_test.dart index 98f200e..f636a43 100644 --- a/test/icon_async_button_test.dart +++ b/test/icon_async_button_test.dart @@ -65,7 +65,7 @@ void main() { group('IconAsyncButton loading foreground', () { testWidgets('.filled spinner uses onPrimary', (tester) async { final (:onPressed, :completer) = pendingPress(); - final theme = ThemeData(extensions: const [AsyncButtonTheme.empty]); + final theme = emptyAsyncButtonTheme; await tester.pumpWidget( pumpHost( IconAsyncButton.filled( @@ -75,9 +75,7 @@ void main() { theme: theme, ), ); - await tester.tap(find.byType(IconButton)); - await tester.pump(); - await tester.pump(const Duration(milliseconds: 250)); + await tapIntoLoading(tester, find.byType(IconButton)); check(spinnerColor(tester)).equals(theme.colorScheme.onPrimary); completer.complete(); await tester.pumpAndSettle(); @@ -94,9 +92,7 @@ void main() { ), ), ); - await tester.tap(find.byType(IconButton)); - await tester.pump(); - await tester.pump(const Duration(milliseconds: 250)); + await tapIntoLoading(tester, find.byType(IconButton)); check(spinnerColor(tester)).equals(Colors.purple); completer.complete(); await tester.pumpAndSettle(); diff --git a/test/material_async_button_theme_test.dart b/test/material_async_button_theme_test.dart index 0d059e5..522f630 100644 --- a/test/material_async_button_theme_test.dart +++ b/test/material_async_button_theme_test.dart @@ -8,6 +8,12 @@ Widget _noopTransition(BuildContext context, Widget child, bool isLoading) { return child; } +// Two distinct loading builders — reused across tests that assert field +// identity (copyWith / lerp / equality). Their separate references are the +// point, so they live at top level rather than being redeclared per test. +Widget _loadingA(BuildContext _) => const SizedBox.shrink(); +Widget _loadingB(BuildContext _) => const SizedBox.shrink(); + void main() { group('AsyncButtonTheme', () { test('empty default has all null fields', () { @@ -18,15 +24,13 @@ void main() { }); test('copyWith overrides only specified fields, preserving the rest', () { - Widget loadingA(BuildContext _) => const SizedBox.shrink(); - Widget loadingB(BuildContext _) => const SizedBox.shrink(); - final base = AsyncButtonTheme( - loadingBuilder: loadingA, + const base = AsyncButtonTheme( + loadingBuilder: _loadingA, transitionBuilder: _noopTransition, ); - final overridden = base.copyWith(loadingBuilder: loadingB); + final overridden = base.copyWith(loadingBuilder: _loadingB); check(overridden) - ..has((it) => it.loadingBuilder, 'loadingBuilder').equals(loadingB) + ..has((it) => it.loadingBuilder, 'loadingBuilder').equals(_loadingB) ..has( (it) => it.transitionBuilder, 'transitionBuilder', @@ -34,33 +38,29 @@ void main() { }); test('lerp snaps fields at the halfway point', () { - Widget loadingA(BuildContext _) => const SizedBox.shrink(); - Widget loadingB(BuildContext _) => const SizedBox.shrink(); - final from = AsyncButtonTheme(loadingBuilder: loadingA); - final to = AsyncButtonTheme(loadingBuilder: loadingB); + const from = AsyncButtonTheme(loadingBuilder: _loadingA); + const to = AsyncButtonTheme(loadingBuilder: _loadingB); check( from.lerp(to, 0.4), - ).has((it) => it.loadingBuilder, 'loadingBuilder').equals(loadingA); + ).has((it) => it.loadingBuilder, 'loadingBuilder').equals(_loadingA); check( from.lerp(to, 0.6), - ).has((it) => it.loadingBuilder, 'loadingBuilder').equals(loadingB); + ).has((it) => it.loadingBuilder, 'loadingBuilder').equals(_loadingB); }); test('lerp with non-AsyncButtonTheme returns self', () { - Widget loadingA(BuildContext _) => const SizedBox.shrink(); - final a = AsyncButtonTheme(loadingBuilder: loadingA); + const a = AsyncButtonTheme(loadingBuilder: _loadingA); check( a.lerp(null, 0.5), - ).has((it) => it.loadingBuilder, 'loadingBuilder').equals(loadingA); + ).has((it) => it.loadingBuilder, 'loadingBuilder').equals(_loadingA); }); testWidgets('of(context) returns the registered extension', (tester) async { - Widget loadingA(BuildContext _) => const SizedBox.shrink(); - final ext = AsyncButtonTheme(loadingBuilder: loadingA); + const ext = AsyncButtonTheme(loadingBuilder: _loadingA); AsyncButtonTheme? captured; await tester.pumpWidget( MaterialApp( - theme: ThemeData(extensions: [ext]), + theme: ThemeData(extensions: const [ext]), home: Builder( builder: (ctx) { captured = AsyncButtonTheme.of(ctx); @@ -72,7 +72,7 @@ void main() { check(captured) .isNotNull() .has((it) => it.loadingBuilder, 'loadingBuilder') - .equals(loadingA); + .equals(_loadingA); }); testWidgets('of(context) falls back to empty when no extension is set', ( @@ -95,13 +95,12 @@ void main() { }); test('equality is value-based', () { - Widget loadingA(BuildContext _) => const SizedBox.shrink(); - final a = AsyncButtonTheme( - loadingBuilder: loadingA, + const a = AsyncButtonTheme( + loadingBuilder: _loadingA, transitionBuilder: _noopTransition, ); - final b = AsyncButtonTheme( - loadingBuilder: loadingA, + const b = AsyncButtonTheme( + loadingBuilder: _loadingA, transitionBuilder: _noopTransition, ); check(a).equals(b); diff --git a/test/outlined_async_button_test.dart b/test/outlined_async_button_test.dart index 7647b9a..a13db21 100644 --- a/test/outlined_async_button_test.dart +++ b/test/outlined_async_button_test.dart @@ -44,9 +44,7 @@ void main() { ), ), ); - await tester.tap(find.byType(OutlinedButton)); - await tester.pump(); - await tester.pump(const Duration(milliseconds: 250)); + await tapIntoLoading(tester, find.byType(OutlinedButton)); check(spinnerColor(tester)).equals(Colors.red); check(spinnerIconThemeColor(tester)).equals(Colors.red); completer.complete(); From 9184caa9b4fba7575a75bb815073760486608a95 Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Sun, 31 May 2026 12:03:07 +0300 Subject: [PATCH 113/176] chore: remove dead code ahead of publish MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - AsyncButtonController: drop the isLoading getter — redundant with the ValueListenable `value` it already exposes (caller's removal). - test/_helpers.dart: drop unused FinderChecks.findsMany. - example: drop the unused (and doubly-nested-AnimatedSize) _animatedSwitchSize. - Fix the now-broken `controller.isLoading` snippet in README to `controller.value`; align SKILL.md and the CHANGELOG controller note. analyze clean (package + example), 52 tests pass. Co-Authored-By: Claude Opus 4.8 --- CHANGELOG.md | 4 ++-- README.md | 2 +- lib/src/async_button_controller.dart | 5 +---- test/_helpers.dart | 2 -- tool/claude/flutter-material-async-button/SKILL.md | 2 +- 5 files changed, 5 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c13e44..98294fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,8 +22,8 @@ a pure complement to `ButtonStyle`. / your `runZonedGuarded` zone. `controller.trigger()` rethrows instead of completing normally. - **`AsyncButtonController` is now a read-only `ValueListenable`** - (`ChangeNotifier implements ValueListenable`, `isLoading`). There is no - public `value` setter — drive it with `trigger()` / `reset()` and observe with + (`ChangeNotifier implements ValueListenable`). There is no public + `value` setter — drive it with `trigger()` / `reset()` and observe with `addListener` / `ValueListenableBuilder`. Builders receive `bool isLoading` instead of an `AsyncButtonStatus`. - **`AsyncButtonTheme` carries only `loadingBuilder` + `transitionBuilder`.** diff --git a/README.md b/README.md index f767c9c..f902d79 100644 --- a/README.md +++ b/README.md @@ -145,7 +145,7 @@ ElevatedAsyncButton( controller.trigger(); // run onPressed from outside (rethrows on failure) controller.reset(); // force back to idle -controller.isLoading; // bool +controller.value; // bool — true while loading (ValueListenable) controller.canTrigger; // bool — true when trigger() would run (not loading, callback attached) ``` diff --git a/lib/src/async_button_controller.dart b/lib/src/async_button_controller.dart index df24d2f..a15db58 100644 --- a/lib/src/async_button_controller.dart +++ b/lib/src/async_button_controller.dart @@ -12,7 +12,7 @@ part of '../material_async_button.dart'; /// - trigger the attached `onPressed` from outside the button /// (e.g. a form keyboard "Done" action), /// - reset to idle, -/// - read [isLoading] / [canTrigger] to gate surrounding UI. +/// - read [value] / [canTrigger] to gate surrounding UI. /// /// Dispose like any [ChangeNotifier]. class AsyncButtonController extends ChangeNotifier @@ -27,9 +27,6 @@ class AsyncButtonController extends ChangeNotifier @override bool get value => _isLoading; - /// Alias for [value] — whether `onPressed` is currently in flight. - bool get isLoading => _isLoading; - /// True when [trigger] would actually run the attached callback (not loading /// and a callback is attached). Use it to gate surrounding UI. bool get canTrigger => !_isLoading && _onPressed != null; diff --git a/test/_helpers.dart b/test/_helpers.dart index dd1def7..a1d228d 100644 --- a/test/_helpers.dart +++ b/test/_helpers.dart @@ -107,8 +107,6 @@ Color? spinnerIconThemeColor(WidgetTester tester) { extension FinderChecks on Subject { void findsOne() => has((f) => f.evaluate().length, 'matches').equals(1); void findsNone() => has((f) => f.evaluate(), 'matches').isEmpty(); - void findsMany([int min = 1]) => - has((f) => f.evaluate().length, 'matches').isGreaterOrEqual(min); } /// `checks`-style assertions for [AsyncButtonController]. diff --git a/tool/claude/flutter-material-async-button/SKILL.md b/tool/claude/flutter-material-async-button/SKILL.md index a75ab79..d64dc70 100644 --- a/tool/claude/flutter-material-async-button/SKILL.md +++ b/tool/claude/flutter-material-async-button/SKILL.md @@ -51,7 +51,7 @@ controller.trigger(); // run onPressed externally (e.g. form "Done") controller.reset(); ``` -`ValueListenable` (`isLoading`). +Read-only `ValueListenable` — observe `value` (true while loading); gate UI with `canTrigger`. ## Custom button — `AsyncButton` From 3532eeade78735a296c913bc796e195ba86fa634 Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Sun, 31 May 2026 12:32:43 +0300 Subject: [PATCH 114/176] style: format two files to satisfy pana's pinned formatter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pana 0.23.12 formats with its bundled dart_style 3.1.4, whose DartFormatter.latestLanguageVersion is 3.9 — older than the SDK's bundled formatter (lang 3.11) that `dart format` and CI run. The two formatters disagreed only on the wrapped function-type typedefs in async_button.dart and the constructor bodies in material_async_button_theme.dart, costing 10 pana points (40/50 static analysis) on otherwise-clean code. pana's 3.9 form is ALSO a fixed point under the SDK 3.11 formatter (verified: `dart format --set-exit-if-changed` accepts it), so adopting it satisfies both — pana scores 160/160 and the CI `dart format` gate stays green. No semantic change; analyze clean, 52 tests pass. Co-Authored-By: Claude Opus 4.8 --- lib/src/async_button.dart | 5 +---- lib/src/material_async_button_theme.dart | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/lib/src/async_button.dart b/lib/src/async_button.dart index b4a7b9c..faafbe5 100644 --- a/lib/src/async_button.dart +++ b/lib/src/async_button.dart @@ -178,10 +178,7 @@ class _AsyncButtonState extends State { // Keyed by loading state so a user-supplied transitionBuilder can animate // the swap (e.g. via AnimatedSwitcher / AnimatedSize). With no builder it // is an instant swap. - content = KeyedSubtree( - key: ValueKey(isLoading), - child: content, - ); + content = KeyedSubtree(key: ValueKey(isLoading), child: content); if (transitionBuilder != null) { content = transitionBuilder(context, content, isLoading); } diff --git a/lib/src/material_async_button_theme.dart b/lib/src/material_async_button_theme.dart index 4d72137..151520e 100644 --- a/lib/src/material_async_button_theme.dart +++ b/lib/src/material_async_button_theme.dart @@ -24,10 +24,7 @@ part of '../material_async_button.dart'; class AsyncButtonTheme extends ThemeExtension { /// Builds an [AsyncButtonTheme]. Every field is nullable so callers only /// set the ones they want. - const AsyncButtonTheme({ - this.loadingBuilder, - this.transitionBuilder, - }); + const AsyncButtonTheme({this.loadingBuilder, this.transitionBuilder}); /// Builds the widget shown in place of the button's child while the future is /// in flight. Falls back to an [AsyncButtonSpinner] when null. The spinner From 77961f0755003a1aaf307042f1f4a78647a07bea Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Sun, 31 May 2026 15:15:59 +0300 Subject: [PATCH 115/176] fix: size loading spinner to button shape so icon buttons don't shrink while loading The default AsyncButtonSpinner always sized to the ambient font size, so icon-bearing buttons (whose idle height is driven by the icon) shrank vertically while loading. Size the default spinner per button shape instead: iconSize for IconAsyncButton, max(iconSize, fontSize) for the .icon constructors (the idle row height), and fontSize for text-only buttons (unchanged). Sizes are read from the button's resolved IconTheme / DefaultTextStyle, so a per-widget iconSize and theme overrides flow through. No public API change. Co-Authored-By: Claude Opus 4.8 --- lib/src/buttons/async_material_button.dart | 67 ++++++++++++++++++++++ lib/src/buttons/elevated_async_button.dart | 2 +- lib/src/buttons/filled_async_button.dart | 2 +- lib/src/buttons/icon_async_button.dart | 2 +- lib/src/buttons/outlined_async_button.dart | 2 +- lib/src/buttons/text_async_button.dart | 2 +- test/_helpers.dart | 43 ++++++++++++++ test/elevated_async_button_test.dart | 29 ++++++++++ test/icon_async_button_test.dart | 41 +++++++++++++ test/text_async_button_test.dart | 17 ++++++ 10 files changed, 202 insertions(+), 5 deletions(-) diff --git a/lib/src/buttons/async_material_button.dart b/lib/src/buttons/async_material_button.dart index a262671..66961e8 100644 --- a/lib/src/buttons/async_material_button.dart +++ b/lib/src/buttons/async_material_button.dart @@ -38,6 +38,23 @@ abstract class AsyncMaterialButton extends StatelessWidget { /// See [AsyncButton.transitionBuilder]. final AsyncButtonTransitionBuilder? transitionBuilder; + + /// Resolves the loading builder this button hands to its [AsyncButton]: the + /// per-widget [loadingBuilder] wins, then [AsyncButtonTheme.loadingBuilder], + /// then a default spinner sized for the button's shape (see [_SpinnerSize]). + /// + /// The shape-aware default exists because the bare [AsyncButtonSpinner] sizes + /// to the ambient font size — right for a text label, but it would shrink an + /// icon-bearing button (whose idle height is driven by the icon) while + /// loading. + WidgetBuilder _resolveLoadingBuilder( + BuildContext context, + _SpinnerSize sizing, + ) { + return loadingBuilder ?? + AsyncButtonTheme.of(context).loadingBuilder ?? + (_) => _DefaultLoadingSpinner(sizing); + } } /// Sub-base for the four [AsyncMaterialButton]s that share the standard @@ -98,4 +115,54 @@ abstract class AsyncStandardMaterialButton extends AsyncMaterialButton { final Widget? _icon; final IconAlignment? _iconAlignment; + + /// The default spinner sizing for this button's current shape: an `.icon` + /// constructor lays out an icon beside the label, so its idle row height is + /// `max(iconSize, fontSize)`; a plain constructor shows only the label, so it + /// tracks the font size. + _SpinnerSize get _loadingSizing => + _icon != null ? _SpinnerSize.max : _SpinnerSize.fontSize; +} + +/// How [_DefaultLoadingSpinner] derives its dimension from the ambient theme, +/// chosen per button shape so the loading view keeps the idle footprint. +enum _SpinnerSize { + /// Text-only buttons — match the label font size. + fontSize, + + /// Icon-only buttons ([IconAsyncButton]) — match the icon size. + iconSize, + + /// Icon + label buttons (the `.icon` constructors) — match the taller of the + /// two, i.e. the idle row height. + max, +} + +double? _largest(double? a, double? b) => a == null + ? b + : b == null + ? a + : (a > b ? a : b); + +/// The shape-aware default loading view. Reads the resolved [IconTheme] / +/// [DefaultTextStyle] set by the surrounding Material button (the same scope +/// [AsyncButtonSpinner] reads for its colour) and sizes the spinner so the +/// button holds its idle height while loading. +class _DefaultLoadingSpinner extends StatelessWidget { + const _DefaultLoadingSpinner(this.sizing); + + final _SpinnerSize sizing; + + @override + Widget build(BuildContext context) { + final fontSize = DefaultTextStyle.of(context).style.fontSize; + final iconSize = IconTheme.of(context).size; + final dimension = switch (sizing) { + _SpinnerSize.fontSize => fontSize, + _SpinnerSize.iconSize => iconSize, + _SpinnerSize.max => _largest(iconSize, fontSize), + }; + // A null dimension lets AsyncButtonSpinner fall back to fontSize ?? 16. + return AsyncButtonSpinner(size: dimension); + } } diff --git a/lib/src/buttons/elevated_async_button.dart b/lib/src/buttons/elevated_async_button.dart index 25e1139..a7c2780 100644 --- a/lib/src/buttons/elevated_async_button.dart +++ b/lib/src/buttons/elevated_async_button.dart @@ -49,7 +49,7 @@ class ElevatedAsyncButton extends AsyncStandardMaterialButton { onPressed: onPressed, enabled: enabled, controller: controller, - loadingBuilder: loadingBuilder, + loadingBuilder: _resolveLoadingBuilder(context, _loadingSizing), transitionBuilder: transitionBuilder, builder: (context, animatedChild, callback, isLoading) { final longPress = (callback != null && !isLoading) ? onLongPress : null; diff --git a/lib/src/buttons/filled_async_button.dart b/lib/src/buttons/filled_async_button.dart index a64ec7d..5a50422 100644 --- a/lib/src/buttons/filled_async_button.dart +++ b/lib/src/buttons/filled_async_button.dart @@ -94,7 +94,7 @@ class FilledAsyncButton extends AsyncStandardMaterialButton { onPressed: onPressed, enabled: enabled, controller: controller, - loadingBuilder: loadingBuilder, + loadingBuilder: _resolveLoadingBuilder(context, _loadingSizing), transitionBuilder: transitionBuilder, builder: (context, animatedChild, callback, isLoading) { final longPress = (callback != null && !isLoading) ? onLongPress : null; diff --git a/lib/src/buttons/icon_async_button.dart b/lib/src/buttons/icon_async_button.dart index 494bab1..5901334 100644 --- a/lib/src/buttons/icon_async_button.dart +++ b/lib/src/buttons/icon_async_button.dart @@ -214,7 +214,7 @@ class IconAsyncButton extends AsyncMaterialButton { onPressed: onPressed, enabled: enabled, controller: controller, - loadingBuilder: loadingBuilder, + loadingBuilder: _resolveLoadingBuilder(context, _SpinnerSize.iconSize), transitionBuilder: transitionBuilder, builder: (context, child, callback, isLoading) { return switch (_variant) { diff --git a/lib/src/buttons/outlined_async_button.dart b/lib/src/buttons/outlined_async_button.dart index 3cd9f35..e0f33db 100644 --- a/lib/src/buttons/outlined_async_button.dart +++ b/lib/src/buttons/outlined_async_button.dart @@ -47,7 +47,7 @@ class OutlinedAsyncButton extends AsyncStandardMaterialButton { onPressed: onPressed, enabled: enabled, controller: controller, - loadingBuilder: loadingBuilder, + loadingBuilder: _resolveLoadingBuilder(context, _loadingSizing), transitionBuilder: transitionBuilder, builder: (context, animatedChild, callback, isLoading) { final longPress = (callback != null && !isLoading) ? onLongPress : null; diff --git a/lib/src/buttons/text_async_button.dart b/lib/src/buttons/text_async_button.dart index 2b5f3ad..1d4b9dd 100644 --- a/lib/src/buttons/text_async_button.dart +++ b/lib/src/buttons/text_async_button.dart @@ -47,7 +47,7 @@ class TextAsyncButton extends AsyncStandardMaterialButton { onPressed: onPressed, enabled: enabled, controller: controller, - loadingBuilder: loadingBuilder, + loadingBuilder: _resolveLoadingBuilder(context, _loadingSizing), transitionBuilder: transitionBuilder, builder: (context, animatedChild, callback, isLoading) { final longPress = (callback != null && !isLoading) ? onLongPress : null; diff --git a/test/_helpers.dart b/test/_helpers.dart index a1d228d..b8300c7 100644 --- a/test/_helpers.dart +++ b/test/_helpers.dart @@ -103,6 +103,49 @@ Color? spinnerIconThemeColor(WidgetTester tester) { return iconTheme.data.color; } +/// Side length the loading spinner is laid out in — the `width` of the nearest +/// [SizedBox] above the [CircularProgressIndicator] ([AsyncButtonSpinner] uses +/// [SizedBox.square], so width == height == the resolved dimension). +double? loadingSpinnerSize(WidgetTester tester) { + final box = tester.widget( + find + .ancestor( + of: find.byType(CircularProgressIndicator), + matching: find.byType(SizedBox), + ) + .first, + ); + return box.width; +} + +/// The size of the nearest [IconTheme] above the spinner — the button's +/// resolved icon size, the scope an icon loading child inherits. +double? spinnerIconThemeSize(WidgetTester tester) { + final iconTheme = tester.widget( + find + .ancestor( + of: find.byType(CircularProgressIndicator), + matching: find.byType(IconTheme), + ) + .first, + ); + return iconTheme.data.size; +} + +/// The font size of the nearest [DefaultTextStyle] above the spinner — the +/// button's resolved label size. +double? spinnerFontSize(WidgetTester tester) { + final style = tester.widget( + find + .ancestor( + of: find.byType(CircularProgressIndicator), + matching: find.byType(DefaultTextStyle), + ) + .first, + ); + return style.style.fontSize; +} + /// `checks`-style assertions for [Finder]. extension FinderChecks on Subject { void findsOne() => has((f) => f.evaluate().length, 'matches').equals(1); diff --git a/test/elevated_async_button_test.dart b/test/elevated_async_button_test.dart index fd164ab..0cf7833 100644 --- a/test/elevated_async_button_test.dart +++ b/test/elevated_async_button_test.dart @@ -88,5 +88,34 @@ void main() { check(find.byIcon(Icons.send)).findsOne(); check(find.text('send')).findsOne(); }); + + testWidgets('loading spinner is sized to the taller of icon and font', ( + tester, + ) async { + final (:onPressed, :completer) = pendingPress(); + await tester.pumpWidget( + pumpHost( + ElevatedAsyncButton.icon( + onPressed: onPressed, + icon: const Icon(Icons.send), + label: const Text('send'), + ), + ), + ); + await tapIntoLoading(tester, find.byType(ElevatedButton)); + final iconSize = spinnerIconThemeSize(tester); + final fontSize = spinnerFontSize(tester); + check(iconSize).isNotNull(); + check(fontSize).isNotNull(); + // The .icon row height is max(icon, font); the spinner matches it so the + // button keeps its height while loading. + final expected = iconSize! > fontSize! ? iconSize : fontSize; + check(loadingSpinnerSize(tester)).equals(expected); + // Regression guard: the icon is the taller element, so the spinner must + // exceed the font size (the old, shrinking behaviour). + check(loadingSpinnerSize(tester)!).isGreaterThan(fontSize); + completer.complete(); + await tester.pump(); + }); }); } diff --git a/test/icon_async_button_test.dart b/test/icon_async_button_test.dart index f636a43..3a68822 100644 --- a/test/icon_async_button_test.dart +++ b/test/icon_async_button_test.dart @@ -98,4 +98,45 @@ void main() { await tester.pumpAndSettle(); }); }); + + group('IconAsyncButton loading size', () { + testWidgets('spinner matches the resolved icon size, not the font size', ( + tester, + ) async { + final (:onPressed, :completer) = pendingPress(); + await tester.pumpWidget( + pumpHost( + IconAsyncButton( + onPressed: onPressed, + icon: const Icon(Icons.refresh), + ), + ), + ); + await tapIntoLoading(tester, find.byType(IconButton)); + final iconSize = spinnerIconThemeSize(tester); + check(iconSize).isNotNull(); + check(loadingSpinnerSize(tester)).equals(iconSize); + completer.complete(); + await tester.pump(); + }); + + testWidgets('explicit iconSize flows through to the spinner', ( + tester, + ) async { + final (:onPressed, :completer) = pendingPress(); + await tester.pumpWidget( + pumpHost( + IconAsyncButton( + onPressed: onPressed, + iconSize: 40, + icon: const Icon(Icons.refresh), + ), + ), + ); + await tapIntoLoading(tester, find.byType(IconButton)); + check(loadingSpinnerSize(tester)).equals(40); + completer.complete(); + await tester.pump(); + }); + }); } diff --git a/test/text_async_button_test.dart b/test/text_async_button_test.dart index 6db8588..54e04af 100644 --- a/test/text_async_button_test.dart +++ b/test/text_async_button_test.dart @@ -30,5 +30,22 @@ void main() { check(find.byIcon(Icons.copy)).findsOne(); check(find.text('copy')).findsOne(); }); + + testWidgets('plain loading spinner tracks the label font size', ( + tester, + ) async { + final (:onPressed, :completer) = pendingPress(); + await tester.pumpWidget( + pumpHost( + TextAsyncButton(onPressed: onPressed, child: const Text('go')), + ), + ); + await tapIntoLoading(tester, find.byType(TextButton)); + final fontSize = spinnerFontSize(tester); + check(fontSize).isNotNull(); + check(loadingSpinnerSize(tester)).equals(fontSize); + completer.complete(); + await tester.pump(); + }); }); } From 967835135b47a780facc32902d67da7f81a0607a Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Sun, 31 May 2026 15:16:07 +0300 Subject: [PATCH 116/176] chore: release 2.0.1 Co-Authored-By: Claude Opus 4.8 --- CHANGELOG.md | 12 ++++++++++++ pubspec.yaml | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 98294fd..dd18186 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # CHANGELOG +## 2.0.1 + +### Fixed + +- **Icon-bearing buttons no longer shrink vertically while loading.** The + default spinner sizes to the button's shape instead of always to the font + size: `iconSize` for `IconAsyncButton`, `max(iconSize, fontSize)` for the + `.icon` constructors (the idle row height), and `fontSize` for text-only + buttons (unchanged). Sizes are read from the button's resolved `IconTheme` / + `DefaultTextStyle`, so a per-widget `iconSize` and theme overrides flow + through. + ## 2.0.0 Breaking redesign. The button now does exactly one job — show a spinner while diff --git a/pubspec.yaml b/pubspec.yaml index 46b44d8..eceb579 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: material_async_button description: >- Drop-in async wrappers for Flutter Material buttons. Adds a loading state, with theming via ThemeExtension and external control via a controller. -version: 2.0.0 +version: 2.0.1 homepage: https://mehmetesen.com repository: https://github.com/esenmx/material_async_button issue_tracker: https://github.com/esenmx/material_async_button/issues From 25f65a8ff0ebf2edfc3ec8dbdb51401a64a51647 Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Sun, 31 May 2026 16:38:02 +0300 Subject: [PATCH 117/176] fix: size default spinner to the label line box, not raw fontSize The default spinner measured the raw `fontSize`, which is shorter than the text's rendered line box, so buttons shrank by a sub-pixel while loading. Size to the ambient label's `preferredLineHeight` instead (honouring the ambient TextScaler): text-only buttons take the line box, `.icon` buttons take max(iconSize, lineBox), icon-only buttons keep iconSize. Co-Authored-By: Claude Opus 4.8 --- README.md | 7 +++-- lib/src/buttons/async_material_button.dart | 24 ++++++++------- lib/src/material_async_button_theme.dart | 27 +++++++++++++---- test/_helpers.dart | 22 ++++++++++++++ test/elevated_async_button_test.dart | 11 +++---- test/outlined_async_button_test.dart | 35 ++++++++++++++++++++++ test/text_async_button_test.dart | 10 ++++--- 7 files changed, 107 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index f902d79..d69780a 100644 --- a/README.md +++ b/README.md @@ -103,9 +103,10 @@ ThemeData( With no extension registered, `AsyncButtonTheme.of` falls back to `AsyncButtonTheme.empty` — the default spinner and nothing else. -The default spinner sizes itself from the ambient font size, not `IconTheme.size`, -so inside an `IconAsyncButton` pass `loadingBuilder: (_) => AsyncButtonSpinner(size: ...)` -to match the icon's footprint. +The default spinner sizes itself to the ambient label's line box (the text's +rendered height), not `IconTheme.size`, so inside an `IconAsyncButton` pass +`loadingBuilder: (_) => AsyncButtonSpinner(size: ...)` to match the icon's +footprint. ## Custom buttons — `AsyncButton` diff --git a/lib/src/buttons/async_material_button.dart b/lib/src/buttons/async_material_button.dart index 66961e8..b869329 100644 --- a/lib/src/buttons/async_material_button.dart +++ b/lib/src/buttons/async_material_button.dart @@ -44,9 +44,10 @@ abstract class AsyncMaterialButton extends StatelessWidget { /// then a default spinner sized for the button's shape (see [_SpinnerSize]). /// /// The shape-aware default exists because the bare [AsyncButtonSpinner] sizes - /// to the ambient font size — right for a text label, but it would shrink an - /// icon-bearing button (whose idle height is driven by the icon) while - /// loading. + /// to the ambient label line box — right for a text label, but an + /// icon-bearing button's idle height can be driven by the icon (taller than + /// the line box), so it would shrink while loading unless the icon is taken + /// into account. WidgetBuilder _resolveLoadingBuilder( BuildContext context, _SpinnerSize sizing, @@ -118,8 +119,8 @@ abstract class AsyncStandardMaterialButton extends AsyncMaterialButton { /// The default spinner sizing for this button's current shape: an `.icon` /// constructor lays out an icon beside the label, so its idle row height is - /// `max(iconSize, fontSize)`; a plain constructor shows only the label, so it - /// tracks the font size. + /// `max(iconSize, lineBox)`; a plain constructor shows only the label, so it + /// tracks the label's line box. _SpinnerSize get _loadingSizing => _icon != null ? _SpinnerSize.max : _SpinnerSize.fontSize; } @@ -127,14 +128,15 @@ abstract class AsyncStandardMaterialButton extends AsyncMaterialButton { /// How [_DefaultLoadingSpinner] derives its dimension from the ambient theme, /// chosen per button shape so the loading view keeps the idle footprint. enum _SpinnerSize { - /// Text-only buttons — match the label font size. + /// Text-only buttons — match the label's line-box height (its idle extent, + /// taller than the raw `fontSize`). fontSize, /// Icon-only buttons ([IconAsyncButton]) — match the icon size. iconSize, /// Icon + label buttons (the `.icon` constructors) — match the taller of the - /// two, i.e. the idle row height. + /// icon size and the label line box, i.e. the idle row height. max, } @@ -155,14 +157,14 @@ class _DefaultLoadingSpinner extends StatelessWidget { @override Widget build(BuildContext context) { - final fontSize = DefaultTextStyle.of(context).style.fontSize; final iconSize = IconTheme.of(context).size; final dimension = switch (sizing) { - _SpinnerSize.fontSize => fontSize, + _SpinnerSize.fontSize => _ambientTextLineBox(context), _SpinnerSize.iconSize => iconSize, - _SpinnerSize.max => _largest(iconSize, fontSize), + _SpinnerSize.max => _largest(iconSize, _ambientTextLineBox(context)), }; - // A null dimension lets AsyncButtonSpinner fall back to fontSize ?? 16. + // A null dimension (icon-only with an unset icon size) lets + // AsyncButtonSpinner fall back to the ambient line box. return AsyncButtonSpinner(size: dimension); } } diff --git a/lib/src/material_async_button_theme.dart b/lib/src/material_async_button_theme.dart index 151520e..aad1a62 100644 --- a/lib/src/material_async_button_theme.dart +++ b/lib/src/material_async_button_theme.dart @@ -92,6 +92,20 @@ class AsyncButtonTheme extends ThemeExtension { } } +/// The single-line height of the ambient label style at [context] — the +/// vertical extent a one-line [Text] occupies here. The default spinner sizes +/// to this (the idle content's *line box*, which is taller than the raw +/// `fontSize`) so the button keeps its idle height while loading instead of +/// shrinking. Honours the ambient [TextScaler], matching how the label scales. +double _ambientTextLineBox(BuildContext context) { + final painter = TextPainter( + text: TextSpan(text: '', style: DefaultTextStyle.of(context).style), + textDirection: Directionality.of(context), + textScaler: MediaQuery.textScalerOf(context), + )..layout(); + return painter.preferredLineHeight; +} + /// The default loading indicator — a sized, indeterminate /// [CircularProgressIndicator]. Used as the fallback loading view, and exposed /// so you can tweak it and return it from a `loadingBuilder`: @@ -123,11 +137,12 @@ class AsyncButtonSpinner extends StatelessWidget { /// Stroke width of the [CircularProgressIndicator]. final double strokeWidth; - /// Side length of the square the indicator is laid out in. When null it is - /// derived from the ambient [DefaultTextStyle] font size (matching a text - /// button's label), falling back to `16`. [IconThemeData.size] is - /// intentionally not used — it is typically 24 and would oversize the spinner - /// on text buttons. + /// Side length of the square the indicator is laid out in. When null it + /// tracks the ambient label's line-box height (the vertical extent of a + /// one-line [Text] in the surrounding [DefaultTextStyle]), so the spinner + /// fills the same height the label did and the button doesn't shrink. + /// [IconThemeData.size] is intentionally not read here — it is typically 24 + /// and would oversize the spinner on text buttons. final double? size; @override @@ -136,7 +151,7 @@ class AsyncButtonSpinner extends StatelessWidget { color ?? IconTheme.of(context).color ?? Theme.of(context).colorScheme.primary; - final dimension = size ?? DefaultTextStyle.of(context).style.fontSize ?? 16; + final dimension = size ?? _ambientTextLineBox(context); return Center( child: SizedBox.square( dimension: dimension, diff --git a/test/_helpers.dart b/test/_helpers.dart index b8300c7..8e01462 100644 --- a/test/_helpers.dart +++ b/test/_helpers.dart @@ -146,6 +146,28 @@ double? spinnerFontSize(WidgetTester tester) { return style.style.fontSize; } +/// The single-line *line-box* height of the label style resolved at the spinner +/// — the height the default spinner is meant to match (taller than the raw +/// font size for real fonts / explicit `height`). Mirrors the package's own +/// `_ambientTextLineBox` measurement so tests assert the same number. +double spinnerTextLineBox(WidgetTester tester) { + final style = tester + .widget( + find + .ancestor( + of: find.byType(CircularProgressIndicator), + matching: find.byType(DefaultTextStyle), + ) + .first, + ) + .style; + final painter = TextPainter( + text: TextSpan(text: '', style: style), + textDirection: TextDirection.ltr, + )..layout(); + return painter.preferredLineHeight; +} + /// `checks`-style assertions for [Finder]. extension FinderChecks on Subject { void findsOne() => has((f) => f.evaluate().length, 'matches').equals(1); diff --git a/test/elevated_async_button_test.dart b/test/elevated_async_button_test.dart index 0cf7833..d616264 100644 --- a/test/elevated_async_button_test.dart +++ b/test/elevated_async_button_test.dart @@ -89,7 +89,7 @@ void main() { check(find.text('send')).findsOne(); }); - testWidgets('loading spinner is sized to the taller of icon and font', ( + testWidgets('loading spinner is sized to the taller of icon and line box', ( tester, ) async { final (:onPressed, :completer) = pendingPress(); @@ -105,15 +105,16 @@ void main() { await tapIntoLoading(tester, find.byType(ElevatedButton)); final iconSize = spinnerIconThemeSize(tester); final fontSize = spinnerFontSize(tester); + final lineBox = spinnerTextLineBox(tester); check(iconSize).isNotNull(); check(fontSize).isNotNull(); - // The .icon row height is max(icon, font); the spinner matches it so the - // button keeps its height while loading. - final expected = iconSize! > fontSize! ? iconSize : fontSize; + // The .icon row height is max(icon, lineBox); the spinner matches it so + // the button keeps its height while loading. + final expected = iconSize! > lineBox ? iconSize : lineBox; check(loadingSpinnerSize(tester)).equals(expected); // Regression guard: the icon is the taller element, so the spinner must // exceed the font size (the old, shrinking behaviour). - check(loadingSpinnerSize(tester)!).isGreaterThan(fontSize); + check(loadingSpinnerSize(tester)!).isGreaterThan(fontSize!); completer.complete(); await tester.pump(); }); diff --git a/test/outlined_async_button_test.dart b/test/outlined_async_button_test.dart index a13db21..0790eeb 100644 --- a/test/outlined_async_button_test.dart +++ b/test/outlined_async_button_test.dart @@ -50,5 +50,40 @@ void main() { completer.complete(); await tester.pumpAndSettle(); }); + + testWidgets('.icon spinner tracks the line box, not the raw font size', ( + tester, + ) async { + final (:onPressed, :completer) = pendingPress(); + // An explicit `height: 2` makes the label's line box (fontSize * 2) + // exceed both the raw font size and the default icon size — the same way + // a real font's rendered line is taller than its fontSize. The default + // spinner must size to that line box so the button keeps its idle height + // while loading (the old behaviour sized to the raw fontSize and shrank). + final theme = ThemeData( + extensions: const [AsyncButtonTheme.empty], + outlinedButtonTheme: OutlinedButtonThemeData( + style: OutlinedButton.styleFrom( + textStyle: const TextStyle(fontSize: 15, height: 2), + ), + ), + ); + await tester.pumpWidget( + pumpHost( + OutlinedAsyncButton.icon( + onPressed: onPressed, + icon: const Icon(Icons.delete), + label: const Text('Delete account'), + ), + theme: theme, + ), + ); + await tapIntoLoading(tester, find.byType(OutlinedButton)); + final lineBox = spinnerTextLineBox(tester); // 15 * 2 = 30 + check(lineBox).isGreaterThan(spinnerFontSize(tester)!); // 30 > 15 + check(loadingSpinnerSize(tester)).equals(lineBox); + completer.complete(); + await tester.pumpAndSettle(); + }); }); } diff --git a/test/text_async_button_test.dart b/test/text_async_button_test.dart index 54e04af..5c83bda 100644 --- a/test/text_async_button_test.dart +++ b/test/text_async_button_test.dart @@ -31,7 +31,7 @@ void main() { check(find.text('copy')).findsOne(); }); - testWidgets('plain loading spinner tracks the label font size', ( + testWidgets('plain loading spinner tracks the label line box', ( tester, ) async { final (:onPressed, :completer) = pendingPress(); @@ -41,9 +41,11 @@ void main() { ), ); await tapIntoLoading(tester, find.byType(TextButton)); - final fontSize = spinnerFontSize(tester); - check(fontSize).isNotNull(); - check(loadingSpinnerSize(tester)).equals(fontSize); + // The spinner fills the label's line box, so a text button keeps its idle + // height while loading. (In the test font the line box equals the font + // size; the line-box basis is exercised explicitly in the OutlinedButton + // regression test, where an explicit `height` makes them differ.) + check(loadingSpinnerSize(tester)).equals(spinnerTextLineBox(tester)); completer.complete(); await tester.pump(); }); From ecc26e6b809a2326891100c80fe348a961fe9e16 Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Sun, 31 May 2026 16:38:02 +0300 Subject: [PATCH 118/176] docs(example): demo a custom-styled OutlinedAsyncButton Add an OutlinedAsyncButton.icon with a GoogleFonts textStyle and custom padding to show that styling flows through unchanged while loading. Co-Authored-By: Claude Opus 4.8 --- example/lib/main.dart | 12 ++++++++++++ example/pubspec.yaml | 1 + 2 files changed, 13 insertions(+) diff --git a/example/lib/main.dart b/example/lib/main.dart index f32ad56..158ef53 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; import 'package:material_async_button/material_async_button.dart'; void main() => runApp(const MyApp()); @@ -207,6 +208,17 @@ class _HomePageState extends State { child: Text('Custom', style: TextStyle(color: Colors.white)), ), ), + const Divider(height: 32), + const _SectionLabel('Custom button style OutlinedButton'), + OutlinedAsyncButton.icon( + onPressed: _simulateWork, + icon: const Icon(Icons.save), + label: const Text('Save'), + style: OutlinedButton.styleFrom( + padding: const .symmetric(vertical: 16, horizontal: 24), + textStyle: GoogleFonts.dmSans(fontSize: 15, fontWeight: .w500), + ), + ), ], ), ), diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 62c1a51..58e9942 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -10,6 +10,7 @@ environment: dependencies: flutter: sdk: flutter + google_fonts: ^8.1.0 material_async_button: path: ../ From f78654dcdb90858ef7eb9a098207d8b608fbe0b4 Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Sun, 31 May 2026 16:38:02 +0300 Subject: [PATCH 119/176] chore: release 2.0.2 Co-Authored-By: Claude Opus 4.8 --- CHANGELOG.md | 12 ++++++++++++ pubspec.yaml | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd18186..6f0ec1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # CHANGELOG +## 2.0.2 + +### Fixed + +- **Buttons no longer shrink by a sub-pixel while loading.** The default spinner + now sizes to the label's **line-box height** (the idle content's vertical + extent) rather than the raw `fontSize`, which is shorter than the rendered + line. `.icon` buttons take `max(iconSize, lineBox)`, text-only buttons take the + line box, icon-only buttons keep `iconSize` (unchanged). The line box is + measured with the ambient `TextScaler`, so the loading view also tracks text + scaling. + ## 2.0.1 ### Fixed diff --git a/pubspec.yaml b/pubspec.yaml index eceb579..af6c0f4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: material_async_button description: >- Drop-in async wrappers for Flutter Material buttons. Adds a loading state, with theming via ThemeExtension and external control via a controller. -version: 2.0.1 +version: 2.0.2 homepage: https://mehmetesen.com repository: https://github.com/esenmx/material_async_button issue_tracker: https://github.com/esenmx/material_async_button/issues From 3f71e2c86c71219094c29534616860a01d354c71 Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Sun, 31 May 2026 16:47:19 +0300 Subject: [PATCH 120/176] docs(skill): spinner sizes to label line box, not raw font size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sync the skill with the 2.0.2 behavior and README — the bare AsyncButtonSpinner now sizes to the ambient label's line box, matching the package's _ambientTextLineBox measurement. Co-Authored-By: Claude Opus 4.8 --- tool/claude/flutter-material-async-button/SKILL.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tool/claude/flutter-material-async-button/SKILL.md b/tool/claude/flutter-material-async-button/SKILL.md index d64dc70..c8085ec 100644 --- a/tool/claude/flutter-material-async-button/SKILL.md +++ b/tool/claude/flutter-material-async-button/SKILL.md @@ -38,8 +38,9 @@ AsyncButtonTheme(loadingBuilder: (_) => const AsyncButtonSpinner(strokeWidth: 3) Per-button props win. No styling knobs — that's `ButtonStyle`'s job. Animate the swap with `transitionBuilder` (wrap `child` in `AnimatedSwitcher` + `AnimatedSize`). -The default spinner sizes from the ambient font size, not `IconTheme.size`; inside an -`IconAsyncButton` pass `loadingBuilder: (_) => AsyncButtonSpinner(size: ...)` to match the icon. +The default spinner sizes to the ambient label's line box (rendered text height), not +`IconTheme.size`; inside an `IconAsyncButton` pass `loadingBuilder: (_) => AsyncButtonSpinner(size: ...)` +to match the icon. ## Controller — drive from outside From 31068fe21ccb5439a2913400cd9c2298aa74e2d9 Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Sun, 31 May 2026 16:48:35 +0300 Subject: [PATCH 121/176] style: use dot-shorthand for _SpinnerSize at typed slots Drop the redundant _SpinnerSize prefix where the slot witnesses the type (switch arms, ternary against the declared return type, the typed _resolveLoadingBuilder argument). No behaviour change. Co-Authored-By: Claude Opus 4.8 --- lib/src/buttons/async_material_button.dart | 11 +++++------ lib/src/buttons/icon_async_button.dart | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/src/buttons/async_material_button.dart b/lib/src/buttons/async_material_button.dart index b869329..820849f 100644 --- a/lib/src/buttons/async_material_button.dart +++ b/lib/src/buttons/async_material_button.dart @@ -54,7 +54,7 @@ abstract class AsyncMaterialButton extends StatelessWidget { ) { return loadingBuilder ?? AsyncButtonTheme.of(context).loadingBuilder ?? - (_) => _DefaultLoadingSpinner(sizing); + (context) => _DefaultLoadingSpinner(sizing); } } @@ -121,8 +121,7 @@ abstract class AsyncStandardMaterialButton extends AsyncMaterialButton { /// constructor lays out an icon beside the label, so its idle row height is /// `max(iconSize, lineBox)`; a plain constructor shows only the label, so it /// tracks the label's line box. - _SpinnerSize get _loadingSizing => - _icon != null ? _SpinnerSize.max : _SpinnerSize.fontSize; + _SpinnerSize get _loadingSizing => _icon != null ? .max : .fontSize; } /// How [_DefaultLoadingSpinner] derives its dimension from the ambient theme, @@ -159,9 +158,9 @@ class _DefaultLoadingSpinner extends StatelessWidget { Widget build(BuildContext context) { final iconSize = IconTheme.of(context).size; final dimension = switch (sizing) { - _SpinnerSize.fontSize => _ambientTextLineBox(context), - _SpinnerSize.iconSize => iconSize, - _SpinnerSize.max => _largest(iconSize, _ambientTextLineBox(context)), + .fontSize => _ambientTextLineBox(context), + .iconSize => iconSize, + .max => _largest(iconSize, _ambientTextLineBox(context)), }; // A null dimension (icon-only with an unset icon size) lets // AsyncButtonSpinner fall back to the ambient line box. diff --git a/lib/src/buttons/icon_async_button.dart b/lib/src/buttons/icon_async_button.dart index 5901334..0736621 100644 --- a/lib/src/buttons/icon_async_button.dart +++ b/lib/src/buttons/icon_async_button.dart @@ -214,7 +214,7 @@ class IconAsyncButton extends AsyncMaterialButton { onPressed: onPressed, enabled: enabled, controller: controller, - loadingBuilder: _resolveLoadingBuilder(context, _SpinnerSize.iconSize), + loadingBuilder: _resolveLoadingBuilder(context, .iconSize), transitionBuilder: transitionBuilder, builder: (context, child, callback, isLoading) { return switch (_variant) { From 2a5bf7941c8f6ef2857d5deae3890c14eb984b2c Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Sat, 27 Jun 2026 14:59:32 +0300 Subject: [PATCH 122/176] release: v2.1.0 - FloatingActionAsyncButton and accessibility semantics --- CHANGELOG.md | 11 + example/lib/main.dart | 24 ++ lib/material_async_button.dart | 6 +- .../buttons/floating_action_async_button.dart | 354 ++++++++++++++++++ lib/src/material_async_button_theme.dart | 8 +- pubspec.yaml | 2 +- test/floating_action_async_button_test.dart | 172 +++++++++ .../flutter-material-async-button/SKILL.md | 18 +- 8 files changed, 585 insertions(+), 10 deletions(-) create mode 100644 lib/src/buttons/floating_action_async_button.dart create mode 100644 test/floating_action_async_button_test.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f0ec1e..c3cf825 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # CHANGELOG +## 2.1.0 + +### Added + +- **New `FloatingActionAsyncButton` wrapper.** Adds drop-in async loading states + to `FloatingActionButton` with support for all four core variants: standard, + `.small`, `.large`, and `.extended`. +- **Improved accessibility for screen readers.** Added `semanticsLabel` parameter to + `AsyncButtonSpinner` (defaulting to `'Loading'`) to ensure screen readers + actively announce the progress of asynchronous operations when buttons are clicked. + ## 2.0.2 ### Fixed diff --git a/example/lib/main.dart b/example/lib/main.dart index 158ef53..a3844f9 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -139,6 +139,30 @@ class _HomePageState extends State { ], ), const Divider(height: 32), + const _SectionLabel('Floating Action Buttons'), + Row( + mainAxisAlignment: .spaceEvenly, + children: [ + FloatingActionAsyncButton( + onPressed: _simulateWork, + child: const Icon(Icons.navigation), + ), + FloatingActionAsyncButton.small( + onPressed: _simulateWork, + child: const Icon(Icons.navigation), + ), + FloatingActionAsyncButton.large( + onPressed: _simulateWork, + child: const Icon(Icons.navigation), + ), + FloatingActionAsyncButton.extended( + onPressed: _simulateWork, + icon: const Icon(Icons.navigation), + label: const Text('Navigate'), + ), + ], + ), + const Divider(height: 32), const _SectionLabel('Animated spinner swap'), FilledAsyncButton( onPressed: _simulateWork, diff --git a/lib/material_async_button.dart b/lib/material_async_button.dart index d319b72..f6559dd 100644 --- a/lib/material_async_button.dart +++ b/lib/material_async_button.dart @@ -1,8 +1,9 @@ /// Drop-in async wrappers for Flutter Material buttons. /// /// See `ElevatedAsyncButton`, `FilledAsyncButton`, `OutlinedAsyncButton`, -/// `TextAsyncButton`, and `IconAsyncButton` for the named-constructor -/// variants. Use `AsyncButton` when you need a custom non-Material button. +/// `TextAsyncButton`, `IconAsyncButton`, and `FloatingActionAsyncButton` for +/// the named-constructor variants. Use `AsyncButton` when you need a custom +/// non-Material button. library; import 'package:flutter/foundation.dart'; @@ -13,6 +14,7 @@ part 'src/async_button_controller.dart'; part 'src/buttons/async_material_button.dart'; part 'src/buttons/elevated_async_button.dart'; part 'src/buttons/filled_async_button.dart'; +part 'src/buttons/floating_action_async_button.dart'; part 'src/buttons/icon_async_button.dart'; part 'src/buttons/outlined_async_button.dart'; part 'src/buttons/text_async_button.dart'; diff --git a/lib/src/buttons/floating_action_async_button.dart b/lib/src/buttons/floating_action_async_button.dart new file mode 100644 index 0000000..72666ef --- /dev/null +++ b/lib/src/buttons/floating_action_async_button.dart @@ -0,0 +1,354 @@ +part of '../../material_async_button.dart'; + +enum _FloatingActionButtonVariant { standard, small, large, extended } + +class _DefaultHeroTag { + const _DefaultHeroTag(); +} + +const Object _defaultHeroTag = _DefaultHeroTag(); + +/// Async-aware [FloatingActionButton]. While `onPressed` is running the child +/// (or label, for `.extended`) is swapped for the loading widget. +class FloatingActionAsyncButton extends AsyncMaterialButton { + /// Mirrors [FloatingActionButton.new]. + const FloatingActionAsyncButton({ + super.key, + required super.onPressed, + Widget? child, + super.enabled, + super.controller, + super.loadingBuilder, + super.transitionBuilder, + this.tooltip, + this.foregroundColor, + this.backgroundColor, + this.focusColor, + this.hoverColor, + this.splashColor, + this.elevation, + this.focusElevation, + this.hoverElevation, + this.highlightElevation, + this.disabledElevation, + this.mouseCursor, + this.shape, + this.clipBehavior = .none, + this.focusNode, + this.autofocus = false, + this.materialTapTargetSize, + this.isExtended = false, + this.heroTag = _defaultHeroTag, + this.enableFeedback, + this.mini = false, + }) : _variant = .standard, + _icon = null, + _extendedIconLabelSpacing = null, + _extendedPadding = null, + _extendedTextStyle = null, + super(child: child ?? const SizedBox.shrink()); + + /// Mirrors [FloatingActionButton.small]. + const FloatingActionAsyncButton.small({ + super.key, + required super.onPressed, + Widget? child, + super.enabled, + super.controller, + super.loadingBuilder, + super.transitionBuilder, + this.tooltip, + this.foregroundColor, + this.backgroundColor, + this.focusColor, + this.hoverColor, + this.splashColor, + this.elevation, + this.focusElevation, + this.hoverElevation, + this.highlightElevation, + this.disabledElevation, + this.mouseCursor, + this.shape, + this.clipBehavior = .none, + this.focusNode, + this.autofocus = false, + this.materialTapTargetSize, + this.heroTag = _defaultHeroTag, + this.enableFeedback, + }) : _variant = .small, + mini = false, + isExtended = false, + _icon = null, + _extendedIconLabelSpacing = null, + _extendedPadding = null, + _extendedTextStyle = null, + super(child: child ?? const SizedBox.shrink()); + + /// Mirrors [FloatingActionButton.large]. + const FloatingActionAsyncButton.large({ + super.key, + required super.onPressed, + Widget? child, + super.enabled, + super.controller, + super.loadingBuilder, + super.transitionBuilder, + this.tooltip, + this.foregroundColor, + this.backgroundColor, + this.focusColor, + this.hoverColor, + this.splashColor, + this.elevation, + this.focusElevation, + this.hoverElevation, + this.highlightElevation, + this.disabledElevation, + this.mouseCursor, + this.shape, + this.clipBehavior = .none, + this.focusNode, + this.autofocus = false, + this.materialTapTargetSize, + this.heroTag = _defaultHeroTag, + this.enableFeedback, + }) : _variant = .large, + mini = false, + isExtended = false, + _icon = null, + _extendedIconLabelSpacing = null, + _extendedPadding = null, + _extendedTextStyle = null, + super(child: child ?? const SizedBox.shrink()); + + /// Mirrors [FloatingActionButton.extended]. + const FloatingActionAsyncButton.extended({ + super.key, + required super.onPressed, + required Widget label, + Widget? icon, + super.enabled, + super.controller, + super.loadingBuilder, + super.transitionBuilder, + this.tooltip, + this.foregroundColor, + this.backgroundColor, + this.focusColor, + this.hoverColor, + this.splashColor, + this.elevation, + this.focusElevation, + this.hoverElevation, + this.highlightElevation, + this.disabledElevation, + this.mouseCursor, + this.shape, + this.clipBehavior = .none, + this.focusNode, + this.autofocus = false, + this.materialTapTargetSize, + this.isExtended = true, + this.heroTag = _defaultHeroTag, + this.enableFeedback, + double? extendedIconLabelSpacing, + EdgeInsetsGeometry? extendedPadding, + TextStyle? extendedTextStyle, + }) : _variant = .extended, + mini = false, + _icon = icon, + _extendedIconLabelSpacing = extendedIconLabelSpacing, + _extendedPadding = extendedPadding, + _extendedTextStyle = extendedTextStyle, + super(child: label); + + /// Forwarded to the underlying [FloatingActionButton]. + final String? tooltip; + + /// Forwarded to the underlying [FloatingActionButton]. + final Color? foregroundColor; + + /// Forwarded to the underlying [FloatingActionButton]. + final Color? backgroundColor; + + /// Forwarded to the underlying [FloatingActionButton]. + final Color? focusColor; + + /// Forwarded to the underlying [FloatingActionButton]. + final Color? hoverColor; + + /// Forwarded to the underlying [FloatingActionButton]. + final Color? splashColor; + + /// Forwarded to the underlying [FloatingActionButton]. + final double? elevation; + + /// Forwarded to the underlying [FloatingActionButton]. + final double? focusElevation; + + /// Forwarded to the underlying [FloatingActionButton]. + final double? hoverElevation; + + /// Forwarded to the underlying [FloatingActionButton]. + final double? highlightElevation; + + /// Forwarded to the underlying [FloatingActionButton]. + final double? disabledElevation; + + /// Forwarded to the underlying [FloatingActionButton]. + final MouseCursor? mouseCursor; + + /// Forwarded to the underlying [FloatingActionButton]. + final ShapeBorder? shape; + + /// Forwarded to the underlying [FloatingActionButton]. + final Clip clipBehavior; + + /// Forwarded to the underlying [FloatingActionButton]. + final FocusNode? focusNode; + + /// Forwarded to the underlying [FloatingActionButton]. + final bool autofocus; + + /// Forwarded to the underlying [FloatingActionButton]. + final MaterialTapTargetSize? materialTapTargetSize; + + /// Forwarded to the underlying [FloatingActionButton]. + final bool isExtended; + + /// Forwarded to the underlying [FloatingActionButton]. + final Object? heroTag; + + /// Forwarded to the underlying [FloatingActionButton]. + final bool? enableFeedback; + + /// Forwarded to the underlying [FloatingActionButton]. + final bool mini; + + final Widget? _icon; + final double? _extendedIconLabelSpacing; + final EdgeInsetsGeometry? _extendedPadding; + final TextStyle? _extendedTextStyle; + + final _FloatingActionButtonVariant _variant; + + @override + Widget build(BuildContext context) { + return AsyncButton( + onPressed: onPressed, + enabled: enabled, + controller: controller, + loadingBuilder: _resolveLoadingBuilder( + context, + _variant == .extended ? .max : .iconSize, + ), + transitionBuilder: transitionBuilder, + builder: (context, animatedChild, callback, isLoading) { + final hasHeroTag = heroTag != _defaultHeroTag; + return switch (_variant) { + .standard => FloatingActionButton( + onPressed: callback, + tooltip: tooltip, + foregroundColor: foregroundColor, + backgroundColor: backgroundColor, + focusColor: focusColor, + hoverColor: hoverColor, + splashColor: splashColor, + elevation: elevation, + focusElevation: focusElevation, + hoverElevation: hoverElevation, + highlightElevation: highlightElevation, + disabledElevation: disabledElevation, + mouseCursor: mouseCursor, + shape: shape, + clipBehavior: clipBehavior, + focusNode: focusNode, + autofocus: autofocus, + materialTapTargetSize: materialTapTargetSize, + isExtended: isExtended, + heroTag: hasHeroTag ? heroTag : const _DefaultHeroTag(), + enableFeedback: enableFeedback, + mini: mini, + child: animatedChild, + ), + .small => FloatingActionButton.small( + onPressed: callback, + tooltip: tooltip, + foregroundColor: foregroundColor, + backgroundColor: backgroundColor, + focusColor: focusColor, + hoverColor: hoverColor, + splashColor: splashColor, + elevation: elevation, + focusElevation: focusElevation, + hoverElevation: hoverElevation, + highlightElevation: highlightElevation, + disabledElevation: disabledElevation, + mouseCursor: mouseCursor, + shape: shape, + clipBehavior: clipBehavior, + focusNode: focusNode, + autofocus: autofocus, + materialTapTargetSize: materialTapTargetSize, + heroTag: hasHeroTag ? heroTag : const _DefaultHeroTag(), + enableFeedback: enableFeedback, + child: animatedChild, + ), + .large => FloatingActionButton.large( + onPressed: callback, + tooltip: tooltip, + foregroundColor: foregroundColor, + backgroundColor: backgroundColor, + focusColor: focusColor, + hoverColor: hoverColor, + splashColor: splashColor, + elevation: elevation, + focusElevation: focusElevation, + hoverElevation: hoverElevation, + highlightElevation: highlightElevation, + disabledElevation: disabledElevation, + mouseCursor: mouseCursor, + shape: shape, + clipBehavior: clipBehavior, + focusNode: focusNode, + autofocus: autofocus, + materialTapTargetSize: materialTapTargetSize, + heroTag: hasHeroTag ? heroTag : const _DefaultHeroTag(), + enableFeedback: enableFeedback, + child: animatedChild, + ), + .extended => FloatingActionButton.extended( + onPressed: callback, + label: animatedChild, + icon: isLoading ? null : _icon, + tooltip: tooltip, + foregroundColor: foregroundColor, + backgroundColor: backgroundColor, + focusColor: focusColor, + hoverColor: hoverColor, + splashColor: splashColor, + elevation: elevation, + focusElevation: focusElevation, + hoverElevation: hoverElevation, + highlightElevation: highlightElevation, + disabledElevation: disabledElevation, + mouseCursor: mouseCursor, + shape: shape, + clipBehavior: clipBehavior, + focusNode: focusNode, + autofocus: autofocus, + materialTapTargetSize: materialTapTargetSize, + isExtended: isExtended, + heroTag: hasHeroTag ? heroTag : const _DefaultHeroTag(), + enableFeedback: enableFeedback, + extendedIconLabelSpacing: _extendedIconLabelSpacing, + extendedPadding: _extendedPadding, + extendedTextStyle: _extendedTextStyle, + ), + }; + }, + child: child, + ); + } +} diff --git a/lib/src/material_async_button_theme.dart b/lib/src/material_async_button_theme.dart index aad1a62..964d9e4 100644 --- a/lib/src/material_async_button_theme.dart +++ b/lib/src/material_async_button_theme.dart @@ -121,12 +121,14 @@ class AsyncButtonSpinner extends StatelessWidget { /// Creates a spinner. [color] defaults to the button's foreground and /// otherwise the primary colour; [strokeWidth] sets the line weight; [size] /// sets the square the indicator occupies — when null it tracks the ambient - /// font size so the spinner matches the button's label. + /// font size so the spinner matches the button's label; [semanticsLabel] + /// sets the accessibility label read by screen readers. const AsyncButtonSpinner({ super.key, this.color, this.strokeWidth = 2, this.size, + this.semanticsLabel = 'Loading', }); /// Indicator colour. When null, inherits the button's foreground (its @@ -145,6 +147,9 @@ class AsyncButtonSpinner extends StatelessWidget { /// and would oversize the spinner on text buttons. final double? size; + /// Accessibility label read by screen readers. Defaults to `'Loading'`. + final String? semanticsLabel; + @override Widget build(BuildContext context) { final resolved = @@ -158,6 +163,7 @@ class AsyncButtonSpinner extends StatelessWidget { child: CircularProgressIndicator( strokeWidth: strokeWidth, valueColor: AlwaysStoppedAnimation(resolved), + semanticsLabel: semanticsLabel, ), ), ); diff --git a/pubspec.yaml b/pubspec.yaml index af6c0f4..0f878b6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: material_async_button description: >- Drop-in async wrappers for Flutter Material buttons. Adds a loading state, with theming via ThemeExtension and external control via a controller. -version: 2.0.2 +version: 2.1.0 homepage: https://mehmetesen.com repository: https://github.com/esenmx/material_async_button issue_tracker: https://github.com/esenmx/material_async_button/issues diff --git a/test/floating_action_async_button_test.dart b/test/floating_action_async_button_test.dart new file mode 100644 index 0000000..6666cf0 --- /dev/null +++ b/test/floating_action_async_button_test.dart @@ -0,0 +1,172 @@ +import 'package:checks/checks.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:material_async_button/material_async_button.dart'; + +import '_helpers.dart'; + +void main() { + group('FloatingActionAsyncButton', () { + testWidgets('renders a FloatingActionButton with the child', ( + tester, + ) async { + await tester.pumpWidget( + pumpHost( + FloatingActionAsyncButton( + onPressed: () async {}, + child: const Text('go'), + ), + ), + ); + check(find.byType(FloatingActionButton)).findsOne(); + check(find.text('go')).findsOne(); + }); + + testWidgets('small and large variants render FloatingActionButton', ( + tester, + ) async { + await tester.pumpWidget( + pumpHost( + Column( + children: [ + FloatingActionAsyncButton.small( + onPressed: () async {}, + child: const Icon(Icons.add), + ), + FloatingActionAsyncButton.large( + onPressed: () async {}, + child: const Icon(Icons.add), + ), + ], + ), + ), + ); + check(find.byType(FloatingActionButton).evaluate().length).equals(2); + }); + + testWidgets( + 'loading spinner uses onPrimaryContainer, not the disabled grey', + (tester) async { + final (:onPressed, :completer) = pendingPress(); + final theme = emptyAsyncButtonTheme; + await tester.pumpWidget( + pumpHost( + FloatingActionAsyncButton( + onPressed: onPressed, + child: const Text('go'), + ), + theme: theme, + ), + ); + await tapIntoLoading(tester, find.byType(FloatingActionButton)); + check( + spinnerColor(tester), + ).equals(theme.colorScheme.onPrimaryContainer); + completer.complete(); + await tester.pumpAndSettle(); + }, + ); + }); + + group('FloatingActionAsyncButton.extended', () { + testWidgets('spinner replaces icon and label, both restored after', ( + tester, + ) async { + final (:onPressed, :completer) = pendingPress(); + await tester.pumpWidget( + pumpHost( + FloatingActionAsyncButton.extended( + onPressed: onPressed, + icon: const Icon(Icons.send), + label: const Text('send'), + ), + ), + ); + check(find.byIcon(Icons.send)).findsOne(); + check(find.text('send')).findsOne(); + await tapIntoLoading(tester, find.byType(FloatingActionButton)); + // Loading drops the icon and shows the spinner alone. + check(find.byType(CircularProgressIndicator)).findsOne(); + check(find.byIcon(Icons.send)).findsNone(); + completer.complete(); + await tester.pumpAndSettle(); + // Icon and label both return once the work completes. + check(find.byIcon(Icons.send)).findsOne(); + check(find.text('send')).findsOne(); + }); + + testWidgets( + 'loading spinner is sized to the taller of icon and line box ' + 'when IconTheme is present', + (tester) async { + final (:onPressed, :completer) = pendingPress(); + await tester.pumpWidget( + pumpHost( + IconTheme( + data: const IconThemeData(size: 32), + child: FloatingActionAsyncButton.extended( + onPressed: onPressed, + icon: const Icon(Icons.send), + label: const Text('send'), + ), + ), + ), + ); + await tapIntoLoading(tester, find.byType(FloatingActionButton)); + final lineBox = spinnerTextLineBox(tester); + final expected = 32.0 > lineBox ? 32.0 : lineBox; + check(loadingSpinnerSize(tester)).equals(expected); + completer.complete(); + await tester.pump(); + }, + ); + }); + + group('AsyncButtonSpinner Accessibility', () { + testWidgets( + 'spinner exposes semanticsLabel for screen readers by default', + (tester) async { + final (:onPressed, :completer) = pendingPress(); + await tester.pumpWidget( + pumpHost( + FloatingActionAsyncButton( + onPressed: onPressed, + child: const Text('go'), + ), + ), + ); + await tapIntoLoading(tester, find.byType(FloatingActionButton)); + final cpi = tester.widget( + find.byType(CircularProgressIndicator), + ); + check(cpi.semanticsLabel).equals('Loading'); + completer.complete(); + await tester.pumpAndSettle(); + }, + ); + + testWidgets('custom semanticsLabel flows to CircularProgressIndicator', ( + tester, + ) async { + final (:onPressed, :completer) = pendingPress(); + await tester.pumpWidget( + pumpHost( + FloatingActionAsyncButton( + onPressed: onPressed, + loadingBuilder: (context) => const AsyncButtonSpinner( + semanticsLabel: 'Submitting', + ), + child: const Text('go'), + ), + ), + ); + await tapIntoLoading(tester, find.byType(FloatingActionButton)); + final cpi = tester.widget( + find.byType(CircularProgressIndicator), + ); + check(cpi.semanticsLabel).equals('Submitting'); + completer.complete(); + await tester.pumpAndSettle(); + }); + }); +} diff --git a/tool/claude/flutter-material-async-button/SKILL.md b/tool/claude/flutter-material-async-button/SKILL.md index c8085ec..f03eb78 100644 --- a/tool/claude/flutter-material-async-button/SKILL.md +++ b/tool/claude/flutter-material-async-button/SKILL.md @@ -3,9 +3,9 @@ name: flutter-material-async-button description: Use this skill when working in a Flutter project that depends on the material_async_button package, or when the user wants to add a loading state to a Material button (ElevatedButton, FilledButton, OutlinedButton, - TextButton, IconButton) whose onPressed is async. Triggers on "async button", - "loading button", or any handler the user writes as `() async {}` and passes - to a Material button. + TextButton, IconButton, FloatingActionButton) whose onPressed is async. Triggers + on "async button", "loading button", "floating action async button", or any handler + the user writes as `() async {}` and passes to a Material button. --- # material_async_button @@ -20,6 +20,7 @@ it shows a spinner while the future runs. Every Material param is forwarded. |`OutlinedButton`|`OutlinedAsyncButton`|`.icon`| |`TextButton`|`TextAsyncButton`|`.icon`| |`IconButton`|`IconAsyncButton`|`.filled` `.filledTonal` `.outlined`| +|`FloatingActionButton`|`FloatingActionAsyncButton`|`.small` `.large` `.extended`| ```dart ElevatedAsyncButton(onPressed: notifier.save, child: const Text('Save')) @@ -33,14 +34,19 @@ button. ## Theme (once) ```dart -AsyncButtonTheme(loadingBuilder: (_) => const AsyncButtonSpinner(strokeWidth: 3)) +AsyncButtonTheme( + loadingBuilder: (_) => const AsyncButtonSpinner( + strokeWidth: 3, + semanticsLabel: 'Loading', // screen readers (defaults to 'Loading') + ), +) ``` Per-button props win. No styling knobs — that's `ButtonStyle`'s job. Animate the swap with `transitionBuilder` (wrap `child` in `AnimatedSwitcher` + `AnimatedSize`). The default spinner sizes to the ambient label's line box (rendered text height), not -`IconTheme.size`; inside an `IconAsyncButton` pass `loadingBuilder: (_) => AsyncButtonSpinner(size: ...)` -to match the icon. +`IconTheme.size`; inside an `IconAsyncButton` or `FloatingActionAsyncButton` pass +`loadingBuilder: (_) => AsyncButtonSpinner(size: ...)` to match the icon. ## Controller — drive from outside From 8e38ede70295594ffc5a380fc4f1b1316a97aebf Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 1 Jul 2026 13:36:55 +0000 Subject: [PATCH 123/176] =?UTF-8?q?=F0=9F=A7=B9=20Refactor=20AsyncButtonTh?= =?UTF-8?q?eme.lerp=20to=20fix=20dead=20code=20warning?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changed the parameter type of `AsyncButtonTheme.lerp` to `covariant AsyncButtonTheme? other` and updated the condition to `if (other == null)`. This safely avoids the static analysis "dead code" warning without altering the runtime behavior. Co-authored-by: esenmx <43244505+esenmx@users.noreply.github.com> --- lib/src/material_async_button_theme.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/material_async_button_theme.dart b/lib/src/material_async_button_theme.dart index 964d9e4..f43a319 100644 --- a/lib/src/material_async_button_theme.dart +++ b/lib/src/material_async_button_theme.dart @@ -64,10 +64,10 @@ class AsyncButtonTheme extends ThemeExtension { @override AsyncButtonTheme lerp( - covariant ThemeExtension? other, + covariant AsyncButtonTheme? other, double t, ) { - if (other is! AsyncButtonTheme) { + if (other == null) { return this; } // Widgets and callbacks don't lerp; snap at the halfway point. From ab4c6419fa5c451f0be006d9eb1705638ad6a626 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 1 Jul 2026 13:37:00 +0000 Subject: [PATCH 124/176] test: add test for AsyncButtonController _setLoading after dispose Added a test to ensure that when `AsyncButtonController` is disposed while an async `onPressed` operation is running, the completion of that operation does not throw an error when attempting to call `_setLoading`. This increases the robustness of the controller and prevents unintended crashes from `notifyListeners` being called post-disposal. Co-authored-by: esenmx <43244505+esenmx@users.noreply.github.com> --- test/async_button_controller_test.dart | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/async_button_controller_test.dart b/test/async_button_controller_test.dart index 76bb78d..edc81d8 100644 --- a/test/async_button_controller_test.dart +++ b/test/async_button_controller_test.dart @@ -90,6 +90,17 @@ void main() { await f; check(c).isIdle(); }); + + test('disposing during onPressed does not throw on completion', () async { + final completer = Completer(); + final c = AsyncButtonController()..attach(onPressed: () => completer.future); + final f = c.trigger(); + check(c).isLoading(); + c.dispose(); + completer.complete(); + await f; + // Should complete without FlutterError/AssertionError from notifyListeners + }); }); group('AsyncButtonController interop', () { From a912e574ce55d56f47a602b5ac9be45778e81e57 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 1 Jul 2026 13:40:35 +0000 Subject: [PATCH 125/176] test: add test for AsyncButtonController _setLoading after dispose Added a test to ensure that when `AsyncButtonController` is disposed while an async `onPressed` operation is running, the completion of that operation does not throw an error when attempting to call `_setLoading`. This increases the robustness of the controller and prevents unintended crashes from `notifyListeners` being called post-disposal. Formatted code to pass CI. Co-authored-by: esenmx <43244505+esenmx@users.noreply.github.com> --- test/async_button_controller_test.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/async_button_controller_test.dart b/test/async_button_controller_test.dart index edc81d8..e02af97 100644 --- a/test/async_button_controller_test.dart +++ b/test/async_button_controller_test.dart @@ -93,7 +93,8 @@ void main() { test('disposing during onPressed does not throw on completion', () async { final completer = Completer(); - final c = AsyncButtonController()..attach(onPressed: () => completer.future); + final c = AsyncButtonController() + ..attach(onPressed: () => completer.future); final f = c.trigger(); check(c).isLoading(); c.dispose(); From 86d5a051aa965a53b079150d7a1256ca5ec14a40 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 1 Jul 2026 13:44:21 +0000 Subject: [PATCH 126/176] =?UTF-8?q?=E2=9A=A1=20Optimize=20TextPainter=20la?= =?UTF-8?q?yout=20with=20memoization=20in=20material=5Fasync=5Fbutton=5Fth?= =?UTF-8?q?eme.dart?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: esenmx <43244505+esenmx@users.noreply.github.com> --- lib/src/material_async_button_theme.dart | 30 ++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/lib/src/material_async_button_theme.dart b/lib/src/material_async_button_theme.dart index 964d9e4..8b4d2e7 100644 --- a/lib/src/material_async_button_theme.dart +++ b/lib/src/material_async_button_theme.dart @@ -92,18 +92,40 @@ class AsyncButtonTheme extends ThemeExtension { } } +TextStyle? _cachedTextStyle; +TextDirection? _cachedTextDirection; +TextScaler? _cachedTextScaler; +double? _cachedLineBox; + /// The single-line height of the ambient label style at [context] — the /// vertical extent a one-line [Text] occupies here. The default spinner sizes /// to this (the idle content's *line box*, which is taller than the raw /// `fontSize`) so the button keeps its idle height while loading instead of /// shrinking. Honours the ambient [TextScaler], matching how the label scales. double _ambientTextLineBox(BuildContext context) { + final style = DefaultTextStyle.of(context).style; + final textDirection = Directionality.of(context); + final textScaler = MediaQuery.textScalerOf(context); + + if (_cachedTextStyle == style && + _cachedTextDirection == textDirection && + _cachedTextScaler == textScaler && + _cachedLineBox != null) { + return _cachedLineBox!; + } + final painter = TextPainter( - text: TextSpan(text: '', style: DefaultTextStyle.of(context).style), - textDirection: Directionality.of(context), - textScaler: MediaQuery.textScalerOf(context), + text: TextSpan(text: '', style: style), + textDirection: textDirection, + textScaler: textScaler, )..layout(); - return painter.preferredLineHeight; + + _cachedTextStyle = style; + _cachedTextDirection = textDirection; + _cachedTextScaler = textScaler; + _cachedLineBox = painter.preferredLineHeight; + + return _cachedLineBox!; } /// The default loading indicator — a sized, indeterminate From 2d23def18686a4a3f6bfe517c1e397b1a83ffe3c Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 1 Jul 2026 14:40:00 +0000 Subject: [PATCH 127/176] test: cover swapping external controller in AsyncButton Added test coverage for AsyncButton.didUpdateWidget to ensure listeners are correctly transferred or internal controllers are correctly managed when the widget's controller parameter transitions between null and an external AsyncButtonController instance. Co-authored-by: esenmx <43244505+esenmx@users.noreply.github.com> --- test/async_button_test.dart | 56 +++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/test/async_button_test.dart b/test/async_button_test.dart index 3ff21bb..388b0ec 100644 --- a/test/async_button_test.dart +++ b/test/async_button_test.dart @@ -282,6 +282,62 @@ void main() { completer.complete(); }); + testWidgets( + 'swapping from internal to external controller disposes internal and uses new', + (tester) async { + final externalController = newController(); + final completer = Completer(); + AsyncButton button(AsyncButtonController? c) => AsyncButton( + controller: c, + onPressed: () => completer.future, + builder: textBuilder, + child: const Text('child'), + ); + + // 1. Pump with internal controller (null) + await tester.pumpWidget(pumpHost(button(null))); + + // 2. Pump with external controller + await tester.pumpWidget(pumpHost(button(externalController))); + + // The widget now listens to externalController: driving it must show loading. + unawaited(externalController.trigger()); + await tester.pump(); + check(find.byType(CircularProgressIndicator)).findsOne(); + + completer.complete(); + await tester.pumpAndSettle(); + }, + ); + + testWidgets( + 'swapping from external to internal controller', + (tester) async { + final externalController = newController(); + final completer = Completer(); + AsyncButton button(AsyncButtonController? c) => AsyncButton( + controller: c, + onPressed: () => completer.future, + builder: textBuilder, + child: const Text('child'), + ); + + // 1. Pump with external controller + await tester.pumpWidget(pumpHost(button(externalController))); + + // 2. Pump with internal controller (null) + await tester.pumpWidget(pumpHost(button(null))); + + // Driving externalController should NOT show loading because it's detached + unawaited(externalController.trigger()); + await tester.pump(); + check(find.byType(CircularProgressIndicator)).findsNone(); + + completer.complete(); + await tester.pumpAndSettle(); + }, + ); + testWidgets( 'swapping the external controller transfers listening without leak', (tester) async { From 1eb0c63aa6fab7fc31af9389abcc6b1b5e4176b8 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 1 Jul 2026 14:45:02 +0000 Subject: [PATCH 128/176] style: fix line length in test/async_button_test.dart Fix line length issues found by flutter analyze in the newly added tests for swapping the external controller. Co-authored-by: esenmx <43244505+esenmx@users.noreply.github.com> --- test/async_button_test.dart | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/test/async_button_test.dart b/test/async_button_test.dart index 388b0ec..6afabc2 100644 --- a/test/async_button_test.dart +++ b/test/async_button_test.dart @@ -283,16 +283,17 @@ void main() { }); testWidgets( - 'swapping from internal to external controller disposes internal and uses new', + 'swapping from internal to external controller disposes internal ' + 'and uses new', (tester) async { final externalController = newController(); final completer = Completer(); AsyncButton button(AsyncButtonController? c) => AsyncButton( - controller: c, - onPressed: () => completer.future, - builder: textBuilder, - child: const Text('child'), - ); + controller: c, + onPressed: () => completer.future, + builder: textBuilder, + child: const Text('child'), + ); // 1. Pump with internal controller (null) await tester.pumpWidget(pumpHost(button(null))); @@ -300,7 +301,8 @@ void main() { // 2. Pump with external controller await tester.pumpWidget(pumpHost(button(externalController))); - // The widget now listens to externalController: driving it must show loading. + // The widget now listens to externalController: driving it must show + // loading. unawaited(externalController.trigger()); await tester.pump(); check(find.byType(CircularProgressIndicator)).findsOne(); @@ -316,11 +318,11 @@ void main() { final externalController = newController(); final completer = Completer(); AsyncButton button(AsyncButtonController? c) => AsyncButton( - controller: c, - onPressed: () => completer.future, - builder: textBuilder, - child: const Text('child'), - ); + controller: c, + onPressed: () => completer.future, + builder: textBuilder, + child: const Text('child'), + ); // 1. Pump with external controller await tester.pumpWidget(pumpHost(button(externalController))); @@ -328,7 +330,8 @@ void main() { // 2. Pump with internal controller (null) await tester.pumpWidget(pumpHost(button(null))); - // Driving externalController should NOT show loading because it's detached + // Driving externalController should NOT show loading because it's + // detached. unawaited(externalController.trigger()); await tester.pump(); check(find.byType(CircularProgressIndicator)).findsNone(); From 4f4ad52ddf32bfb42c8df14320c43d3ecc5b83ff Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Sat, 11 Jul 2026 15:06:23 +0300 Subject: [PATCH 129/176] perf: replace singleton text metrics cache with a bounded Map --- lib/src/material_async_button_theme.dart | 28 +++++++++++------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/lib/src/material_async_button_theme.dart b/lib/src/material_async_button_theme.dart index 1f0a5f6..dc4d8cb 100644 --- a/lib/src/material_async_button_theme.dart +++ b/lib/src/material_async_button_theme.dart @@ -92,10 +92,10 @@ class AsyncButtonTheme extends ThemeExtension { } } -TextStyle? _cachedTextStyle; -TextDirection? _cachedTextDirection; -TextScaler? _cachedTextScaler; -double? _cachedLineBox; +// Bounded cache to prevent thrashing between multiple button styles on screen, +// while avoiding unbounded memory growth in apps with dynamic text styles. +typedef _LineBoxKey = (TextStyle, TextDirection, TextScaler); +final _lineBoxCache = <_LineBoxKey, double>{}; /// The single-line height of the ambient label style at [context] — the /// vertical extent a one-line [Text] occupies here. The default spinner sizes @@ -106,12 +106,15 @@ double _ambientTextLineBox(BuildContext context) { final style = DefaultTextStyle.of(context).style; final textDirection = Directionality.of(context); final textScaler = MediaQuery.textScalerOf(context); + final key = (style, textDirection, textScaler); - if (_cachedTextStyle == style && - _cachedTextDirection == textDirection && - _cachedTextScaler == textScaler && - _cachedLineBox != null) { - return _cachedLineBox!; + final cached = _lineBoxCache[key]; + if (cached != null) { + return cached; + } + + if (_lineBoxCache.length >= 16) { + _lineBoxCache.clear(); } final painter = TextPainter( @@ -120,12 +123,7 @@ double _ambientTextLineBox(BuildContext context) { textScaler: textScaler, )..layout(); - _cachedTextStyle = style; - _cachedTextDirection = textDirection; - _cachedTextScaler = textScaler; - _cachedLineBox = painter.preferredLineHeight; - - return _cachedLineBox!; + return _lineBoxCache[key] = painter.preferredLineHeight; } /// The default loading indicator — a sized, indeterminate From 66960d55f59e8bb56439a17cb613a18fd71e16e5 Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Sat, 11 Jul 2026 15:10:58 +0300 Subject: [PATCH 130/176] chore: release 2.1.1 --- CHANGELOG.md | 8 ++++++++ pubspec.yaml | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c3cf825..5eb2c3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # CHANGELOG +## 2.1.1 + +### Fixed + +- **Avoid layout cache thrashing.** Replaced the singleton `TextPainter` cache with a bounded Map. This fixes a performance issue where the cache would thrash (and incorrectly re-measure) if multiple buttons with different text styles were rendered in the same frame. +- **Dead code warning.** Fixed a static analysis warning in `AsyncButtonTheme.lerp` by using `covariant` for the `other` parameter. +- Added comprehensive test coverage for `AsyncButtonController` disposal during an active asynchronous operation and external controller swapping. + ## 2.1.0 ### Added diff --git a/pubspec.yaml b/pubspec.yaml index 0f878b6..b5407d5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: material_async_button description: >- Drop-in async wrappers for Flutter Material buttons. Adds a loading state, with theming via ThemeExtension and external control via a controller. -version: 2.1.0 +version: 2.1.1 homepage: https://mehmetesen.com repository: https://github.com/esenmx/material_async_button issue_tracker: https://github.com/esenmx/material_async_button/issues From 3cee6e95c1a4db44bfbdb00678f2ed9829d4ddc3 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 16 Jul 2026 14:43:46 +0000 Subject: [PATCH 131/176] =?UTF-8?q?=E2=9A=A1=20Optimize=20async=20button?= =?UTF-8?q?=20line=20box=20cache=20with=20LRU=20eviction?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaced the "clear all" eviction strategy in `_lineBoxCache` with an LRU strategy. Since Dart's standard Map preserves insertion order, removing and re-inserting items efficiently maintains recent usage at the end of the map. When the limit of 16 entries is reached, only the oldest item is evicted. --- lib/src/material_async_button_theme.dart | 5 +- test/benchmark_test.dart | 95 ++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 test/benchmark_test.dart diff --git a/lib/src/material_async_button_theme.dart b/lib/src/material_async_button_theme.dart index dc4d8cb..9401e88 100644 --- a/lib/src/material_async_button_theme.dart +++ b/lib/src/material_async_button_theme.dart @@ -108,13 +108,14 @@ double _ambientTextLineBox(BuildContext context) { final textScaler = MediaQuery.textScalerOf(context); final key = (style, textDirection, textScaler); - final cached = _lineBoxCache[key]; + final cached = _lineBoxCache.remove(key); if (cached != null) { + _lineBoxCache[key] = cached; return cached; } if (_lineBoxCache.length >= 16) { - _lineBoxCache.clear(); + _lineBoxCache.remove(_lineBoxCache.keys.first); } final painter = TextPainter( diff --git a/test/benchmark_test.dart b/test/benchmark_test.dart new file mode 100644 index 0000000..1d82f59 --- /dev/null +++ b/test/benchmark_test.dart @@ -0,0 +1,95 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +typedef _LineBoxKey = (TextStyle, TextDirection, TextScaler); +final _lineBoxCache = <_LineBoxKey, double>{}; + +double _ambientTextLineBox(TextStyle style, TextDirection textDirection, TextScaler textScaler) { + final key = (style, textDirection, textScaler); + + final cached = _lineBoxCache[key]; + if (cached != null) { + return cached; + } + + if (_lineBoxCache.length >= 16) { + _lineBoxCache.clear(); + } + + final painter = TextPainter( + text: TextSpan(text: '', style: style), + textDirection: textDirection, + textScaler: textScaler, + )..layout(); + + return _lineBoxCache[key] = painter.preferredLineHeight; +} + +double _ambientTextLineBoxLRU(TextStyle style, TextDirection textDirection, TextScaler textScaler) { + final key = (style, textDirection, textScaler); + + final cached = _lineBoxCache[key]; + if (cached != null) { + // LRU: move to end + _lineBoxCache.remove(key); + _lineBoxCache[key] = cached; + return cached; + } + + if (_lineBoxCache.length >= 16) { + _lineBoxCache.remove(_lineBoxCache.keys.first); + } + + final painter = TextPainter( + text: TextSpan(text: '', style: style), + textDirection: textDirection, + textScaler: textScaler, + )..layout(); + + return _lineBoxCache[key] = painter.preferredLineHeight; +} + +void main() { + testWidgets('Benchmark cache eviction', (WidgetTester tester) async { + final commonStyles = List.generate(15, (i) => TextStyle(fontSize: 10.0 + i)); + final rareStyles = List.generate(10, (i) => TextStyle(fontSize: 30.0 + i)); + final textDirection = TextDirection.ltr; + final textScaler = TextScaler.noScaling; + + // Warmup + for (int i = 0; i < 100; i++) { + _ambientTextLineBox(commonStyles[0], textDirection, textScaler); + } + + _lineBoxCache.clear(); + final watch1 = Stopwatch()..start(); + int misses1 = 0; + for (int iter = 0; iter < 1000; iter++) { + for (final style in commonStyles) { + if (!_lineBoxCache.containsKey((style, textDirection, textScaler))) misses1++; + _ambientTextLineBox(style, textDirection, textScaler); + } + final rare = rareStyles[iter % rareStyles.length]; + if (!_lineBoxCache.containsKey((rare, textDirection, textScaler))) misses1++; + _ambientTextLineBox(rare, textDirection, textScaler); + } + watch1.stop(); + + _lineBoxCache.clear(); + final watch2 = Stopwatch()..start(); + int misses2 = 0; + for (int iter = 0; iter < 1000; iter++) { + for (final style in commonStyles) { + if (!_lineBoxCache.containsKey((style, textDirection, textScaler))) misses2++; + _ambientTextLineBoxLRU(style, textDirection, textScaler); + } + final rare = rareStyles[iter % rareStyles.length]; + if (!_lineBoxCache.containsKey((rare, textDirection, textScaler))) misses2++; + _ambientTextLineBoxLRU(rare, textDirection, textScaler); + } + watch2.stop(); + + print('Current Strategy (Clear): ${watch1.elapsedMilliseconds} ms, misses: $misses1'); + print('LRU Strategy: ${watch2.elapsedMilliseconds} ms, misses: $misses2'); + }); +} From 7b69ea46809576c4c3476c523cfa70dae0197fe9 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 16 Jul 2026 14:45:00 +0000 Subject: [PATCH 132/176] test: add test for AsyncButtonSpinner strokeWidth Adds a missing test to verify that custom `strokeWidth` provided to `AsyncButtonSpinner` correctly propagates to the rendered `CircularProgressIndicator`. --- test/floating_action_async_button_test.dart | 26 ++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/test/floating_action_async_button_test.dart b/test/floating_action_async_button_test.dart index 6666cf0..9abdc42 100644 --- a/test/floating_action_async_button_test.dart +++ b/test/floating_action_async_button_test.dart @@ -122,7 +122,31 @@ void main() { ); }); - group('AsyncButtonSpinner Accessibility', () { + group('AsyncButtonSpinner', () { + testWidgets('custom strokeWidth flows to CircularProgressIndicator', ( + tester, + ) async { + final (:onPressed, :completer) = pendingPress(); + await tester.pumpWidget( + pumpHost( + FloatingActionAsyncButton( + onPressed: onPressed, + loadingBuilder: (context) => const AsyncButtonSpinner( + strokeWidth: 4.5, + ), + child: const Text('go'), + ), + ), + ); + await tapIntoLoading(tester, find.byType(FloatingActionButton)); + final cpi = tester.widget( + find.byType(CircularProgressIndicator), + ); + check(cpi.strokeWidth).equals(4.5); + completer.complete(); + await tester.pumpAndSettle(); + }); + testWidgets( 'spinner exposes semanticsLabel for screen readers by default', (tester) async { From 71693cebcd4eaea5babe7d16bfe1323c41caea46 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 16 Jul 2026 14:47:56 +0000 Subject: [PATCH 133/176] =?UTF-8?q?=E2=9A=A1=20Optimize=20async=20button?= =?UTF-8?q?=20line=20box=20cache=20with=20LRU=20eviction?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaced the "clear all" eviction strategy in `_lineBoxCache` with an LRU strategy. Since Dart's standard Map preserves insertion order, removing and re-inserting items efficiently maintains recent usage at the end of the map. When the limit of 16 entries is reached, only the oldest item is evicted. (Removed benchmark file to fix CI checks) --- test/benchmark_test.dart | 95 ---------------------------------------- 1 file changed, 95 deletions(-) delete mode 100644 test/benchmark_test.dart diff --git a/test/benchmark_test.dart b/test/benchmark_test.dart deleted file mode 100644 index 1d82f59..0000000 --- a/test/benchmark_test.dart +++ /dev/null @@ -1,95 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -typedef _LineBoxKey = (TextStyle, TextDirection, TextScaler); -final _lineBoxCache = <_LineBoxKey, double>{}; - -double _ambientTextLineBox(TextStyle style, TextDirection textDirection, TextScaler textScaler) { - final key = (style, textDirection, textScaler); - - final cached = _lineBoxCache[key]; - if (cached != null) { - return cached; - } - - if (_lineBoxCache.length >= 16) { - _lineBoxCache.clear(); - } - - final painter = TextPainter( - text: TextSpan(text: '', style: style), - textDirection: textDirection, - textScaler: textScaler, - )..layout(); - - return _lineBoxCache[key] = painter.preferredLineHeight; -} - -double _ambientTextLineBoxLRU(TextStyle style, TextDirection textDirection, TextScaler textScaler) { - final key = (style, textDirection, textScaler); - - final cached = _lineBoxCache[key]; - if (cached != null) { - // LRU: move to end - _lineBoxCache.remove(key); - _lineBoxCache[key] = cached; - return cached; - } - - if (_lineBoxCache.length >= 16) { - _lineBoxCache.remove(_lineBoxCache.keys.first); - } - - final painter = TextPainter( - text: TextSpan(text: '', style: style), - textDirection: textDirection, - textScaler: textScaler, - )..layout(); - - return _lineBoxCache[key] = painter.preferredLineHeight; -} - -void main() { - testWidgets('Benchmark cache eviction', (WidgetTester tester) async { - final commonStyles = List.generate(15, (i) => TextStyle(fontSize: 10.0 + i)); - final rareStyles = List.generate(10, (i) => TextStyle(fontSize: 30.0 + i)); - final textDirection = TextDirection.ltr; - final textScaler = TextScaler.noScaling; - - // Warmup - for (int i = 0; i < 100; i++) { - _ambientTextLineBox(commonStyles[0], textDirection, textScaler); - } - - _lineBoxCache.clear(); - final watch1 = Stopwatch()..start(); - int misses1 = 0; - for (int iter = 0; iter < 1000; iter++) { - for (final style in commonStyles) { - if (!_lineBoxCache.containsKey((style, textDirection, textScaler))) misses1++; - _ambientTextLineBox(style, textDirection, textScaler); - } - final rare = rareStyles[iter % rareStyles.length]; - if (!_lineBoxCache.containsKey((rare, textDirection, textScaler))) misses1++; - _ambientTextLineBox(rare, textDirection, textScaler); - } - watch1.stop(); - - _lineBoxCache.clear(); - final watch2 = Stopwatch()..start(); - int misses2 = 0; - for (int iter = 0; iter < 1000; iter++) { - for (final style in commonStyles) { - if (!_lineBoxCache.containsKey((style, textDirection, textScaler))) misses2++; - _ambientTextLineBoxLRU(style, textDirection, textScaler); - } - final rare = rareStyles[iter % rareStyles.length]; - if (!_lineBoxCache.containsKey((rare, textDirection, textScaler))) misses2++; - _ambientTextLineBoxLRU(rare, textDirection, textScaler); - } - watch2.stop(); - - print('Current Strategy (Clear): ${watch1.elapsedMilliseconds} ms, misses: $misses1'); - print('LRU Strategy: ${watch2.elapsedMilliseconds} ms, misses: $misses2'); - }); -} From 820dd26405b7308eddfd43a7ef5a6bbb4622afbb Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Thu, 16 Jul 2026 17:51:45 +0300 Subject: [PATCH 134/176] style: enforce required-param ordering, reformat Re-enable always_put_required_named_parameters_first lint and apply automatic trailing-comma formatting; reflow affected files accordingly. Co-Authored-By: Claude --- analysis_options.yaml | 7 +-- lib/src/async_button.dart | 2 +- lib/src/buttons/async_material_button.dart | 4 +- lib/src/buttons/elevated_async_button.dart | 8 ++-- lib/src/buttons/filled_async_button.dart | 18 +++---- .../buttons/floating_action_async_button.dart | 8 ++-- lib/src/buttons/icon_async_button.dart | 16 +++---- lib/src/buttons/outlined_async_button.dart | 8 ++-- lib/src/buttons/text_async_button.dart | 8 ++-- lib/src/material_async_button_theme.dart | 7 +-- test/_helpers.dart | 4 +- test/async_button_controller_test.dart | 6 +-- test/async_button_test.dart | 47 +++++++++--------- test/floating_action_async_button_test.dart | 48 +++++++++---------- 14 files changed, 88 insertions(+), 103 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index fb902e3..68010b7 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,7 +1,4 @@ include: package:very_good_analysis/analysis_options.yaml -analyzer: - exclude: - - example/** - errors: - always_put_required_named_parameters_first: ignore +formatter: + trailing_commas: automate diff --git a/lib/src/async_button.dart b/lib/src/async_button.dart index faafbe5..c6a1dc7 100644 --- a/lib/src/async_button.dart +++ b/lib/src/async_button.dart @@ -58,7 +58,6 @@ typedef AsyncButtonTransitionBuilder = class AsyncButton extends StatefulWidget { /// Creates an [AsyncButton]. See the class doc for usage. const AsyncButton({ - super.key, required this.child, required this.onPressed, required this.builder, @@ -66,6 +65,7 @@ class AsyncButton extends StatefulWidget { this.controller, this.loadingBuilder, this.transitionBuilder, + super.key, }); /// Idle widget. Replaced by [loadingBuilder] while loading. diff --git a/lib/src/buttons/async_material_button.dart b/lib/src/buttons/async_material_button.dart index 820849f..85b808d 100644 --- a/lib/src/buttons/async_material_button.dart +++ b/lib/src/buttons/async_material_button.dart @@ -12,13 +12,13 @@ abstract class AsyncMaterialButton extends StatelessWidget { /// Subclass-only constructor. Forwards every field to [AsyncButton]. See /// [AsyncButton] for the semantics of each parameter. const AsyncMaterialButton({ - super.key, required this.child, required this.onPressed, this.enabled = true, this.controller, this.loadingBuilder, this.transitionBuilder, + super.key, }); /// See [AsyncButton.child]. @@ -70,7 +70,6 @@ abstract class AsyncStandardMaterialButton extends AsyncMaterialButton { /// Subclass-only constructor. Adds Material parameters common to /// [ElevatedButton]/[FilledButton]/[OutlinedButton]/[TextButton]. const AsyncStandardMaterialButton({ - super.key, required super.child, required super.onPressed, super.enabled, @@ -87,6 +86,7 @@ abstract class AsyncStandardMaterialButton extends AsyncMaterialButton { this.statesController, Widget? icon, IconAlignment? iconAlignment, + super.key, }) : _icon = icon, _iconAlignment = iconAlignment; diff --git a/lib/src/buttons/elevated_async_button.dart b/lib/src/buttons/elevated_async_button.dart index a7c2780..7804df8 100644 --- a/lib/src/buttons/elevated_async_button.dart +++ b/lib/src/buttons/elevated_async_button.dart @@ -5,7 +5,6 @@ part of '../../material_async_button.dart'; class ElevatedAsyncButton extends AsyncStandardMaterialButton { /// Mirrors [ElevatedButton.new]. const ElevatedAsyncButton({ - super.key, required super.onPressed, required super.child, super.onLongPress, @@ -20,13 +19,15 @@ class ElevatedAsyncButton extends AsyncStandardMaterialButton { super.controller, super.loadingBuilder, super.transitionBuilder, + super.key, }); /// Mirrors [ElevatedButton.icon]. The loading widget replaces `label` /// while `icon` stays put. const ElevatedAsyncButton.icon({ - super.key, required super.onPressed, + required super.icon, + required Widget label, super.onLongPress, super.onHover, super.onFocusChange, @@ -39,8 +40,7 @@ class ElevatedAsyncButton extends AsyncStandardMaterialButton { super.controller, super.loadingBuilder, super.transitionBuilder, - required super.icon, - required Widget label, + super.key, }) : super(child: label); @override diff --git a/lib/src/buttons/filled_async_button.dart b/lib/src/buttons/filled_async_button.dart index 5a50422..3be813d 100644 --- a/lib/src/buttons/filled_async_button.dart +++ b/lib/src/buttons/filled_async_button.dart @@ -8,7 +8,6 @@ enum _FilledButtonVariant { primary, tonal } class FilledAsyncButton extends AsyncStandardMaterialButton { /// Mirrors [FilledButton.new]. const FilledAsyncButton({ - super.key, required super.onPressed, required super.child, super.onLongPress, @@ -23,11 +22,12 @@ class FilledAsyncButton extends AsyncStandardMaterialButton { super.controller, super.loadingBuilder, super.transitionBuilder, + super.key, }) : _variant = .primary; /// Mirrors [FilledButton.tonal]. const FilledAsyncButton.tonal({ - super.key, + required super.child, required super.onPressed, super.onLongPress, super.onHover, @@ -41,13 +41,14 @@ class FilledAsyncButton extends AsyncStandardMaterialButton { super.controller, super.loadingBuilder, super.transitionBuilder, - required super.child, + super.key, }) : _variant = .tonal; /// Mirrors [FilledButton.icon]. const FilledAsyncButton.icon({ - super.key, required super.onPressed, + required super.icon, + required Widget label, super.onLongPress, super.onHover, super.onFocusChange, @@ -60,15 +61,15 @@ class FilledAsyncButton extends AsyncStandardMaterialButton { super.controller, super.loadingBuilder, super.transitionBuilder, - required super.icon, - required Widget label, + super.key, }) : _variant = .primary, super(child: label); /// Mirrors [FilledButton.tonalIcon]. const FilledAsyncButton.tonalIcon({ - super.key, required super.onPressed, + required super.icon, + required Widget label, super.onLongPress, super.onHover, super.onFocusChange, @@ -81,8 +82,7 @@ class FilledAsyncButton extends AsyncStandardMaterialButton { super.controller, super.loadingBuilder, super.transitionBuilder, - required super.icon, - required Widget label, + super.key, }) : _variant = .tonal, super(child: label); diff --git a/lib/src/buttons/floating_action_async_button.dart b/lib/src/buttons/floating_action_async_button.dart index 72666ef..ad7efc5 100644 --- a/lib/src/buttons/floating_action_async_button.dart +++ b/lib/src/buttons/floating_action_async_button.dart @@ -13,7 +13,6 @@ const Object _defaultHeroTag = _DefaultHeroTag(); class FloatingActionAsyncButton extends AsyncMaterialButton { /// Mirrors [FloatingActionButton.new]. const FloatingActionAsyncButton({ - super.key, required super.onPressed, Widget? child, super.enabled, @@ -41,6 +40,7 @@ class FloatingActionAsyncButton extends AsyncMaterialButton { this.heroTag = _defaultHeroTag, this.enableFeedback, this.mini = false, + super.key, }) : _variant = .standard, _icon = null, _extendedIconLabelSpacing = null, @@ -50,7 +50,6 @@ class FloatingActionAsyncButton extends AsyncMaterialButton { /// Mirrors [FloatingActionButton.small]. const FloatingActionAsyncButton.small({ - super.key, required super.onPressed, Widget? child, super.enabled, @@ -76,6 +75,7 @@ class FloatingActionAsyncButton extends AsyncMaterialButton { this.materialTapTargetSize, this.heroTag = _defaultHeroTag, this.enableFeedback, + super.key, }) : _variant = .small, mini = false, isExtended = false, @@ -87,7 +87,6 @@ class FloatingActionAsyncButton extends AsyncMaterialButton { /// Mirrors [FloatingActionButton.large]. const FloatingActionAsyncButton.large({ - super.key, required super.onPressed, Widget? child, super.enabled, @@ -113,6 +112,7 @@ class FloatingActionAsyncButton extends AsyncMaterialButton { this.materialTapTargetSize, this.heroTag = _defaultHeroTag, this.enableFeedback, + super.key, }) : _variant = .large, mini = false, isExtended = false, @@ -124,7 +124,6 @@ class FloatingActionAsyncButton extends AsyncMaterialButton { /// Mirrors [FloatingActionButton.extended]. const FloatingActionAsyncButton.extended({ - super.key, required super.onPressed, required Widget label, Widget? icon, @@ -155,6 +154,7 @@ class FloatingActionAsyncButton extends AsyncMaterialButton { double? extendedIconLabelSpacing, EdgeInsetsGeometry? extendedPadding, TextStyle? extendedTextStyle, + super.key, }) : _variant = .extended, mini = false, _icon = icon, diff --git a/lib/src/buttons/icon_async_button.dart b/lib/src/buttons/icon_async_button.dart index 0736621..ab39551 100644 --- a/lib/src/buttons/icon_async_button.dart +++ b/lib/src/buttons/icon_async_button.dart @@ -15,13 +15,12 @@ enum _IconButtonVariant { standard, filled, filledTonal, outlined } class IconAsyncButton extends AsyncMaterialButton { /// Mirrors [IconButton.new]. const IconAsyncButton({ - super.key, required super.onPressed, + required this.icon, super.enabled, super.controller, super.loadingBuilder, super.transitionBuilder, - required this.icon, this.iconSize, this.visualDensity, this.padding, @@ -42,18 +41,18 @@ class IconAsyncButton extends AsyncMaterialButton { this.style, this.isSelected, this.selectedIcon, + super.key, }) : _variant = .standard, super(child: icon); /// Mirrors [IconButton.filled]. const IconAsyncButton.filled({ - super.key, required super.onPressed, + required this.icon, super.enabled, super.controller, super.loadingBuilder, super.transitionBuilder, - required this.icon, this.iconSize, this.visualDensity, this.padding, @@ -74,18 +73,18 @@ class IconAsyncButton extends AsyncMaterialButton { this.style, this.isSelected, this.selectedIcon, + super.key, }) : _variant = .filled, super(child: icon); /// Mirrors [IconButton.filledTonal]. const IconAsyncButton.filledTonal({ - super.key, required super.onPressed, + required this.icon, super.enabled, super.controller, super.loadingBuilder, super.transitionBuilder, - required this.icon, this.iconSize, this.visualDensity, this.padding, @@ -106,18 +105,18 @@ class IconAsyncButton extends AsyncMaterialButton { this.style, this.isSelected, this.selectedIcon, + super.key, }) : _variant = .filledTonal, super(child: icon); /// Mirrors [IconButton.outlined]. const IconAsyncButton.outlined({ - super.key, required super.onPressed, + required this.icon, super.enabled, super.controller, super.loadingBuilder, super.transitionBuilder, - required this.icon, this.iconSize, this.visualDensity, this.padding, @@ -138,6 +137,7 @@ class IconAsyncButton extends AsyncMaterialButton { this.style, this.isSelected, this.selectedIcon, + super.key, }) : _variant = .outlined, super(child: icon); diff --git a/lib/src/buttons/outlined_async_button.dart b/lib/src/buttons/outlined_async_button.dart index e0f33db..df2a53d 100644 --- a/lib/src/buttons/outlined_async_button.dart +++ b/lib/src/buttons/outlined_async_button.dart @@ -4,7 +4,6 @@ part of '../../material_async_button.dart'; class OutlinedAsyncButton extends AsyncStandardMaterialButton { /// Mirrors [OutlinedButton.new]. const OutlinedAsyncButton({ - super.key, required super.onPressed, required super.child, super.onLongPress, @@ -19,12 +18,14 @@ class OutlinedAsyncButton extends AsyncStandardMaterialButton { super.controller, super.loadingBuilder, super.transitionBuilder, + super.key, }); /// Mirrors [OutlinedButton.icon]. const OutlinedAsyncButton.icon({ - super.key, required super.onPressed, + required super.icon, + required Widget label, super.onLongPress, super.onHover, super.onFocusChange, @@ -37,8 +38,7 @@ class OutlinedAsyncButton extends AsyncStandardMaterialButton { super.controller, super.loadingBuilder, super.transitionBuilder, - required super.icon, - required Widget label, + super.key, }) : super(child: label); @override diff --git a/lib/src/buttons/text_async_button.dart b/lib/src/buttons/text_async_button.dart index 1d4b9dd..6869401 100644 --- a/lib/src/buttons/text_async_button.dart +++ b/lib/src/buttons/text_async_button.dart @@ -4,7 +4,6 @@ part of '../../material_async_button.dart'; class TextAsyncButton extends AsyncStandardMaterialButton { /// Mirrors [TextButton.new]. const TextAsyncButton({ - super.key, required super.onPressed, required super.child, super.onLongPress, @@ -19,12 +18,14 @@ class TextAsyncButton extends AsyncStandardMaterialButton { super.controller, super.loadingBuilder, super.transitionBuilder, + super.key, }); /// Mirrors [TextButton.icon]. const TextAsyncButton.icon({ - super.key, required super.onPressed, + required super.icon, + required Widget label, super.onLongPress, super.onHover, super.onFocusChange, @@ -37,8 +38,7 @@ class TextAsyncButton extends AsyncStandardMaterialButton { super.controller, super.loadingBuilder, super.transitionBuilder, - required super.icon, - required Widget label, + super.key, }) : super(child: label); @override diff --git a/lib/src/material_async_button_theme.dart b/lib/src/material_async_button_theme.dart index dc4d8cb..90f155e 100644 --- a/lib/src/material_async_button_theme.dart +++ b/lib/src/material_async_button_theme.dart @@ -63,10 +63,7 @@ class AsyncButtonTheme extends ThemeExtension { } @override - AsyncButtonTheme lerp( - covariant AsyncButtonTheme? other, - double t, - ) { + AsyncButtonTheme lerp(covariant AsyncButtonTheme? other, double t) { if (other == null) { return this; } @@ -144,11 +141,11 @@ class AsyncButtonSpinner extends StatelessWidget { /// font size so the spinner matches the button's label; [semanticsLabel] /// sets the accessibility label read by screen readers. const AsyncButtonSpinner({ - super.key, this.color, this.strokeWidth = 2, this.size, this.semanticsLabel = 'Loading', + super.key, }); /// Indicator colour. When null, inherits the button's foreground (its diff --git a/test/_helpers.dart b/test/_helpers.dart index 8e01462..d97a521 100644 --- a/test/_helpers.dart +++ b/test/_helpers.dart @@ -13,9 +13,7 @@ import 'package:material_async_button/material_async_button.dart'; Widget pumpHost(Widget child, {ThemeData? theme}) { return MaterialApp( theme: theme ?? emptyAsyncButtonTheme, - home: Scaffold( - body: Center(child: child), - ), + home: Scaffold(body: Center(child: child)), ); } diff --git a/test/async_button_controller_test.dart b/test/async_button_controller_test.dart index e02af97..b329c69 100644 --- a/test/async_button_controller_test.dart +++ b/test/async_button_controller_test.dart @@ -113,10 +113,8 @@ void main() { MaterialApp( home: ValueListenableBuilder( valueListenable: c, - builder: (context, isLoading, child) => Text( - isLoading ? 'loading' : 'idle', - textDirection: .ltr, - ), + builder: (context, isLoading, child) => + Text(isLoading ? 'loading' : 'idle', textDirection: .ltr), ), ), ); diff --git a/test/async_button_test.dart b/test/async_button_test.dart index 6afabc2..62131e8 100644 --- a/test/async_button_test.dart +++ b/test/async_button_test.dart @@ -312,34 +312,33 @@ void main() { }, ); - testWidgets( - 'swapping from external to internal controller', - (tester) async { - final externalController = newController(); - final completer = Completer(); - AsyncButton button(AsyncButtonController? c) => AsyncButton( - controller: c, - onPressed: () => completer.future, - builder: textBuilder, - child: const Text('child'), - ); + testWidgets('swapping from external to internal controller', ( + tester, + ) async { + final externalController = newController(); + final completer = Completer(); + AsyncButton button(AsyncButtonController? c) => AsyncButton( + controller: c, + onPressed: () => completer.future, + builder: textBuilder, + child: const Text('child'), + ); - // 1. Pump with external controller - await tester.pumpWidget(pumpHost(button(externalController))); + // 1. Pump with external controller + await tester.pumpWidget(pumpHost(button(externalController))); - // 2. Pump with internal controller (null) - await tester.pumpWidget(pumpHost(button(null))); + // 2. Pump with internal controller (null) + await tester.pumpWidget(pumpHost(button(null))); - // Driving externalController should NOT show loading because it's - // detached. - unawaited(externalController.trigger()); - await tester.pump(); - check(find.byType(CircularProgressIndicator)).findsNone(); + // Driving externalController should NOT show loading because it's + // detached. + unawaited(externalController.trigger()); + await tester.pump(); + check(find.byType(CircularProgressIndicator)).findsNone(); - completer.complete(); - await tester.pumpAndSettle(); - }, - ); + completer.complete(); + await tester.pumpAndSettle(); + }); testWidgets( 'swapping the external controller transfers listening without leak', diff --git a/test/floating_action_async_button_test.dart b/test/floating_action_async_button_test.dart index 6666cf0..25362b4 100644 --- a/test/floating_action_async_button_test.dart +++ b/test/floating_action_async_button_test.dart @@ -95,31 +95,28 @@ void main() { check(find.text('send')).findsOne(); }); - testWidgets( - 'loading spinner is sized to the taller of icon and line box ' - 'when IconTheme is present', - (tester) async { - final (:onPressed, :completer) = pendingPress(); - await tester.pumpWidget( - pumpHost( - IconTheme( - data: const IconThemeData(size: 32), - child: FloatingActionAsyncButton.extended( - onPressed: onPressed, - icon: const Icon(Icons.send), - label: const Text('send'), - ), + testWidgets('loading spinner is sized to the taller of icon and line box ' + 'when IconTheme is present', (tester) async { + final (:onPressed, :completer) = pendingPress(); + await tester.pumpWidget( + pumpHost( + IconTheme( + data: const IconThemeData(size: 32), + child: FloatingActionAsyncButton.extended( + onPressed: onPressed, + icon: const Icon(Icons.send), + label: const Text('send'), ), ), - ); - await tapIntoLoading(tester, find.byType(FloatingActionButton)); - final lineBox = spinnerTextLineBox(tester); - final expected = 32.0 > lineBox ? 32.0 : lineBox; - check(loadingSpinnerSize(tester)).equals(expected); - completer.complete(); - await tester.pump(); - }, - ); + ), + ); + await tapIntoLoading(tester, find.byType(FloatingActionButton)); + final lineBox = spinnerTextLineBox(tester); + final expected = 32.0 > lineBox ? 32.0 : lineBox; + check(loadingSpinnerSize(tester)).equals(expected); + completer.complete(); + await tester.pump(); + }); }); group('AsyncButtonSpinner Accessibility', () { @@ -153,9 +150,8 @@ void main() { pumpHost( FloatingActionAsyncButton( onPressed: onPressed, - loadingBuilder: (context) => const AsyncButtonSpinner( - semanticsLabel: 'Submitting', - ), + loadingBuilder: (context) => + const AsyncButtonSpinner(semanticsLabel: 'Submitting'), child: const Text('go'), ), ), From f40e130228955b610d100a647c16f10d4e296946 Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Fri, 17 Jul 2026 10:47:01 +0300 Subject: [PATCH 135/176] chore: release 2.1.2 Claude-Session: https://claude.ai/code/session_01CQiicqoycPntKDiNW9aRPa --- CHANGELOG.md | 10 ++++++++++ pubspec.yaml | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5eb2c3d..0d18202 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # CHANGELOG +## 2.1.2 + +### Improved + +- **Smarter line-box cache eviction.** The bounded text line-box cache now + evicts only its least-recently-used entry when full, instead of clearing + entirely — cycling through many text styles no longer re-measures every + cached style. +- Added test coverage for `AsyncButtonSpinner.strokeWidth`. + ## 2.1.1 ### Fixed diff --git a/pubspec.yaml b/pubspec.yaml index b5407d5..537015f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: material_async_button description: >- Drop-in async wrappers for Flutter Material buttons. Adds a loading state, with theming via ThemeExtension and external control via a controller. -version: 2.1.1 +version: 2.1.2 homepage: https://mehmetesen.com repository: https://github.com/esenmx/material_async_button issue_tracker: https://github.com/esenmx/material_async_button/issues From dbc447900cca157e48aaf0416425511db1570fb2 Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Fri, 17 Jul 2026 11:00:10 +0300 Subject: [PATCH 136/176] style: format floating_action_async_button_test.dart --- test/floating_action_async_button_test.dart | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/floating_action_async_button_test.dart b/test/floating_action_async_button_test.dart index 96734fb..50feba1 100644 --- a/test/floating_action_async_button_test.dart +++ b/test/floating_action_async_button_test.dart @@ -128,9 +128,8 @@ void main() { pumpHost( FloatingActionAsyncButton( onPressed: onPressed, - loadingBuilder: (context) => const AsyncButtonSpinner( - strokeWidth: 4.5, - ), + loadingBuilder: (context) => + const AsyncButtonSpinner(strokeWidth: 4.5), child: const Text('go'), ), ), From 8c96b0b59c96ddbc0b0c9dbf75b95870fe9f0ee9 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 19 Jul 2026 16:20:02 +0300 Subject: [PATCH 137/176] test: cover AsyncButtonTheme.copyWith() with no arguments Guards the hand-written `?? this.field` fallbacks: a no-arg copyWith on a fully-populated theme must return an equal instance. Closes #8 --- test/material_async_button_theme_test.dart | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/material_async_button_theme_test.dart b/test/material_async_button_theme_test.dart index 522f630..036b383 100644 --- a/test/material_async_button_theme_test.dart +++ b/test/material_async_button_theme_test.dart @@ -23,6 +23,14 @@ void main() { ..has((it) => it.transitionBuilder, 'transitionBuilder').isNull(); }); + test('copyWith with no arguments returns an identical theme', () { + const base = AsyncButtonTheme( + loadingBuilder: _loadingA, + transitionBuilder: _noopTransition, + ); + check(base.copyWith()).equals(base); + }); + test('copyWith overrides only specified fields, preserving the rest', () { const base = AsyncButtonTheme( loadingBuilder: _loadingA, From 0cdca2c155c5fb81b1e64765c3ec2696453f881d Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 19 Jul 2026 16:23:26 +0300 Subject: [PATCH 138/176] test: assert AsyncButtonTheme.empty leaves every field at its default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pins the invariant via the fields directly — comparing `empty` to `const AsyncButtonTheme()` alone is satisfied by const canonicalization and never reaches the field comparison. Closes #7 --- test/material_async_button_theme_test.dart | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/material_async_button_theme_test.dart b/test/material_async_button_theme_test.dart index 036b383..5f2b08a 100644 --- a/test/material_async_button_theme_test.dart +++ b/test/material_async_button_theme_test.dart @@ -114,5 +114,16 @@ void main() { check(a).equals(b); check(a.hashCode).equals(b.hashCode); }); + + test('empty leaves every field at its default', () { + // `empty` is itself `const AsyncButtonTheme()`, so the equality below is + // satisfied by const canonicalization alone. The field checks are what + // actually pin the invariant: `empty` must never grow a set field. + // ignore: use_named_constants + const b = AsyncButtonTheme(); + check(AsyncButtonTheme.empty).equals(b); + check(AsyncButtonTheme.empty.loadingBuilder).isNull(); + check(AsyncButtonTheme.empty.transitionBuilder).isNull(); + }); }); } From 8837cae25847f6e073b09b1b35950f7fa7c6067b Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Fri, 24 Jul 2026 14:12:41 +0300 Subject: [PATCH 139/176] style: formatter-version-neutral source forms Claude-Session: https://claude.ai/code/session_015A1NguqVbfyN4BBe1TRbL6 --- example/lib/main.dart | 5 ++--- lib/src/async_button.dart | 5 +++++ test/async_button_test.dart | 9 +++------ test/filled_async_button_test.dart | 5 ++--- test/floating_action_async_button_test.dart | 5 ++--- test/material_async_button_theme_test.dart | 12 +++--------- 6 files changed, 17 insertions(+), 24 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index a3844f9..0aac147 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -52,9 +52,8 @@ class _HomePageState extends State { await _simulateWork(fail: fail); } on Exception catch (error) { if (context.mounted) { - ScaffoldMessenger.of( - context, - ).showSnackBar(SnackBar(content: Text('Failed: $error'))); + final snackBar = SnackBar(content: Text('Failed: $error')); + ScaffoldMessenger.of(context).showSnackBar(snackBar); } } } diff --git a/lib/src/async_button.dart b/lib/src/async_button.dart index c6a1dc7..53ae8b2 100644 --- a/lib/src/async_button.dart +++ b/lib/src/async_button.dart @@ -7,6 +7,10 @@ part of '../material_async_button.dart'; /// button: while loading, `callback` stays non-null so the button keeps its /// enabled look (the spinner is the state indicator). Taps that can't run are /// silently swallowed by the controller, so they never double-submit. +// Formatter generations disagree on splitting a generalized typedef header +// (`=` break vs `= Widget Function(`); pin one form so local dart format, +// CI, and pana's package-config-free dart_style all leave it untouched. +// dart format off typedef AsyncButtonWidgetBuilder = Widget Function( BuildContext context, @@ -33,6 +37,7 @@ typedef AsyncButtonTransitionBuilder = // ignore: avoid_positional_boolean_parameters bool isLoading, ); +// dart format on /// Low-level async-loading shell for arbitrary buttons. /// diff --git a/test/async_button_test.dart b/test/async_button_test.dart index 62131e8..486fe5e 100644 --- a/test/async_button_test.dart +++ b/test/async_button_test.dart @@ -242,18 +242,15 @@ void main() { ), ), ); + final textButton = find.byType(TextButton); // Idle: interactive. - check( - tester.widget(find.byType(TextButton)).onPressed, - ).isNotNull(); + check(tester.widget(textButton).onPressed).isNotNull(); unawaited(controller.trigger()); await tester.pump(); // Loading: spinner shows and the button keeps its enabled look. check(find.byType(CircularProgressIndicator)).findsOne(); - check( - tester.widget(find.byType(TextButton)).onPressed, - ).isNotNull(); + check(tester.widget(textButton).onPressed).isNotNull(); completer.complete(); await tester.pumpAndSettle(); diff --git a/test/filled_async_button_test.dart b/test/filled_async_button_test.dart index 65a0f3a..071c597 100644 --- a/test/filled_async_button_test.dart +++ b/test/filled_async_button_test.dart @@ -97,9 +97,8 @@ void main() { ), ); await tapIntoLoading(tester, find.byType(FilledButton)); - check( - spinnerColor(tester), - ).equals(theme.colorScheme.onSecondaryContainer); + final expected = theme.colorScheme.onSecondaryContainer; + check(spinnerColor(tester)).equals(expected); completer.complete(); await tester.pumpAndSettle(); }); diff --git a/test/floating_action_async_button_test.dart b/test/floating_action_async_button_test.dart index 50feba1..9f280d1 100644 --- a/test/floating_action_async_button_test.dart +++ b/test/floating_action_async_button_test.dart @@ -59,9 +59,8 @@ void main() { ), ); await tapIntoLoading(tester, find.byType(FloatingActionButton)); - check( - spinnerColor(tester), - ).equals(theme.colorScheme.onPrimaryContainer); + final expected = theme.colorScheme.onPrimaryContainer; + check(spinnerColor(tester)).equals(expected); completer.complete(); await tester.pumpAndSettle(); }, diff --git a/test/material_async_button_theme_test.dart b/test/material_async_button_theme_test.dart index 5f2b08a..7199b4a 100644 --- a/test/material_async_button_theme_test.dart +++ b/test/material_async_button_theme_test.dart @@ -48,19 +48,13 @@ void main() { test('lerp snaps fields at the halfway point', () { const from = AsyncButtonTheme(loadingBuilder: _loadingA); const to = AsyncButtonTheme(loadingBuilder: _loadingB); - check( - from.lerp(to, 0.4), - ).has((it) => it.loadingBuilder, 'loadingBuilder').equals(_loadingA); - check( - from.lerp(to, 0.6), - ).has((it) => it.loadingBuilder, 'loadingBuilder').equals(_loadingB); + check(from.lerp(to, 0.4).loadingBuilder).equals(_loadingA); + check(from.lerp(to, 0.6).loadingBuilder).equals(_loadingB); }); test('lerp with non-AsyncButtonTheme returns self', () { const a = AsyncButtonTheme(loadingBuilder: _loadingA); - check( - a.lerp(null, 0.5), - ).has((it) => it.loadingBuilder, 'loadingBuilder').equals(_loadingA); + check(a.lerp(null, 0.5).loadingBuilder).equals(_loadingA); }); testWidgets('of(context) returns the registered extension', (tester) async { From f0c445130580f55e12ffd4b08bff9c502d506da6 Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Wed, 5 Aug 2026 14:54:07 +0300 Subject: [PATCH 140/176] chore(meta): refresh metadata, ship skill from skills/ Description names all six wrappers including FloatingActionAsyncButton (2.1.0) and the concrete AsyncButtonTheme/AsyncButtonController types; topic `form`, which has no backing API in lib/, becomes `widget`. Skill moves from tool/claude/ to skills/, so it now ships in the published archive; the dead tool/ entry drops out of .pubignore. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01RwBGA5P63m3HkZwH41mjS2 --- .pubignore | 1 - README.md | 2 +- pubspec.yaml | 8 +++----- .../flutter-material-async-button/SKILL.md | 7 +------ 4 files changed, 5 insertions(+), 13 deletions(-) rename {tool/claude => skills}/flutter-material-async-button/SKILL.md (84%) diff --git a/.pubignore b/.pubignore index 2c3be47..a27ad00 100644 --- a/.pubignore +++ b/.pubignore @@ -2,4 +2,3 @@ .vscode/ build/ coverage/ -tool/ diff --git a/README.md b/README.md index d69780a..3a2e9fa 100644 --- a/README.md +++ b/README.md @@ -197,7 +197,7 @@ its `color` / `strokeWidth` / `size` and return it from `loadingBuilder`. A Claude Code skill that teaches Claude to use this package idiomatically lives in the GitHub repo at -[`tool/claude/flutter-material-async-button/SKILL.md`](https://github.com/esenmx/material_async_button/blob/main/tool/claude/flutter-material-async-button/SKILL.md). +[`skills/flutter-material-async-button/SKILL.md`](https://github.com/esenmx/material_async_button/blob/main/skills/flutter-material-async-button/SKILL.md). Copy it into `.claude/skills/` in your project. ## License diff --git a/pubspec.yaml b/pubspec.yaml index 537015f..3cda2ad 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,5 @@ name: material_async_button -description: >- - Drop-in async wrappers for Flutter Material buttons. Adds a loading state, - with theming via ThemeExtension and external control via a controller. +description: Drop-in loading state for Elevated, Filled, Outlined, Text, Icon and FloatingAction Material buttons — spinner while onPressed runs, AsyncButtonTheme, AsyncButtonController. version: 2.1.2 homepage: https://mehmetesen.com repository: https://github.com/esenmx/material_async_button @@ -10,10 +8,10 @@ documentation: https://pub.dev/documentation/material_async_button/latest/ topics: - button + - loading - async - material - - loading - - form + - widget environment: sdk: ^3.10.0 diff --git a/tool/claude/flutter-material-async-button/SKILL.md b/skills/flutter-material-async-button/SKILL.md similarity index 84% rename from tool/claude/flutter-material-async-button/SKILL.md rename to skills/flutter-material-async-button/SKILL.md index f03eb78..1cc23a1 100644 --- a/tool/claude/flutter-material-async-button/SKILL.md +++ b/skills/flutter-material-async-button/SKILL.md @@ -1,11 +1,6 @@ --- name: flutter-material-async-button -description: Use this skill when working in a Flutter project that depends on - the material_async_button package, or when the user wants to add a loading - state to a Material button (ElevatedButton, FilledButton, OutlinedButton, - TextButton, IconButton, FloatingActionButton) whose onPressed is async. Triggers - on "async button", "loading button", "floating action async button", or any handler - the user writes as `() async {}` and passes to a Material button. +description: Add a loading state to a Material button (ElevatedButton, FilledButton, OutlinedButton, TextButton, IconButton, FloatingActionButton) whose onPressed is async, via the material_async_button package. Triggers on "async button", "loading button", or any `() async {}` handler passed to a Material button. --- # material_async_button From 0cf02da22db8da57a3849755f51d0b64a65a89e3 Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Sun, 23 Aug 2026 16:51:38 +0300 Subject: [PATCH 141/176] test: cover AsyncButtonTheme.lerp t=0.5 boundary and transitionBuilder snap AsyncButtonTheme.lerp snaps non-lerpable fields with `t < 0.5`, so t=0.5 must already take `other`. The existing 'lerp snaps fields at the halfway point' test only probed loadingBuilder at 0.4/0.6; it now also asserts transitionBuilder and the exact 0.5 boundary. Mutating lerp to `t <= 0.5` or dropping the transitionBuilder snap now fails the test (both mutations passed the base test). Review changes: replaced the three byte-identical assertion blocks with one record-pattern loop over (t, expected), using `because: 't=$t'` so failures name the t value; per-field `has(...)` checks kept so the test stays independent of `operator==`. Review changes: header comment on `_noopTransition`/`_otherTransition` restores the "no-op" descriptor and ties the pair to the loading-builder rationale (wrapped for the 80-column lint). Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- test/material_async_button_theme_test.dart | 32 ++++++++++++++++++---- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/test/material_async_button_theme_test.dart b/test/material_async_button_theme_test.dart index 7199b4a..91d246a 100644 --- a/test/material_async_button_theme_test.dart +++ b/test/material_async_button_theme_test.dart @@ -3,11 +3,16 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:material_async_button/material_async_button.dart'; -// A no-op transition builder for theme-field tests. +// Two distinct no-op transition builders — as with the loading builders +// below, their separate references are the point. Widget _noopTransition(BuildContext context, Widget child, bool isLoading) { return child; } +Widget _otherTransition(BuildContext context, Widget child, bool isLoading) { + return child; +} + // Two distinct loading builders — reused across tests that assert field // identity (copyWith / lerp / equality). Their separate references are the // point, so they live at top level rather than being redeclared per test. @@ -46,10 +51,27 @@ void main() { }); test('lerp snaps fields at the halfway point', () { - const from = AsyncButtonTheme(loadingBuilder: _loadingA); - const to = AsyncButtonTheme(loadingBuilder: _loadingB); - check(from.lerp(to, 0.4).loadingBuilder).equals(_loadingA); - check(from.lerp(to, 0.6).loadingBuilder).equals(_loadingB); + const from = AsyncButtonTheme( + loadingBuilder: _loadingA, + transitionBuilder: _noopTransition, + ); + const to = AsyncButtonTheme( + loadingBuilder: _loadingB, + transitionBuilder: _otherTransition, + ); + + // `t < 0.5` keeps `this`; the boundary itself already takes `other`. + for (final (t, expected) in [(0.4, from), (0.5, to), (0.6, to)]) { + check(from.lerp(to, t), because: 't=$t') + ..has( + (it) => it.loadingBuilder, + 'loadingBuilder', + ).equals(expected.loadingBuilder) + ..has( + (it) => it.transitionBuilder, + 'transitionBuilder', + ).equals(expected.transitionBuilder); + } }); test('lerp with non-AsyncButtonTheme returns self', () { From ed175810a89296c02df6400ba972f0080e7e0ef9 Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Sun, 23 Aug 2026 16:56:09 +0300 Subject: [PATCH 142/176] test: cover line-box cache 16-entry bound and LRU promotion The line-box cache in lib/src/material_async_button_theme.dart had no test coverage even though its 16-entry bound and LRU eviction shipped as user-facing fixes twice (2.1.1, 2.1.2). This adds a @visibleForTesting debugLineBoxCache getter and one widget test that pumps AsyncButtonSpinner under 16 then 17 distinct font sizes, asserting the capacity bound, oldest-first eviction, and hit promotion to the MRU end. Verified as a real oracle: no-promotion, no-eviction, evict-newest, and capacity off-by-one mutants all fail. Review changes: type the getter as Map<(TextStyle, TextDirection, TextScaler), double> with precedent-matching dartdoc instead of Map. Review changes: move the test into its own 'AsyncButtonSpinner line box cache' group, reset the cache via addTearDown, replace the tautological containsKey check with fontSize assertions, and assert promotion as keys.last == secondKey. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- lib/src/material_async_button_theme.dart | 6 +++ test/material_async_button_theme_test.dart | 44 ++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/lib/src/material_async_button_theme.dart b/lib/src/material_async_button_theme.dart index ca6f629..7c95596 100644 --- a/lib/src/material_async_button_theme.dart +++ b/lib/src/material_async_button_theme.dart @@ -94,6 +94,12 @@ class AsyncButtonTheme extends ThemeExtension { typedef _LineBoxKey = (TextStyle, TextDirection, TextScaler); final _lineBoxCache = <_LineBoxKey, double>{}; +/// The bounded line-box cache. Exposed only so tests can assert its capacity +/// and LRU eviction. Not part of the consumer-facing API. +@visibleForTesting +Map<(TextStyle, TextDirection, TextScaler), double> get debugLineBoxCache => + _lineBoxCache; + /// The single-line height of the ambient label style at [context] — the /// vertical extent a one-line [Text] occupies here. The default spinner sizes /// to this (the idle content's *line box*, which is taller than the raw diff --git a/test/material_async_button_theme_test.dart b/test/material_async_button_theme_test.dart index 91d246a..7e31e94 100644 --- a/test/material_async_button_theme_test.dart +++ b/test/material_async_button_theme_test.dart @@ -142,4 +142,48 @@ void main() { check(AsyncButtonTheme.empty.transitionBuilder).isNull(); }); }); + + group('AsyncButtonSpinner line box cache', () { + testWidgets( + 'caps at 16 entries, evicts the least recently used, promotes hits', + (tester) async { + debugLineBoxCache.clear(); + addTearDown(debugLineBoxCache.clear); + + Future pumpSpinnerWithFontSize(double fontSize) async { + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: DefaultTextStyle( + style: TextStyle(fontSize: fontSize), + child: const AsyncButtonSpinner(), + ), + ), + ), + ); + } + + // Fill the cache to its capacity of 16 with distinct styles. + for (var i = 1; i <= 16; i++) { + await pumpSpinnerWithFontSize(i.toDouble()); + } + check(debugLineBoxCache.length).equals(16); + final firstKey = debugLineBoxCache.keys.first; + check(firstKey.$1.fontSize).equals(1); + + // A 17th style evicts the oldest entry. + await pumpSpinnerWithFontSize(17); + check(debugLineBoxCache.length).equals(16); + check(debugLineBoxCache.containsKey(firstKey)).isFalse(); + + // A hit on the now-oldest entry moves it to the MRU end without + // growing or evicting. + final secondKey = debugLineBoxCache.keys.first; + check(secondKey.$1.fontSize).equals(2); + await pumpSpinnerWithFontSize(2); + check(debugLineBoxCache.length).equals(16); + check(debugLineBoxCache.keys.last).equals(secondKey); + }, + ); + }); } From 5efff50828ee6cc70af24475efc6ca875d16ea2f Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Sun, 23 Aug 2026 17:00:37 +0300 Subject: [PATCH 143/176] test: assert AsyncButton disposes only its own controller on unmount and swap Deleting the internal-controller dispose in _AsyncButtonState.dispose() survived the whole base suite; this adds the first oracle for it, plus explicit no-dispose guarantees for caller-owned controllers on unmount and swap. The existing test 'swapping from internal to external controller disposes internal and uses new' never asserted disposal on base and now does, so its name is true. Review changes: added mountedController(tester) and isDisposed()/isNotDisposed() checks (ChangeNotifier.debugAssertNotDisposed) to test/_helpers.dart as the single dispose-probe mechanism. Review changes: the existing internal->external swap test now captures the internal controller and asserts isDisposed(), killing the didUpdateWidget dispose-branch mutant. Review changes: PR tests 1 and 2 use the helpers and newController() instead of a dynamic cast, an addListener probe and a _SpyController subclass. Review changes: dropped the redundant external a->b swap test and _SpyController; the existing 'transfers listening without leak' test asserts isNotDisposed() on both controllers instead. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- test/_helpers.dart | 20 ++++++++++++++++++ test/async_button_test.dart | 42 +++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/test/_helpers.dart b/test/_helpers.dart index d97a521..ab19a8b 100644 --- a/test/_helpers.dart +++ b/test/_helpers.dart @@ -65,6 +65,14 @@ AsyncButtonController newController() { return c; } +/// The controller the mounted [AsyncButton] is driving. Reaches into the +/// private state via `dynamic` — the only handle on an internally owned +/// controller. +AsyncButtonController mountedController(WidgetTester tester) { + return (tester.state(find.byType(AsyncButton)) as dynamic).controller + as AsyncButtonController; +} + /// Controller pre-attached with `onPressed`, for driving it detached from any /// widget. Auto-disposes. AsyncButtonController attachedController({AsyncCallback? onPressed}) { @@ -176,4 +184,16 @@ extension FinderChecks on Subject { extension AsyncButtonControllerChecks on Subject { void isIdle() => has((c) => c.value, 'isLoading').isFalse(); void isLoading() => has((c) => c.value, 'isLoading').isTrue(); + + void isDisposed() => has( + (c) => + () => ChangeNotifier.debugAssertNotDisposed(c), + 'dispose guard', + ).throws(); + + void isNotDisposed() => has( + (c) => + () => ChangeNotifier.debugAssertNotDisposed(c), + 'dispose guard', + ).returnsNormally(); } diff --git a/test/async_button_test.dart b/test/async_button_test.dart index 486fe5e..0d158f2 100644 --- a/test/async_button_test.dart +++ b/test/async_button_test.dart @@ -294,9 +294,11 @@ void main() { // 1. Pump with internal controller (null) await tester.pumpWidget(pumpHost(button(null))); + final internalController = mountedController(tester); // 2. Pump with external controller await tester.pumpWidget(pumpHost(button(externalController))); + check(internalController).isDisposed(); // The widget now listens to externalController: driving it must show // loading. @@ -364,8 +366,48 @@ void main() { aCompleter.complete(); bCompleter.complete(); await tester.pumpAndSettle(); + // Neither caller-owned controller was disposed by the swap. + check(a).isNotDisposed(); + check(b).isNotDisposed(); }, ); + + testWidgets('disposes internal controller when unmounted', (tester) async { + await tester.pumpWidget( + pumpHost( + AsyncButton( + onPressed: () async {}, + builder: textBuilder, + child: const Text('label'), + ), + ), + ); + final internalController = mountedController(tester); + + await tester.pumpWidget(pumpHost(const SizedBox())); + + check(internalController).isDisposed(); + }); + + testWidgets('does not dispose external controller when unmounted', ( + tester, + ) async { + final controller = newController(); + await tester.pumpWidget( + pumpHost( + AsyncButton( + controller: controller, + onPressed: () async {}, + builder: textBuilder, + child: const Text('label'), + ), + ), + ); + + await tester.pumpWidget(pumpHost(const SizedBox())); + + check(controller).isNotDisposed(); + }); }); group('AsyncButton transition builder', () { From 4c2cc49ccd33399c77c076c65553624e0d801636 Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Sun, 23 Aug 2026 19:05:29 +0300 Subject: [PATCH 144/176] refactor: collapse IconAsyncButton variant switch into constructor tear-off The four switch arms in IconAsyncButton.build differed only in the IconButton constructor name while forwarding an identical 22-argument list. Collapse them into a private _buildIconButton that selects a constructor tear-off and makes one call. All four IconButton constructors share a byte-identical parameter list on stable, beta and master, so the switch infers a single function type and any future SDK drift is a compile error rather than a runtime slip. Render-tree oracles on base and head showed zero behavioural diff; 98 lines removed, forwarding now lives in one place. Review changes: replace the variants smoke test with one that pins each IconAsyncButton variant to its IconButton flavor (Material background and outline side), so a swapped tear-off arm fails the suite instead of passing silently. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- lib/src/buttons/icon_async_button.dart | 135 +++++++------------------ test/icon_async_button_test.dart | 60 ++++++++--- 2 files changed, 81 insertions(+), 114 deletions(-) diff --git a/lib/src/buttons/icon_async_button.dart b/lib/src/buttons/icon_async_button.dart index ab39551..c85b8d2 100644 --- a/lib/src/buttons/icon_async_button.dart +++ b/lib/src/buttons/icon_async_button.dart @@ -208,6 +208,42 @@ class IconAsyncButton extends AsyncMaterialButton { final _IconButtonVariant _variant; + Widget _buildIconButton({ + required VoidCallback? onPressed, + required Widget icon, + }) { + final builder = switch (_variant) { + .standard => IconButton.new, + .filled => IconButton.filled, + .filledTonal => IconButton.filledTonal, + .outlined => IconButton.outlined, + }; + return builder( + onPressed: onPressed, + icon: icon, + iconSize: iconSize, + visualDensity: visualDensity, + padding: padding, + alignment: alignment, + splashRadius: splashRadius, + color: color, + focusColor: focusColor, + hoverColor: hoverColor, + highlightColor: highlightColor, + splashColor: splashColor, + disabledColor: disabledColor, + mouseCursor: mouseCursor, + focusNode: focusNode, + autofocus: autofocus, + tooltip: tooltip, + enableFeedback: enableFeedback, + constraints: constraints, + style: style, + isSelected: isSelected, + selectedIcon: selectedIcon, + ); + } + @override Widget build(BuildContext context) { return AsyncButton( @@ -217,104 +253,7 @@ class IconAsyncButton extends AsyncMaterialButton { loadingBuilder: _resolveLoadingBuilder(context, .iconSize), transitionBuilder: transitionBuilder, builder: (context, child, callback, isLoading) { - return switch (_variant) { - .standard => IconButton( - onPressed: callback, - icon: child, - iconSize: iconSize, - visualDensity: visualDensity, - padding: padding, - alignment: alignment, - splashRadius: splashRadius, - color: color, - focusColor: focusColor, - hoverColor: hoverColor, - highlightColor: highlightColor, - splashColor: splashColor, - disabledColor: disabledColor, - mouseCursor: mouseCursor, - focusNode: focusNode, - autofocus: autofocus, - tooltip: tooltip, - enableFeedback: enableFeedback, - constraints: constraints, - style: style, - isSelected: isSelected, - selectedIcon: selectedIcon, - ), - .filled => IconButton.filled( - onPressed: callback, - icon: child, - iconSize: iconSize, - visualDensity: visualDensity, - padding: padding, - alignment: alignment, - splashRadius: splashRadius, - color: color, - focusColor: focusColor, - hoverColor: hoverColor, - highlightColor: highlightColor, - splashColor: splashColor, - disabledColor: disabledColor, - mouseCursor: mouseCursor, - focusNode: focusNode, - autofocus: autofocus, - tooltip: tooltip, - enableFeedback: enableFeedback, - constraints: constraints, - style: style, - isSelected: isSelected, - selectedIcon: selectedIcon, - ), - .filledTonal => IconButton.filledTonal( - onPressed: callback, - icon: child, - iconSize: iconSize, - visualDensity: visualDensity, - padding: padding, - alignment: alignment, - splashRadius: splashRadius, - color: color, - focusColor: focusColor, - hoverColor: hoverColor, - highlightColor: highlightColor, - splashColor: splashColor, - disabledColor: disabledColor, - mouseCursor: mouseCursor, - focusNode: focusNode, - autofocus: autofocus, - tooltip: tooltip, - enableFeedback: enableFeedback, - constraints: constraints, - style: style, - isSelected: isSelected, - selectedIcon: selectedIcon, - ), - .outlined => IconButton.outlined( - onPressed: callback, - icon: child, - iconSize: iconSize, - visualDensity: visualDensity, - padding: padding, - alignment: alignment, - splashRadius: splashRadius, - color: color, - focusColor: focusColor, - hoverColor: hoverColor, - highlightColor: highlightColor, - splashColor: splashColor, - disabledColor: disabledColor, - mouseCursor: mouseCursor, - focusNode: focusNode, - autofocus: autofocus, - tooltip: tooltip, - enableFeedback: enableFeedback, - constraints: constraints, - style: style, - isSelected: isSelected, - selectedIcon: selectedIcon, - ), - }; + return _buildIconButton(onPressed: callback, icon: child); }, child: icon, ); diff --git a/test/icon_async_button_test.dart b/test/icon_async_button_test.dart index 3a68822..46909b3 100644 --- a/test/icon_async_button_test.dart +++ b/test/icon_async_button_test.dart @@ -20,26 +20,54 @@ void main() { check(find.byType(IconButton)).findsOne(); }); - testWidgets('filled, filledTonal, outlined variants all render', ( - tester, - ) async { - final ctors = [ - () => IconAsyncButton.filled( - onPressed: () async {}, - icon: const Icon(Icons.add), + testWidgets('each variant renders its IconButton flavor', (tester) async { + final colors = emptyAsyncButtonTheme.colorScheme; + // (button, expected Material background, expects an outline side) + final cases = <(Widget, Color, bool)>[ + ( + IconAsyncButton(onPressed: () async {}, icon: const Icon(Icons.add)), + Colors.transparent, + false, + ), + ( + IconAsyncButton.filled( + onPressed: () async {}, + icon: const Icon(Icons.add), + ), + colors.primary, + false, ), - () => IconAsyncButton.filledTonal( - onPressed: () async {}, - icon: const Icon(Icons.add), + ( + IconAsyncButton.filledTonal( + onPressed: () async {}, + icon: const Icon(Icons.add), + ), + colors.secondaryContainer, + false, ), - () => IconAsyncButton.outlined( - onPressed: () async {}, - icon: const Icon(Icons.add), + ( + IconAsyncButton.outlined( + onPressed: () async {}, + icon: const Icon(Icons.add), + ), + Colors.transparent, + true, ), ]; - for (final ctor in ctors) { - await tester.pumpWidget(pumpHost(ctor())); - check(find.byType(IconButton)).findsOne(); + for (final (button, background, outlined) in cases) { + await tester.pumpWidget(pumpHost(button)); + final material = tester.widget( + find.descendant( + of: find.byType(IconButton), + matching: find.byType(Material), + ), + ); + check(material.color, because: '$button').equals(background); + final side = (material.shape as OutlinedBorder?)?.side; + check( + side != null && side != BorderSide.none, + because: '$button', + ).equals(outlined); } }); From 5575affeecf35a8cec6352601cb3f3120ed7386f Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Sun, 23 Aug 2026 19:10:18 +0300 Subject: [PATCH 145/176] refactor: split FloatingActionAsyncButton build into variant helpers FloatingActionAsyncButton.build was a 117-line method with the four variant switch arms inlined. Move each arm into a helper (_buildStandard, _buildSmallOrLarge, _buildExtended) dispatched from a short switch in the AsyncButton builder closure, so build is 13 lines and the file is a net reduction (354 -> 353 lines). Per-arm forwarded arguments are unchanged; behaviour is identical. Review changes: dropped the _resolvedHeroTag getter (provably an identity function) and pass heroTag directly; the _defaultHeroTag sentinel stays since it is load-bearing for Flutter's duplicate-Hero assertion. Review changes: removed the pass-through _buildButton method and put the variant switch directly in the builder closure. Review changes: merged the byte-identical _buildSmall/_buildLarge into _buildSmallOrLarge, selecting FloatingActionButton.small/.large by constructor tear-off (same technique as IconAsyncButton). Review changes: the small/large test now asserts rendered sizes (48x48 padded small, 96x96 large) so a swapped variant-to-constructor mapping fails. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- .../buttons/floating_action_async_button.dart | 207 +++++++++--------- test/floating_action_async_button_test.dart | 7 +- 2 files changed, 109 insertions(+), 105 deletions(-) diff --git a/lib/src/buttons/floating_action_async_button.dart b/lib/src/buttons/floating_action_async_button.dart index ad7efc5..bbf26d3 100644 --- a/lib/src/buttons/floating_action_async_button.dart +++ b/lib/src/buttons/floating_action_async_button.dart @@ -244,111 +244,110 @@ class FloatingActionAsyncButton extends AsyncMaterialButton { _variant == .extended ? .max : .iconSize, ), transitionBuilder: transitionBuilder, - builder: (context, animatedChild, callback, isLoading) { - final hasHeroTag = heroTag != _defaultHeroTag; - return switch (_variant) { - .standard => FloatingActionButton( - onPressed: callback, - tooltip: tooltip, - foregroundColor: foregroundColor, - backgroundColor: backgroundColor, - focusColor: focusColor, - hoverColor: hoverColor, - splashColor: splashColor, - elevation: elevation, - focusElevation: focusElevation, - hoverElevation: hoverElevation, - highlightElevation: highlightElevation, - disabledElevation: disabledElevation, - mouseCursor: mouseCursor, - shape: shape, - clipBehavior: clipBehavior, - focusNode: focusNode, - autofocus: autofocus, - materialTapTargetSize: materialTapTargetSize, - isExtended: isExtended, - heroTag: hasHeroTag ? heroTag : const _DefaultHeroTag(), - enableFeedback: enableFeedback, - mini: mini, - child: animatedChild, - ), - .small => FloatingActionButton.small( - onPressed: callback, - tooltip: tooltip, - foregroundColor: foregroundColor, - backgroundColor: backgroundColor, - focusColor: focusColor, - hoverColor: hoverColor, - splashColor: splashColor, - elevation: elevation, - focusElevation: focusElevation, - hoverElevation: hoverElevation, - highlightElevation: highlightElevation, - disabledElevation: disabledElevation, - mouseCursor: mouseCursor, - shape: shape, - clipBehavior: clipBehavior, - focusNode: focusNode, - autofocus: autofocus, - materialTapTargetSize: materialTapTargetSize, - heroTag: hasHeroTag ? heroTag : const _DefaultHeroTag(), - enableFeedback: enableFeedback, - child: animatedChild, - ), - .large => FloatingActionButton.large( - onPressed: callback, - tooltip: tooltip, - foregroundColor: foregroundColor, - backgroundColor: backgroundColor, - focusColor: focusColor, - hoverColor: hoverColor, - splashColor: splashColor, - elevation: elevation, - focusElevation: focusElevation, - hoverElevation: hoverElevation, - highlightElevation: highlightElevation, - disabledElevation: disabledElevation, - mouseCursor: mouseCursor, - shape: shape, - clipBehavior: clipBehavior, - focusNode: focusNode, - autofocus: autofocus, - materialTapTargetSize: materialTapTargetSize, - heroTag: hasHeroTag ? heroTag : const _DefaultHeroTag(), - enableFeedback: enableFeedback, - child: animatedChild, - ), - .extended => FloatingActionButton.extended( - onPressed: callback, - label: animatedChild, - icon: isLoading ? null : _icon, - tooltip: tooltip, - foregroundColor: foregroundColor, - backgroundColor: backgroundColor, - focusColor: focusColor, - hoverColor: hoverColor, - splashColor: splashColor, - elevation: elevation, - focusElevation: focusElevation, - hoverElevation: hoverElevation, - highlightElevation: highlightElevation, - disabledElevation: disabledElevation, - mouseCursor: mouseCursor, - shape: shape, - clipBehavior: clipBehavior, - focusNode: focusNode, - autofocus: autofocus, - materialTapTargetSize: materialTapTargetSize, - isExtended: isExtended, - heroTag: hasHeroTag ? heroTag : const _DefaultHeroTag(), - enableFeedback: enableFeedback, - extendedIconLabelSpacing: _extendedIconLabelSpacing, - extendedPadding: _extendedPadding, - extendedTextStyle: _extendedTextStyle, - ), - }; - }, + builder: (context, animatedChild, callback, isLoading) => + switch (_variant) { + .standard => _buildStandard(callback, animatedChild), + .small || .large => _buildSmallOrLarge(callback, animatedChild), + .extended => _buildExtended( + callback, + animatedChild, + isLoading: isLoading, + ), + }, child: child, ); } + + Widget _buildStandard(VoidCallback? callback, Widget animatedChild) { + return FloatingActionButton( + onPressed: callback, + tooltip: tooltip, + foregroundColor: foregroundColor, + backgroundColor: backgroundColor, + focusColor: focusColor, + hoverColor: hoverColor, + splashColor: splashColor, + elevation: elevation, + focusElevation: focusElevation, + hoverElevation: hoverElevation, + highlightElevation: highlightElevation, + disabledElevation: disabledElevation, + mouseCursor: mouseCursor, + shape: shape, + clipBehavior: clipBehavior, + focusNode: focusNode, + autofocus: autofocus, + materialTapTargetSize: materialTapTargetSize, + isExtended: isExtended, + heroTag: heroTag, + enableFeedback: enableFeedback, + mini: mini, + child: animatedChild, + ); + } + + Widget _buildSmallOrLarge(VoidCallback? callback, Widget animatedChild) { + final constructor = switch (_variant) { + .small => FloatingActionButton.small, + _ => FloatingActionButton.large, + }; + return constructor( + onPressed: callback, + tooltip: tooltip, + foregroundColor: foregroundColor, + backgroundColor: backgroundColor, + focusColor: focusColor, + hoverColor: hoverColor, + splashColor: splashColor, + elevation: elevation, + focusElevation: focusElevation, + hoverElevation: hoverElevation, + highlightElevation: highlightElevation, + disabledElevation: disabledElevation, + mouseCursor: mouseCursor, + shape: shape, + clipBehavior: clipBehavior, + focusNode: focusNode, + autofocus: autofocus, + materialTapTargetSize: materialTapTargetSize, + heroTag: heroTag, + enableFeedback: enableFeedback, + child: animatedChild, + ); + } + + Widget _buildExtended( + VoidCallback? callback, + Widget animatedChild, { + required bool isLoading, + }) { + return FloatingActionButton.extended( + onPressed: callback, + label: animatedChild, + icon: isLoading ? null : _icon, + tooltip: tooltip, + foregroundColor: foregroundColor, + backgroundColor: backgroundColor, + focusColor: focusColor, + hoverColor: hoverColor, + splashColor: splashColor, + elevation: elevation, + focusElevation: focusElevation, + hoverElevation: hoverElevation, + highlightElevation: highlightElevation, + disabledElevation: disabledElevation, + mouseCursor: mouseCursor, + shape: shape, + clipBehavior: clipBehavior, + focusNode: focusNode, + autofocus: autofocus, + materialTapTargetSize: materialTapTargetSize, + isExtended: isExtended, + heroTag: heroTag, + enableFeedback: enableFeedback, + extendedIconLabelSpacing: _extendedIconLabelSpacing, + extendedPadding: _extendedPadding, + extendedTextStyle: _extendedTextStyle, + ); + } } diff --git a/test/floating_action_async_button_test.dart b/test/floating_action_async_button_test.dart index 9f280d1..fe72356 100644 --- a/test/floating_action_async_button_test.dart +++ b/test/floating_action_async_button_test.dart @@ -41,7 +41,12 @@ void main() { ), ), ); - check(find.byType(FloatingActionButton).evaluate().length).equals(2); + final fabs = find.byType(FloatingActionButton); + check(fabs.evaluate().length).equals(2); + // Pins the variant -> constructor mapping. `.small` is 40x40 inside a + // 48x48 padded tap target (ThemeData default on the test platform). + check(tester.getSize(fabs.first)).equals(const Size(48, 48)); + check(tester.getSize(fabs.last)).equals(const Size(96, 96)); }); testWidgets( From 4b330363e93d61c818173e6b9a07a50f82cc1dd9 Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Sun, 23 Aug 2026 19:14:33 +0300 Subject: [PATCH 146/176] refactor: hoist shared build into AsyncStandardMaterialButton The four standard buttons (Elevated/Filled/Outlined/Text) carried verbatim copies of the same build body: AsyncButton wiring, long-press gating while loading, and icon: isLoading ? null : _icon. That body now lives once in AsyncStandardMaterialButton.build, pinned by test/elevated_async_button_test.dart:37-90 (Outlined/Text previously carried untested duplicate copies); each subclass supplies only the hook that constructs its concrete Material widget. Behaviour is unchanged: every Material constructor receives the same named arguments as before. Review changes: hooks made library-private (_buildButton/_buildIconButton), @protected and the unused BuildContext parameter dropped, so the public API stays byte-identical (no CHANGELOG entry). Review changes: AsyncMaterialButton/AsyncStandardMaterialButton docs updated to state that direct subclasses implement build while AsyncStandardMaterialButton provides it via the hooks. Review changes: AsyncStandardMaterialButton is now sealed (external subclassing was never usable: the icon path depends on private members); docs point custom buttons at AsyncButton. Note for the release CHANGELOG. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- lib/src/buttons/async_material_button.dart | 59 ++++++++- lib/src/buttons/elevated_async_button.dart | 74 +++++------ lib/src/buttons/filled_async_button.dart | 140 ++++++++++----------- lib/src/buttons/outlined_async_button.dart | 74 +++++------ lib/src/buttons/text_async_button.dart | 74 +++++------ 5 files changed, 235 insertions(+), 186 deletions(-) diff --git a/lib/src/buttons/async_material_button.dart b/lib/src/buttons/async_material_button.dart index 85b808d..86c1b89 100644 --- a/lib/src/buttons/async_material_button.dart +++ b/lib/src/buttons/async_material_button.dart @@ -5,9 +5,10 @@ part of '../../material_async_button.dart'; /// [TextAsyncButton], [IconAsyncButton]). /// /// Owns the shared async surface — [onPressed], [controller], and the -/// theme-override knobs. Subclasses implement [build] and forward these fields -/// to an [AsyncButton]. For custom non-Material buttons reach for [AsyncButton] -/// directly. +/// theme-override knobs. Direct subclasses ([IconAsyncButton], +/// [FloatingActionAsyncButton]) implement [build] and forward these fields to +/// an [AsyncButton]; [AsyncStandardMaterialButton] provides it. For custom +/// non-Material buttons reach for [AsyncButton] directly. abstract class AsyncMaterialButton extends StatelessWidget { /// Subclass-only constructor. Forwards every field to [AsyncButton]. See /// [AsyncButton] for the semantics of each parameter. @@ -62,11 +63,16 @@ abstract class AsyncMaterialButton extends StatelessWidget { /// [ButtonStyleButton] surface ([ElevatedAsyncButton], [FilledAsyncButton], /// [OutlinedAsyncButton], [TextAsyncButton]). Centralises the common /// Material parameters and the `.icon` constructor pieces so each concrete -/// subclass only has to render its specific button widget. +/// subclass only has to render its specific button widget via `_buildButton` / +/// `_buildIconButton`. /// /// [IconAsyncButton] does not extend this — it carries a different field /// set ([IconButton]'s API). -abstract class AsyncStandardMaterialButton extends AsyncMaterialButton { +/// +/// Sealed: the four concrete buttons are the whole hierarchy and the build +/// hooks are library-private. To build a custom async button, compose +/// [AsyncButton] directly. +sealed class AsyncStandardMaterialButton extends AsyncMaterialButton { /// Subclass-only constructor. Adds Material parameters common to /// [ElevatedButton]/[FilledButton]/[OutlinedButton]/[TextButton]. const AsyncStandardMaterialButton({ @@ -122,6 +128,49 @@ abstract class AsyncStandardMaterialButton extends AsyncMaterialButton { /// `max(iconSize, lineBox)`; a plain constructor shows only the label, so it /// tracks the label's line box. _SpinnerSize get _loadingSizing => _icon != null ? .max : .fontSize; + + @override + Widget build(BuildContext context) { + return AsyncButton( + onPressed: onPressed, + enabled: enabled, + controller: controller, + loadingBuilder: _resolveLoadingBuilder(context, _loadingSizing), + transitionBuilder: transitionBuilder, + builder: (context, animatedChild, callback, isLoading) { + final longPress = (callback != null && !isLoading) ? onLongPress : null; + if (_icon != null) { + return _buildIconButton( + onPressed: callback, + onLongPress: longPress, + icon: isLoading ? null : _icon, + label: animatedChild, + ); + } + return _buildButton( + onPressed: callback, + onLongPress: longPress, + child: animatedChild, + ); + }, + child: child, + ); + } + + /// Builds the non-icon Material button widget. + Widget _buildButton({ + required VoidCallback? onPressed, + required VoidCallback? onLongPress, + required Widget child, + }); + + /// Builds the icon Material button widget. + Widget _buildIconButton({ + required VoidCallback? onPressed, + required VoidCallback? onLongPress, + required Widget? icon, + required Widget label, + }); } /// How [_DefaultLoadingSpinner] derives its dimension from the ambient theme, diff --git a/lib/src/buttons/elevated_async_button.dart b/lib/src/buttons/elevated_async_button.dart index 7804df8..425a6f3 100644 --- a/lib/src/buttons/elevated_async_button.dart +++ b/lib/src/buttons/elevated_async_button.dart @@ -44,45 +44,45 @@ class ElevatedAsyncButton extends AsyncStandardMaterialButton { }) : super(child: label); @override - Widget build(BuildContext context) { - return AsyncButton( + Widget _buildButton({ + required VoidCallback? onPressed, + required VoidCallback? onLongPress, + required Widget child, + }) { + return ElevatedButton( onPressed: onPressed, - enabled: enabled, - controller: controller, - loadingBuilder: _resolveLoadingBuilder(context, _loadingSizing), - transitionBuilder: transitionBuilder, - builder: (context, animatedChild, callback, isLoading) { - final longPress = (callback != null && !isLoading) ? onLongPress : null; - if (_icon != null) { - return ElevatedButton.icon( - onPressed: callback, - onLongPress: longPress, - onHover: onHover, - onFocusChange: onFocusChange, - style: style, - focusNode: focusNode, - autofocus: autofocus, - clipBehavior: clipBehavior, - statesController: statesController, - iconAlignment: _iconAlignment, - icon: isLoading ? null : _icon, - label: animatedChild, - ); - } - return ElevatedButton( - onPressed: callback, - onLongPress: longPress, - onHover: onHover, - onFocusChange: onFocusChange, - style: style, - focusNode: focusNode, - autofocus: autofocus, - clipBehavior: clipBehavior, - statesController: statesController, - child: animatedChild, - ); - }, + onLongPress: onLongPress, + onHover: onHover, + onFocusChange: onFocusChange, + style: style, + focusNode: focusNode, + autofocus: autofocus, + clipBehavior: clipBehavior, + statesController: statesController, child: child, ); } + + @override + Widget _buildIconButton({ + required VoidCallback? onPressed, + required VoidCallback? onLongPress, + required Widget? icon, + required Widget label, + }) { + return ElevatedButton.icon( + onPressed: onPressed, + onLongPress: onLongPress, + onHover: onHover, + onFocusChange: onFocusChange, + style: style, + focusNode: focusNode, + autofocus: autofocus, + clipBehavior: clipBehavior, + statesController: statesController, + iconAlignment: _iconAlignment, + icon: icon, + label: label, + ); + } } diff --git a/lib/src/buttons/filled_async_button.dart b/lib/src/buttons/filled_async_button.dart index 3be813d..86af117 100644 --- a/lib/src/buttons/filled_async_button.dart +++ b/lib/src/buttons/filled_async_button.dart @@ -89,75 +89,75 @@ class FilledAsyncButton extends AsyncStandardMaterialButton { final _FilledButtonVariant _variant; @override - Widget build(BuildContext context) { - return AsyncButton( - onPressed: onPressed, - enabled: enabled, - controller: controller, - loadingBuilder: _resolveLoadingBuilder(context, _loadingSizing), - transitionBuilder: transitionBuilder, - builder: (context, animatedChild, callback, isLoading) { - final longPress = (callback != null && !isLoading) ? onLongPress : null; - if (_icon != null) { - return switch (_variant) { - .primary => FilledButton.icon( - onPressed: callback, - onLongPress: longPress, - onHover: onHover, - onFocusChange: onFocusChange, - style: style, - focusNode: focusNode, - autofocus: autofocus, - clipBehavior: clipBehavior, - statesController: statesController, - iconAlignment: _iconAlignment, - icon: isLoading ? null : _icon, - label: animatedChild, - ), - .tonal => FilledButton.tonalIcon( - onPressed: callback, - onLongPress: longPress, - onHover: onHover, - onFocusChange: onFocusChange, - style: style, - focusNode: focusNode, - autofocus: autofocus, - clipBehavior: clipBehavior, - statesController: statesController, - iconAlignment: _iconAlignment, - icon: isLoading ? null : _icon, - label: animatedChild, - ), - }; - } - return switch (_variant) { - .primary => FilledButton( - onPressed: callback, - onLongPress: longPress, - onHover: onHover, - onFocusChange: onFocusChange, - style: style, - focusNode: focusNode, - autofocus: autofocus, - clipBehavior: clipBehavior, - statesController: statesController, - child: animatedChild, - ), - .tonal => FilledButton.tonal( - onPressed: callback, - onLongPress: longPress, - onHover: onHover, - onFocusChange: onFocusChange, - style: style, - focusNode: focusNode, - autofocus: autofocus, - clipBehavior: clipBehavior, - statesController: statesController, - child: animatedChild, - ), - }; - }, - child: child, - ); + Widget _buildButton({ + required VoidCallback? onPressed, + required VoidCallback? onLongPress, + required Widget child, + }) { + return switch (_variant) { + .primary => FilledButton( + onPressed: onPressed, + onLongPress: onLongPress, + onHover: onHover, + onFocusChange: onFocusChange, + style: style, + focusNode: focusNode, + autofocus: autofocus, + clipBehavior: clipBehavior, + statesController: statesController, + child: child, + ), + .tonal => FilledButton.tonal( + onPressed: onPressed, + onLongPress: onLongPress, + onHover: onHover, + onFocusChange: onFocusChange, + style: style, + focusNode: focusNode, + autofocus: autofocus, + clipBehavior: clipBehavior, + statesController: statesController, + child: child, + ), + }; + } + + @override + Widget _buildIconButton({ + required VoidCallback? onPressed, + required VoidCallback? onLongPress, + required Widget? icon, + required Widget label, + }) { + return switch (_variant) { + .primary => FilledButton.icon( + onPressed: onPressed, + onLongPress: onLongPress, + onHover: onHover, + onFocusChange: onFocusChange, + style: style, + focusNode: focusNode, + autofocus: autofocus, + clipBehavior: clipBehavior, + statesController: statesController, + iconAlignment: _iconAlignment, + icon: icon, + label: label, + ), + .tonal => FilledButton.tonalIcon( + onPressed: onPressed, + onLongPress: onLongPress, + onHover: onHover, + onFocusChange: onFocusChange, + style: style, + focusNode: focusNode, + autofocus: autofocus, + clipBehavior: clipBehavior, + statesController: statesController, + iconAlignment: _iconAlignment, + icon: icon, + label: label, + ), + }; } } diff --git a/lib/src/buttons/outlined_async_button.dart b/lib/src/buttons/outlined_async_button.dart index df2a53d..a1356a0 100644 --- a/lib/src/buttons/outlined_async_button.dart +++ b/lib/src/buttons/outlined_async_button.dart @@ -42,45 +42,45 @@ class OutlinedAsyncButton extends AsyncStandardMaterialButton { }) : super(child: label); @override - Widget build(BuildContext context) { - return AsyncButton( + Widget _buildButton({ + required VoidCallback? onPressed, + required VoidCallback? onLongPress, + required Widget child, + }) { + return OutlinedButton( onPressed: onPressed, - enabled: enabled, - controller: controller, - loadingBuilder: _resolveLoadingBuilder(context, _loadingSizing), - transitionBuilder: transitionBuilder, - builder: (context, animatedChild, callback, isLoading) { - final longPress = (callback != null && !isLoading) ? onLongPress : null; - if (_icon != null) { - return OutlinedButton.icon( - onPressed: callback, - onLongPress: longPress, - onHover: onHover, - onFocusChange: onFocusChange, - style: style, - focusNode: focusNode, - autofocus: autofocus, - clipBehavior: clipBehavior, - statesController: statesController, - iconAlignment: _iconAlignment, - icon: isLoading ? null : _icon, - label: animatedChild, - ); - } - return OutlinedButton( - onPressed: callback, - onLongPress: longPress, - onHover: onHover, - onFocusChange: onFocusChange, - style: style, - focusNode: focusNode, - autofocus: autofocus, - clipBehavior: clipBehavior, - statesController: statesController, - child: animatedChild, - ); - }, + onLongPress: onLongPress, + onHover: onHover, + onFocusChange: onFocusChange, + style: style, + focusNode: focusNode, + autofocus: autofocus, + clipBehavior: clipBehavior, + statesController: statesController, child: child, ); } + + @override + Widget _buildIconButton({ + required VoidCallback? onPressed, + required VoidCallback? onLongPress, + required Widget? icon, + required Widget label, + }) { + return OutlinedButton.icon( + onPressed: onPressed, + onLongPress: onLongPress, + onHover: onHover, + onFocusChange: onFocusChange, + style: style, + focusNode: focusNode, + autofocus: autofocus, + clipBehavior: clipBehavior, + statesController: statesController, + iconAlignment: _iconAlignment, + icon: icon, + label: label, + ); + } } diff --git a/lib/src/buttons/text_async_button.dart b/lib/src/buttons/text_async_button.dart index 6869401..4dba0cb 100644 --- a/lib/src/buttons/text_async_button.dart +++ b/lib/src/buttons/text_async_button.dart @@ -42,45 +42,45 @@ class TextAsyncButton extends AsyncStandardMaterialButton { }) : super(child: label); @override - Widget build(BuildContext context) { - return AsyncButton( + Widget _buildButton({ + required VoidCallback? onPressed, + required VoidCallback? onLongPress, + required Widget child, + }) { + return TextButton( onPressed: onPressed, - enabled: enabled, - controller: controller, - loadingBuilder: _resolveLoadingBuilder(context, _loadingSizing), - transitionBuilder: transitionBuilder, - builder: (context, animatedChild, callback, isLoading) { - final longPress = (callback != null && !isLoading) ? onLongPress : null; - if (_icon != null) { - return TextButton.icon( - onPressed: callback, - onLongPress: longPress, - onHover: onHover, - onFocusChange: onFocusChange, - style: style, - focusNode: focusNode, - autofocus: autofocus, - clipBehavior: clipBehavior, - statesController: statesController, - iconAlignment: _iconAlignment, - icon: isLoading ? null : _icon, - label: animatedChild, - ); - } - return TextButton( - onPressed: callback, - onLongPress: longPress, - onHover: onHover, - onFocusChange: onFocusChange, - style: style, - focusNode: focusNode, - autofocus: autofocus, - clipBehavior: clipBehavior, - statesController: statesController, - child: animatedChild, - ); - }, + onLongPress: onLongPress, + onHover: onHover, + onFocusChange: onFocusChange, + style: style, + focusNode: focusNode, + autofocus: autofocus, + clipBehavior: clipBehavior, + statesController: statesController, child: child, ); } + + @override + Widget _buildIconButton({ + required VoidCallback? onPressed, + required VoidCallback? onLongPress, + required Widget? icon, + required Widget label, + }) { + return TextButton.icon( + onPressed: onPressed, + onLongPress: onLongPress, + onHover: onHover, + onFocusChange: onFocusChange, + style: style, + focusNode: focusNode, + autofocus: autofocus, + clipBehavior: clipBehavior, + statesController: statesController, + iconAlignment: _iconAlignment, + icon: icon, + label: label, + ); + } } From ab87c9f11741992c4e133a9fbae86a0b5a0d0ddb Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Sun, 23 Aug 2026 19:16:10 +0300 Subject: [PATCH 147/176] test: cover the example's failing action returning to idle and showing the SnackBar --- example/test/widget_test.dart | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/example/test/widget_test.dart b/example/test/widget_test.dart index 763fb11..c4843a0 100644 --- a/example/test/widget_test.dart +++ b/example/test/widget_test.dart @@ -35,4 +35,19 @@ void main() { await tester.pumpAndSettle(); check(find.byType(CircularProgressIndicator)).findsNone(); }); + + testWidgets('failing action returns to idle and shows the error SnackBar', ( + tester, + ) async { + await tester.pumpWidget(const MyApp()); + await tester.pumpAndSettle(); + + await tester.tap(find.text('OutlinedAsyncButton (handles failure)')); + await tester.pump(); + check(find.byType(CircularProgressIndicator)).findsOne(); + + await tester.pumpAndSettle(); + check(find.byType(CircularProgressIndicator)).findsNone(); + check(find.text('Failed: Exception: simulated failure')).findsOne(); + }); } From 1427cf7cca7753916dd08fb25abf65baa6e81301 Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Mon, 24 Aug 2026 19:32:11 +0300 Subject: [PATCH 148/176] test: oracle enabled/controller forwarding and .max spinner sizing The hoisted AsyncStandardMaterialButton.build forwarded enabled and controller into AsyncButton with no test able to notice a dropped forward, and the .icon spinner-sizing test never exercised .max with a dominant icon (default icon 18 < line box 20, so a .fontSize mutant passed). Disable-forwarding, external-controller, and styleFrom(iconSize: 32) coverage kill all three mutants; the test's false "icon is the taller element" comment is corrected. Co-Authored-By: Claude Fable 5 --- test/elevated_async_button_test.dart | 65 +++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 7 deletions(-) diff --git a/test/elevated_async_button_test.dart b/test/elevated_async_button_test.dart index d616264..fd28844 100644 --- a/test/elevated_async_button_test.dart +++ b/test/elevated_async_button_test.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:checks/checks.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -34,6 +36,51 @@ void main() { await tester.pumpAndSettle(); }); + testWidgets('enabled: false disables the underlying button', ( + tester, + ) async { + await tester.pumpWidget( + pumpHost( + ElevatedAsyncButton( + enabled: false, + onPressed: () async {}, + child: const Text('go'), + ), + ), + ); + // The wrapper must forward `enabled` into AsyncButton; if it does not, + // the underlying button stays tappable with a live onPressed. + check( + tester.widget(find.byType(ElevatedButton)).onPressed, + ).isNull(); + }); + + testWidgets('an external controller drives the loading state', ( + tester, + ) async { + final controller = newController(); + final (:onPressed, :completer) = pendingPress(); + await tester.pumpWidget( + pumpHost( + ElevatedAsyncButton( + controller: controller, + onPressed: onPressed, + child: const Text('go'), + ), + ), + ); + check(find.byType(CircularProgressIndicator)).findsNone(); + // Trigger from outside the widget: only works if the wrapper forwarded + // the external controller into AsyncButton (which attaches onPressed). + unawaited(controller.trigger()); + await tester.pump(); + check(controller).isLoading(); + check(find.byType(CircularProgressIndicator)).findsOne(); + completer.complete(); + await tester.pumpAndSettle(); + check(find.byType(CircularProgressIndicator)).findsNone(); + }); + testWidgets('onLongPress is gated off while loading', (tester) async { final (:onPressed, :completer) = pendingPress(); await tester.pumpWidget( @@ -97,6 +144,11 @@ void main() { pumpHost( ElevatedAsyncButton.icon( onPressed: onPressed, + // Push the resolved icon size above the ~20px label line box so + // the icon dominates the row. Must go through the style: an + // ambient IconTheme would be overridden by ButtonStyleButton's + // resolved iconSize. + style: ElevatedButton.styleFrom(iconSize: 32), icon: const Icon(Icons.send), label: const Text('send'), ), @@ -106,14 +158,13 @@ void main() { final iconSize = spinnerIconThemeSize(tester); final fontSize = spinnerFontSize(tester); final lineBox = spinnerTextLineBox(tester); - check(iconSize).isNotNull(); + check(iconSize).equals(32); check(fontSize).isNotNull(); - // The .icon row height is max(icon, lineBox); the spinner matches it so - // the button keeps its height while loading. - final expected = iconSize! > lineBox ? iconSize : lineBox; - check(loadingSpinnerSize(tester)).equals(expected); - // Regression guard: the icon is the taller element, so the spinner must - // exceed the font size (the old, shrinking behaviour). + // The .icon row height is max(icon, lineBox); with the icon (32) taller + // than the line box (~20), the spinner must take the icon's size — a + // line-box-sized spinner is the old, shrinking behaviour. + check(iconSize!).isGreaterThan(lineBox); + check(loadingSpinnerSize(tester)).equals(iconSize); check(loadingSpinnerSize(tester)!).isGreaterThan(fontSize!); completer.complete(); await tester.pump(); From dd6afeefcd2b15feed828d125a9d2243a547c7d4 Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Mon, 24 Aug 2026 19:33:35 +0300 Subject: [PATCH 149/176] test: pin FAB heroTag plumbing and .standard variant routing The heroTag rewrite had no Hero oracle (heroTag:null at all three call sites survived) and nothing pinned .standard to FloatingActionButton.new (routing it through _buildSmallOrLarge survived). Adds: a duplicate-Hero collision test that pushes a route so the Hero scan actually runs, a custom-heroTag forwarding check per variant, a Size(56,56) pin for the standard FAB, and a mini:true -> Size(48,48) pin. Co-Authored-By: Claude Fable 5 --- test/floating_action_async_button_test.dart | 99 +++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/test/floating_action_async_button_test.dart b/test/floating_action_async_button_test.dart index fe72356..ac2f8f3 100644 --- a/test/floating_action_async_button_test.dart +++ b/test/floating_action_async_button_test.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:checks/checks.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -20,6 +22,103 @@ void main() { ); check(find.byType(FloatingActionButton)).findsOne(); check(find.text('go')).findsOne(); + // Pins the .standard -> FloatingActionButton.new mapping: the standard + // FAB is 56x56 (small pads to 48x48, large is 96x96). + check( + tester.getSize(find.byType(FloatingActionButton)), + ).equals(const Size(56, 56)); + }); + + testWidgets('mini is forwarded to the FloatingActionButton', ( + tester, + ) async { + await tester.pumpWidget( + pumpHost( + FloatingActionAsyncButton( + mini: true, + onPressed: () async {}, + child: const Icon(Icons.add), + ), + ), + ); + // A mini FAB is 40x40 inside a 48x48 padded tap target. + check( + tester.getSize(find.byType(FloatingActionButton)), + ).equals(const Size(48, 48)); + }); + + testWidgets('a custom heroTag is forwarded for every variant', ( + tester, + ) async { + final variants = [ + FloatingActionAsyncButton( + heroTag: 'custom-tag', + onPressed: () async {}, + child: const Icon(Icons.add), + ), + FloatingActionAsyncButton.small( + heroTag: 'custom-tag', + onPressed: () async {}, + child: const Icon(Icons.add), + ), + FloatingActionAsyncButton.large( + heroTag: 'custom-tag', + onPressed: () async {}, + child: const Icon(Icons.add), + ), + FloatingActionAsyncButton.extended( + heroTag: 'custom-tag', + onPressed: () async {}, + label: const Text('go'), + ), + ]; + for (final fab in variants) { + await tester.pumpWidget(pumpHost(fab)); + check( + tester + .widget(find.byType(FloatingActionButton)) + .heroTag, + because: '$fab', + ).equals('custom-tag'); + } + }); + + testWidgets('two default-tag FABs collide in the Hero scan on push', ( + tester, + ) async { + final navigatorKey = GlobalKey(); + await tester.pumpWidget( + MaterialApp( + navigatorKey: navigatorKey, + theme: emptyAsyncButtonTheme, + home: Scaffold( + body: Column( + children: [ + FloatingActionAsyncButton( + onPressed: () async {}, + child: const Icon(Icons.add), + ), + FloatingActionAsyncButton( + onPressed: () async {}, + child: const Icon(Icons.remove), + ), + ], + ), + ), + ), + ); + // The duplicate-Hero scan only runs during a route transition — without + // the push this test would pass vacuously even on correct code. Two + // default-tag FABs sharing the const default tag must trip it, proving + // the default heroTag actually reaches the Hero wrapper. + unawaited( + navigatorKey.currentState!.push( + MaterialPageRoute(builder: (_) => const Scaffold()), + ), + ); + await tester.pump(); + await tester.pump(); + check(tester.takeException()).isA(); }); testWidgets('small and large variants render FloatingActionButton', ( From 72d58fdf36a191cdcc91e252665d7c9d29b72a73 Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Mon, 24 Aug 2026 19:34:05 +0300 Subject: [PATCH 150/176] test: pin FilledAsyncButton .tonalIcon to FilledButton.tonalIcon The icon-build variant switch had no oracle for the tonal arm: a mutant mapping .tonal to the primary FilledButton.icon survived. The spinner colour is the observable difference (onSecondaryContainer vs onPrimary), so a .tonalIcon spinner-colour test mirrors the existing .tonal one. Co-Authored-By: Claude Fable 5 --- test/filled_async_button_test.dart | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test/filled_async_button_test.dart b/test/filled_async_button_test.dart index 071c597..c8aec27 100644 --- a/test/filled_async_button_test.dart +++ b/test/filled_async_button_test.dart @@ -103,6 +103,28 @@ void main() { await tester.pumpAndSettle(); }); + testWidgets('.tonalIcon spinner uses onSecondaryContainer', (tester) async { + final (:onPressed, :completer) = pendingPress(); + final theme = emptyAsyncButtonTheme; + await tester.pumpWidget( + pumpHost( + FilledAsyncButton.tonalIcon( + onPressed: onPressed, + icon: const Icon(Icons.save), + label: const Text('save'), + ), + theme: theme, + ), + ); + await tapIntoLoading(tester, find.byType(FilledButton)); + // Pins .tonal -> FilledButton.tonalIcon in the icon build: the primary + // FilledButton.icon would paint the spinner onPrimary instead. + final expected = theme.colorScheme.onSecondaryContainer; + check(spinnerColor(tester)).equals(expected); + completer.complete(); + await tester.pumpAndSettle(); + }); + testWidgets('a custom spinner colour overrides the inherited one', ( tester, ) async { From f5d0a6997b564501a8e4069017d76b2c7cdf111e Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Mon, 24 Aug 2026 19:34:52 +0300 Subject: [PATCH 151/176] test: guard IconAsyncButton parameter forwarding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The centralized ~20-parameter forwarding block in _buildIconButton had no oracle beyond the variant mapping — a tooltip:null mutant survived. One test pins tooltip, isSelected, selectedIcon, and style identity on the underlying IconButton. Co-Authored-By: Claude Fable 5 --- test/icon_async_button_test.dart | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/test/icon_async_button_test.dart b/test/icon_async_button_test.dart index 46909b3..b9d4f1b 100644 --- a/test/icon_async_button_test.dart +++ b/test/icon_async_button_test.dart @@ -88,6 +88,31 @@ void main() { await tester.pumpAndSettle(); check(find.byIcon(Icons.refresh)).findsOne(); }); + + testWidgets('forwards its parameters to the underlying IconButton', ( + tester, + ) async { + // Guards the centralized ~20-parameter forwarding block: a dropped + // forward (e.g. tooltip: null) is invisible to the rendering tests. + final style = IconButton.styleFrom(backgroundColor: Colors.teal); + await tester.pumpWidget( + pumpHost( + IconAsyncButton( + onPressed: () async {}, + icon: const Icon(Icons.save), + tooltip: 'save', + isSelected: true, + selectedIcon: const Icon(Icons.check), + style: style, + ), + ), + ); + final button = tester.widget(find.byType(IconButton)); + check(button.tooltip).equals('save'); + check(button.isSelected).equals(true); + check(button.selectedIcon).isNotNull(); + check(button.style).identicalTo(style); + }); }); group('IconAsyncButton loading foreground', () { From f11476dc487e8535c7986573e7dca47b9594f679 Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Mon, 24 Aug 2026 19:35:25 +0300 Subject: [PATCH 152/176] test: assert LRU promotion preserves the cached value The cache test asserted structure only (length, key order), so a mutant corrupting the value while re-inserting on promotion passed the dedicated test file. Capture the value before the promoting hit and assert it survives unchanged. Co-Authored-By: Claude Fable 5 --- test/material_async_button_theme_test.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/material_async_button_theme_test.dart b/test/material_async_button_theme_test.dart index 7e31e94..e177234 100644 --- a/test/material_async_button_theme_test.dart +++ b/test/material_async_button_theme_test.dart @@ -180,9 +180,13 @@ void main() { // growing or evicting. final secondKey = debugLineBoxCache.keys.first; check(secondKey.$1.fontSize).equals(2); + final valueBeforePromotion = debugLineBoxCache[secondKey]; await pumpSpinnerWithFontSize(2); check(debugLineBoxCache.length).equals(16); check(debugLineBoxCache.keys.last).equals(secondKey); + // Promotion must re-insert the cached measurement unchanged — a + // structural pass with a corrupted value would go unnoticed otherwise. + check(debugLineBoxCache[secondKey]).equals(valueBeforePromotion); }, ); }); From f8a779a6c8f09323c9d77acc25361cfc69bed5b0 Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Mon, 24 Aug 2026 19:35:40 +0300 Subject: [PATCH 153/176] docs: record the AsyncStandardMaterialButton sealing as unreleased breaking Sealing landed in 4b33036 with the break noted only in the commit body; nothing in-tree forced the next release to be a major. The Unreleased BREAKING section makes the 3.0.0 requirement visible at release time. Co-Authored-By: Claude Fable 5 --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d18202..2e07643 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # CHANGELOG +## Unreleased + +### BREAKING + +- `AsyncStandardMaterialButton` is now sealed and can no longer be extended + outside the package; compose `AsyncButton` for custom buttons. + ## 2.1.2 ### Improved From 85baef28a871aa08b7c1a8fb2e6dc8be2333e300 Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Mon, 24 Aug 2026 19:35:40 +0300 Subject: [PATCH 154/176] refactor!: seal AsyncStandardMaterialButton Marker commit: the sealing shipped in 4b33036 without a conventional breaking-change marker, so commit-range tooling would classify v2.1.2..HEAD as a minor bump. Empty by design. BREAKING CHANGE: AsyncStandardMaterialButton is sealed; it can no longer be extended outside the package. Compose AsyncButton directly for custom async buttons. Co-Authored-By: Claude Fable 5 From f6e51fe01c4d06c3c3a016ede643a85487182d58 Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Mon, 24 Aug 2026 19:39:58 +0300 Subject: [PATCH 155/176] test: discard the hero-test push future via ignore(), not unawaited() Analyzer generations disagree on NavigatorState.push: pre-3.47 flags the bare future (unawaited_futures) while 3.47+ marks it @awaitNotRequired and flags the wrapper (unnecessary_unawaited). Future.ignore() passes both; CI stable 3.47.1 failed Analyze on the wrapper. Co-Authored-By: Claude Fable 5 --- test/floating_action_async_button_test.dart | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/test/floating_action_async_button_test.dart b/test/floating_action_async_button_test.dart index ac2f8f3..4f3735a 100644 --- a/test/floating_action_async_button_test.dart +++ b/test/floating_action_async_button_test.dart @@ -1,5 +1,3 @@ -import 'dart:async'; - import 'package:checks/checks.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -111,11 +109,12 @@ void main() { // the push this test would pass vacuously even on correct code. Two // default-tag FABs sharing the const default tag must trip it, proving // the default heroTag actually reaches the Hero wrapper. - unawaited( - navigatorKey.currentState!.push( - MaterialPageRoute(builder: (_) => const Scaffold()), - ), - ); + // .ignore(), not unawaited(): pre-3.47 analyzers flag the bare future + // (unawaited_futures) while 3.47+ flags unawaited() on the + // @awaitNotRequired push (unnecessary_unawaited). + navigatorKey.currentState! + .push(MaterialPageRoute(builder: (_) => const Scaffold())) + .ignore(); await tester.pump(); await tester.pump(); check(tester.takeException()).isA(); From 5e117f79962abe74c324876d2700eaecf521d5e4 Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Sat, 29 Aug 2026 12:32:53 +0300 Subject: [PATCH 156/176] style: adopt dot-shorthand for inferred constructor/enum calls Co-Authored-By: Claude Fable 5 --- example/lib/main.dart | 2 +- test/_helpers.dart | 2 +- test/icon_async_button_test.dart | 2 +- test/material_async_button_theme_test.dart | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 0aac147..a571280 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -179,7 +179,7 @@ class _HomePageState extends State { const _SectionLabel('Form "Done" → controller.trigger()'), TextField( controller: _textController, - textInputAction: TextInputAction.done, + textInputAction: .done, decoration: const InputDecoration(labelText: 'Name'), onSubmitted: (_) => _formController.trigger(), ), diff --git a/test/_helpers.dart b/test/_helpers.dart index ab19a8b..83b0990 100644 --- a/test/_helpers.dart +++ b/test/_helpers.dart @@ -169,7 +169,7 @@ double spinnerTextLineBox(WidgetTester tester) { .style; final painter = TextPainter( text: TextSpan(text: '', style: style), - textDirection: TextDirection.ltr, + textDirection: .ltr, )..layout(); return painter.preferredLineHeight; } diff --git a/test/icon_async_button_test.dart b/test/icon_async_button_test.dart index b9d4f1b..60ff05e 100644 --- a/test/icon_async_button_test.dart +++ b/test/icon_async_button_test.dart @@ -65,7 +65,7 @@ void main() { check(material.color, because: '$button').equals(background); final side = (material.shape as OutlinedBorder?)?.side; check( - side != null && side != BorderSide.none, + side != null && side != .none, because: '$button', ).equals(outlined); } diff --git a/test/material_async_button_theme_test.dart b/test/material_async_button_theme_test.dart index e177234..affe8a7 100644 --- a/test/material_async_button_theme_test.dart +++ b/test/material_async_button_theme_test.dart @@ -87,7 +87,7 @@ void main() { theme: ThemeData(extensions: const [ext]), home: Builder( builder: (ctx) { - captured = AsyncButtonTheme.of(ctx); + captured = .of(ctx); return const SizedBox.shrink(); }, ), @@ -107,7 +107,7 @@ void main() { MaterialApp( home: Builder( builder: (ctx) { - captured = AsyncButtonTheme.of(ctx); + captured = .of(ctx); return const SizedBox.shrink(); }, ), From 93a5be1612094c8ece4686408a2b797940403680 Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Sun, 30 Aug 2026 21:36:45 +0300 Subject: [PATCH 157/176] chore: release 3.0.0 Co-Authored-By: Claude Fable 5 --- CHANGELOG.md | 2 +- pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e07643..fa17edb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # CHANGELOG -## Unreleased +## 3.0.0 ### BREAKING diff --git a/pubspec.yaml b/pubspec.yaml index 3cda2ad..48627a4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: material_async_button description: Drop-in loading state for Elevated, Filled, Outlined, Text, Icon and FloatingAction Material buttons — spinner while onPressed runs, AsyncButtonTheme, AsyncButtonController. -version: 2.1.2 +version: 3.0.0 homepage: https://mehmetesen.com repository: https://github.com/esenmx/material_async_button issue_tracker: https://github.com/esenmx/material_async_button/issues From d17e032f68e7699fd70e707ab90524e564ac0fc7 Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Sat, 5 Sep 2026 12:06:45 +0300 Subject: [PATCH 158/176] chore: bump SDK/Flutter floor and very_good_analysis to 11 Co-Authored-By: Claude Sonnet 5 --- analysis_options.yaml | 6 +- example/analysis_options.yaml | 4 + example/lib/main.dart | 14 +-- example/pubspec.yaml | 4 +- lib/src/async_button.dart | 36 +++---- lib/src/async_button_controller.dart | 2 +- lib/src/buttons/async_material_button.dart | 94 +++++++------------ lib/src/buttons/elevated_async_button.dart | 4 +- lib/src/buttons/filled_async_button.dart | 8 +- .../buttons/floating_action_async_button.dart | 24 ++--- lib/src/buttons/icon_async_button.dart | 8 +- lib/src/buttons/outlined_async_button.dart | 4 +- lib/src/buttons/text_async_button.dart | 4 +- lib/src/material_async_button_theme.dart | 45 ++++----- pubspec.yaml | 6 +- test/floating_action_async_button_test.dart | 10 +- 16 files changed, 113 insertions(+), 160 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 68010b7..12b8e5b 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,4 +1,4 @@ include: package:very_good_analysis/analysis_options.yaml - -formatter: - trailing_commas: automate +analyzer: + exclude: + - build/** diff --git a/example/analysis_options.yaml b/example/analysis_options.yaml index f9b3034..f830802 100644 --- a/example/analysis_options.yaml +++ b/example/analysis_options.yaml @@ -1 +1,5 @@ +analyzer: + exclude: + - build/** + - macos/** include: package:flutter_lints/flutter.yaml diff --git a/example/lib/main.dart b/example/lib/main.dart index a571280..c9d98e7 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -4,9 +4,7 @@ import 'package:material_async_button/material_async_button.dart'; void main() => runApp(const MyApp()); -class MyApp extends StatelessWidget { - const MyApp({super.key}); - +class const MyApp({super.key}) extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( @@ -17,9 +15,7 @@ class MyApp extends StatelessWidget { } } -class HomePage extends StatefulWidget { - const HomePage({super.key}); - +class const HomePage({super.key}) extends StatefulWidget { @override State createState() => _HomePageState(); } @@ -262,11 +258,7 @@ Widget _animatedSwitchSize(BuildContext context, Widget child, bool isLoading) { ); } -class _SectionLabel extends StatelessWidget { - const _SectionLabel(this.text); - - final String text; - +class const _SectionLabel(final String text) extends StatelessWidget { @override Widget build(BuildContext context) => Padding( padding: const EdgeInsets.symmetric(vertical: 8), diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 58e9942..2a7f29d 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -4,8 +4,8 @@ publish_to: "none" version: 1.0.0+1 environment: - sdk: ^3.10.0 - flutter: ">=3.38.0" + sdk: ^3.13.0 + flutter: ">=3.47.0" dependencies: flutter: diff --git a/lib/src/async_button.dart b/lib/src/async_button.dart index 53ae8b2..6da94a9 100644 --- a/lib/src/async_button.dart +++ b/lib/src/async_button.dart @@ -60,47 +60,39 @@ typedef AsyncButtonTransitionBuilder = /// ), /// ) /// ``` -class AsyncButton extends StatefulWidget { - /// Creates an [AsyncButton]. See the class doc for usage. - const AsyncButton({ - required this.child, - required this.onPressed, - required this.builder, - this.enabled = true, - this.controller, - this.loadingBuilder, - this.transitionBuilder, - super.key, - }); - +class const AsyncButton({ /// Idle widget. Replaced by [loadingBuilder] while loading. - final Widget child; + required final Widget child, /// Async callback. `null` makes the button appear disabled. - final AsyncCallback? onPressed; + required final AsyncCallback? onPressed, + + /// Renders the button chrome. See [AsyncButtonWidgetBuilder]. + required final AsyncButtonWidgetBuilder builder, /// Whether the button is interactive. When `false` it renders the disabled /// look, ignores taps, and no-ops an external [AsyncButtonController.trigger] /// — same as `onPressed: null`, but the affirmative form that pairs with a /// tear-off `onPressed`. Defaults to `true`. - final bool enabled; - - /// Renders the button chrome. See [AsyncButtonWidgetBuilder]. - final AsyncButtonWidgetBuilder builder; + final bool enabled = true, /// External controller. When null, the widget creates and owns its own. - final AsyncButtonController? controller; + final AsyncButtonController? controller, /// Builds the widget shown while loading, with the [AsyncButton]'s own /// [BuildContext]. Falls back to [AsyncButtonTheme.loadingBuilder], then to /// an [AsyncButtonSpinner]. The spinner inherits the button's foreground /// colour automatically — to recolour it, return /// `AsyncButtonSpinner(color: ...)`. - final WidgetBuilder? loadingBuilder; + final WidgetBuilder? loadingBuilder, /// Per-widget override of [AsyncButtonTheme.transitionBuilder]. The button /// performs no animation unless this (or the theme's) builder adds one. - final AsyncButtonTransitionBuilder? transitionBuilder; + final AsyncButtonTransitionBuilder? transitionBuilder, + super.key, +}) extends StatefulWidget { + /// Creates an [AsyncButton]. See the class doc for usage. + this; @override State createState() => _AsyncButtonState(); diff --git a/lib/src/async_button_controller.dart b/lib/src/async_button_controller.dart index a15db58..a1ca00d 100644 --- a/lib/src/async_button_controller.dart +++ b/lib/src/async_button_controller.dart @@ -18,7 +18,7 @@ part of '../material_async_button.dart'; class AsyncButtonController extends ChangeNotifier implements ValueListenable { /// Creates a controller in the idle (not-loading) state. - AsyncButtonController(); + new(); bool _isLoading = false; diff --git a/lib/src/buttons/async_material_button.dart b/lib/src/buttons/async_material_button.dart index 86c1b89..c348c3a 100644 --- a/lib/src/buttons/async_material_button.dart +++ b/lib/src/buttons/async_material_button.dart @@ -9,36 +9,29 @@ part of '../../material_async_button.dart'; /// [FloatingActionAsyncButton]) implement [build] and forward these fields to /// an [AsyncButton]; [AsyncStandardMaterialButton] provides it. For custom /// non-Material buttons reach for [AsyncButton] directly. -abstract class AsyncMaterialButton extends StatelessWidget { - /// Subclass-only constructor. Forwards every field to [AsyncButton]. See - /// [AsyncButton] for the semantics of each parameter. - const AsyncMaterialButton({ - required this.child, - required this.onPressed, - this.enabled = true, - this.controller, - this.loadingBuilder, - this.transitionBuilder, - super.key, - }); - +abstract class const AsyncMaterialButton({ /// See [AsyncButton.child]. - final Widget child; + required final Widget child, /// See [AsyncButton.onPressed]. - final AsyncCallback? onPressed; + required final AsyncCallback? onPressed, /// See [AsyncButton.enabled]. - final bool enabled; + final bool enabled = true, /// See [AsyncButton.controller]. - final AsyncButtonController? controller; + final AsyncButtonController? controller, /// See [AsyncButton.loadingBuilder]. - final WidgetBuilder? loadingBuilder; + final WidgetBuilder? loadingBuilder, /// See [AsyncButton.transitionBuilder]. - final AsyncButtonTransitionBuilder? transitionBuilder; + final AsyncButtonTransitionBuilder? transitionBuilder, + super.key, +}) extends StatelessWidget { + /// Subclass-only constructor. Forwards every field to [AsyncButton]. See + /// [AsyncButton] for the semantics of each parameter. + this; /// Resolves the loading builder this button hands to its [AsyncButton]: the /// per-widget [loadingBuilder] wins, then [AsyncButtonTheme.loadingBuilder], @@ -72,56 +65,44 @@ abstract class AsyncMaterialButton extends StatelessWidget { /// Sealed: the four concrete buttons are the whole hierarchy and the build /// hooks are library-private. To build a custom async button, compose /// [AsyncButton] directly. -sealed class AsyncStandardMaterialButton extends AsyncMaterialButton { - /// Subclass-only constructor. Adds Material parameters common to - /// [ElevatedButton]/[FilledButton]/[OutlinedButton]/[TextButton]. - const AsyncStandardMaterialButton({ - required super.child, - required super.onPressed, - super.enabled, - super.controller, - super.loadingBuilder, - super.transitionBuilder, - this.onLongPress, - this.onHover, - this.onFocusChange, - this.style, - this.focusNode, - this.autofocus = false, - this.clipBehavior = .none, - this.statesController, - Widget? icon, - IconAlignment? iconAlignment, - super.key, - }) : _icon = icon, - _iconAlignment = iconAlignment; +sealed class const AsyncStandardMaterialButton({ + required super.child, + required super.onPressed, + super.enabled, + super.controller, + super.loadingBuilder, + super.transitionBuilder, /// Forwarded to the underlying Material button. - final VoidCallback? onLongPress; + final VoidCallback? onLongPress, /// Forwarded to the underlying Material button. - final ValueChanged? onHover; + final ValueChanged? onHover, /// Forwarded to the underlying Material button. - final ValueChanged? onFocusChange; + final ValueChanged? onFocusChange, /// Forwarded to the underlying Material button. - final ButtonStyle? style; + final ButtonStyle? style, /// Forwarded to the underlying Material button. - final FocusNode? focusNode; + final FocusNode? focusNode, /// Forwarded to the underlying Material button. - final bool autofocus; + final bool autofocus = false, /// Forwarded to the underlying Material button. - final Clip clipBehavior; + final Clip clipBehavior = .none, /// Forwarded to the underlying Material button. - final WidgetStatesController? statesController; - - final Widget? _icon; - final IconAlignment? _iconAlignment; + final WidgetStatesController? statesController, + final Widget? _icon, + final IconAlignment? _iconAlignment, + super.key, +}) extends AsyncMaterialButton { + /// Subclass-only constructor. Adds Material parameters common to + /// [ElevatedButton]/[FilledButton]/[OutlinedButton]/[TextButton]. + this; /// The default spinner sizing for this button's current shape: an `.icon` /// constructor lays out an icon beside the label, so its idle row height is @@ -198,11 +179,8 @@ double? _largest(double? a, double? b) => a == null /// [DefaultTextStyle] set by the surrounding Material button (the same scope /// [AsyncButtonSpinner] reads for its colour) and sizes the spinner so the /// button holds its idle height while loading. -class _DefaultLoadingSpinner extends StatelessWidget { - const _DefaultLoadingSpinner(this.sizing); - - final _SpinnerSize sizing; - +class const _DefaultLoadingSpinner(final _SpinnerSize sizing) + extends StatelessWidget { @override Widget build(BuildContext context) { final iconSize = IconTheme.of(context).size; diff --git a/lib/src/buttons/elevated_async_button.dart b/lib/src/buttons/elevated_async_button.dart index 425a6f3..4775cd4 100644 --- a/lib/src/buttons/elevated_async_button.dart +++ b/lib/src/buttons/elevated_async_button.dart @@ -4,7 +4,7 @@ part of '../../material_async_button.dart'; /// swapped for the loading widget. class ElevatedAsyncButton extends AsyncStandardMaterialButton { /// Mirrors [ElevatedButton.new]. - const ElevatedAsyncButton({ + const new({ required super.onPressed, required super.child, super.onLongPress, @@ -24,7 +24,7 @@ class ElevatedAsyncButton extends AsyncStandardMaterialButton { /// Mirrors [ElevatedButton.icon]. The loading widget replaces `label` /// while `icon` stays put. - const ElevatedAsyncButton.icon({ + const new icon({ required super.onPressed, required super.icon, required Widget label, diff --git a/lib/src/buttons/filled_async_button.dart b/lib/src/buttons/filled_async_button.dart index 86af117..4dadb80 100644 --- a/lib/src/buttons/filled_async_button.dart +++ b/lib/src/buttons/filled_async_button.dart @@ -7,7 +7,7 @@ enum _FilledButtonVariant { primary, tonal } /// [FilledAsyncButton.icon], [FilledAsyncButton.tonalIcon]. class FilledAsyncButton extends AsyncStandardMaterialButton { /// Mirrors [FilledButton.new]. - const FilledAsyncButton({ + const new({ required super.onPressed, required super.child, super.onLongPress, @@ -26,7 +26,7 @@ class FilledAsyncButton extends AsyncStandardMaterialButton { }) : _variant = .primary; /// Mirrors [FilledButton.tonal]. - const FilledAsyncButton.tonal({ + const new tonal({ required super.child, required super.onPressed, super.onLongPress, @@ -45,7 +45,7 @@ class FilledAsyncButton extends AsyncStandardMaterialButton { }) : _variant = .tonal; /// Mirrors [FilledButton.icon]. - const FilledAsyncButton.icon({ + const new icon({ required super.onPressed, required super.icon, required Widget label, @@ -66,7 +66,7 @@ class FilledAsyncButton extends AsyncStandardMaterialButton { super(child: label); /// Mirrors [FilledButton.tonalIcon]. - const FilledAsyncButton.tonalIcon({ + const new tonalIcon({ required super.onPressed, required super.icon, required Widget label, diff --git a/lib/src/buttons/floating_action_async_button.dart b/lib/src/buttons/floating_action_async_button.dart index bbf26d3..36bdfba 100644 --- a/lib/src/buttons/floating_action_async_button.dart +++ b/lib/src/buttons/floating_action_async_button.dart @@ -2,9 +2,7 @@ part of '../../material_async_button.dart'; enum _FloatingActionButtonVariant { standard, small, large, extended } -class _DefaultHeroTag { - const _DefaultHeroTag(); -} +class const _DefaultHeroTag(); const Object _defaultHeroTag = _DefaultHeroTag(); @@ -12,7 +10,7 @@ const Object _defaultHeroTag = _DefaultHeroTag(); /// (or label, for `.extended`) is swapped for the loading widget. class FloatingActionAsyncButton extends AsyncMaterialButton { /// Mirrors [FloatingActionButton.new]. - const FloatingActionAsyncButton({ + const new({ required super.onPressed, Widget? child, super.enabled, @@ -49,7 +47,7 @@ class FloatingActionAsyncButton extends AsyncMaterialButton { super(child: child ?? const SizedBox.shrink()); /// Mirrors [FloatingActionButton.small]. - const FloatingActionAsyncButton.small({ + const new small({ required super.onPressed, Widget? child, super.enabled, @@ -86,7 +84,7 @@ class FloatingActionAsyncButton extends AsyncMaterialButton { super(child: child ?? const SizedBox.shrink()); /// Mirrors [FloatingActionButton.large]. - const FloatingActionAsyncButton.large({ + const new large({ required super.onPressed, Widget? child, super.enabled, @@ -123,10 +121,10 @@ class FloatingActionAsyncButton extends AsyncMaterialButton { super(child: child ?? const SizedBox.shrink()); /// Mirrors [FloatingActionButton.extended]. - const FloatingActionAsyncButton.extended({ + const new extended({ required super.onPressed, required Widget label, - Widget? icon, + this._icon, super.enabled, super.controller, super.loadingBuilder, @@ -151,16 +149,12 @@ class FloatingActionAsyncButton extends AsyncMaterialButton { this.isExtended = true, this.heroTag = _defaultHeroTag, this.enableFeedback, - double? extendedIconLabelSpacing, - EdgeInsetsGeometry? extendedPadding, - TextStyle? extendedTextStyle, + this._extendedIconLabelSpacing, + this._extendedPadding, + this._extendedTextStyle, super.key, }) : _variant = .extended, mini = false, - _icon = icon, - _extendedIconLabelSpacing = extendedIconLabelSpacing, - _extendedPadding = extendedPadding, - _extendedTextStyle = extendedTextStyle, super(child: label); /// Forwarded to the underlying [FloatingActionButton]. diff --git a/lib/src/buttons/icon_async_button.dart b/lib/src/buttons/icon_async_button.dart index c85b8d2..6611dde 100644 --- a/lib/src/buttons/icon_async_button.dart +++ b/lib/src/buttons/icon_async_button.dart @@ -14,7 +14,7 @@ enum _IconButtonVariant { standard, filled, filledTonal, outlined } /// unlabeled button. class IconAsyncButton extends AsyncMaterialButton { /// Mirrors [IconButton.new]. - const IconAsyncButton({ + const new({ required super.onPressed, required this.icon, super.enabled, @@ -46,7 +46,7 @@ class IconAsyncButton extends AsyncMaterialButton { super(child: icon); /// Mirrors [IconButton.filled]. - const IconAsyncButton.filled({ + const new filled({ required super.onPressed, required this.icon, super.enabled, @@ -78,7 +78,7 @@ class IconAsyncButton extends AsyncMaterialButton { super(child: icon); /// Mirrors [IconButton.filledTonal]. - const IconAsyncButton.filledTonal({ + const new filledTonal({ required super.onPressed, required this.icon, super.enabled, @@ -110,7 +110,7 @@ class IconAsyncButton extends AsyncMaterialButton { super(child: icon); /// Mirrors [IconButton.outlined]. - const IconAsyncButton.outlined({ + const new outlined({ required super.onPressed, required this.icon, super.enabled, diff --git a/lib/src/buttons/outlined_async_button.dart b/lib/src/buttons/outlined_async_button.dart index a1356a0..9009234 100644 --- a/lib/src/buttons/outlined_async_button.dart +++ b/lib/src/buttons/outlined_async_button.dart @@ -3,7 +3,7 @@ part of '../../material_async_button.dart'; /// Async-aware [OutlinedButton]. class OutlinedAsyncButton extends AsyncStandardMaterialButton { /// Mirrors [OutlinedButton.new]. - const OutlinedAsyncButton({ + const new({ required super.onPressed, required super.child, super.onLongPress, @@ -22,7 +22,7 @@ class OutlinedAsyncButton extends AsyncStandardMaterialButton { }); /// Mirrors [OutlinedButton.icon]. - const OutlinedAsyncButton.icon({ + const new icon({ required super.onPressed, required super.icon, required Widget label, diff --git a/lib/src/buttons/text_async_button.dart b/lib/src/buttons/text_async_button.dart index 4dba0cb..1939d4f 100644 --- a/lib/src/buttons/text_async_button.dart +++ b/lib/src/buttons/text_async_button.dart @@ -3,7 +3,7 @@ part of '../../material_async_button.dart'; /// Async-aware [TextButton]. class TextAsyncButton extends AsyncStandardMaterialButton { /// Mirrors [TextButton.new]. - const TextAsyncButton({ + const new({ required super.onPressed, required super.child, super.onLongPress, @@ -22,7 +22,7 @@ class TextAsyncButton extends AsyncStandardMaterialButton { }); /// Mirrors [TextButton.icon]. - const TextAsyncButton.icon({ + const new icon({ required super.onPressed, required super.icon, required Widget label, diff --git a/lib/src/material_async_button_theme.dart b/lib/src/material_async_button_theme.dart index 7c95596..28ece74 100644 --- a/lib/src/material_async_button_theme.dart +++ b/lib/src/material_async_button_theme.dart @@ -21,22 +21,22 @@ part of '../material_async_button.dart'; /// ) /// ``` @immutable -class AsyncButtonTheme extends ThemeExtension { - /// Builds an [AsyncButtonTheme]. Every field is nullable so callers only - /// set the ones they want. - const AsyncButtonTheme({this.loadingBuilder, this.transitionBuilder}); - +class const AsyncButtonTheme({ /// Builds the widget shown in place of the button's child while the future is /// in flight. Falls back to an [AsyncButtonSpinner] when null. The spinner /// inherits the button's foreground; return `AsyncButtonSpinner(color: ...)` /// to recolour it. - final WidgetBuilder? loadingBuilder; + final WidgetBuilder? loadingBuilder, /// Wraps the state widget to animate the idle ⇄ loading swap. `null` by /// default — the button performs no animation of its own. See /// [AsyncButtonTransitionBuilder] for plugging in an [AnimatedSwitcher] / /// [AnimatedSize]. - final AsyncButtonTransitionBuilder? transitionBuilder; + final AsyncButtonTransitionBuilder? transitionBuilder, +}) extends ThemeExtension { + /// Builds an [AsyncButtonTheme]. Every field is nullable so callers only + /// set the ones they want. + this; /// An extension with every field left null — also the zero-config fallback /// returned by [of] when no extension is registered. Renders the default @@ -141,27 +141,14 @@ double _ambientTextLineBox(BuildContext context) { /// child: const Text('Save'), /// ) /// ``` -class AsyncButtonSpinner extends StatelessWidget { - /// Creates a spinner. [color] defaults to the button's foreground and - /// otherwise the primary colour; [strokeWidth] sets the line weight; [size] - /// sets the square the indicator occupies — when null it tracks the ambient - /// font size so the spinner matches the button's label; [semanticsLabel] - /// sets the accessibility label read by screen readers. - const AsyncButtonSpinner({ - this.color, - this.strokeWidth = 2, - this.size, - this.semanticsLabel = 'Loading', - super.key, - }); - +class const AsyncButtonSpinner({ /// Indicator colour. When null, inherits the button's foreground (its /// enabled foreground while loading), falling back to [ColorScheme.primary] /// outside any button. - final Color? color; + final Color? color, /// Stroke width of the [CircularProgressIndicator]. - final double strokeWidth; + final double strokeWidth = 2, /// Side length of the square the indicator is laid out in. When null it /// tracks the ambient label's line-box height (the vertical extent of a @@ -169,10 +156,18 @@ class AsyncButtonSpinner extends StatelessWidget { /// fills the same height the label did and the button doesn't shrink. /// [IconThemeData.size] is intentionally not read here — it is typically 24 /// and would oversize the spinner on text buttons. - final double? size; + final double? size, /// Accessibility label read by screen readers. Defaults to `'Loading'`. - final String? semanticsLabel; + final String? semanticsLabel = 'Loading', + super.key, +}) extends StatelessWidget { + /// Creates a spinner. [color] defaults to the button's foreground and + /// otherwise the primary colour; [strokeWidth] sets the line weight; [size] + /// sets the square the indicator occupies — when null it tracks the ambient + /// font size so the spinner matches the button's label; [semanticsLabel] + /// sets the accessibility label read by screen readers. + this; @override Widget build(BuildContext context) { diff --git a/pubspec.yaml b/pubspec.yaml index 48627a4..ff16e8e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -14,8 +14,8 @@ topics: - widget environment: - sdk: ^3.10.0 - flutter: ">=3.38.0" + sdk: ^3.13.0 + flutter: ">=3.47.0" dependencies: flutter: @@ -25,4 +25,4 @@ dev_dependencies: checks: ^0.3.1 flutter_test: sdk: flutter - very_good_analysis: ^10.2.0 + very_good_analysis: ^11.0.0 diff --git a/test/floating_action_async_button_test.dart b/test/floating_action_async_button_test.dart index 4f3735a..c5bfa18 100644 --- a/test/floating_action_async_button_test.dart +++ b/test/floating_action_async_button_test.dart @@ -22,9 +22,8 @@ void main() { check(find.text('go')).findsOne(); // Pins the .standard -> FloatingActionButton.new mapping: the standard // FAB is 56x56 (small pads to 48x48, large is 96x96). - check( - tester.getSize(find.byType(FloatingActionButton)), - ).equals(const Size(56, 56)); + check(tester.getSize(find.byType(FloatingActionButton))) + .equals(const Size(56, 56)); }); testWidgets('mini is forwarded to the FloatingActionButton', ( @@ -40,9 +39,8 @@ void main() { ), ); // A mini FAB is 40x40 inside a 48x48 padded tap target. - check( - tester.getSize(find.byType(FloatingActionButton)), - ).equals(const Size(48, 48)); + check(tester.getSize(find.byType(FloatingActionButton))) + .equals(const Size(48, 48)); }); testWidgets('a custom heroTag is forwarded for every variant', ( From ceb22a0af37b7b0b5b401936e452947223d77e1d Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Sat, 3 Oct 2026 14:22:04 +0300 Subject: [PATCH 159/176] ci: drop the tag-triggered pub.dev publish workflow - Publishing is manual now: `dart pub publish` from the release commit; no tags. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/publish.yaml | 42 ---------------------------------- 1 file changed, 42 deletions(-) delete mode 100644 .github/workflows/publish.yaml diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml deleted file mode 100644 index b7fedd1..0000000 --- a/.github/workflows/publish.yaml +++ /dev/null @@ -1,42 +0,0 @@ -name: Publish - -on: - push: - tags: - - 'v[0-9]+.[0-9]+.[0-9]+*' - -permissions: - id-token: write - contents: read - -jobs: - verify: - name: Verify tag matches pubspec - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - name: Check tag matches pubspec version - run: | - TAG="${GITHUB_REF#refs/tags/v}" - PUBSPEC=$(grep '^version:' pubspec.yaml | awk '{print $2}') - if [ "$TAG" != "$PUBSPEC" ]; then - echo "::error::Tag v$TAG does not match pubspec.yaml version $PUBSPEC" - exit 1 - fi - - publish: - name: Publish to pub.dev - needs: verify - runs-on: ubuntu-latest - environment: pub.dev - permissions: - id-token: write - contents: read - steps: - - uses: actions/checkout@v6 - - uses: dart-lang/setup-dart@v1 - - uses: subosito/flutter-action@v2 - with: - channel: stable - - run: flutter pub get - - run: flutter pub publish --force From 167ba17e29e6c38bcaca24f6cac5ade6823a2164 Mon Sep 17 00:00:00 2001 From: Mehmet Esen Date: Sat, 3 Oct 2026 16:48:25 +0300 Subject: [PATCH 160/176] docs(plans): add approved sweep-fixes plan for 3.1.0 Executed by a fresh session; the executor deletes this file in its last commit. Co-Authored-By: Claude Opus 5.5 --- plans/sweep-fixes.md | 536 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 536 insertions(+) create mode 100644 plans/sweep-fixes.md diff --git a/plans/sweep-fixes.md b/plans/sweep-fixes.md new file mode 100644 index 0000000..7294324 --- /dev/null +++ b/plans/sweep-fixes.md @@ -0,0 +1,536 @@ +--- +status: approved +created: 2026-10-03 +updated: 2026-10-03 +--- + +# Plan: material_async_button 3.1.0 — sweep fixes, parity params, maintainSize + minLoadingDuration + +Frontmatter `status` is the plan's lifecycle, one owner per transition: `draft` → `approved` (planner, on user approval, before commit) → `in-progress` (executor, before Phase 1) → deleted (executor's last commit, once every § Verification step ran and passed — one that couldn't run keeps it `in-progress`, logged to the § Found tracker). Plans are ephemeral: git is the archive. `outdated` — whoever finds § Files no longer matching the tree; an outdated plan is re-grounded or replaced, never executed. Every transition bumps `updated`. + +## Progress + +- [ ] Phase 1: Loading button keeps its size (P0) +- [ ] Phase 2: Fire-and-forget lint convention +- [ ] Phase 3: Controller state machine +- [ ] Phase 4: Variant fixes +- [ ] Phase 5: Line-box measurement +- [ ] Phase 6: Parity parameters +- [ ] Phase 7: maintainSize + minLoadingDuration +- [ ] Phase 8: Repo meta, packaging, CI +- [ ] Phase 9: Docs, skill, example +- [ ] Phase 10: Release prep, push, CI + +## Problem + +Since 2.0.0 every non-FAB wrapper grows to fill its parent while loading; the controller double-runs or runs dead callbacks after `reset()`, unmount, swap or sharing; some variants lose the spinner; `.icon` constructors reject the documented `enabled:`; docs, skill and repo meta have drifted. 3.1.0 fixes all of it behind tests that failed first, and adds `maintainSize`, `minLoadingDuration` and the missing Material parameters. + +## Invariants + +- One library of `part` files (`lib/material_async_button.dart`): state↔controller wiring uses new library-private members, never new public API. Minor release, additive only: `AsyncButtonController.attach` and `debugLineBoxCache` stay public `@visibleForTesting`; no rename, removal or class-modifier change. +- Keep each file's Dart 3.13 constructor style (`class const X({...})`, `const new name({...})`); new parameters join those lists. Code below is shape, not layout — `dart format` reflows it. +- Loading never disables: the builder `callback` stays non-null while loading; only `enabled: false` / `onPressed: null` disable. Every `AsyncButtonTheme` field resolves widget → theme → built-in default. +- Maintainer rules: no `!`, no `unawaited(...)` (bare drop), no `late final`, comments only for traps/contracts; format tracked files only (`git ls-files -z -- '*.dart' | xargs -0 dart format`). Tests use `package:checks` + `test/_helpers.dart`; disposal errors are asserted `isA()` (beta throws `StateError` from `package:listen`, stable `FlutterError`). +- `analysis_options.yaml` is guarded by a PreToolUse hook (`~/.claude/hooks/config-protection.sh`). The edit this plan makes to it is a user-approved, deliberate config change (fleet decision X-17). In that step only: `touch .dart_tool/.config-edit-ok`, write the file, then `rm .dart_tool/.config-edit-ok` right away. Never use the marker for any other edit, and never leave it behind. +- `git-committer` commits **and pushes** by default. Every dispatch of it in this plan must say **"commit only, do not push"**, except the one push the final phase names. A phase commit must never reach the remote before that. + +## Decisions + +- Floor stays `sdk: ^3.13.0` / `flutter: ">=3.47.0"`, forward-only; release 3.1.0, floor first under `### Changed`. Commit directly on `main` (planner default) via the `git-committer` agent after each passing oracle (conventional commits); never publish, tag, create releases or change repo settings. +- `reset()` abandons the in-flight run: idle and re-armed at once (escape hatch for a hung future); the abandoned run's completion no longer touches state; a tap after `reset()` is a deliberate new run (planner default). +- One controller drives one mounted `AsyncButton`: a second binder fails a debug `assert`; release keeps last-binder-wins. Unbinding is owner-checked and happens in `deactivate()` (rebind in `activate()`). Swapping controllers mid-flight: the incoming controller adopts the in-flight future unless it is already loading. `trigger()` after `dispose()`: debug `assert`; release no-op (`dispose()` clears the callback). +- `maintainSize: true` overlays the loading view on the invisible idle child (footprint = max(idle, loading)); `.icon` constructors and non-collapsed `.extended` keep their icon visible under it (planner default). Default `false` keeps today's swap. +- `minLoadingDuration` holds loading at least that long from trigger start (tap or `controller.trigger()`); errors rethrow after the floor; default `Duration.zero` creates no timer. New theme fields snap in `lerp` at `t < 0.5`; `copyWith` cannot clear a field (documented, not changed). Default FAB `heroTag` sentinel: documented, not changed (planner default). +- `onPressed: null` + `onLongPress` gives an enabled button, as in Flutter (behaviour change, under `### Changed`; planner default). `isSemanticButton` only on `TextAsyncButton.new` (`TextButton.icon` has none); `IconAsyncButton.onLongPress` is gated only on loading (`IconButton` drops it when `onPressed == null`). +- Line-box cache: keep the bounded LRU; clear it from a `PaintingBinding.instance.systemFonts` listener registered once. CHANGELOG history stays as written (incl. the 2.0.0 `FlutterError.onError` claim) except the title and `### Breaking` capitalisation (planner default). The doc-snippet compile check is a scratch file, never committed (planner default). `bug_report.yaml` drops collection_notifiers' "What happened?" placeholder (planner default). + +## Files + +|Path|Action|Exact symbols| +|--|--|--| +|`lib/src/material_async_button_theme.dart`|modify|`AsyncButtonSpinner.build`; `_ambientTextLineBox`; new `_lineBoxCacheListensToFonts`; `AsyncButtonTheme` +`maintainSize`, +`minLoadingDuration`, `copyWith`, `lerp`, `==`, `hashCode`| +|`lib/src/async_button_controller.dart`|modify|new `_run`, `_inFlight`, `_owner`, `_minLoadingDuration`, `_bind`, `_unbind`, `_adopt`, `_settle`, `_withFloor`; `trigger`, `reset`, `dispose`| +|`lib/src/async_button.dart`|modify|`AsyncButton` +`maintainSize`, +`minLoadingDuration`; `_AsyncButtonState` `_bind`, `initState`, `didUpdateWidget`, `activate`, `deactivate`, `build`| +|`lib/src/buttons/async_material_button.dart`|modify|`AsyncMaterialButton` +2 params, `_resolveMaintainSize`; `AsyncStandardMaterialButton` +2 super params, `build`; `_loadingSizing` removed| +|`lib/src/buttons/{elevated,filled,outlined,text,icon,floating_action}_async_button.dart`|modify|all 18 constructors +2 params; `enabled` on the 5 `.icon`/`.tonalIcon`; `TextAsyncButton.isSemanticButton`; `IconAsyncButton` +`onHover`/`onLongPress`/`statesController`, `_buildIconButton`; FAB `build`, `_buildExtended`, `heroTag` doc| +|`test/{layout,icon_enabled,line_box_font}_test.dart`, `test/leak/{flutter_test_config,line_box_leak_test}.dart`|create|ported repros + feature oracles| +|`test/_helpers.dart`, `test/{async_button,async_button_controller,elevated_async_button,outlined_async_button,text_async_button,icon_async_button,floating_action_async_button,material_async_button_theme}_test.dart`|modify|ported repros, masking-test fixes, feature tests; `_helpers.dart`: delete `spinnerTextLineBox`, `asyncButtonTheme` +2 params, new `columnHost`| +|`pubspec.yaml`, `analysis_options.yaml`, `CHANGELOG.md`, `README.md`, `.github/workflows/ci.yaml`, `example/lib/main.dart`, `example/README.md`, `/Users/mehmetesen/pub-dev/SWEEP.md`|modify|see phases| +|`.pubignore`; `plans/sweep-fixes.md` (last commit)|delete|—| +|`.github/{dependabot.yml,PULL_REQUEST_TEMPLATE.md}`, `.github/ISSUE_TEMPLATE/{bug_report.yaml,feature_request.yaml,config.yml}`, `CONTRIBUTING.md`|create|fleet meta| +|`.github/workflows/publish.yaml`|create (restore)|deleted tag-publish workflow, tag trigger commented out| +|`skills/flutter-material-async-button/SKILL.md` → `skills/material-async-button-usage/SKILL.md`|`git mv` + modify|frontmatter, H1, drift| + +Repros (copy allowed): `/Users/mehmetesen/pub-dev/sweep-2026-10-03/repros/material_async_button/`. "Theme file" = `lib/src/material_async_button_theme.dart`; "wrapper files" = `lib/src/buttons/*_async_button.dart`. Each phase adds its bullets under `## Unreleased` in `CHANGELOG.md` (sections `### Added`, `### Changed`, `### Fixed`). + +## Phases + +### Phase 1: Loading button keeps its size (P0) + +- **Files**: theme file, `test/_helpers.dart`, `test/layout_test.dart`, `CHANGELOG.md`. +- **Change**: + 1. Failing first (MAB-M1): `test/layout_test.dart` from repro `layout_test.dart`, widened to all 18 constructors (Elevated `.new/.icon`; Filled `.new/.tonal/.icon/.tonalIcon`; Outlined `.new/.icon`; Text `.new/.icon`; Icon `.new/.filled/.filledTonal/.outlined`; FAB `.new/.small/.large/.extended`), label `Text('Save')`, icon `Icon(Icons.save)`, finder `find.bySubtype()` / `find.byType(IconButton)` / `find.byType(FloatingActionButton)`. Hosts: `pumpHost` (Center) and new `Widget columnHost(Widget child, {ThemeData? theme}) => MaterialApp(theme: theme ?? emptyAsyncButtonTheme, home: Scaffold(body: Column(children: [child])))`. Per case: `pendingPress()`, `idle = tester.getSize(finder)`, `await tester.tap(finder); await tester.pump();`, `loading = getSize`, complete, pump; `check(loading.height).equals(idle.height)`, `check(loading.width).isLessOrEqual(idle.width)`. Keep the repro's body-level `Row` IconAsyncButton height case. + 2. MAB-B1: `AsyncButtonSpinner.build` → `Center(widthFactor: 1, heightFactor: 1, child: SizedBox.square(...))`. CHANGELOG (MAB-X-8, MAB-I11): title `# Changelog`; `### BREAKING` → `### Breaking`; add `## Unreleased` with `### Changed` "Requires Dart 3.13 / Flutter 3.47 (was Dart 3.10 / Flutter 3.38)." and `### Fixed` "Loading buttons no longer grow to fill their parent (every non-FAB wrapper since 2.0.0, and custom `loadingBuilder`s returning `AsyncButtonSpinner`)." +- **Traps**: measure the Material button, never the spinner's `SizedBox` (the blind spot that hid B1). Load by tap — a dropped `trigger()` Future fails the lints until Phase 2. FAB cases pass before the fix (controls). +- **Oracle**: `flutter test test/layout_test.dart` + +### Phase 2: Fire-and-forget lint convention + +- **Files**: `analysis_options.yaml`, the 4 test files holding the 11 `unawaited(` hits. +- **Change** (MAB-X-17): `analysis_options.yaml` becomes exactly: + ```yaml + include: package:very_good_analysis/analysis_options.yaml + + analyzer: + exclude: + - build/** + + linter: + rules: + # Maintainer convention: fire-and-forget is a bare drop; never unawaited(). + unawaited_futures: false + discarded_futures: false + ``` + Replace every `unawaited()` with `;`; drop a `dart:async` import only where the analyzer reports it unused (`Completer` still needs it). +- **Oracle**: `flutter analyze --fatal-infos --fatal-warnings && ! rg -n 'unawaited\(' lib test example && flutter test` + +### Phase 3: Controller state machine + +- **Files**: `async_button_controller.dart`, `async_button.dart`, `test/async_button_controller_test.dart`, `test/async_button_test.dart`, `CHANGELOG.md`. +- **Change**: + 1. Failing first, from repro `controller_test.dart`. In `async_button_test.dart`: MAB-B2 tap → `reset()` → tap → complete run 1 → `calls == 2` and `c.value` true → complete run 2 → idle (do not port the repro's `calls == 1`; it contradicts the run-token decision). MAB-S1 internal controller, tap (pending), re-pump the same button with `controller: ext` → `ext.value` true; tap → `calls == 1`; complete → idle. MAB-B3 two `TextAsyncButton(controller: c)`, each in `SizedBox(width: 100, height: 48)`, in `Row(mainAxisSize: .min)` → `check(tester.takeException()).isA()`. MAB-B4 the repro's unmount and swap tests as written, plus controls that must pass: same-slot type swap (`ElevatedAsyncButton` → `TextAsyncButton`, same `c`), same-slot key swap, `GlobalKey` reparent into a `Padding` — each `takeException()` null, `c.canTrigger` true, `trigger()` runs the new callback. + In `async_button_controller_test.dart`, MAB-B10: attach, dispose, `check(c.canTrigger).isFalse()`, `await c.trigger().then((_) {}, onError: (Object e) => err = e)`; `ran == 0`, `err` `isA()`. + MAB-M2: in "swapping from external to internal controller" (`async_button_test.dart:314`) and "swapping the external controller transfers listening without leak" (`:342`) count `onPressed` calls per controller; the detached controller's count stays 0 after its `trigger()`. + 2. Controller: new members and rewritten methods (keep public docs; reword `reset()` per Decisions): + ```dart + int _run = 0; Future? _inFlight; Object? _owner; Duration _minLoadingDuration = Duration.zero; + void _bind(Object owner, {required AsyncCallback? onPressed}) { + assert(_owner == null || identical(_owner, owner), 'An AsyncButtonController can drive only one mounted AsyncButton.'); + _owner = owner; _onPressed = onPressed; + } + void _unbind(Object owner) { if (identical(_owner, owner)) { _owner = null; _onPressed = null; } } + Future trigger() async { + assert(ChangeNotifier.debugAssertNotDisposed(this), 'trigger() after dispose()'); + final onPressed = _onPressed; + if (_isLoading || onPressed == null) { return; } + final run = ++_run; _setLoading(true); + final pending = _withFloor(onPressed, _minLoadingDuration); _inFlight = pending; + try { await pending; } finally { _settle(run); } + } + static Future _withFloor(AsyncCallback onPressed, Duration floor) async { + final minimum = floor > Duration.zero ? Future.delayed(floor) : null; + try { await onPressed(); } finally { if (minimum != null) { await minimum; } } + } + void _adopt(Future pending) { + final run = ++_run; _inFlight = pending; _setLoading(true); + pending.then((_) => _settle(run), onError: (Object _) => _settle(run)); + } + void _settle(int run) { if (run == _run) { _inFlight = null; _setLoading(false); } } + void reset() { _run++; _inFlight = null; _setLoading(false); } + // dispose(): _isDisposed = true; _onPressed = null; _owner = null; super.dispose(); + ``` + `_minLoadingDuration` stays zero until Phase 7. + 3. `_AsyncButtonState`: `void _bind() => controller._bind(this, onPressed: effectiveOnPressed);`. `initState`: assign controller, `addListener(listener)`, `_bind()`. `didUpdateWidget` on controller change: `final previous = controller; final inFlight = previous._inFlight;` `previous..removeListener(listener).._unbind(this)`; dispose `previous` only when `oldWidget.controller == null`; assign + `addListener`; `if (inFlight != null && !controller.value) { controller._adopt(inFlight); }`; then always `_bind()`. Add `activate()` (`super.activate(); _bind();`) and `deactivate()` (`controller._unbind(this); super.deactivate();`). `dispose()` unchanged. CHANGELOG: `### Fixed` — reset mid-flight no longer lets the stale run clear a new run; a controller swap mid-flight keeps the loading state; an external controller detaches when its button unmounts or is swapped out (`canTrigger` false, `trigger()` no-op); `trigger()` after `dispose()` never runs `onPressed`. `### Changed` — one controller bound to two mounted buttons fails a debug assertion; `reset()` abandons the in-flight run. +- **Traps**: unbinding in `dispose` would trip the assert on every same-slot swap — the new element's `initState` runs before the old `dispose`, but after the old `deactivate`. An unbounded B3 host turns the `ErrorWidget` into a second (layout) exception and `takeException()` returns a String. `onPressed()` must run inside `_withFloor`'s `try` so a synchronous throw still settles. +- **Oracle**: `flutter test test/async_button_controller_test.dart test/async_button_test.dart` + +### Phase 4: Variant fixes + +- **Files**: the 6 wrapper files, `async_material_button.dart`, `test/icon_enabled_test.dart`, `test/{icon,floating_action,elevated}_async_button_test.dart`, `CHANGELOG.md`. +- **Change**: + 1. Failing first: `test/icon_enabled_test.dart` — the 5 `.icon`/`.tonalIcon` constructors with `enabled: false, onPressed: () async {}`, each pumped alone, `check(tester.widget(find.bySubtype()).enabled).isFalse()`; run it alone first (compile error expected). Repro `variants_test.dart` B5 → `icon_async_button_test.dart`, B6 → `floating_action_async_button_test.dart`; repro `hypotheses_test.dart` "onPressed: null + onLongPress keeps the button enabled" → `elevated_async_button_test.dart`. + 2. MAB-B7: `super.enabled,` after `super.statesController,` in `ElevatedAsyncButton.icon`, `FilledAsyncButton.icon`, `FilledAsyncButton.tonalIcon`, `OutlinedAsyncButton.icon`, `TextAsyncButton.icon`. + 3. MAB-B5: `IconAsyncButton._buildIconButton({required VoidCallback? onPressed, required Widget icon, required bool isLoading})` passes `selectedIcon: isLoading ? null : selectedIcon`. + 4. MAB-B6: `FloatingActionAsyncButton.build`: `final collapsedIcon = _variant == .extended && !isExtended ? _icon : null;` → `AsyncButton(child: collapsedIcon ?? child, …)`, sizing `_variant == .extended && collapsedIcon == null ? .max : .iconSize`; `_buildExtended(callback, animatedChild, isLoading:, collapsed: collapsedIcon != null)` with `icon: collapsed ? animatedChild : (isLoading ? null : _icon)`, `label: collapsed ? child : animatedChild`. + 5. MAB-I6: `AsyncStandardMaterialButton.build` → `final longPress = enabled && !isLoading ? onLongPress : null;`. CHANGELOG: `### Fixed` selected `IconAsyncButton` shows the spinner; collapsed extended FAB shows the spinner; `enabled` on every `.icon`/`.tonalIcon`. `### Changed` `onPressed: null` with `onLongPress` keeps the button enabled for long-press, as in Flutter. +- **Traps**: find `.icon` buttons with `find.bySubtype()` — they may be private subclasses. A collapsed extended FAB with no `icon` stays blank, as in Flutter. +- **Oracle**: `flutter test test/icon_enabled_test.dart test/icon_async_button_test.dart test/floating_action_async_button_test.dart test/elevated_async_button_test.dart` + +### Phase 5: Line-box measurement + +- **Files**: theme file, `pubspec.yaml`, `test/leak/*`, `test/line_box_font_test.dart`, `test/_helpers.dart`, `test/{elevated,outlined,text,floating_action}_async_button_test.dart`, `test/material_async_button_theme_test.dart`, `CHANGELOG.md`. +- **Change**: + 1. Failing first: dev dep `leak_tracker_flutter_testing: ^3.0.10` (resolves on 3.47.0 and 3.47.5); repro `leak/flutter_test_config.dart` → `test/leak/flutter_test_config.dart`, `leak/leak_test.dart` → `test/leak/line_box_leak_test.dart` (drop both `// ignore: depend_on_referenced_packages`). Repro `font_cache_test.dart` → `test/line_box_font_test.dart`, replacing the hard-coded SDK path fallback with `final root = Platform.environment['FLUTTER_ROOT']; if (root == null) fail('flutter test sets FLUTTER_ROOT');`. + 2. MAB-B8: `_ambientTextLineBox` reads `painter.preferredLineHeight` into a local, calls `painter.dispose()`, then caches and returns it. + 3. MAB-B9: top-level `var _lineBoxCacheListensToFonts = false;`; first thing in `_ambientTextLineBox`: if false, set true and `PaintingBinding.instance.systemFonts.addListener(_lineBoxCache.clear);`. + 4. MAB-M3: delete `spinnerTextLineBox`; at `elevated_async_button_test.dart:160`, `outlined_async_button_test.dart:82`, `text_async_button_test.dart:48`, `floating_action_async_button_test.dart:214` use `tester.getSize(find.text('

$U+8fGkKT$S#H+ZAX=2X?m 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 &5GmD#=ci6)F0Qx*mq3@BP7AIn3qFYp?pX^S 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