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

View File

@@ -1,5 +1,7 @@
import 'package:flutter/material.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/features/documents/view/widgets/document_preview.dart';
import 'package:paperless_mobile/features/documents/view/widgets/items/document_item.dart';
@@ -26,6 +28,7 @@ class DocumentGridItem extends DocumentItem {
@override
Widget build(BuildContext context) {
var currentUser = context.watch<LocalUserAccount>().paperlessUser;
return Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
@@ -64,15 +67,16 @@ class DocumentGridItem extends DocumentItem {
const SliverToBoxAdapter(
child: SizedBox(width: 8),
),
TagsWidget.sliver(
tags: document.tags
.map((e) => context
.watch<LabelRepository>()
.state
.tags[e]!)
.toList(),
onTagSelected: onTagSelected,
),
if (currentUser.canViewTags)
TagsWidget.sliver(
tags: document.tags
.map((e) => context
.watch<LabelRepository>()
.state
.tags[e]!)
.toList(),
onTagSelected: onTagSelected,
),
const SliverToBoxAdapter(
child: SizedBox(width: 8),
),
@@ -90,20 +94,22 @@ class DocumentGridItem extends DocumentItem {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
CorrespondentWidget(
correspondent: context
.watch<LabelRepository>()
.state
.correspondents[document.correspondent],
onSelected: onCorrespondentSelected,
),
DocumentTypeWidget(
documentType: context
.watch<LabelRepository>()
.state
.documentTypes[document.documentType],
onSelected: onDocumentTypeSelected,
),
if (currentUser.canViewCorrespondents)
CorrespondentWidget(
correspondent: context
.watch<LabelRepository>()
.state
.correspondents[document.correspondent],
onSelected: onCorrespondentSelected,
),
if (currentUser.canViewDocumentTypes)
DocumentTypeWidget(
documentType: context
.watch<LabelRepository>()
.state
.documentTypes[document.documentType],
onSelected: onDocumentTypeSelected,
),
Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Text(

View File

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

View File

@@ -158,6 +158,7 @@ class HomeShellWidget extends StatelessWidget {
return MultiProvider(
providers: [
Provider(
lazy: false,
create: (context) => DocumentsCubit(
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/landing/view/widgets/expansion_card.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/routes/routes.dart';
import 'package:paperless_mobile/routes/typed/branches/documents_route.dart';
@@ -52,6 +54,27 @@ class _LandingPageState extends State<LandingPage> {
).padded(24),
),
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:paperless_mobile/extensions/flutter_extensions.dart';
class ExpansionCard extends StatelessWidget {
final Widget title;
@@ -10,7 +9,7 @@ class ExpansionCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Card(
margin: EdgeInsets.all(16),
margin: const EdgeInsets.all(16),
child: Theme(
data: Theme.of(context).copyWith(
dividerColor: Colors.transparent,
@@ -23,6 +22,7 @@ class ExpansionCard extends StatelessWidget {
),
),
child: ExpansionTile(
backgroundColor: Theme.of(context).colorScheme.surface,
initiallyExpanded: true,
title: title,
children: [content],

View File

@@ -29,6 +29,7 @@ class SavedViewDetailsCubit extends Cubit<SavedViewDetailsState>
this._labelRepository,
this._userState, {
required this.savedView,
int initialCount = 25,
}) : super(
SavedViewDetailsState(
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) {

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