正在进行初始化减负处理

This commit is contained in:
2026-08-19 23:56:31 +08:00
parent 81990385f4
commit 90f4b4e7ae
5 changed files with 102 additions and 76 deletions
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/white" />
<!-- 纯色背景 -->
<item android:drawable="@color/primary_dark" />
<!-- You can insert your own image assets here -->
<!-- <item>
<!-- 居中 Logo -->
<item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>
android:src="@drawable/ic_launcher_foreground" />
</item>
</layer-list>
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="primary_dark">#0E1211</color>
</resources>
+4 -9
View File
@@ -1,18 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<!-- 启动页主题(无标题栏 + 自定义背景) -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
<item name="android:windowFullscreen">true</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<!-- 正常应用主题 -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>
</resources>
+44 -60
View File
@@ -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<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
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, _) {
+43
View File
@@ -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();
}
}