Download-Tab: Gast-Zugang mit bewusster Wahl + Tages-Zähler

Echte Gäste sehen jetzt zwei Buttons: "Beim Baka-Konto anmelden"
und "Als Gast fortfahren (5 Downloads/Tag)". Im Gast-Modus wird
der Cookie-Schalter ausgeblendet (Server erzwingt cookies=false
für Gast-Zugriffe ohnehin) und ein Zähler "noch N von 5 heute"
gezeigt, sobald der Server ihn meldet.

_YouTubeBereich.build() beobachtet jetzt app-weit GastZugang; das
Qualitäts-Gate deckte auf, dass hauptmenue_test.dart und
home_shell_test.dart eigene Provider-Bäume ohne GastZugang bauen
(sie spiegeln main.dart nach, statt es zu importieren) — dort
GastZugang ergänzt, analog zum bestehenden Muster für die anderen
Dienste.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Hermes (Server)
2026-08-26 21:24:08 +02:00
co-authored by Claude Sonnet 5
parent 5347797292
commit cfebcc03b5
4 changed files with 136 additions and 14 deletions
+65 -1
View File
@@ -11,6 +11,7 @@ import 'package:melo/library/category_service.dart';
import 'package:melo/library/database.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:provider/provider.dart';
@@ -29,7 +30,9 @@ class _MemorySpeicher implements TokenSpeicher {
Widget _wrap(BakaAuth auth,
{required MeloDb db,
required CategoryService categories,
NavidromeService? navidrome}) {
NavidromeService? navidrome,
GastZugang? gast}) {
final gastZugang = gast ?? GastZugang();
return MultiProvider(
providers: [
Provider<MeloDb>.value(value: db),
@@ -38,9 +41,11 @@ Widget _wrap(BakaAuth auth,
// Aufräum-Timer von drift im Test-Rahmen hängen.
ChangeNotifierProvider<CategoryService>.value(value: categories),
ChangeNotifierProvider<BakaAuth>.value(value: auth),
ChangeNotifierProvider<GastZugang>.value(value: gastZugang),
ChangeNotifierProvider<YtDownloadService>(
create: (_) => YtDownloadService(
auth: auth,
gast: gastZugang,
client: MockClient((_) async => http.Response('', 500)),
),
),
@@ -270,4 +275,63 @@ void main() {
expect(gesendeterBenutzer, 'Tinker');
expect(auth.istAngemeldet, isTrue);
});
testWidgets('Gast sieht zwei Buttons: Anmelden und Als Gast fortfahren',
(tester) async {
final auth = BakaAuth(
client: MockClient((_) async => http.Response('', 500)),
speicher: _MemorySpeicher());
await tester.pumpWidget(_wrap(auth, db: db, categories: categories));
await tester.pumpAndSettle();
expect(find.text('Beim Baka-Konto anmelden'), findsOneWidget);
expect(
find.text('Als Gast fortfahren (5 Downloads/Tag)'), findsOneWidget);
expect(find.text('YouTube-Adresse'), findsNothing);
});
testWidgets(
'Als Gast fortfahren holt einen Token und schaltet das Adressfeld frei',
(tester) async {
final auth = BakaAuth(
client: MockClient((_) async => http.Response('', 500)),
speicher: _MemorySpeicher());
final gast = GastZugang(
client: MockClient((_) async =>
http.Response(jsonEncode({'guest_token': 'g-1'}), 200)),
speicher: _MemorySpeicher(),
);
await tester.pumpWidget(
_wrap(auth, db: db, categories: categories, gast: gast));
await tester.pumpAndSettle();
await tester.tap(find.text('Als Gast fortfahren (5 Downloads/Tag)'));
await tester.pumpAndSettle();
expect(find.text('YouTube-Adresse'), findsOneWidget);
expect(find.text('Als Gast unterwegs (5 Downloads/Tag)'), findsOneWidget);
expect(find.text('YouTube-Cookies des Servers verwenden'), findsNothing);
});
testWidgets('Fehler beim Gast-Token wird angezeigt', (tester) async {
final auth = BakaAuth(
client: MockClient((_) async => http.Response('', 500)),
speicher: _MemorySpeicher());
final gast = GastZugang(
client: MockClient((_) async => http.Response('', 500)),
speicher: _MemorySpeicher(),
);
await tester.pumpWidget(
_wrap(auth, db: db, categories: categories, gast: gast));
await tester.pumpAndSettle();
await tester.tap(find.text('Als Gast fortfahren (5 Downloads/Tag)'));
await tester.pumpAndSettle();
expect(find.text('Gast-Zugang fehlgeschlagen (500)'), findsOneWidget);
expect(find.text('YouTube-Adresse'), findsNothing);
});
}
+6 -2
View File
@@ -9,6 +9,7 @@ import 'package:melo/main.dart';
import 'package:melo/player/audio_handler.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/melo_cloud_service.dart';
import 'package:melo/services/navidrome_service.dart';
import 'package:melo/services/offline_mode.dart';
@@ -51,6 +52,7 @@ void main() {
late YtSearchService ytSearch;
late DownloadService downloads;
late SyncService sync;
late GastZugang gast;
MeloAudioHandler? handler;
setUp(() {
@@ -62,8 +64,9 @@ void main() {
auth = BakaAuth(speicher: _MemorySpeicher());
einstellungen = AppSettings();
offline = OfflineMode();
ytDownload = YtDownloadService(auth: auth);
ytSearch = YtSearchService(auth: auth);
gast = GastZugang();
ytDownload = YtDownloadService(auth: auth, gast: gast);
ytSearch = YtSearchService(auth: auth, gast: gast);
downloads = DownloadService(db: db, navidrome: NavidromeService());
sync = SyncService(db: db, cloud: MeloCloudService(auth: auth));
});
@@ -95,6 +98,7 @@ void main() {
ChangeNotifierProvider<AppSettings>.value(value: einstellungen),
ChangeNotifierProvider<OfflineMode>.value(value: offline),
ChangeNotifierProvider<BakaAuth>.value(value: auth),
ChangeNotifierProvider<GastZugang>.value(value: gast),
ChangeNotifierProvider<YtDownloadService>.value(value: ytDownload),
ChangeNotifierProvider<YtSearchService>.value(value: ytSearch),
ChangeNotifierProvider<DownloadService>.value(value: downloads),
+2
View File
@@ -9,6 +9,7 @@ import 'package:melo/main.dart';
import 'package:melo/player/audio_handler.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/melo_cloud_service.dart';
import 'package:melo/services/navidrome_service.dart';
import 'package:melo/services/offline_mode.dart';
@@ -50,6 +51,7 @@ void main() {
ChangeNotifierProvider<AppSettings>(create: (_) => AppSettings()),
ChangeNotifierProvider<OfflineMode>(create: (_) => OfflineMode()),
ChangeNotifierProvider<BakaAuth>(create: (_) => auth),
ChangeNotifierProvider<GastZugang>(create: (_) => GastZugang()),
ChangeNotifierProvider<YtDownloadService>(
create: (_) => YtDownloadService(auth: auth)),
ChangeNotifierProvider<YtSearchService>(