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)} 公里'; } else { return '${distance.toStringAsFixed(0)} 米'; } } 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小时'); if (minutes > 0) parts.add('$minutes分钟'); if (seconds > 0 || parts.isEmpty) parts.add('$seconds秒'); return parts.join(''); } /// 导航卡片组件 /// /// 各元素含义分析: /// - [start]: 起点坐标 (经纬度格式) /// - [end]: 终点坐标 (经纬度格式) /// - [destination]: 目的地名称显示 /// - [modes]: 导航方式列表,包含驾车、步行、公交等选项 /// - [navigation]: 当前导航状态信息(可选) /// - [height]: 卡片高度 Widget navigationCard( BuildContext context, { required String start, required String end, 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( '导航中', 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: Stack( children: [ // 目的地和距离时间信息 Padding( padding: EdgeInsets.only(right: 70.w), // 为右下角按钮留出空间 child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 路径显示:当前位置 → 目的地 Row( children: [ // 起点图标 Icon( Icons.my_location, size: 16.sp, color: Theme.of(context).primaryColor, ), SizedBox(width: 6.w), // 当前位置文本 Text( '当前位置', style: TextStyle( fontSize: 14.sp, fontWeight: FontWeight.w500, color: isDarkMode ? Colors.white70 : Colors.black54, ), ), SizedBox(width: 8.w), // 箭头图标 Icon( Icons.arrow_forward, size: 16.sp, color: isDarkMode ? Colors.white54 : Colors.black45, ), SizedBox(width: 8.w), // 目的地图标 Icon( Icons.location_on, size: 16.sp, color: Colors.red, ), SizedBox(width: 6.w), // 目的地名称 Expanded( child: Text( destination, style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w600, color: isDarkMode ? Colors.white : Colors.black87, ), maxLines: 1, overflow: TextOverflow.ellipsis, ), ), ], ), SizedBox(height: 4.h), // 距离和时间信息 Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 距离信息 Row( children: [ Icon( Icons.straighten, size: 14.sp, color: Theme.of(context).primaryColor, ), SizedBox(width: 4.w), Text( formatDistance( modes[currentIndex]["distance"]), style: TextStyle( fontSize: 14.sp, color: Theme.of(context).primaryColor, fontWeight: FontWeight.w500, ), ), ], ), SizedBox(height: 4.h), // 时间信息 Row( children: [ Icon( Icons.access_time, size: 14.sp, color: Theme.of(context).primaryColor, ), SizedBox(width: 4.w), Text( '约${formatDuration(modes[currentIndex]["duration"])}', style: TextStyle( fontSize: 14.sp, color: Theme.of(context).primaryColor, fontWeight: FontWeight.w500, ), ), ], ), ], ), // 导航状态信息 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"]}进入${navigation["nextRoad"]}", style: TextStyle( fontSize: 12.sp, color: Theme.of(context).primaryColor, fontWeight: FontWeight.w500, ), ), ), ], ], ), ), // 开始导航按钮 - 绝对定位到右下角 Positioned( right: 0, bottom: 0, child: 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(start, end, ""); }, 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; } }