feat: Add saved views to landing page

This commit is contained in:
Anton Stubenbord
2023-08-01 19:49:09 +02:00
parent 53a01ae775
commit b79375cbe0
10 changed files with 198 additions and 36 deletions

View File

@@ -61,15 +61,15 @@ class _DocumentsPageState extends State<DocumentsPage>
length: showSavedViews ? 2 : 1, length: showSavedViews ? 2 : 1,
vsync: this, vsync: this,
); );
Future.wait([ // Future.wait([
context.read<DocumentsCubit>().reload(), // context.read<DocumentsCubit>().reload(),
context.read<SavedViewCubit>().reload(), // context.read<SavedViewCubit>().reload(),
]).onError<PaperlessApiException>( // ]).onError<PaperlessApiException>(
(error, stackTrace) { // (error, stackTrace) {
showErrorMessage(context, error, stackTrace); // showErrorMessage(context, error, stackTrace);
return []; // return [];
}, // },
); // );
_tabController.addListener(_tabChangesListener); _tabController.addListener(_tabChangesListener);
} }
@@ -117,7 +117,7 @@ class _DocumentsPageState extends State<DocumentsPage>
return SafeArea( return SafeArea(
top: true, top: true,
child: Scaffold( child: Scaffold(
drawer: AppDrawer(), drawer: const AppDrawer(),
floatingActionButton: BlocBuilder<DocumentsCubit, DocumentsState>( floatingActionButton: BlocBuilder<DocumentsCubit, DocumentsState>(
builder: (context, state) { builder: (context, state) {
final appliedFiltersCount = state.filter.appliedFiltersCount; final appliedFiltersCount = state.filter.appliedFiltersCount;

View File

@@ -1,5 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:paperless_api/paperless_api.dart';
import 'package:paperless_mobile/core/database/tables/local_user_account.dart';
import 'package:paperless_mobile/core/repository/label_repository.dart'; import 'package:paperless_mobile/core/repository/label_repository.dart';
import 'package:paperless_mobile/features/documents/view/widgets/document_preview.dart'; import 'package:paperless_mobile/features/documents/view/widgets/document_preview.dart';
import 'package:paperless_mobile/features/documents/view/widgets/items/document_item.dart'; import 'package:paperless_mobile/features/documents/view/widgets/items/document_item.dart';
@@ -26,6 +28,7 @@ class DocumentGridItem extends DocumentItem {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var currentUser = context.watch<LocalUserAccount>().paperlessUser;
return Padding( return Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Card( child: Card(
@@ -64,6 +67,7 @@ class DocumentGridItem extends DocumentItem {
const SliverToBoxAdapter( const SliverToBoxAdapter(
child: SizedBox(width: 8), child: SizedBox(width: 8),
), ),
if (currentUser.canViewTags)
TagsWidget.sliver( TagsWidget.sliver(
tags: document.tags tags: document.tags
.map((e) => context .map((e) => context
@@ -90,6 +94,7 @@ class DocumentGridItem extends DocumentItem {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
if (currentUser.canViewCorrespondents)
CorrespondentWidget( CorrespondentWidget(
correspondent: context correspondent: context
.watch<LabelRepository>() .watch<LabelRepository>()
@@ -97,6 +102,7 @@ class DocumentGridItem extends DocumentItem {
.correspondents[document.correspondent], .correspondents[document.correspondent],
onSelected: onCorrespondentSelected, onSelected: onCorrespondentSelected,
), ),
if (currentUser.canViewDocumentTypes)
DocumentTypeWidget( DocumentTypeWidget(
documentType: context documentType: context
.watch<LabelRepository>() .watch<LabelRepository>()

View File

@@ -11,8 +11,10 @@ import 'package:provider/provider.dart';
class DocumentListItem extends DocumentItem { class DocumentListItem extends DocumentItem {
static const _a4AspectRatio = 1 / 1.4142; static const _a4AspectRatio = 1 / 1.4142;
final Color? backgroundColor;
const DocumentListItem({ const DocumentListItem({
super.key, super.key,
this.backgroundColor,
required super.document, required super.document,
required super.isSelected, required super.isSelected,
required super.isSelectionActive, required super.isSelectionActive,
@@ -31,6 +33,7 @@ class DocumentListItem extends DocumentItem {
final labels = context.watch<LabelRepository>().state; final labels = context.watch<LabelRepository>().state;
return Material( return Material(
child: ListTile( child: ListTile(
tileColor: backgroundColor,
dense: true, dense: true,
selected: isSelected, selected: isSelected,
onTap: () => _onTap(), onTap: () => _onTap(),

View File

@@ -158,6 +158,7 @@ class HomeShellWidget extends StatelessWidget {
return MultiProvider( return MultiProvider(
providers: [ providers: [
Provider( Provider(
lazy: false,
create: (context) => DocumentsCubit( create: (context) => DocumentsCubit(
context.read(), context.read(),
context.read(), context.read(),

View File

@@ -8,6 +8,8 @@ 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/document_search/view/sliver_search_bar.dart';
import 'package:paperless_mobile/features/landing/view/widgets/expansion_card.dart'; import 'package:paperless_mobile/features/landing/view/widgets/expansion_card.dart';
import 'package:paperless_mobile/features/landing/view/widgets/mime_types_pie_chart.dart'; import 'package:paperless_mobile/features/landing/view/widgets/mime_types_pie_chart.dart';
import 'package:paperless_mobile/features/saved_view/cubit/saved_view_cubit.dart';
import 'package:paperless_mobile/features/saved_view_details/view/saved_view_details_preview.dart';
import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
import 'package:paperless_mobile/routes/routes.dart'; import 'package:paperless_mobile/routes/routes.dart';
import 'package:paperless_mobile/routes/typed/branches/documents_route.dart'; import 'package:paperless_mobile/routes/typed/branches/documents_route.dart';
@@ -52,6 +54,27 @@ class _LandingPageState extends State<LandingPage> {
).padded(24), ).padded(24),
), ),
SliverToBoxAdapter(child: _buildStatisticsCard(context)), SliverToBoxAdapter(child: _buildStatisticsCard(context)),
BlocBuilder<SavedViewCubit, SavedViewState>(
builder: (context, state) {
return state.maybeWhen(
loaded: (savedViews) {
return SliverList.builder(
itemBuilder: (context, index) {
return SavedViewDetailsPreview(
savedView: savedViews.values.elementAt(index),
);
},
itemCount: savedViews.length,
);
},
orElse: () => const SliverToBoxAdapter(
child: Center(
child: CircularProgressIndicator(),
),
),
);
},
)
], ],
), ),
), ),

View File

@@ -1,5 +1,4 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
class ExpansionCard extends StatelessWidget { class ExpansionCard extends StatelessWidget {
final Widget title; final Widget title;
@@ -10,7 +9,7 @@ class ExpansionCard extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Card( return Card(
margin: EdgeInsets.all(16), margin: const EdgeInsets.all(16),
child: Theme( child: Theme(
data: Theme.of(context).copyWith( data: Theme.of(context).copyWith(
dividerColor: Colors.transparent, dividerColor: Colors.transparent,
@@ -23,6 +22,7 @@ class ExpansionCard extends StatelessWidget {
), ),
), ),
child: ExpansionTile( child: ExpansionTile(
backgroundColor: Theme.of(context).colorScheme.surface,
initiallyExpanded: true, initiallyExpanded: true,
title: title, title: title,
children: [content], children: [content],

View File

@@ -29,6 +29,7 @@ class SavedViewDetailsCubit extends Cubit<SavedViewDetailsState>
this._labelRepository, this._labelRepository,
this._userState, { this._userState, {
required this.savedView, required this.savedView,
int initialCount = 25,
}) : super( }) : super(
SavedViewDetailsState( SavedViewDetailsState(
correspondents: _labelRepository.state.correspondents, correspondents: _labelRepository.state.correspondents,
@@ -56,7 +57,12 @@ class SavedViewDetailsCubit extends Cubit<SavedViewDetailsState>
} }
}, },
); );
updateFilter(filter: savedView.toDocumentFilter()); updateFilter(
filter: savedView.toDocumentFilter().copyWith(
page: 1,
pageSize: initialCount,
),
);
} }
void setViewType(ViewType viewType) { void setViewType(ViewType viewType) {

View File

@@ -0,0 +1,28 @@
import 'package:bloc/bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:paperless_api/paperless_api.dart';
part 'saved_view_preview_state.dart';
part 'saved_view_preview_cubit.freezed.dart';
class SavedViewPreviewCubit extends Cubit<SavedViewPreviewState> {
final PaperlessDocumentsApi _api;
final SavedView view;
SavedViewPreviewCubit(this._api, this.view)
: super(const SavedViewPreviewState.initial());
Future<void> initialize() async {
emit(const SavedViewPreviewState.loading());
try {
final documents = await _api.findAll(
view.toDocumentFilter().copyWith(
page: 1,
pageSize: 5,
),
);
emit(SavedViewPreviewState.loaded(documents: documents.results));
} catch (e) {
emit(const SavedViewPreviewState.error());
}
}
}

View File

@@ -0,0 +1,11 @@
part of 'saved_view_preview_cubit.dart';
@freezed
class SavedViewPreviewState with _$SavedViewPreviewState {
const factory SavedViewPreviewState.initial() = _Initial;
const factory SavedViewPreviewState.loading() = _Loading;
const factory SavedViewPreviewState.loaded({
required List<DocumentModel> documents,
}) = _Loaded;
const factory SavedViewPreviewState.error() = _Error;
}

View File

@@ -0,0 +1,84 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:paperless_api/paperless_api.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/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_details_cubit.dart';
import 'package:paperless_mobile/features/saved_view_details/cubit/saved_view_preview_cubit.dart';
import 'package:paperless_mobile/routes/typed/branches/documents_route.dart';
import 'package:provider/provider.dart';
class SavedViewDetailsPreview extends StatelessWidget {
final SavedView savedView;
const SavedViewDetailsPreview({
super.key,
required this.savedView,
});
@override
Widget build(BuildContext context) {
return Provider(
create: (context) =>
SavedViewPreviewCubit(context.read(), savedView)..initialize(),
builder: (context, child) {
return ExpansionCard(
title: Text(savedView.name),
content: BlocBuilder<SavedViewPreviewCubit, SavedViewPreviewState>(
builder: (context, state) {
return Column(
children: [
state.maybeWhen(
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 more"),
onPressed: documents.length >= 5 ? () {} : null,
),
TextButton.icon(
icon: Icon(Icons.open_in_new),
label: Text("Show in documents"),
onPressed: () {
context.read<DocumentsCubit>().updateFilter(
filter: savedView.toDocumentFilter(),
);
DocumentsRoute().go(context);
},
),
],
),
],
);
},
error: () =>
const Text("Error loading preview"), //TODO: INTL
orElse: () => const Padding(
padding: EdgeInsets.all(8.0),
child: Center(child: CircularProgressIndicator()),
),
),
],
);
},
),
);
},
);
}
}