import 'package:flutter/material.dart'; class UsageHistory { final String date; final String startTime; final String endTime; final int duration; final String startStation; final String endStation; final String status; final bool isSanitized; final bool isDried; UsageHistory({ required this.date, required this.startTime, required this.endTime, required this.duration, required this.startStation, required this.endStation, required this.status, required this.isSanitized, required this.isDried, }); } class HistoryScreen extends StatefulWidget { const HistoryScreen({super.key}); @override State createState() => _HistoryScreenState(); } class _HistoryScreenState extends State { final Color _mainBlueColor = const Color(0xFF002FA7); final Color _mainTextColor = const Color(0xFF1C1C1E); final Color _subTextColor = const Color(0xFF6A717B); final Color _pageBackgroundColor = const Color(0xFFF5F7F9); final Color _cardBackgroundColor = Colors.white; final Color _accentContainerColor = const Color(0xFFF0F2F5); final Color _borderColor = const Color(0xFF0A68FF).withOpacity(0.8); static const BoxShadow _cleanShadow = BoxShadow( color: Color.fromRGBO(0, 0, 0, 0.07), blurRadius: 8, offset: Offset(0, 4), spreadRadius: 0, ); int _selectedFilterIndex = 0; final List _allHistoryList = [ UsageHistory( date: '2025.11.25 (화)', startTime: '18:30', endTime: '19:15', duration: 45, startStation: '스테이션 A - 광주대', endStation: '스테이션 B - 시청', status: 'RETURNED', isSanitized: true, isDried: true, ), UsageHistory( date: '2025.11.23 (일)', startTime: '14:00', endTime: '15:30', duration: 90, startStation: '스테이션 B - 시청', endStation: '스테이션 B - 시청', status: 'RETURNED', isSanitized: true, isDried: false, ), UsageHistory( date: '2025.11.06 (목)', startTime: '09:00', endTime: '09:30', duration: 30, startStation: '스테이션 A - 광주대', endStation: '스테이션 C - 시민공원', status: 'RETURNED', isSanitized: true, isDried: true, ), UsageHistory( date: '2025.09.20 (토)', startTime: '20:00', endTime: '21:00', duration: 60, startStation: '스테이션 C - 시민공원', endStation: '스테이션 B - 시청', status: 'RETURNED', isSanitized: true, isDried: true, ), ]; List get _filteredList { if (_selectedFilterIndex == 0) { return _allHistoryList; } final now = DateTime(2025, 11, 26); return _allHistoryList.where((history) { String dateStr = history.date.split(' ')[0]; List parts = dateStr.split('.'); DateTime historyDate = DateTime( int.parse(parts[0]), int.parse(parts[1]), int.parse(parts[2])); int difference = now.difference(historyDate).inDays; if (_selectedFilterIndex == 1) { return difference <= 7; } else if (_selectedFilterIndex == 2) { return difference <= 30; } return true; }).toList(); } @override Widget build(BuildContext context) { final currentList = _filteredList; return Scaffold( backgroundColor: _pageBackgroundColor, appBar: AppBar( title: Text('나의 기록', style: TextStyle( fontWeight: FontWeight.bold, fontSize: 18, letterSpacing: 0.5, color: _mainTextColor)), backgroundColor: _pageBackgroundColor, scrolledUnderElevation: 0, elevation: 0, centerTitle: false, ), body: Column( children: [ _buildFilterTabs(), Expanded( child: currentList.isEmpty ? Center( child: Text("기록이 없습니다.", style: TextStyle(color: _subTextColor))) : ListView.builder( padding: const EdgeInsets.all(16), itemCount: currentList.length, itemBuilder: (context, index) { final history = currentList[index]; bool showHeader = true; if (index > 0 && currentList[index - 1].date == history.date) { showHeader = false; } return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (showHeader) _buildDateHeader(history.date), _buildHistoryCard(history), ], ); }, ), ), ], ), ); } Widget _buildFilterTabs() { final filters = ["전체", "지난 7일", "지난 30일"]; return Container( height: 50, padding: const EdgeInsets.symmetric(horizontal: 16), child: ListView.separated( scrollDirection: Axis.horizontal, itemCount: filters.length, separatorBuilder: (c, i) => const SizedBox(width: 10), itemBuilder: (context, index) { final isSelected = _selectedFilterIndex == index; return ChoiceChip( label: Text(filters[index]), selected: isSelected, onSelected: (selected) { setState(() => _selectedFilterIndex = index); }, backgroundColor: _cardBackgroundColor, selectedColor: _mainBlueColor, checkmarkColor: Colors.white, labelStyle: TextStyle( color: isSelected ? Colors.white : _mainTextColor, fontWeight: FontWeight.bold, ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), side: BorderSide.none), ); }, ), ); } Widget _buildDateHeader(String date) { return Padding( padding: const EdgeInsets.symmetric(vertical: 16.0), child: Text( date, style: TextStyle( color: _mainTextColor, fontSize: 14, fontWeight: FontWeight.bold), ), ); } Widget _buildHistoryCard(UsageHistory history) { return Container( margin: const EdgeInsets.only(bottom: 12), decoration: BoxDecoration( color: _cardBackgroundColor, borderRadius: BorderRadius.circular(8), boxShadow: [_cleanShadow]), child: InkWell( onTap: () => _showHistoryDetail(context, history), borderRadius: BorderRadius.circular(8), child: Padding( padding: const EdgeInsets.all(16.0), child: Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( '${history.startTime} - ${history.endTime}', style: TextStyle( color: _mainTextColor, fontSize: 16, fontWeight: FontWeight.bold), ), Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: _mainBlueColor, borderRadius: BorderRadius.circular(8), ), child: Text( '${history.duration}분', style: const TextStyle( color: Colors.white, fontSize: 14, fontWeight: FontWeight.w600), ), ), ], ), const SizedBox(height: 12), Row( children: [ _buildDot(_subTextColor), const SizedBox(width: 8), Expanded( child: Text(history.startStation, style: TextStyle(color: _mainTextColor, fontSize: 13), overflow: TextOverflow.ellipsis)), ], ), Container( margin: const EdgeInsets.only(left: 3), height: 10, decoration: BoxDecoration( border: Border( left: BorderSide( color: _subTextColor.withOpacity(0.5), width: 1)), ), ), Row( children: [ _buildDot(_mainBlueColor), const SizedBox(width: 8), Expanded( child: Text(history.endStation, style: TextStyle(color: _mainTextColor, fontSize: 13), overflow: TextOverflow.ellipsis)), ], ), const SizedBox(height: 12), Divider( color: _subTextColor.withOpacity(0.5), thickness: 0.5, ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ if (history.isSanitized) _buildDot(_mainBlueColor), if (history.isSanitized) const SizedBox(width: 8), Text( history.isSanitized ? "살균 완료" : "진행 중", style: TextStyle( color: history.isSanitized ? _mainTextColor : _subTextColor, fontSize: 14, fontWeight: FontWeight.bold), ), ], ), Text( "더보기 >", style: TextStyle(color: _subTextColor, fontSize: 11), ), ], ), ], ), ), ), ); } Widget _buildDot(Color color) { return Container( width: 8, height: 8, decoration: BoxDecoration(color: color, shape: BoxShape.circle)); } void _showHistoryDetail(BuildContext context, UsageHistory history) { int cost = history.duration * 100; showModalBottomSheet( context: context, backgroundColor: Colors.transparent, isScrollControlled: true, builder: (context) { return Container( height: MediaQuery.of(context).size.height * 0.75, decoration: BoxDecoration( color: _cardBackgroundColor, borderRadius: const BorderRadius.vertical(top: Radius.circular(12)), boxShadow: [_cleanShadow]), child: Column( children: [ const SizedBox(height: 12), Container( width: 40, height: 4, decoration: BoxDecoration( color: _subTextColor, borderRadius: BorderRadius.circular(2))), Expanded( child: SingleChildScrollView( padding: const EdgeInsets.all(24), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("이용 상세 정보", style: TextStyle( color: _mainTextColor, fontSize: 20, fontWeight: FontWeight.bold)), const SizedBox(height: 8), Text( history.date, style: TextStyle(color: _subTextColor), ), const SizedBox(height: 30), Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( color: _accentContainerColor, borderRadius: BorderRadius.circular(8)), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("이용 시간", style: TextStyle( color: _subTextColor, fontSize: 12)), const SizedBox(height: 4), Text("${history.duration}분", style: TextStyle( color: _mainTextColor, fontSize: 24, fontWeight: FontWeight.bold)), ], ), Container( width: 1, height: 40, color: _subTextColor.withOpacity(0.5)), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("이용 금액", style: TextStyle( color: _subTextColor, fontSize: 12)), const SizedBox(height: 4), Text("₩ $cost", style: TextStyle( color: _mainTextColor, fontSize: 24, fontWeight: FontWeight.bold)), ], ), ], ), ), const SizedBox(height: 30), Text("시간별 기록", style: TextStyle( color: _mainTextColor, fontSize: 16, fontWeight: FontWeight.bold, letterSpacing: 1.0)), const SizedBox(height: 20), _buildTimelineItem( history.startTime, "대여 시작", history.startStation, isFirst: true, isCompleted: true), _buildTimelineItem( history.endTime, "반납 완료", history.endStation, isCompleted: true), _buildTimelineItem( history.endTime, "살균 시작", "자동 살균 시스템", isCompleted: true), _buildTimelineItem( "15분 후", "살균 완료", "다음 사용자 준비 완료", isLast: true, isCompleted: history.isSanitized), const SizedBox(height: 30), Text("살균/건조 상태", style: TextStyle( color: _mainTextColor, fontSize: 16, fontWeight: FontWeight.bold)), const SizedBox(height: 8), Row( children: [ Expanded( child: _buildConditionCard("살균", history.isSanitized, Icons.sentiment_satisfied_alt)), const SizedBox(width: 12), Expanded( child: _buildConditionCard("건조", history.isDried, Icons.sentiment_very_satisfied)), ], ), ], ), ), ), ], ), ); }, ); } Widget _buildTimelineItem(String time, String title, String subtitle, {bool isFirst = false, bool isLast = false, bool isCompleted = false}) { String displayTime = time.contains("min later") ? "15분 후" : time; return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( width: 60, child: Text(displayTime, style: TextStyle(color: _mainTextColor, fontSize: 12)), ), Column( children: [ Icon( isCompleted ? Icons.check_circle : Icons.radio_button_unchecked, color: isCompleted ? _mainBlueColor : _subTextColor, size: 20), if (!isLast) Container( width: 2, height: 40, color: isCompleted ? _mainBlueColor.withOpacity(0.5) : Colors.grey.shade300), ], ), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(title, style: TextStyle( color: isCompleted ? _mainTextColor : _subTextColor, fontWeight: FontWeight.bold, fontSize: 14)), const SizedBox(height: 4), Text(subtitle, style: TextStyle(color: _subTextColor, fontSize: 12)), const SizedBox(height: 24), ], ), ), ], ); } Widget _buildConditionCard(String title, bool isDone, IconData icon) { return Container( height: 120, width: double.infinity, padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: _accentContainerColor, boxShadow: isDone ? [_cleanShadow] : null, border: Border.all( color: isDone ? _mainBlueColor.withOpacity(0.9) : _subTextColor.withOpacity(0.3), width: 1.0), borderRadius: BorderRadius.circular(8), ), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(icon, color: _mainBlueColor, size: 28), const SizedBox(height: 8), Text( title, style: TextStyle( color: _mainTextColor, fontSize: 14, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 4), Text( isDone ? "완료됨" : "진행 중", style: TextStyle( color: _subTextColor, fontWeight: FontWeight.bold, fontSize: 14), ), ], ), ); } }