loadable error screen, reload actions, autoreload
This commit is contained in:
@ -2,10 +2,14 @@ import 'package:bloc/bloc.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../../utilityWidgets/bloc_module.dart';
|
||||
import '../../utilityWidgets/loadableHydratedBloc/loadable_hydrated_bloc_event.dart';
|
||||
import '../bloc/loadable_state_bloc.dart';
|
||||
import '../bloc/loadable_state_state.dart';
|
||||
import '../loadable_state.dart';
|
||||
import 'loadable_state_background_loading.dart';
|
||||
import 'loadable_state_error_bar.dart';
|
||||
import 'loadable_state_error_screen.dart';
|
||||
import 'loadable_state_primary_loading.dart';
|
||||
|
||||
class LoadableStateConsumer<TController extends Bloc<LoadableHydratedBlocEvent<TState>, LoadableState<TState>>, TState> extends StatelessWidget {
|
||||
@ -17,26 +21,51 @@ class LoadableStateConsumer<TController extends Bloc<LoadableHydratedBlocEvent<T
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var loadableState = context.watch<TController>().state;
|
||||
var childWidget = RefreshIndicator(
|
||||
onRefresh: () {
|
||||
loadableState.error != null && loadableState.error!.retry != null
|
||||
? loadableState.error!.retry!()
|
||||
: null;
|
||||
return Future.value();
|
||||
},
|
||||
child: SizedBox(
|
||||
height: MediaQuery.of(context).size.height,
|
||||
child: loadableState.showContent()
|
||||
? child(loadableState.data, loadableState.isLoading)
|
||||
: const SizedBox.shrink(),
|
||||
),
|
||||
// SingleChildScrollView( // TODO not all childs are reloadable
|
||||
// physics: const AlwaysScrollableScrollPhysics(),
|
||||
// child:
|
||||
// ),
|
||||
);
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
LoadableStateErrorBar(visible: loadableState.showError()),
|
||||
Expanded(
|
||||
child: Stack(
|
||||
children: [
|
||||
LoadableStatePrimaryLoading(visible: loadableState.showPrimaryLoading()),
|
||||
LoadableStateBackgroundLoading(visible: loadableState.showBackgroundLoading()),
|
||||
return BlocModule<LoadableStateBloc, LoadableStateState>(
|
||||
create: (context) => LoadableStateBloc(),
|
||||
child: (context, bloc, state) {
|
||||
bloc.loadingError = loadableState.error;
|
||||
return Column(
|
||||
children: [
|
||||
LoadableStateErrorBar(visible: loadableState.showErrorBar()),
|
||||
Expanded(
|
||||
child: Stack(
|
||||
children: [
|
||||
LoadableStatePrimaryLoading(visible: loadableState.showPrimaryLoading()),
|
||||
LoadableStateBackgroundLoading(visible: loadableState.showBackgroundLoading()),
|
||||
LoadableStateErrorScreen(visible: loadableState.showError()),
|
||||
|
||||
AnimatedOpacity(
|
||||
opacity: loadableState.showContent() ? 1.0 : 0.0,
|
||||
duration: animationDuration,
|
||||
curve: Curves.easeInOut,
|
||||
child: loadableState.showContent() ? child(loadableState.data, loadableState.isLoading) : const SizedBox.shrink()
|
||||
AnimatedOpacity(
|
||||
opacity: loadableState.showContent() ? 1.0 : 0.0,
|
||||
duration: animationDuration,
|
||||
curve: Curves.easeInOut,
|
||||
child: childWidget,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
import '../../utilityWidgets/bloc_module.dart';
|
||||
import '../bloc/loadable_state_bloc.dart';
|
||||
import '../bloc/loadable_state_state.dart';
|
||||
|
||||
class LoadableStateErrorBar extends StatelessWidget {
|
||||
final bool visible;
|
||||
@ -12,48 +10,49 @@ class LoadableStateErrorBar extends StatelessWidget {
|
||||
final Duration animationDuration = const Duration(milliseconds: 200);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => BlocModule<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);
|
||||
Widget build(BuildContext context) => 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 bloc = context.watch<LoadableStateBloc>();
|
||||
var status = (
|
||||
icon: bloc.connectionIcon(),
|
||||
text: bloc.connectionText(),
|
||||
color: bloc.connectivityStatusKnown() && !bloc.isConnected()
|
||||
? Colors.grey.shade600
|
||||
: 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))
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
)
|
||||
)
|
||||
),
|
||||
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,42 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../bloc/loadable_state_bloc.dart';
|
||||
import 'loadable_state_consumer.dart';
|
||||
|
||||
class LoadableStateErrorScreen extends StatelessWidget {
|
||||
final bool visible;
|
||||
const LoadableStateErrorScreen({required this.visible, super.key});
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final bloc = context.watch<LoadableStateBloc>();
|
||||
return AnimatedOpacity(
|
||||
opacity: visible ? 1.0 : 0.0,
|
||||
duration: LoadableStateConsumer.animationDuration,
|
||||
curve: Curves.easeInOut,
|
||||
child: !visible ? null : Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Icon(bloc.connectionIcon(), size: 40),
|
||||
const SizedBox(height: 10),
|
||||
Text(bloc.connectionText(), style: const TextStyle(fontSize: 20)),
|
||||
|
||||
if(bloc.allowRetry()) ...[
|
||||
const SizedBox(height: 10),
|
||||
TextButton(onPressed: () => bloc.loadingError!.retry!(), child: const Text('Erneut versuschen')),
|
||||
],
|
||||
|
||||
if(bloc.showErrorMessage()) ...[
|
||||
const SizedBox(height: 40),
|
||||
Text(bloc.loadingError!.message, style: TextStyle(color: Theme.of(context).hintColor, fontSize: 12))
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user