fix(ui): scroll the germination & condition-check sheets; extend overflow guard

Two save-button sheets wrapped their body in a bare Column (no scroll): the
germination sheet (which grows a list of past tests) and the condition-check
sheet. On a small phone — especially with the keyboard up — the Save button
was pushed off the bottom, unreachable. Both now wrap the body in a
SingleChildScrollView, like the other input sheets already do.

Also extends the small-phone overflow guard to the profile (identity card +
Save), about, intro carousel, and the market/chat screens in their offline
'set up sharing' state. 17 cases green at 320x568 across es/pt/ast.
This commit is contained in:
vjrj 2026-07-11 01:11:12 +02:00
parent 76556f782b
commit 0e41293de5
2 changed files with 77 additions and 16 deletions

View file

@ -448,14 +448,15 @@ Future<void> _showGerminationSheet(
top: 16, top: 16,
bottom: MediaQuery.of(sheetContext).viewInsets.bottom + 16, bottom: MediaQuery.of(sheetContext).viewInsets.bottom + 16,
), ),
child: Column( child: SingleChildScrollView(
mainAxisSize: MainAxisSize.min, child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch, mainAxisSize: MainAxisSize.min,
children: [ crossAxisAlignment: CrossAxisAlignment.stretch,
Text( children: [
t.germination.title, Text(
style: Theme.of(sheetContext).textTheme.titleLarge, t.germination.title,
), style: Theme.of(sheetContext).textTheme.titleLarge,
),
const SizedBox(height: 8), const SizedBox(height: 8),
if (lot.germinationTests.isEmpty) if (lot.germinationTests.isEmpty)
Text(t.germination.none) Text(t.germination.none)
@ -530,6 +531,7 @@ Future<void> _showGerminationSheet(
), ),
], ],
), ),
),
), ),
); );
} }
@ -1175,14 +1177,15 @@ Future<void> _showConditionSheet(
top: 16, top: 16,
bottom: MediaQuery.of(sheetContext).viewInsets.bottom + 16, bottom: MediaQuery.of(sheetContext).viewInsets.bottom + 16,
), ),
child: Column( child: SingleChildScrollView(
mainAxisSize: MainAxisSize.min, child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch, mainAxisSize: MainAxisSize.min,
children: [ crossAxisAlignment: CrossAxisAlignment.stretch,
Text( children: [
t.conditionCheck.title, Text(
style: Theme.of(sheetContext).textTheme.titleLarge, t.conditionCheck.title,
), style: Theme.of(sheetContext).textTheme.titleLarge,
),
const SizedBox(height: 12), const SizedBox(height: 12),
TextField( TextField(
key: const Key('conditionCheck.containers'), key: const Key('conditionCheck.containers'),
@ -1239,6 +1242,7 @@ Future<void> _showConditionSheet(
), ),
], ],
), ),
),
), ),
), ),
); );

View file

@ -10,9 +10,11 @@ import 'package:tane/services/social_connection.dart';
import 'package:tane/services/social_service.dart'; import 'package:tane/services/social_service.dart';
import 'package:tane/services/social_settings.dart'; import 'package:tane/services/social_settings.dart';
import 'package:tane/ui/about_screen.dart'; import 'package:tane/ui/about_screen.dart';
import 'package:tane/ui/chat_screen.dart';
import 'package:tane/ui/home_screen.dart'; import 'package:tane/ui/home_screen.dart';
import 'package:tane/ui/intro_screen.dart'; import 'package:tane/ui/intro_screen.dart';
import 'package:tane/ui/inventory_list_screen.dart'; import 'package:tane/ui/inventory_list_screen.dart';
import 'package:tane/ui/market_screen.dart';
import 'package:tane/ui/profile_screen.dart'; import 'package:tane/ui/profile_screen.dart';
import 'package:tane/ui/settings_screen.dart'; import 'package:tane/ui/settings_screen.dart';
@ -139,6 +141,61 @@ void main() {
await disposeTree(tester); await disposeTree(tester);
}); });
// The market/chat are "live" screens; checked here in their OFFLINE state
// (the shared connection can't reach a relay) — a static layout, and the one
// a user without signal actually sees.
Future<SocialConnection> offlineConn() async {
final social = await SocialService.fromRootSeedHex('00' * 32);
final settings = SocialSettings(InMemorySecretStore());
await settings.setRelayUrls(const []);
return SocialConnection(
social: social,
settings: settings,
open: (_) async => throw StateError('offline'),
online: const Stream.empty(),
);
}
testWidgets('market (offline "set up sharing") fits a small screen',
(tester) async {
final db = newTestDatabase();
addTearDown(db.close);
final connection = await offlineConn();
await pumpSmall(
tester,
wrapScreen(
repository: newTestRepository(db),
locale: AppLocale.es,
child: MarketScreen(
social: await SocialService.fromRootSeedHex('00' * 32),
settings: SocialSettings(InMemorySecretStore()),
connection: connection,
),
),
);
await disposeTree(tester);
});
testWidgets('chat (offline "set up sharing") fits a small screen',
(tester) async {
final db = newTestDatabase();
addTearDown(db.close);
final connection = await offlineConn();
await pumpSmall(
tester,
wrapScreen(
repository: newTestRepository(db),
locale: AppLocale.es,
child: ChatScreen(
social: await SocialService.fromRootSeedHex('00' * 32),
connection: connection,
peerPubkey: 'ab' * 32,
),
),
);
await disposeTree(tester);
});
testWidgets('inventory (empty) fits a small screen', (tester) async { testWidgets('inventory (empty) fits a small screen', (tester) async {
final db = newTestDatabase(); final db = newTestDatabase();
addTearDown(db.close); addTearDown(db.close);