From 8497efdbc36d48b40f328f6f6c512d373693bfa0 Mon Sep 17 00:00:00 2001 From: syed-axonaio Date: Tue, 16 Jun 2026 16:43:51 +0530 Subject: [PATCH 1/3] feat: add date range filter to conversation search (#4457) --- app/lib/backend/http/api/conversations.dart | 4 ++ .../conversations/widgets/search_widget.dart | 48 +++++++++++++------ app/lib/providers/conversation_provider.dart | 26 +++++++++- 3 files changed, 62 insertions(+), 16 deletions(-) diff --git a/app/lib/backend/http/api/conversations.dart b/app/lib/backend/http/api/conversations.dart index a928c16ca3d..5ac0c3668eb 100644 --- a/app/lib/backend/http/api/conversations.dart +++ b/app/lib/backend/http/api/conversations.dart @@ -520,6 +520,8 @@ Future<(List, int, int)> searchConversationsServer( int? page, int? limit, bool includeDiscarded = true, + DateTime? startDate, + DateTime? endDate, }) async { Logger.debug(Env.apiBaseUrl); var response = await makeApiCall( @@ -531,6 +533,8 @@ Future<(List, int, int)> searchConversationsServer( 'page': page ?? 1, 'per_page': limit ?? 10, 'include_discarded': includeDiscarded, + if (startDate != null) 'start_date': startDate.toIso8601String(), + if (endDate != null) 'end_date': endDate.toIso8601String(), }), ); if (response == null) return ([], 0, 0); diff --git a/app/lib/pages/conversations/widgets/search_widget.dart b/app/lib/pages/conversations/widgets/search_widget.dart index 6926e508599..ea61aae5eed 100644 --- a/app/lib/pages/conversations/widgets/search_widget.dart +++ b/app/lib/pages/conversations/widgets/search_widget.dart @@ -73,22 +73,25 @@ class _SearchWidgetState extends State { } } - Future _showDatePicker(BuildContext context, {bool hasExistingFilter = false}) async { + Future _showDateRangePicker(BuildContext context, {bool hasExistingFilter = false}) async { final convoProvider = Provider.of(context, listen: false); - DateTime selectedDate = convoProvider.selectedDate ?? DateTime.now(); + DateTime? startDate = convoProvider.searchStartDate; + DateTime? endDate = convoProvider.searchEndDate; + List selectedRange = [startDate, endDate ?? startDate ?? DateTime.now()]; await showCupertinoModalPopup( context: context, builder: (BuildContext context) { return Container( - height: 420, + height: 480, padding: const EdgeInsets.only(top: 6.0), margin: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), color: const Color(0xFF1F1F25), child: SafeArea( top: false, child: Column( + mainAxisSize: MainAxisSize.min, children: [ - // Header with Cancel and Done buttons + // Header with Cancel and Apply buttons Container( padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), decoration: const BoxDecoration( @@ -104,7 +107,10 @@ class _SearchWidgetState extends State { if (hasExistingFilter) { final provider = Provider.of(context, listen: false); Navigator.of(context).pop(); - await provider.clearDateFilter(); + provider.clearSearchDateRange(); + if (provider.previousQuery.isNotEmpty) { + await provider.searchConversations(provider.previousQuery); + } PlatformManager.instance.analytics.calendarFilterCleared(); } else { Navigator.of(context).pop(); @@ -115,14 +121,23 @@ class _SearchWidgetState extends State { style: const TextStyle(color: Colors.white, fontSize: 16), ), ), - const Spacer(), + Text( + 'Filter by date', + style: TextStyle(color: Colors.grey.shade400, fontSize: 14), + ), CupertinoButton( padding: EdgeInsets.zero, onPressed: () async { final provider = Provider.of(context, listen: false); Navigator.of(context).pop(); - await provider.filterConversationsByDate(selectedDate); - PlatformManager.instance.analytics.calendarFilterApplied(selectedDate); + provider.setSearchDateRange(startDate, endDate); + if (provider.previousQuery.isNotEmpty) { + await provider.searchConversations(provider.previousQuery); + } + final appliedStart = startDate; + if (appliedStart != null) { + PlatformManager.instance.analytics.calendarFilterApplied(appliedStart); + } }, child: Text( context.l10n.done, @@ -132,7 +147,7 @@ class _SearchWidgetState extends State { ], ), ), - // Date picker + // Date range picker Expanded( child: Material( color: ResponsiveHelper.backgroundSecondary, @@ -141,11 +156,13 @@ class _SearchWidgetState extends State { firstDate: DateTime(2020), lastDate: DateTime.now(), currentDate: DateTime.now(), + calendarType: CalendarDatePicker2Type.range, ), - value: [selectedDate], + value: selectedRange, onValueChanged: (dates) { if (dates.isNotEmpty) { - selectedDate = dates[0]; + startDate = dates[0]; + endDate = dates.length > 1 ? dates[1] : null; } }, ), @@ -217,11 +234,12 @@ class _SearchWidgetState extends State { // Calendar button - same height as search bar (48px) Consumer( builder: (context, convoProvider, _) { + final hasActiveFilter = convoProvider.searchStartDate != null; return Container( width: 48, height: 48, decoration: BoxDecoration( - color: convoProvider.selectedDate != null + color: hasActiveFilter ? Colors.deepPurple.withValues(alpha: 0.5) : const Color(0xFF1F1F25), borderRadius: BorderRadius.circular(24), @@ -229,13 +247,13 @@ class _SearchWidgetState extends State { child: IconButton( padding: EdgeInsets.zero, icon: Icon( - convoProvider.selectedDate != null ? FontAwesomeIcons.calendarDay : FontAwesomeIcons.calendarDays, + hasActiveFilter ? FontAwesomeIcons.calendarDay : FontAwesomeIcons.calendarDays, size: 18, - color: convoProvider.selectedDate != null ? Colors.white : Colors.white70, + color: hasActiveFilter ? Colors.white : Colors.white70, ), onPressed: () async { HapticFeedback.mediumImpact(); - await _showDatePicker(context, hasExistingFilter: convoProvider.selectedDate != null); + await _showDateRangePicker(context, hasExistingFilter: hasActiveFilter); }, ), ); diff --git a/app/lib/providers/conversation_provider.dart b/app/lib/providers/conversation_provider.dart index 11a023bcf03..68f38d0543d 100644 --- a/app/lib/providers/conversation_provider.dart +++ b/app/lib/providers/conversation_provider.dart @@ -31,6 +31,9 @@ class ConversationProvider extends ChangeNotifier { int totalSearchPages = 1; int currentSearchPage = 1; + DateTime? searchStartDate; + DateTime? searchEndDate; + Timer? _processingConversationWatchTimer; // Add debounce mechanism for refresh @@ -152,7 +155,12 @@ class ConversationProvider extends ChangeNotifier { } previousQuery = query; - var (convos, current, total) = await searchConversationsServer(query, includeDiscarded: showDiscardedConversations); + var (convos, current, total) = await searchConversationsServer( + query, + includeDiscarded: showDiscardedConversations, + startDate: searchStartDate, + endDate: searchEndDate, + ); convos.sort((a, b) => (b.startedAt ?? b.createdAt).compareTo(a.startedAt ?? a.createdAt)); searchedConversations = convos; currentSearchPage = current; @@ -177,6 +185,8 @@ class ConversationProvider extends ChangeNotifier { previousQuery, page: currentSearchPage + 1, includeDiscarded: showDiscardedConversations, + startDate: searchStartDate, + endDate: searchEndDate, ); searchedConversations.addAll(newConvos); searchedConversations.sort((a, b) => (b.startedAt ?? b.createdAt).compareTo(a.startedAt ?? a.createdAt)); @@ -517,6 +527,20 @@ class ConversationProvider extends ChangeNotifier { }).toList(); } + /// Set search date range (start and end). Null = no limit on that side. + void setSearchDateRange(DateTime? start, DateTime? end) { + searchStartDate = start; + searchEndDate = end; + notifyListeners(); + } + + /// Clear the search date range filter + void clearSearchDateRange() { + searchStartDate = null; + searchEndDate = null; + notifyListeners(); + } + /// Filter conversations by a specific date Future filterConversationsByDate(DateTime date) async { selectedDate = date; From eaae64bb9d7e2e0f141e70eec1a7d304c8a29594 Mon Sep 17 00:00:00 2001 From: Syed Moiz Ali <100577359+Syed-Moiz-Ali@users.noreply.github.com> Date: Tue, 16 Jun 2026 16:56:33 +0530 Subject: [PATCH 2/3] Update app/lib/pages/conversations/widgets/search_widget.dart Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --- app/lib/pages/conversations/widgets/search_widget.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/lib/pages/conversations/widgets/search_widget.dart b/app/lib/pages/conversations/widgets/search_widget.dart index ea61aae5eed..e1586743f8e 100644 --- a/app/lib/pages/conversations/widgets/search_widget.dart +++ b/app/lib/pages/conversations/widgets/search_widget.dart @@ -77,7 +77,7 @@ class _SearchWidgetState extends State { final convoProvider = Provider.of(context, listen: false); DateTime? startDate = convoProvider.searchStartDate; DateTime? endDate = convoProvider.searchEndDate; - List selectedRange = [startDate, endDate ?? startDate ?? DateTime.now()]; + List selectedRange = [startDate, endDate]; await showCupertinoModalPopup( context: context, builder: (BuildContext context) { From e28cdf650d1d61db51bb00e965742e98ec1b0bad Mon Sep 17 00:00:00 2001 From: syed-axonaio Date: Tue, 16 Jun 2026 16:58:43 +0530 Subject: [PATCH 3/3] fix: address review comments for date-range search PR P1: reset searchStartDate/searchEndDate in clearUserData() P2: only set date range when a search query is active (no misleading active-filter indicator on empty search) --- app/lib/pages/conversations/widgets/search_widget.dart | 2 +- app/lib/providers/conversation_provider.dart | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/lib/pages/conversations/widgets/search_widget.dart b/app/lib/pages/conversations/widgets/search_widget.dart index e1586743f8e..c2b4f4f5c83 100644 --- a/app/lib/pages/conversations/widgets/search_widget.dart +++ b/app/lib/pages/conversations/widgets/search_widget.dart @@ -130,8 +130,8 @@ class _SearchWidgetState extends State { onPressed: () async { final provider = Provider.of(context, listen: false); Navigator.of(context).pop(); - provider.setSearchDateRange(startDate, endDate); if (provider.previousQuery.isNotEmpty) { + provider.setSearchDateRange(startDate, endDate); await provider.searchConversations(provider.previousQuery); } final appliedStart = startDate; diff --git a/app/lib/providers/conversation_provider.dart b/app/lib/providers/conversation_provider.dart index 68f38d0543d..5a965f2bf82 100644 --- a/app/lib/providers/conversation_provider.dart +++ b/app/lib/providers/conversation_provider.dart @@ -106,6 +106,8 @@ class ConversationProvider extends ChangeNotifier { hasDailySummaries = false; selectedDate = null; selectedFolderId = null; + searchStartDate = null; + searchEndDate = null; previousQuery = ''; totalSearchPages = 1; currentSearchPage = 1;