fix: code-review findings — error handling, null safety, persist settings, auth header
This commit is contained in:
@@ -43,7 +43,10 @@ class _CloudScreenState extends State<CloudScreen> {
|
|||||||
Future<void> _verbindeCloud() async {
|
Future<void> _verbindeCloud() async {
|
||||||
final user = AuthService().benutzer;
|
final user = AuthService().benutzer;
|
||||||
if (user.isNotEmpty) {
|
if (user.isNotEmpty) {
|
||||||
await widget.cloud.login(user);
|
final ok = await widget.cloud.login(user);
|
||||||
|
if (!ok && mounted) {
|
||||||
|
setState(() => _setzeStatus('Cloud-Login fehlgeschlagen', ok: false));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,6 +94,7 @@ class _CloudScreenState extends State<CloudScreen> {
|
|||||||
Future<void> _upload() async {
|
Future<void> _upload() async {
|
||||||
setState(() => _ladt = true);
|
setState(() => _ladt = true);
|
||||||
_setzeStatus('Suche lokale Songs...');
|
_setzeStatus('Suche lokale Songs...');
|
||||||
|
try {
|
||||||
final dir = Directory('${(await getApplicationDocumentsDirectory()).path}/music');
|
final dir = Directory('${(await getApplicationDocumentsDirectory()).path}/music');
|
||||||
if (!await dir.exists()) {
|
if (!await dir.exists()) {
|
||||||
setState(() { _ladt = false; _setzeStatus('Keine lokalen Songs', ok: false); });
|
setState(() { _ladt = false; _setzeStatus('Keine lokalen Songs', ok: false); });
|
||||||
@@ -110,11 +114,16 @@ class _CloudScreenState extends State<CloudScreen> {
|
|||||||
_setzeStatus('$count Songs hochgeladen', ok: count > 0);
|
_setzeStatus('$count Songs hochgeladen', ok: count > 0);
|
||||||
MeloLogger().aktion('cloud_upload', {'count': count});
|
MeloLogger().aktion('cloud_upload', {'count': count});
|
||||||
}
|
}
|
||||||
|
} catch (e) {
|
||||||
|
MeloLogger().fehler('cloud_upload_path', e);
|
||||||
|
if (mounted) setState(() { _ladt = false; _setzeStatus('Fehler beim Upload', ok: false); });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _download() async {
|
Future<void> _download() async {
|
||||||
setState(() => _ladt = true);
|
setState(() { _ladt = true; });
|
||||||
_setzeStatus('Vergleiche mit Server...');
|
_setzeStatus('Vergleiche mit Server...');
|
||||||
|
try {
|
||||||
final dir = Directory('${(await getApplicationDocumentsDirectory()).path}/music');
|
final dir = Directory('${(await getApplicationDocumentsDirectory()).path}/music');
|
||||||
if (!await dir.exists()) await dir.create(recursive: true);
|
if (!await dir.exists()) await dir.create(recursive: true);
|
||||||
final localFiles = dir.listSync().whereType<File>()
|
final localFiles = dir.listSync().whereType<File>()
|
||||||
@@ -122,7 +131,7 @@ class _CloudScreenState extends State<CloudScreen> {
|
|||||||
final serverSongs = await widget.cloud.listSongs();
|
final serverSongs = await widget.cloud.listSongs();
|
||||||
int downloaded = 0;
|
int downloaded = 0;
|
||||||
for (final song in serverSongs) {
|
for (final song in serverSongs) {
|
||||||
final title = song['title'].toString();
|
final title = (song['title'] ?? 'unknown').toString();
|
||||||
if (localFiles.contains(title)) continue;
|
if (localFiles.contains(title)) continue;
|
||||||
_setzeStatus('Download: $title...');
|
_setzeStatus('Download: $title...');
|
||||||
final sid = song['id'].toString();
|
final sid = song['id'].toString();
|
||||||
@@ -135,6 +144,10 @@ class _CloudScreenState extends State<CloudScreen> {
|
|||||||
_setzeStatus('$downloaded Songs heruntergeladen', ok: true);
|
_setzeStatus('$downloaded Songs heruntergeladen', ok: true);
|
||||||
MeloLogger().aktion('cloud_download', {'count': downloaded});
|
MeloLogger().aktion('cloud_download', {'count': downloaded});
|
||||||
}
|
}
|
||||||
|
} catch (e) {
|
||||||
|
MeloLogger().fehler('cloud_download_path', e);
|
||||||
|
if (mounted) setState(() { _ladt = false; _setzeStatus('Fehler beim Download', ok: false); });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _setzeStatus(String msg, {bool ok = false}) {
|
void _setzeStatus(String msg, {bool ok = false}) {
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import '../widgets/melo_header.dart';
|
|||||||
import '../widgets/statistik_card.dart';
|
import '../widgets/statistik_card.dart';
|
||||||
import '../widgets/tag_leiste.dart';
|
import '../widgets/tag_leiste.dart';
|
||||||
import '../widgets/song_tile.dart';
|
import '../widgets/song_tile.dart';
|
||||||
import '../widgets/navidrome_browser.dart';
|
|
||||||
import '../widgets/playlist_sheet.dart';
|
import '../widgets/playlist_sheet.dart';
|
||||||
import 'download_screen.dart';
|
import 'download_screen.dart';
|
||||||
import 'cloud_screen.dart';
|
import 'cloud_screen.dart';
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import '../config/app_config.dart';
|
import '../config/app_config.dart';
|
||||||
import '../utils/farb_theme.dart';
|
import '../utils/farb_theme.dart';
|
||||||
import 'cloud_screen.dart';
|
import 'cloud_screen.dart';
|
||||||
@@ -15,6 +16,17 @@ class SettingsScreen extends StatefulWidget {
|
|||||||
class _SettingsScreenState extends State<SettingsScreen> {
|
class _SettingsScreenState extends State<SettingsScreen> {
|
||||||
bool _diagnose = AppConfig.sendeDiagnosedaten;
|
bool _diagnose = AppConfig.sendeDiagnosedaten;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_ladeDiagnose();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _ladeDiagnose() async {
|
||||||
|
final p = await SharedPreferences.getInstance();
|
||||||
|
if (mounted) setState(() => _diagnose = p.getBool('diagnose_daten') ?? AppConfig.sendeDiagnosedaten);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
@@ -84,9 +96,11 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
|||||||
),
|
),
|
||||||
value: _diagnose,
|
value: _diagnose,
|
||||||
activeThumbColor: MeloTheme.rot,
|
activeThumbColor: MeloTheme.rot,
|
||||||
onChanged: (v) {
|
onChanged: (v) async {
|
||||||
setState(() => _diagnose = v);
|
setState(() => _diagnose = v);
|
||||||
AppConfig.sendeDiagnosedaten = v;
|
AppConfig.sendeDiagnosedaten = v;
|
||||||
|
final p = await SharedPreferences.getInstance();
|
||||||
|
p.setBool('diagnose_daten', v);
|
||||||
},
|
},
|
||||||
secondary: const Icon(Icons.bug_report_outlined, color: MeloTheme.rot, size: 22),
|
secondary: const Icon(Icons.bug_report_outlined, color: MeloTheme.rot, size: 22),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -21,10 +21,15 @@ class AuthService {
|
|||||||
String? get token => _token;
|
String? get token => _token;
|
||||||
|
|
||||||
/// Auth-Header für API-Requests
|
/// Auth-Header für API-Requests
|
||||||
Map<String, String> get authHeader => {
|
Map<String, String> get authHeader {
|
||||||
'Authorization': 'Bearer ${_token ?? ''}',
|
final headers = <String, String>{
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
};
|
};
|
||||||
|
if (_token != null && _token!.isNotEmpty) {
|
||||||
|
headers['Authorization'] = 'Bearer $_token';
|
||||||
|
}
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
|
||||||
/// Lädt gespeicherten Token beim App-Start
|
/// Lädt gespeicherten Token beim App-Start
|
||||||
Future<void> initialisieren() async {
|
Future<void> initialisieren() async {
|
||||||
|
|||||||
Reference in New Issue
Block a user