feat: Implement bulk label forms (except tags)

This commit is contained in:
Anton Stubenbord
2023-04-11 01:16:20 +02:00
parent f2fa4e16de
commit 83d8abeae2
12 changed files with 447 additions and 308 deletions

View File

@@ -7,6 +7,7 @@ import 'package:paperless_mobile/extensions/flutter_extensions.dart';
import 'package:paperless_mobile/features/document_bulk_action/cubit/document_bulk_action_cubit.dart';
import 'package:paperless_mobile/features/document_bulk_action/view/widgets/bulk_edit_label_bottom_sheet.dart';
import 'package:paperless_mobile/features/document_bulk_action/view/widgets/bulk_edit_tags_bottom_sheet.dart';
import 'package:paperless_mobile/features/document_bulk_action/view/widgets/fullscreen_bulk_edit_label_form_field.dart';
import 'package:paperless_mobile/features/documents/cubit/documents_cubit.dart';
import 'package:paperless_mobile/features/documents/view/widgets/selection/bulk_delete_confirmation_dialog.dart';
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
@@ -65,12 +66,106 @@ class DocumentSelectionSliverAppBar extends StatelessWidget {
child: ListView(
scrollDirection: Axis.horizontal,
children: [
_buildBulkEditCorrespondentChip(context)
.paddedOnly(left: 8, right: 4),
_buildBulkEditDocumentTypeChip(context)
.paddedOnly(left: 4, right: 4),
_buildBulkEditStoragePathChip(context)
.paddedOnly(left: 4, right: 4),
ActionChip(
label: Text(S.of(context)!.correspondent),
avatar: const Icon(Icons.edit),
onPressed: () async {
await Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => BlocProvider(
create: (context) => DocumentBulkActionCubit(
context.read(),
context.read(),
context.read(),
selection: state.selection,
),
child: BlocBuilder<DocumentBulkActionCubit,
DocumentBulkActionState>(
builder: (context, state) {
return FullscreenBulkEditLabelFormField(
options: state.correspondents,
selection: state.selection,
labelMapper: (document) => document.correspondent,
leadingIcon: const Icon(Icons.person_outline),
hintText: S.of(context)!.startTyping,
onSubmit: context
.read<DocumentBulkActionCubit>()
.bulkModifyCorrespondent,
);
},
),
),
),
);
},
).paddedOnly(left: 8, right: 4),
ActionChip(
label: Text(S.of(context)!.documentType),
avatar: const Icon(Icons.edit),
onPressed: () async {
await Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => BlocProvider(
create: (context) => DocumentBulkActionCubit(
context.read(),
context.read(),
context.read(),
selection: state.selection,
),
child: BlocBuilder<DocumentBulkActionCubit,
DocumentBulkActionState>(
builder: (context, state) {
return FullscreenBulkEditLabelFormField(
options: state.documentTypes,
selection: state.selection,
labelMapper: (document) => document.documentType,
leadingIcon:
const Icon(Icons.description_outlined),
hintText: S.of(context)!.startTyping,
onSubmit: context
.read<DocumentBulkActionCubit>()
.bulkModifyDocumentType,
);
},
),
),
),
);
},
).paddedOnly(left: 8, right: 4),
ActionChip(
label: Text(S.of(context)!.storagePath),
avatar: const Icon(Icons.edit),
onPressed: () async {
await Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => BlocProvider(
create: (context) => DocumentBulkActionCubit(
context.read(),
context.read(),
context.read(),
selection: state.selection,
),
child: BlocBuilder<DocumentBulkActionCubit,
DocumentBulkActionState>(
builder: (context, state) {
return FullscreenBulkEditLabelFormField(
options: state.storagePaths,
selection: state.selection,
labelMapper: (document) => document.storagePath,
leadingIcon: const Icon(Icons.folder_outlined),
hintText: S.of(context)!.startTyping,
onSubmit: context
.read<DocumentBulkActionCubit>()
.bulkModifyStoragePath,
);
},
),
),
),
);
},
).paddedOnly(left: 8, right: 4),
_buildBulkEditTagsChip(context).paddedOnly(left: 4, right: 4),
],
),
@@ -79,150 +174,6 @@ class DocumentSelectionSliverAppBar extends StatelessWidget {
);
}
Widget _buildBulkEditCorrespondentChip(BuildContext context) {
return ActionChip(
label: Text(S.of(context)!.correspondent),
avatar: const Icon(Icons.edit),
onPressed: () {
final initialValue = state.selection.every((element) =>
element.correspondent == state.selection.first.correspondent)
? state.selection.first.correspondent
: null;
showModalBottomSheet(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(16),
topRight: Radius.circular(16),
),
),
isScrollControlled: false,
context: context,
builder: (_) {
return BlocProvider(
create: (context) => DocumentBulkActionCubit(
context.read(),
context.read(),
context.read(),
selection: state.selection,
),
child: Builder(builder: (context) {
return BulkEditLabelBottomSheet<Correspondent>(
initialValue: initialValue,
title: "Bulk edit correspondent",
availableOptionsSelector: (state) => state.correspondents,
formFieldLabel: S.of(context)!.correspondent,
formFieldPrefixIcon: const Icon(Icons.person_outline),
onSubmit: (selectedId) async {
await context
.read<DocumentBulkActionCubit>()
.bulkModifyCorrespondent(selectedId);
Navigator.pop(context);
},
);
}),
);
},
);
},
);
}
Widget _buildBulkEditDocumentTypeChip(BuildContext context) {
return ActionChip(
label: Text(S.of(context)!.documentType),
avatar: const Icon(Icons.edit),
onPressed: () {
final initialValue = state.selection.every((element) =>
element.documentType == state.selection.first.documentType)
? state.selection.first.documentType
: null;
showModalBottomSheet(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(16),
topRight: Radius.circular(16),
),
),
isScrollControlled: false,
context: context,
builder: (_) {
return BlocProvider(
create: (context) => DocumentBulkActionCubit(
context.read(),
context.read(),
context.read(),
selection: state.selection,
),
child: Builder(builder: (context) {
return BulkEditLabelBottomSheet<DocumentType>(
initialValue: initialValue,
title: "Bulk edit document type",
availableOptionsSelector: (state) => state.documentTypes,
formFieldLabel: S.of(context)!.documentType,
formFieldPrefixIcon: const Icon(Icons.person_outline),
onSubmit: (selectedId) async {
await context
.read<DocumentBulkActionCubit>()
.bulkModifyDocumentType(selectedId);
Navigator.pop(context);
},
);
}),
);
},
);
},
);
}
Widget _buildBulkEditStoragePathChip(BuildContext context) {
return ActionChip(
label: Text(S.of(context)!.storagePath),
avatar: const Icon(Icons.edit),
onPressed: () {
final initialValue = state.selection.every((element) =>
element.storagePath == state.selection.first.storagePath)
? state.selection.first.storagePath
: null;
showModalBottomSheet(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(16),
topRight: Radius.circular(16),
),
),
isScrollControlled: false,
context: context,
builder: (_) {
return BlocProvider(
create: (context) => DocumentBulkActionCubit(
context.read(),
context.read(),
context.read(),
selection: state.selection,
),
child: Builder(builder: (context) {
return BulkEditLabelBottomSheet<StoragePath>(
initialValue: initialValue,
title: "Bulk edit storage path",
availableOptionsSelector: (state) => state.storagePaths,
formFieldLabel: S.of(context)!.storagePath,
formFieldPrefixIcon: const Icon(Icons.folder_open_outlined),
onSubmit: (selectedId) async {
await context
.read<DocumentBulkActionCubit>()
.bulkModifyStoragePath(selectedId);
Navigator.pop(context);
},
);
}),
);
},
);
},
);
}
Widget _buildBulkEditTagsChip(BuildContext context) {
return ActionChip(
label: Text(S.of(context)!.tags),