diff --git a/README.md b/README.md index 208c748..81ba32c 100644 --- a/README.md +++ b/README.md @@ -214,4 +214,4 @@ Made with [contrib.rocks](https://contrib.rocks). ## Troubleshooting #### Suggestions are not selectable in any of the label form fields -This is a known issue and it has to do with accessibility features of Android. Password managers such as Bitwarden often caused this issue. Luckily, this can be resolved by turning off the accessibility features in these apps. This could also be observed with apps that are allowed to display over other apps, such as emulations of the dynamic island on android. +This is a known issue and it has to do with accessibility features of Android. Password managers such as Bitwarden often caused this issue. Luckily, this can be resolved by turning off the accessibility features in these apps. This could also be observed with apps that are allowed to display over other apps, such as emulations of the dynamic island on android. \ No newline at end of file diff --git a/lib/core/exception/server_message_exception.dart b/lib/core/exception/server_message_exception.dart new file mode 100644 index 0000000..678bcbe --- /dev/null +++ b/lib/core/exception/server_message_exception.dart @@ -0,0 +1,5 @@ +class ServerMessageException implements Exception { + final String message; + + ServerMessageException(this.message); +} diff --git a/lib/core/interceptor/dio_http_error_interceptor.dart b/lib/core/interceptor/dio_http_error_interceptor.dart index 8cb0d38..211aa45 100644 --- a/lib/core/interceptor/dio_http_error_interceptor.dart +++ b/lib/core/interceptor/dio_http_error_interceptor.dart @@ -2,6 +2,7 @@ import 'dart:io'; import 'package:dio/dio.dart'; import 'package:paperless_api/paperless_api.dart'; +import 'package:paperless_mobile/core/exception/server_message_exception.dart'; import 'package:paperless_mobile/core/type/types.dart'; class DioHttpErrorInterceptor extends Interceptor { @@ -16,14 +17,15 @@ class DioHttpErrorInterceptor extends Interceptor { return _handlePlainError(data, handler, err); } } else if (err.response?.statusCode == 403) { - handler.reject( - DioError( + var data = err.response!.data; + if (data is Map && data.containsKey("detail")) { + handler.reject(DioError( requestOptions: err.requestOptions, - error: const PaperlessServerException(ErrorCode.notAuthorized), + error: ServerMessageException(data['detail']), response: err.response, - ), - ); - return; + )); + return; + } } else if (err.error is SocketException) { final ex = err.error as SocketException; if (ex.osError?.errorCode == _OsErrorCodes.serverUnreachable.code) { @@ -84,8 +86,7 @@ class DioHttpErrorInterceptor extends Interceptor { } enum _OsErrorCodes { - serverUnreachable(101), - hostNotFound(7); + serverUnreachable(101); const _OsErrorCodes(this.code); final int code; diff --git a/lib/core/navigation/push_routes.dart b/lib/core/navigation/push_routes.dart index 4a8615f..fc3e9d6 100644 --- a/lib/core/navigation/push_routes.dart +++ b/lib/core/navigation/push_routes.dart @@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart'; import 'package:hive/hive.dart'; import 'package:paperless_api/paperless_api.dart'; +import 'package:paperless_mobile/core/bloc/connectivity_cubit.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/local_user_app_state.dart'; @@ -12,13 +13,19 @@ import 'package:paperless_mobile/core/repository/user_repository.dart'; import 'package:paperless_mobile/features/document_search/cubit/document_search_cubit.dart'; import 'package:paperless_mobile/features/document_search/view/document_search_page.dart'; import 'package:paperless_mobile/features/home/view/model/api_version.dart'; +import 'package:paperless_mobile/features/linked_documents/cubit/linked_documents_cubit.dart'; +import 'package:paperless_mobile/features/linked_documents/view/linked_documents_page.dart'; import 'package:paperless_mobile/features/notifications/services/local_notification_service.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_details/cubit/saved_view_details_cubit.dart'; import 'package:paperless_mobile/features/saved_view_details/view/saved_view_details_page.dart'; import 'package:paperless_mobile/routes/document_details_route.dart'; import 'package:provider/provider.dart'; +// These are convenience methods for nativating to views without having to pass providers around explicitly. +// Providers unfortunately have to be passed to the routes since they are children of the Navigator, not ancestors. + Future pushDocumentSearchPage(BuildContext context) { final currentUser = Hive.box(HiveBoxes.globalSettings).getValue()!.currentLoggedInUser; @@ -64,6 +71,7 @@ Future pushDocumentDetailsRoute( Provider.value(value: context.read()), Provider.value(value: context.read()), Provider.value(value: context.read()), + Provider.value(value: context.read()), if (context.read().hasMultiUserSupport) Provider.value(value: context.read()), ], @@ -76,19 +84,23 @@ Future pushDocumentDetailsRoute( ); } -Future pushSavedViewDetailsRoute(BuildContext context, {required SavedView savedView}) { +Future pushSavedViewDetailsRoute( + BuildContext context, { + required SavedView savedView, +}) { + final apiVersion = context.read(); return Navigator.of(context).push( MaterialPageRoute( builder: (_) => MultiProvider( providers: [ + Provider.value(value: apiVersion), + if (apiVersion.hasMultiUserSupport) Provider.value(value: context.read()), Provider.value(value: context.read()), Provider.value(value: context.read()), Provider.value(value: context.read()), Provider.value(value: context.read()), + Provider.value(value: context.read()), ], - child: SavedViewDetailsPage( - onDelete: context.read().remove, - ), builder: (_, child) { return BlocProvider( create: (context) => SavedViewDetailsCubit( @@ -105,3 +117,47 @@ Future pushSavedViewDetailsRoute(BuildContext context, {required SavedView ), ); } + +Future pushAddSavedViewRoute(BuildContext context, {required DocumentFilter filter}) { + return Navigator.of(context).push( + MaterialPageRoute( + builder: (_) => AddSavedViewPage( + currentFilter: filter, + correspondents: context.read().state.correspondents, + documentTypes: context.read().state.documentTypes, + storagePaths: context.read().state.storagePaths, + tags: context.read().state.tags, + ), + ), + ); +} + +Future pushLinkedDocumentsView(BuildContext context, {required DocumentFilter filter}) { + return Navigator.push( + context, + MaterialPageRoute( + builder: (_) => MultiProvider( + providers: [ + Provider.value(value: context.read()), + Provider.value(value: context.read()), + Provider.value(value: context.read()), + Provider.value(value: context.read()), + Provider.value(value: context.read()), + Provider.value(value: context.read()), + Provider.value(value: context.read()), + if (context.read().hasMultiUserSupport) + Provider.value(value: context.read()), + ], + builder: (context, _) => BlocProvider( + create: (context) => LinkedDocumentsCubit( + filter, + context.read(), + context.read(), + context.read(), + ), + child: const LinkedDocumentsPage(), + ), + ), + ), + ); +} diff --git a/lib/core/notifier/document_changed_notifier.dart b/lib/core/notifier/document_changed_notifier.dart index 392d1bb..04a9781 100644 --- a/lib/core/notifier/document_changed_notifier.dart +++ b/lib/core/notifier/document_changed_notifier.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'dart:developer'; import 'package:flutter/foundation.dart'; import 'package:paperless_api/paperless_api.dart'; diff --git a/lib/core/repository/label_repository.dart b/lib/core/repository/label_repository.dart index b57b19f..1ba16b1 100644 --- a/lib/core/repository/label_repository.dart +++ b/lib/core/repository/label_repository.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'package:flutter/widgets.dart'; -import 'package:hydrated_bloc/hydrated_bloc.dart'; import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/core/repository/label_repository_state.dart'; import 'package:paperless_mobile/core/repository/persistent_repository.dart'; @@ -9,7 +8,9 @@ import 'package:paperless_mobile/core/repository/persistent_repository.dart'; class LabelRepository extends PersistentRepository { final PaperlessLabelsApi _api; - LabelRepository(this._api) : super(const LabelRepositoryState()); + LabelRepository(this._api) : super(const LabelRepositoryState()) { + initialize(); + } Future initialize() { debugPrint("Initializing labels..."); diff --git a/lib/core/repository/saved_view_repository.dart b/lib/core/repository/saved_view_repository.dart index d458358..181d2fc 100644 --- a/lib/core/repository/saved_view_repository.dart +++ b/lib/core/repository/saved_view_repository.dart @@ -7,7 +7,9 @@ import 'package:paperless_mobile/core/repository/saved_view_repository_state.dar class SavedViewRepository extends PersistentRepository { final PaperlessSavedViewsApi _api; - SavedViewRepository(this._api) : super(const SavedViewRepositoryState()); + SavedViewRepository(this._api) : super(const SavedViewRepositoryState()) { + initialize(); + } Future initialize() { return findAll(); diff --git a/lib/core/service/github_issue_service.dart b/lib/core/service/github_issue_service.dart index b4e1d79..3d7e435 100644 --- a/lib/core/service/github_issue_service.dart +++ b/lib/core/service/github_issue_service.dart @@ -1,4 +1,3 @@ -import 'dart:developer'; import 'package:flutter/material.dart'; import 'package:paperless_mobile/core/model/github_error_report.model.dart'; diff --git a/lib/core/service/status_service.dart b/lib/core/service/status_service.dart index 4e42b3d..ea16bee 100644 --- a/lib/core/service/status_service.dart +++ b/lib/core/service/status_service.dart @@ -1,16 +1,8 @@ -import 'dart:convert'; import 'dart:io'; import 'package:dio/dio.dart'; -import 'package:flutter/foundation.dart'; -import 'package:http/http.dart'; -import 'package:paperless_api/paperless_api.dart'; -import 'package:paperless_mobile/core/bloc/document_status_cubit.dart'; -import 'package:paperless_mobile/core/model/document_processing_status.dart'; -import 'package:paperless_mobile/features/login/model/authentication_information.dart'; -import 'package:paperless_mobile/constants.dart'; import 'package:paperless_mobile/core/database/tables/user_credentials.dart'; -import 'package:web_socket_channel/io.dart'; +// import 'package:web_socket_channel/io.dart'; abstract class StatusService { Future startListeningBeforeDocumentUpload( @@ -19,7 +11,7 @@ abstract class StatusService { class WebSocketStatusService implements StatusService { late WebSocket? socket; - late IOWebSocketChannel? _channel; + // late IOWebSocketChannel? _channel; WebSocketStatusService(); diff --git a/lib/core/translation/error_code_localization_mapper.dart b/lib/core/translation/error_code_localization_mapper.dart index 9143850..4b2be11 100644 --- a/lib/core/translation/error_code_localization_mapper.dart +++ b/lib/core/translation/error_code_localization_mapper.dart @@ -72,7 +72,5 @@ String translateError(BuildContext context, ErrorCode code) { return S.of(context)!.couldNotLoadSuggestions; case ErrorCode.acknowledgeTasksError: return S.of(context)!.couldNotAcknowledgeTasks; - case ErrorCode.notAuthorized: - return "You do not have the permission to perform this action."; //TODO: INTL } } diff --git a/lib/core/type/types.dart b/lib/core/type/types.dart index a133cbf..ce6ae47 100644 --- a/lib/core/type/types.dart +++ b/lib/core/type/types.dart @@ -1,5 +1,3 @@ -import 'package:paperless_api/paperless_api.dart'; -import 'package:rxdart/subjects.dart'; typedef JSON = Map; typedef PaperlessValidationErrors = Map; diff --git a/lib/core/widgets/dialog_utils/dialog_cancel_button.dart b/lib/core/widgets/dialog_utils/dialog_cancel_button.dart index 1fede76..a299169 100644 --- a/lib/core/widgets/dialog_utils/dialog_cancel_button.dart +++ b/lib/core/widgets/dialog_utils/dialog_cancel_button.dart @@ -1,6 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter/src/widgets/framework.dart'; -import 'package:flutter/src/widgets/placeholder.dart'; import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; class DialogCancelButton extends StatelessWidget { diff --git a/lib/core/widgets/dialog_utils/dialog_confirm_button.dart b/lib/core/widgets/dialog_utils/dialog_confirm_button.dart index bb9f02d..f1083c4 100644 --- a/lib/core/widgets/dialog_utils/dialog_confirm_button.dart +++ b/lib/core/widgets/dialog_utils/dialog_confirm_button.dart @@ -1,6 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter/src/widgets/framework.dart'; -import 'package:flutter/src/widgets/placeholder.dart'; import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; enum DialogConfirmButtonStyle { diff --git a/lib/core/widgets/form_builder_fields/form_builder_color_picker.dart b/lib/core/widgets/form_builder_fields/form_builder_color_picker.dart index 893b360..912d33d 100644 --- a/lib/core/widgets/form_builder_fields/form_builder_color_picker.dart +++ b/lib/core/widgets/form_builder_fields/form_builder_color_picker.dart @@ -181,8 +181,7 @@ class FormBuilderColorPickerField extends FormBuilderField { ); @override - FormBuilderColorPickerFieldState createState() => - FormBuilderColorPickerFieldState(); + FormBuilderColorPickerFieldState createState() => FormBuilderColorPickerFieldState(); } class FormBuilderColorPickerFieldState @@ -217,8 +216,6 @@ class FormBuilderColorPickerFieldState final selected = await showDialog( context: context, builder: (BuildContext context) { - final materialLocalizations = S.of(context)!; - return AlertDialog( // title: null, //const Text('Pick a color!'), content: _buildColorPicker(), diff --git a/lib/core/widgets/hint_card.dart b/lib/core/widgets/hint_card.dart index 46da68b..c041436 100644 --- a/lib/core/widgets/hint_card.dart +++ b/lib/core/widgets/hint_card.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; import 'package:paperless_mobile/extensions/flutter_extensions.dart'; import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; diff --git a/lib/core/widgets/material/chips_input.dart b/lib/core/widgets/material/chips_input.dart index 9e6bfc8..d8f5ef6 100644 --- a/lib/core/widgets/material/chips_input.dart +++ b/lib/core/widgets/material/chips_input.dart @@ -27,8 +27,7 @@ import 'package:flutter/services.dart'; typedef ChipsInputSuggestions = Future> Function(String query); typedef ChipSelected = void Function(T data, bool selected); -typedef ChipsBuilder = Widget Function( - BuildContext context, ChipsInputState state, T data); +typedef ChipsBuilder = Widget Function(BuildContext context, ChipsInputState state, T data); class ChipsInput extends StatefulWidget { const ChipsInput({ @@ -71,8 +70,7 @@ class ChipsInputState extends State> { TextEditingValue get currentTextEditingValue => _value; - bool get _hasInputConnection => - _connection != null && (_connection?.attached ?? false); + bool get _hasInputConnection => _connection != null && (_connection?.attached ?? false); void requestKeyboard() { if (_focusNode.hasFocus) { @@ -191,8 +189,7 @@ class ChipsInputState extends State> { child: ListView.builder( itemCount: _suggestions.length, itemBuilder: (BuildContext context, int index) { - return widget.suggestionBuilder( - context, this, _suggestions[index]); + return widget.suggestionBuilder(context, this, _suggestions[index]); }, ), ), @@ -213,14 +210,11 @@ class ChipsInputState extends State> { } int _countReplacements(TextEditingValue value) { - return value.text.codeUnits - .where((ch) => ch == kObjectReplacementChar) - .length; + return value.text.codeUnits.where((ch) => ch == kObjectReplacementChar).length; } void _updateTextInputState() { - final text = - String.fromCharCodes(_chips.map((_) => kObjectReplacementChar)); + final text = String.fromCharCodes(_chips.map((_) => kObjectReplacementChar)); _value = TextEditingValue( text: text, selection: TextSelection.collapsed(offset: text.length), @@ -233,35 +227,30 @@ class ChipsInputState extends State> { final localId = ++_searchId; final results = await widget.findSuggestions(value); if (_searchId == localId && mounted) { - setState(() => _suggestions = results - .where((profile) => !_chips.contains(profile)) - .toList(growable: false)); + setState(() => _suggestions = + results.where((profile) => !_chips.contains(profile)).toList(growable: false)); } } } class _TextCaret extends StatefulWidget { const _TextCaret({ - this.duration = const Duration(milliseconds: 500), this.resumed = false, }); - final Duration duration; final bool resumed; @override _TextCursorState createState() => _TextCursorState(); } -class _TextCursorState extends State<_TextCaret> - with SingleTickerProviderStateMixin { +class _TextCursorState extends State<_TextCaret> with SingleTickerProviderStateMixin { bool _displayed = false; late Timer _timer; @override void initState() { super.initState(); - _timer = Timer.periodic(widget.duration, _onTimer); } void _onTimer(Timer timer) { diff --git a/lib/core/widgets/material/search/m3_search.dart b/lib/core/widgets/material/search/m3_search.dart index fdc5f75..9e7b78d 100644 --- a/lib/core/widgets/material/search/m3_search.dart +++ b/lib/core/widgets/material/search/m3_search.dart @@ -251,7 +251,6 @@ abstract class SearchDelegate { /// /// Setting the query string programmatically moves the cursor to the end of the text field. set query(String value) { - assert(query != null); _queryTextController.text = value; if (_queryTextController.text.isNotEmpty) { _queryTextController.selection = TextSelection.fromPosition( diff --git a/lib/core/widgets/material/search/search_anchor.dart b/lib/core/widgets/material/search/search_anchor.dart index 1bfd31a..6acadaa 100644 --- a/lib/core/widgets/material/search/search_anchor.dart +++ b/lib/core/widgets/material/search/search_anchor.dart @@ -7,7 +7,6 @@ import 'dart:ui'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; const int _kOpenViewMilliseconds = 600; const Duration _kOpenViewDuration = @@ -1649,7 +1648,6 @@ class SearchBarTheme extends InheritedWidget { final SearchBarTheme? searchBarTheme = context.dependOnInheritedWidgetOfExactType(); return searchBarTheme?.data ?? const SearchBarThemeData(); - ; } @override diff --git a/lib/features/app_drawer/view/app_drawer.dart b/lib/features/app_drawer/view/app_drawer.dart index 08d1479..103e314 100644 --- a/lib/features/app_drawer/view/app_drawer.dart +++ b/lib/features/app_drawer/view/app_drawer.dart @@ -1,6 +1,5 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:paperless_mobile/constants.dart'; import 'package:paperless_mobile/core/widgets/paperless_logo.dart'; diff --git a/lib/features/app_intro/application_intro_slideshow.dart b/lib/features/app_intro/application_intro_slideshow.dart index cdaf9e5..5168f25 100644 --- a/lib/features/app_intro/application_intro_slideshow.dart +++ b/lib/features/app_intro/application_intro_slideshow.dart @@ -50,7 +50,7 @@ class _ApplicationIntroSlideshowState extends State { image: AssetImages.organizeDocuments.image, ), ), - bodyWidget: Column( + bodyWidget: const Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ @@ -70,7 +70,7 @@ class _ApplicationIntroSlideshowState extends State { padding: const EdgeInsets.all(8.0), child: Image(image: AssetImages.secureDocuments.image), ), - bodyWidget: Column( + bodyWidget: const Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ @@ -90,8 +90,8 @@ class _ApplicationIntroSlideshowState extends State { padding: const EdgeInsets.all(8.0), child: Image(image: AssetImages.success.image), ), - bodyWidget: Column( - children: const [ + bodyWidget: const Column( + children: [ BiometricAuthenticationSetting(), LanguageSelectionSetting(), ThemeModeSetting(), diff --git a/lib/features/document_bulk_action/cubit/document_bulk_action_cubit.dart b/lib/features/document_bulk_action/cubit/document_bulk_action_cubit.dart index 6382c7f..6dc5679 100644 --- a/lib/features/document_bulk_action/cubit/document_bulk_action_cubit.dart +++ b/lib/features/document_bulk_action/cubit/document_bulk_action_cubit.dart @@ -2,7 +2,6 @@ import 'dart:async'; import 'package:bloc/bloc.dart'; import 'package:collection/collection.dart'; -import 'package:equatable/equatable.dart'; import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/core/notifier/document_changed_notifier.dart'; import 'package:paperless_mobile/core/repository/label_repository.dart'; diff --git a/lib/features/document_bulk_action/view/widgets/bulk_edit_label_bottom_sheet.dart b/lib/features/document_bulk_action/view/widgets/bulk_edit_label_bottom_sheet.dart index 77112c4..e99051e 100644 --- a/lib/features/document_bulk_action/view/widgets/bulk_edit_label_bottom_sheet.dart +++ b/lib/features/document_bulk_action/view/widgets/bulk_edit_label_bottom_sheet.dart @@ -17,6 +17,7 @@ class BulkEditLabelBottomSheet extends StatefulWidget { final LabelOptionsSelector availableOptionsSelector; final void Function(int? selectedId) onSubmit; final int? initialValue; + final bool canCreateNewLabel; const BulkEditLabelBottomSheet({ super.key, @@ -26,6 +27,7 @@ class BulkEditLabelBottomSheet extends StatefulWidget { required this.availableOptionsSelector, required this.onSubmit, this.initialValue, + required this.canCreateNewLabel, }); @override @@ -58,6 +60,7 @@ class _BulkEditLabelBottomSheetState extends State _nonSharedTags; - List _addTags = []; - List _removeTags = []; + final List _addTags = []; + final List _removeTags = []; late List _filteredTags; @override diff --git a/lib/features/document_details/view/dialogs/select_file_type_dialog.dart b/lib/features/document_details/view/dialogs/select_file_type_dialog.dart index adb0842..bf56325 100644 --- a/lib/features/document_details/view/dialogs/select_file_type_dialog.dart +++ b/lib/features/document_details/view/dialogs/select_file_type_dialog.dart @@ -41,7 +41,7 @@ class _SelectFileTypeDialogState extends State { }, title: Text(S.of(context)!.archivedPdf), ), - Divider(), + const Divider(), CheckboxListTile( controlAffinity: ListTileControlAffinity.leading, value: _rememberSelection, diff --git a/lib/features/document_details/view/pages/document_details_page.dart b/lib/features/document_details/view/pages/document_details_page.dart index aeced88..e05af25 100644 --- a/lib/features/document_details/view/pages/document_details_page.dart +++ b/lib/features/document_details/view/pages/document_details_page.dart @@ -1,13 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:hive_flutter/adapters.dart'; import 'package:open_filex/open_filex.dart'; import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/core/bloc/connectivity_cubit.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/local_user_account.dart'; -import 'package:paperless_mobile/core/repository/user_repository.dart'; import 'package:paperless_mobile/core/translation/error_code_localization_mapper.dart'; import 'package:paperless_mobile/core/widgets/material/colored_tab_bar.dart'; import 'package:paperless_mobile/extensions/flutter_extensions.dart'; @@ -57,7 +53,7 @@ class _DocumentDetailsPageState extends State { Widget build(BuildContext context) { final apiVersion = context.watch(); - final tabLength = 4 + (apiVersion.supportsPermissions ? 1 : 0); + final tabLength = 4 + (apiVersion.hasMultiUserSupport ? 1 : 0); return WillPopScope( onWillPop: () async { Navigator.of(context).pop(context.read().state.document); @@ -155,7 +151,7 @@ class _DocumentDetailsPageState extends State { ), ), ), - if (apiVersion.supportsPermissions) + if (apiVersion.hasMultiUserSupport) Tab( child: Text( "Permissions", @@ -260,13 +256,9 @@ class _DocumentDetailsPageState extends State { } Widget _buildEditButton() { - bool canEdit = context.watchInternetConnection; - final apiVersion = context.watch(); - - if (apiVersion.supportsPermissions) { - canEdit = - LocalUserAccount.current.paperlessUser.hasPermission(UserPermissions.changeDocument); - } + bool canEdit = context.watchInternetConnection && + LocalUserAccount.current.paperlessUser + .hasPermission(PermissionAction.change, PermissionTarget.document); if (!canEdit) { return const SizedBox.shrink(); } @@ -281,7 +273,7 @@ class _DocumentDetailsPageState extends State { verticalOffset: 40, child: FloatingActionButton( child: const Icon(Icons.edit), - onPressed: canEdit ? () => _onEdit(state.document) : null, + onPressed: () => _onEdit(state.document), ), ); }, @@ -296,15 +288,16 @@ class _DocumentDetailsPageState extends State { builder: (context, connectivityState) { final isConnected = connectivityState.isConnected; - final canDelete = LocalUserAccount.current.paperlessUser - .hasPermission(UserPermissions.deleteDocument); + final canDelete = isConnected && + LocalUserAccount.current.paperlessUser + .hasPermission(PermissionAction.delete, PermissionTarget.document); return Row( mainAxisAlignment: MainAxisAlignment.start, children: [ IconButton( tooltip: S.of(context)!.deleteDocumentTooltip, icon: const Icon(Icons.delete), - onPressed: (isConnected && canDelete) ? () => _onDelete(state.document) : null, + onPressed: canDelete ? () => _onDelete(state.document) : null, ).paddedSymmetrically(horizontal: 4), DocumentDownloadButton( document: state.document, diff --git a/lib/features/document_details/view/widgets/archive_serial_number_field.dart b/lib/features/document_details/view/widgets/archive_serial_number_field.dart index d3597ea..f5c5f52 100644 --- a/lib/features/document_details/view/widgets/archive_serial_number_field.dart +++ b/lib/features/document_details/view/widgets/archive_serial_number_field.dart @@ -3,6 +3,7 @@ import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/core/bloc/connectivity_cubit.dart'; +import 'package:paperless_mobile/core/database/tables/local_user_account.dart'; import 'package:paperless_mobile/core/type/types.dart'; import 'package:paperless_mobile/extensions/flutter_extensions.dart'; import 'package:paperless_mobile/features/document_details/cubit/document_details_cubit.dart'; @@ -17,8 +18,7 @@ class ArchiveSerialNumberField extends StatefulWidget { }); @override - State createState() => - _ArchiveSerialNumberFieldState(); + State createState() => _ArchiveSerialNumberFieldState(); } class _ArchiveSerialNumberFieldState extends State { @@ -39,20 +39,21 @@ class _ArchiveSerialNumberFieldState extends State { void _clearButtonListener() { setState(() { _showClearButton = _asnEditingController.text.isNotEmpty; - _canUpdate = int.tryParse(_asnEditingController.text) != - widget.document.archiveSerialNumber; + _canUpdate = int.tryParse(_asnEditingController.text) != widget.document.archiveSerialNumber; }); } @override Widget build(BuildContext context) { + final userCanEditDocument = LocalUserAccount.current.paperlessUser.hasPermission( + PermissionAction.change, + PermissionTarget.document, + ); return BlocListener( listenWhen: (previous, current) => - previous.document.archiveSerialNumber != - current.document.archiveSerialNumber, + previous.document.archiveSerialNumber != current.document.archiveSerialNumber, listener: (context, state) { - _asnEditingController.text = - state.document.archiveSerialNumber?.toString() ?? ''; + _asnEditingController.text = state.document.archiveSerialNumber?.toString() ?? ''; setState(() { _canUpdate = false; }); @@ -61,6 +62,7 @@ class _ArchiveSerialNumberFieldState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ TextFormField( + enabled: userCanEditDocument, controller: _asnEditingController, keyboardType: TextInputType.number, onChanged: (value) { @@ -78,15 +80,13 @@ class _ArchiveSerialNumberFieldState extends State { IconButton( icon: const Icon(Icons.clear), color: Theme.of(context).colorScheme.primary, - onPressed: _asnEditingController.clear, + onPressed: userCanEditDocument ? _asnEditingController.clear : null, ), IconButton( icon: const Icon(Icons.plus_one_rounded), color: Theme.of(context).colorScheme.primary, onPressed: - context.watchInternetConnection && !_showClearButton - ? _onAutoAssign - : null, + context.watchInternetConnection && !_showClearButton ? _onAutoAssign : null, ).paddedOnly(right: 8), ], ), @@ -97,9 +97,7 @@ class _ArchiveSerialNumberFieldState extends State { ), TextButton.icon( icon: const Icon(Icons.done), - onPressed: context.watchInternetConnection && _canUpdate - ? _onSubmitted - : null, + onPressed: context.watchInternetConnection && _canUpdate ? _onSubmitted : null, label: Text(S.of(context)!.save), ).padded(), ], diff --git a/lib/features/document_details/view/widgets/details_item.dart b/lib/features/document_details/view/widgets/details_item.dart index e50f24c..4003cd0 100644 --- a/lib/features/document_details/view/widgets/details_item.dart +++ b/lib/features/document_details/view/widgets/details_item.dart @@ -24,7 +24,7 @@ class DetailsItem extends StatelessWidget { } DetailsItem.text( - String text, { + String text, {super.key, required this.label, required BuildContext context, }) : content = Text( diff --git a/lib/features/document_details/view/widgets/document_meta_data_widget.dart b/lib/features/document_details/view/widgets/document_meta_data_widget.dart index 24806c6..b2b55ce 100644 --- a/lib/features/document_details/view/widgets/document_meta_data_widget.dart +++ b/lib/features/document_details/view/widgets/document_meta_data_widget.dart @@ -29,8 +29,8 @@ class _DocumentMetaDataWidgetState extends State { builder: (context, state) { debugPrint("Building state..."); if (state.metaData == null) { - return SliverToBoxAdapter( - child: const Center( + return const SliverToBoxAdapter( + child: Center( child: CircularProgressIndicator(), ), ); diff --git a/lib/features/document_details/view/widgets/document_overview_widget.dart b/lib/features/document_details/view/widgets/document_overview_widget.dart index 908c974..0f3edd8 100644 --- a/lib/features/document_details/view/widgets/document_overview_widget.dart +++ b/lib/features/document_details/view/widgets/document_overview_widget.dart @@ -4,7 +4,6 @@ import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/core/widgets/highlighted_text.dart'; import 'package:paperless_mobile/extensions/flutter_extensions.dart'; import 'package:paperless_mobile/features/document_details/view/widgets/details_item.dart'; -import 'package:paperless_mobile/features/labels/storage_path/view/widgets/storage_path_widget.dart'; import 'package:paperless_mobile/features/labels/tags/view/widgets/tags_widget.dart'; import 'package:paperless_mobile/features/labels/view/widgets/label_text.dart'; import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; diff --git a/lib/features/document_edit/view/document_edit_page.dart b/lib/features/document_edit/view/document_edit_page.dart index baf6127..0d836e9 100644 --- a/lib/features/document_edit/view/document_edit_page.dart +++ b/lib/features/document_edit/view/document_edit_page.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'dart:developer'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -8,6 +7,7 @@ import 'package:flutter_typeahead/flutter_typeahead.dart'; import 'package:intl/intl.dart'; import 'package:paperless_api/paperless_api.dart'; +import 'package:paperless_mobile/core/database/tables/local_user_account.dart'; import 'package:paperless_mobile/core/repository/label_repository.dart'; import 'package:paperless_mobile/core/workarounds/colored_chip.dart'; import 'package:paperless_mobile/extensions/flutter_extensions.dart'; @@ -16,7 +16,6 @@ import 'package:paperless_mobile/features/edit_label/view/impl/add_correspondent import 'package:paperless_mobile/features/edit_label/view/impl/add_document_type_page.dart'; import 'package:paperless_mobile/features/edit_label/view/impl/add_storage_path_page.dart'; import 'package:paperless_mobile/features/labels/tags/view/widgets/tags_form_field.dart'; -import 'package:paperless_mobile/features/labels/tags/view/widgets/tags_form_field.dart'; import 'package:paperless_mobile/features/labels/view/widgets/label_form_field.dart'; import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; @@ -117,6 +116,11 @@ class _DocumentEditPageState extends State { name: fkCorrespondent, prefixIcon: const Icon(Icons.person_outlined), allowSelectUnassigned: true, + canCreateNewLabel: + LocalUserAccount.current.paperlessUser.hasPermission( + PermissionAction.add, + PermissionTarget.correspondent, + ), ), if (_filteredSuggestions?.hasSuggestedCorrespondents ?? false) _buildSuggestionsSkeleton( @@ -144,6 +148,11 @@ class _DocumentEditPageState extends State { initialName: currentInput, ), ), + canCreateNewLabel: + LocalUserAccount.current.paperlessUser.hasPermission( + PermissionAction.add, + PermissionTarget.documentType, + ), addLabelText: S.of(context)!.addDocumentType, labelText: S.of(context)!.documentType, initialValue: state.document.documentType != null @@ -177,6 +186,11 @@ class _DocumentEditPageState extends State { value: context.read(), child: AddStoragePathPage(initalName: initialValue), ), + canCreateNewLabel: + LocalUserAccount.current.paperlessUser.hasPermission( + PermissionAction.add, + PermissionTarget.storagePath, + ), addLabelText: S.of(context)!.addStoragePath, labelText: S.of(context)!.storagePath, options: state.storagePaths, diff --git a/lib/features/document_scan/view/widgets/scanned_image_item.dart b/lib/features/document_scan/view/widgets/scanned_image_item.dart index 62931bf..adb597f 100644 --- a/lib/features/document_scan/view/widgets/scanned_image_item.dart +++ b/lib/features/document_scan/view/widgets/scanned_image_item.dart @@ -98,7 +98,7 @@ class _ScannedImageItemState extends State { alignment: Alignment.bottomCenter, child: TextButton( onPressed: widget.onDelete, - child: Text("Remove"), + child: const Text("Remove"), ), ), ], diff --git a/lib/features/document_search/view/document_search_page.dart b/lib/features/document_search/view/document_search_page.dart index 14803f3..131393d 100644 --- a/lib/features/document_search/view/document_search_page.dart +++ b/lib/features/document_search/view/document_search_page.dart @@ -3,15 +3,7 @@ import 'dart:async'; import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_cache_manager/flutter_cache_manager.dart'; -import 'package:hive/hive.dart'; -import 'package:paperless_api/paperless_api.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/local_user_app_state.dart'; import 'package:paperless_mobile/core/navigation/push_routes.dart'; -import 'package:paperless_mobile/core/notifier/document_changed_notifier.dart'; -import 'package:paperless_mobile/core/repository/label_repository.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/view/remove_history_entry_dialog.dart'; @@ -19,10 +11,8 @@ import 'package:paperless_mobile/features/documents/view/widgets/adaptive_docume import 'package:paperless_mobile/features/documents/view/widgets/selection/view_type_selection_widget.dart'; import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; -import 'package:paperless_mobile/routes/document_details_route.dart'; import 'dart:math' as math; -import 'package:provider/provider.dart'; class DocumentSearchPage extends StatefulWidget { const DocumentSearchPage({super.key}); diff --git a/lib/features/document_search/view/sliver_search_bar.dart b/lib/features/document_search/view/sliver_search_bar.dart index ba1feba..ae29581 100644 --- a/lib/features/document_search/view/sliver_search_bar.dart +++ b/lib/features/document_search/view/sliver_search_bar.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.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/core/database/tables/local_user_account.dart'; diff --git a/lib/features/document_upload/cubit/document_upload_cubit.dart b/lib/features/document_upload/cubit/document_upload_cubit.dart index 91eb17a..e066c15 100644 --- a/lib/features/document_upload/cubit/document_upload_cubit.dart +++ b/lib/features/document_upload/cubit/document_upload_cubit.dart @@ -35,6 +35,7 @@ class DocumentUploadCubit extends Cubit { int? correspondent, Iterable tags = const [], DateTime? createdAt, + int? asn, }) async { return await _documentApi.create( bytes, @@ -44,6 +45,7 @@ class DocumentUploadCubit extends Cubit { documentType: documentType, tags: tags, createdAt: createdAt, + asn: asn, ); } diff --git a/lib/features/document_upload/view/document_upload_preparation_page.dart b/lib/features/document_upload/view/document_upload_preparation_page.dart index ea72e5c..cb5be3a 100644 --- a/lib/features/document_upload/view/document_upload_preparation_page.dart +++ b/lib/features/document_upload/view/document_upload_preparation_page.dart @@ -7,6 +7,7 @@ import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:intl/date_symbol_data_local.dart'; import 'package:intl/intl.dart'; import 'package:paperless_api/paperless_api.dart'; +import 'package:paperless_mobile/core/database/tables/local_user_account.dart'; import 'package:paperless_mobile/core/repository/label_repository.dart'; import 'package:paperless_mobile/core/type/types.dart'; import 'package:paperless_mobile/extensions/flutter_extensions.dart'; @@ -32,7 +33,6 @@ class DocumentUploadPreparationPage extends StatefulWidget { final String? filename; final String? fileExtension; - const DocumentUploadPreparationPage({ Key? key, required this.fileBytes, @@ -193,6 +193,10 @@ class _DocumentUploadPreparationPageState extends State( @@ -208,6 +212,10 @@ class _DocumentUploadPreparationPageState extends State id); + final tags = (fv[DocumentModel.tagsKey] as TagsQuery?) + ?.whenOrNull(ids: (include, exclude) => include) ?? + []; + final correspondent = (fv[DocumentModel.correspondentKey] as IdQueryParameter?) + ?.whenOrNull(fromId: (id) => id); + final asn = fv[DocumentModel.asnKey] as int?; final taskId = await cubit.upload( widget.fileBytes, filename: _padWithExtension( @@ -250,10 +262,11 @@ class _DocumentUploadPreparationPageState extends State documentBytes; diff --git a/lib/features/documents/view/pages/documents_page.dart b/lib/features/documents/view/pages/documents_page.dart index 2d9d359..cf19ee5 100644 --- a/lib/features/documents/view/pages/documents_page.dart +++ b/lib/features/documents/view/pages/documents_page.dart @@ -6,7 +6,6 @@ import 'package:paperless_api/paperless_api.dart'; 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/navigation/push_routes.dart'; -import 'package:paperless_mobile/core/repository/label_repository.dart'; import 'package:paperless_mobile/core/widgets/material/colored_tab_bar.dart'; import 'package:paperless_mobile/extensions/flutter_extensions.dart'; import 'package:paperless_mobile/features/app_drawer/view/app_drawer.dart'; @@ -19,12 +18,10 @@ import 'package:paperless_mobile/features/documents/view/widgets/selection/docum 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/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'; import 'package:paperless_mobile/features/tasks/cubit/task_status_cubit.dart'; import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; import 'package:paperless_mobile/helpers/message_helpers.dart'; -import 'package:paperless_mobile/routes/document_details_route.dart'; class DocumentFilterIntent { final DocumentFilter? filter; @@ -370,21 +367,7 @@ class _DocumentsPageState extends State with SingleTickerProvider } void _onCreateSavedView(DocumentFilter filter) async { - final newView = await Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => BlocBuilder( - builder: (context, state) { - return AddSavedViewPage( - currentFilter: filter, - correspondents: context.read().state.correspondents, - documentTypes: context.read().state.documentTypes, - storagePaths: context.read().state.storagePaths, - tags: context.read().state.tags, - ); - }, - ), - ), - ); + final newView = await pushAddSavedViewRoute(context, filter: filter); if (newView != null) { try { await context.read().add(newView); diff --git a/lib/features/documents/view/widgets/items/document_grid_item.dart b/lib/features/documents/view/widgets/items/document_grid_item.dart index 21f05a4..506acbe 100644 --- a/lib/features/documents/view/widgets/items/document_grid_item.dart +++ b/lib/features/documents/view/widgets/items/document_grid_item.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/features/documents/view/widgets/document_preview.dart'; import 'package:paperless_mobile/features/documents/view/widgets/items/document_item.dart'; import 'package:paperless_mobile/features/labels/correspondent/view/widgets/correspondent_widget.dart'; diff --git a/lib/features/documents/view/widgets/placeholder/documents_list_loading_widget.dart b/lib/features/documents/view/widgets/placeholder/documents_list_loading_widget.dart index 492c618..36e5023 100644 --- a/lib/features/documents/view/widgets/placeholder/documents_list_loading_widget.dart +++ b/lib/features/documents/view/widgets/placeholder/documents_list_loading_widget.dart @@ -61,8 +61,8 @@ class DocumentsListLoadingWidget extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ - TagsPlaceholder(count: 2, dense: true), - SizedBox(height: 2), + const TagsPlaceholder(count: 2, dense: true), + const SizedBox(height: 2), TextPlaceholder( length: 250, fontSize: Theme.of(context).textTheme.labelSmall!.fontSize!, diff --git a/lib/features/documents/view/widgets/search/document_filter_form.dart b/lib/features/documents/view/widgets/search/document_filter_form.dart index 27afa04..978c7db 100644 --- a/lib/features/documents/view/widgets/search/document_filter_form.dart +++ b/lib/features/documents/view/widgets/search/document_filter_form.dart @@ -1,10 +1,8 @@ import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:paperless_api/paperless_api.dart'; +import 'package:paperless_mobile/core/database/tables/local_user_account.dart'; import 'package:paperless_mobile/core/widgets/form_builder_fields/extended_date_range_form_field/form_builder_extended_date_range_picker.dart'; -import 'package:paperless_mobile/features/labels/cubit/label_cubit.dart'; -import 'package:paperless_mobile/features/labels/tags/view/widgets/tags_form_field.dart'; import 'package:paperless_mobile/features/labels/tags/view/widgets/tags_form_field.dart'; import 'package:paperless_mobile/features/labels/view/widgets/label_form_field.dart'; import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; @@ -156,6 +154,10 @@ class _DocumentFilterFormState extends State { initialValue: widget.initialFilter.documentType, prefixIcon: const Icon(Icons.description_outlined), allowSelectUnassigned: false, + canCreateNewLabel: LocalUserAccount.current.paperlessUser.hasPermission( + PermissionAction.add, + PermissionTarget.documentType, + ), ); } @@ -167,6 +169,10 @@ class _DocumentFilterFormState extends State { initialValue: widget.initialFilter.correspondent, prefixIcon: const Icon(Icons.person_outline), allowSelectUnassigned: false, + canCreateNewLabel: LocalUserAccount.current.paperlessUser.hasPermission( + PermissionAction.add, + PermissionTarget.correspondent, + ), ); } @@ -178,6 +184,10 @@ class _DocumentFilterFormState extends State { initialValue: widget.initialFilter.storagePath, prefixIcon: const Icon(Icons.folder_outlined), allowSelectUnassigned: false, + canCreateNewLabel: LocalUserAccount.current.paperlessUser.hasPermission( + PermissionAction.add, + PermissionTarget.storagePath, + ), ); } diff --git a/lib/features/documents/view/widgets/search/text_query_form_field.dart b/lib/features/documents/view/widgets/search/text_query_form_field.dart index d6af5b9..f94805c 100644 --- a/lib/features/documents/view/widgets/search/text_query_form_field.dart +++ b/lib/features/documents/view/widgets/search/text_query_form_field.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:paperless_api/paperless_api.dart'; -import 'package:paperless_mobile/core/widgets/form_builder_fields/form_builder_type_ahead.dart'; import 'package:paperless_mobile/features/documents/cubit/documents_cubit.dart'; import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; diff --git a/lib/features/edit_label/view/edit_label_page.dart b/lib/features/edit_label/view/edit_label_page.dart index e090727..7b3044f 100644 --- a/lib/features/edit_label/view/edit_label_page.dart +++ b/lib/features/edit_label/view/edit_label_page.dart @@ -18,6 +18,7 @@ class EditLabelPage extends StatelessWidget { final List additionalFields; final Future Function(BuildContext context, T label) onSubmit; final Future Function(BuildContext context, T label) onDelete; + final bool canDelete; const EditLabelPage({ super.key, @@ -26,6 +27,7 @@ class EditLabelPage extends StatelessWidget { this.additionalFields = const [], required this.onSubmit, required this.onDelete, + required this.canDelete, }); @override @@ -40,6 +42,7 @@ class EditLabelPage extends StatelessWidget { fromJsonT: fromJsonT, onSubmit: onSubmit, onDelete: onDelete, + canDelete: canDelete, ), ); } @@ -51,6 +54,7 @@ class EditLabelForm extends StatelessWidget { final List additionalFields; final Future Function(BuildContext context, T label) onSubmit; final Future Function(BuildContext context, T label) onDelete; + final bool canDelete; const EditLabelForm({ super.key, @@ -59,6 +63,7 @@ class EditLabelForm extends StatelessWidget { required this.additionalFields, required this.onSubmit, required this.onDelete, + required this.canDelete, }); @override @@ -68,7 +73,7 @@ class EditLabelForm extends StatelessWidget { title: Text(S.of(context)!.edit), actions: [ IconButton( - onPressed: () => _onDelete(context), + onPressed: canDelete ? () => _onDelete(context) : null, icon: const Icon(Icons.delete), ), ], diff --git a/lib/features/edit_label/view/impl/edit_correspondent_page.dart b/lib/features/edit_label/view/impl/edit_correspondent_page.dart index f0a6e98..70a8272 100644 --- a/lib/features/edit_label/view/impl/edit_correspondent_page.dart +++ b/lib/features/edit_label/view/impl/edit_correspondent_page.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:paperless_api/paperless_api.dart'; +import 'package:paperless_mobile/core/database/tables/local_user_account.dart'; import 'package:paperless_mobile/features/edit_label/cubit/edit_label_cubit.dart'; import 'package:paperless_mobile/features/edit_label/view/edit_label_page.dart'; @@ -19,10 +20,12 @@ class EditCorrespondentPage extends StatelessWidget { return EditLabelPage( label: correspondent, fromJsonT: Correspondent.fromJson, - onSubmit: (context, label) => - context.read().replaceCorrespondent(label), - onDelete: (context, label) => - context.read().removeCorrespondent(label), + onSubmit: (context, label) => context.read().replaceCorrespondent(label), + onDelete: (context, label) => context.read().removeCorrespondent(label), + canDelete: LocalUserAccount.current.paperlessUser.hasPermission( + PermissionAction.delete, + PermissionTarget.correspondent, + ), ); }), ); diff --git a/lib/features/edit_label/view/impl/edit_document_type_page.dart b/lib/features/edit_label/view/impl/edit_document_type_page.dart index c9b6e25..1be9b23 100644 --- a/lib/features/edit_label/view/impl/edit_document_type_page.dart +++ b/lib/features/edit_label/view/impl/edit_document_type_page.dart @@ -1,7 +1,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:paperless_api/paperless_api.dart'; -import 'package:paperless_mobile/core/repository/label_repository.dart'; +import 'package:paperless_mobile/core/database/tables/local_user_account.dart'; import 'package:paperless_mobile/features/edit_label/cubit/edit_label_cubit.dart'; import 'package:paperless_mobile/features/edit_label/view/edit_label_page.dart'; @@ -18,10 +18,12 @@ class EditDocumentTypePage extends StatelessWidget { child: EditLabelPage( label: documentType, fromJsonT: DocumentType.fromJson, - onSubmit: (context, label) => - context.read().replaceDocumentType(label), - onDelete: (context, label) => - context.read().removeDocumentType(label), + onSubmit: (context, label) => context.read().replaceDocumentType(label), + onDelete: (context, label) => context.read().removeDocumentType(label), + canDelete: LocalUserAccount.current.paperlessUser.hasPermission( + PermissionAction.delete, + PermissionTarget.documentType, + ), ), ); } diff --git a/lib/features/edit_label/view/impl/edit_storage_path_page.dart b/lib/features/edit_label/view/impl/edit_storage_path_page.dart index fb3786e..8bd95a2 100644 --- a/lib/features/edit_label/view/impl/edit_storage_path_page.dart +++ b/lib/features/edit_label/view/impl/edit_storage_path_page.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:paperless_api/paperless_api.dart'; +import 'package:paperless_mobile/core/database/tables/local_user_account.dart'; import 'package:paperless_mobile/features/edit_label/cubit/edit_label_cubit.dart'; import 'package:paperless_mobile/features/edit_label/view/edit_label_page.dart'; import 'package:paperless_mobile/features/labels/storage_path/view/widgets/storage_path_autofill_form_builder_field.dart'; @@ -18,10 +19,12 @@ class EditStoragePathPage extends StatelessWidget { child: EditLabelPage( label: storagePath, fromJsonT: StoragePath.fromJson, - onSubmit: (context, label) => - context.read().replaceStoragePath(label), - onDelete: (context, label) => - context.read().removeStoragePath(label), + onSubmit: (context, label) => context.read().replaceStoragePath(label), + onDelete: (context, label) => context.read().removeStoragePath(label), + canDelete: LocalUserAccount.current.paperlessUser.hasPermission( + PermissionAction.delete, + PermissionTarget.storagePath, + ), additionalFields: [ StoragePathAutofillFormBuilderField( name: StoragePath.pathKey, diff --git a/lib/features/edit_label/view/impl/edit_tag_page.dart b/lib/features/edit_label/view/impl/edit_tag_page.dart index 9c2d79e..3a99726 100644 --- a/lib/features/edit_label/view/impl/edit_tag_page.dart +++ b/lib/features/edit_label/view/impl/edit_tag_page.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:paperless_api/paperless_api.dart'; +import 'package:paperless_mobile/core/database/tables/local_user_account.dart'; import 'package:paperless_mobile/core/widgets/form_builder_fields/form_builder_color_picker.dart'; import 'package:paperless_mobile/features/edit_label/cubit/edit_label_cubit.dart'; import 'package:paperless_mobile/features/edit_label/view/edit_label_page.dart'; @@ -21,10 +22,12 @@ class EditTagPage extends StatelessWidget { child: EditLabelPage( label: tag, fromJsonT: Tag.fromJson, - onSubmit: (context, label) => - context.read().replaceTag(label), - onDelete: (context, label) => - context.read().removeTag(label), + onSubmit: (context, label) => context.read().replaceTag(label), + onDelete: (context, label) => context.read().removeTag(label), + canDelete: LocalUserAccount.current.paperlessUser.hasPermission( + PermissionAction.delete, + PermissionTarget.tag, + ), additionalFields: [ FormBuilderColorPickerField( initialValue: tag.color, diff --git a/lib/features/edit_label/view/label_form.dart b/lib/features/edit_label/view/label_form.dart index 52689fb..366a436 100644 --- a/lib/features/edit_label/view/label_form.dart +++ b/lib/features/edit_label/view/label_form.dart @@ -8,7 +8,6 @@ import 'package:paperless_mobile/extensions/flutter_extensions.dart'; import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; import 'package:paperless_mobile/helpers/message_helpers.dart'; -import 'package:paperless_mobile/constants.dart'; class SubmitButtonConfig { final Widget icon; diff --git a/lib/features/home/view/home_page.dart b/lib/features/home/view/home_page.dart index e1f4eaf..6bac0f8 100644 --- a/lib/features/home/view/home_page.dart +++ b/lib/features/home/view/home_page.dart @@ -6,38 +6,26 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:fluttertoast/fluttertoast.dart'; -import 'package:hive/hive.dart'; import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/core/bloc/connectivity_cubit.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/local_user_app_state.dart'; +import 'package:paperless_mobile/core/database/tables/local_user_account.dart'; import 'package:paperless_mobile/core/global/constants.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/repository/user_repository.dart'; import 'package:paperless_mobile/core/service/file_description.dart'; import 'package:paperless_mobile/core/translation/error_code_localization_mapper.dart'; -import 'package:paperless_mobile/features/document_scan/cubit/document_scanner_cubit.dart'; import 'package:paperless_mobile/features/document_scan/view/scanner_page.dart'; import 'package:paperless_mobile/features/document_upload/cubit/document_upload_cubit.dart'; import 'package:paperless_mobile/features/document_upload/view/document_upload_preparation_page.dart'; -import 'package:paperless_mobile/features/documents/cubit/documents_cubit.dart'; import 'package:paperless_mobile/features/documents/view/pages/documents_page.dart'; import 'package:paperless_mobile/features/home/view/route_description.dart'; import 'package:paperless_mobile/features/inbox/cubit/inbox_cubit.dart'; import 'package:paperless_mobile/features/inbox/view/pages/inbox_page.dart'; -import 'package:paperless_mobile/features/labels/cubit/label_cubit.dart'; import 'package:paperless_mobile/features/labels/view/pages/labels_page.dart'; -import 'package:paperless_mobile/features/login/cubit/authentication_cubit.dart'; -import 'package:paperless_mobile/core/database/tables/local_user_account.dart'; import 'package:paperless_mobile/features/notifications/services/local_notification_service.dart'; -import 'package:paperless_mobile/features/saved_view/cubit/saved_view_cubit.dart'; import 'package:paperless_mobile/features/sharing/share_intent_queue.dart'; import 'package:paperless_mobile/features/tasks/cubit/task_status_cubit.dart'; import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; - -import 'package:paperless_mobile/helpers/message_helpers.dart'; import 'package:receive_sharing_intent/receive_sharing_intent.dart'; import 'package:responsive_builder/responsive_builder.dart'; @@ -196,7 +184,8 @@ class _HomePageState extends State with WidgetsBindingObserver { ), label: S.of(context)!.documents, ), - if (LocalUserAccount.current.paperlessUser.hasPermission(UserPermissions.addDocument)) + if (LocalUserAccount.current.paperlessUser + .hasPermission(PermissionAction.add, PermissionTarget.document)) RouteDescription( icon: const Icon(Icons.document_scanner_outlined), selectedIcon: Icon( @@ -222,32 +211,31 @@ class _HomePageState extends State with WidgetsBindingObserver { label: S.of(context)!.inbox, badgeBuilder: (icon) => BlocBuilder( builder: (context, state) { - if (state.itemsInInboxCount > 0) { - return Badge.count( - count: state.itemsInInboxCount, - child: icon, - ); - } - return icon; + return Badge.count( + isLabelVisible: state.itemsInInboxCount > 0, + count: state.itemsInInboxCount, + child: icon, + ); }, ), ), ]; final routes = [ const DocumentsPage(), - if (LocalUserAccount.current.paperlessUser.hasPermission(UserPermissions.addDocument)) + if (LocalUserAccount.current.paperlessUser + .hasPermission(PermissionAction.add, PermissionTarget.document)) const ScannerPage(), const LabelsPage(), const InboxPage(), ]; - return MultiBlocListener( listeners: [ BlocListener( - //Only re-initialize data if the connectivity changed from not connected to connected + // If app was started offline, load data once it comes back online. listenWhen: (previous, current) => current == ConnectivityState.connected, listener: (context, state) { - _initializeData(context); + context.read().initialize(); + context.read().initialize(); }, ), BlocListener( @@ -299,14 +287,4 @@ class _HomePageState extends State with WidgetsBindingObserver { setState(() => _currentIndex = index); } } - - void _initializeData(BuildContext context) { - Future.wait([ - context.read().initialize(), - context.read().findAll(), - ]).onError((error, stackTrace) { - showErrorMessage(context, error, stackTrace); - throw error; - }); - } } diff --git a/lib/features/home/view/home_route.dart b/lib/features/home/view/home_route.dart index 3d7928d..0324c3c 100644 --- a/lib/features/home/view/home_route.dart +++ b/lib/features/home/view/home_route.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart'; import 'package:hive_flutter/adapters.dart'; import 'package:paperless_api/paperless_api.dart'; @@ -45,9 +44,10 @@ class HomeRoute extends StatelessWidget { return GlobalSettingsBuilder( builder: (context, settings) { final currentLocalUserId = settings.currentLoggedInUser!; + final apiVersion = ApiVersion(paperlessApiVersion); return MultiProvider( providers: [ - Provider.value(value: ApiVersion(paperlessApiVersion)), + Provider.value(value: apiVersion), Provider( create: (context) => CacheManager( Config( @@ -87,7 +87,7 @@ class HomeRoute extends StatelessWidget { apiVersion: paperlessApiVersion, ), ), - if (paperlessApiVersion >= 3) + if (apiVersion.hasMultiUserSupport) ProxyProvider( update: (context, value, previous) => PaperlessUserApiV3Impl( value.client, @@ -98,7 +98,7 @@ class HomeRoute extends StatelessWidget { return MultiProvider( providers: [ ProxyProvider( - update: (context, value, previous) => LabelRepository(value)..initialize(), + update: (context, value, previous) => LabelRepository(value), ), ProxyProvider( update: (context, value, previous) => SavedViewRepository(value)..initialize(), diff --git a/lib/features/home/view/model/api_version.dart b/lib/features/home/view/model/api_version.dart index f44beaf..a7cabd1 100644 --- a/lib/features/home/view/model/api_version.dart +++ b/lib/features/home/view/model/api_version.dart @@ -3,6 +3,5 @@ class ApiVersion { ApiVersion(this.version); - bool get supportsPermissions => version >= 3; bool get hasMultiUserSupport => version >= 3; } diff --git a/lib/features/home/view/widget/verify_identity_page.dart b/lib/features/home/view/widget/verify_identity_page.dart index 45e1e42..f1d3330 100644 --- a/lib/features/home/view/widget/verify_identity_page.dart +++ b/lib/features/home/view/widget/verify_identity_page.dart @@ -1,11 +1,9 @@ import 'package:flutter/material.dart'; import 'package:hydrated_bloc/hydrated_bloc.dart'; -import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/core/repository/label_repository.dart'; import 'package:paperless_mobile/core/repository/saved_view_repository.dart'; 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/global_settings.dart'; import 'package:paperless_mobile/features/settings/view/widgets/user_settings_builder.dart'; import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; diff --git a/lib/features/inbox/view/pages/inbox_page.dart b/lib/features/inbox/view/pages/inbox_page.dart index 0bed511..aa6192a 100644 --- a/lib/features/inbox/view/pages/inbox_page.dart +++ b/lib/features/inbox/view/pages/inbox_page.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:intl/intl.dart'; import 'package:paperless_api/paperless_api.dart'; +import 'package:paperless_mobile/core/exception/server_message_exception.dart'; import 'package:paperless_mobile/core/widgets/dialog_utils/dialog_cancel_button.dart'; import 'package:paperless_mobile/core/widgets/dialog_utils/dialog_confirm_button.dart'; import 'package:paperless_mobile/core/widgets/hint_card.dart'; @@ -10,7 +11,6 @@ import 'package:paperless_mobile/extensions/dart_extensions.dart'; import 'package:paperless_mobile/extensions/flutter_extensions.dart'; import 'package:paperless_mobile/features/app_drawer/view/app_drawer.dart'; import 'package:paperless_mobile/features/document_search/view/sliver_search_bar.dart'; -import 'package:paperless_mobile/features/documents/view/widgets/placeholder/documents_list_loading_widget.dart'; import 'package:paperless_mobile/features/inbox/cubit/inbox_cubit.dart'; import 'package:paperless_mobile/features/inbox/view/widgets/inbox_empty_widget.dart'; import 'package:paperless_mobile/features/inbox/view/widgets/inbox_item.dart'; @@ -26,10 +26,8 @@ class InboxPage extends StatefulWidget { State createState() => _InboxPageState(); } -class _InboxPageState extends State - with DocumentPagingViewMixin { - final SliverOverlapAbsorberHandle searchBarHandle = - SliverOverlapAbsorberHandle(); +class _InboxPageState extends State with DocumentPagingViewMixin { + final SliverOverlapAbsorberHandle searchBarHandle = SliverOverlapAbsorberHandle(); @override final pagingScrollController = ScrollController(); @@ -80,8 +78,7 @@ class _InboxPageState extends State } else if (state.documents.isEmpty) { return Center( child: InboxEmptyWidget( - emptyStateRefreshIndicatorKey: - _emptyStateRefreshIndicatorKey, + emptyStateRefreshIndicatorKey: _emptyStateRefreshIndicatorKey, ), ); } else { @@ -92,8 +89,7 @@ class _InboxPageState extends State SliverToBoxAdapter( child: HintCard( show: !state.isHintAcknowledged, - hintText: - S.of(context)!.swipeLeftToMarkADocumentAsSeen, + hintText: S.of(context)!.swipeLeftToMarkADocumentAsSeen, onHintAcknowledged: () => context.read().acknowledgeHint(), ), @@ -108,13 +104,10 @@ class _InboxPageState extends State child: Align( alignment: Alignment.centerLeft, child: ClipRRect( - borderRadius: - BorderRadius.circular(32.0), + borderRadius: BorderRadius.circular(32.0), child: Text( entry.key, - style: Theme.of(context) - .textTheme - .bodySmall, + style: Theme.of(context).textTheme.bodySmall, textAlign: TextAlign.center, ).padded(), ), @@ -182,7 +175,7 @@ class _InboxPageState extends State ], ).padded(), confirmDismiss: (_) => _onItemDismissed(doc), - key: UniqueKey(), + key: ValueKey(doc.id), child: InboxItem(document: doc), ); } @@ -227,14 +220,15 @@ class _InboxPageState extends State return true; } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); - return false; + } on ServerMessageException catch (error) { + showGenericError(context, error.message); } catch (error) { showErrorMessage( context, const PaperlessServerException.unknown(), ); - return false; } + return false; } Future _onUndoMarkAsSeen( @@ -242,9 +236,7 @@ class _InboxPageState extends State Iterable removedTags, ) async { try { - await context - .read() - .undoRemoveFromInbox(document, removedTags); + await context.read().undoRemoveFromInbox(document, removedTags); } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); } diff --git a/lib/features/inbox/view/widgets/inbox_item.dart b/lib/features/inbox/view/widgets/inbox_item.dart index 910d487..23bf0a2 100644 --- a/lib/features/inbox/view/widgets/inbox_item.dart +++ b/lib/features/inbox/view/widgets/inbox_item.dart @@ -2,6 +2,7 @@ import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:paperless_api/paperless_api.dart'; +import 'package:paperless_mobile/core/database/tables/local_user_account.dart'; import 'package:paperless_mobile/core/navigation/push_routes.dart'; import 'package:paperless_mobile/core/workarounds/colored_chip.dart'; import 'package:paperless_mobile/extensions/flutter_extensions.dart'; @@ -12,8 +13,6 @@ import 'package:paperless_mobile/features/labels/tags/view/widgets/tags_widget.d import 'package:paperless_mobile/features/labels/view/widgets/label_text.dart'; import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; -import 'package:paperless_mobile/routes/document_details_route.dart'; - class InboxItem extends StatefulWidget { static const a4AspectRatio = 1 / 1.4142; @@ -108,8 +107,8 @@ class _InboxItemState extends State { ], ), ), - SizedBox( - height: 56, + LimitedBox( + maxHeight: 56, child: _buildActions(context), ), ], @@ -121,58 +120,46 @@ class _InboxItemState extends State { } Widget _buildActions(BuildContext context) { + final canEdit = LocalUserAccount.current.paperlessUser + .hasPermission(PermissionAction.change, PermissionTarget.document); + final canDelete = LocalUserAccount.current.paperlessUser + .hasPermission(PermissionAction.delete, PermissionTarget.document); final chipShape = RoundedRectangleBorder( borderRadius: BorderRadius.circular(32), ); final actions = [ - _buildAssignAsnAction(chipShape, context), - const SizedBox(width: 8.0), - ColoredChipWrapper( - child: ActionChip( - avatar: const Icon(Icons.delete_outline), - shape: chipShape, - label: Text(S.of(context)!.deleteDocument), - onPressed: () async { - final shouldDelete = await showDialog( - context: context, - builder: (context) => DeleteDocumentConfirmationDialog(document: widget.document), - ) ?? - false; - if (shouldDelete) { - context.read().delete(widget.document); - } - }, + if (canEdit) _buildAssignAsnAction(chipShape, context), + if (canEdit && canDelete) const SizedBox(width: 8.0), + if (canDelete) + ColoredChipWrapper( + child: ActionChip( + avatar: const Icon(Icons.delete_outline), + shape: chipShape, + label: Text(S.of(context)!.deleteDocument), + onPressed: () async { + final shouldDelete = await showDialog( + context: context, + builder: (context) => + DeleteDocumentConfirmationDialog(document: widget.document), + ) ?? + false; + if (shouldDelete) { + context.read().delete(widget.document); + } + }, + ), ), - ), ]; - - // return FutureBuilder( - // future: _fieldSuggestions, - // builder: (context, snapshot) { - // List? suggestions; - // if (!snapshot.hasData) { - // suggestions = [ - // const SizedBox(width: 4), - // ]; - // } else { - // if (snapshot.data!.hasSuggestions) { - // suggestions = [ - // const SizedBox(width: 4), - // ..._buildSuggestionChips( - // chipShape, - // snapshot.data!, - // context.watch().state, - // ), - // ]; - // } - // } + if (actions.isEmpty) { + return const SizedBox.shrink(); + } return Row( children: [ Row( mainAxisSize: MainAxisSize.min, children: [ - const Icon(Icons.bolt_outlined), + const Icon(Icons.auto_awesome), ConstrainedBox( constraints: const BoxConstraints( maxWidth: 50, @@ -229,6 +216,7 @@ class _InboxItemState extends State { setState(() { _isAsnAssignLoading = true; }); + context.read().assignAsn(widget.document).whenComplete( () => setState(() => _isAsnAssignLoading = false), ); diff --git a/lib/features/inbox/view/widgets/inbox_list_loading_widget.dart b/lib/features/inbox/view/widgets/inbox_list_loading_widget.dart index ce9280c..cdd89ea 100644 --- a/lib/features/inbox/view/widgets/inbox_list_loading_widget.dart +++ b/lib/features/inbox/view/widgets/inbox_list_loading_widget.dart @@ -3,7 +3,6 @@ import 'package:paperless_mobile/core/widgets/shimmer_placeholder.dart'; import 'package:paperless_mobile/extensions/flutter_extensions.dart'; import 'package:paperless_mobile/features/documents/view/widgets/placeholder/tags_placeholder.dart'; import 'package:paperless_mobile/features/documents/view/widgets/placeholder/text_placeholder.dart'; -import 'package:paperless_mobile/features/inbox/view/widgets/inbox_item.dart'; class InboxListLoadingWidget extends StatelessWidget { const InboxListLoadingWidget({super.key}); @@ -48,10 +47,10 @@ class InboxListLoadingWidget extends StatelessWidget { ), ), const SizedBox(width: 8), - Flexible( + const Flexible( child: Column( crossAxisAlignment: CrossAxisAlignment.start, - children: const [ + children: [ Spacer(), TextPlaceholder(length: 200, fontSize: 14), Spacer(), diff --git a/lib/features/labels/cubit/label_cubit_mixin.dart b/lib/features/labels/cubit/label_cubit_mixin.dart index 032d30d..020df25 100644 --- a/lib/features/labels/cubit/label_cubit_mixin.dart +++ b/lib/features/labels/cubit/label_cubit_mixin.dart @@ -1,4 +1,3 @@ -import 'package:equatable/equatable.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/core/repository/label_repository.dart'; diff --git a/lib/features/labels/tags/view/widgets/tags_form_field.dart b/lib/features/labels/tags/view/widgets/tags_form_field.dart index e4a2f62..a385ad6 100644 --- a/lib/features/labels/tags/view/widgets/tags_form_field.dart +++ b/lib/features/labels/tags/view/widgets/tags_form_field.dart @@ -1,10 +1,9 @@ -import 'dart:developer'; - import 'package:animations/animations.dart'; import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:paperless_api/paperless_api.dart'; +import 'package:paperless_mobile/core/database/tables/local_user_account.dart'; import 'package:paperless_mobile/core/workarounds/colored_chip.dart'; import 'package:paperless_mobile/features/labels/tags/view/widgets/fullscreen_tags_form.dart'; import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; @@ -72,7 +71,11 @@ class TagsFormField extends StatelessWidget { onSubmit: closeForm, initialValue: field.value, allowOnlySelection: allowOnlySelection, - allowCreation: allowCreation, + allowCreation: allowCreation && + LocalUserAccount.current.paperlessUser.hasPermission( + PermissionAction.add, + PermissionTarget.tag, + ), allowExclude: allowExclude, ), onClosed: (data) { diff --git a/lib/features/labels/view/pages/labels_page.dart b/lib/features/labels/view/pages/labels_page.dart index ef28ab2..6c93123 100644 --- a/lib/features/labels/view/pages/labels_page.dart +++ b/lib/features/labels/view/pages/labels_page.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/core/bloc/connectivity_cubit.dart'; +import 'package:paperless_mobile/core/database/tables/local_user_account.dart'; import 'package:paperless_mobile/core/delegate/customizable_sliver_persistent_header_delegate.dart'; import 'package:paperless_mobile/core/repository/label_repository.dart'; import 'package:paperless_mobile/core/widgets/material/colored_tab_bar.dart'; @@ -16,7 +17,6 @@ import 'package:paperless_mobile/features/edit_label/view/impl/edit_document_typ import 'package:paperless_mobile/features/edit_label/view/impl/edit_storage_path_page.dart'; import 'package:paperless_mobile/features/edit_label/view/impl/edit_tag_page.dart'; import 'package:paperless_mobile/features/labels/cubit/label_cubit.dart'; -import 'package:paperless_mobile/features/labels/cubit/label_cubit_mixin.dart'; import 'package:paperless_mobile/features/labels/view/widgets/label_tab_view.dart'; import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; @@ -148,6 +148,10 @@ class _LabelsPageState extends State with SingleTickerProviderStateM correspondent: IdQueryParameter.fromId(label.id!), pageSize: label.documentCount ?? 0, ), + canEdit: LocalUserAccount.current.paperlessUser.hasPermission( + PermissionAction.change, PermissionTarget.correspondent), + canAddNew: LocalUserAccount.current.paperlessUser.hasPermission( + PermissionAction.add, PermissionTarget.correspondent), onEdit: _openEditCorrespondentPage, emptyStateActionButtonLabel: S.of(context)!.addNewCorrespondent, emptyStateDescription: S.of(context)!.noCorrespondentsSetUp, @@ -169,6 +173,10 @@ class _LabelsPageState extends State with SingleTickerProviderStateM documentType: IdQueryParameter.fromId(label.id!), pageSize: label.documentCount ?? 0, ), + canEdit: LocalUserAccount.current.paperlessUser.hasPermission( + PermissionAction.change, PermissionTarget.documentType), + canAddNew: LocalUserAccount.current.paperlessUser.hasPermission( + PermissionAction.add, PermissionTarget.documentType), onEdit: _openEditDocumentTypePage, emptyStateActionButtonLabel: S.of(context)!.addNewDocumentType, emptyStateDescription: S.of(context)!.noDocumentTypesSetUp, @@ -190,6 +198,10 @@ class _LabelsPageState extends State with SingleTickerProviderStateM tags: TagsQuery.ids(include: [label.id!]), pageSize: label.documentCount ?? 0, ), + canEdit: LocalUserAccount.current.paperlessUser + .hasPermission(PermissionAction.change, PermissionTarget.tag), + canAddNew: LocalUserAccount.current.paperlessUser + .hasPermission(PermissionAction.add, PermissionTarget.tag), onEdit: _openEditTagPage, leadingBuilder: (t) => CircleAvatar( backgroundColor: t.color, @@ -221,6 +233,10 @@ class _LabelsPageState extends State with SingleTickerProviderStateM storagePath: IdQueryParameter.fromId(label.id!), pageSize: label.documentCount ?? 0, ), + canEdit: LocalUserAccount.current.paperlessUser.hasPermission( + PermissionAction.change, PermissionTarget.storagePath), + canAddNew: LocalUserAccount.current.paperlessUser.hasPermission( + PermissionAction.add, PermissionTarget.storagePath), contentBuilder: (path) => Text(path.path), emptyStateActionButtonLabel: S.of(context)!.addNewStoragePath, emptyStateDescription: S.of(context)!.noStoragePathsSetUp, diff --git a/lib/features/labels/view/widgets/fullscreen_label_form.dart b/lib/features/labels/view/widgets/fullscreen_label_form.dart index 414a40a..8a949c2 100644 --- a/lib/features/labels/view/widgets/fullscreen_label_form.dart +++ b/lib/features/labels/view/widgets/fullscreen_label_form.dart @@ -16,6 +16,7 @@ class FullscreenLabelForm extends StatefulWidget { final String? addNewLabelText; final bool autofocus; final bool allowSelectUnassigned; + final bool canCreateNewLabel; FullscreenLabelForm({ super.key, @@ -29,6 +30,7 @@ class FullscreenLabelForm extends StatefulWidget { this.addNewLabelText, this.autofocus = true, this.allowSelectUnassigned = true, + required this.canCreateNewLabel, }) : assert( !(initialValue?.isOnlyAssigned() ?? false) || showAnyAssignedOption, ), diff --git a/lib/features/labels/view/widgets/label_form_field.dart b/lib/features/labels/view/widgets/label_form_field.dart index 29a839d..46a4504 100644 --- a/lib/features/labels/view/widgets/label_form_field.dart +++ b/lib/features/labels/view/widgets/label_form_field.dart @@ -1,5 +1,3 @@ -import 'dart:developer'; - import 'package:animations/animations.dart'; import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; @@ -28,6 +26,7 @@ class LabelFormField extends StatelessWidget { final List suggestions; final String? addLabelText; final bool allowSelectUnassigned; + final bool canCreateNewLabel; const LabelFormField({ Key? key, @@ -44,6 +43,7 @@ class LabelFormField extends StatelessWidget { this.suggestions = const [], this.addLabelText, required this.allowSelectUnassigned, + required this.canCreateNewLabel, }) : super(key: key); String _buildText(BuildContext context, IdQueryParameter? value) { @@ -103,6 +103,7 @@ class LabelFormField extends StatelessWidget { ), openBuilder: (context, closeForm) => FullscreenLabelForm( allowSelectUnassigned: allowSelectUnassigned, + canCreateNewLabel: canCreateNewLabel, addNewLabelText: addLabelText, leadingIcon: prefixIcon, onCreateNewLabel: addLabelPageBuilder != null diff --git a/lib/features/labels/view/widgets/label_item.dart b/lib/features/labels/view/widgets/label_item.dart index e8faa79..52c950b 100644 --- a/lib/features/labels/view/widgets/label_item.dart +++ b/lib/features/labels/view/widgets/label_item.dart @@ -1,19 +1,14 @@ import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:hive/hive.dart'; import 'package:paperless_api/paperless_api.dart'; -import 'package:paperless_mobile/core/config/hive/hive_config.dart'; -import 'package:paperless_mobile/features/linked_documents/cubit/linked_documents_cubit.dart'; -import 'package:paperless_mobile/features/linked_documents/view/linked_documents_page.dart'; import 'package:paperless_mobile/core/database/tables/local_user_account.dart'; -import 'package:paperless_mobile/core/database/tables/global_settings.dart'; +import 'package:paperless_mobile/core/navigation/push_routes.dart'; import 'package:paperless_mobile/helpers/format_helpers.dart'; class LabelItem extends StatelessWidget { final T label; final String name; final Widget content; - final void Function(T) onOpenEditPage; + final void Function(T)? onOpenEditPage; final DocumentFilter Function(T) filterBuilder; final Widget? leading; @@ -33,38 +28,25 @@ class LabelItem extends StatelessWidget { title: Text(name), subtitle: content, leading: leading, - onTap: () => onOpenEditPage(label), + onTap: onOpenEditPage != null ? () => onOpenEditPage!(label) : null, trailing: _buildReferencedDocumentsWidget(context), isThreeLine: true, ); } Widget _buildReferencedDocumentsWidget(BuildContext context) { + final canOpen = (label.documentCount ?? 0) > 0 && + LocalUserAccount.current.paperlessUser + .hasPermission(PermissionAction.view, PermissionTarget.document); return TextButton.icon( label: const Icon(Icons.link), icon: Text(formatMaxCount(label.documentCount)), - onPressed: (label.documentCount ?? 0) == 0 - ? null - : () { - final currentUser = Hive.box(HiveBoxes.globalSettings) - .getValue()! - .currentLoggedInUser!; + onPressed: canOpen + ? () { final filter = filterBuilder(label); - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => BlocProvider( - create: (context) => LinkedDocumentsCubit( - filter, - context.read(), - context.read(), - context.read(), - ), - child: const LinkedDocumentsPage(), - ), - ), - ); - }, + pushLinkedDocumentsView(context, filter: filter); + } + : null, ); } } diff --git a/lib/features/labels/view/widgets/label_tab_view.dart b/lib/features/labels/view/widgets/label_tab_view.dart index 5174e96..4918fb0 100644 --- a/lib/features/labels/view/widgets/label_tab_view.dart +++ b/lib/features/labels/view/widgets/label_tab_view.dart @@ -11,7 +11,9 @@ class LabelTabView extends StatelessWidget { final Map labels; final DocumentFilter Function(Label) filterBuilder; final void Function(T) onEdit; + final bool canEdit; final void Function() onAddNew; + final bool canAddNew; /// Displayed as the subtitle of the [ListTile] final Widget Function(T)? contentBuilder; @@ -33,6 +35,8 @@ class LabelTabView extends StatelessWidget { required this.onAddNew, required this.emptyStateActionButtonLabel, required this.labels, + required this.canEdit, + required this.canAddNew, }); @override @@ -54,7 +58,7 @@ class LabelTabView extends StatelessWidget { textAlign: TextAlign.center, ), TextButton( - onPressed: onAddNew, + onPressed: canAddNew ? onAddNew : null, child: Text(emptyStateActionButtonLabel), ), ].padded(), @@ -70,14 +74,11 @@ class LabelTabView extends StatelessWidget { name: l.name, content: contentBuilder?.call(l) ?? Text( - translateMatchingAlgorithmName( - context, l.matchingAlgorithm) + - ((l.match?.isNotEmpty ?? false) - ? ": ${l.match}" - : ""), + translateMatchingAlgorithmName(context, l.matchingAlgorithm) + + ((l.match?.isNotEmpty ?? false) ? ": ${l.match}" : ""), maxLines: 2, ), - onOpenEditPage: onEdit, + onOpenEditPage: canEdit ? onEdit : null, filterBuilder: filterBuilder, leading: leadingBuilder?.call(l), label: l, diff --git a/lib/features/labels/view/widgets/label_text.dart b/lib/features/labels/view/widgets/label_text.dart index a6e2df8..bf15b42 100644 --- a/lib/features/labels/view/widgets/label_text.dart +++ b/lib/features/labels/view/widgets/label_text.dart @@ -20,6 +20,5 @@ class LabelText extends StatelessWidget { maxLines: 1, overflow: TextOverflow.ellipsis, ); - ; } } diff --git a/lib/features/linked_documents/view/linked_documents_page.dart b/lib/features/linked_documents/view/linked_documents_page.dart index eeaa148..70c1bf2 100644 --- a/lib/features/linked_documents/view/linked_documents_page.dart +++ b/lib/features/linked_documents/view/linked_documents_page.dart @@ -8,7 +8,6 @@ import 'package:paperless_mobile/features/linked_documents/cubit/linked_document import 'package:paperless_mobile/features/paged_document_view/view/document_paging_view_mixin.dart'; import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; -import 'package:paperless_mobile/routes/document_details_route.dart'; class LinkedDocumentsPage extends StatefulWidget { const LinkedDocumentsPage({super.key}); diff --git a/lib/features/login/cubit/authentication_cubit.dart b/lib/features/login/cubit/authentication_cubit.dart index 0dc1d76..cdfb5d3 100644 --- a/lib/features/login/cubit/authentication_cubit.dart +++ b/lib/features/login/cubit/authentication_cubit.dart @@ -179,6 +179,7 @@ class AuthenticationCubit extends Cubit { return; } } + final userCredentialsBox = await _getUserCredentialsBox(); final authentication = userCredentialsBox.get(globalSettings.currentLoggedInUser!); await userCredentialsBox.close(); diff --git a/lib/features/login/model/authentication_information.dart b/lib/features/login/model/authentication_information.dart index 7c1c192..1743f1f 100644 --- a/lib/features/login/model/authentication_information.dart +++ b/lib/features/login/model/authentication_information.dart @@ -1,5 +1,4 @@ import 'package:hive/hive.dart'; -import 'package:json_annotation/json_annotation.dart'; import 'package:paperless_mobile/core/config/hive/hive_config.dart'; import 'package:paperless_mobile/features/login/model/client_certificate.dart'; diff --git a/lib/features/login/model/client_certificate.dart b/lib/features/login/model/client_certificate.dart index e3af6df..8c920ba 100644 --- a/lib/features/login/model/client_certificate.dart +++ b/lib/features/login/model/client_certificate.dart @@ -1,4 +1,3 @@ -import 'dart:convert'; import 'dart:typed_data'; import 'package:hive_flutter/adapters.dart'; diff --git a/lib/features/login/model/client_certificate_form_model.dart b/lib/features/login/model/client_certificate_form_model.dart index cac452d..afb9ddb 100644 --- a/lib/features/login/model/client_certificate_form_model.dart +++ b/lib/features/login/model/client_certificate_form_model.dart @@ -1,4 +1,3 @@ -import 'dart:convert'; import 'dart:typed_data'; class ClientCertificateFormModel { diff --git a/lib/features/login/view/widgets/form_fields/client_certificate_form_field.dart b/lib/features/login/view/widgets/form_fields/client_certificate_form_field.dart index 560c478..c492b76 100644 --- a/lib/features/login/view/widgets/form_fields/client_certificate_form_field.dart +++ b/lib/features/login/view/widgets/form_fields/client_certificate_form_field.dart @@ -4,12 +4,9 @@ import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:paperless_mobile/extensions/flutter_extensions.dart'; -import 'package:paperless_mobile/features/login/model/client_certificate.dart'; import 'package:paperless_mobile/features/login/model/client_certificate_form_model.dart'; import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; -import 'package:paperless_mobile/constants.dart'; -import 'package:permission_handler/permission_handler.dart'; import 'obscured_input_text_form_field.dart'; diff --git a/lib/features/login/view/widgets/form_fields/server_address_form_field.dart b/lib/features/login/view/widgets/form_fields/server_address_form_field.dart index dbd9609..9d0b5a0 100644 --- a/lib/features/login/view/widgets/form_fields/server_address_form_field.dart +++ b/lib/features/login/view/widgets/form_fields/server_address_form_field.dart @@ -1,4 +1,3 @@ -import 'dart:developer'; import 'package:flutter/material.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; @@ -49,6 +48,7 @@ class _ServerAddressFormFieldState extends State { if (!RegExp(r"https?://.*").hasMatch(value!)) { return S.of(context)!.serverAddressMustIncludeAScheme; } + return null; }, decoration: InputDecoration( hintText: "http://192.168.1.50:8000", diff --git a/lib/features/login/view/widgets/form_fields/user_credentials_form_field.dart b/lib/features/login/view/widgets/form_fields/user_credentials_form_field.dart index a70be87..a517fc6 100644 --- a/lib/features/login/view/widgets/form_fields/user_credentials_form_field.dart +++ b/lib/features/login/view/widgets/form_fields/user_credentials_form_field.dart @@ -39,6 +39,7 @@ class _UserCredentialsFormFieldState extends State { if (value?.trim().isEmpty ?? true) { return S.of(context)!.usernameMustNotBeEmpty; } + return null; }, autofillHints: const [AutofillHints.username], decoration: InputDecoration( @@ -56,6 +57,7 @@ class _UserCredentialsFormFieldState extends State { if (value?.trim().isEmpty ?? true) { return S.of(context)!.passwordMustNotBeEmpty; } + return null; }, ), ].map((child) => child.padded()).toList(), diff --git a/lib/features/login/view/widgets/login_pages/server_connection_page.dart b/lib/features/login/view/widgets/login_pages/server_connection_page.dart index 550ed90..eaf6b66 100644 --- a/lib/features/login/view/widgets/login_pages/server_connection_page.dart +++ b/lib/features/login/view/widgets/login_pages/server_connection_page.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:paperless_mobile/core/service/connectivity_status_service.dart'; -import 'package:paperless_mobile/core/widgets/paperless_logo.dart'; import 'package:paperless_mobile/extensions/flutter_extensions.dart'; import 'package:paperless_mobile/features/login/model/client_certificate.dart'; import 'package:paperless_mobile/features/login/model/client_certificate_form_model.dart'; diff --git a/lib/features/notifications/services/local_notification_service.dart b/lib/features/notifications/services/local_notification_service.dart index 97d0cff..089132c 100644 --- a/lib/features/notifications/services/local_notification_service.dart +++ b/lib/features/notifications/services/local_notification_service.dart @@ -1,7 +1,6 @@ import 'dart:convert'; import 'dart:developer'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:open_filex/open_filex.dart'; diff --git a/lib/features/paged_document_view/cubit/paged_documents_state.dart b/lib/features/paged_document_view/cubit/paged_documents_state.dart index d956cb3..298248e 100644 --- a/lib/features/paged_document_view/cubit/paged_documents_state.dart +++ b/lib/features/paged_document_view/cubit/paged_documents_state.dart @@ -1,5 +1,4 @@ import 'package:equatable/equatable.dart'; -import 'package:json_annotation/json_annotation.dart'; import 'package:paperless_api/paperless_api.dart'; /// diff --git a/lib/features/saved_view/cubit/saved_view_cubit.dart b/lib/features/saved_view/cubit/saved_view_cubit.dart index ca2bff6..ce4a290 100644 --- a/lib/features/saved_view/cubit/saved_view_cubit.dart +++ b/lib/features/saved_view/cubit/saved_view_cubit.dart @@ -3,7 +3,6 @@ import 'dart:async'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:paperless_api/paperless_api.dart'; -import 'package:paperless_mobile/core/repository/label_repository.dart'; import 'package:paperless_mobile/core/repository/saved_view_repository.dart'; part 'saved_view_state.dart'; diff --git a/lib/features/saved_view/view/saved_view_list.dart b/lib/features/saved_view/view/saved_view_list.dart index 5f6ac15..7d349c4 100644 --- a/lib/features/saved_view/view/saved_view_list.dart +++ b/lib/features/saved_view/view/saved_view_list.dart @@ -1,15 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:hive/hive.dart'; import 'package:paperless_mobile/core/bloc/connectivity_cubit.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/local_user_app_state.dart'; import 'package:paperless_mobile/core/navigation/push_routes.dart'; import 'package:paperless_mobile/core/widgets/hint_card.dart'; import 'package:paperless_mobile/features/saved_view/cubit/saved_view_cubit.dart'; -import 'package:paperless_mobile/features/saved_view_details/cubit/saved_view_details_cubit.dart'; -import 'package:paperless_mobile/features/saved_view_details/view/saved_view_details_page.dart'; import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; class SavedViewList extends StatelessWidget { @@ -23,7 +17,7 @@ class SavedViewList extends StatelessWidget { builder: (context, state) { return state.when( initial: () => SliverToBoxAdapter(child: Container()), - loading: () => SliverToBoxAdapter( + loading: () => const SliverToBoxAdapter( child: Center( child: Text("Saved views loading..."), //TODO: INTL ), @@ -55,7 +49,7 @@ class SavedViewList extends StatelessWidget { ), ); }, - error: () => Center( + error: () => const Center( child: Text( "An error occurred while trying to load the saved views.", ), diff --git a/lib/features/saved_view_details/cubit/saved_view_details_cubit.dart b/lib/features/saved_view_details/cubit/saved_view_details_cubit.dart index 4f5d393..1dc9448 100644 --- a/lib/features/saved_view_details/cubit/saved_view_details_cubit.dart +++ b/lib/features/saved_view_details/cubit/saved_view_details_cubit.dart @@ -1,5 +1,4 @@ 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/database/tables/local_user_app_state.dart'; import 'package:paperless_mobile/core/notifier/document_changed_notifier.dart'; diff --git a/lib/features/saved_view_details/view/saved_view_details_page.dart b/lib/features/saved_view_details/view/saved_view_details_page.dart index 234d21f..d19e0e1 100644 --- a/lib/features/saved_view_details/view/saved_view_details_page.dart +++ b/lib/features/saved_view_details/view/saved_view_details_page.dart @@ -9,7 +9,6 @@ import 'package:paperless_mobile/features/documents/view/widgets/selection/confi import 'package:paperless_mobile/features/documents/view/widgets/selection/view_type_selection_widget.dart'; import 'package:paperless_mobile/features/paged_document_view/view/document_paging_view_mixin.dart'; import 'package:paperless_mobile/features/saved_view_details/cubit/saved_view_details_cubit.dart'; -import 'package:paperless_mobile/routes/document_details_route.dart'; class SavedViewDetailsPage extends StatefulWidget { final Future Function(SavedView savedView) onDelete; diff --git a/lib/features/settings/view/manage_accounts_page.dart b/lib/features/settings/view/manage_accounts_page.dart index edec819..2ab1f96 100644 --- a/lib/features/settings/view/manage_accounts_page.dart +++ b/lib/features/settings/view/manage_accounts_page.dart @@ -1,6 +1,5 @@ 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:paperless_mobile/core/config/hive/hive_config.dart'; import 'package:paperless_mobile/core/database/tables/global_settings.dart'; @@ -49,7 +48,6 @@ class ManageAccountsPage extends StatelessWidget { children: [ _buildAccountTile(context, globalSettings.currentLoggedInUser!, box.get(globalSettings.currentLoggedInUser!)!, globalSettings), - // if (otherAccounts.isNotEmpty) Text("Other accounts"), Column( children: [ for (int index = 0; index < otherAccounts.length; index++) @@ -69,17 +67,11 @@ class ManageAccountsPage extends StatelessWidget { _onAddAccount(context, globalSettings.currentLoggedInUser!); }, ), - Consumer( - builder: (context, value, child) { - if (value.version >= 3) { - return const ListTile( - leading: Icon(Icons.admin_panel_settings), - title: Text("Manage permissions"), //TODO : INTL - ); - } - return const SizedBox.shrink(); - }, - ) + if (context.watch().hasMultiUserSupport) + const ListTile( + leading: Icon(Icons.admin_panel_settings), + title: Text("Manage permissions"), //TODO: INTL + ), ], ); }, @@ -106,9 +98,7 @@ class ManageAccountsPage extends StatelessWidget { if (account.paperlessUser.fullName != null) Text(account.paperlessUser.fullName!), Text( account.serverUrl.replaceFirst(RegExp(r'https://?'), ''), - style: TextStyle( - color: Theme.of(context).colorScheme.primary, - ), + style: TextStyle(color: theme.colorScheme.primary), ), ], ), diff --git a/lib/features/settings/view/pages/security_settings_page.dart b/lib/features/settings/view/pages/security_settings_page.dart index da28480..c98b2c8 100644 --- a/lib/features/settings/view/pages/security_settings_page.dart +++ b/lib/features/settings/view/pages/security_settings_page.dart @@ -10,10 +10,10 @@ class SecuritySettingsPage extends StatelessWidget { return Scaffold( appBar: AppBar( title: Text(S.of(context)!.security), - actions: [ + actions: const [ Padding( - padding: const EdgeInsets.all(16.0), - child: const Icon(Icons.person_outline), + padding: EdgeInsets.all(16.0), + child: Icon(Icons.person_outline), ) ], ), diff --git a/lib/features/settings/view/widgets/clear_storage_settings.dart b/lib/features/settings/view/widgets/clear_storage_settings.dart index 78709bf..a8f3ea4 100644 --- a/lib/features/settings/view/widgets/clear_storage_settings.dart +++ b/lib/features/settings/view/widgets/clear_storage_settings.dart @@ -13,9 +13,9 @@ class ClearCacheSetting extends StatelessWidget { @override Widget build(BuildContext context) { return ListTile( - title: Text("Clear downloaded files"), //TODO: INTL + title: const Text("Clear downloaded files"), //TODO: INTL subtitle: - Text("Deletes all files downloaded from this app."), //TODO: INTL + const Text("Deletes all files downloaded from this app."), //TODO: INTL onTap: () async { final dir = await FileService.downloadsDirectory; final deletedSize = _dirSize(dir); @@ -36,8 +36,8 @@ class ClearDownloadsSetting extends StatelessWidget { @override Widget build(BuildContext context) { return ListTile( - title: Text("Clear downloads"), //TODO: INTL - subtitle: Text( + title: const Text("Clear downloads"), //TODO: INTL + subtitle: const Text( "Remove downloaded files, scans and clear the cache's content"), //TODO: INTL onTap: () { FileService.documentsDirectory; diff --git a/lib/features/settings/view/widgets/color_scheme_option_setting.dart b/lib/features/settings/view/widgets/color_scheme_option_setting.dart index af6f3b0..0b29cc3 100644 --- a/lib/features/settings/view/widgets/color_scheme_option_setting.dart +++ b/lib/features/settings/view/widgets/color_scheme_option_setting.dart @@ -1,13 +1,9 @@ import 'dart:io'; import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:hive_flutter/adapters.dart'; import 'package:paperless_mobile/constants.dart'; -import 'package:paperless_mobile/core/config/hive/hive_config.dart'; import 'package:paperless_mobile/core/translation/color_scheme_option_localization_mapper.dart'; import 'package:paperless_mobile/core/widgets/hint_card.dart'; -import 'package:paperless_mobile/core/database/tables/global_settings.dart'; import 'package:paperless_mobile/features/settings/model/color_scheme_option.dart'; import 'package:paperless_mobile/features/settings/view/widgets/global_settings_builder.dart'; import 'package:paperless_mobile/features/settings/view/widgets/radio_settings_dialog.dart'; @@ -69,7 +65,7 @@ class ColorSchemeOptionSetting extends StatelessWidget { bool _isBelowAndroid12() { if (Platform.isAndroid) { - final int version = int.tryParse(androidInfo!.version.release ?? '0') ?? 0; + final int version = int.tryParse(androidInfo!.version.release) ?? 0; return version < 12; } return false; diff --git a/lib/features/settings/view/widgets/global_settings_builder.dart b/lib/features/settings/view/widgets/global_settings_builder.dart index e8425d3..d24f9bd 100644 --- a/lib/features/settings/view/widgets/global_settings_builder.dart +++ b/lib/features/settings/view/widgets/global_settings_builder.dart @@ -1,6 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter/src/widgets/framework.dart'; -import 'package:flutter/src/widgets/placeholder.dart'; import 'package:hive_flutter/adapters.dart'; import 'package:paperless_mobile/core/config/hive/hive_config.dart'; import 'package:paperless_mobile/core/database/tables/global_settings.dart'; diff --git a/lib/features/settings/view/widgets/radio_settings_dialog.dart b/lib/features/settings/view/widgets/radio_settings_dialog.dart index 96329bc..658fdeb 100644 --- a/lib/features/settings/view/widgets/radio_settings_dialog.dart +++ b/lib/features/settings/view/widgets/radio_settings_dialog.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:paperless_mobile/core/widgets/dialog_utils/dialog_cancel_button.dart'; import 'package:paperless_mobile/core/widgets/dialog_utils/dialog_confirm_button.dart'; -import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; class RadioSettingsDialog extends StatefulWidget { final List> options; diff --git a/lib/features/settings/view/widgets/theme_mode_setting.dart b/lib/features/settings/view/widgets/theme_mode_setting.dart index a0e490d..a4b563b 100644 --- a/lib/features/settings/view/widgets/theme_mode_setting.dart +++ b/lib/features/settings/view/widgets/theme_mode_setting.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:paperless_mobile/features/settings/view/widgets/global_settings_builder.dart'; import 'package:paperless_mobile/features/settings/view/widgets/radio_settings_dialog.dart'; import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; diff --git a/lib/features/settings/view/widgets/user_avatar.dart b/lib/features/settings/view/widgets/user_avatar.dart index 1e44bef..41be64a 100644 --- a/lib/features/settings/view/widgets/user_avatar.dart +++ b/lib/features/settings/view/widgets/user_avatar.dart @@ -1,8 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/core/database/tables/local_user_account.dart'; -import 'package:paperless_mobile/core/repository/user_repository.dart'; class UserAvatar extends StatelessWidget { final String userId; diff --git a/lib/features/settings/view/widgets/user_settings_builder.dart b/lib/features/settings/view/widgets/user_settings_builder.dart index b4247fc..0684251 100644 --- a/lib/features/settings/view/widgets/user_settings_builder.dart +++ b/lib/features/settings/view/widgets/user_settings_builder.dart @@ -3,7 +3,6 @@ import 'package:hive_flutter/adapters.dart'; import 'package:paperless_mobile/core/config/hive/hive_config.dart'; import 'package:paperless_mobile/core/database/tables/local_user_account.dart'; import 'package:paperless_mobile/core/database/tables/global_settings.dart'; -import 'package:paperless_mobile/core/database/tables/local_user_settings.dart'; class UserAccountBuilder extends StatelessWidget { final Widget Function( diff --git a/lib/features/sharing/share_intent_queue.dart b/lib/features/sharing/share_intent_queue.dart index b22fb04..79ccd60 100644 --- a/lib/features/sharing/share_intent_queue.dart +++ b/lib/features/sharing/share_intent_queue.dart @@ -1,5 +1,4 @@ import 'dart:collection'; -import 'dart:developer'; import 'package:flutter/widgets.dart'; import 'package:receive_sharing_intent/receive_sharing_intent.dart'; diff --git a/lib/helpers/message_helpers.dart b/lib/helpers/message_helpers.dart index 4e5d977..09ddaee 100644 --- a/lib/helpers/message_helpers.dart +++ b/lib/helpers/message_helpers.dart @@ -2,9 +2,7 @@ import 'dart:developer'; import 'package:flutter/material.dart'; import 'package:paperless_api/paperless_api.dart'; -import 'package:paperless_mobile/core/service/github_issue_service.dart'; import 'package:paperless_mobile/core/translation/error_code_localization_mapper.dart'; -import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; class SnackBarActionConfig { final String label; @@ -67,13 +65,13 @@ void showGenericError( showSnackBar( context, error.toString(), - action: SnackBarActionConfig( - label: S.of(context)!.report, - onPressed: () => GithubIssueService.createIssueFromError( - context, - stackTrace: stackTrace, - ), - ), + // action: SnackBarActionConfig( + // label: S.of(context)!.report, + // onPressed: () => GithubIssueService.createIssueFromError( + // context, + // stackTrace: stackTrace, + // ), + // ), ); log( "An error has occurred.", diff --git a/lib/main.dart b/lib/main.dart index eea1556..69b10a2 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:io'; import 'package:connectivity_plus/connectivity_plus.dart'; @@ -56,10 +57,8 @@ String get defaultPreferredLocaleSubtag { Future _initHive() async { await Hive.initFlutter(); - // //TODO: REMOVE! - // await getApplicationDocumentsDirectory().then((value) => value.delete(recursive: true)); - registerHiveAdapters(); + // await getApplicationDocumentsDirectory().then((value) => value.deleteSync(recursive: true)); await Hive.openBox(HiveBoxes.localUserAccount); await Hive.openBox(HiveBoxes.localUserAppState); final globalSettingsBox = await Hive.openBox(HiveBoxes.globalSettings); @@ -126,9 +125,7 @@ void main() async { providers: [ ChangeNotifierProvider.value(value: sessionManager), Provider.value(value: localAuthService), - Provider.value( - value: connectivityStatusService, - ), + Provider.value(value: connectivityStatusService), Provider.value(value: localNotificationService), Provider.value(value: DocumentChangedNotifier()), ], @@ -136,12 +133,7 @@ void main() async { providers: [ BlocProvider.value(value: connectivityCubit), BlocProvider( - create: (context) => AuthenticationCubit( - localAuthService, - apiFactory, - sessionManager, - ), - child: Container(), + create: (context) => AuthenticationCubit(localAuthService, apiFactory, sessionManager), ) ], child: PaperlessMobileEntrypoint( @@ -215,6 +207,7 @@ class AuthenticationWrapper extends StatefulWidget { } class _AuthenticationWrapperState extends State { + late final StreamSubscription _shareMediaSubscription; @override void didChangeDependencies() { super.didChangeDependencies(); @@ -223,6 +216,12 @@ class _AuthenticationWrapperState extends State { }); } + @override + void dispose() { + _shareMediaSubscription.cancel(); + super.dispose(); + } + @override void initState() { super.initState(); @@ -233,7 +232,8 @@ class _AuthenticationWrapperState extends State { } initializeDateFormatting(); // For sharing files coming from outside the app while the app is still opened - ReceiveSharingIntent.getMediaStream().listen(ShareIntentQueue.instance.addAll); + _shareMediaSubscription = + ReceiveSharingIntent.getMediaStream().listen(ShareIntentQueue.instance.addAll); // For sharing files coming from outside the app while the app is closed ReceiveSharingIntent.getInitialMedia().then(ShareIntentQueue.instance.addAll); } diff --git a/lib/theme.dart b/lib/theme.dart index adee91d..46ab95d 100644 --- a/lib/theme.dart +++ b/lib/theme.dart @@ -43,7 +43,7 @@ ThemeData buildTheme({ inputDecorationTheme: _defaultInputDecorationTheme, listTileTheme: _defaultListTileTheme, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, - appBarTheme: AppBarTheme( + appBarTheme: const AppBarTheme( scrolledUnderElevation: 0, ), chipTheme: ChipThemeData( diff --git a/packages/paperless_api/lib/config/hive/hive_type_ids.dart b/packages/paperless_api/lib/config/hive/hive_type_ids.dart index c2a3887..d08224a 100644 --- a/packages/paperless_api/lib/config/hive/hive_type_ids.dart +++ b/packages/paperless_api/lib/config/hive/hive_type_ids.dart @@ -1,6 +1,5 @@ import 'package:hive/hive.dart'; import 'package:paperless_api/paperless_api.dart'; -import 'package:paperless_api/src/models/user_model.dart'; class PaperlessApiHiveTypeIds { PaperlessApiHiveTypeIds._(); @@ -56,7 +55,6 @@ void registerPaperlessApiHiveTypeAdapters() { // Users and permissions Hive.registerAdapter(UserModelV3Adapter()); Hive.registerAdapter(UserModelV2Adapter()); - Hive.registerAdapter(UserPermissionsAdapter()); Hive.registerAdapter(InheritedPermissionsAdapter()); Hive.registerAdapter(GroupModelAdapter()); Hive.registerAdapter(PermissionsAdapter()); diff --git a/packages/paperless_api/lib/src/converters/date_range_query_json_converter.dart b/packages/paperless_api/lib/src/converters/date_range_query_json_converter.dart index 52a45ee..7115fe2 100644 --- a/packages/paperless_api/lib/src/converters/date_range_query_json_converter.dart +++ b/packages/paperless_api/lib/src/converters/date_range_query_json_converter.dart @@ -1,7 +1,5 @@ import 'package:json_annotation/json_annotation.dart'; import 'package:paperless_api/src/models/models.dart'; -import 'package:paperless_api/src/models/query_parameters/date_range_queries/absolute_date_range_query.dart'; -import 'package:paperless_api/src/models/query_parameters/date_range_queries/relative_date_range_query.dart'; class DateRangeQueryJsonConverter extends JsonConverter> { diff --git a/packages/paperless_api/lib/src/converters/local_date_time_json_converter.dart b/packages/paperless_api/lib/src/converters/local_date_time_json_converter.dart index 5f95bc2..71b9060 100644 --- a/packages/paperless_api/lib/src/converters/local_date_time_json_converter.dart +++ b/packages/paperless_api/lib/src/converters/local_date_time_json_converter.dart @@ -1,4 +1,3 @@ -import 'dart:developer'; import 'package:json_annotation/json_annotation.dart'; diff --git a/packages/paperless_api/lib/src/models/filter_rule_model.dart b/packages/paperless_api/lib/src/models/filter_rule_model.dart index b8feec3..21268e0 100644 --- a/packages/paperless_api/lib/src/models/filter_rule_model.dart +++ b/packages/paperless_api/lib/src/models/filter_rule_model.dart @@ -1,9 +1,10 @@ +// ignore_for_file: unused_field + import 'package:equatable/equatable.dart'; import 'package:json_annotation/json_annotation.dart'; import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_api/src/constants.dart'; import 'package:paperless_api/src/converters/local_date_time_json_converter.dart'; -import 'package:paperless_api/src/models/query_parameters/tags_query/tags_query.dart'; part 'filter_rule_model.g.dart'; diff --git a/packages/paperless_api/lib/src/models/group_model.dart b/packages/paperless_api/lib/src/models/group_model.dart index f932e4a..ac952d5 100644 --- a/packages/paperless_api/lib/src/models/group_model.dart +++ b/packages/paperless_api/lib/src/models/group_model.dart @@ -11,7 +11,7 @@ class GroupModel with _$GroupModel { const factory GroupModel({ @HiveField(0) required int id, @HiveField(1) required String name, - @HiveField(2) required List permissions, + @HiveField(2) required List permissions, }) = _GroupModel; factory GroupModel.fromJson(Map json) => _$GroupModelFromJson(json); diff --git a/packages/paperless_api/lib/src/models/group_model.freezed.dart b/packages/paperless_api/lib/src/models/group_model.freezed.dart index d91b6bc..d3bc9cb 100644 --- a/packages/paperless_api/lib/src/models/group_model.freezed.dart +++ b/packages/paperless_api/lib/src/models/group_model.freezed.dart @@ -25,7 +25,7 @@ mixin _$GroupModel { @HiveField(1) String get name => throw _privateConstructorUsedError; @HiveField(2) - List get permissions => throw _privateConstructorUsedError; + List get permissions => throw _privateConstructorUsedError; Map toJson() => throw _privateConstructorUsedError; @JsonKey(ignore: true) @@ -42,7 +42,7 @@ abstract class $GroupModelCopyWith<$Res> { $Res call( {@HiveField(0) int id, @HiveField(1) String name, - @HiveField(2) List permissions}); + @HiveField(2) List permissions}); } /// @nodoc @@ -74,7 +74,7 @@ class _$GroupModelCopyWithImpl<$Res, $Val extends GroupModel> permissions: null == permissions ? _value.permissions : permissions // ignore: cast_nullable_to_non_nullable - as List, + as List, ) as $Val); } } @@ -90,7 +90,7 @@ abstract class _$$_GroupModelCopyWith<$Res> $Res call( {@HiveField(0) int id, @HiveField(1) String name, - @HiveField(2) List permissions}); + @HiveField(2) List permissions}); } /// @nodoc @@ -120,7 +120,7 @@ class __$$_GroupModelCopyWithImpl<$Res> permissions: null == permissions ? _value._permissions : permissions // ignore: cast_nullable_to_non_nullable - as List, + as List, )); } } @@ -131,7 +131,7 @@ class _$_GroupModel implements _GroupModel { const _$_GroupModel( {@HiveField(0) required this.id, @HiveField(1) required this.name, - @HiveField(2) required final List permissions}) + @HiveField(2) required final List permissions}) : _permissions = permissions; factory _$_GroupModel.fromJson(Map json) => @@ -143,10 +143,10 @@ class _$_GroupModel implements _GroupModel { @override @HiveField(1) final String name; - final List _permissions; + final List _permissions; @override @HiveField(2) - List get permissions { + List get permissions { if (_permissions is EqualUnmodifiableListView) return _permissions; // ignore: implicit_dynamic_type return EqualUnmodifiableListView(_permissions); @@ -189,10 +189,9 @@ class _$_GroupModel implements _GroupModel { abstract class _GroupModel implements GroupModel { const factory _GroupModel( - {@HiveField(0) required final int id, - @HiveField(1) required final String name, - @HiveField(2) required final List permissions}) = - _$_GroupModel; + {@HiveField(0) required final int id, + @HiveField(1) required final String name, + @HiveField(2) required final List permissions}) = _$_GroupModel; factory _GroupModel.fromJson(Map json) = _$_GroupModel.fromJson; @@ -205,7 +204,7 @@ abstract class _GroupModel implements GroupModel { String get name; @override @HiveField(2) - List get permissions; + List get permissions; @override @JsonKey(ignore: true) _$$_GroupModelCopyWith<_$_GroupModel> get copyWith => diff --git a/packages/paperless_api/lib/src/models/labels/tag_model.dart b/packages/paperless_api/lib/src/models/labels/tag_model.dart index f317d32..6052809 100644 --- a/packages/paperless_api/lib/src/models/labels/tag_model.dart +++ b/packages/paperless_api/lib/src/models/labels/tag_model.dart @@ -1,7 +1,5 @@ -import 'dart:developer'; import 'dart:ui'; -import 'package:flutter/foundation.dart'; import 'package:json_annotation/json_annotation.dart'; import 'package:paperless_api/src/converters/hex_color_json_converter.dart'; import 'package:paperless_api/src/models/labels/label_model.dart'; @@ -24,7 +22,7 @@ class Tag extends Label { final bool isInboxTag; - Tag({ + const Tag({ super.id, required super.name, super.documentCount, diff --git a/packages/paperless_api/lib/src/models/paperless_server_exception.dart b/packages/paperless_api/lib/src/models/paperless_server_exception.dart index 3d180de..10ada4d 100644 --- a/packages/paperless_api/lib/src/models/paperless_server_exception.dart +++ b/packages/paperless_api/lib/src/models/paperless_server_exception.dart @@ -53,6 +53,5 @@ enum ErrorCode { requestTimedOut, unsupportedFileFormat, missingClientCertificate, - acknowledgeTasksError, - notAuthorized; + acknowledgeTasksError; } diff --git a/packages/paperless_api/lib/src/models/permissions/user_permissions.dart b/packages/paperless_api/lib/src/models/permissions/user_permissions.dart index 14d0a54..dda513e 100644 --- a/packages/paperless_api/lib/src/models/permissions/user_permissions.dart +++ b/packages/paperless_api/lib/src/models/permissions/user_permissions.dart @@ -1,117 +1,30 @@ -import 'package:freezed_annotation/freezed_annotation.dart'; -import 'package:hive/hive.dart'; -import 'package:paperless_api/config/hive/hive_type_ids.dart'; -part 'user_permissions.g.dart'; - -@HiveType(typeId: PaperlessApiHiveTypeIds.userPermissions) -@JsonEnum(valueField: "value") -enum UserPermissions { - @HiveField(0) - addCorrespondent("add_correspondent"), - @HiveField(1) - addDocument("add_document"), - @HiveField(2) - addDocumenttype("add_documenttype"), - @HiveField(3) - addGroup("add_group"), - @HiveField(4) - addMailaccount("add_mailaccount"), - @HiveField(5) - addMailrule("add_mailrule"), - @HiveField(6) - addNote("add_note"), - @HiveField(7) - addPaperlesstask("add_paperlesstask"), - @HiveField(8) - addSavedview("add_savedview"), - @HiveField(9) - addStoragepath("add_storagepath"), - @HiveField(10) - addTag("add_tag"), - @HiveField(11) - addUisettings("add_uisettings"), - @HiveField(12) - addUser("add_user"), - @HiveField(13) - changeCorrespondent("change_correspondent"), - @HiveField(14) - changeDocument("change_document"), - @HiveField(15) - changeDocumenttype("change_documenttype"), - @HiveField(16) - changeGroup("change_group"), - @HiveField(17) - changeMailaccount("change_mailaccount"), - @HiveField(18) - changeMailrule("change_mailrule"), - @HiveField(19) - changeNote("change_note"), - @HiveField(20) - changePaperlesstask("change_paperlesstask"), - @HiveField(21) - changeSavedview("change_savedview"), - @HiveField(22) - changeStoragepath("change_storagepath"), - @HiveField(23) - changeTag("change_tag"), - @HiveField(24) - changeUisettings("change_uisettings"), - @HiveField(25) - changeUser("change_user"), - @HiveField(26) - deleteCorrespondent("delete_correspondent"), - @HiveField(27) - deleteDocument("delete_document"), - @HiveField(28) - deleteDocumenttype("delete_documenttype"), - @HiveField(29) - deleteGroup("delete_group"), - @HiveField(30) - deleteMailaccount("delete_mailaccount"), - @HiveField(31) - deleteMailrule("delete_mailrule"), - @HiveField(32) - deleteNote("delete_note"), - @HiveField(33) - deletePaperlesstask("delete_paperlesstask"), - @HiveField(34) - deleteSavedview("delete_savedview"), - @HiveField(35) - deleteStoragepath("delete_storagepath"), - @HiveField(36) - deleteTag("delete_tag"), - @HiveField(37) - deleteUisettings("delete_uisettings"), - @HiveField(38) - deleteUser("delete_user"), - @HiveField(39) - viewCorrespondent("view_correspondent"), - @HiveField(40) - viewDocument("view_document"), - @HiveField(41) - viewDocumenttype("view_documenttype"), - @HiveField(42) - viewGroup("view_group"), - @HiveField(43) - viewMailaccount("view_mailaccount"), - @HiveField(44) - viewMailrule("view_mailrule"), - @HiveField(45) - viewNote("view_note"), - @HiveField(46) - viewPaperlesstask("view_paperlesstask"), - @HiveField(47) - viewSavedview("view_savedview"), - @HiveField(48) - viewStoragepath("view_storagepath"), - @HiveField(49) - viewTag("view_tag"), - @HiveField(50) - viewUisettings("view_uisettings"), - @HiveField(51) - viewUser("view_user"); - - const UserPermissions(this.value); +enum PermissionAction { + add("add"), + change("change"), + delete("delete"), + view("view"); final String value; + const PermissionAction(this.value); +} + +enum PermissionTarget { + correspondent("correspondent"), + document("document"), + documentType("documenttype"), + group("group"), + mailAccount("mailaccount"), + mailrule("mailrule"), + note("note"), + paperlesstask("paperlesstask"), + savedView("savedview"), + storagePath("storagepath"), + tag("tag"), + uiSettings("uisettings"), + user("user"), + logentry("logentry"), + permission("permission"); + + final String value; + const PermissionTarget(this.value); } diff --git a/packages/paperless_api/lib/src/models/query_parameters/date_range_queries/unset_date_range_query.dart b/packages/paperless_api/lib/src/models/query_parameters/date_range_queries/unset_date_range_query.dart index 94e494d..438c9d7 100644 --- a/packages/paperless_api/lib/src/models/query_parameters/date_range_queries/unset_date_range_query.dart +++ b/packages/paperless_api/lib/src/models/query_parameters/date_range_queries/unset_date_range_query.dart @@ -1,5 +1,4 @@ import 'package:hive/hive.dart'; -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 'date_range_query.dart'; diff --git a/packages/paperless_api/lib/src/models/query_parameters/tags_query/tags_query.dart b/packages/paperless_api/lib/src/models/query_parameters/tags_query/tags_query.dart index 6d66da0..f099539 100644 --- a/packages/paperless_api/lib/src/models/query_parameters/tags_query/tags_query.dart +++ b/packages/paperless_api/lib/src/models/query_parameters/tags_query/tags_query.dart @@ -1,4 +1,3 @@ -import 'package:equatable/equatable.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:hive/hive.dart'; import 'package:paperless_api/config/hive/hive_type_ids.dart'; diff --git a/packages/paperless_api/lib/src/models/user_model.dart b/packages/paperless_api/lib/src/models/user_model.dart index acfba27..509b6a1 100644 --- a/packages/paperless_api/lib/src/models/user_model.dart +++ b/packages/paperless_api/lib/src/models/user_model.dart @@ -16,17 +16,33 @@ class UserModel with _$UserModel { @JsonSerializable(fieldRename: FieldRename.snake) @HiveType(typeId: PaperlessApiHiveTypeIds.userModelv3) const factory UserModel.v3({ - @HiveField(0) required int id, - @HiveField(1) required String username, - @HiveField(2) required String email, - @HiveField(3) String? firstName, - @HiveField(4) String? lastName, - @HiveField(5) DateTime? dateJoined, - @HiveField(6) @Default(true) bool isStaff, - @HiveField(7) @Default(true) bool isActive, - @HiveField(8) @Default(true) bool isSuperuser, - @HiveField(9) @Default([]) List groups, - @HiveField(10) @Default(UserPermissions.values) List userPermissions, + @HiveField(0) + required int id, + @HiveField(1) + required String username, + @HiveField(2) + required String email, + @HiveField(3) + String? firstName, + @HiveField(4) + String? lastName, + @HiveField(5) + DateTime? dateJoined, + @HiveField(6) + @Default(true) + bool isStaff, + @HiveField(7) + @Default(true) + bool isActive, + @HiveField(8) + @Default(true) + bool isSuperuser, + @HiveField(9) + @Default([]) + List groups, + @HiveField(10) + @Default([]) + List userPermissions, @HiveField(11) @Default(InheritedPermissions.values) List inheritedPermissions, @@ -55,13 +71,14 @@ class UserModel with _$UserModel { }, ); - bool hasPermission(UserPermissions permission) { + bool hasPermission(PermissionAction action, PermissionTarget target) { return map( v3: (value) { if (value.isSuperuser) { return true; } - return value.userPermissions.contains(permission); + final permissionIdentifier = "${action.value}_${target.value}"; + return value.userPermissions.contains(permissionIdentifier); }, v2: (value) { // In previous versions, all users have all permissions. diff --git a/packages/paperless_api/lib/src/models/user_model.freezed.dart b/packages/paperless_api/lib/src/models/user_model.freezed.dart index c675095..8d17d63 100644 --- a/packages/paperless_api/lib/src/models/user_model.freezed.dart +++ b/packages/paperless_api/lib/src/models/user_model.freezed.dart @@ -46,7 +46,7 @@ mixin _$UserModel { @HiveField(7) bool isActive, @HiveField(8) bool isSuperuser, @HiveField(9) List groups, - @HiveField(10) List userPermissions, + @HiveField(10) List userPermissions, @HiveField(11) List inheritedPermissions) v3, required TResult Function(@HiveField(0) @JsonKey(name: "user_id") int id, @@ -67,7 +67,7 @@ mixin _$UserModel { @HiveField(7) bool isActive, @HiveField(8) bool isSuperuser, @HiveField(9) List groups, - @HiveField(10) List userPermissions, + @HiveField(10) List userPermissions, @HiveField(11) List inheritedPermissions)? v3, TResult? Function(@HiveField(0) @JsonKey(name: "user_id") int id, @@ -88,7 +88,7 @@ mixin _$UserModel { @HiveField(7) bool isActive, @HiveField(8) bool isSuperuser, @HiveField(9) List groups, - @HiveField(10) List userPermissions, + @HiveField(10) List userPermissions, @HiveField(11) List inheritedPermissions)? v3, TResult Function(@HiveField(0) @JsonKey(name: "user_id") int id, @@ -178,7 +178,7 @@ abstract class _$$UserModelV3CopyWith<$Res> @HiveField(7) bool isActive, @HiveField(8) bool isSuperuser, @HiveField(9) List groups, - @HiveField(10) List userPermissions, + @HiveField(10) List userPermissions, @HiveField(11) List inheritedPermissions}); } @@ -250,7 +250,7 @@ class __$$UserModelV3CopyWithImpl<$Res> userPermissions: null == userPermissions ? _value._userPermissions : userPermissions // ignore: cast_nullable_to_non_nullable - as List, + as List, inheritedPermissions: null == inheritedPermissions ? _value._inheritedPermissions : inheritedPermissions // ignore: cast_nullable_to_non_nullable @@ -275,8 +275,7 @@ class _$UserModelV3 extends UserModelV3 { @HiveField(7) this.isActive = true, @HiveField(8) this.isSuperuser = true, @HiveField(9) final List groups = const [], - @HiveField(10) final List userPermissions = - UserPermissions.values, + @HiveField(10) final List userPermissions = const [], @HiveField(11) final List inheritedPermissions = InheritedPermissions.values, final String? $type}) @@ -329,11 +328,11 @@ class _$UserModelV3 extends UserModelV3 { return EqualUnmodifiableListView(_groups); } - final List _userPermissions; + final List _userPermissions; @override @JsonKey() @HiveField(10) - List get userPermissions { + List get userPermissions { if (_userPermissions is EqualUnmodifiableListView) return _userPermissions; // ignore: implicit_dynamic_type return EqualUnmodifiableListView(_userPermissions); @@ -422,7 +421,7 @@ class _$UserModelV3 extends UserModelV3 { @HiveField(7) bool isActive, @HiveField(8) bool isSuperuser, @HiveField(9) List groups, - @HiveField(10) List userPermissions, + @HiveField(10) List userPermissions, @HiveField(11) List inheritedPermissions) v3, required TResult Function(@HiveField(0) @JsonKey(name: "user_id") int id, @@ -447,7 +446,7 @@ class _$UserModelV3 extends UserModelV3 { @HiveField(7) bool isActive, @HiveField(8) bool isSuperuser, @HiveField(9) List groups, - @HiveField(10) List userPermissions, + @HiveField(10) List userPermissions, @HiveField(11) List inheritedPermissions)? v3, TResult? Function(@HiveField(0) @JsonKey(name: "user_id") int id, @@ -483,7 +482,7 @@ class _$UserModelV3 extends UserModelV3 { @HiveField(7) bool isActive, @HiveField(8) bool isSuperuser, @HiveField(9) List groups, - @HiveField(10) List userPermissions, + @HiveField(10) List userPermissions, @HiveField(11) List inheritedPermissions)? v3, TResult Function(@HiveField(0) @JsonKey(name: "user_id") int id, @@ -560,7 +559,7 @@ abstract class UserModelV3 extends UserModel { @HiveField(9) final List groups, @HiveField(10) - final List userPermissions, + final List userPermissions, @HiveField(11) final List inheritedPermissions}) = _$UserModelV3; @@ -592,7 +591,7 @@ abstract class UserModelV3 extends UserModel { @HiveField(9) List get groups; @HiveField(10) - List get userPermissions; + List get userPermissions; @HiveField(11) List get inheritedPermissions; @override @@ -718,7 +717,7 @@ class _$UserModelV2 extends UserModelV2 { @HiveField(7) bool isActive, @HiveField(8) bool isSuperuser, @HiveField(9) List groups, - @HiveField(10) List userPermissions, + @HiveField(10) List userPermissions, @HiveField(11) List inheritedPermissions) v3, required TResult Function(@HiveField(0) @JsonKey(name: "user_id") int id, @@ -742,7 +741,7 @@ class _$UserModelV2 extends UserModelV2 { @HiveField(7) bool isActive, @HiveField(8) bool isSuperuser, @HiveField(9) List groups, - @HiveField(10) List userPermissions, + @HiveField(10) List userPermissions, @HiveField(11) List inheritedPermissions)? v3, TResult? Function(@HiveField(0) @JsonKey(name: "user_id") int id, @@ -766,7 +765,7 @@ class _$UserModelV2 extends UserModelV2 { @HiveField(7) bool isActive, @HiveField(8) bool isSuperuser, @HiveField(9) List groups, - @HiveField(10) List userPermissions, + @HiveField(10) List userPermissions, @HiveField(11) List inheritedPermissions)? v3, TResult Function(@HiveField(0) @JsonKey(name: "user_id") int id, diff --git a/packages/paperless_api/lib/src/modules/documents_api/paperless_documents_api_impl.dart b/packages/paperless_api/lib/src/modules/documents_api/paperless_documents_api_impl.dart index 0f6d251..d444909 100644 --- a/packages/paperless_api/lib/src/modules/documents_api/paperless_documents_api_impl.dart +++ b/packages/paperless_api/lib/src/modules/documents_api/paperless_documents_api_impl.dart @@ -154,10 +154,10 @@ class PaperlessDocumentsApiImpl implements PaperlessDocumentsApi { @override Future findNextAsn() async { - final DocumentFilter asnQueryFilter = DocumentFilter( + const DocumentFilter asnQueryFilter = DocumentFilter( sortField: SortField.archiveSerialNumber, sortOrder: SortOrder.descending, - asnQuery: const IdQueryParameter.anyAssigned(), + asnQuery: IdQueryParameter.anyAssigned(), page: 1, pageSize: 1, ); diff --git a/packages/paperless_api/lib/src/modules/tasks_api/paperless_tasks_api_impl.dart b/packages/paperless_api/lib/src/modules/tasks_api/paperless_tasks_api_impl.dart index e38ba81..c40be65 100644 --- a/packages/paperless_api/lib/src/modules/tasks_api/paperless_tasks_api_impl.dart +++ b/packages/paperless_api/lib/src/modules/tasks_api/paperless_tasks_api_impl.dart @@ -2,7 +2,6 @@ import 'dart:developer'; import 'package:dio/dio.dart'; import 'package:paperless_api/paperless_api.dart'; -import 'package:paperless_api/src/request_utils.dart'; class PaperlessTasksApiImpl implements PaperlessTasksApi { final Dio _client; diff --git a/packages/paperless_api/test/saved_view_test.dart b/packages/paperless_api/test/saved_view_test.dart index e87d979..adabfe3 100644 --- a/packages/paperless_api/test/saved_view_test.dart +++ b/packages/paperless_api/test/saved_view_test.dart @@ -1,6 +1,5 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:paperless_api/paperless_api.dart'; -import 'package:paperless_api/src/models/query_parameters/text_query.dart'; void main() { group('Validate parsing logic from [SavedView] to [DocumentFilter]:', () { @@ -202,16 +201,16 @@ void main() { test('Values are correctly parsed if unset.', () { expect( SavedView.fromDocumentFilter( - DocumentFilter( - correspondent: const IdQueryParameter.unset(), - documentType: const IdQueryParameter.unset(), - storagePath: const IdQueryParameter.unset(), - tags: const IdsTagsQuery(), + const DocumentFilter( + correspondent: IdQueryParameter.unset(), + documentType: IdQueryParameter.unset(), + storagePath: IdQueryParameter.unset(), + tags: IdsTagsQuery(), sortField: SortField.created, sortOrder: SortOrder.descending, - added: const UnsetDateRangeQuery(), - created: const UnsetDateRangeQuery(), - query: const TextQuery(), + added: UnsetDateRangeQuery(), + created: UnsetDateRangeQuery(), + query: TextQuery(), ), name: "test_name", showInSidebar: false, diff --git a/packages/paperless_document_scanner/example/lib/edge_detection_shape/animated_touch_bubble_part.dart b/packages/paperless_document_scanner/example/lib/edge_detection_shape/animated_touch_bubble_part.dart index 138a78a..d80aabc 100644 --- a/packages/paperless_document_scanner/example/lib/edge_detection_shape/animated_touch_bubble_part.dart +++ b/packages/paperless_document_scanner/example/lib/edge_detection_shape/animated_touch_bubble_part.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; class AnimatedTouchBubblePart extends StatefulWidget { - AnimatedTouchBubblePart({ + const AnimatedTouchBubblePart({super.key, required this.dragging, required this.size, }); @@ -35,7 +35,7 @@ class _AnimatedTouchBubblePartState extends State ).animate( CurvedAnimation( parent: _controller, - curve: Interval(0.5, 1.0), + curve: const Interval(0.5, 1.0), ), ); diff --git a/packages/paperless_document_scanner/example/lib/edge_detection_shape/edge_detection_shape.dart b/packages/paperless_document_scanner/example/lib/edge_detection_shape/edge_detection_shape.dart index 2c63ede..f171026 100644 --- a/packages/paperless_document_scanner/example/lib/edge_detection_shape/edge_detection_shape.dart +++ b/packages/paperless_document_scanner/example/lib/edge_detection_shape/edge_detection_shape.dart @@ -1,8 +1,6 @@ import 'dart:math'; -import 'dart:ui'; import 'package:flutter/material.dart'; -import 'package:paperless_document_scanner/paperless_document_scanner.dart'; import 'package:paperless_document_scanner/types/edge_detection_result.dart'; import 'edge_painter.dart'; diff --git a/packages/paperless_document_scanner/example/lib/edge_detection_shape/magnifier.dart b/packages/paperless_document_scanner/example/lib/edge_detection_shape/magnifier.dart index a7cc2a2..3550786 100644 --- a/packages/paperless_document_scanner/example/lib/edge_detection_shape/magnifier.dart +++ b/packages/paperless_document_scanner/example/lib/edge_detection_shape/magnifier.dart @@ -47,18 +47,11 @@ class _MagnifierState extends State { @override Widget build(BuildContext context) { return Stack( - children: [ - widget.child, - if (widget.visible && widget.position != null) _getMagnifier(context) - ], + children: [widget.child, if (widget.visible) _getMagnifier(context)], ); } void _calculateMatrix() { - if (widget.position == null) { - return; - } - setState(() { double newX = widget.position.dx - (_magnifierSize.width / 2 / _scale); double newY = widget.position.dy - (_magnifierSize.height / 2 / _scale); @@ -78,8 +71,7 @@ class _MagnifierState extends State { child: BackdropFilter( filter: ImageFilter.matrix(_matrix.storage), child: CustomPaint( - painter: MagnifierPainter( - color: Theme.of(context).colorScheme.secondary), + painter: MagnifierPainter(color: Theme.of(context).colorScheme.secondary), size: _magnifierSize, ), ), @@ -96,6 +88,5 @@ class _MagnifierState extends State { } bool _bubbleCrossesMagnifier() => - widget.position.dx < widget.size.width && - widget.position.dy < widget.size.height; + widget.position.dx < widget.size.width && widget.position.dy < widget.size.height; } diff --git a/packages/paperless_document_scanner/example/lib/edge_detection_shape/magnifier_painter.dart b/packages/paperless_document_scanner/example/lib/edge_detection_shape/magnifier_painter.dart index a0a8075..1c17492 100644 --- a/packages/paperless_document_scanner/example/lib/edge_detection_shape/magnifier_painter.dart +++ b/packages/paperless_document_scanner/example/lib/edge_detection_shape/magnifier_painter.dart @@ -19,7 +19,7 @@ class MagnifierPainter extends CustomPainter { ..color = color; canvas.drawCircle( - size.center(Offset(0, 0)), size.longestSide / 2, paintObject); + size.center(const Offset(0, 0)), size.longestSide / 2, paintObject); } void _drawCrosshair(Canvas canvas, Size size) { diff --git a/packages/paperless_document_scanner/example/lib/main.dart b/packages/paperless_document_scanner/example/lib/main.dart index 19f8648..1f514bc 100644 --- a/packages/paperless_document_scanner/example/lib/main.dart +++ b/packages/paperless_document_scanner/example/lib/main.dart @@ -1,10 +1,8 @@ -import 'dart:typed_data'; import 'package:camera/camera.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:image/image.dart' as imglib; -import 'scan.dart'; late final List cameras; void main() async { @@ -58,8 +56,8 @@ class _EdgeDetectionAppState extends State { final int uvRowStride = image.planes[1].bytesPerRow; final int uvPixelStride = image.planes[1].bytesPerPixel!; - print("uvRowStride: " + uvRowStride.toString()); - print("uvPixelStride: " + uvPixelStride.toString()); + print("uvRowStride: $uvRowStride"); + print("uvPixelStride: $uvPixelStride"); // imgLib -> Image package from https://pub.dartlang.org/packages/image var img = imglib.Image( @@ -89,7 +87,7 @@ class _EdgeDetectionAppState extends State { } } - imglib.PngEncoder pngEncoder = new imglib.PngEncoder(level: 0); + imglib.PngEncoder pngEncoder = imglib.PngEncoder(level: 0); final png = pngEncoder.encode(img); return Image.memory(png); } @@ -105,7 +103,7 @@ class _EdgeDetectionAppState extends State { body: Center( child: _image != null ? convertYUV420toImageColor(_image!) - : Placeholder(), + : const Placeholder(), ), ), ); diff --git a/packages/paperless_document_scanner/example/lib/scan.dart b/packages/paperless_document_scanner/example/lib/scan.dart index 0b2a419..cfacfb8 100644 --- a/packages/paperless_document_scanner/example/lib/scan.dart +++ b/packages/paperless_document_scanner/example/lib/scan.dart @@ -80,7 +80,7 @@ class _ScanState extends State { return Align( alignment: Alignment.bottomCenter, child: FloatingActionButton( - child: Icon(Icons.check), + child: const Icon(Icons.check), onPressed: () async { if (croppedImagePath == null) { return _processImage(imagePath!, edgeDetectionResult!); @@ -101,8 +101,8 @@ class _ScanState extends State { children: [ FloatingActionButton( foregroundColor: Colors.white, - child: Icon(Icons.camera_alt), onPressed: onTakePictureButtonPressed, + child: const Icon(Icons.camera_alt), ), ], ); @@ -167,7 +167,7 @@ class _ScanState extends State { Padding _getBottomBar() { return Padding( - padding: EdgeInsets.only(bottom: 32), + padding: const EdgeInsets.only(bottom: 32), child: Align(alignment: Alignment.bottomCenter, child: _getButtonRow()), ); } diff --git a/packages/paperless_document_scanner/example/pubspec.lock b/packages/paperless_document_scanner/example/pubspec.lock index 3f47cac..37fac4d 100644 --- a/packages/paperless_document_scanner/example/pubspec.lock +++ b/packages/paperless_document_scanner/example/pubspec.lock @@ -5,18 +5,18 @@ packages: dependency: transitive description: name: archive - sha256: d6347d54a2d8028e0437e3c099f66fdb8ae02c4720c1e7534c9f24c10351f85d + sha256: "0c8368c9b3f0abbc193b9d6133649a614204b528982bebc7026372d61677ce3a" url: "https://pub.dev" source: hosted - version: "3.3.6" + version: "3.3.7" async: dependency: transitive description: name: async - sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" url: "https://pub.dev" source: hosted - version: "2.10.0" + version: "2.11.0" boolean_selector: dependency: transitive description: @@ -29,50 +29,50 @@ packages: dependency: "direct main" description: name: camera - sha256: e7ac55af24a890d20276821eb3c95857074d03b7de6f9892b99a205ee30bd179 + sha256: "309b823e61f15ff6b5b2e4c0ff2e1512ea661cad5355f71fc581e510ae5b26bb" url: "https://pub.dev" source: hosted - version: "0.10.3" + version: "0.10.5" camera_android: dependency: transitive description: name: camera_android - sha256: e491c836147f60dd8a54cf3895fd2960e13b21b78a9d15b563a1b6c70894f142 + sha256: e0f9b7eea2d1f4d4f5460f178522f0d02c095d2ae00b01a77419ce61c4184bfe url: "https://pub.dev" source: hosted - version: "0.10.4" + version: "0.10.7" camera_avfoundation: dependency: transitive description: name: camera_avfoundation - sha256: "6a68c20593d4cd58974d555f74a48b244f9db28cc9156de57781122d11b8754b" + sha256: "7ac8b950672716722af235eed7a7c37896853669800b7da706bb0a9fd41d3737" url: "https://pub.dev" source: hosted - version: "0.9.11" + version: "0.9.13+1" camera_platform_interface: dependency: transitive description: name: camera_platform_interface - sha256: b632be28e61d00a233f67d98ea90fd7041956f27a1c65500188ee459be60e15f + sha256: "525017018d116c5db8c4c43ec2d9b1663216b369c9f75149158280168a7ce472" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.5.0" camera_web: dependency: transitive description: name: camera_web - sha256: "496de93c5d462738ce991dbfe91fb19026f115ed36406700a20a380fb0018299" + sha256: d77965f32479ee6d8f48205dcf10f845d7210595c6c00faa51eab265d1cae993 url: "https://pub.dev" source: hosted - version: "0.3.1+1" + version: "0.3.1+3" characters: dependency: transitive description: name: characters - sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.3.0" clock: dependency: transitive description: @@ -85,10 +85,10 @@ packages: dependency: transitive description: name: collection - sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" url: "https://pub.dev" source: hosted - version: "1.17.0" + version: "1.17.1" convert: dependency: transitive description: @@ -109,10 +109,10 @@ packages: dependency: transitive description: name: crypto - sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.3" cupertino_icons: dependency: "direct main" description: @@ -133,10 +133,10 @@ packages: dependency: transitive description: name: ffi - sha256: a38574032c5f1dd06c4aee541789906c12ccaab8ba01446e800d9c5b79c4a978 + sha256: ed5337a5660c506388a9f012be0288fb38b49020ce2b45fe1f8b8323fe429f99 url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.0.2" file: dependency: transitive description: @@ -162,10 +162,10 @@ packages: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: "60fc7b78455b94e6de2333d2f95196d32cf5c22f4b0b0520a628804cb463503b" + sha256: "96af49aa6b57c10a312106ad6f71deed5a754029c24789bbf620ba784f0bd0b0" url: "https://pub.dev" source: hosted - version: "2.0.7" + version: "2.0.14" flutter_test: dependency: "direct dev" description: flutter @@ -180,34 +180,34 @@ packages: dependency: "direct main" description: name: image - sha256: "483a389d6ccb292b570c31b3a193779b1b0178e7eb571986d9a49904b6861227" + sha256: a72242c9a0ffb65d03de1b7113bc4e189686fc07c7147b8b41811d0dd0e0d9bf url: "https://pub.dev" source: hosted - version: "4.0.15" + version: "4.0.17" js: dependency: transitive description: name: js - sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 url: "https://pub.dev" source: hosted - version: "0.6.5" + version: "0.6.7" lints: dependency: transitive description: name: lints - sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593" + sha256: "6b0206b0bf4f04961fc5438198ccb3a885685cd67d4d4a32cc20ad7f8adbe015" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.1.0" matcher: dependency: transitive description: name: matcher - sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" + sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" url: "https://pub.dev" source: hosted - version: "0.12.13" + version: "0.12.15" material_color_utilities: dependency: transitive description: @@ -220,10 +220,10 @@ packages: dependency: transitive description: name: meta - sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.9.1" paperless_document_scanner: dependency: "direct main" description: @@ -235,66 +235,66 @@ packages: dependency: transitive description: name: path - sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" url: "https://pub.dev" source: hosted - version: "1.8.2" + version: "1.8.3" path_provider: dependency: "direct main" description: name: path_provider - sha256: dcea5feb97d8abf90cab9e9030b497fb7c3cbf26b7a1fe9e3ef7dcb0a1ddec95 + sha256: "3087813781ab814e4157b172f1a11c46be20179fcc9bea043e0fba36bc0acaa2" url: "https://pub.dev" source: hosted - version: "2.0.12" + version: "2.0.15" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: a776c088d671b27f6e3aa8881d64b87b3e80201c64e8869b811325de7a76c15e + sha256: "2cec049d282c7f13c594b4a73976b0b4f2d7a1838a6dd5aaf7bd9719196bee86" url: "https://pub.dev" source: hosted - version: "2.0.22" + version: "2.0.27" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "62a68e7e1c6c459f9289859e2fae58290c981ce21d1697faf54910fe1faa4c74" + sha256: "1995d88ec2948dac43edf8fe58eb434d35d22a2940ecee1a9fefcd62beee6eb3" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.2.3" path_provider_linux: dependency: transitive description: name: path_provider_linux - sha256: "2e32f1640f07caef0d3cb993680f181c79e54a3827b997d5ee221490d131fbd9" + sha256: "2ae08f2216225427e64ad224a24354221c2c7907e448e6e0e8b57b1eb9f10ad1" url: "https://pub.dev" source: hosted - version: "2.1.8" + version: "2.1.10" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface - sha256: f0abc8ebd7253741f05488b4813d936b4d07c6bae3e86148a09e342ee4b08e76 + sha256: "57585299a729335f1298b43245842678cb9f43a6310351b18fb577d6e33165ec" url: "https://pub.dev" source: hosted - version: "2.0.5" + version: "2.0.6" path_provider_windows: dependency: transitive description: name: path_provider_windows - sha256: bcabbe399d4042b8ee687e17548d5d3f527255253b4a639f5f8d2094a9c2b45c + sha256: d3f80b32e83ec208ac95253e0cd4d298e104fbc63cb29c5c69edaed43b0c69d6 url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.1.6" petitparser: dependency: transitive description: name: petitparser - sha256: "49392a45ced973e8d94a85fdb21293fbb40ba805fc49f2965101ae748a3683b4" + sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750 url: "https://pub.dev" source: hosted - version: "5.1.0" + version: "5.4.0" platform: dependency: transitive description: @@ -307,18 +307,18 @@ packages: dependency: transitive description: name: plugin_platform_interface - sha256: dbf0f707c78beedc9200146ad3cb0ab4d5da13c246336987be6940f026500d3a + sha256: "6a2128648c854906c53fa8e33986fc0247a1116122f9534dd20e3ab9e16a32bc" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.1.4" pointycastle: dependency: transitive description: name: pointycastle - sha256: db7306cf0249f838d1a24af52b5a5887c5bf7f31d8bb4e827d071dc0939ad346 + sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" url: "https://pub.dev" source: hosted - version: "3.6.2" + version: "3.7.3" process: dependency: transitive description: @@ -392,18 +392,18 @@ packages: dependency: transitive description: name: test_api - sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 + sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb url: "https://pub.dev" source: hosted - version: "0.4.16" + version: "0.5.1" typed_data: dependency: transitive description: name: typed_data - sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.3.2" vector_math: dependency: transitive description: @@ -416,10 +416,10 @@ packages: dependency: transitive description: name: win32 - sha256: c9ebe7ee4ab0c2194e65d3a07d8c54c5d00bb001b76081c4a04cdb8448b59e46 + sha256: "5a751eddf9db89b3e5f9d50c20ab8612296e4e8db69009788d6c8b060a84191c" url: "https://pub.dev" source: hosted - version: "3.1.3" + version: "4.1.4" xdg_directories: dependency: transitive description: @@ -432,10 +432,10 @@ packages: dependency: transitive description: name: xml - sha256: "979ee37d622dec6365e2efa4d906c37470995871fe9ae080d967e192d88286b5" + sha256: "5bc72e1e45e941d825fd7468b9b4cc3b9327942649aeb6fc5cdbf135f0a86e84" url: "https://pub.dev" source: hosted - version: "6.2.2" + version: "6.3.0" sdks: - dart: ">=2.19.2 <3.0.0" - flutter: ">=3.0.0" + dart: ">=3.0.0-417 <4.0.0" + flutter: ">=3.3.0"