chore(project): 初始化项目基础配置文件
- 添加 CodeGraph、Android 和通用 gitignore 配置 - 创建项目元数据文件跟踪 Flutter 项目属性 - 添加 Codex AI 指导文档 AGENTS.md 说明项目架构 - 配置代码分析选项 analysis_options.yaml - 设置 Android 应用清单权限和 Kiosk 模式配置 - 实现中英文国际化支持 AppLocalizations - 配置 GoRouter 应用路由导航 - 创建明亮工业控制风格的主题配置 AppTheme
This commit is contained in:
202
lib/features/home/pages/complete_page.dart
Normal file
202
lib/features/home/pages/complete_page.dart
Normal file
@@ -0,0 +1,202 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import '../../../core/localization/app_localizations.dart';
|
||||
import '../../../core/theme/app_theme.dart';
|
||||
import '../../../shared/widgets/common_button.dart';
|
||||
import '../../device/providers/run_state_provider.dart';
|
||||
|
||||
/// 运行完成提示页面
|
||||
class CompletePage extends ConsumerWidget {
|
||||
const CompletePage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final l10n = AppLocalizations.of(context);
|
||||
final runState = ref.watch(runStateProvider);
|
||||
final runNotifier = ref.read(runStateProvider.notifier);
|
||||
|
||||
return Scaffold(
|
||||
body: Container(
|
||||
color: AppTheme.backgroundColor,
|
||||
child: Center(
|
||||
child: Container(
|
||||
width: 600,
|
||||
padding: const EdgeInsets.all(40),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withValues(alpha: 0.15),
|
||||
blurRadius: 20,
|
||||
offset: const Offset(0, 10),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// 成功图标
|
||||
Container(
|
||||
width: 100,
|
||||
height: 100,
|
||||
decoration: BoxDecoration(
|
||||
color: AppTheme.successColor.withValues(alpha: 0.1),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Icon(
|
||||
Icons.check_circle,
|
||||
size: 60,
|
||||
color: AppTheme.successColor,
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// 标题
|
||||
Text(
|
||||
l10n?.runComplete ?? '程序运行完成',
|
||||
style: TextStyle(
|
||||
color: AppTheme.textPrimary,
|
||||
fontSize: 28,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// 提示信息
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 24,
|
||||
vertical: 12,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: AppTheme.warningColor.withValues(alpha: 0.1),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Text(
|
||||
l10n?.sampleDropGuide ?? '请将样本滴入检测卡',
|
||||
style: TextStyle(
|
||||
color: AppTheme.warningColor,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 32),
|
||||
|
||||
// 操作示意图
|
||||
_buildOperationGuide(),
|
||||
|
||||
const SizedBox(height: 32),
|
||||
|
||||
// 按钮区域
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
// 返回首页按钮
|
||||
CommonButton(
|
||||
text: l10n?.backToHome ?? '返回首页',
|
||||
icon: Icons.home,
|
||||
type: ButtonType.primary,
|
||||
onPressed: () {
|
||||
runNotifier.reset();
|
||||
context.go('/');
|
||||
},
|
||||
),
|
||||
const SizedBox(width: 24),
|
||||
|
||||
// 重新运行按钮
|
||||
CommonButton(
|
||||
text: l10n?.runAgain ?? '重新运行',
|
||||
icon: Icons.refresh,
|
||||
type: ButtonType.secondary,
|
||||
onPressed: () {
|
||||
final program = runState.currentProgram;
|
||||
if (program != null) {
|
||||
runNotifier.reset();
|
||||
runNotifier.start(program);
|
||||
context.go('/');
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 操作指引示意图
|
||||
Widget _buildOperationGuide() {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
color: AppTheme.backgroundColor,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: AppTheme.idleColor.withValues(alpha: 0.2)),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
'操作步骤',
|
||||
style: TextStyle(
|
||||
color: AppTheme.textPrimary,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
_buildStepItem(1, '取出样本', Icons.science),
|
||||
_buildStepItem(2, '滴入检测卡', Icons.water_drop),
|
||||
_buildStepItem(3, '等待反应', Icons.timer),
|
||||
_buildStepItem(4, '查看结果', Icons.visibility),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 步骤项
|
||||
Widget _buildStepItem(int number, String text, IconData icon) {
|
||||
return Column(
|
||||
children: [
|
||||
Container(
|
||||
width: 50,
|
||||
height: 50,
|
||||
decoration: BoxDecoration(
|
||||
color: AppTheme.primaryColor.withValues(alpha: 0.1),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Icon(icon, color: AppTheme.primaryColor, size: 24),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'$number',
|
||||
style: TextStyle(
|
||||
color: AppTheme.primaryColor,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
text,
|
||||
style: TextStyle(
|
||||
color: AppTheme.textSecondary,
|
||||
fontSize: 11,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
176
lib/features/home/pages/home_page.dart
Normal file
176
lib/features/home/pages/home_page.dart
Normal file
@@ -0,0 +1,176 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import '../../../core/database/database_service.dart';
|
||||
import '../../../core/theme/app_theme.dart';
|
||||
import '../../device/providers/run_state_provider.dart';
|
||||
import '../../programs/pages/programs_page.dart';
|
||||
import '../../settings/pages/settings_page.dart';
|
||||
import '../widgets/status_bar.dart';
|
||||
import '../widgets/program_list.dart';
|
||||
import '../widgets/running_control_panel.dart';
|
||||
import '../widgets/run_status_monitor.dart';
|
||||
|
||||
/// 首页 - 设备控制面板 (暗色工业风格)
|
||||
/// 布局:状态栏 + 导航标签栏 + 内容区(设备控制/程序管理/系统设置)
|
||||
class HomePage extends ConsumerStatefulWidget {
|
||||
const HomePage({super.key});
|
||||
|
||||
@override
|
||||
ConsumerState<HomePage> createState() => _HomePageState();
|
||||
}
|
||||
|
||||
class _HomePageState extends ConsumerState<HomePage>
|
||||
with SingleTickerProviderStateMixin {
|
||||
bool _lightOn = false;
|
||||
final bool _ceramicSleeveInstalled = false; // TODO: 后续对接硬件传感器后改为可变状态
|
||||
int _currentIndex = 0;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
DatabaseService.instance.initTestData();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final runState = ref.watch(runStateProvider);
|
||||
|
||||
// 监听运行完成状态,自动跳转
|
||||
ref.listen<RunState>(runStateProvider, (prev, next) {
|
||||
if (prev?.status != RunStatus.completed && next.status == RunStatus.completed) {
|
||||
// 仅首页才自动跳转
|
||||
if (_currentIndex == 0) {
|
||||
context.push('/complete');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return Scaffold(
|
||||
body: Container(
|
||||
color: AppTheme.bgDeep,
|
||||
child: Column(
|
||||
children: [
|
||||
// 状态栏
|
||||
StatusBar(
|
||||
isRunning: runState.status == RunStatus.running,
|
||||
lightOn: _lightOn,
|
||||
onLightToggle: () {
|
||||
setState(() {
|
||||
_lightOn = !_lightOn;
|
||||
});
|
||||
},
|
||||
ceramicSleeveInstalled: _ceramicSleeveInstalled,
|
||||
),
|
||||
|
||||
// 导航标签栏
|
||||
_buildTabBar(),
|
||||
|
||||
// 内容区
|
||||
Expanded(
|
||||
child: IndexedStack(
|
||||
index: _currentIndex,
|
||||
children: [
|
||||
_buildDeviceControlPage(runState),
|
||||
const ProgramsPage(),
|
||||
const SettingsPage(),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 导航标签栏
|
||||
Widget _buildTabBar() {
|
||||
const tabs = [
|
||||
(icon: Icons.dashboard, label: '设备控制'),
|
||||
(icon: Icons.list_alt, label: '程序管理'),
|
||||
(icon: Icons.settings, label: '系统设置'),
|
||||
];
|
||||
|
||||
return Container(
|
||||
height: 48,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
child: Row(
|
||||
children: List.generate(tabs.length, (index) {
|
||||
final tab = tabs[index];
|
||||
final isSelected = _currentIndex == index;
|
||||
return GestureDetector(
|
||||
onTap: () => setState(() => _currentIndex = index),
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
margin: const EdgeInsets.only(right: 4),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected ? AppTheme.accentPrimary : AppTheme.cardBg,
|
||||
borderRadius: const BorderRadius.vertical(top: Radius.circular(8)),
|
||||
border: Border.all(
|
||||
color: isSelected
|
||||
? AppTheme.accentPrimary
|
||||
: AppTheme.borderSubtle,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
tab.icon,
|
||||
size: 18,
|
||||
color: isSelected ? Colors.white : AppTheme.textSecondary,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
tab.label,
|
||||
style: TextStyle(
|
||||
color: isSelected ? Colors.white : AppTheme.textSecondary,
|
||||
fontSize: 14,
|
||||
fontWeight: isSelected
|
||||
? FontWeight.w600
|
||||
: FontWeight.normal,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 设备控制页面内容
|
||||
Widget _buildDeviceControlPage(RunState runState) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.fromLTRB(20, 0, 20, 20),
|
||||
child: Row(
|
||||
children: [
|
||||
// 左侧:程序列表(运行时锁定)
|
||||
Opacity(
|
||||
opacity: runState.status == RunStatus.idle ? 1.0 : 0.6,
|
||||
child: IgnorePointer(
|
||||
ignoring: runState.status != RunStatus.idle,
|
||||
child: const ProgramList(),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 20),
|
||||
// 右侧:运行控制区域
|
||||
Expanded(
|
||||
child: Column(
|
||||
children: [
|
||||
const Expanded(child: RunningControlPanel()),
|
||||
if (runState.status != RunStatus.idle) ...[
|
||||
const SizedBox(height: 16),
|
||||
const Expanded(child: RunStatusMonitor()),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user