import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:intl/intl.dart'; import '../../../core/localization/app_localizations.dart'; import '../../../core/theme/app_theme.dart'; import '../../programs/models/program.dart'; import '../../programs/providers/programs_provider.dart'; /// 程序列表组件 - 暗色工业风格 /// 显示程序卡片列表,支持选择操作 class ProgramList extends ConsumerWidget { const ProgramList({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final l10n = AppLocalizations.of(context); final programsState = ref.watch(programsProvider); final programsNotifier = ref.read(programsProvider.notifier); return Container( decoration: BoxDecoration( color: AppTheme.cardBg, borderRadius: BorderRadius.circular(8), border: Border.all(color: AppTheme.borderSubtle, width: 1), ), child: Column( children: [ // 标题 Padding( padding: const EdgeInsets.all(14), child: Row( children: [ Icon(Icons.list_alt, color: AppTheme.textHeading, size: 18), const SizedBox(width: 10), Text( l10n?.availablePrograms ?? '可用程序', style: const TextStyle( color: AppTheme.textHeading, fontSize: 16, fontWeight: FontWeight.w600, ), ), ], ), ), // 程序列表 Expanded( child: programsState.isLoading ? const Center(child: CircularProgressIndicator()) : programsState.programs.isEmpty ? Center( child: Text( l10n?.noData ?? '暂无数据', style: const TextStyle( color: AppTheme.textSecondary, fontSize: 14, ), ), ) : ListView.builder( padding: const EdgeInsets.symmetric(horizontal: 14), itemCount: programsState.programs.length, itemBuilder: (context, index) { final program = programsState.programs[index]; final isSelected = programsState.selectedProgramId == program.id; return Padding( padding: const EdgeInsets.only(bottom: 8), child: _ProgramCard( program: program, isSelected: isSelected, onTap: () { programsNotifier.selectProgram(program.id); }, ), ); }, ), ), ], ), ); } } /// 单个程序卡片 - 暗色工业风格 class _ProgramCard extends StatelessWidget { final Program program; final bool isSelected; final VoidCallback? onTap; const _ProgramCard({ required this.program, this.isSelected = false, this.onTap, }); @override Widget build(BuildContext context) { final dateFormat = DateFormat('yyyy-MM-dd HH:mm'); final createdAt = _parseDate(program.createdAt); final l10n = AppLocalizations.of(context); return Material( color: Colors.transparent, child: InkWell( onTap: onTap, borderRadius: BorderRadius.circular(8), child: Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: isSelected ? AppTheme.cardSelectedBg : AppTheme.cardBg, borderRadius: BorderRadius.circular(8), border: Border.all( color: isSelected ? AppTheme.accentPrimary : AppTheme.borderSubtle, width: isSelected ? 2 : 1, ), ), child: Row( children: [ // 选择指示器 Container( width: 20, height: 20, decoration: BoxDecoration( shape: BoxShape.circle, color: isSelected ? AppTheme.accentPrimary : Colors.transparent, border: Border.all( color: isSelected ? AppTheme.accentPrimary : AppTheme.statusStopped, width: 2, ), ), child: isSelected ? const Icon(Icons.check, color: Colors.white, size: 12) : null, ), const SizedBox(width: 12), // 程序信息 Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Text( program.code, style: const TextStyle( color: AppTheme.textSecondary, fontSize: 12, ), ), const SizedBox(width: 8), Container( padding: const EdgeInsets.symmetric( horizontal: 6, vertical: 2, ), decoration: BoxDecoration( color: program.status == 1 ? AppTheme.statusRunning.withValues(alpha: 0.15) : AppTheme.statusStopped.withValues(alpha: 0.15), borderRadius: BorderRadius.circular(4), ), child: Text( program.status == 1 ? (l10n?.enabled ?? '启用') : (l10n?.disabled ?? '停用'), style: TextStyle( color: program.status == 1 ? AppTheme.statusRunning : AppTheme.statusStopped, fontSize: 10, ), ), ), ], ), const SizedBox(height: 4), Text( program.name, style: const TextStyle( color: AppTheme.textHeading, fontSize: 14, fontWeight: FontWeight.w500, ), maxLines: 1, overflow: TextOverflow.ellipsis, ), const SizedBox(height: 4), Text( createdAt != null ? dateFormat.format(createdAt) : program.createdAt, style: const TextStyle( color: AppTheme.textTertiary, fontSize: 11, fontFamily: 'monospace', ), ), ], ), ), ], ), ), ), ); } DateTime? _parseDate(String dateStr) { try { return DateTime.parse(dateStr); } catch (e) { return null; } } }