fix(ui): floating buttons stay put while the keyboard is up
A screen making way for the keyboard had its floating buttons lifted above it, where they stood over what was typed, such as the Library's search results. They now stay where they stand, behind the keyboard. Whats-New: The buttons at the foot of a screen no longer rise with the keyboard. Whats-New-De: Die Knöpfe am Fuß eines Bildschirms steigen nicht mehr mit der Tastatur. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
1781553f1d
commit
29f900992b
2 changed files with 44 additions and 9 deletions
|
|
@ -1,3 +1,5 @@
|
|||
import 'dart:math' as math;
|
||||
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:halkyon_ui/l10n/halkyon_ui_localizations.dart';
|
||||
|
|
@ -660,28 +662,43 @@ class const FrameFade({super.key}) extends StatefulWidget {
|
|||
FloatingActionButtonLocation base = FloatingActionButtonLocation.endFloat,
|
||||
]) {
|
||||
final foot = context.dependOnInheritedWidgetOfExactType<_FrameFoot>();
|
||||
return foot != null && foot.showsBar ? _OverTheFade(base) : base;
|
||||
return foot != null && foot.showsBar
|
||||
? _OverTheFade(base, foot.claims)
|
||||
: base;
|
||||
}
|
||||
|
||||
@override
|
||||
State<FrameFade> createState() => _FrameFadeState();
|
||||
}
|
||||
|
||||
/// [base] lowered by the fade's height.
|
||||
final class const _OverTheFade(final FloatingActionButtonLocation base)
|
||||
extends FloatingActionButtonLocation {
|
||||
/// [base] lowered by the fade's height, and kept where it stands while the
|
||||
/// keyboard is up (the developer's review, 10 Nov 2026): the Scaffold lifts
|
||||
/// a floating button above the keyboard, where it stood in the way of
|
||||
/// what is typed, as a search's results; lowered by as much as the keyboard
|
||||
/// rises above the foot ([_FadeClaims.footHeight]), it stays behind it.
|
||||
final class const _OverTheFade(
|
||||
final FloatingActionButtonLocation base,
|
||||
final _FadeClaims foot,
|
||||
) extends FloatingActionButtonLocation {
|
||||
@override
|
||||
Offset getOffset(ScaffoldPrelayoutGeometry scaffoldGeometry) => base
|
||||
.getOffset(scaffoldGeometry)
|
||||
.translate(0, FlushNavigationBar.fadeHeight);
|
||||
Offset getOffset(ScaffoldPrelayoutGeometry scaffoldGeometry) {
|
||||
final raised = math.max(
|
||||
0,
|
||||
scaffoldGeometry.minInsets.bottom - foot.footHeight,
|
||||
);
|
||||
return base
|
||||
.getOffset(scaffoldGeometry)
|
||||
.translate(0, FlushNavigationBar.fadeHeight + raised);
|
||||
}
|
||||
|
||||
// Equal for the same base, so that a screen built again doesn't move its
|
||||
// button as if to another place.
|
||||
@override
|
||||
bool operator ==(Object other) => other is _OverTheFade && other.base == base;
|
||||
bool operator ==(Object other) =>
|
||||
other is _OverTheFade && other.base == base && other.foot == foot;
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(_OverTheFade, base);
|
||||
int get hashCode => Object.hash(_OverTheFade, base, foot);
|
||||
}
|
||||
|
||||
class _FrameFadeState() extends State<FrameFade> {
|
||||
|
|
@ -759,6 +776,7 @@ class _FrameFadeState() extends State<FrameFade> {
|
|||
final height = keyboard
|
||||
? _height ?? MediaQuery.paddingOf(context).bottom
|
||||
: _height = MediaQuery.paddingOf(context).bottom;
|
||||
_foot!.claims.footHeight = height;
|
||||
return SizedBox(
|
||||
height: height,
|
||||
child: Align(
|
||||
|
|
@ -773,6 +791,10 @@ class _FrameFadeState() extends State<FrameFade> {
|
|||
/// ([FrameFade]); the frame paints its own while none does.
|
||||
class _FadeClaims() extends ChangeNotifier {
|
||||
final _claims = <Object>{};
|
||||
|
||||
/// The height of the foot a [FrameFade] keeps beneath its screen, as last
|
||||
/// built: what its button stands above.
|
||||
double footHeight = 0;
|
||||
bool _disposed = false;
|
||||
|
||||
/// Whether a screen in view paints the fade.
|
||||
|
|
|
|||
|
|
@ -299,6 +299,19 @@ void main() {
|
|||
expect(tester.getRect(find.byType(FloatingActionButton)), before);
|
||||
});
|
||||
|
||||
testWidgets('the button stays where it stands, behind the keyboard, on a '
|
||||
'screen that makes way for it (a search in the Library)', (tester) async {
|
||||
await showPhone(tester, fadingScreen());
|
||||
await tester.pumpAndSettle();
|
||||
final before = tester.getRect(find.byType(FloatingActionButton));
|
||||
|
||||
tester.view.viewInsets = const FakeViewPadding(bottom: 300);
|
||||
addTearDown(tester.view.resetViewInsets);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(tester.getRect(find.byType(FloatingActionButton)), before);
|
||||
});
|
||||
|
||||
testWidgets("a screen without its own fade keeps the frame's", (
|
||||
tester,
|
||||
) async {
|
||||
|
|
|
|||
Loading…
Reference in a new issue