feat(device): 添加USB设备通信支持和程序参数优化

- 在AndroidManifest.xml中添加USB Host权限和设备过滤器配置
- 新增设备控制国际化词条包括速度档位、吹气时间等
- 重构数据库结构将速度相关字段统一为档位数值存储
- 添加通用KV存储方法用于settings表数据读写
- 优化首页导航实现tab间跳转和状态保持功能
- 更新程序详情页面布局和参数表单界面
- 移除模拟运行器相关测试代码
- 添加USB串口通信依赖包usb_serial
This commit is contained in:
Developer
2026-06-04 15:13:36 +08:00
parent 67e2c7c76c
commit d53c41c300
24 changed files with 795 additions and 635 deletions

View File

@@ -1,17 +1,18 @@
import 'dart:async';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../programs/models/program.dart';
import '../../programs/models/step.dart';
import '../../programs/services/program_service.dart';
import '../services/mock_runner.dart';
import '../services/runner_interface.dart';
import 'serial_provider.dart';
/// 运行状态枚举
enum RunStatus {
idle, // 待机
running, // 运行中
paused, // 已暂停
completed,// 已完成
error, // 错误
idle, // 待机
running, // 运行中
paused, // 已暂停
completed, // 已完成
error, // 错误
}
/// 运行状态
@@ -23,6 +24,7 @@ class RunState {
final int remainingSeconds;
final double progress;
final String? currentWell;
final String? errorMessage;
const RunState({
this.status = RunStatus.idle,
@@ -32,6 +34,7 @@ class RunState {
this.remainingSeconds = 0,
this.progress = 0,
this.currentWell,
this.errorMessage,
});
RunState copyWith({
@@ -42,17 +45,21 @@ class RunState {
int? remainingSeconds,
double? progress,
String? currentWell,
String? errorMessage,
bool clearProgram = false,
bool clearWell = false,
bool clearError = false,
}) {
return RunState(
status: status ?? this.status,
currentProgram: clearProgram ? null : (currentProgram ?? this.currentProgram),
currentProgram:
clearProgram ? null : (currentProgram ?? this.currentProgram),
steps: steps ?? this.steps,
currentStepIndex: currentStepIndex ?? this.currentStepIndex,
remainingSeconds: remainingSeconds ?? this.remainingSeconds,
progress: progress ?? this.progress,
currentWell: clearWell ? null : (currentWell ?? this.currentWell),
errorMessage: clearError ? null : (errorMessage ?? this.errorMessage),
);
}
@@ -68,8 +75,8 @@ class RunState {
final minutes = (remainingSeconds % 3600) ~/ 60;
final seconds = remainingSeconds % 60;
return '${hours.toString().padLeft(2, '0')}:'
'${minutes.toString().padLeft(2, '0')}:'
'${seconds.toString().padLeft(2, '0')}';
'${minutes.toString().padLeft(2, '0')}:'
'${seconds.toString().padLeft(2, '0')}';
}
/// 格式化进度百分比
@@ -80,18 +87,24 @@ class RunState {
/// 运行状态 Notifier
class RunStateNotifier extends StateNotifier<RunState> {
final MockRunner _runner;
final Runner _runner;
final ProgramService _programService;
RunStateNotifier(this._runner, this._programService) : super(const RunState());
/// 开始运行程序
Future<void> start(Program program) async {
// 获取程序步骤(这里使用模拟数据,实际应从数据库读取)
final steps = await _loadSteps(program.id!);
if (state.status == RunStatus.running ||
state.status == RunStatus.paused) {
return;
}
final steps = await _programService.getStepsByProgramId(program.id!);
if (steps.isEmpty) {
state = state.copyWith(status: RunStatus.error);
state = state.copyWith(
status: RunStatus.error,
errorMessage: '程序步骤为空',
);
return;
}
@@ -101,26 +114,36 @@ class RunStateNotifier extends StateNotifier<RunState> {
steps: steps,
currentStepIndex: 0,
progress: 0,
currentWell: steps.first.position,
clearError: true,
);
_runner.start(
program,
steps,
(stepIndex, remaining, progress, well) {
state = state.copyWith(
currentStepIndex: stepIndex,
remainingSeconds: remaining,
progress: progress,
currentWell: well,
);
},
() {
state = state.copyWith(
status: RunStatus.completed,
progress: 1,
clearWell: true,
);
},
RunnerCallbacks(
onProgress: (stepIndex, remaining, progress, well) {
state = state.copyWith(
currentStepIndex: stepIndex,
remainingSeconds: remaining,
progress: progress,
currentWell: well,
);
},
onComplete: () {
state = state.copyWith(
status: RunStatus.completed,
progress: 1,
currentWell: steps.last.position,
);
},
onError: (msg) {
state = state.copyWith(
status: RunStatus.error,
errorMessage: msg,
);
},
),
);
}
@@ -142,26 +165,17 @@ class RunStateNotifier extends StateNotifier<RunState> {
/// 停止运行
void stop() {
_runner.stop();
if (state.status == RunStatus.running ||
state.status == RunStatus.paused) {
_runner.stop();
}
state = const RunState(status: RunStatus.idle);
}
/// 重置状态
void reset() {
stop();
}
/// 加载程序步骤(从数据库读取)
Future<List<Step>> _loadSteps(int programId) async {
return await _programService.getStepsByProgramId(programId);
}
void reset() => stop();
}
/// MockRunner Provider
final mockRunnerProvider = Provider<MockRunner>((ref) {
return MockRunner();
});
/// ProgramService Provider
final programServiceProvider = Provider<ProgramService>((ref) {
return ProgramService.instance;
@@ -170,7 +184,7 @@ final programServiceProvider = Provider<ProgramService>((ref) {
/// 运行状态 Provider
final runStateProvider =
StateNotifierProvider<RunStateNotifier, RunState>((ref) {
final runner = ref.watch(mockRunnerProvider);
final runner = ref.watch(runnerProvider);
final programService = ref.watch(programServiceProvider);
return RunStateNotifier(runner, programService);
});
@@ -185,4 +199,4 @@ final isRunningProvider = Provider<bool>((ref) {
final isPausedProvider = Provider<bool>((ref) {
final status = ref.watch(runStateProvider).status;
return status == RunStatus.paused;
});
});