import 'package:flutter/material.dart'; import '../api/oa_client.dart'; import '../device/push_bridge.dart'; import '../app_config.dart'; import '../labels.dart'; import '../ota/updater.dart'; import '../pages/legal_page.dart'; import '../pages/profile_page.dart'; import '../session/session.dart'; import '../theme.dart'; import '../widgets/beian_footer.dart'; import '../widgets/desktop_ui.dart'; import '../widgets/wecom.dart'; class MinePage extends StatefulWidget { const MinePage({super.key, required this.session, required this.api, this.desktopStyle = false}); final SessionStore session; final OaClient api; final bool desktopStyle; @override State createState() => _MinePageState(); } class _MinePageState extends State { AppRelease? _rel; bool _checking = false; @override void initState() { super.initState(); widget.session.addListener(_onSession); _peek(); } @override void dispose() { widget.session.removeListener(_onSession); super.dispose(); } void _onSession() { if (mounted) setState(() {}); } Future _peek() async { final rel = await OtaUpdater(widget.api).fetch(); if (mounted) setState(() => _rel = rel); } Future _logout() async { try { await widget.api .post('/auth/logout', {'refreshToken': widget.session.refreshToken}); } catch (_) {} await widget.session.clear(); } Future _checkUpdate() async { setState(() => _checking = true); try { final rel = await OtaUpdater(widget.api).fetch(); if (!mounted) return; setState(() => _rel = rel); if (rel == null) { ScaffoldMessenger.of(context) .showSnackBar(const SnackBar(content: Text('暂时无法检查更新'))); return; } await OtaUpdater(widget.api).prompt(context, rel, manual: true); } finally { if (mounted) setState(() => _checking = false); } } @override Widget build(BuildContext context) { final s = widget.session; final avatarId = '${s.user['avatarFileId'] ?? ''}'; return ColoredBox( color: widget.desktopStyle ? kDeskBg : kPaper, child: Column( children: [ widget.desktopStyle ? const DesktopPaneHeader(title: '我') : const WxHeader(title: '我'), Expanded( child: widget.desktopStyle ? Center( child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 720), child: ListView( padding: const EdgeInsets.fromLTRB(20, 16, 20, 24), children: _mineItems(s, avatarId), ), ), ) : ListView( children: _mineItems(s, avatarId), ), ), ], ), ); } List _mineItems(SessionStore s, String avatarId) { return [ const SizedBox(height: 12), Material( color: Colors.white, child: InkWell( onTap: () => Navigator.of(context).push(MaterialPageRoute( builder: (_) => ProfilePage(session: s, api: widget.api), )), child: Padding( padding: const EdgeInsets.fromLTRB(16, 16, 16, 16), child: Row( children: [ SquareAvatar( label: s.displayName, size: 64, fileId: avatarId.isEmpty ? null : avatarId, api: widget.api, ), const SizedBox(width: 14), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(s.displayName, style: const TextStyle( fontSize: 20, fontWeight: FontWeight.w600)), const SizedBox(height: 4), Text('账号 ${s.user['username'] ?? ''}', style: const TextStyle( color: kMute, fontSize: 13)), Text(s.roles.map(zh).join(' · '), style: const TextStyle( color: kMute, fontSize: 12)), ], ), ), const Icon(Icons.chevron_right, color: Color(0xFFC0C0C0)), ], ), ), ), ), const SizedBox(height: 12), CellGroup( children: [ if (!widget.desktopStyle) Cell( title: '后台运行与通知', subtitle: '允许自启动和后台,消息才能及时送达', leading: const SquareAvatar( label: '通', color: kBind, icon: Icons.notifications_active_outlined, size: 32), onTap: () async { await PushBridge.requestBattery(); await PushBridge.openOemKeepAlive(); }, ), if (!widget.desktopStyle) Cell( title: '检查更新', subtitle: _rel != null && _rel!.newer ? '有新版本 ${_rel!.version}' : '当前 ${AppConfig.version} (${AppConfig.build})', leading: const SquareAvatar( label: '升', color: kBind, icon: Icons.system_update_alt, size: 32), trailing: _checking ? const SizedBox( width: 18, height: 18, child: CircularProgressIndicator(strokeWidth: 2)) : (_rel != null && _rel!.newer ? const UnreadBadge(1, dot: true) : null), onTap: _checkUpdate, ), if (widget.desktopStyle) Cell( title: '检查更新', subtitle: _rel != null && _rel!.newer ? '有新版本 ${_rel!.version}' : '当前 ${AppConfig.version} (${AppConfig.build})', leading: const SquareAvatar( label: '升', color: kBind, icon: Icons.system_update_alt, size: 32), trailing: _checking ? const SizedBox( width: 18, height: 18, child: CircularProgressIndicator(strokeWidth: 2)) : (_rel != null && _rel!.newer ? const UnreadBadge(1, dot: true) : null), onTap: _checkUpdate, ), Cell( title: '用户协议', leading: const SquareAvatar( label: '协', color: kBind, icon: Icons.article_outlined, size: 32), onTap: () => Navigator.of(context).push( MaterialPageRoute( builder: (_) => LegalPage( api: widget.api, kind: 'user-agreement')), ), ), Cell( title: '隐私政策', leading: const SquareAvatar( label: '私', color: kBind, icon: Icons.privacy_tip_outlined, size: 32), onTap: () => Navigator.of(context).push( MaterialPageRoute( builder: (_) => LegalPage(api: widget.api, kind: 'privacy')), ), showLine: false, ), ], ), Padding( padding: const EdgeInsets.fromLTRB(12, 8, 12, 8), child: Material( color: Colors.white, borderRadius: BorderRadius.circular(8), child: InkWell( onTap: _logout, borderRadius: BorderRadius.circular(8), child: const SizedBox( height: 48, child: Center( child: Text('退出登录', style: TextStyle(fontSize: 16, color: kDanger))), ), ), ), ), const SizedBox(height: 8), Text( '${AppConfig.brand}\n${AppConfig.version} (${AppConfig.build})', textAlign: TextAlign.center, style: const TextStyle(color: kMute, fontSize: 12, height: 1.5), ), const BeianFooter(), ]; } }