diff --git a/android/app/src/main/res/drawable/launch_background.xml b/android/app/src/main/res/drawable/launch_background.xml
index 304732f..af2b35b 100644
--- a/android/app/src/main/res/drawable/launch_background.xml
+++ b/android/app/src/main/res/drawable/launch_background.xml
@@ -1,12 +1,12 @@
-
-
+
+
-
-
+ -
-
-->
-
+ android:src="@drawable/ic_launcher_foreground" />
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/values/colors.xml b/android/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..4046b37
--- /dev/null
+++ b/android/app/src/main/res/values/colors.xml
@@ -0,0 +1,4 @@
+
+
+ #0E1211
+
\ No newline at end of file
diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml
index cb1ef88..fd3209e 100644
--- a/android/app/src/main/res/values/styles.xml
+++ b/android/app/src/main/res/values/styles.xml
@@ -1,18 +1,13 @@
-
+
-
+
-
+
\ No newline at end of file
diff --git a/lib/main.dart b/lib/main.dart
index 30b1cbe..be86c4c 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -3,6 +3,8 @@ import 'package:provider/provider.dart';
import 'package:media_kit/media_kit.dart';
import 'services/audio_service.dart';
import 'services/playback_service.dart';
+import 'services/app_lifecycle_service.dart';
+import 'services/webdav_service.dart';
import 'pages/home_page.dart';
import 'pages/player_page.dart';
import 'pages/playlist_page.dart';
@@ -13,34 +15,54 @@ final GlobalKey navigatorKey = GlobalKey();
void main() {
WidgetsFlutterBinding.ensureInitialized();
- bool initSuccess = false;
- String? initError;
-
- try {
- MediaKit.ensureInitialized();
- PlaybackService().init();
- initSuccess = true;
- } catch (e, stack) {
- initError = '初始化失败: $e';
- debugPrint('❌ $initError');
- debugPrint(stack.toString());
- }
-
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => AudioService()),
+ ChangeNotifierProvider(create: (_) => AppLifecycleService()),
],
- child: QTPlayerApp(
- initSuccess: initSuccess,
- initError: initError,
- ),
+ child: const QTPlayerApp(),
),
);
+
+ // ⭐ 首帧渲染完成后才执行初始化
+ WidgetsBinding.instance.addPostFrameCallback((_) {
+ _initializeServices();
+ });
+}
+
+void _initializeServices() async {
+ final lifecycle = AppLifecycleService();
+
+ try {
+ // 1. MediaKit
+ lifecycle.updateStatus(AppStatus.mediaKitInitializing);
+ MediaKit.ensureInitialized();
+ lifecycle.updateStatus(AppStatus.mediaKitReady);
+
+ // 2. PlaybackService
+ lifecycle.updateStatus(AppStatus.playerInitializing);
+ PlaybackService().init();
+ lifecycle.updateStatus(AppStatus.playerReady);
+
+ // 3. WebDAV
+ lifecycle.updateStatus(AppStatus.webdavChecking);
+ final hasCred = await WebDAVService.instance.loadCredentials();
+ if (hasCred) {
+ lifecycle.updateStatus(AppStatus.webdavReady);
+ } else {
+ lifecycle.updateStatus(AppStatus.webdavMissing);
+ }
+
+ lifecycle.updateStatus(AppStatus.fullReady);
+ } catch (e) {
+ debugPrint('❌ 初始化错误: $e');
+ lifecycle.updateStatus(AppStatus.error);
+ }
}
// ═══════════════════════════════════════════════════
-// RouteManager - 路由状态管理
+// RouteManager
// ═══════════════════════════════════════════════════
class RouteManager extends ChangeNotifier {
static final RouteManager _instance = RouteManager._internal();
@@ -64,7 +86,7 @@ class RouteManager extends ChangeNotifier {
}
// ═══════════════════════════════════════════════════
-// 导航观察者 - 监听路由变化
+// 导航观察者
// ═══════════════════════════════════════════════════
class MiniPlayerNavigatorObserver extends NavigatorObserver {
void _updateRoute(Route? route) {
@@ -79,7 +101,6 @@ class MiniPlayerNavigatorObserver extends NavigatorObserver {
@override
void didPop(Route route, Route? previousRoute) {
- // ⭐ 关键:用 previousRoute 而不是 navigatorKey.currentContext
_updateRoute(previousRoute);
}
@@ -90,47 +111,14 @@ class MiniPlayerNavigatorObserver extends NavigatorObserver {
}
// ═══════════════════════════════════════════════════
-// 主应用
+// QTPlayerApp - 无状态,只负责组装
// ═══════════════════════════════════════════════════
class QTPlayerApp extends StatelessWidget {
- final bool initSuccess;
- final String? initError;
-
- const QTPlayerApp({
- super.key,
- required this.initSuccess,
- required this.initError,
- });
+ const QTPlayerApp({super.key});
@override
Widget build(BuildContext context) {
- if (!initSuccess) {
- return MaterialApp(
- home: Scaffold(
- backgroundColor: const Color(0xFF0E1211),
- body: Center(
- child: Column(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- Icon(Icons.error_outline, size: 64, color: Colors.red[300]),
- const SizedBox(height: 16),
- const Text(
- '应用初始化失败',
- style: TextStyle(color: Colors.white, fontSize: 20),
- ),
- const SizedBox(height: 8),
- Text(
- initError ?? '未知错误',
- style: TextStyle(color: Colors.grey[400], fontSize: 14),
- textAlign: TextAlign.center,
- ),
- ],
- ),
- ),
- ),
- );
- }
-
+ debugPrint('🔥 QTPlayerApp.build() 执行,首帧即将渲染');
return MaterialApp(
title: '清听',
theme: ThemeData(
@@ -151,15 +139,11 @@ class QTPlayerApp extends StatelessWidget {
'/player': (context) => const PlayerPage(),
'/playlist': (context) => const PlaylistPage(),
},
- // ⭐ 核心改动:删除手写 Overlay,直接用 Stack
builder: (context, child) {
return Stack(
fit: StackFit.expand,
children: [
- // 1. Navigator(所有路由页面)
if (child != null) child,
-
- // 2. MiniPlayer(由路由状态控制显隐)
AnimatedBuilder(
animation: RouteManager(),
builder: (context, _) {
diff --git a/lib/services/app_lifecycle_service.dart b/lib/services/app_lifecycle_service.dart
new file mode 100644
index 0000000..4ecd333
--- /dev/null
+++ b/lib/services/app_lifecycle_service.dart
@@ -0,0 +1,43 @@
+import 'package:flutter/material.dart';
+
+/// App 生命周期状态
+enum AppStatus {
+ starting, // 启动中
+ mediaKitInitializing, // MediaKit 初始化中
+ mediaKitReady, // MediaKit 就绪
+ playerInitializing, // 播放器初始化中
+ playerReady, // 播放器就绪
+ webdavChecking, // WebDAV 检测中
+ webdavReady, // WebDAV 就绪
+ webdavMissing, // WebDAV 未配置
+ fullReady, // 完全就绪
+ error, // 错误
+}
+
+class AppLifecycleService extends ChangeNotifier {
+ AppStatus _status = AppStatus.starting;
+
+ AppStatus get status => _status;
+
+ bool get isPlayerReady =>
+ _status == AppStatus.playerReady || _status == AppStatus.fullReady;
+
+ bool get isWebDAVReady =>
+ _status == AppStatus.webdavReady || _status == AppStatus.fullReady;
+
+ bool get isFullReady => _status == AppStatus.fullReady;
+
+ void updateStatus(AppStatus newStatus) {
+ if (_status != newStatus) {
+ _status = newStatus;
+ debugPrint('🔄 App 状态更新: $newStatus');
+ notifyListeners();
+ }
+ }
+
+ // 重置(用于错误恢复)
+ void reset() {
+ _status = AppStatus.starting;
+ notifyListeners();
+ }
+}