117 lines
3.5 KiB
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;
|
|
}
|
|
}
|
|
}
|