Browse Source

Merge branch 'new_dev' of https://github.com/deepcloud2048/deep_voice into new_dev

newdev_shunjiawei
fdp 1 year ago
parent
commit
41fa8b8334
  1. 3
      lib/core/bindings/initial_binding.dart
  2. 9
      lib/core/translations/app_translations.dart
  3. 84
      lib/core/utils/app_lifecycle_manager.dart
  4. 10
      lib/data/services/qq_music.dart
  5. 24
      lib/modules/agent/controllers/agent_controller.dart
  6. 64
      local_plugins/qq_music/ios/qq_music/Sources/qq_music/QPlayAutoManager.swift

3
lib/core/bindings/initial_binding.dart

@ -21,12 +21,15 @@ import '../../data/services/ble_manager.dart';
import '../../data/services/account_service.dart';
import '../../data/services/version_update_service.dart';
import '../../data/services/ota_check_service.dart';
import '../../core/utils/app_lifecycle_manager.dart';
/// 初始绑定,用于管理全局依赖
class InitialBinding extends Bindings {
@override
void dependencies() {
Logger.warning('InitialBinding dependencies');
// 应用生命周期管理器
Get.put<AppLifecycleManager>(AppLifecycleManager(), permanent: true);
// 语言管理器(需要最先初始化)
Get.lazyPut<LanguageManager>(() => LanguageManager(), fenix: true);

9
lib/core/translations/app_translations.dart

@ -88,6 +88,7 @@ class AppTranslations extends Translations {
// 默认使用简体中文
return fallbackLocale;
}
static final supportedLocales = [
const Locale('zh', 'CN'), // 简体中文
const Locale('zh', 'HK'), // 香港繁体中文
@ -165,6 +166,14 @@ class AppTranslations extends Translations {
final GetStorage storage = GetStorage();
String? language = storage.read('language');
// print('lxm---系统语言发生变化: --------------------------');
// print('lxm---Get.deviceLocale: ${Get.deviceLocale}');
// print('lxm---Get.locale: ${Get.locale}');
// print('lxm---语言代码: ${Get.deviceLocale?.languageCode}');
// print('lxm---国家代码: ${Get.deviceLocale?.countryCode}');
// print('lxm---脚本代码: ${Get.deviceLocale?.scriptCode}');
// 如果用户手动设置了语言且不是跟随系统
if (language != null && language != 'system') {
List languageList = language.split('_');

84
lib/core/utils/app_lifecycle_manager.dart

@ -1,23 +1,28 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import 'logger.dart';
import '../translations/app_translations.dart';
//import '../../modules/settings/controllers/settings_controller.dart';
/// 应用生命周期管理器
///
/// 监控应用的前台/后台状态变化,并在状态变化时执行相应操作
class AppLifecycleManager extends GetxService with WidgetsBindingObserver {
// 当前应用生命周期状态
final Rx<AppLifecycleState> _appLifecycleState = AppLifecycleState.resumed.obs;
final Rx<AppLifecycleState> _appLifecycleState =
AppLifecycleState.resumed.obs;
AppLifecycleState get appLifecycleState => _appLifecycleState.value;
// 状态变化流
final _lifecycleStateStream = AppLifecycleState.resumed.obs;
Stream<AppLifecycleState> get lifecycleStateStream => _lifecycleStateStream.stream;
Stream<AppLifecycleState> get lifecycleStateStream =>
_lifecycleStateStream.stream;
// 是否在前台
final RxBool _isInForeground = true.obs;
bool get isInForeground => _isInForeground.value;
@override
void onInit() {
super.onInit();
@ -25,15 +30,15 @@ class AppLifecycleManager extends GetxService with WidgetsBindingObserver {
WidgetsBinding.instance.addObserver(this);
Logger.info('AppLifecycleManager 已初始化');
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
final previousState = _appLifecycleState.value;
_appLifecycleState.value = state;
_lifecycleStateStream.value = state;
// Logger.info('应用生命周期状态变化: $previousState -> $state');
// 根据状态变化更新前台/后台标志
switch (state) {
case AppLifecycleState.resumed:
@ -50,12 +55,12 @@ class AppLifecycleManager extends GetxService with WidgetsBindingObserver {
break;
}
}
/// 处理应用进入前台
void _handleAppResumed() {
// Logger.info('应用进入前台');
// 这里不需要主动恢复服务,因为我们希望用户手动控制录音开始
// 如果正在录音,停止录音
// 如果正在录音,停止录音
// if (asrService.isRecording) {
// Logger.info('应用进入后台,停止语音识别');
@ -64,11 +69,11 @@ class AppLifecycleManager extends GetxService with WidgetsBindingObserver {
// ttsService.disconnect();
// }
}
/// 处理应用进入后台
void _handleAppPaused(AppLifecycleState state) {
// Logger.info('应用进入后台: $state');
// 获取 VolcanoAsrApiService 实例
// 如果正在录音,停止录音
@ -80,7 +85,7 @@ class AppLifecycleManager extends GetxService with WidgetsBindingObserver {
// }
}
@override
void onClose() {
// 移除应用生命周期观察者
@ -88,4 +93,55 @@ class AppLifecycleManager extends GetxService with WidgetsBindingObserver {
// Logger.info('AppLifecycleManager 已关闭');
super.onClose();
}
}
/// 处理系统语言变化
@override
void didChangeLocales(List<Locale>? locales) {
super.didChangeLocales(locales);
// print('lxm---系统语言发生变化: ${locales?.first}');
// print('lxm---Get.deviceLocale: ${Get.deviceLocale}');
// print('lxm---Get.locale: ${Get.locale}');
// print(
// 'lxm---AppTranslations.deviceLocale(): ${AppTranslations.deviceLocale()}');
// print('lxm---语言代码: ${locales?.first.languageCode}');
// print('lxm---国家代码: ${locales?.first.countryCode}');
// print('lxm---脚本代码: ${locales?.first.scriptCode}');
Logger.info('系统语言发生变化: ${locales?.first}');
// 检查用户是否手动设置了语言
final storage = GetStorage();
String? userLanguage = storage.read('language');
if (userLanguage != null && userLanguage != 'system') {
// 用户手动设置了语言,保持用户选择,不跟随系统
Logger.info('用户已手动设置语言为: $userLanguage,忽略系统语言变化');
// 强制恢复用户设置的语言
List languageList = userLanguage.split('_');
Locale userLocale = Locale(languageList[0], languageList[1]);
// 延迟执行,确保系统语言变化处理完成
Future.delayed(const Duration(milliseconds: 100), () {
Get.updateLocale(userLocale);
Logger.info('已恢复用户设置的语言: ${userLocale.toString()}');
});
} else {
// 用户选择跟随系统,更新应用语言
Logger.info('用户选择跟随系统语言,更新应用语言');
Locale? newLocale = AppTranslations.deviceLocale();
if (newLocale != null) {
Get.updateLocale(newLocale);
// 同步更新设置控制器中的语言状态
try {
//final settingsController = Get.find<SettingsController>();
// 这里可能需要根据新的locale更新settingsController的language状态
} catch (e) {
Logger.warning('未找到SettingsController实例: $e');
}
}
}
}
}

10
lib/data/services/qq_music.dart

@ -37,7 +37,7 @@ class QqMusicService extends GetxService {
if (result['success'] == true) {
print('QQ音乐自动登录成功: ${result['openId']}');
Future.delayed(Duration(milliseconds: 1000), () {
syncCurrentPlayInfo(isFrest: true);
syncCurrentPlayInfo();
});
} else {
print('QQ音乐自动登录失败: ${result['error']}');
@ -422,7 +422,7 @@ class QqMusicService extends GetxService {
/// 同步当前播放信息 - 统一接口
Future<Map<String, dynamic>> syncCurrentPlayInfo(
{bool isFrest = false}) async {
{bool isOpenPlay = false}) async {
try {
_stateMonitorTimer?.cancel(); //先关闭计时器
final result = await _qqMusic.syncCurrentPlayInfo();
@ -473,6 +473,12 @@ class QqMusicService extends GetxService {
} else {
stopPlaybackStateMonitor();
currentSong.value = null;
if (isOpenPlay) {
Future.delayed(Duration(seconds: 2), () {
syncCurrentPlayInfo();
});
}
}
// 通知所有监听器
_notifyListeners();

24
lib/modules/agent/controllers/agent_controller.dart

@ -780,16 +780,20 @@ class AgentController extends GetxController {
);
}
}
if (metaResult.containsKey("qqmusic_searchandplay_songs")) {
final qqmusic_search_songs =
metaResult['qqmusic_searchandplay_songs']
as Map<String, dynamic>;
final data = qqmusic_search_songs['data'];
if (data != null && data is List) {
Future.delayed(Duration(seconds: 1), () {
_qqmusicManager.syncCurrentPlayInfo();
});
}
final musicKey = metaResult.keys.firstWhere(
(key) => key.contains("music"),
orElse: () => "",
);
if (musicKey.isNotEmpty) {
// final qqmusic_search_songs =
// metaResult['qqmusic_searchandplay_songs']
// as Map<String, dynamic>;
// final data = qqmusic_search_songs['data'];
// if (data != null && data is List) {
Future.delayed(Duration(seconds: 2), () {
_qqmusicManager.syncCurrentPlayInfo(isOpenPlay: true);
});
// }
} else if (metaResult.containsKey("maps_route_navigation")) {
//导航
final start = metaResult["maps_route_navigation"]

64
local_plugins/qq_music/ios/qq_music/Sources/qq_music/QPlayAutoManager.swift

@ -492,8 +492,13 @@ import QPlayAutoSDK
print("QPlayAutoManager: 播放歌曲失败 - 登录失败")
}
}
private var pendingPlayCompletion: ((Bool, String?) -> Void)?
private var playVerificationTimer: Timer?
@objc public func playSongs(mids: [String], index: Int = 0, completion: @escaping (Bool, String?) -> Void) {
playSongsWithRetry(mids: mids, index: index, retryCount: 0, maxRetries: 3, completion: completion)
}
private func playSongsWithRetry(mids: [String], index: Int, retryCount: Int, maxRetries: Int, completion: @escaping (Bool, String?) -> Void) {
guard !mids.isEmpty else {
completion(false, "歌曲列表为空")
return
@ -504,16 +509,47 @@ import QPlayAutoSDK
return
}
// 修改:使用 ensureQQMusicInstalledAndLoginAndExecute 替代 ensureLoginAndExecute
ensureQQMusicInstalledAndLoginAndExecute {
QPlayAutoSDK.playSongMid(atIndex: mids, play: index) { errorCode in
if errorCode == 0 {
completion(true, nil)
print("QQ音乐播放列表启动成功,共\(mids.count)首歌曲")
// 不立即返回成功,而是等待播放状态确认
self.pendingPlayCompletion = completion
// 设置超时检查
self.playVerificationTimer = Timer.scheduledTimer(withTimeInterval: 2.0, repeats: false) { _ in
if let pendingCompletion = self.pendingPlayCompletion {
self.pendingPlayCompletion = nil
// 检查当前播放状态
let currentState = self.currentPlayState
if currentState == .playing {
pendingCompletion(true, nil)
print("QQ音乐播放列表验证成功,共\(mids.count)首歌曲")
} else {
// 播放验证失败,尝试重试
if retryCount < maxRetries {
print("QQ音乐播放验证失败,第\(retryCount + 1)次重试...")
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
self.playSongsWithRetry(mids: mids, index: index, retryCount: retryCount + 1, maxRetries: maxRetries, completion: completion)
}
} else {
pendingCompletion(false, "播放验证超时,已重试\(maxRetries)次,当前状态: \(currentState.rawValue)")
}
}
}
}
} else {
let errorMessage = "QQ音乐播放列表启动失败,错误码: \(errorCode)"
completion(false, errorMessage)
print(errorMessage)
// SDK调用失败,尝试重试
if retryCount < maxRetries {
let errorMessage = "QQ音乐播放列表启动失败,错误码: \(errorCode),第\(retryCount + 1)次重试..."
print(errorMessage)
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
self.playSongsWithRetry(mids: mids, index: index, retryCount: retryCount + 1, maxRetries: maxRetries, completion: completion)
}
} else {
let errorMessage = "QQ音乐播放列表启动失败,已重试\(maxRetries)次,错误码: \(errorCode)"
completion(false, errorMessage)
print(errorMessage)
}
}
}
} onQQMusicNotInstalled: {
@ -522,7 +558,6 @@ import QPlayAutoSDK
completion(false, "登录失败,无法播放歌曲列表")
}
}
@objc public func next() {
ensureQQMusicInstalledAndLoginAndExecute {
QPlayAutoSDK.playerPlayNext { errorCode in
@ -803,6 +838,19 @@ extension QPlayAutoManager: QPlayAutoSDKDelegate {
for weakDelegate in delegates {
weakDelegate.delegate?.onPlayStateChanged?(playState, song: song, position: position)
}
// 检查是否有待验证的播放请求
if let pendingCompletion = pendingPlayCompletion {
if playState == .playing {
pendingPlayCompletion = nil
playVerificationTimer?.invalidate()
pendingCompletion(true, nil)
print("QQ音乐播放状态确认:真正开始播放")
} else {
pendingPlayCompletion = nil
playVerificationTimer?.invalidate()
pendingCompletion(false, "播放失败,歌曲可能不可用")
}
}
}
public func onQPlayAutoPlayProgressChanged(_ song: QPlayAutoListItem, progress: TimeInterval, duration: TimeInterval) {

Loading…
Cancel
Save