diff --git a/lib/core/bloc/paperless_server_information_cubit.dart b/lib/core/bloc/paperless_server_information_cubit.dart deleted file mode 100644 index 3067d8f..0000000 --- a/lib/core/bloc/paperless_server_information_cubit.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:paperless_api/paperless_api.dart'; -import 'package:paperless_mobile/core/bloc/paperless_server_information_state.dart'; - -class PaperlessServerInformationCubit - extends Cubit { - final PaperlessServerStatsApi _api; - - PaperlessServerInformationCubit(this._api) - : super(PaperlessServerInformationState()); - - Future updateInformtion() async { - final information = await _api.getServerInformation(); - emit(PaperlessServerInformationState( - isLoaded: true, - information: information, - )); - } -} diff --git a/lib/core/bloc/server_information_cubit.dart b/lib/core/bloc/server_information_cubit.dart new file mode 100644 index 0000000..942c2d3 --- /dev/null +++ b/lib/core/bloc/server_information_cubit.dart @@ -0,0 +1,17 @@ +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:paperless_api/paperless_api.dart'; +import 'package:paperless_mobile/core/bloc/server_information_state.dart'; + +class ServerInformationCubit extends Cubit { + final PaperlessServerStatsApi _api; + + ServerInformationCubit(this._api) : super(ServerInformationState()); + + Future updateInformation() async { + final information = await _api.getServerInformation(); + emit(ServerInformationState( + isLoaded: true, + information: information, + )); + } +} diff --git a/lib/core/bloc/paperless_server_information_state.dart b/lib/core/bloc/server_information_state.dart similarity index 71% rename from lib/core/bloc/paperless_server_information_state.dart rename to lib/core/bloc/server_information_state.dart index aa63eab..401ed3f 100644 --- a/lib/core/bloc/paperless_server_information_state.dart +++ b/lib/core/bloc/server_information_state.dart @@ -1,10 +1,10 @@ import 'package:paperless_api/paperless_api.dart'; -class PaperlessServerInformationState { +class ServerInformationState { final bool isLoaded; final PaperlessServerInformationModel? information; - PaperlessServerInformationState({ + ServerInformationState({ this.isLoaded = false, this.information, }); diff --git a/lib/core/config/hive/hive_config.dart b/lib/core/config/hive/hive_config.dart index 7b5df09..1c071d5 100644 --- a/lib/core/config/hive/hive_config.dart +++ b/lib/core/config/hive/hive_config.dart @@ -2,35 +2,37 @@ import 'package:hive_flutter/adapters.dart'; import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/core/config/hive/custom_adapters/theme_mode_adapter.dart'; import 'package:paperless_mobile/core/database/tables/global_settings.dart'; -import 'package:paperless_mobile/core/database/tables/user_app_state.dart'; +import 'package:paperless_mobile/core/database/tables/local_user_app_state.dart'; import 'package:paperless_mobile/core/database/tables/user_credentials.dart'; import 'package:paperless_mobile/features/login/model/authentication_information.dart'; import 'package:paperless_mobile/features/login/model/client_certificate.dart'; -import 'package:paperless_mobile/core/database/tables/user_account.dart'; +import 'package:paperless_mobile/core/database/tables/local_user_account.dart'; import 'package:paperless_mobile/features/settings/model/color_scheme_option.dart'; -import 'package:paperless_mobile/core/database/tables/user_settings.dart'; +import 'package:paperless_mobile/core/database/tables/local_user_settings.dart'; +import 'package:paperless_mobile/features/settings/model/view_type.dart'; class HiveBoxes { HiveBoxes._(); static const globalSettings = 'globalSettings'; static const authentication = 'authentication'; - static const userCredentials = 'userCredentials'; - static const userAccount = 'userAccount'; - static const userAppState = 'userAppState'; - static const userSettings = 'userSettings'; + static const localUserCredentials = 'localUserCredentials'; + static const localUserAccount = 'localUserAccount'; + static const localUserAppState = 'localUserAppState'; + static const localUserSettings = 'localUserSettings'; } class HiveTypeIds { HiveTypeIds._(); static const globalSettings = 0; - static const userSettings = 1; + static const localUserSettings = 1; static const themeMode = 2; static const colorSchemeOption = 3; static const authentication = 4; static const clientCertificate = 5; - static const userCredentials = 6; - static const userAccount = 7; - static const userAppState = 8; + static const localUserCredentials = 6; + static const localUserAccount = 7; + static const localUserAppState = 8; + static const viewType = 9; } void registerHiveAdapters() { @@ -40,10 +42,11 @@ void registerHiveAdapters() { Hive.registerAdapter(GlobalSettingsAdapter()); Hive.registerAdapter(AuthenticationInformationAdapter()); Hive.registerAdapter(ClientCertificateAdapter()); - Hive.registerAdapter(UserSettingsAdapter()); + Hive.registerAdapter(LocalUserSettingsAdapter()); Hive.registerAdapter(UserCredentialsAdapter()); - Hive.registerAdapter(UserAccountAdapter()); - Hive.registerAdapter(UserAppStateAdapter()); + Hive.registerAdapter(LocalUserAccountAdapter()); + Hive.registerAdapter(LocalUserAppStateAdapter()); + Hive.registerAdapter(ViewTypeAdapter()); } extension HiveSingleValueBox on Box { diff --git a/lib/core/database/tables/user_account.dart b/lib/core/database/tables/local_user_account.dart similarity index 62% rename from lib/core/database/tables/user_account.dart rename to lib/core/database/tables/local_user_account.dart index 8d53261..a8bed4e 100644 --- a/lib/core/database/tables/user_account.dart +++ b/lib/core/database/tables/local_user_account.dart @@ -1,11 +1,11 @@ import 'package:hive_flutter/adapters.dart'; import 'package:paperless_mobile/core/config/hive/hive_config.dart'; -import 'package:paperless_mobile/core/database/tables/user_settings.dart'; +import 'package:paperless_mobile/core/database/tables/local_user_settings.dart'; -part 'user_account.g.dart'; +part 'local_user_account.g.dart'; -@HiveType(typeId: HiveTypeIds.userAccount) -class UserAccount extends HiveObject { +@HiveType(typeId: HiveTypeIds.localUserAccount) +class LocalUserAccount extends HiveObject { @HiveField(0) final String serverUrl; @@ -19,9 +19,9 @@ class UserAccount extends HiveObject { final String id; @HiveField(4) - UserSettings settings; + LocalUserSettings settings; - UserAccount({ + LocalUserAccount({ required this.id, required this.serverUrl, required this.username, diff --git a/lib/core/database/tables/local_user_app_state.dart b/lib/core/database/tables/local_user_app_state.dart new file mode 100644 index 0000000..8dd9603 --- /dev/null +++ b/lib/core/database/tables/local_user_app_state.dart @@ -0,0 +1,40 @@ +import 'package:hive_flutter/adapters.dart'; +import 'package:paperless_api/paperless_api.dart'; +import 'package:paperless_mobile/core/config/hive/hive_config.dart'; +import 'package:paperless_mobile/features/settings/model/view_type.dart'; + +part 'local_user_app_state.g.dart'; + +/// +/// Object used for the persistence of app state, e.g. set filters, +/// search history and implicit settings. +/// +@HiveType(typeId: HiveTypeIds.localUserAppState) +class LocalUserAppState extends HiveObject { + @HiveField(0) + final String userId; + + @HiveField(1) + DocumentFilter currentDocumentFilter; + + @HiveField(2) + List documentSearchHistory; + + @HiveField(3) + ViewType documentsPageViewType; + + @HiveField(4) + ViewType savedViewsViewType; + + @HiveField(5) + ViewType documentSearchViewType; + + LocalUserAppState({ + required this.userId, + this.currentDocumentFilter = const DocumentFilter(), + this.documentSearchHistory = const [], + this.documentsPageViewType = ViewType.list, + this.documentSearchViewType = ViewType.list, + this.savedViewsViewType = ViewType.list, + }); +} diff --git a/lib/core/database/tables/user_settings.dart b/lib/core/database/tables/local_user_settings.dart similarity index 54% rename from lib/core/database/tables/user_settings.dart rename to lib/core/database/tables/local_user_settings.dart index f501c46..4398e85 100644 --- a/lib/core/database/tables/user_settings.dart +++ b/lib/core/database/tables/local_user_settings.dart @@ -1,15 +1,14 @@ import 'package:hive/hive.dart'; -import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/core/config/hive/hive_config.dart'; -part 'user_settings.g.dart'; +part 'local_user_settings.g.dart'; -@HiveType(typeId: HiveTypeIds.userSettings) -class UserSettings with HiveObjectMixin { +@HiveType(typeId: HiveTypeIds.localUserSettings) +class LocalUserSettings with HiveObjectMixin { @HiveField(0) bool isBiometricAuthenticationEnabled; - UserSettings({ + LocalUserSettings({ this.isBiometricAuthenticationEnabled = false, }); } diff --git a/lib/core/database/tables/user_app_state.dart b/lib/core/database/tables/user_app_state.dart deleted file mode 100644 index 02e7399..0000000 --- a/lib/core/database/tables/user_app_state.dart +++ /dev/null @@ -1,22 +0,0 @@ -import 'package:hive_flutter/adapters.dart'; -import 'package:paperless_api/paperless_api.dart'; -import 'package:paperless_mobile/core/config/hive/hive_config.dart'; -part 'user_app_state.g.dart'; - -@HiveType(typeId: HiveTypeIds.userAppState) -class UserAppState extends HiveObject { - @HiveField(0) - final String userId; - - @HiveField(1) - DocumentFilter currentDocumentFilter; - - @HiveField(2) - List documentSearchHistory; - - UserAppState({ - required this.userId, - this.currentDocumentFilter = const DocumentFilter(), - this.documentSearchHistory = const [], - }); -} diff --git a/lib/core/database/tables/user_credentials.dart b/lib/core/database/tables/user_credentials.dart index f2228b8..bd8ac77 100644 --- a/lib/core/database/tables/user_credentials.dart +++ b/lib/core/database/tables/user_credentials.dart @@ -4,7 +4,7 @@ import 'package:paperless_mobile/features/login/model/client_certificate.dart'; part 'user_credentials.g.dart'; -@HiveType(typeId: HiveTypeIds.userCredentials) +@HiveType(typeId: HiveTypeIds.localUserCredentials) class UserCredentials extends HiveObject { @HiveField(0) final String token; diff --git a/lib/core/security/session_manager.dart b/lib/core/security/session_manager.dart index 37c0c58..efca93b 100644 --- a/lib/core/security/session_manager.dart +++ b/lib/core/security/session_manager.dart @@ -1,4 +1,3 @@ -import 'dart:convert'; import 'dart:io'; import 'package:dio/dio.dart'; @@ -8,14 +7,18 @@ import 'package:paperless_mobile/core/interceptor/retry_on_connection_change_int import 'package:paperless_mobile/features/login/model/client_certificate.dart'; import 'package:pretty_dio_logger/pretty_dio_logger.dart'; +/// Manages the security context, authentication and base request URL for +/// an underlying [Dio] client which is injected into all services +/// requiring authenticated access to the Paperless HTTP API. class SessionManager { - final Dio client; - final List interceptors; - PaperlessServerInformationModel serverInformation; + final Dio _client; + PaperlessServerInformationModel _serverInformation; - SessionManager([this.interceptors = const []]) - : client = _initDio(interceptors), - serverInformation = PaperlessServerInformationModel(); + Dio get client => _client; + + SessionManager([List interceptors = const []]) + : _client = _initDio(interceptors), + _serverInformation = PaperlessServerInformationModel(); static Dio _initDio(List interceptors) { //en- and decoded by utf8 by default @@ -63,8 +66,7 @@ class SessionManager { ); final adapter = IOHttpClientAdapter() ..onHttpClientCreate = (client) => HttpClient(context: context) - ..badCertificateCallback = - (X509Certificate cert, String host, int port) => true; + ..badCertificateCallback = (X509Certificate cert, String host, int port) => true; client.httpClientAdapter = adapter; } @@ -80,7 +82,7 @@ class SessionManager { } if (serverInformation != null) { - this.serverInformation = serverInformation; + _serverInformation = serverInformation; } } @@ -88,6 +90,6 @@ class SessionManager { client.httpClientAdapter = IOHttpClientAdapter(); client.options.baseUrl = ''; client.options.headers.remove(HttpHeaders.authorizationHeader); - serverInformation = PaperlessServerInformationModel(); + _serverInformation = PaperlessServerInformationModel(); } } diff --git a/lib/features/app_drawer/view/app_drawer.dart b/lib/features/app_drawer/view/app_drawer.dart index 295db95..18c523f 100644 --- a/lib/features/app_drawer/view/app_drawer.dart +++ b/lib/features/app_drawer/view/app_drawer.dart @@ -2,7 +2,7 @@ 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/bloc/paperless_server_information_cubit.dart'; +import 'package:paperless_mobile/core/bloc/server_information_cubit.dart'; import 'package:paperless_mobile/core/widgets/paperless_logo.dart'; import 'package:paperless_mobile/extensions/flutter_extensions.dart'; import 'package:paperless_mobile/features/settings/view/settings_page.dart'; @@ -69,7 +69,7 @@ class AppDrawer extends StatelessWidget { onTap: () => Navigator.of(context).push( MaterialPageRoute( builder: (_) => BlocProvider.value( - value: context.read(), + value: context.read(), child: const SettingsPage(), ), ), 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 670c3be..e0bf799 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 @@ -55,7 +55,9 @@ class _BulkEditLabelBottomSheetState extends State( - initialValue: IdQueryParameter.fromId(widget.initialValue), + initialValue: widget.initialValue != null + ? IdQueryParameter.fromId(widget.initialValue!) + : const IdQueryParameter.unset(), name: "labelFormField", options: widget.availableOptionsSelector(state), labelText: widget.formFieldLabel, diff --git a/lib/features/document_edit/view/document_edit_page.dart b/lib/features/document_edit/view/document_edit_page.dart index 99362f8..1bd02d1 100644 --- a/lib/features/document_edit/view/document_edit_page.dart +++ b/lib/features/document_edit/view/document_edit_page.dart @@ -111,9 +111,9 @@ class _DocumentEditPageState extends State { addLabelText: S.of(context)!.addCorrespondent, labelText: S.of(context)!.correspondent, options: context.watch().state.correspondents, - initialValue: IdQueryParameter.fromId( - state.document.correspondent, - ), + initialValue: state.document.correspondent != null + ? IdQueryParameter.fromId(state.document.correspondent!) + : const IdQueryParameter.unset(), name: fkCorrespondent, prefixIcon: const Icon(Icons.person_outlined), ), @@ -145,7 +145,9 @@ class _DocumentEditPageState extends State { ), addLabelText: S.of(context)!.addDocumentType, labelText: S.of(context)!.documentType, - initialValue: IdQueryParameter.fromId(state.document.documentType), + initialValue: state.document.documentType != null + ? IdQueryParameter.fromId(state.document.documentType!) + : const IdQueryParameter.unset(), options: state.documentTypes, name: _DocumentEditPageState.fkDocumentType, prefixIcon: const Icon(Icons.description_outlined), @@ -176,7 +178,9 @@ class _DocumentEditPageState extends State { addLabelText: S.of(context)!.addStoragePath, labelText: S.of(context)!.storagePath, options: state.storagePaths, - initialValue: IdQueryParameter.fromId(state.document.storagePath), + initialValue: state.document.storagePath != null + ? IdQueryParameter.fromId(state.document.storagePath!) + : const IdQueryParameter.unset(), name: fkStoragePath, prefixIcon: const Icon(Icons.folder_outlined), ), diff --git a/lib/features/document_search/cubit/document_search_cubit.dart b/lib/features/document_search/cubit/document_search_cubit.dart index 4cd5717..9afa344 100644 --- a/lib/features/document_search/cubit/document_search_cubit.dart +++ b/lib/features/document_search/cubit/document_search_cubit.dart @@ -2,7 +2,7 @@ import 'package:collection/collection.dart'; import 'package:hydrated_bloc/hydrated_bloc.dart'; import 'package:json_annotation/json_annotation.dart'; import 'package:paperless_api/paperless_api.dart'; -import 'package:paperless_mobile/core/database/tables/user_app_state.dart'; +import 'package:paperless_mobile/core/database/tables/local_user_app_state.dart'; import 'package:paperless_mobile/core/notifier/document_changed_notifier.dart'; import 'package:paperless_mobile/core/repository/label_repository.dart'; import 'package:paperless_mobile/features/paged_document_view/cubit/document_paging_bloc_mixin.dart'; @@ -20,7 +20,7 @@ class DocumentSearchCubit extends Cubit with DocumentPaging @override final DocumentChangedNotifier notifier; - final UserAppState _userAppState; + final LocalUserAppState _userAppState; DocumentSearchCubit( this.api, this.notifier, @@ -56,7 +56,7 @@ class DocumentSearchCubit extends Cubit with DocumentPaging final searchFilter = DocumentFilter( query: TextQuery.extended(query), ); - + await updateFilter(filter: searchFilter); emit( state.copyWith( diff --git a/lib/features/document_search/view/document_search_page.dart b/lib/features/document_search/view/document_search_page.dart index 02570f4..3bebab7 100644 --- a/lib/features/document_search/view/document_search_page.dart +++ b/lib/features/document_search/view/document_search_page.dart @@ -6,7 +6,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:hive/hive.dart'; import 'package:paperless_mobile/core/config/hive/hive_config.dart'; import 'package:paperless_mobile/core/database/tables/global_settings.dart'; -import 'package:paperless_mobile/core/database/tables/user_app_state.dart'; +import 'package:paperless_mobile/core/database/tables/local_user_app_state.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'; @@ -27,7 +27,7 @@ Future showDocumentSearchPage(BuildContext context) { context.read(), context.read(), context.read(), - Hive.box(HiveBoxes.userAppState).get(currentUser)!, + Hive.box(HiveBoxes.localUserAppState).get(currentUser)!, ), child: const DocumentSearchPage(), ), diff --git a/lib/features/document_search/view/sliver_search_bar.dart b/lib/features/document_search/view/sliver_search_bar.dart index 1882999..4cb1bf8 100644 --- a/lib/features/document_search/view/sliver_search_bar.dart +++ b/lib/features/document_search/view/sliver_search_bar.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:hive_flutter/adapters.dart'; -import 'package:paperless_mobile/core/bloc/paperless_server_information_cubit.dart'; +import 'package:paperless_mobile/core/bloc/server_information_cubit.dart'; import 'package:paperless_mobile/core/config/hive/hive_config.dart'; -import 'package:paperless_mobile/core/database/tables/user_account.dart'; +import 'package:paperless_mobile/core/database/tables/local_user_account.dart'; import 'package:paperless_mobile/core/delegate/customizable_sliver_persistent_header_delegate.dart'; import 'package:paperless_mobile/core/widgets/material/search/m3_search_bar.dart' as s; import 'package:paperless_mobile/features/document_search/view/document_search_page.dart'; @@ -43,7 +43,8 @@ class SliverSearchBar extends StatelessWidget { icon: GlobalSettingsBuilder( builder: (context, settings) { return ValueListenableBuilder( - valueListenable: Hive.box(HiveBoxes.userAccount).listenable(), + valueListenable: + Hive.box(HiveBoxes.localUserAccount).listenable(), builder: (context, box, _) { final account = box.get(settings.currentLoggedInUser!)!; return UserAvatar(userId: settings.currentLoggedInUser!, account: account); @@ -55,7 +56,7 @@ class SliverSearchBar extends StatelessWidget { showDialog( context: context, builder: (_) => BlocProvider.value( - value: context.read(), + value: context.read(), child: const ManageAccountsPage(), ), ); diff --git a/lib/features/documents/cubit/documents_cubit.dart b/lib/features/documents/cubit/documents_cubit.dart index 5326f12..36297f5 100644 --- a/lib/features/documents/cubit/documents_cubit.dart +++ b/lib/features/documents/cubit/documents_cubit.dart @@ -4,10 +4,9 @@ import 'package:flutter/foundation.dart'; import 'package:hydrated_bloc/hydrated_bloc.dart'; import 'package:json_annotation/json_annotation.dart'; import 'package:paperless_api/paperless_api.dart'; -import 'package:paperless_mobile/core/database/tables/user_app_state.dart'; +import 'package:paperless_mobile/core/database/tables/local_user_app_state.dart'; import 'package:paperless_mobile/core/notifier/document_changed_notifier.dart'; import 'package:paperless_mobile/core/repository/label_repository.dart'; -import 'package:paperless_mobile/core/database/tables/user_account.dart'; import 'package:paperless_mobile/features/paged_document_view/cubit/document_paging_bloc_mixin.dart'; import 'package:paperless_mobile/features/paged_document_view/cubit/paged_documents_state.dart'; import 'package:paperless_mobile/features/settings/model/view_type.dart'; @@ -24,14 +23,17 @@ class DocumentsCubit extends Cubit with DocumentPagingBlocMixin @override final DocumentChangedNotifier notifier; - final UserAppState _userState; + final LocalUserAppState _userState; DocumentsCubit( this.api, this.notifier, this._labelRepository, this._userState, - ) : super(DocumentsState(filter: _userState.currentDocumentFilter)) { + ) : super(DocumentsState( + filter: _userState.currentDocumentFilter, + viewType: _userState.documentsPageViewType, + )) { notifier.addListener( this, onUpdated: (document) { @@ -103,16 +105,6 @@ class DocumentsCubit extends Cubit with DocumentPagingBlocMixin return res; } - @override - DocumentsState? fromJson(Map json) { - return DocumentsState.fromJson(json); - } - - @override - Map? toJson(DocumentsState state) { - return state.toJson(); - } - @override Future close() { notifier.removeListener(this); @@ -122,6 +114,8 @@ class DocumentsCubit extends Cubit with DocumentPagingBlocMixin void setViewType(ViewType viewType) { emit(state.copyWith(viewType: viewType)); + _userState.documentsPageViewType = viewType; + _userState.save(); } @override diff --git a/lib/features/documents/view/pages/documents_page.dart b/lib/features/documents/view/pages/documents_page.dart index dd0bf80..22b7363 100644 --- a/lib/features/documents/view/pages/documents_page.dart +++ b/lib/features/documents/view/pages/documents_page.dart @@ -482,7 +482,7 @@ class _DocumentsPageState extends State with SingleTickerProvider try { final correspondent = cubit.state.filter.correspondent; if (correspondent is SetIdQueryParameter) { - if (correspondent.id == correspondentId) { + if (correspondentId == null || correspondent.id == correspondentId) { cubit.updateCurrentFilter( (filter) => filter.copyWith(correspondent: const IdQueryParameter.unset()), ); @@ -502,7 +502,7 @@ class _DocumentsPageState extends State with SingleTickerProvider try { final documentType = cubit.state.filter.documentType; if (documentType is SetIdQueryParameter) { - if (documentType.id == documentTypeId) { + if (documentTypeId == null || documentType.id == documentTypeId) { cubit.updateCurrentFilter( (filter) => filter.copyWith(documentType: const IdQueryParameter.unset()), ); @@ -522,7 +522,7 @@ class _DocumentsPageState extends State with SingleTickerProvider try { final path = cubit.state.filter.documentType; if (path is SetIdQueryParameter) { - if (path.id == pathId) { + if (pathId == null || path.id == pathId) { cubit.updateCurrentFilter( (filter) => filter.copyWith(storagePath: const IdQueryParameter.unset()), ); diff --git a/lib/features/home/view/home_page.dart b/lib/features/home/view/home_page.dart index 5eee767..ffc5793 100644 --- a/lib/features/home/view/home_page.dart +++ b/lib/features/home/view/home_page.dart @@ -9,10 +9,10 @@ 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/bloc/paperless_server_information_cubit.dart'; +import 'package:paperless_mobile/core/bloc/server_information_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/user_app_state.dart'; +import 'package:paperless_mobile/core/database/tables/local_user_app_state.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'; @@ -30,7 +30,7 @@ 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/user_account.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'; @@ -62,15 +62,6 @@ class _HomePageState extends State with WidgetsBindingObserver { void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); - - WidgetsBinding.instance.addPostFrameCallback((timeStamp) { - _listenForReceivedFiles(); - }); - } - - @override - void didChangeDependencies() { - super.didChangeDependencies(); _initializeData(context); final userId = Hive.box(HiveBoxes.globalSettings).getValue()!.currentLoggedInUser; @@ -78,7 +69,7 @@ class _HomePageState extends State with WidgetsBindingObserver { context.read(), context.read(), context.read(), - Hive.box(HiveBoxes.userAppState).get(userId)!, + Hive.box(HiveBoxes.localUserAppState).get(userId)!, )..reload(); _savedViewCubit = SavedViewCubit( context.read(), @@ -91,6 +82,14 @@ class _HomePageState extends State with WidgetsBindingObserver { context.read(), ); _listenToInboxChanges(); + WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + _listenForReceivedFiles(); + }); + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); } void _listenToInboxChanges() { @@ -352,7 +351,7 @@ class _HomePageState extends State with WidgetsBindingObserver { Future.wait([ context.read().initialize(), context.read().findAll(), - context.read().updateInformtion(), + context.read().updateInformation(), ]).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 new file mode 100644 index 0000000..4f06c9b --- /dev/null +++ b/lib/features/home/view/home_route.dart @@ -0,0 +1,29 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/src/widgets/framework.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:paperless_mobile/core/bloc/server_information_cubit.dart'; +import 'package:paperless_mobile/features/home/view/home_page.dart'; +import 'package:paperless_mobile/features/tasks/cubit/task_status_cubit.dart'; + +class HomeRoute extends StatelessWidget { + const HomeRoute({super.key}); + + @override + Widget build(BuildContext context) { + return MultiBlocProvider( + providers: [ + BlocProvider( + create: (context) => TaskStatusCubit( + context.read(), + ), + ), + BlocProvider( + create: (context) => ServerInformationCubit( + context.read(), + )..updateInformation(), + ), + ], + child: HomePage(), + ); + } +} diff --git a/lib/features/labels/view/pages/labels_page.dart b/lib/features/labels/view/pages/labels_page.dart index 991b952..ef28ab2 100644 --- a/lib/features/labels/view/pages/labels_page.dart +++ b/lib/features/labels/view/pages/labels_page.dart @@ -145,7 +145,7 @@ class _LabelsPageState extends State with SingleTickerProviderStateM LabelTabView( labels: context.watch().state.correspondents, filterBuilder: (label) => DocumentFilter( - correspondent: IdQueryParameter.fromId(label.id), + correspondent: IdQueryParameter.fromId(label.id!), pageSize: label.documentCount ?? 0, ), onEdit: _openEditCorrespondentPage, @@ -166,7 +166,7 @@ class _LabelsPageState extends State with SingleTickerProviderStateM LabelTabView( labels: context.watch().state.documentTypes, filterBuilder: (label) => DocumentFilter( - documentType: IdQueryParameter.fromId(label.id), + documentType: IdQueryParameter.fromId(label.id!), pageSize: label.documentCount ?? 0, ), onEdit: _openEditDocumentTypePage, @@ -218,7 +218,7 @@ class _LabelsPageState extends State with SingleTickerProviderStateM labels: context.watch().state.storagePaths, onEdit: _openEditStoragePathPage, filterBuilder: (label) => DocumentFilter( - storagePath: IdQueryParameter.fromId(label.id), + storagePath: IdQueryParameter.fromId(label.id!), pageSize: label.documentCount ?? 0, ), contentBuilder: (path) => Text(path.path), diff --git a/lib/features/labels/view/widgets/fullscreen_label_form.dart b/lib/features/labels/view/widgets/fullscreen_label_form.dart index a8c3829..b7b694d 100644 --- a/lib/features/labels/view/widgets/fullscreen_label_form.dart +++ b/lib/features/labels/view/widgets/fullscreen_label_form.dart @@ -80,11 +80,12 @@ class _FullscreenLabelFormState extends State id, - ), - )); + returnValue: value?.maybeWhen( + fromId: (id) => IdQueryParameter.fromId(id), + orElse: () => const IdQueryParameter.unset(), + ) ?? + const IdQueryParameter.unset(), + ); }, autofocus: true, style: theme.textTheme.bodyLarge?.apply( @@ -167,7 +168,7 @@ class _FullscreenLabelFormState extends State extends State extends State e.name.trim().toLowerCase().contains(normalizedQuery)); if (matches.isNotEmpty) { for (final match in matches) { - yield IdQueryParameter.fromId(match.id); + yield IdQueryParameter.fromId(match.id!); } if (widget.showNotAssignedOption) { yield const IdQueryParameter.notAssigned(); @@ -225,7 +226,7 @@ class _FullscreenLabelFormState extends State S.of(context)!.startTyping, notAssigned: () => S.of(context)!.notAssigned, anyAssigned: () => S.of(context)!.anyAssigned, - fromId: (id) => widget.options[id]!.name, + fromId: (id) => widget.options[id]?.name ?? S.of(context)!.startTyping, ); } diff --git a/lib/features/labels/view/widgets/label_form_field.dart b/lib/features/labels/view/widgets/label_form_field.dart index 7aaf09f..66a3252 100644 --- a/lib/features/labels/view/widgets/label_form_field.dart +++ b/lib/features/labels/view/widgets/label_form_field.dart @@ -49,7 +49,7 @@ class LabelFormField extends StatelessWidget { unset: () => '', notAssigned: () => S.of(context)!.notAssigned, anyAssigned: () => S.of(context)!.anyAssigned, - fromId: (id) => options[id]!.name, + fromId: (id) => options[id]?.name, ) ?? ''; } @@ -142,7 +142,7 @@ class LabelFormField extends StatelessWidget { child: ActionChip( label: Text(suggestion.name), onPressed: () => field.didChange( - IdQueryParameter.fromId(suggestion.id), + IdQueryParameter.fromId(suggestion.id!), ), ), ); diff --git a/lib/features/labels/view/widgets/label_item.dart b/lib/features/labels/view/widgets/label_item.dart index 333a617..e8faa79 100644 --- a/lib/features/labels/view/widgets/label_item.dart +++ b/lib/features/labels/view/widgets/label_item.dart @@ -5,7 +5,7 @@ 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/user_account.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/helpers/format_helpers.dart'; diff --git a/lib/features/login/cubit/authentication_cubit.dart b/lib/features/login/cubit/authentication_cubit.dart index e32e43b..1ead7c1 100644 --- a/lib/features/login/cubit/authentication_cubit.dart +++ b/lib/features/login/cubit/authentication_cubit.dart @@ -7,25 +7,25 @@ import 'package:hive_flutter/adapters.dart'; import 'package:hydrated_bloc/hydrated_bloc.dart'; import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/core/config/hive/hive_config.dart'; -import 'package:paperless_mobile/core/database/tables/user_app_state.dart'; +import 'package:paperless_mobile/core/database/tables/local_user_app_state.dart'; import 'package:paperless_mobile/core/interceptor/dio_http_error_interceptor.dart'; import 'package:paperless_mobile/core/repository/label_repository.dart'; import 'package:paperless_mobile/core/repository/saved_view_repository.dart'; import 'package:paperless_mobile/core/security/session_manager.dart'; import 'package:paperless_mobile/features/login/model/client_certificate.dart'; import 'package:paperless_mobile/features/login/model/login_form_credentials.dart'; -import 'package:paperless_mobile/core/database/tables/user_account.dart'; +import 'package:paperless_mobile/core/database/tables/local_user_account.dart'; import 'package:paperless_mobile/core/database/tables/user_credentials.dart'; import 'package:paperless_mobile/features/login/services/authentication_service.dart'; import 'package:paperless_mobile/core/database/tables/global_settings.dart'; -import 'package:paperless_mobile/core/database/tables/user_settings.dart'; +import 'package:paperless_mobile/core/database/tables/local_user_settings.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; part 'authentication_state.dart'; class AuthenticationCubit extends Cubit { final LocalAuthenticationService _localAuthService; final PaperlessAuthenticationApi _authApi; - final SessionManager _dioWrapper; + final SessionManager _sessionManager; final LabelRepository _labelRepository; final SavedViewRepository _savedViewRepository; final PaperlessServerStatsApi _serverStatsApi; @@ -33,7 +33,7 @@ class AuthenticationCubit extends Cubit { AuthenticationCubit( this._localAuthService, this._authApi, - this._dioWrapper, + this._sessionManager, this._labelRepository, this._savedViewRepository, this._serverStatsApi, @@ -46,7 +46,7 @@ class AuthenticationCubit extends Cubit { }) async { assert(credentials.username != null && credentials.password != null); - _dioWrapper.updateSettings( + _sessionManager.updateSettings( baseUrl: serverUrl, clientCertificate: clientCertificate, ); @@ -54,13 +54,14 @@ class AuthenticationCubit extends Cubit { username: credentials.username!, password: credentials.password!, ); - _dioWrapper.updateSettings( + _sessionManager.updateSettings( baseUrl: serverUrl, clientCertificate: clientCertificate, authToken: token, ); - final userAccountBox = Hive.box(HiveBoxes.userAccount); - final userStateBox = Hive.box(HiveBoxes.userAppState); + + final userAccountBox = Hive.box(HiveBoxes.localUserAccount); + final userStateBox = Hive.box(HiveBoxes.localUserAppState); final userId = "${credentials.username}@$serverUrl"; @@ -72,9 +73,9 @@ class AuthenticationCubit extends Cubit { // Create user account await userAccountBox.put( userId, - UserAccount( + LocalUserAccount( id: userId, - settings: UserSettings(), + settings: LocalUserSettings(), serverUrl: serverUrl, username: credentials.username!, fullName: fullName, @@ -84,7 +85,7 @@ class AuthenticationCubit extends Cubit { // Create user state await userStateBox.put( userId, - UserAppState(userId: userId), + LocalUserAppState(userId: userId), ); // Save credentials in encrypted box @@ -119,7 +120,7 @@ class AuthenticationCubit extends Cubit { if (globalSettings.currentLoggedInUser == userId) { return; } - final userAccountBox = Hive.box(HiveBoxes.userAccount); + final userAccountBox = Hive.box(HiveBoxes.localUserAccount); if (!userAccountBox.containsKey(userId)) { debugPrint("User $userId not yet registered."); @@ -148,7 +149,7 @@ class AuthenticationCubit extends Cubit { await _resetExternalState(); - _dioWrapper.updateSettings( + _sessionManager.updateSettings( authToken: credentials!.token, clientCertificate: credentials.clientCertificate, serverInformation: PaperlessServerInformationModel(), @@ -178,8 +179,8 @@ class AuthenticationCubit extends Cubit { assert(credentials.password != null && credentials.username != null); final userId = "${credentials.username}@$serverUrl"; - final userAccountsBox = Hive.box(HiveBoxes.userAccount); - final userStateBox = Hive.box(HiveBoxes.userAppState); + final userAccountsBox = Hive.box(HiveBoxes.localUserAccount); + final userStateBox = Hive.box(HiveBoxes.localUserAppState); if (userAccountsBox.containsKey(userId)) { throw Exception("User already exists"); @@ -204,11 +205,11 @@ class AuthenticationCubit extends Cubit { await userAccountsBox.put( userId, - UserAccount( + LocalUserAccount( id: userId, serverUrl: serverUrl, username: credentials.username!, - settings: UserSettings( + settings: LocalUserSettings( isBiometricAuthenticationEnabled: enableBiometricAuthentication, ), fullName: fullName, @@ -217,7 +218,7 @@ class AuthenticationCubit extends Cubit { await userStateBox.put( userId, - UserAppState( + LocalUserAppState( userId: userId, ), ); @@ -236,15 +237,15 @@ class AuthenticationCubit extends Cubit { Future removeAccount(String userId) async { final globalSettings = Hive.box(HiveBoxes.globalSettings).getValue()!; - final userAccountBox = Hive.box(HiveBoxes.userAccount); + final userAccountBox = Hive.box(HiveBoxes.localUserAccount); final userCredentialsBox = await _getUserCredentialsBox(); - final userAppStateBox = Hive.box(HiveBoxes.userAppState); + final userAppStateBox = Hive.box(HiveBoxes.localUserAppState); final currentUser = globalSettings.currentLoggedInUser; await userAccountBox.delete(userId); await userAppStateBox.delete(userId); await userCredentialsBox.delete(userId); - await userAccountBox.close(); + await userCredentialsBox.close(); if (currentUser == userId) { return logout(); @@ -262,7 +263,7 @@ class AuthenticationCubit extends Cubit { return; } - final userAccount = Hive.box(HiveBoxes.userAccount).get(userId)!; + final userAccount = Hive.box(HiveBoxes.localUserAccount).get(userId)!; if (userAccount.settings.isBiometricAuthenticationEnabled) { final localAuthSuccess = @@ -280,7 +281,7 @@ class AuthenticationCubit extends Cubit { if (authentication == null) { throw Exception("User should be authenticated but no authentication information was found."); } - _dioWrapper.updateSettings( + _sessionManager.updateSettings( clientCertificate: authentication.clientCertificate, authToken: authentication.token, baseUrl: userAccount.serverUrl, @@ -321,13 +322,13 @@ class AuthenticationCubit extends Cubit { Future> _getUserCredentialsBox() async { final keyBytes = await _getEncryptedBoxKey(); return Hive.openBox( - HiveBoxes.userCredentials, + HiveBoxes.localUserCredentials, encryptionCipher: HiveAesCipher(keyBytes), ); } Future _resetExternalState() { - _dioWrapper.resetSettings(); + _sessionManager.resetSettings(); return Future.wait([ HydratedBloc.storage.clear(), _labelRepository.clear(), diff --git a/lib/features/login/view/login_page.dart b/lib/features/login/view/login_page.dart index a7263f0..29e710c 100644 --- a/lib/features/login/view/login_page.dart +++ b/lib/features/login/view/login_page.dart @@ -1,10 +1,5 @@ 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/type/types.dart'; -import 'package:paperless_mobile/features/app_intro/application_intro_slideshow.dart'; -import 'package:paperless_mobile/features/login/cubit/authentication_cubit.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/features/login/model/login_form_credentials.dart'; @@ -12,8 +7,6 @@ import 'package:paperless_mobile/features/login/view/widgets/form_fields/client_ import 'package:paperless_mobile/features/login/view/widgets/form_fields/server_address_form_field.dart'; import 'package:paperless_mobile/features/login/view/widgets/form_fields/user_credentials_form_field.dart'; import 'package:paperless_mobile/features/login/view/widgets/login_pages/server_connection_page.dart'; -import 'package:paperless_mobile/core/database/tables/global_settings.dart'; -import 'package:paperless_mobile/helpers/message_helpers.dart'; import 'widgets/login_pages/server_login_page.dart'; import 'widgets/never_scrollable_scroll_behavior.dart'; diff --git a/lib/features/saved_view/view/saved_view_list.dart b/lib/features/saved_view/view/saved_view_list.dart index 881ef21..29b263f 100644 --- a/lib/features/saved_view/view/saved_view_list.dart +++ b/lib/features/saved_view/view/saved_view_list.dart @@ -1,6 +1,10 @@ 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/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'; @@ -17,11 +21,9 @@ class SavedViewList extends StatelessWidget { return BlocBuilder( builder: (context, state) { return state.when( - initial: (correspondents, documentTypes, tags, storagePaths) => - Container(), - loading: (correspondents, documentTypes, tags, storagePaths) => - Center( - child: Text("Saved views loading..."), + initial: (correspondents, documentTypes, tags, storagePaths) => Container(), + loading: (correspondents, documentTypes, tags, storagePaths) => Center( + child: Text("Saved views loading..."), //TODO: INTL ), loaded: ( savedViews, @@ -33,9 +35,7 @@ class SavedViewList extends StatelessWidget { if (savedViews.isEmpty) { return SliverToBoxAdapter( child: HintCard( - hintText: S - .of(context)! - .createViewsToQuicklyFilterYourDocuments, + hintText: S.of(context)!.createViewsToQuicklyFilterYourDocuments, ), ); } @@ -59,13 +59,17 @@ class SavedViewList extends StatelessWidget { ctxt.read(), ctxt.read(), context.read(), + Hive.box(HiveBoxes.localUserAppState).get( + Hive.box(HiveBoxes.globalSettings) + .getValue()! + .currentLoggedInUser!, + )!, savedView: view, ), ), ], child: SavedViewDetailsPage( - onDelete: - context.read().remove, + onDelete: context.read().remove, ), ), ), 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 1bddcb1..4f5d393 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,17 +1,16 @@ 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'; import 'package:paperless_mobile/core/repository/label_repository.dart'; import 'package:paperless_mobile/features/paged_document_view/cubit/paged_documents_state.dart'; import 'package:paperless_mobile/features/paged_document_view/cubit/document_paging_bloc_mixin.dart'; import 'package:paperless_mobile/features/settings/model/view_type.dart'; -part 'saved_view_details_cubit.g.dart'; part 'saved_view_details_state.dart'; -class SavedViewDetailsCubit extends HydratedCubit - with DocumentPagingBlocMixin { +class SavedViewDetailsCubit extends Cubit with DocumentPagingBlocMixin { @override final PaperlessDocumentsApi api; @@ -22,10 +21,13 @@ class SavedViewDetailsCubit extends HydratedCubit final SavedView savedView; + final LocalUserAppState _userState; + SavedViewDetailsCubit( this.api, this.notifier, - this._labelRepository, { + this._labelRepository, + this._userState, { required this.savedView, }) : super( SavedViewDetailsState( @@ -33,6 +35,7 @@ class SavedViewDetailsCubit extends HydratedCubit documentTypes: _labelRepository.state.documentTypes, tags: _labelRepository.state.tags, storagePaths: _labelRepository.state.storagePaths, + viewType: _userState.savedViewsViewType, ), ) { notifier.addListener( @@ -58,16 +61,9 @@ class SavedViewDetailsCubit extends HydratedCubit void setViewType(ViewType viewType) { emit(state.copyWith(viewType: viewType)); - } - - @override - SavedViewDetailsState? fromJson(Map json) { - return SavedViewDetailsState.fromJson(json); - } - - @override - Map? toJson(SavedViewDetailsState state) { - return state.toJson(); + _userState + ..savedViewsViewType = viewType + ..save(); } @override diff --git a/lib/features/saved_view_details/cubit/saved_view_details_state.dart b/lib/features/saved_view_details/cubit/saved_view_details_state.dart index 00a160f..858d598 100644 --- a/lib/features/saved_view_details/cubit/saved_view_details_state.dart +++ b/lib/features/saved_view_details/cubit/saved_view_details_state.dart @@ -1,8 +1,6 @@ part of 'saved_view_details_cubit.dart'; -@JsonSerializable(ignoreUnannotated: true) class SavedViewDetailsState extends DocumentPagingState { - @JsonKey() final ViewType viewType; final Map correspondents; @@ -70,9 +68,4 @@ class SavedViewDetailsState extends DocumentPagingState { storagePaths: storagePaths ?? this.storagePaths, ); } - - factory SavedViewDetailsState.fromJson(Map json) => - _$SavedViewDetailsStateFromJson(json); - - Map toJson() => _$SavedViewDetailsStateToJson(this); } diff --git a/lib/features/settings/model/view_type.dart b/lib/features/settings/model/view_type.dart index 57ff3c5..72b13df 100644 --- a/lib/features/settings/model/view_type.dart +++ b/lib/features/settings/model/view_type.dart @@ -1,6 +1,15 @@ +import 'package:hive/hive.dart'; +import 'package:paperless_mobile/core/config/hive/hive_config.dart'; + +part 'view_type.g.dart'; + +@HiveType(typeId: HiveTypeIds.viewType) enum ViewType { + @HiveField(0) grid, + @HiveField(1) list, + @HiveField(2) detailed; ViewType toggle() { diff --git a/lib/features/settings/view/manage_accounts_page.dart b/lib/features/settings/view/manage_accounts_page.dart index 282de66..1337487 100644 --- a/lib/features/settings/view/manage_accounts_page.dart +++ b/lib/features/settings/view/manage_accounts_page.dart @@ -9,7 +9,7 @@ import 'package:paperless_mobile/core/config/hive/hive_config.dart'; import 'package:paperless_mobile/extensions/flutter_extensions.dart'; import 'package:paperless_mobile/features/login/cubit/authentication_cubit.dart'; import 'package:paperless_mobile/features/login/model/login_form_credentials.dart'; -import 'package:paperless_mobile/core/database/tables/user_account.dart'; +import 'package:paperless_mobile/core/database/tables/local_user_account.dart'; import 'package:paperless_mobile/features/login/view/login_page.dart'; import 'package:paperless_mobile/core/database/tables/global_settings.dart'; import 'package:paperless_mobile/features/settings/view/dialogs/switch_account_dialog.dart'; @@ -26,7 +26,7 @@ class ManageAccountsPage extends StatelessWidget { return GlobalSettingsBuilder( builder: (context, globalSettings) { return ValueListenableBuilder( - valueListenable: Hive.box(HiveBoxes.userAccount).listenable(), + valueListenable: Hive.box(HiveBoxes.localUserAccount).listenable(), builder: (context, box, _) { final userIds = box.keys.toList().cast(); final otherAccounts = userIds @@ -68,7 +68,7 @@ class ManageAccountsPage extends StatelessWidget { title: Text(S.of(context)!.addAccount), leading: const Icon(Icons.person_add), onTap: () { - _onAddAccount(context); + _onAddAccount(context, globalSettings.currentLoggedInUser!); }, ), ], @@ -82,7 +82,7 @@ class ManageAccountsPage extends StatelessWidget { Widget _buildAccountTile( BuildContext context, String userId, - UserAccount account, + LocalUserAccount account, GlobalSettings settings, ) { final isLoggedIn = userId == settings.currentLoggedInUser; @@ -147,16 +147,7 @@ class ManageAccountsPage extends StatelessWidget { onSelected: (value) async { if (value == 0) { // Switch - final navigator = Navigator.of(context); - if (settings.currentLoggedInUser == userId) return; - Navigator.pushReplacement( - context, - MaterialPageRoute( - builder: (context) => const SwitchingAccountsPage(), - ), - ); - await context.read().switchAccount(userId); - navigator.popUntil((route) => route.isFirst); + _onSwitchAccount(context, settings.currentLoggedInUser!, userId); } else if (value == 1) { // Remove final shouldPop = userId == settings.currentLoggedInUser; @@ -177,7 +168,7 @@ class ManageAccountsPage extends StatelessWidget { return child; } - Future _onAddAccount(BuildContext context) async { + Future _onAddAccount(BuildContext context, String currentUser) async { final userId = await Navigator.push( context, MaterialPageRoute( @@ -207,9 +198,21 @@ class ManageAccountsPage extends StatelessWidget { ) ?? false; if (shoudSwitch) { - await context.read().switchAccount(userId); - Navigator.pop(context); + _onSwitchAccount(context, currentUser, userId); } } } + + _onSwitchAccount(BuildContext context, String currentUser, String newUser) async { + final navigator = Navigator.of(context); + if (currentUser == newUser) return; + Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) => const SwitchingAccountsPage(), + ), + ); + await context.read().switchAccount(newUser); + navigator.popUntil((route) => route.isFirst); + } } diff --git a/lib/features/settings/view/settings_page.dart b/lib/features/settings/view/settings_page.dart index d3c8cba..5ba5f4a 100644 --- a/lib/features/settings/view/settings_page.dart +++ b/lib/features/settings/view/settings_page.dart @@ -1,9 +1,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:paperless_mobile/core/bloc/paperless_server_information_cubit.dart'; -import 'package:paperless_mobile/core/bloc/paperless_server_information_state.dart'; +import 'package:paperless_mobile/core/bloc/server_information_cubit.dart'; +import 'package:paperless_mobile/core/bloc/server_information_state.dart'; import 'package:paperless_mobile/features/settings/view/pages/application_settings_page.dart'; import 'package:paperless_mobile/features/settings/view/pages/security_settings_page.dart'; +import 'package:paperless_mobile/features/settings/view/widgets/user_settings_builder.dart'; import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; class SettingsPage extends StatelessWidget { @@ -15,23 +16,27 @@ class SettingsPage extends StatelessWidget { appBar: AppBar( title: Text(S.of(context)!.settings), ), - bottomNavigationBar: - BlocBuilder( - builder: (context, state) { - final info = state.information!; + bottomNavigationBar: UserAccountBuilder( + builder: (context, user) { + assert(user != null); + final host = user!.serverUrl.replaceFirst(RegExp(r"https?://"), ""); return ListTile( title: Text( - S.of(context)!.loggedInAs(info.username ?? 'unknown') + "@${info.host}", + S.of(context)!.loggedInAs(user.username) + "@$host", style: Theme.of(context).textTheme.labelSmall, textAlign: TextAlign.center, ), - subtitle: Text( - S.of(context)!.paperlessServerVersion + - ' ' + - info.version.toString() + - ' (API v${info.apiVersion})', - style: Theme.of(context).textTheme.labelSmall, - textAlign: TextAlign.center, + subtitle: BlocBuilder( + builder: (context, state) { + return Text( + S.of(context)!.paperlessServerVersion + + ' ' + + state.information!.version.toString() + + ' (API v${state.information!.apiVersion})', + style: Theme.of(context).textTheme.labelSmall, + textAlign: TextAlign.center, + ); + }, ), ); }, diff --git a/lib/features/settings/view/widgets/user_avatar.dart b/lib/features/settings/view/widgets/user_avatar.dart index 0339cbd..82a8356 100644 --- a/lib/features/settings/view/widgets/user_avatar.dart +++ b/lib/features/settings/view/widgets/user_avatar.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; -import 'package:paperless_mobile/core/database/tables/user_account.dart'; +import 'package:paperless_mobile/core/database/tables/local_user_account.dart'; class UserAvatar extends StatelessWidget { final String userId; - final UserAccount account; + final LocalUserAccount account; const UserAvatar({ super.key, required this.userId, diff --git a/lib/features/settings/view/widgets/user_settings_builder.dart b/lib/features/settings/view/widgets/user_settings_builder.dart index 5b78f44..b4247fc 100644 --- a/lib/features/settings/view/widgets/user_settings_builder.dart +++ b/lib/features/settings/view/widgets/user_settings_builder.dart @@ -1,14 +1,14 @@ import 'package:flutter/material.dart'; import 'package:hive_flutter/adapters.dart'; import 'package:paperless_mobile/core/config/hive/hive_config.dart'; -import 'package:paperless_mobile/core/database/tables/user_account.dart'; +import 'package:paperless_mobile/core/database/tables/local_user_account.dart'; import 'package:paperless_mobile/core/database/tables/global_settings.dart'; -import 'package:paperless_mobile/core/database/tables/user_settings.dart'; +import 'package:paperless_mobile/core/database/tables/local_user_settings.dart'; class UserAccountBuilder extends StatelessWidget { final Widget Function( BuildContext context, - UserAccount? settings, + LocalUserAccount? settings, ) builder; const UserAccountBuilder({ @@ -18,8 +18,8 @@ class UserAccountBuilder extends StatelessWidget { @override Widget build(BuildContext context) { - return ValueListenableBuilder>( - valueListenable: Hive.box(HiveBoxes.userAccount).listenable(), + return ValueListenableBuilder>( + valueListenable: Hive.box(HiveBoxes.localUserAccount).listenable(), builder: (context, accountBox, _) { final currentUser = Hive.box(HiveBoxes.globalSettings).getValue()!.currentLoggedInUser; diff --git a/lib/features/similar_documents/cubit/similar_documents_cubit.dart b/lib/features/similar_documents/cubit/similar_documents_cubit.dart index 7899889..43641d5 100644 --- a/lib/features/similar_documents/cubit/similar_documents_cubit.dart +++ b/lib/features/similar_documents/cubit/similar_documents_cubit.dart @@ -23,7 +23,7 @@ class SimilarDocumentsCubit extends Cubit with DocumentPa this.notifier, this._labelRepository, { required this.documentId, - }) : super(SimilarDocumentsState(filter: DocumentFilter())) { + }) : super(const SimilarDocumentsState(filter: DocumentFilter())) { notifier.addListener( this, onDeleted: remove, diff --git a/lib/main.dart b/lib/main.dart index f7029ee..b9043af 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -18,9 +18,9 @@ import 'package:package_info_plus/package_info_plus.dart'; import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/constants.dart'; import 'package:paperless_mobile/core/bloc/connectivity_cubit.dart'; -import 'package:paperless_mobile/core/bloc/paperless_server_information_cubit.dart'; +import 'package:paperless_mobile/core/bloc/server_information_cubit.dart'; import 'package:paperless_mobile/core/config/hive/hive_config.dart'; -import 'package:paperless_mobile/core/database/tables/user_app_state.dart'; +import 'package:paperless_mobile/core/database/tables/local_user_app_state.dart'; import 'package:paperless_mobile/core/interceptor/dio_http_error_interceptor.dart'; import 'package:paperless_mobile/core/interceptor/language_header.interceptor.dart'; import 'package:paperless_mobile/core/notifier/document_changed_notifier.dart'; @@ -32,11 +32,12 @@ import 'package:paperless_mobile/core/service/dio_file_service.dart'; import 'package:paperless_mobile/core/type/types.dart'; import 'package:paperless_mobile/features/app_intro/application_intro_slideshow.dart'; import 'package:paperless_mobile/features/home/view/home_page.dart'; +import 'package:paperless_mobile/features/home/view/home_route.dart'; import 'package:paperless_mobile/features/home/view/widget/verify_identity_page.dart'; import 'package:paperless_mobile/features/login/cubit/authentication_cubit.dart'; import 'package:paperless_mobile/features/login/model/client_certificate.dart'; import 'package:paperless_mobile/features/login/model/login_form_credentials.dart'; -import 'package:paperless_mobile/core/database/tables/user_account.dart'; +import 'package:paperless_mobile/core/database/tables/local_user_account.dart'; import 'package:paperless_mobile/features/login/services/authentication_service.dart'; import 'package:paperless_mobile/features/login/view/login_page.dart'; import 'package:paperless_mobile/features/notifications/services/local_notification_service.dart'; @@ -66,8 +67,8 @@ Future _initHive() async { // await getApplicationDocumentsDirectory().then((value) => value.delete(recursive: true)); registerHiveAdapters(); - await Hive.openBox(HiveBoxes.userAccount); - await Hive.openBox(HiveBoxes.userAppState); + await Hive.openBox(HiveBoxes.localUserAccount); + await Hive.openBox(HiveBoxes.localUserAppState); final globalSettingsBox = await Hive.openBox(HiveBoxes.globalSettings); if (!globalSettingsBox.hasValue) { @@ -302,26 +303,8 @@ class _AuthenticationWrapperState extends State { return BlocBuilder( builder: (context, authentication) { if (authentication.isAuthenticated) { - return MultiBlocProvider( - // This key will cause the subtree to be remounted, which will again - // call the provider's create callback! Without this key, the blocs - // would not be recreated on account switch! + return HomeRoute( key: ValueKey(authentication.userId), - providers: [ - BlocProvider( - create: (context) => TaskStatusCubit( - context.read(), - ), - ), - BlocProvider( - create: (context) => PaperlessServerInformationCubit( - context.read(), - ), - ), - ], - child: HomePage( - key: ValueKey(authentication.userId), - ), ); } else if (authentication.showBiometricAuthenticationScreen) { return const VerifyIdentityPage(); diff --git a/packages/paperless_api/lib/src/models/query_parameters/id_query_parameter.dart b/packages/paperless_api/lib/src/models/query_parameters/id_query_parameter.dart index 699e99d..e18261c 100644 --- a/packages/paperless_api/lib/src/models/query_parameters/id_query_parameter.dart +++ b/packages/paperless_api/lib/src/models/query_parameters/id_query_parameter.dart @@ -14,7 +14,7 @@ class IdQueryParameter with _$IdQueryParameter { @HiveType(typeId: PaperlessApiHiveTypeIds.anyAssignedIdQueryParameter) const factory IdQueryParameter.anyAssigned() = AnyAssignedIdQueryParameter; @HiveType(typeId: PaperlessApiHiveTypeIds.setIdQueryParameter) - const factory IdQueryParameter.fromId(@HiveField(0) int? id) = SetIdQueryParameter; + const factory IdQueryParameter.fromId(@HiveField(0) int id) = SetIdQueryParameter; Map toQueryParameter(String field) { return when( diff --git a/packages/paperless_api/lib/src/models/query_parameters/id_query_parameter.freezed.dart b/packages/paperless_api/lib/src/models/query_parameters/id_query_parameter.freezed.dart index 5acf14e..0509d0b 100644 --- a/packages/paperless_api/lib/src/models/query_parameters/id_query_parameter.freezed.dart +++ b/packages/paperless_api/lib/src/models/query_parameters/id_query_parameter.freezed.dart @@ -38,7 +38,7 @@ mixin _$IdQueryParameter { required TResult Function() unset, required TResult Function() notAssigned, required TResult Function() anyAssigned, - required TResult Function(@HiveField(0) int? id) fromId, + required TResult Function(@HiveField(0) int id) fromId, }) => throw _privateConstructorUsedError; @optionalTypeArgs @@ -46,7 +46,7 @@ mixin _$IdQueryParameter { TResult? Function()? unset, TResult? Function()? notAssigned, TResult? Function()? anyAssigned, - TResult? Function(@HiveField(0) int? id)? fromId, + TResult? Function(@HiveField(0) int id)? fromId, }) => throw _privateConstructorUsedError; @optionalTypeArgs @@ -54,7 +54,7 @@ mixin _$IdQueryParameter { TResult Function()? unset, TResult Function()? notAssigned, TResult Function()? anyAssigned, - TResult Function(@HiveField(0) int? id)? fromId, + TResult Function(@HiveField(0) int id)? fromId, required TResult orElse(), }) => throw _privateConstructorUsedError; @@ -155,7 +155,7 @@ class _$UnsetIdQueryParameter extends UnsetIdQueryParameter { required TResult Function() unset, required TResult Function() notAssigned, required TResult Function() anyAssigned, - required TResult Function(@HiveField(0) int? id) fromId, + required TResult Function(@HiveField(0) int id) fromId, }) { return unset(); } @@ -166,7 +166,7 @@ class _$UnsetIdQueryParameter extends UnsetIdQueryParameter { TResult? Function()? unset, TResult? Function()? notAssigned, TResult? Function()? anyAssigned, - TResult? Function(@HiveField(0) int? id)? fromId, + TResult? Function(@HiveField(0) int id)? fromId, }) { return unset?.call(); } @@ -177,7 +177,7 @@ class _$UnsetIdQueryParameter extends UnsetIdQueryParameter { TResult Function()? unset, TResult Function()? notAssigned, TResult Function()? anyAssigned, - TResult Function(@HiveField(0) int? id)? fromId, + TResult Function(@HiveField(0) int id)? fromId, required TResult orElse(), }) { if (unset != null) { @@ -293,7 +293,7 @@ class _$NotAssignedIdQueryParameter extends NotAssignedIdQueryParameter { required TResult Function() unset, required TResult Function() notAssigned, required TResult Function() anyAssigned, - required TResult Function(@HiveField(0) int? id) fromId, + required TResult Function(@HiveField(0) int id) fromId, }) { return notAssigned(); } @@ -304,7 +304,7 @@ class _$NotAssignedIdQueryParameter extends NotAssignedIdQueryParameter { TResult? Function()? unset, TResult? Function()? notAssigned, TResult? Function()? anyAssigned, - TResult? Function(@HiveField(0) int? id)? fromId, + TResult? Function(@HiveField(0) int id)? fromId, }) { return notAssigned?.call(); } @@ -315,7 +315,7 @@ class _$NotAssignedIdQueryParameter extends NotAssignedIdQueryParameter { TResult Function()? unset, TResult Function()? notAssigned, TResult Function()? anyAssigned, - TResult Function(@HiveField(0) int? id)? fromId, + TResult Function(@HiveField(0) int id)? fromId, required TResult orElse(), }) { if (notAssigned != null) { @@ -431,7 +431,7 @@ class _$AnyAssignedIdQueryParameter extends AnyAssignedIdQueryParameter { required TResult Function() unset, required TResult Function() notAssigned, required TResult Function() anyAssigned, - required TResult Function(@HiveField(0) int? id) fromId, + required TResult Function(@HiveField(0) int id) fromId, }) { return anyAssigned(); } @@ -442,7 +442,7 @@ class _$AnyAssignedIdQueryParameter extends AnyAssignedIdQueryParameter { TResult? Function()? unset, TResult? Function()? notAssigned, TResult? Function()? anyAssigned, - TResult? Function(@HiveField(0) int? id)? fromId, + TResult? Function(@HiveField(0) int id)? fromId, }) { return anyAssigned?.call(); } @@ -453,7 +453,7 @@ class _$AnyAssignedIdQueryParameter extends AnyAssignedIdQueryParameter { TResult Function()? unset, TResult Function()? notAssigned, TResult Function()? anyAssigned, - TResult Function(@HiveField(0) int? id)? fromId, + TResult Function(@HiveField(0) int id)? fromId, required TResult orElse(), }) { if (anyAssigned != null) { @@ -521,7 +521,7 @@ abstract class _$$SetIdQueryParameterCopyWith<$Res> { $Res Function(_$SetIdQueryParameter) then) = __$$SetIdQueryParameterCopyWithImpl<$Res>; @useResult - $Res call({@HiveField(0) int? id}); + $Res call({@HiveField(0) int id}); } /// @nodoc @@ -535,13 +535,13 @@ class __$$SetIdQueryParameterCopyWithImpl<$Res> @pragma('vm:prefer-inline') @override $Res call({ - Object? id = freezed, + Object? id = null, }) { return _then(_$SetIdQueryParameter( - freezed == id + null == id ? _value.id : id // ignore: cast_nullable_to_non_nullable - as int?, + as int, )); } } @@ -559,7 +559,7 @@ class _$SetIdQueryParameter extends SetIdQueryParameter { @override @HiveField(0) - final int? id; + final int id; @JsonKey(name: 'runtimeType') final String $type; @@ -594,7 +594,7 @@ class _$SetIdQueryParameter extends SetIdQueryParameter { required TResult Function() unset, required TResult Function() notAssigned, required TResult Function() anyAssigned, - required TResult Function(@HiveField(0) int? id) fromId, + required TResult Function(@HiveField(0) int id) fromId, }) { return fromId(id); } @@ -605,7 +605,7 @@ class _$SetIdQueryParameter extends SetIdQueryParameter { TResult? Function()? unset, TResult? Function()? notAssigned, TResult? Function()? anyAssigned, - TResult? Function(@HiveField(0) int? id)? fromId, + TResult? Function(@HiveField(0) int id)? fromId, }) { return fromId?.call(id); } @@ -616,7 +616,7 @@ class _$SetIdQueryParameter extends SetIdQueryParameter { TResult Function()? unset, TResult Function()? notAssigned, TResult Function()? anyAssigned, - TResult Function(@HiveField(0) int? id)? fromId, + TResult Function(@HiveField(0) int id)? fromId, required TResult orElse(), }) { if (fromId != null) { @@ -671,7 +671,7 @@ class _$SetIdQueryParameter extends SetIdQueryParameter { } abstract class SetIdQueryParameter extends IdQueryParameter { - const factory SetIdQueryParameter(@HiveField(0) final int? id) = + const factory SetIdQueryParameter(@HiveField(0) final int id) = _$SetIdQueryParameter; const SetIdQueryParameter._() : super._(); @@ -679,7 +679,7 @@ abstract class SetIdQueryParameter extends IdQueryParameter { _$SetIdQueryParameter.fromJson; @HiveField(0) - int? get id; + int get id; @JsonKey(ignore: true) _$$SetIdQueryParameterCopyWith<_$SetIdQueryParameter> get copyWith => throw _privateConstructorUsedError; diff --git a/packages/paperless_api/lib/src/models/query_parameters/text_query.dart b/packages/paperless_api/lib/src/models/query_parameters/text_query.dart index d024790..27dbe02 100644 --- a/packages/paperless_api/lib/src/models/query_parameters/text_query.dart +++ b/packages/paperless_api/lib/src/models/query_parameters/text_query.dart @@ -7,6 +7,7 @@ import 'query_type.dart'; part 'text_query.g.dart'; +//TODO: Realize with freezed... @HiveType(typeId: PaperlessApiHiveTypeIds.textQuery) @JsonSerializable() class TextQuery extends Equatable { 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 b848362..e2845c7 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 @@ -78,6 +78,7 @@ class PaperlessDocumentsApiImpl implements PaperlessDocumentsApi { throw const PaperlessServerException(ErrorCode.documentUpdateFailed); } } on DioError catch (err) { + //TODO: Handle 403 permission errors for 1.14.0 throw err.error!; } } @@ -86,8 +87,7 @@ class PaperlessDocumentsApiImpl implements PaperlessDocumentsApi { Future> findAll( DocumentFilter filter, ) async { - final filterParams = filter.toQueryParameters() - ..addAll({'truncate_content': "true"}); + final filterParams = filter.toQueryParameters()..addAll({'truncate_content': "true"}); try { final response = await client.get( "/api/documents/", @@ -137,9 +137,8 @@ class PaperlessDocumentsApiImpl implements PaperlessDocumentsApi { try { final response = await client.get( getPreviewUrl(documentId), - options: Options( - responseType: ResponseType - .bytes), //TODO: Check if bytes or stream is required + options: + Options(responseType: ResponseType.bytes), //TODO: Check if bytes or stream is required ); if (response.statusCode == 200) { return response.data; @@ -219,8 +218,7 @@ class PaperlessDocumentsApiImpl implements PaperlessDocumentsApi { final response = await client.download( "/api/documents/${document.id}/download/", localFilePath, - onReceiveProgress: (count, total) => - onProgressChanged?.call(count / total), + onReceiveProgress: (count, total) => onProgressChanged?.call(count / total), queryParameters: {'original': original}, ); return response.data; @@ -232,8 +230,7 @@ class PaperlessDocumentsApiImpl implements PaperlessDocumentsApi { @override Future getMetaData(DocumentModel document) async { try { - final response = - await client.get("/api/documents/${document.id}/metadata/"); + final response = await client.get("/api/documents/${document.id}/metadata/"); return compute( DocumentMetaData.fromJson, response.data as Map, @@ -265,11 +262,9 @@ class PaperlessDocumentsApiImpl implements PaperlessDocumentsApi { @override Future findSuggestions(DocumentModel document) async { try { - final response = - await client.get("/api/documents/${document.id}/suggestions/"); + final response = await client.get("/api/documents/${document.id}/suggestions/"); if (response.statusCode == 200) { - return FieldSuggestions.fromJson(response.data) - .forDocumentId(document.id); + return FieldSuggestions.fromJson(response.data).forDocumentId(document.id); } throw const PaperlessServerException(ErrorCode.suggestionsQueryError); } on DioError catch (err) { diff --git a/packages/paperless_api/lib/src/modules/server_stats_api/paperless_server_stats_api_impl.dart b/packages/paperless_api/lib/src/modules/server_stats_api/paperless_server_stats_api_impl.dart index d0e21fa..9a2f8c0 100644 --- a/packages/paperless_api/lib/src/modules/server_stats_api/paperless_server_stats_api_impl.dart +++ b/packages/paperless_api/lib/src/modules/server_stats_api/paperless_server_stats_api_impl.dart @@ -1,7 +1,4 @@ -import 'dart:convert'; - import 'package:dio/dio.dart'; -import 'package:http/http.dart'; import 'package:paperless_api/src/models/paperless_server_exception.dart'; import 'package:paperless_api/src/models/paperless_server_information_model.dart'; import 'package:paperless_api/src/models/paperless_server_statistics_model.dart'; @@ -21,20 +18,14 @@ class PaperlessServerStatsApiImpl implements PaperlessServerStatsApi { @override Future getServerInformation() async { - final response = await client.get("/api/ui_settings/"); + final response = await client.get("/api/"); final version = response.headers[PaperlessServerInformationModel.versionHeader]?.first ?? 'unknown'; final apiVersion = int.tryParse( response.headers[PaperlessServerInformationModel.apiVersionHeader]?.first ?? '1'); - final String username = response.data['username']; - final String host = response.headers[PaperlessServerInformationModel.hostHeader]?.first ?? - response.headers[PaperlessServerInformationModel.hostHeader]?.first ?? - ('${response.requestOptions.uri.host}:${response.requestOptions.uri.port}'); return PaperlessServerInformationModel( - username: username, version: version, apiVersion: apiVersion, - host: host, ); }