import 'dart:async'; import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:fis_common/http/options.dart'; import 'package:fis_jsonrpc/http_pool.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:vitalapp/architecture/network_connectivity.dart'; import 'package:vitalapp/global.dart'; import 'package:vitalapp/pages/help/help_dialog.dart'; import 'package:fis_common/logger/logger.dart'; import 'package:vitalapp/rpc.dart'; import 'package:wifi_iot/wifi_iot.dart'; class HeaderStatusBar extends StatelessWidget { const HeaderStatusBar({super.key}); @override Widget build(BuildContext context) { return Row( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ _NetStatusWidget(), const SizedBox(width: 2), IconButton( onPressed: () { HelpDialog.show(); }, padding: EdgeInsets.all(0), icon: const Icon(Icons.help, size: 36, color: Colors.white), ), ], ); } } class _NetStatusWidget extends StatefulWidget { @override State createState() => _NetStatusWidgetState(); } class _NetStatusWidgetState extends State<_NetStatusWidget> { Timer? _waitTimer; bool _isOnline = false; bool _isServerConnectable = true; @override void initState() { super.initState(); _isOnline = kIsOnline; WidgetsBinding.instance.addPostFrameCallback((timeStamp) { netChecker.onlineChangedEvent.addListener(_onlineChanged); if (_isOnline) { _checkServerConnectable(); } }); } @override void dispose() { netChecker.onlineChangedEvent.removeListener(_onlineChanged); super.dispose(); } @override Widget build(BuildContext context) { return Tooltip( triggerMode: TooltipTriggerMode.tap, message: _buildTipsText(), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ _buildIcon(), _buildWifiName(), ], ), ); } String _buildTipsText() { if (_isOnline) { if (_isServerConnectable) { return "网络已连接"; } else { return "无法连接服务器"; } } else { if (_waitTimer == null) { return "网络已断开"; } else { return "网络等待中"; } } } Widget _buildIcon() { if (_isOnline) { if (!_isServerConnectable) { return Icon(Icons.wifi_off_outlined, size: 36, color: Colors.red); } if (netChecker.status == ConnectivityResult.mobile) { return _NetworkIcon4G(); } return Icon(Icons.wifi, size: 36, color: Colors.green); } if (_waitTimer == null) { return Icon(Icons.wifi_off_outlined, size: 36, color: Colors.red); } else { return SizedBox(width: 36, height: 36, child: _NetWaitingWidget()); } } Widget _buildWifiName() { if (netChecker.status != ConnectivityResult.wifi) { return const SizedBox(); } return _WifiNameWidget(); } void _onlineChanged(_, e) { if (_isOnline != e) { setState(() { _isOnline = e; }); } if (e) { _stopWaitNetRecover(); _checkServerConnectable(); } else { _waitNetRecover(); } } void _waitNetRecover() { if (_waitTimer != null) { return; } logger.i("HeaderStatusBar - Wait network start."); print("HeaderStatusBar - Wait network start."); _waitTimer = Timer(const Duration(milliseconds: 5 * 1000), () { setState(() { _waitTimer = null; }); logger.i("HeaderStatusBar - Wait network done."); print("HeaderStatusBar - Wait network done."); }); } void _stopWaitNetRecover() { if (_waitTimer != null) { _waitTimer?.cancel(); _waitTimer = null; logger.i("HeaderStatusBar - Wait network abort."); print("HeaderStatusBar - Wait network abort."); } } Future _checkServerConnectable() async { final result = await _tryConnectRpcOnce(); setState(() { _isServerConnectable = result; }); } /// 检验服务有效性 Future _tryConnectRpcOnce() async { print("${netChecker.status} _tryConnectRpcOnce: ${DateTime.now()}"); try { final reqJson = '{"jsonrpc":"2.0","method":"VerifyAccountAsync","params":[{"UserName": "abc123"}],"id":1}'; var response = await jrpcHttpPool.getClient( rpc.currentHostAddress, // timeout: 1000, // 设置了但没生效 headers: {'content-type': "text/plain"}, ).post( '/IVitalLoginService', data: reqJson, options: FHttpScopedOptions(timeout: 1000), ); print(response); return true; } catch (e) { print("Http unknown error:${e}"); } return false; } } class _NetWaitingWidget extends StatefulWidget { @override State<_NetWaitingWidget> createState() => _NetWaitingWidgetState(); } class _NetWaitingWidgetState extends State<_NetWaitingWidget> { static final _color = Colors.orange.shade200; bool _isShow = false; Timer? _timer; @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((timeStamp) { _timer = Timer.periodic(const Duration(milliseconds: 1000), (timer) { setState(() { _isShow = !_isShow; }); }); }); } @override void dispose() { _timer?.cancel(); _timer = null; super.dispose(); } @override Widget build(BuildContext context) { return Stack( children: [ Icon( Icons.wifi, size: 36, color: _isShow ? _color : _color.withOpacity(.4), ), const Center( child: Padding( padding: EdgeInsets.all(8), child: CircularProgressIndicator( strokeWidth: 4, color: Colors.white, ), ), ), ], ); } } class _NetworkIcon4G extends StatelessWidget { @override Widget build(BuildContext context) { return Expanded( child: Column( children: [ Transform.translate( offset: Offset(-4, 10), child: Text( "4G", style: TextStyle( fontSize: 18, color: Colors.white, ), ), ), Transform.translate( offset: Offset(0, -6), child: Transform.scale( scaleX: 1.2, child: Icon( Icons.signal_cellular_alt_rounded, size: 36, color: Colors.green, ), ), ), ], ), ); } } class _WifiNameWidget extends StatelessWidget { @override Widget build(BuildContext context) { return FutureBuilder( builder: (context, snapshot) { if (snapshot.hasData && snapshot.data != null && snapshot.data!.isNotEmpty) { return Container( constraints: BoxConstraints(maxWidth: 120), child: Text( _breakWord(snapshot.data!), style: TextStyle( fontSize: 16, color: Colors.white, ), overflow: TextOverflow.ellipsis, ), ); } return const SizedBox(); }, future: WiFiForIoTPlugin.getSSID(), ); } /// 插入零宽空格 static String _breakWord(String word) { if (word.isEmpty) return word; String breakWord = ' '; for (var element in word.runes) { breakWord += String.fromCharCode(element); breakWord += '\u200B'; } return breakWord; } }