Browse Source

Merge commit '452c8c3e71197894caf0d2673e34b296b4ee737a' into new_dev

newdev_shunjiawei
lxm 1 year ago
parent
commit
cd74c0a4fd
  1. 2
      lib/data/services/music_manager.dart
  2. 53
      lib/modules/agent/controllers/agent_controller.dart
  3. 2
      lib/modules/agent/views/music_card.dart
  4. 58
      lib/modules/meeting/controllers/meeting_connect_controller.dart
  5. 15
      lib/modules/music/views/music_playlist_view.dart
  6. 8
      local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentService.kt
  7. 46
      local_plugins/music_service/android/src/main/kotlin/com/yunqiinnovation/music_service/MusicService.kt
  8. 7
      local_plugins/music_service/lib/music_service.dart
  9. 1
      pubspec.yaml

2
lib/data/services/music_manager.dart

@ -105,7 +105,7 @@ class MusicManager extends GetxService {
required Function() onPrevious, required Function() onPrevious,
required Function(int) onSeekTo, required Function(int) onSeekTo,
required Function() onStop, required Function() onStop,
required Function(String, int, int, double) onStop1, required Function(int, int, int, double) onStop1,
}) async { }) async {
try { try {
await _musicService.setMediaSessionCallbacks( await _musicService.setMediaSessionCallbacks(

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

@ -5,7 +5,6 @@ import 'dart:io';
import 'package:amap_service/amap_service.dart'; import 'package:amap_service/amap_service.dart';
import 'package:deep_voice/core/utils/upload_oss.dart'; import 'package:deep_voice/core/utils/upload_oss.dart';
import 'package:deep_voice/data/models/user_Info.dart'; import 'package:deep_voice/data/models/user_Info.dart';
import 'package:deep_voice/data/services/location_manager.dart';
import 'package:deep_voice/data/services/music_manager.dart'; import 'package:deep_voice/data/services/music_manager.dart';
import 'package:deep_voice/data/services/navigation_manager.dart'; import 'package:deep_voice/data/services/navigation_manager.dart';
import 'package:deep_voice/data/services/network/api.dart'; import 'package:deep_voice/data/services/network/api.dart';
@ -126,11 +125,11 @@ class AgentController extends GetxController {
// 添加加载状态跟踪 // 添加加载状态跟踪
final RxBool isLoadingMusic = false.obs; final RxBool isLoadingMusic = false.obs;
final RxString loadingMusicId = ''.obs; final RxInt loadingMusicId = 0.obs;
// 设置加载状态的方法 // 设置加载状态的方法
void setLoadingMusic(String id, bool loading) { void setLoadingMusic(int id, bool loading) {
loadingMusicId.value = loading ? id : ''; loadingMusicId.value = loading ? id : 0;
isLoadingMusic.value = loading; isLoadingMusic.value = loading;
} }
@ -1333,7 +1332,7 @@ class AgentController extends GetxController {
try { try {
var status = await _musiceManager.getStatus(); var status = await _musiceManager.getStatus();
isPlaying.value = status['isPlaying'] ?? false; isPlaying.value = status['isPlaying'] ?? false;
currentId.value = status['id'] ?? 0; currentId.value = status['id'] as int;
Logger.d('AgentController', Logger.d('AgentController',
'音乐状态更新: playing=${isPlaying.value}, url=${currentId.value}'); '音乐状态更新: playing=${isPlaying.value}, url=${currentId.value}');
print("音乐状态更新: playing=${isPlaying.value}, url=${currentId.value}"); print("音乐状态更新: playing=${isPlaying.value}, url=${currentId.value}");
@ -1351,16 +1350,14 @@ class AgentController extends GetxController {
isPlaying.value = true; isPlaying.value = true;
// 修复:确保currentId接收int类型 // 修复:确保currentId接收int类型
final songId = song['id']; final songId = song['id'];
currentId.value = songId is int currentId.value = songId ?? 0;
? songId
: (int.tryParse(songId?.toString() ?? '0') ?? 0);
// 重置进度状态 // 重置进度状态
currentPosition.value = 0; currentPosition.value = 0;
duration.value = 0; duration.value = 0;
progress.value = 0.0; progress.value = 0.0;
final id = song['id'] ?? ""; final id = song['id'] ?? 0;
final timestampMs = song['ts'] ?? 0; final timestampMs = song['ts'] ?? 0;
// 检查URL是否需要刷新(只有当有时间戳时才检查) // 检查URL是否需要刷新(只有当有时间戳时才检查)
@ -1382,9 +1379,7 @@ class AgentController extends GetxController {
song["url"] = urldata['url'] ?? ''; song["url"] = urldata['url'] ?? '';
// 修复:确保currentId接收int类型 // 修复:确保currentId接收int类型
final newSongId = song['id']; final newSongId = song['id'];
currentId.value = newSongId is int currentId.value = newSongId ?? 0;
? newSongId
: (int.tryParse(newSongId?.toString() ?? '0') ?? 0);
Logger.d(TAG, '获取新URL成功'); Logger.d(TAG, '获取新URL成功');
} catch (e) { } catch (e) {
Logger.e(TAG, '获取新URL失败: $e'); Logger.e(TAG, '获取新URL失败: $e');
@ -1394,8 +1389,8 @@ class AgentController extends GetxController {
} }
// 转换为MusicManager期望的格式 // 转换为MusicManager期望的格式
final musicData = <String, String>{ final musicData = <String, dynamic>{
'id': song['id']?.toString() ?? '', 'id': song['id'],
'url': song['url']?.toString() ?? '', 'url': song['url']?.toString() ?? '',
'title': song['title']?.toString() ?? song['name']?.toString() ?? '', 'title': song['title']?.toString() ?? song['name']?.toString() ?? '',
'artist': 'artist':
@ -1521,10 +1516,10 @@ class AgentController extends GetxController {
} }
// 获取播放进度 // 获取播放进度
Future<void> updateMusicProgress1(String currentIdInternal, int newPosition, Future<void> updateMusicProgress1(int currentIdInternal, int newPosition,
int newDuration, double newProgress) async { int newDuration, double newProgress) async {
try { try {
if (int.parse(currentIdInternal) != 0) { if (currentIdInternal != 0) {
isPlaying.value = true; isPlaying.value = true;
// return; // 如果没有在播放,直接返回 // return; // 如果没有在播放,直接返回
} }
@ -1533,11 +1528,11 @@ class AgentController extends GetxController {
// final newPosition = progressInfo['currentPosition'] ?? 0; // final newPosition = progressInfo['currentPosition'] ?? 0;
// final newDuration = progressInfo['duration'] ?? 0; // final newDuration = progressInfo['duration'] ?? 0;
// final newProgress = progressInfo['progress'] ?? 0.0; // final newProgress = progressInfo['progress'] ?? 0.0;
print( // print(
"updateMusicProgress1:currentIdInternal:$currentIdInternal newPosition:$newPosition newDuration:$newDuration newProgress:$newProgress"); // "updateMusicProgress1:currentIdInternal:$currentIdInternal newPosition:$newPosition newDuration:$newDuration newProgress:$newProgress");
bool hasUpdate = false; bool hasUpdate = false;
if (currentId.value != int.parse(currentIdInternal)) { if (currentId.value != currentIdInternal) {
currentId.value = int.parse(currentIdInternal); currentId.value = currentIdInternal;
hasUpdate = true; hasUpdate = true;
} }
// 只有当值发生变化时才更新,避免不必要的UI刷新 // 只有当值发生变化时才更新,避免不必要的UI刷新
@ -1610,7 +1605,7 @@ class AgentController extends GetxController {
} }
// 跳转到指定位置 // 跳转到指定位置
Future<void> seekToPosition1(String currentIdInternal, int newPosition, Future<void> seekToPosition1(int currentIdInternal, int newPosition,
int newDuration, double newProgress) async { int newDuration, double newProgress) async {
try { try {
//await _musiceManager.seekTo(positionMs); //await _musiceManager.seekTo(positionMs);
@ -1676,7 +1671,7 @@ class AgentController extends GetxController {
// 设置加载状态 // 设置加载状态
isLoadingMusic.value = true; isLoadingMusic.value = true;
loadingMusicId.value = playlist[0]['id']?.toString() ?? ''; loadingMusicId.value = playlist[0]['id'];
// 重置播放状态 // 重置播放状态
isPlaying.value = true; isPlaying.value = true;
@ -1687,7 +1682,7 @@ class AgentController extends GetxController {
// 格式化歌曲列表数据 // 格式化歌曲列表数据
final formattedPlaylist = playlist.map((song) { final formattedPlaylist = playlist.map((song) {
return { return {
'id': song['id']?.toString() ?? '', 'id': song['id'],
'url': song['url']?.toString() ?? '', 'url': song['url']?.toString() ?? '',
'title': song['title']?.toString() ?? song['name']?.toString() ?? '', 'title': song['title']?.toString() ?? song['name']?.toString() ?? '',
'artist': 'artist':
@ -1702,7 +1697,7 @@ class AgentController extends GetxController {
// 更新当前播放歌曲ID // 更新当前播放歌曲ID
if (formattedPlaylist.isNotEmpty) { if (formattedPlaylist.isNotEmpty) {
currentId.value = int.tryParse(formattedPlaylist[0]['id'] ?? '0') ?? 0; currentId.value = formattedPlaylist[0]['id'] ?? 0;
} }
// 启动进度定时器 // 启动进度定时器
@ -1726,7 +1721,7 @@ class AgentController extends GetxController {
} finally { } finally {
// 清除加载状态 // 清除加载状态
isLoadingMusic.value = false; isLoadingMusic.value = false;
loadingMusicId.value = ''; loadingMusicId.value = 0;
} }
} }
@ -1778,7 +1773,7 @@ class AgentController extends GetxController {
// 查找当前歌曲在列表中的索引 // 查找当前歌曲在列表中的索引
int index = -1; int index = -1;
for (int i = 0; i < playlist.length; i++) { for (int i = 0; i < playlist.length; i++) {
if (int.tryParse(playlist[i]['id']?.toString() ?? '0') == songId) { if (playlist[i]['id'] == songId) {
index = i; index = i;
break; break;
} }
@ -1837,10 +1832,10 @@ class AgentController extends GetxController {
} }
/// 处理来自系统通知栏的跳转操作 /// 处理来自系统通知栏的跳转操作
Future<void> onMediaSessionSeekTo1(String currentIdInternal, int newPosition, Future<void> onMediaSessionSeekTo1(int currentIdInternal, int newPosition,
int newDuration, double newProgress) async { int newDuration, double newProgress) async {
print( // print(
"onMediaSessionSeekTo1 currentIdInternal :$currentIdInternal ,newPosition:$newPosition newDuration:$newDuration newProgress:$newProgress"); // "onMediaSessionSeekTo1 currentIdInternal :$currentIdInternal ,newPosition:$newPosition newDuration:$newDuration newProgress:$newProgress");
await seekToPosition1( await seekToPosition1(
currentIdInternal, newPosition, newDuration, newProgress); currentIdInternal, newPosition, newDuration, newProgress);
} }

2
lib/modules/agent/views/music_card.dart

@ -200,7 +200,7 @@ Widget buildMusicContent(
...playlist.asMap().entries.take(4).map((entry) { ...playlist.asMap().entries.take(4).map((entry) {
final index = entry.key; final index = entry.key;
final item = entry.value; final item = entry.value;
final id = item["id"] ?? 0; final id = item["id"];
final name = item["name"] ?? "未知歌曲"; final name = item["name"] ?? "未知歌曲";
final url = item["url"] ?? ""; final url = item["url"] ?? "";
final singer = item["sgener"] ?? "未知歌手"; final singer = item["sgener"] ?? "未知歌手";

58
lib/modules/meeting/controllers/meeting_connect_controller.dart

@ -2,6 +2,7 @@ import 'dart:async';
import 'package:flutter_blue_plus/flutter_blue_plus.dart'; import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:wifi_iot/wifi_iot.dart';
class MeetingConnectController extends GetxController { class MeetingConnectController extends GetxController {
RxString stateStr = '搜索中...'.obs; RxString stateStr = '搜索中...'.obs;
@ -20,6 +21,10 @@ class MeetingConnectController extends GetxController {
String _wifiSSID = ''; String _wifiSSID = '';
String _wifiPassword = ''; String _wifiPassword = '';
String _ftpAddress = '';
String _ftpPort = '';
String _ftpAccount = '';
String _ftpPassword = '';
@override @override
void onInit() { void onInit() {
@ -81,6 +86,7 @@ class MeetingConnectController extends GetxController {
} }
Future<void> _disconnect() async { Future<void> _disconnect() async {
await WiFiForIoTPlugin.disconnect();
await _device?.disconnect(); await _device?.disconnect();
} }
@ -139,27 +145,61 @@ class MeetingConnectController extends GetxController {
break; break;
case 0x87: // Wi-Fi 开启/关闭 case 0x87: // Wi-Fi 开启/关闭
if (value[3] == 0x01 && value[4] == 0x01) { if (value[3] == 0x01 && value[4] == 0x01) {
sendData([0x5a, 0x01, 0x0b]); _getWifi();
sendData([0x5a, 0x01, 0x0c]);
} }
break; break;
case 0x0b: // WiFi 热点 SSID case 0x0b: // WiFi 热点 SSID
_wifiSSID = String.fromCharCodes(value.sublist(3, value.length - 2)); _wifiSSID = String.fromCharCodes(value.sublist(3, value.length - 2));
if (_wifiSSID.isNotEmpty && _wifiPassword.isNotEmpty) { _connectWifi();
_connectWifi();
}
break; break;
case 0x0c: // WiFi 热点密码 case 0x0c: // WiFi 热点密码
_wifiPassword = _decodePassword(value); _wifiPassword = _decodePassword(value);
if (_wifiSSID.isNotEmpty && _wifiPassword.isNotEmpty) { _connectWifi();
_connectWifi(); break;
} case 0x03: // FTP 地址
_ftpAddress = String.fromCharCodes(value.sublist(3, value.length - 2));
sendData([0x5a, 0x01, 0x04]);
break;
case 0x04: // FTP 端口
_ftpPort = String.fromCharCodes(value.sublist(3, value.length - 2));
sendData([0x5a, 0x01, 0x05]);
break;
case 0x05: // FTP 账号
_ftpAccount = String.fromCharCodes(value.sublist(3, value.length - 2));
sendData([0x5a, 0x01, 0x06]);
break;
case 0x06: // FTP 密码
_ftpPassword = _decodePassword(value);
_connectFtp();
break; break;
default: default:
} }
} }
void _connectWifi() {} void _getWifi() async {
await sendData([0x5a, 0x01, 0x0b]);
await sendData([0x5a, 0x01, 0x0c]);
}
void _connectWifi() async {
if (_wifiSSID.isNotEmpty && _wifiPassword.isNotEmpty) {
stateStr.value = '正在连接 Wi-Fi...';
await WiFiForIoTPlugin.connect(
_wifiSSID,
password: _wifiPassword,
security: NetworkSecurity.WPA,
);
stateStr.value = 'Wi-Fi 连接成功';
sendData([0x5a, 0x01, 0x03]);
}
}
void _connectFtp() {
if (_ftpAddress.isNotEmpty &&
_ftpPort.isNotEmpty &&
_ftpAccount.isNotEmpty &&
_ftpPassword.isNotEmpty) {}
}
String _decodePassword(List<int> data) { String _decodePassword(List<int> data) {
final passwordData = data.sublist(3, data.length - 2); final passwordData = data.sublist(3, data.length - 2);

15
lib/modules/music/views/music_playlist_view.dart

@ -1,8 +1,6 @@
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter/services.dart';
import '../../../core/utils/logger.dart'; import '../../../core/utils/logger.dart';
import '../../agent/controllers/agent_controller.dart'; import '../../agent/controllers/agent_controller.dart';
import '../../agent/views/circular_progress_button.dart'; import '../../agent/views/circular_progress_button.dart';
@ -80,12 +78,11 @@ class MusicPlaylistView extends StatelessWidget {
if (controller.currentId.value != 0) { if (controller.currentId.value != 0) {
try { try {
currentSong = playlist.firstWhere( currentSong = playlist.firstWhere(
(song) => (song) => song['id'] == controller.currentId.value,
int.tryParse(song['id']?.toString() ?? '0') ==
controller.currentId.value,
); );
} catch (e) { } catch (e) {
// 如果没找到,使用第一首歌曲 // 如果没找到,使用第一首歌曲
currentSong = playlist.isNotEmpty ? playlist.first : null; currentSong = playlist.isNotEmpty ? playlist.first : null;
} }
} else { } else {
@ -192,7 +189,7 @@ class MusicPlaylistView extends StatelessWidget {
itemCount: playlist.length, itemCount: playlist.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final item = playlist[index]; final item = playlist[index];
final id = item["id"]?.toString() ?? ""; final id = item["id"] ?? 0;
final name = item["name"] ?? "未知歌曲"; final name = item["name"] ?? "未知歌曲";
final url = item["url"] ?? ""; final url = item["url"] ?? "";
final singer = item["singer"] ?? item["sgener"] ?? "未知歌手"; final singer = item["singer"] ?? item["sgener"] ?? "未知歌手";
@ -215,7 +212,7 @@ class MusicPlaylistView extends StatelessWidget {
Widget _buildMusicItem( Widget _buildMusicItem(
BuildContext context, BuildContext context,
AgentController controller, AgentController controller,
String id, int id,
String name, String name,
String url, String url,
String singer, String singer,
@ -323,7 +320,7 @@ class MusicPlaylistView extends StatelessWidget {
SizedBox(width: 14.w), SizedBox(width: 14.w),
// 播放按钮 // 播放按钮
Obx(() { Obx(() {
final currentIdInt = int.tryParse(id) ?? 0; final currentIdInt = id;
final isThisPlaying = controller.isPlaying.value && final isThisPlaying = controller.isPlaying.value &&
controller.currentId.value == currentIdInt; controller.currentId.value == currentIdInt;
final currentProgress = final currentProgress =
@ -601,7 +598,7 @@ class MusicPlaylistView extends StatelessWidget {
// 播放选中的歌曲 // 播放选中的歌曲
void _playSelectedSong(AgentController controller, Map<String, dynamic> song, void _playSelectedSong(AgentController controller, Map<String, dynamic> song,
List<Map<String, dynamic>> playlist) { List<Map<String, dynamic>> playlist) {
final songId = int.tryParse(song['id']?.toString() ?? '0') ?? 0; final songId = song['id'] ?? 0;
controller.updateCurrentPlaylistContext(playlist, songId); controller.updateCurrentPlaylistContext(playlist, songId);
controller.musicPlay(song); controller.musicPlay(song);
} }

8
local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentService.kt

@ -1447,12 +1447,12 @@ object AgentService : CoroutineScope {
// Log.d(TAG, "mcp调用结果: $metaStr") // Log.d(TAG, "mcp调用结果: $metaStr")
if (meta.has("card_music")) { //音乐卡片 if (meta.has("card_music")) { //音乐卡片
val cardMusic = meta.getJSONObject("card_music") val cardMusic = meta.getJSONObject("card_music")
val id = cardMusic.optInt("id", 0) val id = cardMusic.optLong("id", 0)
val url = cardMusic.optString("url", "") val url = cardMusic.optString("url", "")
val name = cardMusic.optString("name", "") val name = cardMusic.optString("name", "")
val sgener = cardMusic.optString("sgener", "") val sgener = cardMusic.optString("sgener", "")
val image = cardMusic.optString("image", "") val image = cardMusic.optString("image", "")
val ts = cardMusic.optInt("ts", 0) val ts = cardMusic.optLong("ts", 0)
processMusicPlay( processMusicPlay(
mapOf( mapOf(
"id" to id, "id" to id,
@ -1470,12 +1470,12 @@ object AgentService : CoroutineScope {
val playlist = mutableListOf<Map<String, Any>>() val playlist = mutableListOf<Map<String, Any>>()
for (i in 0 until musics.length()) { for (i in 0 until musics.length()) {
val item = musics.optJSONObject(i) ?: continue val item = musics.optJSONObject(i) ?: continue
val id = item.optInt("id", 0) val id = item.optLong("id", 0)
val url = item.optString("url", "") val url = item.optString("url", "")
val name = item.optString("name", "") val name = item.optString("name", "")
val sgener = item.optString("sgener", "") val sgener = item.optString("sgener", "")
val image = item.optString("image", "") val image = item.optString("image", "")
val ts = item.optInt("ts", 0) val ts = item.optLong("ts", 0)
playlist.add( playlist.add(
mapOf( mapOf(
"id" to id, "id" to id,

46
local_plugins/music_service/android/src/main/kotlin/com/yunqiinnovation/music_service/MusicService.kt

@ -38,7 +38,7 @@ class MusicService : MediaBrowserServiceCompat() {
private const val DELETE_ACTION = "com.yunqiinnovation.music_service.DELETE_NOTIFICATION" private const val DELETE_ACTION = "com.yunqiinnovation.music_service.DELETE_NOTIFICATION"
private val isRunning = AtomicBoolean(false) private val isRunning = AtomicBoolean(false)
private var currentIdInternal: String? = null private var currentIdInternal: Long? = null
private var currentStatus = false private var currentStatus = false
private var playlist = mutableListOf<Map<String,Any>>() private var playlist = mutableListOf<Map<String,Any>>()
private var currentIndex = 0 private var currentIndex = 0
@ -48,7 +48,7 @@ class MusicService : MediaBrowserServiceCompat() {
fun isServiceRunning() = isRunning.get() fun isServiceRunning() = isRunning.get()
fun isPlaying() = currentStatus fun isPlaying() = currentStatus
fun getCurrentId(): String? = currentIdInternal fun getCurrentId(): Long? = currentIdInternal
// // 获取播放进度信息 // // 获取播放进度信息
// fun getProgress(): Map<String, Any> { // fun getProgress(): Map<String, Any> {
@ -118,11 +118,11 @@ class MusicService : MediaBrowserServiceCompat() {
fun updateMediaSessionMetadata(song: Map<String, Any>) { fun updateMediaSessionMetadata(song: Map<String, Any>) {
instance?.let { service -> instance?.let { service ->
try { try {
val title = song["title"] as? String ?: song["name"] as? String ?: "未知标题" val title = song["title"] as? String ??: "未知标题"
val artist = song["artist"] as? String ?: song["sgener"] as? String ?: "未知歌手" val artist = song["artist"] as? String ??: "未知歌手"
val coverUrl = song["coverUrl"] as? String ?: song["image"] as? String ?: "" val coverUrl = song["coverUrl"] as? String ??: ""
currentIdInternal = song["id"] as? String ?: song["id"] as? String ?: "0" currentIdInternal = (song["id"] as? Number)?.toLong() ?: 0L
Log.i(TAG, "updateMediaSessionMetadata currentIdInternal: $currentIdInternal") Log.i(TAG, "updateMediaSessionMetadata currentIdInternal: $currentIdInternal")
val metadata = android.support.v4.media.MediaMetadataCompat.Builder() val metadata = android.support.v4.media.MediaMetadataCompat.Builder()
.putString(android.support.v4.media.MediaMetadataCompat.METADATA_KEY_TITLE, title) .putString(android.support.v4.media.MediaMetadataCompat.METADATA_KEY_TITLE, title)
.putString(android.support.v4.media.MediaMetadataCompat.METADATA_KEY_ARTIST, artist) .putString(android.support.v4.media.MediaMetadataCompat.METADATA_KEY_ARTIST, artist)
@ -216,13 +216,12 @@ private fun updateProgress() {
// 更新媒体会话进度 // 更新媒体会话进度
// 通知Flutter层 // 通知Flutter层
flutterChannel?.invokeMethod("onMediaSessionSeekTo1", flutterChannel?.invokeMethod("onMediaSessionSeekTo1", mapOf(
mapOf(
"currentIdInternal" to currentIdInternal, "currentIdInternal" to currentIdInternal,
"currentPosition" to currentPosition, "currentPosition" to currentPosition,
"duration" to duration, "duration" to duration,
"progress" to progress "progress" to progress
)) ))
} }
} }
} }
@ -238,19 +237,20 @@ private fun updateProgress() {
when (command) { when (command) {
"play" -> intent.getSerializableExtra("song")?.let { url -> "play" -> intent.getSerializableExtra("song")?.let { url ->
val songMap = intent.getSerializableExtra("song") as? Map<String, Any> val songMap = intent.getSerializableExtra("song") as? Map<String, Any>
Log.i(TAG, "MusicePlay onStartCommand: $songMap")
songMap?.let { song -> songMap?.let { song ->
val songId = song["id"]as? String ?:"0" val songId = (song["id"] as? Number)?.toLong() ?: 0L
Log.i(TAG, "command songId: $songId")
currentIdInternal = songId currentIdInternal = songId
val existingIndex = playlist.indexOfFirst { it["id"] == songId } val existingIndex = playlist.indexOfFirst { it["id"] == songId}
if (existingIndex == -1) { if (existingIndex == -1) {
playlist.add(song) playlist.add(song)
currentIndex = playlist.size - 1 currentIndex = playlist.size - 1
} else { } else {
currentIndex = existingIndex currentIndex = existingIndex
} }
Log.i(TAG, "MusicePlay songId: $songId currentIndex:$currentIndex" )
play(song) play(song)
} }
} }
@ -546,8 +546,8 @@ private fun updateProgress() {
private fun play(song: Map<String,Any>) { private fun play(song: Map<String,Any>) {
val url = song["url"] as? String ?: return val url = song["url"] as? String ?: return
Log.i(TAG, "开始播放: $url") Log.i(TAG, "开始播放: $url")
val id = song["id"] as? String ?: "0" val id = (song["id"] as? Number)?.toLong() ?: 0L
Log.i(TAG, "开始播放play id: $id") Log.i(TAG, "开始播放play id: $id")
val title = song["title"] as? String ?: "未知标题" val title = song["title"] as? String ?: "未知标题"
val artist = song["artist"] as? String ?: "未知歌手" val artist = song["artist"] as? String ?: "未知歌手"
val coverUrl = song["coverUrl"] as String val coverUrl = song["coverUrl"] as String
@ -586,8 +586,8 @@ private fun updateProgress() {
val title = song["title"] as? String ?: "未知标题" val title = song["title"] as? String ?: "未知标题"
val artist = song["artist"] as? String ?: "未知歌手" val artist = song["artist"] as? String ?: "未知歌手"
val coverUrl = song["coverUrl"] as String val coverUrl = song["coverUrl"] as String
val id = song["id"] as? String ?: "0" val id =(song["id"] as? Number)?.toLong() ?: 0L
Log.i(TAG, "pause id: $id") Log.i(TAG, "pause id: $id")
currentIdInternal = id currentIdInternal = id
updateNotification(title,artist,coverUrl) updateNotification(title,artist,coverUrl)
setPlaybackState(PlaybackStateCompat.STATE_PAUSED); setPlaybackState(PlaybackStateCompat.STATE_PAUSED);
@ -607,8 +607,8 @@ private fun updateProgress() {
val title = song["title"] as? String ?: "未知标题" val title = song["title"] as? String ?: "未知标题"
val artist = song["artist"] as? String ?: "未知歌手" val artist = song["artist"] as? String ?: "未知歌手"
val coverUrl = song["coverUrl"] as String val coverUrl = song["coverUrl"] as String
val id = song["id"] as? String ?: "0" val id = (song["id"] as? Number)?.toLong() ?: 0L
Log.i(TAG, "resume id: $id") Log.i(TAG, "resume id: $id")
currentIdInternal = id currentIdInternal = id
updateNotification(title,artist,coverUrl) updateNotification(title,artist,coverUrl)
setPlaybackState(PlaybackStateCompat.STATE_PLAYING); setPlaybackState(PlaybackStateCompat.STATE_PLAYING);

7
local_plugins/music_service/lib/music_service.dart

@ -1,3 +1,5 @@
import 'dart:ffi';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
class MusicService { class MusicService {
@ -101,7 +103,7 @@ class MusicService {
required Function() onPrevious, required Function() onPrevious,
required Function(int) onSeekTo, required Function(int) onSeekTo,
required Function() onStop, required Function() onStop,
required Function(String, int, int, double) onStop1, required Function(int, int, int, double) onStop1,
}) async { }) async {
// 设置方法调用处理器来处理来自原生平台的回调 // 设置方法调用处理器来处理来自原生平台的回调
_methodChannel.setMethodCallHandler((call) async { _methodChannel.setMethodCallHandler((call) async {
@ -126,8 +128,7 @@ class MusicService {
onStop(); onStop();
break; break;
case 'onMediaSessionSeekTo1': case 'onMediaSessionSeekTo1':
final currentIdInternal = final currentIdInternal = call.arguments['currentIdInternal'] as int;
call.arguments['currentIdInternal'] as String;
final currentPosition = call.arguments['currentPosition'] as int; final currentPosition = call.arguments['currentPosition'] as int;
final duration = call.arguments['duration'] as int; final duration = call.arguments['duration'] as int;
final progress = call.arguments['progress'] as double; final progress = call.arguments['progress'] as double;

1
pubspec.yaml

@ -27,6 +27,7 @@ dependencies:
git: git:
url: https://github.com/AppFlowy-IO/appflowy-editor.git url: https://github.com/AppFlowy-IO/appflowy-editor.git
ref: main ref: main
wifi_iot: ^0.3.19+2
permission_handler: ^10.4.5 permission_handler: ^10.4.5
web_socket_channel: ^2.4.0 web_socket_channel: ^2.4.0
flutter_dotenv: ^5.1.0 flutter_dotenv: ^5.1.0

Loading…
Cancel
Save