From 843e252940810d76a1b165161169e3a3ee83c1e6 Mon Sep 17 00:00:00 2001 From: tanlongsheng <252620078@qq.com> Date: Thu, 15 May 2025 14:22:57 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=BC=96=E8=BE=91?= =?UTF-8?q?=E5=8F=91=E8=A8=80=E8=80=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../views/speaker_all_bottom_sheet.dart | 353 ++++++++++++++++++ lib/modules/meeting/views/speech_tab.dart | 3 +- lib/modules/meeting/views/summary_tab.dart | 3 +- 3 files changed, 357 insertions(+), 2 deletions(-) create mode 100644 lib/modules/meeting/views/speaker_all_bottom_sheet.dart diff --git a/lib/modules/meeting/views/speaker_all_bottom_sheet.dart b/lib/modules/meeting/views/speaker_all_bottom_sheet.dart new file mode 100644 index 000000000..b2b8d553e --- /dev/null +++ b/lib/modules/meeting/views/speaker_all_bottom_sheet.dart @@ -0,0 +1,353 @@ +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; + +import '../controllers/meeting_details_controller.dart'; + +class SpeakerAllBottomSheet extends GetView { + const SpeakerAllBottomSheet({super.key}); + + @override + Widget build(BuildContext context) { + List dataList = _getDataList(); + + return Padding( + padding: EdgeInsets.only( + left: 12.w, + right: 12.w, + bottom: MediaQuery.of(context).viewInsets.bottom, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + padding: EdgeInsets.symmetric(vertical: 10.w), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + '命名发言者', + style: TextStyle( + fontSize: 16.sp, + color: Colors.black87, + fontWeight: FontWeight.bold, + ), + ), + GestureDetector( + onTap: () => Get.back(), + child: Container( + width: 26.w, + height: 26.w, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(26.r), + ), + child: Icon( + Icons.close, + size: 18.w, + color: Colors.grey[400], + ), + ), + ) + ], + ), + ), + Divider( + height: 1, + color: Colors.grey[300], + ), + Container( + constraints: BoxConstraints( + maxHeight: + 1.sh - 240.w - MediaQuery.of(context).viewInsets.bottom, + ), + child: ListView.builder( + itemCount: dataList.length, + shrinkWrap: true, + itemBuilder: (BuildContext context, int index) { + TextEditingController textController = TextEditingController(); + Map item = dataList[index]; + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + margin: EdgeInsets.only(top: 15.w), + alignment: Alignment.center, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12.r), + ), + child: TextField( + controller: textController, + style: TextStyle( + fontSize: 16.sp, + color: Colors.black87, + letterSpacing: 0, + height: 1.4, + ), + decoration: InputDecoration( + hintText: item['speaker'], + hintStyle: TextStyle( + fontSize: 16.sp, + color: Colors.grey[400], + letterSpacing: 0, + height: 1.4, + ), + isDense: true, + fillColor: Colors.transparent, + border: InputBorder.none, + contentPadding: EdgeInsets.symmetric( + horizontal: 10.w, + vertical: 12.w, + ), + ), + ), + ), + Padding( + padding: EdgeInsets.symmetric( + horizontal: 10.w, + vertical: 8.w, + ), + child: Row( + children: [ + Text( + '总计', + style: TextStyle( + fontSize: 12.sp, + color: Colors.grey, + ), + ), + 5.horizontalSpace, + Text( + '${item['totaltime'] / 1000}s', + style: TextStyle( + fontSize: 12.sp, + color: Colors.black87, + ), + ), + ], + ), + ), + ...List.generate( + item['list'].length, + (int idx) { + Map data = item['list'][idx]; + return Padding( + padding: EdgeInsets.symmetric(horizontal: 10.w), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Icon( + Icons.play_circle, + color: Colors.red[400], + size: 15.w, + ), + 2.horizontalSpace, + Text( + DateUtil.formatDateMs( + data['starttime'], + format: 'HH:mm:ss', + isUtc: true, + ), + style: TextStyle( + color: Colors.grey, + fontSize: 12.sp, + ), + ), + Padding( + padding: + EdgeInsets.symmetric(horizontal: 2.w), + child: Text( + '-', + style: TextStyle( + color: Colors.grey, + fontSize: 12.sp, + ), + ), + ), + Text( + DateUtil.formatDateMs( + data['endtime'], + format: 'HH:mm:ss', + isUtc: true, + ), + style: TextStyle( + color: Colors.grey, + fontSize: 12.sp, + ), + ), + 5.horizontalSpace, + Text( + '${(data['endtime'] - data['starttime']) / 1000}s', + style: TextStyle( + color: Colors.black54, + fontSize: 12.sp, + ), + ), + ], + ), + Padding( + padding: EdgeInsets.symmetric(vertical: 8.w), + child: Text( + data['content'], + overflow: TextOverflow.ellipsis, + maxLines: 2, + style: TextStyle( + color: Colors.grey[700], + fontSize: 12.sp, + ), + ), + ), + ], + ), + ); + }, + ), + if (item['isOmit']) + Padding( + padding: + EdgeInsets.only(left: 10.w, top: 5.w, bottom: 8.w), + child: Row( + children: List.generate( + 6, + (int idx) => Container( + width: 3.w, + height: 3.w, + margin: EdgeInsets.only(right: 3.w), + decoration: BoxDecoration( + color: Colors.grey[700], + borderRadius: BorderRadius.circular(3.r), + ), + ), + ), + ), + ), + Padding( + padding: EdgeInsets.only(top: 7.w), + child: _separator(), + ), + ], + ); + }, + ), + ), + Padding( + padding: EdgeInsets.symmetric(vertical: 5.w), + child: Text( + '总结的发言者将自动更新', + style: TextStyle( + fontSize: 14.sp, + color: Colors.grey[600], + ), + ), + ), + Padding( + padding: EdgeInsets.only(bottom: 20.w), + child: Row( + children: [ + Expanded( + child: GestureDetector( + onTap: () => Get.back(), + child: Container( + height: 48.w, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Colors.grey[300], + borderRadius: BorderRadius.circular(12.r), + ), + child: Text( + '取消', + style: TextStyle( + fontSize: 16.sp, + color: Colors.black, + ), + ), + ), + ), + ), + 10.horizontalSpace, + Expanded( + child: GestureDetector( + onTap: () {}, + child: Container( + height: 48.w, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Colors.black, + borderRadius: BorderRadius.circular(12.r), + ), + child: Text( + '确认', + style: TextStyle( + fontSize: 16.sp, + color: Colors.white, + ), + ), + ), + ), + ), + ], + ), + ), + ], + ), + ); + } + + Widget _separator() { + return LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + final boxWidth = constraints.constrainWidth(); + const dashWidth = 2.0; + const dashHeight = 1.0; + final dashCount = (boxWidth / (2 * dashWidth)).floor(); + return Flex( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + direction: Axis.horizontal, + children: List.generate(dashCount, (_) { + return SizedBox( + width: dashWidth, + height: dashHeight, + child: DecoratedBox( + decoration: BoxDecoration(color: Colors.grey[300]), + ), + ); + }), + ); + }, + ); + } + + List _getDataList() { + List textList = controller.textList; + List dataList = []; + for (var item in textList) { + Map? foundElement = dataList.firstWhere( + (element) => element['speaker'] == item['speaker'], + orElse: () => null, + ); + if (foundElement != null) { + int time = item['endtime'] - item['starttime']; + foundElement['totaltime'] = foundElement['totaltime'] + time; + if (!foundElement['isOmit']) { + if (foundElement['list'].length < 2) { + foundElement['list'].add(Map.from(item)); + } else { + foundElement['isOmit'] = true; + } + } + } else { + dataList.add({ + 'speaker': item['speaker'], + 'totaltime': item['endtime'] - item['starttime'], + 'isOmit': false, + 'list': [Map.from(item)], + }); + } + } + return dataList; + } +} diff --git a/lib/modules/meeting/views/speech_tab.dart b/lib/modules/meeting/views/speech_tab.dart index 8a586f27d..f7a4bb0f3 100644 --- a/lib/modules/meeting/views/speech_tab.dart +++ b/lib/modules/meeting/views/speech_tab.dart @@ -4,6 +4,7 @@ import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import '../controllers/meeting_details_controller.dart'; +import 'speaker_all_bottom_sheet.dart'; import 'speaker_bottom_sheet.dart'; class SpeechTab extends GetView { @@ -200,7 +201,7 @@ class SpeechTab extends GetView { ), ), builder: (BuildContext context) { - return Container(); + return const SpeakerAllBottomSheet(); }, ); }, diff --git a/lib/modules/meeting/views/summary_tab.dart b/lib/modules/meeting/views/summary_tab.dart index ed3a49437..d663ee748 100644 --- a/lib/modules/meeting/views/summary_tab.dart +++ b/lib/modules/meeting/views/summary_tab.dart @@ -5,6 +5,7 @@ import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import '../controllers/meeting_details_controller.dart'; +import 'speaker_all_bottom_sheet.dart'; class SummaryTab extends GetView { const SummaryTab({super.key}); @@ -168,7 +169,7 @@ class SummaryTab extends GetView { ), ), builder: (BuildContext context) { - return Container(); + return const SpeakerAllBottomSheet(); }, ); }, From 0c7dd8d1b21cdc4a1c552df9add64f3eb8d63678 Mon Sep 17 00:00:00 2001 From: tanlongsheng <252620078@qq.com> Date: Thu, 15 May 2025 18:12:42 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=BC=96=E8=BE=91?= =?UTF-8?q?=E5=8F=91=E8=A8=80=E8=80=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../views/speaker_all_bottom_sheet.dart | 244 ++++++++++++++---- .../meeting/views/speaker_bottom_sheet.dart | 1 - 2 files changed, 194 insertions(+), 51 deletions(-) diff --git a/lib/modules/meeting/views/speaker_all_bottom_sheet.dart b/lib/modules/meeting/views/speaker_all_bottom_sheet.dart index b2b8d553e..48b331c8f 100644 --- a/lib/modules/meeting/views/speaker_all_bottom_sheet.dart +++ b/lib/modules/meeting/views/speaker_all_bottom_sheet.dart @@ -1,17 +1,79 @@ import 'package:common_utils/common_utils.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; +import 'package:get_storage/get_storage.dart'; +import '../../../data/services/db/sqflite_api.dart'; import '../controllers/meeting_details_controller.dart'; -class SpeakerAllBottomSheet extends GetView { +class SpeakerAllBottomSheet extends StatefulWidget { const SpeakerAllBottomSheet({super.key}); @override - Widget build(BuildContext context) { - List dataList = _getDataList(); + State createState() => _SpeakerAllBottomSheetState(); +} + +class _SpeakerAllBottomSheetState extends State { + final _controller = Get.find(); + final GetStorage _storage = GetStorage(); + + List _dataList = []; + + List _historySpeakerList = []; + List _speakerList = []; + + @override + void initState() { + super.initState(); + _getSpeakerList(); + } + + void _getSpeakerList() { + _historySpeakerList = _storage.read("speaker_list") ?? []; + _speakerList = List.from(_historySpeakerList); + List textList = _controller.textList; + List dataList = []; + for (var item in textList) { + String speaker = item['speaker']; + Map? foundElement = dataList.firstWhere( + (element) => element['speaker'] == speaker, + orElse: () => null, + ); + if (foundElement != null) { + int time = item['endtime'] - item['starttime']; + foundElement['totaltime'] = foundElement['totaltime'] + time; + if (!foundElement['isOmit']) { + if (foundElement['list'].length < 2) { + foundElement['list'].add(Map.from(item)); + } else { + foundElement['isOmit'] = true; + } + } + } else { + dataList.add({ + 'speaker': speaker, + 'speakerText': TextEditingController(), + 'isShow': false, + 'totaltime': item['endtime'] - item['starttime'], + 'isOmit': false, + 'list': [Map.from(item)], + }); + } + if (speaker.isNotEmpty && + !RegExp(r'^Speaker \d+$').hasMatch(speaker) && + !_speakerList.contains(speaker)) { + _speakerList.add(speaker); + } + } + setState(() { + _dataList = dataList; + }); + } + @override + Widget build(BuildContext context) { return Padding( padding: EdgeInsets.only( left: 12.w, @@ -63,11 +125,10 @@ class SpeakerAllBottomSheet extends GetView { 1.sh - 240.w - MediaQuery.of(context).viewInsets.bottom, ), child: ListView.builder( - itemCount: dataList.length, + itemCount: _dataList.length, shrinkWrap: true, itemBuilder: (BuildContext context, int index) { - TextEditingController textController = TextEditingController(); - Map item = dataList[index]; + Map item = _dataList[index]; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -76,34 +137,107 @@ class SpeakerAllBottomSheet extends GetView { alignment: Alignment.center, decoration: BoxDecoration( color: Colors.white, - borderRadius: BorderRadius.circular(12.r), + borderRadius: item['isShow'] && _speakerList.isNotEmpty + ? BorderRadius.vertical( + top: Radius.circular(12.r), + ) + : BorderRadius.circular(12.r), ), - child: TextField( - controller: textController, - style: TextStyle( - fontSize: 16.sp, - color: Colors.black87, - letterSpacing: 0, - height: 1.4, - ), - decoration: InputDecoration( - hintText: item['speaker'], - hintStyle: TextStyle( + child: Focus( + onFocusChange: (bool hasFocus) { + item['isShow'] = hasFocus; + }, + child: TextField( + controller: item['speakerText'], + style: TextStyle( fontSize: 16.sp, - color: Colors.grey[400], + color: Colors.black87, letterSpacing: 0, height: 1.4, ), - isDense: true, - fillColor: Colors.transparent, - border: InputBorder.none, - contentPadding: EdgeInsets.symmetric( - horizontal: 10.w, - vertical: 12.w, + decoration: InputDecoration( + hintText: item['speaker'], + hintStyle: TextStyle( + fontSize: 16.sp, + color: Colors.grey[400], + letterSpacing: 0, + height: 1.4, + ), + isDense: true, + fillColor: Colors.transparent, + border: InputBorder.none, + contentPadding: EdgeInsets.symmetric( + horizontal: 10.w, + vertical: 12.w, + ), ), ), ), ), + if (item['isShow'] && _speakerList.isNotEmpty) + Container( + padding: EdgeInsets.only(left: 10.w), + clipBehavior: Clip.hardEdge, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.vertical( + bottom: Radius.circular(12.r), + ), + border: Border( + top: BorderSide( + width: 1, + color: Colors.grey[300]!, + ), + ), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.only(top: 10.w, bottom: 5.w), + child: Text( + '最近使用过的名称', + style: TextStyle( + fontSize: 12.sp, + color: Colors.grey[600]!, + ), + ), + ), + Container( + constraints: BoxConstraints( + maxHeight: 150.h, + ), + child: ListView.builder( + itemCount: _speakerList.length, + shrinkWrap: true, + itemBuilder: (BuildContext context, int idx) { + return GestureDetector( + onTap: () { + item['speakerText'].text = + _speakerList[idx]; + FocusScope.of(context).unfocus(); + }, + behavior: HitTestBehavior.translucent, + child: SizedBox( + height: 42.w, + child: Align( + alignment: Alignment.centerLeft, + child: Text( + _speakerList[idx], + style: TextStyle( + fontSize: 14.sp, + color: Colors.black87, + ), + ), + ), + ), + ); + }, + ), + ), + ], + ), + ), Padding( padding: EdgeInsets.symmetric( horizontal: 10.w, @@ -271,7 +405,7 @@ class SpeakerAllBottomSheet extends GetView { 10.horizontalSpace, Expanded( child: GestureDetector( - onTap: () {}, + onTap: _save, child: Container( height: 48.w, alignment: Alignment.center, @@ -321,33 +455,43 @@ class SpeakerAllBottomSheet extends GetView { ); } - List _getDataList() { - List textList = controller.textList; - List dataList = []; - for (var item in textList) { - Map? foundElement = dataList.firstWhere( - (element) => element['speaker'] == item['speaker'], - orElse: () => null, - ); - if (foundElement != null) { - int time = item['endtime'] - item['starttime']; - foundElement['totaltime'] = foundElement['totaltime'] + time; - if (!foundElement['isOmit']) { - if (foundElement['list'].length < 2) { - foundElement['list'].add(Map.from(item)); - } else { - foundElement['isOmit'] = true; + void _save() async { + EasyLoading.show(); + List textList = _controller.textList; + List newTextList = []; + List editSpeakerList = []; + String personnel = ''; + for (var element in textList) { + final dataMap = Map.from(element); + for (var data in _dataList) { + String speaker = data['speakerText'].text; + if (speaker.isNotEmpty && speaker != data['speaker']) { + if (dataMap['speaker'] == data['speaker']) { + dataMap['speaker'] = speaker; + editSpeakerList.add({ + 'id': dataMap['id'], + 'speaker': dataMap['speaker'], + }); + } + if (!RegExp(r'^Speaker \d+$').hasMatch(speaker) && + !_historySpeakerList.contains(speaker)) { + _historySpeakerList.insert(0, speaker); } } - } else { - dataList.add({ - 'speaker': item['speaker'], - 'totaltime': item['endtime'] - item['starttime'], - 'isOmit': false, - 'list': [Map.from(item)], - }); } + if (!personnel.contains(dataMap['speaker'])) { + personnel += '[${dataMap['speaker']}] '; + } + newTextList.add(dataMap); + } + var result = await SqfliteApi.editMeetingSpeaker(editSpeakerList); + if (result != null) { + _controller.textList.value = newTextList; + SqfliteApi.editMeeting(_controller.id, {'personnel': personnel}); + _controller.meetingDetails.value.personnel = personnel; + _storage.write("speaker_list", _historySpeakerList); + Get.back(); } - return dataList; + EasyLoading.dismiss(); } } diff --git a/lib/modules/meeting/views/speaker_bottom_sheet.dart b/lib/modules/meeting/views/speaker_bottom_sheet.dart index 4d51927f6..3bc629643 100644 --- a/lib/modules/meeting/views/speaker_bottom_sheet.dart +++ b/lib/modules/meeting/views/speaker_bottom_sheet.dart @@ -171,7 +171,6 @@ class _SpeakerBottomSheetState extends State { }, behavior: HitTestBehavior.translucent, child: SizedBox( - width: 200.w, height: 42.w, child: Align( alignment: Alignment.centerLeft, From 35abbbdbc5ca1d92bdedb496df30ed9d8425c83b Mon Sep 17 00:00:00 2001 From: lxm <1274844347@qq.com> Date: Fri, 16 May 2025 00:53:40 +0800 Subject: [PATCH 3/4] =?UTF-8?q?feat(=E4=B8=BB=E9=A2=98=E9=80=82=E9=85=8D):?= =?UTF-8?q?=20=E6=B7=BB=E5=8A=A0=E6=9A=97=E9=BB=91=E6=A8=A1=E5=BC=8F?= =?UTF-8?q?=E6=94=AF=E6=8C=81=EF=BC=8C=E8=B0=83=E6=95=B4UI=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E9=A2=9C=E8=89=B2=E4=BB=A5=E9=80=82=E9=85=8D=E4=B8=8D?= =?UTF-8?q?=E5=90=8C=E4=B8=BB=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 本次提交主要针对UI组件进行了颜色调整,使其能够根据系统主题自动切换颜色。具体修改包括按钮、背景、文本、边框等组件的颜色适配,确保在暗黑模式下也能有良好的视觉效果。这一改进提升了用户体验,并增强了应用的视觉一致性。 --- lib/modules/agent/views/agent_view.dart | 32 ++++++--- lib/modules/agent/views/message_bubble.dart | 78 +++++++++++++++------ 2 files changed, 80 insertions(+), 30 deletions(-) diff --git a/lib/modules/agent/views/agent_view.dart b/lib/modules/agent/views/agent_view.dart index f4bed8cc6..9d9aec1d7 100644 --- a/lib/modules/agent/views/agent_view.dart +++ b/lib/modules/agent/views/agent_view.dart @@ -290,12 +290,16 @@ class AgentView extends StatelessWidget { width: 44, height: 44, decoration: BoxDecoration( - color: Colors.grey[200], + color: isDarkMode + ? Colors.grey[800] + : Colors.grey[200], borderRadius: BorderRadius.circular(22), ), child: Icon( isTextMode ? Icons.mic_none : Icons.keyboard, - color: Colors.grey[700], + color: isDarkMode + ? Colors.grey[300] + : Colors.grey[700], size: 22, ), ), @@ -315,10 +319,15 @@ class AgentView extends StatelessWidget { //height: 44, padding: const EdgeInsets.symmetric(horizontal: 16), decoration: BoxDecoration( - color: Colors.grey[200], + color: isDarkMode + ? Colors.grey[800] + : Colors.grey[200], borderRadius: BorderRadius.circular(22), border: Border.all( - color: Colors.grey.withOpacity(0.1), + color: isDarkMode + ? Colors.grey[ + 800]! // 修改: 从 Colors.grey[700] 改为 Colors.grey[800] + : Colors.grey.withOpacity(0.1), width: 1.0, ), ), @@ -338,7 +347,7 @@ class AgentView extends StatelessWidget { fontSize: 15, color: isDarkMode ? Colors.white - : Colors.black87, + : Colors.grey[800], ), decoration: InputDecoration( hintText: isImageActive @@ -386,10 +395,14 @@ class AgentView extends StatelessWidget { padding: const EdgeInsets.symmetric(horizontal: 16), decoration: BoxDecoration( - color: Colors.grey[200], + color: isDarkMode + ? Colors.grey[800] + : Colors.grey[200], borderRadius: BorderRadius.circular(22), border: Border.all( - color: Colors.grey.withOpacity(0.1), + color: isDarkMode + ? Colors.grey[800]! + : Colors.grey.withOpacity(0.1), width: 1.0, ), ), @@ -450,13 +463,14 @@ class AgentView extends StatelessWidget { width: 44, height: 44, decoration: BoxDecoration( - color: Colors.grey[200], + color: isDarkMode ? Colors.grey[800] : Colors.grey[200], borderRadius: BorderRadius.circular(22), ), child: PopupMenuButton( icon: Icon( Icons.add_photo_alternate_outlined, - color: Colors.grey[700], + color: + isDarkMode ? Colors.grey[300] : Colors.grey[700], size: 22, ), padding: EdgeInsets.zero, diff --git a/lib/modules/agent/views/message_bubble.dart b/lib/modules/agent/views/message_bubble.dart index cfc505157..a90eefba7 100644 --- a/lib/modules/agent/views/message_bubble.dart +++ b/lib/modules/agent/views/message_bubble.dart @@ -87,7 +87,9 @@ class MessageBubble extends GetView { timeFormat.format(timestamp), style: TextStyle( fontSize: 10, - color: Colors.grey[500], + color: Theme.of(context).brightness == Brightness.dark + ? Colors.grey[400] + : Colors.grey[500], fontWeight: FontWeight.w400, ), ), @@ -103,12 +105,16 @@ class MessageBubble extends GetView { /// 获取气泡颜色 Color _getBubbleColor(BuildContext context) { + final isDarkMode = Theme.of(context).brightness == Brightness.dark; + if (isUser) { return isRecognizing ? Color(0xFF3B82F6).withOpacity(0.8) // 识别中的用户消息使用半透明的蓝色 : Color(0xFF3B82F6); // 使用更明亮的蓝色 } else { - return Color(0xFFF1F5F9); // 更淡的灰色背景 + return isDarkMode + ? Color(0xFF2A2A2A) + : Color(0xFFF1F5F9); // 根据主题调整AI消息背景色 } } @@ -285,7 +291,11 @@ class MessageBubble extends GetView { return Text( message, style: TextStyle( - color: isUser ? Colors.white : Colors.black87, + color: isUser + ? Colors.white + : (Theme.of(context).brightness == Brightness.dark + ? Colors.white.withOpacity(0.9) + : Colors.black87), fontSize: 14, height: 1.4, fontWeight: FontWeight.w400, @@ -317,13 +327,15 @@ class MessageBubble extends GetView { /// 构建音乐内容卡片 Widget _buildMusicContent( BuildContext context, List> playlist) { + final isDarkMode = Theme.of(context).brightness == Brightness.dark; + return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text( + Text( '以下是一些推荐的音乐:', style: TextStyle( - color: Colors.black87, + color: isDarkMode ? Colors.white.withOpacity(0.9) : Colors.black87, fontSize: 14, height: 1.4, fontWeight: FontWeight.w400, @@ -361,7 +373,9 @@ class MessageBubble extends GetView { style: TextStyle( fontSize: 13, fontWeight: FontWeight.w600, - color: Colors.grey[700], + color: Theme.of(context).brightness == Brightness.dark + ? Colors.grey[300] + : Colors.grey[700], ), ), ], @@ -381,7 +395,13 @@ class MessageBubble extends GetView { children: [ _buildMusicItem(context, id, name, url, singer, image), if (index != playlist.length - 1) - Divider(height: 1, thickness: 1, color: Colors.grey[100]), + Divider( + height: 1, + thickness: 1, + color: Theme.of(context).brightness == Brightness.dark + ? Colors.grey[800] + : Colors.grey[100], + ), ], ); }).toList(), @@ -580,6 +600,8 @@ class MessageBubble extends GetView { Widget _buildMusicItem(BuildContext context, String id, String name, String url, String singer, String image) { final controller = Get.find(); // 获取控制器 + final isDarkMode = Theme.of(context).brightness == Brightness.dark; + Map song = { 'id': id, 'url': url, @@ -591,11 +613,11 @@ class MessageBubble extends GetView { return Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( - color: Colors.white, + color: isDarkMode ? Color(0xFF1E1E1E) : Colors.white, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( - color: Colors.black.withOpacity(0.03), + color: Colors.black.withOpacity(isDarkMode ? 0.2 : 0.03), blurRadius: 3, spreadRadius: 1, offset: const Offset(0, 1), @@ -691,6 +713,8 @@ class MessageBubble extends GetView { /// 构建地点项目 Widget _buildLocationItem( String name, String description, BuildContext context) { + final isDarkMode = Theme.of(context).brightness == Brightness.dark; + return Padding( padding: const EdgeInsets.symmetric(vertical: 8), child: Row( @@ -699,7 +723,7 @@ class MessageBubble extends GetView { width: 38, height: 38, decoration: BoxDecoration( - color: Colors.blue[50], + color: isDarkMode ? Color(0xFF1A365D) : Colors.blue[50], borderRadius: BorderRadius.circular(8), ), child: Icon( @@ -718,7 +742,9 @@ class MessageBubble extends GetView { style: TextStyle( fontSize: 13, fontWeight: FontWeight.w500, - color: Colors.grey[800], + color: isDarkMode + ? Colors.white.withOpacity(0.9) + : Colors.grey[800], ), overflow: TextOverflow.ellipsis, ), @@ -727,7 +753,7 @@ class MessageBubble extends GetView { description, style: TextStyle( fontSize: 12, - color: Colors.grey[600], + color: isDarkMode ? Colors.grey[400] : Colors.grey[600], ), overflow: TextOverflow.ellipsis, ), @@ -749,13 +775,15 @@ class MessageBubble extends GetView { /// 构建天气内容卡片 Widget _buildWeatherContent(BuildContext context, String city, Map now, List> days) { + final isDarkMode = Theme.of(context).brightness == Brightness.dark; + return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '查询天气情况:', style: TextStyle( - color: Colors.black87, + color: isDarkMode ? Colors.white.withOpacity(0.9) : Colors.black87, fontSize: 14, height: 1.4, fontWeight: FontWeight.w400, @@ -765,15 +793,21 @@ class MessageBubble extends GetView { Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [Color(0xFF60A5FA), Color(0xFF3B82F6)], - ), + gradient: isDarkMode + ? LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [Color(0xFF1E40AF), Color(0xFF1E3A8A)], + ) + : LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [Color(0xFF60A5FA), Color(0xFF3B82F6)], + ), borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( - color: Colors.black.withOpacity(0.1), + color: Colors.black.withOpacity(isDarkMode ? 0.3 : 0.1), blurRadius: 8, offset: const Offset(0, 2), ), @@ -850,7 +884,7 @@ class MessageBubble extends GetView { SizedBox(height: 16), Container( height: 1, - color: Colors.white.withOpacity(0.2), + color: Colors.white.withOpacity(isDarkMode ? 0.15 : 0.2), ), SizedBox(height: 16), const Text( @@ -896,7 +930,9 @@ class MessageBubble extends GetView { Container( padding: EdgeInsets.symmetric(vertical: 8, horizontal: 12), decoration: BoxDecoration( - color: Colors.white.withOpacity(0.2), + color: isDarkMode + ? Colors.white.withOpacity(0.15) + : Colors.white.withOpacity(0.2), borderRadius: BorderRadius.circular(8), ), child: const Row( From 8bbf8e89bad58ee8acfb133263817dbf399afc2d Mon Sep 17 00:00:00 2001 From: lxm <1274844347@qq.com> Date: Fri, 16 May 2025 10:57:41 +0800 Subject: [PATCH 4/4] =?UTF-8?q?fix:=20=E4=BF=AE=E6=AD=A3=E5=8F=98=E9=87=8F?= =?UTF-8?q?=E5=90=8D=E6=8B=BC=E5=86=99=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将 `mate` 修正为 `meta`,确保代码逻辑正确执行 --- lib/modules/agent/views/message_bubble.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/modules/agent/views/message_bubble.dart b/lib/modules/agent/views/message_bubble.dart index 637b5199a..ba2d33ff8 100644 --- a/lib/modules/agent/views/message_bubble.dart +++ b/lib/modules/agent/views/message_bubble.dart @@ -275,8 +275,8 @@ class MessageBubble extends GetView { now, daylist, ); - } else if (mate!.keys.contains('card_travel')) { - final rawList = mate!['card_travel']['items'] as List; + } else if (meta!.keys.contains('card_travel')) { + final rawList = meta!['card_travel']['items'] as List; final travellist = rawList.map((e) => Map.from(e)).toList(); // 旅游