This repository has been archived on 2026-08-19. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
melo-app/lib/widgets/song_tile.dart
T
Dustin 36c744d6e3 v2.31 — Login, Einstellungen & Cloud Sync Redesign
- Login-Screen im Melo-Design (Schwarz+Rot) mit Baka-Auth JWT
- AuthService fuer Token-Management ueber baka-net.de/auth
- Registrierungs-Modus + 'Ohne Login fortfahren'
- Navidrome-Credentials optional im Login aufklappbar

- SettingsScreen ersetzt AlertDialog
- BottomNav navigiert statt Dialog zu triggern
- Cloud Sync, Server verbinden, Diagnosedaten, App-Info, Abmelden

- CloudEinstellungen-Dialog entfernt, alles in CloudScreen konsolidiert
- Hardcode login('Baka','') entfernt → AuthService.benutzer
- Gradient-Statuskarte, animierte Segment-Intervall-Auswahl
- JWT Authorization statt Klartext-Passwort

- AppConfig: API-Key defaultValue entfernt (kein Fallback-Leak)
- Build crasht ohne --dart-define MELO_API_KEY

Build: split APK (arm64 19.6M, armeabi 17.1M, x86_64 21.1M)
2026-08-01 15:03:22 +02:00

105 lines
3.7 KiB
Dart

import 'dart:io';
import 'package:flutter/material.dart';
import '../models/song.dart';
import '../utils/farb_theme.dart';
import 'metadaten_dialog.dart';
import 'tag_auswahl_dialog.dart';
class SongTile extends StatelessWidget {
final Song song;
final bool istFavorit;
final ValueChanged<Song> onFavoriteToggle;
final ValueChanged<Song> onPlay;
final VoidCallback onMetadataChanged;
final ValueChanged<Song>? onAddToPlaylist;
const SongTile({
super.key,
required this.song,
required this.istFavorit,
required this.onFavoriteToggle,
required this.onPlay,
required this.onMetadataChanged,
this.onAddToPlaylist,
});
@override
Widget build(BuildContext context) {
final hatDatei = song.dateiPfad.isNotEmpty;
final hatCover = song.coverPfad != null && File(song.coverPfad!).existsSync();
return ListTile(
contentPadding: const EdgeInsets.symmetric(vertical: 2),
leading: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Container(
width: 44, height: 44,
decoration: const BoxDecoration(
gradient: LinearGradient(colors: [Color(0xFF1A0000), Color(0xFF660000)]),
),
child: hatCover
? Image.file(File(song.coverPfad!), fit: BoxFit.cover)
: const Center(child: Text('♪', style: TextStyle(fontSize: 18, color: Colors.white54))),
),
),
title: Text(song.titel, style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white)),
subtitle: Text(song.kuenstler, style: const TextStyle(fontSize: 12, color: MeloTheme.textSekundaer)),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
InkWell(
borderRadius: BorderRadius.circular(50),
onTap: () async {
final geaendert = await showDialog<bool>(
context: context,
builder: (_) => MetadatenDialog(song: song),
);
if (geaendert == true) onMetadataChanged();
},
child: Padding(
padding: const EdgeInsets.all(6),
child: Icon(Icons.edit, size: 14, color: MeloTheme.textSekundaer),
),
),
InkWell(
borderRadius: BorderRadius.circular(50),
onTap: () => showDialog(
context: context,
builder: (_) => TagAuswahlDialog(
songId: song.id!,
songTitel: song.titel,
onChanged: onMetadataChanged,
),
),
child: Padding(
padding: const EdgeInsets.all(6),
child: const Icon(Icons.label_outline, size: 14, color: MeloTheme.textSekundaer),
),
),
if (onAddToPlaylist != null)
InkWell(
borderRadius: BorderRadius.circular(50),
onTap: () => onAddToPlaylist!(song),
child: Padding(
padding: const EdgeInsets.all(6),
child: const Icon(Icons.playlist_add, size: 14, color: MeloTheme.textSekundaer),
),
),
InkWell(
borderRadius: BorderRadius.circular(50),
onTap: () => onFavoriteToggle(song),
child: Padding(
padding: const EdgeInsets.all(6),
child: Icon(
istFavorit ? Icons.favorite : Icons.favorite_border,
size: 16, color: MeloTheme.rot,
),
),
),
Text(song.dauerFormatiert, style: const TextStyle(fontSize: 12, color: MeloTheme.textSekundaer)),
],
),
onTap: hatDatei ? () => onPlay(song) : null,
);
}
}