import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import '../controllers/agent_controller.dart'; String formatDistance(String distanceStr) { final distance = double.tryParse(distanceStr); if (distance == null) return distanceStr; // 如果无法解析,则返回原始字符串 if (distance >= 1000) { final km = distance / 1000; return '${km.toStringAsFixed(1)} KM'; } else { return '${distance.toStringAsFixed(0)} M'; } } String formatDuration(String secondsStr) { int totalSeconds = int.tryParse(secondsStr) ?? 0; Duration duration = Duration(seconds: totalSeconds); int hours = duration.inHours; int minutes = duration.inMinutes.remainder(60); int seconds = duration.inSeconds.remainder(60); List parts = []; if (hours > 0) parts.add('$hours${'hours'.tr}'); // 小时 if (minutes > 0) parts.add('$minutes${'minutes'.tr}'); // 分钟 //不需要秒 //if (seconds > 0 || parts.isEmpty) parts.add('$seconds${'seconds'.tr}'); // 秒 return parts.join(''); } /// 导航卡片组件 /// /// 各元素含义分析: /// - [start]: 起点坐标 (经纬度格式) /// - [end]: 终点坐标 (经纬度格式) /// - [destination]: 目的地名称显示 /// - [modes]: 导航方式列表,包含驾车、步行、公交等选项 /// - [navigation]: 当前导航状态信息(可选) /// - [height]: 卡片高度 Widget navigationCard( BuildContext context, { required String start, required String end, required String endlatitude, required String endlongitude, required String destination, required List> modes, Map? navigation, double? height, // 改为可选参数,允许自适应高度 }) { int currentIndex = 0; final controller = Get.find(); final isDarkMode = Theme.of(context).brightness == Brightness.dark; return Container( height: height?.h ?? 350.h, // 如果没有指定高度,使用350作为默认高度 decoration: BoxDecoration( borderRadius: BorderRadius.circular(16.r), color: isDarkMode ? const Color(0xFF1E1E1E) : Colors.white, boxShadow: [ BoxShadow( blurRadius: 12, color: Colors.black.withValues(alpha: isDarkMode ? 0.4 : 0.08), offset: const Offset(0, 2), ), ], ), child: StatefulBuilder( builder: (context, setInnerState) { return Column( children: [ // 顶部:路线预览图片区域 Expanded( flex: 4, // 增加图片区域的flex值,让图片占更多空间 child: ClipRRect( borderRadius: BorderRadius.vertical(top: Radius.circular(16.r)), child: Stack( children: [ // 路线图片 AnimatedSwitcher( duration: const Duration(milliseconds: 300), child: Image.network( modes[currentIndex]["image"] as String, key: ValueKey( modes[currentIndex]["ntype"] as String), height: double.infinity, width: double.infinity, fit: BoxFit.cover, errorBuilder: (context, error, stackTrace) { return Container( color: isDarkMode ? Colors.grey[800] : Colors.grey[200], child: Icon( Icons.map_outlined, size: 48.sp, color: isDarkMode ? Colors.grey[600] : Colors.grey[400], ), ); }, ), ), // 导航状态覆盖层 if (navigation != null) Positioned( top: 12.h, left: 12.w, child: Container( padding: EdgeInsets.symmetric( horizontal: 8.w, vertical: 4.h), decoration: BoxDecoration( color: Theme.of(context).primaryColor.withOpacity(0.9), borderRadius: BorderRadius.circular(12.r), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon( Icons.navigation, color: Colors.white, size: 14.sp, ), SizedBox(width: 4.w), Text( 'navigating'.tr, // 导航中 style: TextStyle( color: Colors.white, fontSize: 12.sp, fontWeight: FontWeight.w500, ), ), ], ), ), ), ], ), ), ), // 中部:导航方式选择器 Container( padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 16.w), child: Row( children: List.generate(modes.length, (index) { final mode = modes[index]; final isSelected = index == currentIndex; final isEnabled = mode['enable'] as bool; return Expanded( child: GestureDetector( onTap: isEnabled ? () { setInnerState(() => currentIndex = index); } : null, child: Container( margin: EdgeInsets.symmetric(horizontal: 4.w), padding: EdgeInsets.symmetric( vertical: 8.h, horizontal: 12.w), decoration: BoxDecoration( color: isSelected ? Theme.of(context).primaryColor.withOpacity(0.1) : Colors.transparent, borderRadius: BorderRadius.circular(8.r), border: Border.all( color: isSelected ? Theme.of(context).primaryColor : (isDarkMode ? Colors.grey[700]! : Colors.grey[300]!), width: isSelected ? 2 : 1, ), ), child: Column( mainAxisSize: MainAxisSize.min, children: [ Icon( _getNavigationIcon(mode["ntype"] as String), color: isEnabled ? (isSelected ? Theme.of(context).primaryColor : (isDarkMode ? Colors.white70 : Colors.black87)) : Colors.grey, size: 20.sp, ), // SizedBox(height: 4.h), // Text( // (mode["ntype"] as String).tr, // textAlign: TextAlign.center, // style: TextStyle( // color: isEnabled // ? (isSelected // ? Theme.of(context).primaryColor // : (isDarkMode // ? Colors.white70 // : Colors.black87)) // : Colors.grey, // fontSize: 11.sp, // fontWeight: isSelected // ? FontWeight.w600 // : FontWeight.w400, // ), // ), ], ), ), ), ); }), ), ), // 底部:目的地信息和操作按钮 Container( padding: EdgeInsets.fromLTRB(20.w, 8.h, 20.w, 16.h), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 第一层:起点 → 目的地信息(独占整个宽度) Row( crossAxisAlignment: CrossAxisAlignment.center, // 确保垂直居中对齐 children: [ // 起点图标 - 统一图标容器宽度,确保对齐 SizedBox( width: 16.sp, // 固定图标容器宽度 child: Icon( Icons.my_location, size: 15.sp, // 统一图标大小 color: Theme.of(context).primaryColor, ), ), SizedBox(width: 6.w), // 统一间距 // 当前位置文本 Text( 'currentLocation'.tr, // 当前位置 style: TextStyle( fontSize: 14.sp, fontWeight: FontWeight.w500, color: isDarkMode ? Colors.white70 : Colors.black54, height: 1.3, // 设置行高,提升多行文本可读性 ), softWrap: true, // 启用软换行 overflow: TextOverflow.visible, // 确保文本完全显示 ), SizedBox(width: 8.w), // 箭头图标 Icon( Icons.arrow_forward, size: 15.sp, // 统一图标大小 color: isDarkMode ? Colors.white54 : Colors.black45, ), SizedBox(width: 8.w), // 目的地图标 Icon( Icons.location_on, size: 15.sp, // 统一图标大小 color: Colors.red, ), SizedBox(width: 6.w), // 统一间距 // 目的地名称 - 使用Expanded确保自动换行 Expanded( child: Text( destination, style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w600, color: isDarkMode ? Colors.white : Colors.black87, height: 1.2, // 设置行高,提升多行文本可读性 ), softWrap: true, // 启用软换行 overflow: TextOverflow.visible, // 确保文本完全显示 ), ), ], ), SizedBox(height: 4.h), // 第一层和第二层之间的间距 // 第二层:距离时间信息(左侧)+ 导航按钮(右侧) Row( crossAxisAlignment: CrossAxisAlignment.end, // 底部对齐 children: [ // 左侧:距离和时间信息 Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 距离信息 Row( crossAxisAlignment: CrossAxisAlignment.center, // 确保垂直居中对齐 children: [ // 距离图标 - 统一图标容器宽度,确保与第一层对齐 SizedBox( width: 16.sp, // 与第一层图标容器宽度一致 child: Icon( Icons.straighten, size: 15.sp, // 统一图标大小 color: Theme.of(context).primaryColor, ), ), SizedBox(width: 6.w), // 与第一层间距一致 Flexible( child: Text( formatDistance( modes[currentIndex]["distance"]), style: TextStyle( fontSize: 14.sp, color: Theme.of(context).primaryColor, fontWeight: FontWeight.w500, height: 1.3, // 设置行高,提升多行文本可读性 ), softWrap: true, // 启用软换行 overflow: TextOverflow.visible, // 确保文本完全显示 ), ), ], ), SizedBox(height: 4.h), // 时间信息 Row( crossAxisAlignment: CrossAxisAlignment.center, // 确保垂直居中对齐 children: [ // 时间图标 - 统一图标容器宽度,确保与第一层对齐 SizedBox( width: 16.sp, // 与第一层图标容器宽度一致 child: Icon( Icons.access_time, size: 15.sp, // 统一图标大小 color: Theme.of(context).primaryColor, ), ), SizedBox(width: 6.w), // 与第一层间距一致 Flexible( child: Text( '${'approximate'.tr}${formatDuration(modes[currentIndex]["duration"])}', // 约 style: TextStyle( fontSize: 14.sp, color: Theme.of(context).primaryColor, fontWeight: FontWeight.w500, height: 1.3, // 设置行高,提升多行文本可读性 ), softWrap: true, // 启用软换行 overflow: TextOverflow.visible, // 确保文本完全显示 ), ), ], ), // 导航状态信息 if (navigation != null) ...[ SizedBox(height: 6.h), Container( padding: EdgeInsets.symmetric( horizontal: 8.w, vertical: 4.h), decoration: BoxDecoration( color: Theme.of(context) .primaryColor .withOpacity(0.1), borderRadius: BorderRadius.circular(6.r), ), child: Text( "${navigation["distanceText"]}${'enterRoad'.tr}${navigation["nextRoad"]}", // 进入 style: TextStyle( fontSize: 12.sp, color: Theme.of(context).primaryColor, fontWeight: FontWeight.w500, height: 1.3, // 设置行高,提升多行文本可读性 ), softWrap: true, // 启用软换行 overflow: TextOverflow.visible, // 确保文本完全显示 ), ), ], ], ), ), SizedBox(width: 16.w), // 左右内容之间的间距 // 右侧:开始导航按钮 Container( decoration: BoxDecoration( gradient: LinearGradient( colors: [ Theme.of(context).primaryColor, Theme.of(context).primaryColor.withOpacity(0.8), ], begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadius.circular(12.r), boxShadow: [ BoxShadow( color: Theme.of(context) .primaryColor .withOpacity(0.3), blurRadius: 8, offset: const Offset(0, 2), ), ], ), child: Material( color: Colors.transparent, child: InkWell( borderRadius: BorderRadius.circular(12.r), onTap: () { controller.openNavigation( true, start, destination, endlatitude, endlongitude, modes[currentIndex]["ntype"] as String); }, child: Container( padding: EdgeInsets.symmetric( horizontal: 16.w, vertical: 12.h, ), child: Icon( Icons.navigation, color: Colors.white, size: 20.sp, ), ), ), ), ), ], ), ], ), ), ], ); }, ), ); } /// 根据导航类型获取对应图标 IconData _getNavigationIcon(String ntype) { switch (ntype.toLowerCase()) { case 'driving': case '驾车': return Icons.directions_car; case 'walking': case '步行': return Icons.directions_walk; case 'transit': case 'tsransit': // 修正拼写错误 case '公交': return Icons.directions_transit; case 'bicycling': // 修正为正确的英文值 case 'cycling': case '骑行': return Icons.directions_bike; default: return Icons.navigation; } }