3 Tap-Stellen öffnen den Vollbild-Player jetzt über PlayerExpansionController statt Navigator.push
Zusätzlich test/player/now_playing_heart_test.dart angepasst (Plan-Lücke: nutzt denselben SongZeile-Tap-Pfad, war nicht in Task 3s Datei-Liste erwähnt) — Provider ergänzt, Route für die Layout-Prüfung selbst separat geöffnet, bis Task 5 NowPlayingScreen zu Overlay-Inhalt umbaut.
This commit is contained in:
@@ -5,7 +5,7 @@ import 'package:provider/provider.dart';
|
|||||||
import '../library/database.dart';
|
import '../library/database.dart';
|
||||||
import '../library/song_media.dart';
|
import '../library/song_media.dart';
|
||||||
import '../player/audio_handler.dart';
|
import '../player/audio_handler.dart';
|
||||||
import '../player/now_playing_screen.dart';
|
import '../player/player_expansion_controller.dart';
|
||||||
import '../services/navidrome_service.dart';
|
import '../services/navidrome_service.dart';
|
||||||
import '../shared/cover.dart';
|
import '../shared/cover.dart';
|
||||||
import '../shared/lauf_balken.dart';
|
import '../shared/lauf_balken.dart';
|
||||||
@@ -79,9 +79,7 @@ class _ServerTitelScreenState extends State<ServerTitelScreen> {
|
|||||||
try {
|
try {
|
||||||
final uebersprungen = await handler.loadPlaylist(items, startIndex: ab);
|
final uebersprungen = await handler.loadPlaylist(items, startIndex: ab);
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
Navigator.of(context).push(
|
context.read<PlayerExpansionController>().open(context);
|
||||||
MaterialPageRoute(builder: (_) => const NowPlayingScreen()),
|
|
||||||
);
|
|
||||||
if (uebersprungen > 0) {
|
if (uebersprungen > 0) {
|
||||||
messenger.showSnackBar(
|
messenger.showSnackBar(
|
||||||
SnackBar(content: Text(offlineHinweis(uebersprungen))),
|
SnackBar(content: Text(offlineHinweis(uebersprungen))),
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
import '../player/audio_handler.dart';
|
import '../player/audio_handler.dart';
|
||||||
import '../player/now_playing_screen.dart';
|
import '../player/player_expansion_controller.dart';
|
||||||
import '../playlists/create_playlist_dialog.dart';
|
import '../playlists/create_playlist_dialog.dart';
|
||||||
import '../settings/app_settings.dart';
|
import '../settings/app_settings.dart';
|
||||||
import '../shared/cover.dart';
|
import '../shared/cover.dart';
|
||||||
@@ -384,9 +384,7 @@ class SongZeile extends StatelessWidget {
|
|||||||
groupByCategory: settings.groupCoversByCategory),
|
groupByCategory: settings.groupCoversByCategory),
|
||||||
);
|
);
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
Navigator.of(context).push(
|
context.read<PlayerExpansionController>().open(context);
|
||||||
MaterialPageRoute(builder: (_) => const NowPlayingScreen()),
|
|
||||||
);
|
|
||||||
if (uebersprungen > 0) {
|
if (uebersprungen > 0) {
|
||||||
messenger.showSnackBar(
|
messenger.showSnackBar(
|
||||||
SnackBar(content: Text(offlineHinweis(uebersprungen))),
|
SnackBar(content: Text(offlineHinweis(uebersprungen))),
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import '../library/database.dart';
|
|||||||
import '../library/playlist_service.dart';
|
import '../library/playlist_service.dart';
|
||||||
import '../library/song_media.dart';
|
import '../library/song_media.dart';
|
||||||
import '../player/audio_handler.dart';
|
import '../player/audio_handler.dart';
|
||||||
import '../player/now_playing_screen.dart';
|
import '../player/player_expansion_controller.dart';
|
||||||
import '../settings/app_settings.dart';
|
import '../settings/app_settings.dart';
|
||||||
import '../shared/cover.dart';
|
import '../shared/cover.dart';
|
||||||
import '../shared/lauf_balken.dart';
|
import '../shared/lauf_balken.dart';
|
||||||
@@ -135,9 +135,7 @@ class _Zeile extends StatelessWidget {
|
|||||||
groupByCategory: settings.groupCoversByCategory),
|
groupByCategory: settings.groupCoversByCategory),
|
||||||
);
|
);
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
Navigator.of(context).push(
|
context.read<PlayerExpansionController>().open(context);
|
||||||
MaterialPageRoute(builder: (_) => const NowPlayingScreen()),
|
|
||||||
);
|
|
||||||
if (uebersprungen > 0) {
|
if (uebersprungen > 0) {
|
||||||
messenger.showSnackBar(
|
messenger.showSnackBar(
|
||||||
SnackBar(content: Text(offlineHinweis(uebersprungen))),
|
SnackBar(content: Text(offlineHinweis(uebersprungen))),
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import 'package:shared_preferences/shared_preferences.dart';
|
|||||||
import 'package:melo/downloads/server_titel_screen.dart';
|
import 'package:melo/downloads/server_titel_screen.dart';
|
||||||
import 'package:melo/library/database.dart';
|
import 'package:melo/library/database.dart';
|
||||||
import 'package:melo/player/audio_handler.dart';
|
import 'package:melo/player/audio_handler.dart';
|
||||||
import 'package:melo/player/now_playing_screen.dart';
|
import 'package:melo/player/player_expansion_controller.dart';
|
||||||
import 'package:melo/services/navidrome_service.dart';
|
import 'package:melo/services/navidrome_service.dart';
|
||||||
|
|
||||||
/// Ersetzt in [MeloAudioHandler.loadPlaylist] den echten just_audio-Zugriff:
|
/// Ersetzt in [MeloAudioHandler.loadPlaylist] den echten just_audio-Zugriff:
|
||||||
@@ -57,10 +57,13 @@ void main() {
|
|||||||
handler.dispose();
|
handler.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
Widget wrap(Widget child) => MultiProvider(
|
Widget wrap(Widget child, PlayerExpansionController expansion) =>
|
||||||
|
MultiProvider(
|
||||||
providers: [
|
providers: [
|
||||||
Provider<MeloDb>.value(value: db),
|
Provider<MeloDb>.value(value: db),
|
||||||
Provider<MeloAudioHandler>.value(value: handler),
|
Provider<MeloAudioHandler>.value(value: handler),
|
||||||
|
ChangeNotifierProvider<PlayerExpansionController>.value(
|
||||||
|
value: expansion),
|
||||||
],
|
],
|
||||||
child: MaterialApp(home: child),
|
child: MaterialApp(home: child),
|
||||||
);
|
);
|
||||||
@@ -68,21 +71,26 @@ void main() {
|
|||||||
testWidgets('Titel antippen öffnet den Vollbild-Player', (tester) async {
|
testWidgets('Titel antippen öffnet den Vollbild-Player', (tester) async {
|
||||||
final navidrome = NavidromeService()
|
final navidrome = NavidromeService()
|
||||||
..setCredentials('https://musik.baka-net.de', 'Baka', 'geheim');
|
..setCredentials('https://musik.baka-net.de', 'Baka', 'geheim');
|
||||||
await tester.pumpWidget(wrap(ServerTitelScreen(
|
final expansion = PlayerExpansionController(vsync: tester);
|
||||||
|
addTearDown(expansion.dispose);
|
||||||
|
await tester.pumpWidget(wrap(
|
||||||
|
ServerTitelScreen(
|
||||||
titel: 'Ablaze',
|
titel: 'Ablaze',
|
||||||
navidrome: navidrome,
|
navidrome: navidrome,
|
||||||
holeTitel: () async => const [
|
holeTitel: () async => const [
|
||||||
SubsonicSong(id: 's1', titel: 'Feuer', kuenstler: 'X', dauerSekunden: 120),
|
SubsonicSong(id: 's1', titel: 'Feuer', kuenstler: 'X', dauerSekunden: 120),
|
||||||
],
|
],
|
||||||
)));
|
),
|
||||||
|
expansion,
|
||||||
|
));
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
expect(find.byType(NowPlayingScreen), findsNothing);
|
expect(expansion.progress, 0.0);
|
||||||
|
|
||||||
await tester.tap(find.text('Feuer'));
|
await tester.tap(find.text('Feuer'));
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
expect(find.byType(NowPlayingScreen), findsOneWidget);
|
expect(expansion.progress, 1.0);
|
||||||
|
|
||||||
// Ohne diesen Abschluss bleibt ein drift-Stream-Abo beim Abbau des
|
// Ohne diesen Abschluss bleibt ein drift-Stream-Abo beim Abbau des
|
||||||
// Baums als offener Fake-Timer stehen.
|
// Baums als offener Fake-Timer stehen.
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import 'package:melo/library/database.dart';
|
|||||||
import 'package:melo/library/playlist_service.dart';
|
import 'package:melo/library/playlist_service.dart';
|
||||||
import 'package:melo/library/song_list.dart';
|
import 'package:melo/library/song_list.dart';
|
||||||
import 'package:melo/player/audio_handler.dart';
|
import 'package:melo/player/audio_handler.dart';
|
||||||
import 'package:melo/player/now_playing_screen.dart';
|
import 'package:melo/player/player_expansion_controller.dart';
|
||||||
import 'package:melo/settings/app_settings.dart';
|
import 'package:melo/settings/app_settings.dart';
|
||||||
|
|
||||||
/// Ersetzt in [MeloAudioHandler.loadPlaylist] den echten just_audio-Zugriff:
|
/// Ersetzt in [MeloAudioHandler.loadPlaylist] den echten just_audio-Zugriff:
|
||||||
@@ -91,6 +91,8 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('Song antippen öffnet den Vollbild-Player mit großem Cover',
|
testWidgets('Song antippen öffnet den Vollbild-Player mit großem Cover',
|
||||||
(tester) async {
|
(tester) async {
|
||||||
|
final expansion = PlayerExpansionController(vsync: tester);
|
||||||
|
addTearDown(expansion.dispose);
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MultiProvider(
|
MultiProvider(
|
||||||
providers: [
|
providers: [
|
||||||
@@ -99,6 +101,8 @@ void main() {
|
|||||||
ChangeNotifierProvider<CategoryService>.value(value: kategorien),
|
ChangeNotifierProvider<CategoryService>.value(value: kategorien),
|
||||||
ChangeNotifierProvider<PlaylistService>.value(value: playlists),
|
ChangeNotifierProvider<PlaylistService>.value(value: playlists),
|
||||||
ChangeNotifierProvider<AppSettings>.value(value: einstellungen),
|
ChangeNotifierProvider<AppSettings>.value(value: einstellungen),
|
||||||
|
ChangeNotifierProvider<PlayerExpansionController>.value(
|
||||||
|
value: expansion),
|
||||||
],
|
],
|
||||||
child: MaterialApp(
|
child: MaterialApp(
|
||||||
home: Scaffold(
|
home: Scaffold(
|
||||||
@@ -112,12 +116,12 @@ void main() {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(find.byType(NowPlayingScreen), findsNothing);
|
expect(expansion.progress, 0.0);
|
||||||
|
|
||||||
await tester.tap(find.text('Roses'));
|
await tester.tap(find.text('Roses'));
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
expect(find.byType(NowPlayingScreen), findsOneWidget);
|
expect(expansion.progress, 1.0);
|
||||||
|
|
||||||
// Ohne diesen Abschluss bleibt ein drift-Stream-Abo (Favoriten-Herz)
|
// Ohne diesen Abschluss bleibt ein drift-Stream-Abo (Favoriten-Herz)
|
||||||
// beim Abbau des Baums als offener Fake-Timer stehen — dieselbe
|
// beim Abbau des Baums als offener Fake-Timer stehen — dieselbe
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import 'package:melo/library/playlist_service.dart';
|
|||||||
import 'package:melo/library/song_list.dart';
|
import 'package:melo/library/song_list.dart';
|
||||||
import 'package:melo/player/audio_handler.dart';
|
import 'package:melo/player/audio_handler.dart';
|
||||||
import 'package:melo/player/now_playing_screen.dart';
|
import 'package:melo/player/now_playing_screen.dart';
|
||||||
|
import 'package:melo/player/player_expansion_controller.dart';
|
||||||
import 'package:melo/settings/app_settings.dart';
|
import 'package:melo/settings/app_settings.dart';
|
||||||
import 'package:melo/shared/favorite_button.dart';
|
import 'package:melo/shared/favorite_button.dart';
|
||||||
|
|
||||||
@@ -92,7 +93,19 @@ void main() {
|
|||||||
// song_list_navigation_test.dart (Tap auf eine SongZeile) — dieser Weg ist
|
// song_list_navigation_test.dart (Tap auf eine SongZeile) — dieser Weg ist
|
||||||
// dort nachweislich unproblematisch, im Unterschied zu einem direkten
|
// dort nachweislich unproblematisch, im Unterschied zu einem direkten
|
||||||
// Aufbau von NowPlayingScreen mit vorab befülltem MediaItem-Stream.
|
// Aufbau von NowPlayingScreen mit vorab befülltem MediaItem-Stream.
|
||||||
|
//
|
||||||
|
// Seit dem Umbau auf PlayerExpansionController (Plan
|
||||||
|
// 2026-08-29-blur-oeffnen-transition, Task 3) zeigt der Tap allein noch
|
||||||
|
// keine sichtbare Oberfläche — das Overlay-Rendering kommt erst mit
|
||||||
|
// Task 4/5 ("Bekannte Zwischenlücke", siehe Plan). Für die Prüfung von
|
||||||
|
// NowPlayingScreens eigenem Layout (Herz-Position) wird die Route hier
|
||||||
|
// deshalb zusätzlich, unabhängig vom Produktions-Pfad, direkt geöffnet.
|
||||||
|
// Sobald Task 5 NowPlayingScreen zu Overlay-Inhalt umbaut, muss dieser
|
||||||
|
// Test ohnehin überarbeitet werden (Task 5 durchsucht dafür selbst
|
||||||
|
// `test -iname "*now_playing*"`, was diese Datei einschließt).
|
||||||
Future<void> oeffnePlayer(WidgetTester tester) async {
|
Future<void> oeffnePlayer(WidgetTester tester) async {
|
||||||
|
final expansion = PlayerExpansionController(vsync: tester);
|
||||||
|
addTearDown(expansion.dispose);
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MultiProvider(
|
MultiProvider(
|
||||||
providers: [
|
providers: [
|
||||||
@@ -101,6 +114,8 @@ void main() {
|
|||||||
ChangeNotifierProvider<CategoryService>.value(value: kategorien),
|
ChangeNotifierProvider<CategoryService>.value(value: kategorien),
|
||||||
ChangeNotifierProvider<PlaylistService>.value(value: playlists),
|
ChangeNotifierProvider<PlaylistService>.value(value: playlists),
|
||||||
ChangeNotifierProvider<AppSettings>.value(value: einstellungen),
|
ChangeNotifierProvider<AppSettings>.value(value: einstellungen),
|
||||||
|
ChangeNotifierProvider<PlayerExpansionController>.value(
|
||||||
|
value: expansion),
|
||||||
],
|
],
|
||||||
child: MaterialApp(
|
child: MaterialApp(
|
||||||
home: Scaffold(
|
home: Scaffold(
|
||||||
@@ -116,6 +131,12 @@ void main() {
|
|||||||
|
|
||||||
await tester.tap(find.text('Roses'));
|
await tester.tap(find.text('Roses'));
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
|
expect(expansion.progress, 1.0);
|
||||||
|
|
||||||
|
Navigator.of(tester.element(find.byType(SongZeile))).push(
|
||||||
|
MaterialPageRoute(builder: (_) => const NowPlayingScreen()),
|
||||||
|
);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> raeumeAuf(WidgetTester tester) async {
|
Future<void> raeumeAuf(WidgetTester tester) async {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import 'package:melo/library/category_service.dart';
|
|||||||
import 'package:melo/library/database.dart';
|
import 'package:melo/library/database.dart';
|
||||||
import 'package:melo/library/playlist_service.dart';
|
import 'package:melo/library/playlist_service.dart';
|
||||||
import 'package:melo/player/audio_handler.dart';
|
import 'package:melo/player/audio_handler.dart';
|
||||||
import 'package:melo/player/now_playing_screen.dart';
|
import 'package:melo/player/player_expansion_controller.dart';
|
||||||
import 'package:melo/playlists/playlist_detail_screen.dart';
|
import 'package:melo/playlists/playlist_detail_screen.dart';
|
||||||
import 'package:melo/settings/app_settings.dart';
|
import 'package:melo/settings/app_settings.dart';
|
||||||
|
|
||||||
@@ -90,6 +90,8 @@ void main() {
|
|||||||
deleted: false,
|
deleted: false,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final expansion = PlayerExpansionController(vsync: tester);
|
||||||
|
addTearDown(expansion.dispose);
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MultiProvider(
|
MultiProvider(
|
||||||
providers: [
|
providers: [
|
||||||
@@ -98,6 +100,8 @@ void main() {
|
|||||||
ChangeNotifierProvider<CategoryService>.value(value: kategorien),
|
ChangeNotifierProvider<CategoryService>.value(value: kategorien),
|
||||||
ChangeNotifierProvider<PlaylistService>.value(value: playlists),
|
ChangeNotifierProvider<PlaylistService>.value(value: playlists),
|
||||||
ChangeNotifierProvider<AppSettings>.value(value: einstellungen),
|
ChangeNotifierProvider<AppSettings>.value(value: einstellungen),
|
||||||
|
ChangeNotifierProvider<PlayerExpansionController>.value(
|
||||||
|
value: expansion),
|
||||||
],
|
],
|
||||||
child: MaterialApp(
|
child: MaterialApp(
|
||||||
home: PlaylistDetailScreen(playlist: playlist),
|
home: PlaylistDetailScreen(playlist: playlist),
|
||||||
@@ -106,12 +110,12 @@ void main() {
|
|||||||
);
|
);
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
expect(find.byType(NowPlayingScreen), findsNothing);
|
expect(expansion.progress, 0.0);
|
||||||
|
|
||||||
await tester.tap(find.text('Roses'));
|
await tester.tap(find.text('Roses'));
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
expect(find.byType(NowPlayingScreen), findsOneWidget);
|
expect(expansion.progress, 1.0);
|
||||||
|
|
||||||
// Ohne diesen Abschluss bleibt ein drift-Stream-Abo beim Abbau des
|
// Ohne diesen Abschluss bleibt ein drift-Stream-Abo beim Abbau des
|
||||||
// Baums als offener Fake-Timer stehen.
|
// Baums als offener Fake-Timer stehen.
|
||||||
|
|||||||
Reference in New Issue
Block a user