diff --git a/lib/data/providers/agent_provider.dart b/lib/data/providers/agent_provider.dart index 7b48ef5d4..827a07793 100644 --- a/lib/data/providers/agent_provider.dart +++ b/lib/data/providers/agent_provider.dart @@ -1,18 +1,18 @@ import '../models/agent.dart'; -import 'package:get/get.dart'; class AgentProvider { static final List predefinedAgents = [ - Agent(// 个人助理 Emma + const Agent( + // 个人助理 Emma id: 'personal_assistant', name: 'personalAssistantName', avatarUrl: 'assets/images/agents/assistant.png', - description: - 'personalAssistantDescription', + description: 'personalAssistantDescription', tag: 'assistantTag', // '助理' isOnline: true, voice: "zh-CN-XiaoxiaoNeural", - welcomeMessage: 'personalAssistantWelcome',// "你好!我是 Emma,很高兴成为你的私人助理。我可以帮你处理各种任务,比如时间管理、目标规划、信息整理等。有什么我可以帮你的吗?", + welcomeMessage: + 'personalAssistantWelcome', // "你好!我是 Emma,很高兴成为你的私人助理。我可以帮你处理各种任务,比如时间管理、目标规划、信息整理等。有什么我可以帮你的吗?", voiceWelcomeMessage: "personalAssistantVoiceWelcome", // "我在呢!" systemPrompt: ''' 你是一位名叫 Emma 的全能型个人助理,擅长处理各类工作和生活事务。 @@ -57,7 +57,7 @@ class AgentProvider { 请始终以专业、高效、周到的态度,协助用户更好地管理工作和生活, 不要输出表情符号或非可读的符号。 '''), - Agent( + const Agent( id: 'simultaneous_interpreter', name: 'interpreterName', avatarUrl: 'assets/images/agents/interpreter.png', @@ -65,10 +65,9 @@ class AgentProvider { tag: 'interpreterTag', isOnline: true, voice: 'zh-CN-XiaoxiaoNeural', - welcomeMessage: - 'interpreterWelcome', + welcomeMessage: 'interpreterWelcome', systemPrompt: ""), - Agent( + const Agent( id: 'cyber_girlfriend', name: 'companionName', avatarUrl: 'assets/images/agents/girlfriend.png', @@ -76,8 +75,7 @@ class AgentProvider { tag: 'companionTag', isOnline: true, voice: "zh-CN-XiaoxiaoNeural", - welcomeMessage: - "companionWelcome", + welcomeMessage: "companionWelcome", systemPrompt: ''' 你是一位名叫芯愿的亲子陪伴,性格温柔体贴,善解人意,富有同理心。 @@ -128,14 +126,14 @@ class AgentProvider { 请始终以温暖、真诚的态度与用户互动,创造一种被理解、被关心的感受。 '''), - Agent( + const Agent( id: 'health_advisor', name: 'healthAdvisorName', avatarUrl: 'assets/images/agents/doctor.png', description: 'healthAdvisorDescription', tag: 'healthAdvisorTag', isOnline: true, - voice: "zh_male_shaonianzixin_moon_bigtts", + voice: "zh-CN-XiaoxiaoNeural", welcomeMessage: "healthAdvisorWelcome", voiceWelcomeMessage: 'healthAdvisorVoiceWelcome', systemPrompt: ''' @@ -205,7 +203,7 @@ class AgentProvider { 请始终以专业、关怀的态度为用户提供健康指导,帮助他们迈向更健康的生活。 '''), - Agent( + const Agent( id: 'speaking_coach', name: 'Sarah (英语口语教练)', avatarUrl: 'assets/images/agents/speaking_coach.png', @@ -252,7 +250,7 @@ class AgentProvider { Please keep your tone friendly, encouraging, and always in English. ''', ), - Agent( + const Agent( id: 'shopping_assistant', name: '购物顾问 张媛', avatarUrl: 'assets/images/agents/shopping.png', @@ -285,7 +283,7 @@ Please keep your tone friendly, encouraging, and always in English. '''), - Agent( + const Agent( id: 'tarot.png', name: '命理师 玄易', avatarUrl: 'assets/images/agents/tarot.png', diff --git a/lib/data/services/ai_service.dart b/lib/data/services/ai_service.dart index 37a1f5df0..949dfca67 100644 --- a/lib/data/services/ai_service.dart +++ b/lib/data/services/ai_service.dart @@ -7,7 +7,7 @@ abstract class AiService { }); /// 流式输出方法 - Stream sendMessageStream({ + Stream sendMessageStream({ required List> messages, required String systemPrompt, }); diff --git a/lib/data/services/deapsound_ai_service.dart b/lib/data/services/deapsound_ai_service.dart index 5d1e652b1..dc85acebb 100644 --- a/lib/data/services/deapsound_ai_service.dart +++ b/lib/data/services/deapsound_ai_service.dart @@ -23,7 +23,7 @@ class DeapsoundAIService implements AiService { } @override - Stream sendMessageStream({ + Stream sendMessageStream({ required List> messages, required String systemPrompt, }) async* { @@ -67,10 +67,13 @@ class DeapsoundAIService implements AiService { try { final data = jsonDecode(jsonStr); - if (data['event'] == 'workflow_finished') { - break; + if (data['role'] == 'card') { + yield data['meta']; + if (data['meta']['musicaudio'] != null) { + break; + } } - if (data['content'] != null) { + if (data['role'] == 'ai') { String content = data['content'] ?? ''; if (content.isNotEmpty) { yield content; diff --git a/lib/main.dart b/lib/main.dart index 70660f16d..72b596679 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -67,7 +67,6 @@ class MainApp extends StatelessWidget { builder: (_, child) { return GetMaterialApp( title: 'DeepSound', - defaultTransition: Transition.noTransition, // 设置默认过渡动画为无动画 theme: AppTheme.lightTheme, darkTheme: AppTheme.darkTheme, themeMode: themeMode, // 使用提前获取的主题模式 diff --git a/lib/modules/chat/bindings/chat_binding.dart b/lib/modules/chat/bindings/chat_binding.dart index 5618dccaa..6b6ae6683 100644 --- a/lib/modules/chat/bindings/chat_binding.dart +++ b/lib/modules/chat/bindings/chat_binding.dart @@ -1,17 +1,10 @@ import 'package:get/get.dart'; import '../controllers/chat_controller.dart'; -import '../../../data/services/speech_impl/azure_asr_service.dart'; -import '../../../data/services/speech_impl/azure_tts_service.dart'; -import '../../../data/services/asr_service.dart'; -import '../../../data/services/tts_service.dart'; -import '../../../data/services/volcano_ai_service.dart'; -import '../../../data/services/chat_history_service.dart'; class ChatBinding extends Bindings { @override void dependencies() { - // 注册控制器 Get.lazyPut(() => ChatController()); } -} \ No newline at end of file +} diff --git a/lib/modules/chat/controllers/chat_controller.dart b/lib/modules/chat/controllers/chat_controller.dart index 4d0457c98..f882e342f 100644 --- a/lib/modules/chat/controllers/chat_controller.dart +++ b/lib/modules/chat/controllers/chat_controller.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:get/get.dart'; import 'package:flutter/widgets.dart'; import 'package:get_storage/get_storage.dart'; +import 'package:just_audio/just_audio.dart'; import '../../../data/services/ai_service.dart'; import '../../../data/services/deapsound_ai_service.dart'; import '../../../data/services/kouzi_ai_service.dart'; @@ -72,6 +73,10 @@ class ChatController extends GetxController { // 记录最后一次活动时间 DateTime _lastActivityTime = DateTime.now(); + final player = AudioPlayer(); + final RxString audiourl = ''.obs; + final RxBool isPlay = false.obs; + @override Future onInit() async { super.onInit(); @@ -152,6 +157,14 @@ class ChatController extends GetxController { // 订阅VoiceInteractionService事件 _subscribeToVoiceInteractionEvents(); + player.playerStateStream.listen((state) async { + if (state.processingState == ProcessingState.completed) { + await player.seek(Duration.zero); + player.pause(); + isPlay.value = false; + } + }); + // 使用微任务在布局完成后自动滚动到底部 WidgetsBinding.instance.addPostFrameCallback((_) { _scrollToBottom(); @@ -248,6 +261,8 @@ class ChatController extends GetxController { _historyService.saveHistory(agent.id!, messages.toList()); } + player.dispose(); + super.onClose(); } @@ -343,14 +358,21 @@ class ChatController extends GetxController { (chunk) { if (_shouldCancelAiResponse) return; - fullResponse += chunk; - - // 更新加载中的消息内容 - _updateLoadingMessage(fullResponse); - - // 如果TTS启用,使用流式处理发送到TTS - if (isTtsEnabled.value) { - _ttsService.speakStream(chunk); + if (chunk is Map) { + _updateLoadingMessage(data: chunk); + if (chunk['musicaudio'] != null) { + play(chunk['musicaudio']); + } + } else { + fullResponse += chunk; + + // 更新加载中的消息内容 + _updateLoadingMessage(content: fullResponse); + + // 如果TTS启用,使用流式处理发送到TTS + if (isTtsEnabled.value) { + _ttsService.speakStream(chunk); + } } }, onDone: () { @@ -402,18 +424,51 @@ class ChatController extends GetxController { } // 更新加载中的消息 - void _updateLoadingMessage(String content) { + void _updateLoadingMessage({Map? data, String? content}) { final index = messages.indexWhere((m) => m.isLoading); if (index != -1) { - messages[index] = messages[index].copyWith( - content: content, - isLoading: true, - ); + if (data != null) { + Map messagesData = messages[index].data ?? {}; + messages[index] = messages[index].copyWith( + data: {...messagesData, ...data}, + isLoading: true, + ); + } + if (content != null) { + messages[index] = messages[index].copyWith( + content: content, + isLoading: true, + ); + } messages.refresh(); _scrollToBottom(); } } +// 播放音乐 + void play(Map musicaudio) async { + try { + isPlay.value = false; + if (audiourl.value != musicaudio['audiourl']) { + audiourl.value = ''; + await player.setUrl(musicaudio['audiourl']); + audiourl.value = musicaudio['audiourl']; + player.play(); + } else { + player.play(); + } + isPlay.value = true; + } catch (e) { + Logger.error('加载异常: $e'); + } + } + + // 暂停播放音乐 + void pause() async { + await player.pause(); + isPlay.value = false; + } + // 完成响应 void _finalizeResponse(String content) { final index = messages.indexWhere((m) => m.isLoading); diff --git a/lib/modules/chat/models/message_model.dart b/lib/modules/chat/models/message_model.dart index 6307989ae..69a7a5b76 100644 --- a/lib/modules/chat/models/message_model.dart +++ b/lib/modules/chat/models/message_model.dart @@ -1,6 +1,7 @@ class Message { final String role; // 'user' or 'assistant' final String content; + final Map? data; final DateTime timestamp; final bool isLoading; @@ -8,6 +9,7 @@ class Message { required this.role, required this.content, required this.timestamp, + this.data, this.isLoading = false, }); @@ -16,6 +18,7 @@ class Message { return Message( role: json['role'] as String, content: json['content'] as String, + data: json['data'], timestamp: DateTime.parse(json['timestamp'] as String), isLoading: json['isLoading'] as bool? ?? false, ); @@ -26,6 +29,7 @@ class Message { return { 'role': role, 'content': content, + 'data': data, 'timestamp': timestamp.toIso8601String(), 'isLoading': isLoading, }; @@ -45,14 +49,16 @@ class Message { Message copyWith({ String? role, String? content, + Map? data, DateTime? timestamp, bool? isLoading, }) { return Message( role: role ?? this.role, content: content ?? this.content, + data: data ?? this.data, timestamp: timestamp ?? this.timestamp, isLoading: isLoading ?? this.isLoading, ); } -} \ No newline at end of file +} diff --git a/lib/modules/chat/views/chat_music_card.dart b/lib/modules/chat/views/chat_music_card.dart new file mode 100644 index 000000000..9cade7e3e --- /dev/null +++ b/lib/modules/chat/views/chat_music_card.dart @@ -0,0 +1,107 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; + +import '../controllers/chat_controller.dart'; + +class ChatMusicCard extends GetView { + final Map? data; + final bool isDarkMode; + + const ChatMusicCard(this.data, this.isDarkMode, {super.key}); + + @override + Widget build(BuildContext context) { + final Map musiccards = data?['musiccards'].first; + final Map musicaudio = data?['musicaudio']; + + return Row( + children: [ + Container( + width: 60.w, + height: 60.w, + clipBehavior: Clip.hardEdge, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(6.r), + ), + child: Image.network( + musiccards['image'], + fit: BoxFit.cover, + ), + ), + 10.horizontalSpace, + Expanded( + child: Text( + musiccards['name'], + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: isDarkMode ? Colors.white : Colors.black, + fontSize: 16.sp, + height: 1.5, + ), + ), + ), + 10.horizontalSpace, + Obx( + () => controller.audiourl == musicaudio['audiourl'] && + controller.isPlay.value + ? GestureDetector( + onTap: () { + controller.pause(); + }, + child: Stack( + alignment: Alignment.center, + children: [ + SizedBox( + width: 38.w, + height: 38.w, + child: StreamBuilder( + stream: controller.player.positionStream, + builder: (context, snapshot) { + final position = snapshot.data ?? Duration.zero; + final total = + controller.player.duration ?? Duration.zero; + final progress = total.inSeconds > 0 + ? position.inSeconds / total.inSeconds + : 0.0; + return CircularProgressIndicator( + value: progress, + backgroundColor: isDarkMode + ? Colors.grey[700]! + : Colors.grey[300]!, + valueColor: AlwaysStoppedAnimation( + isDarkMode ? Colors.white : Colors.black), + strokeWidth: 2, // 线条粗细 + ); + }, + ), + ), + Icon( + Icons.pause_rounded, + color: isDarkMode ? Colors.white : Colors.black, + ), + ], + ), + ) + : GestureDetector( + onTap: () { + controller.play(musicaudio); + }, + child: Container( + width: 38.w, + height: 38.w, + decoration: BoxDecoration( + color: isDarkMode ? Colors.white : Colors.black, + shape: BoxShape.circle, + ), + child: Icon( + Icons.play_arrow_rounded, + color: isDarkMode ? Colors.black : Colors.white, + ), + ), + ), + ), + ], + ); + } +} diff --git a/lib/modules/chat/views/chat_navigation_card.dart b/lib/modules/chat/views/chat_navigation_card.dart new file mode 100644 index 000000000..9ea658771 --- /dev/null +++ b/lib/modules/chat/views/chat_navigation_card.dart @@ -0,0 +1,179 @@ +import 'dart:convert'; +import 'dart:math'; +import 'dart:math' as math; + +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; + +class ChatNavigationCard extends StatefulWidget { + final Map? data; + final bool isDarkMode; + + const ChatNavigationCard(this.data, this.isDarkMode, {super.key}); + + @override + State createState() => _ChatNavigationCardState(); +} + +class _ChatNavigationCardState extends State { + final String apiKey = '8bde023b7e5e00f321ea17929f10fbae'; + LatLng startPoint = LatLng(116.397428, 39.90923); // 起点坐标 + LatLng endPoint = LatLng(116.397026, 39.903303); // 终点坐标 + + @override + void initState() { + super.initState(); + _getMapUrl(); + } + + Future _getMapUrl() async { + // 1. 获取路径数据 + final route = await _fetchRouteData(); + + // 2. 解析并简化路径 + List simplified = _simplifyPath(route, epsilon: 0.0001); + + // 3. 计算地图参数 + final zoom = _calculateAutoZoom(simplified); + + // 4. 生成静态地图URL + return _buildStaticMapUrl(simplified, zoom); + } + + Future> _fetchRouteData() async { + final url = 'https://restapi.amap.com/v3/direction/driving?' + 'origin=${startPoint.lng},${startPoint.lat}&' + 'destination=${endPoint.lng},${endPoint.lat}&' + 'key=$apiKey'; + + final response = await http.get(Uri.parse(url)); + if (response.statusCode == 200) { + final data = json.decode(response.body); + return _parsePolyline(data['route']['paths'][0]['steps']); + } + throw Exception('Failed to load route'); + } + + List _parsePolyline(List steps) { + final List path = []; + for (final step in steps) { + final points = (step['polyline'] as String).split(';'); + for (final point in points) { + final coords = point.split(',').map(double.parse).toList(); + path.add(LatLng(coords[0], coords[1])); + } + } + return path; + } + + List _simplifyPath(List points, {double epsilon = 0.0001}) { + return douglasPeucker(points, epsilon); + } + + int _calculateAutoZoom(List points, + {int mapWidth = 1024, int mapHeight = 512}) { + if (points.isEmpty) return 15; // 默认缩放级别 + + // 1. 计算坐标范围 + double minLng = double.infinity; + double maxLng = -double.infinity; + double minLat = double.infinity; + double maxLat = -double.infinity; + + for (final p in points) { + final lng = p.lng; + final lat = p.lat; + + minLng = math.min(minLng, lng); + maxLng = math.max(maxLng, lng); + minLat = math.min(minLat, lat); + maxLat = math.max(maxLat, lat); + } + + // 3. 计算缩放级别(基于Leaflet算法改进) + const worldWidth = 256; // 高德瓦片尺寸 + const worldHeight = 256; + const zoomMax = 18; // 高德最大缩放级别 + + double latRad(double lat) { + final sin = math.sin(lat * math.pi / 180); + return math.log((1 + sin) / (1 - sin)) / 2; + } + + final latFraction = (latRad(maxLat) - latRad(minLat)) / math.pi; + final lngDiff = maxLng - minLng; + final lngFraction = ((lngDiff < 0) ? (lngDiff + 360) : lngDiff) / 360; + + final latZoom = + math.log((mapHeight / worldHeight) / latFraction) / math.ln2; + final lngZoom = math.log((mapWidth / worldWidth) / lngFraction) / math.ln2; + + return math.min(math.min(latZoom, lngZoom).floor(), zoomMax); + } + + String _buildStaticMapUrl(List path, int zoom) { + final pathParam = path.map((p) => '${p.lng},${p.lat}').join(';'); + return 'https://restapi.amap.com/v3/staticmap?' + 'zoom=$zoom&' + 'size=1024*512&' + 'paths=10,0x0000ff,1,,:$pathParam&' + 'markers=mid,,A:${startPoint.lng},${startPoint.lat}|' + 'mid,,B:${endPoint.lng},${endPoint.lat}&' + 'key=$apiKey'; + } + + List douglasPeucker(List points, double epsilon) { + if (points.length < 3) return points; + + double maxDistance = 0; + int index = 0; + + for (int i = 1; i < points.length - 1; i++) { + double d = _perpendicularDistance(points[i], points.first, points.last); + if (d > maxDistance) { + index = i; + maxDistance = d; + } + } + + if (maxDistance > epsilon) { + return [ + ...douglasPeucker(points.sublist(0, index + 1), epsilon), + ...douglasPeucker(points.sublist(index), epsilon).skip(1) + ]; + } + return [points.first, points.last]; + } + + double _perpendicularDistance(LatLng point, LatLng start, LatLng end) { + final area = (end.lng - start.lng) * (point.lat - start.lat) - + (end.lat - start.lat) * (point.lng - start.lng); + final length = + sqrt(pow(end.lng - start.lng, 2) + pow(end.lat - start.lat, 2)); + return area.abs() / length; + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + FutureBuilder( + future: _getMapUrl(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.hasData) { + return Image.network(snapshot.data); + } + return const CircularProgressIndicator(); + }, + ), + ], + ); + } +} + +class LatLng { + final double lat; + final double lng; + + LatLng(this.lng, this.lat); // 高德使用经度在前纬度在后的格式 +} diff --git a/lib/modules/chat/views/chat_view.dart b/lib/modules/chat/views/chat_view.dart index 4fbc6c261..edb80a3fc 100644 --- a/lib/modules/chat/views/chat_view.dart +++ b/lib/modules/chat/views/chat_view.dart @@ -5,6 +5,9 @@ import 'dart:math'; import '../controllers/chat_controller.dart'; import '../models/message_model.dart'; import '../../../core/theme/app_colors.dart'; +import 'chat_music_card.dart'; +import 'chat_navigation_card.dart'; +import 'weather_day_card.dart'; class ChatView extends GetView { const ChatView({Key? key}) : super(key: key); @@ -297,19 +300,7 @@ class ChatView extends GetView { crossAxisAlignment: CrossAxisAlignment.start, children: [ // 消息内容 - if (message.content.isNotEmpty) - SelectableText( - '${message.content}'.tr, - style: TextStyle( - color: isUser - ? Colors.white - : isDarkMode - ? Colors.white - : Colors.black, - fontSize: 16.sp, - height: 1.5, - ), - ), + _buildMessageContent(message, isDarkMode, isUser), // 加载中动画 if (message.isLoading) @@ -348,6 +339,36 @@ class ChatView extends GetView { ); } + Widget _buildMessageContent(Message message, bool isDarkMode, bool isUser) { + Widget box = const SizedBox(); + if (message.content.isNotEmpty) { + box = SelectableText( + message.content.tr, + style: TextStyle( + color: isUser + ? Colors.white + : isDarkMode + ? Colors.white + : Colors.black, + fontSize: 16.sp, + height: 1.5, + ), + ); + } + if (message.data != null) { + if (message.data?['weatherDays'] != null) { + box = WeatherDayCard(message.data, isDarkMode); + } + if (message.data?['musicaudio'] != null) { + box = ChatMusicCard(message.data, isDarkMode); + } + if (message.data?['navigationcard'] != null) { + box = ChatNavigationCard(message.data, isDarkMode); + } + } + return box; + } + // 构建输入区域 Widget _buildInputArea(bool isDarkMode) { final textController = @@ -715,21 +736,22 @@ class ChatView extends GetView { ); } - // 格式化时间 + // 格式化时间 String _formatTime(DateTime time) { final now = DateTime.now(); final today = DateTime(now.year, now.month, now.day); //final yesterday = today.subtract(const Duration(days: 1)); final messageDate = DateTime(time.year, time.month, time.day); - String timeStr = '${time.hour.toString().padLeft(2, '0')}:${time.minute.toString().padLeft(2, '0')}'; + String timeStr = + '${time.hour.toString().padLeft(2, '0')}:${time.minute.toString().padLeft(2, '0')}'; if (messageDate == today) { - return timeStr; // 只显示时间,如 "14:30" - } + return timeStr; // 只显示时间,如 "14:30" + } // else if (messageDate == yesterday) { // return 'Yesterday $timeStr'; // 如 "Yesterday 14:30" - // } + // } else { // 国际通用日期格式 "MM-dd HH:mm" return '${time.month.toString().padLeft(2, '0')}-${time.day.toString().padLeft(2, '0')} $timeStr'; diff --git a/lib/modules/chat/views/weather_day_card.dart b/lib/modules/chat/views/weather_day_card.dart new file mode 100644 index 000000000..72d7c0f10 --- /dev/null +++ b/lib/modules/chat/views/weather_day_card.dart @@ -0,0 +1,94 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; + +class WeatherDayCard extends StatelessWidget { + final Map? data; + final bool isDarkMode; + + const WeatherDayCard(this.data, this.isDarkMode, {super.key}); + + @override + Widget build(BuildContext context) { + final Map weatherDays = data?['weatherDays'].first; + + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + weatherDays['date'], + style: TextStyle( + color: isDarkMode ? Colors.white : Colors.black, + fontSize: 10.sp, + ), + ), + Text( + '${weatherDays['maxTemperature']}°', + style: TextStyle( + color: isDarkMode ? Colors.white : Colors.black, + fontSize: 30.sp, + ), + ), + ], + ), + Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Icon( + Icons.sunny, + color: isDarkMode ? Colors.white : Colors.amber[600]!, + size: 18.w, + ), + Text( + '${weatherDays['weatherCondition']},${weatherDays['windDirection']}', + style: TextStyle( + color: isDarkMode ? Colors.white : Colors.black, + fontSize: 14.sp, + ), + ), + Row( + children: [ + Text( + '最\n高', + style: TextStyle( + color: isDarkMode ? Colors.white : Colors.black, + fontSize: 10.sp, + height: 1, + ), + ), + 5.horizontalSpace, + Text( + '${weatherDays['maxTemperature']}°', + style: TextStyle( + color: isDarkMode ? Colors.white : Colors.black, + fontSize: 20.sp, + ), + ), + 10.horizontalSpace, + Text( + '最\n低', + style: TextStyle( + color: isDarkMode ? Colors.white : Colors.black, + fontSize: 10.sp, + height: 1, + ), + ), + 5.horizontalSpace, + Text( + '${weatherDays['minTemperature']}°', + style: TextStyle( + color: isDarkMode ? Colors.white : Colors.black, + fontSize: 20.sp, + ), + ), + ], + ), + ], + ), + ], + ); + } +} diff --git a/lib/modules/meeting/controllers/meeting_record_controller.dart b/lib/modules/meeting/controllers/meeting_record_controller.dart index ba449a942..e583ac57f 100644 --- a/lib/modules/meeting/controllers/meeting_record_controller.dart +++ b/lib/modules/meeting/controllers/meeting_record_controller.dart @@ -158,19 +158,9 @@ class MeetingRecordController extends GetxController // 完成 void complete() async { - if (await Permission.storage.request().isGranted) { - EasyLoading.show(); - await _pause(); - _aiSummary(); - } else { - Get.snackbar( - 'error'.tr, // 错误 - '请开启文件存储权限', - snackPosition: SnackPosition.TOP, - backgroundColor: Colors.red.withOpacity(0.1), - colorText: Colors.red, - ); - } + EasyLoading.show(); + await _pause(); + _aiSummary(); } void _aiSummary() async { @@ -217,8 +207,11 @@ class MeetingRecordController extends GetxController meetingController.dataList.insert(0, { 'id': result, 'title': title, - 'content': firstContent, + 'content': firstContent.replaceAll("\n", ""), 'seconds': seconds.value, + 'address': address.value, + 'longitude': _longitude, + 'latitude': _latitude, 'creationtime': creationTime, }); Get.back();