Browse Source

上传补充导航选择界面

weicu
liwei1dao 1 year ago
parent
commit
d8f2a5a097
  1. 418
      lib/modules/agent/controllers/agent_controller.dart
  2. 1
      lib/modules/agent/views/navigation_card.dart
  3. 16
      local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentService.kt
  4. 2
      local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/MusicSystemFunctionHandler.kt
  5. 2
      local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/QQMusicSystemFunctionHandler.kt

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

@ -827,7 +827,7 @@ class AgentController extends GetxController with WidgetsBindingObserver {
// Logger.i(TAG, 'liwei-------- 打开导航页面: $start $end ');
// 2秒后执行的代码
openNavigation(start, destination, end_latitude,
openNavigation(false, start, destination, end_latitude,
end_longitude, "");
});
}
@ -1865,18 +1865,234 @@ class AgentController extends GetxController with WidgetsBindingObserver {
}
//去导航
void openNavigation(String start, String destination, String endlatitude,
String endlongitude, String mode) {
void openNavigation(bool isshow, String start, String destination,
String endlatitude, String endlongitude, String mode) {
print('liwei 导航:$destination $endlatitude $endlongitude $mode');
if (isshow) {
// 弹出导航选择面板
_showNavigationSelectionDialog(
start, destination, endlatitude, endlongitude, mode);
} else {
// 使用默认配置直接导航
_navigateWithDefaultMode(
start, destination, endlatitude, endlongitude, mode);
}
}
// 显示导航选择底部面板
void _showNavigationSelectionDialog(String start, String destination,
String endlatitude, String endlongitude, String mode) {
Get.bottomSheet(
Container(
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20),
),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// 顶部指示条
Container(
margin: const EdgeInsets.only(top: 12),
width: 40,
height: 4,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(2),
),
),
// 标题
const Padding(
padding: EdgeInsets.all(20),
child: Text(
'选择导航软件',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
),
// 导航选项列表
ListTile(
leading: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.blue.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
),
child: const Icon(Icons.map, color: Colors.blue),
),
title: const Text('高德地图'),
subtitle: const Text('使用高德地图导航'),
onTap: () {
Get.back();
openGaodeMap(destination, endlatitude, endlongitude, mode);
},
),
ListTile(
leading: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.green.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
),
child: const Icon(Icons.map, color: Colors.green),
),
title: const Text('百度地图'),
subtitle: const Text('使用百度地图导航'),
onTap: () {
Get.back();
openBaiduMap(destination, endlatitude, endlongitude, mode);
},
),
ListTile(
leading: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.red.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
),
child: const Icon(Icons.map, color: Colors.red),
),
title: const Text('谷歌地图'),
subtitle: const Text('使用谷歌地图导航'),
onTap: () {
Get.back();
openGoogleMap(destination, mode);
},
),
// 苹果导航 - 仅在 iOS 平台显示
if (Platform.isIOS)
ListTile(
leading: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.grey.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
),
child: const Icon(Icons.navigation, color: Colors.grey),
),
title: const Text('苹果地图'),
subtitle: const Text('使用苹果地图导航'),
onTap: () {
Get.back();
openAppleMap(destination, mode);
},
),
// 底部安全区域
SizedBox(height: MediaQuery.of(Get.context!).padding.bottom + 20),
],
),
),
isScrollControlled: true,
isDismissible: true, // 点击外部区域可关闭
enableDrag: true, // 支持拖拽关闭
);
}
// 使用默认配置导航
void _navigateWithDefaultMode(String start, String destination,
String endlatitude, String endlongitude, String mode) {
final navigationMode =
AppConfig.env('APP_NAVIGATION_MODE') ?? 'external_auto';
if (navigationMode == 'internal_gaode') {
_navigationManager.open(start, "$endlongitude,$endlatitude", mode);
} else if (navigationMode == 'external_baidu') {
openBaiduMap(destination, mode);
openBaiduMap(destination, endlatitude, endlongitude, mode);
} else if (navigationMode == 'external_gaode') {
openGaodeMap(destination, endlatitude, destination, mode);
openGaodeMap(destination, endlatitude, endlongitude, mode);
} else if (navigationMode == 'external_google') {
openGoogleMap(destination, mode);
} else {
// 自动选择导航应用,优先级:百度 > 高德 > 谷歌
_autoSelectNavigation(
start, destination, endlatitude, endlongitude, mode);
}
}
// 自动选择导航应用
Future<void> _autoSelectNavigation(String start, String destination,
String endlatitude, String endlongitude, String mode) async {
try {
// 1. 优先尝试百度地图
final baiduUri = Uri(
scheme: 'baidumap',
host: 'map',
path: 'direction',
queryParameters: {
'destination': destination,
'coord_type': 'gcj02',
'mode': mode == 'driving' ? 'driving' : 'transit',
'src': 'deepvoice',
},
);
if (await canLaunchUrl(baiduUri)) {
print('自动选择:使用百度地图');
openBaiduMap(destination, endlatitude, endlongitude, mode);
return;
}
// 2. 其次尝试高德地图
final gaodeUri = Uri(
scheme: 'amapuri',
host: 'navi',
queryParameters: {
'to': destination,
'mode': mode.isNotEmpty ? mode : 'driving',
'callnative': '1',
},
);
if (await canLaunchUrl(gaodeUri)) {
print('自动选择:使用高德地图');
openGaodeMap(destination, endlatitude, endlongitude, mode);
return;
}
// 3. 然后尝试谷歌地图
final googleUri = Uri(
scheme: 'comgooglemaps',
queryParameters: {
'daddr': destination,
'directionsmode': mode == 'driving' ? 'driving' : 'transit',
},
);
if (await canLaunchUrl(googleUri)) {
print('自动选择:使用谷歌地图');
openGoogleMap(destination, mode);
return;
}
// 4. 在 iOS 平台尝试苹果地图
if (Platform.isIOS) {
final appleUri = Uri(
scheme: 'maps',
queryParameters: {
'daddr': destination,
'dirflg': mode == 'driving' ? 'd' : 'r',
},
);
if (await canLaunchUrl(appleUri)) {
print('自动选择:使用苹果地图');
openAppleMap(destination, mode);
return;
}
}
// 5. 如果都没有安装,提示用户
print('未找到可用的导航应用');
final availableApps =
Platform.isIOS ? '百度地图、高德地图、谷歌地图或苹果地图' : '百度地图、高德地图或谷歌地图';
Get.snackbar('提示', '未找到可用的导航应用,请安装$availableApps');
} catch (e) {
print('自动选择导航失败: $e');
Get.snackbar('错误', '启动导航失败');
}
}
@ -2187,7 +2403,7 @@ class AgentController extends GetxController with WidgetsBindingObserver {
}
/// 打开Google地图进行导航
Future<void> openGoogleMap(String daddr, String mode) async {
Future<bool> openGoogleMap(String daddr, String mode) async {
try {
// 方案1: 尝试使用Google Maps应用的URL scheme
// final Uri googleMapsUri = Uri.parse(url);
@ -2197,26 +2413,28 @@ class AgentController extends GetxController with WidgetsBindingObserver {
'comgooglemaps://?saddr=CurrentLocation&daddr=$daddr&directionsmode=$mode');
if (await canLaunchUrl(appUri)) {
await launchUrl(appUri, mode: LaunchMode.externalApplication);
return;
return true;
} else {
final Uri webUrl = Uri.parse(
"https://www.google.com/maps/dir/?api=1&origin=Current+Location&destination=$daddr&travelmode=$mode");
if (await canLaunchUrl(webUrl)) {
await launchUrl(webUrl);
return true;
}
return false;
}
} catch (e) {
print('打开地图失败: $e');
Get.snackbar('错误', '打开地图时发生错误');
return false;
}
}
/// 打开高德地图进行导航
Future<void> openGaodeMap(
Future<bool> openGaodeMap(
String destination,
String lat,
String lon,
String mode,
String mode, // 'driving', 'transit', 'walking', 'cycling'
) async {
try {
// 获取应用包名
@ -2224,92 +2442,174 @@ class AgentController extends GetxController with WidgetsBindingObserver {
// 构建src参数(带平台前缀)
final String src = Platform.isAndroid
? "android.${packageInfo.packageName}"
? packageInfo.packageName
: "ios.${packageInfo.packageName}";
// 构建高德地图导航链接
final Uri uri = Uri(
// 导航模式映射
String gaodeMode;
switch (mode) {
case 'transit':
gaodeMode = '1'; // 公交
break;
case 'walking':
gaodeMode = '2'; // 步行
break;
case 'cycling':
gaodeMode = '3'; // 骑行
break;
case 'driving':
default:
gaodeMode = '0'; // 驾车
break;
}
// 根据平台选择不同的 scheme 和参数
final Uri uri;
if (Platform.isAndroid) {
uri = Uri(
scheme: 'androidamap',
host: 'navi',
host: 'route',
path: 'plan',
queryParameters: {
'poiname': destination, // 目的地地址
'lat': lat,
'lon': lon,
'mode': mode.isNotEmpty ? mode : 'driving', // 导航模式,默认驾车
'sourceApplication': src, // 来源标识
'callnative': '1', // 优先调用原生应用
'dlat': lat,
'dlon': lon,
'dname': destination,
'dev': '0', // 0: gcj02
't': gaodeMode,
'sourceApplication': src,
},
);
} else {
// iOS
uri = Uri(
scheme: 'amapuri',
host: 'route',
path: 'plan',
queryParameters: {
'dlat': lat,
'dlon': lon,
'dname': destination,
'dev': '0', // 0: gcj02
't': gaodeMode,
'sourceApplication': src,
},
);
}
print('高德导航链接: ${uri.toString()}');
// final Uri testMapsUri = Uri.parse(
// 'androidamap://navi?sourceApplication=android.com.saitong.voitrans&lat=22.615274&lon=114.035576&poiname=深圳北站&dev=0&mode=driving');
// // 尝试打开高德地图应用
if (await canLaunchUrl(uri)) {
final bool launched = await launchUrl(
uri,
mode: LaunchMode.externalApplication,
);
if (!launched) {
print('高德地图已安装,但启动失败');
Get.snackbar('提示', '高德地图启动失败');
}
return launched;
} else {
print('高德地图未安装');
Get.snackbar('提示', '请先安装高德地图应用');
return false;
}
} catch (e) {
print('打开地图失败: $e');
print('打开高德地图失败: $e');
Get.snackbar('错误', '打开地图时发生错误');
return false;
}
}
/// 打开Baidu地图进行导航
Future<void> openBaiduMap(
Future<bool> openBaiduMap(
String destination,
String mode,
String lat,
String lon,
String mode, // 'driving', 'transit', 'walking', 'riding'
) async {
try {
// 地址和城市(已编码的字符串也可以直接使用)
// String destination = "深圳北站";
// String city = "深圳";
// 获取应用包名
final packageInfo = await PackageInfo.fromPlatform();
final String src =
'${Platform.isAndroid ? '' : 'ios.'}${packageInfo.packageName}';
// 百度地图导航模式映射
String baiduMode;
switch (mode) {
case 'transit':
baiduMode = 'transit'; // 公交
break;
case 'walking':
baiduMode = 'walking'; // 步行
break;
case 'cycling':
baiduMode = 'riding'; // 骑行
break;
case 'driving':
default:
baiduMode = 'driving'; // 驾车
break;
}
// 构建正确的导航链接
final Uri appUri = Uri(
final Uri uri = Uri(
scheme: 'baidumap',
host: 'map',
path: 'direction', // 使用direction端点而非navi
path: 'direction',
queryParameters: {
'destination': destination,
// 'city': '深圳',
'mode': mode, // 明确导航模式
'src': 'com.saitong.voitrans', // 带平台前缀的src参数
'destination': 'name:$destination|latlng:$lat,$lon',
'coord_type': 'gcj02',
'mode': baiduMode,
'src': src,
},
);
print('生成的链接: ${appUri.toString()}');
print('百度导航链接: ${uri.toString()}');
if (await canLaunchUrl(appUri)) {
await launchUrl(appUri, mode: LaunchMode.externalApplication);
if (await canLaunchUrl(uri)) {
final bool launched = await launchUrl(
uri,
mode: LaunchMode.externalApplication,
);
return launched;
} else {
print('无法打开百度地图,请检查是否已安装');
}
// final packageInfo = await PackageInfo.fromPlatform();
// String packageName = packageInfo.packageName;
// // 方案1: 尝试使用Google Maps应用的URL scheme
// // final Uri googleMapsUri = Uri.parse(url);
// // 简化版链接(仅包含必要参数)
// final Uri testUri = Uri.parse(
// 'baidumap://map/navi?location=$end_latitude,$end_longitude&coord_type=bd09ll&src$packageName');
// if (await canLaunchUrl(testUri)) {
// await launchUrl(testUri, mode: LaunchMode.externalApplication);
// } else {
// print('打开地图失败');
// }
print('百度地图未安装');
Get.snackbar('提示', '请先安装百度地图应用');
return false;
}
} catch (e) {
print('打开地图失败: $e');
print('打开百度地图失败: $e');
Get.snackbar('错误', '打开地图时发生错误');
return false;
}
}
/// 打开苹果地图进行导航
Future<void> openAppleMap(String destination, String mode) async {
try {
// 构建苹果地图导航链接
final Uri uri = Uri(
scheme: 'maps',
queryParameters: {
'daddr': destination, // 目的地地址
'dirflg': mode == 'driving' ? 'd' : 'r', // d=驾车, r=公交
},
);
print('苹果地图导航链接: ${uri.toString()}');
// 尝试打开苹果地图应用
if (await canLaunchUrl(uri)) {
final bool launched = await launchUrl(
uri,
mode: LaunchMode.externalApplication,
);
if (!launched) {
print('苹果地图启动失败');
Get.snackbar('提示', '苹果地图启动失败');
}
} else {
print('苹果地图不可用');
Get.snackbar('提示', '苹果地图不可用');
}
} catch (e) {
print('打开苹果地图失败: $e');
Get.snackbar('错误', '打开苹果地图时发生错误');
}
}
}

1
lib/modules/agent/views/navigation_card.dart

@ -416,6 +416,7 @@ Widget navigationCard(
borderRadius: BorderRadius.circular(12.r),
onTap: () {
controller.openNavigation(
true,
start,
destination,
endlatitude,

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

@ -894,7 +894,7 @@ object AgentService : CoroutineScope {
var userMetadata = JSONObject()
var reply = true; //是否回复
var broadcast = true //是否播发
var nocard = false;
var iscard = false;
// 如果有图片,添加图片信息到元数据
if (hasImage) {
@ -1084,8 +1084,8 @@ object AgentService : CoroutineScope {
aiMetadata = resultmap["meta"] as String;
broadcast = resultmap["broadcast"] as Boolean;
reply = !(resultmap["notreply"] as Boolean);
nocard = resultmap["nocard"] as Boolean;
if (!nocard){
iscard = resultmap["iscard"] as Boolean;
if (iscard){
sendEvent(
"function_call_result", mapOf(
"function_call" to functionCall.toString(),
@ -1869,7 +1869,7 @@ object AgentService : CoroutineScope {
val metadata: MutableMap<String, Any> = mutableMapOf()
var broadcast = true;
var notreply = false;
var nocard = false;
var iscard = false;
if (textStr.isNotEmpty()) {
val meta = JSONObject(textStr)
if (meta.has("broadcast")) {
@ -1878,8 +1878,8 @@ object AgentService : CoroutineScope {
if (meta.has("notreply")) {
notreply = meta["notreply"] as Boolean
}
if (meta.has("nocard")) {
nocard = meta["nocard"] as Boolean
if (meta.has("iscard")) {
iscard = meta["iscard"] as Boolean
}
metadata[toolname] = meta // 现在可以赋值
@ -1970,13 +1970,13 @@ object AgentService : CoroutineScope {
val end = cardNavigation.optString("end", "")
processNavigation(start, end);
}
return mapOf("meta" to metaStr, "broadcast" to broadcast, "notreply" to notreply,"nocard" to nocard);
return mapOf("meta" to metaStr, "broadcast" to broadcast, "notreply" to notreply,"iscard" to iscard);
}
} catch (e: Exception) {
// 捕获其他类型的异常(可选)
println("为解析到卡片数据!")
}
return mapOf("meta" to "", "broadcast" to true, "notreply" to false,"nocard" to false);
return mapOf("meta" to "", "broadcast" to true, "notreply" to false,"iscard" to false);
}
/**

2
local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/MusicSystemFunctionHandler.kt

@ -147,7 +147,7 @@ private class MusicSearchHandler(private val context: Context?) : FunctionHandle
// val ts = songMap["ts"] ?: 0
"{\"id\": $id, \"name\": \"$name\", \"singer\": \"$singer\",\"image\": \"$image\"}"
}
"{\"success\": true, \"broadcast\": false, \"message\": \"搜索成功,正在播放\", \"data\": [$songsJson]}"
"{\"success\": true, \"iscard\": true, \"broadcast\": false, \"message\": \"搜索成功,正在播放\", \"data\": [$songsJson]}"
} else {
val error = searchResult.exceptionOrNull()
"{\"success\": false, \"message\": \"搜索失败: ${error?.message}\"}"

2
local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/QQMusicSystemFunctionHandler.kt

@ -148,7 +148,7 @@ private class QQMusicSearchHandler(private val context: Context?) : FunctionHand
val duration = songMap["duration"] ?: 0
"{\"mid\": \"$mid\", \"name\": \"$name\", \"artist\": \"$artist\", \"album\": \"$album\", \"duration\":$duration,\"pic\": \"$pic\"}"
}
"{\"success\": true, \"broadcast\": false, \"message\": \"搜索成功,正在播放\", \"data\": [$songsJson]}"
"{\"success\": true,\"iscard\": true, \"broadcast\": false, \"message\": \"搜索成功,正在播放\", \"data\": [$songsJson]}"
} else {
val error = searchResult.exceptionOrNull()
"{\"success\": false, \"message\": \"搜索失败: ${error?.message}\"}"

Loading…
Cancel
Save