import 'package:common_utils/common_utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:get/get.dart'; /// 构建天气内容卡片 Widget hefengWeatherContent(BuildContext context, String city, Map now, List> days) { final isDarkMode = Theme.of(context).brightness == Brightness.dark; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'weatherQuery'.tr, // 翻译键代表的中文文本内容:查询天气情况: style: TextStyle( color: isDarkMode ? Colors.white.withValues(alpha: 0.9) : Colors.black87, fontSize: 14.sp, height: 1.4, fontWeight: FontWeight.w400, ), ), SizedBox(height: 12.h), Container( padding: EdgeInsets.all(16.w), decoration: BoxDecoration( gradient: _getWeatherGradient(now['textDay'] ?? '', isDarkMode), borderRadius: BorderRadius.circular(12.r), boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: isDarkMode ? 0.3 : 0.1), blurRadius: 8, offset: const Offset(0, 2), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "${city} ${now["fxDate"]}", style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w600, color: Colors.white, ), ), SizedBox(height: 4.w), Text( _getWeatherDescriptionTranslation(now["textDay"]), style: TextStyle( fontSize: 14.sp, color: Colors.white.withValues(alpha: 0.9), ), ), SizedBox(height: 8.h), Row( children: [ Text( "${now["tempMax"]}°", style: TextStyle( fontSize: 36.sp, fontWeight: FontWeight.bold, color: Colors.white, ), ), SizedBox(width: 8.w), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '${'highest'.tr}: ${now["tempMax"]}°', // 翻译键代表的中文文本内容:最高 style: TextStyle( fontSize: 12.sp, color: Colors.white.withValues(alpha: 0.9), ), ), Text( '${'lowest'.tr}: ${now["tempMin"]}°', // 翻译键代表的中文文本内容:最低 style: TextStyle( fontSize: 12.sp, color: Colors.white.withValues(alpha: 0.9), ), ), ], ), ], ), ], ), getWeatherSvgIcon( now['iconDay'], size: 48.sp, ), ], ), SizedBox(height: 16.h), Container( height: 1, color: Colors.white.withValues(alpha: isDarkMode ? 0.15 : 0.2), ), SizedBox(height: 16.h), Text( 'futureForecast'.tr, // 翻译键代表的中文文本内容:未来预报 style: TextStyle( fontSize: 14.sp, fontWeight: FontWeight.w600, color: Colors.white, ), ), SizedBox(height: 8.h), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: List.generate( days.length, (index) { String dateStr = days[index]['fxDate']; DateTime? date = DateUtil.getDateTime(dateStr); Widget weatherIcon = getWeatherSvgIcon(days[index]['iconDay'], size: 20.sp); // 获取星期几的翻译键 String weekdayKey = _getWeekdayTranslationKey(date); String weekday = weekdayKey.tr; // 翻译键代表的中文文本内容:对应的星期几 String temp = "${days[index]['tempMax']}°"; return _buildForecastDay( weekday, weatherIcon, temp, ); }, ), ), SizedBox(height: 16.h), _hefengWeatherTip(context, now, isDarkMode), ], ), ), ], ); } /// 获取天气描述的翻译 String _getWeatherDescriptionTranslation(String weatherDescription) { final description = weatherDescription.trim(); // 天气描述映射表 final Map weatherMap = { // 晴天类 '晴': 'sunny'.tr, // 翻译键代表的中文文本内容:晴 '少云': 'partlyCloudy'.tr, // 翻译键代表的中文文本内容:少云 '晴间多云': 'partlySunny'.tr, // 翻译键代表的中文文本内容:晴间多云 // 多云类 '多云': 'cloudy'.tr, // 翻译键代表的中文文本内容:多云 '阴': 'overcast'.tr, // 翻译键代表的中文文本内容:阴 // 雨天类 '阵雨': 'shower'.tr, // 翻译键代表的中文文本内容:阵雨 '雷阵雨': 'thundershower'.tr, // 翻译键代表的中文文本内容:雷阵雨 '小雨': 'lightRain'.tr, // 翻译键代表的中文文本内容:小雨 '中雨': 'moderateRain'.tr, // 翻译键代表的中文文本内容:中雨 '大雨': 'heavyRain'.tr, // 翻译键代表的中文文本内容:大雨 '暴雨': 'rainstorm'.tr, // 翻译键代表的中文文本内容:暴雨 // 雪天类 '阵雪': 'snowShower'.tr, // 翻译键代表的中文文本内容:阵雪 '小雪': 'lightSnow'.tr, // 翻译键代表的中文文本内容:小雪 '中雪': 'moderateSnow'.tr, // 翻译键代表的中文文本内容:中雪 '大雪': 'heavySnow'.tr, // 翻译键代表的中文文本内容:大雪 '暴雪': 'blizzard'.tr, // 翻译键代表的中文文本内容:暴雪 // 雾霾类 '雾': 'fog'.tr, // 翻译键代表的中文文本内容:雾 '霾': 'haze'.tr, // 翻译键代表的中文文本内容:霾 // 风类 '大风': 'strongWind'.tr, // 翻译键代表的中文文本内容:大风 }; // 返回翻译后的描述,如果没有找到对应翻译则返回原文 return weatherMap[description] ?? description; } /// 获取星期几的翻译键 String _getWeekdayTranslationKey(DateTime? date) { if (date == null) return 'unknown'; switch (date.weekday) { case 1: return 'monday'; // 翻译键代表的中文文本内容:周一 case 2: return 'tuesday'; // 翻译键代表的中文文本内容:周二 case 3: return 'wednesday'; // 翻译键代表的中文文本内容:周三 case 4: return 'thursday'; // 翻译键代表的中文文本内容:周四 case 5: return 'friday'; // 翻译键代表的中文文本内容:周五 case 6: return 'saturday'; // 翻译键代表的中文文本内容:周六 case 7: return 'sunday'; // 翻译键代表的中文文本内容:周日 default: return 'unknown'; } } /// 构建智能天气提示 Widget _hefengWeatherTip( BuildContext context, Map now, bool isDarkMode) { final weatherTip = _generateWeatherTip(now); return Container( padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 12.w), decoration: BoxDecoration( color: isDarkMode ? Colors.white.withValues(alpha: 0.15) : Colors.white.withValues(alpha: 0.2), borderRadius: BorderRadius.circular(8.r), ), child: Row( children: [ Icon( weatherTip.icon, size: 16.sp, color: Colors.white, ), SizedBox(width: 8.w), Flexible( child: Text( weatherTip.message, style: TextStyle( fontSize: 12.sp, color: Colors.white, ), ), ), ], ), ); } /// 天气提示数据类 class WeatherTip { final IconData icon; final String message; const WeatherTip({required this.icon, required this.message}); } /// 根据天气数据生成智能提示 WeatherTip _generateWeatherTip(Map now) { final dayWeather = (now['textDay'] as String? ?? '').trim(); final dayTemp = int.tryParse(now['tempMax']?.toString() ?? '0') ?? 0; final nightTemp = int.tryParse(now['tempMin']?.toString() ?? '0') ?? 0; // 高温提示 (>= 35°C) if (dayTemp >= 35) { return WeatherTip( icon: Icons.local_fire_department, message: 'hotWeatherTip'.tr, // 翻译键代表的中文文本内容:今日高温炎热,请注意防暑降温,多喝水避免中暑 ); } // 低温提示 (<= 5°C) if (dayTemp <= 5) { return WeatherTip( icon: Icons.ac_unit, message: 'coldWeatherTip'.tr, // 翻译键代表的中文文本内容:今日气温较低,外出请注意保暖,小心感冒 ); } // 雨天提示 if (dayWeather.contains('雨') || ['阵雨', '雷阵雨', '小雨', '中雨', '大雨', '暴雨'] .any((rain) => dayWeather.contains(rain))) { return WeatherTip( icon: Icons.umbrella, message: 'rainyWeatherTip'.tr, // 翻译键代表的中文文本内容:今日有雨,外出请携带雨具,注意出行安全 ); } // 雪天提示 if (dayWeather.contains('雪') || ['阵雪', '小雪', '中雪', '大雪', '暴雪'].any((snow) => dayWeather.contains(snow))) { return WeatherTip( icon: Icons.ac_unit, message: 'snowyWeatherTip'.tr, // 翻译键代表的中文文本内容:今日有雪,路面湿滑请注意安全,做好保暖措施 ); } // 雾霾提示 if (dayWeather.contains('雾') || dayWeather.contains('霾') || ['雾', '浓雾', '霾', '中度霾', '重度霾'].any((fog) => dayWeather.contains(fog))) { return WeatherTip( icon: Icons.blur_on, message: 'foggyWeatherTip'.tr, // 翻译键代表的中文文本内容:今日有雾霾,能见度较低,外出请佩戴口罩 ); } // 大风提示 if (dayWeather.contains('风') || ['大风', '强风', '疾风', '烈风'].any((wind) => dayWeather.contains(wind))) { return WeatherTip( icon: Icons.air, message: 'windyWeatherTip'.tr, // 翻译键代表的中文文本内容:今日风力较大,外出请注意安全,固定好物品 ); } // 晴天紫外线提示 (温度 >= 25°C) if (['晴', '少云', '晴间多云'].any((sunny) => dayWeather.contains(sunny)) && dayTemp >= 25) { return WeatherTip( icon: Icons.wb_sunny, message: 'sunnyWeatherTip'.tr, // 翻译键代表的中文文本内容:今日阳光充足紫外线较强,外出请做好防晒 ); } // 温差大提示 (>= 10°C) if ((dayTemp - nightTemp).abs() >= 10) { return WeatherTip( icon: Icons.thermostat, message: 'temperatureDifferenceTip'.tr, // 翻译键代表的中文文本内容:今日昼夜温差较大,请适时增减衣物 ); } // 默认舒适天气提示 return WeatherTip( icon: Icons.wb_sunny_outlined, message: 'comfortableWeatherTip'.tr, // 翻译键代表的中文文本内容:今日天气适宜,是外出活动的好时光 ); } /// 构建单日天气预报 Widget _buildForecastDay(String day, Widget icon, String temp) { return Column( children: [ Text( day, style: TextStyle( fontSize: 12.sp, color: Colors.white.withValues(alpha: 0.9), ), ), SizedBox(height: 4.h), icon, SizedBox(height: 4.h), Text( temp, style: TextStyle( fontSize: 12.sp, fontWeight: FontWeight.w500, color: Colors.white, ), ), ], ); } /// 获取天气 SVG 图标 Widget Widget getWeatherSvgIcon(String mappedCode, {double size = 24.0}) { return _getWeatherSvgByCode(mappedCode, size: size); } /// 根据和风天气代码获取 SVG 图标 Widget _getWeatherSvgByCode(String code, {double size = 24.0}) { // 检查 SVG 文件是否存在,如果不存在则使用默认图标 final svgPath = 'assets/weather/$code.svg'; return SvgPicture.asset( svgPath, width: size, height: size, fit: BoxFit.contain, colorFilter: const ColorFilter.mode(Colors.white, BlendMode.srcIn), // 如果 SVG 加载失败,显示默认图标 placeholderBuilder: (context) => Icon( Icons.help_outline, size: size, ), ); } /// 根据天气类型获取背景渐变颜色 LinearGradient _getWeatherGradient(String weather, bool isDarkMode) { final weatherType = weather.trim(); // 晴天 - 温暖的橙黄色 if (['晴', '少云', '晴间多云'].any((sunny) => weatherType.contains(sunny))) { return LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: isDarkMode ? [Color(0xFFFF8A00), Color(0xFFE65100)] // 深色模式:深橙色 : [Color(0xFFFFB74D), Color(0xFFFF9800)], // 浅色模式:亮橙色 ); } // 多云/阴天 - 灰蓝色 if (['多云', '阴'].any((cloudy) => weatherType.contains(cloudy))) { return LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: isDarkMode ? [Color(0xFF455A64), Color(0xFF37474F)] // 深色模式:深灰蓝 : [Color(0xFF78909C), Color(0xFF607D8B)], // 浅色模式:灰蓝色 ); } // 雨天 - 深蓝色 if (weatherType.contains('雨') || ['阵雨', '雷阵雨', '小雨', '中雨', '大雨', '暴雨'] .any((rain) => weatherType.contains(rain))) { return LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: isDarkMode ? [Color(0xFF1565C0), Color(0xFF0D47A1)] // 深色模式:深蓝色 : [Color(0xFF42A5F5), Color(0xFF1976D2)], // 浅色模式:亮蓝色 ); } // 雪天 - 冷色调蓝白色 if (weatherType.contains('雪') || ['阵雪', '小雪', '中雪', '大雪', '暴雪'] .any((snow) => weatherType.contains(snow))) { return LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: isDarkMode ? [Color(0xFF0277BD), Color(0xFF01579B)] // 深色模式:深冷蓝 : [Color(0xFF81D4FA), Color(0xFF29B6F6)], // 浅色模式:浅蓝色 ); } // 雾霾天 - 暗黄灰色 if (weatherType.contains('雾') || weatherType.contains('霾') || ['雾', '浓雾', '霾', '中度霾', '重度霾'].any((fog) => weatherType.contains(fog))) { return LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: isDarkMode ? [Color(0xFF5D4037), Color(0xFF3E2723)] // 深色模式:深棕色 : [Color(0xFF8D6E63), Color(0xFF6D4C41)], // 浅色模式:棕灰色 ); } // 大风天 - 青绿色 if (weatherType.contains('风') || ['大风', '强风', '疾风', '烈风'].any((wind) => weatherType.contains(wind))) { return LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: isDarkMode ? [Color(0xFF00695C), Color(0xFF004D40)] // 深色模式:深青色 : [Color(0xFF26A69A), Color(0xFF00796B)], // 浅色模式:青绿色 ); } // 默认 - 原来的蓝色 return LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: isDarkMode ? [Color(0xFF1E40AF), Color(0xFF1E3A8A)] : [Color(0xFF60A5FA), Color(0xFF3B82F6)], ); }