diff --git a/lib/features/events/services/events_service.dart b/lib/features/events/services/events_service.dart index c73ed55..f2b293b 100644 --- a/lib/features/events/services/events_service.dart +++ b/lib/features/events/services/events_service.dart @@ -43,10 +43,11 @@ class EventsService { /// Get events filtered by pincode with pagination. /// [page] starts at 1. [pageSize] defaults to 50. /// Returns a list of events for the requested page. - Future> getEventsByPincode(String pincode, {int page = 1, int pageSize = 50, int perType = 5}) async { - // Use cache for 'all' pincode queries (first page only for initial load) + Future> getEventsByPincode(String pincode, {int page = 1, int pageSize = 50, int perType = 5, String q = ''}) async { + // Use cache for 'all' pincode queries (first page only, no active search) if (pincode == 'all' && page == 1 && + q.isEmpty && _cachedAllEvents != null && _eventsCacheTime != null && DateTime.now().difference(_eventsCacheTime!) < _eventsCacheTTL) { @@ -56,6 +57,8 @@ class EventsService { final Map body = {'pincode': pincode, 'page': page, 'page_size': pageSize}; // Diverse mode: fetch a few events per type so all categories are represented if (perType > 0 && page == 1) body['per_type'] = perType; + // Server-side search filter + if (q.isNotEmpty) body['q'] = q; final res = await _api.post( ApiEndpoints.eventsByPincode, diff --git a/lib/screens/home_screen.dart b/lib/screens/home_screen.dart index 08ce25b..7676fdf 100644 --- a/lib/screens/home_screen.dart +++ b/lib/screens/home_screen.dart @@ -302,7 +302,9 @@ class _HomeScreenState extends State with SingleTickerProviderStateM builder: (context, scrollController) { String query = ''; List results = List.from(_events); + bool searching = false; return StatefulBuilder(builder: (context, setModalState) { + // Instant client-side filter while typing void _onQueryChanged(String v) { query = v.trim().toLowerCase(); final r = _events.where((e) { @@ -314,6 +316,22 @@ class _HomeScreenState extends State with SingleTickerProviderStateM }); } + // Server-side search on submit (keyboard action / enter) + Future _onSubmitted(String v) async { + final q = v.trim(); + if (q.isEmpty) return; + setModalState(() => searching = true); + try { + final serverResults = await _eventsService.getEventsByPincode(_pincode, q: q); + setModalState(() { + results = serverResults; + searching = false; + }); + } catch (_) { + setModalState(() => searching = false); + } + } + return Container( decoration: BoxDecoration( color: theme.cardColor, @@ -357,7 +375,7 @@ class _HomeScreenState extends State with SingleTickerProviderStateM autofocus: true, onChanged: _onQueryChanged, textInputAction: TextInputAction.search, - onSubmitted: (v) => _onQueryChanged(v), + onSubmitted: _onSubmitted, ), ) ], @@ -372,7 +390,7 @@ class _HomeScreenState extends State with SingleTickerProviderStateM ], ), const SizedBox(height: 12), - if (_loading) + if (_loading || searching) Center(child: CircularProgressIndicator(color: theme.colorScheme.primary)) else if (results.isEmpty) Padding(