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:
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(
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user