From 681d551b56805a27592182b8dbb4aa2b3509df70 Mon Sep 17 00:00:00 2001 From: Anton Stubenbord Date: Sun, 12 Feb 2023 18:48:24 +0100 Subject: [PATCH] feat: Add detailed view type --- .../documents/view/pages/documents_page.dart | 102 ++++++++++-------- .../view/widgets/adaptive_documents_view.dart | 66 ++++++++++++ .../widgets/items/document_detailed_item.dart | 32 ++++++ .../selection/view_type_selection_widget.dart | 54 +++++++++- lib/features/settings/model/view_type.dart | 5 +- 5 files changed, 205 insertions(+), 54 deletions(-) create mode 100644 lib/features/documents/view/widgets/items/document_detailed_item.dart diff --git a/lib/features/documents/view/pages/documents_page.dart b/lib/features/documents/view/pages/documents_page.dart index e2a5aae..03886c0 100644 --- a/lib/features/documents/view/pages/documents_page.dart +++ b/lib/features/documents/view/pages/documents_page.dart @@ -18,6 +18,7 @@ import 'package:paperless_mobile/features/saved_view/cubit/saved_view_cubit.dart import 'package:paperless_mobile/features/saved_view/view/add_saved_view_page.dart'; import 'package:paperless_mobile/features/saved_view/view/saved_view_list.dart'; import 'package:paperless_mobile/features/search_app_bar/view/search_app_bar.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/message_helpers.dart'; @@ -247,55 +248,62 @@ class _DocumentsPageState extends State onRefresh: _onReloadDocuments, notificationPredicate: (_) => connectivityState.isConnected, - child: CustomScrollView( - key: const PageStorageKey("documents"), - slivers: [ - SliverOverlapInjector( - handle: NestedScrollView - .sliverOverlapAbsorberHandleFor( - context), - ), - _buildViewActions(), + child: BlocBuilder( - builder: (context, state) { - if (state.hasLoaded && - state.documents.isEmpty) { - return SliverToBoxAdapter( - child: DocumentsEmptyState( - state: state, - onReset: () { - context - .read() - .resetFilter(); - }, - ), - ); - } + builder: (context, state) { + return CustomScrollView( + key: const PageStorageKey( + "documents"), + slivers: [ + SliverOverlapInjector( + handle: NestedScrollView + .sliverOverlapAbsorberHandleFor( + context), + ), + _buildViewActions(), + Builder( + builder: (context) { + if (state.hasLoaded && + state.documents.isEmpty) { + return SliverToBoxAdapter( + child: DocumentsEmptyState( + state: state, + onReset: () { + context + .read() + .resetFilter(); + }, + ), + ); + } - return SliverAdaptiveDocumentsView( - viewType: state.viewType, - onTap: _openDetails, - onSelected: context - .read() - .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, - ); - }, - ), - ], + return SliverAdaptiveDocumentsView( + viewType: state.viewType, + onTap: _openDetails, + onSelected: context + .read() + .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, + ); + }, + ), + ], + ); + }, ), ); }, diff --git a/lib/features/documents/view/widgets/adaptive_documents_view.dart b/lib/features/documents/view/widgets/adaptive_documents_view.dart index eb997a5..fd88235 100644 --- a/lib/features/documents/view/widgets/adaptive_documents_view.dart +++ b/lib/features/documents/view/widgets/adaptive_documents_view.dart @@ -3,6 +3,7 @@ import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/core/repository/provider/label_repositories_provider.dart'; import 'package:paperless_mobile/features/documents/view/widgets/document_grid_loading_widget.dart'; import 'package:paperless_mobile/features/documents/view/widgets/documents_list_loading_widget.dart'; +import 'package:paperless_mobile/features/documents/view/widgets/items/document_detailed_item.dart'; import 'package:paperless_mobile/features/documents/view/widgets/items/document_grid_item.dart'; import 'package:paperless_mobile/features/documents/view/widgets/items/document_list_item.dart'; import 'package:paperless_mobile/features/settings/model/view_type.dart'; @@ -69,6 +70,8 @@ class SliverAdaptiveDocumentsView extends AdaptiveDocumentsView { return _buildGridView(); case ViewType.list: return _buildListView(); + case ViewType.detailed: + return _buildFullView(); } } @@ -101,6 +104,36 @@ class SliverAdaptiveDocumentsView extends AdaptiveDocumentsView { ); } + Widget _buildFullView() { + if (showLoadingPlaceholder) { + //TODO: Build detailed loading animation + return DocumentsListLoadingWidget.sliver(); + } + return SliverList( + delegate: SliverChildBuilderDelegate( + childCount: documents.length, + (context, index) { + final document = documents.elementAt(index); + return LabelRepositoriesProvider( + child: DocumentDetailedItem( + isLabelClickable: isLabelClickable, + document: document, + onTap: onTap, + isSelected: selectedDocumentIds.contains(document.id), + onSelected: onSelected, + isSelectionActive: selectedDocumentIds.isNotEmpty, + onTagSelected: onTagSelected, + onCorrespondentSelected: onCorrespondentSelected, + onDocumentTypeSelected: onDocumentTypeSelected, + onStoragePathSelected: onStoragePathSelected, + enableHeroAnimation: enableHeroAnimation, + ), + ); + }, + ), + ); + } + Widget _buildGridView() { if (showLoadingPlaceholder) { return DocumentGridLoadingWidget.sliver(); @@ -161,6 +194,8 @@ class DefaultAdaptiveDocumentsView extends AdaptiveDocumentsView { return _buildGridView(); case ViewType.list: return _buildListView(); + case ViewType.detailed: + return _buildFullView(); } } @@ -194,6 +229,37 @@ class DefaultAdaptiveDocumentsView extends AdaptiveDocumentsView { ); } + Widget _buildFullView() { + if (showLoadingPlaceholder) { + return DocumentsListLoadingWidget(); + } + + return ListView.builder( + physics: const PageScrollPhysics(), + controller: scrollController, + primary: false, + itemCount: documents.length, + itemBuilder: (context, index) { + final document = documents.elementAt(index); + return LabelRepositoriesProvider( + child: DocumentDetailedItem( + isLabelClickable: isLabelClickable, + document: document, + onTap: onTap, + isSelected: selectedDocumentIds.contains(document.id), + onSelected: onSelected, + isSelectionActive: selectedDocumentIds.isNotEmpty, + onTagSelected: onTagSelected, + onCorrespondentSelected: onCorrespondentSelected, + onDocumentTypeSelected: onDocumentTypeSelected, + onStoragePathSelected: onStoragePathSelected, + enableHeroAnimation: enableHeroAnimation, + ), + ); + }, + ); + } + Widget _buildGridView() { if (showLoadingPlaceholder) { return DocumentGridLoadingWidget(); diff --git a/lib/features/documents/view/widgets/items/document_detailed_item.dart b/lib/features/documents/view/widgets/items/document_detailed_item.dart new file mode 100644 index 0000000..2ab6115 --- /dev/null +++ b/lib/features/documents/view/widgets/items/document_detailed_item.dart @@ -0,0 +1,32 @@ + +import 'package:flutter/material.dart'; +import 'package:paperless_mobile/features/documents/view/widgets/document_preview.dart'; +import 'package:paperless_mobile/features/documents/view/widgets/items/document_item.dart'; + +class DocumentDetailedItem extends DocumentItem { + const DocumentDetailedItem({ + super.key, + required super.document, + required super.isSelected, + required super.isSelectionActive, + required super.isLabelClickable, + required super.enableHeroAnimation, + super.onCorrespondentSelected, + super.onDocumentTypeSelected, + super.onSelected, + super.onStoragePathSelected, + super.onTagSelected, + super.onTap, + }); + + @override + Widget build(BuildContext context) { + return Card( + child: Column( + children: [ + DocumentPreview(id: document.id), + ], + ), + ); + } +} diff --git a/lib/features/documents/view/widgets/selection/view_type_selection_widget.dart b/lib/features/documents/view/widgets/selection/view_type_selection_widget.dart index 66ae74c..fdaa64a 100644 --- a/lib/features/documents/view/widgets/selection/view_type_selection_widget.dart +++ b/lib/features/documents/view/widgets/selection/view_type_selection_widget.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/features/settings/model/view_type.dart'; /// Meant to be used with blocbuilder. @@ -14,13 +15,56 @@ class ViewTypeSelectionWidget extends StatelessWidget { @override Widget build(BuildContext context) { - final next = viewType.toggle(); - final icon = next == ViewType.grid ? Icons.grid_view_rounded : Icons.list; - return IconButton( - icon: Icon(icon), - onPressed: () { + late final IconData icon; + switch (viewType) { + case ViewType.grid: + icon = Icons.grid_view_rounded; + break; + case ViewType.list: + icon = Icons.list; + break; + case ViewType.detailed: + icon = Icons.article_outlined; + break; + } + return PopupMenuButton( + child: Icon(icon), + itemBuilder: (context) => [ + _buildViewTypeOption( + ViewType.list, + 'List', + Icons.list, + ), + _buildViewTypeOption( + ViewType.grid, + 'Grid', + Icons.grid_view_rounded, + ), + _buildViewTypeOption( + ViewType.detailed, + 'Detailed', + Icons.article_outlined, + ), + ], + onSelected: (next) { onChanged(next); }, ); } + + PopupMenuItem _buildViewTypeOption( + ViewType type, + String label, + IconData icon, + ) { + return PopupMenuItem( + value: type, + child: ListTile( + selected: type == viewType, + trailing: type == viewType ? const Icon(Icons.done) : null, + title: Text(label), + leading: Icon(icon), + ), + ); + } } diff --git a/lib/features/settings/model/view_type.dart b/lib/features/settings/model/view_type.dart index 6407dec..57ff3c5 100644 --- a/lib/features/settings/model/view_type.dart +++ b/lib/features/settings/model/view_type.dart @@ -1,8 +1,9 @@ enum ViewType { grid, - list; + list, + detailed; ViewType toggle() { - return this == grid ? list : grid; + return ViewType.values[(index + 1) % ViewType.values.length]; } }