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 readAccepted() => _storage.read(key: acceptedKey); @override State createState() => _TermsScreenState(); } class _TermsScreenState extends State { bool _saving = false; static const String _content = ''' 《视野》使用协议 感谢您使用「视野」动物观察应用。使用本应用前,请仔细阅读并同意以下条款: 一、用途限制 本应用仅用于野生动物观察、记录与科普学习,严禁用于任何非法用途。 二、禁止行为 1. 禁止近距离打扰、追逐、驱赶、恐吓野生动物; 2. 禁止投喂、诱捕、猎捕、伤害野生动物; 3. 禁止利用本应用从事盗猎、野生动物交易或其他违法犯罪活动; 4. 禁止进入自然保护区禁区、私人领地等未经许可的区域进行观察。 三、法律合规 您须遵守《中华人民共和国野生动物保护法》及相关法律法规。 因违法违规使用产生的一切后果由使用者自行承担。 四、安全提示 野外观察存在风险,请结伴而行、注意自身安全。因使用本应用产生的安全事故,本应用不承担责任。 五、识别结果说明 本应用的动物识别结果基于人工智能模型,可能存在误差或漏检,识别结果仅供参考,不构成科学鉴定或法律依据。 六、其他 本协议内容可能适时更新,更新后您继续使用即视为接受。'''; Future _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().readToken(); if (!mounted) return; Navigator.of(context) .pushReplacementNamed(token == null ? '/login' : '/home'); } Future _decline() async { if (_saving) return; final ok = await showDialog( 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('同意并继续'), ), ), ], ), ), ), ); } }