From 450c26b187cac54c4a725c226f901a355fea9adc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20M=C3=BCller?= Date: Tue, 23 Apr 2024 14:48:12 +0200 Subject: [PATCH] WIP state management loadable errorbar --- .../marianum_message_controller.dart | 2 +- lib/state/infrastructure/loadable_state.dart | 10 ++- .../widgets/loadable_controller_consumer.dart | 72 +++++++++++++++---- lib/view/pages/more/test.dart | 10 ++- 4 files changed, 73 insertions(+), 21 deletions(-) diff --git a/lib/state/app/application/marianumMessage/marianum_message_controller.dart b/lib/state/app/application/marianumMessage/marianum_message_controller.dart index 47e7881..22ebc2b 100644 --- a/lib/state/app/application/marianumMessage/marianum_message_controller.dart +++ b/lib/state/app/application/marianumMessage/marianum_message_controller.dart @@ -19,6 +19,6 @@ class MarianumMessageController extends Controller { LoadableState done(TState state) => LoadableState(loadingState: LoadingState.none, data: state); - LoadableState error(TState state) => - LoadableState(loadingState: LoadingState.none, data: state); + LoadableState error({TState? state}) => + LoadableState(loadingState: LoadingState.failed, data: state); bool isBackgroundLoading() => loadingState == LoadingState.loading && data != null; + bool hasError() => + loadingState == LoadingState.failed; + bool hasStateData() => data != null; + + bool errorBarVisible() => + hasError() && hasStateData(); } enum LoadingState { diff --git a/lib/state/widgets/loadable_controller_consumer.dart b/lib/state/widgets/loadable_controller_consumer.dart index 3f82187..7ac0412 100644 --- a/lib/state/widgets/loadable_controller_consumer.dart +++ b/lib/state/widgets/loadable_controller_consumer.dart @@ -5,35 +5,77 @@ import '../infrastructure/loadable_state.dart'; import '../infrastructure/state_extensions.dart'; class LoadableControllerConsumer, TState extends LoadableState> extends StatelessWidget { - final Widget Function(BuildContext context, TState state) child; + final Widget child; const LoadableControllerConsumer({required this.child, super.key}); + final Duration animationDuration = const Duration(milliseconds: 200); + @override Widget build(BuildContext context) { var state = context.readController().state; - return Stack( + + var loadableContent = Stack( children: [ - if(!state.hasStateData()) const Center(child: CircularProgressIndicator()), + AnimatedOpacity( + opacity: !state.hasStateData() ? 1.0 : 0.0, + duration: animationDuration, + curve: Curves.easeInOut, + child: const Center(child: CircularProgressIndicator()), + ), AnimatedSwitcher( - duration: const Duration(milliseconds: 100), + duration: animationDuration, transitionBuilder: (Widget child, Animation animation) => SlideTransition( - position: Tween( - begin: const Offset(0.0, -1.0), - end: Offset.zero, - ).animate(animation), - child: child, - ), - child: state.isBackgroundLoading() ? const LinearProgressIndicator() : const SizedBox.shrink(), + position: Tween( + begin: const Offset(0.0, -1.0), + end: Offset.zero, + ).animate(animation), + child: child, + ), + child: state.isBackgroundLoading() && !state.errorBarVisible() ? const LinearProgressIndicator() : const SizedBox.shrink(), ), AnimatedOpacity( - opacity: state.hasStateData() ? 1.0 : 0.0, - duration: const Duration(milliseconds: 100), - curve: Curves.easeInOut, - child: state.hasStateData() ? child(context, state) : const SizedBox.shrink() + opacity: state.hasStateData() ? 1.0 : 0.0, + duration: animationDuration, + curve: Curves.easeInOut, + child: state.hasStateData() ? child : const SizedBox.shrink() ), ], ); + + var errorBar = AnimatedSwitcher( + duration: animationDuration, + transitionBuilder: (Widget child, Animation animation) => SlideTransition( + position: Tween( + begin: const Offset(0.0, -1.0), + end: Offset.zero, + ).animate(animation), + child: child, + ), + child: !state.errorBarVisible() + ? const SizedBox.shrink() + : Container( + height: 20, + decoration: const BoxDecoration( + color: Colors.red, + ), + child: const Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.wifi_find_outlined, size: 12), + SizedBox(width: 10), + Text('Keine Verbindung', style: TextStyle(fontSize: 12)) + ], + ), + ), + ); + + return Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [errorBar, loadableContent], + ); } } diff --git a/lib/view/pages/more/test.dart b/lib/view/pages/more/test.dart index dcac21a..fb1966a 100644 --- a/lib/view/pages/more/test.dart +++ b/lib/view/pages/more/test.dart @@ -15,13 +15,13 @@ class Test extends StatelessWidget { Widget build(BuildContext context) => ControllerProvider( create: (context) => MarianumMessageController(), child: (context) => Scaffold( - appBar: AppBar(title: const Text("TEST")), + appBar: AppBar(title: const Text('TEST')), body: LoadableControllerConsumer>( - child: (context, data) => Column( + child: Column( children: [ TextButton( onPressed: () => context.readController().loading(), - child: Text(data.loadingState.toString()) + child: Text(context.watchController().state.loadingState.toString()) ), TextButton( onPressed: () => context.readController().backgroundLoading(), @@ -31,6 +31,10 @@ class Test extends StatelessWidget { onPressed: () => context.readController().done(), child: Text(context.watchController().state.loadingState.toString()) ), + TextButton( + onPressed: () => context.readController().error(), + child: Text(context.watchController().state.loadingState.toString()) + ), ControllerConsumer>(child: (context, state) => Text(state.data!.test.toString())), SubSelectedControllerConsumer, LoadingState>( subselect: (state) => state.loadingState,