mirror of
https://github.com/Xevion/paperless-mobile.git
synced 2025-12-07 18:07:44 -06:00
Improved search, changed saved view display
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:badges/badges.dart' as b;
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -5,35 +7,26 @@ 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/repository/provider/label_repositories_provider.dart';
|
||||
import 'package:paperless_mobile/core/translation/sort_field_localization_mapper.dart';
|
||||
import 'package:paperless_mobile/core/widgets/app_options_popup_menu.dart';
|
||||
import 'package:paperless_mobile/core/widgets/material/search/m3_search.dart';
|
||||
import 'package:paperless_mobile/core/widgets/material/search/m3_search_bar.dart';
|
||||
import 'package:paperless_mobile/features/document_details/bloc/document_details_cubit.dart';
|
||||
import 'package:paperless_mobile/features/document_details/view/pages/document_details_page.dart';
|
||||
import 'package:paperless_mobile/features/document_search/cubit/document_search_cubit.dart';
|
||||
import 'package:paperless_mobile/features/document_search/document_search_delegate.dart';
|
||||
import 'package:paperless_mobile/features/document_search/view/document_search_bar.dart';
|
||||
import 'package:paperless_mobile/features/documents/bloc/documents_cubit.dart';
|
||||
import 'package:paperless_mobile/features/documents/bloc/documents_state.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/list/adaptive_documents_view.dart';
|
||||
import 'package:paperless_mobile/features/documents/view/widgets/new_items_loading_widget.dart';
|
||||
import 'package:paperless_mobile/features/documents/view/widgets/search/document_filter_panel.dart';
|
||||
import 'package:paperless_mobile/features/documents/view/widgets/selection/bulk_delete_confirmation_dialog.dart';
|
||||
import 'package:paperless_mobile/features/documents/view/widgets/sort_documents_button.dart';
|
||||
import 'package:paperless_mobile/features/home/view/widget/app_drawer.dart';
|
||||
import 'package:paperless_mobile/features/documents/view/widgets/view_actions.dart';
|
||||
import 'package:paperless_mobile/features/labels/bloc/providers/labels_bloc_provider.dart';
|
||||
import 'package:paperless_mobile/features/login/bloc/authentication_cubit.dart';
|
||||
import 'package:paperless_mobile/features/saved_view/cubit/saved_view_cubit.dart';
|
||||
import 'package:paperless_mobile/features/saved_view/view/saved_view_selection_widget.dart';
|
||||
import 'package:paperless_mobile/features/saved_view/view/add_saved_view_page.dart';
|
||||
import 'package:paperless_mobile/features/saved_view/view/saved_view_list.dart';
|
||||
import 'package:paperless_mobile/features/search/view/document_search_page.dart';
|
||||
import 'package:paperless_mobile/features/search_app_bar/view/search_app_bar.dart';
|
||||
import 'package:paperless_mobile/features/settings/bloc/application_settings_cubit.dart';
|
||||
import 'package:paperless_mobile/features/settings/bloc/application_settings_state.dart';
|
||||
import 'package:paperless_mobile/features/settings/model/view_type.dart';
|
||||
import 'package:paperless_mobile/features/tasks/cubit/task_status_cubit.dart';
|
||||
import 'package:paperless_mobile/generated/l10n.dart';
|
||||
import 'package:paperless_mobile/helpers/format_helpers.dart';
|
||||
import 'package:paperless_mobile/helpers/message_helpers.dart';
|
||||
|
||||
class DocumentFilterIntent {
|
||||
@@ -46,6 +39,7 @@ class DocumentFilterIntent {
|
||||
});
|
||||
}
|
||||
|
||||
//TODO: Refactor this
|
||||
class DocumentsPage extends StatefulWidget {
|
||||
const DocumentsPage({Key? key}) : super(key: key);
|
||||
|
||||
@@ -53,56 +47,38 @@ class DocumentsPage extends StatefulWidget {
|
||||
State<DocumentsPage> createState() => _DocumentsPageState();
|
||||
}
|
||||
|
||||
class _DocumentsPageState extends State<DocumentsPage> {
|
||||
final ScrollController _scrollController = ScrollController();
|
||||
double _offset = 0;
|
||||
double _last = 0;
|
||||
class _DocumentsPageState extends State<DocumentsPage>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late final TabController _tabController;
|
||||
|
||||
static const double _savedViewWidgetHeight = 80 + 16;
|
||||
int _currentTab = 0;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_tabController = TabController(
|
||||
length: 2,
|
||||
vsync: this,
|
||||
initialIndex: 0,
|
||||
);
|
||||
try {
|
||||
context.read<DocumentsCubit>().reload();
|
||||
context.read<SavedViewCubit>().reload();
|
||||
} on PaperlessServerException catch (error, stackTrace) {
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
}
|
||||
_scrollController
|
||||
..addListener(_listenForScrollChanges)
|
||||
..addListener(_listenForLoadNewData);
|
||||
_tabController.addListener(_listenForTabChanges);
|
||||
}
|
||||
|
||||
void _listenForLoadNewData() async {
|
||||
final currState = context.read<DocumentsCubit>().state;
|
||||
if (_scrollController.offset >=
|
||||
_scrollController.position.maxScrollExtent * 0.75 &&
|
||||
!currState.isLoading &&
|
||||
!currState.isLastPageLoaded) {
|
||||
try {
|
||||
await context.read<DocumentsCubit>().loadMore();
|
||||
} on PaperlessServerException catch (error, stackTrace) {
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _listenForScrollChanges() {
|
||||
final current = _scrollController.offset;
|
||||
_offset += _last - current;
|
||||
|
||||
if (_offset <= -_savedViewWidgetHeight) _offset = -_savedViewWidgetHeight;
|
||||
if (_offset >= 0) _offset = 0;
|
||||
_last = current;
|
||||
if (_offset <= 0 && _offset >= -_savedViewWidgetHeight) {
|
||||
setState(() {});
|
||||
}
|
||||
void _listenForTabChanges() {
|
||||
setState(() {
|
||||
_currentTab = _tabController.index;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_scrollController.dispose();
|
||||
_tabController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@@ -140,149 +116,204 @@ class _DocumentsPageState extends State<DocumentsPage> {
|
||||
},
|
||||
builder: (context, connectivityState) {
|
||||
return Scaffold(
|
||||
// appBar: PreferredSize(
|
||||
// preferredSize: const Size.fromHeight(
|
||||
// kToolbarHeight,
|
||||
// ),
|
||||
// child: BlocBuilder<DocumentsCubit, DocumentsState>(
|
||||
// builder: (context, state) {
|
||||
// if (state.selection.isEmpty) {
|
||||
// return DocumentSearchBar();
|
||||
// // return AppBar(
|
||||
// // title: Text(S.of(context).documentsPageTitle +
|
||||
// // " (${formatMaxCount(state.documents.length)})"),
|
||||
// // actions: [
|
||||
// // IconButton(
|
||||
// // icon: const Icon(Icons.search),
|
||||
// // onPressed: () {
|
||||
// // showMaterial3Search(
|
||||
// // context: context,
|
||||
// // delegate: DocumentSearchDelegate(
|
||||
// // DocumentSearchCubit(context.read()),
|
||||
// // searchFieldStyle:
|
||||
// // Theme.of(context).textTheme.bodyLarge,
|
||||
// // hintText: "Search documents", //TODO: INTL
|
||||
// // ),
|
||||
// // );
|
||||
// // },
|
||||
// // ),
|
||||
// // const SortDocumentsButton(),
|
||||
// // const AppOptionsPopupMenu(
|
||||
// // displayedActions: [
|
||||
// // AppPopupMenuEntries.documentsSelectListView,
|
||||
// // AppPopupMenuEntries.documentsSelectGridView,
|
||||
// // AppPopupMenuEntries.divider,
|
||||
// // AppPopupMenuEntries.openAboutThisAppDialog,
|
||||
// // AppPopupMenuEntries.reportBug,
|
||||
// // AppPopupMenuEntries.openSettings,
|
||||
// // ],
|
||||
// // ),
|
||||
// // ],
|
||||
// // );
|
||||
// } else {
|
||||
// return AppBar(
|
||||
// leading: IconButton(
|
||||
// icon: const Icon(Icons.close),
|
||||
// onPressed: () =>
|
||||
// context.read<DocumentsCubit>().resetSelection(),
|
||||
// ),
|
||||
// title: Text(
|
||||
// '${state.selection.length} ${S.of(context).documentsSelectedText}'),
|
||||
// actions: [
|
||||
// IconButton(
|
||||
// icon: const Icon(Icons.delete),
|
||||
// onPressed: () => _onDelete(context, state),
|
||||
// ),
|
||||
// ],
|
||||
// );
|
||||
// }
|
||||
// },
|
||||
// ),
|
||||
// ),
|
||||
// floatingActionButton: BlocBuilder<DocumentsCubit, DocumentsState>(
|
||||
// builder: (context, state) {
|
||||
// final appliedFiltersCount = state.filter.appliedFiltersCount;
|
||||
// return b.Badge(
|
||||
// position: b.BadgePosition.topEnd(top: -12, end: -6),
|
||||
// showBadge: appliedFiltersCount > 0,
|
||||
// badgeContent: Text(
|
||||
// '$appliedFiltersCount',
|
||||
// style: const TextStyle(
|
||||
// color: Colors.white,
|
||||
// ),
|
||||
// ),
|
||||
// animationType: b.BadgeAnimationType.fade,
|
||||
// badgeColor: Colors.red,
|
||||
// child: FloatingActionButton(
|
||||
// child: const Icon(Icons.filter_alt_outlined),
|
||||
// onPressed: _openDocumentFilter,
|
||||
// ),
|
||||
// );
|
||||
// },
|
||||
// ),
|
||||
floatingActionButton: BlocBuilder<DocumentsCubit, DocumentsState>(
|
||||
builder: (context, state) {
|
||||
final appliedFiltersCount = state.filter.appliedFiltersCount;
|
||||
return b.Badge(
|
||||
position: b.BadgePosition.topEnd(top: -12, end: -6),
|
||||
showBadge: appliedFiltersCount > 0,
|
||||
badgeContent: Text(
|
||||
'$appliedFiltersCount',
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
animationType: b.BadgeAnimationType.fade,
|
||||
badgeColor: Colors.red,
|
||||
child: _currentTab == 0
|
||||
? FloatingActionButton(
|
||||
child: const Icon(Icons.filter_alt_outlined),
|
||||
onPressed: _openDocumentFilter,
|
||||
)
|
||||
: FloatingActionButton(
|
||||
child: const Icon(Icons.add),
|
||||
onPressed: () => _onCreateSavedView(state.filter),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
resizeToAvoidBottomInset: true,
|
||||
body: NestedScrollView(
|
||||
headerSliverBuilder: (context, innerBoxIsScrolled) {
|
||||
return [
|
||||
SliverAppBar(
|
||||
floating: true,
|
||||
pinned: true,
|
||||
snap: true,
|
||||
title: SearchBar(
|
||||
height: kToolbarHeight - 2,
|
||||
supportingText: "Search documents",
|
||||
onTap: () {
|
||||
showDocumentSearchPage(context);
|
||||
},
|
||||
leadingIcon: Icon(Icons.menu),
|
||||
trailingIcon: CircleAvatar(
|
||||
child: Text("A"),
|
||||
body: WillPopScope(
|
||||
onWillPop: () async {
|
||||
if (context.read<DocumentsCubit>().state.selection.isNotEmpty) {
|
||||
context.read<DocumentsCubit>().resetSelection();
|
||||
}
|
||||
return false;
|
||||
},
|
||||
child: NestedScrollView(
|
||||
floatHeaderSlivers: true,
|
||||
headerSliverBuilder: (context, innerBoxIsScrolled) => [
|
||||
SliverOverlapAbsorber(
|
||||
// This widget takes the overlapping behavior of the SliverAppBar,
|
||||
// and redirects it to the SliverOverlapInjector below. If it is
|
||||
// missing, then it is possible for the nested "inner" scroll view
|
||||
// below to end up under the SliverAppBar even when the inner
|
||||
// scroll view thinks it has not been scrolled.
|
||||
// This is not necessary if the "headerSliverBuilder" only builds
|
||||
// widgets that do not overlap the next sliver.
|
||||
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(
|
||||
context,
|
||||
),
|
||||
sliver: SearchAppBar(
|
||||
onOpenSearch: showDocumentSearchPage,
|
||||
bottom: TabBar(
|
||||
controller: _tabController,
|
||||
isScrollable: true,
|
||||
tabs: [
|
||||
Tab(text: S.of(context).documentsPageTitle),
|
||||
Tab(text: S.of(context).savedViewsLabel),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
];
|
||||
},
|
||||
body: WillPopScope(
|
||||
onWillPop: () async {
|
||||
if (context
|
||||
.read<DocumentsCubit>()
|
||||
.state
|
||||
.selection
|
||||
.isNotEmpty) {
|
||||
context.read<DocumentsCubit>().resetSelection();
|
||||
}
|
||||
return false;
|
||||
},
|
||||
child: RefreshIndicator(
|
||||
onRefresh: _onRefresh,
|
||||
notificationPredicate: (_) => connectivityState.isConnected,
|
||||
child: BlocBuilder<TaskStatusCubit, TaskStatusState>(
|
||||
builder: (context, taskState) {
|
||||
return _buildBody(connectivityState);
|
||||
// return Stack(
|
||||
// children: [
|
||||
// Positioned(
|
||||
// left: 0,
|
||||
// right: 0,
|
||||
// top: _offset,
|
||||
// child: BlocBuilder<DocumentsCubit, DocumentsState>(
|
||||
// builder: (context, state) {
|
||||
// return ColoredBox(
|
||||
// color:
|
||||
// Theme.of(context).colorScheme.background,
|
||||
// child: SavedViewSelectionWidget(
|
||||
// height: _savedViewWidgetHeight,
|
||||
// currentFilter: state.filter,
|
||||
// enabled: state.selection.isEmpty &&
|
||||
// connectivityState.isConnected,
|
||||
// ),
|
||||
// );
|
||||
// },
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// );
|
||||
),
|
||||
],
|
||||
body: NotificationListener<ScrollUpdateNotification>(
|
||||
onNotification: (notification) {
|
||||
final metrics = notification.metrics;
|
||||
final desiredTab =
|
||||
(metrics.pixels / metrics.maxScrollExtent).round();
|
||||
if (metrics.axis == Axis.horizontal &&
|
||||
_currentTab != desiredTab) {
|
||||
setState(() => _currentTab = desiredTab);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
child: NotificationListener<ScrollMetricsNotification>(
|
||||
onNotification: (notification) {
|
||||
// Listen for scroll notifications to load new data.
|
||||
// Scroll controller does not work here due to nestedscrollview limitations.
|
||||
final currState = context.read<DocumentsCubit>().state;
|
||||
final max = notification.metrics.maxScrollExtent;
|
||||
if (max == 0 ||
|
||||
_currentTab != 0 ||
|
||||
currState.isLoading ||
|
||||
currState.isLastPageLoaded) {
|
||||
return true;
|
||||
}
|
||||
final offset = notification.metrics.pixels;
|
||||
if (offset >= max * 0.7) {
|
||||
context
|
||||
.read<DocumentsCubit>()
|
||||
.loadMore()
|
||||
.onError<PaperlessServerException>(
|
||||
(error, stackTrace) => showErrorMessage(
|
||||
context,
|
||||
error,
|
||||
stackTrace,
|
||||
),
|
||||
);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
child: TabBarView(
|
||||
controller: _tabController,
|
||||
children: [
|
||||
Builder(
|
||||
builder: (context) {
|
||||
return RefreshIndicator(
|
||||
edgeOffset: kToolbarHeight,
|
||||
onRefresh: _onReloadDocuments,
|
||||
notificationPredicate: (_) =>
|
||||
connectivityState.isConnected,
|
||||
child: CustomScrollView(
|
||||
key: const PageStorageKey<String>("documents"),
|
||||
slivers: <Widget>[
|
||||
SliverOverlapInjector(
|
||||
handle: NestedScrollView
|
||||
.sliverOverlapAbsorberHandleFor(
|
||||
context),
|
||||
),
|
||||
BlocBuilder<DocumentsCubit, DocumentsState>(
|
||||
buildWhen: (previous, current) =>
|
||||
!const ListEquality().equals(
|
||||
previous.documents,
|
||||
current.documents,
|
||||
) ||
|
||||
previous.selectedIds !=
|
||||
current.selectedIds,
|
||||
builder: (context, state) {
|
||||
if (state.hasLoaded &&
|
||||
state.documents.isEmpty) {
|
||||
return SliverToBoxAdapter(
|
||||
child: DocumentsEmptyState(
|
||||
state: state,
|
||||
onReset: () {
|
||||
context
|
||||
.read<DocumentsCubit>()
|
||||
.resetFilter();
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
return BlocBuilder<
|
||||
ApplicationSettingsCubit,
|
||||
ApplicationSettingsState>(
|
||||
builder: (context, settings) {
|
||||
return SliverAdaptiveDocumentsView(
|
||||
viewType:
|
||||
settings.preferredViewType,
|
||||
onTap: _openDetails,
|
||||
onSelected: context
|
||||
.read<DocumentsCubit>()
|
||||
.toggleDocumentSelection,
|
||||
hasInternetConnection:
|
||||
connectivityState.isConnected,
|
||||
onTagSelected: _addTagToFilter,
|
||||
onCorrespondentSelected:
|
||||
_addCorrespondentToFilter,
|
||||
onDocumentTypeSelected:
|
||||
_addDocumentTypeToFilter,
|
||||
onStoragePathSelected:
|
||||
_addStoragePathToFilter,
|
||||
documents: state.documents,
|
||||
hasLoaded: state.hasLoaded,
|
||||
isLabelClickable: true,
|
||||
isLoading: state.isLoading,
|
||||
selectedDocumentIds:
|
||||
state.selectedIds,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
Builder(
|
||||
builder: (context) {
|
||||
return RefreshIndicator(
|
||||
edgeOffset: kToolbarHeight,
|
||||
onRefresh: _onReloadSavedViews,
|
||||
notificationPredicate: (_) =>
|
||||
connectivityState.isConnected,
|
||||
child: CustomScrollView(
|
||||
key: const PageStorageKey<String>("savedViews"),
|
||||
slivers: <Widget>[
|
||||
SliverOverlapInjector(
|
||||
handle: NestedScrollView
|
||||
.sliverOverlapAbsorberHandleFor(
|
||||
context),
|
||||
),
|
||||
const SavedViewList(),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -293,28 +324,7 @@ class _DocumentsPageState extends State<DocumentsPage> {
|
||||
);
|
||||
}
|
||||
|
||||
BlocBuilder<ApplicationSettingsCubit, ApplicationSettingsState>
|
||||
_buildViewTypeButton() {
|
||||
return BlocBuilder<ApplicationSettingsCubit, ApplicationSettingsState>(
|
||||
builder: (context, settingsState) => IconButton(
|
||||
icon: Icon(
|
||||
settingsState.preferredViewType == ViewType.grid
|
||||
? Icons.list
|
||||
: Icons.grid_view_rounded,
|
||||
),
|
||||
onPressed: () {
|
||||
// Reset saved view widget position as scroll offset will be reset anyway.
|
||||
setState(() {
|
||||
_offset = 0;
|
||||
_last = 0;
|
||||
});
|
||||
final cubit = context.read<ApplicationSettingsCubit>();
|
||||
cubit.setViewType(cubit.state.preferredViewType.toggle());
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
//TODO: Add app bar...
|
||||
void _onDelete(BuildContext context, DocumentsState documentsState) async {
|
||||
final shouldDelete = await showDialog<bool>(
|
||||
context: context,
|
||||
@@ -338,6 +348,25 @@ class _DocumentsPageState extends State<DocumentsPage> {
|
||||
}
|
||||
}
|
||||
|
||||
void _onCreateSavedView(DocumentFilter filter) async {
|
||||
final newView = await Navigator.of(context).push<SavedView?>(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => LabelsBlocProvider(
|
||||
child: AddSavedViewPage(
|
||||
currentFilter: filter,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
if (newView != null) {
|
||||
try {
|
||||
await context.read<SavedViewCubit>().add(newView);
|
||||
} on PaperlessServerException catch (error, stackTrace) {
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _openDocumentFilter() async {
|
||||
final draggableSheetController = DraggableScrollableController();
|
||||
final filterIntent = await showModalBottomSheet<DocumentFilterIntent>(
|
||||
@@ -373,12 +402,7 @@ class _DocumentsPageState extends State<DocumentsPage> {
|
||||
try {
|
||||
if (filterIntent.shouldReset) {
|
||||
await context.read<DocumentsCubit>().resetFilter();
|
||||
context.read<DocumentsCubit>().unselectView();
|
||||
} else {
|
||||
if (filterIntent.filter !=
|
||||
context.read<DocumentsCubit>().state.filter) {
|
||||
context.read<DocumentsCubit>().unselectView();
|
||||
}
|
||||
await context
|
||||
.read<DocumentsCubit>()
|
||||
.updateFilter(filter: filterIntent.filter!);
|
||||
@@ -389,75 +413,11 @@ class _DocumentsPageState extends State<DocumentsPage> {
|
||||
}
|
||||
}
|
||||
|
||||
String _formatDocumentCount(int count) {
|
||||
return count > 99 ? "99+" : count.toString();
|
||||
}
|
||||
|
||||
Widget _buildBody(ConnectivityState connectivityState) {
|
||||
final isConnected = connectivityState == ConnectivityState.connected;
|
||||
return BlocBuilder<ApplicationSettingsCubit, ApplicationSettingsState>(
|
||||
builder: (context, settings) {
|
||||
return BlocBuilder<DocumentsCubit, DocumentsState>(
|
||||
buildWhen: (previous, current) =>
|
||||
!const ListEquality()
|
||||
.equals(previous.documents, current.documents) ||
|
||||
previous.selectedIds != current.selectedIds,
|
||||
builder: (context, state) {
|
||||
if (state.hasLoaded && state.documents.isEmpty) {
|
||||
return DocumentsEmptyState(
|
||||
state: state,
|
||||
onReset: () {
|
||||
context.read<DocumentsCubit>().resetFilter();
|
||||
context.read<DocumentsCubit>().unselectView();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
return AdaptiveDocumentsView(
|
||||
viewType: settings.preferredViewType,
|
||||
state: state,
|
||||
scrollController: _scrollController,
|
||||
onTap: _openDetails,
|
||||
onSelected: _onSelected,
|
||||
hasInternetConnection: isConnected,
|
||||
onTagSelected: _addTagToFilter,
|
||||
onCorrespondentSelected: _addCorrespondentToFilter,
|
||||
onDocumentTypeSelected: _addDocumentTypeToFilter,
|
||||
onStoragePathSelected: _addStoragePathToFilter,
|
||||
pageLoadingWidget: const NewItemsLoadingWidget(),
|
||||
beforeItems: SizedBox(
|
||||
height: kToolbarHeight,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const SortDocumentsButton(),
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
settings.preferredViewType == ViewType.grid
|
||||
? Icons.list
|
||||
: Icons.grid_view_rounded,
|
||||
),
|
||||
onPressed: () =>
|
||||
context.read<ApplicationSettingsCubit>().setViewType(
|
||||
settings.preferredViewType.toggle(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _openDetails(DocumentModel document) async {
|
||||
final potentiallyUpdatedModel =
|
||||
await Navigator.of(context).push<DocumentModel?>(
|
||||
final updatedModel = await Navigator.of(context).push<DocumentModel?>(
|
||||
_buildDetailsPageRoute(document),
|
||||
);
|
||||
if (potentiallyUpdatedModel != document) {
|
||||
if (updatedModel != document) {
|
||||
context.read<DocumentsCubit>().reload();
|
||||
}
|
||||
}
|
||||
@@ -558,15 +518,19 @@ class _DocumentsPageState extends State<DocumentsPage> {
|
||||
}
|
||||
}
|
||||
|
||||
void _onSelected(DocumentModel model) {
|
||||
context.read<DocumentsCubit>().toggleDocumentSelection(model);
|
||||
}
|
||||
|
||||
Future<void> _onRefresh() async {
|
||||
Future<void> _onReloadDocuments() async {
|
||||
try {
|
||||
// We do not await here on purpose so we can show a linear progress indicator below the app bar.
|
||||
context.read<DocumentsCubit>().reload();
|
||||
context.read<SavedViewCubit>().reload();
|
||||
await context.read<DocumentsCubit>().reload();
|
||||
} on PaperlessServerException catch (error, stackTrace) {
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onReloadSavedViews() async {
|
||||
try {
|
||||
// We do not await here on purpose so we can show a linear progress indicator below the app bar.
|
||||
await context.read<SavedViewCubit>().reload();
|
||||
} on PaperlessServerException catch (error, stackTrace) {
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user