first commit

This commit is contained in:
ytc1012
2025-11-13 15:45:28 +08:00
commit 6b321890c0
54 changed files with 8412 additions and 0 deletions

View File

@@ -0,0 +1,182 @@
import 'package:flutter/services.dart';
import '../models/app_usage.dart';
import '../database/app_usage_dao.dart';
import 'category_service.dart';
import 'statistics_service.dart';
class TimeTrackingService {
static const MethodChannel _channel = MethodChannel('autotime_tracker/time_tracking');
final AppUsageDao _appUsageDao = AppUsageDao();
final CategoryService _categoryService = CategoryService();
final StatisticsService _statisticsService = StatisticsService();
/// 检查权限状态
Future<bool> hasPermission() async {
try {
final result = await _channel.invokeMethod<bool>('hasPermission');
return result ?? false;
} catch (e) {
print('Error checking permission: $e');
return false;
}
}
/// 请求权限
Future<bool> requestPermission() async {
try {
final result = await _channel.invokeMethod<bool>('requestPermission');
return result ?? false;
} catch (e) {
print('Error requesting permission: $e');
return false;
}
}
/// 获取应用使用数据(从系统 API
Future<List<AppUsageData>> getAppUsageFromSystem({
required DateTime startTime,
required DateTime endTime,
}) async {
try {
final result = await _channel.invokeMethod<List<dynamic>>('getAppUsage', {
'startTime': startTime.millisecondsSinceEpoch,
'endTime': endTime.millisecondsSinceEpoch,
});
if (result == null) return [];
return result
.map((item) => AppUsageData.fromMap(Map<String, dynamic>.from(item)))
.toList();
} catch (e) {
print('Error getting app usage from system: $e');
return [];
}
}
/// 同步应用使用数据到数据库
Future<void> syncAppUsageToDatabase({
required DateTime startTime,
required DateTime endTime,
}) async {
try {
// 1. 从系统获取数据
final systemData = await getAppUsageFromSystem(
startTime: startTime,
endTime: endTime,
);
if (systemData.isEmpty) {
print('No app usage data from system');
return;
}
// 2. 转换为 AppUsage 模型并分类
final appUsages = <AppUsage>[];
for (final data in systemData) {
// 获取分类
final category = await _categoryService.getCategory(data.packageName);
// 创建 AppUsage 对象
final usage = AppUsage(
packageName: data.packageName,
appName: data.appName,
startTime: data.startTime,
endTime: data.endTime,
duration: data.duration,
category: category,
deviceUnlockCount: data.deviceUnlockCount ?? 0,
createdAt: DateTime.now(),
updatedAt: DateTime.now(),
);
appUsages.add(usage);
}
// 3. 批量插入数据库
if (appUsages.isNotEmpty) {
await _appUsageDao.batchInsertAppUsages(appUsages);
print('Synced ${appUsages.length} app usage records to database');
}
// 4. 更新今日统计
await _statisticsService.refreshTodayStats();
} catch (e) {
print('Error syncing app usage to database: $e');
rethrow;
}
}
/// 同步今日数据
Future<void> syncTodayData() async {
final now = DateTime.now();
final startOfDay = DateTime(now.year, now.month, now.day);
final endOfDay = startOfDay.add(const Duration(days: 1));
await syncAppUsageToDatabase(
startTime: startOfDay,
endTime: endOfDay,
);
}
/// 启动后台追踪
Future<void> startBackgroundTracking() async {
try {
await _channel.invokeMethod('startBackgroundTracking');
} catch (e) {
print('Error starting background tracking: $e');
}
}
/// 停止后台追踪
Future<void> stopBackgroundTracking() async {
try {
await _channel.invokeMethod('stopBackgroundTracking');
} catch (e) {
print('Error stopping background tracking: $e');
}
}
/// 检查后台追踪状态
Future<bool> isBackgroundTrackingActive() async {
try {
final result = await _channel.invokeMethod<bool>('isBackgroundTrackingActive');
return result ?? false;
} catch (e) {
print('Error checking background tracking status: $e');
return false;
}
}
}
/// 系统返回的应用使用数据模型
class AppUsageData {
final String packageName;
final String appName;
final DateTime startTime;
final DateTime endTime;
final int duration; // 秒
final int? deviceUnlockCount;
AppUsageData({
required this.packageName,
required this.appName,
required this.startTime,
required this.endTime,
required this.duration,
this.deviceUnlockCount,
});
factory AppUsageData.fromMap(Map<String, dynamic> map) {
return AppUsageData(
packageName: map['packageName'] as String,
appName: map['appName'] as String,
startTime: DateTime.fromMillisecondsSinceEpoch(map['startTime'] as int),
endTime: DateTime.fromMillisecondsSinceEpoch(map['endTime'] as int),
duration: map['duration'] as int,
deviceUnlockCount: map['deviceUnlockCount'] as int?,
);
}
}