Files
tongxunruanjian/mobile/lib/main.dart
T
KIMI b95159f7eb 新增 mobile/:畅联手机端 Flutter 工程(B-58)
- 登录:工号+密码走 account-service /api/login,自动登录、被踢下线回登录页
- 消息:会话列表(未读角标/免打扰/时间)、单聊群聊、文字/语音/图片/文件消息、失败重发、历史分页
- 通讯录:新的同事/我的群聊入口、按部门分组(好友 ex 字段)、搜索
- 通话:一对一语音通话(信令走 OpenIM 自定义消息 + LiveKit,token 走 /api/rtc_token)
- 界面按确认效果图 m1/m2/m3 实现,主色 #3B87F5,四态视图齐全,无英文残留
2026-08-09 01:28:12 +08:00

114 lines
3.3 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'nav.dart';
import 'screens/call_screen.dart';
import 'screens/home_screen.dart';
import 'screens/login_screen.dart';
import 'services/call_service.dart';
import 'services/im_service.dart';
import 'theme.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(const ChanglianApp());
}
class ChanglianApp extends StatefulWidget {
const ChanglianApp({super.key});
@override
State<ChanglianApp> createState() => _ChanglianAppState();
}
class _ChanglianAppState extends State<ChanglianApp> {
@override
void initState() {
super.initState();
// 被踢下线 / token 失效:清凭证、回登录页
IMService.instance.onForceLogout = () async {
await LoginScreen.clearCredential();
navigatorKey.currentState?.pushAndRemoveUntil(
MaterialPageRoute(builder: (_) => const LoginScreen()),
(route) => false,
);
};
// 来电时弹出通话界面
CallService.instance.onIncomingCall = () {
navigatorKey.currentState?.push(
MaterialPageRoute(builder: (_) => const CallScreen(), fullscreenDialog: true),
);
};
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '畅联',
navigatorKey: navigatorKey,
theme: buildAppTheme(),
debugShowCheckedModeBanner: false,
localizationsDelegates: const [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [Locale('zh', 'CN')],
locale: const Locale('zh', 'CN'),
home: const SplashGate(),
);
}
}
/// 启动页:初始化 SDK,有本地凭证则自动登录进主页,否则进登录页
class SplashGate extends StatefulWidget {
const SplashGate({super.key});
@override
State<SplashGate> createState() => _SplashGateState();
}
class _SplashGateState extends State<SplashGate> {
@override
void initState() {
super.initState();
_boot();
}
Future<void> _boot() async {
final im = IMService.instance;
try {
await im.init();
final credential = await LoginScreen.readCredential();
if (credential != null) {
await im.login(userID: credential.$1, token: credential.$2);
CallService.instance.start();
if (!mounted) return;
Navigator.of(context).pushReplacement(MaterialPageRoute(builder: (_) => const HomeScreen()));
return;
}
} catch (_) {
// 自动登录失败(token 失效等):清凭证回登录页
await LoginScreen.clearCredential();
}
if (!mounted) return;
Navigator.of(context).pushReplacement(MaterialPageRoute(builder: (_) => const LoginScreen()));
}
@override
Widget build(BuildContext context) {
return const Scaffold(
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text('畅联', style: TextStyle(fontSize: 32, fontWeight: FontWeight.w600, color: AppColors.primary)),
SizedBox(height: AppGap.x6),
SizedBox(width: 28, height: 28, child: CircularProgressIndicator(strokeWidth: 3, color: AppColors.primary)),
],
),
),
);
}
}