mirror of
https://github.com/Xevion/paperless-mobile.git
synced 2025-12-07 03:15:49 -06:00
fix: Add labels to each cubit using repositories and state properties, remove label cubits
This commit is contained in:
@@ -1,34 +0,0 @@
|
||||
import 'package:hydrated_bloc/hydrated_bloc.dart';
|
||||
import 'package:paperless_mobile/core/repository/state/indexed_repository_state.dart';
|
||||
import 'package:rxdart/subjects.dart';
|
||||
|
||||
///
|
||||
/// Base repository class which all repositories should implement
|
||||
///
|
||||
abstract class BaseRepository<T> extends Cubit<IndexedRepositoryState<T>>
|
||||
with HydratedMixin {
|
||||
final IndexedRepositoryState<T> _initialState;
|
||||
|
||||
BaseRepository(this._initialState) : super(_initialState) {
|
||||
hydrate();
|
||||
}
|
||||
|
||||
Stream<IndexedRepositoryState<T>?> get values =>
|
||||
BehaviorSubject.seeded(state)..addStream(super.stream);
|
||||
|
||||
IndexedRepositoryState<T>? get current => state;
|
||||
|
||||
bool get isInitialized => state.hasLoaded;
|
||||
|
||||
Future<T> create(T object);
|
||||
Future<T?> find(int id);
|
||||
Future<Iterable<T>> findAll([Iterable<int>? ids]);
|
||||
Future<T> update(T object);
|
||||
Future<int> delete(T object);
|
||||
|
||||
@override
|
||||
Future<void> clear() async {
|
||||
await super.clear();
|
||||
emit(_initialState);
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||
import 'package:paperless_mobile/core/repository/state/impl/correspondent_repository_state.dart';
|
||||
|
||||
class CorrespondentRepositoryImpl extends LabelRepository<Correspondent> {
|
||||
final PaperlessLabelsApi _api;
|
||||
|
||||
CorrespondentRepositoryImpl(this._api)
|
||||
: super(const CorrespondentRepositoryState());
|
||||
|
||||
@override
|
||||
Future<Correspondent> create(Correspondent correspondent) async {
|
||||
final created = await _api.saveCorrespondent(correspondent);
|
||||
final updatedState = {...state.values ?? {}}
|
||||
..putIfAbsent(created.id!, () => created);
|
||||
emit(CorrespondentRepositoryState(values: updatedState, hasLoaded: true));
|
||||
return created;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> delete(Correspondent correspondent) async {
|
||||
await _api.deleteCorrespondent(correspondent);
|
||||
final updatedState = {...state.values ?? {}}
|
||||
..removeWhere((k, v) => k == correspondent.id);
|
||||
emit(CorrespondentRepositoryState(values: updatedState, hasLoaded: true));
|
||||
return correspondent.id!;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Correspondent?> find(int id) async {
|
||||
final correspondent = await _api.getCorrespondent(id);
|
||||
if (correspondent != null) {
|
||||
final updatedState = {...state.values ?? {}}..[id] = correspondent;
|
||||
emit(CorrespondentRepositoryState(values: updatedState, hasLoaded: true));
|
||||
return correspondent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Iterable<Correspondent>> findAll([Iterable<int>? ids]) async {
|
||||
final correspondents = await _api.getCorrespondents(ids);
|
||||
final updatedState = {...state.values ?? {}}
|
||||
..addEntries(correspondents.map((e) => MapEntry(e.id!, e)));
|
||||
emit(CorrespondentRepositoryState(values: updatedState, hasLoaded: true));
|
||||
return correspondents;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Correspondent> update(Correspondent correspondent) async {
|
||||
final updated = await _api.updateCorrespondent(correspondent);
|
||||
final updatedState = {...state.values ?? {}}
|
||||
..update(updated.id!, (_) => updated);
|
||||
emit(CorrespondentRepositoryState(values: updatedState, hasLoaded: true));
|
||||
return updated;
|
||||
}
|
||||
|
||||
@override
|
||||
CorrespondentRepositoryState fromJson(Map<String, dynamic> json) {
|
||||
return CorrespondentRepositoryState.fromJson(json);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson(covariant CorrespondentRepositoryState state) {
|
||||
return state.toJson();
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
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';
|
||||
|
||||
class DocumentTypeRepositoryImpl extends LabelRepository<DocumentType> {
|
||||
final PaperlessLabelsApi _api;
|
||||
|
||||
DocumentTypeRepositoryImpl(this._api)
|
||||
: super(const DocumentTypeRepositoryState());
|
||||
|
||||
@override
|
||||
Future<DocumentType> create(DocumentType documentType) async {
|
||||
final created = await _api.saveDocumentType(documentType);
|
||||
final updatedState = {...state.values ?? {}}
|
||||
..putIfAbsent(created.id!, () => created);
|
||||
emit(DocumentTypeRepositoryState(values: updatedState, hasLoaded: true));
|
||||
return created;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> delete(DocumentType documentType) async {
|
||||
await _api.deleteDocumentType(documentType);
|
||||
final updatedState = {...state.values ?? {}}
|
||||
..removeWhere((k, v) => k == documentType.id);
|
||||
emit(DocumentTypeRepositoryState(values: updatedState, hasLoaded: true));
|
||||
return documentType.id!;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<DocumentType?> find(int id) async {
|
||||
final documentType = await _api.getDocumentType(id);
|
||||
if (documentType != null) {
|
||||
final updatedState = {...state.values ?? {}}..[id] = documentType;
|
||||
emit(DocumentTypeRepositoryState(values: updatedState, hasLoaded: true));
|
||||
return documentType;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Iterable<DocumentType>> findAll([Iterable<int>? ids]) async {
|
||||
final documentTypes = await _api.getDocumentTypes(ids);
|
||||
final updatedState = {...state.values ?? {}}
|
||||
..addEntries(documentTypes.map((e) => MapEntry(e.id!, e)));
|
||||
emit(DocumentTypeRepositoryState(values: updatedState, hasLoaded: true));
|
||||
return documentTypes;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<DocumentType> update(DocumentType documentType) async {
|
||||
final updated = await _api.updateDocumentType(documentType);
|
||||
final updatedState = {...state.values ?? {}}
|
||||
..update(updated.id!, (_) => updated);
|
||||
emit(DocumentTypeRepositoryState(values: updatedState, hasLoaded: true));
|
||||
return updated;
|
||||
}
|
||||
|
||||
@override
|
||||
DocumentTypeRepositoryState fromJson(Map<String, dynamic> json) {
|
||||
return DocumentTypeRepositoryState.fromJson(json);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson(covariant DocumentTypeRepositoryState state) {
|
||||
return state.toJson();
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/repository/saved_view_repository.dart';
|
||||
import 'package:paperless_mobile/core/repository/state/impl/saved_view_repository_state.dart';
|
||||
|
||||
class SavedViewRepositoryImpl extends SavedViewRepository {
|
||||
final PaperlessSavedViewsApi _api;
|
||||
|
||||
SavedViewRepositoryImpl(this._api) : super(const SavedViewRepositoryState());
|
||||
|
||||
@override
|
||||
Future<SavedView> create(SavedView object) async {
|
||||
final created = await _api.save(object);
|
||||
final updatedState = {...state.values ?? {}}
|
||||
..putIfAbsent(created.id!, () => created);
|
||||
emit(SavedViewRepositoryState(values: updatedState, hasLoaded: true));
|
||||
return created;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> delete(SavedView view) async {
|
||||
await _api.delete(view);
|
||||
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 = {...state.values ?? {}}
|
||||
..update(id, (_) => found, ifAbsent: () => found);
|
||||
emit(SavedViewRepositoryState(values: updatedState, hasLoaded: true));
|
||||
return found;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Iterable<SavedView>> findAll([Iterable<int>? ids]) async {
|
||||
final found = await _api.findAll(ids);
|
||||
final updatedState = {
|
||||
...state.values ?? {},
|
||||
...{for (final view in found) view.id!: view},
|
||||
};
|
||||
emit(SavedViewRepositoryState(values: updatedState, hasLoaded: true));
|
||||
return found;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<SavedView> update(SavedView object) {
|
||||
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(covariant SavedViewRepositoryState state) {
|
||||
return state.toJson();
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
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 extends LabelRepository<StoragePath> {
|
||||
final PaperlessLabelsApi _api;
|
||||
|
||||
StoragePathRepositoryImpl(this._api)
|
||||
: super(const StoragePathRepositoryState());
|
||||
|
||||
@override
|
||||
Future<StoragePath> create(StoragePath storagePath) async {
|
||||
final created = await _api.saveStoragePath(storagePath);
|
||||
final updatedState = {...state.values ?? {}}
|
||||
..putIfAbsent(created.id!, () => created);
|
||||
emit(StoragePathRepositoryState(values: updatedState, hasLoaded: true));
|
||||
return created;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> delete(StoragePath storagePath) async {
|
||||
await _api.deleteStoragePath(storagePath);
|
||||
final updatedState = {...state.values ?? {}}
|
||||
..removeWhere((k, v) => k == storagePath.id);
|
||||
emit(StoragePathRepositoryState(values: updatedState, hasLoaded: true));
|
||||
return storagePath.id!;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<StoragePath?> find(int id) async {
|
||||
final storagePath = await _api.getStoragePath(id);
|
||||
if (storagePath != null) {
|
||||
final updatedState = {...state.values ?? {}}..[id] = storagePath;
|
||||
emit(StoragePathRepositoryState(values: updatedState, hasLoaded: true));
|
||||
return storagePath;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Iterable<StoragePath>> findAll([Iterable<int>? ids]) async {
|
||||
final storagePaths = await _api.getStoragePaths(ids);
|
||||
final updatedState = {...state.values ?? {}}
|
||||
..addEntries(storagePaths.map((e) => MapEntry(e.id!, e)));
|
||||
emit(StoragePathRepositoryState(values: updatedState, hasLoaded: true));
|
||||
return storagePaths;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<StoragePath> update(StoragePath storagePath) async {
|
||||
final updated = await _api.updateStoragePath(storagePath);
|
||||
final updatedState = {...state.values ?? {}}
|
||||
..update(updated.id!, (_) => updated);
|
||||
emit(StoragePathRepositoryState(values: updatedState, hasLoaded: true));
|
||||
return updated;
|
||||
}
|
||||
|
||||
@override
|
||||
StoragePathRepositoryState fromJson(Map<String, dynamic> json) {
|
||||
return StoragePathRepositoryState.fromJson(json);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson(covariant StoragePathRepositoryState state) {
|
||||
return state.toJson();
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||
import 'package:paperless_mobile/core/repository/state/impl/tag_repository_state.dart';
|
||||
|
||||
class TagRepositoryImpl extends LabelRepository<Tag> {
|
||||
final PaperlessLabelsApi _api;
|
||||
|
||||
TagRepositoryImpl(this._api) : super(const TagRepositoryState());
|
||||
|
||||
@override
|
||||
Future<Tag> create(Tag object) async {
|
||||
final created = await _api.saveTag(object);
|
||||
final updatedState = {...state.values ?? {}}
|
||||
..putIfAbsent(created.id!, () => created);
|
||||
emit(TagRepositoryState(values: updatedState, hasLoaded: true));
|
||||
return created;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> delete(Tag tag) async {
|
||||
await _api.deleteTag(tag);
|
||||
final updatedState = {...state.values ?? {}}
|
||||
..removeWhere((k, v) => k == tag.id);
|
||||
emit(TagRepositoryState(values: updatedState, hasLoaded: true));
|
||||
return tag.id!;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Tag?> find(int id) async {
|
||||
final tag = await _api.getTag(id);
|
||||
if (tag != null) {
|
||||
final updatedState = {...state.values ?? {}}..[id] = tag;
|
||||
emit(TagRepositoryState(values: updatedState, hasLoaded: true));
|
||||
return tag;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Iterable<Tag>> findAll([Iterable<int>? ids]) async {
|
||||
final tags = await _api.getTags(ids);
|
||||
final updatedState = {...state.values ?? {}}
|
||||
..addEntries(tags.map((e) => MapEntry(e.id!, e)));
|
||||
emit(TagRepositoryState(values: updatedState, hasLoaded: true));
|
||||
return tags;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Tag> update(Tag tag) async {
|
||||
final updated = await _api.updateTag(tag);
|
||||
final updatedState = {...state.values ?? {}}
|
||||
..update(updated.id!, (_) => updated);
|
||||
emit(TagRepositoryState(values: updatedState, hasLoaded: true));
|
||||
return updated;
|
||||
}
|
||||
|
||||
@override
|
||||
TagRepositoryState? fromJson(Map<String, dynamic> json) {
|
||||
return TagRepositoryState.fromJson(json);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic>? toJson(covariant TagRepositoryState state) {
|
||||
return state.toJson();
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,218 @@
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/repository/base_repository.dart';
|
||||
import 'package:paperless_mobile/core/repository/state/indexed_repository_state.dart';
|
||||
import 'dart:async';
|
||||
|
||||
abstract class LabelRepository<T extends Label> extends BaseRepository<T> {
|
||||
LabelRepository(IndexedRepositoryState<T> initial) : super(initial);
|
||||
import 'package:hydrated_bloc/hydrated_bloc.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/repository/label_repository_state.dart';
|
||||
|
||||
class LabelRepository extends HydratedCubit<LabelRepositoryState> {
|
||||
final PaperlessLabelsApi _api;
|
||||
final Map<Object, StreamSubscription> _subscribers = {};
|
||||
|
||||
void subscribe(
|
||||
Object source, {
|
||||
required void Function(LabelRepositoryState) onChanged,
|
||||
}) {
|
||||
_subscribers.putIfAbsent(source, () {
|
||||
onChanged(state);
|
||||
return stream.listen((event) => onChanged(event));
|
||||
});
|
||||
}
|
||||
|
||||
void unsubscribe(Object source) async {
|
||||
await _subscribers[source]?.cancel();
|
||||
_subscribers.remove(source);
|
||||
}
|
||||
|
||||
LabelRepository(this._api) : super(const LabelRepositoryState());
|
||||
|
||||
Future<Tag> createTag(Tag object) async {
|
||||
final created = await _api.saveTag(object);
|
||||
final updatedState = {...state.tags}
|
||||
..putIfAbsent(created.id!, () => created);
|
||||
emit(state.copyWith(tags: updatedState));
|
||||
return created;
|
||||
}
|
||||
|
||||
Future<int> deleteTag(Tag tag) async {
|
||||
await _api.deleteTag(tag);
|
||||
final updatedState = {...state.tags}..removeWhere((k, v) => k == tag.id);
|
||||
emit(state.copyWith(tags: updatedState));
|
||||
return tag.id!;
|
||||
}
|
||||
|
||||
Future<Tag?> findTag(int id) async {
|
||||
final tag = await _api.getTag(id);
|
||||
if (tag != null) {
|
||||
final updatedState = {...state.tags}..[id] = tag;
|
||||
emit(state.copyWith(tags: updatedState));
|
||||
return tag;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<Iterable<Tag>> findAllTags([Iterable<int>? ids]) async {
|
||||
final tags = await _api.getTags(ids);
|
||||
final updatedState = {...state.tags}
|
||||
..addEntries(tags.map((e) => MapEntry(e.id!, e)));
|
||||
emit(state.copyWith(tags: updatedState));
|
||||
return tags;
|
||||
}
|
||||
|
||||
Future<Tag> updateTag(Tag tag) async {
|
||||
final updated = await _api.updateTag(tag);
|
||||
final updatedState = {...state.tags}..update(updated.id!, (_) => updated);
|
||||
emit(state.copyWith(tags: updatedState));
|
||||
return updated;
|
||||
}
|
||||
|
||||
Future<Correspondent> createCorrespondent(Correspondent correspondent) async {
|
||||
final created = await _api.saveCorrespondent(correspondent);
|
||||
final updatedState = {...state.correspondents}
|
||||
..putIfAbsent(created.id!, () => created);
|
||||
emit(state.copyWith(correspondents: updatedState));
|
||||
return created;
|
||||
}
|
||||
|
||||
Future<int> deleteCorrespondent(Correspondent correspondent) async {
|
||||
await _api.deleteCorrespondent(correspondent);
|
||||
final updatedState = {...state.correspondents}
|
||||
..removeWhere((k, v) => k == correspondent.id);
|
||||
emit(state.copyWith(correspondents: updatedState));
|
||||
|
||||
return correspondent.id!;
|
||||
}
|
||||
|
||||
Future<Correspondent?> findCorrespondent(int id) async {
|
||||
final correspondent = await _api.getCorrespondent(id);
|
||||
if (correspondent != null) {
|
||||
final updatedState = {...state.correspondents}..[id] = correspondent;
|
||||
emit(state.copyWith(correspondents: updatedState));
|
||||
|
||||
return correspondent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<Iterable<Correspondent>> findAllCorrespondents(
|
||||
[Iterable<int>? ids]) async {
|
||||
final correspondents = await _api.getCorrespondents(ids);
|
||||
final updatedState = {...state.correspondents}
|
||||
..addEntries(correspondents.map((e) => MapEntry(e.id!, e)));
|
||||
emit(state.copyWith(correspondents: updatedState));
|
||||
|
||||
return correspondents;
|
||||
}
|
||||
|
||||
Future<Correspondent> updateCorrespondent(Correspondent correspondent) async {
|
||||
final updated = await _api.updateCorrespondent(correspondent);
|
||||
final updatedState = {...state.correspondents}
|
||||
..update(updated.id!, (_) => updated);
|
||||
emit(state.copyWith(correspondents: updatedState));
|
||||
|
||||
return updated;
|
||||
}
|
||||
|
||||
Future<DocumentType> createDocumentType(DocumentType documentType) async {
|
||||
final created = await _api.saveDocumentType(documentType);
|
||||
final updatedState = {...state.documentTypes}
|
||||
..putIfAbsent(created.id!, () => created);
|
||||
emit(state.copyWith(documentTypes: updatedState));
|
||||
return created;
|
||||
}
|
||||
|
||||
Future<int> deleteDocumentType(DocumentType documentType) async {
|
||||
await _api.deleteDocumentType(documentType);
|
||||
final updatedState = {...state.documentTypes}
|
||||
..removeWhere((k, v) => k == documentType.id);
|
||||
emit(state.copyWith(documentTypes: updatedState));
|
||||
return documentType.id!;
|
||||
}
|
||||
|
||||
Future<DocumentType?> findDocumentType(int id) async {
|
||||
final documentType = await _api.getDocumentType(id);
|
||||
if (documentType != null) {
|
||||
final updatedState = {...state.documentTypes}..[id] = documentType;
|
||||
emit(state.copyWith(documentTypes: updatedState));
|
||||
return documentType;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<Iterable<DocumentType>> findAllDocumentTypes(
|
||||
[Iterable<int>? ids]) async {
|
||||
final documentTypes = await _api.getDocumentTypes(ids);
|
||||
final updatedState = {...state.documentTypes}
|
||||
..addEntries(documentTypes.map((e) => MapEntry(e.id!, e)));
|
||||
emit(state.copyWith(documentTypes: updatedState));
|
||||
return documentTypes;
|
||||
}
|
||||
|
||||
Future<DocumentType> updateDocumentType(DocumentType documentType) async {
|
||||
final updated = await _api.updateDocumentType(documentType);
|
||||
final updatedState = {...state.documentTypes}
|
||||
..update(updated.id!, (_) => updated);
|
||||
emit(state.copyWith(documentTypes: updatedState));
|
||||
return updated;
|
||||
}
|
||||
|
||||
Future<StoragePath> createStoragePath(StoragePath storagePath) async {
|
||||
final created = await _api.saveStoragePath(storagePath);
|
||||
final updatedState = {...state.storagePaths}
|
||||
..putIfAbsent(created.id!, () => created);
|
||||
emit(state.copyWith(storagePaths: updatedState));
|
||||
return created;
|
||||
}
|
||||
|
||||
Future<int> deleteStoragePath(StoragePath storagePath) async {
|
||||
await _api.deleteStoragePath(storagePath);
|
||||
final updatedState = {...state.storagePaths}
|
||||
..removeWhere((k, v) => k == storagePath.id);
|
||||
emit(state.copyWith(storagePaths: updatedState));
|
||||
return storagePath.id!;
|
||||
}
|
||||
|
||||
Future<StoragePath?> findStoragePath(int id) async {
|
||||
final storagePath = await _api.getStoragePath(id);
|
||||
if (storagePath != null) {
|
||||
final updatedState = {...state.storagePaths}..[id] = storagePath;
|
||||
emit(state.copyWith(storagePaths: updatedState));
|
||||
return storagePath;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<Iterable<StoragePath>> findAllStoragePaths(
|
||||
[Iterable<int>? ids]) async {
|
||||
final storagePaths = await _api.getStoragePaths(ids);
|
||||
final updatedState = {...state.storagePaths}
|
||||
..addEntries(storagePaths.map((e) => MapEntry(e.id!, e)));
|
||||
emit(state.copyWith(storagePaths: updatedState));
|
||||
return storagePaths;
|
||||
}
|
||||
|
||||
Future<StoragePath> updateStoragePath(StoragePath storagePath) async {
|
||||
final updated = await _api.updateStoragePath(storagePath);
|
||||
final updatedState = {...state.storagePaths}
|
||||
..update(updated.id!, (_) => updated);
|
||||
emit(state.copyWith(storagePaths: updatedState));
|
||||
return updated;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
_subscribers.forEach((key, subscription) {
|
||||
subscription.cancel();
|
||||
});
|
||||
return super.close();
|
||||
}
|
||||
|
||||
@override
|
||||
LabelRepositoryState? fromJson(Map<String, dynamic> json) {
|
||||
return LabelRepositoryState.fromJson(json);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic>? toJson(LabelRepositoryState state) {
|
||||
return state.toJson();
|
||||
}
|
||||
}
|
||||
|
||||
18
lib/core/repository/label_repository_state.dart
Normal file
18
lib/core/repository/label_repository_state.dart
Normal file
@@ -0,0 +1,18 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
|
||||
part 'label_repository_state.freezed.dart';
|
||||
part 'label_repository_state.g.dart';
|
||||
|
||||
@freezed
|
||||
class LabelRepositoryState with _$LabelRepositoryState {
|
||||
const factory LabelRepositoryState({
|
||||
@Default({}) Map<int, Correspondent> correspondents,
|
||||
@Default({}) Map<int, DocumentType> documentTypes,
|
||||
@Default({}) Map<int, Tag> tags,
|
||||
@Default({}) Map<int, StoragePath> storagePaths,
|
||||
}) = _LabelRepositoryState;
|
||||
|
||||
factory LabelRepositoryState.fromJson(Map<String, dynamic> json) =>
|
||||
_$LabelRepositoryStateFromJson(json);
|
||||
}
|
||||
258
lib/core/repository/label_repository_state.freezed.dart
Normal file
258
lib/core/repository/label_repository_state.freezed.dart
Normal file
@@ -0,0 +1,258 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'label_repository_state.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
|
||||
|
||||
LabelRepositoryState _$LabelRepositoryStateFromJson(Map<String, dynamic> json) {
|
||||
return _LabelRepositoryState.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$LabelRepositoryState {
|
||||
Map<int, Correspondent> get correspondents =>
|
||||
throw _privateConstructorUsedError;
|
||||
Map<int, DocumentType> get documentTypes =>
|
||||
throw _privateConstructorUsedError;
|
||||
Map<int, Tag> get tags => throw _privateConstructorUsedError;
|
||||
Map<int, StoragePath> get storagePaths => throw _privateConstructorUsedError;
|
||||
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
$LabelRepositoryStateCopyWith<LabelRepositoryState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $LabelRepositoryStateCopyWith<$Res> {
|
||||
factory $LabelRepositoryStateCopyWith(LabelRepositoryState value,
|
||||
$Res Function(LabelRepositoryState) then) =
|
||||
_$LabelRepositoryStateCopyWithImpl<$Res, LabelRepositoryState>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{Map<int, Correspondent> correspondents,
|
||||
Map<int, DocumentType> documentTypes,
|
||||
Map<int, Tag> tags,
|
||||
Map<int, StoragePath> storagePaths});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$LabelRepositoryStateCopyWithImpl<$Res,
|
||||
$Val extends LabelRepositoryState>
|
||||
implements $LabelRepositoryStateCopyWith<$Res> {
|
||||
_$LabelRepositoryStateCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? correspondents = null,
|
||||
Object? documentTypes = null,
|
||||
Object? tags = null,
|
||||
Object? storagePaths = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
correspondents: null == correspondents
|
||||
? _value.correspondents
|
||||
: correspondents // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, Correspondent>,
|
||||
documentTypes: null == documentTypes
|
||||
? _value.documentTypes
|
||||
: documentTypes // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, DocumentType>,
|
||||
tags: null == tags
|
||||
? _value.tags
|
||||
: tags // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, Tag>,
|
||||
storagePaths: null == storagePaths
|
||||
? _value.storagePaths
|
||||
: storagePaths // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, StoragePath>,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$_LabelRepositoryStateCopyWith<$Res>
|
||||
implements $LabelRepositoryStateCopyWith<$Res> {
|
||||
factory _$$_LabelRepositoryStateCopyWith(_$_LabelRepositoryState value,
|
||||
$Res Function(_$_LabelRepositoryState) then) =
|
||||
__$$_LabelRepositoryStateCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{Map<int, Correspondent> correspondents,
|
||||
Map<int, DocumentType> documentTypes,
|
||||
Map<int, Tag> tags,
|
||||
Map<int, StoragePath> storagePaths});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$_LabelRepositoryStateCopyWithImpl<$Res>
|
||||
extends _$LabelRepositoryStateCopyWithImpl<$Res, _$_LabelRepositoryState>
|
||||
implements _$$_LabelRepositoryStateCopyWith<$Res> {
|
||||
__$$_LabelRepositoryStateCopyWithImpl(_$_LabelRepositoryState _value,
|
||||
$Res Function(_$_LabelRepositoryState) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? correspondents = null,
|
||||
Object? documentTypes = null,
|
||||
Object? tags = null,
|
||||
Object? storagePaths = null,
|
||||
}) {
|
||||
return _then(_$_LabelRepositoryState(
|
||||
correspondents: null == correspondents
|
||||
? _value._correspondents
|
||||
: correspondents // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, Correspondent>,
|
||||
documentTypes: null == documentTypes
|
||||
? _value._documentTypes
|
||||
: documentTypes // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, DocumentType>,
|
||||
tags: null == tags
|
||||
? _value._tags
|
||||
: tags // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, Tag>,
|
||||
storagePaths: null == storagePaths
|
||||
? _value._storagePaths
|
||||
: storagePaths // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, StoragePath>,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$_LabelRepositoryState implements _LabelRepositoryState {
|
||||
const _$_LabelRepositoryState(
|
||||
{final Map<int, Correspondent> correspondents = const {},
|
||||
final Map<int, DocumentType> documentTypes = const {},
|
||||
final Map<int, Tag> tags = const {},
|
||||
final Map<int, StoragePath> storagePaths = const {}})
|
||||
: _correspondents = correspondents,
|
||||
_documentTypes = documentTypes,
|
||||
_tags = tags,
|
||||
_storagePaths = storagePaths;
|
||||
|
||||
factory _$_LabelRepositoryState.fromJson(Map<String, dynamic> json) =>
|
||||
_$$_LabelRepositoryStateFromJson(json);
|
||||
|
||||
final Map<int, Correspondent> _correspondents;
|
||||
@override
|
||||
@JsonKey()
|
||||
Map<int, Correspondent> get correspondents {
|
||||
if (_correspondents is EqualUnmodifiableMapView) return _correspondents;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableMapView(_correspondents);
|
||||
}
|
||||
|
||||
final Map<int, DocumentType> _documentTypes;
|
||||
@override
|
||||
@JsonKey()
|
||||
Map<int, DocumentType> get documentTypes {
|
||||
if (_documentTypes is EqualUnmodifiableMapView) return _documentTypes;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableMapView(_documentTypes);
|
||||
}
|
||||
|
||||
final Map<int, Tag> _tags;
|
||||
@override
|
||||
@JsonKey()
|
||||
Map<int, Tag> get tags {
|
||||
if (_tags is EqualUnmodifiableMapView) return _tags;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableMapView(_tags);
|
||||
}
|
||||
|
||||
final Map<int, StoragePath> _storagePaths;
|
||||
@override
|
||||
@JsonKey()
|
||||
Map<int, StoragePath> get storagePaths {
|
||||
if (_storagePaths is EqualUnmodifiableMapView) return _storagePaths;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableMapView(_storagePaths);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'LabelRepositoryState(correspondents: $correspondents, documentTypes: $documentTypes, tags: $tags, storagePaths: $storagePaths)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(dynamic other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$_LabelRepositoryState &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._correspondents, _correspondents) &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._documentTypes, _documentTypes) &&
|
||||
const DeepCollectionEquality().equals(other._tags, _tags) &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._storagePaths, _storagePaths));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
const DeepCollectionEquality().hash(_correspondents),
|
||||
const DeepCollectionEquality().hash(_documentTypes),
|
||||
const DeepCollectionEquality().hash(_tags),
|
||||
const DeepCollectionEquality().hash(_storagePaths));
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$_LabelRepositoryStateCopyWith<_$_LabelRepositoryState> get copyWith =>
|
||||
__$$_LabelRepositoryStateCopyWithImpl<_$_LabelRepositoryState>(
|
||||
this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$_LabelRepositoryStateToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _LabelRepositoryState implements LabelRepositoryState {
|
||||
const factory _LabelRepositoryState(
|
||||
{final Map<int, Correspondent> correspondents,
|
||||
final Map<int, DocumentType> documentTypes,
|
||||
final Map<int, Tag> tags,
|
||||
final Map<int, StoragePath> storagePaths}) = _$_LabelRepositoryState;
|
||||
|
||||
factory _LabelRepositoryState.fromJson(Map<String, dynamic> json) =
|
||||
_$_LabelRepositoryState.fromJson;
|
||||
|
||||
@override
|
||||
Map<int, Correspondent> get correspondents;
|
||||
@override
|
||||
Map<int, DocumentType> get documentTypes;
|
||||
@override
|
||||
Map<int, Tag> get tags;
|
||||
@override
|
||||
Map<int, StoragePath> get storagePaths;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$_LabelRepositoryStateCopyWith<_$_LabelRepositoryState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/repository/impl/document_type_repository_impl.dart';
|
||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||
import 'package:paperless_mobile/core/repository/state/impl/correspondent_repository_state.dart';
|
||||
import 'package:paperless_mobile/core/repository/state/impl/document_type_repository_state.dart';
|
||||
import 'package:paperless_mobile/core/repository/state/impl/storage_path_repository_state.dart';
|
||||
import 'package:paperless_mobile/core/repository/state/impl/tag_repository_state.dart';
|
||||
|
||||
class LabelRepositoriesProvider extends StatelessWidget {
|
||||
final Widget child;
|
||||
const LabelRepositoriesProvider({super.key, required this.child});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MultiRepositoryProvider(
|
||||
providers: [
|
||||
RepositoryProvider(
|
||||
create: (context) => context.read<LabelRepository<Correspondent>>(),
|
||||
),
|
||||
RepositoryProvider(
|
||||
create: (context) => context.read<LabelRepository<DocumentType>>(),
|
||||
),
|
||||
RepositoryProvider(
|
||||
create: (context) => context.read<LabelRepository<StoragePath>>(),
|
||||
),
|
||||
RepositoryProvider(
|
||||
create: (context) => context.read<LabelRepository<Tag>>(),
|
||||
),
|
||||
],
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,80 @@
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/repository/base_repository.dart';
|
||||
import 'package:paperless_mobile/core/repository/state/impl/saved_view_repository_state.dart';
|
||||
import 'package:paperless_mobile/core/repository/state/indexed_repository_state.dart';
|
||||
import 'dart:async';
|
||||
|
||||
abstract class SavedViewRepository extends BaseRepository<SavedView> {
|
||||
SavedViewRepository(super.initialState);
|
||||
import 'package:hydrated_bloc/hydrated_bloc.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/repository/saved_view_repository_state.dart';
|
||||
|
||||
class SavedViewRepository extends HydratedCubit<SavedViewRepositoryState> {
|
||||
final PaperlessSavedViewsApi _api;
|
||||
final Map<Object, StreamSubscription> _subscribers = {};
|
||||
|
||||
void subscribe(
|
||||
Object source,
|
||||
void Function(Map<int, SavedView>) onChanged,
|
||||
) {
|
||||
_subscribers.putIfAbsent(source, () {
|
||||
onChanged(state.savedViews);
|
||||
return stream.listen((event) => onChanged(event.savedViews));
|
||||
});
|
||||
}
|
||||
|
||||
void unsubscribe(Object source) async {
|
||||
await _subscribers[source]?.cancel();
|
||||
_subscribers.remove(source);
|
||||
}
|
||||
|
||||
SavedViewRepository(this._api) : super(const SavedViewRepositoryState());
|
||||
|
||||
Future<SavedView> create(SavedView object) async {
|
||||
final created = await _api.save(object);
|
||||
final updatedState = {...state.savedViews}
|
||||
..putIfAbsent(created.id!, () => created);
|
||||
emit(state.copyWith(savedViews: updatedState));
|
||||
return created;
|
||||
}
|
||||
|
||||
Future<int> delete(SavedView view) async {
|
||||
await _api.delete(view);
|
||||
final updatedState = {...state.savedViews}..remove(view.id);
|
||||
emit(state.copyWith(savedViews: updatedState));
|
||||
return view.id!;
|
||||
}
|
||||
|
||||
Future<SavedView?> find(int id) async {
|
||||
final found = await _api.find(id);
|
||||
if (found != null) {
|
||||
final updatedState = {...state.savedViews}
|
||||
..update(id, (_) => found, ifAbsent: () => found);
|
||||
emit(state.copyWith(savedViews: updatedState));
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
Future<Iterable<SavedView>> findAll([Iterable<int>? ids]) async {
|
||||
final found = await _api.findAll(ids);
|
||||
final updatedState = {
|
||||
...state.savedViews,
|
||||
...{for (final view in found) view.id!: view},
|
||||
};
|
||||
emit(state.copyWith(savedViews: updatedState));
|
||||
return found;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
_subscribers.forEach((key, subscription) {
|
||||
subscription.cancel();
|
||||
});
|
||||
return super.close();
|
||||
}
|
||||
|
||||
@override
|
||||
SavedViewRepositoryState? fromJson(Map<String, dynamic> json) {
|
||||
return SavedViewRepositoryState.fromJson(json);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic>? toJson(SavedViewRepositoryState state) {
|
||||
return state.toJson();
|
||||
}
|
||||
}
|
||||
|
||||
15
lib/core/repository/saved_view_repository_state.dart
Normal file
15
lib/core/repository/saved_view_repository_state.dart
Normal file
@@ -0,0 +1,15 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
|
||||
part 'saved_view_repository_state.freezed.dart';
|
||||
part 'saved_view_repository_state.g.dart';
|
||||
|
||||
@freezed
|
||||
class SavedViewRepositoryState with _$SavedViewRepositoryState {
|
||||
const factory SavedViewRepositoryState({
|
||||
@Default({}) Map<int, SavedView> savedViews,
|
||||
}) = _SavedViewRepositoryState;
|
||||
|
||||
factory SavedViewRepositoryState.fromJson(Map<String, dynamic> json) =>
|
||||
_$SavedViewRepositoryStateFromJson(json);
|
||||
}
|
||||
167
lib/core/repository/saved_view_repository_state.freezed.dart
Normal file
167
lib/core/repository/saved_view_repository_state.freezed.dart
Normal file
@@ -0,0 +1,167 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'saved_view_repository_state.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
|
||||
|
||||
SavedViewRepositoryState _$SavedViewRepositoryStateFromJson(
|
||||
Map<String, dynamic> json) {
|
||||
return _SavedViewRepositoryState.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$SavedViewRepositoryState {
|
||||
Map<int, SavedView> get savedViews => throw _privateConstructorUsedError;
|
||||
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
$SavedViewRepositoryStateCopyWith<SavedViewRepositoryState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $SavedViewRepositoryStateCopyWith<$Res> {
|
||||
factory $SavedViewRepositoryStateCopyWith(SavedViewRepositoryState value,
|
||||
$Res Function(SavedViewRepositoryState) then) =
|
||||
_$SavedViewRepositoryStateCopyWithImpl<$Res, SavedViewRepositoryState>;
|
||||
@useResult
|
||||
$Res call({Map<int, SavedView> savedViews});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$SavedViewRepositoryStateCopyWithImpl<$Res,
|
||||
$Val extends SavedViewRepositoryState>
|
||||
implements $SavedViewRepositoryStateCopyWith<$Res> {
|
||||
_$SavedViewRepositoryStateCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? savedViews = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
savedViews: null == savedViews
|
||||
? _value.savedViews
|
||||
: savedViews // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, SavedView>,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$_SavedViewRepositoryStateCopyWith<$Res>
|
||||
implements $SavedViewRepositoryStateCopyWith<$Res> {
|
||||
factory _$$_SavedViewRepositoryStateCopyWith(
|
||||
_$_SavedViewRepositoryState value,
|
||||
$Res Function(_$_SavedViewRepositoryState) then) =
|
||||
__$$_SavedViewRepositoryStateCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({Map<int, SavedView> savedViews});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$_SavedViewRepositoryStateCopyWithImpl<$Res>
|
||||
extends _$SavedViewRepositoryStateCopyWithImpl<$Res,
|
||||
_$_SavedViewRepositoryState>
|
||||
implements _$$_SavedViewRepositoryStateCopyWith<$Res> {
|
||||
__$$_SavedViewRepositoryStateCopyWithImpl(_$_SavedViewRepositoryState _value,
|
||||
$Res Function(_$_SavedViewRepositoryState) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? savedViews = null,
|
||||
}) {
|
||||
return _then(_$_SavedViewRepositoryState(
|
||||
savedViews: null == savedViews
|
||||
? _value._savedViews
|
||||
: savedViews // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, SavedView>,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$_SavedViewRepositoryState implements _SavedViewRepositoryState {
|
||||
const _$_SavedViewRepositoryState(
|
||||
{final Map<int, SavedView> savedViews = const {}})
|
||||
: _savedViews = savedViews;
|
||||
|
||||
factory _$_SavedViewRepositoryState.fromJson(Map<String, dynamic> json) =>
|
||||
_$$_SavedViewRepositoryStateFromJson(json);
|
||||
|
||||
final Map<int, SavedView> _savedViews;
|
||||
@override
|
||||
@JsonKey()
|
||||
Map<int, SavedView> get savedViews {
|
||||
if (_savedViews is EqualUnmodifiableMapView) return _savedViews;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableMapView(_savedViews);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SavedViewRepositoryState(savedViews: $savedViews)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(dynamic other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$_SavedViewRepositoryState &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._savedViews, _savedViews));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType, const DeepCollectionEquality().hash(_savedViews));
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$_SavedViewRepositoryStateCopyWith<_$_SavedViewRepositoryState>
|
||||
get copyWith => __$$_SavedViewRepositoryStateCopyWithImpl<
|
||||
_$_SavedViewRepositoryState>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$_SavedViewRepositoryStateToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _SavedViewRepositoryState implements SavedViewRepositoryState {
|
||||
const factory _SavedViewRepositoryState(
|
||||
{final Map<int, SavedView> savedViews}) = _$_SavedViewRepositoryState;
|
||||
|
||||
factory _SavedViewRepositoryState.fromJson(Map<String, dynamic> json) =
|
||||
_$_SavedViewRepositoryState.fromJson;
|
||||
|
||||
@override
|
||||
Map<int, SavedView> get savedViews;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$_SavedViewRepositoryStateCopyWith<_$_SavedViewRepositoryState>
|
||||
get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/repository/state/indexed_repository_state.dart';
|
||||
|
||||
part 'correspondent_repository_state.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class CorrespondentRepositoryState
|
||||
extends IndexedRepositoryState<Correspondent> {
|
||||
const CorrespondentRepositoryState({
|
||||
super.values = const {},
|
||||
super.hasLoaded,
|
||||
});
|
||||
|
||||
@override
|
||||
CorrespondentRepositoryState copyWith({
|
||||
Map<int, Correspondent>? values,
|
||||
bool? hasLoaded,
|
||||
}) {
|
||||
return CorrespondentRepositoryState(
|
||||
values: values ?? this.values,
|
||||
hasLoaded: hasLoaded ?? this.hasLoaded,
|
||||
);
|
||||
}
|
||||
|
||||
factory CorrespondentRepositoryState.fromJson(Map<String, dynamic> json) =>
|
||||
_$CorrespondentRepositoryStateFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => _$CorrespondentRepositoryStateToJson(this);
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/repository/state/indexed_repository_state.dart';
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'document_type_repository_state.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class DocumentTypeRepositoryState extends IndexedRepositoryState<DocumentType> {
|
||||
const DocumentTypeRepositoryState({
|
||||
super.values = const {},
|
||||
super.hasLoaded,
|
||||
});
|
||||
|
||||
@override
|
||||
DocumentTypeRepositoryState copyWith({
|
||||
Map<int, DocumentType>? values,
|
||||
bool? hasLoaded,
|
||||
}) {
|
||||
return DocumentTypeRepositoryState(
|
||||
values: values ?? this.values,
|
||||
hasLoaded: hasLoaded ?? this.hasLoaded,
|
||||
);
|
||||
}
|
||||
|
||||
factory DocumentTypeRepositoryState.fromJson(Map<String, dynamic> json) =>
|
||||
_$DocumentTypeRepositoryStateFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => _$DocumentTypeRepositoryStateToJson(this);
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/repository/state/indexed_repository_state.dart';
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'saved_view_repository_state.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class SavedViewRepositoryState extends IndexedRepositoryState<SavedView> {
|
||||
const SavedViewRepositoryState({
|
||||
super.values = const {},
|
||||
super.hasLoaded = false,
|
||||
});
|
||||
|
||||
@override
|
||||
SavedViewRepositoryState copyWith({
|
||||
Map<int, SavedView>? values,
|
||||
bool? hasLoaded,
|
||||
}) {
|
||||
return SavedViewRepositoryState(
|
||||
values: values ?? this.values,
|
||||
hasLoaded: hasLoaded ?? this.hasLoaded,
|
||||
);
|
||||
}
|
||||
|
||||
factory SavedViewRepositoryState.fromJson(Map<String, dynamic> json) =>
|
||||
_$SavedViewRepositoryStateFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => _$SavedViewRepositoryStateToJson(this);
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/repository/state/indexed_repository_state.dart';
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'storage_path_repository_state.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class StoragePathRepositoryState extends IndexedRepositoryState<StoragePath> {
|
||||
const StoragePathRepositoryState({
|
||||
super.values = const {},
|
||||
super.hasLoaded = false,
|
||||
});
|
||||
|
||||
@override
|
||||
StoragePathRepositoryState copyWith({
|
||||
Map<int, StoragePath>? values,
|
||||
bool? hasLoaded,
|
||||
}) {
|
||||
return StoragePathRepositoryState(
|
||||
values: values ?? this.values,
|
||||
hasLoaded: hasLoaded ?? this.hasLoaded,
|
||||
);
|
||||
}
|
||||
|
||||
factory StoragePathRepositoryState.fromJson(Map<String, dynamic> json) =>
|
||||
_$StoragePathRepositoryStateFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => _$StoragePathRepositoryStateToJson(this);
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/repository/state/indexed_repository_state.dart';
|
||||
|
||||
part 'tag_repository_state.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class TagRepositoryState extends IndexedRepositoryState<Tag> {
|
||||
const TagRepositoryState({
|
||||
super.values = const {},
|
||||
super.hasLoaded = false,
|
||||
});
|
||||
|
||||
@override
|
||||
TagRepositoryState copyWith({
|
||||
Map<int, Tag>? values,
|
||||
bool? hasLoaded,
|
||||
}) {
|
||||
return TagRepositoryState(
|
||||
values: values ?? this.values,
|
||||
hasLoaded: hasLoaded ?? this.hasLoaded,
|
||||
);
|
||||
}
|
||||
|
||||
factory TagRepositoryState.fromJson(Map<String, dynamic> json) =>
|
||||
_$TagRepositoryStateFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => _$TagRepositoryStateToJson(this);
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
abstract class IndexedRepositoryState<T> {
|
||||
final Map<int, T>? values;
|
||||
final bool hasLoaded;
|
||||
|
||||
const IndexedRepositoryState({
|
||||
required this.values,
|
||||
this.hasLoaded = false,
|
||||
}) : assert(!(values == null) || !hasLoaded);
|
||||
|
||||
IndexedRepositoryState.loaded(this.values) : hasLoaded = true;
|
||||
|
||||
IndexedRepositoryState<T> copyWith({
|
||||
Map<int, T>? values,
|
||||
bool? hasLoaded,
|
||||
});
|
||||
}
|
||||
@@ -6,45 +6,28 @@ import 'package:equatable/equatable.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/notifier/document_changed_notifier.dart';
|
||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'document_bulk_action_state.dart';
|
||||
part 'document_bulk_action_cubit.freezed.dart';
|
||||
|
||||
class DocumentBulkActionCubit extends Cubit<DocumentBulkActionState> {
|
||||
final PaperlessDocumentsApi _documentsApi;
|
||||
final LabelRepository<Correspondent> _correspondentRepository;
|
||||
final LabelRepository<DocumentType> _documentTypeRepository;
|
||||
final LabelRepository<Tag> _tagRepository;
|
||||
final LabelRepository<StoragePath> _storagePathRepository;
|
||||
final LabelRepository _labelRepository;
|
||||
final DocumentChangedNotifier _notifier;
|
||||
|
||||
final List<StreamSubscription> _subscriptions = [];
|
||||
|
||||
DocumentBulkActionCubit(
|
||||
this._documentsApi,
|
||||
this._correspondentRepository,
|
||||
this._documentTypeRepository,
|
||||
this._tagRepository,
|
||||
this._storagePathRepository,
|
||||
this._labelRepository,
|
||||
this._notifier, {
|
||||
required List<DocumentModel> selection,
|
||||
}) : super(
|
||||
DocumentBulkActionState(
|
||||
selection: selection,
|
||||
correspondentOptions:
|
||||
(_correspondentRepository.current?.hasLoaded ?? false)
|
||||
? _correspondentRepository.current!.values!
|
||||
: {},
|
||||
tagOptions: (_tagRepository.current?.hasLoaded ?? false)
|
||||
? _tagRepository.current!.values!
|
||||
: {},
|
||||
documentTypeOptions:
|
||||
(_documentTypeRepository.current?.hasLoaded ?? false)
|
||||
? _documentTypeRepository.current!.values!
|
||||
: {},
|
||||
storagePathOptions:
|
||||
(_storagePathRepository.current?.hasLoaded ?? false)
|
||||
? _storagePathRepository.current!.values!
|
||||
: {},
|
||||
correspondents: _labelRepository.state.correspondents,
|
||||
documentTypes: _labelRepository.state.documentTypes,
|
||||
storagePaths: _labelRepository.state.storagePaths,
|
||||
tags: _labelRepository.state.tags,
|
||||
),
|
||||
) {
|
||||
_notifier.subscribe(
|
||||
@@ -60,35 +43,18 @@ class DocumentBulkActionCubit extends Cubit<DocumentBulkActionState> {
|
||||
);
|
||||
},
|
||||
);
|
||||
_subscriptions.add(
|
||||
_tagRepository.values.listen((event) {
|
||||
if (event?.hasLoaded ?? false) {
|
||||
emit(state.copyWith(tagOptions: event!.values));
|
||||
}
|
||||
}),
|
||||
);
|
||||
_subscriptions.add(
|
||||
_correspondentRepository.values.listen((event) {
|
||||
if (event?.hasLoaded ?? false) {
|
||||
emit(state.copyWith(
|
||||
correspondentOptions: event!.values,
|
||||
));
|
||||
}
|
||||
}),
|
||||
);
|
||||
_subscriptions.add(
|
||||
_documentTypeRepository.values.listen((event) {
|
||||
if (event?.hasLoaded ?? false) {
|
||||
emit(state.copyWith(documentTypeOptions: event!.values));
|
||||
}
|
||||
}),
|
||||
);
|
||||
_subscriptions.add(
|
||||
_storagePathRepository.values.listen((event) {
|
||||
if (event?.hasLoaded ?? false) {
|
||||
emit(state.copyWith(storagePathOptions: event!.values));
|
||||
}
|
||||
}),
|
||||
_labelRepository.subscribe(
|
||||
this,
|
||||
onChanged: (labels) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
correspondents: labels.correspondents,
|
||||
documentTypes: labels.documentTypes,
|
||||
storagePaths: labels.storagePaths,
|
||||
tags: labels.tags,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -177,9 +143,7 @@ class DocumentBulkActionCubit extends Cubit<DocumentBulkActionState> {
|
||||
@override
|
||||
Future<void> close() {
|
||||
_notifier.unsubscribe(this);
|
||||
for (final sub in _subscriptions) {
|
||||
sub.cancel();
|
||||
}
|
||||
_labelRepository.unsubscribe(this);
|
||||
return super.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,269 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'document_bulk_action_cubit.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
|
||||
|
||||
/// @nodoc
|
||||
mixin _$DocumentBulkActionState {
|
||||
List<DocumentModel> get selection => throw _privateConstructorUsedError;
|
||||
Map<int, Correspondent> get correspondents =>
|
||||
throw _privateConstructorUsedError;
|
||||
Map<int, DocumentType> get documentTypes =>
|
||||
throw _privateConstructorUsedError;
|
||||
Map<int, Tag> get tags => throw _privateConstructorUsedError;
|
||||
Map<int, StoragePath> get storagePaths => throw _privateConstructorUsedError;
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
$DocumentBulkActionStateCopyWith<DocumentBulkActionState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $DocumentBulkActionStateCopyWith<$Res> {
|
||||
factory $DocumentBulkActionStateCopyWith(DocumentBulkActionState value,
|
||||
$Res Function(DocumentBulkActionState) then) =
|
||||
_$DocumentBulkActionStateCopyWithImpl<$Res, DocumentBulkActionState>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{List<DocumentModel> selection,
|
||||
Map<int, Correspondent> correspondents,
|
||||
Map<int, DocumentType> documentTypes,
|
||||
Map<int, Tag> tags,
|
||||
Map<int, StoragePath> storagePaths});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$DocumentBulkActionStateCopyWithImpl<$Res,
|
||||
$Val extends DocumentBulkActionState>
|
||||
implements $DocumentBulkActionStateCopyWith<$Res> {
|
||||
_$DocumentBulkActionStateCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? selection = null,
|
||||
Object? correspondents = null,
|
||||
Object? documentTypes = null,
|
||||
Object? tags = null,
|
||||
Object? storagePaths = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
selection: null == selection
|
||||
? _value.selection
|
||||
: selection // ignore: cast_nullable_to_non_nullable
|
||||
as List<DocumentModel>,
|
||||
correspondents: null == correspondents
|
||||
? _value.correspondents
|
||||
: correspondents // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, Correspondent>,
|
||||
documentTypes: null == documentTypes
|
||||
? _value.documentTypes
|
||||
: documentTypes // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, DocumentType>,
|
||||
tags: null == tags
|
||||
? _value.tags
|
||||
: tags // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, Tag>,
|
||||
storagePaths: null == storagePaths
|
||||
? _value.storagePaths
|
||||
: storagePaths // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, StoragePath>,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$_DocumentBulkActionStateCopyWith<$Res>
|
||||
implements $DocumentBulkActionStateCopyWith<$Res> {
|
||||
factory _$$_DocumentBulkActionStateCopyWith(_$_DocumentBulkActionState value,
|
||||
$Res Function(_$_DocumentBulkActionState) then) =
|
||||
__$$_DocumentBulkActionStateCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{List<DocumentModel> selection,
|
||||
Map<int, Correspondent> correspondents,
|
||||
Map<int, DocumentType> documentTypes,
|
||||
Map<int, Tag> tags,
|
||||
Map<int, StoragePath> storagePaths});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$_DocumentBulkActionStateCopyWithImpl<$Res>
|
||||
extends _$DocumentBulkActionStateCopyWithImpl<$Res,
|
||||
_$_DocumentBulkActionState>
|
||||
implements _$$_DocumentBulkActionStateCopyWith<$Res> {
|
||||
__$$_DocumentBulkActionStateCopyWithImpl(_$_DocumentBulkActionState _value,
|
||||
$Res Function(_$_DocumentBulkActionState) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? selection = null,
|
||||
Object? correspondents = null,
|
||||
Object? documentTypes = null,
|
||||
Object? tags = null,
|
||||
Object? storagePaths = null,
|
||||
}) {
|
||||
return _then(_$_DocumentBulkActionState(
|
||||
selection: null == selection
|
||||
? _value._selection
|
||||
: selection // ignore: cast_nullable_to_non_nullable
|
||||
as List<DocumentModel>,
|
||||
correspondents: null == correspondents
|
||||
? _value._correspondents
|
||||
: correspondents // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, Correspondent>,
|
||||
documentTypes: null == documentTypes
|
||||
? _value._documentTypes
|
||||
: documentTypes // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, DocumentType>,
|
||||
tags: null == tags
|
||||
? _value._tags
|
||||
: tags // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, Tag>,
|
||||
storagePaths: null == storagePaths
|
||||
? _value._storagePaths
|
||||
: storagePaths // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, StoragePath>,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$_DocumentBulkActionState extends _DocumentBulkActionState {
|
||||
const _$_DocumentBulkActionState(
|
||||
{required final List<DocumentModel> selection,
|
||||
required final Map<int, Correspondent> correspondents,
|
||||
required final Map<int, DocumentType> documentTypes,
|
||||
required final Map<int, Tag> tags,
|
||||
required final Map<int, StoragePath> storagePaths})
|
||||
: _selection = selection,
|
||||
_correspondents = correspondents,
|
||||
_documentTypes = documentTypes,
|
||||
_tags = tags,
|
||||
_storagePaths = storagePaths,
|
||||
super._();
|
||||
|
||||
final List<DocumentModel> _selection;
|
||||
@override
|
||||
List<DocumentModel> get selection {
|
||||
if (_selection is EqualUnmodifiableListView) return _selection;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_selection);
|
||||
}
|
||||
|
||||
final Map<int, Correspondent> _correspondents;
|
||||
@override
|
||||
Map<int, Correspondent> get correspondents {
|
||||
if (_correspondents is EqualUnmodifiableMapView) return _correspondents;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableMapView(_correspondents);
|
||||
}
|
||||
|
||||
final Map<int, DocumentType> _documentTypes;
|
||||
@override
|
||||
Map<int, DocumentType> get documentTypes {
|
||||
if (_documentTypes is EqualUnmodifiableMapView) return _documentTypes;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableMapView(_documentTypes);
|
||||
}
|
||||
|
||||
final Map<int, Tag> _tags;
|
||||
@override
|
||||
Map<int, Tag> get tags {
|
||||
if (_tags is EqualUnmodifiableMapView) return _tags;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableMapView(_tags);
|
||||
}
|
||||
|
||||
final Map<int, StoragePath> _storagePaths;
|
||||
@override
|
||||
Map<int, StoragePath> get storagePaths {
|
||||
if (_storagePaths is EqualUnmodifiableMapView) return _storagePaths;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableMapView(_storagePaths);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'DocumentBulkActionState(selection: $selection, correspondents: $correspondents, documentTypes: $documentTypes, tags: $tags, storagePaths: $storagePaths)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(dynamic other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$_DocumentBulkActionState &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._selection, _selection) &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._correspondents, _correspondents) &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._documentTypes, _documentTypes) &&
|
||||
const DeepCollectionEquality().equals(other._tags, _tags) &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._storagePaths, _storagePaths));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
const DeepCollectionEquality().hash(_selection),
|
||||
const DeepCollectionEquality().hash(_correspondents),
|
||||
const DeepCollectionEquality().hash(_documentTypes),
|
||||
const DeepCollectionEquality().hash(_tags),
|
||||
const DeepCollectionEquality().hash(_storagePaths));
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$_DocumentBulkActionStateCopyWith<_$_DocumentBulkActionState>
|
||||
get copyWith =>
|
||||
__$$_DocumentBulkActionStateCopyWithImpl<_$_DocumentBulkActionState>(
|
||||
this, _$identity);
|
||||
}
|
||||
|
||||
abstract class _DocumentBulkActionState extends DocumentBulkActionState {
|
||||
const factory _DocumentBulkActionState(
|
||||
{required final List<DocumentModel> selection,
|
||||
required final Map<int, Correspondent> correspondents,
|
||||
required final Map<int, DocumentType> documentTypes,
|
||||
required final Map<int, Tag> tags,
|
||||
required final Map<int, StoragePath> storagePaths}) =
|
||||
_$_DocumentBulkActionState;
|
||||
const _DocumentBulkActionState._() : super._();
|
||||
|
||||
@override
|
||||
List<DocumentModel> get selection;
|
||||
@override
|
||||
Map<int, Correspondent> get correspondents;
|
||||
@override
|
||||
Map<int, DocumentType> get documentTypes;
|
||||
@override
|
||||
Map<int, Tag> get tags;
|
||||
@override
|
||||
Map<int, StoragePath> get storagePaths;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$_DocumentBulkActionStateCopyWith<_$_DocumentBulkActionState>
|
||||
get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
@@ -1,44 +1,15 @@
|
||||
part of 'document_bulk_action_cubit.dart';
|
||||
|
||||
class DocumentBulkActionState extends Equatable {
|
||||
final List<DocumentModel> selection;
|
||||
final Map<int, Correspondent> correspondentOptions;
|
||||
final Map<int, DocumentType> documentTypeOptions;
|
||||
final Map<int, Tag> tagOptions;
|
||||
final Map<int, StoragePath> storagePathOptions;
|
||||
|
||||
const DocumentBulkActionState({
|
||||
this.correspondentOptions = const {},
|
||||
this.documentTypeOptions = const {},
|
||||
this.tagOptions = const {},
|
||||
this.storagePathOptions = const {},
|
||||
this.selection = const [],
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object> get props => [
|
||||
selection,
|
||||
correspondentOptions,
|
||||
documentTypeOptions,
|
||||
tagOptions,
|
||||
storagePathOptions,
|
||||
];
|
||||
@freezed
|
||||
class DocumentBulkActionState with _$DocumentBulkActionState {
|
||||
const DocumentBulkActionState._();
|
||||
const factory DocumentBulkActionState({
|
||||
required List<DocumentModel> selection,
|
||||
required Map<int, Correspondent> correspondents,
|
||||
required Map<int, DocumentType> documentTypes,
|
||||
required Map<int, Tag> tags,
|
||||
required Map<int, StoragePath> storagePaths,
|
||||
}) = _DocumentBulkActionState;
|
||||
|
||||
Iterable<int> get selectedIds => selection.map((d) => d.id);
|
||||
|
||||
DocumentBulkActionState copyWith({
|
||||
List<DocumentModel>? selection,
|
||||
Map<int, Correspondent>? correspondentOptions,
|
||||
Map<int, DocumentType>? documentTypeOptions,
|
||||
Map<int, Tag>? tagOptions,
|
||||
Map<int, StoragePath>? storagePathOptions,
|
||||
}) {
|
||||
return DocumentBulkActionState(
|
||||
selection: selection ?? this.selection,
|
||||
correspondentOptions: correspondentOptions ?? this.correspondentOptions,
|
||||
documentTypeOptions: documentTypeOptions ?? this.documentTypeOptions,
|
||||
storagePathOptions: storagePathOptions ?? this.storagePathOptions,
|
||||
tagOptions: tagOptions ?? this.tagOptions,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
|
||||
class BulkEditPage<int, T extends Label> extends StatefulWidget {
|
||||
final bool enableMultipleChoice;
|
||||
final Map<int, T> availableOptions;
|
||||
|
||||
const BulkEditPage({
|
||||
super.key,
|
||||
required this.enableMultipleChoice,
|
||||
required this.availableOptions,
|
||||
});
|
||||
|
||||
@override
|
||||
State<BulkEditPage> createState() => _BulkEditPageState();
|
||||
}
|
||||
|
||||
class _BulkEditPageState extends State<BulkEditPage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container();
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,11 @@ import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_form_builder/flutter_form_builder.dart';
|
||||
import 'package:flutter_typeahead/flutter_typeahead.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/widgets/dialog_utils/dialog_cancel_button.dart';
|
||||
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
|
||||
import 'package:paperless_mobile/features/document_bulk_action/cubit/document_bulk_action_cubit.dart';
|
||||
import 'package:paperless_mobile/features/labels/tags/view/widgets/tag_widget.dart';
|
||||
import 'package:paperless_mobile/features/labels/tags/view/widgets/tags_form_field.dart';
|
||||
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||
|
||||
class BulkEditTagsBottomSheet extends StatefulWidget {
|
||||
@@ -20,29 +19,42 @@ class BulkEditTagsBottomSheet extends StatefulWidget {
|
||||
|
||||
class _BulkEditTagsBottomSheetState extends State<BulkEditTagsBottomSheet> {
|
||||
final _formKey = GlobalKey<FormBuilderState>();
|
||||
List<int> _tagsToRemove = [];
|
||||
List<int> _tagsToAdd = [];
|
||||
final _textEditingController = TextEditingController();
|
||||
late Set<int> _sharedTags;
|
||||
late Set<int> _nonSharedTags;
|
||||
final Set<int> _sharedTagsToRemove = {};
|
||||
final Set<int> _nonSharedTagsToRemove = {};
|
||||
final Set<int> _tagsToAdd = {};
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
final state = context.read<DocumentBulkActionCubit>().state;
|
||||
_sharedTags = state.selection
|
||||
.map((doc) => doc.tags)
|
||||
.reduce((previousValue, element) =>
|
||||
previousValue.toSet().intersection(element.toSet()))
|
||||
.toSet();
|
||||
print(_sharedTags.map((e) => e).join(", "));
|
||||
_nonSharedTags = state.selection
|
||||
.map((doc) => doc.tags)
|
||||
.flattened
|
||||
.toSet()
|
||||
.difference(_sharedTags)
|
||||
.toSet();
|
||||
print(_nonSharedTags.map((e) => e).join(", "));
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<DocumentBulkActionCubit, DocumentBulkActionState>(
|
||||
builder: (context, state) {
|
||||
final sharedTags = state.selection
|
||||
.map((doc) => doc.tags)
|
||||
.reduce((previousValue, element) =>
|
||||
previousValue.toSet().intersection(element.toSet()))
|
||||
.toList();
|
||||
final nonSharedTags = state.selection
|
||||
.map((doc) => doc.tags)
|
||||
.flattened
|
||||
.toSet()
|
||||
.difference(sharedTags.toSet())
|
||||
.toList();
|
||||
return Padding(
|
||||
padding:
|
||||
EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
|
||||
child: BlocBuilder<DocumentBulkActionCubit, DocumentBulkActionState>(
|
||||
builder: (context, state) {
|
||||
print(state);
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: SingleChildScrollView(
|
||||
@@ -54,25 +66,123 @@ class _BulkEditTagsBottomSheetState extends State<BulkEditTagsBottomSheet> {
|
||||
"Bulk modify tags",
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
).paddedOnly(bottom: 24),
|
||||
FormBuilder(
|
||||
key: _formKey,
|
||||
child: TagFormField(
|
||||
initialValue: IdsTagsQuery(
|
||||
sharedTags.map((tag) => IncludeTagIdQuery(tag)),
|
||||
TypeAheadFormField<Tag>(
|
||||
textFieldConfiguration: TextFieldConfiguration(
|
||||
controller: _textEditingController,
|
||||
decoration: const InputDecoration(
|
||||
labelText: "Tags",
|
||||
hintText: "Start typing to add tags...",
|
||||
),
|
||||
name: "labelFormField",
|
||||
selectableOptions: state.tagOptions,
|
||||
allowCreation: false,
|
||||
anyAssignedSelectable: false,
|
||||
excludeAllowed: false,
|
||||
),
|
||||
onSuggestionSelected: (suggestion) {
|
||||
setState(() {
|
||||
_tagsToAdd.add(suggestion.id!);
|
||||
});
|
||||
_textEditingController.clear();
|
||||
},
|
||||
itemBuilder: (context, option) {
|
||||
return ListTile(
|
||||
leading: SizedBox(
|
||||
width: 32,
|
||||
height: 32,
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: option.color!,
|
||||
),
|
||||
),
|
||||
),
|
||||
title: Text(option.name),
|
||||
);
|
||||
},
|
||||
suggestionsCallback: (pattern) {
|
||||
final searchString = pattern.toLowerCase();
|
||||
return state.tags.entries
|
||||
.where(
|
||||
(tag) => tag.value.name
|
||||
.toLowerCase()
|
||||
.contains(searchString),
|
||||
)
|
||||
.map((e) => e.key)
|
||||
.toSet()
|
||||
.difference(_sharedTags)
|
||||
.difference(_nonSharedTags)
|
||||
.map((e) => state.tags[e]!);
|
||||
},
|
||||
),
|
||||
Text("Shared tags"),
|
||||
Wrap(
|
||||
children: _sharedTags
|
||||
.map(
|
||||
(tag) => RemovableTagWidget(
|
||||
tag: state.tags[tag]!,
|
||||
onDeleted: (tag) {
|
||||
setState(() {
|
||||
_sharedTagsToRemove.add(tag);
|
||||
_sharedTags.remove(tag);
|
||||
});
|
||||
},
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text("Tags removed after apply"),
|
||||
Wrap(),
|
||||
Text("Non-shared tags"),
|
||||
Wrap(
|
||||
children: _nonSharedTags
|
||||
.map(
|
||||
(tag) => RemovableTagWidget(
|
||||
tag: state.tags[tag]!,
|
||||
onDeleted: (tag) {
|
||||
setState(() {
|
||||
_nonSharedTagsToRemove.add(tag);
|
||||
_nonSharedTags.remove(tag);
|
||||
});
|
||||
},
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
Text("Remove"),
|
||||
Wrap(
|
||||
children: _sharedTagsToRemove.map((tag) {
|
||||
return RemovableTagWidget(
|
||||
tag: state.tags[tag]!,
|
||||
onDeleted: (tag) {
|
||||
setState(() {
|
||||
_sharedTagsToRemove.remove(tag);
|
||||
_sharedTags.add(tag);
|
||||
});
|
||||
},
|
||||
);
|
||||
}).toList() +
|
||||
_nonSharedTagsToRemove.map((tag) {
|
||||
return RemovableTagWidget(
|
||||
tag: state.tags[tag]!,
|
||||
onDeleted: (tag) {
|
||||
setState(() {
|
||||
_nonSharedTagsToRemove.remove(tag);
|
||||
_nonSharedTags.add(tag);
|
||||
});
|
||||
},
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text("Tags added after apply"),
|
||||
Wrap(),
|
||||
Text("Add"),
|
||||
Wrap(
|
||||
children: _tagsToAdd
|
||||
.map(
|
||||
(tag) => RemovableTagWidget(
|
||||
tag: state.tags[tag]!,
|
||||
onDeleted: (tag) {
|
||||
setState(() {
|
||||
_tagsToAdd.remove(tag);
|
||||
});
|
||||
}),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
@@ -107,3 +217,28 @@ class _BulkEditTagsBottomSheetState extends State<BulkEditTagsBottomSheet> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class RemovableTagWidget extends StatelessWidget {
|
||||
final Tag tag;
|
||||
final void Function(int tagId) onDeleted;
|
||||
const RemovableTagWidget(
|
||||
{super.key, required this.tag, required this.onDeleted});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Chip(
|
||||
label: Text(
|
||||
tag.name,
|
||||
style: TextStyle(
|
||||
color: tag.textColor,
|
||||
),
|
||||
),
|
||||
onDeleted: () => onDeleted(tag.id!),
|
||||
deleteIcon: Icon(Icons.clear),
|
||||
backgroundColor: tag.color,
|
||||
deleteIconColor: tag.textColor,
|
||||
padding: EdgeInsets.zero,
|
||||
side: BorderSide.none,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
// import 'package:flutter/material.dart';
|
||||
// import 'package:flutter/src/widgets/framework.dart';
|
||||
// import 'package:flutter/src/widgets/placeholder.dart';
|
||||
|
||||
// class LabelBulkSelectionWidget extends StatelessWidget {
|
||||
// final int labelId;
|
||||
// final String title;
|
||||
// final bool selected;
|
||||
// final bool excluded;
|
||||
// final Widget Function(int id) leadingWidgetBuilder;
|
||||
// final void Function(int id) onSelected;
|
||||
// final void Function(int id) onUnselected;
|
||||
// final void Function(int id) onRemoved;
|
||||
|
||||
// const LabelBulkSelectionWidget({
|
||||
// super.key,
|
||||
// required this.labelId,
|
||||
// required this.title,
|
||||
// required this.leadingWidgetBuilder,
|
||||
// required this.onSelected,
|
||||
// required this.onUnselected,
|
||||
// required this.onRemoved,
|
||||
// });
|
||||
// @override
|
||||
// Widget build(BuildContext context) {
|
||||
// return ListTile(
|
||||
// title: Text(title),
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
@@ -2,32 +2,47 @@ import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:open_filex/open_filex.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/notifier/document_changed_notifier.dart';
|
||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||
import 'package:paperless_mobile/core/service/file_description.dart';
|
||||
import 'package:paperless_mobile/core/service/file_service.dart';
|
||||
import 'package:paperless_mobile/features/notifications/services/local_notification_service.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
|
||||
part 'document_details_cubit.freezed.dart';
|
||||
part 'document_details_state.dart';
|
||||
|
||||
class DocumentDetailsCubit extends Cubit<DocumentDetailsState> {
|
||||
final PaperlessDocumentsApi _api;
|
||||
final DocumentChangedNotifier _notifier;
|
||||
final LocalNotificationService _notificationService;
|
||||
|
||||
final LabelRepository _labelRepository;
|
||||
final List<StreamSubscription> _subscriptions = [];
|
||||
DocumentDetailsCubit(
|
||||
this._api,
|
||||
this._labelRepository,
|
||||
this._notifier,
|
||||
this._notificationService, {
|
||||
required DocumentModel initialDocument,
|
||||
}) : super(DocumentDetailsState(document: initialDocument)) {
|
||||
}) : super(DocumentDetailsState(
|
||||
document: initialDocument,
|
||||
)) {
|
||||
_notifier.subscribe(this, onUpdated: replace);
|
||||
_labelRepository.subscribe(
|
||||
this,
|
||||
onChanged: (labels) => emit(
|
||||
state.copyWith(
|
||||
correspondents: labels.correspondents,
|
||||
documentTypes: labels.documentTypes,
|
||||
tags: labels.tags,
|
||||
storagePaths: labels.storagePaths,
|
||||
),
|
||||
),
|
||||
);
|
||||
loadSuggestions();
|
||||
loadMetaData();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,350 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'document_details_cubit.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
|
||||
|
||||
/// @nodoc
|
||||
mixin _$DocumentDetailsState {
|
||||
DocumentModel get document => throw _privateConstructorUsedError;
|
||||
DocumentMetaData? get metaData => throw _privateConstructorUsedError;
|
||||
bool get isFullContentLoaded => throw _privateConstructorUsedError;
|
||||
String? get fullContent => throw _privateConstructorUsedError;
|
||||
FieldSuggestions? get suggestions => throw _privateConstructorUsedError;
|
||||
Map<int, Correspondent> get correspondents =>
|
||||
throw _privateConstructorUsedError;
|
||||
Map<int, DocumentType> get documentTypes =>
|
||||
throw _privateConstructorUsedError;
|
||||
Map<int, Tag> get tags => throw _privateConstructorUsedError;
|
||||
Map<int, StoragePath> get storagePaths => throw _privateConstructorUsedError;
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
$DocumentDetailsStateCopyWith<DocumentDetailsState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $DocumentDetailsStateCopyWith<$Res> {
|
||||
factory $DocumentDetailsStateCopyWith(DocumentDetailsState value,
|
||||
$Res Function(DocumentDetailsState) then) =
|
||||
_$DocumentDetailsStateCopyWithImpl<$Res, DocumentDetailsState>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{DocumentModel document,
|
||||
DocumentMetaData? metaData,
|
||||
bool isFullContentLoaded,
|
||||
String? fullContent,
|
||||
FieldSuggestions? suggestions,
|
||||
Map<int, Correspondent> correspondents,
|
||||
Map<int, DocumentType> documentTypes,
|
||||
Map<int, Tag> tags,
|
||||
Map<int, StoragePath> storagePaths});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$DocumentDetailsStateCopyWithImpl<$Res,
|
||||
$Val extends DocumentDetailsState>
|
||||
implements $DocumentDetailsStateCopyWith<$Res> {
|
||||
_$DocumentDetailsStateCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? document = null,
|
||||
Object? metaData = freezed,
|
||||
Object? isFullContentLoaded = null,
|
||||
Object? fullContent = freezed,
|
||||
Object? suggestions = freezed,
|
||||
Object? correspondents = null,
|
||||
Object? documentTypes = null,
|
||||
Object? tags = null,
|
||||
Object? storagePaths = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
document: null == document
|
||||
? _value.document
|
||||
: document // ignore: cast_nullable_to_non_nullable
|
||||
as DocumentModel,
|
||||
metaData: freezed == metaData
|
||||
? _value.metaData
|
||||
: metaData // ignore: cast_nullable_to_non_nullable
|
||||
as DocumentMetaData?,
|
||||
isFullContentLoaded: null == isFullContentLoaded
|
||||
? _value.isFullContentLoaded
|
||||
: isFullContentLoaded // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
fullContent: freezed == fullContent
|
||||
? _value.fullContent
|
||||
: fullContent // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
suggestions: freezed == suggestions
|
||||
? _value.suggestions
|
||||
: suggestions // ignore: cast_nullable_to_non_nullable
|
||||
as FieldSuggestions?,
|
||||
correspondents: null == correspondents
|
||||
? _value.correspondents
|
||||
: correspondents // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, Correspondent>,
|
||||
documentTypes: null == documentTypes
|
||||
? _value.documentTypes
|
||||
: documentTypes // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, DocumentType>,
|
||||
tags: null == tags
|
||||
? _value.tags
|
||||
: tags // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, Tag>,
|
||||
storagePaths: null == storagePaths
|
||||
? _value.storagePaths
|
||||
: storagePaths // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, StoragePath>,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$_DocumentDetailsStateCopyWith<$Res>
|
||||
implements $DocumentDetailsStateCopyWith<$Res> {
|
||||
factory _$$_DocumentDetailsStateCopyWith(_$_DocumentDetailsState value,
|
||||
$Res Function(_$_DocumentDetailsState) then) =
|
||||
__$$_DocumentDetailsStateCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{DocumentModel document,
|
||||
DocumentMetaData? metaData,
|
||||
bool isFullContentLoaded,
|
||||
String? fullContent,
|
||||
FieldSuggestions? suggestions,
|
||||
Map<int, Correspondent> correspondents,
|
||||
Map<int, DocumentType> documentTypes,
|
||||
Map<int, Tag> tags,
|
||||
Map<int, StoragePath> storagePaths});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$_DocumentDetailsStateCopyWithImpl<$Res>
|
||||
extends _$DocumentDetailsStateCopyWithImpl<$Res, _$_DocumentDetailsState>
|
||||
implements _$$_DocumentDetailsStateCopyWith<$Res> {
|
||||
__$$_DocumentDetailsStateCopyWithImpl(_$_DocumentDetailsState _value,
|
||||
$Res Function(_$_DocumentDetailsState) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? document = null,
|
||||
Object? metaData = freezed,
|
||||
Object? isFullContentLoaded = null,
|
||||
Object? fullContent = freezed,
|
||||
Object? suggestions = freezed,
|
||||
Object? correspondents = null,
|
||||
Object? documentTypes = null,
|
||||
Object? tags = null,
|
||||
Object? storagePaths = null,
|
||||
}) {
|
||||
return _then(_$_DocumentDetailsState(
|
||||
document: null == document
|
||||
? _value.document
|
||||
: document // ignore: cast_nullable_to_non_nullable
|
||||
as DocumentModel,
|
||||
metaData: freezed == metaData
|
||||
? _value.metaData
|
||||
: metaData // ignore: cast_nullable_to_non_nullable
|
||||
as DocumentMetaData?,
|
||||
isFullContentLoaded: null == isFullContentLoaded
|
||||
? _value.isFullContentLoaded
|
||||
: isFullContentLoaded // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
fullContent: freezed == fullContent
|
||||
? _value.fullContent
|
||||
: fullContent // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
suggestions: freezed == suggestions
|
||||
? _value.suggestions
|
||||
: suggestions // ignore: cast_nullable_to_non_nullable
|
||||
as FieldSuggestions?,
|
||||
correspondents: null == correspondents
|
||||
? _value._correspondents
|
||||
: correspondents // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, Correspondent>,
|
||||
documentTypes: null == documentTypes
|
||||
? _value._documentTypes
|
||||
: documentTypes // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, DocumentType>,
|
||||
tags: null == tags
|
||||
? _value._tags
|
||||
: tags // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, Tag>,
|
||||
storagePaths: null == storagePaths
|
||||
? _value._storagePaths
|
||||
: storagePaths // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, StoragePath>,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$_DocumentDetailsState implements _DocumentDetailsState {
|
||||
const _$_DocumentDetailsState(
|
||||
{required this.document,
|
||||
this.metaData,
|
||||
this.isFullContentLoaded = false,
|
||||
this.fullContent,
|
||||
this.suggestions,
|
||||
final Map<int, Correspondent> correspondents = const {},
|
||||
final Map<int, DocumentType> documentTypes = const {},
|
||||
final Map<int, Tag> tags = const {},
|
||||
final Map<int, StoragePath> storagePaths = const {}})
|
||||
: _correspondents = correspondents,
|
||||
_documentTypes = documentTypes,
|
||||
_tags = tags,
|
||||
_storagePaths = storagePaths;
|
||||
|
||||
@override
|
||||
final DocumentModel document;
|
||||
@override
|
||||
final DocumentMetaData? metaData;
|
||||
@override
|
||||
@JsonKey()
|
||||
final bool isFullContentLoaded;
|
||||
@override
|
||||
final String? fullContent;
|
||||
@override
|
||||
final FieldSuggestions? suggestions;
|
||||
final Map<int, Correspondent> _correspondents;
|
||||
@override
|
||||
@JsonKey()
|
||||
Map<int, Correspondent> get correspondents {
|
||||
if (_correspondents is EqualUnmodifiableMapView) return _correspondents;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableMapView(_correspondents);
|
||||
}
|
||||
|
||||
final Map<int, DocumentType> _documentTypes;
|
||||
@override
|
||||
@JsonKey()
|
||||
Map<int, DocumentType> get documentTypes {
|
||||
if (_documentTypes is EqualUnmodifiableMapView) return _documentTypes;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableMapView(_documentTypes);
|
||||
}
|
||||
|
||||
final Map<int, Tag> _tags;
|
||||
@override
|
||||
@JsonKey()
|
||||
Map<int, Tag> get tags {
|
||||
if (_tags is EqualUnmodifiableMapView) return _tags;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableMapView(_tags);
|
||||
}
|
||||
|
||||
final Map<int, StoragePath> _storagePaths;
|
||||
@override
|
||||
@JsonKey()
|
||||
Map<int, StoragePath> get storagePaths {
|
||||
if (_storagePaths is EqualUnmodifiableMapView) return _storagePaths;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableMapView(_storagePaths);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'DocumentDetailsState(document: $document, metaData: $metaData, isFullContentLoaded: $isFullContentLoaded, fullContent: $fullContent, suggestions: $suggestions, correspondents: $correspondents, documentTypes: $documentTypes, tags: $tags, storagePaths: $storagePaths)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(dynamic other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$_DocumentDetailsState &&
|
||||
(identical(other.document, document) ||
|
||||
other.document == document) &&
|
||||
(identical(other.metaData, metaData) ||
|
||||
other.metaData == metaData) &&
|
||||
(identical(other.isFullContentLoaded, isFullContentLoaded) ||
|
||||
other.isFullContentLoaded == isFullContentLoaded) &&
|
||||
(identical(other.fullContent, fullContent) ||
|
||||
other.fullContent == fullContent) &&
|
||||
(identical(other.suggestions, suggestions) ||
|
||||
other.suggestions == suggestions) &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._correspondents, _correspondents) &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._documentTypes, _documentTypes) &&
|
||||
const DeepCollectionEquality().equals(other._tags, _tags) &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._storagePaths, _storagePaths));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
document,
|
||||
metaData,
|
||||
isFullContentLoaded,
|
||||
fullContent,
|
||||
suggestions,
|
||||
const DeepCollectionEquality().hash(_correspondents),
|
||||
const DeepCollectionEquality().hash(_documentTypes),
|
||||
const DeepCollectionEquality().hash(_tags),
|
||||
const DeepCollectionEquality().hash(_storagePaths));
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$_DocumentDetailsStateCopyWith<_$_DocumentDetailsState> get copyWith =>
|
||||
__$$_DocumentDetailsStateCopyWithImpl<_$_DocumentDetailsState>(
|
||||
this, _$identity);
|
||||
}
|
||||
|
||||
abstract class _DocumentDetailsState implements DocumentDetailsState {
|
||||
const factory _DocumentDetailsState(
|
||||
{required final DocumentModel document,
|
||||
final DocumentMetaData? metaData,
|
||||
final bool isFullContentLoaded,
|
||||
final String? fullContent,
|
||||
final FieldSuggestions? suggestions,
|
||||
final Map<int, Correspondent> correspondents,
|
||||
final Map<int, DocumentType> documentTypes,
|
||||
final Map<int, Tag> tags,
|
||||
final Map<int, StoragePath> storagePaths}) = _$_DocumentDetailsState;
|
||||
|
||||
@override
|
||||
DocumentModel get document;
|
||||
@override
|
||||
DocumentMetaData? get metaData;
|
||||
@override
|
||||
bool get isFullContentLoaded;
|
||||
@override
|
||||
String? get fullContent;
|
||||
@override
|
||||
FieldSuggestions? get suggestions;
|
||||
@override
|
||||
Map<int, Correspondent> get correspondents;
|
||||
@override
|
||||
Map<int, DocumentType> get documentTypes;
|
||||
@override
|
||||
Map<int, Tag> get tags;
|
||||
@override
|
||||
Map<int, StoragePath> get storagePaths;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$_DocumentDetailsStateCopyWith<_$_DocumentDetailsState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@@ -1,42 +1,16 @@
|
||||
part of 'document_details_cubit.dart';
|
||||
|
||||
class DocumentDetailsState with EquatableMixin {
|
||||
final DocumentModel document;
|
||||
final DocumentMetaData? metaData;
|
||||
final bool isFullContentLoaded;
|
||||
final String? fullContent;
|
||||
final FieldSuggestions suggestions;
|
||||
|
||||
const DocumentDetailsState({
|
||||
required this.document,
|
||||
this.metaData,
|
||||
this.suggestions = const FieldSuggestions(),
|
||||
this.isFullContentLoaded = false,
|
||||
this.fullContent,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
document,
|
||||
suggestions,
|
||||
isFullContentLoaded,
|
||||
fullContent,
|
||||
metaData,
|
||||
];
|
||||
|
||||
DocumentDetailsState copyWith({
|
||||
DocumentModel? document,
|
||||
FieldSuggestions? suggestions,
|
||||
bool? isFullContentLoaded,
|
||||
String? fullContent,
|
||||
@freezed
|
||||
class DocumentDetailsState with _$DocumentDetailsState {
|
||||
const factory DocumentDetailsState({
|
||||
required DocumentModel document,
|
||||
DocumentMetaData? metaData,
|
||||
}) {
|
||||
return DocumentDetailsState(
|
||||
document: document ?? this.document,
|
||||
suggestions: suggestions ?? this.suggestions,
|
||||
isFullContentLoaded: isFullContentLoaded ?? this.isFullContentLoaded,
|
||||
fullContent: fullContent ?? this.fullContent,
|
||||
metaData: metaData ?? this.metaData,
|
||||
);
|
||||
}
|
||||
@Default(false) bool isFullContentLoaded,
|
||||
String? fullContent,
|
||||
FieldSuggestions? suggestions,
|
||||
@Default({}) Map<int, Correspondent> correspondents,
|
||||
@Default({}) Map<int, DocumentType> documentTypes,
|
||||
@Default({}) Map<int, Tag> tags,
|
||||
@Default({}) Map<int, StoragePath> storagePaths,
|
||||
}) = _DocumentDetailsState;
|
||||
}
|
||||
|
||||
@@ -186,6 +186,7 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
|
||||
document: state.document,
|
||||
itemSpacing: _itemSpacing,
|
||||
queryString: widget.titleAndContentQueryString,
|
||||
|
||||
),
|
||||
DocumentContentWidget(
|
||||
isFullContentLoaded: state.isFullContentLoaded,
|
||||
|
||||
@@ -11,6 +11,10 @@ import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||
|
||||
class DocumentOverviewWidget extends StatelessWidget {
|
||||
final DocumentModel document;
|
||||
final Map<int, Correspondent> availableCorrespondents;
|
||||
final Map<int, DocumentType> availableDocumentTypes;
|
||||
final Map<int, Tag> availableTags;
|
||||
final Map<int, StoragePath> availableStoragePaths;
|
||||
final String? queryString;
|
||||
final double itemSpacing;
|
||||
const DocumentOverviewWidget({
|
||||
@@ -18,6 +22,10 @@ class DocumentOverviewWidget extends StatelessWidget {
|
||||
required this.document,
|
||||
this.queryString,
|
||||
required this.itemSpacing,
|
||||
required this.availableCorrespondents,
|
||||
required this.availableDocumentTypes,
|
||||
required this.availableTags,
|
||||
required this.availableStoragePaths,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -47,7 +55,7 @@ class DocumentOverviewWidget extends StatelessWidget {
|
||||
label: S.of(context)!.documentType,
|
||||
content: LabelText<DocumentType>(
|
||||
style: Theme.of(context).textTheme.bodyLarge,
|
||||
id: document.documentType,
|
||||
label: availableDocumentTypes[document.documentType],
|
||||
),
|
||||
).paddedOnly(bottom: itemSpacing),
|
||||
),
|
||||
@@ -57,7 +65,7 @@ class DocumentOverviewWidget extends StatelessWidget {
|
||||
label: S.of(context)!.correspondent,
|
||||
content: LabelText<Correspondent>(
|
||||
style: Theme.of(context).textTheme.bodyLarge,
|
||||
id: document.correspondent,
|
||||
label: availableCorrespondents[document.correspondent],
|
||||
),
|
||||
).paddedOnly(bottom: itemSpacing),
|
||||
),
|
||||
@@ -65,8 +73,8 @@ class DocumentOverviewWidget extends StatelessWidget {
|
||||
visible: document.storagePath != null,
|
||||
child: DetailsItem(
|
||||
label: S.of(context)!.storagePath,
|
||||
content: StoragePathWidget(
|
||||
pathId: document.storagePath,
|
||||
content: LabelText<StoragePath>(
|
||||
label: availableStoragePaths[document.storagePath],
|
||||
),
|
||||
).paddedOnly(bottom: itemSpacing),
|
||||
),
|
||||
@@ -78,7 +86,7 @@ class DocumentOverviewWidget extends StatelessWidget {
|
||||
padding: const EdgeInsets.only(top: 8.0),
|
||||
child: TagsWidget(
|
||||
isClickable: false,
|
||||
tagIds: document.tags,
|
||||
tags: document.tags.map((e) => availableTags[e]!).toList(),
|
||||
),
|
||||
),
|
||||
).paddedOnly(bottom: itemSpacing),
|
||||
|
||||
@@ -1,66 +1,41 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/notifier/document_changed_notifier.dart';
|
||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||
|
||||
part 'document_edit_state.dart';
|
||||
part 'document_edit_cubit.freezed.dart';
|
||||
|
||||
class DocumentEditCubit extends Cubit<DocumentEditState> {
|
||||
final DocumentModel _initialDocument;
|
||||
final PaperlessDocumentsApi _docsApi;
|
||||
|
||||
final DocumentChangedNotifier _notifier;
|
||||
final LabelRepository<Correspondent> _correspondentRepository;
|
||||
final LabelRepository<DocumentType> _documentTypeRepository;
|
||||
final LabelRepository<StoragePath> _storagePathRepository;
|
||||
final LabelRepository<Tag> _tagRepository;
|
||||
final LabelRepository _labelRepository;
|
||||
final List<StreamSubscription> _subscriptions = [];
|
||||
|
||||
DocumentEditCubit(
|
||||
DocumentModel document, {
|
||||
required PaperlessDocumentsApi documentsApi,
|
||||
required LabelRepository<Correspondent> correspondentRepository,
|
||||
required LabelRepository<DocumentType> documentTypeRepository,
|
||||
required LabelRepository<StoragePath> storagePathRepository,
|
||||
required LabelRepository<Tag> tagRepository,
|
||||
required DocumentChangedNotifier notifier,
|
||||
this._labelRepository,
|
||||
this._docsApi,
|
||||
this._notifier, {
|
||||
required DocumentModel document,
|
||||
}) : _initialDocument = document,
|
||||
_docsApi = documentsApi,
|
||||
_correspondentRepository = correspondentRepository,
|
||||
_documentTypeRepository = documentTypeRepository,
|
||||
_storagePathRepository = storagePathRepository,
|
||||
_tagRepository = tagRepository,
|
||||
_notifier = notifier,
|
||||
super(
|
||||
DocumentEditState(
|
||||
document: document,
|
||||
correspondents: correspondentRepository.current?.values ?? {},
|
||||
documentTypes: documentTypeRepository.current?.values ?? {},
|
||||
storagePaths: storagePathRepository.current?.values ?? {},
|
||||
tags: tagRepository.current?.values ?? {},
|
||||
correspondents: _labelRepository.state.correspondents,
|
||||
documentTypes: _labelRepository.state.documentTypes,
|
||||
storagePaths: _labelRepository.state.storagePaths,
|
||||
tags: _labelRepository.state.tags,
|
||||
),
|
||||
) {
|
||||
_notifier.subscribe(this, onUpdated: replace);
|
||||
_subscriptions.add(
|
||||
_correspondentRepository.values
|
||||
.listen((v) => emit(state.copyWith(correspondents: v?.values))),
|
||||
);
|
||||
_subscriptions.add(
|
||||
_documentTypeRepository.values
|
||||
.listen((v) => emit(state.copyWith(documentTypes: v?.values))),
|
||||
);
|
||||
_subscriptions.add(
|
||||
_storagePathRepository.values
|
||||
.listen((v) => emit(state.copyWith(storagePaths: v?.values))),
|
||||
);
|
||||
_subscriptions.add(
|
||||
_tagRepository.values.listen(
|
||||
(v) => emit(state.copyWith(tags: v?.values)),
|
||||
),
|
||||
_labelRepository.subscribe(
|
||||
this,
|
||||
onStateChanged: (labels) => emit(state.copyWith()),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -70,20 +45,20 @@ class DocumentEditCubit extends Cubit<DocumentEditState> {
|
||||
|
||||
// Reload changed labels (documentCount property changes with removal/add)
|
||||
if (document.documentType != _initialDocument.documentType) {
|
||||
_documentTypeRepository
|
||||
.find((document.documentType ?? _initialDocument.documentType)!);
|
||||
_labelRepository.findDocumentType(
|
||||
(document.documentType ?? _initialDocument.documentType)!);
|
||||
}
|
||||
if (document.correspondent != _initialDocument.correspondent) {
|
||||
_correspondentRepository
|
||||
.find((document.correspondent ?? _initialDocument.correspondent)!);
|
||||
_labelRepository.findCorrespondent(
|
||||
(document.correspondent ?? _initialDocument.correspondent)!);
|
||||
}
|
||||
if (document.storagePath != _initialDocument.storagePath) {
|
||||
_storagePathRepository
|
||||
.find((document.storagePath ?? _initialDocument.storagePath)!);
|
||||
_labelRepository.findStoragePath(
|
||||
(document.storagePath ?? _initialDocument.storagePath)!);
|
||||
}
|
||||
if (!const DeepCollectionEquality.unordered()
|
||||
.equals(document.tags, _initialDocument.tags)) {
|
||||
_tagRepository.findAll(document.tags);
|
||||
_labelRepository.findAllTags(document.tags);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,256 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'document_edit_cubit.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
|
||||
|
||||
/// @nodoc
|
||||
mixin _$DocumentEditState {
|
||||
DocumentModel get document => throw _privateConstructorUsedError;
|
||||
Map<int, Correspondent> get correspondents =>
|
||||
throw _privateConstructorUsedError;
|
||||
Map<int, DocumentType> get documentTypes =>
|
||||
throw _privateConstructorUsedError;
|
||||
Map<int, StoragePath> get storagePaths => throw _privateConstructorUsedError;
|
||||
Map<int, Tag> get tags => throw _privateConstructorUsedError;
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
$DocumentEditStateCopyWith<DocumentEditState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $DocumentEditStateCopyWith<$Res> {
|
||||
factory $DocumentEditStateCopyWith(
|
||||
DocumentEditState value, $Res Function(DocumentEditState) then) =
|
||||
_$DocumentEditStateCopyWithImpl<$Res, DocumentEditState>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{DocumentModel document,
|
||||
Map<int, Correspondent> correspondents,
|
||||
Map<int, DocumentType> documentTypes,
|
||||
Map<int, StoragePath> storagePaths,
|
||||
Map<int, Tag> tags});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$DocumentEditStateCopyWithImpl<$Res, $Val extends DocumentEditState>
|
||||
implements $DocumentEditStateCopyWith<$Res> {
|
||||
_$DocumentEditStateCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? document = null,
|
||||
Object? correspondents = null,
|
||||
Object? documentTypes = null,
|
||||
Object? storagePaths = null,
|
||||
Object? tags = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
document: null == document
|
||||
? _value.document
|
||||
: document // ignore: cast_nullable_to_non_nullable
|
||||
as DocumentModel,
|
||||
correspondents: null == correspondents
|
||||
? _value.correspondents
|
||||
: correspondents // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, Correspondent>,
|
||||
documentTypes: null == documentTypes
|
||||
? _value.documentTypes
|
||||
: documentTypes // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, DocumentType>,
|
||||
storagePaths: null == storagePaths
|
||||
? _value.storagePaths
|
||||
: storagePaths // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, StoragePath>,
|
||||
tags: null == tags
|
||||
? _value.tags
|
||||
: tags // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, Tag>,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$_DocumentEditStateCopyWith<$Res>
|
||||
implements $DocumentEditStateCopyWith<$Res> {
|
||||
factory _$$_DocumentEditStateCopyWith(_$_DocumentEditState value,
|
||||
$Res Function(_$_DocumentEditState) then) =
|
||||
__$$_DocumentEditStateCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{DocumentModel document,
|
||||
Map<int, Correspondent> correspondents,
|
||||
Map<int, DocumentType> documentTypes,
|
||||
Map<int, StoragePath> storagePaths,
|
||||
Map<int, Tag> tags});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$_DocumentEditStateCopyWithImpl<$Res>
|
||||
extends _$DocumentEditStateCopyWithImpl<$Res, _$_DocumentEditState>
|
||||
implements _$$_DocumentEditStateCopyWith<$Res> {
|
||||
__$$_DocumentEditStateCopyWithImpl(
|
||||
_$_DocumentEditState _value, $Res Function(_$_DocumentEditState) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? document = null,
|
||||
Object? correspondents = null,
|
||||
Object? documentTypes = null,
|
||||
Object? storagePaths = null,
|
||||
Object? tags = null,
|
||||
}) {
|
||||
return _then(_$_DocumentEditState(
|
||||
document: null == document
|
||||
? _value.document
|
||||
: document // ignore: cast_nullable_to_non_nullable
|
||||
as DocumentModel,
|
||||
correspondents: null == correspondents
|
||||
? _value._correspondents
|
||||
: correspondents // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, Correspondent>,
|
||||
documentTypes: null == documentTypes
|
||||
? _value._documentTypes
|
||||
: documentTypes // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, DocumentType>,
|
||||
storagePaths: null == storagePaths
|
||||
? _value._storagePaths
|
||||
: storagePaths // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, StoragePath>,
|
||||
tags: null == tags
|
||||
? _value._tags
|
||||
: tags // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, Tag>,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$_DocumentEditState implements _DocumentEditState {
|
||||
const _$_DocumentEditState(
|
||||
{required this.document,
|
||||
required final Map<int, Correspondent> correspondents,
|
||||
required final Map<int, DocumentType> documentTypes,
|
||||
required final Map<int, StoragePath> storagePaths,
|
||||
required final Map<int, Tag> tags})
|
||||
: _correspondents = correspondents,
|
||||
_documentTypes = documentTypes,
|
||||
_storagePaths = storagePaths,
|
||||
_tags = tags;
|
||||
|
||||
@override
|
||||
final DocumentModel document;
|
||||
final Map<int, Correspondent> _correspondents;
|
||||
@override
|
||||
Map<int, Correspondent> get correspondents {
|
||||
if (_correspondents is EqualUnmodifiableMapView) return _correspondents;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableMapView(_correspondents);
|
||||
}
|
||||
|
||||
final Map<int, DocumentType> _documentTypes;
|
||||
@override
|
||||
Map<int, DocumentType> get documentTypes {
|
||||
if (_documentTypes is EqualUnmodifiableMapView) return _documentTypes;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableMapView(_documentTypes);
|
||||
}
|
||||
|
||||
final Map<int, StoragePath> _storagePaths;
|
||||
@override
|
||||
Map<int, StoragePath> get storagePaths {
|
||||
if (_storagePaths is EqualUnmodifiableMapView) return _storagePaths;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableMapView(_storagePaths);
|
||||
}
|
||||
|
||||
final Map<int, Tag> _tags;
|
||||
@override
|
||||
Map<int, Tag> get tags {
|
||||
if (_tags is EqualUnmodifiableMapView) return _tags;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableMapView(_tags);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'DocumentEditState(document: $document, correspondents: $correspondents, documentTypes: $documentTypes, storagePaths: $storagePaths, tags: $tags)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(dynamic other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$_DocumentEditState &&
|
||||
(identical(other.document, document) ||
|
||||
other.document == document) &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._correspondents, _correspondents) &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._documentTypes, _documentTypes) &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._storagePaths, _storagePaths) &&
|
||||
const DeepCollectionEquality().equals(other._tags, _tags));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
document,
|
||||
const DeepCollectionEquality().hash(_correspondents),
|
||||
const DeepCollectionEquality().hash(_documentTypes),
|
||||
const DeepCollectionEquality().hash(_storagePaths),
|
||||
const DeepCollectionEquality().hash(_tags));
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$_DocumentEditStateCopyWith<_$_DocumentEditState> get copyWith =>
|
||||
__$$_DocumentEditStateCopyWithImpl<_$_DocumentEditState>(
|
||||
this, _$identity);
|
||||
}
|
||||
|
||||
abstract class _DocumentEditState implements DocumentEditState {
|
||||
const factory _DocumentEditState(
|
||||
{required final DocumentModel document,
|
||||
required final Map<int, Correspondent> correspondents,
|
||||
required final Map<int, DocumentType> documentTypes,
|
||||
required final Map<int, StoragePath> storagePaths,
|
||||
required final Map<int, Tag> tags}) = _$_DocumentEditState;
|
||||
|
||||
@override
|
||||
DocumentModel get document;
|
||||
@override
|
||||
Map<int, Correspondent> get correspondents;
|
||||
@override
|
||||
Map<int, DocumentType> get documentTypes;
|
||||
@override
|
||||
Map<int, StoragePath> get storagePaths;
|
||||
@override
|
||||
Map<int, Tag> get tags;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$_DocumentEditStateCopyWith<_$_DocumentEditState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@@ -1,43 +1,12 @@
|
||||
part of 'document_edit_cubit.dart';
|
||||
|
||||
class DocumentEditState extends Equatable {
|
||||
final DocumentModel document;
|
||||
|
||||
final Map<int, Correspondent> correspondents;
|
||||
final Map<int, DocumentType> documentTypes;
|
||||
final Map<int, StoragePath> storagePaths;
|
||||
final Map<int, Tag> tags;
|
||||
|
||||
const DocumentEditState({
|
||||
required this.correspondents,
|
||||
required this.documentTypes,
|
||||
required this.storagePaths,
|
||||
required this.tags,
|
||||
required this.document,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object> get props => [
|
||||
correspondents,
|
||||
documentTypes,
|
||||
storagePaths,
|
||||
tags,
|
||||
document,
|
||||
];
|
||||
|
||||
DocumentEditState copyWith({
|
||||
Map<int, Correspondent>? correspondents,
|
||||
Map<int, DocumentType>? documentTypes,
|
||||
Map<int, StoragePath>? storagePaths,
|
||||
Map<int, Tag>? tags,
|
||||
DocumentModel? document,
|
||||
}) {
|
||||
return DocumentEditState(
|
||||
document: document ?? this.document,
|
||||
correspondents: correspondents ?? this.correspondents,
|
||||
documentTypes: documentTypes ?? this.documentTypes,
|
||||
storagePaths: storagePaths ?? this.storagePaths,
|
||||
tags: tags ?? this.tags,
|
||||
);
|
||||
}
|
||||
@freezed
|
||||
class DocumentEditState with _$DocumentEditState {
|
||||
const factory DocumentEditState({
|
||||
required DocumentModel document,
|
||||
required Map<int, Correspondent> correspondents,
|
||||
required Map<int, DocumentType> documentTypes,
|
||||
required Map<int, StoragePath> storagePaths,
|
||||
required Map<int, Tag> tags,
|
||||
}) = _DocumentEditState;
|
||||
}
|
||||
|
||||
@@ -194,8 +194,9 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
|
||||
LabelFormField<StoragePath>(
|
||||
notAssignedSelectable: false,
|
||||
formBuilderState: _formKey.currentState,
|
||||
labelCreationWidgetBuilder: (initialValue) => RepositoryProvider(
|
||||
create: (context) => context.read<LabelRepository<StoragePath>>(),
|
||||
labelCreationWidgetBuilder: (initialValue) =>
|
||||
RepositoryProvider.value(
|
||||
value: context.read<LabelRepository>(),
|
||||
child: AddStoragePathPage(initalName: initialValue),
|
||||
),
|
||||
textFieldLabel: S.of(context)!.storagePath,
|
||||
|
||||
@@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart';
|
||||
import 'package:hydrated_bloc/hydrated_bloc.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/notifier/document_changed_notifier.dart';
|
||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||
import 'package:paperless_mobile/features/paged_document_view/cubit/document_paging_bloc_mixin.dart';
|
||||
import 'package:paperless_mobile/features/settings/model/view_type.dart';
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
@@ -19,10 +20,18 @@ class DocumentsCubit extends HydratedCubit<DocumentsState>
|
||||
@override
|
||||
final PaperlessDocumentsApi api;
|
||||
|
||||
final LabelRepository _labelRepository;
|
||||
|
||||
@override
|
||||
final DocumentChangedNotifier notifier;
|
||||
|
||||
DocumentsCubit(this.api, this.notifier) : super(const DocumentsState()) {
|
||||
DocumentsCubit(this.api, this.notifier, this._labelRepository)
|
||||
: super(DocumentsState(
|
||||
correspondents: _labelRepository.state.correspondents,
|
||||
documentTypes: _labelRepository.state.documentTypes,
|
||||
storagePaths: _labelRepository.state.storagePaths,
|
||||
tags: _labelRepository.state.tags,
|
||||
)) {
|
||||
notifier.subscribe(
|
||||
this,
|
||||
onUpdated: (document) {
|
||||
@@ -45,6 +54,17 @@ class DocumentsCubit extends HydratedCubit<DocumentsState>
|
||||
);
|
||||
},
|
||||
);
|
||||
_labelRepository.subscribe(
|
||||
this,
|
||||
onStateChanged: (labels) => emit(
|
||||
state.copyWith(
|
||||
correspondents: labels.correspondents,
|
||||
documentTypes: labels.documentTypes,
|
||||
storagePaths: labels.storagePaths,
|
||||
tags: labels.tags,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> bulkDelete(List<DocumentModel> documents) async {
|
||||
@@ -101,6 +121,7 @@ class DocumentsCubit extends HydratedCubit<DocumentsState>
|
||||
@override
|
||||
Future<void> close() {
|
||||
notifier.unsubscribe(this);
|
||||
_labelRepository.unsubscribe(this);
|
||||
return super.close();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
part of 'documents_cubit.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
@JsonSerializable(ignoreUnannotated: true)
|
||||
class DocumentsState extends DocumentPagingState {
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
final List<DocumentModel> selection;
|
||||
|
||||
final Map<int, Correspondent> correspondents;
|
||||
final Map<int, DocumentType> documentTypes;
|
||||
final Map<int, Tag> tags;
|
||||
final Map<int, StoragePath> storagePaths;
|
||||
|
||||
@JsonKey()
|
||||
final ViewType viewType;
|
||||
|
||||
const DocumentsState({
|
||||
@@ -14,6 +19,10 @@ class DocumentsState extends DocumentPagingState {
|
||||
super.filter = const DocumentFilter(),
|
||||
super.hasLoaded = false,
|
||||
super.isLoading = false,
|
||||
this.correspondents = const {},
|
||||
this.documentTypes = const {},
|
||||
this.tags = const {},
|
||||
this.storagePaths = const {},
|
||||
});
|
||||
|
||||
List<int> get selectedIds => selection.map((e) => e.id).toList();
|
||||
@@ -25,6 +34,10 @@ class DocumentsState extends DocumentPagingState {
|
||||
DocumentFilter? filter,
|
||||
List<DocumentModel>? selection,
|
||||
ViewType? viewType,
|
||||
Map<int, Correspondent>? correspondents,
|
||||
Map<int, DocumentType>? documentTypes,
|
||||
Map<int, Tag>? tags,
|
||||
Map<int, StoragePath>? storagePaths,
|
||||
}) {
|
||||
return DocumentsState(
|
||||
hasLoaded: hasLoaded ?? this.hasLoaded,
|
||||
@@ -33,6 +46,10 @@ class DocumentsState extends DocumentPagingState {
|
||||
filter: filter ?? this.filter,
|
||||
selection: selection ?? this.selection,
|
||||
viewType: viewType ?? this.viewType,
|
||||
correspondents: correspondents ?? this.correspondents,
|
||||
documentTypes: documentTypes ?? this.documentTypes,
|
||||
tags: tags ?? this.tags,
|
||||
storagePaths: storagePaths ?? this.storagePaths,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/repository/provider/label_repositories_provider.dart';
|
||||
import 'package:paperless_mobile/features/documents/view/widgets/placeholder/document_grid_loading_widget.dart';
|
||||
import 'package:paperless_mobile/features/documents/view/widgets/items/document_detailed_item.dart';
|
||||
import 'package:paperless_mobile/features/documents/view/widgets/items/document_grid_item.dart';
|
||||
@@ -25,7 +24,13 @@ abstract class AdaptiveDocumentsView extends StatelessWidget {
|
||||
final void Function(int? id)? onDocumentTypeSelected;
|
||||
final void Function(int? id)? onStoragePathSelected;
|
||||
|
||||
bool get showLoadingPlaceholder => (!hasLoaded && isLoading);
|
||||
final Map<int, Correspondent> correspondents;
|
||||
final Map<int, DocumentType> documentTypes;
|
||||
final Map<int, Tag> tags;
|
||||
final Map<int, StoragePath> storagePaths;
|
||||
|
||||
bool get showLoadingPlaceholder => !hasLoaded && isLoading;
|
||||
|
||||
const AdaptiveDocumentsView({
|
||||
super.key,
|
||||
this.selectedDocumentIds = const [],
|
||||
@@ -42,6 +47,10 @@ abstract class AdaptiveDocumentsView extends StatelessWidget {
|
||||
required this.isLoading,
|
||||
required this.hasLoaded,
|
||||
this.enableHeroAnimation = true,
|
||||
required this.correspondents,
|
||||
required this.documentTypes,
|
||||
required this.tags,
|
||||
required this.storagePaths,
|
||||
});
|
||||
|
||||
AdaptiveDocumentsView.fromPagedState(
|
||||
@@ -58,6 +67,10 @@ abstract class AdaptiveDocumentsView extends StatelessWidget {
|
||||
required this.hasInternetConnection,
|
||||
this.viewType = ViewType.list,
|
||||
this.selectedDocumentIds = const [],
|
||||
required this.correspondents,
|
||||
required this.documentTypes,
|
||||
required this.tags,
|
||||
required this.storagePaths,
|
||||
}) : documents = state.documents,
|
||||
isLoading = state.isLoading,
|
||||
hasLoaded = state.hasLoaded;
|
||||
@@ -80,6 +93,10 @@ class SliverAdaptiveDocumentsView extends AdaptiveDocumentsView {
|
||||
super.enableHeroAnimation,
|
||||
required super.isLoading,
|
||||
required super.hasLoaded,
|
||||
required super.correspondents,
|
||||
required super.documentTypes,
|
||||
required super.tags,
|
||||
required super.storagePaths,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -96,27 +113,29 @@ class SliverAdaptiveDocumentsView extends AdaptiveDocumentsView {
|
||||
|
||||
Widget _buildListView() {
|
||||
if (showLoadingPlaceholder) {
|
||||
return DocumentsListLoadingWidget.sliver();
|
||||
return const DocumentsListLoadingWidget.sliver();
|
||||
}
|
||||
return SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
childCount: documents.length,
|
||||
(context, index) {
|
||||
final document = documents.elementAt(index);
|
||||
return LabelRepositoriesProvider(
|
||||
child: DocumentListItem(
|
||||
isLabelClickable: isLabelClickable,
|
||||
document: document,
|
||||
onTap: onTap,
|
||||
isSelected: selectedDocumentIds.contains(document.id),
|
||||
onSelected: onSelected,
|
||||
isSelectionActive: selectedDocumentIds.isNotEmpty,
|
||||
onTagSelected: onTagSelected,
|
||||
onCorrespondentSelected: onCorrespondentSelected,
|
||||
onDocumentTypeSelected: onDocumentTypeSelected,
|
||||
onStoragePathSelected: onStoragePathSelected,
|
||||
enableHeroAnimation: enableHeroAnimation,
|
||||
),
|
||||
return DocumentListItem(
|
||||
isLabelClickable: isLabelClickable,
|
||||
document: document,
|
||||
onTap: onTap,
|
||||
isSelected: selectedDocumentIds.contains(document.id),
|
||||
onSelected: onSelected,
|
||||
isSelectionActive: selectedDocumentIds.isNotEmpty,
|
||||
onTagSelected: onTagSelected,
|
||||
onCorrespondentSelected: onCorrespondentSelected,
|
||||
onDocumentTypeSelected: onDocumentTypeSelected,
|
||||
onStoragePathSelected: onStoragePathSelected,
|
||||
enableHeroAnimation: enableHeroAnimation,
|
||||
correspondents: correspondents,
|
||||
documentTypes: documentTypes,
|
||||
storagePaths: storagePaths,
|
||||
tags: tags,
|
||||
);
|
||||
},
|
||||
),
|
||||
@@ -133,21 +152,23 @@ class SliverAdaptiveDocumentsView extends AdaptiveDocumentsView {
|
||||
childCount: documents.length,
|
||||
(context, index) {
|
||||
final document = documents.elementAt(index);
|
||||
return LabelRepositoriesProvider(
|
||||
child: DocumentDetailedItem(
|
||||
isLabelClickable: isLabelClickable,
|
||||
document: document,
|
||||
onTap: onTap,
|
||||
isSelected: selectedDocumentIds.contains(document.id),
|
||||
onSelected: onSelected,
|
||||
isSelectionActive: selectedDocumentIds.isNotEmpty,
|
||||
onTagSelected: onTagSelected,
|
||||
onCorrespondentSelected: onCorrespondentSelected,
|
||||
onDocumentTypeSelected: onDocumentTypeSelected,
|
||||
onStoragePathSelected: onStoragePathSelected,
|
||||
enableHeroAnimation: enableHeroAnimation,
|
||||
highlights: document.searchHit?.highlights,
|
||||
),
|
||||
return DocumentDetailedItem(
|
||||
isLabelClickable: isLabelClickable,
|
||||
document: document,
|
||||
onTap: onTap,
|
||||
isSelected: selectedDocumentIds.contains(document.id),
|
||||
onSelected: onSelected,
|
||||
isSelectionActive: selectedDocumentIds.isNotEmpty,
|
||||
onTagSelected: onTagSelected,
|
||||
onCorrespondentSelected: onCorrespondentSelected,
|
||||
onDocumentTypeSelected: onDocumentTypeSelected,
|
||||
onStoragePathSelected: onStoragePathSelected,
|
||||
enableHeroAnimation: enableHeroAnimation,
|
||||
highlights: document.searchHit?.highlights,
|
||||
correspondents: correspondents,
|
||||
documentTypes: documentTypes,
|
||||
storagePaths: storagePaths,
|
||||
tags: tags,
|
||||
);
|
||||
},
|
||||
),
|
||||
@@ -180,6 +201,10 @@ class SliverAdaptiveDocumentsView extends AdaptiveDocumentsView {
|
||||
onDocumentTypeSelected: onDocumentTypeSelected,
|
||||
onStoragePathSelected: onStoragePathSelected,
|
||||
enableHeroAnimation: enableHeroAnimation,
|
||||
correspondents: correspondents,
|
||||
documentTypes: documentTypes,
|
||||
storagePaths: storagePaths,
|
||||
tags: tags,
|
||||
);
|
||||
},
|
||||
);
|
||||
@@ -205,6 +230,10 @@ class DefaultAdaptiveDocumentsView extends AdaptiveDocumentsView {
|
||||
super.selectedDocumentIds,
|
||||
super.viewType,
|
||||
super.enableHeroAnimation = true,
|
||||
required super.correspondents,
|
||||
required super.documentTypes,
|
||||
required super.tags,
|
||||
required super.storagePaths,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -231,20 +260,22 @@ class DefaultAdaptiveDocumentsView extends AdaptiveDocumentsView {
|
||||
itemCount: documents.length,
|
||||
itemBuilder: (context, index) {
|
||||
final document = documents.elementAt(index);
|
||||
return LabelRepositoriesProvider(
|
||||
child: DocumentListItem(
|
||||
isLabelClickable: isLabelClickable,
|
||||
document: document,
|
||||
onTap: onTap,
|
||||
isSelected: selectedDocumentIds.contains(document.id),
|
||||
onSelected: onSelected,
|
||||
isSelectionActive: selectedDocumentIds.isNotEmpty,
|
||||
onTagSelected: onTagSelected,
|
||||
onCorrespondentSelected: onCorrespondentSelected,
|
||||
onDocumentTypeSelected: onDocumentTypeSelected,
|
||||
onStoragePathSelected: onStoragePathSelected,
|
||||
enableHeroAnimation: enableHeroAnimation,
|
||||
),
|
||||
return DocumentListItem(
|
||||
isLabelClickable: isLabelClickable,
|
||||
document: document,
|
||||
onTap: onTap,
|
||||
isSelected: selectedDocumentIds.contains(document.id),
|
||||
onSelected: onSelected,
|
||||
isSelectionActive: selectedDocumentIds.isNotEmpty,
|
||||
onTagSelected: onTagSelected,
|
||||
onCorrespondentSelected: onCorrespondentSelected,
|
||||
onDocumentTypeSelected: onDocumentTypeSelected,
|
||||
onStoragePathSelected: onStoragePathSelected,
|
||||
enableHeroAnimation: enableHeroAnimation,
|
||||
correspondents: correspondents,
|
||||
documentTypes: documentTypes,
|
||||
storagePaths: storagePaths,
|
||||
tags: tags,
|
||||
);
|
||||
},
|
||||
);
|
||||
@@ -252,7 +283,7 @@ class DefaultAdaptiveDocumentsView extends AdaptiveDocumentsView {
|
||||
|
||||
Widget _buildFullView() {
|
||||
if (showLoadingPlaceholder) {
|
||||
return DocumentsListLoadingWidget();
|
||||
return const DocumentsListLoadingWidget();
|
||||
}
|
||||
|
||||
return ListView.builder(
|
||||
@@ -263,20 +294,22 @@ class DefaultAdaptiveDocumentsView extends AdaptiveDocumentsView {
|
||||
itemCount: documents.length,
|
||||
itemBuilder: (context, index) {
|
||||
final document = documents.elementAt(index);
|
||||
return LabelRepositoriesProvider(
|
||||
child: DocumentDetailedItem(
|
||||
isLabelClickable: isLabelClickable,
|
||||
document: document,
|
||||
onTap: onTap,
|
||||
isSelected: selectedDocumentIds.contains(document.id),
|
||||
onSelected: onSelected,
|
||||
isSelectionActive: selectedDocumentIds.isNotEmpty,
|
||||
onTagSelected: onTagSelected,
|
||||
onCorrespondentSelected: onCorrespondentSelected,
|
||||
onDocumentTypeSelected: onDocumentTypeSelected,
|
||||
onStoragePathSelected: onStoragePathSelected,
|
||||
enableHeroAnimation: enableHeroAnimation,
|
||||
),
|
||||
return DocumentDetailedItem(
|
||||
isLabelClickable: isLabelClickable,
|
||||
document: document,
|
||||
onTap: onTap,
|
||||
isSelected: selectedDocumentIds.contains(document.id),
|
||||
onSelected: onSelected,
|
||||
isSelectionActive: selectedDocumentIds.isNotEmpty,
|
||||
onTagSelected: onTagSelected,
|
||||
onCorrespondentSelected: onCorrespondentSelected,
|
||||
onDocumentTypeSelected: onDocumentTypeSelected,
|
||||
onStoragePathSelected: onStoragePathSelected,
|
||||
enableHeroAnimation: enableHeroAnimation,
|
||||
correspondents: correspondents,
|
||||
documentTypes: documentTypes,
|
||||
storagePaths: storagePaths,
|
||||
tags: tags,
|
||||
);
|
||||
},
|
||||
);
|
||||
@@ -284,7 +317,7 @@ class DefaultAdaptiveDocumentsView extends AdaptiveDocumentsView {
|
||||
|
||||
Widget _buildGridView() {
|
||||
if (showLoadingPlaceholder) {
|
||||
return DocumentGridLoadingWidget();
|
||||
return const DocumentGridLoadingWidget();
|
||||
}
|
||||
return GridView.builder(
|
||||
padding: EdgeInsets.zero,
|
||||
@@ -311,6 +344,10 @@ class DefaultAdaptiveDocumentsView extends AdaptiveDocumentsView {
|
||||
onDocumentTypeSelected: onDocumentTypeSelected,
|
||||
onStoragePathSelected: onStoragePathSelected,
|
||||
enableHeroAnimation: enableHeroAnimation,
|
||||
correspondents: correspondents,
|
||||
documentTypes: documentTypes,
|
||||
storagePaths: storagePaths,
|
||||
tags: tags,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
|
||||
import 'package:paperless_mobile/features/documents/cubit/documents_cubit.dart';
|
||||
import 'package:paperless_mobile/features/documents/view/widgets/document_preview.dart';
|
||||
import 'package:paperless_mobile/features/documents/view/widgets/items/document_item.dart';
|
||||
import 'package:paperless_mobile/features/labels/correspondent/view/widgets/correspondent_widget.dart';
|
||||
@@ -26,6 +28,10 @@ class DocumentDetailedItem extends DocumentItem {
|
||||
super.onStoragePathSelected,
|
||||
super.onTagSelected,
|
||||
super.onTap,
|
||||
required super.tags,
|
||||
required super.correspondents,
|
||||
required super.documentTypes,
|
||||
required super.storagePaths,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -113,7 +119,7 @@ class DocumentDetailedItem extends DocumentItem {
|
||||
textStyle: Theme.of(context).textTheme.titleSmall?.apply(
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
correspondentId: document.correspondent,
|
||||
correspondent: context.read<DocumentsCubit>().correspondent,
|
||||
),
|
||||
],
|
||||
).paddedLTRB(8, 0, 8, 4),
|
||||
|
||||
@@ -21,6 +21,10 @@ class DocumentGridItem extends DocumentItem {
|
||||
super.onTagSelected,
|
||||
super.onTap,
|
||||
required super.enableHeroAnimation,
|
||||
required super.tags,
|
||||
required super.correspondents,
|
||||
required super.documentTypes,
|
||||
required super.storagePaths,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -54,10 +58,10 @@ class DocumentGridItem extends DocumentItem {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
CorrespondentWidget(
|
||||
correspondentId: document.correspondent,
|
||||
correspondent: correspondents[document.correspondent],
|
||||
),
|
||||
DocumentTypeWidget(
|
||||
documentTypeId: document.documentType,
|
||||
documentType: documentTypes[document.documentType],
|
||||
),
|
||||
Text(
|
||||
document.title,
|
||||
@@ -67,7 +71,7 @@ class DocumentGridItem extends DocumentItem {
|
||||
),
|
||||
const Spacer(),
|
||||
TagsWidget(
|
||||
tagIds: document.tags,
|
||||
tags: document.tags.map((e) => tags[e]!).toList(),
|
||||
isMultiLine: false,
|
||||
onTagSelected: onTagSelected,
|
||||
),
|
||||
|
||||
@@ -10,6 +10,11 @@ abstract class DocumentItem extends StatelessWidget {
|
||||
final bool isLabelClickable;
|
||||
final bool enableHeroAnimation;
|
||||
|
||||
final Map<int, Tag> tags;
|
||||
final Map<int, Correspondent> correspondents;
|
||||
final Map<int, DocumentType> documentTypes;
|
||||
final Map<int, StoragePath> storagePaths;
|
||||
|
||||
final void Function(int tagId)? onTagSelected;
|
||||
final void Function(int? correspondentId)? onCorrespondentSelected;
|
||||
final void Function(int? documentTypeId)? onDocumentTypeSelected;
|
||||
@@ -28,5 +33,9 @@ abstract class DocumentItem extends StatelessWidget {
|
||||
this.onDocumentTypeSelected,
|
||||
this.onStoragePathSelected,
|
||||
required this.enableHeroAnimation,
|
||||
required this.tags,
|
||||
required this.correspondents,
|
||||
required this.documentTypes,
|
||||
required this.storagePaths,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/features/documents/view/widgets/document_preview.dart';
|
||||
import 'package:paperless_mobile/features/documents/view/widgets/items/document_item.dart';
|
||||
import 'package:paperless_mobile/features/labels/cubit/label_cubit.dart';
|
||||
import 'package:paperless_mobile/features/labels/cubit/providers/document_type_bloc_provider.dart';
|
||||
import 'package:paperless_mobile/features/labels/correspondent/view/widgets/correspondent_widget.dart';
|
||||
import 'package:paperless_mobile/features/labels/tags/view/widgets/tags_widget.dart';
|
||||
|
||||
@@ -25,113 +24,109 @@ class DocumentListItem extends DocumentItem {
|
||||
super.onTagSelected,
|
||||
super.onTap,
|
||||
super.enableHeroAnimation = true,
|
||||
required super.tags,
|
||||
required super.correspondents,
|
||||
required super.documentTypes,
|
||||
required super.storagePaths,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DocumentTypeBlocProvider(
|
||||
child: Material(
|
||||
child: ListTile(
|
||||
dense: true,
|
||||
selected: isSelected,
|
||||
onTap: () => _onTap(),
|
||||
selectedTileColor: Theme.of(context).colorScheme.inversePrimary,
|
||||
onLongPress: () => onSelected?.call(document),
|
||||
title: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
AbsorbPointer(
|
||||
absorbing: isSelectionActive,
|
||||
child: CorrespondentWidget(
|
||||
isClickable: isLabelClickable,
|
||||
correspondentId: document.correspondent,
|
||||
onSelected: onCorrespondentSelected,
|
||||
),
|
||||
return Material(
|
||||
child: ListTile(
|
||||
dense: true,
|
||||
selected: isSelected,
|
||||
onTap: () => _onTap(),
|
||||
selectedTileColor: Theme.of(context).colorScheme.inversePrimary,
|
||||
onLongPress: () => onSelected?.call(document),
|
||||
title: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
AbsorbPointer(
|
||||
absorbing: isSelectionActive,
|
||||
child: CorrespondentWidget(
|
||||
isClickable: isLabelClickable,
|
||||
correspondent: correspondents[document.correspondent],
|
||||
onSelected: onCorrespondentSelected,
|
||||
),
|
||||
],
|
||||
),
|
||||
Text(
|
||||
document.title,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 1,
|
||||
),
|
||||
AbsorbPointer(
|
||||
absorbing: isSelectionActive,
|
||||
child: TagsWidget(
|
||||
isClickable: isLabelClickable,
|
||||
tagIds: document.tags,
|
||||
isMultiLine: false,
|
||||
onTagSelected: (id) => onTagSelected?.call(id),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
subtitle: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4),
|
||||
child: BlocBuilder<LabelCubit<DocumentType>,
|
||||
LabelState<DocumentType>>(
|
||||
builder: (context, docTypes) {
|
||||
return RichText(
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
text: TextSpan(
|
||||
text: DateFormat.yMMMd().format(document.created),
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.labelSmall
|
||||
?.apply(color: Colors.grey),
|
||||
children: document.documentType != null
|
||||
? [
|
||||
const TextSpan(text: '\u30FB'),
|
||||
TextSpan(
|
||||
text: docTypes
|
||||
.labels[document.documentType]?.name,
|
||||
),
|
||||
]
|
||||
: null,
|
||||
),
|
||||
);
|
||||
},
|
||||
)
|
||||
// Row(
|
||||
// children: [
|
||||
// Text(
|
||||
// DateFormat.yMMMd().format(document.created),
|
||||
// style: Theme.of(context)
|
||||
// .textTheme
|
||||
// .bodySmall
|
||||
// ?.apply(color: Colors.grey),
|
||||
// ),
|
||||
// if (document.documentType != null) ...[
|
||||
// Text("\u30FB"),
|
||||
// DocumentTypeWidget(
|
||||
// documentTypeId: document.documentType,
|
||||
// textStyle: Theme.of(context).textTheme.bodySmall?.apply(
|
||||
// color: Colors.grey,
|
||||
// overflow: TextOverflow.ellipsis,
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ],
|
||||
// ),
|
||||
),
|
||||
isThreeLine: document.tags.isNotEmpty,
|
||||
leading: AspectRatio(
|
||||
aspectRatio: _a4AspectRatio,
|
||||
child: GestureDetector(
|
||||
child: DocumentPreview(
|
||||
document: document,
|
||||
fit: BoxFit.cover,
|
||||
alignment: Alignment.topCenter,
|
||||
enableHero: enableHeroAnimation,
|
||||
],
|
||||
),
|
||||
Text(
|
||||
document.title,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 1,
|
||||
),
|
||||
AbsorbPointer(
|
||||
absorbing: isSelectionActive,
|
||||
child: TagsWidget(
|
||||
isClickable: isLabelClickable,
|
||||
tags: document.tags.map((e) => tags[e]!).toList(),
|
||||
isMultiLine: false,
|
||||
onTagSelected: (id) => onTagSelected?.call(id),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
subtitle: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4),
|
||||
child: RichText(
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
text: TextSpan(
|
||||
text: DateFormat.yMMMd().format(document.created),
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.labelSmall
|
||||
?.apply(color: Colors.grey),
|
||||
children: document.documentType != null
|
||||
? [
|
||||
const TextSpan(text: '\u30FB'),
|
||||
TextSpan(
|
||||
text: documentTypes[document.documentType]?.name,
|
||||
),
|
||||
]
|
||||
: null,
|
||||
),
|
||||
),
|
||||
contentPadding: const EdgeInsets.all(8.0),
|
||||
// Row(
|
||||
// children: [
|
||||
// Text(
|
||||
// DateFormat.yMMMd().format(document.created),
|
||||
// style: Theme.of(context)
|
||||
// .textTheme
|
||||
// .bodySmall
|
||||
// ?.apply(color: Colors.grey),
|
||||
// ),
|
||||
// if (document.documentType != null) ...[
|
||||
// Text("\u30FB"),
|
||||
// DocumentTypeWidget(
|
||||
// documentTypeId: document.documentType,
|
||||
// textStyle: Theme.of(context).textTheme.bodySmall?.apply(
|
||||
// color: Colors.grey,
|
||||
// overflow: TextOverflow.ellipsis,
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ],
|
||||
// ),
|
||||
),
|
||||
isThreeLine: document.tags.isNotEmpty,
|
||||
leading: AspectRatio(
|
||||
aspectRatio: _a4AspectRatio,
|
||||
child: GestureDetector(
|
||||
child: DocumentPreview(
|
||||
document: document,
|
||||
fit: BoxFit.cover,
|
||||
alignment: Alignment.topCenter,
|
||||
enableHero: enableHeroAnimation,
|
||||
),
|
||||
),
|
||||
),
|
||||
contentPadding: const EdgeInsets.all(8.0),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ class DocumentSelectionSliverAppBar extends StatelessWidget {
|
||||
.paddedOnly(left: 4, right: 4),
|
||||
_buildBulkEditStoragePathChip(context)
|
||||
.paddedOnly(left: 4, right: 4),
|
||||
// _buildBulkEditTagsChip(context).paddedOnly(left: 4, right: 4),
|
||||
_buildBulkEditTagsChip(context).paddedOnly(left: 4, right: 4),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -100,9 +100,6 @@ class DocumentSelectionSliverAppBar extends StatelessWidget {
|
||||
builder: (_) {
|
||||
return BlocProvider(
|
||||
create: (context) => DocumentBulkActionCubit(
|
||||
context.read(),
|
||||
context.read(),
|
||||
context.read(),
|
||||
context.read(),
|
||||
context.read(),
|
||||
context.read(),
|
||||
@@ -112,8 +109,7 @@ class DocumentSelectionSliverAppBar extends StatelessWidget {
|
||||
return BulkEditLabelBottomSheet<Correspondent>(
|
||||
initialValue: initialValue,
|
||||
title: "Bulk edit correspondent",
|
||||
availableOptionsSelector: (state) =>
|
||||
state.correspondentOptions,
|
||||
availableOptionsSelector: (state) => state.correspondents,
|
||||
formFieldLabel: S.of(context)!.correspondent,
|
||||
formFieldPrefixIcon: const Icon(Icons.person_outline),
|
||||
onSubmit: (selectedId) async {
|
||||
@@ -152,9 +148,6 @@ class DocumentSelectionSliverAppBar extends StatelessWidget {
|
||||
builder: (_) {
|
||||
return BlocProvider(
|
||||
create: (context) => DocumentBulkActionCubit(
|
||||
context.read(),
|
||||
context.read(),
|
||||
context.read(),
|
||||
context.read(),
|
||||
context.read(),
|
||||
context.read(),
|
||||
@@ -164,8 +157,7 @@ class DocumentSelectionSliverAppBar extends StatelessWidget {
|
||||
return BulkEditLabelBottomSheet<DocumentType>(
|
||||
initialValue: initialValue,
|
||||
title: "Bulk edit document type",
|
||||
availableOptionsSelector: (state) =>
|
||||
state.documentTypeOptions,
|
||||
availableOptionsSelector: (state) => state.documentTypes,
|
||||
formFieldLabel: S.of(context)!.documentType,
|
||||
formFieldPrefixIcon: const Icon(Icons.person_outline),
|
||||
onSubmit: (selectedId) async {
|
||||
@@ -204,9 +196,6 @@ class DocumentSelectionSliverAppBar extends StatelessWidget {
|
||||
builder: (_) {
|
||||
return BlocProvider(
|
||||
create: (context) => DocumentBulkActionCubit(
|
||||
context.read(),
|
||||
context.read(),
|
||||
context.read(),
|
||||
context.read(),
|
||||
context.read(),
|
||||
context.read(),
|
||||
@@ -216,7 +205,7 @@ class DocumentSelectionSliverAppBar extends StatelessWidget {
|
||||
return BulkEditLabelBottomSheet<StoragePath>(
|
||||
initialValue: initialValue,
|
||||
title: "Bulk edit storage path",
|
||||
availableOptionsSelector: (state) => state.storagePathOptions,
|
||||
availableOptionsSelector: (state) => state.storagePaths,
|
||||
formFieldLabel: S.of(context)!.storagePath,
|
||||
formFieldPrefixIcon: const Icon(Icons.folder_open_outlined),
|
||||
onSubmit: (selectedId) async {
|
||||
@@ -246,14 +235,11 @@ class DocumentSelectionSliverAppBar extends StatelessWidget {
|
||||
topRight: Radius.circular(16),
|
||||
),
|
||||
),
|
||||
isScrollControlled: false,
|
||||
isScrollControlled: true,
|
||||
context: context,
|
||||
builder: (_) {
|
||||
return BlocProvider(
|
||||
create: (context) => DocumentBulkActionCubit(
|
||||
context.read(),
|
||||
context.read(),
|
||||
context.read(),
|
||||
context.read(),
|
||||
context.read(),
|
||||
context.read(),
|
||||
|
||||
@@ -43,14 +43,7 @@ class SortDocumentsButton extends StatelessWidget {
|
||||
child: MultiBlocProvider(
|
||||
providers: [
|
||||
BlocProvider(
|
||||
create: (context) => LabelCubit<DocumentType>(
|
||||
context.read<LabelRepository<DocumentType>>(),
|
||||
),
|
||||
),
|
||||
BlocProvider(
|
||||
create: (context) => LabelCubit<Correspondent>(
|
||||
context.read<LabelRepository<Correspondent>>(),
|
||||
),
|
||||
create: (context) => LabelCubit(context.read()),
|
||||
),
|
||||
],
|
||||
child: SortFieldSelectionBottomSheet(
|
||||
|
||||
@@ -1,34 +1,44 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||
|
||||
import 'package:paperless_mobile/features/labels/cubit/label_cubit_mixin.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
part 'edit_label_state.dart';
|
||||
part 'edit_label_cubit.freezed.dart';
|
||||
|
||||
class EditLabelCubit<T extends Label> extends Cubit<EditLabelState<T>> {
|
||||
final LabelRepository<T> _repository;
|
||||
class EditLabelCubit extends Cubit<EditLabelState> with LabelCubitMixin {
|
||||
@override
|
||||
final LabelRepository labelRepository;
|
||||
|
||||
StreamSubscription? _subscription;
|
||||
|
||||
EditLabelCubit(LabelRepository<T> repository)
|
||||
: _repository = repository,
|
||||
super(EditLabelState<T>(labels: repository.current?.values ?? {})) {
|
||||
_subscription = repository.values.listen(
|
||||
(event) => emit(EditLabelState(labels: event?.values ?? {})),
|
||||
EditLabelCubit(this.labelRepository) : super(const EditLabelState()) {
|
||||
labelRepository.subscribe(
|
||||
this,
|
||||
onChanged: (labels) => state.copyWith(
|
||||
correspondents: labels.correspondents,
|
||||
documentTypes: labels.documentTypes,
|
||||
tags: labels.tags,
|
||||
storagePaths: labels.storagePaths,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<T> create(T label) => _repository.create(label);
|
||||
|
||||
Future<T> update(T label) => _repository.update(label);
|
||||
|
||||
Future<void> delete(T label) => _repository.delete(label);
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
_subscription?.cancel();
|
||||
labelRepository.unsubscribe(this);
|
||||
return super.close();
|
||||
}
|
||||
|
||||
@override
|
||||
Map<int, Correspondent> get correspondents => state.correspondents;
|
||||
|
||||
@override
|
||||
Map<int, DocumentType> get documentTypes => state.documentTypes;
|
||||
|
||||
@override
|
||||
Map<int, StoragePath> get storagePaths => state.storagePaths;
|
||||
|
||||
@override
|
||||
Map<int, Tag> get tags => state.tags;
|
||||
}
|
||||
|
||||
237
lib/features/edit_label/cubit/edit_label_cubit.freezed.dart
Normal file
237
lib/features/edit_label/cubit/edit_label_cubit.freezed.dart
Normal file
@@ -0,0 +1,237 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'edit_label_cubit.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
|
||||
|
||||
/// @nodoc
|
||||
mixin _$EditLabelState {
|
||||
Map<int, Correspondent> get correspondents =>
|
||||
throw _privateConstructorUsedError;
|
||||
Map<int, DocumentType> get documentTypes =>
|
||||
throw _privateConstructorUsedError;
|
||||
Map<int, Tag> get tags => throw _privateConstructorUsedError;
|
||||
Map<int, StoragePath> get storagePaths => throw _privateConstructorUsedError;
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
$EditLabelStateCopyWith<EditLabelState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $EditLabelStateCopyWith<$Res> {
|
||||
factory $EditLabelStateCopyWith(
|
||||
EditLabelState value, $Res Function(EditLabelState) then) =
|
||||
_$EditLabelStateCopyWithImpl<$Res, EditLabelState>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{Map<int, Correspondent> correspondents,
|
||||
Map<int, DocumentType> documentTypes,
|
||||
Map<int, Tag> tags,
|
||||
Map<int, StoragePath> storagePaths});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$EditLabelStateCopyWithImpl<$Res, $Val extends EditLabelState>
|
||||
implements $EditLabelStateCopyWith<$Res> {
|
||||
_$EditLabelStateCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? correspondents = null,
|
||||
Object? documentTypes = null,
|
||||
Object? tags = null,
|
||||
Object? storagePaths = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
correspondents: null == correspondents
|
||||
? _value.correspondents
|
||||
: correspondents // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, Correspondent>,
|
||||
documentTypes: null == documentTypes
|
||||
? _value.documentTypes
|
||||
: documentTypes // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, DocumentType>,
|
||||
tags: null == tags
|
||||
? _value.tags
|
||||
: tags // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, Tag>,
|
||||
storagePaths: null == storagePaths
|
||||
? _value.storagePaths
|
||||
: storagePaths // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, StoragePath>,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$_EditLabelStateCopyWith<$Res>
|
||||
implements $EditLabelStateCopyWith<$Res> {
|
||||
factory _$$_EditLabelStateCopyWith(
|
||||
_$_EditLabelState value, $Res Function(_$_EditLabelState) then) =
|
||||
__$$_EditLabelStateCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{Map<int, Correspondent> correspondents,
|
||||
Map<int, DocumentType> documentTypes,
|
||||
Map<int, Tag> tags,
|
||||
Map<int, StoragePath> storagePaths});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$_EditLabelStateCopyWithImpl<$Res>
|
||||
extends _$EditLabelStateCopyWithImpl<$Res, _$_EditLabelState>
|
||||
implements _$$_EditLabelStateCopyWith<$Res> {
|
||||
__$$_EditLabelStateCopyWithImpl(
|
||||
_$_EditLabelState _value, $Res Function(_$_EditLabelState) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? correspondents = null,
|
||||
Object? documentTypes = null,
|
||||
Object? tags = null,
|
||||
Object? storagePaths = null,
|
||||
}) {
|
||||
return _then(_$_EditLabelState(
|
||||
correspondents: null == correspondents
|
||||
? _value._correspondents
|
||||
: correspondents // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, Correspondent>,
|
||||
documentTypes: null == documentTypes
|
||||
? _value._documentTypes
|
||||
: documentTypes // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, DocumentType>,
|
||||
tags: null == tags
|
||||
? _value._tags
|
||||
: tags // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, Tag>,
|
||||
storagePaths: null == storagePaths
|
||||
? _value._storagePaths
|
||||
: storagePaths // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, StoragePath>,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$_EditLabelState implements _EditLabelState {
|
||||
const _$_EditLabelState(
|
||||
{final Map<int, Correspondent> correspondents = const {},
|
||||
final Map<int, DocumentType> documentTypes = const {},
|
||||
final Map<int, Tag> tags = const {},
|
||||
final Map<int, StoragePath> storagePaths = const {}})
|
||||
: _correspondents = correspondents,
|
||||
_documentTypes = documentTypes,
|
||||
_tags = tags,
|
||||
_storagePaths = storagePaths;
|
||||
|
||||
final Map<int, Correspondent> _correspondents;
|
||||
@override
|
||||
@JsonKey()
|
||||
Map<int, Correspondent> get correspondents {
|
||||
if (_correspondents is EqualUnmodifiableMapView) return _correspondents;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableMapView(_correspondents);
|
||||
}
|
||||
|
||||
final Map<int, DocumentType> _documentTypes;
|
||||
@override
|
||||
@JsonKey()
|
||||
Map<int, DocumentType> get documentTypes {
|
||||
if (_documentTypes is EqualUnmodifiableMapView) return _documentTypes;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableMapView(_documentTypes);
|
||||
}
|
||||
|
||||
final Map<int, Tag> _tags;
|
||||
@override
|
||||
@JsonKey()
|
||||
Map<int, Tag> get tags {
|
||||
if (_tags is EqualUnmodifiableMapView) return _tags;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableMapView(_tags);
|
||||
}
|
||||
|
||||
final Map<int, StoragePath> _storagePaths;
|
||||
@override
|
||||
@JsonKey()
|
||||
Map<int, StoragePath> get storagePaths {
|
||||
if (_storagePaths is EqualUnmodifiableMapView) return _storagePaths;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableMapView(_storagePaths);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'EditLabelState(correspondents: $correspondents, documentTypes: $documentTypes, tags: $tags, storagePaths: $storagePaths)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(dynamic other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$_EditLabelState &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._correspondents, _correspondents) &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._documentTypes, _documentTypes) &&
|
||||
const DeepCollectionEquality().equals(other._tags, _tags) &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._storagePaths, _storagePaths));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
const DeepCollectionEquality().hash(_correspondents),
|
||||
const DeepCollectionEquality().hash(_documentTypes),
|
||||
const DeepCollectionEquality().hash(_tags),
|
||||
const DeepCollectionEquality().hash(_storagePaths));
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$_EditLabelStateCopyWith<_$_EditLabelState> get copyWith =>
|
||||
__$$_EditLabelStateCopyWithImpl<_$_EditLabelState>(this, _$identity);
|
||||
}
|
||||
|
||||
abstract class _EditLabelState implements EditLabelState {
|
||||
const factory _EditLabelState(
|
||||
{final Map<int, Correspondent> correspondents,
|
||||
final Map<int, DocumentType> documentTypes,
|
||||
final Map<int, Tag> tags,
|
||||
final Map<int, StoragePath> storagePaths}) = _$_EditLabelState;
|
||||
|
||||
@override
|
||||
Map<int, Correspondent> get correspondents;
|
||||
@override
|
||||
Map<int, DocumentType> get documentTypes;
|
||||
@override
|
||||
Map<int, Tag> get tags;
|
||||
@override
|
||||
Map<int, StoragePath> get storagePaths;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$_EditLabelStateCopyWith<_$_EditLabelState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
part of 'edit_label_cubit.dart';
|
||||
|
||||
class EditLabelState<T> extends Equatable {
|
||||
final Map<int, T> labels;
|
||||
|
||||
const EditLabelState({this.labels = const {}});
|
||||
|
||||
@override
|
||||
List<Object> get props => [labels];
|
||||
@freezed
|
||||
class EditLabelState with _$EditLabelState {
|
||||
const factory EditLabelState({
|
||||
@Default({}) Map<int, Correspondent> correspondents,
|
||||
@Default({}) Map<int, DocumentType> documentTypes,
|
||||
@Default({}) Map<int, Tag> tags,
|
||||
@Default({}) Map<int, StoragePath> storagePaths,
|
||||
}) = _EditLabelState;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||
import 'package:paperless_mobile/core/repository/state/indexed_repository_state.dart';
|
||||
import 'package:paperless_mobile/features/edit_label/cubit/edit_label_cubit.dart';
|
||||
import 'package:paperless_mobile/features/edit_label/view/label_form.dart';
|
||||
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||
@@ -12,6 +11,7 @@ class AddLabelPage<T extends Label> extends StatelessWidget {
|
||||
final Widget pageTitle;
|
||||
final T Function(Map<String, dynamic> json) fromJsonT;
|
||||
final List<Widget> additionalFields;
|
||||
final Future<T> Function(BuildContext context, T label) onSubmit;
|
||||
|
||||
const AddLabelPage({
|
||||
super.key,
|
||||
@@ -19,19 +19,21 @@ class AddLabelPage<T extends Label> extends StatelessWidget {
|
||||
required this.pageTitle,
|
||||
required this.fromJsonT,
|
||||
this.additionalFields = const [],
|
||||
required this.onSubmit,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => EditLabelCubit(
|
||||
context.read<LabelRepository<T>>(),
|
||||
context.read<LabelRepository>(),
|
||||
),
|
||||
child: AddLabelFormWidget(
|
||||
pageTitle: pageTitle,
|
||||
label: initialName != null ? fromJsonT({'name': initialName}) : null,
|
||||
additionalFields: additionalFields,
|
||||
fromJsonT: fromJsonT,
|
||||
onSubmit: onSubmit,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -41,6 +43,7 @@ class AddLabelFormWidget<T extends Label> extends StatelessWidget {
|
||||
final T? label;
|
||||
final T Function(Map<String, dynamic> json) fromJsonT;
|
||||
final List<Widget> additionalFields;
|
||||
final Future<T> Function(BuildContext context, T label) onSubmit;
|
||||
|
||||
final Widget pageTitle;
|
||||
const AddLabelFormWidget({
|
||||
@@ -49,6 +52,7 @@ class AddLabelFormWidget<T extends Label> extends StatelessWidget {
|
||||
required this.fromJsonT,
|
||||
required this.additionalFields,
|
||||
required this.pageTitle,
|
||||
required this.onSubmit,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -63,7 +67,7 @@ class AddLabelFormWidget<T extends Label> extends StatelessWidget {
|
||||
submitButtonConfig: SubmitButtonConfig<T>(
|
||||
icon: const Icon(Icons.add),
|
||||
label: Text(S.of(context)!.create),
|
||||
onSubmit: context.read<EditLabelCubit<T>>().create,
|
||||
onSubmit: (label) => onSubmit(context, label),
|
||||
),
|
||||
additionalFields: additionalFields,
|
||||
),
|
||||
|
||||
@@ -1,40 +1,43 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||
import 'package:paperless_mobile/core/repository/state/indexed_repository_state.dart';
|
||||
import 'package:paperless_mobile/features/edit_label/cubit/edit_label_cubit.dart';
|
||||
import 'package:paperless_mobile/features/edit_label/view/label_form.dart';
|
||||
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||
|
||||
import 'package:paperless_mobile/helpers/message_helpers.dart';
|
||||
import 'package:paperless_mobile/constants.dart';
|
||||
|
||||
class EditLabelPage<T extends Label> extends StatelessWidget {
|
||||
final T label;
|
||||
final T Function(Map<String, dynamic> json) fromJsonT;
|
||||
final List<Widget> additionalFields;
|
||||
final Future<T> Function(BuildContext context, T label) onSubmit;
|
||||
final Future<void> Function(BuildContext context, T label) onDelete;
|
||||
|
||||
const EditLabelPage({
|
||||
super.key,
|
||||
required this.label,
|
||||
required this.fromJsonT,
|
||||
this.additionalFields = const [],
|
||||
required this.onSubmit,
|
||||
required this.onDelete,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => EditLabelCubit(
|
||||
context.read<LabelRepository<T>>(),
|
||||
context.read<LabelRepository>(),
|
||||
),
|
||||
child: EditLabelForm(
|
||||
label: label,
|
||||
additionalFields: additionalFields,
|
||||
fromJsonT: fromJsonT,
|
||||
onSubmit: onSubmit,
|
||||
onDelete: onDelete,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -44,12 +47,16 @@ class EditLabelForm<T extends Label> extends StatelessWidget {
|
||||
final T label;
|
||||
final T Function(Map<String, dynamic> json) fromJsonT;
|
||||
final List<Widget> additionalFields;
|
||||
final Future<T> Function(BuildContext context, T label) onSubmit;
|
||||
final Future<void> Function(BuildContext context, T label) onDelete;
|
||||
|
||||
const EditLabelForm({
|
||||
super.key,
|
||||
required this.label,
|
||||
required this.fromJsonT,
|
||||
required this.additionalFields,
|
||||
required this.onSubmit,
|
||||
required this.onDelete,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -70,7 +77,7 @@ class EditLabelForm<T extends Label> extends StatelessWidget {
|
||||
submitButtonConfig: SubmitButtonConfig<T>(
|
||||
icon: const Icon(Icons.save),
|
||||
label: Text(S.of(context)!.saveChanges),
|
||||
onSubmit: context.read<EditLabelCubit<T>>().update,
|
||||
onSubmit: (label) => onSubmit(context, label),
|
||||
),
|
||||
additionalFields: additionalFields,
|
||||
),
|
||||
@@ -107,7 +114,7 @@ class EditLabelForm<T extends Label> extends StatelessWidget {
|
||||
false;
|
||||
if (shouldDelete) {
|
||||
try {
|
||||
context.read<EditLabelCubit<T>>().delete(label);
|
||||
onDelete(context, label);
|
||||
} on PaperlessServerException catch (error) {
|
||||
showErrorMessage(context, error);
|
||||
} catch (error, stackTrace) {
|
||||
@@ -116,7 +123,7 @@ class EditLabelForm<T extends Label> extends StatelessWidget {
|
||||
Navigator.pop(context);
|
||||
}
|
||||
} else {
|
||||
context.read<EditLabelCubit<T>>().delete(label);
|
||||
onDelete(context, label);
|
||||
Navigator.pop(context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||
import 'package:paperless_mobile/core/repository/state/impl/correspondent_repository_state.dart';
|
||||
import 'package:paperless_mobile/features/edit_label/cubit/edit_label_cubit.dart';
|
||||
import 'package:paperless_mobile/features/edit_label/view/add_label_page.dart';
|
||||
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||
@@ -14,13 +12,15 @@ class AddCorrespondentPage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => EditLabelCubit<Correspondent>(
|
||||
context.read<LabelRepository<Correspondent>>(),
|
||||
create: (context) => EditLabelCubit(
|
||||
context.read(),
|
||||
),
|
||||
child: AddLabelPage<Correspondent>(
|
||||
pageTitle: Text(S.of(context)!.addCorrespondent),
|
||||
fromJsonT: Correspondent.fromJson,
|
||||
initialName: initialName,
|
||||
onSubmit: (context, label) =>
|
||||
context.read<EditLabelCubit>().addCorrespondent(label),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
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:paperless_mobile/features/edit_label/cubit/edit_label_cubit.dart';
|
||||
import 'package:paperless_mobile/features/edit_label/view/add_label_page.dart';
|
||||
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||
@@ -17,13 +15,15 @@ class AddDocumentTypePage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => EditLabelCubit<DocumentType>(
|
||||
context.read<LabelRepository<DocumentType>>(),
|
||||
create: (context) => EditLabelCubit(
|
||||
context.read(),
|
||||
),
|
||||
child: AddLabelPage<DocumentType>(
|
||||
pageTitle: Text(S.of(context)!.addDocumentType),
|
||||
fromJsonT: DocumentType.fromJson,
|
||||
initialName: initialName,
|
||||
onSubmit: (context, label) =>
|
||||
context.read<EditLabelCubit>().addDocumentType(label),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
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:paperless_mobile/features/edit_label/cubit/edit_label_cubit.dart';
|
||||
import 'package:paperless_mobile/features/edit_label/view/add_label_page.dart';
|
||||
import 'package:paperless_mobile/features/labels/storage_path/view/widgets/storage_path_autofill_form_builder_field.dart';
|
||||
@@ -15,13 +13,15 @@ class AddStoragePathPage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => EditLabelCubit<StoragePath>(
|
||||
context.read<LabelRepository<StoragePath>>(),
|
||||
create: (context) => EditLabelCubit(
|
||||
context.read(),
|
||||
),
|
||||
child: AddLabelPage<StoragePath>(
|
||||
pageTitle: Text(S.of(context)!.addStoragePath),
|
||||
fromJsonT: StoragePath.fromJson,
|
||||
initialName: initalName,
|
||||
onSubmit: (context, label) =>
|
||||
context.read<EditLabelCubit>().addStoragePath(label),
|
||||
additionalFields: const [
|
||||
StoragePathAutofillFormBuilderField(name: StoragePath.pathKey),
|
||||
SizedBox(height: 120.0),
|
||||
|
||||
@@ -4,8 +4,6 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_form_builder/flutter_form_builder.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||
import 'package:paperless_mobile/core/repository/state/impl/tag_repository_state.dart';
|
||||
import 'package:paperless_mobile/core/widgets/form_builder_fields/form_builder_color_picker.dart';
|
||||
import 'package:paperless_mobile/features/edit_label/cubit/edit_label_cubit.dart';
|
||||
import 'package:paperless_mobile/features/edit_label/view/add_label_page.dart';
|
||||
@@ -18,13 +16,15 @@ class AddTagPage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => EditLabelCubit<Tag>(
|
||||
context.read<LabelRepository<Tag>>(),
|
||||
create: (context) => EditLabelCubit(
|
||||
context.read(),
|
||||
),
|
||||
child: AddLabelPage<Tag>(
|
||||
pageTitle: Text(S.of(context)!.addTag),
|
||||
fromJsonT: Tag.fromJson,
|
||||
initialName: initialValue,
|
||||
onSubmit: (context, label) =>
|
||||
context.read<EditLabelCubit>().addTag(label),
|
||||
additionalFields: [
|
||||
FormBuilderColorPickerField(
|
||||
name: Tag.colorKey,
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||
import 'package:paperless_mobile/core/repository/state/impl/correspondent_repository_state.dart';
|
||||
import 'package:paperless_mobile/features/edit_label/cubit/edit_label_cubit.dart';
|
||||
import 'package:paperless_mobile/features/edit_label/view/edit_label_page.dart';
|
||||
|
||||
@@ -13,12 +11,16 @@ class EditCorrespondentPage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => EditLabelCubit<Correspondent>(
|
||||
context.read<LabelRepository<Correspondent>>(),
|
||||
create: (context) => EditLabelCubit(
|
||||
context.read(),
|
||||
),
|
||||
child: EditLabelPage<Correspondent>(
|
||||
label: correspondent,
|
||||
fromJsonT: Correspondent.fromJson,
|
||||
onSubmit: (context, label) =>
|
||||
context.read<EditLabelCubit>().addCorrespondent(label),
|
||||
onDelete: (context, label) =>
|
||||
context.read<EditLabelCubit>().removeCorrespondent(label),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
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:paperless_mobile/features/edit_label/cubit/edit_label_cubit.dart';
|
||||
import 'package:paperless_mobile/features/edit_label/view/edit_label_page.dart';
|
||||
|
||||
@@ -13,12 +12,16 @@ class EditDocumentTypePage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => EditLabelCubit<DocumentType>(
|
||||
context.read<LabelRepository<DocumentType>>(),
|
||||
create: (context) => EditLabelCubit(
|
||||
context.read(),
|
||||
),
|
||||
child: EditLabelPage<DocumentType>(
|
||||
label: documentType,
|
||||
fromJsonT: DocumentType.fromJson,
|
||||
onSubmit: (context, label) =>
|
||||
context.read<EditLabelCubit>().addDocumentType(label),
|
||||
onDelete: (context, label) =>
|
||||
context.read<EditLabelCubit>().removeDocumentType(label),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
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:paperless_mobile/features/edit_label/cubit/edit_label_cubit.dart';
|
||||
import 'package:paperless_mobile/features/edit_label/view/edit_label_page.dart';
|
||||
import 'package:paperless_mobile/features/labels/storage_path/view/widgets/storage_path_autofill_form_builder_field.dart';
|
||||
@@ -14,12 +12,16 @@ class EditStoragePathPage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => EditLabelCubit<StoragePath>(
|
||||
context.read<LabelRepository<StoragePath>>(),
|
||||
create: (context) => EditLabelCubit(
|
||||
context.read(),
|
||||
),
|
||||
child: EditLabelPage<StoragePath>(
|
||||
label: storagePath,
|
||||
fromJsonT: StoragePath.fromJson,
|
||||
onSubmit: (context, label) =>
|
||||
context.read<EditLabelCubit>().addStoragePath(label),
|
||||
onDelete: (context, label) =>
|
||||
context.read<EditLabelCubit>().removeStoragePath(label),
|
||||
additionalFields: [
|
||||
StoragePathAutofillFormBuilderField(
|
||||
name: StoragePath.pathKey,
|
||||
|
||||
@@ -2,8 +2,6 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_form_builder/flutter_form_builder.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||
import 'package:paperless_mobile/core/repository/state/impl/tag_repository_state.dart';
|
||||
import 'package:paperless_mobile/core/widgets/form_builder_fields/form_builder_color_picker.dart';
|
||||
import 'package:paperless_mobile/features/edit_label/cubit/edit_label_cubit.dart';
|
||||
import 'package:paperless_mobile/features/edit_label/view/edit_label_page.dart';
|
||||
@@ -17,12 +15,16 @@ class EditTagPage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => EditLabelCubit<Tag>(
|
||||
context.read<LabelRepository<Tag>>(),
|
||||
create: (context) => EditLabelCubit(
|
||||
context.read(),
|
||||
),
|
||||
child: EditLabelPage<Tag>(
|
||||
label: tag,
|
||||
fromJsonT: Tag.fromJson,
|
||||
onSubmit: (context, label) =>
|
||||
context.read<EditLabelCubit>().addTag(label),
|
||||
onDelete: (context, label) =>
|
||||
context.read<EditLabelCubit>().removeTag(label),
|
||||
additionalFields: [
|
||||
FormBuilderColorPickerField(
|
||||
initialValue: tag.color,
|
||||
|
||||
@@ -31,9 +31,7 @@ import 'package:paperless_mobile/features/sharing/share_intent_queue.dart';
|
||||
import 'package:paperless_mobile/features/tasks/cubit/task_status_cubit.dart';
|
||||
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||
|
||||
import 'package:paperless_mobile/helpers/file_helpers.dart';
|
||||
import 'package:paperless_mobile/helpers/message_helpers.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:receive_sharing_intent/receive_sharing_intent.dart';
|
||||
import 'package:responsive_builder/responsive_builder.dart';
|
||||
|
||||
@@ -60,8 +58,6 @@ class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
|
||||
context.read(),
|
||||
context.read(),
|
||||
context.read(),
|
||||
context.read(),
|
||||
context.read(),
|
||||
);
|
||||
_listenToInboxChanges();
|
||||
|
||||
@@ -260,17 +256,8 @@ class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
|
||||
MultiBlocProvider(
|
||||
providers: [
|
||||
BlocProvider(
|
||||
create: (context) => LabelCubit<Correspondent>(context.read()),
|
||||
),
|
||||
BlocProvider(
|
||||
create: (context) => LabelCubit<DocumentType>(context.read()),
|
||||
),
|
||||
BlocProvider(
|
||||
create: (context) => LabelCubit<Tag>(context.read()),
|
||||
),
|
||||
BlocProvider(
|
||||
create: (context) => LabelCubit<StoragePath>(context.read()),
|
||||
),
|
||||
create: (context) => LabelCubit(context.read()),
|
||||
)
|
||||
],
|
||||
child: const LabelsPage(),
|
||||
),
|
||||
@@ -345,15 +332,13 @@ class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
|
||||
}
|
||||
|
||||
void _initializeData(BuildContext context) {
|
||||
try {
|
||||
context.read<LabelRepository<Tag>>().findAll();
|
||||
context.read<LabelRepository<Correspondent>>().findAll();
|
||||
context.read<LabelRepository<DocumentType>>().findAll();
|
||||
context.read<LabelRepository<StoragePath>>().findAll();
|
||||
context.read<SavedViewRepository>().findAll();
|
||||
context.read<PaperlessServerInformationCubit>().updateInformtion();
|
||||
} on PaperlessServerException catch (error, stackTrace) {
|
||||
Future.wait([
|
||||
context.read<LabelRepository>().initialize(),
|
||||
context.read<SavedViewRepository>().findAll(),
|
||||
context.read<PaperlessServerInformationCubit>().updateInformtion(),
|
||||
]).onError<PaperlessServerException>((error, stackTrace) {
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
}
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,10 +65,7 @@ class VerifyIdentityPage extends StatelessWidget {
|
||||
|
||||
void _logout(BuildContext context) {
|
||||
context.read<AuthenticationCubit>().logout();
|
||||
context.read<LabelRepository<Tag>>().clear();
|
||||
context.read<LabelRepository<Correspondent>>().clear();
|
||||
context.read<LabelRepository<DocumentType>>().clear();
|
||||
context.read<LabelRepository<StoragePath>>().clear();
|
||||
context.read<LabelRepository>().clear();
|
||||
context.read<SavedViewRepository>().clear();
|
||||
HydratedBloc.storage.clear();
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/notifier/document_changed_notifier.dart';
|
||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||
import 'package:paperless_mobile/core/repository/label_repository_state.dart';
|
||||
import 'package:paperless_mobile/features/paged_document_view/cubit/paged_documents_state.dart';
|
||||
import 'package:paperless_mobile/features/paged_document_view/cubit/document_paging_bloc_mixin.dart';
|
||||
|
||||
@@ -13,9 +14,7 @@ part 'inbox_state.dart';
|
||||
|
||||
class InboxCubit extends HydratedCubit<InboxState>
|
||||
with DocumentPagingBlocMixin {
|
||||
final LabelRepository<Tag> _tagsRepository;
|
||||
final LabelRepository<Correspondent> _correspondentRepository;
|
||||
final LabelRepository<DocumentType> _documentTypeRepository;
|
||||
final LabelRepository _labelRepository;
|
||||
|
||||
final PaperlessDocumentsApi _documentsApi;
|
||||
|
||||
@@ -24,27 +23,15 @@ class InboxCubit extends HydratedCubit<InboxState>
|
||||
|
||||
final PaperlessServerStatsApi _statsApi;
|
||||
|
||||
final List<StreamSubscription> _subscriptions = [];
|
||||
|
||||
@override
|
||||
PaperlessDocumentsApi get api => _documentsApi;
|
||||
|
||||
InboxCubit(
|
||||
this._tagsRepository,
|
||||
this._documentsApi,
|
||||
this._correspondentRepository,
|
||||
this._documentTypeRepository,
|
||||
this._statsApi,
|
||||
this._labelRepository,
|
||||
this.notifier,
|
||||
) : super(
|
||||
InboxState(
|
||||
availableCorrespondents:
|
||||
_correspondentRepository.current?.values ?? {},
|
||||
availableDocumentTypes:
|
||||
_documentTypeRepository.current?.values ?? {},
|
||||
availableTags: _tagsRepository.current?.values ?? {},
|
||||
),
|
||||
) {
|
||||
) : super(InboxState(labels: _labelRepository.state)) {
|
||||
notifier.subscribe(
|
||||
this,
|
||||
onDeleted: remove,
|
||||
@@ -60,28 +47,11 @@ class InboxCubit extends HydratedCubit<InboxState>
|
||||
}
|
||||
},
|
||||
);
|
||||
_subscriptions.add(
|
||||
_tagsRepository.values.listen((event) {
|
||||
if (event?.hasLoaded ?? false) {
|
||||
emit(state.copyWith(availableTags: event!.values));
|
||||
}
|
||||
}),
|
||||
);
|
||||
_subscriptions.add(
|
||||
_correspondentRepository.values.listen((event) {
|
||||
if (event?.hasLoaded ?? false) {
|
||||
emit(state.copyWith(
|
||||
availableCorrespondents: event!.values,
|
||||
));
|
||||
}
|
||||
}),
|
||||
);
|
||||
_subscriptions.add(
|
||||
_documentTypeRepository.values.listen((event) {
|
||||
if (event?.hasLoaded ?? false) {
|
||||
emit(state.copyWith(availableDocumentTypes: event!.values));
|
||||
}
|
||||
}),
|
||||
_labelRepository.subscribe(
|
||||
this,
|
||||
onChanged: (labels) {
|
||||
emit(state.copyWith(labels: labels));
|
||||
},
|
||||
);
|
||||
|
||||
refreshItemsInInboxCount(false);
|
||||
@@ -105,7 +75,7 @@ class InboxCubit extends HydratedCubit<InboxState>
|
||||
/// Fetches inbox tag ids and loads the inbox items (documents).
|
||||
///
|
||||
Future<void> loadInbox() async {
|
||||
final inboxTags = await _tagsRepository.findAll().then(
|
||||
final inboxTags = await _labelRepository.findAllTags().then(
|
||||
(tags) => tags.where((t) => t.isInboxTag ?? false).map((t) => t.id!),
|
||||
);
|
||||
|
||||
@@ -133,7 +103,7 @@ class InboxCubit extends HydratedCubit<InboxState>
|
||||
///
|
||||
Future<void> reloadInbox() async {
|
||||
emit(state.copyWith(hasLoaded: false, isLoading: true));
|
||||
final inboxTags = await _tagsRepository.findAll().then(
|
||||
final inboxTags = await _labelRepository.findAllTags().then(
|
||||
(tags) => tags.where((t) => t.isInboxTag ?? false).map((t) => t.id!),
|
||||
);
|
||||
|
||||
@@ -239,9 +209,7 @@ class InboxCubit extends HydratedCubit<InboxState>
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
for (var sub in _subscriptions) {
|
||||
sub.cancel();
|
||||
}
|
||||
_labelRepository.unsubscribe(this);
|
||||
return super.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,11 +4,7 @@ part of 'inbox_cubit.dart';
|
||||
class InboxState extends DocumentPagingState {
|
||||
final Iterable<int> inboxTags;
|
||||
|
||||
final Map<int, Tag> availableTags;
|
||||
|
||||
final Map<int, DocumentType> availableDocumentTypes;
|
||||
|
||||
final Map<int, Correspondent> availableCorrespondents;
|
||||
final LabelRepositoryState labels;
|
||||
|
||||
final int itemsInInboxCount;
|
||||
|
||||
@@ -22,10 +18,8 @@ class InboxState extends DocumentPagingState {
|
||||
super.filter = const DocumentFilter(),
|
||||
this.inboxTags = const [],
|
||||
this.isHintAcknowledged = false,
|
||||
this.availableTags = const {},
|
||||
this.availableDocumentTypes = const {},
|
||||
this.availableCorrespondents = const {},
|
||||
this.itemsInInboxCount = 0,
|
||||
this.labels = const LabelRepositoryState(),
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -37,10 +31,8 @@ class InboxState extends DocumentPagingState {
|
||||
inboxTags,
|
||||
documents,
|
||||
isHintAcknowledged,
|
||||
availableTags,
|
||||
availableDocumentTypes,
|
||||
availableCorrespondents,
|
||||
itemsInInboxCount,
|
||||
labels,
|
||||
];
|
||||
|
||||
InboxState copyWith({
|
||||
@@ -50,9 +42,7 @@ class InboxState extends DocumentPagingState {
|
||||
List<PagedSearchResult<DocumentModel>>? value,
|
||||
DocumentFilter? filter,
|
||||
bool? isHintAcknowledged,
|
||||
Map<int, Tag>? availableTags,
|
||||
Map<int, Correspondent>? availableCorrespondents,
|
||||
Map<int, DocumentType>? availableDocumentTypes,
|
||||
LabelRepositoryState? labels,
|
||||
Map<int, FieldSuggestions>? suggestions,
|
||||
int? itemsInInboxCount,
|
||||
}) {
|
||||
@@ -62,11 +52,7 @@ class InboxState extends DocumentPagingState {
|
||||
value: value ?? super.value,
|
||||
inboxTags: inboxTags ?? this.inboxTags,
|
||||
isHintAcknowledged: isHintAcknowledged ?? this.isHintAcknowledged,
|
||||
availableCorrespondents:
|
||||
availableCorrespondents ?? this.availableCorrespondents,
|
||||
availableDocumentTypes:
|
||||
availableDocumentTypes ?? this.availableDocumentTypes,
|
||||
availableTags: availableTags ?? this.availableTags,
|
||||
labels: labels ?? this.labels,
|
||||
filter: filter ?? super.filter,
|
||||
itemsInInboxCount: itemsInInboxCount ?? this.itemsInInboxCount,
|
||||
);
|
||||
|
||||
@@ -32,60 +32,98 @@ class _InboxItemState extends State<InboxItem> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () async {
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
DocumentDetailsRoute.routeName,
|
||||
arguments: DocumentDetailsRouteArguments(
|
||||
document: widget.document,
|
||||
isLabelClickable: false,
|
||||
return BlocBuilder<InboxCubit, InboxState>(
|
||||
builder: (context, state) {
|
||||
return GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () async {
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
DocumentDetailsRoute.routeName,
|
||||
arguments: DocumentDetailsRouteArguments(
|
||||
document: widget.document,
|
||||
isLabelClickable: false,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: SizedBox(
|
||||
height: 200,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Flexible(
|
||||
child: Row(
|
||||
children: [
|
||||
AspectRatio(
|
||||
aspectRatio: InboxItem.a4AspectRatio,
|
||||
child: DocumentPreview(
|
||||
document: widget.document,
|
||||
fit: BoxFit.cover,
|
||||
alignment: Alignment.topCenter,
|
||||
enableHero: false,
|
||||
),
|
||||
).padded(),
|
||||
Flexible(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildTitle().paddedOnly(left: 8, right: 8, top: 8),
|
||||
const Spacer(),
|
||||
_buildTextWithLeadingIcon(
|
||||
Icon(
|
||||
Icons.person_outline,
|
||||
size: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium
|
||||
?.fontSize,
|
||||
),
|
||||
LabelText<Correspondent>(
|
||||
label: state.labels.correspondents[
|
||||
widget.document.correspondent],
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
placeholder: "-",
|
||||
),
|
||||
).paddedSymmetrically(horizontal: 8),
|
||||
_buildTextWithLeadingIcon(
|
||||
Icon(
|
||||
Icons.description_outlined,
|
||||
size: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium
|
||||
?.fontSize,
|
||||
),
|
||||
LabelText<DocumentType>(
|
||||
label: state.labels.documentTypes[
|
||||
widget.document.documentType],
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
placeholder: "-",
|
||||
),
|
||||
).paddedSymmetrically(horizontal: 8),
|
||||
const Spacer(),
|
||||
TagsWidget(
|
||||
tags: widget.document.tags
|
||||
.map((e) => state.labels.tags[e]!)
|
||||
.toList(),
|
||||
isMultiLine: false,
|
||||
isClickable: false,
|
||||
showShortNames: true,
|
||||
dense: true,
|
||||
).paddedOnly(left: 8, bottom: 8),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 56,
|
||||
child: _buildActions(context),
|
||||
),
|
||||
],
|
||||
).paddedOnly(left: 8, top: 8, bottom: 8),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: SizedBox(
|
||||
height: 200,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Flexible(
|
||||
child: Row(
|
||||
children: [
|
||||
AspectRatio(
|
||||
aspectRatio: InboxItem.a4AspectRatio,
|
||||
child: DocumentPreview(
|
||||
document: widget.document,
|
||||
fit: BoxFit.cover,
|
||||
alignment: Alignment.topCenter,
|
||||
enableHero: false,
|
||||
),
|
||||
).padded(),
|
||||
Flexible(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildTitle().paddedOnly(left: 8, right: 8, top: 8),
|
||||
const Spacer(),
|
||||
_buildCorrespondent(context)
|
||||
.paddedSymmetrically(horizontal: 8),
|
||||
_buildDocumentType(context)
|
||||
.paddedSymmetrically(horizontal: 8),
|
||||
const Spacer(),
|
||||
_buildTags().paddedOnly(left: 8, bottom: 8),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 56,
|
||||
child: _buildActions(context),
|
||||
),
|
||||
],
|
||||
).paddedOnly(left: 8, top: 8, bottom: 8),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -211,44 +249,6 @@ class _InboxItemState extends State<InboxItem> {
|
||||
);
|
||||
}
|
||||
|
||||
TagsWidget _buildTags() {
|
||||
return TagsWidget(
|
||||
tagIds: widget.document.tags,
|
||||
isMultiLine: false,
|
||||
isClickable: false,
|
||||
showShortNames: true,
|
||||
dense: true,
|
||||
);
|
||||
}
|
||||
|
||||
Row _buildDocumentType(BuildContext context) {
|
||||
return _buildTextWithLeadingIcon(
|
||||
Icon(
|
||||
Icons.description_outlined,
|
||||
size: Theme.of(context).textTheme.bodyMedium?.fontSize,
|
||||
),
|
||||
LabelText<DocumentType>(
|
||||
id: widget.document.documentType,
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
placeholder: "-",
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Row _buildCorrespondent(BuildContext context) {
|
||||
return _buildTextWithLeadingIcon(
|
||||
Icon(
|
||||
Icons.person_outline,
|
||||
size: Theme.of(context).textTheme.bodyMedium?.fontSize,
|
||||
),
|
||||
LabelText<Correspondent>(
|
||||
id: widget.document.correspondent,
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
placeholder: "-",
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Text _buildTitle() {
|
||||
return Text(
|
||||
widget.document.title,
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/features/labels/cubit/label_cubit.dart';
|
||||
import 'package:paperless_mobile/features/labels/cubit/providers/correspondent_bloc_provider.dart';
|
||||
|
||||
class CorrespondentWidget extends StatelessWidget {
|
||||
final int? correspondentId;
|
||||
final Correspondent? correspondent;
|
||||
final void Function(int? id)? onSelected;
|
||||
final Color? textColor;
|
||||
final bool isClickable;
|
||||
@@ -13,7 +10,7 @@ class CorrespondentWidget extends StatelessWidget {
|
||||
|
||||
const CorrespondentWidget({
|
||||
Key? key,
|
||||
required this.correspondentId,
|
||||
required this.correspondent,
|
||||
this.textColor,
|
||||
this.isClickable = true,
|
||||
this.textStyle,
|
||||
@@ -22,25 +19,18 @@ class CorrespondentWidget extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CorrespondentBlocProvider(
|
||||
child: AbsorbPointer(
|
||||
absorbing: !isClickable,
|
||||
child:
|
||||
BlocBuilder<LabelCubit<Correspondent>, LabelState<Correspondent>>(
|
||||
builder: (context, state) {
|
||||
return GestureDetector(
|
||||
onTap: () => onSelected?.call(correspondentId!),
|
||||
child: Text(
|
||||
(state.getLabel(correspondentId)?.name) ?? "-",
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: (textStyle ?? Theme.of(context).textTheme.bodyMedium)
|
||||
?.copyWith(
|
||||
color: textColor ?? Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
return AbsorbPointer(
|
||||
absorbing: !isClickable,
|
||||
child: GestureDetector(
|
||||
onTap: () => onSelected?.call(correspondent?.id),
|
||||
child: Text(
|
||||
correspondent?.name ?? "-",
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style:
|
||||
(textStyle ?? Theme.of(context).textTheme.bodyMedium)?.copyWith(
|
||||
color: textColor ?? Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,68 +1,45 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||
import 'package:paperless_mobile/features/labels/cubit/label_cubit_mixin.dart';
|
||||
|
||||
part 'label_state.dart';
|
||||
part 'label_cubit.freezed.dart';
|
||||
|
||||
class LabelCubit<T extends Label> extends Cubit<LabelState<T>> {
|
||||
final LabelRepository<T> _repository;
|
||||
class LabelCubit extends Cubit<LabelState> with LabelCubitMixin<LabelState> {
|
||||
@override
|
||||
final LabelRepository labelRepository;
|
||||
|
||||
late StreamSubscription _subscription;
|
||||
|
||||
LabelCubit(LabelRepository<T> repository)
|
||||
: _repository = repository,
|
||||
super(LabelState(
|
||||
isLoaded: repository.isInitialized,
|
||||
labels: repository.current?.values ?? {},
|
||||
)) {
|
||||
_subscription = _repository.values.listen(
|
||||
(event) {
|
||||
if (event == null) {
|
||||
emit(LabelState());
|
||||
}
|
||||
emit(
|
||||
LabelState(isLoaded: event!.hasLoaded, labels: event.values ?? {}));
|
||||
LabelCubit(this.labelRepository) : super(const LabelState()) {
|
||||
labelRepository.subscribe(
|
||||
this,
|
||||
onChanged: (labels) {
|
||||
emit(state.copyWith(
|
||||
correspondents: labels.correspondents,
|
||||
documentTypes: labels.documentTypes,
|
||||
storagePaths: labels.storagePaths,
|
||||
tags: labels.tags,
|
||||
));
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
///
|
||||
/// Adds [item] to the current state. A new state is automatically pushed
|
||||
/// due to the subscription to the repository, which updates the state on
|
||||
/// operation.
|
||||
///
|
||||
Future<T> add(T item) async {
|
||||
assert(item.id == null);
|
||||
final addedItem = await _repository.create(item);
|
||||
return addedItem;
|
||||
}
|
||||
|
||||
Future<void> reload() {
|
||||
return _repository.findAll();
|
||||
}
|
||||
|
||||
Future<T> replace(T item) async {
|
||||
assert(item.id != null);
|
||||
final updatedItem = await _repository.update(item);
|
||||
return updatedItem;
|
||||
}
|
||||
|
||||
Future<void> remove(T item) async {
|
||||
assert(item.id != null);
|
||||
if (state.labels.containsKey(item.id)) {
|
||||
await _repository.delete(item);
|
||||
}
|
||||
}
|
||||
|
||||
void reset() {
|
||||
emit(LabelState(isLoaded: false, labels: {}));
|
||||
@override
|
||||
Future<void> close() {
|
||||
labelRepository.unsubscribe(this);
|
||||
return super.close();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
_subscription.cancel();
|
||||
return super.close();
|
||||
}
|
||||
Map<int, Correspondent> get correspondents => state.correspondents;
|
||||
|
||||
@override
|
||||
Map<int, DocumentType> get documentTypes => state.documentTypes;
|
||||
|
||||
@override
|
||||
Map<int, StoragePath> get storagePaths => state.storagePaths;
|
||||
|
||||
@override
|
||||
Map<int, Tag> get tags => state.tags;
|
||||
}
|
||||
|
||||
237
lib/features/labels/cubit/label_cubit.freezed.dart
Normal file
237
lib/features/labels/cubit/label_cubit.freezed.dart
Normal file
@@ -0,0 +1,237 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'label_cubit.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
|
||||
|
||||
/// @nodoc
|
||||
mixin _$LabelState {
|
||||
Map<int, Correspondent> get correspondents =>
|
||||
throw _privateConstructorUsedError;
|
||||
Map<int, DocumentType> get documentTypes =>
|
||||
throw _privateConstructorUsedError;
|
||||
Map<int, Tag> get tags => throw _privateConstructorUsedError;
|
||||
Map<int, StoragePath> get storagePaths => throw _privateConstructorUsedError;
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
$LabelStateCopyWith<LabelState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $LabelStateCopyWith<$Res> {
|
||||
factory $LabelStateCopyWith(
|
||||
LabelState value, $Res Function(LabelState) then) =
|
||||
_$LabelStateCopyWithImpl<$Res, LabelState>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{Map<int, Correspondent> correspondents,
|
||||
Map<int, DocumentType> documentTypes,
|
||||
Map<int, Tag> tags,
|
||||
Map<int, StoragePath> storagePaths});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$LabelStateCopyWithImpl<$Res, $Val extends LabelState>
|
||||
implements $LabelStateCopyWith<$Res> {
|
||||
_$LabelStateCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? correspondents = null,
|
||||
Object? documentTypes = null,
|
||||
Object? tags = null,
|
||||
Object? storagePaths = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
correspondents: null == correspondents
|
||||
? _value.correspondents
|
||||
: correspondents // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, Correspondent>,
|
||||
documentTypes: null == documentTypes
|
||||
? _value.documentTypes
|
||||
: documentTypes // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, DocumentType>,
|
||||
tags: null == tags
|
||||
? _value.tags
|
||||
: tags // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, Tag>,
|
||||
storagePaths: null == storagePaths
|
||||
? _value.storagePaths
|
||||
: storagePaths // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, StoragePath>,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$_LabelStateCopyWith<$Res>
|
||||
implements $LabelStateCopyWith<$Res> {
|
||||
factory _$$_LabelStateCopyWith(
|
||||
_$_LabelState value, $Res Function(_$_LabelState) then) =
|
||||
__$$_LabelStateCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{Map<int, Correspondent> correspondents,
|
||||
Map<int, DocumentType> documentTypes,
|
||||
Map<int, Tag> tags,
|
||||
Map<int, StoragePath> storagePaths});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$_LabelStateCopyWithImpl<$Res>
|
||||
extends _$LabelStateCopyWithImpl<$Res, _$_LabelState>
|
||||
implements _$$_LabelStateCopyWith<$Res> {
|
||||
__$$_LabelStateCopyWithImpl(
|
||||
_$_LabelState _value, $Res Function(_$_LabelState) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? correspondents = null,
|
||||
Object? documentTypes = null,
|
||||
Object? tags = null,
|
||||
Object? storagePaths = null,
|
||||
}) {
|
||||
return _then(_$_LabelState(
|
||||
correspondents: null == correspondents
|
||||
? _value._correspondents
|
||||
: correspondents // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, Correspondent>,
|
||||
documentTypes: null == documentTypes
|
||||
? _value._documentTypes
|
||||
: documentTypes // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, DocumentType>,
|
||||
tags: null == tags
|
||||
? _value._tags
|
||||
: tags // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, Tag>,
|
||||
storagePaths: null == storagePaths
|
||||
? _value._storagePaths
|
||||
: storagePaths // ignore: cast_nullable_to_non_nullable
|
||||
as Map<int, StoragePath>,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$_LabelState implements _LabelState {
|
||||
const _$_LabelState(
|
||||
{final Map<int, Correspondent> correspondents = const {},
|
||||
final Map<int, DocumentType> documentTypes = const {},
|
||||
final Map<int, Tag> tags = const {},
|
||||
final Map<int, StoragePath> storagePaths = const {}})
|
||||
: _correspondents = correspondents,
|
||||
_documentTypes = documentTypes,
|
||||
_tags = tags,
|
||||
_storagePaths = storagePaths;
|
||||
|
||||
final Map<int, Correspondent> _correspondents;
|
||||
@override
|
||||
@JsonKey()
|
||||
Map<int, Correspondent> get correspondents {
|
||||
if (_correspondents is EqualUnmodifiableMapView) return _correspondents;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableMapView(_correspondents);
|
||||
}
|
||||
|
||||
final Map<int, DocumentType> _documentTypes;
|
||||
@override
|
||||
@JsonKey()
|
||||
Map<int, DocumentType> get documentTypes {
|
||||
if (_documentTypes is EqualUnmodifiableMapView) return _documentTypes;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableMapView(_documentTypes);
|
||||
}
|
||||
|
||||
final Map<int, Tag> _tags;
|
||||
@override
|
||||
@JsonKey()
|
||||
Map<int, Tag> get tags {
|
||||
if (_tags is EqualUnmodifiableMapView) return _tags;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableMapView(_tags);
|
||||
}
|
||||
|
||||
final Map<int, StoragePath> _storagePaths;
|
||||
@override
|
||||
@JsonKey()
|
||||
Map<int, StoragePath> get storagePaths {
|
||||
if (_storagePaths is EqualUnmodifiableMapView) return _storagePaths;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableMapView(_storagePaths);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'LabelState(correspondents: $correspondents, documentTypes: $documentTypes, tags: $tags, storagePaths: $storagePaths)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(dynamic other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$_LabelState &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._correspondents, _correspondents) &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._documentTypes, _documentTypes) &&
|
||||
const DeepCollectionEquality().equals(other._tags, _tags) &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._storagePaths, _storagePaths));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
const DeepCollectionEquality().hash(_correspondents),
|
||||
const DeepCollectionEquality().hash(_documentTypes),
|
||||
const DeepCollectionEquality().hash(_tags),
|
||||
const DeepCollectionEquality().hash(_storagePaths));
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$_LabelStateCopyWith<_$_LabelState> get copyWith =>
|
||||
__$$_LabelStateCopyWithImpl<_$_LabelState>(this, _$identity);
|
||||
}
|
||||
|
||||
abstract class _LabelState implements LabelState {
|
||||
const factory _LabelState(
|
||||
{final Map<int, Correspondent> correspondents,
|
||||
final Map<int, DocumentType> documentTypes,
|
||||
final Map<int, Tag> tags,
|
||||
final Map<int, StoragePath> storagePaths}) = _$_LabelState;
|
||||
|
||||
@override
|
||||
Map<int, Correspondent> get correspondents;
|
||||
@override
|
||||
Map<int, DocumentType> get documentTypes;
|
||||
@override
|
||||
Map<int, Tag> get tags;
|
||||
@override
|
||||
Map<int, StoragePath> get storagePaths;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$_LabelStateCopyWith<_$_LabelState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
104
lib/features/labels/cubit/label_cubit_mixin.dart
Normal file
104
lib/features/labels/cubit/label_cubit_mixin.dart
Normal file
@@ -0,0 +1,104 @@
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||
|
||||
mixin LabelCubitMixin<T> on BlocBase<T> {
|
||||
LabelRepository get labelRepository;
|
||||
|
||||
Map<int, Correspondent> get correspondents;
|
||||
Map<int, DocumentType> get documentTypes;
|
||||
Map<int, Tag> get tags;
|
||||
Map<int, StoragePath> get storagePaths;
|
||||
|
||||
Future<Correspondent> addCorrespondent(Correspondent item) async {
|
||||
assert(item.id == null);
|
||||
final addedItem = await labelRepository.createCorrespondent(item);
|
||||
return addedItem;
|
||||
}
|
||||
|
||||
Future<void> reloadCorrespondents() {
|
||||
return labelRepository.findAllCorrespondents();
|
||||
}
|
||||
|
||||
Future<Correspondent> replaceCorrespondent(Correspondent item) async {
|
||||
assert(item.id != null);
|
||||
final updatedItem = await labelRepository.updateCorrespondent(item);
|
||||
return updatedItem;
|
||||
}
|
||||
|
||||
Future<void> removeCorrespondent(Correspondent item) async {
|
||||
assert(item.id != null);
|
||||
if (correspondents.containsKey(item.id)) {
|
||||
await labelRepository.deleteCorrespondent(item);
|
||||
}
|
||||
}
|
||||
|
||||
Future<DocumentType> addDocumentType(DocumentType item) async {
|
||||
assert(item.id == null);
|
||||
final addedItem = await labelRepository.createDocumentType(item);
|
||||
return addedItem;
|
||||
}
|
||||
|
||||
Future<void> reloadDocumentTypes() {
|
||||
return labelRepository.findAllDocumentTypes();
|
||||
}
|
||||
|
||||
Future<DocumentType> replaceDocumentType(DocumentType item) async {
|
||||
assert(item.id != null);
|
||||
final updatedItem = await labelRepository.updateDocumentType(item);
|
||||
return updatedItem;
|
||||
}
|
||||
|
||||
Future<void> removeDocumentType(DocumentType item) async {
|
||||
assert(item.id != null);
|
||||
if (documentTypes.containsKey(item.id)) {
|
||||
await labelRepository.deleteDocumentType(item);
|
||||
}
|
||||
}
|
||||
|
||||
Future<StoragePath> addStoragePath(StoragePath item) async {
|
||||
assert(item.id == null);
|
||||
final addedItem = await labelRepository.createStoragePath(item);
|
||||
return addedItem;
|
||||
}
|
||||
|
||||
Future<void> reloadStoragePaths() {
|
||||
return labelRepository.findAllStoragePaths();
|
||||
}
|
||||
|
||||
Future<StoragePath> replaceStoragePath(StoragePath item) async {
|
||||
assert(item.id != null);
|
||||
final updatedItem = await labelRepository.updateStoragePath(item);
|
||||
return updatedItem;
|
||||
}
|
||||
|
||||
Future<void> removeStoragePath(StoragePath item) async {
|
||||
assert(item.id != null);
|
||||
if (storagePaths.containsKey(item.id)) {
|
||||
await labelRepository.deleteStoragePath(item);
|
||||
}
|
||||
}
|
||||
|
||||
Future<Tag> addTag(Tag item) async {
|
||||
assert(item.id == null);
|
||||
final addedItem = await labelRepository.createTag(item);
|
||||
return addedItem;
|
||||
}
|
||||
|
||||
Future<void> reloadTags() {
|
||||
return labelRepository.findAllTags();
|
||||
}
|
||||
|
||||
Future<Tag> replaceTag(Tag item) async {
|
||||
assert(item.id != null);
|
||||
final updatedItem = await labelRepository.updateTag(item);
|
||||
return updatedItem;
|
||||
}
|
||||
|
||||
Future<void> removeTag(Tag item) async {
|
||||
assert(item.id != null);
|
||||
if (tags.containsKey(item.id)) {
|
||||
await labelRepository.deleteTag(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,11 @@
|
||||
part of 'label_cubit.dart';
|
||||
|
||||
class LabelState<T extends Label> {
|
||||
LabelState.initial() : this(isLoaded: false, labels: {});
|
||||
final bool isLoaded;
|
||||
final Map<int, T> labels;
|
||||
|
||||
LabelState({
|
||||
this.isLoaded = false,
|
||||
this.labels = const {},
|
||||
});
|
||||
|
||||
T? getLabel(int? key) {
|
||||
if (isLoaded) {
|
||||
return labels[key];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@freezed
|
||||
class LabelState with _$LabelState {
|
||||
const factory LabelState({
|
||||
@Default({}) Map<int, Correspondent> correspondents,
|
||||
@Default({}) Map<int, DocumentType> documentTypes,
|
||||
@Default({}) Map<int, Tag> tags,
|
||||
@Default({}) Map<int, StoragePath> storagePaths,
|
||||
}) = _LabelState;
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||
import 'package:paperless_mobile/core/repository/state/impl/correspondent_repository_state.dart';
|
||||
import 'package:paperless_mobile/features/labels/cubit/label_cubit.dart';
|
||||
|
||||
class CorrespondentBlocProvider extends StatelessWidget {
|
||||
final Widget child;
|
||||
const CorrespondentBlocProvider({
|
||||
super.key,
|
||||
required this.child,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => LabelCubit<Correspondent>(
|
||||
context.read<LabelRepository<Correspondent>>(),
|
||||
),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
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:paperless_mobile/features/labels/cubit/label_cubit.dart';
|
||||
|
||||
class DocumentTypeBlocProvider extends StatelessWidget {
|
||||
final Widget child;
|
||||
const DocumentTypeBlocProvider({super.key, required this.child});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => LabelCubit<DocumentType>(
|
||||
context.read<LabelRepository<DocumentType>>(),
|
||||
),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||
import 'package:paperless_mobile/core/repository/state/impl/correspondent_repository_state.dart';
|
||||
import 'package:paperless_mobile/core/repository/state/impl/document_type_repository_state.dart';
|
||||
import 'package:paperless_mobile/core/repository/state/impl/storage_path_repository_state.dart';
|
||||
import 'package:paperless_mobile/core/repository/state/impl/tag_repository_state.dart';
|
||||
import 'package:paperless_mobile/features/labels/cubit/label_cubit.dart';
|
||||
|
||||
class LabelsBlocProvider extends StatelessWidget {
|
||||
final Widget child;
|
||||
const LabelsBlocProvider({super.key, required this.child});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MultiBlocProvider(
|
||||
providers: [
|
||||
BlocProvider<LabelCubit<StoragePath>>(
|
||||
create: (context) => LabelCubit<StoragePath>(
|
||||
context.read<LabelRepository<StoragePath>>(),
|
||||
),
|
||||
),
|
||||
BlocProvider<LabelCubit<Correspondent>>(
|
||||
create: (context) => LabelCubit<Correspondent>(
|
||||
context.read<LabelRepository<Correspondent>>(),
|
||||
),
|
||||
),
|
||||
BlocProvider<LabelCubit<DocumentType>>(
|
||||
create: (context) => LabelCubit<DocumentType>(
|
||||
context.read<LabelRepository<DocumentType>>(),
|
||||
),
|
||||
),
|
||||
BlocProvider<LabelCubit<Tag>>(
|
||||
create: (context) => LabelCubit<Tag>(
|
||||
context.read<LabelRepository<Tag>>(),
|
||||
),
|
||||
),
|
||||
],
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
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:paperless_mobile/features/labels/cubit/label_cubit.dart';
|
||||
|
||||
class StoragePathBlocProvider extends StatelessWidget {
|
||||
final Widget child;
|
||||
const StoragePathBlocProvider({super.key, required this.child});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => LabelCubit<StoragePath>(
|
||||
context.read<LabelRepository<StoragePath>>(),
|
||||
),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||
import 'package:paperless_mobile/core/repository/state/impl/tag_repository_state.dart';
|
||||
import 'package:paperless_mobile/features/labels/cubit/label_cubit.dart';
|
||||
|
||||
class TagBlocProvider extends StatelessWidget {
|
||||
final Widget child;
|
||||
const TagBlocProvider({super.key, required this.child});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => LabelCubit<Tag>(
|
||||
context.read<LabelRepository<Tag>>(),
|
||||
),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,14 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/features/labels/cubit/label_cubit.dart';
|
||||
import 'package:paperless_mobile/features/labels/cubit/providers/document_type_bloc_provider.dart';
|
||||
|
||||
class DocumentTypeWidget extends StatelessWidget {
|
||||
final int? documentTypeId;
|
||||
final DocumentType? documentType;
|
||||
final bool isClickable;
|
||||
final TextStyle? textStyle;
|
||||
final void Function(int? id)? onSelected;
|
||||
const DocumentTypeWidget({
|
||||
Key? key,
|
||||
required this.documentTypeId,
|
||||
required this.documentType,
|
||||
this.isClickable = true,
|
||||
this.textStyle,
|
||||
this.onSelected,
|
||||
@@ -19,23 +16,16 @@ class DocumentTypeWidget extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DocumentTypeBlocProvider(
|
||||
child: AbsorbPointer(
|
||||
absorbing: !isClickable,
|
||||
child: GestureDetector(
|
||||
onTap: () => onSelected?.call(documentTypeId),
|
||||
child:
|
||||
BlocBuilder<LabelCubit<DocumentType>, LabelState<DocumentType>>(
|
||||
builder: (context, state) {
|
||||
return Text(
|
||||
state.labels[documentTypeId]?.toString() ?? "-",
|
||||
style: (textStyle ?? Theme.of(context).textTheme.bodyMedium)
|
||||
?.copyWith(color: Theme.of(context).colorScheme.tertiary),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 1,
|
||||
);
|
||||
},
|
||||
),
|
||||
return AbsorbPointer(
|
||||
absorbing: !isClickable,
|
||||
child: GestureDetector(
|
||||
onTap: () => onSelected?.call(documentType?.id),
|
||||
child: Text(
|
||||
documentType?.toString() ?? "-",
|
||||
style: (textStyle ?? Theme.of(context).textTheme.bodyMedium)
|
||||
?.copyWith(color: Theme.of(context).colorScheme.tertiary),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 1,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/features/labels/cubit/label_cubit.dart';
|
||||
import 'package:paperless_mobile/features/labels/cubit/providers/storage_path_bloc_provider.dart';
|
||||
|
||||
class StoragePathWidget extends StatelessWidget {
|
||||
final int? pathId;
|
||||
final StoragePath? storagePath;
|
||||
final Color? textColor;
|
||||
final bool isClickable;
|
||||
final void Function(int? id)? onSelected;
|
||||
|
||||
const StoragePathWidget({
|
||||
Key? key,
|
||||
this.pathId,
|
||||
this.storagePath,
|
||||
this.textColor,
|
||||
this.isClickable = true,
|
||||
this.onSelected,
|
||||
@@ -20,23 +17,17 @@ class StoragePathWidget extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return StoragePathBlocProvider(
|
||||
child: AbsorbPointer(
|
||||
absorbing: !isClickable,
|
||||
child: BlocBuilder<LabelCubit<StoragePath>, LabelState<StoragePath>>(
|
||||
builder: (context, state) {
|
||||
return GestureDetector(
|
||||
onTap: () => onSelected?.call(pathId),
|
||||
child: Text(
|
||||
state.getLabel(pathId)?.name ?? "-",
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
color: textColor ?? Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
return AbsorbPointer(
|
||||
absorbing: !isClickable,
|
||||
child: GestureDetector(
|
||||
onTap: () => onSelected?.call(storagePath?.id),
|
||||
child: Text(
|
||||
storagePath?.name ?? "-",
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
color: textColor ?? Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -6,7 +6,6 @@ import 'package:flutter_form_builder/flutter_form_builder.dart';
|
||||
import 'package:flutter_typeahead/flutter_typeahead.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||
import 'package:paperless_mobile/core/repository/state/impl/tag_repository_state.dart';
|
||||
import 'package:paperless_mobile/core/workarounds/colored_chip.dart';
|
||||
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
|
||||
import 'package:paperless_mobile/features/edit_label/view/impl/add_tag_page.dart';
|
||||
@@ -21,6 +20,8 @@ class TagFormField extends StatefulWidget {
|
||||
final bool excludeAllowed;
|
||||
final Map<int, Tag> selectableOptions;
|
||||
final Widget? suggestions;
|
||||
final String? labelText;
|
||||
final String? hintText;
|
||||
|
||||
const TagFormField({
|
||||
super.key,
|
||||
@@ -32,6 +33,8 @@ class TagFormField extends StatefulWidget {
|
||||
this.excludeAllowed = true,
|
||||
required this.selectableOptions,
|
||||
this.suggestions,
|
||||
this.labelText,
|
||||
this.hintText,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -94,8 +97,8 @@ class _TagFormFieldState extends State<TagFormField> {
|
||||
Icons.label_outline,
|
||||
),
|
||||
suffixIcon: _buildSuffixIcon(context, field),
|
||||
labelText: S.of(context)!.tags,
|
||||
hintText: S.of(context)!.filterTags,
|
||||
labelText: widget.labelText ?? S.of(context)!.tags,
|
||||
hintText: widget.hintText ?? S.of(context)!.filterTags,
|
||||
),
|
||||
controller: _textEditingController,
|
||||
),
|
||||
@@ -240,8 +243,8 @@ class _TagFormFieldState extends State<TagFormField> {
|
||||
void _onAddTag(BuildContext context, FormFieldState<TagsQuery> field) async {
|
||||
final Tag? tag = await Navigator.of(context).push<Tag>(
|
||||
MaterialPageRoute(
|
||||
builder: (_) => RepositoryProvider(
|
||||
create: (context) => context.read<LabelRepository<Tag>>(),
|
||||
builder: (_) => RepositoryProvider.value(
|
||||
value: context.read<LabelRepository>(),
|
||||
child: AddTagPage(initialValue: _textEditingController.text),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/features/labels/cubit/label_cubit.dart';
|
||||
import 'package:paperless_mobile/features/labels/cubit/providers/tag_bloc_provider.dart';
|
||||
import 'package:paperless_mobile/features/labels/tags/view/widgets/tag_widget.dart';
|
||||
|
||||
class TagsWidget extends StatelessWidget {
|
||||
final Iterable<int> tagIds;
|
||||
final List<Tag> tags;
|
||||
final bool isMultiLine;
|
||||
final void Function(int tagId)? onTagSelected;
|
||||
final bool isClickable;
|
||||
@@ -15,7 +12,7 @@ class TagsWidget extends StatelessWidget {
|
||||
|
||||
const TagsWidget({
|
||||
Key? key,
|
||||
required this.tagIds,
|
||||
required this.tags,
|
||||
this.isMultiLine = true,
|
||||
this.isClickable = true,
|
||||
this.onTagSelected,
|
||||
@@ -25,36 +22,33 @@ class TagsWidget extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return TagBlocProvider(
|
||||
child: BlocBuilder<LabelCubit<Tag>, LabelState<Tag>>(
|
||||
builder: (context, state) {
|
||||
final children = tagIds
|
||||
.where((id) => state.labels.containsKey(id))
|
||||
.map(
|
||||
(id) => TagWidget(
|
||||
tag: state.getLabel(id)!,
|
||||
isClickable: isClickable,
|
||||
onSelected: () => onTagSelected?.call(id),
|
||||
showShortName: showShortNames,
|
||||
dense: dense,
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
if (isMultiLine) {
|
||||
return Wrap(
|
||||
runAlignment: WrapAlignment.start,
|
||||
children: children,
|
||||
runSpacing: 4,
|
||||
spacing: 4,
|
||||
);
|
||||
} else {
|
||||
return SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Row(children: children),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
return Builder(
|
||||
builder: (context) {
|
||||
final children = tags
|
||||
.map(
|
||||
(tag) => TagWidget(
|
||||
tag: tag,
|
||||
isClickable: isClickable,
|
||||
onSelected: () => onTagSelected?.call(tag.id!),
|
||||
showShortName: showShortNames,
|
||||
dense: dense,
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
if (isMultiLine) {
|
||||
return Wrap(
|
||||
runAlignment: WrapAlignment.start,
|
||||
children: children,
|
||||
runSpacing: 4,
|
||||
spacing: 4,
|
||||
);
|
||||
} else {
|
||||
return SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Row(children: children),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import 'package:paperless_mobile/core/delegate/customizable_sliver_persistent_he
|
||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||
import 'package:paperless_mobile/core/widgets/material/search/colored_tab_bar.dart';
|
||||
import 'package:paperless_mobile/features/app_drawer/view/app_drawer.dart';
|
||||
import 'package:paperless_mobile/features/document_details/view/pages/document_details_page.dart';
|
||||
import 'package:paperless_mobile/features/document_search/view/sliver_search_bar.dart';
|
||||
import 'package:paperless_mobile/features/edit_label/view/impl/add_correspondent_page.dart';
|
||||
import 'package:paperless_mobile/features/edit_label/view/impl/add_document_type_page.dart';
|
||||
@@ -17,6 +16,7 @@ import 'package:paperless_mobile/features/edit_label/view/impl/edit_document_typ
|
||||
import 'package:paperless_mobile/features/edit_label/view/impl/edit_storage_path_page.dart';
|
||||
import 'package:paperless_mobile/features/edit_label/view/impl/edit_tag_page.dart';
|
||||
import 'package:paperless_mobile/features/labels/cubit/label_cubit.dart';
|
||||
import 'package:paperless_mobile/features/labels/cubit/label_cubit_mixin.dart';
|
||||
import 'package:paperless_mobile/features/labels/view/widgets/label_tab_view.dart';
|
||||
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||
|
||||
@@ -141,12 +141,12 @@ class _LabelsPageState extends State<LabelsPage>
|
||||
notificationPredicate: (notification) =>
|
||||
connectedState.isConnected,
|
||||
onRefresh: () => [
|
||||
context.read<LabelCubit<Correspondent>>(),
|
||||
context.read<LabelCubit<DocumentType>>(),
|
||||
context.read<LabelCubit<Tag>>(),
|
||||
context.read<LabelCubit<StoragePath>>(),
|
||||
context.read<LabelCubit>().reloadCorrespondents,
|
||||
context.read<LabelCubit>().reloadDocumentTypes,
|
||||
context.read<LabelCubit>().reloadTags,
|
||||
context.read<LabelCubit>().reloadStoragePaths,
|
||||
][_currentIndex]
|
||||
.reload(),
|
||||
.call(),
|
||||
child: TabBarView(
|
||||
controller: _tabController,
|
||||
children: [
|
||||
@@ -157,6 +157,10 @@ class _LabelsPageState extends State<LabelsPage>
|
||||
SliverOverlapInjector(handle: searchBarHandle),
|
||||
SliverOverlapInjector(handle: tabBarHandle),
|
||||
LabelTabView<Correspondent>(
|
||||
labels: context
|
||||
.watch<LabelCubit>()
|
||||
.state
|
||||
.correspondents,
|
||||
filterBuilder: (label) => DocumentFilter(
|
||||
correspondent:
|
||||
IdQueryParameter.fromId(label.id),
|
||||
@@ -180,6 +184,10 @@ class _LabelsPageState extends State<LabelsPage>
|
||||
SliverOverlapInjector(handle: searchBarHandle),
|
||||
SliverOverlapInjector(handle: tabBarHandle),
|
||||
LabelTabView<DocumentType>(
|
||||
labels: context
|
||||
.watch<LabelCubit>()
|
||||
.state
|
||||
.documentTypes,
|
||||
filterBuilder: (label) => DocumentFilter(
|
||||
documentType:
|
||||
IdQueryParameter.fromId(label.id),
|
||||
@@ -203,6 +211,8 @@ class _LabelsPageState extends State<LabelsPage>
|
||||
SliverOverlapInjector(handle: searchBarHandle),
|
||||
SliverOverlapInjector(handle: tabBarHandle),
|
||||
LabelTabView<Tag>(
|
||||
labels:
|
||||
context.watch<LabelCubit>().state.tags,
|
||||
filterBuilder: (label) => DocumentFilter(
|
||||
tags: IdsTagsQuery.fromIds([label.id!]),
|
||||
pageSize: label.documentCount ?? 0,
|
||||
@@ -234,6 +244,10 @@ class _LabelsPageState extends State<LabelsPage>
|
||||
SliverOverlapInjector(handle: searchBarHandle),
|
||||
SliverOverlapInjector(handle: tabBarHandle),
|
||||
LabelTabView<StoragePath>(
|
||||
labels: context
|
||||
.watch<LabelCubit>()
|
||||
.state
|
||||
.storagePaths,
|
||||
onEdit: _openEditStoragePathPage,
|
||||
filterBuilder: (label) => DocumentFilter(
|
||||
storagePath:
|
||||
@@ -267,8 +281,8 @@ class _LabelsPageState extends State<LabelsPage>
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (_) => RepositoryProvider(
|
||||
create: (context) => context.read<LabelRepository<Correspondent>>(),
|
||||
builder: (_) => RepositoryProvider.value(
|
||||
value: context.read<LabelRepository>(),
|
||||
child: EditCorrespondentPage(correspondent: correspondent),
|
||||
),
|
||||
),
|
||||
@@ -279,8 +293,8 @@ class _LabelsPageState extends State<LabelsPage>
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (_) => RepositoryProvider(
|
||||
create: (context) => context.read<LabelRepository<DocumentType>>(),
|
||||
builder: (_) => RepositoryProvider.value(
|
||||
value: context.read<LabelRepository>(),
|
||||
child: EditDocumentTypePage(documentType: docType),
|
||||
),
|
||||
),
|
||||
@@ -291,8 +305,8 @@ class _LabelsPageState extends State<LabelsPage>
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (_) => RepositoryProvider(
|
||||
create: (context) => context.read<LabelRepository<Tag>>(),
|
||||
builder: (_) => RepositoryProvider.value(
|
||||
value: context.read<LabelRepository>(),
|
||||
child: EditTagPage(tag: tag),
|
||||
),
|
||||
),
|
||||
@@ -303,8 +317,8 @@ class _LabelsPageState extends State<LabelsPage>
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (_) => RepositoryProvider(
|
||||
create: (context) => context.read<LabelRepository<StoragePath>>(),
|
||||
builder: (_) => RepositoryProvider.value(
|
||||
value: context.read<LabelRepository>(),
|
||||
child: EditStoragePathPage(
|
||||
storagePath: path,
|
||||
),
|
||||
@@ -317,8 +331,8 @@ class _LabelsPageState extends State<LabelsPage>
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (_) => RepositoryProvider(
|
||||
create: (context) => context.read<LabelRepository<Correspondent>>(),
|
||||
builder: (_) => RepositoryProvider.value(
|
||||
value: context.read<LabelRepository>(),
|
||||
child: const AddCorrespondentPage(),
|
||||
),
|
||||
),
|
||||
@@ -329,8 +343,8 @@ class _LabelsPageState extends State<LabelsPage>
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (_) => RepositoryProvider(
|
||||
create: (context) => context.read<LabelRepository<DocumentType>>(),
|
||||
builder: (_) => RepositoryProvider.value(
|
||||
value: context.read<LabelRepository>(),
|
||||
child: const AddDocumentTypePage(),
|
||||
),
|
||||
),
|
||||
@@ -341,8 +355,8 @@ class _LabelsPageState extends State<LabelsPage>
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (_) => RepositoryProvider(
|
||||
create: (context) => context.read<LabelRepository<Tag>>(),
|
||||
builder: (_) => RepositoryProvider.value(
|
||||
value: context.read<LabelRepository>(),
|
||||
child: const AddTagPage(),
|
||||
),
|
||||
),
|
||||
@@ -353,8 +367,8 @@ class _LabelsPageState extends State<LabelsPage>
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (_) => RepositoryProvider(
|
||||
create: (context) => context.read<LabelRepository<StoragePath>>(),
|
||||
builder: (_) => RepositoryProvider.value(
|
||||
value: context.read<LabelRepository>(),
|
||||
child: const AddStoragePathPage(),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -51,6 +51,7 @@ class LabelItem<T extends Label> extends StatelessWidget {
|
||||
filter,
|
||||
context.read(),
|
||||
context.read(),
|
||||
context.read(),
|
||||
),
|
||||
child: const LinkedDocumentsPage(),
|
||||
),
|
||||
|
||||
@@ -3,12 +3,12 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/bloc/connectivity_cubit.dart';
|
||||
import 'package:paperless_mobile/core/translation/matching_algorithm_localization_mapper.dart';
|
||||
import 'package:paperless_mobile/features/labels/cubit/label_cubit.dart';
|
||||
import 'package:paperless_mobile/core/widgets/offline_widget.dart';
|
||||
import 'package:paperless_mobile/features/labels/view/widgets/label_item.dart';
|
||||
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
|
||||
|
||||
class LabelTabView<T extends Label> extends StatelessWidget {
|
||||
final Map<int, T> labels;
|
||||
final DocumentFilter Function(Label) filterBuilder;
|
||||
final void Function(T) onEdit;
|
||||
final void Function() onAddNew;
|
||||
@@ -32,69 +32,61 @@ class LabelTabView<T extends Label> extends StatelessWidget {
|
||||
required this.emptyStateDescription,
|
||||
required this.onAddNew,
|
||||
required this.emptyStateActionButtonLabel,
|
||||
required this.labels,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => LabelCubit<T>(
|
||||
context.read(),
|
||||
),
|
||||
child: BlocBuilder<ConnectivityCubit, ConnectivityState>(
|
||||
builder: (context, connectivityState) {
|
||||
return BlocBuilder<LabelCubit<T>, LabelState<T>>(
|
||||
builder: (context, state) {
|
||||
if (!state.isLoaded && !connectivityState.isConnected) {
|
||||
return const OfflineWidget();
|
||||
}
|
||||
final labels = state.labels.values.toList()..sort();
|
||||
if (labels.isEmpty) {
|
||||
return SliverFillRemaining(
|
||||
child: Center(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
emptyStateDescription,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
TextButton(
|
||||
onPressed: onAddNew,
|
||||
child: Text(emptyStateActionButtonLabel),
|
||||
),
|
||||
].padded(),
|
||||
),
|
||||
return BlocBuilder<ConnectivityCubit, ConnectivityState>(
|
||||
builder: (context, connectivityState) {
|
||||
if (!connectivityState.isConnected) {
|
||||
return const OfflineWidget();
|
||||
}
|
||||
final sortedLabels = labels.values.toList()..sort();
|
||||
if (labels.isEmpty) {
|
||||
return SliverFillRemaining(
|
||||
child: Center(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
emptyStateDescription,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
);
|
||||
}
|
||||
return SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
final l = labels.elementAt(index);
|
||||
return LabelItem<T>(
|
||||
name: l.name,
|
||||
content: contentBuilder?.call(l) ??
|
||||
Text(
|
||||
translateMatchingAlgorithmName(
|
||||
context, l.matchingAlgorithm) +
|
||||
((l.match?.isNotEmpty ?? false)
|
||||
? ": ${l.match}"
|
||||
: ""),
|
||||
maxLines: 2,
|
||||
),
|
||||
onOpenEditPage: onEdit,
|
||||
filterBuilder: filterBuilder,
|
||||
leading: leadingBuilder?.call(l),
|
||||
label: l,
|
||||
);
|
||||
},
|
||||
childCount: labels.length,
|
||||
),
|
||||
TextButton(
|
||||
onPressed: onAddNew,
|
||||
child: Text(emptyStateActionButtonLabel),
|
||||
),
|
||||
].padded(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
return SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
final l = sortedLabels.elementAt(index);
|
||||
return LabelItem<T>(
|
||||
name: l.name,
|
||||
content: contentBuilder?.call(l) ??
|
||||
Text(
|
||||
translateMatchingAlgorithmName(
|
||||
context, l.matchingAlgorithm) +
|
||||
((l.match?.isNotEmpty ?? false)
|
||||
? ": ${l.match}"
|
||||
: ""),
|
||||
maxLines: 2,
|
||||
),
|
||||
onOpenEditPage: onEdit,
|
||||
filterBuilder: filterBuilder,
|
||||
leading: leadingBuilder?.call(l),
|
||||
label: l,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
childCount: labels.length,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,37 +1,24 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||
import 'package:paperless_mobile/features/labels/cubit/label_cubit.dart';
|
||||
|
||||
class LabelText<T extends Label> extends StatelessWidget {
|
||||
final int? id;
|
||||
final T? label;
|
||||
final String placeholder;
|
||||
final TextStyle? style;
|
||||
|
||||
const LabelText({
|
||||
super.key,
|
||||
this.style,
|
||||
this.id,
|
||||
this.placeholder = "",
|
||||
required this.label,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => LabelCubit<T>(
|
||||
context.read<LabelRepository<T>>(),
|
||||
),
|
||||
child: BlocBuilder<LabelCubit<T>, LabelState<T>>(
|
||||
builder: (context, state) {
|
||||
return Text(
|
||||
state.labels[id]?.toString() ?? placeholder,
|
||||
style: style,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
);
|
||||
},
|
||||
),
|
||||
return Text(
|
||||
label?.toString() ?? placeholder,
|
||||
style: style,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
);
|
||||
;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:hydrated_bloc/hydrated_bloc.dart';
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/notifier/document_changed_notifier.dart';
|
||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||
import 'package:paperless_mobile/features/paged_document_view/cubit/paged_documents_state.dart';
|
||||
import 'package:paperless_mobile/features/paged_document_view/cubit/document_paging_bloc_mixin.dart';
|
||||
import 'package:paperless_mobile/features/settings/model/view_type.dart';
|
||||
@@ -17,12 +18,26 @@ class LinkedDocumentsCubit extends HydratedCubit<LinkedDocumentsState>
|
||||
@override
|
||||
final DocumentChangedNotifier notifier;
|
||||
|
||||
final LabelRepository _labelRepository;
|
||||
|
||||
LinkedDocumentsCubit(
|
||||
DocumentFilter filter,
|
||||
this.api,
|
||||
this.notifier,
|
||||
this._labelRepository,
|
||||
) : super(const LinkedDocumentsState()) {
|
||||
updateFilter(filter: filter);
|
||||
_labelRepository.subscribe(
|
||||
this,
|
||||
onChanged: (labels) {
|
||||
emit(state.copyWith(
|
||||
correspondents: labels.correspondents,
|
||||
documentTypes: labels.documentTypes,
|
||||
tags: labels.tags,
|
||||
storagePaths: labels.storagePaths,
|
||||
));
|
||||
},
|
||||
);
|
||||
notifier.subscribe(
|
||||
this,
|
||||
onUpdated: replace,
|
||||
|
||||
@@ -4,12 +4,22 @@ part of 'linked_documents_cubit.dart';
|
||||
class LinkedDocumentsState extends DocumentPagingState {
|
||||
@JsonKey()
|
||||
final ViewType viewType;
|
||||
|
||||
final Map<int, Correspondent> correspondents;
|
||||
final Map<int, DocumentType> documentTypes;
|
||||
final Map<int, StoragePath> storagePaths;
|
||||
final Map<int, Tag> tags;
|
||||
|
||||
const LinkedDocumentsState({
|
||||
this.viewType = ViewType.list,
|
||||
super.filter,
|
||||
super.isLoading,
|
||||
super.hasLoaded,
|
||||
super.value,
|
||||
this.correspondents = const {},
|
||||
this.documentTypes = const {},
|
||||
this.storagePaths = const {},
|
||||
this.tags = const {},
|
||||
});
|
||||
|
||||
LinkedDocumentsState copyWith({
|
||||
@@ -18,6 +28,10 @@ class LinkedDocumentsState extends DocumentPagingState {
|
||||
bool? hasLoaded,
|
||||
List<PagedSearchResult<DocumentModel>>? value,
|
||||
ViewType? viewType,
|
||||
Map<int, Correspondent>? correspondents,
|
||||
Map<int, DocumentType>? documentTypes,
|
||||
Map<int, StoragePath>? storagePaths,
|
||||
Map<int, Tag>? tags,
|
||||
}) {
|
||||
return LinkedDocumentsState(
|
||||
filter: filter ?? this.filter,
|
||||
@@ -25,6 +39,10 @@ class LinkedDocumentsState extends DocumentPagingState {
|
||||
hasLoaded: hasLoaded ?? this.hasLoaded,
|
||||
value: value ?? this.value,
|
||||
viewType: viewType ?? this.viewType,
|
||||
correspondents: correspondents ?? this.correspondents,
|
||||
documentTypes: documentTypes ?? this.documentTypes,
|
||||
storagePaths: storagePaths ?? this.storagePaths,
|
||||
tags: tags ?? this.tags,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -61,6 +61,10 @@ class _LinkedDocumentsPageState extends State<LinkedDocumentsPage>
|
||||
),
|
||||
);
|
||||
},
|
||||
correspondents: state.correspondents,
|
||||
documentTypes: state.documentTypes,
|
||||
storagePaths: state.storagePaths,
|
||||
tags: state.tags,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -2,42 +2,72 @@ import 'dart:async';
|
||||
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||
import 'package:paperless_mobile/core/repository/saved_view_repository.dart';
|
||||
|
||||
part 'saved_view_state.dart';
|
||||
part 'saved_view_cubit.freezed.dart';
|
||||
|
||||
class SavedViewCubit extends Cubit<SavedViewState> {
|
||||
final SavedViewRepository _repository;
|
||||
StreamSubscription? _subscription;
|
||||
final SavedViewRepository _savedViewRepository;
|
||||
final LabelRepository _labelRepository;
|
||||
|
||||
SavedViewCubit(this._repository) : super(const SavedViewState()) {
|
||||
_subscription = _repository.values.listen(
|
||||
(savedViews) {
|
||||
if (savedViews?.hasLoaded ?? false) {
|
||||
emit(state.copyWith(value: savedViews?.values, hasLoaded: true));
|
||||
} else {
|
||||
emit(state.copyWith(hasLoaded: false));
|
||||
}
|
||||
SavedViewCubit(this._savedViewRepository, this._labelRepository)
|
||||
: super(SavedViewState.initial(
|
||||
correspondents: _labelRepository.state.correspondents,
|
||||
documentTypes: _labelRepository.state.documentTypes,
|
||||
storagePaths: _labelRepository.state.storagePaths,
|
||||
tags: _labelRepository.state.tags,
|
||||
)) {
|
||||
_labelRepository.subscribe(
|
||||
this,
|
||||
onChanged: (labels) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
correspondents: labels.correspondents,
|
||||
documentTypes: labels.documentTypes,
|
||||
tags: labels.tags,
|
||||
storagePaths: labels.storagePaths,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
_savedViewRepository.subscribe(this, (views) {
|
||||
emit(
|
||||
state.maybeWhen(
|
||||
loaded:
|
||||
(savedViews, correspondents, documentTypes, tags, storagePaths) =>
|
||||
(state as _SavedViewLoadedState).copyWith(
|
||||
savedViews: views,
|
||||
),
|
||||
orElse: () => state,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Future<SavedView> add(SavedView view) async {
|
||||
final savedView = await _repository.create(view);
|
||||
emit(state.copyWith(value: {...state.value, savedView.id!: savedView}));
|
||||
return savedView;
|
||||
return _savedViewRepository.create(view);
|
||||
}
|
||||
|
||||
Future<int> remove(SavedView view) {
|
||||
return _repository.delete(view);
|
||||
return _savedViewRepository.delete(view);
|
||||
}
|
||||
|
||||
Future<void> initialize() async {
|
||||
final views = await _repository.findAll();
|
||||
final views = await _savedViewRepository.findAll();
|
||||
final values = {for (var element in views) element.id!: element};
|
||||
if (!isClosed) {
|
||||
emit(SavedViewState(value: values, hasLoaded: true));
|
||||
emit(SavedViewState.loaded(
|
||||
savedViews: values,
|
||||
correspondents: state.correspondents,
|
||||
documentTypes: state.documentTypes,
|
||||
storagePaths: state.storagePaths,
|
||||
tags: state.tags,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +75,8 @@ class SavedViewCubit extends Cubit<SavedViewState> {
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
_subscription?.cancel();
|
||||
_savedViewRepository.unsubscribe(this);
|
||||
_labelRepository.unsubscribe(this);
|
||||
return super.close();
|
||||
}
|
||||
}
|
||||
|
||||
1382
lib/features/saved_view/cubit/saved_view_cubit.freezed.dart
Normal file
1382
lib/features/saved_view/cubit/saved_view_cubit.freezed.dart
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,29 +1,33 @@
|
||||
part of 'saved_view_cubit.dart';
|
||||
|
||||
class SavedViewState extends Equatable {
|
||||
final bool hasLoaded;
|
||||
final Map<int, SavedView> value;
|
||||
@freezed
|
||||
class SavedViewState with _$SavedViewState {
|
||||
const factory SavedViewState.initial({
|
||||
required Map<int, Correspondent> correspondents,
|
||||
required Map<int, DocumentType> documentTypes,
|
||||
required Map<int, Tag> tags,
|
||||
required Map<int, StoragePath> storagePaths,
|
||||
}) = _SavedViewIntialState;
|
||||
|
||||
const SavedViewState({
|
||||
this.value = const {},
|
||||
this.hasLoaded = false,
|
||||
});
|
||||
const factory SavedViewState.loading({
|
||||
required Map<int, Correspondent> correspondents,
|
||||
required Map<int, DocumentType> documentTypes,
|
||||
required Map<int, Tag> tags,
|
||||
required Map<int, StoragePath> storagePaths,
|
||||
}) = _SavedViewLoadingState;
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
hasLoaded,
|
||||
value,
|
||||
];
|
||||
const factory SavedViewState.loaded({
|
||||
required Map<int, SavedView> savedViews,
|
||||
required Map<int, Correspondent> correspondents,
|
||||
required Map<int, DocumentType> documentTypes,
|
||||
required Map<int, Tag> tags,
|
||||
required Map<int, StoragePath> storagePaths,
|
||||
}) = _SavedViewLoadedState;
|
||||
|
||||
SavedViewState copyWith({
|
||||
Map<int, SavedView>? value,
|
||||
int? selectedSavedViewId,
|
||||
bool overwriteSelectedSavedViewId = false,
|
||||
bool? hasLoaded,
|
||||
}) {
|
||||
return SavedViewState(
|
||||
value: value ?? this.value,
|
||||
hasLoaded: hasLoaded ?? this.hasLoaded,
|
||||
);
|
||||
}
|
||||
const factory SavedViewState.error({
|
||||
required Map<int, Correspondent> correspondents,
|
||||
required Map<int, DocumentType> documentTypes,
|
||||
required Map<int, Tag> tags,
|
||||
required Map<int, StoragePath> storagePaths,
|
||||
}) = _SavedViewErrorState;
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ class _AddSavedViewPageState extends State<AddSavedViewPage> {
|
||||
],
|
||||
),
|
||||
),
|
||||
Divider(),
|
||||
const Divider(),
|
||||
Text(
|
||||
"Review filter",
|
||||
style: Theme.of(context).textTheme.bodyLarge,
|
||||
@@ -80,42 +80,6 @@ class _AddSavedViewPageState extends State<AddSavedViewPage> {
|
||||
);
|
||||
}
|
||||
|
||||
Padding _buildOld(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
children: [
|
||||
FormBuilder(
|
||||
key: _savedViewFormKey,
|
||||
child: Expanded(
|
||||
child: ListView(
|
||||
children: [
|
||||
FormBuilderTextField(
|
||||
name: fkName,
|
||||
validator: FormBuilderValidators.required(),
|
||||
decoration: InputDecoration(
|
||||
label: Text(S.of(context)!.name),
|
||||
),
|
||||
),
|
||||
FormBuilderCheckbox(
|
||||
name: fkShowOnDashboard,
|
||||
initialValue: false,
|
||||
title: Text(S.of(context)!.showOnDashboard),
|
||||
),
|
||||
FormBuilderCheckbox(
|
||||
name: fkShowInSidebar,
|
||||
initialValue: false,
|
||||
title: Text(S.of(context)!.showInSidebar),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _onCreate(BuildContext context) {
|
||||
if (_savedViewFormKey.currentState?.saveAndValidate() ?? false) {
|
||||
Navigator.pop(
|
||||
|
||||
@@ -12,52 +12,70 @@ class SavedViewList extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final savedViewCubit = context.read<SavedViewCubit>();
|
||||
return BlocBuilder<ConnectivityCubit, ConnectivityState>(
|
||||
builder: (context, connectivity) {
|
||||
return BlocBuilder<SavedViewCubit, SavedViewState>(
|
||||
builder: (context, state) {
|
||||
if (state.value.isEmpty) {
|
||||
return SliverToBoxAdapter(
|
||||
child: HintCard(
|
||||
hintText:
|
||||
S.of(context)!.createViewsToQuicklyFilterYourDocuments,
|
||||
),
|
||||
);
|
||||
}
|
||||
return SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
final view = state.value.values.elementAt(index);
|
||||
return ListTile(
|
||||
enabled: connectivity.isConnected,
|
||||
title: Text(view.name),
|
||||
subtitle: Text(
|
||||
S.of(context)!.nFiltersSet(view.filterRules.length),
|
||||
return state.when(
|
||||
initial: (correspondents, documentTypes, tags, storagePaths) =>
|
||||
Container(),
|
||||
loading: (correspondents, documentTypes, tags, storagePaths) =>
|
||||
Center(
|
||||
child: Text("Saved views loading..."),
|
||||
),
|
||||
loaded: (savedViews, correspondents, documentTypes, tags,
|
||||
storagePaths) {
|
||||
if (savedViews.isEmpty) {
|
||||
return SliverToBoxAdapter(
|
||||
child: HintCard(
|
||||
hintText: S
|
||||
.of(context)!
|
||||
.createViewsToQuicklyFilterYourDocuments,
|
||||
),
|
||||
onTap: () {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => MultiBlocProvider(
|
||||
providers: [
|
||||
BlocProvider(
|
||||
create: (context) => SavedViewDetailsCubit(
|
||||
context.read(),
|
||||
context.read(),
|
||||
savedView: view,
|
||||
);
|
||||
}
|
||||
return SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
final view = savedViews.values.elementAt(index);
|
||||
return ListTile(
|
||||
enabled: connectivity.isConnected,
|
||||
title: Text(view.name),
|
||||
subtitle: Text(
|
||||
S.of(context)!.nFiltersSet(view.filterRules.length),
|
||||
),
|
||||
onTap: () {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => MultiBlocProvider(
|
||||
providers: [
|
||||
BlocProvider(
|
||||
create: (context) => SavedViewDetailsCubit(
|
||||
context.read(),
|
||||
context.read(),
|
||||
savedView: view,
|
||||
),
|
||||
),
|
||||
],
|
||||
child: SavedViewDetailsPage(
|
||||
onDelete:
|
||||
context.read<SavedViewCubit>().remove,
|
||||
),
|
||||
),
|
||||
],
|
||||
child: SavedViewDetailsPage(
|
||||
onDelete: savedViewCubit.remove,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
childCount: state.value.length,
|
||||
childCount: savedViews.length,
|
||||
),
|
||||
);
|
||||
},
|
||||
error: (correspondents, documentTypes, tags, storagePaths) =>
|
||||
Center(
|
||||
child: Text(
|
||||
"An error occurred while trying to load the saved views.",
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
|
||||
@@ -82,10 +82,7 @@ class AccountSettingsDialog extends StatelessWidget {
|
||||
try {
|
||||
await context.read<AuthenticationCubit>().logout();
|
||||
await context.read<ApplicationSettingsCubit>().clear();
|
||||
await context.read<LabelRepository<Tag>>().clear();
|
||||
await context.read<LabelRepository<Correspondent>>().clear();
|
||||
await context.read<LabelRepository<DocumentType>>().clear();
|
||||
await context.read<LabelRepository<StoragePath>>().clear();
|
||||
await context.read<LabelRepository>().clear();
|
||||
await context.read<SavedViewRepository>().clear();
|
||||
await HydratedBloc.storage.clear();
|
||||
} on PaperlessServerException catch (error, stackTrace) {
|
||||
|
||||
@@ -21,17 +21,12 @@ import 'package:paperless_mobile/core/bloc/paperless_server_information_cubit.da
|
||||
import 'package:paperless_mobile/core/interceptor/dio_http_error_interceptor.dart';
|
||||
import 'package:paperless_mobile/core/interceptor/language_header.interceptor.dart';
|
||||
import 'package:paperless_mobile/core/notifier/document_changed_notifier.dart';
|
||||
import 'package:paperless_mobile/core/repository/impl/correspondent_repository_impl.dart';
|
||||
import 'package:paperless_mobile/core/repository/impl/document_type_repository_impl.dart';
|
||||
import 'package:paperless_mobile/core/repository/impl/saved_view_repository_impl.dart';
|
||||
import 'package:paperless_mobile/core/repository/impl/storage_path_repository_impl.dart';
|
||||
import 'package:paperless_mobile/core/repository/impl/tag_repository_impl.dart';
|
||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||
import 'package:paperless_mobile/core/repository/saved_view_repository.dart';
|
||||
import 'package:paperless_mobile/core/security/session_manager.dart';
|
||||
import 'package:paperless_mobile/core/service/connectivity_status_service.dart';
|
||||
import 'package:paperless_mobile/core/service/dio_file_service.dart';
|
||||
import 'package:paperless_mobile/core/service/file_service.dart';
|
||||
import 'package:paperless_mobile/features/app_intro/application_intro_slideshow.dart';
|
||||
import 'package:paperless_mobile/features/home/view/home_page.dart';
|
||||
import 'package:paperless_mobile/features/home/view/widget/verify_identity_page.dart';
|
||||
@@ -105,10 +100,7 @@ void main() async {
|
||||
await connectivityCubit.initialize();
|
||||
|
||||
// Create repositories
|
||||
final tagRepository = TagRepositoryImpl(labelsApi);
|
||||
final correspondentRepository = CorrespondentRepositoryImpl(labelsApi);
|
||||
final documentTypeRepository = DocumentTypeRepositoryImpl(labelsApi);
|
||||
final storagePathRepository = StoragePathRepositoryImpl(labelsApi);
|
||||
final labelRepository = LabelRepository(labelsApi);
|
||||
final savedViewRepository = SavedViewRepositoryImpl(savedViewsApi);
|
||||
|
||||
//Create cubits/blocs
|
||||
@@ -163,17 +155,8 @@ void main() async {
|
||||
],
|
||||
child: MultiRepositoryProvider(
|
||||
providers: [
|
||||
RepositoryProvider<LabelRepository<Tag>>.value(
|
||||
value: tagRepository,
|
||||
),
|
||||
RepositoryProvider<LabelRepository<Correspondent>>.value(
|
||||
value: correspondentRepository,
|
||||
),
|
||||
RepositoryProvider<LabelRepository<DocumentType>>.value(
|
||||
value: documentTypeRepository,
|
||||
),
|
||||
RepositoryProvider<LabelRepository<StoragePath>>.value(
|
||||
value: storagePathRepository,
|
||||
RepositoryProvider<LabelRepository>.value(
|
||||
value: labelRepository,
|
||||
),
|
||||
RepositoryProvider<SavedViewRepository>.value(
|
||||
value: savedViewRepository,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/repository/provider/label_repositories_provider.dart';
|
||||
import 'package:paperless_mobile/features/document_details/cubit/document_details_cubit.dart';
|
||||
import 'package:paperless_mobile/features/document_details/view/pages/document_details_page.dart';
|
||||
|
||||
@@ -19,9 +18,11 @@ class DocumentDetailsRoute extends StatelessWidget {
|
||||
context.read(),
|
||||
context.read(),
|
||||
context.read(),
|
||||
context.read(),
|
||||
initialDocument: args.document,
|
||||
),
|
||||
child: LabelRepositoriesProvider(
|
||||
child: RepositoryProvider.value(
|
||||
value: context.read(),
|
||||
child: DocumentDetailsPage(
|
||||
allowEdit: args.allowEdit,
|
||||
isLabelClickable: args.isLabelClickable,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:paperless_api/src/models/saved_view_model.dart';
|
||||
|
||||
abstract class PaperlessSavedViewsApi {
|
||||
Future<SavedView> find(int id);
|
||||
Future<SavedView?> find(int id);
|
||||
Future<Iterable<SavedView>> findAll([Iterable<int>? ids]);
|
||||
|
||||
Future<SavedView> save(SavedView view);
|
||||
|
||||
@@ -60,7 +60,7 @@ class PaperlessSavedViewsApiImpl implements PaperlessSavedViewsApi {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<SavedView> find(int id) {
|
||||
Future<SavedView?> find(int id) {
|
||||
return getSingleResult(
|
||||
"/api/saved_views/$id/",
|
||||
SavedView.fromJson,
|
||||
|
||||
@@ -4,7 +4,7 @@ import 'package:dio/dio.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:paperless_api/src/models/paperless_server_exception.dart';
|
||||
|
||||
Future<T> getSingleResult<T>(
|
||||
Future<T?> getSingleResult<T>(
|
||||
String url,
|
||||
T Function(Map<String, dynamic>) fromJson,
|
||||
ErrorCode errorCode, {
|
||||
|
||||
16
pubspec.lock
16
pubspec.lock
@@ -731,6 +731,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.4.0"
|
||||
freezed:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: freezed
|
||||
sha256: e819441678f1679b719008ff2ff0ef045d66eed9f9ec81166ca0d9b02a187454
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.2"
|
||||
freezed_annotation:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: freezed_annotation
|
||||
sha256: aeac15850ef1b38ee368d4c53ba9a847e900bb2c53a4db3f6881cbb3cb684338
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
frontend_server_client:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -91,6 +91,7 @@ dependencies:
|
||||
dynamic_color: ^1.5.4
|
||||
flutter_html: ^3.0.0-alpha.6
|
||||
in_app_review: ^2.0.6
|
||||
freezed_annotation: ^2.2.0
|
||||
|
||||
dev_dependencies:
|
||||
integration_test:
|
||||
@@ -105,6 +106,7 @@ dev_dependencies:
|
||||
json_serializable: ^6.5.4
|
||||
dart_code_metrics: ^5.4.0
|
||||
auto_route_generator: ^5.0.3
|
||||
freezed: ^2.3.2
|
||||
|
||||
# For information on the generic Dart part of this file, see the
|
||||
# following page: https://dart.dev/tools/pub/pubspec
|
||||
|
||||
Reference in New Issue
Block a user