todo-app/lib/ui/note_editor_views.dart
Krzysztof kuhy Rudnicki 63725e726f Split note_editor.dart into nine files under the cap
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>
2026-08-14 16:12:04 +02:00

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,
);
}
}