fix(ui): a window resized across 600 dp keeps every screen as it was

Crossing from compact to medium windows or back built screens anew,
losing what they held: a study session started over, a card being
written lost its text, a video began again. The frame around a screen
over the tabs (FramedScreen) was added above it only from medium windows
on, and the snack bars' width (FittedSnackBars) put a Theme above the
app's navigator only there, so the screens below sat at another depth
after the change. The snack bars now always keep their Theme, changing
only the width in it, and the framed screen keeps its screen under a
global key, which moves it whole between the two places.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-10-13 16:35:44 +02:00
commit 96cbd912de
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64
2 changed files with 93 additions and 12 deletions

View file

@ -0,0 +1,49 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_learn_flutter/src/core/theme/app_theme.dart';
import 'package:halkyon_learn_flutter/src/core/widget/tinted_frame.dart';
import 'package:material_ui/material_ui.dart';
void main() {
/// A screen with something typed into it, as a study session or a card
/// being written holds what was done.
Future<void> typeIn(
WidgetTester tester,
Widget Function(Widget) around,
) async {
tester.view.physicalSize = const Size(1200, 800);
tester.view.devicePixelRatio = 1;
addTearDown(tester.view.reset);
await tester.pumpWidget(
MaterialApp(
theme: appTheme(Brightness.light),
home: around(const Scaffold(body: TextField())),
),
);
await tester.enterText(find.byType(TextField), 'kept');
}
/// Crosses every line where the frame or the snack bars change: medium,
/// compact, medium again.
Future<void> resize(WidgetTester tester) async {
for (final width in const [700.0, 400.0, 1200.0]) {
tester.view.physicalSize = Size(width, 800);
await tester.pumpAndSettle();
}
}
testWidgets('a framed screen keeps what it holds when the window crosses '
'from medium to compact and back', (tester) async {
await typeIn(tester, (screen) => FramedScreen(child: screen));
await resize(tester);
expect(find.text('kept'), findsOneWidget);
});
testWidgets('so does every screen under the snack bars fitted to the '
'window', (tester) async {
await typeIn(tester, (screen) => FittedSnackBars(child: screen));
await resize(tester);
expect(find.text('kept'), findsOneWidget);
});
}

View file

@ -343,6 +343,27 @@ void main() {
expect(tester.takeException(), isNull);
});
testWidgets('resizing the window, across every size class, keeps the '
'video where it is', (tester) async {
await watch(tester);
await playTo(tester, const Duration(minutes: 2));
final playing = players.last;
for (final size in const [
Size(800, 900),
Size(500, 900),
Size(1400, 900),
]) {
tester.view.physicalSize = size;
await tester.pumpAndSettle();
}
expect(players.opened, hasLength(1));
expect(players.last, same(playing));
expect(playing!.disposed, isFalse);
expect(playing.state.value.position, const Duration(minutes: 2));
});
testWidgets('on a phone the words are below the video', (tester) async {
await watch(tester, size: const Size(412, 915));
await playTo(tester, const Duration(seconds: 2));