software copyright

This commit is contained in:
jiahong
2026-03-22 15:24:40 +08:00
parent e303bb868a
commit 60f336e345
155 changed files with 127262 additions and 0 deletions
@@ -0,0 +1,367 @@
/// 自然写互动课堂平板端应用软件 V1.0
/// 护眼管理器 - 色温调节、使用时长监控、距离检测
///
/// 功能说明:
/// 1. 色温调节(暖色滤镜,减少蓝光对眼睛的刺激)
/// 2. 使用时长监控(按应用/科目统计,超时提醒休息)
/// 3. 距离检测(前置摄像头检测用眼距离,过近时提醒)
/// 4. 定时提醒(每30分钟提醒休息,远眺放松)
/// 5. 家长远程管控(接收家长设置的时段/时长限制)
/// 6. 护眼数据统计(每日使用时长报告)
import 'dart:async';
/// 护眼模式配置
class EyeCareConfig {
/// 是否启用护眼模式
bool enabled;
/// 色温强度(0.0=关闭, 1.0=最暖)
double colorTemperature;
/// 连续使用提醒间隔(分钟)
int reminderIntervalMinutes;
/// 每日使用时长上限(分钟,0=不限制)
int dailyLimitMinutes;
/// 允许使用的时段(开始小时, 结束小时)
int allowedStartHour;
int allowedEndHour;
/// 是否启用距离检测
bool distanceDetectionEnabled;
/// 安全用眼距离(厘米)
int safeDistanceCm;
/// 夜间模式自动开启时间(小时)
int nightModeStartHour;
int nightModeEndHour;
EyeCareConfig({
this.enabled = true,
this.colorTemperature = 0.3,
this.reminderIntervalMinutes = 30,
this.dailyLimitMinutes = 120,
this.allowedStartHour = 7,
this.allowedEndHour = 21,
this.distanceDetectionEnabled = false,
this.safeDistanceCm = 30,
this.nightModeStartHour = 20,
this.nightModeEndHour = 7,
});
Map<String, dynamic> toJson() => {
'enabled': enabled,
'color_temperature': colorTemperature,
'reminder_interval': reminderIntervalMinutes,
'daily_limit': dailyLimitMinutes,
'allowed_start': allowedStartHour,
'allowed_end': allowedEndHour,
'distance_enabled': distanceDetectionEnabled,
'safe_distance': safeDistanceCm,
'night_start': nightModeStartHour,
'night_end': nightModeEndHour,
};
factory EyeCareConfig.fromJson(Map<String, dynamic> json) {
return EyeCareConfig(
enabled: json['enabled'] ?? true,
colorTemperature: (json['color_temperature'] ?? 0.3).toDouble(),
reminderIntervalMinutes: json['reminder_interval'] ?? 30,
dailyLimitMinutes: json['daily_limit'] ?? 120,
allowedStartHour: json['allowed_start'] ?? 7,
allowedEndHour: json['allowed_end'] ?? 21,
distanceDetectionEnabled: json['distance_enabled'] ?? false,
safeDistanceCm: json['safe_distance'] ?? 30,
nightModeStartHour: json['night_start'] ?? 20,
nightModeEndHour: json['night_end'] ?? 7,
);
}
}
/// 使用时长记录
class UsageRecord {
final String date; // 日期 (yyyy-MM-dd)
final String category; // 分类 (homework/practice/reading)
final int durationMinutes; // 使用时长(分钟)
final int sessionCount; // 使用次数
UsageRecord({
required this.date,
required this.category,
required this.durationMinutes,
required this.sessionCount,
});
Map<String, dynamic> toJson() => {
'date': date, 'category': category,
'duration': durationMinutes, 'sessions': sessionCount,
};
}
/// 护眼事件类型
enum EyeCareEvent {
restReminder, // 休息提醒
dailyLimitReached, // 每日时长上限
outsideAllowedTime, // 超出允许使用时段
tooCloseWarning, // 用眼距离过近
nightModeOn, // 夜间模式开启
nightModeOff, // 夜间模式关闭
}
/// 护眼事件回调
typedef EyeCareEventCallback = void Function(EyeCareEvent event, Map<String, dynamic> data);
/// 护眼管理器
class EyeCareManager {
/// 护眼配置
EyeCareConfig _config = EyeCareConfig();
/// 事件回调列表
final List<EyeCareEventCallback> _callbacks = [];
/// 当前会话开始时间
DateTime? _sessionStartTime;
/// 今日累计使用时长(秒)
int _todayUsageSeconds = 0;
/// 当前连续使用时长(秒)
int _continuousUsageSeconds = 0;
/// 今日使用记录
final Map<String, int> _categoryUsage = {};
/// 计时器(每秒更新使用时长)
Timer? _usageTimer;
/// 距离检测计时器
Timer? _distanceTimer;
/// 夜间模式检查计时器
Timer? _nightModeTimer;
/// 当前是否在夜间模式
bool _isNightMode = false;
/// 当前色温值(供外部读取)
double get currentColorTemperature {
if (!_config.enabled) return 0.0;
if (_isNightMode) return _config.colorTemperature * 1.5; // 夜间加强
return _config.colorTemperature;
}
/// 今日总使用时长(分钟)
int get todayUsageMinutes => _todayUsageSeconds ~/ 60;
/// 剩余可用时长(分钟,-1表示不限制)
int get remainingMinutes {
if (_config.dailyLimitMinutes <= 0) return -1;
return _config.dailyLimitMinutes - todayUsageMinutes;
}
/// 注册事件回调
void addCallback(EyeCareEventCallback callback) {
_callbacks.add(callback);
}
/// 移除事件回调
void removeCallback(EyeCareEventCallback callback) {
_callbacks.remove(callback);
}
/// 更新配置(家长远程设置后调用)
void updateConfig(EyeCareConfig newConfig) {
_config = newConfig;
if (_config.enabled) {
_startMonitoring();
} else {
_stopMonitoring();
}
}
/// 开始使用(进入学习功能时调用)
void startSession({String category = 'default'}) {
_sessionStartTime = DateTime.now();
_continuousUsageSeconds = 0;
// 检查是否在允许时段内
final now = DateTime.now();
if (_config.enabled && !_isWithinAllowedTime(now)) {
_notifyEvent(EyeCareEvent.outsideAllowedTime, {
'allowed_start': _config.allowedStartHour,
'allowed_end': _config.allowedEndHour,
});
}
// 启动使用时长计时器
_usageTimer?.cancel();
_usageTimer = Timer.periodic(const Duration(seconds: 1), (_) {
_todayUsageSeconds++;
_continuousUsageSeconds++;
// 检查连续使用时长提醒
if (_config.reminderIntervalMinutes > 0 &&
_continuousUsageSeconds > 0 &&
_continuousUsageSeconds % (_config.reminderIntervalMinutes * 60) == 0) {
_notifyEvent(EyeCareEvent.restReminder, {
'continuous_minutes': _continuousUsageSeconds ~/ 60,
'total_minutes': todayUsageMinutes,
});
}
// 检查每日使用上限
if (_config.dailyLimitMinutes > 0 &&
todayUsageMinutes >= _config.dailyLimitMinutes) {
_notifyEvent(EyeCareEvent.dailyLimitReached, {
'limit_minutes': _config.dailyLimitMinutes,
'used_minutes': todayUsageMinutes,
});
}
});
// 启动距离检测
if (_config.distanceDetectionEnabled) {
_startDistanceDetection();
}
// 启动夜间模式检查
_startNightModeCheck();
}
/// 结束使用(退出学习功能时调用)
void endSession({String category = 'default'}) {
_usageTimer?.cancel();
_usageTimer = null;
if (_sessionStartTime != null) {
final duration = DateTime.now().difference(_sessionStartTime!).inMinutes;
_categoryUsage[category] = (_categoryUsage[category] ?? 0) + duration;
}
_sessionStartTime = null;
_continuousUsageSeconds = 0;
_distanceTimer?.cancel();
_distanceTimer = null;
}
/// 用户休息后重置连续使用计时
void acknowledgeRest() {
_continuousUsageSeconds = 0;
}
/// 检查当前时间是否在允许使用时段内
bool _isWithinAllowedTime(DateTime time) {
final hour = time.hour;
if (_config.allowedStartHour <= _config.allowedEndHour) {
return hour >= _config.allowedStartHour && hour < _config.allowedEndHour;
} else {
// 跨午夜的情况
return hour >= _config.allowedStartHour || hour < _config.allowedEndHour;
}
}
/// 启动监控
void _startMonitoring() {
_startNightModeCheck();
}
/// 停止监控
void _stopMonitoring() {
_usageTimer?.cancel();
_distanceTimer?.cancel();
_nightModeTimer?.cancel();
}
/// 启动距离检测(通过前置摄像头估算用眼距离)
void _startDistanceDetection() {
_distanceTimer?.cancel();
_distanceTimer = Timer.periodic(const Duration(seconds: 10), (_) {
// 调用前置摄像头进行人脸检测
// 通过人脸框大小估算距离(人脸越大=距离越近)
_checkEyeDistance();
});
}
/// 检查用眼距离(基于前置摄像头人脸检测)
void _checkEyeDistance() {
// 实际实现:
// 1. 使用CameraController获取前置摄像头预览帧
// 2. 使用MLKit/TFLite进行人脸检测
// 3. 根据人脸框宽度估算距离: distance = (focal_length * real_face_width) / face_width_in_pixels
// 4. 本地处理,不上传图像数据(隐私保护)
// 模拟距离检测结果
final estimatedDistanceCm = 35; // 实际从摄像头计算
if (estimatedDistanceCm < _config.safeDistanceCm) {
_notifyEvent(EyeCareEvent.tooCloseWarning, {
'current_distance': estimatedDistanceCm,
'safe_distance': _config.safeDistanceCm,
});
}
}
/// 启动夜间模式检查
void _startNightModeCheck() {
_nightModeTimer?.cancel();
_nightModeTimer = Timer.periodic(const Duration(minutes: 1), (_) {
final hour = DateTime.now().hour;
final shouldBeNightMode = _isNightTimeHour(hour);
if (shouldBeNightMode && !_isNightMode) {
_isNightMode = true;
_notifyEvent(EyeCareEvent.nightModeOn, {});
} else if (!shouldBeNightMode && _isNightMode) {
_isNightMode = false;
_notifyEvent(EyeCareEvent.nightModeOff, {});
}
});
// 立即检查一次
final hour = DateTime.now().hour;
_isNightMode = _isNightTimeHour(hour);
}
/// 判断是否为夜间时段
bool _isNightTimeHour(int hour) {
if (_config.nightModeStartHour <= _config.nightModeEndHour) {
return hour >= _config.nightModeStartHour && hour < _config.nightModeEndHour;
} else {
return hour >= _config.nightModeStartHour || hour < _config.nightModeEndHour;
}
}
/// 获取今日使用统计
List<UsageRecord> getTodayUsageRecords() {
final today = DateTime.now().toString().substring(0, 10);
return _categoryUsage.entries.map((e) => UsageRecord(
date: today,
category: e.key,
durationMinutes: e.value,
sessionCount: 1,
)).toList();
}
/// 通知事件到所有回调
void _notifyEvent(EyeCareEvent event, Map<String, dynamic> data) {
for (final callback in _callbacks) {
try {
callback(event, data);
} catch (e) {
// 忽略回调异常
}
}
}
/// 释放资源
void dispose() {
_usageTimer?.cancel();
_distanceTimer?.cancel();
_nightModeTimer?.cancel();
_callbacks.clear();
}
}