wip: bloc for files
This commit is contained in:
@ -2,26 +2,21 @@ import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
abstract class DataLoader<TResult> {
|
||||
abstract class HttpDataLoader<TResult> {
|
||||
final Dio dio;
|
||||
DataLoader(this.dio) {
|
||||
HttpDataLoader(this.dio) {
|
||||
dio.options.connectTimeout = const Duration(seconds: 10).inMilliseconds;
|
||||
dio.options.sendTimeout = const Duration(seconds: 30).inMilliseconds;
|
||||
dio.options.receiveTimeout = const Duration(seconds: 30).inMilliseconds;
|
||||
}
|
||||
|
||||
Future<TResult> run() async {
|
||||
var fetcher = fetch();
|
||||
await Future.wait([
|
||||
fetcher,
|
||||
Future.delayed(const Duration(milliseconds: 500)) // TODO tune or remove
|
||||
]);
|
||||
|
||||
var response = await fetcher;
|
||||
var response = await fetch();
|
||||
try {
|
||||
return assemble(DataLoaderResult(
|
||||
json: jsonDecode(response.data!),
|
||||
json: await compute(jsonDecode, response.data!),
|
||||
headers: response.headers.map.map((key, value) => MapEntry(key, value.join(';'))),
|
||||
));
|
||||
} catch(trace, e) {
|
@ -166,27 +166,22 @@ class __$$LoadableStateImplCopyWithImpl<TState, $Res>
|
||||
|
||||
class _$LoadableStateImpl<TState> extends _LoadableState<TState> {
|
||||
const _$LoadableStateImpl(
|
||||
{this.isLoading = true,
|
||||
this.data = null,
|
||||
this.lastFetch = null,
|
||||
this.reFetch = null,
|
||||
this.error = null})
|
||||
{required this.isLoading,
|
||||
required this.data,
|
||||
required this.lastFetch,
|
||||
required this.reFetch,
|
||||
required this.error})
|
||||
: super._();
|
||||
|
||||
@override
|
||||
@JsonKey()
|
||||
final bool isLoading;
|
||||
@override
|
||||
@JsonKey()
|
||||
final TState? data;
|
||||
@override
|
||||
@JsonKey()
|
||||
final int? lastFetch;
|
||||
@override
|
||||
@JsonKey()
|
||||
final void Function()? reFetch;
|
||||
@override
|
||||
@JsonKey()
|
||||
final LoadingError? error;
|
||||
|
||||
@override
|
||||
@ -222,11 +217,11 @@ class _$LoadableStateImpl<TState> extends _LoadableState<TState> {
|
||||
|
||||
abstract class _LoadableState<TState> extends LoadableState<TState> {
|
||||
const factory _LoadableState(
|
||||
{final bool isLoading,
|
||||
final TState? data,
|
||||
final int? lastFetch,
|
||||
final void Function()? reFetch,
|
||||
final LoadingError? error}) = _$LoadableStateImpl<TState>;
|
||||
{required final bool isLoading,
|
||||
required final TState? data,
|
||||
required final int? lastFetch,
|
||||
required final void Function()? reFetch,
|
||||
required final LoadingError? error}) = _$LoadableStateImpl<TState>;
|
||||
const _LoadableState._() : super._();
|
||||
|
||||
@override
|
||||
|
@ -30,16 +30,17 @@ abstract class LoadableHydratedBloc<
|
||||
isLoading: state.isLoading,
|
||||
data: event.state(innerState ?? fromNothing()),
|
||||
lastFetch: state.lastFetch,
|
||||
reFetch: retry,
|
||||
reFetch: fetch,
|
||||
error: state.error,
|
||||
));
|
||||
if(event.fetch) fetch();
|
||||
});
|
||||
|
||||
on<DataGathered<TState>>((event, emit) => emit(LoadableState(
|
||||
isLoading: false,
|
||||
data: event.state(innerState ?? fromNothing()),
|
||||
lastFetch: DateTime.now().millisecondsSinceEpoch,
|
||||
reFetch: retry,
|
||||
reFetch: fetch,
|
||||
error: null,
|
||||
)));
|
||||
|
||||
@ -55,7 +56,7 @@ abstract class LoadableHydratedBloc<
|
||||
isLoading: false,
|
||||
data: innerState,
|
||||
lastFetch: state.lastFetch,
|
||||
reFetch: retry,
|
||||
reFetch: fetch,
|
||||
error: event.error
|
||||
)));
|
||||
|
||||
@ -66,19 +67,14 @@ abstract class LoadableHydratedBloc<
|
||||
TState? get innerState => state.data;
|
||||
TRepository get repo => _repository;
|
||||
|
||||
void retry() {
|
||||
log('Fetch retry triggered for ${TState.toString()}');
|
||||
add(RefetchStarted<TState>());
|
||||
fetch();
|
||||
}
|
||||
|
||||
void fetch() {
|
||||
log('Fetching data for ${TState.toString()}');
|
||||
add(RefetchStarted<TState>());
|
||||
gatherData().catchError(
|
||||
(e) {
|
||||
log('Error while fetching ${TState.toString()}: ${e.toString()}');
|
||||
add(Error(LoadingError(
|
||||
message: e.message ?? e.toString(),
|
||||
message: e.toString(),
|
||||
allowRetry: true,
|
||||
)));
|
||||
},
|
||||
@ -92,7 +88,7 @@ abstract class LoadableHydratedBloc<
|
||||
var rawData = LoadableSaveContext.unwrap(json);
|
||||
return LoadableState(
|
||||
isLoading: true,
|
||||
data: fromStorage(rawData.data),
|
||||
data: fromStorage(rawData.data), // TODO fromStorage in isolate
|
||||
lastFetch: rawData.meta.timestamp,
|
||||
reFetch: null,
|
||||
error: null,
|
||||
@ -103,7 +99,7 @@ abstract class LoadableHydratedBloc<
|
||||
Map<String, dynamic>? toJson(LoadableState<TState> state) {
|
||||
Map<String, dynamic>? data;
|
||||
try {
|
||||
data = state.data == null ? null : toStorage(state.data);
|
||||
data = state.data == null ? null : toStorage(state.data); // TODO toStorage in isolate
|
||||
} catch(e) {
|
||||
log('Failed to save state ${TState.toString()}: ${e.toString()}');
|
||||
}
|
||||
|
@ -3,7 +3,8 @@ import '../../loadableState/loading_error.dart';
|
||||
class LoadableHydratedBlocEvent<TState> {}
|
||||
class Emit<TState> extends LoadableHydratedBlocEvent<TState> {
|
||||
final TState Function(TState state) state;
|
||||
Emit(this.state);
|
||||
final bool fetch;
|
||||
Emit(this.state, {this.fetch = false});
|
||||
}
|
||||
class DataGathered<TState> extends LoadableHydratedBlocEvent<TState> {
|
||||
final TState Function(TState state) state;
|
||||
|
@ -9,7 +9,7 @@ part of 'loadable_save_context.dart';
|
||||
_$LoadableSaveContextImpl _$$LoadableSaveContextImplFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$LoadableSaveContextImpl(
|
||||
timestamp: json['timestamp'] as int,
|
||||
timestamp: (json['timestamp'] as num).toInt(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$LoadableSaveContextImplToJson(
|
||||
|
@ -0,0 +1,48 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'bloc_module.dart';
|
||||
|
||||
class SwappingBloc<TBloc> {
|
||||
final TBloc initialBloc;
|
||||
final StreamController<TBloc> updater = StreamController<TBloc>();
|
||||
|
||||
SwappingBloc(this.initialBloc);
|
||||
|
||||
void swap(TBloc bloc) {
|
||||
updater.add(bloc);
|
||||
}
|
||||
}
|
||||
|
||||
class SwappingBlocModule<TBloc extends StateStreamableSource<TState>, TState> extends StatefulWidget {
|
||||
final SwappingBloc<TBloc> bloc;
|
||||
final Widget Function(BuildContext context, TBloc bloc, TState state) child;
|
||||
const SwappingBlocModule({super.key, required this.bloc, required this.child});
|
||||
|
||||
@override
|
||||
State<SwappingBlocModule<TBloc, TState>> createState() => _SwappingBlocModuleState<TBloc, TState>();
|
||||
}
|
||||
|
||||
class _SwappingBlocModuleState<TBloc extends StateStreamableSource<TState>, TState> extends State<SwappingBlocModule<TBloc, TState>> {
|
||||
late TBloc bloc;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
bloc = widget.bloc.initialBloc;
|
||||
widget.bloc.updater.stream.listen((event) {
|
||||
setState(() {
|
||||
bloc = event;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => BlocModule<TBloc, TState>(
|
||||
autoRebuild: true,
|
||||
create: (context) => bloc,
|
||||
child: (context, bloc, state) => widget.child(context, bloc, state),
|
||||
);
|
||||
}
|
Reference in New Issue
Block a user