Stop text dialogs collapsing their field above the landscape keyboard

On the tablet in landscape the keyboard leaves ~200 dp, and the save-route
dialog squeezed its text field to a line. The route-name, stream-address and
settings number/text dialogs now scroll instead and use smaller margins.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
tajniak81andClaude Opus 5.5 committed 2026-10-22 14:49:26 +02:00
1 parent 66c3dbcd71
commit a813648b75
4 files changed
+34

No files matched your search

@@ -428,6 +428,10 @@ class _RenameDialogState extends State<_RenameDialog> {
@override
Widget build(BuildContext context) => AlertDialog(
// In landscape the keyboard leaves ~200 dp: scroll rather than
// squeeze the field to a line, and spend little on margins.
scrollable: true,
insetPadding: const EdgeInsets.symmetric(horizontal: 40, vertical: 8),
backgroundColor: const Color(0xF20B1426),
title: Text(widget.title, style: HudText.sans.copyWith(fontSize: 14)),
content: TextField(
@@ -97,6 +97,9 @@ class _UrlDialogState extends State<_UrlDialog> {
Widget build(BuildContext context) {
final bool ok = _c.text.trim().isEmpty || validStreamUrl(_c.text);
return AlertDialog(
// Landscape with the keyboard up leaves ~200 dp: scroll, never squeeze.
scrollable: true,
insetPadding: const EdgeInsets.symmetric(horizontal: 40, vertical: 8),
title: const Text('Stream address'),
content: TextField(
key: const ValueKey<String>('liveStreamUrl-field'),
@@ -215,6 +215,9 @@ class _NumberDialogState extends State<_NumberDialog> {
Widget build(BuildContext context) {
final String unit = widget.unit.isEmpty ? '' : ' ${widget.unit}';
return AlertDialog(
// Landscape with the keyboard up leaves ~200 dp: scroll, never squeeze.
scrollable: true,
insetPadding: const EdgeInsets.symmetric(horizontal: 40, vertical: 8),
backgroundColor: const Color(0xFF10203F),
title: Text(widget.label, style: HudText.sans.copyWith(fontSize: 15)),
content: TextField(
@@ -271,6 +274,9 @@ class _TextSettingDialogState extends State<TextSettingDialog> {
@override
Widget build(BuildContext context) {
return AlertDialog(
// Landscape with the keyboard up leaves ~200 dp: scroll, never squeeze.
scrollable: true,
insetPadding: const EdgeInsets.symmetric(horizontal: 40, vertical: 8),
backgroundColor: const Color(0xFF10203F),
title: Text(widget.label, style: HudText.sans.copyWith(fontSize: 15)),
content: TextField(
+21
View File
@@ -15,7 +15,9 @@ import 'package:pilotvault_fly/fly/state/aircraft_state.dart';
import 'package:pilotvault_fly/fly/state/mission_state.dart';
import 'package:pilotvault_fly/fly/telemetry_reducer.dart';
import 'package:pilotvault_fly/ui/fly/dialogs/slide_to_confirm.dart';
import 'package:pilotvault_fly/theme.dart';
import 'package:pilotvault_fly/ui/fly/fly_screen.dart';
import 'package:pilotvault_fly/ui/fly/modes/waypoints/waypoint_sheets.dart' show showRenameDialog;
import 'package:shared_preferences/shared_preferences.dart';
import 'fake_dji.dart';
@@ -799,6 +801,24 @@ void main() {
expect(dji.calls.last, 'pauseWaypointMission');
});
});
testWidgets('the route name field keeps its height above the keyboard', (WidgetTester tester) async {
// The tablet in landscape with the keyboard up left ~205 dp for the dialog;
// this is tighter still, and the field must keep its full height.
tester.view.physicalSize = const Size(1280, 800);
tester.view.devicePixelRatio = 1;
tester.view.viewInsets = const FakeViewPadding(bottom: 600);
tester.view.padding = const FakeViewPadding(top: 40);
addTearDown(tester.view.reset);
await tester.pumpWidget(MaterialApp(
theme: PV.theme(),
home: Builder(builder: (BuildContext context) => TextButton(onPressed: () => showRenameDialog(context, 'New route', title: 'Save route as'), child: const Text('open'))),
));
await tester.tap(find.text('open'));
await tester.pumpAndSettle();
final Rect field = tester.getRect(find.byKey(const ValueKey<String>('rename-field')));
expect(field.height, greaterThanOrEqualTo(56), reason: 'the field, with its counter, is never squeezed');
expect(tester.takeException(), isNull);
});
}
/// An in-memory API Server route store, with the server's last-writer-wins rule.
@@ -842,4 +862,5 @@ class _FakeRemote implements MissionRemote {
routes[id] = RemoteRoute(id, at, null);
return null;
}
}