Implemented note templates and enhanced usability by adjusting the dimension of the note dialogs

This commit is contained in:
Dennis Nemec
2026-01-08 14:10:21 +01:00
parent 6a53d2d716
commit ffdd7fa0ff
6 changed files with 98 additions and 56 deletions

View File

@ -25,15 +25,17 @@ class NoteBloc extends Bloc<NoteEvent, NoteState> {
required this.opBloc,
required this.deliveryId,
}) : super(NoteInitial()) {
_combinedSubscription = CombineLatestStream.combine2(
_combinedSubscription = CombineLatestStream.combine3(
repository.notes,
repository.images,
(note, image) => {"note": note, "image": image},
repository.templates,
(note, image, templates) => {"note": note, "image": image, "templates": templates},
).listen(
(data) => add(
DataUpdated(
images: data["image"] as List<ImageNote>,
notes: data["note"] as List<Note>,
templates: data["templates"] as List<NoteTemplate>
),
),
);
@ -56,7 +58,7 @@ class NoteBloc extends Bloc<NoteEvent, NoteState> {
}
Future<void> _dataUpdated(DataUpdated event, Emitter<NoteState> emit) async {
emit(NoteLoaded(notes: event.notes, images: event.images));
emit(NoteLoaded(notes: event.notes, images: event.images, templates: event.templates));
}
Future<void> _reset(ResetNotes event, Emitter<NoteState> emit) async {

View File

@ -70,6 +70,7 @@ class ImageUpdated extends NoteEvent {
class DataUpdated extends NoteEvent {
final List<ImageNote> images;
final List<Note> notes;
final List<NoteTemplate> templates;
DataUpdated({required this.images, required this.notes});
DataUpdated({required this.images, required this.notes, required this.templates});
}

View File

@ -41,14 +41,6 @@ class _NoteAddDialogState extends State<NoteAddDialog> {
void _onSave() {
String content = _noteController.text;
if (_noteSelectionController.text.isNotEmpty) {
NoteTemplate template = widget.templates.firstWhere(
(note) => note.title == _noteSelectionController.text,
);
content = template.content;
}
context.read<NoteBloc>().add(
AddNote(note: content, deliveryId: widget.delivery),
);
@ -60,12 +52,12 @@ class _NoteAddDialogState extends State<NoteAddDialog> {
Widget build(BuildContext context) {
return Dialog(
child: SizedBox(
width: MediaQuery.of(context).size.width * 0.75,
height: MediaQuery.of(context).size.height * 0.45,
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height * 0.6,
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
child: ListView(
//mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
@ -88,11 +80,10 @@ class _NoteAddDialogState extends State<NoteAddDialog> {
controller: _noteSelectionController,
onSelected: (int? value) {
setState(() {
_noteSelectionController.text =
widget.templates[value!].title;
_noteController.text =
widget.templates[value!].content;
});
},
enabled: _isCustomNotesEmpty,
width: double.infinity,
label: const Text("Notiz auswählen"),
dropdownMenuEntries:
@ -106,20 +97,22 @@ class _NoteAddDialogState extends State<NoteAddDialog> {
),
const Padding(
padding: EdgeInsets.only(top: 0.0, bottom: 0.0),
child: Text("oder"),
child: Center(child: Text("oder")),
),
Padding(
padding: const EdgeInsets.only(top: 10.0, bottom: 20.0),
child: TextFormField(
onTapOutside: (_) { _noteFieldFocusNode.unfocus(); },
controller: _noteController,
enabled: _noteSelectionController.text.isEmpty,
textInputAction: TextInputAction.done,
onFieldSubmitted: (_) {_noteFieldFocusNode.unfocus();},
focusNode: _noteFieldFocusNode,
decoration: const InputDecoration(
labelText: "Eigene Notiz",
border: OutlineInputBorder(),
),
minLines: 3,
maxLines: 5,
minLines: 8,
maxLines: 10,
),
),
Row(
@ -136,7 +129,10 @@ class _NoteAddDialogState extends State<NoteAddDialog> {
Padding(
padding: const EdgeInsets.only(left: 10.0),
child: OutlinedButton(
onPressed: null,
onPressed: () {
_noteController.clear();
_noteSelectionController.clear();
},
child: const Text("Zurücksetzen"),
),
),

View File

@ -17,11 +17,14 @@ class NoteEditDialog extends StatefulWidget {
class _NoteEditDialogState extends State<NoteEditDialog> {
final _formKey = GlobalKey<FormState>();
late TextEditingController _editController;
late FocusNode _noteFieldFocusNode;
@override
void initState() {
super.initState();
_noteFieldFocusNode = FocusNode();
_editController = TextEditingController(text: widget.note.content);
}
@ -40,11 +43,11 @@ class _NoteEditDialogState extends State<NoteEditDialog> {
Widget build(BuildContext context) {
return Dialog(
child: SizedBox(
width: MediaQuery.of(context).size.width * 0.75,
height: MediaQuery.of(context).size.height * 0.32,
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height * 0.5,
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
child: ListView(
children: [
Text(
"Notiz bearbeiten",
@ -59,13 +62,18 @@ class _NoteEditDialogState extends State<NoteEditDialog> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextFormField(
onTapOutside: (event) {
FocusScope.of(context).unfocus();
focusNode: _noteFieldFocusNode,
onTapOutside: (_) {
_noteFieldFocusNode.unfocus();
},
textInputAction: TextInputAction.done,
onFieldSubmitted: (_) {
_noteFieldFocusNode.unfocus();
},
decoration: InputDecoration(label: const Text("Notiz")),
controller: _editController,
minLines: 4,
maxLines: 8,
minLines: 10,
maxLines: 12,
),
Padding(

View File

@ -9,6 +9,8 @@ import 'package:hl_lieferservice/feature/delivery/overview/bloc/tour_state.dart'
import '../../../../../model/delivery.dart';
enum NoteItemAction { noteEdit, noteDelete }
class NoteListItem extends StatelessWidget {
final NoteInformation note;
final String deliveryId;
@ -31,13 +33,25 @@ class NoteListItem extends StatelessWidget {
.tour
.discountArticleNumber;
if (note.article != null && note.article?.articleNumber == discountArticleId) {
if (note.article != null &&
note.article?.articleNumber == discountArticleId) {
return const Text("Begründung der Gutschrift");
}
return note.article != null ? Text(note.article!.name) : null;
}
void _onEdit(BuildContext context) {
showDialog(
context: context,
builder:
(_) => BlocProvider.value(
value: context.read<NoteBloc>(),
child: NoteEditDialog(note: note.note),
),
);
}
@override
Widget build(BuildContext context) {
return Padding(
@ -47,16 +61,21 @@ class NoteListItem extends StatelessWidget {
subtitle: _subtitle(context),
tileColor: Theme.of(context).colorScheme.surfaceContainerLowest,
leading: CircleAvatar(child: Text("${index + 1}")),
trailing: PopupMenuButton(
itemBuilder: (context) {
trailing: PopupMenuButton<NoteItemAction>(
onSelected: (NoteItemAction action) {
switch (action) {
case NoteItemAction.noteDelete:
_onDelete(context);
break;
case NoteItemAction.noteEdit:
_onEdit(context);
break;
}
},
itemBuilder: (_) {
return [
PopupMenuItem(
onTap: () {
showDialog(
context: context,
builder: (context) => NoteEditDialog(note: note.note),
);
},
PopupMenuItem<NoteItemAction>(
value: NoteItemAction.noteEdit,
child: Row(
children: [
Icon(Icons.edit, color: Colors.blueAccent),
@ -67,10 +86,8 @@ class NoteListItem extends StatelessWidget {
],
),
),
PopupMenuItem(
onTap: () {
_onDelete(context);
},
PopupMenuItem<NoteItemAction>(
value: NoteItemAction.noteDelete,
child: Row(
children: [
Icon(Icons.delete, color: Colors.redAccent),

View File

@ -13,6 +13,11 @@ import 'package:hl_lieferservice/widget/operations/bloc/operation_bloc.dart';
import 'package:hl_lieferservice/widget/operations/bloc/operation_event.dart';
import 'package:image_picker/image_picker.dart';
enum NoteAction {
addNote,
addImage
}
class NoteOverview extends StatefulWidget {
final List<NoteInformation> notes;
final List<NoteTemplate> templates;
@ -35,12 +40,15 @@ class _NoteOverviewState extends State<NoteOverview> {
final _imagePicker = ImagePicker();
Widget _notes() {
for (final note in widget.notes) {
debugPrint("Note: ${note.note.content}");
debugPrint("NOTE Article: ${note.article?.name.toString()}");
}
return NoteList(notes: widget.notes, deliveryId: widget.deliveryId);
}
Widget _images() {
debugPrint("IMAGES: ${widget.images}");
return NoteImageOverview(
images: widget.images,
deliveryId: widget.deliveryId,
@ -50,11 +58,11 @@ class _NoteOverviewState extends State<NoteOverview> {
void _onAddNote(BuildContext context) {
showDialog(
context: context,
builder: (context) {
return NoteAddDialog(
builder: (_) {
return BlocProvider.value(value: context.read<NoteBloc>(), child: NoteAddDialog(
delivery: widget.deliveryId,
templates: widget.templates,
);
));
},
);
}
@ -107,10 +115,21 @@ class _NoteOverviewState extends State<NoteOverview> {
alignment: Alignment.bottomRight,
child: Padding(
padding: const EdgeInsets.only(right: 25),
child: PopupMenuButton(
itemBuilder: (context) {
child: PopupMenuButton<NoteAction>(
onSelected: (NoteAction action) {
switch (action) {
case NoteAction.addNote:
_onAddNote(context);
break;
case NoteAction.addImage:
_onAddImage(context);
break;
}
},
itemBuilder: (_) {
return [
PopupMenuItem(
PopupMenuItem<NoteAction>(
value: NoteAction.addNote,
child: Row(
children: [
Icon(
@ -123,9 +142,9 @@ class _NoteOverviewState extends State<NoteOverview> {
),
],
),
onTap: () => _onAddNote(context),
),
PopupMenuItem(
PopupMenuItem<NoteAction>(
value: NoteAction.addImage,
child: Row(
children: [
Icon(
@ -138,7 +157,6 @@ class _NoteOverviewState extends State<NoteOverview> {
),
],
),
onTap: () => _onAddImage(context),
),
];
},