Zurück-Geste auf Nicht-Start-Tabs navigiert zu Meine Musik statt die App zu minimieren

Tab-Wechsel in HomeShell laufen nur über setState (IndexedStack +
BottomNavigationBar), nie über Navigator.push — eine System-Zurück-Geste
hatte auf Nicht-Start-Tabs also nie eine Route zum Poppen und minimierte
stattdessen die App. build() jetzt in ein PopScope gewickelt, das bei
_index != 0 zuerst zu Tab 0 zurückspringt.
This commit is contained in:
Hermes (Server)
2026-08-27 15:31:21 +02:00
parent 1b096f5227
commit 90b63c467e
3 changed files with 123 additions and 32 deletions
+67
View File
@@ -72,4 +72,71 @@ void main() {
handler.dispose();
await db.close();
});
testWidgets('Zurück-Geste auf einem Nicht-Start-Tab wechselt zu '
'"Meine Musik" statt die App zu minimieren', (tester) async {
final db = MeloDb(NativeDatabase.memory());
final lib = LibraryService(db);
final playlists = PlaylistService(db);
final handler = MeloAudioHandler(db: db);
final auth = BakaAuth(speicher: _MemorySpeicher());
await tester.pumpWidget(MultiProvider(
providers: [
Provider<MeloDb>.value(value: db),
ChangeNotifierProvider<LibraryService>.value(value: lib),
ChangeNotifierProvider<PlaylistService>.value(value: playlists),
Provider<MeloAudioHandler>.value(value: handler),
ChangeNotifierProvider<CategoryService>(create: (_) => CategoryService(db)),
ChangeNotifierProvider<AppSettings>(create: (_) => AppSettings()),
ChangeNotifierProvider<OfflineMode>(create: (_) => OfflineMode()),
ChangeNotifierProvider<BakaAuth>(create: (_) => auth),
ChangeNotifierProvider<YtDownloadService>(
create: (_) => YtDownloadService(auth: auth)),
ChangeNotifierProvider<YtSearchService>(
create: (_) => YtSearchService(auth: auth)),
ChangeNotifierProvider<DownloadService>(
create: (_) => DownloadService(db: db, navidrome: NavidromeService())),
ChangeNotifierProvider<SyncService>(
create: (_) => SyncService(
db: db, cloud: MeloCloudService(auth: auth))),
],
child: const MaterialApp(home: HomeShell()),
));
await tester.pump();
// Auf "Favoriten" wechseln (Index 3) — kein Navigator.push, nur der Tab.
await tester.tap(find.descendant(
of: find.byType(BottomNavigationBar), matching: find.text('Favoriten')));
await tester.pump();
expect(
tester
.widget<BottomNavigationBar>(find.byType(BottomNavigationBar))
.currentIndex,
3);
// System-Zurück-Geste simulieren — derselbe Weg, über den auch das
// echte Android-Zurück-Gesten-Signal bei WidgetsApp ankommt.
final widgetsAppState = tester.state(find.byType(WidgetsApp));
// ignore: avoid_dynamic_calls
await (widgetsAppState as dynamic).didPopRoute();
await tester.pump();
// Ohne Abfangen bliebe der Tab unverändert (Flutter minimiert dann die
// App statt zu navigieren) — die Geste muss stattdessen zu Tab 0 führen.
expect(
tester
.widget<BottomNavigationBar>(find.byType(BottomNavigationBar))
.currentIndex,
0);
// Baum abbauen, bevor der Test endet: der Positions-Timer des Audio-
// Handlers läuft sonst über das Testende hinaus weiter, und der
// Test-Rahmen meldet einen offenen Timer (wie in hauptmenue_test.dart
// dokumentiert). Aus demselben Grund bewusst kein db.close() nach
// einem tester.tap.
await tester.pumpWidget(const SizedBox());
handler.dispose();
await tester.pump(const Duration(milliseconds: 1));
});
}