import 'package:flisp_app/models/todo.dart'; import 'package:flisp_app/utils/todo_utils.dart'; import 'package:flisp_app/widgets/common.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:toggle_switch/toggle_switch.dart'; // 统计卡片 Widget buildStatsCard(List todos) { int totalCount = todos.length; int activeCount = todos.where((todo) => !todo.isCompleted).length; int completedCount = todos.where((todo) => todo.isCompleted).length; return buildCard( child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ _buildStatItem('总计', totalCount, Colors.blue), _buildStatItem('待完成', activeCount, Colors.orange), _buildStatItem('已完成', completedCount, Colors.green), ], ), ); } Widget _buildStatItem(String label, int count, Color color) { return Column( children: [ Text( count.toString(), style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: color, ), ), const SizedBox(height: 4), Text(label, style: const TextStyle(fontSize: 12, color: Colors.grey)), ], ); } // Tab页 Widget buildTabs({ required TodoTab currentTab, required ValueChanged onTabChanged, }) { return Container( padding: EdgeInsets.all(8), child: ToggleSwitch( minWidth: 90.0, minHeight: 40.0, initialLabelIndex: TodoTab.values.indexOf(currentTab), totalSwitches: TodoTab.values.length, labels: TodoTab.values.map((e) => e.label).toList(), activeBgColor: [Colors.orange.shade600], activeFgColor: Colors.white, inactiveBgColor: Colors.grey.shade200, inactiveFgColor: Colors.grey.shade700, cornerRadius: 12.0, customTextStyles: [TextStyle(fontSize: 12, fontWeight: FontWeight.w500)], onToggle: (index) { if (index != null) { onTabChanged(TodoTab.values[index]); } }, ), ); } Widget buildTodoList({ required List todos, required ValueChanged onToggleTodo, required ValueChanged onEditTodo, }) { return ListView.separated( itemCount: todos.length, separatorBuilder: (context, index) => SizedBox(height: 8), itemBuilder: (context, index) { final todo = todos[index]; return _buildTodoItem( todo: todo, onToggle: onToggleTodo, onEdit: onEditTodo, ); }, ); } Widget _buildTodoItem({ required Todo todo, required ValueChanged onToggle, required ValueChanged onEdit, }) { return buildCard( child: ListTile( contentPadding: EdgeInsets.symmetric(horizontal: 8, vertical: 0), leading: SizedBox( width: 24, child: Checkbox( value: todo.isCompleted, onChanged: (value) => onToggle(todo), materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, ), ), title: _buildTodoTitle(todo), subtitle: _buildTodoSubtitle(todo), trailing: _buildPriorityBadge(todo.priority), onTap: () => onEdit(todo), // onLongPress: () => onShowOptions(todo), ), ); } Widget _buildTodoTitle(Todo todo) { return Text( todo.title, style: TextStyle( decoration: todo.isCompleted ? TextDecoration.lineThrough : null, color: todo.isCompleted ? Colors.grey : null, fontSize: 16, fontWeight: FontWeight.w500, ), ); } Widget _buildContent(Todo todo) { return Padding( padding: const EdgeInsets.only(bottom: 8), child: Text( todo.content, maxLines: 2, overflow: TextOverflow.ellipsis, style: TextStyle(fontSize: 13, color: Colors.grey[600], height: 1.3), ), ); } Widget _buildDueDateChip(Todo todo) { final isOverdue = todo.dueDate != null && todo.dueDate!.isBefore(DateTime.now()) && !todo.isCompleted; final isDueToday = todo.dueDate != null && isSameDay(todo.dueDate!, DateTime.now()); final isDueTomorrow = todo.dueDate != null && isSameDay(todo.dueDate!, DateTime.now().add(Duration(days: 1))); return _buildInfoChip( icon: Icons.access_time_rounded, text: formatDueDate(todo.dueDate!, isDueToday, isDueTomorrow), backgroundColor: isOverdue ? Colors.red[50]! : (isDueToday ? Colors.orange[50]! : Colors.grey[50]!), borderColor: isOverdue ? Colors.red[200]! : (isDueToday ? Colors.orange[200]! : Colors.grey[300]!), textColor: isOverdue ? Colors.red[700]! : (isDueToday ? Colors.orange[700]! : Colors.grey[700]!), iconColor: isOverdue ? Colors.red[500]! : (isDueToday ? Colors.orange[500]! : Colors.grey[500]!), ); } Widget _buildScheduledTimeChip(Todo todo) { return _buildInfoChip( icon: Icons.notifications_active_rounded, text: DateFormat("MM-dd HH:mm").format(todo.scheduledTime!), backgroundColor: Colors.blue[50]!, borderColor: Colors.blue[200]!, textColor: Colors.blue[700]!, iconColor: Colors.blue[500]!, ); } // 构建待办事项副标题 Widget? _buildTodoSubtitle(Todo todo) { final hasContent = todo.content.isNotEmpty == true || todo.dueDate != null || todo.scheduledTime != null; if (!hasContent) return null; return Padding( padding: const EdgeInsets.only(top: 6), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 内容文本 if (todo.content.isNotEmpty == true) _buildContent(todo), // 标签容器 Wrap( spacing: 6, runSpacing: 6, children: [ // 截止日期标签 if (todo.dueDate != null) _buildDueDateChip(todo), // 提醒时间标签 if (todo.scheduledTime != null) _buildScheduledTimeChip(todo), ], ), ], ), ); } // 构建信息标签 Widget _buildInfoChip({ required IconData icon, required String text, required Color backgroundColor, required Color borderColor, required Color textColor, required Color iconColor, }) { return Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: backgroundColor, borderRadius: BorderRadius.circular(12), border: Border.all(color: borderColor, width: 1), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon(icon, size: 12, color: iconColor), const SizedBox(width: 4), Text( text, style: TextStyle( fontSize: 10, color: textColor, fontWeight: FontWeight.w500, height: 1.2, ), ), ], ), ); } // 构建优先级徽章 Widget _buildPriorityBadge(TodoPriority priority) { return Chip( label: Text(priority.label), backgroundColor: priority.color, labelStyle: TextStyle(color: Colors.white, fontWeight: FontWeight.bold), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), side: BorderSide(color: Colors.white), ), materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, visualDensity: VisualDensity.compact, ); } // 空状态 Widget buildEmptyState(TodoTab tab) { final messages = { TodoTab.all: '📝 还没有待办事项\n点击➕号添加第一个任务吧~', TodoTab.active: '🎯 没有待完成的任务\n享受轻松时光吧!✨', TodoTab.completed: '🎉 还没有完成的任务\n加油哦!💪', TodoTab.today: '📅 今天没有安排任务\n好好放松一下吧~😊', }; return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.checklist, size: 80, color: Colors.orange.shade600), Text( messages[tab] ?? '暂无数据', textAlign: TextAlign.center, style: TextStyle(color: Colors.orange.shade600), ), ], ), ); }