From 2cf1fb648cbcc68aae79dec2216f9999e07eac92 Mon Sep 17 00:00:00 2001 From: Herwig Birke Date: Tue, 4 Nov 2025 17:37:10 +0100 Subject: [PATCH] Movie Context Menu --- lib/core/api/backend_api.dart | 4 ++ .../presentation/movie_list_screen.dart | 68 ++++++++++++++++++- 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/lib/core/api/backend_api.dart b/lib/core/api/backend_api.dart index a80ad43..fd7eb28 100644 --- a/lib/core/api/backend_api.dart +++ b/lib/core/api/backend_api.dart @@ -143,6 +143,10 @@ class BackendApi { }); } + Future deleteMovie(int movieId) async { + await _post({'action': 'delete_movie', 'movie_id': movieId}); + } + Future>> getEpisodes({ String? status, String? q, diff --git a/lib/features/movies/presentation/movie_list_screen.dart b/lib/features/movies/presentation/movie_list_screen.dart index 678c2a0..a9592a5 100644 --- a/lib/features/movies/presentation/movie_list_screen.dart +++ b/lib/features/movies/presentation/movie_list_screen.dart @@ -127,7 +127,7 @@ class MovieListScreen extends ConsumerWidget { separatorBuilder: (_, __) => const Divider(height: 1), itemBuilder: (context, i) { final m = itemsSorted[i]; - return ListTile( + final tile = ListTile( tileColor: _statusBg(m.status, context), leading: m.posterPath != null ? ClipRRect( @@ -187,6 +187,72 @@ class MovieListScreen extends ConsumerWidget { ); }, ); + + Future setStatus(ItemStatus s) async { + final messenger = ScaffoldMessenger.of(context); + try { + await ref.read(backendApiProvider).setStatus(type: 'movie', refId: m.id, status: s.name); + ref.invalidate(moviesStreamProvider); + ref.invalidate(moviesProvider); + messenger.showSnackBar(SnackBar(content: Text('Status gesetzt: ${s.name}'))); + } catch (e) { + messenger.showSnackBar(SnackBar(content: Text('Fehler: $e'))); + } + } + + Future updateMovie() async { + final messenger = ScaffoldMessenger.of(context); + try { + final tmdb = ref.read(tmdbApiProvider); + final json = await tmdb.getMovie(m.tmdbId); + await ref.read(backendApiProvider).upsertMovie(json); + ref.invalidate(moviesStreamProvider); + ref.invalidate(moviesProvider); + messenger.showSnackBar(const SnackBar(content: Text('Film aktualisiert'))); + } catch (e) { + messenger.showSnackBar(SnackBar(content: Text('Update fehlgeschlagen: $e'))); + } + } + + Future deleteMovie() async { + final confirm = await showDialog( + context: context, + builder: (ctx) => AlertDialog( + title: const Text('Film löschen?'), + content: Text(m.title), + actions: [ + TextButton(onPressed: () => Navigator.of(ctx).pop(false), child: const Text('Abbrechen')), + FilledButton(onPressed: () => Navigator.of(ctx).pop(true), child: const Text('Löschen')), + ], + ), + ); + if (confirm != true) return; + final messenger = ScaffoldMessenger.of(context); + try { + await ref.read(backendApiProvider).deleteMovie(m.id); + ref.invalidate(moviesStreamProvider); + ref.invalidate(moviesProvider); + messenger.showSnackBar(const SnackBar(content: Text('Film gelöscht'))); + } catch (e) { + messenger.showSnackBar(SnackBar(content: Text('Löschen fehlgeschlagen: $e'))); + } + } + + return MenuAnchor( + menuChildren: [ + MenuItemButton(onPressed: () => setStatus(ItemStatus.Init), child: const Text('set to init')), + MenuItemButton(onPressed: () => setStatus(ItemStatus.Progress), child: const Text('set to progress')), + MenuItemButton(onPressed: () => setStatus(ItemStatus.Done), child: const Text('set to done')), + MenuItemButton(onPressed: updateMovie, child: const Text('update')), + MenuItemButton(onPressed: deleteMovie, child: const Text('delete')), + ], + builder: (ctx, controller, child) => GestureDetector( + onSecondaryTapDown: (_) => controller.open(), + onSecondaryTapUp: (_) => controller.open(), + onLongPress: () => controller.open(), + child: tile, + ), + ); }, ), );