feat: Fix hive errors, change provider hierarchy for blocs, translate strings

This commit is contained in:
Anton Stubenbord
2023-04-25 01:16:14 +02:00
parent 1f335119b3
commit 8c2a6928b4
34 changed files with 502 additions and 363 deletions

View File

@@ -54,12 +54,16 @@ class DocumentDetailsCubit extends Cubit<DocumentDetailsState> {
Future<void> loadSuggestions() async { Future<void> loadSuggestions() async {
final suggestions = await _api.findSuggestions(state.document); final suggestions = await _api.findSuggestions(state.document);
emit(state.copyWith(suggestions: suggestions)); if (!isClosed) {
emit(state.copyWith(suggestions: suggestions));
}
} }
Future<void> loadMetaData() async { Future<void> loadMetaData() async {
final metaData = await _api.getMetaData(state.document); final metaData = await _api.getMetaData(state.document);
emit(state.copyWith(metaData: metaData)); if (!isClosed) {
emit(state.copyWith(metaData: metaData));
}
} }
Future<void> loadFullContent() async { Future<void> loadFullContent() async {
@@ -85,8 +89,8 @@ class DocumentDetailsCubit extends Cubit<DocumentDetailsState> {
_notifier.notifyUpdated(updatedDocument); _notifier.notifyUpdated(updatedDocument);
} else { } else {
final int autoAsn = await _api.findNextAsn(); final int autoAsn = await _api.findNextAsn();
final updatedDocument = await _api final updatedDocument =
.update(document.copyWith(archiveSerialNumber: () => autoAsn)); await _api.update(document.copyWith(archiveSerialNumber: () => autoAsn));
_notifier.notifyUpdated(updatedDocument); _notifier.notifyUpdated(updatedDocument);
} }
} }
@@ -97,8 +101,7 @@ class DocumentDetailsCubit extends Cubit<DocumentDetailsState> {
if (state.metaData == null) { if (state.metaData == null) {
await loadMetaData(); await loadMetaData();
} }
final desc = FileDescription.fromPath( final desc = FileDescription.fromPath(state.metaData!.mediaFilename.replaceAll("/", " "));
state.metaData!.mediaFilename.replaceAll("/", " "));
final fileName = "${desc.filename}.pdf"; final fileName = "${desc.filename}.pdf";
final file = File("${cacheDir.path}/$fileName"); final file = File("${cacheDir.path}/$fileName");
@@ -132,8 +135,7 @@ class DocumentDetailsCubit extends Cubit<DocumentDetailsState> {
await FileService.downloadsDirectory, await FileService.downloadsDirectory,
); );
final desc = FileDescription.fromPath( final desc = FileDescription.fromPath(
state.metaData!.mediaFilename state.metaData!.mediaFilename.replaceAll("/", " "), // Flatten directory structure
.replaceAll("/", " "), // Flatten directory structure
); );
if (!File(filePath).existsSync()) { if (!File(filePath).existsSync()) {
File(filePath).createSync(); File(filePath).createSync();
@@ -198,8 +200,7 @@ class DocumentDetailsCubit extends Cubit<DocumentDetailsState> {
String _buildDownloadFilePath(bool original, Directory dir) { String _buildDownloadFilePath(bool original, Directory dir) {
final description = FileDescription.fromPath( final description = FileDescription.fromPath(
state.metaData!.mediaFilename state.metaData!.mediaFilename.replaceAll("/", " "), // Flatten directory structure
.replaceAll("/", " "), // Flatten directory structure
); );
final extension = original ? description.extension : 'pdf'; final extension = original ? description.extension : 'pdf';
return "${dir.path}/${description.filename}.$extension"; return "${dir.path}/${description.filename}.$extension";

View File

@@ -60,36 +60,28 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return WillPopScope( return WillPopScope(
onWillPop: () async { onWillPop: () async {
Navigator.of(context) Navigator.of(context).pop(context.read<DocumentDetailsCubit>().state.document);
.pop(context.read<DocumentDetailsCubit>().state.document);
return false; return false;
}, },
child: DefaultTabController( child: DefaultTabController(
length: 4, length: 4,
child: BlocListener<ConnectivityCubit, ConnectivityState>( child: BlocListener<ConnectivityCubit, ConnectivityState>(
listenWhen: (previous, current) => listenWhen: (previous, current) => !previous.isConnected && current.isConnected,
!previous.isConnected && current.isConnected,
listener: (context, state) { listener: (context, state) {
_loadMetaData(); _loadMetaData();
setState(() {}); setState(() {});
}, },
child: Scaffold( child: Scaffold(
extendBodyBehindAppBar: false, extendBodyBehindAppBar: false,
floatingActionButtonLocation: floatingActionButtonLocation: FloatingActionButtonLocation.endDocked,
FloatingActionButtonLocation.endDocked,
floatingActionButton: widget.allowEdit ? _buildEditButton() : null, floatingActionButton: widget.allowEdit ? _buildEditButton() : null,
bottomNavigationBar: _buildBottomAppBar(), bottomNavigationBar: _buildBottomAppBar(),
body: NestedScrollView( body: NestedScrollView(
headerSliverBuilder: (context, innerBoxIsScrolled) => [ headerSliverBuilder: (context, innerBoxIsScrolled) => [
SliverOverlapAbsorber( SliverOverlapAbsorber(
handle: handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
NestedScrollView.sliverOverlapAbsorberHandleFor(context),
sliver: SliverAppBar( sliver: SliverAppBar(
title: Text(context title: Text(context.watch<DocumentDetailsCubit>().state.document.title),
.watch<DocumentDetailsCubit>()
.state
.document
.title),
leading: const BackButton(), leading: const BackButton(),
pinned: true, pinned: true,
forceElevated: innerBoxIsScrolled, forceElevated: innerBoxIsScrolled,
@@ -99,8 +91,7 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
background: Stack( background: Stack(
alignment: Alignment.topCenter, alignment: Alignment.topCenter,
children: [ children: [
BlocBuilder<DocumentDetailsCubit, BlocBuilder<DocumentDetailsCubit, DocumentDetailsState>(
DocumentDetailsState>(
builder: (context, state) => Positioned.fill( builder: (context, state) => Positioned.fill(
child: DocumentPreview( child: DocumentPreview(
document: state.document, document: state.document,
@@ -137,9 +128,7 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
child: Text( child: Text(
S.of(context)!.overview, S.of(context)!.overview,
style: TextStyle( style: TextStyle(
color: Theme.of(context) color: Theme.of(context).colorScheme.onPrimaryContainer,
.colorScheme
.onPrimaryContainer,
), ),
), ),
), ),
@@ -147,9 +136,7 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
child: Text( child: Text(
S.of(context)!.content, S.of(context)!.content,
style: TextStyle( style: TextStyle(
color: Theme.of(context) color: Theme.of(context).colorScheme.onPrimaryContainer,
.colorScheme
.onPrimaryContainer,
), ),
), ),
), ),
@@ -157,9 +144,7 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
child: Text( child: Text(
S.of(context)!.metaData, S.of(context)!.metaData,
style: TextStyle( style: TextStyle(
color: Theme.of(context) color: Theme.of(context).colorScheme.onPrimaryContainer,
.colorScheme
.onPrimaryContainer,
), ),
), ),
), ),
@@ -167,9 +152,7 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
child: Text( child: Text(
S.of(context)!.similarDocuments, S.of(context)!.similarDocuments,
style: TextStyle( style: TextStyle(
color: Theme.of(context) color: Theme.of(context).colorScheme.onPrimaryContainer,
.colorScheme
.onPrimaryContainer,
), ),
), ),
), ),
@@ -198,8 +181,7 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
CustomScrollView( CustomScrollView(
slivers: [ slivers: [
SliverOverlapInjector( SliverOverlapInjector(
handle: NestedScrollView handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
.sliverOverlapAbsorberHandleFor(context),
), ),
DocumentOverviewWidget( DocumentOverviewWidget(
document: state.document, document: state.document,
@@ -215,8 +197,7 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
CustomScrollView( CustomScrollView(
slivers: [ slivers: [
SliverOverlapInjector( SliverOverlapInjector(
handle: NestedScrollView handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
.sliverOverlapAbsorberHandleFor(context),
), ),
DocumentContentWidget( DocumentContentWidget(
isFullContentLoaded: state.isFullContentLoaded, isFullContentLoaded: state.isFullContentLoaded,
@@ -229,8 +210,7 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
CustomScrollView( CustomScrollView(
slivers: [ slivers: [
SliverOverlapInjector( SliverOverlapInjector(
handle: NestedScrollView handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
.sliverOverlapAbsorberHandleFor(context),
), ),
DocumentMetaDataWidget( DocumentMetaDataWidget(
document: state.document, document: state.document,
@@ -242,8 +222,7 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
controller: _pagingScrollController, controller: _pagingScrollController,
slivers: [ slivers: [
SliverOverlapInjector( SliverOverlapInjector(
handle: NestedScrollView handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
.sliverOverlapAbsorberHandleFor(context),
), ),
SimilarDocumentsView( SimilarDocumentsView(
pagingScrollController: _pagingScrollController, pagingScrollController: _pagingScrollController,
@@ -301,9 +280,8 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
IconButton( IconButton(
tooltip: S.of(context)!.deleteDocumentTooltip, tooltip: S.of(context)!.deleteDocumentTooltip,
icon: const Icon(Icons.delete), icon: const Icon(Icons.delete),
onPressed: widget.allowEdit && isConnected onPressed:
? () => _onDelete(state.document) widget.allowEdit && isConnected ? () => _onDelete(state.document) : null,
: null,
).paddedSymmetrically(horizontal: 4), ).paddedSymmetrically(horizontal: 4),
DocumentDownloadButton( DocumentDownloadButton(
document: state.document, document: state.document,
@@ -313,8 +291,7 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
IconButton( IconButton(
tooltip: S.of(context)!.previewTooltip, tooltip: S.of(context)!.previewTooltip,
icon: const Icon(Icons.visibility), icon: const Icon(Icons.visibility),
onPressed: onPressed: isConnected ? () => _onOpen(state.document) : null,
isConnected ? () => _onOpen(state.document) : null,
).paddedOnly(right: 4.0), ).paddedOnly(right: 4.0),
IconButton( IconButton(
tooltip: S.of(context)!.openInSystemViewer, tooltip: S.of(context)!.openInSystemViewer,
@@ -352,8 +329,7 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
), ),
], ],
child: BlocListener<DocumentEditCubit, DocumentEditState>( child: BlocListener<DocumentEditCubit, DocumentEditState>(
listenWhen: (previous, current) => listenWhen: (previous, current) => previous.document != current.document,
previous.document != current.document,
listener: (context, state) { listener: (context, state) {
cubit.replace(state.document); cubit.replace(state.document);
}, },
@@ -373,8 +349,7 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
} }
void _onOpenFileInSystemViewer() async { void _onOpenFileInSystemViewer() async {
final status = final status = await context.read<DocumentDetailsCubit>().openDocumentInSystemViewer();
await context.read<DocumentDetailsCubit>().openDocumentInSystemViewer();
if (status == ResultType.done) return; if (status == ResultType.done) return;
if (status == ResultType.noAppToOpen) { if (status == ResultType.noAppToOpen) {
showGenericError(context, S.of(context)!.noAppToDisplayPDFFilesFound); showGenericError(context, S.of(context)!.noAppToDisplayPDFFilesFound);
@@ -383,16 +358,14 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
showGenericError(context, translateError(context, ErrorCode.unknown)); showGenericError(context, translateError(context, ErrorCode.unknown));
} }
if (status == ResultType.permissionDenied) { if (status == ResultType.permissionDenied) {
showGenericError( showGenericError(context, S.of(context)!.couldNotOpenFilePermissionDenied);
context, S.of(context)!.couldNotOpenFilePermissionDenied);
} }
} }
void _onDelete(DocumentModel document) async { void _onDelete(DocumentModel document) async {
final delete = await showDialog( final delete = await showDialog(
context: context, context: context,
builder: (context) => builder: (context) => DeleteDocumentConfirmationDialog(document: document),
DeleteDocumentConfirmationDialog(document: document),
) ?? ) ??
false; false;
if (delete) { if (delete) {
@@ -412,8 +385,7 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
Navigator.of(context).push( Navigator.of(context).push(
MaterialPageRoute( MaterialPageRoute(
builder: (context) => DocumentView( builder: (context) => DocumentView(
documentBytes: documentBytes: context.read<PaperlessDocumentsApi>().getPreview(document.id),
context.read<PaperlessDocumentsApi>().getPreview(document.id),
), ),
), ),
); );

View File

@@ -190,7 +190,7 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
allowCreation: true, allowCreation: true,
allowExclude: false, allowExclude: false,
initialValue: TagsQuery.ids( initialValue: TagsQuery.ids(
include: state.document.tags, include: state.document.tags.toList(),
), ),
).padded(), ).padded(),
if (_filteredSuggestions?.tags if (_filteredSuggestions?.tags

View File

@@ -1,27 +1,32 @@
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:hydrated_bloc/hydrated_bloc.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_api/paperless_api.dart';
import 'package:paperless_mobile/core/database/tables/user_app_state.dart';
import 'package:paperless_mobile/core/notifier/document_changed_notifier.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.dart';
import 'package:paperless_mobile/core/database/tables/user_account.dart';
import 'package:paperless_mobile/features/paged_document_view/cubit/document_paging_bloc_mixin.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'; import 'package:paperless_mobile/features/paged_document_view/cubit/paged_documents_state.dart';
import 'package:paperless_mobile/core/database/tables/user_settings.dart';
import 'package:paperless_mobile/features/settings/model/view_type.dart'; import 'package:paperless_mobile/features/settings/model/view_type.dart';
part 'document_search_state.dart';
part 'document_search_cubit.g.dart'; part 'document_search_cubit.g.dart';
part 'document_search_state.dart';
class DocumentSearchCubit extends HydratedCubit<DocumentSearchState> with DocumentPagingBlocMixin { class DocumentSearchCubit extends Cubit<DocumentSearchState> with DocumentPagingBlocMixin {
@override @override
final PaperlessDocumentsApi api; final PaperlessDocumentsApi api;
final LabelRepository _labelRepository; final LabelRepository _labelRepository;
@override @override
final DocumentChangedNotifier notifier; final DocumentChangedNotifier notifier;
DocumentSearchCubit(this.api, this.notifier, this._labelRepository)
: super(const DocumentSearchState()) { final UserAppState _userAppState;
DocumentSearchCubit(
this.api,
this.notifier,
this._labelRepository,
this._userAppState,
) : super(DocumentSearchState(searchHistory: _userAppState.documentSearchHistory)) {
_labelRepository.addListener( _labelRepository.addListener(
this, this,
onChanged: (labels) { onChanged: (labels) {
@@ -61,6 +66,9 @@ class DocumentSearchCubit extends HydratedCubit<DocumentSearchState> with Docume
], ],
), ),
); );
_userAppState
..documentSearchHistory = state.searchHistory
..save();
} }
void updateViewType(ViewType viewType) { void updateViewType(ViewType viewType) {
@@ -73,6 +81,9 @@ class DocumentSearchCubit extends HydratedCubit<DocumentSearchState> with Docume
searchHistory: state.searchHistory.whereNot((element) => element == entry).toList(), searchHistory: state.searchHistory.whereNot((element) => element == entry).toList(),
), ),
); );
_userAppState
..documentSearchHistory = state.searchHistory
..save();
} }
Future<void> suggest(String query) async { Future<void> suggest(String query) async {
@@ -92,11 +103,13 @@ class DocumentSearchCubit extends HydratedCubit<DocumentSearchState> with Docume
} }
void reset() { void reset() {
emit(state.copyWith( emit(
view: SearchView.suggestions, state.copyWith(
suggestions: [], view: SearchView.suggestions,
isLoading: false, suggestions: [],
)); isLoading: false,
),
);
} }
@override @override
@@ -106,16 +119,6 @@ class DocumentSearchCubit extends HydratedCubit<DocumentSearchState> with Docume
return super.close(); return super.close();
} }
@override
DocumentSearchState? fromJson(Map<String, dynamic> json) {
return DocumentSearchState.fromJson(json);
}
@override
Map<String, dynamic>? toJson(DocumentSearchState state) {
return state.toJson();
}
@override @override
Future<void> onFilterUpdated(DocumentFilter filter) async {} Future<void> onFilterUpdated(DocumentFilter filter) async {}
} }

View File

@@ -3,6 +3,10 @@ import 'dart:async';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:hive/hive.dart';
import 'package:paperless_mobile/core/config/hive/hive_config.dart';
import 'package:paperless_mobile/core/database/tables/global_settings.dart';
import 'package:paperless_mobile/core/database/tables/user_app_state.dart';
import 'package:paperless_mobile/extensions/flutter_extensions.dart'; import 'package:paperless_mobile/extensions/flutter_extensions.dart';
import 'package:paperless_mobile/features/document_search/cubit/document_search_cubit.dart'; import 'package:paperless_mobile/features/document_search/cubit/document_search_cubit.dart';
import 'package:paperless_mobile/features/document_search/view/remove_history_entry_dialog.dart'; import 'package:paperless_mobile/features/document_search/view/remove_history_entry_dialog.dart';
@@ -14,6 +18,8 @@ import 'package:paperless_mobile/routes/document_details_route.dart';
import 'dart:math' as math; import 'dart:math' as math;
Future<void> showDocumentSearchPage(BuildContext context) { Future<void> showDocumentSearchPage(BuildContext context) {
final currentUser =
Hive.box<GlobalSettings>(HiveBoxes.globalSettings).getValue()!.currentLoggedInUser;
return Navigator.of(context).push( return Navigator.of(context).push(
MaterialPageRoute( MaterialPageRoute(
builder: (context) => BlocProvider( builder: (context) => BlocProvider(
@@ -21,6 +27,7 @@ Future<void> showDocumentSearchPage(BuildContext context) {
context.read(), context.read(),
context.read(), context.read(),
context.read(), context.read(),
Hive.box<UserAppState>(HiveBoxes.userAppState).get(currentUser)!,
), ),
child: const DocumentSearchPage(), child: const DocumentSearchPage(),
), ),
@@ -111,9 +118,8 @@ class _DocumentSearchPageState extends State<DocumentSearchPage> {
} }
Widget _buildSuggestionsView(DocumentSearchState state) { Widget _buildSuggestionsView(DocumentSearchState state) {
final suggestions = state.suggestions final suggestions =
.whereNot((element) => state.searchHistory.contains(element)) state.suggestions.whereNot((element) => state.searchHistory.contains(element)).toList();
.toList();
final historyMatches = state.searchHistory final historyMatches = state.searchHistory
.where( .where(
(element) => element.startsWith(query), (element) => element.startsWith(query),
@@ -195,8 +201,7 @@ class _DocumentSearchPageState extends State<DocumentSearchPage> {
builder: (context, state) { builder: (context, state) {
return ViewTypeSelectionWidget( return ViewTypeSelectionWidget(
viewType: state.viewType, viewType: state.viewType,
onChanged: (type) => onChanged: (type) => context.read<DocumentSearchCubit>().updateViewType(type),
context.read<DocumentSearchCubit>().updateViewType(type),
); );
}, },
) )

View File

@@ -2,13 +2,11 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:hive_flutter/adapters.dart'; import 'package:hive_flutter/adapters.dart';
import 'package:paperless_mobile/core/bloc/paperless_server_information_cubit.dart'; import 'package:paperless_mobile/core/bloc/paperless_server_information_cubit.dart';
import 'package:paperless_mobile/core/bloc/paperless_server_information_state.dart';
import 'package:paperless_mobile/core/config/hive/hive_config.dart'; import 'package:paperless_mobile/core/config/hive/hive_config.dart';
import 'package:paperless_mobile/core/database/tables/user_account.dart';
import 'package:paperless_mobile/core/delegate/customizable_sliver_persistent_header_delegate.dart'; import 'package:paperless_mobile/core/delegate/customizable_sliver_persistent_header_delegate.dart';
import 'package:paperless_mobile/core/widgets/material/search/m3_search_bar.dart' as s; import 'package:paperless_mobile/core/widgets/material/search/m3_search_bar.dart' as s;
import 'package:paperless_mobile/features/document_search/view/document_search_page.dart'; import 'package:paperless_mobile/features/document_search/view/document_search_page.dart';
import 'package:paperless_mobile/core/database/tables/user_account.dart';
import 'package:paperless_mobile/features/settings/view/dialogs/account_settings_dialog.dart';
import 'package:paperless_mobile/features/settings/view/manage_accounts_page.dart'; import 'package:paperless_mobile/features/settings/view/manage_accounts_page.dart';
import 'package:paperless_mobile/features/settings/view/widgets/global_settings_builder.dart'; import 'package:paperless_mobile/features/settings/view/widgets/global_settings_builder.dart';
import 'package:paperless_mobile/features/settings/view/widgets/user_avatar.dart'; import 'package:paperless_mobile/features/settings/view/widgets/user_avatar.dart';

View File

@@ -15,7 +15,7 @@ import 'package:paperless_mobile/features/settings/model/view_type.dart';
part 'documents_cubit.g.dart'; part 'documents_cubit.g.dart';
part 'documents_state.dart'; part 'documents_state.dart';
class DocumentsCubit extends HydratedCubit<DocumentsState> with DocumentPagingBlocMixin { class DocumentsCubit extends Cubit<DocumentsState> with DocumentPagingBlocMixin {
@override @override
final PaperlessDocumentsApi api; final PaperlessDocumentsApi api;

View File

@@ -461,8 +461,8 @@ class _DocumentsPageState extends State<DocumentsPage> with SingleTickerProvider
context.read<DocumentsCubit>().updateCurrentFilter( context.read<DocumentsCubit>().updateCurrentFilter(
(filter) => filter.copyWith( (filter) => filter.copyWith(
tags: tagsQuery.copyWith( tags: tagsQuery.copyWith(
include: tagsQuery.include.whereNot((id) => id == tagId), include: tagsQuery.include.whereNot((id) => id == tagId).toList(),
exclude: tagsQuery.exclude.whereNot((id) => id == tagId)), exclude: tagsQuery.exclude.whereNot((id) => id == tagId).toList()),
), ),
); );
} else { } else {

View File

@@ -11,6 +11,7 @@ import 'package:paperless_api/paperless_api.dart';
import 'package:paperless_mobile/core/bloc/connectivity_cubit.dart'; import 'package:paperless_mobile/core/bloc/connectivity_cubit.dart';
import 'package:paperless_mobile/core/bloc/paperless_server_information_cubit.dart'; import 'package:paperless_mobile/core/bloc/paperless_server_information_cubit.dart';
import 'package:paperless_mobile/core/config/hive/hive_config.dart'; import 'package:paperless_mobile/core/config/hive/hive_config.dart';
import 'package:paperless_mobile/core/database/tables/global_settings.dart';
import 'package:paperless_mobile/core/database/tables/user_app_state.dart'; import 'package:paperless_mobile/core/database/tables/user_app_state.dart';
import 'package:paperless_mobile/core/global/constants.dart'; import 'package:paperless_mobile/core/global/constants.dart';
import 'package:paperless_mobile/core/repository/label_repository.dart'; import 'package:paperless_mobile/core/repository/label_repository.dart';
@@ -40,6 +41,8 @@ import 'package:paperless_mobile/helpers/message_helpers.dart';
import 'package:receive_sharing_intent/receive_sharing_intent.dart'; import 'package:receive_sharing_intent/receive_sharing_intent.dart';
import 'package:responsive_builder/responsive_builder.dart'; import 'package:responsive_builder/responsive_builder.dart';
/// Wrapper around all functionality for a logged in user.
/// Performs initialization logic.
class HomePage extends StatefulWidget { class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key); const HomePage({Key? key}) : super(key: key);
@@ -50,14 +53,37 @@ class HomePage extends StatefulWidget {
class _HomePageState extends State<HomePage> with WidgetsBindingObserver { class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
int _currentIndex = 0; int _currentIndex = 0;
final DocumentScannerCubit _scannerCubit = DocumentScannerCubit(); final DocumentScannerCubit _scannerCubit = DocumentScannerCubit();
late final DocumentsCubit _documentsCubit;
late final InboxCubit _inboxCubit; late final InboxCubit _inboxCubit;
late final SavedViewCubit _savedViewCubit;
late Timer _inboxTimer; late Timer _inboxTimer;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
WidgetsBinding.instance.addObserver(this); WidgetsBinding.instance.addObserver(this);
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
_listenForReceivedFiles();
});
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
_initializeData(context); _initializeData(context);
final userId =
Hive.box<GlobalSettings>(HiveBoxes.globalSettings).getValue()!.currentLoggedInUser;
_documentsCubit = DocumentsCubit(
context.read(),
context.read(),
context.read(),
Hive.box<UserAppState>(HiveBoxes.userAppState).get(userId)!,
)..reload();
_savedViewCubit = SavedViewCubit(
context.read(),
context.read(),
)..reload();
_inboxCubit = InboxCubit( _inboxCubit = InboxCubit(
context.read(), context.read(),
context.read(), context.read(),
@@ -65,14 +91,9 @@ class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
context.read(), context.read(),
); );
_listenToInboxChanges(); _listenToInboxChanges();
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
_listenForReceivedFiles();
});
} }
void _listenToInboxChanges() { void _listenToInboxChanges() {
_inboxCubit.refreshItemsInInboxCount();
_inboxTimer = Timer.periodic(const Duration(seconds: 10), (timer) { _inboxTimer = Timer.periodic(const Duration(seconds: 10), (timer) {
if (!mounted) { if (!mounted) {
timer.cancel(); timer.cancel();
@@ -108,6 +129,8 @@ class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
WidgetsBinding.instance.removeObserver(this); WidgetsBinding.instance.removeObserver(this);
_inboxTimer.cancel(); _inboxTimer.cancel();
_inboxCubit.close(); _inboxCubit.close();
_documentsCubit.close();
_savedViewCubit.close();
super.dispose(); super.dispose();
} }
@@ -190,7 +213,8 @@ class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final userId = context.watch<AuthenticationCubit>().state.userId; final userId =
Hive.box<GlobalSettings>(HiveBoxes.globalSettings).getValue()!.currentLoggedInUser!;
final destinations = [ final destinations = [
RouteDescription( RouteDescription(
icon: const Icon(Icons.description_outlined), icon: const Icon(Icons.description_outlined),
@@ -239,22 +263,10 @@ class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
]; ];
final routes = <Widget>[ final routes = <Widget>[
MultiBlocProvider( MultiBlocProvider(
key: ValueKey(userId), // key: ValueKey(userId),
providers: [ providers: [
BlocProvider( BlocProvider.value(value: _documentsCubit),
create: (context) => DocumentsCubit( BlocProvider.value(value: _savedViewCubit),
context.read(),
context.read(),
context.read(),
Hive.box<UserAppState>(HiveBoxes.userAppState).get(userId)!,
)..reload(),
),
BlocProvider(
create: (context) => SavedViewCubit(
context.read(),
context.read(),
)..reload(),
),
], ],
child: const DocumentsPage(), child: const DocumentsPage(),
), ),
@@ -263,7 +275,7 @@ class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
child: const ScannerPage(), child: const ScannerPage(),
), ),
MultiBlocProvider( MultiBlocProvider(
key: ValueKey(userId), // key: ValueKey(userId),
providers: [ providers: [
BlocProvider( BlocProvider(
create: (context) => LabelCubit(context.read()), create: (context) => LabelCubit(context.read()),

View File

@@ -97,7 +97,7 @@ class InboxCubit extends HydratedCubit<InboxState> with DocumentPagingBlocMixin
updateFilter( updateFilter(
filter: DocumentFilter( filter: DocumentFilter(
sortField: SortField.added, sortField: SortField.added,
tags: TagsQuery.ids(include: inboxTags), tags: TagsQuery.ids(include: inboxTags.toList()),
), ),
); );
} }
@@ -127,7 +127,7 @@ class InboxCubit extends HydratedCubit<InboxState> with DocumentPagingBlocMixin
updateFilter( updateFilter(
filter: DocumentFilter( filter: DocumentFilter(
sortField: SortField.added, sortField: SortField.added,
tags: TagsQuery.ids(include: inboxTags), tags: TagsQuery.ids(include: inboxTags.toList()),
), ),
); );
} }

View File

@@ -121,15 +121,15 @@ class TagsFormField extends StatelessWidget {
final tag = options[id]!; final tag = options[id]!;
return QueryTagChip( return QueryTagChip(
onDeleted: () => field.didChange(formValue.copyWith( onDeleted: () => field.didChange(formValue.copyWith(
include: formValue.include.whereNot((element) => element == id), include: formValue.include.whereNot((element) => element == id).toList(),
exclude: formValue.exclude.whereNot((element) => element == id), exclude: formValue.exclude.whereNot((element) => element == id).toList(),
)), )),
onSelected: allowExclude onSelected: allowExclude
? () { ? () {
if (formValue.include.contains(id)) { if (formValue.include.contains(id)) {
field.didChange( field.didChange(
formValue.copyWith( formValue.copyWith(
include: formValue.include.whereNot((element) => element == id), include: formValue.include.whereNot((element) => element == id).toList(),
exclude: [...formValue.exclude, id], exclude: [...formValue.exclude, id],
), ),
); );
@@ -137,7 +137,7 @@ class TagsFormField extends StatelessWidget {
field.didChange( field.didChange(
formValue.copyWith( formValue.copyWith(
include: [...formValue.include, id], include: [...formValue.include, id],
exclude: formValue.exclude.whereNot((element) => element == id), exclude: formValue.exclude.whereNot((element) => element == id).toList(),
), ),
); );
} }
@@ -171,7 +171,7 @@ class TagsFormField extends StatelessWidget {
return QueryTagChip( return QueryTagChip(
onDeleted: () { onDeleted: () {
final updatedQuery = query.copyWith( final updatedQuery = query.copyWith(
tagIds: query.tagIds.whereNot((element) => element == e), tagIds: query.tagIds.whereNot((element) => element == e).toList(),
); );
if (updatedQuery.tagIds.isEmpty) { if (updatedQuery.tagIds.isEmpty) {
field.didChange(const TagsQuery.ids()); field.didChange(const TagsQuery.ids());

View File

@@ -59,7 +59,6 @@ class LabelItem<T extends Label> extends StatelessWidget {
context.read(), context.read(),
context.read(), context.read(),
context.read(), context.read(),
Hive.box<UserAccount>(HiveBoxes.userAccount).get(currentUser)!,
), ),
child: const LinkedDocumentsPage(), child: const LinkedDocumentsPage(),
), ),

View File

@@ -3,7 +3,6 @@ import 'package:json_annotation/json_annotation.dart';
import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_api/paperless_api.dart';
import 'package:paperless_mobile/core/notifier/document_changed_notifier.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.dart';
import 'package:paperless_mobile/core/database/tables/user_account.dart';
import 'package:paperless_mobile/features/paged_document_view/cubit/paged_documents_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'; 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:paperless_mobile/features/settings/model/view_type.dart';
@@ -21,15 +20,11 @@ class LinkedDocumentsCubit extends HydratedCubit<LinkedDocumentsState>
final LabelRepository _labelRepository; final LabelRepository _labelRepository;
@override
// TODO: implement account
final UserAccount account;
LinkedDocumentsCubit( LinkedDocumentsCubit(
DocumentFilter filter, DocumentFilter filter,
this.api, this.api,
this.notifier, this.notifier,
this._labelRepository, this._labelRepository,
this.account,
) : super(LinkedDocumentsState(filter: filter)) { ) : super(LinkedDocumentsState(filter: filter)) {
updateFilter(filter: filter); updateFilter(filter: filter);
_labelRepository.addListener( _labelRepository.addListener(

View File

@@ -143,8 +143,9 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
debugPrint("Invalid authentication for $userId"); debugPrint("Invalid authentication for $userId");
return; return;
} }
final credentials = credentialsBox.get(userId); final credentials = credentialsBox.get(userId);
await credentialsBox.close();
await _resetExternalState(); await _resetExternalState();
_dioWrapper.updateSettings( _dioWrapper.updateSettings(
@@ -154,9 +155,10 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
baseUrl: account.serverUrl, baseUrl: account.serverUrl,
); );
await _reloadRepositories();
globalSettings.currentLoggedInUser = userId; globalSettings.currentLoggedInUser = userId;
await globalSettings.save(); await globalSettings.save();
await _reloadRepositories();
emit( emit(
AuthenticationState( AuthenticationState(
isAuthenticated: true, isAuthenticated: true,

View File

@@ -65,7 +65,7 @@ class _ServerConnectionPageState extends State<ServerConnectionPage> {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
TextButton( TextButton(
child: Text("Test connection"), //TODO: INTL child: Text(S.of(context)!.testConnection),
onPressed: _updateReachability, onPressed: _updateReachability,
), ),
FilledButton( FilledButton(

View File

@@ -1,114 +0,0 @@
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:hive_flutter/adapters.dart';
import 'package:hydrated_bloc/hydrated_bloc.dart';
import 'package:paperless_api/paperless_api.dart';
import 'package:paperless_mobile/core/bloc/paperless_server_information_cubit.dart';
import 'package:paperless_mobile/core/bloc/paperless_server_information_state.dart';
import 'package:paperless_mobile/core/config/hive/hive_config.dart';
import 'package:paperless_mobile/core/widgets/hint_card.dart';
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
import 'package:paperless_mobile/features/login/cubit/authentication_cubit.dart';
import 'package:paperless_mobile/core/database/tables/user_account.dart';
import 'package:paperless_mobile/features/settings/view/widgets/global_settings_builder.dart';
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
import 'package:paperless_mobile/helpers/message_helpers.dart';
class AccountSettingsDialog extends StatelessWidget {
const AccountSettingsDialog({super.key});
@override
Widget build(BuildContext context) {
return GlobalSettingsBuilder(builder: (context, globalSettings) {
return AlertDialog(
insetPadding: EdgeInsets.symmetric(horizontal: 24, vertical: 32),
scrollable: true,
contentPadding: EdgeInsets.zero,
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(S.of(context)!.account),
const CloseButton(),
],
),
content: BlocBuilder<PaperlessServerInformationCubit, PaperlessServerInformationState>(
builder: (context, state) {
return Column(
children: [
ValueListenableBuilder(
valueListenable: Hive.box<UserAccount>(HiveBoxes.userAccount).listenable(),
builder: (context, box, _) {
// final currentUser = globalSettings.currentLoggedInUser;
final currentUser = null;
final accountIds =
box.keys.whereNot((element) => element == currentUser).toList();
final accounts = accountIds.map((id) => box.get(id)!).toList();
return ExpansionTile(
leading: CircleAvatar(
child: Text(state.information?.userInitials ?? ''),
),
title: Text(state.information?.username ?? ''),
subtitle: Text(state.information?.host ?? ''),
children:
accounts.map((account) => _buildAccountTile(account, true)).toList(),
);
},
),
ListTile(
dense: true,
leading: const Icon(Icons.person_add_rounded),
title: Text(S.of(context)!.addAnotherAccount),
onTap: () {},
),
const Divider(),
FilledButton(
style: ButtonStyle(
backgroundColor: MaterialStatePropertyAll(
Theme.of(context).colorScheme.error,
),
),
child: Text(
S.of(context)!.disconnect,
style: TextStyle(
color: Theme.of(context).colorScheme.onError,
),
),
onPressed: () async {
await _onLogout(context);
Navigator.of(context).maybePop();
},
).padded(16),
],
);
},
),
);
});
}
Future<void> _onLogout(BuildContext context) async {
try {
await context.read<AuthenticationCubit>().logout();
await HydratedBloc.storage.clear();
} on PaperlessServerException catch (error, stackTrace) {
showErrorMessage(context, error, stackTrace);
}
}
Widget _buildAccountTile(UserAccount account, bool isActive) {
return ListTile(
selected: isActive,
title: Text(account.username),
subtitle: Text(account.serverUrl),
leading: CircleAvatar(
child: Text((account.fullName ?? account.username)
.split(" ")
.take(2)
.map((e) => e.substring(0, 1))
.map((e) => e.toUpperCase())
.join(" ")),
),
);
}
}

View File

@@ -4,25 +4,19 @@ import 'package:paperless_mobile/core/widgets/dialog_utils/dialog_confirm_button
import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
class SwitchAccountDialog extends StatelessWidget { class SwitchAccountDialog extends StatelessWidget {
final String username; const SwitchAccountDialog({super.key});
final String serverUrl;
const SwitchAccountDialog({
super.key,
required this.username,
required this.serverUrl,
});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return AlertDialog( return AlertDialog(
title: Text("Switch account"), title: Text(S.of(context)!.switchAccountTitle),
content: Text("Do you want to switch to $serverUrl and log in as $username?"), content: Text(S.of(context)!.switchToNewAccount),
actions: [ actions: [
const DialogCancelButton(),
DialogConfirmButton( DialogConfirmButton(
style: DialogConfirmButtonStyle.danger, style: DialogConfirmButtonStyle.normal,
label: S.of(context)!.continueLabel, //TODO: INTL change labels label: S.of(context)!.switchAccount,
), ),
DialogCancelButton(),
], ],
); );
} }

View File

@@ -42,7 +42,7 @@ class ManageAccountsPage extends StatelessWidget {
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: CloseButton(), child: CloseButton(),
), ),
Center(child: Text("Accounts")), Center(child: Text(S.of(context)!.accounts)),
], ],
), //TODO: INTL ), //TODO: INTL
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
@@ -65,7 +65,7 @@ class ManageAccountsPage extends StatelessWidget {
), ),
const Divider(), const Divider(),
ListTile( ListTile(
title: const Text("Add account"), title: Text(S.of(context)!.addAccount),
leading: const Icon(Icons.person_add), leading: const Icon(Icons.person_add),
onTap: () { onTap: () {
_onAddAccount(context); _onAddAccount(context);
@@ -113,17 +113,17 @@ class ManageAccountsPage extends StatelessWidget {
itemBuilder: (context) { itemBuilder: (context) {
return [ return [
if (!isLoggedIn) if (!isLoggedIn)
const PopupMenuItem( PopupMenuItem(
child: ListTile( child: ListTile(
title: Text("Switch"), //TODO: INTL title: Text(S.of(context)!.switchAccount),
leading: Icon(Icons.switch_account_rounded), leading: Icon(Icons.switch_account_rounded),
), ),
value: 0, value: 0,
), ),
if (!isLoggedIn) if (!isLoggedIn)
const PopupMenuItem( PopupMenuItem(
child: ListTile( child: ListTile(
title: Text("Remove"), // TODO: INTL title: Text(S.of(context)!.remove),
leading: Icon( leading: Icon(
Icons.person_remove, Icons.person_remove,
color: Colors.red, color: Colors.red,
@@ -132,9 +132,9 @@ class ManageAccountsPage extends StatelessWidget {
value: 1, value: 1,
) )
else else
const PopupMenuItem( PopupMenuItem(
child: ListTile( child: ListTile(
title: Text("Logout"), // TODO: INTL title: Text(S.of(context)!.logout),
leading: Icon( leading: Icon(
Icons.person_remove, Icons.person_remove,
color: Colors.red, color: Colors.red,
@@ -177,12 +177,12 @@ class ManageAccountsPage extends StatelessWidget {
return child; return child;
} }
Future<void> _onAddAccount(BuildContext context) { Future<void> _onAddAccount(BuildContext context) async {
return Navigator.push( final userId = await Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (context) => LoginPage( builder: (context) => LoginPage(
titleString: "Add account", //TODO: INTL titleString: S.of(context)!.addAccount,
onSubmit: (context, username, password, serverUrl, clientCertificate) async { onSubmit: (context, username, password, serverUrl, clientCertificate) async {
final userId = await context.read<AuthenticationCubit>().addAccount( final userId = await context.read<AuthenticationCubit>().addAccount(
credentials: LoginFormCredentials( credentials: LoginFormCredentials(
@@ -194,19 +194,22 @@ class ManageAccountsPage extends StatelessWidget {
//TODO: Ask user whether to enable biometric authentication //TODO: Ask user whether to enable biometric authentication
enableBiometricAuthentication: false, enableBiometricAuthentication: false,
); );
final shoudSwitch = await showDialog( Navigator.of(context).pop<String?>(userId);
context: context,
builder: (context) =>
SwitchAccountDialog(username: username, serverUrl: serverUrl),
) ??
false;
if (shoudSwitch) {
context.read<AuthenticationCubit>().switchAccount(userId);
}
}, },
submitText: "Add account", //TODO: INTL submitText: S.of(context)!.addAccount,
), ),
), ),
); );
if (userId != null) {
final shoudSwitch = await showDialog<bool>(
context: context,
builder: (context) => const SwitchAccountDialog(),
) ??
false;
if (shoudSwitch) {
await context.read<AuthenticationCubit>().switchAccount(userId);
Navigator.pop(context);
}
}
} }
} }

View File

@@ -15,12 +15,8 @@ class ApplicationSettingsPage extends StatelessWidget {
actions: [ actions: [
Padding( Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: Tooltip( child: const Icon(Icons.public),
triggerMode: TooltipTriggerMode.tap, )
message: "These settings apply to all accounts", //TODO: INTL
child: Icon(Icons.info_outline),
),
),
], ],
), ),
body: ListView( body: ListView(

View File

@@ -13,12 +13,8 @@ class SecuritySettingsPage extends StatelessWidget {
actions: [ actions: [
Padding( Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: Tooltip( child: const Icon(Icons.person_outline),
triggerMode: TooltipTriggerMode.tap, )
message: "These settings apply to the current user only", //TODO: INTL
child: Icon(Icons.info_outline),
),
),
], ],
), ),
body: ListView( body: ListView(

View File

@@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
class SwitchingAccountsPage extends StatelessWidget { class SwitchingAccountsPage extends StatelessWidget {
const SwitchingAccountsPage({super.key}); const SwitchingAccountsPage({super.key});
@@ -6,17 +7,19 @@ class SwitchingAccountsPage extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return WillPopScope( return WillPopScope(
onWillPop: () async { onWillPop: () async => false,
return false;
},
child: Material( child: Material(
child: Center( child: Center(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
CircularProgressIndicator(), const CircularProgressIndicator(),
Text("Switching accounts. Please wait..."), const SizedBox(height: 16),
Text(
S.of(context)!.switchingAccountsPleaseWait,
style: Theme.of(context).textTheme.labelLarge,
),
], ],
), ),
), ),

View File

@@ -1,10 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:hive_flutter/adapters.dart';
import 'package:paperless_mobile/core/config/hive/hive_config.dart';
import 'package:paperless_mobile/features/login/services/authentication_service.dart'; import 'package:paperless_mobile/features/login/services/authentication_service.dart';
import 'package:paperless_mobile/core/database/tables/global_settings.dart';
import 'package:paperless_mobile/core/database/tables/user_settings.dart';
import 'package:paperless_mobile/features/settings/view/widgets/user_settings_builder.dart'; import 'package:paperless_mobile/features/settings/view/widgets/user_settings_builder.dart';
import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';

View File

@@ -729,5 +729,37 @@
"allTags": "All", "allTags": "All",
"@allTags": { "@allTags": {
"description": "Label shown when a document has to be assigned to all selected tags" "description": "Label shown when a document has to be assigned to all selected tags"
},
"switchingAccountsPleaseWait": "Switching accounts. Please wait...",
"@switchingAccountsPleaseWait": {
"description": "Message shown while switching accounts is in progress."
},
"testConnection": "Test connection",
"@testConnection": {
"description": "Button label shown on login page. Allows user to test whether the server is reachable or not."
},
"accounts": "Accounts",
"@accounts": {
"description": "Title of the account management dialog"
},
"addAccount": "Add account",
"@addAccount": {
"description": "Label of add account action"
},
"switchAccount": "Switch",
"@switchAccount": {
"description": "Label for switch account action"
},
"logout": "Logout",
"@logout": {
"description": "Generic Logout label"
},
"switchAccountTitle": "Switch account",
"@switchAccountTitle": {
"description": "Title of the dialog shown after adding an account, asking the user whether to switch to the newly added account or not."
},
"switchToNewAccount": "Do you want to switch to the new account? You can switch back at any time.",
"@switchToNewAccount": {
"description": "Content of the dialog shown after adding an account, asking the user whether to switch to the newly added account or not."
} }
} }

View File

@@ -729,5 +729,37 @@
"allTags": "Alle", "allTags": "Alle",
"@allTags": { "@allTags": {
"description": "Label shown when a document has to be assigned to all selected tags" "description": "Label shown when a document has to be assigned to all selected tags"
},
"switchingAccountsPleaseWait": "Kontowechsel, bitte warten...",
"@switchingAccountsPleaseWait": {
"description": "Message shown while switching accounts is in progress."
},
"testConnection": "Verbindung testen",
"@testConnection": {
"description": "Button label shown on login page. Allows user to test whether the server is reachable or not."
},
"accounts": "Accounts",
"@accounts": {
"description": "Title of the account management dialog"
},
"addAccount": "Account hinzufügen",
"@addAccount": {
"description": "Label of add account action"
},
"switchAccount": "Wechseln",
"@switchAccount": {
"description": "Label for switch account action"
},
"logout": "Ausloggen",
"@logout": {
"description": "Generic Logout label"
},
"switchAccountTitle": "Account wechseln",
"@switchAccountTitle": {
"description": "Title of the dialog shown after adding an account, asking the user whether to switch to the newly added account or not."
},
"switchToNewAccount": "Möchtest du zum neuen Account wechseln? Du kannst jederzeit zurückwechseln.",
"@switchToNewAccount": {
"description": "Content of the dialog shown after adding an account, asking the user whether to switch to the newly added account or not."
} }
} }

View File

@@ -729,5 +729,37 @@
"allTags": "All", "allTags": "All",
"@allTags": { "@allTags": {
"description": "Label shown when a document has to be assigned to all selected tags" "description": "Label shown when a document has to be assigned to all selected tags"
},
"switchingAccountsPleaseWait": "Switching accounts. Please wait...",
"@switchingAccountsPleaseWait": {
"description": "Message shown while switching accounts is in progress."
},
"testConnection": "Test connection",
"@testConnection": {
"description": "Button label shown on login page. Allows user to test whether the server is reachable or not."
},
"accounts": "Accounts",
"@accounts": {
"description": "Title of the account management dialog"
},
"addAccount": "Add account",
"@addAccount": {
"description": "Label of add account action"
},
"switchAccount": "Switch",
"@switchAccount": {
"description": "Label for switch account action"
},
"logout": "Logout",
"@logout": {
"description": "Generic Logout label"
},
"switchAccountTitle": "Switch account",
"@switchAccountTitle": {
"description": "Title of the dialog shown after adding an account, asking the user whether to switch to the newly added account or not."
},
"switchToNewAccount": "Do you want to switch to the new account? You can switch back at any time.",
"@switchToNewAccount": {
"description": "Content of the dialog shown after adding an account, asking the user whether to switch to the newly added account or not."
} }
} }

View File

@@ -729,5 +729,37 @@
"allTags": "All", "allTags": "All",
"@allTags": { "@allTags": {
"description": "Label shown when a document has to be assigned to all selected tags" "description": "Label shown when a document has to be assigned to all selected tags"
},
"switchingAccountsPleaseWait": "Switching accounts. Please wait...",
"@switchingAccountsPleaseWait": {
"description": "Message shown while switching accounts is in progress."
},
"testConnection": "Test connection",
"@testConnection": {
"description": "Button label shown on login page. Allows user to test whether the server is reachable or not."
},
"accounts": "Accounts",
"@accounts": {
"description": "Title of the account management dialog"
},
"addAccount": "Add account",
"@addAccount": {
"description": "Label of add account action"
},
"switchAccount": "Switch",
"@switchAccount": {
"description": "Label for switch account action"
},
"logout": "Logout",
"@logout": {
"description": "Generic Logout label"
},
"switchAccountTitle": "Switch account",
"@switchAccountTitle": {
"description": "Title of the dialog shown after adding an account, asking the user whether to switch to the newly added account or not."
},
"switchToNewAccount": "Do you want to switch to the new account? You can switch back at any time.",
"@switchToNewAccount": {
"description": "Content of the dialog shown after adding an account, asking the user whether to switch to the newly added account or not."
} }
} }

View File

@@ -729,5 +729,37 @@
"allTags": "All", "allTags": "All",
"@allTags": { "@allTags": {
"description": "Label shown when a document has to be assigned to all selected tags" "description": "Label shown when a document has to be assigned to all selected tags"
},
"switchingAccountsPleaseWait": "Switching accounts. Please wait...",
"@switchingAccountsPleaseWait": {
"description": "Message shown while switching accounts is in progress."
},
"testConnection": "Test connection",
"@testConnection": {
"description": "Button label shown on login page. Allows user to test whether the server is reachable or not."
},
"accounts": "Accounts",
"@accounts": {
"description": "Title of the account management dialog"
},
"addAccount": "Add account",
"@addAccount": {
"description": "Label of add account action"
},
"switchAccount": "Switch",
"@switchAccount": {
"description": "Label for switch account action"
},
"logout": "Logout",
"@logout": {
"description": "Generic Logout label"
},
"switchAccountTitle": "Switch account",
"@switchAccountTitle": {
"description": "Title of the dialog shown after adding an account, asking the user whether to switch to the newly added account or not."
},
"switchToNewAccount": "Do you want to switch to the new account? You can switch back at any time.",
"@switchToNewAccount": {
"description": "Content of the dialog shown after adding an account, asking the user whether to switch to the newly added account or not."
} }
} }

View File

@@ -729,5 +729,37 @@
"allTags": "All", "allTags": "All",
"@allTags": { "@allTags": {
"description": "Label shown when a document has to be assigned to all selected tags" "description": "Label shown when a document has to be assigned to all selected tags"
},
"switchingAccountsPleaseWait": "Switching accounts. Please wait...",
"@switchingAccountsPleaseWait": {
"description": "Message shown while switching accounts is in progress."
},
"testConnection": "Test connection",
"@testConnection": {
"description": "Button label shown on login page. Allows user to test whether the server is reachable or not."
},
"accounts": "Accounts",
"@accounts": {
"description": "Title of the account management dialog"
},
"addAccount": "Add account",
"@addAccount": {
"description": "Label of add account action"
},
"switchAccount": "Switch",
"@switchAccount": {
"description": "Label for switch account action"
},
"logout": "Logout",
"@logout": {
"description": "Generic Logout label"
},
"switchAccountTitle": "Switch account",
"@switchAccountTitle": {
"description": "Title of the dialog shown after adding an account, asking the user whether to switch to the newly added account or not."
},
"switchToNewAccount": "Do you want to switch to the new account? You can switch back at any time.",
"@switchToNewAccount": {
"description": "Content of the dialog shown after adding an account, asking the user whether to switch to the newly added account or not."
} }
} }

View File

@@ -729,5 +729,37 @@
"allTags": "All", "allTags": "All",
"@allTags": { "@allTags": {
"description": "Label shown when a document has to be assigned to all selected tags" "description": "Label shown when a document has to be assigned to all selected tags"
},
"switchingAccountsPleaseWait": "Switching accounts. Please wait...",
"@switchingAccountsPleaseWait": {
"description": "Message shown while switching accounts is in progress."
},
"testConnection": "Test connection",
"@testConnection": {
"description": "Button label shown on login page. Allows user to test whether the server is reachable or not."
},
"accounts": "Accounts",
"@accounts": {
"description": "Title of the account management dialog"
},
"addAccount": "Add account",
"@addAccount": {
"description": "Label of add account action"
},
"switchAccount": "Switch",
"@switchAccount": {
"description": "Label for switch account action"
},
"logout": "Logout",
"@logout": {
"description": "Generic Logout label"
},
"switchAccountTitle": "Switch account",
"@switchAccountTitle": {
"description": "Title of the dialog shown after adding an account, asking the user whether to switch to the newly added account or not."
},
"switchToNewAccount": "Do you want to switch to the new account? You can switch back at any time.",
"@switchToNewAccount": {
"description": "Content of the dialog shown after adding an account, asking the user whether to switch to the newly added account or not."
} }
} }

View File

@@ -319,7 +319,9 @@ class _AuthenticationWrapperState extends State<AuthenticationWrapper> {
), ),
), ),
], ],
child: const HomePage(), child: HomePage(
key: ValueKey(authentication.userId),
),
); );
} else if (authentication.showBiometricAuthenticationScreen) { } else if (authentication.showBiometricAuthenticationScreen) {
return const VerifyIdentityPage(); return const VerifyIdentityPage();

View File

@@ -2,9 +2,7 @@ import 'package:collection/collection.dart';
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:json_annotation/json_annotation.dart'; import 'package:json_annotation/json_annotation.dart';
import 'package:paperless_api/config/hive/hive_type_ids.dart';
import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_api/paperless_api.dart';
import 'package:paperless_api/src/models/query_parameters/tags_query/tags_query.dart';
part 'document_filter.g.dart'; part 'document_filter.g.dart';
@@ -23,30 +21,43 @@ class DocumentFilter extends Equatable {
@HiveField(0) @HiveField(0)
final int pageSize; final int pageSize;
@HiveField(1) @HiveField(1)
final int page; final int page;
@HiveField(2) @HiveField(2)
final IdQueryParameter documentType; final IdQueryParameter documentType;
@HiveField(3) @HiveField(3)
final IdQueryParameter correspondent; final IdQueryParameter correspondent;
@HiveField(4) @HiveField(4)
final IdQueryParameter storagePath; final IdQueryParameter storagePath;
@HiveField(5) @HiveField(5)
final IdQueryParameter asnQuery; final IdQueryParameter asnQuery;
@HiveField(6) @HiveField(6)
final TagsQuery tags; final TagsQuery tags;
@HiveField(7) @HiveField(7)
final SortField? sortField; final SortField? sortField;
@HiveField(8) @HiveField(8)
final SortOrder sortOrder; final SortOrder sortOrder;
@HiveField(9) @HiveField(9)
final DateRangeQuery created; final DateRangeQuery created;
@HiveField(10) @HiveField(10)
final DateRangeQuery added; final DateRangeQuery added;
@HiveField(11) @HiveField(11)
final DateRangeQuery modified; final DateRangeQuery modified;
@HiveField(12) @HiveField(12)
final TextQuery query; final TextQuery query;
@HiveField(13) @HiveField(13)
final int? moreLike; final int? moreLike;

View File

@@ -3,9 +3,7 @@ import 'package:paperless_api/config/hive/hive_type_ids.dart';
import 'package:paperless_api/src/models/query_parameters/date_range_queries/date_range_query_field.dart'; import 'package:paperless_api/src/models/query_parameters/date_range_queries/date_range_query_field.dart';
import 'date_range_query.dart'; import 'date_range_query.dart';
part 'unset_date_range_query.g.dart';
@HiveType(typeId: PaperlessApiHiveTypeIds.unsetDateRangeQuery)
class UnsetDateRangeQuery extends DateRangeQuery { class UnsetDateRangeQuery extends DateRangeQuery {
const UnsetDateRangeQuery(); const UnsetDateRangeQuery();
@override @override
@@ -20,3 +18,29 @@ class UnsetDateRangeQuery extends DateRangeQuery {
@override @override
bool matches(DateTime dt) => true; bool matches(DateTime dt) => true;
} }
class UnsetDateRangeQueryAdapter extends TypeAdapter<UnsetDateRangeQuery> {
@override
final int typeId = 113;
@override
UnsetDateRangeQuery read(BinaryReader reader) {
reader.readByte();
return const UnsetDateRangeQuery();
}
@override
void write(BinaryWriter writer, UnsetDateRangeQuery obj) {
writer.writeByte(0);
}
@override
int get hashCode => typeId.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is UnsetDateRangeQueryAdapter &&
runtimeType == other.runtimeType &&
typeId == other.typeId;
}

View File

@@ -13,13 +13,13 @@ class TagsQuery with _$TagsQuery {
@HiveType(typeId: PaperlessApiHiveTypeIds.anyAssignedTagsQuery) @HiveType(typeId: PaperlessApiHiveTypeIds.anyAssignedTagsQuery)
const factory TagsQuery.anyAssigned({ const factory TagsQuery.anyAssigned({
@Default([]) Iterable<int> tagIds, @Default([]) List<int> tagIds,
}) = AnyAssignedTagsQuery; }) = AnyAssignedTagsQuery;
@HiveType(typeId: PaperlessApiHiveTypeIds.idsTagsQuery) @HiveType(typeId: PaperlessApiHiveTypeIds.idsTagsQuery)
const factory TagsQuery.ids({ const factory TagsQuery.ids({
@Default([]) Iterable<int> include, @Default([]) List<int> include,
@Default([]) Iterable<int> exclude, @Default([]) List<int> exclude,
}) = IdsTagsQuery; }) = IdsTagsQuery;
Map<String, String> toQueryParameter() { Map<String, String> toQueryParameter() {
@@ -46,10 +46,6 @@ class TagsQuery with _$TagsQuery {
); );
} }
Map<String, dynamic> toJson() {
return {};
}
bool matches(Iterable<int> ids) { bool matches(Iterable<int> ids) {
return when( return when(
anyAssigned: (_) => ids.isNotEmpty, anyAssigned: (_) => ids.isNotEmpty,

View File

@@ -34,22 +34,22 @@ mixin _$TagsQuery {
@optionalTypeArgs @optionalTypeArgs
TResult when<TResult extends Object?>({ TResult when<TResult extends Object?>({
required TResult Function() notAssigned, required TResult Function() notAssigned,
required TResult Function(Iterable<int> tagIds) anyAssigned, required TResult Function(List<int> tagIds) anyAssigned,
required TResult Function(Iterable<int> include, Iterable<int> exclude) ids, required TResult Function(List<int> include, List<int> exclude) ids,
}) => }) =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
@optionalTypeArgs @optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({ TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? notAssigned, TResult? Function()? notAssigned,
TResult? Function(Iterable<int> tagIds)? anyAssigned, TResult? Function(List<int> tagIds)? anyAssigned,
TResult? Function(Iterable<int> include, Iterable<int> exclude)? ids, TResult? Function(List<int> include, List<int> exclude)? ids,
}) => }) =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
@optionalTypeArgs @optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({ TResult maybeWhen<TResult extends Object?>({
TResult Function()? notAssigned, TResult Function()? notAssigned,
TResult Function(Iterable<int> tagIds)? anyAssigned, TResult Function(List<int> tagIds)? anyAssigned,
TResult Function(Iterable<int> include, Iterable<int> exclude)? ids, TResult Function(List<int> include, List<int> exclude)? ids,
required TResult orElse(), required TResult orElse(),
}) => }) =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
@@ -144,8 +144,8 @@ class _$NotAssignedTagsQuery extends NotAssignedTagsQuery {
@optionalTypeArgs @optionalTypeArgs
TResult when<TResult extends Object?>({ TResult when<TResult extends Object?>({
required TResult Function() notAssigned, required TResult Function() notAssigned,
required TResult Function(Iterable<int> tagIds) anyAssigned, required TResult Function(List<int> tagIds) anyAssigned,
required TResult Function(Iterable<int> include, Iterable<int> exclude) ids, required TResult Function(List<int> include, List<int> exclude) ids,
}) { }) {
return notAssigned(); return notAssigned();
} }
@@ -154,8 +154,8 @@ class _$NotAssignedTagsQuery extends NotAssignedTagsQuery {
@optionalTypeArgs @optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({ TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? notAssigned, TResult? Function()? notAssigned,
TResult? Function(Iterable<int> tagIds)? anyAssigned, TResult? Function(List<int> tagIds)? anyAssigned,
TResult? Function(Iterable<int> include, Iterable<int> exclude)? ids, TResult? Function(List<int> include, List<int> exclude)? ids,
}) { }) {
return notAssigned?.call(); return notAssigned?.call();
} }
@@ -164,8 +164,8 @@ class _$NotAssignedTagsQuery extends NotAssignedTagsQuery {
@optionalTypeArgs @optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({ TResult maybeWhen<TResult extends Object?>({
TResult Function()? notAssigned, TResult Function()? notAssigned,
TResult Function(Iterable<int> tagIds)? anyAssigned, TResult Function(List<int> tagIds)? anyAssigned,
TResult Function(Iterable<int> include, Iterable<int> exclude)? ids, TResult Function(List<int> include, List<int> exclude)? ids,
required TResult orElse(), required TResult orElse(),
}) { }) {
if (notAssigned != null) { if (notAssigned != null) {
@@ -230,7 +230,7 @@ abstract class _$$AnyAssignedTagsQueryCopyWith<$Res> {
$Res Function(_$AnyAssignedTagsQuery) then) = $Res Function(_$AnyAssignedTagsQuery) then) =
__$$AnyAssignedTagsQueryCopyWithImpl<$Res>; __$$AnyAssignedTagsQueryCopyWithImpl<$Res>;
@useResult @useResult
$Res call({Iterable<int> tagIds}); $Res call({List<int> tagIds});
} }
/// @nodoc /// @nodoc
@@ -248,9 +248,9 @@ class __$$AnyAssignedTagsQueryCopyWithImpl<$Res>
}) { }) {
return _then(_$AnyAssignedTagsQuery( return _then(_$AnyAssignedTagsQuery(
tagIds: null == tagIds tagIds: null == tagIds
? _value.tagIds ? _value._tagIds
: tagIds // ignore: cast_nullable_to_non_nullable : tagIds // ignore: cast_nullable_to_non_nullable
as Iterable<int>, as List<int>,
)); ));
} }
} }
@@ -259,16 +259,23 @@ class __$$AnyAssignedTagsQueryCopyWithImpl<$Res>
@JsonSerializable() @JsonSerializable()
@HiveType(typeId: PaperlessApiHiveTypeIds.anyAssignedTagsQuery) @HiveType(typeId: PaperlessApiHiveTypeIds.anyAssignedTagsQuery)
class _$AnyAssignedTagsQuery extends AnyAssignedTagsQuery { class _$AnyAssignedTagsQuery extends AnyAssignedTagsQuery {
const _$AnyAssignedTagsQuery({this.tagIds = const [], final String? $type}) const _$AnyAssignedTagsQuery(
: $type = $type ?? 'anyAssigned', {final List<int> tagIds = const [], final String? $type})
: _tagIds = tagIds,
$type = $type ?? 'anyAssigned',
super._(); super._();
factory _$AnyAssignedTagsQuery.fromJson(Map<String, dynamic> json) => factory _$AnyAssignedTagsQuery.fromJson(Map<String, dynamic> json) =>
_$$AnyAssignedTagsQueryFromJson(json); _$$AnyAssignedTagsQueryFromJson(json);
final List<int> _tagIds;
@override @override
@JsonKey() @JsonKey()
final Iterable<int> tagIds; List<int> get tagIds {
if (_tagIds is EqualUnmodifiableListView) return _tagIds;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_tagIds);
}
@JsonKey(name: 'runtimeType') @JsonKey(name: 'runtimeType')
final String $type; final String $type;
@@ -283,13 +290,13 @@ class _$AnyAssignedTagsQuery extends AnyAssignedTagsQuery {
return identical(this, other) || return identical(this, other) ||
(other.runtimeType == runtimeType && (other.runtimeType == runtimeType &&
other is _$AnyAssignedTagsQuery && other is _$AnyAssignedTagsQuery &&
const DeepCollectionEquality().equals(other.tagIds, tagIds)); const DeepCollectionEquality().equals(other._tagIds, _tagIds));
} }
@JsonKey(ignore: true) @JsonKey(ignore: true)
@override @override
int get hashCode => int get hashCode =>
Object.hash(runtimeType, const DeepCollectionEquality().hash(tagIds)); Object.hash(runtimeType, const DeepCollectionEquality().hash(_tagIds));
@JsonKey(ignore: true) @JsonKey(ignore: true)
@override @override
@@ -302,8 +309,8 @@ class _$AnyAssignedTagsQuery extends AnyAssignedTagsQuery {
@optionalTypeArgs @optionalTypeArgs
TResult when<TResult extends Object?>({ TResult when<TResult extends Object?>({
required TResult Function() notAssigned, required TResult Function() notAssigned,
required TResult Function(Iterable<int> tagIds) anyAssigned, required TResult Function(List<int> tagIds) anyAssigned,
required TResult Function(Iterable<int> include, Iterable<int> exclude) ids, required TResult Function(List<int> include, List<int> exclude) ids,
}) { }) {
return anyAssigned(tagIds); return anyAssigned(tagIds);
} }
@@ -312,8 +319,8 @@ class _$AnyAssignedTagsQuery extends AnyAssignedTagsQuery {
@optionalTypeArgs @optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({ TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? notAssigned, TResult? Function()? notAssigned,
TResult? Function(Iterable<int> tagIds)? anyAssigned, TResult? Function(List<int> tagIds)? anyAssigned,
TResult? Function(Iterable<int> include, Iterable<int> exclude)? ids, TResult? Function(List<int> include, List<int> exclude)? ids,
}) { }) {
return anyAssigned?.call(tagIds); return anyAssigned?.call(tagIds);
} }
@@ -322,8 +329,8 @@ class _$AnyAssignedTagsQuery extends AnyAssignedTagsQuery {
@optionalTypeArgs @optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({ TResult maybeWhen<TResult extends Object?>({
TResult Function()? notAssigned, TResult Function()? notAssigned,
TResult Function(Iterable<int> tagIds)? anyAssigned, TResult Function(List<int> tagIds)? anyAssigned,
TResult Function(Iterable<int> include, Iterable<int> exclude)? ids, TResult Function(List<int> include, List<int> exclude)? ids,
required TResult orElse(), required TResult orElse(),
}) { }) {
if (anyAssigned != null) { if (anyAssigned != null) {
@@ -375,14 +382,14 @@ class _$AnyAssignedTagsQuery extends AnyAssignedTagsQuery {
} }
abstract class AnyAssignedTagsQuery extends TagsQuery { abstract class AnyAssignedTagsQuery extends TagsQuery {
const factory AnyAssignedTagsQuery({final Iterable<int> tagIds}) = const factory AnyAssignedTagsQuery({final List<int> tagIds}) =
_$AnyAssignedTagsQuery; _$AnyAssignedTagsQuery;
const AnyAssignedTagsQuery._() : super._(); const AnyAssignedTagsQuery._() : super._();
factory AnyAssignedTagsQuery.fromJson(Map<String, dynamic> json) = factory AnyAssignedTagsQuery.fromJson(Map<String, dynamic> json) =
_$AnyAssignedTagsQuery.fromJson; _$AnyAssignedTagsQuery.fromJson;
Iterable<int> get tagIds; List<int> get tagIds;
@JsonKey(ignore: true) @JsonKey(ignore: true)
_$$AnyAssignedTagsQueryCopyWith<_$AnyAssignedTagsQuery> get copyWith => _$$AnyAssignedTagsQueryCopyWith<_$AnyAssignedTagsQuery> get copyWith =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
@@ -394,7 +401,7 @@ abstract class _$$IdsTagsQueryCopyWith<$Res> {
_$IdsTagsQuery value, $Res Function(_$IdsTagsQuery) then) = _$IdsTagsQuery value, $Res Function(_$IdsTagsQuery) then) =
__$$IdsTagsQueryCopyWithImpl<$Res>; __$$IdsTagsQueryCopyWithImpl<$Res>;
@useResult @useResult
$Res call({Iterable<int> include, Iterable<int> exclude}); $Res call({List<int> include, List<int> exclude});
} }
/// @nodoc /// @nodoc
@@ -413,13 +420,13 @@ class __$$IdsTagsQueryCopyWithImpl<$Res>
}) { }) {
return _then(_$IdsTagsQuery( return _then(_$IdsTagsQuery(
include: null == include include: null == include
? _value.include ? _value._include
: include // ignore: cast_nullable_to_non_nullable : include // ignore: cast_nullable_to_non_nullable
as Iterable<int>, as List<int>,
exclude: null == exclude exclude: null == exclude
? _value.exclude ? _value._exclude
: exclude // ignore: cast_nullable_to_non_nullable : exclude // ignore: cast_nullable_to_non_nullable
as Iterable<int>, as List<int>,
)); ));
} }
} }
@@ -429,19 +436,34 @@ class __$$IdsTagsQueryCopyWithImpl<$Res>
@HiveType(typeId: PaperlessApiHiveTypeIds.idsTagsQuery) @HiveType(typeId: PaperlessApiHiveTypeIds.idsTagsQuery)
class _$IdsTagsQuery extends IdsTagsQuery { class _$IdsTagsQuery extends IdsTagsQuery {
const _$IdsTagsQuery( const _$IdsTagsQuery(
{this.include = const [], this.exclude = const [], final String? $type}) {final List<int> include = const [],
: $type = $type ?? 'ids', final List<int> exclude = const [],
final String? $type})
: _include = include,
_exclude = exclude,
$type = $type ?? 'ids',
super._(); super._();
factory _$IdsTagsQuery.fromJson(Map<String, dynamic> json) => factory _$IdsTagsQuery.fromJson(Map<String, dynamic> json) =>
_$$IdsTagsQueryFromJson(json); _$$IdsTagsQueryFromJson(json);
final List<int> _include;
@override @override
@JsonKey() @JsonKey()
final Iterable<int> include; List<int> get include {
if (_include is EqualUnmodifiableListView) return _include;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_include);
}
final List<int> _exclude;
@override @override
@JsonKey() @JsonKey()
final Iterable<int> exclude; List<int> get exclude {
if (_exclude is EqualUnmodifiableListView) return _exclude;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_exclude);
}
@JsonKey(name: 'runtimeType') @JsonKey(name: 'runtimeType')
final String $type; final String $type;
@@ -456,16 +478,16 @@ class _$IdsTagsQuery extends IdsTagsQuery {
return identical(this, other) || return identical(this, other) ||
(other.runtimeType == runtimeType && (other.runtimeType == runtimeType &&
other is _$IdsTagsQuery && other is _$IdsTagsQuery &&
const DeepCollectionEquality().equals(other.include, include) && const DeepCollectionEquality().equals(other._include, _include) &&
const DeepCollectionEquality().equals(other.exclude, exclude)); const DeepCollectionEquality().equals(other._exclude, _exclude));
} }
@JsonKey(ignore: true) @JsonKey(ignore: true)
@override @override
int get hashCode => Object.hash( int get hashCode => Object.hash(
runtimeType, runtimeType,
const DeepCollectionEquality().hash(include), const DeepCollectionEquality().hash(_include),
const DeepCollectionEquality().hash(exclude)); const DeepCollectionEquality().hash(_exclude));
@JsonKey(ignore: true) @JsonKey(ignore: true)
@override @override
@@ -477,8 +499,8 @@ class _$IdsTagsQuery extends IdsTagsQuery {
@optionalTypeArgs @optionalTypeArgs
TResult when<TResult extends Object?>({ TResult when<TResult extends Object?>({
required TResult Function() notAssigned, required TResult Function() notAssigned,
required TResult Function(Iterable<int> tagIds) anyAssigned, required TResult Function(List<int> tagIds) anyAssigned,
required TResult Function(Iterable<int> include, Iterable<int> exclude) ids, required TResult Function(List<int> include, List<int> exclude) ids,
}) { }) {
return ids(include, exclude); return ids(include, exclude);
} }
@@ -487,8 +509,8 @@ class _$IdsTagsQuery extends IdsTagsQuery {
@optionalTypeArgs @optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({ TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? notAssigned, TResult? Function()? notAssigned,
TResult? Function(Iterable<int> tagIds)? anyAssigned, TResult? Function(List<int> tagIds)? anyAssigned,
TResult? Function(Iterable<int> include, Iterable<int> exclude)? ids, TResult? Function(List<int> include, List<int> exclude)? ids,
}) { }) {
return ids?.call(include, exclude); return ids?.call(include, exclude);
} }
@@ -497,8 +519,8 @@ class _$IdsTagsQuery extends IdsTagsQuery {
@optionalTypeArgs @optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({ TResult maybeWhen<TResult extends Object?>({
TResult Function()? notAssigned, TResult Function()? notAssigned,
TResult Function(Iterable<int> tagIds)? anyAssigned, TResult Function(List<int> tagIds)? anyAssigned,
TResult Function(Iterable<int> include, Iterable<int> exclude)? ids, TResult Function(List<int> include, List<int> exclude)? ids,
required TResult orElse(), required TResult orElse(),
}) { }) {
if (ids != null) { if (ids != null) {
@@ -551,15 +573,14 @@ class _$IdsTagsQuery extends IdsTagsQuery {
abstract class IdsTagsQuery extends TagsQuery { abstract class IdsTagsQuery extends TagsQuery {
const factory IdsTagsQuery( const factory IdsTagsQuery(
{final Iterable<int> include, {final List<int> include, final List<int> exclude}) = _$IdsTagsQuery;
final Iterable<int> exclude}) = _$IdsTagsQuery;
const IdsTagsQuery._() : super._(); const IdsTagsQuery._() : super._();
factory IdsTagsQuery.fromJson(Map<String, dynamic> json) = factory IdsTagsQuery.fromJson(Map<String, dynamic> json) =
_$IdsTagsQuery.fromJson; _$IdsTagsQuery.fromJson;
Iterable<int> get include; List<int> get include;
Iterable<int> get exclude; List<int> get exclude;
@JsonKey(ignore: true) @JsonKey(ignore: true)
_$$IdsTagsQueryCopyWith<_$IdsTagsQuery> get copyWith => _$$IdsTagsQueryCopyWith<_$IdsTagsQuery> get copyWith =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;