Kein Redesign — Schwarz/Rot, 4 Tabs und Lieder/Kategorie bleiben. Grundlage sind die Design-Skills: ui-ux-pro-max (Barrierefreiheit, Touch, Typografie, Bewegung), ui-design/mobile-android (Material 3) und die Token-Disziplin aus Hue. Behobene Maengel (messbar, nicht Geschmack): - Text in Colors.white38 an 17 Stellen = 3,4:1 Kontrast, WCAG verlangt 4,5:1. Ersetzt durch drei benannte Stufen (text1 15,9:1 / text2 8,8:1 / text3 4,9:1). theme_kontrast_test.dart rechnet die Verhaeltnisse bei jedem Lauf nach, statt sie zu behaupten. - SubTabs waren ~38 dp hoch (Material 3 verlangt 48), ohne Ripple und ohne Uebergang. Jetzt 48 dp, InkWell, AnimatedContainer, und die Auswahl wird Vorlesehilfen als Zustand gemeldet (Semantics.selected). - mini_player.dart: Expanded UM eine feste Hoehe herum — zwei widerspruechliche Angaben. Entschaerft. - Emoji in Bedienelementen der Einstellungen (jeweils neben einem echten Icon) entfernt. Neu in shared/theme.dart: MeloSpace (8er-Raster), MeloRadius, MeloMotion, Farbrollen text1/2/3 + border + hairline, minTouchTarget, vollstaendiges textTheme (7 Stufen) und Themes fuer Listen, Sheets, Snackbars, Fortschritt, Trenner. 318 Tests gruen (23 neue, 1 uebersprungen), flutter analyze ohne Befund. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FpPu4nuKjKKeX1RpdDeX81
103 lines
3.4 KiB
Dart
103 lines
3.4 KiB
Dart
import 'package:drift/drift.dart';
|
|
import 'package:drift/native.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:provider/provider.dart';
|
|
import 'package:melo/library/database.dart';
|
|
import 'package:melo/library/library_service.dart';
|
|
import 'package:melo/services/baka_auth.dart';
|
|
import 'package:melo/services/melo_cloud_service.dart';
|
|
import 'package:melo/services/offline_mode.dart';
|
|
import 'package:melo/services/sync_service.dart';
|
|
import 'package:melo/settings/app_settings.dart';
|
|
import 'package:melo/settings/settings_screen.dart';
|
|
|
|
/// Token-Ablage ohne Plattform-Kanäle — im Test gibt es keinen sicheren
|
|
/// Gerätespeicher.
|
|
class _MemorySpeicher implements TokenSpeicher {
|
|
final Map<String, String> werte = {};
|
|
@override
|
|
Future<String?> lesen(String key) async => werte[key];
|
|
@override
|
|
Future<void> schreiben(String key, String wert) async => werte[key] = wert;
|
|
@override
|
|
Future<void> loeschen(String key) async => werte.remove(key);
|
|
}
|
|
|
|
Widget _wrap(MeloDb db, Widget child) {
|
|
return MultiProvider(
|
|
providers: [
|
|
Provider<MeloDb>.value(value: db),
|
|
ChangeNotifierProvider<OfflineMode>.value(value: OfflineMode()),
|
|
ChangeNotifierProvider<LibraryService>.value(value: LibraryService(db)),
|
|
ChangeNotifierProvider<AppSettings>(create: (_) => AppSettings()),
|
|
ChangeNotifierProvider<BakaAuth>(
|
|
create: (_) => BakaAuth(speicher: _MemorySpeicher())),
|
|
ChangeNotifierProvider<SyncService>(
|
|
create: (context) => SyncService(
|
|
db: db,
|
|
cloud: MeloCloudService(auth: context.read<BakaAuth>()),
|
|
)),
|
|
],
|
|
child: MaterialApp(home: child),
|
|
);
|
|
}
|
|
|
|
void main() {
|
|
testWidgets('zeigt 0 Songs ohne Bibliothek', (tester) async {
|
|
final db = MeloDb(NativeDatabase.memory());
|
|
|
|
await tester.pumpWidget(_wrap(db, const SettingsScreen()));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('0 Songs in der Bibliothek'), findsOneWidget);
|
|
|
|
await db.close();
|
|
});
|
|
|
|
testWidgets('zeigt korrekte Song-Anzahl und Gesamtspieldauer', (tester) async {
|
|
final db = MeloDb(NativeDatabase.memory());
|
|
await db.into(db.songs).insert(SongsCompanion.insert(
|
|
id: 'song-1',
|
|
path: '/a.mp3',
|
|
title: 'Song A',
|
|
dateAddedMs: 0,
|
|
updatedAtMs: 0,
|
|
durationMs: const Value(200000),
|
|
));
|
|
await db.into(db.songs).insert(SongsCompanion.insert(
|
|
id: 'song-2',
|
|
path: '/b.mp3',
|
|
title: 'Song B',
|
|
dateAddedMs: 0,
|
|
updatedAtMs: 0,
|
|
durationMs: const Value(185000),
|
|
));
|
|
|
|
await tester.pumpWidget(_wrap(db, const SettingsScreen()));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('2 Songs in der Bibliothek'), findsOneWidget);
|
|
expect(find.text('6m Gesamtspieldauer'), findsOneWidget);
|
|
|
|
await db.close();
|
|
});
|
|
|
|
testWidgets('zeigt Favoriten- und Playlisten-Sync', (tester) async {
|
|
final db = MeloDb(NativeDatabase.memory());
|
|
|
|
await tester.pumpWidget(_wrap(db, const SettingsScreen()));
|
|
await tester.pumpAndSettle();
|
|
|
|
// Die Sync-Einträge liegen weiter unten in der Liste und müssen erst
|
|
// in den sichtbaren Bereich gescrollt werden.
|
|
await tester.scrollUntilVisible(find.text('Favoriten-Sync'), 200);
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('Favoriten-Sync'), findsOneWidget);
|
|
expect(find.text('Playlisten-Sync'), findsOneWidget);
|
|
|
|
await db.close();
|
|
});
|
|
}
|