Files
bowlingManager/mobile/lib/screens/club/tabs/basic_info_tab.dart
T
2025-11-10 14:14:08 +09:00

211 lines
7.1 KiB
Dart

import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import '../../../models/event_model.dart';
import '../../../utils/url_utils.dart';
import '../../../utils/enum_mappings.dart';
import '../../../theme/badges.dart';
class BasicInfoTab extends StatelessWidget {
final Event event;
final int participantsCount;
final VoidCallback onShareEvent;
final VoidCallback onSetEventReminders;
const BasicInfoTab({
super.key,
required this.event,
required this.participantsCount,
required this.onShareEvent,
required this.onSetEventReminders,
});
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Wrap(
spacing: 8,
runSpacing: 4,
children: [
_badge(
text: getEventTypeLabel(event.type),
color: _getTypeColor(getEventTypeLabel(event.type)),
icon: _getTypeIcon(getEventTypeLabel(event.type)),
),
if (event.status != null)
BadgeStyles.eventStatus(
getEventStatusLabel(event.status),
),
],
),
),
IconButton(
icon: const Icon(Icons.share),
onPressed: onShareEvent,
tooltip: '이벤트 공유',
),
],
),
const SizedBox(height: 16),
if (event.description != null && event.description!.isNotEmpty) ...[
const Text('설명', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
const SizedBox(height: 8),
Container(
width: double.infinity,
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.grey[100],
borderRadius: BorderRadius.circular(8),
),
child: Text(event.description ?? ''),
),
const SizedBox(height: 16),
],
const Text('이벤트 정보', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
const SizedBox(height: 8),
_infoRow(Icons.calendar_today, '시작: ${DateFormat('yyyy-MM-dd HH:mm').format(event.startDate)}'),
if (event.endDate != null)
_infoRow(Icons.calendar_today, '종료: ${DateFormat('yyyy-MM-dd HH:mm').format(event.endDate!)}'),
if (event.location != null && event.location!.isNotEmpty)
_infoRow(Icons.location_on, '장소: ${event.location}'),
if (event.maxParticipants != null)
_infoRow(Icons.people, '최대 참가자: ${event.maxParticipants}명'),
if (event.gameCount != null)
_infoRow(Icons.sports, '게임 수: ${event.gameCount}게임'),
if (event.participantFee != null)
_infoRow(
Icons.attach_money,
event.participantFee == 0
? '참가비: 무료'
: '참가비: ${NumberFormat.currency(locale: 'ko_KR', symbol: '₩', decimalDigits: 0).format(event.participantFee)}',
),
if (event.registrationDeadline != null)
_infoRow(Icons.timer, '신청마감: ${DateFormat('yyyy-MM-dd HH:mm').format(event.registrationDeadline!)}'),
const SizedBox(height: 16),
const Text('공개 접근', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
const SizedBox(height: 8),
if (event.publicHash != null && event.publicHash!.isNotEmpty) ...[
Row(
children: [
Expanded(
child: _infoRow(
Icons.link,
UrlUtils.getEventPublicUrl(event.publicHash!),
isSelectable: true,
),
),
IconButton(
icon: const Icon(Icons.copy),
onPressed: () {
final publicUrl = UrlUtils.getEventPublicUrl(event.publicHash!);
UrlUtils.copyUrlToClipboard(context, publicUrl);
},
tooltip: 'URL 복사',
),
],
),
],
if (event.accessPassword != null && event.accessPassword!.isNotEmpty)
_infoRow(Icons.lock, '접근 비밀번호: ${event.accessPassword}'),
const SizedBox(height: 16),
const Text('참가자 정보', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
const SizedBox(height: 8),
_infoRow(Icons.people, '현재 참가자: $participantsCount명'),
const SizedBox(height: 24),
ElevatedButton.icon(
onPressed: onSetEventReminders,
icon: const Icon(Icons.notifications_active),
label: const Text('알림 설정'),
style: ElevatedButton.styleFrom(
foregroundColor: Colors.white,
backgroundColor: Colors.green,
minimumSize: const Size(double.infinity, 48),
),
),
],
),
);
}
Widget _infoRow(IconData icon, String text, {bool isSelectable = false}) {
final textWidget = isSelectable
? SelectableText(
text,
maxLines: 3,
onTap: () {},
)
: Text(text);
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(icon, size: 20, color: Colors.blueGrey),
const SizedBox(width: 8),
Expanded(child: textWidget),
],
),
);
}
Widget _badge({required String text, required Color color, required IconData icon}) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: color.withOpacity(0.15),
borderRadius: BorderRadius.circular(12),
border: Border.all(color: color.withOpacity(0.3)),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(icon, size: 16, color: color),
const SizedBox(width: 6),
Text(
text,
style: TextStyle(fontWeight: FontWeight.w600, color: color),
),
],
),
);
}
Color _getTypeColor(String type) {
switch (type) {
case '정기전':
return Colors.indigo;
case '연습':
return Colors.teal;
case '대회':
return Colors.deepOrange;
default:
return Colors.blueGrey;
}
}
IconData _getTypeIcon(String type) {
switch (type) {
case '정기전':
return Icons.event;
case '연습':
return Icons.fitness_center;
case '대회':
return Icons.emoji_events;
default:
return Icons.info;
}
}
}