YT-Suche-Tab: Gast-Zugang mit bewusster Wahl + Tages-Zähler
Analog zum Download-Tab: echte Gäste sehen zusätzlich zum bestehenden Hinweis den Button "Als Gast fortfahren (5 Downloads/Tag)"; im Gast-Modus ersetzt ein Zähler den Hinweis. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
81ec1e232b
commit
aecb8e3364
@@ -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<YoutubeSearchScreen> {
|
||||
/// 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<YoutubeSearchScreen> {
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _alsGastFortfahren() async {
|
||||
final gast = context.read<GastZugang>();
|
||||
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<YoutubeSearchScreen> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final auth = context.watch<BakaAuth>();
|
||||
final gast = context.watch<GastZugang>();
|
||||
final suche = context.watch<YtSearchService>();
|
||||
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<YoutubeSearchScreen> {
|
||||
],
|
||||
),
|
||||
),
|
||||
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(),
|
||||
|
||||
@@ -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<MeloDb>.value(value: db),
|
||||
ChangeNotifierProvider<LibraryService>.value(value: LibraryService(db)),
|
||||
ChangeNotifierProvider<BakaAuth>.value(value: auth),
|
||||
ChangeNotifierProvider<GastZugang>.value(value: gast ?? GastZugang()),
|
||||
ChangeNotifierProvider<YtSearchService>.value(value: search),
|
||||
ChangeNotifierProvider<YtDownloadService>.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();
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user