import 'package:flutter/material.dart'; import 'package:social_app/core/theme/design_tokens.dart'; import '../../data/models/tool_result.dart'; /// 卡片类型常量 const _calendarCardType = 'calendar_card.v1'; const _errorCardType = 'error_card.v1'; const _aiGeneratedSource = 'ai_generated'; const _primaryActionType = 'primary'; class UiSchemaRenderer { static Widget render(UiCard card) { return switch (card.cardType) { _calendarCardType => _renderCalendarCard(card), _errorCardType => _renderErrorCard(card), _ => _renderUnknownCard(card), }; } static Widget _renderCalendarCard(UiCard card) { final data = CalendarCardData.fromJson(card.data); final color = data.color != null ? Color(int.parse(data.color!.replaceFirst('#', '0xFF'))) : AppColors.blue500; final isAiGenerated = data.sourceType == _aiGeneratedSource; return Container( decoration: BoxDecoration( color: AppColors.messageCardBg, borderRadius: BorderRadius.circular(AppRadius.lg), border: Border.all(color: AppColors.messageCardBorder), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( height: AppSpacing.sm, decoration: BoxDecoration( color: color, borderRadius: BorderRadius.only( topLeft: Radius.circular(AppRadius.lg), topRight: Radius.circular(AppRadius.lg), ), ), ), Padding( padding: EdgeInsets.all(AppSpacing.lg), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (isAiGenerated) ...[ _buildAiTag(), SizedBox(height: AppSpacing.sm), ], Text( _formatTime(data.startAt, data.endAt), style: TextStyle(fontSize: 12, color: AppColors.slate500), ), SizedBox(height: AppSpacing.sm), Text( data.title, style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, color: AppColors.slate900, ), ), if (data.description != null) ...[ SizedBox(height: AppSpacing.xs), Text( data.description!, style: TextStyle(fontSize: 14, color: AppColors.slate600), ), ], if (data.location != null) ...[ SizedBox(height: AppSpacing.sm), _buildLocation(data.location!), ], if (card.actions != null && card.actions!.isNotEmpty) ...[ SizedBox(height: AppSpacing.md), _buildActions(card.actions!), ], ], ), ), ], ), ); } static Widget _buildAiTag() { return Container( padding: EdgeInsets.symmetric( horizontal: AppSpacing.sm, vertical: AppSpacing.xs, ), decoration: BoxDecoration( color: AppColors.messageTagBg, borderRadius: BorderRadius.circular(AppRadius.sm), ), child: Text( 'AI生成', style: TextStyle(fontSize: 10, color: AppColors.blue600), ), ); } static Widget _buildLocation(String location) { return Row( children: [ Icon(Icons.location_on_outlined, size: 16, color: AppColors.slate500), SizedBox(width: AppSpacing.xs), Text( location, style: TextStyle(fontSize: 12, color: AppColors.slate500), ), ], ); } static Widget _buildActions(List actions) { return Wrap( spacing: AppSpacing.sm, children: actions.map((action) => _buildActionButton(action)).toList(), ); } static Widget _buildActionButton(CardAction action) { final isPrimary = action.type == _primaryActionType; return GestureDetector( onTap: () => _handleAction(action), child: Container( padding: EdgeInsets.symmetric( horizontal: AppSpacing.md, vertical: AppSpacing.sm, ), decoration: BoxDecoration( color: isPrimary ? AppColors.blue500 : AppColors.messageBtnWrap, borderRadius: BorderRadius.circular(AppRadius.sm), border: Border.all( color: isPrimary ? AppColors.blue500 : AppColors.messageBtnBorder, ), ), child: Text( action.label, style: TextStyle( fontSize: 14, color: isPrimary ? AppColors.white : AppColors.slate600, ), ), ), ); } static Widget _renderErrorCard(UiCard card) { final message = card.data['message'] as String? ?? '发生错误'; return Container( padding: EdgeInsets.all(AppSpacing.lg), decoration: BoxDecoration( color: AppColors.warningBackground, borderRadius: BorderRadius.circular(AppRadius.lg), border: Border.all(color: AppColors.red400), ), child: Row( children: [ Icon(Icons.error_outline, size: 20, color: AppColors.red600), SizedBox(width: AppSpacing.sm), Expanded( child: Text( message, style: TextStyle(fontSize: 14, color: AppColors.red600), ), ), ], ), ); } static Widget _renderUnknownCard(UiCard card) { return Container( padding: EdgeInsets.all(AppSpacing.lg), decoration: BoxDecoration( color: AppColors.messageCardBg, borderRadius: BorderRadius.circular(AppRadius.lg), border: Border.all(color: AppColors.border), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '未知卡片类型: ${card.cardType}', style: TextStyle( fontSize: 14, fontWeight: FontWeight.w500, color: AppColors.slate600, ), ), SizedBox(height: AppSpacing.sm), Text( card.data.toString(), style: TextStyle(fontSize: 12, color: AppColors.slate500), ), ], ), ); } static String _formatTime(String startAt, String? endAt) { try { final start = DateTime.parse(startAt); final buffer = StringBuffer(); buffer.write('${start.month}月${start.day}日 '); buffer.write( '${start.hour.toString().padLeft(2, '0')}:${start.minute.toString().padLeft(2, '0')}', ); if (endAt != null) { final end = DateTime.parse(endAt); buffer.write( ' - ${end.hour.toString().padLeft(2, '0')}:${end.minute.toString().padLeft(2, '0')}', ); } return buffer.toString(); } catch (e) { return startAt; } } static void _handleAction(CardAction action) { // TODO: 实现 action 处理 } }