Cleaned up code, implemented message queue to notify subscribers of document updates.

This commit is contained in:
Anton Stubenbord
2023-02-06 01:04:13 +01:00
parent 337c178be8
commit 4d7fab1839
111 changed files with 1412 additions and 1029 deletions

View File

@@ -82,7 +82,7 @@ class _LabelsPageState extends State<LabelsPage>
context,
),
sliver: SearchAppBar(
hintText: "Search documents", //TODO: INTL
hintText: S.of(context).documentSearchSearchDocuments,
onOpenSearch: showDocumentSearchPage,
bottom: TabBar(
controller: _tabController,
@@ -141,176 +141,138 @@ class _LabelsPageState extends State<LabelsPage>
}
return true;
},
child: MultiBlocProvider(
providers: [
BlocProvider(
create: (context) => LabelCubit<Correspondent>(
context.read<
LabelRepository<Correspondent,
CorrespondentRepositoryState>>(),
child: RefreshIndicator(
edgeOffset: kToolbarHeight + kTextTabBarHeight,
notificationPredicate: (notification) =>
connectedState.isConnected,
onRefresh: () => [
context.read<LabelCubit<Correspondent>>(),
context.read<LabelCubit<DocumentType>>(),
context.read<LabelCubit<Tag>>(),
context.read<LabelCubit<StoragePath>>(),
][_currentIndex]
.reload(),
child: TabBarView(
controller: _tabController,
children: [
Builder(
builder: (context) {
return CustomScrollView(
slivers: [
SliverOverlapInjector(
handle: NestedScrollView
.sliverOverlapAbsorberHandleFor(context),
),
LabelTabView<Correspondent>(
filterBuilder: (label) => DocumentFilter(
correspondent:
IdQueryParameter.fromId(label.id),
pageSize: label.documentCount ?? 0,
),
onEdit: _openEditCorrespondentPage,
emptyStateActionButtonLabel: S
.of(context)
.labelsPageCorrespondentEmptyStateAddNewLabel,
emptyStateDescription: S
.of(context)
.labelsPageCorrespondentEmptyStateDescriptionText,
onAddNew: _openAddCorrespondentPage,
),
],
);
},
),
),
BlocProvider(
create: (context) => LabelCubit<DocumentType>(
context.read<
LabelRepository<DocumentType,
DocumentTypeRepositoryState>>(),
Builder(
builder: (context) {
return CustomScrollView(
slivers: [
SliverOverlapInjector(
handle: NestedScrollView
.sliverOverlapAbsorberHandleFor(context),
),
LabelTabView<DocumentType>(
filterBuilder: (label) => DocumentFilter(
documentType:
IdQueryParameter.fromId(label.id),
pageSize: label.documentCount ?? 0,
),
onEdit: _openEditDocumentTypePage,
emptyStateActionButtonLabel: S
.of(context)
.labelsPageDocumentTypeEmptyStateAddNewLabel,
emptyStateDescription: S
.of(context)
.labelsPageDocumentTypeEmptyStateDescriptionText,
onAddNew: _openAddDocumentTypePage,
),
],
);
},
),
),
BlocProvider(
create: (context) => LabelCubit<Tag>(
context
.read<LabelRepository<Tag, TagRepositoryState>>(),
Builder(
builder: (context) {
return CustomScrollView(
slivers: [
SliverOverlapInjector(
handle: NestedScrollView
.sliverOverlapAbsorberHandleFor(context),
),
LabelTabView<Tag>(
filterBuilder: (label) => DocumentFilter(
tags: IdsTagsQuery.fromIds([label.id!]),
pageSize: label.documentCount ?? 0,
),
onEdit: _openEditTagPage,
leadingBuilder: (t) => CircleAvatar(
backgroundColor: t.color,
child: t.isInboxTag ?? false
? Icon(
Icons.inbox,
color: t.textColor,
)
: null,
),
emptyStateActionButtonLabel: S
.of(context)
.labelsPageTagsEmptyStateAddNewLabel,
emptyStateDescription: S
.of(context)
.labelsPageTagsEmptyStateDescriptionText,
onAddNew: _openAddTagPage,
),
],
);
},
),
),
BlocProvider(
create: (context) => LabelCubit<StoragePath>(
context.read<
LabelRepository<StoragePath,
StoragePathRepositoryState>>(),
Builder(
builder: (context) {
return CustomScrollView(
slivers: [
SliverOverlapInjector(
handle: NestedScrollView
.sliverOverlapAbsorberHandleFor(context),
),
LabelTabView<StoragePath>(
onEdit: _openEditStoragePathPage,
filterBuilder: (label) => DocumentFilter(
storagePath:
IdQueryParameter.fromId(label.id),
pageSize: label.documentCount ?? 0,
),
contentBuilder: (path) => Text(path.path ?? ""),
emptyStateActionButtonLabel: S
.of(context)
.labelsPageStoragePathEmptyStateAddNewLabel,
emptyStateDescription: S
.of(context)
.labelsPageStoragePathEmptyStateDescriptionText,
onAddNew: _openAddStoragePathPage,
),
],
);
},
),
),
],
child: RefreshIndicator(
edgeOffset: kToolbarHeight,
notificationPredicate: (notification) =>
connectedState.isConnected,
onRefresh: () => [
context.read<LabelCubit<Correspondent>>(),
context.read<LabelCubit<DocumentType>>(),
context.read<LabelCubit<Tag>>(),
context.read<LabelCubit<StoragePath>>(),
][_currentIndex]
.reload(),
child: TabBarView(
controller: _tabController,
children: [
Builder(
builder: (context) {
return CustomScrollView(
slivers: [
SliverOverlapInjector(
handle: NestedScrollView
.sliverOverlapAbsorberHandleFor(context),
),
LabelTabView<Correspondent>(
filterBuilder: (label) => DocumentFilter(
correspondent:
IdQueryParameter.fromId(label.id),
pageSize: label.documentCount ?? 0,
),
onEdit: _openEditCorrespondentPage,
emptyStateActionButtonLabel: S
.of(context)
.labelsPageCorrespondentEmptyStateAddNewLabel,
emptyStateDescription: S
.of(context)
.labelsPageCorrespondentEmptyStateDescriptionText,
onAddNew: _openAddCorrespondentPage,
),
],
);
},
),
Builder(
builder: (context) {
return CustomScrollView(
slivers: [
SliverOverlapInjector(
handle: NestedScrollView
.sliverOverlapAbsorberHandleFor(context),
),
DocumentTypeBlocProvider(
child: LabelTabView<DocumentType>(
filterBuilder: (label) => DocumentFilter(
documentType:
IdQueryParameter.fromId(label.id),
pageSize: label.documentCount ?? 0,
),
onEdit: _openEditDocumentTypePage,
emptyStateActionButtonLabel: S
.of(context)
.labelsPageDocumentTypeEmptyStateAddNewLabel,
emptyStateDescription: S
.of(context)
.labelsPageDocumentTypeEmptyStateDescriptionText,
onAddNew: _openAddDocumentTypePage,
),
),
],
);
},
),
Builder(
builder: (context) {
return CustomScrollView(
slivers: [
SliverOverlapInjector(
handle: NestedScrollView
.sliverOverlapAbsorberHandleFor(context),
),
TagBlocProvider(
child: LabelTabView<Tag>(
filterBuilder: (label) => DocumentFilter(
tags: IdsTagsQuery.fromIds([label.id!]),
pageSize: label.documentCount ?? 0,
),
onEdit: _openEditTagPage,
leadingBuilder: (t) => CircleAvatar(
backgroundColor: t.color,
child: t.isInboxTag ?? false
? Icon(
Icons.inbox,
color: t.textColor,
)
: null,
),
emptyStateActionButtonLabel: S
.of(context)
.labelsPageTagsEmptyStateAddNewLabel,
emptyStateDescription: S
.of(context)
.labelsPageTagsEmptyStateDescriptionText,
onAddNew: _openAddTagPage,
),
),
],
);
},
),
Builder(
builder: (context) {
return CustomScrollView(
slivers: [
SliverOverlapInjector(
handle: NestedScrollView
.sliverOverlapAbsorberHandleFor(context),
),
StoragePathBlocProvider(
child: LabelTabView<StoragePath>(
onEdit: _openEditStoragePathPage,
filterBuilder: (label) => DocumentFilter(
storagePath:
IdQueryParameter.fromId(label.id),
pageSize: label.documentCount ?? 0,
),
contentBuilder: (path) =>
Text(path.path ?? ""),
emptyStateActionButtonLabel: S
.of(context)
.labelsPageStoragePathEmptyStateAddNewLabel,
emptyStateDescription: S
.of(context)
.labelsPageStoragePathEmptyStateDescriptionText,
onAddNew: _openAddStoragePathPage,
),
),
],
);
},
),
],
),
],
),
),
),
@@ -326,8 +288,7 @@ class _LabelsPageState extends State<LabelsPage>
context,
MaterialPageRoute(
builder: (_) => RepositoryProvider(
create: (context) => context.read<
LabelRepository<Correspondent, CorrespondentRepositoryState>>(),
create: (context) => context.read<LabelRepository<Correspondent>>(),
child: EditCorrespondentPage(correspondent: correspondent),
),
),
@@ -339,8 +300,7 @@ class _LabelsPageState extends State<LabelsPage>
context,
MaterialPageRoute(
builder: (_) => RepositoryProvider(
create: (context) => context.read<
LabelRepository<DocumentType, DocumentTypeRepositoryState>>(),
create: (context) => context.read<LabelRepository<DocumentType>>(),
child: EditDocumentTypePage(documentType: docType),
),
),
@@ -352,8 +312,7 @@ class _LabelsPageState extends State<LabelsPage>
context,
MaterialPageRoute(
builder: (_) => RepositoryProvider(
create: (context) =>
context.read<LabelRepository<Tag, TagRepositoryState>>(),
create: (context) => context.read<LabelRepository<Tag>>(),
child: EditTagPage(tag: tag),
),
),
@@ -365,8 +324,7 @@ class _LabelsPageState extends State<LabelsPage>
context,
MaterialPageRoute(
builder: (_) => RepositoryProvider(
create: (context) => context
.read<LabelRepository<StoragePath, StoragePathRepositoryState>>(),
create: (context) => context.read<LabelRepository<StoragePath>>(),
child: EditStoragePathPage(
storagePath: path,
),
@@ -380,8 +338,7 @@ class _LabelsPageState extends State<LabelsPage>
context,
MaterialPageRoute(
builder: (_) => RepositoryProvider(
create: (context) => context.read<
LabelRepository<Correspondent, CorrespondentRepositoryState>>(),
create: (context) => context.read<LabelRepository<Correspondent>>(),
child: const AddCorrespondentPage(),
),
),
@@ -393,8 +350,7 @@ class _LabelsPageState extends State<LabelsPage>
context,
MaterialPageRoute(
builder: (_) => RepositoryProvider(
create: (context) => context.read<
LabelRepository<DocumentType, DocumentTypeRepositoryState>>(),
create: (context) => context.read<LabelRepository<DocumentType>>(),
child: const AddDocumentTypePage(),
),
),
@@ -406,8 +362,7 @@ class _LabelsPageState extends State<LabelsPage>
context,
MaterialPageRoute(
builder: (_) => RepositoryProvider(
create: (context) =>
context.read<LabelRepository<Tag, TagRepositoryState>>(),
create: (context) => context.read<LabelRepository<Tag>>(),
child: const AddTagPage(),
),
),
@@ -419,8 +374,7 @@ class _LabelsPageState extends State<LabelsPage>
context,
MaterialPageRoute(
builder: (_) => RepositoryProvider(
create: (context) => context
.read<LabelRepository<StoragePath, StoragePathRepositoryState>>(),
create: (context) => context.read<LabelRepository<StoragePath>>(),
child: const AddStoragePathPage(),
),
),

View File

@@ -48,8 +48,9 @@ class LabelItem<T extends Label> extends StatelessWidget {
MaterialPageRoute(
builder: (context) => BlocProvider(
create: (context) => LinkedDocumentsCubit(
context.read<PaperlessDocumentsApi>(),
filter,
context.read(),
context.read(),
),
child: const LinkedDocumentsPage(),
),

View File

@@ -37,60 +37,65 @@ class LabelTabView<T extends Label> extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocBuilder<ConnectivityCubit, ConnectivityState>(
builder: (context, connectivityState) {
return BlocBuilder<LabelCubit<T>, LabelState<T>>(
builder: (context, state) {
if (!state.isLoaded && !connectivityState.isConnected) {
return const OfflineWidget();
}
final labels = state.labels.values.toList()..sort();
if (labels.isEmpty) {
return SliverFillRemaining(
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
emptyStateDescription,
textAlign: TextAlign.center,
),
TextButton(
onPressed: onAddNew,
child: Text(emptyStateActionButtonLabel),
),
].padded(),
return BlocProvider(
create: (context) => LabelCubit<T>(
context.read(),
),
child: BlocBuilder<ConnectivityCubit, ConnectivityState>(
builder: (context, connectivityState) {
return BlocBuilder<LabelCubit<T>, LabelState<T>>(
builder: (context, state) {
if (!state.isLoaded && !connectivityState.isConnected) {
return const OfflineWidget();
}
final labels = state.labels.values.toList()..sort();
if (labels.isEmpty) {
return SliverFillRemaining(
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
emptyStateDescription,
textAlign: TextAlign.center,
),
TextButton(
onPressed: onAddNew,
child: Text(emptyStateActionButtonLabel),
),
].padded(),
),
),
);
}
return SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
final l = labels.elementAt(index);
return LabelItem<T>(
name: l.name,
content: contentBuilder?.call(l) ??
Text(
translateMatchingAlgorithmName(
context, l.matchingAlgorithm) +
((l.match?.isNotEmpty ?? false)
? ": ${l.match}"
: ""),
maxLines: 2,
),
onOpenEditPage: onEdit,
filterBuilder: filterBuilder,
leading: leadingBuilder?.call(l),
label: l,
);
},
childCount: labels.length,
),
);
}
return SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
final l = labels.elementAt(index);
return LabelItem<T>(
name: l.name,
content: contentBuilder?.call(l) ??
Text(
translateMatchingAlgorithmName(
context, l.matchingAlgorithm) +
((l.match?.isNotEmpty ?? false)
? ": ${l.match}"
: ""),
maxLines: 2,
),
onOpenEditPage: onEdit,
filterBuilder: filterBuilder,
leading: leadingBuilder?.call(l),
label: l,
);
},
childCount: labels.length,
),
);
},
);
},
},
);
},
),
);
}
}

View File

@@ -2,13 +2,10 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:paperless_api/paperless_api.dart';
import 'package:paperless_mobile/core/repository/label_repository.dart';
import 'package:paperless_mobile/core/repository/state/repository_state.dart';
import 'package:paperless_mobile/features/labels/bloc/label_cubit.dart';
import 'package:paperless_mobile/features/labels/bloc/label_state.dart';
import 'package:paperless_mobile/features/labels/bloc/providers/document_type_bloc_provider.dart';
class LabelText<T extends Label, State extends RepositoryState>
extends StatelessWidget {
class LabelText<T extends Label> extends StatelessWidget {
final int? id;
final String placeholder;
final TextStyle? style;
@@ -24,7 +21,7 @@ class LabelText<T extends Label, State extends RepositoryState>
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => LabelCubit<T>(
context.read<LabelRepository<T, State>>(),
context.read<LabelRepository<T>>(),
),
child: BlocBuilder<LabelCubit<T>, LabelState<T>>(
builder: (context, state) {