import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../core/theme/app_theme.dart'; import '../../models/timetable.dart'; import '../../providers/timetable_provider.dart'; class TimetableScreen extends ConsumerWidget { const TimetableScreen({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final timetableAsync = ref.watch(timetableProvider); return Scaffold( appBar: AppBar( title: const Text('Weekly Timetable'), ), body: RefreshIndicator( onRefresh: () async { ref.invalidate(timetableProvider); await ref.read(timetableProvider.future); }, child: timetableAsync.when( loading: () => const Center(child: CircularProgressIndicator()), error: (err, _) => Center( child: Padding( padding: const EdgeInsets.all(24), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.error_outline_rounded, size: 48, color: AppTheme.errorColor), const SizedBox(height: 12), const Text('Failed to load timetable', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)), const SizedBox(height: 8), Text(err.toString(), textAlign: TextAlign.center, style: const TextStyle(color: AppTheme.textSecondary, fontSize: 13)), const SizedBox(height: 16), ElevatedButton( onPressed: () => ref.refresh(timetableProvider), child: const Text('Retry'), ), ], ), ), ), data: (slots) { if (slots.isEmpty) { return const Center( child: Padding( padding: EdgeInsets.all(32), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.calendar_month_outlined, size: 60, color: AppTheme.textMuted), SizedBox(height: 12), Text( 'No timetable slots scheduled', style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600), ), SizedBox(height: 6), Text( 'Your class schedule has not been published yet.', textAlign: TextAlign.center, style: TextStyle(color: AppTheme.textSecondary, fontSize: 13), ), ], ), ), ); } // Group slots by Day or Date final Map> grouped = {}; for (final slot in slots) { final key = slot.day.isNotEmpty ? slot.day : (slot.date.isNotEmpty ? slot.date : 'Scheduled Classes'); grouped.putIfAbsent(key, () => []).add(slot); } return ListView( padding: const EdgeInsets.all(16), children: grouped.entries.map((entry) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 4), child: Text( entry.key.toUpperCase(), style: const TextStyle( fontSize: 13, fontWeight: FontWeight.bold, color: AppTheme.primaryColor, letterSpacing: 0.5, ), ), ), ...entry.value.map((slot) => _buildSlotCard(slot)), const SizedBox(height: 12), ], ); }).toList(), ); }, ), ), ); } Widget _buildSlotCard(TimetableSlot slot) { return Card( child: Padding( padding: const EdgeInsets.all(14), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 8), decoration: BoxDecoration( color: AppTheme.primaryColor.withOpacity(0.08), borderRadius: BorderRadius.circular(8), ), child: Column( children: [ Text( slot.startTime, style: const TextStyle( fontSize: 12, fontWeight: FontWeight.bold, color: AppTheme.primaryDark, ), ), const Text('to', style: TextStyle(fontSize: 10, color: AppTheme.textSecondary)), Text( slot.endTime, style: const TextStyle( fontSize: 12, fontWeight: FontWeight.bold, color: AppTheme.primaryDark, ), ), ], ), ), const SizedBox(width: 14), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( slot.subject?.name ?? 'Lecture Session', style: const TextStyle( fontSize: 15, fontWeight: FontWeight.bold, color: AppTheme.textPrimary, ), ), const SizedBox(height: 6), if (slot.faculty?.name != null) Row( children: [ const Icon(Icons.person_outline, size: 14, color: AppTheme.textSecondary), const SizedBox(width: 4), Text( slot.faculty!.name, style: const TextStyle(fontSize: 12, color: AppTheme.textSecondary), ), ], ), if (slot.room?.name != null) ...[ const SizedBox(height: 3), Row( children: [ const Icon(Icons.meeting_room_outlined, size: 14, color: AppTheme.textSecondary), const SizedBox(width: 4), Text( slot.room!.name, style: const TextStyle(fontSize: 12, color: AppTheme.textSecondary), ), ], ), ], ], ), ), ], ), ), ); } }