import 'package:flutter/material.dart'; import 'package:neon/blocs.dart'; import 'package:neon/utils.dart'; import 'package:neon/widgets.dart'; import 'package:neon_notes/l10n/localizations.dart'; import 'package:neon_notes/neon_notes.dart'; import 'package:nextcloud/notes.dart' as notes; /// A dialog for creating a note. class NotesCreateNoteDialog extends StatefulWidget { /// Creates a new create note dialog. const NotesCreateNoteDialog({ required this.bloc, this.initialCategory, super.key, }); /// The active notes bloc. final NotesBloc bloc; /// The initial category of the note. final String? initialCategory; @override State createState() => _NotesCreateNoteDialogState(); } class _NotesCreateNoteDialogState extends State { final formKey = GlobalKey(); final controller = TextEditingController(); String? selectedCategory; @override void dispose() { controller.dispose(); super.dispose(); } void submit() { if (formKey.currentState!.validate()) { Navigator.of(context).pop((controller.text, widget.initialCategory ?? selectedCategory)); } } @override Widget build(final BuildContext context) { final titleField = Form( key: formKey, child: TextFormField( autofocus: true, controller: controller, decoration: InputDecoration( hintText: NotesLocalizations.of(context).noteTitle, ), validator: (final input) => validateNotEmpty(context, input), onFieldSubmitted: (final _) { submit(); }, ), ); final folderSelector = ResultBuilder>.behaviorSubject( subject: widget.bloc.notesList, builder: (final context, final notes) { if (notes.hasError) { return Center( child: NeonError( notes.error, onRetry: widget.bloc.refresh, ), ); } if (!notes.hasData) { return Center( child: NeonLinearProgressIndicator( visible: notes.isLoading, ), ); } return NotesCategorySelect( categories: notes.requireData.map((final note) => note.category).toSet().toList(), onChanged: (final category) { selectedCategory = category; }, onSubmitted: submit, ); }, ); return NeonDialog( title: Text(NotesLocalizations.of(context).noteCreate), content: Material( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.end, children: [ titleField, const SizedBox(height: 8), folderSelector, ], ), ), actions: [ NeonDialogAction( isDefaultAction: true, onPressed: submit, child: Text( NotesLocalizations.of(context).noteCreate, textAlign: TextAlign.end, ), ), ], ); } } /// A dialog for selecting a category for a note. class NotesSelectCategoryDialog extends StatefulWidget { /// Creates a new category selection dialog. const NotesSelectCategoryDialog({ required this.bloc, this.initialCategory, super.key, }); /// The active notes bloc. final NotesBloc bloc; /// The initial category of the note. final String? initialCategory; @override State createState() => _NotesSelectCategoryDialogState(); } class _NotesSelectCategoryDialogState extends State { final formKey = GlobalKey(); String? selectedCategory; void submit() { if (formKey.currentState!.validate()) { Navigator.of(context).pop(selectedCategory); } } @override Widget build(final BuildContext context) { final folderSelector = ResultBuilder>.behaviorSubject( subject: widget.bloc.notesList, builder: (final context, final notes) { if (notes.hasError) { return Center( child: NeonError( notes.error, onRetry: widget.bloc.refresh, ), ); } if (!notes.hasData) { return Center( child: NeonLinearProgressIndicator( visible: notes.isLoading, ), ); } return Form( key: formKey, child: NotesCategorySelect( categories: notes.requireData.map((final note) => note.category).toSet().toList(), initialValue: widget.initialCategory, onChanged: (final category) { selectedCategory = category; }, onSubmitted: submit, ), ); }, ); return NeonDialog( title: Text(NotesLocalizations.of(context).category), content: Material( child: folderSelector, ), actions: [ NeonDialogAction( isDefaultAction: true, onPressed: submit, child: Text( NotesLocalizations.of(context).noteSetCategory, textAlign: TextAlign.end, ), ), ], ); } }