fix: Add labels to each cubit using repositories and state properties, remove label cubits

This commit is contained in:
Anton Stubenbord
2023-04-04 20:30:25 +02:00
parent 78fbd042a6
commit a2388b014b
95 changed files with 4790 additions and 1823 deletions

View File

@@ -0,0 +1,23 @@
import 'package:flutter/material.dart';
import 'package:paperless_api/paperless_api.dart';
class BulkEditPage<int, T extends Label> extends StatefulWidget {
final bool enableMultipleChoice;
final Map<int, T> availableOptions;
const BulkEditPage({
super.key,
required this.enableMultipleChoice,
required this.availableOptions,
});
@override
State<BulkEditPage> createState() => _BulkEditPageState();
}
class _BulkEditPageState extends State<BulkEditPage> {
@override
Widget build(BuildContext context) {
return Container();
}
}

View File

@@ -2,12 +2,11 @@ import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:flutter_typeahead/flutter_typeahead.dart';
import 'package:paperless_api/paperless_api.dart';
import 'package:paperless_mobile/core/widgets/dialog_utils/dialog_cancel_button.dart';
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/labels/tags/view/widgets/tag_widget.dart';
import 'package:paperless_mobile/features/labels/tags/view/widgets/tags_form_field.dart';
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
class BulkEditTagsBottomSheet extends StatefulWidget {
@@ -20,29 +19,42 @@ class BulkEditTagsBottomSheet extends StatefulWidget {
class _BulkEditTagsBottomSheetState extends State<BulkEditTagsBottomSheet> {
final _formKey = GlobalKey<FormBuilderState>();
List<int> _tagsToRemove = [];
List<int> _tagsToAdd = [];
final _textEditingController = TextEditingController();
late Set<int> _sharedTags;
late Set<int> _nonSharedTags;
final Set<int> _sharedTagsToRemove = {};
final Set<int> _nonSharedTagsToRemove = {};
final Set<int> _tagsToAdd = {};
@override
void initState() {
super.initState();
final state = context.read<DocumentBulkActionCubit>().state;
_sharedTags = state.selection
.map((doc) => doc.tags)
.reduce((previousValue, element) =>
previousValue.toSet().intersection(element.toSet()))
.toSet();
print(_sharedTags.map((e) => e).join(", "));
_nonSharedTags = state.selection
.map((doc) => doc.tags)
.flattened
.toSet()
.difference(_sharedTags)
.toSet();
print(_nonSharedTags.map((e) => e).join(", "));
}
@override
Widget build(BuildContext context) {
return BlocBuilder<DocumentBulkActionCubit, DocumentBulkActionState>(
builder: (context, state) {
final sharedTags = state.selection
.map((doc) => doc.tags)
.reduce((previousValue, element) =>
previousValue.toSet().intersection(element.toSet()))
.toList();
final nonSharedTags = state.selection
.map((doc) => doc.tags)
.flattened
.toSet()
.difference(sharedTags.toSet())
.toList();
return Padding(
padding:
EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
child: BlocBuilder<DocumentBulkActionCubit, DocumentBulkActionState>(
builder: (context, state) {
print(state);
return Padding(
padding: const EdgeInsets.all(16.0),
child: SingleChildScrollView(
@@ -54,25 +66,123 @@ class _BulkEditTagsBottomSheetState extends State<BulkEditTagsBottomSheet> {
"Bulk modify tags",
style: Theme.of(context).textTheme.titleLarge,
).paddedOnly(bottom: 24),
FormBuilder(
key: _formKey,
child: TagFormField(
initialValue: IdsTagsQuery(
sharedTags.map((tag) => IncludeTagIdQuery(tag)),
TypeAheadFormField<Tag>(
textFieldConfiguration: TextFieldConfiguration(
controller: _textEditingController,
decoration: const InputDecoration(
labelText: "Tags",
hintText: "Start typing to add tags...",
),
name: "labelFormField",
selectableOptions: state.tagOptions,
allowCreation: false,
anyAssignedSelectable: false,
excludeAllowed: false,
),
onSuggestionSelected: (suggestion) {
setState(() {
_tagsToAdd.add(suggestion.id!);
});
_textEditingController.clear();
},
itemBuilder: (context, option) {
return ListTile(
leading: SizedBox(
width: 32,
height: 32,
child: DecoratedBox(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: option.color!,
),
),
),
title: Text(option.name),
);
},
suggestionsCallback: (pattern) {
final searchString = pattern.toLowerCase();
return state.tags.entries
.where(
(tag) => tag.value.name
.toLowerCase()
.contains(searchString),
)
.map((e) => e.key)
.toSet()
.difference(_sharedTags)
.difference(_nonSharedTags)
.map((e) => state.tags[e]!);
},
),
Text("Shared tags"),
Wrap(
children: _sharedTags
.map(
(tag) => RemovableTagWidget(
tag: state.tags[tag]!,
onDeleted: (tag) {
setState(() {
_sharedTagsToRemove.add(tag);
_sharedTags.remove(tag);
});
},
),
)
.toList(),
),
const SizedBox(height: 8),
Text("Tags removed after apply"),
Wrap(),
Text("Non-shared tags"),
Wrap(
children: _nonSharedTags
.map(
(tag) => RemovableTagWidget(
tag: state.tags[tag]!,
onDeleted: (tag) {
setState(() {
_nonSharedTagsToRemove.add(tag);
_nonSharedTags.remove(tag);
});
},
),
)
.toList(),
),
Text("Remove"),
Wrap(
children: _sharedTagsToRemove.map((tag) {
return RemovableTagWidget(
tag: state.tags[tag]!,
onDeleted: (tag) {
setState(() {
_sharedTagsToRemove.remove(tag);
_sharedTags.add(tag);
});
},
);
}).toList() +
_nonSharedTagsToRemove.map((tag) {
return RemovableTagWidget(
tag: state.tags[tag]!,
onDeleted: (tag) {
setState(() {
_nonSharedTagsToRemove.remove(tag);
_nonSharedTags.add(tag);
});
},
);
}).toList(),
),
const SizedBox(height: 8),
Text("Tags added after apply"),
Wrap(),
Text("Add"),
Wrap(
children: _tagsToAdd
.map(
(tag) => RemovableTagWidget(
tag: state.tags[tag]!,
onDeleted: (tag) {
setState(() {
_tagsToAdd.remove(tag);
});
}),
)
.toList(),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
@@ -107,3 +217,28 @@ class _BulkEditTagsBottomSheetState extends State<BulkEditTagsBottomSheet> {
);
}
}
class RemovableTagWidget extends StatelessWidget {
final Tag tag;
final void Function(int tagId) onDeleted;
const RemovableTagWidget(
{super.key, required this.tag, required this.onDeleted});
@override
Widget build(BuildContext context) {
return Chip(
label: Text(
tag.name,
style: TextStyle(
color: tag.textColor,
),
),
onDeleted: () => onDeleted(tag.id!),
deleteIcon: Icon(Icons.clear),
backgroundColor: tag.color,
deleteIconColor: tag.textColor,
padding: EdgeInsets.zero,
side: BorderSide.none,
);
}
}

View File

@@ -0,0 +1,30 @@
// import 'package:flutter/material.dart';
// import 'package:flutter/src/widgets/framework.dart';
// import 'package:flutter/src/widgets/placeholder.dart';
// class LabelBulkSelectionWidget extends StatelessWidget {
// final int labelId;
// final String title;
// final bool selected;
// final bool excluded;
// final Widget Function(int id) leadingWidgetBuilder;
// final void Function(int id) onSelected;
// final void Function(int id) onUnselected;
// final void Function(int id) onRemoved;
// const LabelBulkSelectionWidget({
// super.key,
// required this.labelId,
// required this.title,
// required this.leadingWidgetBuilder,
// required this.onSelected,
// required this.onUnselected,
// required this.onRemoved,
// });
// @override
// Widget build(BuildContext context) {
// return ListTile(
// title: Text(title),
// );
// }
// }