Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1aba004e43 | ||
|
|
cdf77b308d | ||
|
|
200067a3b2 |
@@ -7,6 +7,7 @@
|
|||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
|
||||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||||
|
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+25
@@ -8,6 +8,8 @@ import io.flutter.embedding.android.FlutterActivity
|
|||||||
import io.flutter.embedding.engine.FlutterEngine
|
import io.flutter.embedding.engine.FlutterEngine
|
||||||
import io.flutter.plugin.common.MethodChannel
|
import io.flutter.plugin.common.MethodChannel
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import android.content.Context
|
||||||
|
import android.media.AudioManager
|
||||||
|
|
||||||
class MainActivity : FlutterActivity() {
|
class MainActivity : FlutterActivity() {
|
||||||
|
|
||||||
@@ -32,9 +34,32 @@ class MainActivity : FlutterActivity() {
|
|||||||
|
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
requestAudioFocus()
|
||||||
|
|
||||||
setHighRefreshRate()
|
setHighRefreshRate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun requestAudioFocus() {
|
||||||
|
val audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
audioManager.requestAudioFocus(
|
||||||
|
AudioManager.OnAudioFocusChangeListener { focusChange ->
|
||||||
|
Log.d("MainActivity", "音频焦点变化: $focusChange")
|
||||||
|
},
|
||||||
|
AudioManager.STREAM_MUSIC,
|
||||||
|
AudioManager.AUDIOFOCUS_GAIN
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
audioManager.requestAudioFocus(
|
||||||
|
null,
|
||||||
|
AudioManager.STREAM_MUSIC,
|
||||||
|
AudioManager.AUDIOFOCUS_GAIN
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Log.d("MainActivity", "✅ 已请求音频焦点")
|
||||||
|
}
|
||||||
|
|
||||||
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
|
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
|
||||||
super.configureFlutterEngine(flutterEngine)
|
super.configureFlutterEngine(flutterEngine)
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ pluginManagement {
|
|||||||
plugins {
|
plugins {
|
||||||
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
|
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
|
||||||
id("com.android.application") version "9.0.1" apply false
|
id("com.android.application") version "9.0.1" apply false
|
||||||
id("org.jetbrains.kotlin.android") version "2.2.20" apply false
|
id("org.jetbrains.kotlin.android") version "2.3.20" apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
include(":app")
|
include(":app")
|
||||||
|
|||||||
+67
-57
@@ -5,6 +5,7 @@ import 'package:media_kit/media_kit.dart';
|
|||||||
import 'package:audio_service/audio_service.dart' as audio_service;
|
import 'package:audio_service/audio_service.dart' as audio_service;
|
||||||
import 'package:permission_handler/permission_handler.dart';
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'services/audio_service.dart';
|
import 'services/audio_service.dart';
|
||||||
import 'services/playback_service.dart';
|
import 'services/playback_service.dart';
|
||||||
import 'services/app_lifecycle_service.dart';
|
import 'services/app_lifecycle_service.dart';
|
||||||
@@ -15,8 +16,8 @@ import 'pages/home_page.dart';
|
|||||||
import 'pages/player_page.dart';
|
import 'pages/player_page.dart';
|
||||||
import 'pages/playlist_page.dart';
|
import 'pages/playlist_page.dart';
|
||||||
import 'widgets/global_mini_player.dart';
|
import 'widgets/global_mini_player.dart';
|
||||||
|
import 'utils/navigation.dart';
|
||||||
|
|
||||||
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
|
|
||||||
final stopwatch = Stopwatch();
|
final stopwatch = Stopwatch();
|
||||||
|
|
||||||
bool _appInitialized = false;
|
bool _appInitialized = false;
|
||||||
@@ -363,65 +364,74 @@ class _QTPlayerAppState extends State<QTPlayerApp> {
|
|||||||
debugPrint(
|
debugPrint(
|
||||||
'🎨 [QTPlayerApp] build #$_buildCount ${stopwatch.elapsedMilliseconds}ms');
|
'🎨 [QTPlayerApp] build #$_buildCount ${stopwatch.elapsedMilliseconds}ms');
|
||||||
|
|
||||||
return MaterialApp(
|
// ⭐ 使用 AnnotatedRegion 包裹 MaterialApp,统一控制系统栏样式
|
||||||
title: '清听',
|
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||||
theme: ThemeData(
|
value: SystemUiOverlayStyle(
|
||||||
brightness: Brightness.dark,
|
statusBarColor: Colors.transparent,
|
||||||
primaryColor: const Color(0xFF7C9A9E),
|
statusBarIconBrightness: Brightness.light,
|
||||||
colorScheme: const ColorScheme.dark(
|
systemNavigationBarColor: const Color(0xFF1A1F1E),
|
||||||
primary: Color(0xFF7C9A9E),
|
systemNavigationBarIconBrightness: Brightness.light,
|
||||||
secondary: Color(0xFFB8D4D0),
|
|
||||||
surface: Color(0xFF1A1F1E),
|
|
||||||
onSurface: Colors.white,
|
|
||||||
),
|
|
||||||
useMaterial3: true,
|
|
||||||
),
|
),
|
||||||
navigatorKey: navigatorKey,
|
child: MaterialApp(
|
||||||
navigatorObservers: [MiniPlayerNavigatorObserver()],
|
title: '清听',
|
||||||
onGenerateRoute: _onGenerateRoute,
|
theme: ThemeData(
|
||||||
builder: (context, child) {
|
brightness: Brightness.dark,
|
||||||
return Stack(
|
primaryColor: const Color(0xFF7C9A9E),
|
||||||
fit: StackFit.expand,
|
colorScheme: const ColorScheme.dark(
|
||||||
children: [
|
primary: Color(0xFF7C9A9E),
|
||||||
if (child != null) child,
|
secondary: Color(0xFFB8D4D0),
|
||||||
AnimatedBuilder(
|
surface: Color(0xFF1A1F1E),
|
||||||
animation: RouteManager(),
|
onSurface: Colors.white,
|
||||||
builder: (context, _) {
|
),
|
||||||
final routeManager = RouteManager();
|
useMaterial3: true,
|
||||||
final shouldShow = routeManager.currentRoute != '/player' &&
|
),
|
||||||
routeManager.currentRoute != '/playlist';
|
navigatorKey: navigatorKey,
|
||||||
|
navigatorObservers: [MiniPlayerNavigatorObserver()],
|
||||||
|
onGenerateRoute: _onGenerateRoute,
|
||||||
|
builder: (context, child) {
|
||||||
|
return Stack(
|
||||||
|
fit: StackFit.expand,
|
||||||
|
children: [
|
||||||
|
if (child != null) child,
|
||||||
|
AnimatedBuilder(
|
||||||
|
animation: RouteManager(),
|
||||||
|
builder: (context, _) {
|
||||||
|
final routeManager = RouteManager();
|
||||||
|
final shouldShow = routeManager.currentRoute != '/player' &&
|
||||||
|
routeManager.currentRoute != '/playlist';
|
||||||
|
|
||||||
return AnimatedSwitcher(
|
return AnimatedSwitcher(
|
||||||
duration: const Duration(milliseconds: 300),
|
duration: const Duration(milliseconds: 300),
|
||||||
switchInCurve: Curves.easeOut,
|
switchInCurve: Curves.easeOut,
|
||||||
switchOutCurve: Curves.easeIn,
|
switchOutCurve: Curves.easeIn,
|
||||||
transitionBuilder: (child, animation) {
|
transitionBuilder: (child, animation) {
|
||||||
return FadeTransition(
|
return FadeTransition(
|
||||||
opacity: animation,
|
opacity: animation,
|
||||||
child: SlideTransition(
|
child: SlideTransition(
|
||||||
position: Tween<Offset>(
|
position: Tween<Offset>(
|
||||||
begin: const Offset(0, 0.1),
|
begin: const Offset(0, 0.1),
|
||||||
end: Offset.zero,
|
end: Offset.zero,
|
||||||
).animate(animation),
|
).animate(animation),
|
||||||
child: child,
|
child: child,
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
child: shouldShow
|
|
||||||
? const Align(
|
|
||||||
key: ValueKey('mini_player_visible'),
|
|
||||||
alignment: Alignment.bottomCenter,
|
|
||||||
child: GlobalMiniPlayer(),
|
|
||||||
)
|
|
||||||
: const SizedBox.shrink(
|
|
||||||
key: ValueKey('mini_player_hidden'),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
child: shouldShow
|
||||||
],
|
? const Align(
|
||||||
);
|
key: ValueKey('mini_player_visible'),
|
||||||
},
|
alignment: Alignment.bottomCenter,
|
||||||
|
child: GlobalMiniPlayer(),
|
||||||
|
)
|
||||||
|
: const SizedBox.shrink(
|
||||||
|
key: ValueKey('mini_player_hidden'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import '../services/audio_service.dart';
|
import '../services/audio_service.dart';
|
||||||
|
import '../utils/navigation.dart'; // ⭐ 导入 navigatorKey
|
||||||
|
|
||||||
class GlobalMiniPlayer extends StatelessWidget {
|
class GlobalMiniPlayer extends StatelessWidget {
|
||||||
const GlobalMiniPlayer({super.key});
|
const GlobalMiniPlayer({super.key});
|
||||||
@@ -45,11 +46,9 @@ class GlobalMiniPlayer extends StatelessWidget {
|
|||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
// ⭐ 使用 Navigator.of(context) 替代 navigatorKey
|
// ⭐ 使用 navigatorKey 直接跳转
|
||||||
Navigator.of(context, rootNavigator: true)
|
navigatorKey.currentState?.pushNamed('/player');
|
||||||
.pushNamed('/player');
|
|
||||||
},
|
},
|
||||||
// ⭐ 替换弃用的 withOpacity 为 withValues
|
|
||||||
highlightColor: Colors.white.withValues(alpha: 0.05),
|
highlightColor: Colors.white.withValues(alpha: 0.05),
|
||||||
splashColor: Colors.white.withValues(alpha: 0.1),
|
splashColor: Colors.white.withValues(alpha: 0.1),
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
@@ -124,8 +123,8 @@ class GlobalMiniPlayer extends StatelessWidget {
|
|||||||
size: 24,
|
size: 24,
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
// ⭐ 使用 Navigator.of(context)
|
// ⭐ 使用 navigatorKey 直接跳转
|
||||||
Navigator.of(context).pushNamed('/playlist');
|
navigatorKey.currentState?.pushNamed('/playlist');
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ dependencies:
|
|||||||
sdk: flutter
|
sdk: flutter
|
||||||
media_kit: 1.2.6
|
media_kit: 1.2.6
|
||||||
media_kit_libs_audio: ^1.0.7
|
media_kit_libs_audio: ^1.0.7
|
||||||
#media_kit_libs_android_audio: 1.3.8
|
|
||||||
shared_preferences: 2.2.2
|
shared_preferences: 2.2.2
|
||||||
provider: ^6.1.2
|
provider: ^6.1.2
|
||||||
dio: ^5.4.0 # HTTP 客户端
|
dio: ^5.4.0 # HTTP 客户端
|
||||||
|
|||||||
Reference in New Issue
Block a user