From 34a39ada319745875470f1f57e0dc6e6eba5ee44 Mon Sep 17 00:00:00 2001 From: Sicherhaven Date: Mon, 30 Mar 2026 20:32:54 +0530 Subject: [PATCH] feat: fix View All buttons and category selection UX - "View All" on "Events Around You" header now toggles between horizontal scroll and expanded wrap grid showing all categories - Tapping a category chip replaces all shelf sections with a filtered vertical list of events for that category only - Tapping "All Events" restores the shelf layout for all categories - "View All" on each shelf header (Music, Festivals, etc.) selects that category in the chips and shows its filtered event list - Added AnimatedSwitcher for smooth transition between views - Added AnimatedCrossFade for chip expand/collapse animation Co-Authored-By: Claude Opus 4.6 (1M context) --- lib/screens/home_screen.dart | 112 ++++++++++++++++++++++++++++------- 1 file changed, 90 insertions(+), 22 deletions(-) diff --git a/lib/screens/home_screen.dart b/lib/screens/home_screen.dart index fb66fbf..1222ca0 100644 --- a/lib/screens/home_screen.dart +++ b/lib/screens/home_screen.dart @@ -40,6 +40,7 @@ class _HomeScreenState extends State with SingleTickerProviderStateM List _events = []; List _types = []; int _selectedTypeId = -1; // -1 == All + bool _categoriesExpanded = false; bool _loading = true; @@ -1579,21 +1580,50 @@ class _HomeScreenState extends State with SingleTickerProviderStateM ), ), TextButton( - onPressed: () {}, - child: const Text( - 'View All', - style: TextStyle(color: Color(0xFF2563EB), fontWeight: FontWeight.w600), + onPressed: () => setState(() => _categoriesExpanded = !_categoriesExpanded), + child: Text( + _categoriesExpanded ? 'Show Less' : 'View All', + style: const TextStyle(color: Color(0xFF2563EB), fontWeight: FontWeight.w600), ), ), ], ), const SizedBox(height: 12), - // Category chips (card-style) - SizedBox( - height: 140, - child: ListView( - scrollDirection: Axis.horizontal, + // Category chips — horizontal scroll (collapsed) or wrap grid (expanded) + AnimatedCrossFade( + duration: const Duration(milliseconds: 300), + crossFadeState: _categoriesExpanded ? CrossFadeState.showSecond : CrossFadeState.showFirst, + // Collapsed: horizontal scroll + firstChild: SizedBox( + height: 140, + child: ListView( + scrollDirection: Axis.horizontal, + children: [ + _categoryChip( + label: 'All Events', + icon: Icons.grid_view_rounded, + selected: _selectedTypeId == -1, + onTap: () => _onSelectType(-1), + ), + const SizedBox(width: 12), + for (final t in _types) ...[ + _categoryChip( + label: t.name, + imageUrl: t.iconUrl, + icon: _getIconForType(t.name), + selected: _selectedTypeId == t.id, + onTap: () => _onSelectType(t.id), + ), + const SizedBox(width: 12), + ], + ], + ), + ), + // Expanded: wrap grid showing all categories + secondChild: Wrap( + spacing: 10, + runSpacing: 10, children: [ _categoryChip( label: 'All Events', @@ -1601,8 +1631,7 @@ class _HomeScreenState extends State with SingleTickerProviderStateM selected: _selectedTypeId == -1, onTap: () => _onSelectType(-1), ), - const SizedBox(width: 12), - for (final t in _types) ...[ + for (final t in _types) _categoryChip( label: t.name, imageUrl: t.iconUrl, @@ -1610,14 +1639,12 @@ class _HomeScreenState extends State with SingleTickerProviderStateM selected: _selectedTypeId == t.id, onTap: () => _onSelectType(t.id), ), - const SizedBox(width: 12), - ], ], ), ), const SizedBox(height: 16), - // Event sections by type — always show ALL categories + // Event sections — shelves (All) or filtered list (specific category) if (_loading) const Padding( padding: EdgeInsets.all(40), @@ -1632,14 +1659,55 @@ class _HomeScreenState extends State with SingleTickerProviderStateM )), ) else - Column( - children: [ - for (final t in _types) - if (_allFilteredByDate.where((e) => e.eventTypeId == t.id).isNotEmpty) ...[ - _buildTypeSection(t), - const SizedBox(height: 18), - ], - ], + AnimatedSwitcher( + duration: const Duration(milliseconds: 300), + switchInCurve: Curves.easeOut, + switchOutCurve: Curves.easeIn, + child: _selectedTypeId == -1 + // "All Events" — show category shelf sections + ? Column( + key: const ValueKey('shelves'), + children: [ + for (final t in _types) + if (_allFilteredByDate.where((e) => e.eventTypeId == t.id).isNotEmpty) ...[ + _buildTypeSection(t), + const SizedBox(height: 18), + ], + ], + ) + // Specific category — show vertical list of events for that category only + : Column( + key: ValueKey('filtered_$_selectedTypeId'), + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Category name header + Padding( + padding: const EdgeInsets.only(bottom: 14), + child: Row( + children: [ + Expanded( + child: Text( + _types.firstWhere((t) => t.id == _selectedTypeId, orElse: () => _types.first).name, + style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: Color(0xFF111827)), + ), + ), + Text( + '${_allFilteredByDate.where((e) => e.eventTypeId == _selectedTypeId).length} events', + style: const TextStyle(fontSize: 13, color: Color(0xFF9CA3AF)), + ), + ], + ), + ), + // Event cards + for (final e in _allFilteredByDate.where((e) => e.eventTypeId == _selectedTypeId)) + _buildFullWidthCard(e), + if (_allFilteredByDate.where((e) => e.eventTypeId == _selectedTypeId).isEmpty) + const Padding( + padding: EdgeInsets.all(40), + child: Center(child: Text('No events in this category', style: TextStyle(color: Color(0xFF9CA3AF)))), + ), + ], + ), ), // Bottom padding for nav bar