Issue #1: CloudScreen Zurück-Button — onZurueck Callback statt Navigator.pop() - CloudScreen erhält VoidCallback? onZurueck Parameter - Bei onZurueck != null → Callback (Tab-Wechsel in home_screen) - Fallback: Navigator.pop(context) für Standalone-Nutzung Issue #5: Token wird nur bei HTTP 401 gelöscht - _tokenOnlinePruefen(): nur statusCode == 401 → false - 5xx, andere Fehler, Netzwerkfehler → true (Token behalten) - Verhindert Ausloggen bei temporären Server-Problemen Issue #4: Android 13+ Berechtigungen beim App-Start - main.dart: frageSpeicherZugriff() + POST_NOTIFICATIONS nach Auth-Init - musik_scanner.dart: Permission-Check vor externen Ordnern in _sammleMusikPfade() Build: ⏭️ (no APK)
This commit is contained in:
@@ -1,12 +1,15 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'dart:io' show Platform;
|
||||||
import 'package:audio_service/audio_service.dart';
|
import 'package:audio_service/audio_service.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
import 'database/db_helper.dart';
|
import 'database/db_helper.dart';
|
||||||
import 'services/favoriten_service.dart';
|
import 'services/favoriten_service.dart';
|
||||||
import 'services/auth_service.dart';
|
import 'services/auth_service.dart';
|
||||||
import 'services/cloud_service.dart';
|
import 'services/cloud_service.dart';
|
||||||
import 'services/melo_logger.dart';
|
import 'services/melo_logger.dart';
|
||||||
import 'services/audio_handler.dart';
|
import 'services/audio_handler.dart';
|
||||||
|
import 'services/musik_scanner.dart';
|
||||||
import 'utils/farb_theme.dart';
|
import 'utils/farb_theme.dart';
|
||||||
import 'screens/home_screen.dart';
|
import 'screens/home_screen.dart';
|
||||||
import 'screens/login_screen.dart';
|
import 'screens/login_screen.dart';
|
||||||
@@ -37,6 +40,15 @@ void main() async {
|
|||||||
// Auth initialisieren (Token aus SharedPreferences laden + online validieren)
|
// Auth initialisieren (Token aus SharedPreferences laden + online validieren)
|
||||||
await AuthService().initialisieren();
|
await AuthService().initialisieren();
|
||||||
|
|
||||||
|
// Android-Berechtigungen beim Start abfragen (Issue #4)
|
||||||
|
// Speicherzugriff für Musik-Scan (READ_MEDIA_AUDIO / Storage)
|
||||||
|
await MusikScanner().frageSpeicherZugriff();
|
||||||
|
|
||||||
|
// POST_NOTIFICATIONS für Android 13+ (Notifications für Downloads, Player)
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
await Permission.notification.request();
|
||||||
|
}
|
||||||
|
|
||||||
// Auto-Sync beim Start (wenn eingeloggt und Auto-Sync aktiv)
|
// Auto-Sync beim Start (wenn eingeloggt und Auto-Sync aktiv)
|
||||||
_starteAutoSyncFallsNoetig();
|
_starteAutoSyncFallsNoetig();
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ import '../services/melo_logger.dart';
|
|||||||
/// Playlisten, Favoriten, Auto-Sync, Persistent Login, Benutzerdefinierte Namen
|
/// Playlisten, Favoriten, Auto-Sync, Persistent Login, Benutzerdefinierte Namen
|
||||||
class CloudScreen extends StatefulWidget {
|
class CloudScreen extends StatefulWidget {
|
||||||
final CloudService cloud;
|
final CloudService cloud;
|
||||||
const CloudScreen({super.key, required this.cloud});
|
final VoidCallback? onZurueck;
|
||||||
|
const CloudScreen({super.key, required this.cloud, this.onZurueck});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<CloudScreen> createState() => _CloudScreenState();
|
State<CloudScreen> createState() => _CloudScreenState();
|
||||||
@@ -590,7 +591,13 @@ class _CloudScreenState extends State<CloudScreen> {
|
|||||||
backgroundColor: MeloTheme.dunkel1,
|
backgroundColor: MeloTheme.dunkel1,
|
||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
icon: const Icon(Icons.arrow_back, color: Colors.white, size: 22),
|
icon: const Icon(Icons.arrow_back, color: Colors.white, size: 22),
|
||||||
onPressed: () => Navigator.pop(context),
|
onPressed: () {
|
||||||
|
if (widget.onZurueck != null) {
|
||||||
|
widget.onZurueck!();
|
||||||
|
} else {
|
||||||
|
Navigator.pop(context);
|
||||||
|
}
|
||||||
|
},
|
||||||
),
|
),
|
||||||
title: const Row(
|
title: const Row(
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
@@ -303,7 +303,10 @@ class _MeloHomeState extends State<MeloHome> {
|
|||||||
onSongsChanged: _vm.ladeSongs,
|
onSongsChanged: _vm.ladeSongs,
|
||||||
)
|
)
|
||||||
: _aktiverTab == 4
|
: _aktiverTab == 4
|
||||||
? CloudScreen(cloud: _cloud)
|
? CloudScreen(
|
||||||
|
cloud: _cloud,
|
||||||
|
onZurueck: () => setState(() => _aktiverTab = 0),
|
||||||
|
)
|
||||||
: Column(
|
: Column(
|
||||||
children: [
|
children: [
|
||||||
MeloHeader(onDownload: _zeigeDownloadDialog, onSearch: _zeigeSuche, onServer: _zeigeServerBrowser),
|
MeloHeader(onDownload: _zeigeDownloadDialog, onSearch: _zeigeSuche, onServer: _zeigeServerBrowser),
|
||||||
|
|||||||
@@ -69,7 +69,11 @@ class AuthService {
|
|||||||
headers: authHeader,
|
headers: authHeader,
|
||||||
)
|
)
|
||||||
.timeout(const Duration(seconds: 5));
|
.timeout(const Duration(seconds: 5));
|
||||||
return response.statusCode == 200;
|
if (response.statusCode == 200) return true;
|
||||||
|
// Nur bei explizitem 401 (abgelaufen/ungültig) den Token löschen.
|
||||||
|
// Bei 5xx, anderen Fehlern oder temporären Server-Problemen Token behalten.
|
||||||
|
if (response.statusCode == 401) return false;
|
||||||
|
return true;
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
// Bei Netzwerkfehler: Token lokal akzeptieren (Offline-Modus)
|
// Bei Netzwerkfehler: Token lokal akzeptieren (Offline-Modus)
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -135,8 +135,11 @@ class MusikScanner {
|
|||||||
MeloLogger().fehler('scanner_intern_pfad', e);
|
MeloLogger().fehler('scanner_intern_pfad', e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Externe System-Ordner (nur Android)
|
// 2. Externe System-Ordner (nur Android, nur wenn Berechtigung vorhanden)
|
||||||
if (Platform.isAndroid) {
|
if (Platform.isAndroid) {
|
||||||
|
final hatZugriff = await frageSpeicherZugriff();
|
||||||
|
if (!hatZugriff) return pfade.toList();
|
||||||
|
|
||||||
final ordner = <String>[
|
final ordner = <String>[
|
||||||
'/storage/emulated/0/Music',
|
'/storage/emulated/0/Music',
|
||||||
'/storage/emulated/0/Download',
|
'/storage/emulated/0/Download',
|
||||||
|
|||||||
Reference in New Issue
Block a user