ui수정
This commit is contained in:
@@ -32,6 +32,79 @@ class _PublicEventScreenState extends State<PublicEventScreen> {
|
||||
final Map<String, Timer> _postTimers = {};
|
||||
_ResultSort _resultSort = _ResultSort.total;
|
||||
|
||||
String _statusLabel(EventStatus s) {
|
||||
switch (s) {
|
||||
case EventStatus.ready:
|
||||
return 'ready';
|
||||
case EventStatus.active:
|
||||
return 'active';
|
||||
case EventStatus.completed:
|
||||
return 'completed';
|
||||
case EventStatus.canceled:
|
||||
return 'canceled';
|
||||
default:
|
||||
return 'unknown';
|
||||
}
|
||||
}
|
||||
|
||||
Color _statusColor(EventStatus s) {
|
||||
switch (s) {
|
||||
case EventStatus.ready:
|
||||
return Colors.blue.shade50;
|
||||
case EventStatus.active:
|
||||
return Colors.green.shade50;
|
||||
case EventStatus.completed:
|
||||
return Colors.grey.shade200;
|
||||
case EventStatus.canceled:
|
||||
return Colors.red.shade50;
|
||||
default:
|
||||
return Colors.grey.shade100;
|
||||
}
|
||||
}
|
||||
|
||||
String _typeLabel(EventType t) {
|
||||
switch (t) {
|
||||
case EventType.regular:
|
||||
return 'regular';
|
||||
case EventType.tournament:
|
||||
return 'tournament';
|
||||
case EventType.practice:
|
||||
return 'practice';
|
||||
case EventType.league:
|
||||
return 'league';
|
||||
default:
|
||||
return 'unknown';
|
||||
}
|
||||
}
|
||||
|
||||
String _participantStatusLabel(ParticipantStatus s) {
|
||||
switch (s) {
|
||||
case ParticipantStatus.pending:
|
||||
return 'pending';
|
||||
case ParticipantStatus.confirmed:
|
||||
return 'confirmed';
|
||||
case ParticipantStatus.canceled:
|
||||
return 'canceled';
|
||||
default:
|
||||
return 'unknown';
|
||||
}
|
||||
}
|
||||
|
||||
String _paymentLabel(PaymentStatus s) {
|
||||
switch (s) {
|
||||
case PaymentStatus.paid:
|
||||
return 'paid';
|
||||
case PaymentStatus.unpaid:
|
||||
return 'unpaid';
|
||||
case PaymentStatus.refunded:
|
||||
return 'refunded';
|
||||
case PaymentStatus.partial:
|
||||
return 'partial';
|
||||
default:
|
||||
return 'unknown';
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@@ -385,10 +458,13 @@ class _PublicEventScreenState extends State<PublicEventScreen> {
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
children: [
|
||||
if (event.status != null)
|
||||
Chip(key: const Key('status_chip'), label: Text(event.status!)),
|
||||
Chip(
|
||||
key: const Key('status_chip'),
|
||||
label: Text(_statusLabel(event.statusEnum)),
|
||||
backgroundColor: _statusColor(event.statusEnum),
|
||||
),
|
||||
if (event.eventType != null && event.eventType!.isNotEmpty)
|
||||
Chip(key: const Key('type_chip'), label: Text(event.eventType!)),
|
||||
Chip(key: const Key('type_chip'), label: Text(_typeLabel(event.typeEnum))),
|
||||
if (event.startDate != null || event.endDate != null)
|
||||
Chip(
|
||||
key: const Key('period_chip'),
|
||||
@@ -402,32 +478,52 @@ class _PublicEventScreenState extends State<PublicEventScreen> {
|
||||
Chip(key: const Key('deadline_chip'), label: Text('신청마감 ' + event.registrationDeadline!.toLocal().toString().split('.').first)),
|
||||
if (event.participantFee != null)
|
||||
Chip(key: const Key('fee_chip'), label: Text('참가비 ₩' + event.participantFee!.toString())),
|
||||
if (event.location != null && event.location!.isNotEmpty)
|
||||
Chip(key: const Key('location_chip'), label: Text(event.location!)),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
],
|
||||
const SizedBox(height: 8),
|
||||
const Text('참가자', style: TextStyle(fontWeight: FontWeight.bold), key: Key('section_participants')),
|
||||
Text('총 ' + participants.length.toString() + '명', key: const Key('participants_count')),
|
||||
const SizedBox(height: 8),
|
||||
Card(
|
||||
child: participants.isEmpty
|
||||
? const ListTile(
|
||||
key: Key('empty_participants'),
|
||||
title: Text('참가자가 없습니다'),
|
||||
)
|
||||
: Column(
|
||||
children: [
|
||||
for (final p in participants)
|
||||
ListTile(
|
||||
if (teams.isEmpty) ...[
|
||||
const SizedBox(height: 8),
|
||||
const Text('참가자', style: TextStyle(fontWeight: FontWeight.bold), key: Key('section_participants')),
|
||||
Text('총 ' + participants.length.toString() + '명', key: const Key('participants_count')),
|
||||
const SizedBox(height: 8),
|
||||
Card(
|
||||
child: participants.isEmpty
|
||||
? const ListTile(
|
||||
key: Key('empty_participants'),
|
||||
title: Text('참가자가 없습니다'),
|
||||
)
|
||||
: Column(
|
||||
children: [
|
||||
for (final p in participants)
|
||||
ListTile(
|
||||
key: Key('participant_tile_' + p.participantId),
|
||||
title: Text(p.name),
|
||||
subtitle: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
(p.status ?? '-') + ' · avg:' + (p.average?.toString() ?? '-') + ' · hc:' + p.handicap.toString(),
|
||||
key: Key('participant_info_' + p.participantId),
|
||||
Wrap(
|
||||
spacing: 6,
|
||||
runSpacing: 6,
|
||||
children: [
|
||||
Chip(
|
||||
key: Key('participant_status_' + p.participantId),
|
||||
label: Text(_participantStatusLabel(p.statusEnum)),
|
||||
),
|
||||
if (p.paymentStatus != null && p.paymentStatus!.isNotEmpty)
|
||||
Chip(
|
||||
key: Key('participant_payment_' + p.participantId),
|
||||
label: Text(_paymentLabel(p.paymentEnum)),
|
||||
),
|
||||
if (p.memberType != null && p.memberType!.isNotEmpty)
|
||||
Chip(
|
||||
key: Key('participant_type_' + p.participantId),
|
||||
label: Text(p.memberType!),
|
||||
),
|
||||
Text('avg:' + (p.average?.toString() ?? '-') + ' · hc:' + p.handicap.toString(), key: Key('participant_info_' + p.participantId)),
|
||||
],
|
||||
),
|
||||
if (canInputScore && event != null)
|
||||
Padding(
|
||||
@@ -438,7 +534,7 @@ class _PublicEventScreenState extends State<PublicEventScreen> {
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 6),
|
||||
child: SizedBox(
|
||||
width: 54,
|
||||
width: 60,
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
@@ -466,7 +562,7 @@ class _PublicEventScreenState extends State<PublicEventScreen> {
|
||||
isDense: true,
|
||||
hintText: '---',
|
||||
counterText: '',
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 6, horizontal: 6),
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 6, horizontal: 8),
|
||||
),
|
||||
maxLength: 3,
|
||||
onChanged: (v) => _onScoreChanged(p, g, v),
|
||||
@@ -480,10 +576,25 @@ class _PublicEventScreenState extends State<PublicEventScreen> {
|
||||
),
|
||||
],
|
||||
),
|
||||
trailing: Text(
|
||||
'R ' + (partRankMap[p.participantId]?['rank']?.toString() ?? '-') +
|
||||
' · 총 ' + PublicRankingUtils.participantTotalWithHc(p).toString(),
|
||||
key: Key('participant_total_' + p.participantId),
|
||||
trailing: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Container(
|
||||
key: Key('participant_rank_' + p.participantId),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.blue.shade50,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Text('R ' + (partRankMap[p.participantId]?['rank']?.toString() ?? '-'), style: const TextStyle(fontSize: 12)),
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Text(
|
||||
'총 ' + PublicRankingUtils.participantTotalWithHc(p).toString(),
|
||||
key: Key('participant_total_' + p.participantId),
|
||||
),
|
||||
],
|
||||
),
|
||||
onTap: () {
|
||||
if (!canInputScore) {
|
||||
@@ -492,10 +603,11 @@ class _PublicEventScreenState extends State<PublicEventScreen> {
|
||||
}
|
||||
_openScoreDialog(p.participantId, initial: p.rawScores.isNotEmpty ? p.rawScores[0] : null);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 24),
|
||||
const Text('팀', style: TextStyle(fontWeight: FontWeight.bold), key: Key('section_teams')),
|
||||
Text('총 ' + teams.length.toString() + '팀', key: const Key('teams_count')),
|
||||
@@ -509,41 +621,88 @@ class _PublicEventScreenState extends State<PublicEventScreen> {
|
||||
: Column(
|
||||
children: [
|
||||
for (final t in teams)
|
||||
ListTile(
|
||||
title: Row(
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 8),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('팀 ' + t.teamNumber.toString()),
|
||||
const SizedBox(width: 6),
|
||||
Container(
|
||||
key: Key('team_rank_' + t.teamNumber.toString()),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.blue.shade50,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Text('R ' + (teamRankMap[t.teamNumber]?['rank']?.toString() ?? '-'), style: const TextStyle(fontSize: 12)),
|
||||
Row(
|
||||
children: [
|
||||
Text('팀 ' + t.teamNumber.toString()),
|
||||
const SizedBox(width: 6),
|
||||
Container(
|
||||
key: Key('team_rank_' + t.teamNumber.toString()),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.blue.shade50,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Text('R ' + (teamRankMap[t.teamNumber]?['rank']?.toString() ?? '-'), style: const TextStyle(fontSize: 12)),
|
||||
),
|
||||
const Spacer(),
|
||||
SizedBox(
|
||||
width: 100,
|
||||
child: TextFormField(
|
||||
key: Key('team_hc_input_' + t.teamNumber.toString()),
|
||||
initialValue: t.handicap.toString(),
|
||||
keyboardType: TextInputType.number,
|
||||
decoration: const InputDecoration(
|
||||
isDense: true,
|
||||
labelText: '팀 HC',
|
||||
counterText: '',
|
||||
),
|
||||
maxLength: 3,
|
||||
onChanged: (v) async {
|
||||
final val = int.tryParse(v);
|
||||
if (val == null || val < 0 || val > 300) return;
|
||||
try {
|
||||
await _service.updateTeamHandicap(widget.publicHash, teamNumber: t.teamNumber, handicap: val);
|
||||
// 로컬 반영
|
||||
final idx = _teams.indexWhere((tt) => tt.teamNumber == t.teamNumber);
|
||||
if (idx >= 0) {
|
||||
_teams[idx] = PublicTeam(teamId: _teams[idx].teamId, teamNumber: _teams[idx].teamNumber, handicap: val, members: _teams[idx].members);
|
||||
setState(() {});
|
||||
}
|
||||
} catch (_) {}
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Builder(builder: (context) {
|
||||
int membersTotal = 0;
|
||||
for (final m in t.members) {
|
||||
int mt = 0;
|
||||
for (int i = 0; i < m.rawScores.length; i++) {
|
||||
final raw = m.rawScores[i];
|
||||
final hc = (i < m.handicaps.length) ? m.handicaps[i] : 0;
|
||||
if (raw == null) continue;
|
||||
mt += PublicRankingUtils.capScore(raw + hc);
|
||||
}
|
||||
membersTotal += mt;
|
||||
}
|
||||
final total = membersTotal + t.handicap;
|
||||
final avg = t.members.isNotEmpty ? (total / t.members.length).toStringAsFixed(1) : '-';
|
||||
return Text(
|
||||
'총 ' + total.toString() + ' · 평균 ' + avg + ' (팀 HC ' + t.handicap.toString() + ')',
|
||||
key: Key('team_summary_' + t.teamNumber.toString()),
|
||||
);
|
||||
}),
|
||||
const SizedBox(height: 6),
|
||||
// 팀 구성원 리스트
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
for (final m in t.members)
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 2),
|
||||
child: Text('• ' + m.name),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
subtitle: Builder(builder: (context) {
|
||||
int membersTotal = 0;
|
||||
for (final m in t.members) {
|
||||
int mt = 0;
|
||||
for (int i = 0; i < m.rawScores.length; i++) {
|
||||
final raw = m.rawScores[i];
|
||||
final hc = (i < m.handicaps.length) ? m.handicaps[i] : 0;
|
||||
if (raw == null) continue;
|
||||
mt += PublicRankingUtils.capScore(raw + hc);
|
||||
}
|
||||
membersTotal += mt;
|
||||
}
|
||||
final total = membersTotal + t.handicap;
|
||||
final avg = t.members.isNotEmpty ? (total / t.members.length).toStringAsFixed(1) : '-';
|
||||
return Text(
|
||||
'총 ' + total.toString() + ' · 평균 ' + avg + ' (팀 HC ' + t.handicap.toString() + ')',
|
||||
key: Key('team_summary_' + t.teamNumber.toString()),
|
||||
);
|
||||
}),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user