diff --git a/lib/src/common_widgets/ll_app.dart b/lib/src/common_widgets/ll_app.dart new file mode 100644 index 0000000..135d26c --- /dev/null +++ b/lib/src/common_widgets/ll_app.dart @@ -0,0 +1,159 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:lm_labs_utils/localization.dart'; + +class LLApp extends ConsumerWidget { + final WidgetBuilder appBuilder; + final void Function(WidgetRef, FutureProvider) onRetry; // () { + // ref.invalidate(onboardingRepositoryProvider); + // ref.invalidate(appStartupProvider); + // } + final WidgetBuilder loadingBuilder; + final Widget Function( + BuildContext context, + Object error, + StackTrace? stackTrace, + VoidCallback onRetry, + ) errorBuilder; + + final FutureProvider initAppProvider; + + const LLApp({ + required this.appBuilder, + required this.initAppProvider, + super.key, + }) : onRetry = defaultOnRetry, + loadingBuilder = defaultLoadingBuilder, + errorBuilder = defaultErrorBuilder; + + const LLApp.custom({ + required this.appBuilder, + required this.initAppProvider, + super.key, + this.onRetry = defaultOnRetry, + this.loadingBuilder = defaultLoadingBuilder, + this.errorBuilder = defaultErrorBuilder, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) => + switch (ref.watch(initAppProvider)) { + AsyncError(error: final error, stackTrace: final stackTrace) => + errorBuilder( + context, + error, + stackTrace, + () => onRetry(ref, initAppProvider), + ), + AsyncLoading() => loadingBuilder(context), + AsyncData(value: final _) || AsyncValue() => appBuilder(context), + }; + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add( + ObjectFlagProperty.has('appBuilder', appBuilder), + ) + ..add( + ObjectFlagProperty.has( + 'loadingBuilder', + loadingBuilder, + ), + ) + ..add( + ObjectFlagProperty< + Widget Function( + BuildContext context, + Object error, + StackTrace? stackTrace, + VoidCallback onRetry, + )>.has('errorBuilder', errorBuilder), + ) + ..add( + ObjectFlagProperty< + void Function( + WidgetRef p1, + FutureProvider p2, + )>.has('onRetry', onRetry), + ) + ..add( + DiagnosticsProperty>( + 'initAppProvider', + initAppProvider, + ), + ); + } + + static Widget defaultErrorBuilder( + BuildContext context, + Object error, + StackTrace? stackTrace, + VoidCallback onRetry, + ) => + _LLAppErrorWidget( + message: error.toString(), + onRetry: onRetry, + ); + + static Widget defaultLoadingBuilder(BuildContext context) => + const _LLAppLoadingWidget(); + + static void defaultOnRetry( + WidgetRef ref, + FutureProvider initAppProvider, + ) { + ref.invalidate(initAppProvider); + } +} + +class _LLAppErrorWidget extends StatelessWidget { + final String message; + final VoidCallback onRetry; + + const _LLAppErrorWidget({ + required this.message, + required this.onRetry, + }); + + @override + Widget build(BuildContext context) => MaterialApp( + home: Scaffold( + body: Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text(message, style: Theme.of(context).textTheme.headlineSmall), + const SizedBox(height: 16), + ElevatedButton( + onPressed: onRetry, + child: Text('Retry'.i18n), + ), + ], + ), + ), + ), + ); + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(StringProperty('message', message)) + ..add(ObjectFlagProperty.has('onRetry', onRetry)); + } +} + +class _LLAppLoadingWidget extends StatelessWidget { + const _LLAppLoadingWidget(); + + @override + Widget build(BuildContext context) => const MaterialApp( + home: Scaffold( + body: Center( + child: CircularProgressIndicator(), + ), + ), + ); +} diff --git a/lib/src/common_widgets/ll_tappable.dart b/lib/src/common_widgets/ll_tappable.dart index 22aff29..3da0580 100644 --- a/lib/src/common_widgets/ll_tappable.dart +++ b/lib/src/common_widgets/ll_tappable.dart @@ -16,7 +16,7 @@ class LLTappable extends HookWidget { super.key, }) : _builder = LLTappable._constrainedBuilder; - const LLTappable.shrink({ + const LLTappable.expand({ required this.child, this.onTap, this.duration = const Duration(milliseconds: 500), @@ -56,13 +56,7 @@ class LLTappable extends HookWidget { minWidth: 48, minHeight: 48, ), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - child, - ], - ), + child: child, ); static Widget _simpleBuilder(Widget child) => child; diff --git a/lib/src/localization/i18n.dart b/lib/src/localization/i18n.dart index e61c20a..9364835 100644 --- a/lib/src/localization/i18n.dart +++ b/lib/src/localization/i18n.dart @@ -17,8 +17,8 @@ extension LmLabsUtilsLocalization on String { 'fr': 'Non', } + { - 'en': '', - 'fr': '', + 'en': 'Retry', + 'fr': 'Réessayer', } + { 'en': '', diff --git a/lib/src/utils/future_easy_throttle.dart b/lib/src/utils/future_easy_throttle.dart index 5912ea9..d2fc6e3 100644 --- a/lib/src/utils/future_easy_throttle.dart +++ b/lib/src/utils/future_easy_throttle.dart @@ -49,6 +49,7 @@ class FutureEasyThrottle { _FutureEasyThrottleOperation( onExecute, Timer(duration, () { + _operations[tag]?.$2.tryComplete(); _operations[tag]?.$1.timer.cancel(); final removed = _operations.remove(tag); diff --git a/lib/widgets.dart b/lib/widgets.dart index fdc8142..7b9ce6d 100644 --- a/lib/widgets.dart +++ b/lib/widgets.dart @@ -1,3 +1,4 @@ export 'src/common_widgets/async_value_widget.dart'; +export 'src/common_widgets/ll_app.dart'; export 'src/common_widgets/ll_app_bar.dart'; export 'src/common_widgets/ll_tappable.dart'; diff --git a/pubspec.lock b/pubspec.lock index fd6cd9c..b8078b6 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -77,18 +77,18 @@ packages: dependency: transitive description: name: build_resolvers - sha256: "64e12b0521812d1684b1917bc80945625391cb9bdd4312536b1d69dcb6133ed8" + sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a" url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.4.2" build_runner: dependency: "direct dev" description: name: build_runner - sha256: "67d591d602906ef9201caf93452495ad1812bea2074f04e25dbd7c133785821b" + sha256: "581bacf68f89ec8792f5e5a0b2c4decd1c948e97ce659dc783688c8a88fbec21" url: "https://pub.dev" source: hosted - version: "2.4.7" + version: "2.4.8" build_runner_core: dependency: transitive description: @@ -109,10 +109,10 @@ packages: dependency: transitive description: name: built_value - sha256: "723b4021e903217dfc445ec4cf5b42e27975aece1fc4ebbc1ca6329c2d9fb54e" + sha256: a3ec2e0f967bc47f69f95009bb93db936288d61d5343b9436e378b28a2f830c6 url: "https://pub.dev" source: hosted - version: "8.7.0" + version: "8.9.0" characters: dependency: transitive description: @@ -141,10 +141,10 @@ packages: dependency: transitive description: name: cli_util - sha256: b8db3080e59b2503ca9e7922c3df2072cf13992354d5e944074ffa836fba43b7 + sha256: c05b7406fdabc7a49a3929d4af76bcaccbbffcbcdcf185b082e1ae07da323d19 url: "https://pub.dev" source: hosted - version: "0.4.0" + version: "0.4.1" clock: dependency: transitive description: @@ -157,10 +157,10 @@ packages: dependency: transitive description: name: code_builder - sha256: "1be9be30396d7e4c0db42c35ea6ccd7cc6a1e19916b5dc64d6ac216b5544d677" + sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37 url: "https://pub.dev" source: hosted - version: "4.7.0" + version: "4.10.0" collection: dependency: transitive description: @@ -205,34 +205,34 @@ packages: dependency: "direct dev" description: name: custom_lint - sha256: "198ec6b8e084d22f508a76556c9afcfb71706ad3f42b083fe0ee923351a96d90" + sha256: dfb893ff17c83cf08676c6b64df11d3e53d80590978d7c1fb242afff3ba6dedb url: "https://pub.dev" source: hosted - version: "0.5.7" + version: "0.5.8" custom_lint_builder: dependency: transitive description: name: custom_lint_builder - sha256: dfcfa987d2bd9d0ba751ef4bdef0f6c1aa0062f2a67fe716fd5f3f8b709d6418 + sha256: "8df6634b38a36a6c6cb74a9c0eb02e9ba0b0ab89b29e38e6daa86e8ed2c6288d" url: "https://pub.dev" source: hosted - version: "0.5.7" + version: "0.5.8" custom_lint_core: dependency: transitive description: name: custom_lint_core - sha256: f84c3fe2f27ef3b8831953e477e59d4a29c2952623f9eac450d7b40d9cdd94cc + sha256: "2b235be098d157e244f18ea905a15a18c16a205e30553888fac6544bbf52f03f" url: "https://pub.dev" source: hosted - version: "0.5.7" + version: "0.5.8" dart_style: dependency: transitive description: name: dart_style - sha256: abd7625e16f51f554ea244d090292945ec4d4be7bfbaf2ec8cccea568919d334 + sha256: "40ae61a5d43feea6d24bd22c0537a6629db858963b99b4bc1c3db80676f32368" url: "https://pub.dev" source: hosted - version: "2.3.3" + version: "2.3.4" dbus: dependency: transitive description: @@ -315,10 +315,10 @@ packages: dependency: "direct main" description: name: flutter_hooks - sha256: "7c8db779c2d1010aa7f9ea3fbefe8f86524fcb87b69e8b0af31e1a4b55422dec" + sha256: "09f64db63fee3b2ab8b9038a1346be7d8986977fae3fec601275bf32455ccfc0" url: "https://pub.dev" source: hosted - version: "0.20.3" + version: "0.20.4" flutter_lints: dependency: transitive description: @@ -354,10 +354,10 @@ packages: dependency: "direct dev" description: name: freezed - sha256: "21bf2825311de65501d22e563e3d7605dff57fb5e6da982db785ae5372ff018a" + sha256: "6c5031daae12c7072b3a87eff98983076434b4889ef2a44384d0cae3f82372ba" url: "https://pub.dev" source: hosted - version: "2.4.5" + version: "2.4.6" freezed_annotation: dependency: "direct main" description: @@ -554,10 +554,10 @@ packages: dependency: transitive description: name: plugin_platform_interface - sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8 + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" url: "https://pub.dev" source: hosted - version: "2.1.7" + version: "2.1.8" pool: dependency: transitive description: @@ -655,10 +655,10 @@ packages: dependency: transitive description: name: source_gen - sha256: fc0da689e5302edb6177fdd964efcb7f58912f43c28c2047a808f5bfff643d16 + sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832" url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.5.0" source_helper: dependency: transitive description: @@ -759,10 +759,10 @@ packages: dependency: transitive description: name: uuid - sha256: df5a4d8f22ee4ccd77f8839ac7cb274ebc11ef9adcce8b92be14b797fe889921 + sha256: cd210a09f7c18cbe5a02511718e0334de6559871052c90a90c0cca46a4aa81c8 url: "https://pub.dev" source: hosted - version: "4.2.1" + version: "4.3.3" vector_math: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index d05b178..ec4de56 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,7 +4,7 @@ description: "A new Flutter project." # Prevent accidental publishing to pub.dev. publish_to: 'none' -version: 1.0.0+4 +version: 1.0.0+5 environment: sdk: '>=3.2.0 <4.0.0' diff --git a/test/full_coverage_test.dart b/test/full_coverage_test.dart new file mode 100644 index 0000000..76b1b2b --- /dev/null +++ b/test/full_coverage_test.dart @@ -0,0 +1,25 @@ +// ignore_for_file: unused_import +import 'package:lm_labs_utils/constants.dart'; +import 'package:lm_labs_utils/extensions.dart'; +import 'package:lm_labs_utils/http_client.dart'; +import 'package:lm_labs_utils/localization.dart'; +import 'package:lm_labs_utils/main.dart'; +import 'package:lm_labs_utils/snack_bar.dart'; +import 'package:lm_labs_utils/src/common_widgets/async_value_widget.dart'; +import 'package:lm_labs_utils/src/common_widgets/ll_app.dart'; +import 'package:lm_labs_utils/src/common_widgets/ll_app_bar.dart'; +import 'package:lm_labs_utils/src/common_widgets/ll_tappable.dart'; +import 'package:lm_labs_utils/src/constants/platform.dart'; +import 'package:lm_labs_utils/src/features/snack_bar/presentation/snack_bar_provider.dart'; +import 'package:lm_labs_utils/src/localization/i18n.dart'; +import 'package:lm_labs_utils/src/utils/extensions/completer_extension.dart'; +import 'package:lm_labs_utils/src/utils/future_easy_debounce.dart'; +import 'package:lm_labs_utils/src/utils/future_easy_throttle.dart'; +import 'package:lm_labs_utils/src/utils/http_client/cancel_token_ref.dart'; +import 'package:lm_labs_utils/src/utils/http_client/dio_provider.dart'; +import 'package:lm_labs_utils/src/utils/http_client/logger_interceptor.dart'; +import 'package:lm_labs_utils/src/utils/http_client/network_interceptor.dart'; +import 'package:lm_labs_utils/utils.dart'; +import 'package:lm_labs_utils/widgets.dart'; + +void main() {}