import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../auth/session_store.dart'; import 'home_view_model.dart'; /// 主界面:当前账号到期时间 + 搜索按钮(强制服务端校验后进相机)+ 充值入口 class HomeScreen extends StatefulWidget { const HomeScreen({super.key}); @override State createState() => _HomeScreenState(); } class _HomeScreenState extends State { @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { context.read().refresh(); }); } Future _onSearch() async { final vm = context.read(); final allowed = await vm.verifyForCamera(); if (!mounted) return; if (vm.sessionExpired) { _toLogin(); return; } if (!allowed) { if (vm.error != null) { // 网络/服务端异常:无法确认授权状态,提示错误 _showBlocked(vm.error); return; } // 服务端确认无有效授权:直接进充值页 await _onRecharge(); return; } await Navigator.of(context).pushNamed('/camera'); if (mounted) vm.refresh(); } Future _onRecharge() async { await Navigator.of(context).pushNamed('/paywall'); if (mounted) context.read().refresh(); } Future _toLogin() async { final container = context.read(); await container.clear(); if (!mounted) return; Navigator.of(context).pushReplacementNamed('/login'); } void _showBlocked(String? error) { showDialog( context: context, builder: (ctx) => AlertDialog( title: const Text('授权不可用'), content: Text(error ?? '授权已过期,请充值后续费'), actions: [ TextButton( onPressed: () => Navigator.of(ctx).pop(), child: const Text('取消'), ), FilledButton( onPressed: () { Navigator.of(ctx).pop(); _onRecharge(); }, child: const Text('去充值'), ), ], ), ); } @override Widget build(BuildContext context) { final vm = context.watch(); final license = vm.license; final active = license?.isActive ?? false; final statusText = vm.loading ? '加载中…' : (license == null || license.expiresAt == null ? '未充值' : (active ? '有效至 ${_fmt(license.expiresAt!)}' : '已过期(${_fmt(license.expiresAt!)})')); return Scaffold( appBar: AppBar( title: const Text('视野'), centerTitle: true, actions: [ IconButton( tooltip: '退出登录', icon: const Icon(Icons.logout), onPressed: _toLogin, ), ], ), body: SafeArea( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 24), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const SizedBox(height: 24), _StatusCard( licenseText: statusText, active: active, ), const SizedBox(height: 40), SizedBox( height: 88, child: FilledButton.icon( onPressed: vm.verifying ? null : _onSearch, style: FilledButton.styleFrom( backgroundColor: Colors.green, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(44), ), ), icon: vm.verifying ? const SizedBox( width: 24, height: 24, child: CircularProgressIndicator( strokeWidth: 2, color: Colors.white), ) : const Icon(Icons.visibility, size: 32), label: Text( vm.verifying ? '正在校验授权…' : '打开视野', style: const TextStyle( fontSize: 22, fontWeight: FontWeight.w600), ), ), ), const SizedBox(height: 16), SizedBox( height: 52, child: OutlinedButton.icon( onPressed: _onRecharge, icon: const Icon(Icons.payment), label: const Text('充值', style: TextStyle(fontSize: 16)), ), ), if (vm.error != null && vm.license != null) ...[ const SizedBox(height: 16), Text( vm.error!, textAlign: TextAlign.center, style: const TextStyle(color: Colors.red), ), ], ], ), ), ), ); } static String _fmt(DateTime t) { String p(int n) => n.toString().padLeft(2, '0'); return '${t.year}-${p(t.month)}-${p(t.day)} ${p(t.hour)}:${p(t.minute)}'; } } class _StatusCard extends StatelessWidget { final String licenseText; final bool active; const _StatusCard({ required this.licenseText, required this.active, }); @override Widget build(BuildContext context) { return Card( child: Padding( padding: const EdgeInsets.all(20), child: Row( children: [ Icon( active ? Icons.verified_user : Icons.error_outline, color: active ? Colors.green : Colors.orange, size: 36, ), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('当前账户', style: TextStyle( color: Colors.grey.shade600, fontSize: 13)), const SizedBox(height: 4), Text( licenseText, style: const TextStyle( fontSize: 18, fontWeight: FontWeight.w600), ), ], ), ), ], ), ), ); } }