mirror of
https://github.com/kuhyx/todo-app.git
synced 2026-11-10 20:27:01 +01:00
Editing an existing note looked nothing like capturing a new one: it always showed the template dropdown, the View/Guided/Raw pills and the priority/status row. The cause was one missing argument -- both screens already embedded the same NoteEditor, but NoteDetailScreen never passed advancedMode, which defaults to true in the widget while the app-wide AppSettings.advancedMode defaults to false. Extract the shared form as three single-purpose components rather than one widget owning several jobs: - note_meta_row.dart renders the priority/status row (was capture_meta_row.dart; drops the private _MetaDropdown duplicate the detail screen carried, which used DropdownButtonFormField where the shared one uses DropdownButton). - note_form_chrome_gate.dart owns chrome visibility and nothing else, replacing the _chromeVisible flag both screens copy-pasted. - note_form.dart composes those two with NoteEditor. appSettings is now a required parameter through NotesListScreen and NoteDetailScreen. Required, not defaulted: a silent default is exactly what caused this, so it must not be reintroducible. Also in the capture app bar: drop the decorative Icons.list_alt_outlined beside the note count, since the adjacent Icons.list button already names what is counted, and move the count to the right of that button. The finalize-and-clear action becomes Icons.check instead of Icons.add -- it never saved anything (every keystroke is already persisted), so a plus sign misdescribed it. 314 tests, 100% line coverage. Verified in a running web build that edit and capture render identically with advanced mode both off and on. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
100 lines
3.3 KiB
Dart
100 lines
3.3 KiB
Dart
/// Composes the note-editing form shared by capture and the detail screen.
|
|
///
|
|
/// Composition only, no logic of its own: [NoteFormChromeGate] decides
|
|
/// visibility, [NoteMetaRow] renders the priority/status row, and [NoteEditor]
|
|
/// owns the text. Both surfaces render this so an edited note and a fresh
|
|
/// capture cannot look different -- the divergence this replaced was the
|
|
/// detail screen defaulting `advancedMode` to true while the app-wide setting
|
|
/// defaults to false.
|
|
library;
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import 'package:todo/data/note.dart';
|
|
import 'package:todo/data/note_template.dart';
|
|
import 'package:todo/ui/note_editor.dart';
|
|
import 'package:todo/ui/note_form_chrome_gate.dart';
|
|
import 'package:todo/ui/note_meta_row.dart';
|
|
|
|
/// The metadata row above a [NoteEditor], gated on advanced mode.
|
|
class NoteForm extends StatelessWidget {
|
|
/// Creates the form for the given note values.
|
|
const NoteForm({
|
|
required this.advancedMode,
|
|
required this.priority,
|
|
required this.status,
|
|
required this.onPriorityChanged,
|
|
required this.onStatusChanged,
|
|
required this.onChanged,
|
|
this.initialText = '',
|
|
this.initialTemplate,
|
|
this.autofocus = false,
|
|
super.key,
|
|
});
|
|
|
|
/// Whether the metadata row and the editor's own chrome may be shown.
|
|
final bool advancedMode;
|
|
|
|
/// The note's current priority.
|
|
final Priority priority;
|
|
|
|
/// The note's current status.
|
|
final Status status;
|
|
|
|
/// Called with a newly picked priority.
|
|
final ValueChanged<Priority> onPriorityChanged;
|
|
|
|
/// Called with a newly picked status.
|
|
final ValueChanged<Status> onStatusChanged;
|
|
|
|
/// Called with the freshly assembled note text on every edit.
|
|
final ValueChanged<String> onChanged;
|
|
|
|
/// Existing note text to load. Empty for a fresh draft.
|
|
final String initialText;
|
|
|
|
/// Template to author with. Null detects it from [initialText], which is
|
|
/// what opening an existing note wants.
|
|
final NoteTemplate? initialTemplate;
|
|
|
|
/// Autofocus the editor, so a fresh capture needs zero taps before typing.
|
|
final bool autofocus;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return NoteFormChromeGate(
|
|
advancedMode: advancedMode,
|
|
builder:
|
|
(context, {required chromeVisible, required onChromeVisibleChanged}) {
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
children: [
|
|
if (chromeVisible) ...[
|
|
NoteMetaRow(
|
|
priority: priority,
|
|
status: status,
|
|
onPriorityChanged: onPriorityChanged,
|
|
onStatusChanged: onStatusChanged,
|
|
),
|
|
const SizedBox(height: 12),
|
|
],
|
|
Expanded(
|
|
child: NoteEditor(
|
|
initialText: initialText,
|
|
initialTemplate: initialTemplate,
|
|
initialMode: NoteEditorMode.raw,
|
|
advancedMode: advancedMode,
|
|
priority: priority,
|
|
onPriorityChanged: onPriorityChanged,
|
|
onChromeVisibleChanged: onChromeVisibleChanged,
|
|
autofocus: autofocus,
|
|
onChanged: onChanged,
|
|
),
|
|
),
|
|
],
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|