mirror of
https://github.com/Xevion/paperless-mobile.git
synced 2025-12-07 13:15:55 -06:00
fix: Refactor labels structure
This commit is contained in:
@@ -23,8 +23,8 @@ class DocumentChangedNotifier {
|
||||
_deleted.add(deleted);
|
||||
}
|
||||
|
||||
void subscribe(
|
||||
dynamic subscriber, {
|
||||
void addListener(
|
||||
Object subscriber, {
|
||||
DocumentChangedCallback? onUpdated,
|
||||
DocumentChangedCallback? onDeleted,
|
||||
}) {
|
||||
@@ -41,7 +41,7 @@ class DocumentChangedNotifier {
|
||||
);
|
||||
}
|
||||
|
||||
void unsubscribe(dynamic subscriber) {
|
||||
void removeListener(Object subscriber) {
|
||||
_subscribers[subscriber]?.forEach((element) {
|
||||
element.cancel();
|
||||
});
|
||||
|
||||
@@ -8,7 +8,9 @@ class LabelRepository extends HydratedCubit<LabelRepositoryState> {
|
||||
final PaperlessLabelsApi _api;
|
||||
final Map<Object, StreamSubscription> _subscribers = {};
|
||||
|
||||
void subscribe(
|
||||
LabelRepository(this._api) : super(const LabelRepositoryState());
|
||||
|
||||
void addListener(
|
||||
Object source, {
|
||||
required void Function(LabelRepositoryState) onChanged,
|
||||
}) {
|
||||
@@ -18,12 +20,19 @@ class LabelRepository extends HydratedCubit<LabelRepositoryState> {
|
||||
});
|
||||
}
|
||||
|
||||
void unsubscribe(Object source) async {
|
||||
void removeListener(Object source) async {
|
||||
await _subscribers[source]?.cancel();
|
||||
_subscribers.remove(source);
|
||||
}
|
||||
|
||||
LabelRepository(this._api) : super(const LabelRepositoryState());
|
||||
Future<void> initialize() {
|
||||
return Future.wait([
|
||||
findAllCorrespondents(),
|
||||
findAllDocumentTypes(),
|
||||
findAllStoragePaths(),
|
||||
findAllTags(),
|
||||
]);
|
||||
}
|
||||
|
||||
Future<Tag> createTag(Tag object) async {
|
||||
final created = await _api.saveTag(object);
|
||||
|
||||
@@ -30,7 +30,7 @@ class DocumentBulkActionCubit extends Cubit<DocumentBulkActionState> {
|
||||
tags: _labelRepository.state.tags,
|
||||
),
|
||||
) {
|
||||
_notifier.subscribe(
|
||||
_notifier.addListener(
|
||||
this,
|
||||
onDeleted: (document) {
|
||||
// Remove items from internal selection after the document was deleted.
|
||||
@@ -43,7 +43,7 @@ class DocumentBulkActionCubit extends Cubit<DocumentBulkActionState> {
|
||||
);
|
||||
},
|
||||
);
|
||||
_labelRepository.subscribe(
|
||||
_labelRepository.addListener(
|
||||
this,
|
||||
onChanged: (labels) {
|
||||
emit(
|
||||
@@ -142,8 +142,8 @@ class DocumentBulkActionCubit extends Cubit<DocumentBulkActionState> {
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
_notifier.unsubscribe(this);
|
||||
_labelRepository.unsubscribe(this);
|
||||
_notifier.removeListener(this);
|
||||
_labelRepository.removeListener(this);
|
||||
return super.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,8 +31,8 @@ class DocumentDetailsCubit extends Cubit<DocumentDetailsState> {
|
||||
}) : super(DocumentDetailsState(
|
||||
document: initialDocument,
|
||||
)) {
|
||||
_notifier.subscribe(this, onUpdated: replace);
|
||||
_labelRepository.subscribe(
|
||||
_notifier.addListener(this, onUpdated: replace);
|
||||
_labelRepository.addListener(
|
||||
this,
|
||||
onChanged: (labels) => emit(
|
||||
state.copyWith(
|
||||
@@ -210,7 +210,7 @@ class DocumentDetailsCubit extends Cubit<DocumentDetailsState> {
|
||||
for (final element in _subscriptions) {
|
||||
await element.cancel();
|
||||
}
|
||||
_notifier.unsubscribe(this);
|
||||
_notifier.removeListener(this);
|
||||
await super.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,6 +176,7 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
|
||||
builder: (context, state) {
|
||||
return BlocProvider(
|
||||
create: (context) => SimilarDocumentsCubit(
|
||||
context.read(),
|
||||
context.read(),
|
||||
context.read(),
|
||||
documentId: state.document.id,
|
||||
@@ -186,7 +187,10 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
|
||||
document: state.document,
|
||||
itemSpacing: _itemSpacing,
|
||||
queryString: widget.titleAndContentQueryString,
|
||||
|
||||
availableCorrespondents: state.correspondents,
|
||||
availableDocumentTypes: state.documentTypes,
|
||||
availableTags: state.tags,
|
||||
availableStoragePaths: state.storagePaths,
|
||||
),
|
||||
DocumentContentWidget(
|
||||
isFullContentLoaded: state.isFullContentLoaded,
|
||||
@@ -215,7 +219,7 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
|
||||
return BlocBuilder<DocumentDetailsCubit, DocumentDetailsState>(
|
||||
builder: (context, state) {
|
||||
final _filteredSuggestions =
|
||||
state.suggestions.documentDifference(state.document);
|
||||
state.suggestions?.documentDifference(state.document);
|
||||
return BlocBuilder<ConnectivityCubit, ConnectivityState>(
|
||||
builder: (context, connectivityState) {
|
||||
if (!connectivityState.isConnected) {
|
||||
@@ -223,7 +227,7 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
|
||||
}
|
||||
return b.Badge(
|
||||
position: b.BadgePosition.topEnd(top: -12, end: -6),
|
||||
showBadge: _filteredSuggestions.hasSuggestions,
|
||||
showBadge: _filteredSuggestions?.hasSuggestions ?? false,
|
||||
child: Tooltip(
|
||||
message: S.of(context)!.editDocumentTooltip,
|
||||
preferBelow: false,
|
||||
@@ -234,7 +238,7 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
|
||||
),
|
||||
),
|
||||
badgeContent: Text(
|
||||
'${_filteredSuggestions.suggestionsCount}',
|
||||
'${_filteredSuggestions?.suggestionsCount ?? 0}',
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
),
|
||||
@@ -300,13 +304,10 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
|
||||
providers: [
|
||||
BlocProvider.value(
|
||||
value: DocumentEditCubit(
|
||||
document,
|
||||
documentsApi: context.read(),
|
||||
correspondentRepository: context.read(),
|
||||
documentTypeRepository: context.read(),
|
||||
storagePathRepository: context.read(),
|
||||
tagRepository: context.read(),
|
||||
notifier: context.read(),
|
||||
context.read(),
|
||||
context.read(),
|
||||
context.read(),
|
||||
document: document,
|
||||
),
|
||||
),
|
||||
BlocProvider<DocumentDetailsCubit>.value(
|
||||
|
||||
@@ -32,10 +32,10 @@ class DocumentEditCubit extends Cubit<DocumentEditState> {
|
||||
tags: _labelRepository.state.tags,
|
||||
),
|
||||
) {
|
||||
_notifier.subscribe(this, onUpdated: replace);
|
||||
_labelRepository.subscribe(
|
||||
_notifier.addListener(this, onUpdated: replace);
|
||||
_labelRepository.addListener(
|
||||
this,
|
||||
onStateChanged: (labels) => emit(state.copyWith()),
|
||||
onChanged: (labels) => emit(state.copyWith()),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ class DocumentEditCubit extends Cubit<DocumentEditState> {
|
||||
for (final sub in _subscriptions) {
|
||||
sub.cancel();
|
||||
}
|
||||
_notifier.unsubscribe(this);
|
||||
_notifier.removeListener(this);
|
||||
return super.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||
import 'package:paperless_mobile/helpers/message_helpers.dart';
|
||||
|
||||
class DocumentEditPage extends StatefulWidget {
|
||||
final FieldSuggestions suggestions;
|
||||
final FieldSuggestions? suggestions;
|
||||
const DocumentEditPage({
|
||||
Key? key,
|
||||
required this.suggestions,
|
||||
@@ -43,13 +43,13 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
|
||||
final GlobalKey<FormBuilderState> _formKey = GlobalKey();
|
||||
bool _isSubmitLoading = false;
|
||||
|
||||
late final FieldSuggestions _filteredSuggestions;
|
||||
late final FieldSuggestions? _filteredSuggestions;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_filteredSuggestions = widget.suggestions
|
||||
.documentDifference(context.read<DocumentEditCubit>().state.document);
|
||||
?.documentDifference(context.read<DocumentEditCubit>().state.document);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -115,12 +115,14 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
|
||||
excludeAllowed: false,
|
||||
name: fkTags,
|
||||
selectableOptions: state.tags,
|
||||
suggestions: _filteredSuggestions.tags
|
||||
.toSet()
|
||||
suggestions: (_filteredSuggestions?.tags.toSet() ??
|
||||
{})
|
||||
.difference(state.document.tags.toSet())
|
||||
.isNotEmpty
|
||||
? _buildSuggestionsSkeleton<int>(
|
||||
suggestions: _filteredSuggestions.tags,
|
||||
suggestions:
|
||||
(_filteredSuggestions?.tags.toSet() ??
|
||||
{}),
|
||||
itemBuilder: (context, itemData) {
|
||||
final tag = state.tags[itemData]!;
|
||||
return ActionChip(
|
||||
@@ -216,8 +218,9 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
|
||||
LabelFormField<Correspondent>(
|
||||
notAssignedSelectable: false,
|
||||
formBuilderState: _formKey.currentState,
|
||||
labelCreationWidgetBuilder: (initialValue) => RepositoryProvider(
|
||||
create: (context) => context.read<LabelRepository<Correspondent>>(),
|
||||
labelCreationWidgetBuilder: (initialValue) =>
|
||||
RepositoryProvider.value(
|
||||
value: context.read<LabelRepository>(),
|
||||
child: AddCorrespondentPage(initialName: initialValue),
|
||||
),
|
||||
textFieldLabel: S.of(context)!.correspondent,
|
||||
@@ -226,9 +229,9 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
|
||||
name: fkCorrespondent,
|
||||
prefixIcon: const Icon(Icons.person_outlined),
|
||||
),
|
||||
if (_filteredSuggestions.hasSuggestedCorrespondents)
|
||||
if (_filteredSuggestions?.hasSuggestedCorrespondents ?? false)
|
||||
_buildSuggestionsSkeleton<int>(
|
||||
suggestions: _filteredSuggestions.correspondents,
|
||||
suggestions: _filteredSuggestions!.correspondents,
|
||||
itemBuilder: (context, itemData) => ActionChip(
|
||||
label: Text(options[itemData]!.name),
|
||||
onPressed: () => _formKey.currentState?.fields[fkCorrespondent]
|
||||
@@ -248,8 +251,9 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
|
||||
LabelFormField<DocumentType>(
|
||||
notAssignedSelectable: false,
|
||||
formBuilderState: _formKey.currentState,
|
||||
labelCreationWidgetBuilder: (currentInput) => RepositoryProvider(
|
||||
create: (context) => context.read<LabelRepository<DocumentType>>(),
|
||||
labelCreationWidgetBuilder: (currentInput) =>
|
||||
RepositoryProvider.value(
|
||||
value: context.read<LabelRepository>(),
|
||||
child: AddDocumentTypePage(
|
||||
initialName: currentInput,
|
||||
),
|
||||
@@ -260,9 +264,9 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
|
||||
name: fkDocumentType,
|
||||
prefixIcon: const Icon(Icons.description_outlined),
|
||||
),
|
||||
if (_filteredSuggestions.hasSuggestedDocumentTypes)
|
||||
if (_filteredSuggestions?.hasSuggestedDocumentTypes ?? false)
|
||||
_buildSuggestionsSkeleton<int>(
|
||||
suggestions: _filteredSuggestions.documentTypes,
|
||||
suggestions: _filteredSuggestions!.documentTypes,
|
||||
itemBuilder: (context, itemData) => ActionChip(
|
||||
label: Text(options[itemData]!.name),
|
||||
onPressed: () => _formKey.currentState?.fields[fkDocumentType]
|
||||
@@ -327,9 +331,9 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
|
||||
format: DateFormat.yMMMMd(),
|
||||
initialEntryMode: DatePickerEntryMode.calendar,
|
||||
),
|
||||
if (_filteredSuggestions.hasSuggestedDates)
|
||||
if (_filteredSuggestions?.hasSuggestedDates ?? false)
|
||||
_buildSuggestionsSkeleton<DateTime>(
|
||||
suggestions: _filteredSuggestions.dates,
|
||||
suggestions: _filteredSuggestions!.dates,
|
||||
itemBuilder: (context, itemData) => ActionChip(
|
||||
label: Text(DateFormat.yMMMd().format(itemData)),
|
||||
onPressed: () => _formKey.currentState?.fields[fkCreatedDate]
|
||||
|
||||
@@ -12,7 +12,6 @@ import 'package:paperless_mobile/core/bloc/connectivity_cubit.dart';
|
||||
import 'package:paperless_mobile/core/delegate/customizable_sliver_persistent_header_delegate.dart';
|
||||
import 'package:paperless_mobile/core/global/constants.dart';
|
||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||
import 'package:paperless_mobile/core/repository/provider/label_repositories_provider.dart';
|
||||
import 'package:paperless_mobile/core/service/file_description.dart';
|
||||
import 'package:paperless_mobile/core/service/file_service.dart';
|
||||
import 'package:paperless_mobile/features/app_drawer/view/app_drawer.dart';
|
||||
@@ -198,15 +197,10 @@ class _ScannerPageState extends State<ScannerPage>
|
||||
);
|
||||
final uploadResult = await Navigator.of(context).push<DocumentUploadResult>(
|
||||
MaterialPageRoute(
|
||||
builder: (_) => LabelRepositoriesProvider(
|
||||
child: BlocProvider(
|
||||
builder: (_) => BlocProvider(
|
||||
create: (context) => DocumentUploadCubit(
|
||||
documentApi: context.read<PaperlessDocumentsApi>(),
|
||||
correspondentRepository:
|
||||
context.read<LabelRepository<Correspondent>>(),
|
||||
documentTypeRepository:
|
||||
context.read<LabelRepository<DocumentType>>(),
|
||||
tagRepository: context.read<LabelRepository<Tag>>(),
|
||||
context.read(),
|
||||
context.read(),
|
||||
),
|
||||
child: DocumentUploadPreparationPage(
|
||||
fileBytes: file.bytes,
|
||||
@@ -214,7 +208,6 @@ class _ScannerPageState extends State<ScannerPage>
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
if ((uploadResult?.success ?? false) && uploadResult?.taskId != null) {
|
||||
// For paperless version older than 1.11.3, task id will always be null!
|
||||
@@ -316,15 +309,10 @@ class _ScannerPageState extends State<ScannerPage>
|
||||
}
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (_) => LabelRepositoriesProvider(
|
||||
child: BlocProvider(
|
||||
builder: (_) => BlocProvider(
|
||||
create: (context) => DocumentUploadCubit(
|
||||
documentApi: context.read<PaperlessDocumentsApi>(),
|
||||
correspondentRepository:
|
||||
context.read<LabelRepository<Correspondent>>(),
|
||||
documentTypeRepository:
|
||||
context.read<LabelRepository<DocumentType>>(),
|
||||
tagRepository: context.read<LabelRepository<Tag>>(),
|
||||
context.read(),
|
||||
context.read(),
|
||||
),
|
||||
child: DocumentUploadPreparationPage(
|
||||
fileBytes: file.readAsBytesSync(),
|
||||
@@ -334,7 +322,6 @@ class _ScannerPageState extends State<ScannerPage>
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:collection/collection.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:json_annotation/json_annotation.dart';
|
||||
import 'package:paperless_mobile/features/paged_document_view/cubit/paged_documents_state.dart';
|
||||
@@ -15,12 +16,22 @@ class DocumentSearchCubit extends HydratedCubit<DocumentSearchState>
|
||||
with DocumentPagingBlocMixin {
|
||||
@override
|
||||
final PaperlessDocumentsApi api;
|
||||
|
||||
final LabelRepository _labelRepository;
|
||||
@override
|
||||
final DocumentChangedNotifier notifier;
|
||||
|
||||
DocumentSearchCubit(this.api, this.notifier)
|
||||
DocumentSearchCubit(this.api, this.notifier, this._labelRepository)
|
||||
: super(const DocumentSearchState()) {
|
||||
notifier.subscribe(
|
||||
_labelRepository.addListener(this, onChanged: (labels) {
|
||||
emit(state.copyWith(
|
||||
correspondents: labels.correspondents,
|
||||
documentTypes: labels.documentTypes,
|
||||
tags: labels.tags,
|
||||
storagePaths: labels.storagePaths,
|
||||
));
|
||||
});
|
||||
notifier.addListener(
|
||||
this,
|
||||
onDeleted: remove,
|
||||
onUpdated: replace,
|
||||
@@ -89,7 +100,7 @@ class DocumentSearchCubit extends HydratedCubit<DocumentSearchState>
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
notifier.unsubscribe(this);
|
||||
notifier.removeListener(this);
|
||||
return super.close();
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,12 @@ class DocumentSearchState extends DocumentPagingState {
|
||||
final List<String> suggestions;
|
||||
@JsonKey()
|
||||
final ViewType viewType;
|
||||
|
||||
final Map<int, Correspondent> correspondents;
|
||||
final Map<int, DocumentType> documentTypes;
|
||||
final Map<int, Tag> tags;
|
||||
final Map<int, StoragePath> storagePaths;
|
||||
|
||||
const DocumentSearchState({
|
||||
this.view = SearchView.suggestions,
|
||||
this.searchHistory = const [],
|
||||
@@ -22,6 +28,10 @@ class DocumentSearchState extends DocumentPagingState {
|
||||
super.hasLoaded,
|
||||
super.isLoading,
|
||||
super.value,
|
||||
this.correspondents = const {},
|
||||
this.documentTypes = const {},
|
||||
this.tags = const {},
|
||||
this.storagePaths = const {},
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -31,6 +41,10 @@ class DocumentSearchState extends DocumentPagingState {
|
||||
suggestions,
|
||||
view,
|
||||
viewType,
|
||||
correspondents,
|
||||
documentTypes,
|
||||
tags,
|
||||
storagePaths,
|
||||
];
|
||||
|
||||
@override
|
||||
@@ -57,6 +71,10 @@ class DocumentSearchState extends DocumentPagingState {
|
||||
List<String>? suggestions,
|
||||
SearchView? view,
|
||||
ViewType? viewType,
|
||||
Map<int, Correspondent>? correspondents,
|
||||
Map<int, DocumentType>? documentTypes,
|
||||
Map<int, Tag>? tags,
|
||||
Map<int, StoragePath>? storagePaths,
|
||||
}) {
|
||||
return DocumentSearchState(
|
||||
value: value ?? this.value,
|
||||
@@ -67,6 +85,10 @@ class DocumentSearchState extends DocumentPagingState {
|
||||
view: view ?? this.view,
|
||||
suggestions: suggestions ?? this.suggestions,
|
||||
viewType: viewType ?? this.viewType,
|
||||
correspondents: correspondents ?? this.correspondents,
|
||||
documentTypes: documentTypes ?? this.documentTypes,
|
||||
tags: tags ?? this.tags,
|
||||
storagePaths: storagePaths ?? this.storagePaths,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ Future<void> showDocumentSearchPage(BuildContext context) {
|
||||
create: (context) => DocumentSearchCubit(
|
||||
context.read(),
|
||||
context.read(),
|
||||
context.read(),
|
||||
),
|
||||
child: const DocumentSearchPage(),
|
||||
),
|
||||
@@ -229,6 +230,10 @@ class _DocumentSearchPageState extends State<DocumentSearchPage> {
|
||||
),
|
||||
);
|
||||
},
|
||||
correspondents: state.correspondents,
|
||||
documentTypes: state.documentTypes,
|
||||
tags: state.tags,
|
||||
storagePaths: state.storagePaths,
|
||||
)
|
||||
],
|
||||
);
|
||||
|
||||
@@ -5,42 +5,26 @@ import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter/foundation.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/tag_repository_state.dart';
|
||||
|
||||
part 'document_upload_state.dart';
|
||||
|
||||
class DocumentUploadCubit extends Cubit<DocumentUploadState> {
|
||||
final PaperlessDocumentsApi _documentApi;
|
||||
|
||||
final LabelRepository<Tag> _tagRepository;
|
||||
final LabelRepository<Correspondent> _correspondentRepository;
|
||||
final LabelRepository<DocumentType> _documentTypeRepository;
|
||||
final LabelRepository _labelRepository;
|
||||
|
||||
final List<StreamSubscription> _subs = [];
|
||||
|
||||
DocumentUploadCubit({
|
||||
required PaperlessDocumentsApi documentApi,
|
||||
required LabelRepository<Tag> tagRepository,
|
||||
required LabelRepository<Correspondent> correspondentRepository,
|
||||
required LabelRepository<DocumentType> documentTypeRepository,
|
||||
}) : _documentApi = documentApi,
|
||||
_tagRepository = tagRepository,
|
||||
_correspondentRepository = correspondentRepository,
|
||||
_documentTypeRepository = documentTypeRepository,
|
||||
super(const DocumentUploadState()) {
|
||||
_subs.add(_tagRepository.values.listen(
|
||||
(tags) => emit(state.copyWith(tags: tags?.values)),
|
||||
));
|
||||
_subs.add(_correspondentRepository.values.listen(
|
||||
(correspondents) =>
|
||||
emit(state.copyWith(correspondents: correspondents?.values)),
|
||||
));
|
||||
_subs.add(_documentTypeRepository.values.listen(
|
||||
(documentTypes) =>
|
||||
emit(state.copyWith(documentTypes: documentTypes?.values)),
|
||||
DocumentUploadCubit(this._labelRepository, this._documentApi)
|
||||
: super(const DocumentUploadState()) {
|
||||
_labelRepository.addListener(
|
||||
this,
|
||||
onChanged: (labels) {
|
||||
emit(state.copyWith(
|
||||
correspondents: labels.correspondents,
|
||||
documentTypes: labels.documentTypes,
|
||||
tags: labels.tags,
|
||||
));
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<String?> upload(
|
||||
@@ -65,9 +49,7 @@ class DocumentUploadCubit extends Cubit<DocumentUploadState> {
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
for (final sub in _subs) {
|
||||
await sub.cancel();
|
||||
}
|
||||
_labelRepository.removeListener(this);
|
||||
return super.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,9 +192,8 @@ class _DocumentUploadPreparationPageState
|
||||
notAssignedSelectable: false,
|
||||
formBuilderState: _formKey.currentState,
|
||||
labelCreationWidgetBuilder: (initialName) =>
|
||||
RepositoryProvider(
|
||||
create: (context) =>
|
||||
context.read<LabelRepository<Correspondent>>(),
|
||||
RepositoryProvider.value(
|
||||
value: context.read<LabelRepository>(),
|
||||
child: AddCorrespondentPage(initialName: initialName),
|
||||
),
|
||||
textFieldLabel: S.of(context)!.correspondent + " *",
|
||||
@@ -207,9 +206,8 @@ class _DocumentUploadPreparationPageState
|
||||
notAssignedSelectable: false,
|
||||
formBuilderState: _formKey.currentState,
|
||||
labelCreationWidgetBuilder: (initialName) =>
|
||||
RepositoryProvider(
|
||||
create: (context) =>
|
||||
context.read<LabelRepository<DocumentType>>(),
|
||||
RepositoryProvider.value(
|
||||
value: context.read<LabelRepository>(),
|
||||
child: AddDocumentTypePage(initialName: initialName),
|
||||
),
|
||||
textFieldLabel: S.of(context)!.documentType + " *",
|
||||
@@ -229,7 +227,7 @@ class _DocumentUploadPreparationPageState
|
||||
"* " + S.of(context)!.uploadInferValuesHint,
|
||||
style: Theme.of(context).textTheme.bodySmall,
|
||||
),
|
||||
SizedBox(height: 300),
|
||||
const SizedBox(height: 300),
|
||||
].padded(),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
import 'dart:async';
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
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/document_paging_bloc_mixin.dart';
|
||||
import 'package:paperless_mobile/features/settings/model/view_type.dart';
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:paperless_mobile/features/paged_document_view/cubit/paged_documents_state.dart';
|
||||
import 'package:paperless_mobile/features/settings/model/view_type.dart';
|
||||
|
||||
part 'documents_state.dart';
|
||||
part 'documents_cubit.g.dart';
|
||||
part 'documents_state.dart';
|
||||
|
||||
class DocumentsCubit extends HydratedCubit<DocumentsState>
|
||||
with DocumentPagingBlocMixin {
|
||||
@@ -32,7 +30,7 @@ class DocumentsCubit extends HydratedCubit<DocumentsState>
|
||||
storagePaths: _labelRepository.state.storagePaths,
|
||||
tags: _labelRepository.state.tags,
|
||||
)) {
|
||||
notifier.subscribe(
|
||||
notifier.addListener(
|
||||
this,
|
||||
onUpdated: (document) {
|
||||
replace(document);
|
||||
@@ -54,9 +52,9 @@ class DocumentsCubit extends HydratedCubit<DocumentsState>
|
||||
);
|
||||
},
|
||||
);
|
||||
_labelRepository.subscribe(
|
||||
_labelRepository.addListener(
|
||||
this,
|
||||
onStateChanged: (labels) => emit(
|
||||
onChanged: (labels) => emit(
|
||||
state.copyWith(
|
||||
correspondents: labels.correspondents,
|
||||
documentTypes: labels.documentTypes,
|
||||
@@ -120,8 +118,8 @@ class DocumentsCubit extends HydratedCubit<DocumentsState>
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
notifier.unsubscribe(this);
|
||||
_labelRepository.unsubscribe(this);
|
||||
notifier.removeListener(this);
|
||||
_labelRepository.removeListener(this);
|
||||
return super.close();
|
||||
}
|
||||
|
||||
|
||||
@@ -12,11 +12,9 @@ import 'package:paperless_mobile/features/documents/cubit/documents_cubit.dart';
|
||||
import 'package:paperless_mobile/features/documents/view/widgets/adaptive_documents_view.dart';
|
||||
import 'package:paperless_mobile/features/documents/view/widgets/documents_empty_state.dart';
|
||||
import 'package:paperless_mobile/features/documents/view/widgets/search/document_filter_panel.dart';
|
||||
import 'package:paperless_mobile/features/documents/view/widgets/selection/bulk_delete_confirmation_dialog.dart';
|
||||
import 'package:paperless_mobile/features/documents/view/widgets/selection/document_selection_sliver_app_bar.dart';
|
||||
import 'package:paperless_mobile/features/documents/view/widgets/selection/view_type_selection_widget.dart';
|
||||
import 'package:paperless_mobile/features/documents/view/widgets/sort_documents_button.dart';
|
||||
import 'package:paperless_mobile/features/labels/cubit/providers/labels_bloc_provider.dart';
|
||||
import 'package:paperless_mobile/features/saved_view/cubit/saved_view_cubit.dart';
|
||||
import 'package:paperless_mobile/features/saved_view/view/add_saved_view_page.dart';
|
||||
import 'package:paperless_mobile/features/saved_view/view/saved_view_list.dart';
|
||||
@@ -358,6 +356,10 @@ class _DocumentsPageState extends State<DocumentsPage>
|
||||
isLabelClickable: true,
|
||||
isLoading: state.isLoading,
|
||||
selectedDocumentIds: state.selectedIds,
|
||||
correspondents: state.correspondents,
|
||||
documentTypes: state.documentTypes,
|
||||
tags: state.tags,
|
||||
storagePaths: state.storagePaths,
|
||||
);
|
||||
},
|
||||
),
|
||||
@@ -391,10 +393,16 @@ class _DocumentsPageState extends State<DocumentsPage>
|
||||
void _onCreateSavedView(DocumentFilter filter) async {
|
||||
final newView = await Navigator.of(context).push<SavedView?>(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => LabelsBlocProvider(
|
||||
child: AddSavedViewPage(
|
||||
builder: (context) => BlocBuilder<SavedViewCubit, SavedViewState>(
|
||||
builder: (context, state) {
|
||||
return AddSavedViewPage(
|
||||
currentFilter: filter,
|
||||
),
|
||||
correspondents: state.correspondents,
|
||||
documentTypes: state.documentTypes,
|
||||
storagePaths: state.storagePaths,
|
||||
tags: state.tags,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -428,12 +436,19 @@ class _DocumentsPageState extends State<DocumentsPage>
|
||||
snapSizes: const [0.9, 1],
|
||||
initialChildSize: .9,
|
||||
maxChildSize: 1,
|
||||
builder: (context, controller) => LabelsBlocProvider(
|
||||
child: DocumentFilterPanel(
|
||||
builder: (context, controller) =>
|
||||
BlocBuilder<DocumentsCubit, DocumentsState>(
|
||||
builder: (context, state) {
|
||||
return DocumentFilterPanel(
|
||||
initialFilter: context.read<DocumentsCubit>().state.filter,
|
||||
scrollController: controller,
|
||||
draggableSheetController: draggableSheetController,
|
||||
),
|
||||
correspondents: state.correspondents,
|
||||
documentTypes: state.documentTypes,
|
||||
storagePaths: state.storagePaths,
|
||||
tags: state.tags,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -119,7 +119,7 @@ class DocumentDetailedItem extends DocumentItem {
|
||||
textStyle: Theme.of(context).textTheme.titleSmall?.apply(
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
correspondent: context.read<DocumentsCubit>().correspondent,
|
||||
correspondent: correspondents[document.correspondent],
|
||||
),
|
||||
],
|
||||
).paddedLTRB(8, 0, 8, 4),
|
||||
@@ -134,13 +134,13 @@ class DocumentDetailedItem extends DocumentItem {
|
||||
textStyle: Theme.of(context).textTheme.titleSmall?.apply(
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
documentTypeId: document.documentType,
|
||||
documentType: documentTypes[document.documentType],
|
||||
),
|
||||
],
|
||||
).paddedLTRB(8, 0, 8, 4),
|
||||
TagsWidget(
|
||||
isMultiLine: false,
|
||||
tagIds: document.tags,
|
||||
tags: document.tags.map((e) => tags[e]!).toList(),
|
||||
).padded(),
|
||||
if (highlights != null)
|
||||
Html(
|
||||
|
||||
@@ -49,6 +49,11 @@ class DocumentFilterForm extends StatefulWidget {
|
||||
final DocumentFilter initialFilter;
|
||||
final ScrollController? scrollController;
|
||||
final EdgeInsets padding;
|
||||
final Map<int, Correspondent> correspondents;
|
||||
final Map<int, DocumentType> documentTypes;
|
||||
final Map<int, Tag> tags;
|
||||
final Map<int, StoragePath> storagePaths;
|
||||
|
||||
const DocumentFilterForm({
|
||||
super.key,
|
||||
this.header,
|
||||
@@ -56,6 +61,10 @@ class DocumentFilterForm extends StatefulWidget {
|
||||
required this.initialFilter,
|
||||
this.scrollController,
|
||||
this.padding = const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
|
||||
required this.correspondents,
|
||||
required this.documentTypes,
|
||||
required this.tags,
|
||||
required this.storagePaths,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -145,48 +154,36 @@ class _DocumentFilterFormState extends State<DocumentFilterForm> {
|
||||
}
|
||||
|
||||
Widget _buildDocumentTypeFormField() {
|
||||
return BlocBuilder<LabelCubit<DocumentType>, LabelState<DocumentType>>(
|
||||
builder: (context, state) {
|
||||
return LabelFormField<DocumentType>(
|
||||
formBuilderState: widget.formKey.currentState,
|
||||
name: DocumentFilterForm.fkDocumentType,
|
||||
labelOptions: state.labels,
|
||||
labelOptions: widget.documentTypes,
|
||||
textFieldLabel: S.of(context)!.documentType,
|
||||
initialValue: widget.initialFilter.documentType,
|
||||
prefixIcon: const Icon(Icons.description_outlined),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCorrespondentFormField() {
|
||||
return BlocBuilder<LabelCubit<Correspondent>, LabelState<Correspondent>>(
|
||||
builder: (context, state) {
|
||||
return LabelFormField<Correspondent>(
|
||||
formBuilderState: widget.formKey.currentState,
|
||||
name: DocumentFilterForm.fkCorrespondent,
|
||||
labelOptions: state.labels,
|
||||
labelOptions: widget.correspondents,
|
||||
textFieldLabel: S.of(context)!.correspondent,
|
||||
initialValue: widget.initialFilter.correspondent,
|
||||
prefixIcon: const Icon(Icons.person_outline),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildStoragePathFormField() {
|
||||
return BlocBuilder<LabelCubit<StoragePath>, LabelState<StoragePath>>(
|
||||
builder: (context, state) {
|
||||
return LabelFormField<StoragePath>(
|
||||
formBuilderState: widget.formKey.currentState,
|
||||
name: DocumentFilterForm.fkStoragePath,
|
||||
labelOptions: state.labels,
|
||||
labelOptions: widget.storagePaths,
|
||||
textFieldLabel: S.of(context)!.storagePath,
|
||||
initialValue: widget.initialFilter.storagePath,
|
||||
prefixIcon: const Icon(Icons.folder_outlined),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildQueryFormField() {
|
||||
@@ -197,16 +194,12 @@ class _DocumentFilterFormState extends State<DocumentFilterForm> {
|
||||
);
|
||||
}
|
||||
|
||||
BlocBuilder<LabelCubit<Tag>, LabelState<Tag>> _buildTagsFormField() {
|
||||
return BlocBuilder<LabelCubit<Tag>, LabelState<Tag>>(
|
||||
builder: (context, state) {
|
||||
Widget _buildTagsFormField() {
|
||||
return TagFormField(
|
||||
name: DocumentModel.tagsKey,
|
||||
initialValue: widget.initialFilter.tags,
|
||||
allowCreation: false,
|
||||
selectableOptions: state.labels,
|
||||
);
|
||||
},
|
||||
selectableOptions: widget.tags,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,11 +13,20 @@ class DocumentFilterPanel extends StatefulWidget {
|
||||
final DocumentFilter initialFilter;
|
||||
final ScrollController scrollController;
|
||||
final DraggableScrollableController draggableSheetController;
|
||||
final Map<int, Correspondent> correspondents;
|
||||
final Map<int, DocumentType> documentTypes;
|
||||
final Map<int, Tag> tags;
|
||||
final Map<int, StoragePath> storagePaths;
|
||||
|
||||
const DocumentFilterPanel({
|
||||
Key? key,
|
||||
required this.initialFilter,
|
||||
required this.scrollController,
|
||||
required this.draggableSheetController,
|
||||
required this.correspondents,
|
||||
required this.documentTypes,
|
||||
required this.tags,
|
||||
required this.storagePaths,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
@@ -38,10 +47,8 @@ class _DocumentFilterPanelState extends State<DocumentFilterPanel> {
|
||||
|
||||
void animateTitleByDrag() {
|
||||
setState(
|
||||
() {
|
||||
_heightAnimationValue = dp(
|
||||
((max(0.9, widget.draggableSheetController.size) - 0.9) / 0.1), 5);
|
||||
},
|
||||
() => _heightAnimationValue =
|
||||
dp(((max(0.9, widget.draggableSheetController.size) - 0.9) / 0.1), 5),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -96,6 +103,10 @@ class _DocumentFilterPanelState extends State<DocumentFilterPanel> {
|
||||
scrollController: widget.scrollController,
|
||||
initialFilter: widget.initialFilter,
|
||||
header: _buildPanelHeader(),
|
||||
correspondents: widget.correspondents,
|
||||
documentTypes: widget.documentTypes,
|
||||
storagePaths: widget.storagePaths,
|
||||
tags: widget.tags,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -10,6 +10,10 @@ import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||
class SortFieldSelectionBottomSheet extends StatefulWidget {
|
||||
final SortOrder initialSortOrder;
|
||||
final SortField? initialSortField;
|
||||
final Map<int, Correspondent> correspondents;
|
||||
final Map<int, DocumentType> documentTypes;
|
||||
final Map<int, Tag> tags;
|
||||
final Map<int, StoragePath> storagePaths;
|
||||
|
||||
final Future Function(SortField? field, SortOrder order) onSubmit;
|
||||
|
||||
@@ -18,6 +22,10 @@ class SortFieldSelectionBottomSheet extends StatefulWidget {
|
||||
required this.initialSortOrder,
|
||||
required this.initialSortField,
|
||||
required this.onSubmit,
|
||||
required this.correspondents,
|
||||
required this.documentTypes,
|
||||
required this.tags,
|
||||
required this.storagePaths,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -67,31 +75,20 @@ class _SortFieldSelectionBottomSheetState
|
||||
Column(
|
||||
children: [
|
||||
_buildSortOption(SortField.archiveSerialNumber),
|
||||
BlocBuilder<LabelCubit<Correspondent>,
|
||||
LabelState<Correspondent>>(
|
||||
builder: (context, state) {
|
||||
return _buildSortOption(
|
||||
_buildSortOption(
|
||||
SortField.correspondentName,
|
||||
enabled: state.labels.values.fold<bool>(
|
||||
enabled: widget.correspondents.values.fold<bool>(
|
||||
false,
|
||||
(previousValue, element) =>
|
||||
previousValue ||
|
||||
(element.documentCount ?? 0) > 0),
|
||||
);
|
||||
},
|
||||
previousValue || (element.documentCount ?? 0) > 0),
|
||||
),
|
||||
_buildSortOption(SortField.title),
|
||||
BlocBuilder<LabelCubit<DocumentType>, LabelState<DocumentType>>(
|
||||
builder: (context, state) {
|
||||
return _buildSortOption(
|
||||
_buildSortOption(
|
||||
SortField.documentType,
|
||||
enabled: state.labels.values.fold<bool>(
|
||||
enabled: widget.documentTypes.values.fold<bool>(
|
||||
false,
|
||||
(previousValue, element) =>
|
||||
previousValue ||
|
||||
(element.documentCount ?? 0) > 0),
|
||||
);
|
||||
},
|
||||
previousValue || (element.documentCount ?? 0) > 0),
|
||||
),
|
||||
_buildSortOption(SortField.created),
|
||||
_buildSortOption(SortField.added),
|
||||
|
||||
@@ -57,6 +57,10 @@ class SortDocumentsButton extends StatelessWidget {
|
||||
sortOrder: order,
|
||||
),
|
||||
),
|
||||
correspondents: state.correspondents,
|
||||
documentTypes: state.documentTypes,
|
||||
storagePaths: state.storagePaths,
|
||||
tags: state.tags,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -13,7 +13,7 @@ class EditLabelCubit extends Cubit<EditLabelState> with LabelCubitMixin {
|
||||
final LabelRepository labelRepository;
|
||||
|
||||
EditLabelCubit(this.labelRepository) : super(const EditLabelState()) {
|
||||
labelRepository.subscribe(
|
||||
labelRepository.addListener(
|
||||
this,
|
||||
onChanged: (labels) => state.copyWith(
|
||||
correspondents: labels.correspondents,
|
||||
@@ -26,7 +26,7 @@ class EditLabelCubit extends Cubit<EditLabelState> with LabelCubitMixin {
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
labelRepository.unsubscribe(this);
|
||||
labelRepository.removeListener(this);
|
||||
return super.close();
|
||||
}
|
||||
|
||||
|
||||
@@ -157,10 +157,8 @@ class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
|
||||
MaterialPageRoute(
|
||||
builder: (context) => BlocProvider.value(
|
||||
value: DocumentUploadCubit(
|
||||
documentApi: context.read(),
|
||||
tagRepository: context.read(),
|
||||
correspondentRepository: context.read(),
|
||||
documentTypeRepository: context.read(),
|
||||
context.read(),
|
||||
context.read(),
|
||||
),
|
||||
child: DocumentUploadPreparationPage(
|
||||
fileBytes: bytes,
|
||||
@@ -239,11 +237,13 @@ class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
|
||||
create: (context) => DocumentsCubit(
|
||||
context.read(),
|
||||
context.read(),
|
||||
context.read(),
|
||||
),
|
||||
),
|
||||
BlocProvider(
|
||||
create: (context) => SavedViewCubit(
|
||||
context.read(),
|
||||
context.read(),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -32,7 +32,7 @@ class InboxCubit extends HydratedCubit<InboxState>
|
||||
this._labelRepository,
|
||||
this.notifier,
|
||||
) : super(InboxState(labels: _labelRepository.state)) {
|
||||
notifier.subscribe(
|
||||
notifier.addListener(
|
||||
this,
|
||||
onDeleted: remove,
|
||||
onUpdated: (document) {
|
||||
@@ -47,7 +47,7 @@ class InboxCubit extends HydratedCubit<InboxState>
|
||||
}
|
||||
},
|
||||
);
|
||||
_labelRepository.subscribe(
|
||||
_labelRepository.addListener(
|
||||
this,
|
||||
onChanged: (labels) {
|
||||
emit(state.copyWith(labels: labels));
|
||||
@@ -209,7 +209,7 @@ class InboxCubit extends HydratedCubit<InboxState>
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
_labelRepository.unsubscribe(this);
|
||||
_labelRepository.removeListener(this);
|
||||
return super.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ class LabelCubit extends Cubit<LabelState> with LabelCubitMixin<LabelState> {
|
||||
final LabelRepository labelRepository;
|
||||
|
||||
LabelCubit(this.labelRepository) : super(const LabelState()) {
|
||||
labelRepository.subscribe(
|
||||
labelRepository.addListener(
|
||||
this,
|
||||
onChanged: (labels) {
|
||||
emit(state.copyWith(
|
||||
@@ -27,7 +27,7 @@ class LabelCubit extends Cubit<LabelState> with LabelCubitMixin<LabelState> {
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
labelRepository.unsubscribe(this);
|
||||
labelRepository.removeListener(this);
|
||||
return super.close();
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ class LinkedDocumentsCubit extends HydratedCubit<LinkedDocumentsState>
|
||||
this._labelRepository,
|
||||
) : super(const LinkedDocumentsState()) {
|
||||
updateFilter(filter: filter);
|
||||
_labelRepository.subscribe(
|
||||
_labelRepository.addListener(
|
||||
this,
|
||||
onChanged: (labels) {
|
||||
emit(state.copyWith(
|
||||
@@ -38,7 +38,7 @@ class LinkedDocumentsCubit extends HydratedCubit<LinkedDocumentsState>
|
||||
));
|
||||
},
|
||||
);
|
||||
notifier.subscribe(
|
||||
notifier.addListener(
|
||||
this,
|
||||
onUpdated: replace,
|
||||
onDeleted: remove,
|
||||
|
||||
@@ -172,7 +172,7 @@ mixin DocumentPagingBlocMixin<State extends DocumentPagingState>
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
notifier.unsubscribe(this);
|
||||
notifier.removeListener(this);
|
||||
return super.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ class SavedViewCubit extends Cubit<SavedViewState> {
|
||||
storagePaths: _labelRepository.state.storagePaths,
|
||||
tags: _labelRepository.state.tags,
|
||||
)) {
|
||||
_labelRepository.subscribe(
|
||||
_labelRepository.addListener(
|
||||
this,
|
||||
onChanged: (labels) {
|
||||
emit(
|
||||
@@ -76,7 +76,7 @@ class SavedViewCubit extends Cubit<SavedViewState> {
|
||||
@override
|
||||
Future<void> close() {
|
||||
_savedViewRepository.unsubscribe(this);
|
||||
_labelRepository.unsubscribe(this);
|
||||
_labelRepository.removeListener(this);
|
||||
return super.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,18 @@ import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||
|
||||
class AddSavedViewPage extends StatefulWidget {
|
||||
final DocumentFilter currentFilter;
|
||||
const AddSavedViewPage({super.key, required this.currentFilter});
|
||||
final Map<int, Correspondent> correspondents;
|
||||
final Map<int, DocumentType> documentTypes;
|
||||
final Map<int, Tag> tags;
|
||||
final Map<int, StoragePath> storagePaths;
|
||||
const AddSavedViewPage({
|
||||
super.key,
|
||||
required this.currentFilter,
|
||||
required this.correspondents,
|
||||
required this.documentTypes,
|
||||
required this.tags,
|
||||
required this.storagePaths,
|
||||
});
|
||||
|
||||
@override
|
||||
State<AddSavedViewPage> createState() => _AddSavedViewPageState();
|
||||
@@ -72,6 +83,10 @@ class _AddSavedViewPageState extends State<AddSavedViewPage> {
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
formKey: _filterFormKey,
|
||||
initialFilter: widget.currentFilter,
|
||||
correspondents: widget.correspondents,
|
||||
documentTypes: widget.documentTypes,
|
||||
storagePaths: widget.storagePaths,
|
||||
tags: widget.tags,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -23,7 +23,7 @@ class SavedViewDetailsCubit extends HydratedCubit<SavedViewDetailsState>
|
||||
this.notifier, {
|
||||
required this.savedView,
|
||||
}) : super(const SavedViewDetailsState()) {
|
||||
notifier.subscribe(
|
||||
notifier.addListener(
|
||||
this,
|
||||
onDeleted: remove,
|
||||
onUpdated: replace,
|
||||
|
||||
@@ -5,17 +5,30 @@ class SavedViewDetailsState extends DocumentPagingState {
|
||||
@JsonKey()
|
||||
final ViewType viewType;
|
||||
|
||||
final Map<int, Correspondent> correspondents;
|
||||
final Map<int, DocumentType> documentTypes;
|
||||
final Map<int, Tag> tags;
|
||||
final Map<int, StoragePath> storagePaths;
|
||||
|
||||
const SavedViewDetailsState({
|
||||
this.viewType = ViewType.list,
|
||||
super.filter,
|
||||
super.hasLoaded,
|
||||
super.isLoading,
|
||||
super.value,
|
||||
this.correspondents = const {},
|
||||
this.documentTypes = const {},
|
||||
this.tags = const {},
|
||||
this.storagePaths = const {},
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
viewType,
|
||||
correspondents,
|
||||
documentTypes,
|
||||
tags,
|
||||
storagePaths,
|
||||
...super.props,
|
||||
];
|
||||
|
||||
@@ -40,6 +53,10 @@ class SavedViewDetailsState extends DocumentPagingState {
|
||||
List<PagedSearchResult<DocumentModel>>? value,
|
||||
DocumentFilter? filter,
|
||||
ViewType? viewType,
|
||||
Map<int, Correspondent>? correspondents,
|
||||
Map<int, DocumentType>? documentTypes,
|
||||
Map<int, Tag>? tags,
|
||||
Map<int, StoragePath>? storagePaths,
|
||||
}) {
|
||||
return SavedViewDetailsState(
|
||||
hasLoaded: hasLoaded ?? this.hasLoaded,
|
||||
@@ -47,6 +64,10 @@ class SavedViewDetailsState extends DocumentPagingState {
|
||||
value: value ?? this.value,
|
||||
filter: filter ?? this.filter,
|
||||
viewType: viewType ?? this.viewType,
|
||||
correspondents: correspondents ?? this.correspondents,
|
||||
documentTypes: documentTypes ?? this.documentTypes,
|
||||
tags: tags ?? this.tags,
|
||||
storagePaths: storagePaths ?? this.storagePaths,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -86,6 +86,10 @@ class _SavedViewDetailsPageState extends State<SavedViewDetailsPage>
|
||||
);
|
||||
},
|
||||
viewType: state.viewType,
|
||||
correspondents: state.correspondents,
|
||||
documentTypes: state.documentTypes,
|
||||
tags: state.tags,
|
||||
storagePaths: state.storagePaths,
|
||||
),
|
||||
if (state.hasLoaded && state.isLoading)
|
||||
const SliverToBoxAdapter(
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:bloc/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/paged_document_view/cubit/paged_documents_state.dart';
|
||||
|
||||
@@ -13,19 +14,33 @@ class SimilarDocumentsCubit extends Cubit<SimilarDocumentsState>
|
||||
@override
|
||||
final PaperlessDocumentsApi api;
|
||||
|
||||
final LabelRepository _labelRepository;
|
||||
|
||||
@override
|
||||
final DocumentChangedNotifier notifier;
|
||||
|
||||
SimilarDocumentsCubit(
|
||||
this.api,
|
||||
this.notifier, {
|
||||
this.notifier,
|
||||
this._labelRepository, {
|
||||
required this.documentId,
|
||||
}) : super(const SimilarDocumentsState()) {
|
||||
notifier.subscribe(
|
||||
notifier.addListener(
|
||||
this,
|
||||
onDeleted: remove,
|
||||
onUpdated: replace,
|
||||
);
|
||||
_labelRepository.addListener(
|
||||
this,
|
||||
onChanged: (labels) {
|
||||
emit(state.copyWith(
|
||||
correspondents: labels.correspondents,
|
||||
documentTypes: labels.documentTypes,
|
||||
tags: labels.tags,
|
||||
storagePaths: labels.storagePaths,
|
||||
));
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> initialize() async {
|
||||
@@ -38,4 +53,11 @@ class SimilarDocumentsCubit extends Cubit<SimilarDocumentsState>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
notifier.removeListener(this);
|
||||
_labelRepository.removeListener(this);
|
||||
return super.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,20 @@
|
||||
part of 'similar_documents_cubit.dart';
|
||||
|
||||
class SimilarDocumentsState extends DocumentPagingState {
|
||||
final Map<int, Correspondent> correspondents;
|
||||
final Map<int, DocumentType> documentTypes;
|
||||
final Map<int, Tag> tags;
|
||||
final Map<int, StoragePath> storagePaths;
|
||||
|
||||
const SimilarDocumentsState({
|
||||
super.filter,
|
||||
super.hasLoaded,
|
||||
super.isLoading,
|
||||
super.value,
|
||||
this.correspondents = const {},
|
||||
this.documentTypes = const {},
|
||||
this.tags = const {},
|
||||
this.storagePaths = const {},
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -14,6 +23,10 @@ class SimilarDocumentsState extends DocumentPagingState {
|
||||
hasLoaded,
|
||||
isLoading,
|
||||
value,
|
||||
correspondents,
|
||||
documentTypes,
|
||||
tags,
|
||||
storagePaths,
|
||||
];
|
||||
|
||||
@override
|
||||
@@ -36,12 +49,20 @@ class SimilarDocumentsState extends DocumentPagingState {
|
||||
bool? isLoading,
|
||||
List<PagedSearchResult<DocumentModel>>? value,
|
||||
DocumentFilter? filter,
|
||||
Map<int, Correspondent>? correspondents,
|
||||
Map<int, DocumentType>? documentTypes,
|
||||
Map<int, Tag>? tags,
|
||||
Map<int, StoragePath>? storagePaths,
|
||||
}) {
|
||||
return SimilarDocumentsState(
|
||||
hasLoaded: hasLoaded ?? this.hasLoaded,
|
||||
isLoading: isLoading ?? this.isLoading,
|
||||
value: value ?? this.value,
|
||||
filter: filter ?? this.filter,
|
||||
correspondents: correspondents ?? this.correspondents,
|
||||
documentTypes: documentTypes ?? this.documentTypes,
|
||||
tags: tags ?? this.tags,
|
||||
storagePaths: storagePaths ?? this.storagePaths,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,6 +78,10 @@ class _SimilarDocumentsViewState extends State<SimilarDocumentsView>
|
||||
),
|
||||
);
|
||||
},
|
||||
correspondents: state.correspondents,
|
||||
documentTypes: state.documentTypes,
|
||||
tags: state.tags,
|
||||
storagePaths: state.storagePaths,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -21,7 +21,6 @@ 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/saved_view_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';
|
||||
@@ -101,7 +100,7 @@ void main() async {
|
||||
|
||||
// Create repositories
|
||||
final labelRepository = LabelRepository(labelsApi);
|
||||
final savedViewRepository = SavedViewRepositoryImpl(savedViewsApi);
|
||||
final savedViewRepository = SavedViewRepository(savedViewsApi);
|
||||
|
||||
//Create cubits/blocs
|
||||
final authCubit = AuthenticationCubit(
|
||||
|
||||
Reference in New Issue
Block a user