import 'package:ac_web/Api/Dtos/AgentTaskDto.dart'; import 'package:flutter/material.dart'; /// Card that shows a single task of an agent. /// /// Collapsed it only shows the title, the start time and the newest status /// line. Expanded it lists every status update the agent reported so far. class AgentTaskCard extends StatelessWidget { const AgentTaskCard({super.key, required this.task, this.initiallyExpanded = false}); final AgentTaskDto task; /// Expands the status update history right away, e.g. for the newest task. final bool initiallyExpanded; @override Widget build(BuildContext context) { final ThemeData theme = Theme.of(context); return Card( shape: RoundedRectangleBorder(borderRadius: BorderRadiusGeometry.circular(12)), shadowColor: Colors.white, color: Colors.black38, margin: EdgeInsetsGeometry.fromLTRB(0, 8, 0, 8), clipBehavior: Clip.antiAlias, child: ExpansionTile( initiallyExpanded: initiallyExpanded, shape: const Border(), collapsedShape: const Border(), leading: CircleAvatar( backgroundColor: theme.colorScheme.inversePrimary, child: Icon(Icons.task_alt, color: theme.colorScheme.onSurface), ), title: Text( task.title.isEmpty ? "Untitled Task" : task.title, style: theme.textTheme.titleMedium, ), subtitle: Text( _subtitle(), style: theme.textTheme.bodySmall, ), childrenPadding: EdgeInsetsGeometry.fromLTRB(16, 0, 16, 16), expandedCrossAxisAlignment: CrossAxisAlignment.start, children: [ if (!task.hasStatusUpdates) Text( "This task has no status updates yet.", style: theme.textTheme.bodyMedium, ) else for (int i = 0; i < task.statusUpdates.length; i++) _buildStatusUpdate( context, task.statusUpdates[i], isLast: i == task.statusUpdates.length - 1, ), ], ), ); } /// Start time and, when the agent already reported one, the newest status. String _subtitle() { final String? latest = task.latestStatus; final String started = task.startTime == null ? "Start unknown" : "Started ${_formatTimestamp(task.startTime!.toLocal())}"; if (latest == null || latest.isEmpty) { return started; } return "$started • $latest"; } /// One entry of the status update history, drawn as a small timeline. Widget _buildStatusUpdate(BuildContext context, String update, {required bool isLast}) { final ThemeData theme = Theme.of(context); return IntrinsicHeight( child: Row( crossAxisAlignment: CrossAxisAlignment.stretch, spacing: 12, children: [ // Dot of this entry plus the line down to the following one. Column( children: [ Container( width: 10, height: 10, margin: EdgeInsetsGeometry.only(top: 6), decoration: BoxDecoration( color: isLast ? theme.colorScheme.primary : theme.colorScheme.outline, shape: BoxShape.circle, ), ), if (!isLast) Expanded( child: Container( width: 2, color: theme.colorScheme.outline, ), ), ], ), Expanded( child: Padding( padding: EdgeInsetsGeometry.only(bottom: isLast ? 0 : 12), child: SelectableText( update, style: isLast ? theme.textTheme.bodyMedium : theme.textTheme.bodyMedium?.copyWith(color: theme.colorScheme.onSurfaceVariant), ), ), ), ], ), ); } /// e.g. "15.08.2025 09:05" String _formatTimestamp(DateTime timestamp) { final String day = timestamp.day.toString().padLeft(2, '0'); final String month = timestamp.month.toString().padLeft(2, '0'); final String hour = timestamp.hour.toString().padLeft(2, '0'); final String minute = timestamp.minute.toString().padLeft(2, '0'); return "$day.$month.${timestamp.year} $hour:$minute"; } }