diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index f1e1dd1..4001596 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -3,7 +3,8 @@ + android:requestLegacyExternalStorage="true" + > pushSavedViewDetailsRoute( ); } -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 pushBulkEditCorrespondentRoute( BuildContext context, { required List selection, diff --git a/lib/core/repository/saved_view_repository.dart b/lib/core/repository/saved_view_repository.dart index 234ceb3..09fb82d 100644 --- a/lib/core/repository/saved_view_repository.dart +++ b/lib/core/repository/saved_view_repository.dart @@ -35,6 +35,18 @@ class SavedViewRepository return created; } + Future update(SavedView object) async { + await _initialized.future; + final updated = await _api.update(object); + final updatedState = {...state.savedViews}..update( + updated.id!, + (_) => updated, + ifAbsent: () => updated, + ); + emit(SavedViewRepositoryState.loaded(savedViews: updatedState)); + return updated; + } + Future delete(SavedView view) async { await _initialized.future; await _api.delete(view); diff --git a/lib/core/translation/error_code_localization_mapper.dart b/lib/core/translation/error_code_localization_mapper.dart index 24d938c..4e653e7 100644 --- a/lib/core/translation/error_code_localization_mapper.dart +++ b/lib/core/translation/error_code_localization_mapper.dart @@ -54,7 +54,7 @@ String translateError(BuildContext context, ErrorCode code) { ErrorCode.suggestionsQueryError => S.of(context)!.couldNotLoadSuggestions, ErrorCode.acknowledgeTasksError => S.of(context)!.couldNotAcknowledgeTasks, ErrorCode.correspondentDeleteFailed => - "Could not delete correspondent, please try again.", + "Could not delete correspondent, please try again.", //TODO: INTL ErrorCode.documentTypeDeleteFailed => "Could not delete document type, please try again.", ErrorCode.tagDeleteFailed => "Could not delete tag, please try again.", @@ -73,5 +73,6 @@ String translateError(BuildContext context, ErrorCode code) { ErrorCode.uiSettingsLoadFailed => "Could not load UI settings", ErrorCode.loadTasksError => "Could not load tasks.", ErrorCode.userNotFound => "User could not be found.", + ErrorCode.updateSavedViewError => "Could not update saved view.", }; } diff --git a/lib/features/document_search/view/sliver_search_bar.dart b/lib/features/document_search/view/sliver_search_bar.dart index 4dcf665..072b331 100644 --- a/lib/features/document_search/view/sliver_search_bar.dart +++ b/lib/features/document_search/view/sliver_search_bar.dart @@ -1,12 +1,9 @@ import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:hive/hive.dart'; 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/core/database/tables/local_user_account.dart'; import 'package:paperless_mobile/features/document_search/view/document_search_bar.dart'; -import 'package:paperless_mobile/features/home/view/model/api_version.dart'; import 'package:paperless_mobile/features/settings/view/manage_accounts_page.dart'; import 'package:paperless_mobile/features/settings/view/widgets/global_settings_builder.dart'; import 'package:paperless_mobile/features/settings/view/widgets/user_avatar.dart'; diff --git a/lib/features/documents/view/pages/documents_page.dart b/lib/features/documents/view/pages/documents_page.dart index 6db35d8..a8ce920 100644 --- a/lib/features/documents/view/pages/documents_page.dart +++ b/lib/features/documents/view/pages/documents_page.dart @@ -5,15 +5,13 @@ 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/navigation/push_routes.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'; import 'package:paperless_mobile/features/document_search/view/sliver_search_bar.dart'; import 'package:paperless_mobile/features/documents/cubit/documents_cubit.dart'; import 'package:paperless_mobile/features/documents/view/widgets/adaptive_documents_view.dart'; import 'package:paperless_mobile/features/documents/view/widgets/documents_empty_state.dart'; +import 'package:paperless_mobile/features/documents/view/widgets/saved_views/saved_view_changed_dialog.dart'; +import 'package:paperless_mobile/features/documents/view/widgets/saved_views/saved_views_widget.dart'; import 'package:paperless_mobile/features/documents/view/widgets/search/document_filter_panel.dart'; import 'package:paperless_mobile/features/documents/view/widgets/selection/document_selection_sliver_app_bar.dart'; import 'package:paperless_mobile/features/documents/view/widgets/selection/view_type_selection_widget.dart'; @@ -24,6 +22,7 @@ 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/typed/branches/documents_route.dart'; +import 'package:sliver_tools/sliver_tools.dart'; class DocumentFilterIntent { final DocumentFilter? filter; @@ -46,12 +45,29 @@ class _DocumentsPageState extends State with SingleTickerProviderStateMixin { final SliverOverlapAbsorberHandle searchBarHandle = SliverOverlapAbsorberHandle(); - final SliverOverlapAbsorberHandle tabBarHandle = + final SliverOverlapAbsorberHandle savedViewsHandle = SliverOverlapAbsorberHandle(); late final TabController _tabController; int _currentTab = 0; + bool get hasSelectedViewChanged { + final cubit = context.watch(); + final savedViewCubit = context.watch(); + final activeView = savedViewCubit.state.maybeMap( + loaded: (state) { + if (cubit.state.filter.selectedView != null) { + return state.savedViews[cubit.state.filter.selectedView!]; + } + return null; + }, + orElse: () => null, + ); + final viewHasChanged = activeView != null && + activeView.toDocumentFilter() != cubit.state.filter; + return viewHasChanged; + } + @override void initState() { super.initState(); @@ -139,7 +155,7 @@ class _DocumentsPageState extends State .colorScheme .onPrimaryContainer, onPressed: () { - context.read().updateFilter(); + _onResetFilter(); }, child: Icon( Icons.refresh, @@ -195,107 +211,148 @@ class _DocumentsPageState extends State } return true; }, - child: NestedScrollView( - floatHeaderSlivers: true, - headerSliverBuilder: (context, innerBoxIsScrolled) => [ - SliverOverlapAbsorber( - handle: searchBarHandle, - sliver: BlocBuilder( - builder: (context, state) { - if (state.selection.isEmpty) { - return SliverSearchBar( - floating: true, - titleText: S.of(context)!.documents, - ); - } else { - return DocumentSelectionSliverAppBar( - state: state, - ); + child: Stack( + children: [ + NestedScrollView( + floatHeaderSlivers: true, + headerSliverBuilder: (context, innerBoxIsScrolled) => [ + SliverOverlapAbsorber( + handle: searchBarHandle, + sliver: BlocBuilder( + builder: (context, state) { + if (state.selection.isEmpty) { + return SliverSearchBar( + floating: true, + titleText: S.of(context)!.documents, + ); + } else { + return DocumentSelectionSliverAppBar( + state: state, + ); + } + }, + ), + ), + SliverOverlapAbsorber( + handle: savedViewsHandle, + sliver: SliverPinnedHeader( + child: _buildViewActions(), + ), + ), + // SliverOverlapAbsorber( + // handle: tabBarHandle, + // sliver: BlocBuilder( + // builder: (context, state) { + // if (state.selection.isNotEmpty) { + // return const SliverToBoxAdapter( + // child: SizedBox.shrink(), + // ); + // } + // return SliverPersistentHeader( + // pinned: true, + // delegate: + // CustomizableSliverPersistentHeaderDelegate( + // minExtent: kTextTabBarHeight, + // maxExtent: kTextTabBarHeight, + // child: ColoredTabBar( + // tabBar: TabBar( + // controller: _tabController, + // tabs: [ + // Tab(text: S.of(context)!.documents), + // if (context + // .watch() + // .paperlessUser + // .canViewSavedViews) + // Tab(text: S.of(context)!.views), + // ], + // ), + // ), + // ), + // ); + // }, + // ), + // ), + ], + body: NotificationListener( + onNotification: (notification) { + final metrics = notification.metrics; + if (metrics.maxScrollExtent == 0) { + return true; } + final desiredTab = + (metrics.pixels / metrics.maxScrollExtent) + .round(); + if (metrics.axis == Axis.horizontal && + _currentTab != desiredTab) { + setState(() => _currentTab = desiredTab); + } + return false; }, + child: TabBarView( + controller: _tabController, + physics: context + .watch() + .state + .selection + .isNotEmpty + ? const NeverScrollableScrollPhysics() + : null, + children: [ + Builder( + builder: (context) { + return _buildDocumentsTab( + connectivityState, + context, + ); + }, + ), + if (context + .watch() + .paperlessUser + .canViewSavedViews) + Builder( + builder: (context) { + return _buildSavedViewsTab( + connectivityState, + context, + ); + }, + ), + ], + ), ), ), - SliverOverlapAbsorber( - handle: tabBarHandle, - sliver: BlocBuilder( - builder: (context, state) { - if (state.selection.isNotEmpty) { - return const SliverToBoxAdapter( - child: SizedBox.shrink(), - ); - } - return SliverPersistentHeader( - pinned: true, - delegate: - CustomizableSliverPersistentHeaderDelegate( - minExtent: kTextTabBarHeight, - maxExtent: kTextTabBarHeight, - child: ColoredTabBar( - tabBar: TabBar( - controller: _tabController, - tabs: [ - Tab(text: S.of(context)!.documents), - if (context - .watch() - .paperlessUser - .canViewSavedViews) - Tab(text: S.of(context)!.views), - ], + AnimatedOpacity( + opacity: hasSelectedViewChanged ? 1 : 0, + duration: const Duration(milliseconds: 300), + child: Align( + alignment: Alignment.bottomCenter, + child: Container( + margin: const EdgeInsets.only(bottom: 24), + child: Material( + borderRadius: BorderRadius.circular(24), + color: Theme.of(context) + .colorScheme + .surfaceVariant + .withOpacity(0.9), + child: InkWell( + customBorder: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(24), + ), + onTap: () {}, + child: Padding( + padding: EdgeInsets.fromLTRB(16, 8, 16, 8), + child: Text( + "Update selected view", + style: Theme.of(context).textTheme.labelLarge, ), ), ), - ); - }, + ), + ), ), ), ], - body: NotificationListener( - onNotification: (notification) { - final metrics = notification.metrics; - if (metrics.maxScrollExtent == 0) { - return true; - } - final desiredTab = - (metrics.pixels / metrics.maxScrollExtent).round(); - if (metrics.axis == Axis.horizontal && - _currentTab != desiredTab) { - setState(() => _currentTab = desiredTab); - } - return false; - }, - child: TabBarView( - controller: _tabController, - physics: context - .watch() - .state - .selection - .isNotEmpty - ? const NeverScrollableScrollPhysics() - : null, - children: [ - Builder( - builder: (context) { - return _buildDocumentsTab( - connectivityState, - context, - ); - }, - ), - if (context - .watch() - .paperlessUser - .canViewSavedViews) - Builder( - builder: (context) { - return _buildSavedViewsTab( - connectivityState, - context, - ); - }, - ), - ], - ), - ), ), ), ), @@ -315,12 +372,12 @@ class _DocumentsPageState extends State notificationPredicate: (_) => connectivityState.isConnected, child: CustomScrollView( key: const PageStorageKey("savedViews"), - slivers: [ + slivers: [ SliverOverlapInjector( handle: searchBarHandle, ), SliverOverlapInjector( - handle: tabBarHandle, + handle: savedViewsHandle, ), const SavedViewList(), ], @@ -370,15 +427,40 @@ class _DocumentsPageState extends State key: const PageStorageKey("documents"), slivers: [ SliverOverlapInjector(handle: searchBarHandle), - SliverOverlapInjector(handle: tabBarHandle), - _buildViewActions(), + SliverOverlapInjector(handle: savedViewsHandle), + BlocBuilder( + buildWhen: (previous, current) => + previous.filter != current.filter, + builder: (context, state) { + return SliverToBoxAdapter( + child: SavedViewsWidget( + onViewSelected: (view) { + final cubit = context.read(); + if (state.filter.selectedView == view.id) { + _onResetFilter(); + } else { + cubit.updateFilter( + filter: view.toDocumentFilter(), + ); + } + }, + onUpdateView: (view) async { + await context.read().update(view); + showSnackBar(context, + "Saved view successfully updated."); //TODO: INTL + }, + filter: state.filter, + ), + ); + }, + ), BlocBuilder( builder: (context, state) { if (state.hasLoaded && state.documents.isEmpty) { return SliverToBoxAdapter( child: DocumentsEmptyState( state: state, - onReset: context.read().resetFilter, + onReset: _onResetFilter, ), ); } @@ -413,10 +495,12 @@ class _DocumentsPageState extends State } Widget _buildViewActions() { - return SliverToBoxAdapter( - child: BlocBuilder( - builder: (context, state) { - return Row( + return BlocBuilder( + builder: (context, state) { + return Container( + padding: EdgeInsets.all(4), + color: Theme.of(context).colorScheme.background, + child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ SortDocumentsButton( @@ -427,21 +511,22 @@ class _DocumentsPageState extends State onChanged: context.read().setViewType, ), ], - ); - }, - ).paddedSymmetrically(horizontal: 8, vertical: 4), + ), + ); + }, ); } void _onCreateSavedView(DocumentFilter filter) async { - final newView = await pushAddSavedViewRoute(context, filter: filter); - if (newView != null) { - try { - await context.read().add(newView); - } on PaperlessApiException catch (error, stackTrace) { - showErrorMessage(context, error, stackTrace); - } - } + //TODO: Implement + // final newView = await pushAddSavedViewRoute(context, filter: filter); + // if (newView != null) { + // try { + // await context.read().add(newView); + // } on PaperlessApiException catch (error, stackTrace) { + // showErrorMessage(context, error, stackTrace); + // } + // } } void _openDocumentFilter() async { @@ -485,7 +570,7 @@ class _DocumentsPageState extends State if (filterIntent != null) { try { if (filterIntent.shouldReset) { - await context.read().resetFilter(); + await _onResetFilter(); } else { await context .read() @@ -651,4 +736,40 @@ class _DocumentsPageState extends State showErrorMessage(context, error, stackTrace); } } + + Future _onResetFilter() async { + final cubit = context.read(); + final savedViewCubit = context.read(); + final activeView = savedViewCubit.state.maybeMap( + loaded: (state) { + if (cubit.state.filter.selectedView != null) { + return state.savedViews[cubit.state.filter.selectedView!]; + } + return null; + }, + orElse: () => null, + ); + final viewHasChanged = activeView != null && + activeView.toDocumentFilter() != cubit.state.filter; + if (viewHasChanged) { + final discardChanges = await showDialog( + context: context, + builder: (context) => SavedViewChangedDialog(), + ); + if (discardChanges == true) { + cubit.resetFilter(); + // Reset + } else if (discardChanges == false) { + final newView = activeView.copyWith( + filterRules: FilterRule.fromFilter(cubit.state.filter), + ); + final savedViewCubit2 = context.read(); + + await savedViewCubit2.update(newView); + showSnackBar(context, "Saved view successfully updated."); + } + } else { + cubit.resetFilter(); + } + } } diff --git a/lib/features/documents/view/widgets/saved_views/saved_view_changed_dialog.dart b/lib/features/documents/view/widgets/saved_views/saved_view_changed_dialog.dart new file mode 100644 index 0000000..4db26ed --- /dev/null +++ b/lib/features/documents/view/widgets/saved_views/saved_view_changed_dialog.dart @@ -0,0 +1,33 @@ +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 SavedViewChangedDialog extends StatelessWidget { + const SavedViewChangedDialog({super.key}); + + @override + Widget build(BuildContext context) { + return AlertDialog( + title: Text("Discard changes?"), //TODO: INTL + content: Text( + "Some filters of the currently active view have changed. By resetting the filter, these changes will be lost. Do you still wish to continue?", //TODO: INTL + ), + actionsOverflowButtonSpacing: 8, + actions: [ + const DialogCancelButton(), + TextButton( + child: Text(S.of(context)!.saveChanges), + onPressed: () { + Navigator.pop(context, false); + }, + ), + DialogConfirmButton( + label: S.of(context)!.resetFilter, + style: DialogConfirmButtonStyle.danger, + returnValue: true, + ), + ], + ); + } +} diff --git a/lib/features/documents/view/widgets/saved_views/saved_view_chip.dart b/lib/features/documents/view/widgets/saved_views/saved_view_chip.dart new file mode 100644 index 0000000..399e39f --- /dev/null +++ b/lib/features/documents/view/widgets/saved_views/saved_view_chip.dart @@ -0,0 +1,43 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; +import 'package:paperless_api/paperless_api.dart'; + +class SavedViewChip extends StatelessWidget { + final SavedView view; + final void Function(SavedView view) onViewSelected; + final void Function(SavedView vie) onUpdateView; + final bool selected; + final bool hasChanged; + + const SavedViewChip({ + super.key, + required this.view, + required this.onViewSelected, + required this.selected, + required this.hasChanged, + required this.onUpdateView, + }); + + @override + Widget build(BuildContext context) { + return Badge( + smallSize: 12, + alignment: const AlignmentDirectional(1.1, -1.2), + backgroundColor: Colors.red, + isLabelVisible: hasChanged, + child: FilterChip( + avatar: Icon( + Icons.saved_search, + color: Theme.of(context).colorScheme.onSurface, + ), + showCheckmark: false, + selectedColor: Theme.of(context).colorScheme.primaryContainer, + selected: selected, + label: Text(view.name), + onSelected: (_) { + onViewSelected(view); + }, + ), + ); + } +} diff --git a/lib/features/documents/view/widgets/saved_views/saved_views_widget.dart b/lib/features/documents/view/widgets/saved_views/saved_views_widget.dart new file mode 100644 index 0000000..28c4b09 --- /dev/null +++ b/lib/features/documents/view/widgets/saved_views/saved_views_widget.dart @@ -0,0 +1,58 @@ +import 'package:flutter/widgets.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:paperless_api/paperless_api.dart'; +import 'package:paperless_mobile/features/documents/view/widgets/saved_views/saved_view_chip.dart'; +import 'package:paperless_mobile/features/saved_view/cubit/saved_view_cubit.dart'; + +class SavedViewsWidget extends StatelessWidget { + final void Function(SavedView view) onViewSelected; + final void Function(SavedView view) onUpdateView; + final DocumentFilter filter; + const SavedViewsWidget({ + super.key, + required this.onViewSelected, + required this.filter, + required this.onUpdateView, + }); + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.only( + top: 12, + left: 16, + right: 16, + ), + height: 50, + child: BlocBuilder( + builder: (context, state) { + return state.maybeWhen( + loaded: (savedViews) { + if (savedViews.isEmpty) { + return Text("No saved views"); + } + return ListView.builder( + scrollDirection: Axis.horizontal, + itemBuilder: (context, index) { + final view = savedViews.values.elementAt(index); + return SavedViewChip( + view: view, + onUpdateView: onUpdateView, + onViewSelected: onViewSelected, + selected: filter.selectedView != null && + view.id == filter.selectedView, + hasChanged: filter.selectedView == view.id && + filter != view.toDocumentFilter(), + ); + }, + itemCount: savedViews.length, + ); + }, + error: () => Text("Error loading saved views"), + orElse: () => Placeholder(), + ); + }, + ), + ); + } +} 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 29cb7a0..30813a9 100644 --- a/lib/features/documents/view/widgets/search/document_filter_form.dart +++ b/lib/features/documents/view/widgets/search/document_filter_form.dart @@ -19,10 +19,12 @@ class DocumentFilterForm extends StatefulWidget { static const fkAddedAt = DocumentModel.addedKey; static DocumentFilter assembleFilter( - GlobalKey formKey, DocumentFilter initialFilter) { + GlobalKey formKey, + DocumentFilter initialFilter, + ) { formKey.currentState?.save(); final v = formKey.currentState!.value; - return DocumentFilter( + return initialFilter.copyWith( correspondent: v[DocumentFilterForm.fkCorrespondent] as IdQueryParameter? ?? DocumentFilter.initial.correspondent, @@ -36,11 +38,7 @@ class DocumentFilterForm extends StatefulWidget { DocumentFilter.initial.query, created: (v[DocumentFilterForm.fkCreatedAt] as DateRangeQuery), added: (v[DocumentFilterForm.fkAddedAt] as DateRangeQuery), - asnQuery: initialFilter.asnQuery, page: 1, - pageSize: initialFilter.pageSize, - sortField: initialFilter.sortField, - sortOrder: initialFilter.sortOrder, ); } diff --git a/lib/features/home/view/scaffold_with_navigation_bar.dart b/lib/features/home/view/scaffold_with_navigation_bar.dart index fab2344..afc50b0 100644 --- a/lib/features/home/view/scaffold_with_navigation_bar.dart +++ b/lib/features/home/view/scaffold_with_navigation_bar.dart @@ -5,7 +5,6 @@ import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/features/app_drawer/view/app_drawer.dart'; import 'package:paperless_mobile/features/inbox/cubit/inbox_cubit.dart'; import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; -import 'package:paperless_mobile/helpers/message_helpers.dart'; const _landingPage = 0; const _documentsIndex = 1; @@ -30,134 +29,123 @@ class ScaffoldWithNavigationBar extends StatefulWidget { class ScaffoldWithNavigationBarState extends State { @override Widget build(BuildContext context) { - final disabledColor = Theme.of(context).disabledColor; final primaryColor = Theme.of(context).colorScheme.primary; + return Scaffold( drawer: const AppDrawer(), bottomNavigationBar: NavigationBar( selectedIndex: widget.navigationShell.currentIndex, onDestinationSelected: (index) { - switch (index) { - case _landingPage: - widget.navigationShell.goBranch(index); - break; - case _documentsIndex: - if (widget.authenticatedUser.canViewDocuments) { - widget.navigationShell.goBranch(index); - } else { - showSnackBar(context, S.of(context)!.missingPermissions); - } - break; - case _scannerIndex: - if (widget.authenticatedUser.canCreateDocuments) { - widget.navigationShell.goBranch(index); - } else { - showSnackBar(context, S.of(context)!.missingPermissions); - } - break; - case _labelsIndex: - if (widget.authenticatedUser.canViewAnyLabel) { - widget.navigationShell.goBranch(index); - } else { - showSnackBar(context, S.of(context)!.missingPermissions); - } - break; - case _inboxIndex: - if (widget.authenticatedUser.canViewDocuments && - widget.authenticatedUser.canViewTags) { - widget.navigationShell.goBranch(index); - } else { - showSnackBar(context, S.of(context)!.missingPermissions); - } - break; - default: - break; - } + widget.navigationShell.goBranch( + index, + initialLocation: index == widget.navigationShell.currentIndex, + ); }, destinations: [ NavigationDestination( - icon: Icon(Icons.home_outlined), + icon: const Icon(Icons.home_outlined), selectedIcon: Icon( Icons.home, color: primaryColor, ), label: "Home", //TODO: INTL ), - NavigationDestination( - icon: Icon( - Icons.description_outlined, - color: !widget.authenticatedUser.canViewDocuments - ? disabledColor - : null, + _toggleDestination( + NavigationDestination( + icon: const Icon(Icons.description_outlined), + selectedIcon: Icon( + Icons.description, + color: primaryColor, + ), + label: S.of(context)!.documents, ), - selectedIcon: Icon( - Icons.description, - color: primaryColor, - ), - label: S.of(context)!.documents, + disableWhen: !widget.authenticatedUser.canViewDocuments, ), - NavigationDestination( - icon: Icon( - Icons.document_scanner_outlined, - color: !widget.authenticatedUser.canCreateDocuments - ? disabledColor - : null, + _toggleDestination( + NavigationDestination( + icon: const Icon(Icons.document_scanner_outlined), + selectedIcon: Icon( + Icons.document_scanner, + color: primaryColor, + ), + label: S.of(context)!.scanner, ), - selectedIcon: Icon( - Icons.document_scanner, - color: primaryColor, - ), - label: S.of(context)!.scanner, + disableWhen: !widget.authenticatedUser.canCreateDocuments, ), - NavigationDestination( - icon: Icon( - Icons.sell_outlined, - color: !widget.authenticatedUser.canViewAnyLabel - ? disabledColor - : null, + _toggleDestination( + NavigationDestination( + icon: const Icon(Icons.sell_outlined), + selectedIcon: Icon( + Icons.sell, + color: primaryColor, + ), + label: S.of(context)!.labels, ), - selectedIcon: Icon( - Icons.sell, - color: primaryColor, - ), - label: S.of(context)!.labels, + disableWhen: !widget.authenticatedUser.canViewAnyLabel, ), - NavigationDestination( - icon: Builder(builder: (context) { - if (!(widget.authenticatedUser.canViewDocuments && - widget.authenticatedUser.canViewTags)) { - return Icon( - Icons.inbox_outlined, - color: disabledColor, - ); - } - return BlocBuilder( - builder: (context, state) { - return Badge.count( - isLabelVisible: state.itemsInInboxCount > 0, - count: state.itemsInInboxCount, - child: const Icon(Icons.inbox_outlined), + _toggleDestination( + NavigationDestination( + icon: Builder( + builder: (context) { + return BlocBuilder( + builder: (context, state) { + return Badge.count( + isLabelVisible: state.itemsInInboxCount > 0, + count: state.itemsInInboxCount, + child: const Icon(Icons.inbox_outlined), + ); + }, ); }, - ); - }), - selectedIcon: BlocBuilder( - builder: (context, state) { - return Badge.count( - isLabelVisible: state.itemsInInboxCount > 0, - count: state.itemsInInboxCount, - child: Icon( - Icons.inbox, - color: primaryColor, - ), - ); - }, + ), + selectedIcon: BlocBuilder( + builder: (context, state) { + return Badge.count( + isLabelVisible: state.itemsInInboxCount > 0 && + widget.authenticatedUser.canViewInbox, + count: state.itemsInInboxCount, + child: Icon( + Icons.inbox, + color: primaryColor, + ), + ); + }, + ), + label: S.of(context)!.inbox, ), - label: S.of(context)!.inbox, + disableWhen: !widget.authenticatedUser.canViewInbox, ), ], ), body: widget.navigationShell, ); } + + Widget _toggleDestination( + Widget destination, { + required bool disableWhen, + }) { + final disabledColor = Theme.of(context).disabledColor; + + final disabledTheme = Theme.of(context).navigationBarTheme.copyWith( + labelTextStyle: MaterialStatePropertyAll( + Theme.of(context) + .textTheme + .labelSmall + ?.copyWith(color: disabledColor), + ), + iconTheme: MaterialStatePropertyAll( + Theme.of(context).iconTheme.copyWith(color: disabledColor), + ), + ); + if (disableWhen) { + return AbsorbPointer( + child: Theme( + data: Theme.of(context).copyWith(navigationBarTheme: disabledTheme), + child: destination, + ), + ); + } + return destination; + } } diff --git a/lib/features/landing/view/landing_page.dart b/lib/features/landing/view/landing_page.dart index b8a1921..7767dbf 100644 --- a/lib/features/landing/view/landing_page.dart +++ b/lib/features/landing/view/landing_page.dart @@ -51,44 +51,58 @@ class _LandingPageState extends State { ).padded(24), ), SliverToBoxAdapter(child: _buildStatisticsCard(context)), - SliverPadding( - padding: const EdgeInsets.fromLTRB(16, 16, 0, 8), - sliver: SliverToBoxAdapter( - child: Text( - "Saved Views", - style: Theme.of(context).textTheme.titleMedium, + if (currentUser.canViewSavedViews) ...[ + SliverPadding( + padding: const EdgeInsets.fromLTRB(16, 16, 0, 8), + sliver: SliverToBoxAdapter( + child: Text( + "Saved Views", + style: Theme.of(context).textTheme.titleMedium, + ), ), ), - ), - BlocBuilder( - builder: (context, state) { - return state.maybeWhen( - loaded: (savedViews) { - final dashboardViews = savedViews.values - .where((element) => element.showOnDashboard) - .toList(); - if (dashboardViews.isEmpty) { - return const SliverToBoxAdapter( - child: Text("No views"), - ); - } - return SliverList.builder( - itemBuilder: (context, index) { - return SavedViewPreview( - savedView: dashboardViews.elementAt(index), + BlocBuilder( + builder: (context, state) { + return state.maybeWhen( + loaded: (savedViews) { + final dashboardViews = savedViews.values + .where((element) => element.showOnDashboard) + .toList(); + if (dashboardViews.isEmpty) { + return SliverToBoxAdapter( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "There are no saved views to show on your dashboard.", //TODO: INTL + ), + TextButton.icon( + onPressed: () {}, + icon: const Icon(Icons.add), + label: Text("Add new view"), + ) + ], + ).paddedOnly(left: 16), ); - }, - itemCount: dashboardViews.length, - ); - }, - orElse: () => const SliverToBoxAdapter( - child: Center( - child: CircularProgressIndicator(), + } + return SliverList.builder( + itemBuilder: (context, index) { + return SavedViewPreview( + savedView: dashboardViews.elementAt(index), + ); + }, + itemCount: dashboardViews.length, + ); + }, + orElse: () => const SliverToBoxAdapter( + child: Center( + child: CircularProgressIndicator(), + ), ), - ), - ); - }, - ) + ); + }, + ), + ], ], ), ), @@ -121,6 +135,7 @@ class _LandingPageState extends State { } final stats = snapshot.data!; return ExpansionCard( + initiallyExpanded: false, title: Text( "Statistics", //TODO: INTL style: Theme.of(context).textTheme.titleLarge, diff --git a/lib/features/paged_document_view/cubit/document_paging_bloc_mixin.dart b/lib/features/paged_document_view/cubit/document_paging_bloc_mixin.dart index 4d7ed16..33b43b5 100644 --- a/lib/features/paged_document_view/cubit/document_paging_bloc_mixin.dart +++ b/lib/features/paged_document_view/cubit/document_paging_bloc_mixin.dart @@ -68,7 +68,7 @@ mixin DocumentPagingBlocMixin /// Convenience method which allows to directly use [DocumentFilter.copyWith] on the current filter. /// Future updateCurrentFilter( - final DocumentFilter Function(DocumentFilter) transformFn, + final DocumentFilter Function(DocumentFilter filter) transformFn, ) async => updateFilter(filter: transformFn(state.filter)); diff --git a/lib/features/saved_view/cubit/saved_view_cubit.dart b/lib/features/saved_view/cubit/saved_view_cubit.dart index 9215c2c..c35d235 100644 --- a/lib/features/saved_view/cubit/saved_view_cubit.dart +++ b/lib/features/saved_view/cubit/saved_view_cubit.dart @@ -35,6 +35,10 @@ class SavedViewCubit extends Cubit { return _savedViewRepository.delete(view); } + Future update(SavedView view) async { + return await _savedViewRepository.update(view); + } + Future reload() async { final views = await _savedViewRepository.findAll(); final values = {for (var element in views) element.id!: element}; diff --git a/lib/features/saved_view/view/add_saved_view_page.dart b/lib/features/saved_view/view/add_saved_view_page.dart index e24ad87..07a6613 100644 --- a/lib/features/saved_view/view/add_saved_view_page.dart +++ b/lib/features/saved_view/view/add_saved_view_page.dart @@ -1,25 +1,15 @@ import 'package:flutter/material.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:go_router/go_router.dart'; - import 'package:paperless_api/paperless_api.dart'; -import 'package:paperless_mobile/extensions/flutter_extensions.dart'; import 'package:paperless_mobile/features/documents/view/widgets/search/document_filter_form.dart'; import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; class AddSavedViewPage extends StatefulWidget { - final DocumentFilter currentFilter; - final Map correspondents; - final Map documentTypes; - final Map tags; - final Map storagePaths; + final DocumentFilter? initialFilter; const AddSavedViewPage({ super.key, - required this.currentFilter, - required this.correspondents, - required this.documentTypes, - required this.tags, - required this.storagePaths, + this.initialFilter, }); @override @@ -81,21 +71,6 @@ class _AddSavedViewPageState extends State { ), ), const Divider(), - Text( - "Review filter", - style: Theme.of(context).textTheme.bodyLarge, - ).padded(), - Flexible( - child: DocumentFilterForm( - padding: const EdgeInsets.symmetric(vertical: 8), - formKey: _filterFormKey, - initialFilter: widget.currentFilter, - correspondents: widget.correspondents, - documentTypes: widget.documentTypes, - storagePaths: widget.storagePaths, - tags: widget.tags, - ), - ), ], ), ), @@ -104,19 +79,19 @@ class _AddSavedViewPageState extends State { void _onCreate(BuildContext context) { if (_savedViewFormKey.currentState?.saveAndValidate() ?? false) { - context.pop( - SavedView.fromDocumentFilter( - DocumentFilterForm.assembleFilter( - _filterFormKey, - widget.currentFilter, - ), - name: _savedViewFormKey.currentState?.value[fkName] as String, - showOnDashboard: - _savedViewFormKey.currentState?.value[fkShowOnDashboard] as bool, - showInSidebar: - _savedViewFormKey.currentState?.value[fkShowInSidebar] as bool, - ), - ); + // context.pop( + // SavedView.fromDocumentFilter( + // DocumentFilterForm.assembleFilter( + // _filterFormKey, + // widget.currentFilter, + // ), + // name: _savedViewFormKey.currentState?.value[fkName] as String, + // showOnDashboard: + // _savedViewFormKey.currentState?.value[fkShowOnDashboard] as bool, + // showInSidebar: + // _savedViewFormKey.currentState?.value[fkShowInSidebar] as bool, + // ), + // ); } } } diff --git a/lib/features/saved_view_details/view/saved_view_preview.dart b/lib/features/saved_view_details/view/saved_view_preview.dart index 2571f3a..6dac4af 100644 --- a/lib/features/saved_view_details/view/saved_view_preview.dart +++ b/lib/features/saved_view_details/view/saved_view_preview.dart @@ -1,10 +1,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:paperless_api/paperless_api.dart'; +import 'package:paperless_mobile/extensions/flutter_extensions.dart'; import 'package:paperless_mobile/features/documents/cubit/documents_cubit.dart'; import 'package:paperless_mobile/features/documents/view/widgets/items/document_list_item.dart'; import 'package:paperless_mobile/features/landing/view/widgets/expansion_card.dart'; import 'package:paperless_mobile/features/saved_view_details/cubit/saved_view_preview_cubit.dart'; +import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; import 'package:paperless_mobile/routes/typed/branches/documents_route.dart'; import 'package:provider/provider.dart'; @@ -30,27 +32,26 @@ class SavedViewPreview extends StatelessWidget { loaded: (documents) { return Column( children: [ - for (final document in documents) - DocumentListItem( - document: document, - isLabelClickable: false, - isSelected: false, - isSelectionActive: false, - onTap: (document) { - DocumentDetailsRoute($extra: document) - .push(context); - }, - ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - TextButton( - child: Text("Show"), - onPressed: documents.length >= 5 ? () {} : null, + if (documents.isEmpty) + Text("This view is empty.").padded() + else + for (final document in documents) + DocumentListItem( + document: document, + isLabelClickable: false, + isSelected: false, + isSelectionActive: false, + onTap: (document) { + DocumentDetailsRoute($extra: document) + .push(context); + }, ), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ TextButton.icon( - icon: Icon(Icons.open_in_new), - label: Text("Show in documents"), + icon: const Icon(Icons.open_in_new), + label: Text("Show all"), //TODO: INTL onPressed: () { context.read().updateFilter( filter: savedView.toDocumentFilter(), diff --git a/lib/main.dart b/lib/main.dart index 8b7a1e9..dfc2669 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -192,11 +192,6 @@ class GoRouterShell extends StatefulWidget { } class _GoRouterShellState extends State { - @override - void didChangeDependencies() { - super.didChangeDependencies(); - } - @override void initState() { super.initState(); diff --git a/lib/routes/typed/branches/saved_views_route.dart b/lib/routes/typed/branches/saved_views_route.dart new file mode 100644 index 0000000..2967e54 --- /dev/null +++ b/lib/routes/typed/branches/saved_views_route.dart @@ -0,0 +1,25 @@ +import 'package:flutter/src/widgets/framework.dart'; +import 'package:go_router/go_router.dart'; +import 'package:paperless_api/paperless_api.dart'; +import 'package:paperless_mobile/features/saved_view/view/add_saved_view_page.dart'; + +@TypedGoRoute(path: "/saved-views", routes: []) +class SavedViewsRoute extends GoRouteData { + const SavedViewsRoute(); +} + +class CreateSavedViewRoute extends GoRouteData { + final DocumentFilter? $extra; + const CreateSavedViewRoute(this.$extra); + + @override + Widget build(BuildContext context, GoRouterState state) { + return AddSavedViewPage( + initialFilter: $extra, + ); + } +} + +class EditSavedViewRoute extends GoRouteData { + const EditSavedViewRoute(); +} diff --git a/packages/paperless_api/lib/src/models/document_filter.dart b/packages/paperless_api/lib/src/models/document_filter.dart index ca2becd..19ceea3 100644 --- a/packages/paperless_api/lib/src/models/document_filter.dart +++ b/packages/paperless_api/lib/src/models/document_filter.dart @@ -63,6 +63,9 @@ class DocumentFilter extends Equatable { @HiveField(13) final int? moreLike; + @HiveField(14) + final int? selectedView; + const DocumentFilter({ this.documentType = const IdQueryParameter.unset(), this.correspondent = const IdQueryParameter.unset(), @@ -78,6 +81,7 @@ class DocumentFilter extends Equatable { this.created = const UnsetDateRangeQuery(), this.modified = const UnsetDateRangeQuery(), this.moreLike, + this.selectedView, }); bool get forceExtendedQuery { @@ -143,6 +147,7 @@ class DocumentFilter extends Equatable { DateRangeQuery? modified, TextQuery? query, int? Function()? moreLike, + int? Function()? selectedView, }) { final newFilter = DocumentFilter( pageSize: pageSize ?? this.pageSize, @@ -159,6 +164,7 @@ class DocumentFilter extends Equatable { created: created ?? this.created, modified: modified ?? this.modified, moreLike: moreLike != null ? moreLike.call() : this.moreLike, + selectedView: selectedView != null ? selectedView.call() : this.selectedView, ); if (query?.queryType != QueryType.extended && newFilter.forceExtendedQuery) { @@ -244,6 +250,8 @@ class DocumentFilter extends Equatable { created, modified, query, + moreLike, + selectedView, ]; factory DocumentFilter.fromJson(Map json) => diff --git a/packages/paperless_api/lib/src/models/exception/paperless_server_message_exception.dart b/packages/paperless_api/lib/src/models/exception/paperless_server_message_exception.dart index 1cad789..b4794ea 100644 --- a/packages/paperless_api/lib/src/models/exception/paperless_server_message_exception.dart +++ b/packages/paperless_api/lib/src/models/exception/paperless_server_message_exception.dart @@ -8,8 +8,12 @@ class PaperlessServerMessageException implements Exception { PaperlessServerMessageException(this.detail); - static bool canParse(Map json) { - return json.containsKey('detail') && json.length == 1; + static bool canParse(dynamic json) { + if (json is Map) { + return json.containsKey('detail') && json.length == 1; + } else { + return false; + } } factory PaperlessServerMessageException.fromJson(Map json) => diff --git a/packages/paperless_api/lib/src/models/paperless_api_exception.dart b/packages/paperless_api/lib/src/models/paperless_api_exception.dart index ac5fc02..adaa874 100644 --- a/packages/paperless_api/lib/src/models/paperless_api_exception.dart +++ b/packages/paperless_api/lib/src/models/paperless_api_exception.dart @@ -54,5 +54,18 @@ enum ErrorCode { unsupportedFileFormat, missingClientCertificate, acknowledgeTasksError, - correspondentDeleteFailed, documentTypeDeleteFailed, tagDeleteFailed, correspondentUpdateFailed, documentTypeUpdateFailed, tagUpdateFailed, storagePathDeleteFailed, storagePathUpdateFailed, serverInformationLoadFailed, serverStatisticsLoadFailed, uiSettingsLoadFailed, loadTasksError, userNotFound; + correspondentDeleteFailed, + documentTypeDeleteFailed, + tagDeleteFailed, + correspondentUpdateFailed, + documentTypeUpdateFailed, + tagUpdateFailed, + storagePathDeleteFailed, + storagePathUpdateFailed, + serverInformationLoadFailed, + serverStatisticsLoadFailed, + uiSettingsLoadFailed, + loadTasksError, + userNotFound, + updateSavedViewError; } diff --git a/packages/paperless_api/lib/src/models/permissions/user_permission_extension.dart b/packages/paperless_api/lib/src/models/permissions/user_permission_extension.dart index 0a6921f..d6a0186 100644 --- a/packages/paperless_api/lib/src/models/permissions/user_permission_extension.dart +++ b/packages/paperless_api/lib/src/models/permissions/user_permission_extension.dart @@ -87,4 +87,6 @@ extension UserPermissionExtension on UserModel { canViewDocumentTypes || canViewTags || canViewStoragePaths; + + bool get canViewInbox => canViewTags && canViewDocuments; } diff --git a/packages/paperless_api/lib/src/models/saved_view_model.dart b/packages/paperless_api/lib/src/models/saved_view_model.dart index ae89590..2918f28 100644 --- a/packages/paperless_api/lib/src/models/saved_view_model.dart +++ b/packages/paperless_api/lib/src/models/saved_view_model.dart @@ -50,11 +50,32 @@ class SavedView with EquatableMixin { Map toJson() => _$SavedViewToJson(this); + SavedView copyWith({ + int? id, + String? name, + bool? showOnDashboard, + bool? showInSidebar, + SortField? sortField, + bool? sortReverse, + List? filterRules, + }) { + return SavedView( + id: id ?? this.id, + name: name ?? this.name, + showOnDashboard: showOnDashboard ?? this.showOnDashboard, + showInSidebar: showInSidebar ?? this.showInSidebar, + sortField: sortField ?? this.sortField, + sortReverse: sortReverse ?? this.sortReverse, + filterRules: filterRules ?? this.filterRules, + ); + } + DocumentFilter toDocumentFilter() { return filterRules.fold( DocumentFilter( sortOrder: sortReverse ? SortOrder.descending : SortOrder.ascending, sortField: sortField, + selectedView: id, ), (filter, filterRule) => filterRule.applyToFilter(filter), ); diff --git a/packages/paperless_api/lib/src/modules/authentication_api/authentication_api_impl.dart b/packages/paperless_api/lib/src/modules/authentication_api/authentication_api_impl.dart index fb7e9f2..631fbc3 100644 --- a/packages/paperless_api/lib/src/modules/authentication_api/authentication_api_impl.dart +++ b/packages/paperless_api/lib/src/modules/authentication_api/authentication_api_impl.dart @@ -1,6 +1,6 @@ import 'package:dio/dio.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_api/src/extensions/dio_exception_extension.dart'; -import 'package:paperless_api/src/modules/authentication_api/authentication_api.dart'; class PaperlessAuthenticationApiImpl implements PaperlessAuthenticationApi { final Dio client; @@ -20,10 +20,19 @@ class PaperlessAuthenticationApiImpl implements PaperlessAuthenticationApi { "password": password, }, options: Options( - validateStatus: (status) => status == 200, + followRedirects: false, + headers: { + "Accept": "application/json", + }, + validateStatus: (status) { + return status! == 200; + }, ), ); return response.data['token']; + // } else if (response.statusCode == 302) { + // final redirectUrl = response.headers.value("location"); + // return AuthenticationTemporaryRedirect(redirectUrl!); } on DioException catch (exception) { throw exception.unravel(); } diff --git a/packages/paperless_api/lib/src/modules/saved_views_api/paperless_saved_views_api.dart b/packages/paperless_api/lib/src/modules/saved_views_api/paperless_saved_views_api.dart index 8628cdd..ef483cf 100644 --- a/packages/paperless_api/lib/src/modules/saved_views_api/paperless_saved_views_api.dart +++ b/packages/paperless_api/lib/src/modules/saved_views_api/paperless_saved_views_api.dart @@ -6,4 +6,7 @@ abstract class PaperlessSavedViewsApi { Future save(SavedView view); Future delete(SavedView view); + + /// Since API V3 + Future update(SavedView view); } diff --git a/packages/paperless_api/lib/src/modules/saved_views_api/paperless_saved_views_api_impl.dart b/packages/paperless_api/lib/src/modules/saved_views_api/paperless_saved_views_api_impl.dart index 976ba1c..88512e5 100644 --- a/packages/paperless_api/lib/src/modules/saved_views_api/paperless_saved_views_api_impl.dart +++ b/packages/paperless_api/lib/src/modules/saved_views_api/paperless_saved_views_api_impl.dart @@ -41,6 +41,22 @@ class PaperlessSavedViewsApiImpl implements PaperlessSavedViewsApi { } } + @override + Future update(SavedView view) async { + try { + final response = await _client.patch( + "/api/saved_views/${view.id}/", + data: view.toJson(), + options: Options(validateStatus: (status) => status == 200), + ); + return SavedView.fromJson(response.data); + } on DioException catch (exception) { + throw exception.unravel( + orElse: const PaperlessApiException(ErrorCode.updateSavedViewError), + ); + } + } + @override Future delete(SavedView view) async { try { diff --git a/packages/paperless_document_scanner/example/pubspec.lock b/packages/paperless_document_scanner/example/pubspec.lock index a5c1778..433f843 100644 --- a/packages/paperless_document_scanner/example/pubspec.lock +++ b/packages/paperless_document_scanner/example/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: archive - sha256: "0c8368c9b3f0abbc193b9d6133649a614204b528982bebc7026372d61677ce3a" + sha256: e0902a06f0e00414e4e3438a084580161279f137aeb862274710f29ec10cf01e url: "https://pub.dev" source: hosted - version: "3.3.7" + version: "3.3.9" async: dependency: transitive description: @@ -29,42 +29,42 @@ packages: dependency: "direct main" description: name: camera - sha256: ebebead3d5ec3d148249331d751d462d7e8c98102b8830a9b45ec96a2bd4333f + sha256: f63f2687fb1795c36f7c57b18a03071880eabb0fd8b5291b0fcd3fb979cb0fb1 url: "https://pub.dev" source: hosted - version: "0.10.5+2" + version: "0.10.5+4" camera_android: dependency: transitive description: name: camera_android - sha256: f43d07f9d7228ea1ca87d22e30881bd68da4b78484a1fbd1f1408b412a41cefb + sha256: ed4f645848074166fc3b8e20350f83ca07e09a2becc1e185040ee561f955d4df url: "https://pub.dev" source: hosted - version: "0.10.8+3" + version: "0.10.8+8" camera_avfoundation: dependency: transitive description: name: camera_avfoundation - sha256: "1a416e452b30955b392f4efbf23291d3f2ba3660a85e1628859eb62d2a2bab26" + sha256: "718b60ed2e22b4067fe6e2c0e9ebe2856c2de5c8b1289ba95d10db85b0b00bc2" url: "https://pub.dev" source: hosted - version: "0.9.13+2" + version: "0.9.13+4" camera_platform_interface: dependency: transitive description: name: camera_platform_interface - sha256: "60fa0bb62a4f3bf3a7c413e31e4cd01b69c779ccc8e4668904a24581b86c316b" + sha256: "8734d1c682f034bdb12d0d6ff379b0535a9b8e44266b530025bf8266d6a62f28" url: "https://pub.dev" source: hosted - version: "2.5.1" + version: "2.5.2" camera_web: dependency: transitive description: name: camera_web - sha256: bcbd775fb3a9d51cc3ece899d54ad66f6306410556bac5759f78e13f9228841f + sha256: d4c2c571c7af04f8b10702ca16bb9ed2a26e64534171e8f75c9349b2c004d8f1 url: "https://pub.dev" source: hosted - version: "0.3.1+4" + version: "0.3.2+3" camerawesome: dependency: transitive description: @@ -101,10 +101,10 @@ packages: dependency: transitive description: name: collection - sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" + sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 url: "https://pub.dev" source: hosted - version: "1.17.1" + version: "1.17.2" colorfilter_generator: dependency: transitive description: @@ -125,10 +125,10 @@ packages: dependency: transitive description: name: cross_file - sha256: "0b0036e8cccbfbe0555fd83c1d31a6f30b77a96b598b35a5d36dd41f718695e9" + sha256: fd832b5384d0d6da4f6df60b854d33accaaeb63aa9e10e736a87381f08dee2cb url: "https://pub.dev" source: hosted - version: "0.3.3+4" + version: "0.3.3+5" crypto: dependency: transitive description: @@ -141,10 +141,10 @@ packages: dependency: "direct main" description: name: cupertino_icons - sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be + sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d url: "https://pub.dev" source: hosted - version: "1.0.5" + version: "1.0.6" fake_async: dependency: transitive description: @@ -157,18 +157,10 @@ packages: dependency: transitive description: name: ffi - sha256: ed5337a5660c506388a9f012be0288fb38b49020ce2b45fe1f8b8323fe429f99 + sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" url: "https://pub.dev" source: hosted - version: "2.0.2" - file: - dependency: transitive - description: - name: file - sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" - url: "https://pub.dev" - source: hosted - version: "6.1.4" + version: "2.1.0" flutter: dependency: "direct main" description: flutter @@ -178,18 +170,18 @@ packages: dependency: "direct dev" description: name: flutter_lints - sha256: "2118df84ef0c3ca93f96123a616ae8540879991b8b57af2f81b76a7ada49b2a4" + sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04 url: "https://pub.dev" source: hosted - version: "2.0.2" + version: "2.0.3" flutter_plugin_android_lifecycle: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: "950e77c2bbe1692bc0874fc7fb491b96a4dc340457f4ea1641443d0a6c1ea360" + sha256: f185ac890306b5779ecbd611f52502d8d4d63d27703ef73161ca0407e815f02c url: "https://pub.dev" source: hosted - version: "2.0.15" + version: "2.0.16" flutter_test: dependency: "direct dev" description: flutter @@ -228,18 +220,18 @@ packages: dependency: transitive description: name: matcher - sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" url: "https://pub.dev" source: hosted - version: "0.12.15" + version: "0.12.16" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "0.5.0" matrix2d: dependency: transitive description: @@ -275,50 +267,50 @@ packages: dependency: "direct main" description: name: path_provider - sha256: "3087813781ab814e4157b172f1a11c46be20179fcc9bea043e0fba36bc0acaa2" + sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa url: "https://pub.dev" source: hosted - version: "2.0.15" + version: "2.1.1" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: "2cec049d282c7f13c594b4a73976b0b4f2d7a1838a6dd5aaf7bd9719196bee86" + sha256: "6b8b19bd80da4f11ce91b2d1fb931f3006911477cec227cce23d3253d80df3f1" url: "https://pub.dev" source: hosted - version: "2.0.27" + version: "2.2.0" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "1995d88ec2948dac43edf8fe58eb434d35d22a2940ecee1a9fefcd62beee6eb3" + sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d" url: "https://pub.dev" source: hosted - version: "2.2.3" + version: "2.3.1" path_provider_linux: dependency: transitive description: name: path_provider_linux - sha256: ffbb8cc9ed2c9ec0e4b7a541e56fd79b138e8f47d2fb86815f15358a349b3b57 + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 url: "https://pub.dev" source: hosted - version: "2.1.11" + version: "2.2.1" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface - sha256: "57585299a729335f1298b43245842678cb9f43a6310351b18fb577d6e33165ec" + sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c" url: "https://pub.dev" source: hosted - version: "2.0.6" + version: "2.1.1" path_provider_windows: dependency: transitive description: name: path_provider_windows - sha256: "1cb68ba4cd3a795033de62ba1b7b4564dace301f952de6bfb3cd91b202b6ee96" + sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" url: "https://pub.dev" source: hosted - version: "2.1.7" + version: "2.2.1" petitparser: dependency: transitive description: @@ -331,18 +323,18 @@ packages: dependency: transitive description: name: platform - sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" + sha256: ae68c7bfcd7383af3629daafb32fb4e8681c7154428da4febcff06200585f102 url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.2" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - sha256: "6a2128648c854906c53fa8e33986fc0247a1116122f9534dd20e3ab9e16a32bc" + sha256: da3fdfeccc4d4ff2da8f8c556704c08f912542c5fb3cf2233ed75372384a034d url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.1.6" pointycastle: dependency: transitive description: @@ -351,14 +343,6 @@ packages: url: "https://pub.dev" source: hosted version: "3.7.3" - process: - dependency: transitive - description: - name: process - sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" - url: "https://pub.dev" - source: hosted - version: "4.2.4" quiver: dependency: transitive description: @@ -384,10 +368,10 @@ packages: dependency: transitive description: name: source_span - sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.10.0" stack_trace: dependency: transitive description: @@ -432,10 +416,10 @@ packages: dependency: transitive description: name: test_api - sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb + sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "0.6.0" typed_data: dependency: transitive description: @@ -452,22 +436,30 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + web: + dependency: transitive + description: + name: web + sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 + url: "https://pub.dev" + source: hosted + version: "0.1.4-beta" win32: dependency: transitive description: name: win32 - sha256: dfdf0136e0aa7a1b474ea133e67cb0154a0acd2599c4f3ada3b49d38d38793ee + sha256: "9e82a402b7f3d518fb9c02d0e9ae45952df31b9bf34d77baf19da2de03fc2aaa" url: "https://pub.dev" source: hosted - version: "5.0.5" + version: "5.0.7" xdg_directories: dependency: transitive description: name: xdg_directories - sha256: ee1505df1426458f7f60aac270645098d318a8b4766d85fde75f76f2e21807d1 + sha256: "589ada45ba9e39405c198fe34eb0f607cddb2108527e658136120892beac46d2" url: "https://pub.dev" source: hosted - version: "1.0.0" + version: "1.0.3" xml: dependency: transitive description: @@ -477,5 +469,5 @@ packages: source: hosted version: "6.3.0" sdks: - dart: ">=3.0.0 <4.0.0" - flutter: ">=3.3.0" + dart: ">=3.1.0 <4.0.0" + flutter: ">=3.13.0" diff --git a/pubspec.lock b/pubspec.lock index 7585a75..25656cd 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -29,10 +29,10 @@ packages: dependency: "direct main" description: name: animations - sha256: fe8a6bdca435f718bb1dc8a11661b2c22504c6da40ef934cee8327ed77934164 + sha256: ef57563eed3620bd5d75ad96189846aca1e033c0c45fc9a7d26e80ab02b88a70 url: "https://pub.dev" source: hosted - version: "2.0.7" + version: "2.0.8" ansicolor: dependency: transitive description: @@ -45,10 +45,10 @@ packages: dependency: transitive description: name: archive - sha256: "0c8368c9b3f0abbc193b9d6133649a614204b528982bebc7026372d61677ce3a" + sha256: e0902a06f0e00414e4e3438a084580161279f137aeb862274710f29ec10cf01e url: "https://pub.dev" source: hosted - version: "3.3.7" + version: "3.3.9" args: dependency: transitive description: @@ -101,10 +101,10 @@ packages: dependency: transitive description: name: bidi - sha256: "6794b226bc939731308b8539c49bb6c2fdbf0e78c3a65e9b9e81e727c256dfe6" + sha256: "2c162a66885167f1f92c41583efea9a435cb268d58322ba266613b9582440f87" url: "https://pub.dev" source: hosted - version: "2.0.7" + version: "2.0.8" bloc: dependency: transitive description: @@ -117,10 +117,10 @@ packages: dependency: "direct dev" description: name: bloc_test - sha256: "43d5b2f3d09ba768d6b611151bdf20ca141ffb46e795eb9550a58c9c2f4eae3f" + sha256: af0de1a1e16a7536e95dcd7491e0a6d6078e11d2d691988e862280b74f5c7968 url: "https://pub.dev" source: hosted - version: "9.1.3" + version: "9.1.4" boolean_selector: dependency: transitive description: @@ -157,10 +157,10 @@ packages: dependency: transitive description: name: build_resolvers - sha256: "6c4dd11d05d056e76320b828a1db0fc01ccd376922526f8e9d6c796a5adbac20" + sha256: d912852cce27c9e80a93603db721c267716894462e7033165178b91138587972 url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.3.2" build_runner: dependency: "direct dev" description: @@ -189,10 +189,10 @@ packages: dependency: transitive description: name: built_value - sha256: "598a2a682e2a7a90f08ba39c0aaa9374c5112340f0a2e275f61b59389543d166" + sha256: ff627b645b28fb8bdb69e645f910c2458fd6b65f6585c3a53e0626024897dedf url: "https://pub.dev" source: hosted - version: "8.6.1" + version: "8.6.2" cached_network_image: dependency: "direct main" description: @@ -245,26 +245,26 @@ packages: dependency: transitive description: name: code_builder - sha256: "4ad01d6e56db961d29661561effde45e519939fdaeb46c351275b182eac70189" + sha256: "315a598c7fbe77f22de1c9da7cfd6fd21816312f16ffa124453b4fc679e540f1" url: "https://pub.dev" source: hosted - version: "4.5.0" + version: "4.6.0" collection: dependency: "direct main" description: name: collection - sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" + sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 url: "https://pub.dev" source: hosted - version: "1.17.1" + version: "1.17.2" connectivity_plus: dependency: "direct main" description: name: connectivity_plus - sha256: "8599ae9edca5ff96163fca3e36f8e481ea917d1e71cdad912c084b5579913f34" + sha256: "77a180d6938f78ca7d2382d2240eb626c0f6a735d0bfdce227d8ffb80f95c48b" url: "https://pub.dev" source: hosted - version: "4.0.1" + version: "4.0.2" connectivity_plus_platform_interface: dependency: transitive description: @@ -293,10 +293,10 @@ packages: dependency: transitive description: name: cross_file - sha256: "0b0036e8cccbfbe0555fd83c1d31a6f30b77a96b598b35a5d36dd41f718695e9" + sha256: fd832b5384d0d6da4f6df60b854d33accaaeb63aa9e10e736a87381f08dee2cb url: "https://pub.dev" source: hosted - version: "0.3.3+4" + version: "0.3.3+5" crypto: dependency: transitive description: @@ -381,10 +381,10 @@ packages: dependency: "direct main" description: name: dio - sha256: "3866d67f93523161b643187af65f5ac08bc991a5bcdaf41a2d587fe4ccb49993" + sha256: ce75a1b40947fea0a0e16ce73337122a86762e38b982e1ccb909daa3b9bc4197 url: "https://pub.dev" source: hosted - version: "5.3.0" + version: "5.3.2" dots_indicator: dependency: transitive description: @@ -406,7 +406,7 @@ packages: description: path: "." ref: master - resolved-ref: "01636d9050d409177934ec64876c1c83c2567513" + resolved-ref: "2e6c7396e13c2c6ecd0a704d2322b349a7a21584" url: "https://github.com/sawankumarbundelkhandi/edge_detection" source: git version: "1.1.2" @@ -430,10 +430,10 @@ packages: dependency: transitive description: name: ffi - sha256: ed5337a5660c506388a9f012be0288fb38b49020ce2b45fe1f8b8323fe429f99 + sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" url: "https://pub.dev" source: hosted - version: "2.0.2" + version: "2.1.0" file: dependency: transitive description: @@ -621,10 +621,10 @@ packages: dependency: "direct main" description: name: flutter_native_splash - sha256: ba45d8cfbd778478a74696b012f33ffb6b1760c9bc531b21e2964444a4870dae + sha256: ecff62b3b893f2f665de7e4ad3de89f738941fcfcaaba8ee601e749efafa4698 url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" flutter_pdfview: dependency: "direct main" description: @@ -637,58 +637,58 @@ packages: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: "950e77c2bbe1692bc0874fc7fb491b96a4dc340457f4ea1641443d0a6c1ea360" + sha256: f185ac890306b5779ecbd611f52502d8d4d63d27703ef73161ca0407e815f02c url: "https://pub.dev" source: hosted - version: "2.0.15" + version: "2.0.16" flutter_secure_storage: dependency: "direct main" description: name: flutter_secure_storage - sha256: "98352186ee7ad3639ccc77ad7924b773ff6883076ab952437d20f18a61f0a7c5" + sha256: "22dbf16f23a4bcf9d35e51be1c84ad5bb6f627750565edd70dab70f3ff5fff8f" url: "https://pub.dev" source: hosted - version: "8.0.0" + version: "8.1.0" flutter_secure_storage_linux: dependency: transitive description: name: flutter_secure_storage_linux - sha256: "0912ae29a572230ad52d8a4697e5518d7f0f429052fd51df7e5a7952c7efe2a3" + sha256: "3d5032e314774ee0e1a7d0a9f5e2793486f0dff2dd9ef5a23f4e3fb2a0ae6a9e" url: "https://pub.dev" source: hosted - version: "1.1.3" + version: "1.2.0" flutter_secure_storage_macos: dependency: transitive description: name: flutter_secure_storage_macos - sha256: "083add01847fc1c80a07a08e1ed6927e9acd9618a35e330239d4422cd2a58c50" + sha256: bd33935b4b628abd0b86c8ca20655c5b36275c3a3f5194769a7b3f37c905369c url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "3.0.1" flutter_secure_storage_platform_interface: dependency: transitive description: name: flutter_secure_storage_platform_interface - sha256: b3773190e385a3c8a382007893d678ae95462b3c2279e987b55d140d3b0cb81b + sha256: "0d4d3a5dd4db28c96ae414d7ba3b8422fd735a8255642774803b2532c9a61d7e" url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "1.0.2" flutter_secure_storage_web: dependency: transitive description: name: flutter_secure_storage_web - sha256: "42938e70d4b872e856e678c423cc0e9065d7d294f45bc41fc1981a4eb4beaffe" + sha256: "30f84f102df9dcdaa2241866a958c2ec976902ebdaa8883fbfe525f1f2f3cf20" url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" flutter_secure_storage_windows: dependency: transitive description: name: flutter_secure_storage_windows - sha256: fc2910ec9b28d60598216c29ea763b3a96c401f0ce1d13cdf69ccb0e5c93c3ee + sha256: "38f9501c7cb6f38961ef0e1eacacee2b2d4715c63cc83fe56449c4d3d0b47255" url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "2.1.1" flutter_svg: dependency: "direct main" description: @@ -706,10 +706,10 @@ packages: dependency: "direct main" description: name: flutter_typeahead - sha256: a3539f7a90246b152f569029dedcf0b842532d3f2a440701b520e0bf2acbcf42 + sha256: f3a5f79d9a056e5108452dbec31d12bbd7f6d25e9097bf0f956e3f8d024e1747 url: "https://pub.dev" source: hosted - version: "4.6.2" + version: "4.7.0" flutter_web_plugins: dependency: transitive description: flutter @@ -772,18 +772,18 @@ packages: dependency: "direct main" description: name: go_router - sha256: b3cadd2cd59a4103fd5f6bc572ca75111264698784e927aa471921c3477d5475 + sha256: "5668e6d3dbcb2d0dfa25f7567554b88c57e1e3f3c440b672b24d4a9477017d5b" url: "https://pub.dev" source: hosted - version: "10.0.0" + version: "10.1.2" go_router_builder: dependency: "direct dev" description: name: go_router_builder - sha256: df2034629637d0c7c380aba5daa2f91be4733f2d632e7dff0b082d5ff3155068 + sha256: "89585f7cf2ddd35a3f05908c5bb54339d3f891fc5aac4f30e2864469d7ddc92b" url: "https://pub.dev" source: hosted - version: "2.2.4" + version: "2.3.1" graphs: dependency: transitive description: @@ -812,10 +812,10 @@ packages: dependency: "direct dev" description: name: hive_generator - sha256: "65998cc4d2cd9680a3d9709d893d2f6bb15e6c1f92626c3f1fa650b4b3281521" + sha256: "06cb8f58ace74de61f63500564931f9505368f45f98958bd7a6c35ba24159db4" url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "2.0.1" html: dependency: transitive description: @@ -953,42 +953,42 @@ packages: dependency: "direct main" description: name: local_auth - sha256: "0cf238be2bfa51a6c9e7e9cfc11c05ea39f2a3a4d3e5bb255d0ebc917da24401" + sha256: "7e6c63082e399b61e4af71266b012e767a5d4525dd6e9ba41e174fd42d76e115" url: "https://pub.dev" source: hosted - version: "2.1.6" + version: "2.1.7" local_auth_android: dependency: transitive description: name: local_auth_android - sha256: "36a78898198386d36d4e152b8cb46059b18f0e2017f813a0e833e216199f8950" + sha256: "9ad0b1ffa6f04f4d91e38c2d4c5046583e23f4cae8345776a994e8670df57fb1" url: "https://pub.dev" source: hosted - version: "1.0.32" + version: "1.0.34" local_auth_ios: dependency: transitive description: name: local_auth_ios - sha256: edc2977c5145492f3451db9507a2f2f284ee4f408950b3e16670838726761940 + sha256: "26a8d1ad0b4ef6f861d29921be8383000fda952e323a5b6752cf82ca9cf9a7a9" url: "https://pub.dev" source: hosted - version: "1.1.3" + version: "1.1.4" local_auth_platform_interface: dependency: transitive description: name: local_auth_platform_interface - sha256: "9e160d59ef0743e35f1b50f4fb84dc64f55676b1b8071e319ef35e7f3bc13367" + sha256: fc5bd537970a324260fda506cfb61b33ad7426f37a8ea5c461cf612161ebba54 url: "https://pub.dev" source: hosted - version: "1.0.7" + version: "1.0.8" local_auth_windows: dependency: transitive description: name: local_auth_windows - sha256: "5af808e108c445d0cf702a8c5f8242f1363b7970320334f82e6e1e8ad0b0d7d4" + sha256: "505ba3367ca781efb1c50d3132e44a2446bccc4163427bc203b9b4d8994d97ea" url: "https://pub.dev" source: hosted - version: "1.0.9" + version: "1.0.10" logging: dependency: transitive description: @@ -1001,18 +1001,18 @@ packages: dependency: transitive description: name: matcher - sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" url: "https://pub.dev" source: hosted - version: "0.12.15" + version: "0.12.16" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "0.5.0" meta: dependency: transitive description: @@ -1048,10 +1048,10 @@ packages: dependency: transitive description: name: mocktail - sha256: "80a996cd9a69284b3dc521ce185ffe9150cde69767c2d3a0720147d93c0cef53" + sha256: "9503969a7c2c78c7292022c70c0289ed6241df7a9ba720010c0b215af29a5a58" url: "https://pub.dev" source: hosted - version: "0.3.0" + version: "1.0.0" nested: dependency: transitive description: @@ -1104,10 +1104,10 @@ packages: dependency: "direct main" description: name: package_info_plus - sha256: ceb027f6bc6a60674a233b4a90a7658af1aebdea833da0b5b53c1e9821a78c7b + sha256: "6ff267fcd9d48cb61c8df74a82680e8b82e940231bb5f68356672fde0397334a" url: "https://pub.dev" source: hosted - version: "4.0.2" + version: "4.1.0" package_info_plus_platform_interface: dependency: transitive description: @@ -1120,10 +1120,10 @@ packages: dependency: "direct main" description: name: palette_generator - sha256: "0e3cd6974e10b1434dcf4cf779efddb80e2696585e273a2dbede6af52f94568d" + sha256: eb7082b4b97487ebc65b3ad3f6f0b7489b96e76840381ed0e06a46fe7ffd4068 url: "https://pub.dev" source: hosted - version: "0.3.3+2" + version: "0.3.3+3" paperless_api: dependency: "direct main" description: @@ -1159,50 +1159,50 @@ packages: dependency: "direct main" description: name: path_provider - sha256: "3087813781ab814e4157b172f1a11c46be20179fcc9bea043e0fba36bc0acaa2" + sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa url: "https://pub.dev" source: hosted - version: "2.0.15" + version: "2.1.1" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: "2cec049d282c7f13c594b4a73976b0b4f2d7a1838a6dd5aaf7bd9719196bee86" + sha256: "6b8b19bd80da4f11ce91b2d1fb931f3006911477cec227cce23d3253d80df3f1" url: "https://pub.dev" source: hosted - version: "2.0.27" + version: "2.2.0" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "916731ccbdce44d545414dd9961f26ba5fbaa74bcbb55237d8e65a623a8c7297" + sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d" url: "https://pub.dev" source: hosted - version: "2.2.4" + version: "2.3.1" path_provider_linux: dependency: transitive description: name: path_provider_linux - sha256: ffbb8cc9ed2c9ec0e4b7a541e56fd79b138e8f47d2fb86815f15358a349b3b57 + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 url: "https://pub.dev" source: hosted - version: "2.1.11" + version: "2.2.1" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface - sha256: "57585299a729335f1298b43245842678cb9f43a6310351b18fb577d6e33165ec" + sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c" url: "https://pub.dev" source: hosted - version: "2.0.6" + version: "2.1.1" path_provider_windows: dependency: transitive description: name: path_provider_windows - sha256: "1cb68ba4cd3a795033de62ba1b7b4564dace301f952de6bfb3cd91b202b6ee96" + sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" url: "https://pub.dev" source: hosted - version: "2.1.7" + version: "2.2.1" pdf: dependency: "direct main" description: @@ -1215,18 +1215,18 @@ packages: dependency: "direct main" description: name: permission_handler - sha256: "63e5216aae014a72fe9579ccd027323395ce7a98271d9defa9d57320d001af81" + sha256: bc56bfe9d3f44c3c612d8d393bd9b174eb796d706759f9b495ac254e4294baa5 url: "https://pub.dev" source: hosted - version: "10.4.3" + version: "10.4.5" permission_handler_android: dependency: transitive description: name: permission_handler_android - sha256: "2ffaf52a21f64ac9b35fe7369bb9533edbd4f698e5604db8645b1064ff4cf221" + sha256: "59c6322171c29df93a22d150ad95f3aa19ed86542eaec409ab2691b8f35f9a47" url: "https://pub.dev" source: hosted - version: "10.3.3" + version: "10.3.6" permission_handler_apple: dependency: transitive description: @@ -1239,10 +1239,10 @@ packages: dependency: transitive description: name: permission_handler_platform_interface - sha256: "7c6b1500385dd1d2ca61bb89e2488ca178e274a69144d26bbd65e33eae7c02a9" + sha256: f2343e9fa9c22ae4fd92d4732755bfe452214e7189afcc097380950cf567b4b2 url: "https://pub.dev" source: hosted - version: "3.11.3" + version: "3.11.5" permission_handler_windows: dependency: transitive description: @@ -1279,18 +1279,18 @@ packages: dependency: transitive description: name: plugin_platform_interface - sha256: "43798d895c929056255600343db8f049921cbec94d31ec87f1dc5c16c01935dd" + sha256: da3fdfeccc4d4ff2da8f8c556704c08f912542c5fb3cf2233ed75372384a034d url: "https://pub.dev" source: hosted - version: "2.1.5" + version: "2.1.6" pointer_interceptor: dependency: transitive description: name: pointer_interceptor - sha256: "6aa680b30d96dccef496933d00208ad25f07e047f644dc98ce03ec6141633a9a" + sha256: "7626e034489820fd599380d2bb4d3f4a0a5e3529370b62bfce53ab736b91adb2" url: "https://pub.dev" source: hosted - version: "0.9.3+4" + version: "0.9.3+6" pointycastle: dependency: transitive description: @@ -1423,10 +1423,10 @@ packages: dependency: transitive description: name: share_plus_platform_interface - sha256: "0c6e61471bd71b04a138b8b588fa388e66d8b005e6f2deda63371c5c505a0981" + sha256: "357412af4178d8e11d14f41723f80f12caea54cf0d5cd29af9dcdab85d58aea7" url: "https://pub.dev" source: hosted - version: "3.2.1" + version: "3.3.0" share_plus_web: dependency: transitive description: @@ -1540,10 +1540,10 @@ packages: dependency: transitive description: name: source_span - sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.10.0" sqflite: dependency: transitive description: @@ -1620,26 +1620,26 @@ packages: dependency: transitive description: name: test - sha256: "3dac9aecf2c3991d09b9cdde4f98ded7b30804a88a0d7e4e7e1678e78d6b97f4" + sha256: "13b41f318e2a5751c3169137103b60c584297353d4b1761b66029bae6411fe46" url: "https://pub.dev" source: hosted - version: "1.24.1" + version: "1.24.3" test_api: dependency: transitive description: name: test_api - sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb + sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "0.6.0" test_core: dependency: transitive description: name: test_core - sha256: "5138dbffb77b2289ecb12b81c11ba46036590b72a64a7a90d6ffb880f1a29e93" + sha256: "99806e9e6d95c7b059b7a0fc08f07fc53fabe54a829497f0d9676299f1e8637e" url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "0.5.3" timezone: dependency: transitive description: @@ -1676,66 +1676,66 @@ packages: dependency: "direct main" description: name: url_launcher - sha256: "781bd58a1eb16069412365c98597726cd8810ae27435f04b3b4d3a470bacd61e" + sha256: "47e208a6711459d813ba18af120d9663c20bdf6985d6ad39fe165d2538378d27" url: "https://pub.dev" source: hosted - version: "6.1.12" + version: "6.1.14" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: "78cb6dea3e93148615109e58e42c35d1ffbf5ef66c44add673d0ab75f12ff3af" + sha256: b04af59516ab45762b2ca6da40fa830d72d0f6045cd97744450b73493fa76330 url: "https://pub.dev" source: hosted - version: "6.0.37" + version: "6.1.0" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: "9af7ea73259886b92199f9e42c116072f05ff9bea2dcb339ab935dfc957392c2" + sha256: "7c65021d5dee51813d652357bc65b8dd4a6177082a9966bc8ba6ee477baa795f" url: "https://pub.dev" source: hosted - version: "6.1.4" + version: "6.1.5" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - sha256: "207f4ddda99b95b4d4868320a352d374b0b7e05eefad95a4a26f57da413443f5" + sha256: b651aad005e0cb06a01dbd84b428a301916dc75f0e7ea6165f80057fee2d8e8e url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.6" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - sha256: "1c4fdc0bfea61a70792ce97157e5cc17260f61abbe4f39354513f39ec6fd73b1" + sha256: b55486791f666e62e0e8ff825e58a023fd6b1f71c49926483f1128d3bbd8fe88 url: "https://pub.dev" source: hosted - version: "3.0.6" + version: "3.0.7" url_launcher_platform_interface: dependency: transitive description: name: url_launcher_platform_interface - sha256: bfdfa402f1f3298637d71ca8ecfe840b4696698213d5346e9d12d4ab647ee2ea + sha256: "95465b39f83bfe95fcb9d174829d6476216f2d548b79c38ab2506e0458787618" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.1.5" url_launcher_web: dependency: transitive description: name: url_launcher_web - sha256: cc26720eefe98c1b71d85f9dc7ef0cada5132617046369d9dc296b3ecaa5cbb4 + sha256: "2942294a500b4fa0b918685aff406773ba0a4cd34b7f42198742a94083020ce5" url: "https://pub.dev" source: hosted - version: "2.0.18" + version: "2.0.20" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - sha256: "7967065dd2b5fccc18c653b97958fdf839c5478c28e767c61ee879f4e7882422" + sha256: "95fef3129dc7cfaba2bc3d5ba2e16063bb561fc6d78e63eee16162bc70029069" url: "https://pub.dev" source: hosted - version: "3.0.7" + version: "3.0.8" uuid: dependency: "direct main" description: @@ -1756,10 +1756,10 @@ packages: dependency: transitive description: name: vm_service - sha256: f6deed8ed625c52864792459709183da231ebf66ff0cf09e69b573227c377efe + sha256: c620a6f783fa22436da68e42db7ebbf18b8c44b9a46ab911f666ff09ffd9153f url: "https://pub.dev" source: hosted - version: "11.3.0" + version: "11.7.1" watcher: dependency: transitive description: @@ -1768,6 +1768,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + web: + dependency: transitive + description: + name: web + sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 + url: "https://pub.dev" + source: hosted + version: "0.1.4-beta" web_socket_channel: dependency: "direct main" description: @@ -1788,42 +1796,42 @@ packages: dependency: transitive description: name: webkit_inspection_protocol - sha256: "67d3a8b6c79e1987d19d848b0892e582dbb0c66c57cc1fef58a177dd2aa2823d" + sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.2.1" webview_flutter: dependency: "direct main" description: name: webview_flutter - sha256: "789d52bd789373cc1e100fb634af2127e86c99cf9abde09499743270c5de8d00" + sha256: "82f6787d5df55907aa01e49bd9644f4ed1cc82af7a8257dd9947815959d2e755" url: "https://pub.dev" source: hosted - version: "4.2.2" + version: "4.2.4" webview_flutter_android: dependency: transitive description: name: webview_flutter_android - sha256: d936a09fbfd08cb78f7329e0bbacf6158fbdfe24ffc908b22444c07d295eb193 + sha256: "9427774649fd3c8b7ff53523051395d13aed2ca355822b822e6493d79f5fc05a" url: "https://pub.dev" source: hosted - version: "3.9.2" + version: "3.10.0" webview_flutter_platform_interface: dependency: transitive description: name: webview_flutter_platform_interface - sha256: "564ef378cafc1a0e29f1d76ce175ef517a0a6115875dff7b43fccbef2b0aeb30" + sha256: "6d9213c65f1060116757a7c473247c60f3f7f332cac33dc417c9e362a9a13e4f" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.6.0" webview_flutter_wkwebview: dependency: transitive description: name: webview_flutter_wkwebview - sha256: "5fa098f28b606f699e8ca52d9e4e11edbbfef65189f5f77ae92703ba5408fd25" + sha256: d2f7241849582da80b79acb03bb936422412ce5c0c79fb5f6a1de5421a5aecc4 url: "https://pub.dev" source: hosted - version: "3.7.2" + version: "3.7.4" win32: dependency: transitive description: @@ -1857,5 +1865,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.0.0 <4.0.0" - flutter: ">=3.10.0" + dart: ">=3.1.0 <4.0.0" + flutter: ">=3.13.0"