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,414 @@
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart' show kIsWeb;
import '../theme/app_theme.dart';
import '../database/app_usage_dao.dart';
import '../database/daily_stats_dao.dart';
class DataPrivacyScreen extends StatefulWidget {
const DataPrivacyScreen({super.key});
@override
State<DataPrivacyScreen> createState() => _DataPrivacyScreenState();
}
class _DataPrivacyScreenState extends State<DataPrivacyScreen> {
final AppUsageDao _appUsageDao = AppUsageDao();
final DailyStatsDao _dailyStatsDao = DailyStatsDao();
bool _isDeleting = false;
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Scaffold(
appBar: AppBar(
title: const Text('数据与隐私'),
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 隐私说明
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(Icons.security, color: AppTheme.primaryColor),
const SizedBox(width: 8),
Text(
'隐私保护',
style: theme.textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w600,
),
),
],
),
const SizedBox(height: 16),
_buildPrivacyItem(
theme,
Icons.storage,
'本地存储',
'所有数据仅存储在您的设备本地,不会上传到任何服务器。',
),
_buildPrivacyItem(
theme,
Icons.lock,
'数据加密',
'敏感数据在存储时进行加密处理,确保数据安全。',
),
_buildPrivacyItem(
theme,
Icons.visibility_off,
'隐私保护',
'我们不会收集您的个人信息,也不会追踪您的具体操作内容。',
),
_buildPrivacyItem(
theme,
Icons.delete_forever,
'完全控制',
'您可以随时删除所有数据,完全掌控您的隐私。',
),
],
),
),
),
const SizedBox(height: 16),
// 数据管理
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'数据管理',
style: theme.textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 16),
_buildDataAction(
context,
theme,
Icons.delete_outline,
'删除旧数据',
'删除 30 天前的数据',
Colors.orange,
() => _showDeleteOldDataDialog(context),
),
const SizedBox(height: 12),
_buildDataAction(
context,
theme,
Icons.delete_forever,
'清空所有数据',
'删除所有使用记录和统计数据',
Colors.red,
() => _showDeleteAllDataDialog(context),
),
],
),
),
),
const SizedBox(height: 16),
// 数据使用说明
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'数据使用说明',
style: theme.textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 12),
Text(
'• 应用使用数据仅用于统计和分析\n'
'• 数据不会离开您的设备\n'
'• 不会与第三方分享任何数据\n'
'• 不会用于广告或营销目的\n'
'• 您可以随时导出或删除数据',
style: theme.textTheme.bodyMedium,
),
],
),
),
),
],
),
),
);
}
Widget _buildPrivacyItem(ThemeData theme, IconData icon, String title, String description) {
return Padding(
padding: const EdgeInsets.only(bottom: 16),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(icon, color: AppTheme.primaryColor, size: 24),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: theme.textTheme.bodyLarge?.copyWith(
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 4),
Text(
description,
style: theme.textTheme.bodySmall?.copyWith(
color: theme.colorScheme.onSurface.withOpacity(0.6),
),
),
],
),
),
],
),
);
}
Widget _buildDataAction(
BuildContext context,
ThemeData theme,
IconData icon,
String title,
String subtitle,
Color color,
VoidCallback onTap,
) {
return InkWell(
onTap: _isDeleting ? null : onTap,
borderRadius: BorderRadius.circular(8),
child: Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
border: Border.all(color: color.withOpacity(0.3)),
borderRadius: BorderRadius.circular(8),
),
child: Row(
children: [
Icon(icon, color: color),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: theme.textTheme.bodyLarge?.copyWith(
fontWeight: FontWeight.w600,
color: color,
),
),
const SizedBox(height: 4),
Text(
subtitle,
style: theme.textTheme.bodySmall?.copyWith(
color: theme.colorScheme.onSurface.withOpacity(0.6),
),
),
],
),
),
if (_isDeleting)
const SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(strokeWidth: 2),
)
else
const Icon(Icons.chevron_right),
],
),
),
);
}
void _showDeleteOldDataDialog(BuildContext context) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('删除旧数据'),
content: const Text('确定要删除 30 天前的所有数据吗?此操作不可恢复。'),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('取消'),
),
ElevatedButton(
onPressed: () async {
Navigator.of(context).pop();
await _deleteOldData(context);
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.orange,
),
child: const Text('删除'),
),
],
),
);
}
void _showDeleteAllDataDialog(BuildContext context) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('清空所有数据'),
content: const Text(
'确定要删除所有使用记录和统计数据吗?\n\n'
'此操作将:\n'
'• 删除所有应用使用记录\n'
'• 删除所有统计数据\n'
'• 删除所有分类设置\n'
'• 删除所有目标设置\n\n'
'此操作不可恢复!',
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('取消'),
),
ElevatedButton(
onPressed: () async {
Navigator.of(context).pop();
await _deleteAllData(context);
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red,
),
child: const Text('确认删除'),
),
],
),
);
}
Future<void> _deleteOldData(BuildContext context) async {
if (kIsWeb) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Web 平台不支持数据删除功能'),
backgroundColor: AppTheme.warningColor,
),
);
return;
}
setState(() {
_isDeleting = true;
});
try {
final thirtyDaysAgo = DateTime.now().subtract(const Duration(days: 30));
await _appUsageDao.deleteBeforeDate(thirtyDaysAgo);
await _dailyStatsDao.deleteBeforeDate(thirtyDaysAgo);
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('已删除 30 天前的数据'),
backgroundColor: AppTheme.successColor,
),
);
}
} catch (e) {
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('删除失败: $e'),
backgroundColor: AppTheme.errorColor,
),
);
}
} finally {
if (mounted) {
setState(() {
_isDeleting = false;
});
}
}
}
Future<void> _deleteAllData(BuildContext context) async {
if (kIsWeb) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Web 平台不支持数据删除功能'),
backgroundColor: AppTheme.warningColor,
),
);
return;
}
setState(() {
_isDeleting = true;
});
try {
// 删除所有应用使用记录
final allUsages = await _appUsageDao.getAppUsages(
startTime: DateTime(2000),
endTime: DateTime.now(),
);
for (final usage in allUsages) {
if (usage.id != null) {
await _appUsageDao.deleteAppUsage(usage.id!);
}
}
// 删除所有统计数据
final allStats = await _dailyStatsDao.getStatsRange(
startDate: DateTime(2000),
endDate: DateTime.now(),
);
for (final stat in allStats) {
if (stat.id != null) {
await _dailyStatsDao.deleteDailyStats(stat.id!);
}
}
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('已清空所有数据'),
backgroundColor: AppTheme.successColor,
),
);
}
} catch (e) {
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('删除失败: $e'),
backgroundColor: AppTheme.errorColor,
),
);
}
} finally {
if (mounted) {
setState(() {
_isDeleting = false;
});
}
}
}
}