Files
kuaishai2/lib/features/program_detail/widgets/step_list.dart
Developer 3d849bd468 feat(i18n): 完成全量 UI 文本国际化,替换所有硬编码中文为 AppLocalizations 调用
- core/localization: 新增约 60 个翻译键(含参数化方法),中英双语覆盖
- shared/widgets: CommonDialog 默认参数国际化
- features/home: 完成页操作步骤指引、状态栏串口连接状态、程序列表状态标签
- features/programs: 表头状态列、表单验证提示、导入/模板操作反馈、删除确认(参数化)
- features/program_detail: 步骤列表/表单标题、删除确认、速度档位显示(参数化)
- features/device: run_state_provider 错误消息改为错误码
- features/settings: 升级页、密码面板、语言面板、U盘导入面板、串口配置面板全部替换

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-12 15:09:47 +08:00

272 lines
9.1 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'package:flutter/material.dart';
import '../../../core/localization/app_localizations.dart';
import '../../../core/theme/app_theme.dart';
import '../../../shared/widgets/common_button.dart';
import '../../programs/models/step.dart' as models;
/// 步骤列表组件
class StepList extends StatefulWidget {
final int programId;
final List<models.Step> steps;
final int? selectedStepId;
final void Function(int?) onStepSelected;
final void Function() onAddStep;
final void Function(int oldIndex, int newIndex)? onReorder;
final void Function(List<int> stepIds)? onDeleteSteps;
const StepList({
super.key,
required this.programId,
required this.steps,
this.selectedStepId,
required this.onStepSelected,
required this.onAddStep,
this.onReorder,
this.onDeleteSteps,
});
@override
State<StepList> createState() => _StepListState();
}
class _StepListState extends State<StepList> {
final Set<int> _selectedIds = {};
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context);
final allSelected = _selectedIds.length == widget.steps.length && widget.steps.isNotEmpty;
return Container(
color: Colors.white,
child: Column(
children: [
// 标题
Container(
height: 50,
padding: const EdgeInsets.symmetric(horizontal: 16),
decoration: BoxDecoration(
color: AppTheme.primaryColor.withValues(alpha: 0.1),
),
child: Row(
children: [
Icon(Icons.list, color: AppTheme.primaryColor, size: 20),
const SizedBox(width: 12),
Text(
l10n?.stepList ?? '步骤列表',
style: TextStyle(
color: AppTheme.primaryColor,
fontWeight: FontWeight.w600,
),
),
const Spacer(),
Text(
l10n?.stepsCountLabel(widget.steps.length) ?? '${widget.steps.length}',
style: TextStyle(
color: AppTheme.textSecondary,
fontSize: 12,
),
),
],
),
),
// 表头
Container(
height: 40,
padding: const EdgeInsets.symmetric(horizontal: 12),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(color: AppTheme.idleColor.withValues(alpha: 0.2)),
),
),
child: Row(
children: [
SizedBox(
width: 40,
child: Checkbox(
value: allSelected,
onChanged: (value) {
setState(() {
if (value == true) {
_selectedIds.clear();
_selectedIds.addAll(widget.steps.map((s) => s.id!));
} else {
_selectedIds.clear();
}
});
},
),
),
SizedBox(width: 40, child: Text('#', style: TextStyle(fontSize: 12))),
Expanded(child: Text(l10n?.stepName ?? '名称', style: TextStyle(fontSize: 12))),
SizedBox(width: 60, child: Text(l10n?.position ?? '孔位', style: TextStyle(fontSize: 12))),
],
),
),
// 步骤列表(可拖拽排序)
Expanded(
child: widget.steps.isEmpty
? Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.add_circle_outline, size: 48, color: AppTheme.idleColor),
const SizedBox(height: 12),
Text(l10n?.noSteps ?? '暂无步骤', style: TextStyle(color: AppTheme.textSecondary)),
],
),
)
: ReorderableListView.builder(
padding: const EdgeInsets.all(8),
itemCount: widget.steps.length,
onReorder: (oldIndex, newIndex) {
if (widget.onReorder != null) {
// 调整 newIndexReorderableListView 的特殊行为)
if (newIndex > oldIndex) newIndex -= 1;
widget.onReorder!(oldIndex, newIndex);
}
},
itemBuilder: (context, index) {
final step = widget.steps[index];
final isSelected = widget.selectedStepId == step.id || _selectedIds.contains(step.id);
return _buildStepItem(step, isSelected, index);
},
),
),
// 底部操作栏
Container(
height: 60,
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
border: Border(
top: BorderSide(color: AppTheme.idleColor.withValues(alpha: 0.2)),
),
),
child: Row(
children: [
// 添加按钮
CommonButton(
text: l10n?.add ?? '添加',
icon: Icons.add,
type: ButtonType.primary,
onPressed: widget.onAddStep,
),
const SizedBox(width: 12),
// 删除按钮
if (_selectedIds.isNotEmpty)
CommonButton(
text: l10n?.delete ?? '删除',
icon: Icons.delete,
type: ButtonType.danger,
onPressed: () => _showDeleteConfirmDialog(context),
),
],
),
),
],
),
);
}
/// 步骤项
Widget _buildStepItem(models.Step step, bool isSelected, int index) {
return Container(
key: ValueKey(step.id),
margin: const EdgeInsets.symmetric(vertical: 2),
decoration: BoxDecoration(
color: isSelected ? AppTheme.primaryLight.withValues(alpha: 0.3) : Colors.white,
borderRadius: BorderRadius.circular(4),
border: isSelected ? Border.all(color: AppTheme.primaryColor, width: 2) : null,
),
child: ListTile(
dense: true,
leading: Checkbox(
value: _selectedIds.contains(step.id),
onChanged: (value) {
setState(() {
if (value == true) {
_selectedIds.add(step.id!);
} else {
_selectedIds.remove(step.id!);
}
});
},
),
title: Row(
children: [
Container(
width: 30,
alignment: Alignment.center,
child: Text(
'${step.stepNo}',
style: TextStyle(
color: AppTheme.primaryColor,
fontWeight: FontWeight.bold,
),
),
),
const SizedBox(width: 8),
Expanded(child: Text(step.name)),
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: AppTheme.primaryColor.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(4),
),
child: Text(
step.position,
style: TextStyle(
color: AppTheme.primaryColor,
fontSize: 12,
),
),
),
],
),
trailing: Icon(Icons.drag_handle, color: AppTheme.idleColor),
onTap: () => widget.onStepSelected(step.id),
),
);
}
/// 显示删除确认对话框
void _showDeleteConfirmDialog(BuildContext context) {
final l10n = AppLocalizations.of(context);
showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: Text(l10n?.confirm ?? '确认'),
content: Text(
_selectedIds.length == 1
? l10n?.deleteStepConfirmSingle ?? '确定要删除此步骤吗?'
: l10n?.deleteStepConfirmMultiple(_selectedIds.length) ?? '确定要删除选中的 ${_selectedIds.length} 个步骤吗?',
),
actions: [
TextButton(
onPressed: () => Navigator.of(ctx).pop(),
child: Text(l10n?.cancel ?? '取消'),
),
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: AppTheme.errorColor,
foregroundColor: Colors.white,
),
onPressed: () {
Navigator.of(ctx).pop();
if (widget.onDeleteSteps != null) {
widget.onDeleteSteps!(_selectedIds.toList());
}
setState(() {
_selectedIds.clear();
});
},
child: Text(l10n?.confirm ?? '确认'),
),
],
),
);
}
}