✨ Feature: Login-Verbesserungen für Dustin!
1. 🔗 AUTO-URL: Server-URL \"https://musik.baka-net.de\" vorausgefüllt (editierbar) 2. 👤 USER-BUTTONS: Baka/Tinker/Dustin als Button-Auswahl (statt Text-Input) 3. 🔐 PASSWORT-ONLY: Dialog zeigt nur Passwort-Feld + User-Auswahl (wie beim Register!) 4. 💡 GAST-MODUS: Info-Text erklärt lokale Nutzung ohne Server-Konto → App funktioniert auch komplett offline mit lokaler Musikbibliothek! UX-Verbesserungen: - Weniger zu tippen (URL + User vorgegeben) - Schneller Login für Baka/Tinker/Dustin - Klare Fallback-Option für lokale Nutzung Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XJzQjUtnvYUtHdnTs3iCru
This commit is contained in:
co-authored by
Claude Haiku 4.5
parent
ea6ce5d4a6
commit
2948285d82
@@ -79,6 +79,14 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
onPressed: () => _zeigeNavidromeDialog(),
|
||||
),
|
||||
),
|
||||
if (!_navidrome.istVerbunden)
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
child: Text(
|
||||
'💡 Tipp: Oder nutze Melo lokal ohne Server-Konto (nur deine Musik auf dem Gerät)',
|
||||
style: TextStyle(fontSize: 12, color: Colors.white54),
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.wifi_off),
|
||||
title: const Text('📴 Offline-Modus'),
|
||||
@@ -147,9 +155,9 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
}
|
||||
|
||||
void _zeigeNavidromeDialog() {
|
||||
final urlCtrl = TextEditingController();
|
||||
final userCtrl = TextEditingController();
|
||||
final urlCtrl = TextEditingController(text: 'https://musik.baka-net.de');
|
||||
final passCtrl = TextEditingController();
|
||||
String selectedUser = 'Dustin';
|
||||
bool verbindet = false;
|
||||
String? fehler;
|
||||
|
||||
@@ -158,9 +166,10 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
builder: (ctx) => StatefulBuilder(
|
||||
builder: (ctx, setDialogState) => AlertDialog(
|
||||
backgroundColor: Colors.grey.shade900,
|
||||
title: const Text('🌐 Navidrome Verbinden',
|
||||
title: const Text('🌐 Navidrome Login',
|
||||
style: TextStyle(color: Colors.white, fontSize: 16)),
|
||||
content: Column(
|
||||
content: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
TextField(
|
||||
@@ -168,23 +177,53 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
style: const TextStyle(color: Colors.white),
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Server-URL',
|
||||
hintText: 'https://musik.example.com',
|
||||
labelStyle: TextStyle(color: Colors.grey),
|
||||
hintStyle: TextStyle(color: Colors.grey),
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
TextField(
|
||||
controller: userCtrl,
|
||||
style: const TextStyle(color: Colors.white),
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Benutzer',
|
||||
labelStyle: TextStyle(color: Colors.grey),
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
const Text('Benutzer:', style: TextStyle(fontSize: 12, color: Colors.white70)),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: FilledButton(
|
||||
onPressed: () => setDialogState(() => selectedUser = 'Baka'),
|
||||
style: FilledButton.styleFrom(
|
||||
backgroundColor: selectedUser == 'Baka'
|
||||
? Colors.redAccent
|
||||
: Colors.grey.shade700,
|
||||
),
|
||||
child: const Text('Baka'),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: FilledButton(
|
||||
onPressed: () => setDialogState(() => selectedUser = 'Tinker'),
|
||||
style: FilledButton.styleFrom(
|
||||
backgroundColor: selectedUser == 'Tinker'
|
||||
? Colors.redAccent
|
||||
: Colors.grey.shade700,
|
||||
),
|
||||
child: const Text('Tinker'),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: FilledButton(
|
||||
onPressed: () => setDialogState(() => selectedUser = 'Dustin'),
|
||||
style: FilledButton.styleFrom(
|
||||
backgroundColor: selectedUser == 'Dustin'
|
||||
? Colors.redAccent
|
||||
: Colors.grey.shade700,
|
||||
),
|
||||
child: const Text('Dustin'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
TextField(
|
||||
controller: passCtrl,
|
||||
style: const TextStyle(color: Colors.white),
|
||||
@@ -212,6 +251,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(ctx),
|
||||
@@ -222,20 +262,20 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
: () async {
|
||||
setDialogState(() => verbindet = true);
|
||||
_navidrome.setCredentials(
|
||||
urlCtrl.text, userCtrl.text, passCtrl.text);
|
||||
urlCtrl.text, selectedUser, passCtrl.text);
|
||||
final ok = await _navidrome.ping();
|
||||
setDialogState(() => verbindet = false);
|
||||
if (ok && ctx.mounted) {
|
||||
await _navidrome.speichereZugangsdaten(
|
||||
urlCtrl.text, userCtrl.text, passCtrl.text);
|
||||
urlCtrl.text, selectedUser, passCtrl.text);
|
||||
if (ctx.mounted) Navigator.pop(ctx);
|
||||
if (mounted) setState(() {});
|
||||
} else if (ctx.mounted) {
|
||||
setDialogState(() =>
|
||||
fehler = '❌ Verbindung fehlgeschlagen\nPrüfe URL + Zugangsdaten');
|
||||
fehler = '❌ Login fehlgeschlagen');
|
||||
}
|
||||
},
|
||||
child: const Text('Verbinden',
|
||||
child: const Text('Login',
|
||||
style: TextStyle(color: Colors.redAccent)),
|
||||
),
|
||||
],
|
||||
@@ -243,7 +283,6 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
),
|
||||
).then((_) {
|
||||
urlCtrl.dispose();
|
||||
userCtrl.dispose();
|
||||
passCtrl.dispose();
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user