- 将程序名文本包装在Flexible组件中并添加省略号处理 - 为步骤信息添加Flexible组件以改善布局 - 使用ScrollableVIew包装内容以支持滚动 - 重构步骤参数显示为三列布局 - 移除硬编码的温度和磁力时间参数 - 更新速度、持续时间和样品体积的单位显示 - 从状态栏移除设备名称显示 - 从设置菜单移除USB导入功能选项
224 lines
6.6 KiB
Dart
224 lines
6.6 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import '../../../core/localization/app_localizations.dart';
|
|
import '../../../core/theme/app_theme.dart';
|
|
import '../../device/providers/run_state_provider.dart';
|
|
|
|
/// 运行状态监控面板 - 暗色工业风格
|
|
/// 显示当前孔位、步骤、倒计时、进度条、参数详情
|
|
class RunStatusMonitor extends ConsumerWidget {
|
|
const RunStatusMonitor({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
final l10n = AppLocalizations.of(context);
|
|
final runState = ref.watch(runStateProvider);
|
|
|
|
if (runState.status == RunStatus.idle) {
|
|
return const SizedBox.shrink();
|
|
}
|
|
|
|
return Container(
|
|
padding: const EdgeInsets.all(16),
|
|
decoration: BoxDecoration(
|
|
color: AppTheme.cardBg,
|
|
borderRadius: BorderRadius.circular(8),
|
|
border: Border.all(color: AppTheme.borderSubtle, width: 1),
|
|
),
|
|
child: SingleChildScrollView(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
// 标题 + 程序名
|
|
Row(
|
|
children: [
|
|
Text(
|
|
l10n?.runningMonitor ?? '运行状态监控',
|
|
style: const TextStyle(
|
|
color: AppTheme.textHeading,
|
|
fontSize: 15,
|
|
fontWeight: FontWeight.w600,
|
|
),
|
|
),
|
|
const Spacer(),
|
|
Flexible(
|
|
child: Text(
|
|
runState.currentProgram?.name ?? '',
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
style: const TextStyle(
|
|
color: AppTheme.accentPrimary,
|
|
fontSize: 18,
|
|
fontWeight: FontWeight.w700,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
|
|
const SizedBox(height: 14),
|
|
|
|
// 进度信息横排 (孔位 / 步骤 / 剩余时间)
|
|
Row(
|
|
children: [
|
|
// 当前孔位
|
|
_buildInfoBlock(
|
|
label: l10n?.currentHole ?? '当前孔位',
|
|
value: runState.currentWell ?? '--',
|
|
valueColor: AppTheme.textHeading,
|
|
),
|
|
const SizedBox(width: 20),
|
|
// 当前步骤
|
|
Flexible(
|
|
child: _buildInfoBlock(
|
|
label: l10n?.currentStep ?? '当前步骤',
|
|
value: '${l10n?.stepNo ?? '步骤'} ${runState.currentStepIndex + 1}',
|
|
subValue: runState.currentStep?.name ?? '--',
|
|
valueColor: AppTheme.accentInfo,
|
|
),
|
|
),
|
|
const SizedBox(width: 20),
|
|
// 剩余时间
|
|
_buildInfoBlock(
|
|
label: l10n?.remainingTime ?? '剩余时间',
|
|
value: runState.formattedRemainingTime,
|
|
valueColor: AppTheme.textHeading,
|
|
valueSize: 20,
|
|
),
|
|
],
|
|
),
|
|
|
|
const SizedBox(height: 14),
|
|
|
|
// 总进度条
|
|
_buildProgressBar(l10n, runState),
|
|
|
|
const SizedBox(height: 14),
|
|
|
|
// 步骤参数
|
|
if (runState.currentStep != null)
|
|
_buildStepParams(l10n, runState.currentStep!),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
/// 信息块
|
|
Widget _buildInfoBlock({
|
|
required String label,
|
|
required String value,
|
|
String? subValue,
|
|
Color valueColor = AppTheme.textHeading,
|
|
double valueSize = 16,
|
|
}) {
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
label,
|
|
style: const TextStyle(
|
|
color: AppTheme.textTertiary,
|
|
fontSize: 11,
|
|
),
|
|
),
|
|
const SizedBox(height: 2),
|
|
Text(
|
|
value,
|
|
style: TextStyle(
|
|
color: valueColor,
|
|
fontSize: valueSize,
|
|
fontWeight: FontWeight.w600,
|
|
fontFamily: 'monospace',
|
|
),
|
|
),
|
|
if (subValue != null) ...[
|
|
const SizedBox(height: 2),
|
|
Text(
|
|
subValue,
|
|
style: const TextStyle(
|
|
color: AppTheme.textSecondary,
|
|
fontSize: 11,
|
|
),
|
|
),
|
|
],
|
|
],
|
|
);
|
|
}
|
|
|
|
/// 进度条
|
|
Widget _buildProgressBar(AppLocalizations? l10n, RunState runState) {
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Row(
|
|
children: [
|
|
Text(
|
|
l10n?.progress ?? '总进度',
|
|
style: const TextStyle(
|
|
color: AppTheme.textTertiary,
|
|
fontSize: 11,
|
|
),
|
|
),
|
|
const Spacer(),
|
|
Text(
|
|
runState.formattedProgress,
|
|
style: const TextStyle(
|
|
color: AppTheme.accentPrimary,
|
|
fontSize: 12,
|
|
fontWeight: FontWeight.w600,
|
|
fontFamily: 'monospace',
|
|
),
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 6),
|
|
ClipRRect(
|
|
borderRadius: BorderRadius.circular(4),
|
|
child: LinearProgressIndicator(
|
|
value: runState.progress,
|
|
minHeight: 8,
|
|
backgroundColor: const Color(0xFF1E293B),
|
|
valueColor: AlwaysStoppedAnimation<Color>(AppTheme.accentPrimary),
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
/// 步骤参数详情
|
|
Widget _buildStepParams(AppLocalizations? l10n, dynamic step) {
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
l10n?.stepParams ?? '步骤参数',
|
|
style: const TextStyle(
|
|
color: AppTheme.textTertiary,
|
|
fontSize: 11,
|
|
),
|
|
),
|
|
const SizedBox(height: 8),
|
|
Row(
|
|
children: [
|
|
_buildInfoBlock(
|
|
label: l10n?.speed ?? '速度',
|
|
value: '${step.speed} ${l10n?.speedLevel ?? '档'}',
|
|
),
|
|
const SizedBox(width: 20),
|
|
_buildInfoBlock(
|
|
label: l10n?.duration ?? '持续时间',
|
|
value: '${step.mixTime} s',
|
|
),
|
|
const SizedBox(width: 20),
|
|
_buildInfoBlock(
|
|
label: l10n?.sampleVolume ?? '样品体积',
|
|
value: '${step.volume} μL',
|
|
),
|
|
],
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|