implemented new loadable state concept

This commit is contained in:
2024-05-05 22:58:40 +02:00
parent f58a2ec8cd
commit 6ad8203b6a
31 changed files with 1085 additions and 214 deletions

@ -0,0 +1,21 @@
import 'package:flutter/material.dart';
class LoadableStateBackgroundLoading extends StatelessWidget {
final bool visible;
const LoadableStateBackgroundLoading({required this.visible, super.key});
final Duration animationDuration = const Duration(milliseconds: 200);
@override
Widget build(BuildContext context) => AnimatedSwitcher(
duration: animationDuration,
transitionBuilder: (Widget child, Animation<double> animation) => SlideTransition(
position: Tween<Offset>(
begin: const Offset(0.0, -1.0),
end: Offset.zero,
).animate(animation),
child: child,
),
child: visible ? const LinearProgressIndicator() : const SizedBox.shrink(),
);
}

@ -0,0 +1,42 @@
import 'package:bloc/bloc.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../loadable_state.dart';
import 'loadable_state_background_loading.dart';
import 'loadable_state_error_bar.dart';
import 'loadable_state_primary_loading.dart';
// TODO might be a simpler way
class LoadableStateConsumer<TController extends Bloc<dynamic, TWrappedState>, TWrappedState extends LoadableState<TState>, TState> extends StatelessWidget {
final Widget Function(TState state) child;
const LoadableStateConsumer({required this.child, super.key});
static Duration animationDuration = const Duration(milliseconds: 200);
@override
Widget build(BuildContext context) {
var state = context.read<TController>().state as LoadableState<TState>;
return Column(
children: [
LoadableStateErrorBar(visible: state.showError()),
Expanded(
child: Stack(
children: [
LoadableStatePrimaryLoading(visible: state.showPrimaryLoading()),
LoadableStateBackgroundLoading(visible: state.showBackgroundLoading()),
AnimatedOpacity(
opacity: state.showContent() ? 1.0 : 0.0,
duration: animationDuration,
curve: Curves.easeInOut,
child: state.showContent() ? child(state.data) : const SizedBox.shrink()
),
],
),
)
],
);
}
}

@ -0,0 +1,59 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../utilityWidgets/bloc_providing_builder.dart';
import '../bloc/loadable_state_bloc.dart';
import '../bloc/loadable_state_state.dart';
class LoadableStateErrorBar extends StatelessWidget {
final bool visible;
const LoadableStateErrorBar({required this.visible, super.key});
final Duration animationDuration = const Duration(milliseconds: 200);
@override
Widget build(BuildContext context) => BlocProvidingBuilder<LoadableStateBloc, LoadableStateState>(
create: (context) => LoadableStateBloc(),
child: (context, state) => AnimatedSize(
duration: animationDuration,
child: AnimatedSwitcher(
duration: animationDuration,
transitionBuilder: (Widget child, Animation<double> animation) => SlideTransition(
position: Tween<Offset>(
begin: const Offset(0.0, -1.0),
end: Offset.zero,
).animate(animation),
child: child,
),
child: Visibility(
key: Key(visible.hashCode.toString()),
visible: visible,
replacement: const SizedBox(width: double.infinity),
child: Builder(
builder: (context) {
var controller = context.watch<LoadableStateBloc>();
var status = controller.connectivityStatusKnown() && !controller.isConnected()
? (icon: Icons.wifi_off_outlined, text: 'Offline', color: Colors.grey.shade600)
: (icon: Icons.wifi_find_outlined, text: 'Verbindung fehlgeschlagen', color: Theme.of(context).primaryColor);
return Container(
height: 20,
decoration: BoxDecoration(
color: status.color,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(status.icon, size: 14),
const SizedBox(width: 10),
Text(status.text, style: const TextStyle(fontSize: 12))
],
),
);
},
)
)
),
),
);
}

@ -0,0 +1,16 @@
import 'package:flutter/material.dart';
class LoadableStatePrimaryLoading extends StatelessWidget {
final bool visible;
const LoadableStatePrimaryLoading({required this.visible, super.key});
final Duration animationDuration = const Duration(milliseconds: 200);
@override
Widget build(BuildContext context) => AnimatedOpacity(
opacity: visible ? 1.0 : 0.0,
duration: animationDuration,
curve: Curves.easeInOut,
child: const Center(child: CircularProgressIndicator()),
);
}