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 { static const Color kBackgroundColor = Color(0xFF27292B); static const Color kCardColor = Color(0xFF30343B); static const Color kAccentColor = Colors.white; static const Color kRedAccent = Color(0xFFFF5252); int _selectedFilterIndex = 0; final List _allHistoryList = [ UsageHistory( date: '2025.11.25 (Tue)', startTime: '18:30', endTime: '19:15', duration: 45, startStation: 'STATION A - GU.UNIV', endStation: 'STATION B - CITY HALL', status: 'RETURNED', isSanitized: true, isDried: true, ), UsageHistory( date: '2025.11.23 (Sun)', startTime: '14:00', endTime: '15:30', duration: 90, startStation: 'STATION B - CITY HALL', endStation: 'STATION B - CITY HALL', status: 'RETURNED', isSanitized: true, isDried: false, ), UsageHistory( date: '2025.11.06 (Thu)', startTime: '09:00', endTime: '09:30', duration: 30, startStation: 'STATION A - GU.UNIV', endStation: 'STATION C - PARK', status: 'RETURNED', isSanitized: true, isDried: true, ), UsageHistory( date: '2025.09.20 (Sat)', startTime: '20:00', endTime: '21:00', duration: 60, startStation: 'STATION C - PARK', endStation: 'STATION B - CITY HALL', 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: kBackgroundColor, appBar: AppBar( title: const Text('HISTORY', style: TextStyle(fontWeight: FontWeight .bold, fontSize: 16, color: Colors.white)), backgroundColor: kBackgroundColor, scrolledUnderElevation: 0, elevation: 0, centerTitle: false, actions: [ IconButton(icon: const Icon(Icons.filter_list, color: Colors.white), onPressed: () {}), ], ), body: Column( children: [ _buildFilterTabs(), Expanded( child: currentList.isEmpty ? const Center( child: Text("기록이 없습니다.", style: TextStyle(color: Colors.grey))) : 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: kCardColor, selectedColor: kAccentColor, checkmarkColor: Colors.black, labelStyle: TextStyle( color: isSelected ? Colors.black : Colors.white, fontWeight: FontWeight.bold, ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20), side: BorderSide.none), ); }, ), ); } Widget _buildDateHeader(String date) { return Padding( padding: const EdgeInsets.symmetric(vertical: 16.0), child: Text( date, style: const TextStyle( color: Colors.white, fontSize: 14, fontWeight: FontWeight.bold ), ), ); } Widget _buildHistoryCard(UsageHistory history) { return Container( margin: const EdgeInsets.only(bottom: 12), decoration: BoxDecoration( color: kCardColor, borderRadius: BorderRadius.circular(16), ), child: InkWell( onTap: () => _showHistoryDetail(context, history), borderRadius: BorderRadius.circular(16), child: Padding( padding: const EdgeInsets.all(16.0), child: Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( '${history.startTime} - ${history.endTime}', style: const TextStyle(color: Colors.white, fontSize: 16, fontWeight: FontWeight.bold), ), Container( padding: const EdgeInsets.symmetric( horizontal: 8, vertical: 4), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(8), ), child: Text( '${history.duration} min', style: const TextStyle(color: Colors.black, fontSize: 14, fontWeight: FontWeight.w600), ), ), ], ), const SizedBox(height: 12), Row( children: [ _buildDot(Colors.grey), const SizedBox(width: 8), Expanded(child: Text(history.startStation, style: const TextStyle(color: Colors.white, fontSize: 13), overflow: TextOverflow.ellipsis)), ], ), Container( margin: const EdgeInsets.only(left: 3), height: 10, decoration: const BoxDecoration( border: Border( left: BorderSide(color: Colors.grey, width: 1)), ), ), Row( children: [ _buildDot(kRedAccent), const SizedBox(width: 8), Expanded(child: Text(history.endStation, style: const TextStyle(color: Colors.white, fontSize: 13), overflow: TextOverflow.ellipsis)), ], ), const SizedBox(height: 12), const Divider(color: Colors.white, thickness: 0.5,), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ if (history.isSanitized) _buildDot(kRedAccent), if (history.isSanitized) const SizedBox(width: 8), Text( history.isSanitized ? "살균 완료" : "Pending", style: TextStyle( color: history.isSanitized ? Colors.white : Colors .white, fontSize: 14, fontWeight: FontWeight.bold), ), ], ), const Text( "VIEW DETAILS >", style: TextStyle(color: Colors.white, 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: const BoxDecoration( color: kBackgroundColor, borderRadius: BorderRadius.vertical(top: Radius.circular(24)), ), child: Column( children: [ const SizedBox(height: 12), Container(width: 40, height: 4, decoration: BoxDecoration(color: Colors.grey[600], borderRadius: BorderRadius.circular(2))), Expanded( child: SingleChildScrollView( padding: const EdgeInsets.all(24), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text("HISTORY DETAILS", style: TextStyle( color: Colors.white, fontSize: 20, fontWeight: FontWeight.bold)), const SizedBox(height: 8), Text( history.date, style: const TextStyle(color: Colors.white), ), const SizedBox(height: 30), Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration(color: kCardColor, borderRadius: BorderRadius.circular(16)), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text("이용 시간", style: TextStyle( color: Colors.white, fontSize: 12)), const SizedBox(height: 4), Text("${history.duration} min", style: const TextStyle(color: Colors.white, fontSize: 24, fontWeight: FontWeight.bold)), ], ), Container( width: 1, height: 40, color: Colors.white24), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text("이용 금액", style: TextStyle( color: Colors.white, fontSize: 12)), const SizedBox(height: 4), Text("$cost ₩", style: const TextStyle( color: Colors.white, fontSize: 24, fontWeight: FontWeight.bold)), ], ), ], ), ), const SizedBox(height: 30), const Text("TIMELINE", style: TextStyle( color: Colors.white, 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, "살균 시작", "Auto-Cleaning System", isCompleted: true), _buildTimelineItem( "15 min later", "살균 완료", "Ready for next user", isLast: true, isCompleted: history.isSanitized), const SizedBox(height: 30), const Text("CONDITION", style: TextStyle( color: Colors.white, 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}) { return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( width: 60, child: Text( time, style: const TextStyle(color: Colors.white, fontSize: 12)), ), Column( children: [ Icon( isCompleted ? Icons.check_circle : Icons.radio_button_unchecked, color: isCompleted ? kRedAccent : Colors.grey, size: 20), if (!isLast) Container(width: 2, height: 40, color: isCompleted ? kRedAccent.withValues(alpha: 0.5) : Colors.grey[800]), ], ), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(title, style: TextStyle( color: isCompleted ? Colors.white : Colors.grey, fontWeight: FontWeight.bold, fontSize: 14)), const SizedBox(height: 4), Text(subtitle, style: TextStyle(color: Colors.white, 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: kCardColor, border: Border.all( color: isDone ? Colors.white : Colors.transparent, width: 1.0), borderRadius: BorderRadius.circular(12), ), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(icon, color: Colors.white, size: 28), const SizedBox(height: 8), Text( title, style: const TextStyle( color: Colors.white, fontSize: 14, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 4), Text( isDone ? "Completed" : "In Progress", style: const TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 14 ), ), ], ), ); } }