mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-01-23 02:36:05 +00:00
fix(android): show dialog for overdue reminders instead of skipping (#6068)
- Fix issue where overdue reminders were invisible on Android - Worker correctly detected overdue reminders but dialog was skipped - Native AlarmManager only schedules future reminders, not overdue ones - Now checks if reminders are overdue and shows dialog appropriately - Future reminders: skip dialog (native notification handles them) - Overdue reminders: show dialog (no native notification exists) - Add comprehensive diagnostic logging to reminder scheduling/cancellation - Add logging to track reminder dialog trigger decisions This fixes the issue where changing any task's reminder time would appear to trigger all overdue reminders - they were always there but hidden due to the dialog being skipped on Android.
This commit is contained in:
parent
4de1155280
commit
f784c9c0b9
2 changed files with 76 additions and 6 deletions
|
|
@ -90,11 +90,26 @@ export class CapacitorReminderService {
|
|||
const now = Date.now();
|
||||
const triggerAt = options.triggerAtMs <= now ? now + 1000 : options.triggerAtMs;
|
||||
|
||||
Log.log('📱 CapacitorReminderService.scheduleReminder called', {
|
||||
notificationId: options.notificationId,
|
||||
title: options.title.substring(0, 30),
|
||||
triggerAt: new Date(triggerAt).toISOString(),
|
||||
triggerInMs: triggerAt - now,
|
||||
triggerInMinutes: Math.round((triggerAt - now) / 1000 / 60),
|
||||
isAndroidWebView: IS_ANDROID_WEB_VIEW,
|
||||
hasNativeScheduler: !!androidInterface.scheduleNativeReminder,
|
||||
});
|
||||
|
||||
// On Android, use native AlarmManager for precision
|
||||
if (IS_ANDROID_WEB_VIEW && androidInterface.scheduleNativeReminder) {
|
||||
try {
|
||||
const useAlarmStyle =
|
||||
this._globalConfigService.cfg()?.reminder?.useAlarmStyleReminders ?? false;
|
||||
Log.log('🔔 Calling androidInterface.scheduleNativeReminder', {
|
||||
notificationId: options.notificationId,
|
||||
useAlarmStyle,
|
||||
});
|
||||
|
||||
androidInterface.scheduleNativeReminder(
|
||||
options.notificationId,
|
||||
options.reminderId,
|
||||
|
|
@ -104,14 +119,18 @@ export class CapacitorReminderService {
|
|||
triggerAt,
|
||||
useAlarmStyle,
|
||||
);
|
||||
Log.log('CapacitorReminderService: Android reminder scheduled', {
|
||||
|
||||
Log.log('✅ CapacitorReminderService: Android reminder scheduled successfully', {
|
||||
notificationId: options.notificationId,
|
||||
title: options.title,
|
||||
triggerAt: new Date(triggerAt).toISOString(),
|
||||
});
|
||||
return true;
|
||||
} catch (error) {
|
||||
Log.err('CapacitorReminderService: Failed to schedule Android reminder', error);
|
||||
Log.err(
|
||||
'❌ CapacitorReminderService: Failed to schedule Android reminder',
|
||||
error,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -174,16 +193,22 @@ export class CapacitorReminderService {
|
|||
return false;
|
||||
}
|
||||
|
||||
Log.log('🚫 CapacitorReminderService.cancelReminder called', {
|
||||
notificationId,
|
||||
isAndroidWebView: IS_ANDROID_WEB_VIEW,
|
||||
hasNativeCanceller: !!androidInterface.cancelNativeReminder,
|
||||
});
|
||||
|
||||
// On Android, use native cancellation
|
||||
if (IS_ANDROID_WEB_VIEW && androidInterface.cancelNativeReminder) {
|
||||
try {
|
||||
androidInterface.cancelNativeReminder(notificationId);
|
||||
Log.log('CapacitorReminderService: Android reminder cancelled', {
|
||||
Log.log('✅ CapacitorReminderService: Android reminder cancelled', {
|
||||
notificationId,
|
||||
});
|
||||
return true;
|
||||
} catch (error) {
|
||||
Log.err('CapacitorReminderService: Failed to cancel Android reminder', error);
|
||||
Log.err('❌ CapacitorReminderService: Failed to cancel Android reminder', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -99,13 +99,41 @@ export class ReminderModule {
|
|||
),
|
||||
)
|
||||
.subscribe((reminders: TaskWithReminderData[]) => {
|
||||
const now = Date.now();
|
||||
const overdueReminders = reminders.filter(
|
||||
(r) => r.reminderData?.remindAt && r.reminderData.remindAt < now,
|
||||
);
|
||||
const futureReminders = reminders.filter(
|
||||
(r) => r.reminderData?.remindAt && r.reminderData.remindAt >= now,
|
||||
);
|
||||
|
||||
Log.log('=== REMINDER DIALOG TRIGGER ===', {
|
||||
platform: IS_ANDROID_NATIVE ? 'Android' : IS_ELECTRON ? 'Electron' : 'Web',
|
||||
reminderCount: reminders.length,
|
||||
overdueCount: overdueReminders.length,
|
||||
futureCount: futureReminders.length,
|
||||
reminders: reminders.map((r) => ({
|
||||
id: r.id.substring(0, 8),
|
||||
title: r.title.substring(0, 30),
|
||||
remindAt: r.reminderData?.remindAt
|
||||
? new Date(r.reminderData.remindAt).toISOString()
|
||||
: 'unknown',
|
||||
isOverdue: r.reminderData?.remindAt ? r.reminderData.remindAt < now : false,
|
||||
})),
|
||||
willShowNotification: !IS_NATIVE_PLATFORM,
|
||||
willShowDialog: !IS_ANDROID_NATIVE || overdueReminders.length > 0,
|
||||
});
|
||||
|
||||
if (IS_ELECTRON && this._globalConfigService.cfg()?.reminder?.isFocusWindow) {
|
||||
this._uiHelperService.focusApp();
|
||||
}
|
||||
|
||||
this._showNotification(reminders);
|
||||
|
||||
// Skip dialog on Android - native notifications handle reminders
|
||||
// On Android:
|
||||
// - Future reminders: Native AlarmManager handles them (skip dialog)
|
||||
// - Overdue reminders: No native notification exists (show dialog)
|
||||
// This is because android.effects.ts only schedules future reminders.
|
||||
// TODO: Native Android reminder notification actions (snooze/done buttons) currently
|
||||
// work entirely in the background without notifying TypeScript. This means:
|
||||
// 1. Snooze: Works correctly (native code reschedules the alarm)
|
||||
|
|
@ -113,10 +141,27 @@ export class ReminderModule {
|
|||
// app state. The reminder will be cancelled when the task is marked done in the app.
|
||||
// To fully fix: Add onReminderDone$ subject to android-interface.ts and wire it up
|
||||
// in the Kotlin ReminderBroadcastReceiver to call dismissReminderOnly action.
|
||||
if (IS_ANDROID_NATIVE) {
|
||||
if (
|
||||
IS_ANDROID_NATIVE &&
|
||||
futureReminders.length > 0 &&
|
||||
overdueReminders.length === 0
|
||||
) {
|
||||
Log.log(
|
||||
'⏭️ SKIPPING dialog on Android - all reminders are future, native notifications will handle them',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (IS_ANDROID_NATIVE && overdueReminders.length > 0) {
|
||||
Log.log(
|
||||
'📱 SHOWING dialog on Android for overdue reminders (no native notification exists)',
|
||||
{
|
||||
overdueCount: overdueReminders.length,
|
||||
futureCount: futureReminders.length,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
const oldest = reminders[0];
|
||||
const taskId = oldest.id;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue