From 92f565b1d4692ea015f0a605077942398590a731 Mon Sep 17 00:00:00 2001 From: "Hermes (Server)" Date: Tue, 18 Aug 2026 15:28:24 +0200 Subject: [PATCH] feat(services): add PlaylistService, wire into app providers Co-Authored-By: Claude Haiku 4.5 --- lib/library/playlist_service.dart | 41 ++++++++++++++++++++++++ lib/main.dart | 4 +++ test/library/playlist_service_test.dart | 42 +++++++++++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 lib/library/playlist_service.dart create mode 100644 test/library/playlist_service_test.dart diff --git a/lib/library/playlist_service.dart b/lib/library/playlist_service.dart new file mode 100644 index 0000000..42f4e5a --- /dev/null +++ b/lib/library/playlist_service.dart @@ -0,0 +1,41 @@ +import 'package:flutter/foundation.dart'; +import 'database.dart'; + +/// Koordiniert Playlisten- und Favoriten-Operationen; benachrichtigt Listener +/// nach jeder Mutation (für Feedback wie SnackBars — die Listen selbst +/// beobachten UIs direkt über die watch()-Streams von [MeloDb]). +class PlaylistService extends ChangeNotifier { + PlaylistService(this.db); + final MeloDb db; + + Future createPlaylist(String name, {String? description}) async { + final id = await db.createPlaylist(name, description: description); + notifyListeners(); + return id; + } + + Future deletePlaylist(String id) async { + await db.deletePlaylist(id); + notifyListeners(); + } + + Future addSongToPlaylist(String playlistId, String songId, int position) async { + await db.addSongToPlaylist(playlistId, songId, position); + notifyListeners(); + } + + Future removeSongFromPlaylist(String playlistId, String songId) async { + await db.removeSongFromPlaylist(playlistId, songId); + notifyListeners(); + } + + Future reorderSong(String playlistId, String songId, int newPosition) async { + await db.reorderPlaylistSong(playlistId, songId, newPosition); + notifyListeners(); + } + + Future toggleFavorite(String songId) async { + await db.toggleFavorite(songId); + notifyListeners(); + } +} diff --git a/lib/main.dart b/lib/main.dart index 17a4b7c..2c16f5c 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -6,6 +6,7 @@ import 'home_screen.dart'; import 'library/database.dart'; import 'library/library_screen.dart'; import 'library/library_service.dart'; +import 'library/playlist_service.dart'; import 'library/search_screen.dart'; import 'player/audio_handler.dart'; import 'player/mini_player.dart'; @@ -14,11 +15,13 @@ import 'shared/theme.dart'; late final MeloAudioHandler _handler; late final MeloDb _db; late final LibraryService _library; +late final PlaylistService _playlists; Future main() async { WidgetsFlutterBinding.ensureInitialized(); _db = MeloDb(); _library = LibraryService(_db); + _playlists = PlaylistService(_db); _handler = await AudioService.init( builder: () => MeloAudioHandler(), config: const AudioServiceConfig( @@ -40,6 +43,7 @@ class MeloApp extends StatelessWidget { Provider.value(value: _handler), Provider.value(value: _db), ChangeNotifierProvider.value(value: _library), + ChangeNotifierProvider.value(value: _playlists), ], child: MaterialApp( title: 'Melo', diff --git a/test/library/playlist_service_test.dart b/test/library/playlist_service_test.dart new file mode 100644 index 0000000..606a70d --- /dev/null +++ b/test/library/playlist_service_test.dart @@ -0,0 +1,42 @@ +import 'package:drift/native.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:melo/library/database.dart'; +import 'package:melo/library/playlist_service.dart'; + +void main() { + late MeloDb db; + late PlaylistService service; + + setUp(() { + db = MeloDb(NativeDatabase.memory()); + service = PlaylistService(db); + }); + + tearDown(() async => db.close()); + + test('createPlaylist delegates to db and notifies listeners', () async { + var notified = false; + service.addListener(() => notified = true); + + await service.createPlaylist('Road Trip'); + + final playlists = await db.watchPlaylists().first; + expect(playlists.length, 1); + expect(playlists.first.name, 'Road Trip'); + expect(notified, true); + }); + + test('toggleFavorite delegates to db and notifies listeners', () async { + await db.into(db.songs).insert(SongsCompanion.insert( + id: 'song-1', path: '/a.mp3', title: 'A', dateAddedMs: 0, updatedAtMs: 0, + )); + + var notified = false; + service.addListener(() => notified = true); + + await service.toggleFavorite('song-1'); + + expect(await db.watchIsFavorite('song-1').first, true); + expect(notified, true); + }); +}