feat: HOME-007 — server-side event title/description search (q param)
This commit is contained in:
@@ -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<List<EventModel>> 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<List<EventModel>> 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<String, dynamic> 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,
|
||||
|
||||
@@ -302,7 +302,9 @@ class _HomeScreenState extends State<HomeScreen> with SingleTickerProviderStateM
|
||||
builder: (context, scrollController) {
|
||||
String query = '';
|
||||
List<EventModel> 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<HomeScreen> with SingleTickerProviderStateM
|
||||
});
|
||||
}
|
||||
|
||||
// Server-side search on submit (keyboard action / enter)
|
||||
Future<void> _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<HomeScreen> with SingleTickerProviderStateM
|
||||
autofocus: true,
|
||||
onChanged: _onQueryChanged,
|
||||
textInputAction: TextInputAction.search,
|
||||
onSubmitted: (v) => _onQueryChanged(v),
|
||||
onSubmitted: _onSubmitted,
|
||||
),
|
||||
)
|
||||
],
|
||||
@@ -372,7 +390,7 @@ class _HomeScreenState extends State<HomeScreen> with SingleTickerProviderStateM
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
if (_loading)
|
||||
if (_loading || searching)
|
||||
Center(child: CircularProgressIndicator(color: theme.colorScheme.primary))
|
||||
else if (results.isEmpty)
|
||||
Padding(
|
||||
|
||||
Reference in New Issue
Block a user