Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions app/lib/backend/http/api/conversations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,8 @@ Future<(List<ServerConversation>, int, int)> searchConversationsServer(
int? page,
int? limit,
bool includeDiscarded = true,
DateTime? startDate,
DateTime? endDate,
}) async {
Logger.debug(Env.apiBaseUrl);
var response = await makeApiCall(
Expand All @@ -531,6 +533,8 @@ Future<(List<ServerConversation>, 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 (<ServerConversation>[], 0, 0);
Expand Down
48 changes: 33 additions & 15 deletions app/lib/pages/conversations/widgets/search_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -73,22 +73,25 @@ class _SearchWidgetState extends State<SearchWidget> {
}
}

Future<void> _showDatePicker(BuildContext context, {bool hasExistingFilter = false}) async {
Future<void> _showDateRangePicker(BuildContext context, {bool hasExistingFilter = false}) async {
final convoProvider = Provider.of<ConversationProvider>(context, listen: false);
DateTime selectedDate = convoProvider.selectedDate ?? DateTime.now();
DateTime? startDate = convoProvider.searchStartDate;
DateTime? endDate = convoProvider.searchEndDate;
List<DateTime?> selectedRange = [startDate, endDate ?? startDate ?? DateTime.now()];
Comment thread
Syed-Moiz-Ali marked this conversation as resolved.
Outdated
await showCupertinoModalPopup<void>(
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(
Expand All @@ -104,7 +107,10 @@ class _SearchWidgetState extends State<SearchWidget> {
if (hasExistingFilter) {
final provider = Provider.of<ConversationProvider>(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();
Expand All @@ -115,14 +121,23 @@ class _SearchWidgetState extends State<SearchWidget> {
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<ConversationProvider>(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,
Expand All @@ -132,7 +147,7 @@ class _SearchWidgetState extends State<SearchWidget> {
],
),
),
// Date picker
// Date range picker
Expanded(
child: Material(
color: ResponsiveHelper.backgroundSecondary,
Expand All @@ -141,11 +156,13 @@ class _SearchWidgetState extends State<SearchWidget> {
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;
}
},
),
Expand Down Expand Up @@ -217,25 +234,26 @@ class _SearchWidgetState extends State<SearchWidget> {
// Calendar button - same height as search bar (48px)
Consumer<ConversationProvider>(
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),
),
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);
},
),
);
Expand Down
26 changes: 25 additions & 1 deletion app/lib/providers/conversation_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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));
Expand Down Expand Up @@ -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<void> filterConversationsByDate(DateTime date) async {
selectedDate = date;
Expand Down