import 'package:flutter/material.dart'; /// 배지(Chip) 스타일 매핑과 헬퍼 class BadgeStyles { // 색상 팔레트 static const Color primary = Color(0xFF1565C0); // Blue 700 static const Color success = Color(0xFF2E7D32); // Green 800 static const Color warning = Color(0xFFEF6C00); // Orange 800 static const Color danger = Color(0xFFC62828); // Red 800 // 배경 톤 (100 계열 느낌) static final Color primaryBg = Colors.blue.shade100; static final Color successBg = Colors.green.shade100; static final Color dangerBg = Colors.red.shade100; static final Color neutralBg = Colors.grey.shade200; // 회원 유형 컬러/아이콘 매핑 static Chip memberType(String type) { late final Color bg; late final IconData icon; switch (type) { case '정회원': bg = primaryBg; icon = Icons.person; break; case '준회원': bg = Colors.indigo.shade100; icon = Icons.person_outline; break; case '게스트': bg = neutralBg; icon = Icons.person_add_alt; break; default: bg = neutralBg; icon = Icons.person_outline; } return _chip(type, bg, icon); } // 게스트용 초소형 원형 배지 (이니셜 'G') static Widget guestSmall({double size = 18, Color? bg, Color? fg}) { final Color bgColor = bg ?? neutralBg; final Color fgColor = fg ?? Colors.black87; return Container( width: size, height: size, decoration: BoxDecoration( color: bgColor, shape: BoxShape.circle, border: Border.all(color: Colors.grey.shade300), ), alignment: Alignment.center, child: Text( 'G', style: TextStyle( fontSize: size * 0.62, fontWeight: FontWeight.w700, color: fgColor, height: 1.0, ), ), ); } // 참가 상태 컬러/아이콘 매핑 static Chip participantStatus(String status) { late final Color bg; late final IconData icon; // status는 한국어 라벨 또는 API 값(pending/confirmed/canceled/attended)로 들어올 수 있음 final s = status.toLowerCase(); String label; if (s == 'pending' || s == '참가예정' || s == '등록됨' || s == '대기') { bg = neutralBg; icon = Icons.how_to_reg; label = '예정'; } else if (s == 'confirmed' || s == '참가확정' || s == '확인됨') { bg = successBg; icon = Icons.check_circle; label = '확정'; } else if (s == 'canceled' || s == '취소' || s == '취소됨') { bg = dangerBg; icon = Icons.cancel; label = '취소'; } else if (s == 'attended' || s == '참석' || s == '참석함') { bg = primaryBg; icon = Icons.event_available; label = '참석'; } else { bg = neutralBg; icon = Icons.help_outline; label = status; } return _chip(label, bg, icon); } // 회원 상태 컬러/아이콘 매핑 (라벨 기준: 활성/비활성/정지/삭제됨) static Chip memberStatus(String label) { late final Color bg; late final IconData icon; switch (label) { case '활성': bg = successBg; icon = Icons.check_circle; break; case '비활성': bg = neutralBg; icon = Icons.pause_circle_filled; break; case '정지': bg = dangerBg; icon = Icons.block; break; case '삭제됨': bg = Colors.grey.shade300; icon = Icons.delete_forever; break; default: bg = neutralBg; icon = Icons.person; } return _chip(label, bg, icon); } // 결제 상태 컬러/아이콘 매핑 static Chip payment(bool isPaid) { return _chip( isPaid ? '납부' : '미납', isPaid ? successBg : dangerBg, isPaid ? Icons.check_circle : Icons.cancel, ); } // 이벤트 상태 컬러/아이콘 매핑 static Chip eventStatus(String status) { late final Color bg; late final IconData icon; // DB 원시값(영문) 또는 한국어 라벨을 모두 지원하도록 정규화 final s = status.toLowerCase().trim(); String label = status; // 표시용 라벨 (한국어) if (s == 'active' || s == 'enabled' || s == '활성') { label = '활성'; bg = successBg; icon = Icons.check_circle; } else if (s == 'pending' || s == 'draft' || s == 'scheduled' || s == 'waiting' || s == '대기') { label = '대기'; bg = Colors.amber.shade100; icon = Icons.hourglass_top; } else if (s == 'canceled' || s == 'cancelled' || s == '취소') { label = '취소'; bg = dangerBg; icon = Icons.cancel; } else if (s == 'completed' || s == 'done' || s == 'finished' || s == '완료') { label = '완료'; bg = Colors.grey.shade300; icon = Icons.done_all; } else { // 알 수 없는 상태는 중립 처리 label = status; bg = neutralBg; icon = Icons.event; } return _chip(label, bg, icon); } static Chip _chip(String text, Color bg, IconData icon) { // 배경 대비에 따라 텍스트/아이콘 색상을 자동 설정 (흰/검정 중 더 높은 대비 선택) double lumBg = bg.computeLuminance(); // 대비비 계산 함수 (WCAG 근사) double contrast(double lum1, double lum2) { final double l1 = lum1 > lum2 ? lum1 : lum2; final double l2 = lum1 > lum2 ? lum2 : lum1; return (l1 + 0.05) / (l2 + 0.05); } final double contrastWithWhite = contrast( lumBg, Colors.white.computeLuminance(), ); final double contrastWithBlack = contrast( lumBg, Colors.black.computeLuminance(), ); final Color fg = contrastWithWhite >= contrastWithBlack ? Colors.white : Colors.black; return Chip( avatar: Icon(icon, size: 14, color: fg), label: Text(text, style: TextStyle(color: fg, fontSize: 11)), backgroundColor: bg, padding: const EdgeInsets.symmetric(horizontal: 2, vertical: 0), labelPadding: const EdgeInsets.only(left: -2, right: 5), materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, visualDensity: const VisualDensity(horizontal: -3, vertical: -3), ); } }