todo-app/lib/ui/note_editor_raw_field.dart
Krzysztof kuhy Rudnicki e6e1052c59
Some checks are pending
file-length / file length <= 250 lines (push) Waiting to run
release-apk / release (APK) (push) Waiting to run
Adopt the shared design_system package, dropping theme.dart and confirm.dart
Both files were donors for the new package rather than casualties of it:
theme.dart was byte-identical to untools' copy (md5 6cf8e82d), and
confirm.dart's confirmDestructive() was the ready-made pattern for the
~35 AlertDialogs inlined across the fleet. Keeping local copies after
promoting them upstream is exactly how the two would drift apart again,
so they are deleted and imported from design_system-v0.1.0 instead.

test/confirm_test.dart moves upstream with its subject -- the package
covers that behaviour (Escape and the barrier both refuse, Cancel is
autofocused so a reflexive Return cannot delete) as part of its own
100% gate. test/theme_test.dart stays as a consumer-side smoke check
that the dependency actually resolves to the frozen palette.

Verified: flutter analyze clean (bar one pre-existing bin/ style info),
308 tests pass at 100% coverage (1962/1962 -- the drop from 2005 is
exactly the promoted lines), and the release APK is installed and
running on the Pixel 6a with all 108 notes intact, the gold #B8862E
focus ring rendering from the package's inputDecorationTheme, and no
crashes in logcat.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XS1m7b1piBtAL22USLW6jL
2026-08-14 22:59:59 +02:00

57 lines
1.8 KiB
Dart

/// The raw-mode editing field: the assembled note text, verbatim.
///
/// Split out of `note_editor.dart` for file size. Stateless; the controller
/// stays owned by `_NoteEditorState`.
library;
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
/// A full-height plain-text field for the note's assembled Markdown.
class NoteEditorRawField extends StatelessWidget {
/// Creates the raw field over [controller].
const NoteEditorRawField({
required this.controller,
required this.autofocus,
required this.onChanged,
super.key,
});
/// Controller holding the raw body text.
final TextEditingController controller;
/// Whether the field takes focus on first build.
final bool autofocus;
/// Called on every keystroke.
final VoidCallback onChanged;
@override
Widget build(BuildContext context) {
// Caps the editing column at ~70 chars (rule 21) on the desktop's
// arbitrarily wide Chrome `--app` window. Center/ConstrainedBox only,
// no extra Column — nesting a second Column here previously broke the
// expands:true constraint chain in release builds (see
// NoteEditorStepPage, which documents the same hazard).
return Center(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: kProseMaxWidth),
child: TextField(
controller: controller,
autofocus: autofocus,
maxLines: null,
expands: true,
textAlignVertical: TextAlignVertical.top,
keyboardType: TextInputType.multiline,
style: Theme.of(context).textTheme.bodyLarge,
decoration: const InputDecoration(
border: InputBorder.none,
hintText: 'Write your idea…',
),
onChanged: (_) => onChanged(),
),
),
);
}
}