first commit
This commit is contained in:
70
lib/models/app_usage.dart
Normal file
70
lib/models/app_usage.dart
Normal file
@@ -0,0 +1,70 @@
|
||||
class AppUsage {
|
||||
final int? id;
|
||||
final String packageName;
|
||||
final String appName;
|
||||
final DateTime startTime;
|
||||
final DateTime endTime;
|
||||
final int duration; // 秒
|
||||
final String category;
|
||||
final int? projectId;
|
||||
final int deviceUnlockCount;
|
||||
final DateTime createdAt;
|
||||
final DateTime updatedAt;
|
||||
|
||||
AppUsage({
|
||||
this.id,
|
||||
required this.packageName,
|
||||
required this.appName,
|
||||
required this.startTime,
|
||||
required this.endTime,
|
||||
required this.duration,
|
||||
required this.category,
|
||||
this.projectId,
|
||||
this.deviceUnlockCount = 0,
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'id': id,
|
||||
'package_name': packageName,
|
||||
'app_name': appName,
|
||||
'start_time': startTime.millisecondsSinceEpoch ~/ 1000,
|
||||
'end_time': endTime.millisecondsSinceEpoch ~/ 1000,
|
||||
'duration': duration,
|
||||
'category': category,
|
||||
'project_id': projectId,
|
||||
'device_unlock_count': deviceUnlockCount,
|
||||
'created_at': createdAt.millisecondsSinceEpoch ~/ 1000,
|
||||
'updated_at': updatedAt.millisecondsSinceEpoch ~/ 1000,
|
||||
};
|
||||
}
|
||||
|
||||
factory AppUsage.fromMap(Map<String, dynamic> map) {
|
||||
return AppUsage(
|
||||
id: map['id'],
|
||||
packageName: map['package_name'],
|
||||
appName: map['app_name'],
|
||||
startTime: DateTime.fromMillisecondsSinceEpoch(map['start_time'] * 1000),
|
||||
endTime: DateTime.fromMillisecondsSinceEpoch(map['end_time'] * 1000),
|
||||
duration: map['duration'],
|
||||
category: map['category'],
|
||||
projectId: map['project_id'],
|
||||
deviceUnlockCount: map['device_unlock_count'] ?? 0,
|
||||
createdAt: DateTime.fromMillisecondsSinceEpoch(map['created_at'] * 1000),
|
||||
updatedAt: DateTime.fromMillisecondsSinceEpoch(map['updated_at'] * 1000),
|
||||
);
|
||||
}
|
||||
|
||||
// 格式化时长
|
||||
String get formattedDuration {
|
||||
final hours = duration ~/ 3600;
|
||||
final minutes = (duration % 3600) ~/ 60;
|
||||
if (hours > 0) {
|
||||
return '${hours}h ${minutes}m';
|
||||
}
|
||||
return '${minutes}m';
|
||||
}
|
||||
}
|
||||
|
||||
64
lib/models/daily_stats.dart
Normal file
64
lib/models/daily_stats.dart
Normal file
@@ -0,0 +1,64 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class DailyStats {
|
||||
final int? id;
|
||||
final DateTime date;
|
||||
final int totalTime; // 秒
|
||||
final int workTime;
|
||||
final int studyTime;
|
||||
final int entertainmentTime;
|
||||
final int socialTime;
|
||||
final int toolTime;
|
||||
final int? efficiencyScore;
|
||||
final int? focusScore;
|
||||
final int appSwitchCount;
|
||||
final DateTime createdAt;
|
||||
final DateTime updatedAt;
|
||||
|
||||
DailyStats({
|
||||
this.id,
|
||||
required this.date,
|
||||
required this.totalTime,
|
||||
this.workTime = 0,
|
||||
this.studyTime = 0,
|
||||
this.entertainmentTime = 0,
|
||||
this.socialTime = 0,
|
||||
this.toolTime = 0,
|
||||
this.efficiencyScore,
|
||||
this.focusScore,
|
||||
this.appSwitchCount = 0,
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
});
|
||||
|
||||
Map<String, int> get categoryTime => {
|
||||
'work': workTime,
|
||||
'study': studyTime,
|
||||
'entertainment': entertainmentTime,
|
||||
'social': socialTime,
|
||||
'tool': toolTime,
|
||||
};
|
||||
|
||||
// 格式化总时长
|
||||
String get formattedTotalTime {
|
||||
final hours = totalTime ~/ 3600;
|
||||
final minutes = (totalTime % 3600) ~/ 60;
|
||||
if (hours > 0) {
|
||||
return '${hours}h ${minutes}m';
|
||||
}
|
||||
return '${minutes}m';
|
||||
}
|
||||
|
||||
// 获取效率评分颜色
|
||||
Color get efficiencyColor {
|
||||
final score = efficiencyScore ?? 0;
|
||||
if (score >= 80) {
|
||||
return const Color(0xFF10B981); // Green
|
||||
} else if (score >= 50) {
|
||||
return const Color(0xFFF59E0B); // Orange
|
||||
} else {
|
||||
return const Color(0xFFEF4444); // Red
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
54
lib/models/time_goal.dart
Normal file
54
lib/models/time_goal.dart
Normal file
@@ -0,0 +1,54 @@
|
||||
class TimeGoal {
|
||||
final int? id;
|
||||
final String goalType; // 'daily_total' 或 'daily_category'
|
||||
final String? category; // 如果是分类目标,指定分类
|
||||
final int targetTime; // 目标时长(秒)
|
||||
final bool isActive;
|
||||
final DateTime createdAt;
|
||||
final DateTime updatedAt;
|
||||
|
||||
TimeGoal({
|
||||
this.id,
|
||||
required this.goalType,
|
||||
this.category,
|
||||
required this.targetTime,
|
||||
this.isActive = true,
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'id': id,
|
||||
'goal_type': goalType,
|
||||
'category': category,
|
||||
'target_time': targetTime,
|
||||
'is_active': isActive ? 1 : 0,
|
||||
'created_at': createdAt.millisecondsSinceEpoch ~/ 1000,
|
||||
'updated_at': updatedAt.millisecondsSinceEpoch ~/ 1000,
|
||||
};
|
||||
}
|
||||
|
||||
factory TimeGoal.fromMap(Map<String, dynamic> map) {
|
||||
return TimeGoal(
|
||||
id: map['id'] as int?,
|
||||
goalType: map['goal_type'] as String,
|
||||
category: map['category'] as String?,
|
||||
targetTime: map['target_time'] as int,
|
||||
isActive: (map['is_active'] as int) == 1,
|
||||
createdAt: DateTime.fromMillisecondsSinceEpoch((map['created_at'] as int) * 1000),
|
||||
updatedAt: DateTime.fromMillisecondsSinceEpoch((map['updated_at'] as int) * 1000),
|
||||
);
|
||||
}
|
||||
|
||||
// 格式化目标时长
|
||||
String get formattedTargetTime {
|
||||
final hours = targetTime ~/ 3600;
|
||||
final minutes = (targetTime % 3600) ~/ 60;
|
||||
if (hours > 0) {
|
||||
return '${hours}小时${minutes}分钟';
|
||||
}
|
||||
return '${minutes}分钟';
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user