Tab-Reihenfolge, konfigurierbare Meine-Musik-Sektionen, Berechtigungen beim Start, schärferes Sperrbildschirm-Cover
- 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
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
54cb523cf4
commit
da012a3dca
@@ -30,7 +30,7 @@ class _MemorySpeicher implements TokenSpeicher {
|
||||
}
|
||||
|
||||
/// Die vier Bereiche des Hauptmenüs, in dieser Reihenfolge.
|
||||
const hauptmenue = ['Meine Musik', 'Download', 'Suchen', 'Favoriten'];
|
||||
const hauptmenue = ['Meine Musik', 'Suchen', 'Download', 'Favoriten'];
|
||||
|
||||
void main() {
|
||||
late MeloDb db;
|
||||
|
||||
@@ -32,7 +32,7 @@ void main() {
|
||||
setUp(() => SharedPreferences.setMockInitialValues({}));
|
||||
|
||||
testWidgets('Untere Navigation folgt der Referenz-UI: '
|
||||
'Meine Musik, Download, Suchen, Favoriten', (tester) async {
|
||||
'Meine Musik, Suchen, Download, Favoriten', (tester) async {
|
||||
final db = MeloDb(NativeDatabase.memory());
|
||||
final lib = LibraryService(db);
|
||||
final playlists = PlaylistService(db);
|
||||
@@ -64,7 +64,7 @@ void main() {
|
||||
final bar = tester.widget<BottomNavigationBar>(
|
||||
find.byType(BottomNavigationBar));
|
||||
expect(bar.items.map((i) => i.label).toList(),
|
||||
['Meine Musik', 'Download', 'Suchen', 'Favoriten']);
|
||||
['Meine Musik', 'Suchen', 'Download', 'Favoriten']);
|
||||
|
||||
handler.dispose();
|
||||
await db.close();
|
||||
|
||||
@@ -14,7 +14,7 @@ import 'package:provider/provider.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
Widget _wrap(MeloDb db, LibraryService lib, PlaylistService playlists,
|
||||
MeloAudioHandler handler, Widget child) {
|
||||
MeloAudioHandler handler, Widget child, {AppSettings? settings}) {
|
||||
return MultiProvider(
|
||||
providers: [
|
||||
Provider<MeloDb>.value(value: db),
|
||||
@@ -22,7 +22,9 @@ Widget _wrap(MeloDb db, LibraryService lib, PlaylistService playlists,
|
||||
ChangeNotifierProvider<PlaylistService>.value(value: playlists),
|
||||
Provider<MeloAudioHandler>.value(value: handler),
|
||||
ChangeNotifierProvider<CategoryService>(create: (_) => CategoryService(db)),
|
||||
ChangeNotifierProvider<AppSettings>(create: (_) => AppSettings()),
|
||||
settings == null
|
||||
? ChangeNotifierProvider<AppSettings>(create: (_) => AppSettings())
|
||||
: ChangeNotifierProvider<AppSettings>.value(value: settings),
|
||||
],
|
||||
child: MaterialApp(home: Scaffold(body: child)),
|
||||
);
|
||||
@@ -112,6 +114,31 @@ void main() {
|
||||
await db.close();
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'abgewählte Sektionen fehlen in den Schnellzugriffen, aktive bleiben',
|
||||
(tester) async {
|
||||
final db = MeloDb(NativeDatabase.memory());
|
||||
final lib = LibraryService(db);
|
||||
final playlists = PlaylistService(db);
|
||||
final handler = MeloAudioHandler(db: db);
|
||||
final settings = AppSettings();
|
||||
await settings.init();
|
||||
await settings.setMeineMusikSektionAktiv(
|
||||
AppSettings.sektionWiedergabelisten, false);
|
||||
|
||||
await tester.pumpWidget(_wrap(
|
||||
db, lib, playlists, handler, const MyMusicScreen(),
|
||||
settings: settings));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Favoriten'), findsOneWidget);
|
||||
expect(find.text('Zuletzt'), findsOneWidget);
|
||||
expect(find.text('Wiedergabelisten'), findsNothing);
|
||||
|
||||
handler.dispose();
|
||||
await db.close();
|
||||
});
|
||||
|
||||
testWidgets('Favoriten-Tab zeigt nur favorisierte Songs mit Shuffle',
|
||||
(tester) async {
|
||||
final db = MeloDb(NativeDatabase.memory());
|
||||
@@ -150,4 +177,26 @@ void main() {
|
||||
handler.dispose();
|
||||
await db.close();
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'Banner mit "Einstellungen"-Button, wenn die Benachrichtigung verweigert ist',
|
||||
(tester) async {
|
||||
final db = MeloDb(NativeDatabase.memory());
|
||||
final lib = LibraryService(db)..notificationPermissionDenied = true;
|
||||
final playlists = PlaylistService(db);
|
||||
final handler = MeloAudioHandler(db: db);
|
||||
|
||||
await tester.pumpWidget(
|
||||
_wrap(db, lib, playlists, handler, const MyMusicScreen()));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(
|
||||
find.textContaining('Benachrichtigungen für die Wiedergabe'),
|
||||
findsOneWidget,
|
||||
);
|
||||
expect(find.text('Einstellungen'), findsOneWidget);
|
||||
|
||||
handler.dispose();
|
||||
await db.close();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:melo/settings/app_settings.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
void main() {
|
||||
setUp(() => SharedPreferences.setMockInitialValues({}));
|
||||
|
||||
group('Meine-Musik-Sektionen', () {
|
||||
test('sind ohne Auswahl standardmäßig alle aktiv', () async {
|
||||
final settings = AppSettings();
|
||||
await settings.init();
|
||||
|
||||
expect(settings.meineMusikSektionen,
|
||||
Set.of(AppSettings.alleMeineMusikSektionen));
|
||||
});
|
||||
|
||||
test('lassen sich einzeln abschalten und bleiben gespeichert', () async {
|
||||
final settings = AppSettings();
|
||||
await settings.init();
|
||||
|
||||
await settings.setMeineMusikSektionAktiv(
|
||||
AppSettings.sektionWiedergabelisten, false);
|
||||
|
||||
expect(settings.meineMusikSektionen,
|
||||
{AppSettings.sektionFavoriten, AppSettings.sektionZuletzt});
|
||||
|
||||
final neuGeladen = AppSettings();
|
||||
await neuGeladen.init();
|
||||
expect(neuGeladen.meineMusikSektionen,
|
||||
{AppSettings.sektionFavoriten, AppSettings.sektionZuletzt});
|
||||
});
|
||||
|
||||
test('lassen sich wieder einschalten', () async {
|
||||
final settings = AppSettings();
|
||||
await settings.init();
|
||||
|
||||
await settings.setMeineMusikSektionAktiv(
|
||||
AppSettings.sektionFavoriten, false);
|
||||
await settings.setMeineMusikSektionAktiv(
|
||||
AppSettings.sektionFavoriten, true);
|
||||
|
||||
expect(settings.meineMusikSektionen,
|
||||
Set.of(AppSettings.alleMeineMusikSektionen));
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -11,6 +11,7 @@ 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.
|
||||
@@ -44,6 +45,8 @@ Widget _wrap(MeloDb db, Widget child) {
|
||||
}
|
||||
|
||||
void main() {
|
||||
setUp(() => SharedPreferences.setMockInitialValues({}));
|
||||
|
||||
testWidgets('zeigt 0 Songs ohne Bibliothek', (tester) async {
|
||||
final db = MeloDb(NativeDatabase.memory());
|
||||
|
||||
@@ -99,4 +102,65 @@ void main() {
|
||||
|
||||
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();
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user