feat(app): 初始化家庭网络监控Flutter应用基本结构
- 添加Flutter项目基础文件与配置,包括.gitignore和analysis_options.yaml - 配置Android相关文件及Gradle构建脚本支持 - 新增设备状态与网络状态数据模型及相关枚举 - 实现网络检测及网速测试服务 - 创建监控状态管理Provider,实现设备状态管理和自动刷新机制 - 编写主界面HomeScreen,包括设备列表、网速仪表盘及基础交互 - 添加资源文件支持应用图标和启动画面 - 配置项目元数据文件,支持Flutter迁移及版本控制 - 新增项目README,提供入门指引和相关资源链接
This commit is contained in:
259
home_monitor/lib/screens/home_screen.dart
Normal file
259
home_monitor/lib/screens/home_screen.dart
Normal file
@@ -0,0 +1,259 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import '../providers/providers.dart';
|
||||
import '../widgets/widgets.dart';
|
||||
|
||||
/// 主页面
|
||||
class HomeScreen extends StatefulWidget {
|
||||
const HomeScreen({super.key});
|
||||
|
||||
@override
|
||||
State<HomeScreen> createState() => _HomeScreenState();
|
||||
}
|
||||
|
||||
class _HomeScreenState extends State<HomeScreen> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
// 初始化数据
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
final provider = context.read<MonitorProvider>();
|
||||
provider.initDefaultDevices();
|
||||
provider.refreshAll();
|
||||
provider.startAutoRefresh(intervalSeconds: 30);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: _buildAppBar(),
|
||||
body: _buildBody(),
|
||||
floatingActionButton: _buildFAB(),
|
||||
);
|
||||
}
|
||||
|
||||
PreferredSizeWidget _buildAppBar() {
|
||||
return AppBar(
|
||||
title: const Text('家庭网络监控'),
|
||||
centerTitle: true,
|
||||
actions: [
|
||||
Consumer<MonitorProvider>(
|
||||
builder: (context, provider, _) {
|
||||
return IconButton(
|
||||
icon: provider.isLoading
|
||||
? const SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: CircularProgressIndicator(strokeWidth: 2),
|
||||
)
|
||||
: const Icon(Icons.refresh),
|
||||
onPressed: provider.isLoading ? null : () => provider.refreshAll(),
|
||||
tooltip: '刷新',
|
||||
);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.settings),
|
||||
onPressed: () {
|
||||
_showSettingsDialog();
|
||||
},
|
||||
tooltip: '设置',
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBody() {
|
||||
return Consumer<MonitorProvider>(
|
||||
builder: (context, provider, _) {
|
||||
return RefreshIndicator(
|
||||
onRefresh: () => provider.refreshAll(),
|
||||
child: SingleChildScrollView(
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// 网速仪表盘
|
||||
SpeedGauge(
|
||||
networkStatus: provider.networkStatus,
|
||||
isLoading: provider.isTestingSpeed,
|
||||
),
|
||||
|
||||
// 概览卡片
|
||||
_buildOverviewCards(provider),
|
||||
|
||||
// 设备列表标题
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 16, 16, 8),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'监控设备',
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
),
|
||||
TextButton.icon(
|
||||
onPressed: () => _showAddDeviceDialog(),
|
||||
icon: const Icon(Icons.add, size: 18),
|
||||
label: const Text('添加'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// 设备列表
|
||||
_buildDeviceList(provider),
|
||||
|
||||
const SizedBox(height: 80),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildOverviewCards(MonitorProvider provider) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: StatusCard(
|
||||
title: '在线设备',
|
||||
value: '${provider.onlineDevicesCount}',
|
||||
icon: Icons.check_circle,
|
||||
iconColor: Colors.green,
|
||||
subtitle: '共 ${provider.devices.length} 台设备',
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: StatusCard(
|
||||
title: '离线设备',
|
||||
value: '${provider.offlineDevicesCount}',
|
||||
icon: Icons.error,
|
||||
iconColor: provider.offlineDevicesCount > 0
|
||||
? Colors.red
|
||||
: Colors.grey,
|
||||
subtitle: provider.offlineDevicesCount > 0
|
||||
? '需要检查'
|
||||
: '全部正常',
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDeviceList(MonitorProvider provider) {
|
||||
if (provider.devices.isEmpty) {
|
||||
return const Center(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(32),
|
||||
child: Column(
|
||||
children: [
|
||||
Icon(Icons.devices, size: 64, color: Colors.grey),
|
||||
SizedBox(height: 16),
|
||||
Text('暂无监控设备'),
|
||||
SizedBox(height: 8),
|
||||
Text('点击右上角添加设备', style: TextStyle(color: Colors.grey)),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return ListView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemCount: provider.devices.length,
|
||||
itemBuilder: (context, index) {
|
||||
final device = provider.devices[index];
|
||||
return DeviceTile(
|
||||
device: device,
|
||||
onRefresh: () => provider.checkSingleDevice(device.id),
|
||||
onTap: () => _showDeviceDetail(device),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildFAB() {
|
||||
return Consumer<MonitorProvider>(
|
||||
builder: (context, provider, _) {
|
||||
return FloatingActionButton.extended(
|
||||
onPressed: provider.isTestingSpeed ? null : () => provider.runSpeedTest(),
|
||||
icon: provider.isTestingSpeed
|
||||
? const SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
color: Colors.white,
|
||||
),
|
||||
)
|
||||
: const Icon(Icons.speed),
|
||||
label: Text(provider.isTestingSpeed ? '测速中...' : '测速'),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void _showSettingsDialog() {
|
||||
final provider = context.read<MonitorProvider>();
|
||||
int interval = provider.refreshInterval;
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('设置'),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
ListTile(
|
||||
title: const Text('自动刷新间隔'),
|
||||
subtitle: Text('$interval 秒'),
|
||||
trailing: DropdownButton<int>(
|
||||
value: interval,
|
||||
items: const [
|
||||
DropdownMenuItem(value: 10, child: Text('10秒')),
|
||||
DropdownMenuItem(value: 30, child: Text('30秒')),
|
||||
DropdownMenuItem(value: 60, child: Text('1分钟')),
|
||||
DropdownMenuItem(value: 300, child: Text('5分钟')),
|
||||
],
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
provider.setRefreshInterval(value);
|
||||
Navigator.pop(context);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: const Text('关闭'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showAddDeviceDialog() {
|
||||
// TODO: 实现添加设备对话框
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('添加设备功能开发中...')),
|
||||
);
|
||||
}
|
||||
|
||||
void _showDeviceDetail(device) {
|
||||
// TODO: 实现设备详情页
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('设备: ${device.name}')),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user