uto_manager/lib/presentation/widgets/personnel_list_tile.dart

117 lines
3.5 KiB
Dart

import 'package:flutter/material.dart';
import 'package:uto_manager/domain/entities/personnel_record.dart';
/// A draggable list tile representing a soldier in the personnel panel.
///
/// Can be dragged onto a [PositionSlotCard] to assign the soldier.
class PersonnelListTile extends StatelessWidget {
const PersonnelListTile({
super.key,
required this.record,
this.onTap,
});
final PersonnelRecord record;
final VoidCallback? onTap;
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Draggable<PersonnelRecord>(
data: record,
feedback: Material(
elevation: 6,
borderRadius: BorderRadius.circular(8),
child: Container(
width: 220,
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: theme.colorScheme.primaryContainer,
borderRadius: BorderRadius.circular(8),
),
child: Row(
children: [
Icon(Icons.person, color: theme.colorScheme.onPrimaryContainer, size: 20),
const SizedBox(width: 8),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
record.name,
style: theme.textTheme.bodySmall?.copyWith(
fontWeight: FontWeight.bold,
color: theme.colorScheme.onPrimaryContainer,
),
),
Text(
'${record.payGrade.payGrade} • ${record.primaryMos.code}',
style: theme.textTheme.labelSmall?.copyWith(
color: theme.colorScheme.onPrimaryContainer.withValues(alpha: 0.8),
),
),
],
),
),
],
),
),
),
childWhenDragging: Opacity(
opacity: 0.4,
child: _buildTile(theme),
),
child: _buildTile(theme),
);
}
Widget _buildTile(ThemeData theme) {
return ListTile(
dense: true,
onTap: onTap,
leading: CircleAvatar(
radius: 16,
backgroundColor: _readinessColor(record.readinessState).withValues(alpha: 0.2),
child: Text(
record.payGrade.payGrade,
style: TextStyle(
fontSize: 9,
fontWeight: FontWeight.bold,
color: _readinessColor(record.readinessState),
),
),
),
title: Text(
record.name,
style: theme.textTheme.bodySmall?.copyWith(fontWeight: FontWeight.w600),
),
subtitle: Text(
'${record.primaryMos.code} • ${record.readinessState.displayName}',
style: theme.textTheme.labelSmall?.copyWith(
color: _readinessColor(record.readinessState),
),
),
trailing: Icon(
Icons.drag_indicator,
size: 16,
color: theme.colorScheme.onSurfaceVariant,
),
);
}
Color _readinessColor(ReadinessState state) {
switch (state) {
case ReadinessState.fullyMissionCapable:
return const Color(0xFF4CAF50);
case ReadinessState.partiallyMissionCapable:
return const Color(0xFFFF9800);
case ReadinessState.notMissionCapable:
return const Color(0xFFF44336);
case ReadinessState.unknown:
return Colors.grey;
}
}
}