Files
tongxunruanjian/mobile/lib/screens/mine_screen.dart
T
编码工程师andmultica-agent f1fe4a3928 feat(mobile,deploy): 接入安卓极光与华为通道并准备公网部署配置
客户端默认指向 jxd.jinniu.ink 的 HTTPS/WSS;登录后把 OpenIM userID 设为极光 alias。
华为 agconnect-services.json 不伪造、不入库。Master Secret 只从服务器文件注入。

Co-authored-by: multica-agent <github@multica.ai>
2026-08-30 21:32:58 +08:00

185 lines
6.6 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_openim_sdk/flutter_openim_sdk.dart';
import '../services/im_service.dart';
import '../services/push_service.dart';
import '../theme.dart';
import '../widgets/avatar.dart';
import 'login_screen.dart';
/// 「我的」页:大头像 + 姓名 + 工号,设置 / 关于 / 退出登录
class MineScreen extends StatefulWidget {
const MineScreen({super.key});
@override
State<MineScreen> createState() => _MineScreenState();
}
class _MineScreenState extends State<MineScreen> {
@override
void initState() {
super.initState();
IMService.instance.refreshSelfInfo();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('我的')),
body: AnimatedBuilder(
animation: IMService.instance,
builder: (context, _) {
final user = IMService.instance.selfInfo;
final nickname = user?.nickname?.isNotEmpty == true ? user!.nickname! : '';
final userID = IMService.instance.currentUserID ?? '';
return ListView(
children: [
// 头部:大头像 + 姓名 + 工号
Container(
color: AppColors.pageBg,
padding: const EdgeInsets.all(AppGap.x4),
child: Row(
children: [
NameAvatar(name: nickname.isNotEmpty ? nickname : userID, faceURL: user?.faceURL, size: 64),
const SizedBox(width: AppGap.x4),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
nickname.isNotEmpty ? nickname : userID,
style: const TextStyle(fontSize: AppFont.title, fontWeight: FontWeight.w600, color: AppColors.textPrimary),
),
const SizedBox(height: AppGap.x1),
Text(
'工号:$userID',
style: const TextStyle(fontSize: AppFont.sub, color: AppColors.textSecondary),
),
],
),
],
),
),
const SizedBox(height: AppGap.x3),
_item(Icons.settings_outlined, '设置', () => _showSettings(nickname)),
const Divider(indent: AppGap.x4),
_item(Icons.info_outline, '关于', _showAbout),
const Divider(indent: AppGap.x4),
ListTile(
leading: const Icon(Icons.logout, color: AppColors.danger),
title: const Text('退出登录', style: TextStyle(fontSize: AppFont.body, color: AppColors.danger)),
onTap: _confirmLogout,
),
],
);
},
),
);
}
Widget _item(IconData icon, String label, VoidCallback onTap) {
return ListTile(
leading: Icon(icon, color: AppColors.textPrimary),
title: Text(label, style: const TextStyle(fontSize: AppFont.body)),
trailing: const Icon(Icons.chevron_right, color: AppColors.textSecondary),
onTap: onTap,
);
}
/// 设置:目前只有修改昵称
void _showSettings(String currentNickname) {
final ctrl = TextEditingController(text: currentNickname);
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (ctx) => Padding(
padding: EdgeInsets.only(
left: AppGap.x4,
right: AppGap.x4,
top: AppGap.x4,
bottom: MediaQuery.of(ctx).viewInsets.bottom + AppGap.x4,
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Text('修改昵称', style: TextStyle(fontSize: AppFont.title, fontWeight: FontWeight.w600)),
const SizedBox(height: AppGap.x4),
TextField(
controller: ctrl,
decoration: InputDecoration(
hintText: '请输入新昵称',
filled: true,
fillColor: AppColors.searchBg,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide.none,
),
),
),
const SizedBox(height: AppGap.x4),
FilledButton(
onPressed: () async {
final name = ctrl.text.trim();
if (name.isEmpty) return;
try {
await OpenIM.iMManager.userManager.setSelfInfo(nickname: name);
await IMService.instance.refreshSelfInfo();
if (ctx.mounted) Navigator.of(ctx).pop();
} catch (_) {
if (ctx.mounted) {
ScaffoldMessenger.of(ctx).showSnackBar(
const SnackBar(content: Text('修改失败,请检查网络后重试'), duration: Duration(seconds: 2)),
);
}
}
},
style: FilledButton.styleFrom(backgroundColor: AppColors.primary),
child: const Text('保存', style: TextStyle(fontSize: AppFont.body)),
),
],
),
),
);
}
void _showAbout() {
showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: const Text('关于畅联'),
content: const Text('畅联 1.0.0\n公司内部通讯工具,供同事之间消息、文件与语音通话使用。'),
actions: [
TextButton(onPressed: () => Navigator.of(ctx).pop(), child: const Text('知道了')),
],
),
);
}
void _confirmLogout() {
showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: const Text('退出登录'),
content: const Text('退出后要重新输入工号和密码,确定退出吗?'),
actions: [
TextButton(onPressed: () => Navigator.of(ctx).pop(), child: const Text('取消')),
TextButton(
onPressed: () async {
Navigator.of(ctx).pop();
await LoginScreen.clearCredential();
await PushService.instance.unbindUser();
await IMService.instance.logout();
if (!mounted) return;
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(builder: (_) => const LoginScreen()),
(route) => false,
);
},
child: const Text('退出', style: TextStyle(color: AppColors.danger)),
),
],
),
);
}
}