diff --git a/frontend/appflowy_flutter/lib/user/application/reminder/reminder_bloc.dart b/frontend/appflowy_flutter/lib/user/application/reminder/reminder_bloc.dart index 07024b2668..e04a257dde 100644 --- a/frontend/appflowy_flutter/lib/user/application/reminder/reminder_bloc.dart +++ b/frontend/appflowy_flutter/lib/user/application/reminder/reminder_bloc.dart @@ -43,33 +43,43 @@ class ReminderBloc extends Bloc { final remindersOrFailure = await _reminderService.fetchReminders(); remindersOrFailure.fold( - (reminders) => emit(state.copyWith(reminders: reminders)), - (error) => Log.error(error), + (reminders) { + Log.info('Fetched reminders on startup (${reminders.length})'); + emit(state.copyWith(reminders: reminders)); + }, + (error) { + Log.error('Failed to fetch reminders: $error'); + }, ); }, remove: (reminderId) async { - final unitOrFailure = - await _reminderService.removeReminder(reminderId: reminderId); + final unitOrFailure = await _reminderService.removeReminder( + reminderId: reminderId, + ); unitOrFailure.fold( (_) { + Log.info('Reminder removed: $reminderId'); final reminders = [...state.reminders]; reminders.removeWhere((e) => e.id == reminderId); emit(state.copyWith(reminders: reminders)); }, - (error) => Log.error(error), + (error) => + Log.error('Failed to remove reminder($reminderId): $error'), ); }, add: (reminder) async { - final unitOrFailure = - await _reminderService.addReminder(reminder: reminder); + final unitOrFailure = await _reminderService.addReminder( + reminder: reminder, + ); return unitOrFailure.fold( (_) { + Log.info('Reminder added: ${reminder.id}'); final reminders = [...state.reminders, reminder]; emit(state.copyWith(reminders: reminders)); }, - (error) => Log.error(error), + (error) => Log.error('Failed to add reminder: $error'), ); }, addById: (reminderId, objectId, scheduledAt, meta) async => add( @@ -86,8 +96,9 @@ class ReminderBloc extends Bloc { ), ), update: (updateObject) async { - final reminder = state.reminders - .firstWhereOrNull((r) => r.id == updateObject.id); + final reminder = state.reminders.firstWhereOrNull( + (r) => r.id == updateObject.id, + ); if (reminder == null) { return; @@ -95,18 +106,20 @@ class ReminderBloc extends Bloc { final newReminder = updateObject.merge(a: reminder); final failureOrUnit = await _reminderService.updateReminder( - reminder: newReminder, + reminder: updateObject.merge(a: reminder), ); failureOrUnit.fold( (_) { - final index = - state.reminders.indexWhere((r) => r.id == reminder.id); + Log.info('Reminder updated: ${updateObject.id} $updateObject'); + final index = state.reminders.indexWhere( + (r) => r.id == reminder.id, + ); final reminders = [...state.reminders]; reminders.replaceRange(index, index + 1, [newReminder]); emit(state.copyWith(reminders: reminders)); }, - (error) => Log.error(error), + (error) => Log.error('Failed to update reminder: $error'), ); }, pressReminder: (reminderId, path, view) { @@ -155,46 +168,61 @@ class ReminderBloc extends Bloc { ); } }, - markAsRead: (reminderIds) async { - final reminders = await _onMarkAsRead(reminderIds: reminderIds); - emit( - state.copyWith( - reminders: reminders, - ), - ); - }, - archive: (reminderIds) async { - final reminders = await _onArchived( - isArchived: true, - reminderIds: reminderIds, - ); - emit( - state.copyWith( - reminders: reminders, - ), - ); - }, markAllRead: () async { - final reminders = await _onMarkAsRead(); + final unreadReminders = state.reminders.where( + (reminder) => !reminder.isRead, + ); + + for (final reminder in unreadReminders) { + reminder.isRead = true; + await _reminderService.updateReminder(reminder: reminder); + } + + final reminder = [...state.reminders].map((e) { + if (e.isRead) { + return e; + } + e.freeze(); + return e.rebuild((update) { + update.isRead = true; + }); + }).toList(); + + Log.info('Marked all reminders as read'); + emit( state.copyWith( - reminders: reminders, + reminders: reminder, ), ); }, archiveAll: () async { - final reminders = await _onArchived(isArchived: true); - emit( - state.copyWith( - reminders: reminders, - ), + final unArchivedReminders = state.reminders.where( + (reminder) => !reminder.isArchived, ); - }, - unarchiveAll: () async { - final reminders = await _onArchived(isArchived: false); + + for (final reminder in unArchivedReminders) { + reminder.isRead = true; + reminder.meta[ReminderMetaKeys.isArchived] = true.toString(); + await _reminderService.updateReminder(reminder: reminder); + } + + final reminder = [...state.reminders].map((e) { + if (e.isRead && e.isArchived) { + return e; + } + e.freeze(); + return e.rebuild((update) { + update.isRead = true; + update.meta[ReminderMetaKeys.isArchived] = true.toString(); + }); + }).toList(); + + Log.info('Archived all reminders'); + emit( state.copyWith( - reminders: reminders, + reminders: reminder, ), ); }, @@ -202,8 +230,13 @@ class ReminderBloc extends Bloc { final remindersOrFailure = await _reminderService.fetchReminders(); remindersOrFailure.fold( - (reminders) => emit(state.copyWith(reminders: reminders)), - (error) => emit(state), + (reminders) { + Log.info('Refreshed reminders'); + emit(state.copyWith(reminders: reminders)); + }, + (error) { + Log.error('Failed to refresh reminders: $error'); + }, ); }, ); @@ -211,96 +244,6 @@ class ReminderBloc extends Bloc { ); } - /// Mark the reminder as read - /// - /// If the [reminderIds] is null, all unread reminders will be marked as read - /// Otherwise, only the reminders with the given IDs will be marked as read - Future> _onMarkAsRead({ - List? reminderIds, - }) async { - final Iterable remindersToUpdate; - - if (reminderIds != null) { - remindersToUpdate = state.reminders.where( - (reminder) => reminderIds.contains(reminder.id) && !reminder.isRead, - ); - } else { - // Get all reminders that are not matching the isArchived flag - remindersToUpdate = state.reminders.where( - (reminder) => !reminder.isRead, - ); - } - - for (final reminder in remindersToUpdate) { - reminder.isRead = true; - - await _reminderService.updateReminder(reminder: reminder); - Log.info('Mark reminder ${reminder.id} as read'); - } - - return state.reminders.map((e) { - if (reminderIds != null && !reminderIds.contains(e.id)) { - return e; - } - - if (e.isRead) { - return e; - } - - e.freeze(); - return e.rebuild((update) { - update.isRead = true; - }); - }).toList(); - } - - /// Archive or unarchive reminders - /// - /// If the [reminderIds] is null, all reminders will be archived - /// Otherwise, only the reminders with the given IDs will be archived or unarchived - Future> _onArchived({ - required bool isArchived, - List? reminderIds, - }) async { - final Iterable remindersToUpdate; - - if (reminderIds != null) { - remindersToUpdate = state.reminders.where( - (reminder) => - reminderIds.contains(reminder.id) && - reminder.isArchived != isArchived, - ); - } else { - // Get all reminders that are not matching the isArchived flag - remindersToUpdate = state.reminders.where( - (reminder) => reminder.isArchived != isArchived, - ); - } - - for (final reminder in remindersToUpdate) { - reminder.isRead = isArchived; - reminder.meta[ReminderMetaKeys.isArchived] = isArchived.toString(); - await _reminderService.updateReminder(reminder: reminder); - Log.info('Reminder ${reminder.id} is archived: $isArchived'); - } - - return state.reminders.map((e) { - if (reminderIds != null && !reminderIds.contains(e.id)) { - return e; - } - - if (e.isArchived == isArchived) { - return e; - } - - e.freeze(); - return e.rebuild((update) { - update.isRead = isArchived; - update.meta[ReminderMetaKeys.isArchived] = isArchived.toString(); - }); - }).toList(); - } - Timer _periodicCheck() { return Timer.periodic( const Duration(minutes: 1), @@ -364,30 +307,17 @@ class ReminderEvent with _$ReminderEvent { // Update a reminder (eg. isAck, isRead, etc.) const factory ReminderEvent.update(ReminderUpdate update) = _Update; - // Event to mark specific reminders as read, takes a list of reminder IDs - const factory ReminderEvent.markAsRead(List reminderIds) = - _MarkAsRead; - - // Event to mark all unread reminders as read + // Mark all unread reminders as read const factory ReminderEvent.markAllRead() = _MarkAllRead; - // Event to archive specific reminders, takes a list of reminder IDs - const factory ReminderEvent.archive(List reminderIds) = _Archive; - - // Event to archive all reminders const factory ReminderEvent.archiveAll() = _ArchiveAll; - // Event to unarchive all reminders - const factory ReminderEvent.unarchiveAll() = _UnarchiveAll; - - // Event to handle reminder press action const factory ReminderEvent.pressReminder({ required String reminderId, @Default(null) int? path, @Default(null) ViewPB? view, }) = _PressReminder; - // Event to refresh reminders const factory ReminderEvent.refresh() = _Refresh; } @@ -402,7 +332,6 @@ class ReminderUpdate { this.scheduledAt, this.includeTime, this.isArchived, - this.date, }); final String id; @@ -411,7 +340,6 @@ class ReminderUpdate { final DateTime? scheduledAt; final bool? includeTime; final bool? isArchived; - final DateTime? date; ReminderPB merge({required ReminderPB a}) { final isAcknowledged = isAck == null && scheduledAt != null @@ -427,10 +355,6 @@ class ReminderUpdate { meta[ReminderMetaKeys.isArchived] = isArchived.toString(); } - if (date != a.date && date != null) { - meta[ReminderMetaKeys.date] = date!.millisecondsSinceEpoch.toString(); - } - return ReminderPB( id: a.id, objectId: a.objectId,