From dc0d18562fe2f93ab6d6d1c6bbb908d81f18cde9 Mon Sep 17 00:00:00 2001 From: vjrj Date: Thu, 16 Jul 2026 00:34:42 +0200 Subject: [PATCH] fix(quick-add): wrap sheet action row to prevent overflow on small screens The Cancel / Save-and-add-another / Save actions were a fixed Row that could not shrink, so on narrow phones and long locales (es/pt/de/fr) the buttons overflowed the right edge (the clipped 'Guardar'). Replace it with an OverflowBar that wraps onto stacked, end-aligned lines when they don't fit; move the added-count onto its own line above. Guard it in small_screen_overflow_test.dart across the long locales. --- apps/app_seeds/lib/ui/quick_add_sheet.dart | 26 +++++++++------ .../test/ui/small_screen_overflow_test.dart | 32 +++++++++++++++++++ 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/apps/app_seeds/lib/ui/quick_add_sheet.dart b/apps/app_seeds/lib/ui/quick_add_sheet.dart index d8d5542..49574ab 100644 --- a/apps/app_seeds/lib/ui/quick_add_sheet.dart +++ b/apps/app_seeds/lib/ui/quick_add_sheet.dart @@ -83,20 +83,27 @@ class QuickAddSheet extends StatelessWidget { ), if (state.expanded) const _MoreSection(), const SizedBox(height: 8), - Row( + if (state.addedCount > 0) + Padding( + padding: const EdgeInsetsDirectional.only(bottom: 4), + child: Text( + t.quickAdd.addedCount(n: state.addedCount), + style: Theme.of(context).textTheme.bodySmall, + ), + ), + // OverflowBar wraps the actions onto stacked lines when the + // labels don't fit the width (small phones, long locales), + // instead of clipping with a RenderFlex overflow. + OverflowBar( + alignment: MainAxisAlignment.end, + spacing: 8, + overflowSpacing: 4, + overflowAlignment: OverflowBarAlignment.end, children: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: Text(t.quickAdd.cancel), ), - if (state.addedCount > 0) ...[ - const SizedBox(width: 8), - Text( - t.quickAdd.addedCount(n: state.addedCount), - style: Theme.of(context).textTheme.bodySmall, - ), - ], - const Spacer(), TextButton( key: const Key('quickAdd.saveAndAddAnother'), onPressed: state.submitting @@ -104,7 +111,6 @@ class QuickAddSheet extends StatelessWidget { : cubit.submitAndAddAnother, child: Text(t.quickAdd.saveAndAddAnother), ), - const SizedBox(width: 8), FilledButton( key: const Key('quickAdd.save'), onPressed: state.submitting ? null : cubit.submit, diff --git a/apps/app_seeds/test/ui/small_screen_overflow_test.dart b/apps/app_seeds/test/ui/small_screen_overflow_test.dart index 744def7..d5c18c8 100644 --- a/apps/app_seeds/test/ui/small_screen_overflow_test.dart +++ b/apps/app_seeds/test/ui/small_screen_overflow_test.dart @@ -20,8 +20,11 @@ import 'package:tane/ui/inventory_list_screen.dart'; import 'package:tane/ui/market_screen.dart'; import 'package:tane/ui/plantares_screen.dart'; import 'package:tane/ui/profile_screen.dart'; +import 'package:tane/ui/quick_add_sheet.dart'; import 'package:tane/ui/sales_screen.dart'; import 'package:tane/ui/settings_screen.dart'; +import 'package:tane/state/quick_add_cubit.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import '../support/test_support.dart'; @@ -322,6 +325,35 @@ void main() { await disposeTree(tester); }); + // The quick-add sheet's action row (Cancel / "Save & add another" / Save) is + // the one modal we DO guard: unlike the height concern that excludes sheets + // above, this is a *horizontal* overflow (three text buttons + the longest + // "Guardar y añadir otra" label don't fit a narrow phone). We give it a + // bounded height by pumping it inside a Scaffold body, so only the width + // constraint bites — reproducing the reported "Guardar cut off" report. + for (final locale in longLocales) { + testWidgets('quick-add action row fits a small screen (${locale.languageCode})', + (tester) async { + final db = newTestDatabase(); + addTearDown(db.close); + final repo = newTestRepository(db); + await pumpSmall( + tester, + wrapScreen( + repository: repo, + locale: locale, + child: Scaffold( + body: BlocProvider( + create: (_) => QuickAddCubit(repo), + child: const QuickAddSheet(), + ), + ), + ), + ); + await disposeTree(tester); + }); + } + // NOTE: the variety-detail screen is deliberately NOT overflow-checked here. // It reports a ~2px overflow on a RenderFlex that is already DISPOSED/DEFUNCT // — a transient stale frame while its cubit's Drift stream rebuilds during