feat(android): add getSchedulesWithStatus() and alarm list UI
Adds ability to list alarms with AlarmManager status in web interface.
Changes:
- Add getSchedulesWithStatus() method to DailyNotificationPlugin
- Add ScheduleWithStatus TypeScript interface with isActuallyScheduled flag
- Add alarm list UI to android-test-app with status indicators
Backend:
- getSchedulesWithStatus() returns schedules with AlarmManager verification
- Checks isAlarmScheduled() for each notify schedule with nextRunAt
- Returns isActuallyScheduled boolean flag for each schedule
TypeScript:
- New ScheduleWithStatus interface extending Schedule
- Method signature with JSDoc and usage examples
UI:
- New "📋 List Alarms" button in test app
- Color-coded alarm cards (green=scheduled, orange=not scheduled)
- Shows schedule ID, next run time, pattern, and AlarmManager status
- Useful for debugging recovery scenarios and verifying alarm state
Use case:
- Verify which alarms are in database vs actually scheduled
- Debug Phase 1/2/3 recovery scenarios
- Visual confirmation of alarm state after app launch/boot
Related:
- Enhances: android-test-app for Phase 1-3 testing
- Supports: Recovery verification and debugging
This commit is contained in:
@@ -1864,6 +1864,57 @@ open class DailyNotificationPlugin : Plugin() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all schedules with their AlarmManager status
|
||||
* Returns schedules from database with isActuallyScheduled flag for each
|
||||
*/
|
||||
@PluginMethod
|
||||
fun getSchedulesWithStatus(call: PluginCall) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
try {
|
||||
val options = call.getObject("options")
|
||||
val kind = options?.getString("kind")
|
||||
val enabled = options?.getBoolean("enabled")
|
||||
|
||||
val context = context ?: return@launch call.reject("Context not available")
|
||||
|
||||
val schedules = when {
|
||||
kind != null && enabled != null ->
|
||||
getDatabase().scheduleDao().getByKindAndEnabled(kind, enabled)
|
||||
kind != null ->
|
||||
getDatabase().scheduleDao().getByKind(kind)
|
||||
enabled != null ->
|
||||
if (enabled) getDatabase().scheduleDao().getEnabled() else getDatabase().scheduleDao().getAll().filter { !it.enabled }
|
||||
else ->
|
||||
getDatabase().scheduleDao().getAll()
|
||||
}
|
||||
|
||||
// For each schedule, check if it's actually scheduled in AlarmManager
|
||||
val schedulesArray = org.json.JSONArray()
|
||||
schedules.forEach { schedule ->
|
||||
val scheduleJson = scheduleToJson(schedule)
|
||||
|
||||
// Only check AlarmManager status for "notify" schedules with nextRunAt
|
||||
if (schedule.kind == "notify" && schedule.nextRunAt != null) {
|
||||
val isScheduled = NotifyReceiver.isAlarmScheduled(context, schedule.nextRunAt!!)
|
||||
scheduleJson.put("isActuallyScheduled", isScheduled)
|
||||
} else {
|
||||
scheduleJson.put("isActuallyScheduled", false)
|
||||
}
|
||||
|
||||
schedulesArray.put(scheduleJson)
|
||||
}
|
||||
|
||||
call.resolve(JSObject().apply {
|
||||
put("schedules", schedulesArray)
|
||||
})
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Failed to get schedules with status", e)
|
||||
call.reject("Failed to get schedules with status: ${e.message}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@PluginMethod
|
||||
fun createSchedule(call: PluginCall) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
|
||||
Reference in New Issue
Block a user