Fix guided mode: full-screen TextField and hide Save FAB

Rework guided-mode layout so the text field fills the full available
screen height. The previous approach nested _buildStepPage (a Column
with its own Expanded) inside NoteEditor's outer Expanded — a
nested-Column/Expanded chain that collapses silently in release builds.

Fix: return _buildStepPage directly from build() when in guided mode,
making the TextField a first-level Expanded child of the same Column
as _buildRaw uses. This is the same depth at which expands:true works.

Also hide the Save FAB (_chromeVisible gate in CaptureScreen) while
guided mode is active so it cannot overlap the Next/Done button.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Cb7oE5Xsc8zSBHHtT6qwa
This commit is contained in:
Krzysztof kuhy Rudnicki 2026-06-27 17:32:50 +02:00
parent 5ca289ca81
commit 6398ce9275
2 changed files with 117 additions and 105 deletions

View File

@ -420,11 +420,13 @@ class _CaptureScreenState extends State<CaptureScreen>
], ],
), ),
), ),
floatingActionButton: FloatingActionButton.extended( floatingActionButton: _chromeVisible
? FloatingActionButton.extended(
onPressed: _saveAndReset, onPressed: _saveAndReset,
icon: const Icon(Icons.check), icon: const Icon(Icons.check),
label: const Text('Save'), label: const Text('Save'),
), )
: null,
); );
} }

View File

@ -338,23 +338,15 @@ class _NoteEditorState extends State<NoteEditor> {
final theme = Theme.of(context); final theme = Theme.of(context);
if (_enteringGuided) return _buildGuidedEntryWizard(theme); if (_enteringGuided) return _buildGuidedEntryWizard(theme);
// Guided (the bare stepper) hides the template/mode chrome entirely // Guided hides the template/mode chrome entirely. Return the flat step
// that's the point of "Guided": just the stepper, no top-bar noise. A // page directly so the TextField sits in THIS column's Expanded — same
// single back arrow is the only way out, restoring the full chrome. // depth as _buildRaw, avoiding the nested-Column/Expanded layout issue
final bareGuided = _mode == NoteEditorMode.guided; // that silently collapses the inner flex space in release builds.
if (_mode == NoteEditorMode.guided) return _buildStepPage(theme);
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
if (bareGuided)
Align(
alignment: Alignment.centerLeft,
child: IconButton(
icon: const Icon(Icons.arrow_back),
tooltip: 'Exit guided',
onPressed: _exitGuided,
),
)
else ...[
DropdownButtonFormField<String>( DropdownButtonFormField<String>(
initialValue: _template.id, initialValue: _template.id,
isDense: true, isDense: true,
@ -403,7 +395,6 @@ class _NoteEditorState extends State<NoteEditor> {
onSelectionChanged: (s) => _setMode(s.first), onSelectionChanged: (s) => _setMode(s.first),
), ),
), ),
],
const SizedBox(height: 12), const SizedBox(height: 12),
Expanded(child: _buildBody(theme)), Expanded(child: _buildBody(theme)),
], ],
@ -520,7 +511,8 @@ class _NoteEditorState extends State<NoteEditor> {
case NoteEditorMode.raw: case NoteEditorMode.raw:
return _buildRaw(theme); return _buildRaw(theme);
case NoteEditorMode.guided: case NoteEditorMode.guided:
return _buildStepPage(theme); // build() short-circuits to _buildStepPage before reaching here.
return _buildRaw(theme);
} }
} }
@ -541,6 +533,10 @@ class _NoteEditorState extends State<NoteEditor> {
); );
} }
/// Full-screen per-step view returned directly from [build] so the
/// [TextField] is a first-level [Expanded] child of THIS column the same
/// depth as [_buildRaw]. Nesting it inside a second Column broke the
/// flutter constraint chain in release builds (inner Expanded got 0 height).
Widget _buildStepPage(ThemeData theme) { Widget _buildStepPage(ThemeData theme) {
_ensureControllers(_template); _ensureControllers(_template);
final sections = _template.sections; final sections = _template.sections;
@ -552,9 +548,18 @@ class _NoteEditorState extends State<NoteEditor> {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
// Progress bar + step counter // Back arrow only exit from guided mode.
Align(
alignment: Alignment.centerLeft,
child: IconButton(
icon: const Icon(Icons.arrow_back),
tooltip: 'Exit guided',
onPressed: _exitGuided,
),
),
// Progress bar + step counter.
Padding( Padding(
padding: const EdgeInsets.fromLTRB(16, 8, 16, 4), padding: const EdgeInsets.fromLTRB(16, 0, 16, 4),
child: Row( child: Row(
children: [ children: [
Text('${idx + 1} / $total', style: theme.textTheme.labelMedium), Text('${idx + 1} / $total', style: theme.textTheme.labelMedium),
@ -565,14 +570,12 @@ class _NoteEditorState extends State<NoteEditor> {
], ],
), ),
), ),
// Section label + helper + text field // Section label + helper text.
Expanded( Padding(
child: SingleChildScrollView( padding: const EdgeInsets.fromLTRB(16, 8, 16, 0),
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
const SizedBox(height: 8),
Text( Text(
section.isTitle ? 'title' : section.label, section.isTitle ? 'title' : section.label,
style: theme.textTheme.titleMedium, style: theme.textTheme.titleMedium,
@ -585,12 +588,21 @@ class _NoteEditorState extends State<NoteEditor> {
), ),
), ),
const SizedBox(height: 12), const SizedBox(height: 12),
TextField( ],
),
),
// TextField fills all remaining space directly in this Column's
// Expanded, same as _buildRaw, so expands:true works correctly.
Expanded(
child: Padding(
padding: const EdgeInsets.fromLTRB(16, 0, 16, 0),
child: TextField(
controller: controller, controller: controller,
autofocus: widget.autofocus && idx == 0, autofocus: widget.autofocus && idx == 0,
maxLines: section.inline ? 1 : null, expands: true,
minLines: section.inline ? 1 : 6, maxLines: null,
keyboardType: TextInputType.multiline, keyboardType: TextInputType.multiline,
textAlignVertical: TextAlignVertical.top,
decoration: InputDecoration( decoration: InputDecoration(
hintText: section.hint, hintText: section.hint,
border: const OutlineInputBorder(), border: const OutlineInputBorder(),
@ -601,11 +613,9 @@ class _NoteEditorState extends State<NoteEditor> {
_emit(); _emit();
}, },
), ),
],
), ),
), ),
), // Navigation buttons sibling of Expanded so keyboard pushes them up.
// Navigation buttons below Expanded so they stay above the keyboard
Padding( Padding(
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
child: Row( child: Row(