270 lines
7.3 KiB
Dart
270 lines
7.3 KiB
Dart
import 'dart:ui';
|
|
|
|
import 'package:fluent_ui/fluent_ui.dart';
|
|
import 'package:flutter/material.dart' show SegmentedButton, ButtonSegment;
|
|
import 'package:task_hub/models/task.dart';
|
|
import 'package:task_hub/widgets/task_dialog.dart';
|
|
import 'package:task_hub/widgets/task_item.dart';
|
|
|
|
// 任务页面
|
|
class TaskPage extends StatefulWidget {
|
|
const TaskPage({super.key});
|
|
|
|
@override
|
|
State<TaskPage> createState() => _TaskPageState();
|
|
}
|
|
|
|
class _TaskPageState extends State<TaskPage> {
|
|
final List<Task> _tasks = [];
|
|
String _filter = 'all';
|
|
String _sortBy = 'created';
|
|
|
|
List<Task> get _filteredTasks {
|
|
List<Task> tasks = _tasks.where((task) {
|
|
if (_filter == 'active') return !task.isCompleted;
|
|
if (_filter == 'completed') return task.isCompleted;
|
|
return true;
|
|
}).toList();
|
|
|
|
tasks.sort((a, b) {
|
|
switch (_sortBy) {
|
|
case 'due':
|
|
if (a.dueDate == null && b.dueDate == null) return 0;
|
|
if (a.dueDate == null) return 1;
|
|
if (b.dueDate == null) return -1;
|
|
return a.dueDate!.compareTo(b.dueDate!);
|
|
case 'priority':
|
|
return b.priority.index.compareTo(a.priority.index);
|
|
case 'created':
|
|
default:
|
|
return b.createTime.compareTo(a.createTime);
|
|
}
|
|
});
|
|
|
|
return tasks;
|
|
}
|
|
|
|
void _addTask() {
|
|
showDialog(
|
|
context: context,
|
|
builder: (context) => TaskDialog(
|
|
onSave: (task) {
|
|
setState(() {
|
|
_tasks.add(task);
|
|
});
|
|
},
|
|
),
|
|
);
|
|
}
|
|
|
|
void _editTask(Task task) {
|
|
showDialog(
|
|
context: context,
|
|
builder: (context) => TaskDialog(
|
|
task: task,
|
|
onSave: (editedTask) {
|
|
setState(() {
|
|
final index = _tasks.indexWhere((t) => t.id == task.id);
|
|
if (index != -1) {
|
|
_tasks[index] = editedTask;
|
|
}
|
|
});
|
|
},
|
|
),
|
|
);
|
|
}
|
|
|
|
void _deleteTask(int taskId) {
|
|
setState(() {
|
|
_tasks.removeWhere((task) => task.id == taskId);
|
|
});
|
|
}
|
|
|
|
void _toggleTaskComplete(Task task) {
|
|
setState(() {
|
|
final index = _tasks.indexWhere((t) => t.id == task.id);
|
|
if (index != -1) {
|
|
_tasks[index] = Task(
|
|
id: task.id,
|
|
title: task.title,
|
|
desc: task.desc,
|
|
createTime: task.createTime,
|
|
dueDate: task.dueDate,
|
|
isCompleted: !task.isCompleted,
|
|
priority: task.priority
|
|
);
|
|
}
|
|
});
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return ScaffoldPage.withPadding(
|
|
header: PageHeader(
|
|
title: const Text('待办任务'),
|
|
commandBar: CommandBar(
|
|
mainAxisAlignment: MainAxisAlignment.end,
|
|
primaryItems: [
|
|
CommandBarButton(
|
|
icon: const Icon(FluentIcons.add),
|
|
label: const Text('添加任务'),
|
|
onPressed: _addTask,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
content: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
_buildStatsWidget(),
|
|
const SizedBox(height: 16),
|
|
_buildFilterWidget(),
|
|
const SizedBox(height: 16),
|
|
Expanded(
|
|
child: _tasks.isEmpty ? _buildEmptyTask() : _buildTaskList(),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildStatsWidget() {
|
|
final completedCount = _tasks.where((task) => task.isCompleted).length;
|
|
final activeCount = _tasks.length - completedCount;
|
|
|
|
return Card(
|
|
backgroundColor: FluentTheme.of(context).accentColor.lighter,
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(12.0),
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
|
children: [
|
|
_buildStatsItem('全部', '${_tasks.length}'),
|
|
_buildStatsItem('进行中', '$activeCount'),
|
|
_buildStatsItem('已完成', '$completedCount'),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildStatsItem(String label, String value) {
|
|
return Column(
|
|
children: [
|
|
Text(
|
|
value,
|
|
style: TextStyle(
|
|
fontSize: 24,
|
|
fontWeight: FontWeight.bold,
|
|
color: Colors.white,
|
|
),
|
|
),
|
|
const SizedBox(height: 4),
|
|
Text(label, style: TextStyle(color: Colors.white)),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget _buildFilterWidget() {
|
|
return Card(
|
|
borderColor: Colors.white,
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(12.0),
|
|
child: Row(
|
|
children: [
|
|
const Text('筛选:'),
|
|
const SizedBox(width: 8),
|
|
SegmentedButton<String>(
|
|
showSelectedIcon: false,
|
|
selected: <String>{_filter},
|
|
onSelectionChanged: (Set<String> value) {
|
|
setState(() {
|
|
_filter = value.first;
|
|
});
|
|
},
|
|
segments: const [
|
|
ButtonSegment(
|
|
value: 'all',
|
|
label: Text('全部', style: TextStyle(fontFamily: 'CustomFont')),
|
|
),
|
|
ButtonSegment(
|
|
value: 'active',
|
|
label: Text(
|
|
'进行中',
|
|
style: TextStyle(fontFamily: 'CustomFont'),
|
|
),
|
|
),
|
|
ButtonSegment(
|
|
value: 'completed',
|
|
label: Text(
|
|
'已完成',
|
|
style: TextStyle(fontFamily: 'CustomFont'),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
const Spacer(),
|
|
const Text('排序:'),
|
|
const SizedBox(width: 8),
|
|
ComboBox<String>(
|
|
value: _sortBy,
|
|
items: const [
|
|
ComboBoxItem(value: 'created', child: Text('创建时间')),
|
|
ComboBoxItem(value: 'due', child: Text('截止日期')),
|
|
ComboBoxItem(value: 'priority', child: Text('优先级')),
|
|
],
|
|
onChanged: (value) {
|
|
if (value != null) {
|
|
setState(() {
|
|
_sortBy = value;
|
|
});
|
|
}
|
|
},
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildEmptyTask() {
|
|
return Center(
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
Icon(
|
|
FluentIcons.check_list,
|
|
size: 64,
|
|
color: FluentTheme.of(context).accentColor,
|
|
),
|
|
const SizedBox(height: 20),
|
|
const Text(
|
|
'还没有任务',
|
|
style: TextStyle(fontSize: 20, color: Colors.grey),
|
|
),
|
|
const SizedBox(height: 10),
|
|
Text('点击右上角的"添加任务"按钮开始', style: TextStyle(color: Colors.grey)),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildTaskList() {
|
|
return ListView.builder(
|
|
itemCount: _filteredTasks.length,
|
|
itemBuilder: (context, index) {
|
|
final task = _filteredTasks[index];
|
|
return Padding(
|
|
padding: const EdgeInsets.only(bottom: 8.0),
|
|
child: TaskItem(
|
|
task: task,
|
|
onToggleComplete: () => _toggleTaskComplete(task),
|
|
onEdit: () => _editTask(task),
|
|
onDelete: () => _deleteTask(task.id),
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|