im_flutter_sdk 4.22.0
im_flutter_sdk: ^4.22.0 copied to clipboard
Integrate the Chat SDK to enjoy the global IM services with high reliability, ultra-low latency, and high concurrency.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'auto/auto_mode.dart';
import 'log/floating_log.dart';
import 'log/log_store.dart';
import 'pages/init_page.dart';
import 'sdk_state.dart';
import 'tools/floating_attachment.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await LogStore.instance.init();
runApp(const ApiTesterApp());
}
/// 用于取 Navigator 内部的 Overlay(RootShell 在 Navigator 之上,
/// 直接用自身 context 找不到 Overlay)。
final GlobalKey<NavigatorState> appNavigatorKey = GlobalKey<NavigatorState>();
/// 顶部状态条:未初始化 / 已初始化,未登录 / 已登录:<userId>,不做硬性门控。
class StatusBar extends StatelessWidget {
const StatusBar({super.key});
@override
Widget build(BuildContext context) {
return ListenableBuilder(
listenable: SdkState.instance,
builder: (context, _) {
return Container(
width: double.infinity,
color: Colors.blueGrey.shade700,
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
child: Text(
SdkState.instance.statusText,
style: const TextStyle(color: Colors.white, fontSize: 12),
),
);
},
);
}
}
/// 根壳:状态条常显 + init 成功后插入悬浮日志/悬浮附件(生命周期独立于页面)。
class RootShell extends StatefulWidget {
final Widget? child;
const RootShell({super.key, required this.child});
@override
State<RootShell> createState() => _RootShellState();
}
class _RootShellState extends State<RootShell> {
bool _logShown = false;
@override
Widget build(BuildContext context) {
return ListenableBuilder(
listenable: SdkState.instance,
builder: (context, _) {
if (SdkState.instance.initialized && !_logShown) {
_logShown = true;
WidgetsBinding.instance.addPostFrameCallback((_) {
final overlay = appNavigatorKey.currentState?.overlay;
if (overlay != null) {
FloatingLog.show(overlay);
FloatingAttachment.show(overlay);
}
});
}
return Column(
children: [
// 颜色包在 SafeArea 外层,让刘海/状态栏区域与状态条同色。
Container(
color: Colors.blueGrey.shade700,
child: const SafeArea(bottom: false, child: StatusBar()),
),
// 状态条已处理顶部 inset,移除页面的重复 padding,
// 否则 AppBar 上方会出现一段空白。
Expanded(
child: MediaQuery.removePadding(
context: context,
removeTop: true,
child: widget.child ?? const SizedBox.shrink(),
),
),
],
);
},
);
}
}
class ApiTesterApp extends StatelessWidget {
const ApiTesterApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'IM API Tester',
navigatorKey: appNavigatorKey,
theme: ThemeData(colorSchemeSeed: Colors.blue, useMaterial3: true),
builder: (context, child) => RootShell(child: child),
home: AutoMode.enabled ? const AutoHomePage() : const InitPage(),
);
}
}
/// 自动模式占位页:启动脚本,展示状态;日志走 stdout / 落盘通道。
class AutoHomePage extends StatefulWidget {
const AutoHomePage({super.key});
@override
State<AutoHomePage> createState() => _AutoHomePageState();
}
class _AutoHomePageState extends State<AutoHomePage> {
bool _started = false;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
if (!_started) {
_started = true;
AutoMode.run();
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('自动脚本模式')),
body: const Center(
child: Padding(
padding: EdgeInsets.all(24),
child: Text(
'API_SCRIPT=${AutoMode.scriptPath}\n\n脚本执行中,结果见 [APITEST] 结构化日志(stdout / api_test.log)。',
textAlign: TextAlign.center,
),
),
),
);
}
}