- Tabs: Meine Musik, Suchen, Download, Favoriten (vorher Download vor Suchen) - "Meine Musik": Schnellzugriffe (Favoriten/Wiedergabelisten/Zuletzt) einzeln über die Einstellungen abschaltbar - Audio- und Benachrichtigungs-Berechtigung werden jetzt beim ersten Start gemeinsam angefragt statt erst bei Bedarf; Hinweisbanner + Einstellungen- Button bei dauerhafter Verweigerung (auch für Benachrichtigungen neu) - Cover-Extraktion beim Android-Scan von 512px auf 1024px erhöht, für ein schärferes Cover im Sperrbildschirm - Fix: notifyListeners() in LibraryService nur noch bei echter Wertänderung (verhinderte einen Test-Hang durch den neuen Start-Berechtigungs-Aufruf) 557 Tests grün, flutter analyze ohne Befund. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VM2JK5mV7AL1g2Rt6H6h9w
167 lines
5.7 KiB
Dart
167 lines
5.7 KiB
Dart
import 'package:drift/drift.dart';
|
|
import 'package:drift/native.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:provider/provider.dart';
|
|
import 'package:melo/library/database.dart';
|
|
import 'package:melo/library/library_service.dart';
|
|
import 'package:melo/services/baka_auth.dart';
|
|
import 'package:melo/services/melo_cloud_service.dart';
|
|
import 'package:melo/services/offline_mode.dart';
|
|
import 'package:melo/services/sync_service.dart';
|
|
import 'package:melo/settings/app_settings.dart';
|
|
import 'package:melo/settings/settings_screen.dart';
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
|
|
/// Token-Ablage ohne Plattform-Kanäle — im Test gibt es keinen sicheren
|
|
/// Gerätespeicher.
|
|
class _MemorySpeicher implements TokenSpeicher {
|
|
final Map<String, String> werte = {};
|
|
@override
|
|
Future<String?> lesen(String key) async => werte[key];
|
|
@override
|
|
Future<void> schreiben(String key, String wert) async => werte[key] = wert;
|
|
@override
|
|
Future<void> loeschen(String key) async => werte.remove(key);
|
|
}
|
|
|
|
Widget _wrap(MeloDb db, Widget child) {
|
|
return MultiProvider(
|
|
providers: [
|
|
Provider<MeloDb>.value(value: db),
|
|
ChangeNotifierProvider<OfflineMode>.value(value: OfflineMode()),
|
|
ChangeNotifierProvider<LibraryService>.value(value: LibraryService(db)),
|
|
ChangeNotifierProvider<AppSettings>(create: (_) => AppSettings()),
|
|
ChangeNotifierProvider<BakaAuth>(
|
|
create: (_) => BakaAuth(speicher: _MemorySpeicher())),
|
|
ChangeNotifierProvider<SyncService>(
|
|
create: (context) => SyncService(
|
|
db: db,
|
|
cloud: MeloCloudService(auth: context.read<BakaAuth>()),
|
|
)),
|
|
],
|
|
child: MaterialApp(home: child),
|
|
);
|
|
}
|
|
|
|
void main() {
|
|
setUp(() => SharedPreferences.setMockInitialValues({}));
|
|
|
|
testWidgets('zeigt 0 Songs ohne Bibliothek', (tester) async {
|
|
final db = MeloDb(NativeDatabase.memory());
|
|
|
|
await tester.pumpWidget(_wrap(db, const SettingsScreen()));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('0 Songs in der Bibliothek'), findsOneWidget);
|
|
|
|
await db.close();
|
|
});
|
|
|
|
testWidgets('zeigt korrekte Song-Anzahl und Gesamtspieldauer', (tester) async {
|
|
final db = MeloDb(NativeDatabase.memory());
|
|
await db.into(db.songs).insert(SongsCompanion.insert(
|
|
id: 'song-1',
|
|
path: '/a.mp3',
|
|
title: 'Song A',
|
|
dateAddedMs: 0,
|
|
updatedAtMs: 0,
|
|
durationMs: const Value(200000),
|
|
));
|
|
await db.into(db.songs).insert(SongsCompanion.insert(
|
|
id: 'song-2',
|
|
path: '/b.mp3',
|
|
title: 'Song B',
|
|
dateAddedMs: 0,
|
|
updatedAtMs: 0,
|
|
durationMs: const Value(185000),
|
|
));
|
|
|
|
await tester.pumpWidget(_wrap(db, const SettingsScreen()));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('2 Songs in der Bibliothek'), findsOneWidget);
|
|
expect(find.text('6m Gesamtspieldauer'), findsOneWidget);
|
|
|
|
await db.close();
|
|
});
|
|
|
|
testWidgets('zeigt Favoriten- und Playlisten-Sync', (tester) async {
|
|
final db = MeloDb(NativeDatabase.memory());
|
|
|
|
await tester.pumpWidget(_wrap(db, const SettingsScreen()));
|
|
await tester.pumpAndSettle();
|
|
|
|
// Die Sync-Einträge liegen weiter unten in der Liste und müssen erst
|
|
// in den sichtbaren Bereich gescrollt werden.
|
|
await tester.scrollUntilVisible(find.text('Favoriten-Sync'), 200);
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('Favoriten-Sync'), findsOneWidget);
|
|
expect(find.text('Playlisten-Sync'), findsOneWidget);
|
|
|
|
await db.close();
|
|
});
|
|
|
|
testWidgets('zeigt Musik- und Benachrichtigungs-Berechtigung mit Einstellungs-Button',
|
|
(tester) async {
|
|
final db = MeloDb(NativeDatabase.memory());
|
|
|
|
await tester.pumpWidget(_wrap(db, const SettingsScreen()));
|
|
await tester.pumpAndSettle();
|
|
|
|
await tester.scrollUntilVisible(
|
|
find.text('Benachrichtigungs-Berechtigung'), 200);
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('Musik-Berechtigung'), findsOneWidget);
|
|
expect(find.text('Benachrichtigungs-Berechtigung'), findsOneWidget);
|
|
expect(find.text('Einstellungen öffnen'), findsNWidgets(2));
|
|
|
|
await db.close();
|
|
});
|
|
|
|
testWidgets(
|
|
'Meine-Musik-Sektionen sind als Checkboxen an- und abwählbar',
|
|
(tester) async {
|
|
final db = MeloDb(NativeDatabase.memory());
|
|
final settings = AppSettings();
|
|
await settings.init();
|
|
|
|
await tester.pumpWidget(MultiProvider(
|
|
providers: [
|
|
Provider<MeloDb>.value(value: db),
|
|
ChangeNotifierProvider<OfflineMode>.value(value: OfflineMode()),
|
|
ChangeNotifierProvider<LibraryService>.value(
|
|
value: LibraryService(db)),
|
|
ChangeNotifierProvider<AppSettings>.value(value: settings),
|
|
ChangeNotifierProvider<BakaAuth>(
|
|
create: (_) => BakaAuth(speicher: _MemorySpeicher())),
|
|
ChangeNotifierProvider<SyncService>(
|
|
create: (context) => SyncService(
|
|
db: db,
|
|
cloud: MeloCloudService(auth: context.read<BakaAuth>()),
|
|
)),
|
|
],
|
|
child: const MaterialApp(home: SettingsScreen()),
|
|
));
|
|
await tester.pumpAndSettle();
|
|
|
|
await tester.scrollUntilVisible(find.text('Wiedergabelisten'), 200);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('Favoriten'), findsOneWidget);
|
|
expect(find.text('Wiedergabelisten'), findsOneWidget);
|
|
expect(find.text('Zuletzt hinzugefügt'), findsOneWidget);
|
|
|
|
await tester.tap(find.widgetWithText(CheckboxListTile, 'Wiedergabelisten'));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(
|
|
settings.meineMusikSektionen
|
|
.contains(AppSettings.sektionWiedergabelisten),
|
|
isFalse);
|
|
|
|
await db.close();
|
|
});
|
|
}
|