feat: Add detailed view type

This commit is contained in:
Anton Stubenbord
2023-02-12 18:48:24 +01:00
parent edd8b899c8
commit 681d551b56
5 changed files with 205 additions and 54 deletions

View File

@@ -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/add_saved_view_page.dart';
import 'package:paperless_mobile/features/saved_view/view/saved_view_list.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/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/features/tasks/cubit/task_status_cubit.dart';
import 'package:paperless_mobile/generated/l10n.dart'; import 'package:paperless_mobile/generated/l10n.dart';
import 'package:paperless_mobile/helpers/message_helpers.dart'; import 'package:paperless_mobile/helpers/message_helpers.dart';
@@ -247,55 +248,62 @@ class _DocumentsPageState extends State<DocumentsPage>
onRefresh: _onReloadDocuments, onRefresh: _onReloadDocuments,
notificationPredicate: (_) => notificationPredicate: (_) =>
connectivityState.isConnected, connectivityState.isConnected,
child: CustomScrollView( child:
key: const PageStorageKey<String>("documents"),
slivers: <Widget>[
SliverOverlapInjector(
handle: NestedScrollView
.sliverOverlapAbsorberHandleFor(
context),
),
_buildViewActions(),
BlocBuilder<DocumentsCubit, DocumentsState>( BlocBuilder<DocumentsCubit, DocumentsState>(
builder: (context, state) { builder: (context, state) {
if (state.hasLoaded && return CustomScrollView(
state.documents.isEmpty) { key: const PageStorageKey<String>(
return SliverToBoxAdapter( "documents"),
child: DocumentsEmptyState( slivers: <Widget>[
state: state, SliverOverlapInjector(
onReset: () { handle: NestedScrollView
context .sliverOverlapAbsorberHandleFor(
.read<DocumentsCubit>() context),
.resetFilter(); ),
}, _buildViewActions(),
), Builder(
); builder: (context) {
} if (state.hasLoaded &&
state.documents.isEmpty) {
return SliverToBoxAdapter(
child: DocumentsEmptyState(
state: state,
onReset: () {
context
.read<DocumentsCubit>()
.resetFilter();
},
),
);
}
return SliverAdaptiveDocumentsView( return SliverAdaptiveDocumentsView(
viewType: state.viewType, viewType: state.viewType,
onTap: _openDetails, onTap: _openDetails,
onSelected: context onSelected: context
.read<DocumentsCubit>() .read<DocumentsCubit>()
.toggleDocumentSelection, .toggleDocumentSelection,
hasInternetConnection: hasInternetConnection:
connectivityState.isConnected, connectivityState.isConnected,
onTagSelected: _addTagToFilter, onTagSelected: _addTagToFilter,
onCorrespondentSelected: onCorrespondentSelected:
_addCorrespondentToFilter, _addCorrespondentToFilter,
onDocumentTypeSelected: onDocumentTypeSelected:
_addDocumentTypeToFilter, _addDocumentTypeToFilter,
onStoragePathSelected: onStoragePathSelected:
_addStoragePathToFilter, _addStoragePathToFilter,
documents: state.documents, documents: state.documents,
hasLoaded: state.hasLoaded, hasLoaded: state.hasLoaded,
isLabelClickable: true, isLabelClickable: true,
isLoading: state.isLoading, isLoading: state.isLoading,
selectedDocumentIds: state.selectedIds, selectedDocumentIds:
); state.selectedIds,
}, );
), },
], ),
],
);
},
), ),
); );
}, },

View File

@@ -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/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/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/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_grid_item.dart';
import 'package:paperless_mobile/features/documents/view/widgets/items/document_list_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'; import 'package:paperless_mobile/features/settings/model/view_type.dart';
@@ -69,6 +70,8 @@ class SliverAdaptiveDocumentsView extends AdaptiveDocumentsView {
return _buildGridView(); return _buildGridView();
case ViewType.list: case ViewType.list:
return _buildListView(); 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() { Widget _buildGridView() {
if (showLoadingPlaceholder) { if (showLoadingPlaceholder) {
return DocumentGridLoadingWidget.sliver(); return DocumentGridLoadingWidget.sliver();
@@ -161,6 +194,8 @@ class DefaultAdaptiveDocumentsView extends AdaptiveDocumentsView {
return _buildGridView(); return _buildGridView();
case ViewType.list: case ViewType.list:
return _buildListView(); 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() { Widget _buildGridView() {
if (showLoadingPlaceholder) { if (showLoadingPlaceholder) {
return DocumentGridLoadingWidget(); return DocumentGridLoadingWidget();

View File

@@ -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),
],
),
);
}
}

View File

@@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:paperless_api/paperless_api.dart';
import 'package:paperless_mobile/features/settings/model/view_type.dart'; import 'package:paperless_mobile/features/settings/model/view_type.dart';
/// Meant to be used with blocbuilder. /// Meant to be used with blocbuilder.
@@ -14,13 +15,56 @@ class ViewTypeSelectionWidget extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final next = viewType.toggle(); late final IconData icon;
final icon = next == ViewType.grid ? Icons.grid_view_rounded : Icons.list; switch (viewType) {
return IconButton( case ViewType.grid:
icon: Icon(icon), icon = Icons.grid_view_rounded;
onPressed: () { break;
case ViewType.list:
icon = Icons.list;
break;
case ViewType.detailed:
icon = Icons.article_outlined;
break;
}
return PopupMenuButton<ViewType>(
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); onChanged(next);
}, },
); );
} }
PopupMenuItem<ViewType> _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),
),
);
}
} }

View File

@@ -1,8 +1,9 @@
enum ViewType { enum ViewType {
grid, grid,
list; list,
detailed;
ViewType toggle() { ViewType toggle() {
return this == grid ? list : grid; return ViewType.values[(index + 1) % ViewType.values.length];
} }
} }