diff --git a/lib/screens/calendar_screen.dart b/lib/screens/calendar_screen.dart index 2ddfd04..e06de33 100644 --- a/lib/screens/calendar_screen.dart +++ b/lib/screens/calendar_screen.dart @@ -5,6 +5,12 @@ import 'package:shared_preferences/shared_preferences.dart'; import '../services/google_calendar_service.dart'; import '../utils/translations.dart'; +enum EventType { + regular, // Dežurstvo and other regular events + competition, // Liga and Tekmovanje (League and Competition events) + sestanek, // Meetings +} + class CalendarScreen extends StatefulWidget { const CalendarScreen({super.key}); @@ -91,21 +97,36 @@ class _CalendarScreenState extends State { } bool _isValidEvent(CalendarEvent event) { - // Filter out events that are just single names or too short + // Filter out events with empty summaries if (event.summary == null || event.summary!.trim().isEmpty) { return false; } final summary = event.summary!.trim(); - // Exclude if it's just a single word (likely just a name) - if (!summary.contains(' ') && summary.length < 15) { + // Only exclude very short single-character entries + // This allows short event names like "Meeting", "Training", etc. + if (summary.length < 2) { return false; } return true; } + EventType _getEventType(CalendarEvent event) { + if (event.summary == null) return EventType.regular; + + final summary = event.summary!.toLowerCase(); + + if (summary.contains('liga') || summary.contains('tekmovanje') || summary.contains('tekma')) { + return EventType.competition; + } else if (summary.contains('sestanek')) { + return EventType.sestanek; + } + + return EventType.regular; + } + Future _loadEvents() async { setState(() { _isLoading = true; @@ -214,7 +235,7 @@ class _CalendarScreenState extends State { child: _events.isEmpty ? ListView( children: [ - SizedBox(height: MediaQuery.of(context).size.height * 0.3), + const SizedBox(height: 24), Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, @@ -233,6 +254,25 @@ class _CalendarScreenState extends State { ], ), ), + const SizedBox(height: 32), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Text( + _t('Example Event Preview'), + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: Colors.grey[700], + ), + textAlign: TextAlign.center, + ), + ), + const SizedBox(height: 16), + _buildSampleEventCard(accentColor, EventType.regular), + const SizedBox(height: 8), + _buildSampleEventCard(accentColor, EventType.competition), + const SizedBox(height: 8), + _buildSampleEventCard(accentColor, EventType.sestanek), ], ) : ListView.builder( @@ -247,9 +287,188 @@ class _CalendarScreenState extends State { ); } + Widget _buildSampleEventCard(Color accentColor, EventType eventType) { + // Color coding for each event type + Color cardAccentColor; + Color backgroundColor = Colors.grey[300]!; + IconData eventIcon; + String title; + String time; + + switch (eventType) { + case EventType.competition: + cardAccentColor = Colors.green; + eventIcon = Icons.emoji_events; + title = _selectedLanguage == 'Slovenian' ? 'Liga / Tekmovanje' : 'League / Competition'; + time = '09:00 - 18:00'; + break; + case EventType.sestanek: + cardAccentColor = Colors.purple; + eventIcon = Icons.groups; + title = _selectedLanguage == 'Slovenian' ? 'Sestanek ekipe' : 'Team Meeting'; + time = '18:00 - 19:00'; + break; + case EventType.regular: + cardAccentColor = Colors.blue; + eventIcon = Icons.event; + title = _selectedLanguage == 'Slovenian' ? 'Dežurstvo' : 'Duty Shift'; + time = '14:00 - 16:00'; + break; + } + + return Container( + margin: const EdgeInsets.symmetric(vertical: 6, horizontal: 16), + decoration: BoxDecoration( + color: backgroundColor, + borderRadius: BorderRadius.circular(12), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Date header + Container( + width: double.infinity, + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + decoration: BoxDecoration( + color: cardAccentColor.withValues(alpha: 0.2), + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(12), + topRight: Radius.circular(12), + ), + ), + child: Row( + children: [ + // Small colored indicator + Container( + width: 4, + height: 16, + decoration: BoxDecoration( + color: cardAccentColor, + borderRadius: BorderRadius.circular(2), + ), + ), + const SizedBox(width: 8), + Text( + _t('Today'), + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.bold, + color: cardAccentColor, + ), + ), + const Spacer(), + // Event type badge - filled badges for all types + Container( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5), + decoration: BoxDecoration( + color: cardAccentColor, + borderRadius: BorderRadius.circular(12), + boxShadow: [ + BoxShadow( + color: cardAccentColor.withValues(alpha: 0.3), + blurRadius: 4, + offset: const Offset(0, 2), + ), + ], + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(eventIcon, size: 12, color: Colors.white), + const SizedBox(width: 4), + Text( + eventType == EventType.competition + ? (_selectedLanguage == 'Slovenian' ? 'TEKMOVANJE' : 'COMPETITION') + : eventType == EventType.sestanek + ? (_selectedLanguage == 'Slovenian' ? 'SESTANEK' : 'MEETING') + : (_selectedLanguage == 'Slovenian' ? 'DEŽURSTVO' : 'DUTY'), + style: const TextStyle( + fontSize: 10, + fontWeight: FontWeight.bold, + color: Colors.white, + letterSpacing: 0.8, + ), + ), + ], + ), + ), + ], + ), + ), + // Main content + Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Title with icon + Row( + children: [ + Icon(eventIcon, size: 20, color: cardAccentColor), + const SizedBox(width: 8), + Expanded( + child: Text( + title, + style: const TextStyle( + fontSize: 15, + fontWeight: FontWeight.w600, + color: Colors.black87, + ), + ), + ), + ], + ), + const SizedBox(height: 8), + // Time range + _buildDetailRowInline( + icon: Icons.access_time, + value: time, + accentColor: cardAccentColor, + ), + const SizedBox(height: 6), + // Location + _buildDetailRowInline( + icon: Icons.location_on, + value: _selectedLanguage == 'Slovenian' + ? 'Strelišče Ljubljana' + : 'Shooting Range', + accentColor: cardAccentColor, + ), + ], + ), + ), + ], + ), + ); + } + Widget _buildEventCard(CalendarEvent event, Color accentColor) { final startTime = event.startTime; final isAllDay = event.isAllDay; + final eventType = _getEventType(event); + + // Color coding for each event type + Color cardAccentColor; + Color backgroundColor; + IconData eventIcon; + + switch (eventType) { + case EventType.competition: + cardAccentColor = Colors.green; + backgroundColor = Colors.grey[300]!; + eventIcon = Icons.emoji_events; // Trophy icon for competitions + break; + case EventType.sestanek: + cardAccentColor = Colors.purple; + backgroundColor = Colors.grey[300]!; + eventIcon = Icons.groups; // People icon for meetings + break; + case EventType.regular: + cardAccentColor = Colors.blue; + backgroundColor = Colors.grey[300]!; + eventIcon = Icons.event; + break; + } // Format the date for display String dateText = ''; @@ -279,7 +498,7 @@ class _CalendarScreenState extends State { return Container( margin: const EdgeInsets.symmetric(vertical: 6, horizontal: 16), decoration: BoxDecoration( - color: Colors.grey[300], + color: backgroundColor, borderRadius: BorderRadius.circular(12), ), child: Column( @@ -291,8 +510,8 @@ class _CalendarScreenState extends State { padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), decoration: BoxDecoration( color: isToday - ? accentColor.withValues(alpha: 0.15) - : Colors.grey[200], + ? cardAccentColor.withValues(alpha: 0.2) + : cardAccentColor.withValues(alpha: 0.1), borderRadius: const BorderRadius.only( topLeft: Radius.circular(12), topRight: Radius.circular(12), @@ -305,7 +524,7 @@ class _CalendarScreenState extends State { width: 4, height: 16, decoration: BoxDecoration( - color: accentColor, + color: cardAccentColor, borderRadius: BorderRadius.circular(2), ), ), @@ -315,7 +534,43 @@ class _CalendarScreenState extends State { style: TextStyle( fontSize: 14, fontWeight: FontWeight.bold, - color: isToday ? accentColor : Colors.black87, + color: cardAccentColor, + ), + ), + const Spacer(), + // Event type badge - filled badges for all types + Container( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5), + decoration: BoxDecoration( + color: cardAccentColor, + borderRadius: BorderRadius.circular(12), + boxShadow: [ + BoxShadow( + color: cardAccentColor.withValues(alpha: 0.3), + blurRadius: 4, + offset: const Offset(0, 2), + ), + ], + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(eventIcon, size: 12, color: Colors.white), + const SizedBox(width: 4), + Text( + eventType == EventType.competition + ? (_selectedLanguage == 'Slovenian' ? 'TEKMOVANJE' : 'COMPETITION') + : eventType == EventType.sestanek + ? (_selectedLanguage == 'Slovenian' ? 'SESTANEK' : 'MEETING') + : (_selectedLanguage == 'Slovenian' ? 'DEŽURSTVO' : 'DUTY'), + style: const TextStyle( + fontSize: 10, + fontWeight: FontWeight.bold, + color: Colors.white, + letterSpacing: 0.8, + ), + ), + ], ), ), ], @@ -330,12 +585,12 @@ class _CalendarScreenState extends State { // Title with icon Row( children: [ - Icon(Icons.event, size: 20, color: accentColor), + Icon(eventIcon, size: 20, color: cardAccentColor), const SizedBox(width: 8), Expanded( child: Text( event.summary ?? _t('Untitled Event'), - style: const TextStyle( + style: TextStyle( fontSize: 15, fontWeight: FontWeight.w600, color: Colors.black87, @@ -350,7 +605,7 @@ class _CalendarScreenState extends State { _buildDetailRowInline( icon: Icons.access_time, value: '${DateFormat('HH:mm').format(startTime.toLocal())} - ${DateFormat('HH:mm').format(event.endTime!.toLocal())}', - accentColor: accentColor, + accentColor: cardAccentColor, ), const SizedBox(height: 6), ], @@ -358,7 +613,7 @@ class _CalendarScreenState extends State { _buildDetailRowInline( icon: Icons.access_time, value: _t('All day'), - accentColor: accentColor, + accentColor: cardAccentColor, ), const SizedBox(height: 6), ], @@ -367,7 +622,7 @@ class _CalendarScreenState extends State { _buildDetailRowInline( icon: Icons.location_on, value: event.location!, - accentColor: accentColor, + accentColor: cardAccentColor, ), ], ], diff --git a/lib/screens/home_screen.dart b/lib/screens/home_screen.dart index 492f9b8..efa7fa3 100644 --- a/lib/screens/home_screen.dart +++ b/lib/screens/home_screen.dart @@ -103,7 +103,7 @@ class _HomeScreenState extends State { padding: const EdgeInsets.only(right: 16.0), child: Center( child: Text( - 'V1.0.0', + 'V1.0.1', style: TextStyle( color: Colors.grey[400], fontSize: 12, diff --git a/lib/services/google_calendar_service.dart b/lib/services/google_calendar_service.dart index 05d9e4f..2daa65b 100644 --- a/lib/services/google_calendar_service.dart +++ b/lib/services/google_calendar_service.dart @@ -36,7 +36,26 @@ class GoogleCalendarService { final response = await _httpClient.get(url); if (response.statusCode == 200) { - return _parseICalendar(response.body); + final allEvents = _parseICalendar(response.body); + + // Filter events by date range if provided + if (startDate != null || endDate != null) { + return allEvents.where((event) { + if (event.startTime == null) return false; + + if (startDate != null && event.startTime!.isBefore(startDate)) { + return false; + } + + if (endDate != null && event.startTime!.isAfter(endDate)) { + return false; + } + + return true; + }).toList(); + } + + return allEvents; } else { throw Exception('Failed to load calendar: ${response.statusCode}'); } diff --git a/lib/utils/translations.dart b/lib/utils/translations.dart index 6db5104..fc91f44 100644 --- a/lib/utils/translations.dart +++ b/lib/utils/translations.dart @@ -145,6 +145,22 @@ class AppTranslations { 'English': 'All day', 'Slovenian': 'Cel dan', }, + 'Event Card Styles Preview': { + 'English': 'Event Card Styles Preview', + 'Slovenian': 'Predogled stilov dogodkov', + }, + 'Example Event Preview': { + 'English': 'Example Event Preview', + 'Slovenian': 'Primer dogodka', + }, + 'DEŽURSTVO': { + 'English': 'DUTY', + 'Slovenian': 'DEŽURSTVO', + }, + 'DUTY': { + 'English': 'DUTY', + 'Slovenian': 'DEŽURSTVO', + }, // Preview Screen 'Enter Missing Bullet Scores': {