feat:增加待办提醒功能
This commit is contained in:
BIN
assets/icons/app_icon.ico
Normal file
BIN
assets/icons/app_icon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 168 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 4.2 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.3 KiB |
@@ -1,13 +1,28 @@
|
|||||||
import 'package:fluent_ui/fluent_ui.dart';
|
import 'package:fluent_ui/fluent_ui.dart';
|
||||||
|
import 'package:hive_flutter/adapters.dart';
|
||||||
|
import 'package:task_hub/models/task.dart';
|
||||||
import 'package:task_hub/pages/home_page.dart';
|
import 'package:task_hub/pages/home_page.dart';
|
||||||
import 'package:task_hub/pages/schedule_page.dart';
|
import 'package:task_hub/pages/schedule_page.dart';
|
||||||
import 'package:task_hub/pages/settings_page.dart';
|
import 'package:task_hub/pages/settings_page.dart';
|
||||||
import 'package:task_hub/pages/task_page.dart';
|
import 'package:task_hub/pages/task_page.dart';
|
||||||
|
import 'package:task_hub/utils/notice.dart';
|
||||||
|
import 'package:timezone/data/latest.dart' as tz;
|
||||||
import 'package:window_size/window_size.dart';
|
import 'package:window_size/window_size.dart';
|
||||||
|
|
||||||
void main() {
|
void main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
setWindowMinSize(const Size(800, 600));
|
setWindowMinSize(const Size(800, 600));
|
||||||
|
|
||||||
|
tz.initializeTimeZones();
|
||||||
|
|
||||||
|
await Hive.initFlutter();
|
||||||
|
Hive.registerAdapter(TaskAdapter());
|
||||||
|
await Hive.openBox<Task>('taskBox');
|
||||||
|
|
||||||
|
await initNotify();
|
||||||
|
|
||||||
|
checkScheduleTime();
|
||||||
|
|
||||||
runApp(const TaskHubApp());
|
runApp(const TaskHubApp());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,7 +36,7 @@ class TaskHubApp extends StatelessWidget {
|
|||||||
themeMode: ThemeMode.system,
|
themeMode: ThemeMode.system,
|
||||||
theme: FluentThemeData(
|
theme: FluentThemeData(
|
||||||
fontFamily: 'CustomFont',
|
fontFamily: 'CustomFont',
|
||||||
accentColor: Colors.purple
|
accentColor: Colors.purple,
|
||||||
),
|
),
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
home: const MainLayout(),
|
home: const MainLayout(),
|
||||||
|
|||||||
@@ -13,6 +13,6 @@ class Schedule {
|
|||||||
required this.endTime,
|
required this.endTime,
|
||||||
this.scheduleTime,
|
this.scheduleTime,
|
||||||
DateTime? createTime,
|
DateTime? createTime,
|
||||||
}) : id = id ?? DateTime.timestamp().microsecond,
|
}) : id = id ?? DateTime.now().millisecondsSinceEpoch ~/ 1000,
|
||||||
createTime = DateTime.now();
|
createTime = DateTime.now();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
|
|
||||||
// flutter packages pub run build_runner build
|
// flutter packages pub run build_runner build
|
||||||
// part 'todo.g.dart';
|
part 'task.g.dart';
|
||||||
|
|
||||||
@HiveType(typeId: 0)
|
@HiveType(typeId: 0)
|
||||||
class Task extends HiveObject {
|
class Task extends HiveObject {
|
||||||
@@ -45,10 +45,11 @@ class Task extends HiveObject {
|
|||||||
this.isCompleted = false,
|
this.isCompleted = false,
|
||||||
Priority priority = Priority.medium,
|
Priority priority = Priority.medium,
|
||||||
DateTime? createTime,
|
DateTime? createTime,
|
||||||
}) : id = id ?? DateTime.timestamp().microsecond,
|
DateTime? updateTime,
|
||||||
|
}) : id = id ?? DateTime.now().millisecondsSinceEpoch ~/ 1000,
|
||||||
this.priorityIndex = priority.index,
|
this.priorityIndex = priority.index,
|
||||||
createTime = DateTime.now(),
|
createTime = createTime ?? DateTime.now(),
|
||||||
updateTime = DateTime.now();
|
updateTime = updateTime ?? DateTime.now();
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Priority { low, medium, high }
|
enum Priority { low, medium, high }
|
||||||
|
|||||||
65
lib/models/task.g.dart
Normal file
65
lib/models/task.g.dart
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'task.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// TypeAdapterGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
class TaskAdapter extends TypeAdapter<Task> {
|
||||||
|
@override
|
||||||
|
final int typeId = 0;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Task read(BinaryReader reader) {
|
||||||
|
final numOfFields = reader.readByte();
|
||||||
|
final fields = <int, dynamic>{
|
||||||
|
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
|
||||||
|
};
|
||||||
|
return Task(
|
||||||
|
id: fields[0] as int?,
|
||||||
|
title: fields[1] as String,
|
||||||
|
desc: fields[2] as String?,
|
||||||
|
dueDate: fields[3] as DateTime?,
|
||||||
|
scheduleTime: fields[4] as DateTime?,
|
||||||
|
isCompleted: fields[5] as bool,
|
||||||
|
createTime: fields[7] as DateTime?,
|
||||||
|
)
|
||||||
|
..priorityIndex = fields[6] as int
|
||||||
|
..updateTime = fields[8] as DateTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void write(BinaryWriter writer, Task obj) {
|
||||||
|
writer
|
||||||
|
..writeByte(9)
|
||||||
|
..writeByte(0)
|
||||||
|
..write(obj.id)
|
||||||
|
..writeByte(1)
|
||||||
|
..write(obj.title)
|
||||||
|
..writeByte(2)
|
||||||
|
..write(obj.desc)
|
||||||
|
..writeByte(3)
|
||||||
|
..write(obj.dueDate)
|
||||||
|
..writeByte(4)
|
||||||
|
..write(obj.scheduleTime)
|
||||||
|
..writeByte(5)
|
||||||
|
..write(obj.isCompleted)
|
||||||
|
..writeByte(6)
|
||||||
|
..write(obj.priorityIndex)
|
||||||
|
..writeByte(7)
|
||||||
|
..write(obj.createTime)
|
||||||
|
..writeByte(8)
|
||||||
|
..write(obj.updateTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => typeId.hashCode;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) =>
|
||||||
|
identical(this, other) ||
|
||||||
|
other is TaskAdapter &&
|
||||||
|
runtimeType == other.runtimeType &&
|
||||||
|
typeId == other.typeId;
|
||||||
|
}
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
|
||||||
|
|
||||||
// 初始化通知
|
|
||||||
Future<void> _initNotify() async {
|
|
||||||
final notify = FlutterLocalNotificationsPlugin();
|
|
||||||
await notify.initialize(
|
|
||||||
const InitializationSettings(
|
|
||||||
windows: WindowsInitializationSettings(
|
|
||||||
appName: 'TaskHub',
|
|
||||||
appUserModelId: 'com.cxx.task',
|
|
||||||
guid: 'f47ac10b-58cc-4372-a567-0e02b2c3d479',
|
|
||||||
iconPath: 'assets/icons/task.png'
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 发送通知
|
|
||||||
Future<void> _showNotify(String title, String text) async {
|
|
||||||
final notify = FlutterLocalNotificationsPlugin();
|
|
||||||
final id = DateTime.now().millisecondsSinceEpoch.remainder(10000);
|
|
||||||
|
|
||||||
await notify.show(
|
|
||||||
id,
|
|
||||||
title,
|
|
||||||
text,
|
|
||||||
const NotificationDetails(
|
|
||||||
windows: WindowsNotificationDetails(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -2,7 +2,9 @@ import 'dart:ui';
|
|||||||
|
|
||||||
import 'package:fluent_ui/fluent_ui.dart';
|
import 'package:fluent_ui/fluent_ui.dart';
|
||||||
import 'package:flutter/material.dart' show SegmentedButton, ButtonSegment;
|
import 'package:flutter/material.dart' show SegmentedButton, ButtonSegment;
|
||||||
|
import 'package:hive/hive.dart';
|
||||||
import 'package:task_hub/models/task.dart';
|
import 'package:task_hub/models/task.dart';
|
||||||
|
import 'package:task_hub/utils/notice.dart';
|
||||||
import 'package:task_hub/widgets/task_dialog.dart';
|
import 'package:task_hub/widgets/task_dialog.dart';
|
||||||
import 'package:task_hub/widgets/task_item.dart';
|
import 'package:task_hub/widgets/task_item.dart';
|
||||||
|
|
||||||
@@ -15,10 +17,24 @@ class TaskPage extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _TaskPageState extends State<TaskPage> {
|
class _TaskPageState extends State<TaskPage> {
|
||||||
final List<Task> _tasks = [];
|
late Box<Task> _taskBox;
|
||||||
|
List<Task> _tasks = [];
|
||||||
String _filter = 'all';
|
String _filter = 'all';
|
||||||
String _sortBy = 'created';
|
String _sortBy = 'created';
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_loadTasks();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _loadTasks() {
|
||||||
|
_taskBox = Hive.box<Task>('taskBox');
|
||||||
|
setState(() {
|
||||||
|
_tasks = _taskBox.values.toList();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
List<Task> get _filteredTasks {
|
List<Task> get _filteredTasks {
|
||||||
List<Task> tasks = _tasks.where((task) {
|
List<Task> tasks = _tasks.where((task) {
|
||||||
if (_filter == 'active') return !task.isCompleted;
|
if (_filter == 'active') return !task.isCompleted;
|
||||||
@@ -48,10 +64,12 @@ class _TaskPageState extends State<TaskPage> {
|
|||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => TaskDialog(
|
builder: (context) => TaskDialog(
|
||||||
onSave: (task) {
|
onSave: (task) async {
|
||||||
|
await _taskBox.put(task.id, task);
|
||||||
setState(() {
|
setState(() {
|
||||||
_tasks.add(task);
|
_tasks = _taskBox.values.toList();
|
||||||
});
|
});
|
||||||
|
checkScheduleTime();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -62,22 +80,26 @@ class _TaskPageState extends State<TaskPage> {
|
|||||||
context: context,
|
context: context,
|
||||||
builder: (context) => TaskDialog(
|
builder: (context) => TaskDialog(
|
||||||
task: task,
|
task: task,
|
||||||
onSave: (editedTask) {
|
onSave: (editedTask) async {
|
||||||
|
editedTask.updateTime = DateTime.now();
|
||||||
|
await _taskBox.put(editedTask.id, editedTask);
|
||||||
setState(() {
|
setState(() {
|
||||||
final index = _tasks.indexWhere((t) => t.id == task.id);
|
_tasks = _taskBox.values.toList();
|
||||||
if (index != -1) {
|
|
||||||
_tasks[index] = editedTask;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
checkScheduleTime();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _deleteTask(int taskId) {
|
void _deleteTask(int taskId) async {
|
||||||
|
final task = _tasks.firstWhere((t) => t.id == taskId);
|
||||||
|
await task.delete();
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
_tasks.removeWhere((task) => task.id == taskId);
|
_tasks = _taskBox.values.toList();
|
||||||
});
|
});
|
||||||
|
checkScheduleTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _toggleTaskComplete(Task task) {
|
void _toggleTaskComplete(Task task) {
|
||||||
@@ -91,7 +113,7 @@ class _TaskPageState extends State<TaskPage> {
|
|||||||
createTime: task.createTime,
|
createTime: task.createTime,
|
||||||
dueDate: task.dueDate,
|
dueDate: task.dueDate,
|
||||||
isCompleted: !task.isCompleted,
|
isCompleted: !task.isCompleted,
|
||||||
priority: task.priority
|
priority: task.priority,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
3
lib/utils/common.dart
Normal file
3
lib/utils/common.dart
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
bool isSameDate(DateTime a, DateTime b) {
|
||||||
|
return a.year == b.year && a.month == b.month && a.day == b.day;
|
||||||
|
}
|
||||||
82
lib/utils/notice.dart
Normal file
82
lib/utils/notice.dart
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||||
|
import 'package:hive/hive.dart';
|
||||||
|
import 'package:timezone/timezone.dart' as tz;
|
||||||
|
|
||||||
|
import '../models/task.dart';
|
||||||
|
import 'common.dart';
|
||||||
|
|
||||||
|
// 初始化通知
|
||||||
|
Future<void> initNotify() async {
|
||||||
|
final notify = FlutterLocalNotificationsPlugin();
|
||||||
|
await notify.initialize(
|
||||||
|
const InitializationSettings(
|
||||||
|
windows: WindowsInitializationSettings(
|
||||||
|
appName: 'TaskHub',
|
||||||
|
appUserModelId: 'com.cxx.task',
|
||||||
|
guid: 'f47ac10b-58cc-4372-a567-0e02b2c3d479',
|
||||||
|
iconPath: 'assets/icons/app_icon.ico',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> showNotify(String title, String body) async {
|
||||||
|
final notify = FlutterLocalNotificationsPlugin();
|
||||||
|
final id = DateTime.now().millisecondsSinceEpoch.remainder(10000);
|
||||||
|
|
||||||
|
await notify.show(
|
||||||
|
id,
|
||||||
|
title,
|
||||||
|
body,
|
||||||
|
const NotificationDetails(windows: WindowsNotificationDetails()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送通知
|
||||||
|
Future<void> scheduleNotification(
|
||||||
|
int id,
|
||||||
|
String title,
|
||||||
|
String body,
|
||||||
|
DateTime scheduleTime,
|
||||||
|
) async {
|
||||||
|
final notify = FlutterLocalNotificationsPlugin();
|
||||||
|
|
||||||
|
final local = tz.getLocation('Asia/Shanghai');
|
||||||
|
final tzTime = tz.TZDateTime.from(scheduleTime, local);
|
||||||
|
|
||||||
|
await notify.zonedSchedule(
|
||||||
|
id,
|
||||||
|
title,
|
||||||
|
body,
|
||||||
|
tzTime,
|
||||||
|
const NotificationDetails(windows: WindowsNotificationDetails()),
|
||||||
|
androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 取消通知
|
||||||
|
Future<void> cancelAllSchedule() async {
|
||||||
|
final notify = FlutterLocalNotificationsPlugin();
|
||||||
|
|
||||||
|
await notify.cancelAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkScheduleTime() {
|
||||||
|
final taskBox = Hive.box<Task>('taskBox');
|
||||||
|
final now = DateTime.now();
|
||||||
|
|
||||||
|
cancelAllSchedule();
|
||||||
|
for (var task in taskBox.values) {
|
||||||
|
if (task.scheduleTime != null &&
|
||||||
|
!task.isCompleted &&
|
||||||
|
isSameDate(task.scheduleTime!, DateTime.now()) &&
|
||||||
|
task.scheduleTime!.isAfter(now)) {
|
||||||
|
scheduleNotification(
|
||||||
|
task.id,
|
||||||
|
task.title,
|
||||||
|
task.desc ?? '',
|
||||||
|
task.scheduleTime!,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -79,6 +79,9 @@ Widget buildOmniDateButton({
|
|||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final DateTime? picked = await showOmniDateTimePicker(
|
final DateTime? picked = await showOmniDateTimePicker(
|
||||||
context: context,
|
context: context,
|
||||||
|
constraints: const BoxConstraints(
|
||||||
|
maxWidth: 400,
|
||||||
|
),
|
||||||
initialDate: selectedDate ?? DateTime.now(),
|
initialDate: selectedDate ?? DateTime.now(),
|
||||||
firstDate: DateTime(
|
firstDate: DateTime(
|
||||||
DateTime.now().year,
|
DateTime.now().year,
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ class _TaskDialogState extends State<TaskDialog> {
|
|||||||
late Priority _selectedPriority;
|
late Priority _selectedPriority;
|
||||||
DateTime? _selectedDueDate;
|
DateTime? _selectedDueDate;
|
||||||
DateTime? _selectedScheduleTime;
|
DateTime? _selectedScheduleTime;
|
||||||
|
DateTime? _createTime;
|
||||||
final _formKey = GlobalKey<FormState>();
|
final _formKey = GlobalKey<FormState>();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -29,6 +30,7 @@ class _TaskDialogState extends State<TaskDialog> {
|
|||||||
_selectedPriority = widget.task?.priority ?? Priority.medium;
|
_selectedPriority = widget.task?.priority ?? Priority.medium;
|
||||||
_selectedDueDate = widget.task?.dueDate;
|
_selectedDueDate = widget.task?.dueDate;
|
||||||
_selectedScheduleTime = widget.task?.scheduleTime;
|
_selectedScheduleTime = widget.task?.scheduleTime;
|
||||||
|
_createTime = widget.task?.createTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -38,8 +40,22 @@ class _TaskDialogState extends State<TaskDialog> {
|
|||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
void onConfirmClick() {
|
void onConfirmClick() async {
|
||||||
if (_formKey.currentState!.validate()) {
|
if (_formKey.currentState!.validate()) {
|
||||||
|
if (_selectedScheduleTime != null &&
|
||||||
|
_selectedScheduleTime!.isBefore(DateTime.now())) {
|
||||||
|
await displayInfoBar(
|
||||||
|
context,
|
||||||
|
builder: (context, close) {
|
||||||
|
return InfoBar(
|
||||||
|
title: const Text('提醒时间不能早于当前时间'),
|
||||||
|
severity: InfoBarSeverity.error,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final task = Task(
|
final task = Task(
|
||||||
id: widget.task?.id,
|
id: widget.task?.id,
|
||||||
title: _titleController.text,
|
title: _titleController.text,
|
||||||
@@ -48,6 +64,7 @@ class _TaskDialogState extends State<TaskDialog> {
|
|||||||
scheduleTime: _selectedScheduleTime,
|
scheduleTime: _selectedScheduleTime,
|
||||||
priority: _selectedPriority,
|
priority: _selectedPriority,
|
||||||
isCompleted: widget.task?.isCompleted ?? false,
|
isCompleted: widget.task?.isCompleted ?? false,
|
||||||
|
createTime: _createTime,
|
||||||
);
|
);
|
||||||
widget.onSave(task);
|
widget.onSave(task);
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:fluent_ui/fluent_ui.dart';
|
import 'package:fluent_ui/fluent_ui.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
import 'package:task_hub/models/task.dart';
|
import 'package:task_hub/models/task.dart';
|
||||||
|
|
||||||
class TaskItem extends StatelessWidget {
|
class TaskItem extends StatelessWidget {
|
||||||
@@ -39,11 +40,14 @@ class TaskItem extends StatelessWidget {
|
|||||||
Expanded(child: _buildTitle(context)),
|
Expanded(child: _buildTitle(context)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 4),
|
if (task.desc != null && task.desc!.isNotEmpty) ...[
|
||||||
if (task.desc != null && task.desc!.isNotEmpty) _buildDesc(),
|
const SizedBox(height: 4),
|
||||||
const SizedBox(height: 4),
|
_buildDesc(),
|
||||||
if (task.dueDate != null || task.scheduleTime != null)
|
],
|
||||||
|
if (task.dueDate != null || task.scheduleTime != null) ...[
|
||||||
|
const SizedBox(height: 4),
|
||||||
_buildDate(),
|
_buildDate(),
|
||||||
|
]
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -92,7 +96,7 @@ class TaskItem extends StatelessWidget {
|
|||||||
Icon(FluentIcons.calendar, size: 12, color: Colors.grey),
|
Icon(FluentIcons.calendar, size: 12, color: Colors.grey),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
Text(
|
Text(
|
||||||
'截止日期: ${_formatDate(task.dueDate!)}',
|
'截止日期: ${DateFormat('yyyy-MM-dd').format(task.dueDate!)}',
|
||||||
style: TextStyle(color: Colors.grey, fontSize: 12),
|
style: TextStyle(color: Colors.grey, fontSize: 12),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
@@ -101,7 +105,7 @@ class TaskItem extends StatelessWidget {
|
|||||||
Icon(FluentIcons.clock, size: 12, color: Colors.grey),
|
Icon(FluentIcons.clock, size: 12, color: Colors.grey),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
Text(
|
Text(
|
||||||
'提醒日期: ${_formatDate(task.scheduleTime!)}',
|
'提醒日期: ${DateFormat('yyyy-MM-dd HH:mm:ss').format(task.scheduleTime!)}',
|
||||||
style: TextStyle(color: Colors.grey, fontSize: 12),
|
style: TextStyle(color: Colors.grey, fontSize: 12),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -181,8 +185,4 @@ class TaskItem extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
String _formatDate(DateTime date) {
|
|
||||||
return '${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')}';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
58
pubspec.lock
58
pubspec.lock
@@ -17,6 +17,14 @@ packages:
|
|||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.4.1"
|
version: "6.4.1"
|
||||||
|
archive:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: archive
|
||||||
|
sha256: a96e8b390886ee8abb49b7bd3ac8df6f451c621619f52a26e815fdcf568959ff
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "4.0.9"
|
||||||
args:
|
args:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -129,6 +137,14 @@ packages:
|
|||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.4"
|
version: "2.0.4"
|
||||||
|
cli_util:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cli_util
|
||||||
|
sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "0.4.2"
|
||||||
clock:
|
clock:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -153,6 +169,14 @@ packages:
|
|||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.19.1"
|
version: "1.19.1"
|
||||||
|
console:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: console
|
||||||
|
sha256: e04e7824384c5b39389acdd6dc7d33f3efe6b232f6f16d7626f194f6a01ad69a
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "4.1.0"
|
||||||
convert:
|
convert:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -312,6 +336,14 @@ packages:
|
|||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.0"
|
version: "4.0.0"
|
||||||
|
get_it:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: get_it
|
||||||
|
sha256: "568d62f0e68666fb5d95519743b3c24a34c7f19d834b0658c46e26d778461f66"
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "9.2.1"
|
||||||
glob:
|
glob:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -376,6 +408,14 @@ packages:
|
|||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.1.2"
|
version: "4.1.2"
|
||||||
|
image:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: image
|
||||||
|
sha256: f9881ff4998044947ec38d098bc7c8316ae1186fa786eddffdb867b9bc94dfce
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "4.8.0"
|
||||||
intl:
|
intl:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -504,6 +544,14 @@ packages:
|
|||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.0"
|
version: "2.0.0"
|
||||||
|
msix:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description:
|
||||||
|
name: msix
|
||||||
|
sha256: b6b08e7a7b5d1845f2b1d31216d5b1fb558e98251efefe54eb79ed00d27bc2ac
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "3.16.13"
|
||||||
nested:
|
nested:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -616,6 +664,14 @@ packages:
|
|||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.5.2"
|
version: "1.5.2"
|
||||||
|
posix:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: posix
|
||||||
|
sha256: "185ef7606574f789b40f289c233efa52e96dead518aed988e040a10737febb07"
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "6.5.0"
|
||||||
provider:
|
provider:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -790,7 +846,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.7"
|
version: "0.7.7"
|
||||||
timezone:
|
timezone:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: timezone
|
name: timezone
|
||||||
sha256: dd14a3b83cfd7cb19e7888f1cbc20f258b8d71b54c06f79ac585f14093a287d1
|
sha256: dd14a3b83cfd7cb19e7888f1cbc20f258b8d71b54c06f79ac585f14093a287d1
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
name: task_hub
|
name: task_hub
|
||||||
Reference in New Issue
Block a user