import 'package:flutter/material.dart'; import 'package:social_app/core/theme/design_tokens.dart'; import '../../data/models/tool_result.dart'; class UiSchemaRenderer { static Widget render(UiCard card) { switch (card.cardType) { case 'calendar_card.v1': return _renderCalendarCard(card); case 'error_card.v1': return _renderErrorCard(card); default: return _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; 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 (data.sourceType == 'ai_generated') 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), ), ), if (data.sourceType == 'ai_generated') 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), Row( children: [ Icon( Icons.location_on_outlined, size: 16, color: AppColors.slate500, ), SizedBox(width: AppSpacing.xs), Text( data.location!, style: TextStyle( fontSize: 12, color: AppColors.slate500, ), ), ], ), ], if (card.actions != null && card.actions!.isNotEmpty) ...[ SizedBox(height: AppSpacing.md), Wrap( spacing: AppSpacing.sm, children: card.actions! .map((action) => _buildActionButton(action)) .toList(), ), ], ], ), ), ], ), ); } static Widget _buildActionButton(CardAction action) { final isPrimary = action.type == 'primary'; 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 处理 } }