Files
QingTing-Player/lib/main.dart
T

181 lines
6.1 KiB
Dart

import 'package:flutter/material.dart';
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';
import 'widgets/global_mini_player.dart';
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
// ═══════════════════════════════════════════════════
// main: 只做 runApp,不做任何初始化
// ═══════════════════════════════════════════════════
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => AudioService()),
ChangeNotifierProvider(create: (_) => AppLifecycleService()),
],
child: const QTPlayerApp(),
),
);
}
// ═══════════════════════════════════════════════════
// RouteManager - 路由状态
// ═══════════════════════════════════════════════════
class RouteManager extends ChangeNotifier {
static final RouteManager _instance = RouteManager._internal();
factory RouteManager() => _instance;
RouteManager._internal();
String _currentRoute = '/';
String get currentRoute => _currentRoute;
bool get showMiniPlayer =>
_currentRoute != '/player' && _currentRoute != '/playlist';
void updateRoute(String route) {
if (_currentRoute != route) {
_currentRoute = route;
debugPrint('📌 路由更新: $route');
notifyListeners();
}
}
}
// ═══════════════════════════════════════════════════
// MiniPlayerNavigatorObserver - 路由监听
// ═══════════════════════════════════════════════════
class MiniPlayerNavigatorObserver extends NavigatorObserver {
void _updateRoute(Route? route) {
final name = route?.settings.name ?? '/';
RouteManager().updateRoute(name);
}
@override
void didPush(Route route, Route? previousRoute) {
_updateRoute(route);
}
@override
void didPop(Route route, Route? previousRoute) {
_updateRoute(previousRoute);
}
@override
void didReplace({Route? newRoute, Route? oldRoute}) {
_updateRoute(newRoute);
}
}
// ═══════════════════════════════════════════════════
// QTPlayerApp - 主应用
// ═══════════════════════════════════════════════════
class QTPlayerApp extends StatefulWidget {
const QTPlayerApp({super.key});
@override
State<QTPlayerApp> createState() => _QTPlayerAppState();
}
class _QTPlayerAppState extends State<QTPlayerApp> {
@override
void initState() {
super.initState();
// 首帧完成后才开始初始化
WidgetsBinding.instance.addPostFrameCallback((_) {
debugPrint('🖼️ Flutter 首帧已完成');
_initializeServices();
});
}
@override
Widget build(BuildContext context) {
debugPrint('🎨 QTPlayerApp.build()');
return MaterialApp(
title: '清听',
theme: ThemeData(
brightness: Brightness.dark,
primaryColor: const Color(0xFF7C9A9E),
colorScheme: const ColorScheme.dark(
primary: Color(0xFF7C9A9E),
secondary: Color(0xFFB8D4D0),
surface: Color(0xFF1A1F1E),
onSurface: Colors.white,
),
useMaterial3: true,
),
navigatorKey: navigatorKey,
navigatorObservers: [MiniPlayerNavigatorObserver()],
routes: {
'/': (context) => const HomePage(),
'/player': (context) => const PlayerPage(),
'/playlist': (context) => const PlaylistPage(),
},
builder: (context, child) {
return Stack(
fit: StackFit.expand,
children: [
if (child != null) child,
AnimatedBuilder(
animation: RouteManager(),
builder: (context, _) {
if (!RouteManager().showMiniPlayer) {
return const SizedBox.shrink();
}
return const Align(
alignment: Alignment.bottomCenter,
child: GlobalMiniPlayer(),
);
},
),
],
);
},
);
}
}
// ═══════════════════════════════════════════════════
// 后台初始化 - 在首帧完成后执行
// ═══════════════════════════════════════════════════
void _initializeServices() async {
final lifecycle = AppLifecycleService();
try {
lifecycle.updateStatus(AppStatus.mediaKitInitializing);
MediaKit.ensureInitialized();
lifecycle.updateStatus(AppStatus.mediaKitReady);
lifecycle.updateStatus(AppStatus.playerInitializing);
PlaybackService().init();
lifecycle.updateStatus(AppStatus.playerReady);
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);
debugPrint('✅ 应用完全就绪');
} catch (e) {
debugPrint('❌ 初始化错误: $e');
lifecycle.updateStatus(AppStatus.error);
}
}