Changed saved views handling, changed repository structure with automatic persistence.

This commit is contained in:
Anton Stubenbord
2023-01-08 00:01:04 +01:00
parent 23bcb355b1
commit 3c6c4e63d7
74 changed files with 1374 additions and 863 deletions

View File

@@ -2,40 +2,31 @@ import 'dart:async';
import 'package:paperless_api/paperless_api.dart';
import 'package:paperless_mobile/core/repository/label_repository.dart';
import 'package:rxdart/rxdart.dart' show BehaviorSubject;
import 'package:paperless_mobile/core/repository/state/impl/correspondent_repository_state.dart';
import 'package:paperless_mobile/core/repository/state/repository_state.dart';
class CorrespondentRepositoryImpl implements LabelRepository<Correspondent> {
class CorrespondentRepositoryImpl
extends LabelRepository<Correspondent, CorrespondentRepositoryState> {
final PaperlessLabelsApi _api;
final _subject = BehaviorSubject<Map<int, Correspondent>?>();
CorrespondentRepositoryImpl(this._api);
@override
bool get isInitialized => _subject.valueOrNull != null;
@override
Stream<Map<int, Correspondent>?> get values =>
_subject.stream.asBroadcastStream();
Map<int, Correspondent> get _currentValueOrEmpty =>
_subject.valueOrNull ?? {};
CorrespondentRepositoryImpl(this._api)
: super(const CorrespondentRepositoryState());
@override
Future<Correspondent> create(Correspondent correspondent) async {
final created = await _api.saveCorrespondent(correspondent);
final updatedState = {..._currentValueOrEmpty}
final updatedState = {...state.values}
..putIfAbsent(created.id!, () => created);
_subject.add(updatedState);
emit(CorrespondentRepositoryState(values: updatedState, hasLoaded: true));
return created;
}
@override
Future<int> delete(Correspondent correspondent) async {
await _api.deleteCorrespondent(correspondent);
final updatedState = {..._currentValueOrEmpty}
final updatedState = {...state.values}
..removeWhere((k, v) => k == correspondent.id);
_subject.add(updatedState);
emit(CorrespondentRepositoryState(values: updatedState, hasLoaded: true));
return correspondent.id!;
}
@@ -43,8 +34,8 @@ class CorrespondentRepositoryImpl implements LabelRepository<Correspondent> {
Future<Correspondent?> find(int id) async {
final correspondent = await _api.getCorrespondent(id);
if (correspondent != null) {
final updatedState = {..._currentValueOrEmpty}..[id] = correspondent;
_subject.add(updatedState);
final updatedState = {...state.values}..[id] = correspondent;
emit(CorrespondentRepositoryState(values: updatedState, hasLoaded: true));
return correspondent;
}
return null;
@@ -53,26 +44,27 @@ class CorrespondentRepositoryImpl implements LabelRepository<Correspondent> {
@override
Future<Iterable<Correspondent>> findAll([Iterable<int>? ids]) async {
final correspondents = await _api.getCorrespondents(ids);
final updatedState = {..._currentValueOrEmpty}
final updatedState = {...state.values}
..addEntries(correspondents.map((e) => MapEntry(e.id!, e)));
_subject.add(updatedState);
emit(CorrespondentRepositoryState(values: updatedState, hasLoaded: true));
return correspondents;
}
@override
Future<Correspondent> update(Correspondent correspondent) async {
final updated = await _api.updateCorrespondent(correspondent);
final updatedState = {..._currentValueOrEmpty}
..update(updated.id!, (_) => updated);
_subject.add(updatedState);
final updatedState = {...state.values}..update(updated.id!, (_) => updated);
emit(CorrespondentRepositoryState(values: updatedState, hasLoaded: true));
return updated;
}
@override
void clear() {
_subject.add(null);
CorrespondentRepositoryState fromJson(Map<String, dynamic> json) {
return CorrespondentRepositoryState.fromJson(json);
}
@override
Map<int, Correspondent>? get current => _subject.valueOrNull;
Map<String, dynamic> toJson(CorrespondentRepositoryState state) {
return state.toJson();
}
}

View File

@@ -1,38 +1,30 @@
import 'package:paperless_api/paperless_api.dart';
import 'package:paperless_mobile/core/repository/label_repository.dart';
import 'package:paperless_mobile/core/repository/state/impl/document_type_repository_state.dart';
import 'package:rxdart/rxdart.dart' show BehaviorSubject;
class DocumentTypeRepositoryImpl implements LabelRepository<DocumentType> {
class DocumentTypeRepositoryImpl
extends LabelRepository<DocumentType, DocumentTypeRepositoryState> {
final PaperlessLabelsApi _api;
final _subject = BehaviorSubject<Map<int, DocumentType>?>();
DocumentTypeRepositoryImpl(this._api);
@override
Stream<Map<int, DocumentType>?> get values =>
_subject.stream.asBroadcastStream();
@override
bool get isInitialized => _subject.valueOrNull != null;
Map<int, DocumentType> get _currentValueOrEmpty => _subject.valueOrNull ?? {};
DocumentTypeRepositoryImpl(this._api)
: super(const DocumentTypeRepositoryState());
@override
Future<DocumentType> create(DocumentType documentType) async {
final created = await _api.saveDocumentType(documentType);
final updatedState = {..._currentValueOrEmpty}
final updatedState = {...state.values}
..putIfAbsent(created.id!, () => created);
_subject.add(updatedState);
emit(DocumentTypeRepositoryState(values: updatedState, hasLoaded: true));
return created;
}
@override
Future<int> delete(DocumentType documentType) async {
await _api.deleteDocumentType(documentType);
final updatedState = {..._currentValueOrEmpty}
final updatedState = {...state.values}
..removeWhere((k, v) => k == documentType.id);
_subject.add(updatedState);
emit(DocumentTypeRepositoryState(values: updatedState, hasLoaded: true));
return documentType.id!;
}
@@ -40,8 +32,8 @@ class DocumentTypeRepositoryImpl implements LabelRepository<DocumentType> {
Future<DocumentType?> find(int id) async {
final documentType = await _api.getDocumentType(id);
if (documentType != null) {
final updatedState = {..._currentValueOrEmpty}..[id] = documentType;
_subject.add(updatedState);
final updatedState = {...state.values}..[id] = documentType;
emit(DocumentTypeRepositoryState(values: updatedState, hasLoaded: true));
return documentType;
}
return null;
@@ -50,26 +42,27 @@ class DocumentTypeRepositoryImpl implements LabelRepository<DocumentType> {
@override
Future<Iterable<DocumentType>> findAll([Iterable<int>? ids]) async {
final documentTypes = await _api.getDocumentTypes(ids);
final updatedState = {..._currentValueOrEmpty}
final updatedState = {...state.values}
..addEntries(documentTypes.map((e) => MapEntry(e.id!, e)));
_subject.add(updatedState);
emit(DocumentTypeRepositoryState(values: updatedState, hasLoaded: true));
return documentTypes;
}
@override
Future<DocumentType> update(DocumentType documentType) async {
final updated = await _api.updateDocumentType(documentType);
final updatedState = {..._currentValueOrEmpty}
..update(updated.id!, (_) => updated);
_subject.add(updatedState);
final updatedState = {...state.values}..update(updated.id!, (_) => updated);
emit(DocumentTypeRepositoryState(values: updatedState, hasLoaded: true));
return updated;
}
@override
void clear() {
_subject.add(const {});
DocumentTypeRepositoryState fromJson(Map<String, dynamic> json) {
return DocumentTypeRepositoryState.fromJson(json);
}
@override
Map<int, DocumentType>? get current => _subject.valueOrNull;
Map<String, dynamic> toJson(DocumentTypeRepositoryState state) {
return state.toJson();
}
}

View File

@@ -1,46 +1,35 @@
import 'package:paperless_api/paperless_api.dart';
import 'package:paperless_mobile/core/repository/saved_view_repository.dart';
import 'package:rxdart/rxdart.dart';
import 'package:paperless_mobile/core/repository/state/impl/saved_view_repository_state.dart';
class SavedViewRepositoryImpl implements SavedViewRepository {
class SavedViewRepositoryImpl extends SavedViewRepository {
final PaperlessSavedViewsApi _api;
SavedViewRepositoryImpl(this._api);
final _subject = BehaviorSubject<Map<int, SavedView>?>();
@override
Stream<Map<int, SavedView>?> get values =>
_subject.stream.asBroadcastStream();
@override
void clear() {
_subject.add(const {});
}
SavedViewRepositoryImpl(this._api) : super(const SavedViewRepositoryState());
@override
Future<SavedView> create(SavedView view) async {
final created = await _api.save(view);
final updatedState = {..._subject.valueOrNull ?? {}}
final updatedState = {...state.values}
..putIfAbsent(created.id!, () => created);
_subject.add(updatedState);
emit(SavedViewRepositoryState(values: updatedState, hasLoaded: true));
return created;
}
@override
Future<int> delete(SavedView view) async {
await _api.delete(view);
final updatedState = {..._subject.valueOrNull ?? {}}..remove(view.id);
_subject.add(updatedState);
final updatedState = {...state.values}..remove(view.id);
emit(SavedViewRepositoryState(values: updatedState, hasLoaded: true));
return view.id!;
}
@override
Future<SavedView?> find(int id) async {
final found = await _api.find(id);
final updatedState = {..._subject.valueOrNull ?? {}}
final updatedState = {...state.values}
..update(id, (_) => found, ifAbsent: () => found);
_subject.add(updatedState);
emit(SavedViewRepositoryState(values: updatedState, hasLoaded: true));
return found;
}
@@ -48,21 +37,26 @@ class SavedViewRepositoryImpl implements SavedViewRepository {
Future<Iterable<SavedView>> findAll([Iterable<int>? ids]) async {
final found = await _api.findAll(ids);
final updatedState = {
..._subject.valueOrNull ?? {},
...state.values,
...{for (final view in found) view.id!: view},
};
_subject.add(updatedState);
emit(SavedViewRepositoryState(values: updatedState, hasLoaded: true));
return found;
}
@override
Map<int, SavedView>? get current => _subject.valueOrNull;
@override
bool get isInitialized => _subject.hasValue;
@override
Future<SavedView> update(SavedView object) {
throw UnimplementedError("Saved view update is not yet implemented");
throw UnimplementedError(
"Saved view update is not yet implemented as it is not supported by the API.");
}
@override
SavedViewRepositoryState fromJson(Map<String, dynamic> json) {
return SavedViewRepositoryState.fromJson(json);
}
@override
Map<String, dynamic> toJson(SavedViewRepositoryState state) {
return state.toJson();
}
}

View File

@@ -1,35 +1,30 @@
import 'package:paperless_api/paperless_api.dart';
import 'package:paperless_mobile/core/repository/label_repository.dart';
import 'package:paperless_mobile/core/repository/state/impl/storage_path_repository_state.dart';
import 'package:rxdart/rxdart.dart' show BehaviorSubject;
class StoragePathRepositoryImpl implements LabelRepository<StoragePath> {
class StoragePathRepositoryImpl
extends LabelRepository<StoragePath, StoragePathRepositoryState> {
final PaperlessLabelsApi _api;
final _subject = BehaviorSubject<Map<int, StoragePath>?>();
StoragePathRepositoryImpl(this._api);
@override
Stream<Map<int, StoragePath>?> get values =>
_subject.stream.asBroadcastStream();
Map<int, StoragePath> get _currentValueOrEmpty => _subject.valueOrNull ?? {};
StoragePathRepositoryImpl(this._api)
: super(const StoragePathRepositoryState());
@override
Future<StoragePath> create(StoragePath storagePath) async {
final created = await _api.saveStoragePath(storagePath);
final updatedState = {..._currentValueOrEmpty}
final updatedState = {...state.values}
..putIfAbsent(created.id!, () => created);
_subject.add(updatedState);
emit(StoragePathRepositoryState(values: updatedState, hasLoaded: true));
return created;
}
@override
Future<int> delete(StoragePath storagePath) async {
await _api.deleteStoragePath(storagePath);
final updatedState = {..._currentValueOrEmpty}
final updatedState = {...state.values}
..removeWhere((k, v) => k == storagePath.id);
_subject.add(updatedState);
emit(StoragePathRepositoryState(values: updatedState, hasLoaded: true));
return storagePath.id!;
}
@@ -37,8 +32,8 @@ class StoragePathRepositoryImpl implements LabelRepository<StoragePath> {
Future<StoragePath?> find(int id) async {
final storagePath = await _api.getStoragePath(id);
if (storagePath != null) {
final updatedState = {..._currentValueOrEmpty}..[id] = storagePath;
_subject.add(updatedState);
final updatedState = {...state.values}..[id] = storagePath;
emit(StoragePathRepositoryState(values: updatedState, hasLoaded: true));
return storagePath;
}
return null;
@@ -47,29 +42,27 @@ class StoragePathRepositoryImpl implements LabelRepository<StoragePath> {
@override
Future<Iterable<StoragePath>> findAll([Iterable<int>? ids]) async {
final storagePaths = await _api.getStoragePaths(ids);
final updatedState = {..._currentValueOrEmpty}
final updatedState = {...state.values}
..addEntries(storagePaths.map((e) => MapEntry(e.id!, e)));
_subject.add(updatedState);
emit(StoragePathRepositoryState(values: updatedState, hasLoaded: true));
return storagePaths;
}
@override
Future<StoragePath> update(StoragePath storagePath) async {
final updated = await _api.updateStoragePath(storagePath);
final updatedState = {..._currentValueOrEmpty}
..update(updated.id!, (_) => updated);
_subject.add(updatedState);
final updatedState = {...state.values}..update(updated.id!, (_) => updated);
emit(StoragePathRepositoryState(values: updatedState, hasLoaded: true));
return updated;
}
@override
void clear() {
_subject.add(const {});
StoragePathRepositoryState fromJson(Map<String, dynamic> json) {
return StoragePathRepositoryState.fromJson(json);
}
@override
Map<int, StoragePath>? get current => _subject.valueOrNull;
@override
bool get isInitialized => _subject.valueOrNull != null;
Map<String, dynamic> toJson(StoragePathRepositoryState state) {
return state.toJson();
}
}

View File

@@ -1,34 +1,28 @@
import 'package:paperless_api/paperless_api.dart';
import 'package:paperless_mobile/core/repository/label_repository.dart';
import 'package:rxdart/rxdart.dart' show BehaviorSubject;
import 'package:paperless_mobile/core/repository/state/impl/correspondent_repository_state.dart';
import 'package:paperless_mobile/core/repository/state/impl/tag_repository_state.dart';
import 'package:paperless_mobile/core/repository/state/repository_state.dart';
class TagRepositoryImpl implements LabelRepository<Tag> {
class TagRepositoryImpl extends LabelRepository<Tag, TagRepositoryState> {
final PaperlessLabelsApi _api;
final _subject = BehaviorSubject<Map<int, Tag>?>();
TagRepositoryImpl(this._api);
TagRepositoryImpl(this._api) : super(const TagRepositoryState());
@override
Stream<Map<int, Tag>?> get values => _subject.stream.asBroadcastStream();
Map<int, Tag> get _currentValueOrEmpty => _subject.valueOrNull ?? {};
@override
Future<Tag> create(Tag tag) async {
final created = await _api.saveTag(tag);
final updatedState = {..._currentValueOrEmpty}
Future<Tag> create(Tag object) async {
final created = await _api.saveTag(object);
final updatedState = {...state.values}
..putIfAbsent(created.id!, () => created);
_subject.add(updatedState);
emit(TagRepositoryState(values: updatedState, hasLoaded: true));
return created;
}
@override
Future<int> delete(Tag tag) async {
await _api.deleteTag(tag);
final updatedState = {..._currentValueOrEmpty}
..removeWhere((k, v) => k == tag.id);
_subject.add(updatedState);
final updatedState = {...state.values}..removeWhere((k, v) => k == tag.id);
emit(TagRepositoryState(values: updatedState, hasLoaded: true));
return tag.id!;
}
@@ -36,8 +30,8 @@ class TagRepositoryImpl implements LabelRepository<Tag> {
Future<Tag?> find(int id) async {
final tag = await _api.getTag(id);
if (tag != null) {
final updatedState = {..._currentValueOrEmpty}..[id] = tag;
_subject.add(updatedState);
final updatedState = {...state.values}..[id] = tag;
emit(TagRepositoryState(values: updatedState, hasLoaded: true));
return tag;
}
return null;
@@ -46,29 +40,27 @@ class TagRepositoryImpl implements LabelRepository<Tag> {
@override
Future<Iterable<Tag>> findAll([Iterable<int>? ids]) async {
final tags = await _api.getTags(ids);
final updatedState = {..._currentValueOrEmpty}
final updatedState = {...state.values}
..addEntries(tags.map((e) => MapEntry(e.id!, e)));
_subject.add(updatedState);
emit(TagRepositoryState(values: updatedState, hasLoaded: true));
return tags;
}
@override
Future<Tag> update(Tag tag) async {
final updated = await _api.updateTag(tag);
final updatedState = {..._currentValueOrEmpty}
..update(updated.id!, (_) => updated);
_subject.add(updatedState);
final updatedState = {...state.values}..update(updated.id!, (_) => updated);
emit(TagRepositoryState(values: updatedState, hasLoaded: true));
return updated;
}
@override
void clear() {
_subject.add(null);
TagRepositoryState? fromJson(Map<String, dynamic> json) {
return TagRepositoryState.fromJson(json);
}
@override
Map<int, Tag>? get current => _subject.valueOrNull;
@override
bool get isInitialized => _subject.valueOrNull != null;
Map<String, dynamic>? toJson(TagRepositoryState state) {
return state.toJson();
}
}