Browse Source

feat(ui): 添加暗黑模式支持并优化响应式布局

- 为音乐卡片、导航卡片、旅游卡片和天气卡片添加暗黑模式适配
- 使用flutter_screenutil实现响应式尺寸单位
- 优化天气卡片提示信息,根据天气数据动态生成智能提示
- 统一使用主题颜色替代硬编码颜色值
newdev_shunjiawei
lxm 1 year ago
parent
commit
1c8bd4bece
  1. 27
      lib/modules/agent/views/music_card.dart
  2. 56
      lib/modules/agent/views/navigation_card.dart
  3. 110
      lib/modules/agent/views/travel_card.dart
  4. 213
      lib/modules/agent/views/weather_card.dart

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

@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import '../../../routes/app_routes.dart'; import '../../../routes/app_routes.dart';
import '../controllers/agent_controller.dart'; import '../controllers/agent_controller.dart';
@ -20,10 +21,10 @@ Widget buildMusicItem(BuildContext context, int id, String name, String url,
controller.musicStatus(); //刷新状态 controller.musicStatus(); //刷新状态
return Container( return Container(
padding: const EdgeInsets.all(14), padding: EdgeInsets.all(14.w),
decoration: BoxDecoration( decoration: BoxDecoration(
color: isDarkMode ? const Color(0xFF1E1E1E) : Colors.white, color: isDarkMode ? const Color(0xFF1E1E1E) : Colors.white,
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12.r),
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
color: Colors.black.withValues(alpha: isDarkMode ? 0.2 : 0.03), color: Colors.black.withValues(alpha: isDarkMode ? 0.2 : 0.03),
@ -36,11 +37,11 @@ Widget buildMusicItem(BuildContext context, int id, String name, String url,
child: Row( child: Row(
children: [ children: [
Container( Container(
width: 50, width: 50.w,
height: 50, height: 50.h,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.grey[100], color: isDarkMode ? Colors.grey[800] : Colors.grey[100],
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8.r),
image: image.isNotEmpty image: image.isNotEmpty
? DecorationImage( ? DecorationImage(
image: NetworkImage(image), image: NetworkImage(image),
@ -51,12 +52,12 @@ Widget buildMusicItem(BuildContext context, int id, String name, String url,
child: image.isEmpty child: image.isEmpty
? Icon( ? Icon(
Icons.music_note, Icons.music_note,
size: 18, size: 18.sp,
color: Theme.of(context).primaryColor, color: Theme.of(context).primaryColor,
) )
: null, : null,
), ),
const SizedBox(width: 12), SizedBox(width: 12.w),
Expanded( Expanded(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -64,18 +65,18 @@ Widget buildMusicItem(BuildContext context, int id, String name, String url,
Text( Text(
name, name,
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13.sp,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Colors.grey[800], color: isDarkMode ? Colors.white.withValues(alpha: 0.9) : Colors.grey[800],
), ),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
SizedBox(height: 2), SizedBox(height: 2.h),
Text( Text(
singer, singer,
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12.sp,
color: Colors.grey[600], color: isDarkMode ? Colors.grey[400] : Colors.grey[600],
), ),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),

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

@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import '../controllers/agent_controller.dart'; import '../controllers/agent_controller.dart';
@ -42,16 +43,18 @@ Widget navigationCard(
}) { }) {
int currentIndex = 0; int currentIndex = 0;
final controller = Get.find<AgentController>(); // 获取控制器 final controller = Get.find<AgentController>(); // 获取控制器
final isDarkMode = Theme.of(context).brightness == Brightness.dark;
return Container( return Container(
height: height, height: height.h,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16.r),
color: Colors.white, color: isDarkMode ? const Color(0xFF1E1E1E) : Colors.white,
boxShadow: const [ boxShadow: [
BoxShadow( BoxShadow(
blurRadius: 8, blurRadius: 8,
color: Colors.black12, color: Colors.black.withValues(alpha: isDarkMode ? 0.3 : 0.12),
offset: Offset(0, 4), offset: const Offset(0, 4),
), ),
], ],
), ),
@ -63,13 +66,13 @@ Widget navigationCard(
// 路线图片 // 路线图片
ClipRRect( ClipRRect(
borderRadius: borderRadius:
const BorderRadius.vertical(top: Radius.circular(16)), BorderRadius.vertical(top: Radius.circular(16.r)),
child: AnimatedSwitcher( child: AnimatedSwitcher(
duration: const Duration(milliseconds: 300), duration: const Duration(milliseconds: 300),
child: Image.network( child: Image.network(
modes[currentIndex]["image"] as String, modes[currentIndex]["image"] as String,
key: ValueKey<String>(modes[currentIndex]["ntype"] as String), key: ValueKey<String>(modes[currentIndex]["ntype"] as String),
height: 160, height: 160.h,
width: double.infinity, width: double.infinity,
fit: BoxFit.cover, fit: BoxFit.cover,
), ),
@ -78,7 +81,7 @@ Widget navigationCard(
// 导航方式切换按钮 // 导航方式切换按钮
Padding( Padding(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 4), padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 4.w),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: List.generate(modes.length, (index) { children: List.generate(modes.length, (index) {
@ -90,17 +93,17 @@ Widget navigationCard(
} }
: null, : null,
child: SizedBox( child: SizedBox(
width: 50, width: 50.w,
child: Text( child: Text(
(modes[index]["ntype"] as String).tr, (modes[index]["ntype"] as String).tr,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
color: modes[index]['enable'] color: modes[index]['enable']
? isSelected ? isSelected
? Colors.blue ? Theme.of(context).primaryColor
: Colors.black87 : isDarkMode ? Colors.white.withValues(alpha: 0.9) : Colors.black87
: Colors.grey, : Colors.grey,
fontSize: 12, fontSize: 12.sp,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
), ),
), ),
@ -112,35 +115,36 @@ Widget navigationCard(
// 距离和耗时 // 距离和耗时
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 8), padding: EdgeInsets.symmetric(horizontal: 8.w),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text('$destination', Text(destination,
style: const TextStyle( style: TextStyle(
fontSize: 12, color: Colors.black)), fontSize: 12.sp,
color: isDarkMode ? Colors.white.withValues(alpha: 0.9) : Colors.black87)),
Text( Text(
'${formatDistance(modes[currentIndex]["distance"])}-约${formatDuration(modes[currentIndex]["duration"])}', '${formatDistance(modes[currentIndex]["distance"])}-约${formatDuration(modes[currentIndex]["duration"])}',
style: const TextStyle( style: TextStyle(
fontSize: 15, color: Colors.blue)), fontSize: 15.sp,
color: Theme.of(context).primaryColor)),
if (navigation != null) if (navigation != null)
Text( Text(
"导航中... ${navigation["distanceText"]}进入${navigation["nextRoad"]}", "导航中... ${navigation["distanceText"]}进入${navigation["nextRoad"]}",
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12.sp,
color: color: isDarkMode ? Colors.grey[400] : Colors.grey[600]))
const Color.fromARGB(255, 164, 164, 164)))
], ],
), ),
CircleAvatar( CircleAvatar(
backgroundColor: Colors.blue, backgroundColor: Theme.of(context).primaryColor,
radius: 18, radius: 18.r,
child: IconButton( child: IconButton(
icon: const Icon(Icons.turn_left, icon: Icon(Icons.turn_left,
color: Colors.white, size: 20), color: Colors.white, size: 20.sp),
onPressed: () { onPressed: () {
controller.openNavigation(start, end, ""); controller.openNavigation(start, end, "");
}, },

110
lib/modules/agent/views/travel_card.dart

@ -1,29 +1,32 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
/// 构建旅游内容卡片 /// 构建旅游内容卡片
Widget buildTravelContent( Widget buildTravelContent(
BuildContext context, List<Map<String, dynamic>> travellist) { BuildContext context, List<Map<String, dynamic>> travellist) {
final isDarkMode = Theme.of(context).brightness == Brightness.dark;
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
const Text( Text(
'以下是一些推搜索结果:', '以下是一些推荐搜索结果:',
style: TextStyle( style: TextStyle(
color: Colors.black87, color: isDarkMode ? Colors.white.withValues(alpha: 0.9) : Colors.black87,
fontSize: 14, fontSize: 14.sp,
height: 1.4, height: 1.4,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
), ),
), ),
const SizedBox(height: 12), SizedBox(height: 12.h),
Container( Container(
padding: const EdgeInsets.all(12), padding: EdgeInsets.all(12.w),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: isDarkMode ? const Color(0xFF1E1E1E) : Colors.white,
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12.r),
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
color: Colors.black.withOpacity(0.03), color: Colors.black.withValues(alpha: isDarkMode ? 0.2 : 0.03),
blurRadius: 3, blurRadius: 3,
spreadRadius: 1, spreadRadius: 1,
offset: const Offset(0, 1), offset: const Offset(0, 1),
@ -53,16 +56,16 @@ Widget buildTravelContent(
// ), // ),
// const SizedBox(height: 10), // const SizedBox(height: 10),
// 动态生成音乐条目 // 动态生成旅游景点条目
...travellist.asMap().entries.map((entry) { ...travellist.asMap().entries.map((entry) {
final index = entry.key; final index = entry.key;
final item = entry.value; final item = entry.value;
final name = item["name"] ?? "未知歌曲"; //名字 final name = item["name"] ?? "未知景点"; //名字
final addr = item["addr"] ?? ""; //地址 final addr = item["addr"] ?? ""; //地址
final tag = item["tag"] ?? "未知歌手"; //标签 // final tag = item["tag"] ?? "未知标签"; //标签
final rating = item["rating"] ?? ""; //评分 // final rating = item["rating"] ?? ""; //评分
final distance = item["distance"] ?? ""; //距离 // final distance = item["distance"] ?? ""; //距离
final images = item["images"] ?? []; // 图片列表 // final images = item["images"] ?? []; // 图片列表
return Column( return Column(
children: [ children: [
buildLocationItem( buildLocationItem(
@ -71,7 +74,11 @@ Widget buildTravelContent(
addr, addr,
), ),
if (index != travellist.length - 1) if (index != travellist.length - 1)
Divider(height: 1, thickness: 1, color: Colors.grey[100]), Divider(
height: 1.h,
thickness: 1,
color: isDarkMode ? Colors.grey[700] : Colors.grey[100]
),
], ],
); );
}).toList(), }).toList(),
@ -82,19 +89,19 @@ Widget buildTravelContent(
// Divider(height: 1, thickness: 1, color: Colors.grey[100]), // Divider(height: 1, thickness: 1, color: Colors.grey[100]),
// _buildLocationItem('浅草寺', '东京最古老的寺庙', context), // _buildLocationItem('浅草寺', '东京最古老的寺庙', context),
const SizedBox(height: 8), SizedBox(height: 8.h),
Center( Center(
child: TextButton( child: TextButton(
onPressed: () {}, onPressed: () {},
style: TextButton.styleFrom( style: TextButton.styleFrom(
minimumSize: Size.zero, minimumSize: Size.zero,
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 8), padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 8.h),
tapTargetSize: MaterialTapTargetSize.shrinkWrap, tapTargetSize: MaterialTapTargetSize.shrinkWrap,
), ),
child: Text( child: Text(
'查看更多景点', '查看更多景点',
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12.sp,
color: Theme.of(context).primaryColor, color: Theme.of(context).primaryColor,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
), ),
@ -104,41 +111,41 @@ Widget buildTravelContent(
], ],
), ),
), ),
const SizedBox(height: 10), SizedBox(height: 10.h),
Row( Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Expanded( Expanded(
child: OutlinedButton.icon( child: OutlinedButton.icon(
onPressed: () {}, onPressed: () {},
icon: Icon(Icons.map, size: 16), icon: Icon(Icons.map, size: 16.sp),
label: Text('查看地图'), label: const Text('查看地图'),
style: OutlinedButton.styleFrom( style: OutlinedButton.styleFrom(
foregroundColor: Theme.of(context).primaryColor, foregroundColor: Theme.of(context).primaryColor,
side: BorderSide( side: BorderSide(
color: Theme.of(context).primaryColor.withOpacity(0.5)), color: Theme.of(context).primaryColor.withValues(alpha: 0.5)),
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 4), padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 4.h),
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16.r),
), ),
textStyle: TextStyle(fontSize: 12), textStyle: TextStyle(fontSize: 12.sp),
), ),
), ),
), ),
SizedBox(width: 8), SizedBox(width: 8.w),
Expanded( Expanded(
child: OutlinedButton.icon( child: OutlinedButton.icon(
onPressed: () {}, onPressed: () {},
icon: Icon(Icons.bookmark_border, size: 16), icon: Icon(Icons.bookmark_border, size: 16.sp),
label: Text('保存到收藏'), label: const Text('保存到收藏'),
style: OutlinedButton.styleFrom( style: OutlinedButton.styleFrom(
foregroundColor: Colors.grey[700], foregroundColor: isDarkMode ? Colors.grey[400] : Colors.grey[700],
side: BorderSide(color: Colors.grey[400]!), side: BorderSide(color: isDarkMode ? Colors.grey[600]! : Colors.grey[400]!),
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 4), padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 4.h),
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16.r),
), ),
textStyle: TextStyle(fontSize: 12), textStyle: TextStyle(fontSize: 12.sp),
), ),
), ),
), ),
@ -154,23 +161,25 @@ Widget buildLocationItem(
final isDarkMode = Theme.of(context).brightness == Brightness.dark; final isDarkMode = Theme.of(context).brightness == Brightness.dark;
return Padding( return Padding(
padding: const EdgeInsets.symmetric(vertical: 8), padding: EdgeInsets.symmetric(vertical: 8.h),
child: Row( child: Row(
children: [ children: [
Container( Container(
width: 38, width: 38.w,
height: 38, height: 38.h,
decoration: BoxDecoration( decoration: BoxDecoration(
color: isDarkMode ? Color(0xFF1A365D) : Colors.blue[50], color: isDarkMode
borderRadius: BorderRadius.circular(8), ? const Color(0xFF2A2A2A)
: Theme.of(context).primaryColor.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(8.r),
), ),
child: Icon( child: Icon(
Icons.place, Icons.place,
size: 18, size: 18.sp,
color: Color(0xFFE11D48), color: Theme.of(context).primaryColor,
), ),
), ),
const SizedBox(width: 12), SizedBox(width: 12.w),
Expanded( Expanded(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -178,19 +187,19 @@ Widget buildLocationItem(
Text( Text(
name, name,
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13.sp,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: isDarkMode color: isDarkMode
? Colors.white.withOpacity(0.9) ? Colors.white.withValues(alpha: 0.9)
: Colors.grey[800], : Colors.grey[800],
), ),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
SizedBox(height: 2), SizedBox(height: 2.h),
Text( Text(
description, description,
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12.sp,
color: isDarkMode ? Colors.grey[400] : Colors.grey[600], color: isDarkMode ? Colors.grey[400] : Colors.grey[600],
), ),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
@ -200,10 +209,13 @@ Widget buildLocationItem(
), ),
IconButton( IconButton(
onPressed: () {}, onPressed: () {},
icon: Icon(Icons.arrow_forward, color: Colors.grey[400]), icon: Icon(
Icons.arrow_forward,
color: isDarkMode ? Colors.grey[500] : Colors.grey[400]
),
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
constraints: BoxConstraints(), constraints: const BoxConstraints(),
iconSize: 20, iconSize: 20.sp,
), ),
], ],
), ),

213
lib/modules/agent/views/weather_card.dart

@ -1,5 +1,6 @@
import 'package:common_utils/common_utils.dart'; import 'package:common_utils/common_utils.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
/// 构建天气内容卡片 /// 构建天气内容卡片
Widget buildWeatherContent(BuildContext context, String city, Widget buildWeatherContent(BuildContext context, String city,
@ -12,31 +13,31 @@ Widget buildWeatherContent(BuildContext context, String city,
Text( Text(
'查询天气情况:', '查询天气情况:',
style: TextStyle( style: TextStyle(
color: isDarkMode ? Colors.white.withOpacity(0.9) : Colors.black87, color: isDarkMode ? Colors.white.withValues(alpha: 0.9) : Colors.black87,
fontSize: 14, fontSize: 14.sp,
height: 1.4, height: 1.4,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
), ),
), ),
const SizedBox(height: 12), SizedBox(height: 12.h),
Container( Container(
padding: const EdgeInsets.all(16), padding: EdgeInsets.all(16.w),
decoration: BoxDecoration( decoration: BoxDecoration(
gradient: isDarkMode gradient: isDarkMode
? LinearGradient( ? const LinearGradient(
begin: Alignment.topLeft, begin: Alignment.topLeft,
end: Alignment.bottomRight, end: Alignment.bottomRight,
colors: [Color(0xFF1E40AF), Color(0xFF1E3A8A)], colors: [Color(0xFF1E40AF), Color(0xFF1E3A8A)],
) )
: LinearGradient( : const LinearGradient(
begin: Alignment.topLeft, begin: Alignment.topLeft,
end: Alignment.bottomRight, end: Alignment.bottomRight,
colors: [Color(0xFF60A5FA), Color(0xFF3B82F6)], colors: [Color(0xFF60A5FA), Color(0xFF3B82F6)],
), ),
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12.r),
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
color: Colors.black.withOpacity(isDarkMode ? 0.3 : 0.1), color: Colors.black.withValues(alpha: isDarkMode ? 0.3 : 0.1),
blurRadius: 8, blurRadius: 8,
offset: const Offset(0, 2), offset: const Offset(0, 2),
), ),
@ -64,37 +65,37 @@ Widget buildWeatherContent(BuildContext context, String city,
Text( Text(
now["dayweather"], now["dayweather"],
style: TextStyle( style: TextStyle(
fontSize: 14, fontSize: 14.sp,
color: Colors.white.withOpacity(0.9), color: Colors.white.withValues(alpha: 0.9),
), ),
), ),
SizedBox(height: 8), SizedBox(height: 8.h),
Row( Row(
children: [ children: [
Text( Text(
"${now["daytemp"]}°", "${now["daytemp"]}°",
style: const TextStyle( style: TextStyle(
fontSize: 36, fontSize: 36.sp,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: Colors.white, color: Colors.white,
), ),
), ),
SizedBox(width: 8), SizedBox(width: 8.w),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
'最高: ${now["daytemp"]}°', '最高: ${now["daytemp"]}°',
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12.sp,
color: Colors.white.withOpacity(0.9), color: Colors.white.withValues(alpha: 0.9),
), ),
), ),
Text( Text(
'最低: ${now["nighttemp"]}°', '最低: ${now["nighttemp"]}°',
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12.sp,
color: Colors.white.withOpacity(0.9), color: Colors.white.withValues(alpha: 0.9),
), ),
), ),
], ],
@ -105,26 +106,26 @@ Widget buildWeatherContent(BuildContext context, String city,
), ),
Icon( Icon(
getWeatherIcon(now['dayweather']), getWeatherIcon(now['dayweather']),
size: 48, size: 48.sp,
color: Colors.white, color: Colors.white,
), ),
], ],
), ),
SizedBox(height: 16), SizedBox(height: 16.h),
Container( Container(
height: 1, height: 1,
color: Colors.white.withOpacity(isDarkMode ? 0.15 : 0.2), color: Colors.white.withValues(alpha: isDarkMode ? 0.15 : 0.2),
), ),
SizedBox(height: 16), SizedBox(height: 16.h),
const Text( Text(
'未来预报', '未来预报',
style: TextStyle( style: TextStyle(
fontSize: 14, fontSize: 14.sp,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
color: Colors.white, color: Colors.white,
), ),
), ),
SizedBox(height: 8), SizedBox(height: 8.h),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: List.generate( children: List.generate(
@ -145,35 +146,8 @@ Widget buildWeatherContent(BuildContext context, String city,
}, },
), ),
), ),
SizedBox(height: 16), SizedBox(height: 16.h),
Container( _buildWeatherTip(context, now, isDarkMode),
padding: EdgeInsets.symmetric(vertical: 8, horizontal: 12),
decoration: BoxDecoration(
color: isDarkMode
? Colors.white.withOpacity(0.15)
: Colors.white.withOpacity(0.2),
borderRadius: BorderRadius.circular(8),
),
child: const Row(
children: [
Icon(
Icons.info_outline,
size: 16,
color: Colors.white,
),
SizedBox(width: 8),
Flexible(
child: Text(
'今日紫外线指数较高,外出请做好防晒',
style: TextStyle(
fontSize: 12,
color: Colors.white,
),
),
),
],
),
),
], ],
), ),
), ),
@ -181,6 +155,125 @@ Widget buildWeatherContent(BuildContext context, String city,
); );
} }
/// 构建智能天气提示
Widget _buildWeatherTip(BuildContext context, Map<String, dynamic> 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<String, dynamic> now) {
final dayWeather = (now['dayweather'] as String? ?? '').trim();
final dayTemp = int.tryParse(now['daytemp']?.toString() ?? '0') ?? 0;
final nightTemp = int.tryParse(now['nighttemp']?.toString() ?? '0') ?? 0;
// 高温提示 (>= 35°C)
if (dayTemp >= 35) {
return const WeatherTip(
icon: Icons.local_fire_department,
message: '今日高温炎热,请注意防暑降温,多喝水避免中暑',
);
}
// 低温提示 (<= 5°C)
if (dayTemp <= 5) {
return const WeatherTip(
icon: Icons.ac_unit,
message: '今日气温较低,外出请注意保暖,小心感冒',
);
}
// 雨天提示
if (dayWeather.contains('雨') || ['阵雨', '雷阵雨', '小雨', '中雨', '大雨', '暴雨'].any((rain) => dayWeather.contains(rain))) {
return const WeatherTip(
icon: Icons.umbrella,
message: '今日有雨,外出请携带雨具,注意出行安全',
);
}
// 雪天提示
if (dayWeather.contains('雪') || ['阵雪', '小雪', '中雪', '大雪', '暴雪'].any((snow) => dayWeather.contains(snow))) {
return const WeatherTip(
icon: Icons.ac_unit,
message: '今日有雪,路面湿滑请注意安全,做好保暖措施',
);
}
// 雾霾提示
if (dayWeather.contains('雾') || dayWeather.contains('霾') || ['雾', '浓雾', '霾', '中度霾', '重度霾'].any((fog) => dayWeather.contains(fog))) {
return const WeatherTip(
icon: Icons.blur_on,
message: '今日有雾霾,能见度较低,外出请佩戴口罩',
);
}
// 大风提示
if (dayWeather.contains('风') || ['大风', '强风', '疾风', '烈风'].any((wind) => dayWeather.contains(wind))) {
return const WeatherTip(
icon: Icons.air,
message: '今日风力较大,外出请注意安全,固定好物品',
);
}
// 晴天紫外线提示 (温度 >= 25°C)
if (['晴', '少云', '晴间多云'].any((sunny) => dayWeather.contains(sunny)) && dayTemp >= 25) {
return const WeatherTip(
icon: Icons.wb_sunny,
message: '今日阳光充足紫外线较强,外出请做好防晒',
);
}
// 温差大提示 (>= 10°C)
if ((dayTemp - nightTemp).abs() >= 10) {
return const WeatherTip(
icon: Icons.thermostat,
message: '今日昼夜温差较大,请适时增减衣物',
);
}
// 默认舒适天气提示
return const WeatherTip(
icon: Icons.wb_sunny_outlined,
message: '今日天气适宜,是外出活动的好时光',
);
}
/// 构建单日天气预报 /// 构建单日天气预报
Widget _buildForecastDay(String day, IconData icon, String temp) { Widget _buildForecastDay(String day, IconData icon, String temp) {
return Column( return Column(
@ -188,21 +281,21 @@ Widget _buildForecastDay(String day, IconData icon, String temp) {
Text( Text(
day, day,
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12.sp,
color: Colors.white.withOpacity(0.9), color: Colors.white.withValues(alpha: 0.9),
), ),
), ),
SizedBox(height: 4), SizedBox(height: 4.h),
Icon( Icon(
icon, icon,
size: 20, size: 20.sp,
color: Colors.white, color: Colors.white,
), ),
SizedBox(height: 4), SizedBox(height: 4.h),
Text( Text(
temp, temp,
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12.sp,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Colors.white, color: Colors.white,
), ),

Loading…
Cancel
Save