diff --git a/lib/downloads/youtube_search_screen.dart b/lib/downloads/youtube_search_screen.dart index 6cd35df..9e7b44a 100644 --- a/lib/downloads/youtube_search_screen.dart +++ b/lib/downloads/youtube_search_screen.dart @@ -7,6 +7,7 @@ import '../library/database.dart'; import '../library/library_service.dart'; import '../services/baka_auth.dart'; import '../services/download_service.dart'; +import '../services/gast_zugang.dart'; import '../services/media_store.dart'; import '../services/yt_download_service.dart'; import '../services/yt_search_service.dart'; @@ -34,6 +35,9 @@ class _YoutubeSearchScreenState extends State { /// Hinweis auf die manuelle Anmeldung (siehe Download-Tab) sichtbar. bool _autoLoginFehlgeschlagen = false; + /// Fehlertext, falls das Holen des Gast-Tokens scheitert. + String? _gastFehler; + @override void initState() { super.initState(); @@ -51,6 +55,14 @@ class _YoutubeSearchScreenState extends State { }); } + Future _alsGastFortfahren() async { + final gast = context.read(); + setState(() => _gastFehler = null); + final fehler = await gast.holeToken(); + if (!mounted) return; + if (fehler != null) setState(() => _gastFehler = fehler); + } + @override void dispose() { _query.dispose(); @@ -67,9 +79,12 @@ class _YoutubeSearchScreenState extends State { @override Widget build(BuildContext context) { final auth = context.watch(); + final gast = context.watch(); final suche = context.watch(); - final zugriffOk = - auth.istAngemeldet || (_serverUser && !_autoLoginFehlgeschlagen); + final zugriffOk = auth.istAngemeldet || + (_serverUser && !_autoLoginFehlgeschlagen) || + gast.hatToken; + final istGastModus = !_serverUser && !auth.istAngemeldet && gast.hatToken; return SafeArea( child: Column( @@ -97,13 +112,47 @@ class _YoutubeSearchScreenState extends State { ], ), ), - if (!zugriffOk) - const Padding( - padding: EdgeInsets.symmetric(horizontal: 16, vertical: 4), + if (!zugriffOk) ...[ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4), child: Text( 'Die Suche läuft über den Baka-Server. Dafür brauchst du ' 'deine Baka-Anmeldung (siehe Download-Tab).', - style: TextStyle(color: MeloTheme.text2, fontSize: 13), + style: const TextStyle(color: MeloTheme.text2, fontSize: 13), + ), + ), + if (!_serverUser) ...[ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: SizedBox( + width: double.infinity, + height: MeloTheme.minTouchTarget + 4, + child: OutlinedButton.icon( + icon: const Icon(Icons.person_outline), + label: const Text('Als Gast fortfahren (5 Downloads/Tag)', + style: TextStyle(fontSize: 16)), + onPressed: _alsGastFortfahren, + ), + ), + ), + if (_gastFehler != null) + Padding( + padding: + const EdgeInsets.symmetric(horizontal: 16, vertical: 4), + child: Text(_gastFehler!, + style: + const TextStyle(color: MeloTheme.red, fontSize: 13)), + ), + ], + ], + if (istGastModus) + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4), + child: Text( + gast.verbleibend == null + ? 'Als Gast unterwegs (5 Downloads/Tag)' + : 'Als Gast unterwegs — noch ${gast.verbleibend} von 5 heute', + style: const TextStyle(color: MeloTheme.text2, fontSize: 13), ), ), if (suche.laeuft) const LinearProgressIndicator(), diff --git a/test/downloads/youtube_search_screen_test.dart b/test/downloads/youtube_search_screen_test.dart index 1123b9d..2a827b2 100644 --- a/test/downloads/youtube_search_screen_test.dart +++ b/test/downloads/youtube_search_screen_test.dart @@ -11,6 +11,7 @@ import 'package:melo/library/database.dart'; import 'package:melo/library/library_service.dart'; import 'package:melo/services/baka_auth.dart'; import 'package:melo/services/download_service.dart'; +import 'package:melo/services/gast_zugang.dart'; import 'package:melo/services/navidrome_service.dart'; import 'package:melo/services/yt_download_service.dart'; import 'package:melo/services/yt_search_service.dart'; @@ -43,12 +44,14 @@ Widget _wrap({ required YtSearchService search, required YtDownloadService download, NavidromeService? navidrome, + GastZugang? gast, }) { return MultiProvider( providers: [ Provider.value(value: db), ChangeNotifierProvider.value(value: LibraryService(db)), ChangeNotifierProvider.value(value: auth), + ChangeNotifierProvider.value(value: gast ?? GastZugang()), ChangeNotifierProvider.value(value: search), ChangeNotifierProvider.value(value: download), // Nur für die Server-User-Prüfung gebraucht (siehe @@ -182,4 +185,50 @@ void main() { // _YouTubeBereich (downloads_screen.dart) keinen eigenen Widget-Test — // die Download-Logik selbst ist über yt_download_test.dart ausführlich // abgedeckt. + + testWidgets('Gast sieht den Button "Als Gast fortfahren"', (tester) async { + final db = MeloDb(NativeDatabase.memory()); + final auth = BakaAuth( + client: MockClient((_) async => http.Response('', 500)), + speicher: _MemorySpeicher()); + final search = YtSearchService(auth: auth); + final download = YtDownloadService(auth: auth); + + await tester.pumpWidget(_wrap( + db: db, auth: auth, search: search, download: download)); + await tester.pumpAndSettle(); + + expect( + find.text('Als Gast fortfahren (5 Downloads/Tag)'), findsOneWidget); + + await db.close(); + }); + + testWidgets( + 'Als Gast fortfahren blendet den Baka-Hinweis aus und zeigt den Zähler', + (tester) async { + final db = MeloDb(NativeDatabase.memory()); + final auth = BakaAuth( + client: MockClient((_) async => http.Response('', 500)), + speicher: _MemorySpeicher()); + final search = YtSearchService(auth: auth); + final download = YtDownloadService(auth: auth); + final gast = GastZugang( + client: MockClient((_) async => + http.Response(jsonEncode({'guest_token': 'g-1'}), 200)), + speicher: _MemorySpeicher(), + ); + + await tester.pumpWidget(_wrap( + db: db, auth: auth, search: search, download: download, gast: gast)); + await tester.pumpAndSettle(); + + await tester.tap(find.text('Als Gast fortfahren (5 Downloads/Tag)')); + await tester.pumpAndSettle(); + + expect(find.textContaining('Baka-Anmeldung'), findsNothing); + expect(find.text('Als Gast unterwegs (5 Downloads/Tag)'), findsOneWidget); + + await db.close(); + }); }