Files
AutoTime-Tracker/lib/services/time_tracking_service.dart
2025-11-13 15:45:28 +08:00

183 lines
5.0 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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?,
);
}
}