Files
observer/flutter_app/lib/legal/terms_screen.dart
T
admin a0b115d954 训练体系整合与标注单阶段化
- 标注:AI 预标注直写 labels_json(去候选确认两阶段);重叠去重(minIoU);全量标注按钮
- 训练:脚本迁移入 server/training/(Go 化 prepare_yolo/analyze_rfdetr,保留 train_server.py);tflite 产物自检并入训练流程(check_tflite)
- 数据目录/权重不进 git;.gitignore 迁移至仓库根
2026-08-26 18:22:56 +08:00

127 lines
4.3 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show SystemNavigator;
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:provider/provider.dart';
import '../auth/session_store.dart';
/// 使用协议页:首次启动强制展示,同意后记录(secure storage),拒绝则退出应用。
/// 用途声明:仅限动物观察,禁止近距离打扰与非法使用。
class TermsScreen extends StatefulWidget {
const TermsScreen({super.key});
static const _storage = FlutterSecureStorage();
static const acceptedKey = 'terms_accepted';
static Future<String?> readAccepted() => _storage.read(key: acceptedKey);
@override
State<TermsScreen> createState() => _TermsScreenState();
}
class _TermsScreenState extends State<TermsScreen> {
bool _saving = false;
static const String _content = '''
《视野》使用协议
感谢您使用「视野」动物观察应用。使用本应用前,请仔细阅读并同意以下条款:
一、用途限制
本应用仅用于动物观察、记录与科普学习,严禁用于任何非法用途。
二、禁止行为
1. 禁止近距离打扰、追逐、驱赶、恐吓动物;
2. 禁止投喂、诱捕、猎捕、伤害动物;
3. 禁止利用本应用从事盗猎、动物交易或其他违法犯罪活动;
4. 禁止进入自然保护区禁区、私人领地等未经许可的区域进行观察。
三、法律合规
您须遵守《中华人民共和国野生动物保护法》及相关法律法规。
因违法违规使用产生的一切后果由使用者自行承担。
四、安全提示
野外观察存在风险,请结伴而行、注意自身安全。因使用本应用产生的安全事故,本应用不承担责任。
五、识别结果说明
本应用的动物识别结果基于人工智能模型,可能存在误差或漏检,识别结果仅供参考,不构成科学鉴定或法律依据。
六、其他
本协议内容可能适时更新,更新后您继续使用即视为接受。''';
Future<void> _accept() async {
if (_saving) return;
setState(() => _saving = true);
await TermsScreen._storage.write(key: TermsScreen.acceptedKey, value: '1');
if (!mounted) return;
final token = await context.read<SessionStore>().readToken();
if (!mounted) return;
Navigator.of(context)
.pushReplacementNamed(token == null ? '/login' : '/home');
}
Future<void> _decline() async {
if (_saving) return;
final ok = await showDialog<bool>(
context: context,
builder: (ctx) => AlertDialog(
title: const Text('需要同意协议'),
content: const Text('不同意《使用协议》将无法使用本应用。'),
actions: [
TextButton(
onPressed: () => Navigator.of(ctx).pop(false),
child: const Text('再看看'),
),
TextButton(
onPressed: () => Navigator.of(ctx).pop(true),
child: const Text('退出'),
),
],
),
);
if (ok == true && mounted) await SystemNavigator.pop();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('使用协议')),
body: SingleChildScrollView(
padding: const EdgeInsets.all(20),
child: Text(
_content,
style: const TextStyle(fontSize: 15, height: 1.7),
),
),
bottomNavigationBar: SafeArea(
child: Padding(
padding: const EdgeInsets.fromLTRB(20, 8, 20, 16),
child: Row(
children: [
Expanded(
child: OutlinedButton(
onPressed: _saving ? null : _decline,
child: const Text('不同意'),
),
),
const SizedBox(width: 16),
Expanded(
child: FilledButton(
onPressed: _saving ? null : _accept,
child: _saving
? const SizedBox(
width: 18,
height: 18,
child: CircularProgressIndicator(strokeWidth: 2),
)
: const Text('同意并继续'),
),
),
],
),
),
),
);
}
}