Files
ai_english/client/lib/shared/widgets/network_indicator.dart

224 lines
5.9 KiB
Dart
Raw Permalink Normal View History

2025-11-17 13:39:05 +08:00
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../providers/network_provider.dart';
/// 网络状态指示器
class NetworkIndicator extends ConsumerWidget {
final Widget child;
final bool showBanner;
const NetworkIndicator({
super.key,
required this.child,
this.showBanner = true,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
final networkState = ref.watch(networkProvider);
return Column(
children: [
if (showBanner && networkState.status == NetworkStatus.disconnected)
_buildOfflineBanner(context),
Expanded(child: child),
],
);
}
Widget _buildOfflineBanner(BuildContext context) {
return Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
color: Colors.red[600],
child: Row(
children: [
const Icon(
Icons.wifi_off,
color: Colors.white,
size: 20,
),
const SizedBox(width: 8),
const Expanded(
child: Text(
'网络连接已断开',
style: TextStyle(
color: Colors.white,
fontSize: 14,
fontWeight: FontWeight.w500,
),
),
),
TextButton(
onPressed: () {
// 可以添加重试逻辑
},
child: const Text(
'重试',
style: TextStyle(
color: Colors.white,
fontSize: 14,
),
),
),
],
),
);
}
}
/// 网络状态图标
class NetworkStatusIcon extends ConsumerWidget {
final double size;
final Color? color;
const NetworkStatusIcon({
super.key,
this.size = 24,
this.color,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
final networkState = ref.watch(networkProvider);
return Icon(
_getNetworkIcon(networkState.status, networkState.type),
size: size,
color: color ?? _getNetworkColor(networkState.status),
);
}
IconData _getNetworkIcon(NetworkStatus status, NetworkType type) {
if (status == NetworkStatus.disconnected) {
return Icons.wifi_off;
}
switch (type) {
case NetworkType.wifi:
return Icons.wifi;
case NetworkType.mobile:
return Icons.signal_cellular_4_bar;
case NetworkType.ethernet:
return Icons.cable;
case NetworkType.unknown:
default:
return Icons.device_unknown;
}
}
Color _getNetworkColor(NetworkStatus status) {
switch (status) {
case NetworkStatus.connected:
return Colors.green;
case NetworkStatus.disconnected:
return Colors.red;
case NetworkStatus.unknown:
return Colors.grey;
}
}
}
/// 网络状态卡片
class NetworkStatusCard extends ConsumerWidget {
const NetworkStatusCard({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final networkState = ref.watch(networkProvider);
return Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
NetworkStatusIcon(
size: 32,
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
_getStatusText(networkState.status),
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
),
),
Text(
_getTypeText(networkState.type),
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Colors.grey[600],
),
),
],
),
),
],
),
const SizedBox(height: 12),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'最后更新: ${_formatTime(networkState.lastChecked)}',
style: Theme.of(context).textTheme.bodySmall,
),
TextButton(
onPressed: () {
ref.read(networkProvider.notifier).refreshNetworkStatus();
},
child: const Text('刷新'),
),
],
),
],
),
),
);
}
String _getStatusText(NetworkStatus status) {
switch (status) {
case NetworkStatus.connected:
return '已连接';
case NetworkStatus.disconnected:
return '未连接';
case NetworkStatus.unknown:
return '未知状态';
}
}
String _getTypeText(NetworkType type) {
switch (type) {
case NetworkType.wifi:
return 'Wi-Fi';
case NetworkType.mobile:
return '移动网络';
case NetworkType.ethernet:
return '以太网';
case NetworkType.unknown:
default:
return '未知';
}
}
String _formatTime(DateTime time) {
final now = DateTime.now();
final difference = now.difference(time);
if (difference.inMinutes < 1) {
return '刚刚';
} else if (difference.inHours < 1) {
return '${difference.inMinutes}分钟前';
} else if (difference.inDays < 1) {
return '${difference.inHours}小时前';
} else {
return '${difference.inDays}天前';
}
}
}