moved reload actions out of error context
This commit is contained in:
parent
9fa711e460
commit
181682a424
lib
state/app
infrastructure
loadableState
utilityWidgets/loadableHydratedBloc
modules/marianumMessage
view/pages
widget
@ -4,20 +4,19 @@ import 'package:bloc/bloc.dart';
|
|||||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import '../loading_error.dart';
|
|
||||||
import 'loadable_state_event.dart';
|
import 'loadable_state_event.dart';
|
||||||
import 'loadable_state_state.dart';
|
import 'loadable_state_state.dart';
|
||||||
|
|
||||||
class LoadableStateBloc extends Bloc<LoadableStateEvent, LoadableStateState> {
|
class LoadableStateBloc extends Bloc<LoadableStateEvent, LoadableStateState> {
|
||||||
late StreamSubscription<List<ConnectivityResult>> _updateStream;
|
late StreamSubscription<List<ConnectivityResult>> _updateStream;
|
||||||
LoadingError? loadingError;
|
void Function()? reFetch;
|
||||||
|
|
||||||
LoadableStateBloc() : super(const LoadableStateState(connections: null)) {
|
LoadableStateBloc() : super(const LoadableStateState(connections: null)) {
|
||||||
on<ConnectivityChanged>((event, emit) {
|
on<ConnectivityChanged>((event, emit) {
|
||||||
emit(event.state);
|
emit(event.state);
|
||||||
if(connectivityStatusKnown() && isConnected() && loadingError != null) {
|
if(connectivityStatusKnown() && isConnected()) {
|
||||||
if(!loadingError!.enableRetry) return;
|
if(reFetch == null) return;
|
||||||
loadingError!.retry!();
|
reFetch!();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -29,8 +28,8 @@ class LoadableStateBloc extends Bloc<LoadableStateEvent, LoadableStateState> {
|
|||||||
|
|
||||||
bool connectivityStatusKnown() => state.connections != null;
|
bool connectivityStatusKnown() => state.connections != null;
|
||||||
bool isConnected() => !(state.connections?.contains(ConnectivityResult.none) ?? true);
|
bool isConnected() => !(state.connections?.contains(ConnectivityResult.none) ?? true);
|
||||||
bool allowRetry() => loadingError?.retry != null;
|
bool allowRetry() => reFetch != null;
|
||||||
bool showErrorMessage() => isConnected() && loadingError != null;
|
bool showErrorMessage() => isConnected() && reFetch != null;
|
||||||
|
|
||||||
IconData connectionIcon() => connectivityStatusKnown()
|
IconData connectionIcon() => connectivityStatusKnown()
|
||||||
? isConnected()
|
? isConnected()
|
||||||
|
@ -11,6 +11,7 @@ class LoadableState<TState> with _$LoadableState {
|
|||||||
const factory LoadableState({
|
const factory LoadableState({
|
||||||
@Default(true) bool isLoading,
|
@Default(true) bool isLoading,
|
||||||
@Default(null) TState? data,
|
@Default(null) TState? data,
|
||||||
|
@Default(null) void Function()? reFetch,
|
||||||
@Default(null) LoadingError? error,
|
@Default(null) LoadingError? error,
|
||||||
}) = _LoadableState;
|
}) = _LoadableState;
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ final _privateConstructorUsedError = UnsupportedError(
|
|||||||
mixin _$LoadableState<TState> {
|
mixin _$LoadableState<TState> {
|
||||||
bool get isLoading => throw _privateConstructorUsedError;
|
bool get isLoading => throw _privateConstructorUsedError;
|
||||||
TState? get data => throw _privateConstructorUsedError;
|
TState? get data => throw _privateConstructorUsedError;
|
||||||
|
void Function()? get reFetch => throw _privateConstructorUsedError;
|
||||||
LoadingError? get error => throw _privateConstructorUsedError;
|
LoadingError? get error => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(ignore: true)
|
||||||
@ -31,7 +32,11 @@ abstract class $LoadableStateCopyWith<TState, $Res> {
|
|||||||
$Res Function(LoadableState<TState>) then) =
|
$Res Function(LoadableState<TState>) then) =
|
||||||
_$LoadableStateCopyWithImpl<TState, $Res, LoadableState<TState>>;
|
_$LoadableStateCopyWithImpl<TState, $Res, LoadableState<TState>>;
|
||||||
@useResult
|
@useResult
|
||||||
$Res call({bool isLoading, TState? data, LoadingError? error});
|
$Res call(
|
||||||
|
{bool isLoading,
|
||||||
|
TState? data,
|
||||||
|
void Function()? reFetch,
|
||||||
|
LoadingError? error});
|
||||||
|
|
||||||
$LoadingErrorCopyWith<$Res>? get error;
|
$LoadingErrorCopyWith<$Res>? get error;
|
||||||
}
|
}
|
||||||
@ -52,6 +57,7 @@ class _$LoadableStateCopyWithImpl<TState, $Res,
|
|||||||
$Res call({
|
$Res call({
|
||||||
Object? isLoading = null,
|
Object? isLoading = null,
|
||||||
Object? data = freezed,
|
Object? data = freezed,
|
||||||
|
Object? reFetch = freezed,
|
||||||
Object? error = freezed,
|
Object? error = freezed,
|
||||||
}) {
|
}) {
|
||||||
return _then(_value.copyWith(
|
return _then(_value.copyWith(
|
||||||
@ -63,6 +69,10 @@ class _$LoadableStateCopyWithImpl<TState, $Res,
|
|||||||
? _value.data
|
? _value.data
|
||||||
: data // ignore: cast_nullable_to_non_nullable
|
: data // ignore: cast_nullable_to_non_nullable
|
||||||
as TState?,
|
as TState?,
|
||||||
|
reFetch: freezed == reFetch
|
||||||
|
? _value.reFetch
|
||||||
|
: reFetch // ignore: cast_nullable_to_non_nullable
|
||||||
|
as void Function()?,
|
||||||
error: freezed == error
|
error: freezed == error
|
||||||
? _value.error
|
? _value.error
|
||||||
: error // ignore: cast_nullable_to_non_nullable
|
: error // ignore: cast_nullable_to_non_nullable
|
||||||
@ -91,7 +101,11 @@ abstract class _$$LoadableStateImplCopyWith<TState, $Res>
|
|||||||
__$$LoadableStateImplCopyWithImpl<TState, $Res>;
|
__$$LoadableStateImplCopyWithImpl<TState, $Res>;
|
||||||
@override
|
@override
|
||||||
@useResult
|
@useResult
|
||||||
$Res call({bool isLoading, TState? data, LoadingError? error});
|
$Res call(
|
||||||
|
{bool isLoading,
|
||||||
|
TState? data,
|
||||||
|
void Function()? reFetch,
|
||||||
|
LoadingError? error});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
$LoadingErrorCopyWith<$Res>? get error;
|
$LoadingErrorCopyWith<$Res>? get error;
|
||||||
@ -111,6 +125,7 @@ class __$$LoadableStateImplCopyWithImpl<TState, $Res>
|
|||||||
$Res call({
|
$Res call({
|
||||||
Object? isLoading = null,
|
Object? isLoading = null,
|
||||||
Object? data = freezed,
|
Object? data = freezed,
|
||||||
|
Object? reFetch = freezed,
|
||||||
Object? error = freezed,
|
Object? error = freezed,
|
||||||
}) {
|
}) {
|
||||||
return _then(_$LoadableStateImpl<TState>(
|
return _then(_$LoadableStateImpl<TState>(
|
||||||
@ -122,6 +137,10 @@ class __$$LoadableStateImplCopyWithImpl<TState, $Res>
|
|||||||
? _value.data
|
? _value.data
|
||||||
: data // ignore: cast_nullable_to_non_nullable
|
: data // ignore: cast_nullable_to_non_nullable
|
||||||
as TState?,
|
as TState?,
|
||||||
|
reFetch: freezed == reFetch
|
||||||
|
? _value.reFetch
|
||||||
|
: reFetch // ignore: cast_nullable_to_non_nullable
|
||||||
|
as void Function()?,
|
||||||
error: freezed == error
|
error: freezed == error
|
||||||
? _value.error
|
? _value.error
|
||||||
: error // ignore: cast_nullable_to_non_nullable
|
: error // ignore: cast_nullable_to_non_nullable
|
||||||
@ -134,7 +153,10 @@ class __$$LoadableStateImplCopyWithImpl<TState, $Res>
|
|||||||
|
|
||||||
class _$LoadableStateImpl<TState> extends _LoadableState<TState> {
|
class _$LoadableStateImpl<TState> extends _LoadableState<TState> {
|
||||||
const _$LoadableStateImpl(
|
const _$LoadableStateImpl(
|
||||||
{this.isLoading = true, this.data = null, this.error = null})
|
{this.isLoading = true,
|
||||||
|
this.data = null,
|
||||||
|
this.reFetch = null,
|
||||||
|
this.error = null})
|
||||||
: super._();
|
: super._();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -145,11 +167,14 @@ class _$LoadableStateImpl<TState> extends _LoadableState<TState> {
|
|||||||
final TState? data;
|
final TState? data;
|
||||||
@override
|
@override
|
||||||
@JsonKey()
|
@JsonKey()
|
||||||
|
final void Function()? reFetch;
|
||||||
|
@override
|
||||||
|
@JsonKey()
|
||||||
final LoadingError? error;
|
final LoadingError? error;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'LoadableState<$TState>(isLoading: $isLoading, data: $data, error: $error)';
|
return 'LoadableState<$TState>(isLoading: $isLoading, data: $data, reFetch: $reFetch, error: $error)';
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -160,12 +185,13 @@ class _$LoadableStateImpl<TState> extends _LoadableState<TState> {
|
|||||||
(identical(other.isLoading, isLoading) ||
|
(identical(other.isLoading, isLoading) ||
|
||||||
other.isLoading == isLoading) &&
|
other.isLoading == isLoading) &&
|
||||||
const DeepCollectionEquality().equals(other.data, data) &&
|
const DeepCollectionEquality().equals(other.data, data) &&
|
||||||
|
(identical(other.reFetch, reFetch) || other.reFetch == reFetch) &&
|
||||||
(identical(other.error, error) || other.error == error));
|
(identical(other.error, error) || other.error == error));
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(
|
int get hashCode => Object.hash(runtimeType, isLoading,
|
||||||
runtimeType, isLoading, const DeepCollectionEquality().hash(data), error);
|
const DeepCollectionEquality().hash(data), reFetch, error);
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(ignore: true)
|
||||||
@override
|
@override
|
||||||
@ -179,6 +205,7 @@ abstract class _LoadableState<TState> extends LoadableState<TState> {
|
|||||||
const factory _LoadableState(
|
const factory _LoadableState(
|
||||||
{final bool isLoading,
|
{final bool isLoading,
|
||||||
final TState? data,
|
final TState? data,
|
||||||
|
final void Function()? reFetch,
|
||||||
final LoadingError? error}) = _$LoadableStateImpl<TState>;
|
final LoadingError? error}) = _$LoadableStateImpl<TState>;
|
||||||
const _LoadableState._() : super._();
|
const _LoadableState._() : super._();
|
||||||
|
|
||||||
@ -187,6 +214,8 @@ abstract class _LoadableState<TState> extends LoadableState<TState> {
|
|||||||
@override
|
@override
|
||||||
TState? get data;
|
TState? get data;
|
||||||
@override
|
@override
|
||||||
|
void Function()? get reFetch;
|
||||||
|
@override
|
||||||
LoadingError? get error;
|
LoadingError? get error;
|
||||||
@override
|
@override
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(ignore: true)
|
||||||
|
@ -6,7 +6,6 @@ part 'loading_error.freezed.dart';
|
|||||||
class LoadingError with _$LoadingError {
|
class LoadingError with _$LoadingError {
|
||||||
const factory LoadingError({
|
const factory LoadingError({
|
||||||
required String message,
|
required String message,
|
||||||
@Default(false) bool enableRetry,
|
@Default(false) bool allowRetry,
|
||||||
@Default(null) void Function()? retry,
|
|
||||||
}) = _LoadingError;
|
}) = _LoadingError;
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,7 @@ final _privateConstructorUsedError = UnsupportedError(
|
|||||||
/// @nodoc
|
/// @nodoc
|
||||||
mixin _$LoadingError {
|
mixin _$LoadingError {
|
||||||
String get message => throw _privateConstructorUsedError;
|
String get message => throw _privateConstructorUsedError;
|
||||||
bool get enableRetry => throw _privateConstructorUsedError;
|
bool get allowRetry => throw _privateConstructorUsedError;
|
||||||
void Function()? get retry => throw _privateConstructorUsedError;
|
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(ignore: true)
|
||||||
$LoadingErrorCopyWith<LoadingError> get copyWith =>
|
$LoadingErrorCopyWith<LoadingError> get copyWith =>
|
||||||
@ -31,7 +30,7 @@ abstract class $LoadingErrorCopyWith<$Res> {
|
|||||||
LoadingError value, $Res Function(LoadingError) then) =
|
LoadingError value, $Res Function(LoadingError) then) =
|
||||||
_$LoadingErrorCopyWithImpl<$Res, LoadingError>;
|
_$LoadingErrorCopyWithImpl<$Res, LoadingError>;
|
||||||
@useResult
|
@useResult
|
||||||
$Res call({String message, bool enableRetry, void Function()? retry});
|
$Res call({String message, bool allowRetry});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
@ -48,22 +47,17 @@ class _$LoadingErrorCopyWithImpl<$Res, $Val extends LoadingError>
|
|||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
Object? message = null,
|
Object? message = null,
|
||||||
Object? enableRetry = null,
|
Object? allowRetry = null,
|
||||||
Object? retry = freezed,
|
|
||||||
}) {
|
}) {
|
||||||
return _then(_value.copyWith(
|
return _then(_value.copyWith(
|
||||||
message: null == message
|
message: null == message
|
||||||
? _value.message
|
? _value.message
|
||||||
: message // ignore: cast_nullable_to_non_nullable
|
: message // ignore: cast_nullable_to_non_nullable
|
||||||
as String,
|
as String,
|
||||||
enableRetry: null == enableRetry
|
allowRetry: null == allowRetry
|
||||||
? _value.enableRetry
|
? _value.allowRetry
|
||||||
: enableRetry // ignore: cast_nullable_to_non_nullable
|
: allowRetry // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,
|
as bool,
|
||||||
retry: freezed == retry
|
|
||||||
? _value.retry
|
|
||||||
: retry // ignore: cast_nullable_to_non_nullable
|
|
||||||
as void Function()?,
|
|
||||||
) as $Val);
|
) as $Val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -76,7 +70,7 @@ abstract class _$$LoadingErrorImplCopyWith<$Res>
|
|||||||
__$$LoadingErrorImplCopyWithImpl<$Res>;
|
__$$LoadingErrorImplCopyWithImpl<$Res>;
|
||||||
@override
|
@override
|
||||||
@useResult
|
@useResult
|
||||||
$Res call({String message, bool enableRetry, void Function()? retry});
|
$Res call({String message, bool allowRetry});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
@ -91,22 +85,17 @@ class __$$LoadingErrorImplCopyWithImpl<$Res>
|
|||||||
@override
|
@override
|
||||||
$Res call({
|
$Res call({
|
||||||
Object? message = null,
|
Object? message = null,
|
||||||
Object? enableRetry = null,
|
Object? allowRetry = null,
|
||||||
Object? retry = freezed,
|
|
||||||
}) {
|
}) {
|
||||||
return _then(_$LoadingErrorImpl(
|
return _then(_$LoadingErrorImpl(
|
||||||
message: null == message
|
message: null == message
|
||||||
? _value.message
|
? _value.message
|
||||||
: message // ignore: cast_nullable_to_non_nullable
|
: message // ignore: cast_nullable_to_non_nullable
|
||||||
as String,
|
as String,
|
||||||
enableRetry: null == enableRetry
|
allowRetry: null == allowRetry
|
||||||
? _value.enableRetry
|
? _value.allowRetry
|
||||||
: enableRetry // ignore: cast_nullable_to_non_nullable
|
: allowRetry // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,
|
as bool,
|
||||||
retry: freezed == retry
|
|
||||||
? _value.retry
|
|
||||||
: retry // ignore: cast_nullable_to_non_nullable
|
|
||||||
as void Function()?,
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -114,21 +103,17 @@ class __$$LoadingErrorImplCopyWithImpl<$Res>
|
|||||||
/// @nodoc
|
/// @nodoc
|
||||||
|
|
||||||
class _$LoadingErrorImpl implements _LoadingError {
|
class _$LoadingErrorImpl implements _LoadingError {
|
||||||
const _$LoadingErrorImpl(
|
const _$LoadingErrorImpl({required this.message, this.allowRetry = false});
|
||||||
{required this.message, this.enableRetry = false, this.retry = null});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final String message;
|
final String message;
|
||||||
@override
|
@override
|
||||||
@JsonKey()
|
@JsonKey()
|
||||||
final bool enableRetry;
|
final bool allowRetry;
|
||||||
@override
|
|
||||||
@JsonKey()
|
|
||||||
final void Function()? retry;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'LoadingError(message: $message, enableRetry: $enableRetry, retry: $retry)';
|
return 'LoadingError(message: $message, allowRetry: $allowRetry)';
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -137,13 +122,12 @@ class _$LoadingErrorImpl implements _LoadingError {
|
|||||||
(other.runtimeType == runtimeType &&
|
(other.runtimeType == runtimeType &&
|
||||||
other is _$LoadingErrorImpl &&
|
other is _$LoadingErrorImpl &&
|
||||||
(identical(other.message, message) || other.message == message) &&
|
(identical(other.message, message) || other.message == message) &&
|
||||||
(identical(other.enableRetry, enableRetry) ||
|
(identical(other.allowRetry, allowRetry) ||
|
||||||
other.enableRetry == enableRetry) &&
|
other.allowRetry == allowRetry));
|
||||||
(identical(other.retry, retry) || other.retry == retry));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType, message, enableRetry, retry);
|
int get hashCode => Object.hash(runtimeType, message, allowRetry);
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(ignore: true)
|
||||||
@override
|
@override
|
||||||
@ -155,15 +139,12 @@ class _$LoadingErrorImpl implements _LoadingError {
|
|||||||
abstract class _LoadingError implements LoadingError {
|
abstract class _LoadingError implements LoadingError {
|
||||||
const factory _LoadingError(
|
const factory _LoadingError(
|
||||||
{required final String message,
|
{required final String message,
|
||||||
final bool enableRetry,
|
final bool allowRetry}) = _$LoadingErrorImpl;
|
||||||
final void Function()? retry}) = _$LoadingErrorImpl;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get message;
|
String get message;
|
||||||
@override
|
@override
|
||||||
bool get enableRetry;
|
bool get allowRetry;
|
||||||
@override
|
|
||||||
void Function()? get retry;
|
|
||||||
@override
|
@override
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(ignore: true)
|
||||||
_$$LoadingErrorImplCopyWith<_$LoadingErrorImpl> get copyWith =>
|
_$$LoadingErrorImplCopyWith<_$LoadingErrorImpl> get copyWith =>
|
||||||
|
@ -2,6 +2,7 @@ import 'package:bloc/bloc.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import '../../../../../widget/conditional_wrapper.dart';
|
||||||
import '../../utilityWidgets/bloc_module.dart';
|
import '../../utilityWidgets/bloc_module.dart';
|
||||||
import '../../utilityWidgets/loadableHydratedBloc/loadable_hydrated_bloc_event.dart';
|
import '../../utilityWidgets/loadableHydratedBloc/loadable_hydrated_bloc_event.dart';
|
||||||
import '../bloc/loadable_state_bloc.dart';
|
import '../bloc/loadable_state_bloc.dart';
|
||||||
@ -14,36 +15,42 @@ import 'loadable_state_primary_loading.dart';
|
|||||||
|
|
||||||
class LoadableStateConsumer<TController extends Bloc<LoadableHydratedBlocEvent<TState>, LoadableState<TState>>, TState> extends StatelessWidget {
|
class LoadableStateConsumer<TController extends Bloc<LoadableHydratedBlocEvent<TState>, LoadableState<TState>>, TState> extends StatelessWidget {
|
||||||
final Widget Function(TState state, bool loading) child;
|
final Widget Function(TState state, bool loading) child;
|
||||||
const LoadableStateConsumer({required this.child, super.key});
|
final bool wrapWithScrollView;
|
||||||
|
const LoadableStateConsumer({required this.child, this.wrapWithScrollView = false, super.key});
|
||||||
|
|
||||||
static Duration animationDuration = const Duration(milliseconds: 200);
|
static Duration animationDuration = const Duration(milliseconds: 200);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var loadableState = context.watch<TController>().state;
|
var loadableState = context.watch<TController>().state;
|
||||||
var childWidget = RefreshIndicator(
|
var childWidget = ConditionalWrapper(
|
||||||
onRefresh: () {
|
condition: loadableState.reFetch != null,
|
||||||
loadableState.error != null && loadableState.error!.retry != null
|
wrapper: (child) => RefreshIndicator(
|
||||||
? loadableState.error!.retry!()
|
onRefresh: () {
|
||||||
: null;
|
if(loadableState.reFetch != null) loadableState.reFetch!();
|
||||||
return Future.value();
|
return Future.value();
|
||||||
},
|
},
|
||||||
|
child: ConditionalWrapper(
|
||||||
|
condition: wrapWithScrollView,
|
||||||
|
wrapper: (child) => SingleChildScrollView(
|
||||||
|
physics: const AlwaysScrollableScrollPhysics(),
|
||||||
|
child: child
|
||||||
|
),
|
||||||
|
child: child,
|
||||||
|
)
|
||||||
|
),
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: MediaQuery.of(context).size.height,
|
height: MediaQuery.of(context).size.height,
|
||||||
child: loadableState.showContent()
|
child: loadableState.showContent()
|
||||||
? child(loadableState.data, loadableState.isLoading)
|
? child(loadableState.data, loadableState.isLoading)
|
||||||
: const SizedBox.shrink(),
|
: const SizedBox.shrink(),
|
||||||
),
|
),
|
||||||
// SingleChildScrollView( // TODO not all childs are reloadable
|
|
||||||
// physics: const AlwaysScrollableScrollPhysics(),
|
|
||||||
// child:
|
|
||||||
// ),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return BlocModule<LoadableStateBloc, LoadableStateState>(
|
return BlocModule<LoadableStateBloc, LoadableStateState>(
|
||||||
create: (context) => LoadableStateBloc(),
|
create: (context) => LoadableStateBloc(),
|
||||||
child: (context, bloc, state) {
|
child: (context, bloc, state) {
|
||||||
bloc.loadingError = loadableState.error;
|
bloc.reFetch = loadableState.reFetch;
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
LoadableStateErrorBar(visible: loadableState.showErrorBar()),
|
LoadableStateErrorBar(visible: loadableState.showErrorBar()),
|
||||||
|
@ -27,12 +27,12 @@ class LoadableStateErrorScreen extends StatelessWidget {
|
|||||||
|
|
||||||
if(bloc.allowRetry()) ...[
|
if(bloc.allowRetry()) ...[
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
TextButton(onPressed: () => bloc.loadingError!.retry!(), child: const Text('Erneut versuschen')),
|
TextButton(onPressed: () => bloc.reFetch!(), child: const Text('Erneut versuschen')),
|
||||||
],
|
],
|
||||||
|
|
||||||
if(bloc.showErrorMessage()) ...[
|
if(bloc.showErrorMessage()) ...[
|
||||||
const SizedBox(height: 40),
|
const SizedBox(height: 40),
|
||||||
Text(bloc.loadingError!.message, style: TextStyle(color: Theme.of(context).hintColor, fontSize: 12))
|
Text("bloc.loadingError!.message", style: TextStyle(color: Theme.of(context).hintColor, fontSize: 12))
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -17,10 +17,10 @@ abstract class LoadableHydratedBloc<
|
|||||||
> {
|
> {
|
||||||
late TRepository _repository;
|
late TRepository _repository;
|
||||||
LoadableHydratedBloc() : super(const LoadableState()) {
|
LoadableHydratedBloc() : super(const LoadableState()) {
|
||||||
on<Emit<TState>>((event, emit) => emit(LoadableState(isLoading: event.loading, data: event.state(innerState ?? fromNothing()))));
|
on<Emit<TState>>((event, emit) => emit(LoadableState(isLoading: event.loading, data: event.state(innerState ?? fromNothing()), reFetch: retry)));
|
||||||
on<Reload<TState>>((event, emit) => emit(LoadableState(isLoading: true, data: innerState)));
|
on<RefetchStarted<TState>>((event, emit) => emit(LoadableState(isLoading: true, data: innerState)));
|
||||||
on<ClearState<TState>>((event, emit) => emit(const LoadableState()));
|
on<ClearState<TState>>((event, emit) => emit(const LoadableState()));
|
||||||
on<Error<TState>>((event, emit) => emit(LoadableState(isLoading: false, data: innerState, error: event.error)));
|
on<Error<TState>>((event, emit) => emit(LoadableState(isLoading: false, data: innerState, reFetch: retry, error: event.error)));
|
||||||
|
|
||||||
_repository = repository();
|
_repository = repository();
|
||||||
fetch();
|
fetch();
|
||||||
@ -29,22 +29,25 @@ abstract class LoadableHydratedBloc<
|
|||||||
TState? get innerState => state.data;
|
TState? get innerState => state.data;
|
||||||
TRepository get repo => _repository;
|
TRepository get repo => _repository;
|
||||||
|
|
||||||
|
void retry() {
|
||||||
|
log('Fetch retry triggered for ${TState.toString()}');
|
||||||
|
add(RefetchStarted<TState>());
|
||||||
|
fetch();
|
||||||
|
}
|
||||||
|
|
||||||
void fetch() {
|
void fetch() {
|
||||||
|
log('Fetching data for ${TState.toString()}');
|
||||||
gatherData().catchError(
|
gatherData().catchError(
|
||||||
(e) => add(
|
(e) {
|
||||||
Error(
|
log('Error while fetching ${TState.toString()}: ${e.toString()}');
|
||||||
LoadingError(
|
add(Error(LoadingError(
|
||||||
message: e.toString(),
|
message: e.toString(),
|
||||||
enableRetry: true,
|
allowRetry: true,
|
||||||
retry: () {
|
)));
|
||||||
log('Fetch retry on ${TState.toString()}');
|
}
|
||||||
add(Reload<TState>());
|
).then((value) {
|
||||||
fetch();
|
log('Fetch for ${TState.toString()} completed!');
|
||||||
}
|
});
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
2
lib/state/app/infrastructure/utilityWidgets/loadableHydratedBloc/loadable_hydrated_bloc_event.dart
2
lib/state/app/infrastructure/utilityWidgets/loadableHydratedBloc/loadable_hydrated_bloc_event.dart
@ -11,4 +11,4 @@ class Error<TState> extends LoadableHydratedBlocEvent<TState> {
|
|||||||
final LoadingError error;
|
final LoadingError error;
|
||||||
Error(this.error);
|
Error(this.error);
|
||||||
}
|
}
|
||||||
class Reload<TState> extends LoadableHydratedBlocEvent<TState> {}
|
class RefetchStarted<TState> extends LoadableHydratedBlocEvent<TState> {}
|
||||||
|
@ -23,7 +23,7 @@ class MarianumMessageBloc extends LoadableHydratedBloc<MarianumMessageEvent, Mar
|
|||||||
MarianumMessageRepository repository() => MarianumMessageRepository();
|
MarianumMessageRepository repository() => MarianumMessageRepository();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
MarianumMessageState fromNothing() => const MarianumMessageState(messageList: MarianumMessageList(base: "", messages: []));
|
MarianumMessageState fromNothing() => const MarianumMessageState(messageList: MarianumMessageList(base: '', messages: []));
|
||||||
|
|
||||||
@override
|
@override
|
||||||
MarianumMessageState fromStorage(Map<String, dynamic> json) => MarianumMessageState.fromJson(json);
|
MarianumMessageState fromStorage(Map<String, dynamic> json) => MarianumMessageState.fromJson(json);
|
||||||
|
@ -6,7 +6,7 @@ class MarianumMessageGetMessages extends DataLoader<MarianumMessageList> {
|
|||||||
@override
|
@override
|
||||||
Future<MarianumMessageList> fetch() async {
|
Future<MarianumMessageList> fetch() async {
|
||||||
await Future.delayed(const Duration(seconds: 3));
|
await Future.delayed(const Duration(seconds: 3));
|
||||||
throw UnimplementedError("Test");
|
// throw UnimplementedError("Test");
|
||||||
return const MarianumMessageList(base: '', messages: [MarianumMessage(date: '', name: 'RepoTest', url: '')]);
|
return const MarianumMessageList(base: '', messages: [MarianumMessage(date: '', name: 'RepoTest', url: '')]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,8 @@ class MarianumMessageListView extends StatelessWidget {
|
|||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: const Text('Marianum Message'),
|
title: const Text('Marianum Message'),
|
||||||
actions: [
|
actions: [
|
||||||
IconButton(onPressed: () => context.read<MarianumMessageBloc>().add(Emit((state) => MarianumMessageState(messageList: MarianumMessageList(base: "", messages: [MarianumMessage(url: "", name: "Teeest", date: "now")])))), icon: Icon(Icons.add)),
|
IconButton(onPressed: () => context.read<MarianumMessageBloc>().add(Emit((state) => const MarianumMessageState(messageList: MarianumMessageList(base: '', messages: [MarianumMessage(url: '', name: 'Teeest', date: 'now')])))), icon: const Icon(Icons.add)),
|
||||||
IconButton(onPressed: () => context.read<MarianumMessageBloc>().add(ClearState()), icon: Icon(Icons.add))
|
IconButton(onPressed: () => context.read<MarianumMessageBloc>().add(ClearState()), icon: const Icon(Icons.add))
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: LoadableStateConsumer<MarianumMessageBloc, MarianumMessageState>(
|
body: LoadableStateConsumer<MarianumMessageBloc, MarianumMessageState>(
|
||||||
|
@ -72,8 +72,8 @@ class Overhang extends StatelessWidget {
|
|||||||
trailing: const Icon(Icons.arrow_right),
|
trailing: const Icon(Icons.arrow_right),
|
||||||
onTap: () => pushScreen(context, withNavBar: false, screen: const FeedbackDialog()),
|
onTap: () => pushScreen(context, withNavBar: false, screen: const FeedbackDialog()),
|
||||||
),
|
),
|
||||||
ListTile(
|
const ListTile(
|
||||||
leading: const Icon(Icons.science_outlined),
|
leading: Icon(Icons.science_outlined),
|
||||||
// onTap: () => pushScreen(context, withNavBar: false, screen: const GradeAveragesScreen()),
|
// onTap: () => pushScreen(context, withNavBar: false, screen: const GradeAveragesScreen()),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
17
lib/widget/conditional_wrapper.dart
Normal file
17
lib/widget/conditional_wrapper.dart
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class ConditionalWrapper extends StatelessWidget {
|
||||||
|
final bool condition;
|
||||||
|
final Widget child;
|
||||||
|
final Widget Function(Widget child) wrapper;
|
||||||
|
|
||||||
|
const ConditionalWrapper({
|
||||||
|
required this.condition,
|
||||||
|
required this.child,
|
||||||
|
required this.wrapper,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => condition ? wrapper(child) : child;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user