HomeShell: PlayerExpansionController bereitstellen, Zurück-Taste schließt offenen Player
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:melo/player/player_expansion_controller.dart';
|
||||
|
||||
// Minimaler Host, der dieselbe Provider/PopScope-Verdrahtung wie HomeShell
|
||||
// nachstellt, ohne die volle App (Audio-Handler etc.) hochfahren zu müssen.
|
||||
// Der eigentliche HomeShell-Umbau wird direkt gegen main.dart getestet,
|
||||
// sobald Task 4/5 die Stack-Struktur eingeführt haben; dieser erste Test
|
||||
// sichert nur die PopScope-Erweiterung ab, isoliert an einem Test-Double.
|
||||
class _TestShell extends StatefulWidget {
|
||||
const _TestShell();
|
||||
@override
|
||||
State<_TestShell> createState() => _TestShellState();
|
||||
}
|
||||
|
||||
class _TestShellState extends State<_TestShell> with TickerProviderStateMixin {
|
||||
late final PlayerExpansionController _controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = PlayerExpansionController(vsync: this);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// Eigener AnimatedBuilder um PopScope, damit canPop bei jedem
|
||||
// _controller-Tick neu ausgewertet wird (Reaktivitäts-Regel aus dem
|
||||
// Plan) — ohne ihn bliebe canPop auf dem Wert des allerersten Builds
|
||||
// eingefroren, weil sonst nichts hier ein Rebuild auslöst.
|
||||
return ChangeNotifierProvider<PlayerExpansionController>.value(
|
||||
value: _controller,
|
||||
child: AnimatedBuilder(
|
||||
animation: _controller,
|
||||
builder: (context, child) => PopScope(
|
||||
canPop: _controller.progress == 0,
|
||||
onPopInvokedWithResult: (didPop, _) {
|
||||
if (!didPop) _controller.close(context);
|
||||
},
|
||||
child: child!,
|
||||
),
|
||||
child: const Scaffold(body: SizedBox()),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
testWidgets('Zurück-Taste schließt den Player statt zu poppen, wenn offen',
|
||||
(tester) async {
|
||||
await tester.pumpWidget(const MaterialApp(home: _TestShell()));
|
||||
final controller =
|
||||
tester.state<_TestShellState>(find.byType(_TestShell))._controller;
|
||||
|
||||
controller.open(tester.element(find.byType(_TestShell)));
|
||||
await tester.pumpAndSettle();
|
||||
expect(controller.progress, 1.0);
|
||||
|
||||
// pageBack() sucht einen sichtbaren Zurück-Button, den es hier ohne
|
||||
// zweite Route nicht gibt (siehe Plan-Hinweis für den Umsetzer) —
|
||||
// Navigator.maybePop() löst denselben PopScope-Callback aus.
|
||||
await Navigator.maybePop(tester.element(find.byType(_TestShell)));
|
||||
await tester.pumpAndSettle();
|
||||
expect(controller.progress, 0.0);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user