Hooked notifications to status changes on document upload - some refactorings

This commit is contained in:
Anton Stubenbord
2023-01-11 01:26:36 +01:00
parent 8cf3020335
commit a4c4726c16
55 changed files with 1128 additions and 761 deletions

View File

@@ -1,65 +0,0 @@
import 'package:flutter/material.dart';
import 'package:paperless_api/paperless_api.dart';
import 'package:paperless_mobile/core/widgets/documents_list_loading_widget.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/grid/document_grid_item.dart';
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
class DocumentGridView extends StatelessWidget {
final void Function(DocumentModel model) onTap;
final void Function(DocumentModel) onSelected;
final PagingController<int, DocumentModel> pagingController;
final DocumentsState state;
final bool hasInternetConnection;
final void Function(int tagId) onTagSelected;
final void Function(int correspondentId) onCorrespondentSelected;
final void Function(int correspondentId) onDocumentTypeSelected;
final void Function(int? id)? onStoragePathSelected;
const DocumentGridView({
super.key,
required this.onTap,
required this.pagingController,
required this.state,
required this.onSelected,
required this.hasInternetConnection,
required this.onTagSelected,
required this.onCorrespondentSelected,
required this.onDocumentTypeSelected,
this.onStoragePathSelected,
});
@override
Widget build(BuildContext context) {
return PagedSliverGrid<int, DocumentModel>(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 4,
crossAxisSpacing: 4,
childAspectRatio: 1 / 2,
),
pagingController: pagingController,
builderDelegate: PagedChildBuilderDelegate(
itemBuilder: (context, item, index) {
return DocumentGridItem(
document: item,
onTap: onTap,
isSelected: state.selection.contains(item),
onSelected: onSelected,
isAtLeastOneSelected: state.selection.isNotEmpty,
isTagSelectedPredicate: (int tagId) {
return state.filter.tags is IdsTagsQuery
? (state.filter.tags as IdsTagsQuery)
.includedIds
.contains(tagId)
: false;
},
onTagSelected: onTagSelected,
);
},
noItemsFoundIndicatorBuilder: (context) =>
const DocumentsListLoadingWidget(), //TODO: Replace with grid loading widget
),
);
}
}

View File

