mirror of
https://github.com/kuhyx/todo-app.git
synced 2026-11-10 20:27:01 +01:00
702 -> 220 lines, decomposed rather than just moved, because a single
~600-line State class was the actual problem:
note_editor_document.dart the text model -- template, controllers, and
which of the two sources (raw body vs. section
fields) is authoritative. None of it needed a
BuildContext or a setState, which is what made
it the honest seam. The raw<->guided conversions
and the initial-template detection moved here as
tryAdoptGuided/materialiseToRaw/forInitialText.
note_editor_wizard.dart the two-step priority+template wizard, which now
owns its own step state instead of parking three
fields on the editor.
note_editor_step_page.dart the guided per-step view.
note_editor_chrome.dart the template picker + mode toggle.
note_editor_raw_field.dart the raw-mode text field.
note_editor_mode.dart the mode enum, re-exported so callers are
unaffected.
note_editor_{widget,views} parts, not libraries: createState returns a
private class, so the widget and its State
cannot be split across libraries.
The layout comments about Expanded/expands:true are load-bearing (nesting
broke the constraint chain in release builds before), so they travelled with
the code they describe rather than being summarised away.
Verified: 313 tests pass, flutter analyze clean. Covered lines went UP,
1922 -> 1958, because the wizard's state is now exercised in a widget of its
own; every new file reports 100%.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
66 lines
2.2 KiB
Dart
66 lines
2.2 KiB
Dart
/// The [NoteEditor]'s view wiring: the small methods that hand this editor's
|
|
/// state to the extracted presentation widgets.
|
|
///
|
|
/// A `part` of `note_editor.dart` because every method here reads private
|
|
/// state (`_doc`, `_mode`, `_currentStep`) that Dart scopes to the library.
|
|
part of 'note_editor.dart';
|
|
|
|
extension _NoteEditorViews on _NoteEditorState {
|
|
/// The pre-guided wizard. Its step state lives in the widget itself; only
|
|
/// the two committed choices come back here.
|
|
Widget _guidedEntryWizard() => NoteEditorWizard(
|
|
initialPriority: widget.priority,
|
|
initialTemplate: NoteTemplate.defaultTemplate,
|
|
onCancel: _cancelWizard,
|
|
onStart: (priority, template) {
|
|
widget.onPriorityChanged(priority);
|
|
_enterGuidedWithTemplate(template);
|
|
},
|
|
);
|
|
|
|
/// The raw field, wired to this editor's body controller.
|
|
Widget _rawField() => NoteEditorRawField(
|
|
controller: _doc.body,
|
|
autofocus: widget.autofocus,
|
|
onChanged: () {
|
|
_retemplateDraft();
|
|
_emit();
|
|
},
|
|
);
|
|
|
|
Widget _buildBody() {
|
|
switch (_mode) {
|
|
case NoteEditorMode.preview:
|
|
return MarkdownView(text: _doc.currentText());
|
|
case NoteEditorMode.raw:
|
|
return _rawField();
|
|
// coverage:ignore-start
|
|
// Unreachable: build() short-circuits to _buildStepPage before reaching
|
|
// here, so this arm only exists to make the switch exhaustive.
|
|
case NoteEditorMode.guided:
|
|
return _rawField();
|
|
// coverage:ignore-end
|
|
}
|
|
}
|
|
|
|
/// Full-screen per-step view returned directly from [build] so the
|
|
/// TextField is a first-level Expanded child of that column -- see
|
|
/// [NoteEditorStepPage], which documents why the flat structure matters.
|
|
Widget _buildStepPage() {
|
|
_doc.ensureControllers(_doc.template);
|
|
final sections = _doc.template.sections;
|
|
final idx = _currentStep.clamp(0, sections.length - 1);
|
|
final section = sections[idx];
|
|
return NoteEditorStepPage(
|
|
section: section,
|
|
controller: _doc.section[section.key]!,
|
|
index: idx,
|
|
total: sections.length,
|
|
autofocus: widget.autofocus,
|
|
onGoToStep: _goToStep,
|
|
onExit: _exitGuided,
|
|
onChanged: _onStepFieldChanged,
|
|
);
|
|
}
|
|
}
|