Improved error handling, added multithreading for fromJson calls, made receive sharing intent more robust

This commit is contained in:
Anton Stubenbord
2022-11-13 14:41:42 +01:00
parent afbd4bddb4
commit 1cafd5d246
43 changed files with 644 additions and 746 deletions

View File

@@ -1,47 +0,0 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:injectable/injectable.dart';
import 'package:paperless_mobile/core/model/error_message.dart';
///
/// Class for handling generic errors which usually only require to inform the user via a Snackbar
/// or similar that an error has occurred.
///
@singleton
class GlobalErrorCubit extends Cubit<GlobalErrorState> {
static const _waitBeforeNextErrorDuration = Duration(seconds: 5);
GlobalErrorCubit() : super(GlobalErrorState.initial);
///
/// Adds a new error to this bloc. If the new error is equal to the current error, the new error
/// will not be published unless the previous error occured over 5 seconds ago.
///
void add(ErrorMessage error) {
final now = DateTime.now();
if (error != state.error || (error == state.error && _canEmitNewError())) {
emit(GlobalErrorState(error: error, errorTimestamp: now));
}
}
bool _canEmitNewError() {
if (state.errorTimestamp != null) {
return DateTime.now().difference(state.errorTimestamp!) >=
_waitBeforeNextErrorDuration;
}
return true;
}
void reset() {
emit(GlobalErrorState.initial);
}
}
class GlobalErrorState {
static const GlobalErrorState initial = GlobalErrorState();
final ErrorMessage? error;
final DateTime? errorTimestamp;
const GlobalErrorState({this.error, this.errorTimestamp});
bool get hasError => error != null;
}

View File

@@ -1,75 +1,42 @@
import 'package:flutter/foundation.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:paperless_mobile/core/bloc/global_error_cubit.dart';
import 'package:paperless_mobile/core/model/error_message.dart';
import 'package:paperless_mobile/features/labels/model/label.model.dart';
import 'package:paperless_mobile/features/labels/repository/label_repository.dart';
abstract class LabelCubit<T extends Label> extends Cubit<Map<int, T>> {
final LabelRepository labelRepository;
final GlobalErrorCubit errorCubit;
LabelCubit(this.labelRepository, this.errorCubit) : super({});
LabelCubit(this.labelRepository) : super({});
@protected
void loadFrom(Iterable<T> items) =>
emit(Map.fromIterable(items, key: (e) => (e as T).id!));
Future<T> add(
T item, {
bool propagateEventOnError = true,
}) async {
Future<T> add(T item) async {
assert(item.id == null);
try {
final addedItem = await save(item);
final newState = {...state};
newState.putIfAbsent(addedItem.id!, () => addedItem);
emit(newState);
return addedItem;
} on ErrorMessage catch (error) {
if (propagateEventOnError) {
errorCubit.add(error);
}
return Future.error(error);
}
final addedItem = await save(item);
final newState = {...state};
newState.putIfAbsent(addedItem.id!, () => addedItem);
emit(newState);
return addedItem;
}
Future<T> replace(
T item, {
bool propagateEventOnError = true,
}) async {
Future<T> replace(T item) async {
assert(item.id != null);
try {
final updatedItem = await update(item);
final newState = {...state};
newState[item.id!] = updatedItem;
emit(newState);
return updatedItem;
} on ErrorMessage catch (error) {
if (propagateEventOnError) {
errorCubit.add(error);
}
return Future.error(error);
}
final updatedItem = await update(item);
final newState = {...state};
newState[item.id!] = updatedItem;
emit(newState);
return updatedItem;
}
Future<void> remove(
T item, {
bool propagateEventOnError = true,
}) async {
Future<void> remove(T item) async {
assert(item.id != null);
if (state.containsKey(item.id)) {
try {
final deletedId = await delete(item);
final newState = {...state};
newState.remove(deletedId);
emit(newState);
} on ErrorMessage catch (error) {
if (propagateEventOnError) {
errorCubit.add(error);
}
return Future.error(error);
}
final deletedId = await delete(item);
final newState = {...state};
newState.remove(deletedId);
emit(newState);
}
}