@@ -13,7 +13,7 @@ class DocumentGridItem extends StatelessWidget {
final void Function(DocumentModel) onSelected;
final bool isAtLeastOneSelected;
final bool Function(int tagId) isTagSelectedPredicate;
final void Function(int tagId) onTagSelected;
final void Function(int tagId)? onTagSelected;
const DocumentGridItem({
Key? key,
@@ -57,9 +57,11 @@ class DocumentGridItem extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
CorrespondentWidget(
correspondentId: document.correspondent),
correspondentId: document.correspondent,
),
DocumentTypeWidget(
documentTypeId: document.documentType),
documentTypeId: document.documentType,
),
Text(
document.title,
maxLines: document.tags.isEmpty ? 3 : 2,

View File

@@ -0,0 +1,118 @@
import 'package:flutter/material.dart';
import 'package:paperless_api/paperless_api.dart';
import 'package:paperless_mobile/core/repository/provider/label_repositories_provider.dart';
import 'package:paperless_mobile/features/documents/bloc/documents_state.dart';
import 'package:paperless_mobile/features/documents/view/widgets/grid/document_grid_item.dart';
import 'package:paperless_mobile/features/documents/view/widgets/list/document_list_item.dart';
import 'package:paperless_mobile/features/settings/model/view_type.dart';
class AdaptiveDocumentsView extends StatelessWidget {
final ViewType viewType;
final Widget beforeItems;
final void Function(DocumentModel) onTap;
final void Function(DocumentModel) onSelected;
final ScrollController scrollController;
final DocumentsState state;
final bool hasInternetConnection;
final bool isLabelClickable;
final void Function(int id)? onTagSelected;
final void Function(int? id)? onCorrespondentSelected;
final void Function(int? id)? onDocumentTypeSelected;
final void Function(int? id)? onStoragePathSelected;
final Widget pageLoadingWidget;
const AdaptiveDocumentsView({
super.key,
required this.onTap,
required this.scrollController,
required this.state,
required this.onSelected,
required this.hasInternetConnection,
this.isLabelClickable = true,
this.onTagSelected,
this.onCorrespondentSelected,
this.onDocumentTypeSelected,
this.onStoragePathSelected,
required this.pageLoadingWidget,
required this.beforeItems,
required this.viewType,
});
@override
Widget build(BuildContext context) {
return CustomScrollView(
controller: scrollController,
slivers: [
SliverToBoxAdapter(child: beforeItems),
if (viewType == ViewType.list) _buildListView() else _buildGridView(),
],
);
}
SliverList _buildListView() {
return SliverList(
delegate: SliverChildBuilderDelegate(
childCount: state.documents.length,
(context, index) {
final document = state.documents.elementAt(index);
return LabelRepositoriesProvider(
child: DocumentListItem(
isLabelClickable: isLabelClickable,
document: document,
onTap: onTap,
isSelected: state.selectedIds.contains(document.id),
onSelected: onSelected,
isAtLeastOneSelected: state.selection.isNotEmpty,
isTagSelectedPredicate: (int tagId) {
return state.filter.tags is IdsTagsQuery
? (state.filter.tags as IdsTagsQuery)
.includedIds
.contains(tagId)
: false;
},
onTagSelected: onTagSelected,
onCorrespondentSelected: onCorrespondentSelected,
onDocumentTypeSelected: onDocumentTypeSelected,
onStoragePathSelected: onStoragePathSelected,
),
);
},
),
);
}
Widget _buildGridView() {
return SliverGrid.builder(
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 178,
mainAxisSpacing: 4,
crossAxisSpacing: 4,
childAspectRatio: 1 / 2,
),
itemCount: state.documents.length,
itemBuilder: (context, index) {
if (state.hasLoaded &&
state.isLoading &&
index == state.documents.length) {
return Center(child: pageLoadingWidget);
}
final document = state.documents.elementAt(index);
return DocumentGridItem(
document: document,
onTap: onTap,
isSelected: state.selectedIds.contains(document.id),
onSelected: onSelected,
isAtLeastOneSelected: state.selection.isNotEmpty,
isTagSelectedPredicate: (int tagId) {
return state.filter.tags is IdsTagsQuery
? (state.filter.tags as IdsTagsQuery)
.includedIds
.contains(tagId)
: false;
},
onTagSelected: onTagSelected,
);
},
);
}
}

View File

@@ -1,73 +0,0 @@
import 'package:flutter/material.dart';
import 'package:paperless_api/paperless_api.dart';
import 'package:paperless_mobile/core/repository/provider/label_repositories_provider.dart';
import 'package:paperless_mobile/core/widgets/documents_list_loading_widget.dart';
import 'package:paperless_mobile/core/widgets/offline_widget.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/list/document_list_item.dart';
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
class DocumentListView extends StatelessWidget {
final void Function(DocumentModel) onTap;
final void Function(DocumentModel) onSelected;
final PagingController<int, DocumentModel> pagingController;
final DocumentsState state;
final bool hasInternetConnection;
final bool isLabelClickable;
final void Function(int id)? onTagSelected;
final void Function(int? id)? onCorrespondentSelected;
final void Function(int? id)? onDocumentTypeSelected;
final void Function(int? id)? onStoragePathSelected;
const DocumentListView({
super.key,
required this.onTap,
required this.pagingController,
required this.state,
required this.onSelected,
required this.hasInternetConnection,
this.isLabelClickable = true,
this.onTagSelected,
this.onCorrespondentSelected,
this.onDocumentTypeSelected,
this.onStoragePathSelected,
});
@override
Widget build(BuildContext context) {
return PagedSliverList<int, DocumentModel>(
pagingController: pagingController,
builderDelegate: PagedChildBuilderDelegate(
animateTransitions: true,
itemBuilder: (context, document, index) {
return LabelRepositoriesProvider(
child: DocumentListItem(
isLabelClickable: isLabelClickable,
document: document,
onTap: onTap,
isSelected: state.selection.contains(document),
onSelected: onSelected,
isAtLeastOneSelected: state.selection.isNotEmpty,
isTagSelectedPredicate: (int tagId) {
return state.filter.tags is IdsTagsQuery
? (state.filter.tags as IdsTagsQuery)
.includedIds
.contains(tagId)
: false;
},
onTagSelected: onTagSelected,
onCorrespondentSelected: onCorrespondentSelected,
onDocumentTypeSelected: onDocumentTypeSelected,
onStoragePathSelected: onStoragePathSelected,
),
);
},
noItemsFoundIndicatorBuilder: (context) => hasInternetConnection
? const DocumentsListLoadingWidget()
: const OfflineWidget(),
),
);
}
}

View File

@@ -38,6 +38,7 @@ class DocumentListItem extends StatelessWidget {
Widget build(BuildContext context) {
return SizedBox(
child: ListTile(
trailing: Text("${document.id}"),
dense: true,
selected: isSelected,
onTap: () => _onTap(),

View File

@@ -0,0 +1,10 @@
import 'package:flutter/material.dart';
class NewItemsLoadingWidget extends StatelessWidget {
const NewItemsLoadingWidget({super.key});
@override
Widget build(BuildContext context) {
return const CircularProgressIndicator();
}
}

View File

@@ -138,3 +138,19 @@ class _DocumentsPageAppBarState extends State<DocumentsPageAppBar> {
return count > 99 ? "99+" : count.toString();
}
}
class ScrollListener extends ChangeNotifier {
double top = 0;
double _last = 0;
ScrollListener.initialise(ScrollController controller, [double height = 56]) {
controller.addListener(() {
final current = controller.offset;
top += _last - current;
if (top <= -height) top = -height;
if (top >= 0) top = 0;
_last = current;
if (top <= 0 && top >= -height) notifyListeners();
});
}
}