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:
@@ -74,6 +74,14 @@
|
||||
<button class="button" onclick="requestPermissions()">Request Permissions</button>
|
||||
<button class="button" onclick="testNotification()">Test Notification</button>
|
||||
<button class="button" onclick="checkComprehensiveStatus()">Full System Status</button>
|
||||
<button class="button" onclick="loadAlarmList()">📋 List Alarms</button>
|
||||
|
||||
<div id="alarmListContainer" class="status" style="margin-top: 20px; display: none;">
|
||||
<strong>📋 Scheduled Alarms</strong>
|
||||
<div id="alarmList" style="margin-top: 10px; text-align: left;">
|
||||
Loading...
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="status" class="status">
|
||||
Ready to test...
|
||||
@@ -385,11 +393,89 @@
|
||||
}
|
||||
}
|
||||
|
||||
function loadAlarmList() {
|
||||
const status = document.getElementById('status');
|
||||
const alarmListContainer = document.getElementById('alarmListContainer');
|
||||
const alarmList = document.getElementById('alarmList');
|
||||
|
||||
status.innerHTML = 'Loading alarm list...';
|
||||
status.style.background = 'rgba(255, 255, 0, 0.3)'; // Yellow background
|
||||
alarmListContainer.style.display = 'block';
|
||||
alarmList.innerHTML = 'Loading...';
|
||||
|
||||
try {
|
||||
if (!window.DailyNotification) {
|
||||
status.innerHTML = 'DailyNotification plugin not available';
|
||||
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
|
||||
alarmList.innerHTML = '❌ Plugin unavailable';
|
||||
return;
|
||||
}
|
||||
|
||||
window.DailyNotification.getSchedulesWithStatus({
|
||||
kind: 'notify',
|
||||
enabled: true
|
||||
})
|
||||
.then(result => {
|
||||
const schedules = result.schedules || [];
|
||||
|
||||
if (schedules.length === 0) {
|
||||
alarmList.innerHTML = '<em>No alarms scheduled</em>';
|
||||
status.innerHTML = '✅ No alarms found';
|
||||
status.style.background = 'rgba(255, 255, 255, 0.1)';
|
||||
return;
|
||||
}
|
||||
|
||||
let html = '<div style="display: flex; flex-direction: column; gap: 10px;">';
|
||||
|
||||
schedules.forEach(schedule => {
|
||||
const nextRun = schedule.nextRunAt ? new Date(schedule.nextRunAt) : null;
|
||||
const nextRunStr = nextRun ? nextRun.toLocaleString() : 'Not scheduled';
|
||||
const statusIcon = schedule.isActuallyScheduled ? '✅' : '⚠️';
|
||||
const statusText = schedule.isActuallyScheduled ? 'Scheduled in AlarmManager' : 'Not in AlarmManager';
|
||||
const statusColor = schedule.isActuallyScheduled ? 'rgba(0, 255, 0, 0.2)' : 'rgba(255, 165, 0, 0.2)';
|
||||
|
||||
html += `
|
||||
<div style="padding: 12px; background: ${statusColor}; border-radius: 8px; border-left: 4px solid ${schedule.isActuallyScheduled ? '#0f0' : '#ffa500'};">
|
||||
<div style="font-weight: bold; margin-bottom: 6px;">
|
||||
${statusIcon} ${schedule.id}
|
||||
</div>
|
||||
<div style="font-size: 0.9em; margin-bottom: 4px;">
|
||||
📅 Next Run: ${nextRunStr}
|
||||
</div>
|
||||
<div style="font-size: 0.85em; color: rgba(255, 255, 255, 0.8);">
|
||||
${schedule.cron ? `Cron: ${schedule.cron}` : schedule.clockTime ? `Time: ${schedule.clockTime}` : 'No schedule pattern'}
|
||||
</div>
|
||||
<div style="font-size: 0.85em; margin-top: 4px; color: rgba(255, 255, 255, 0.9);">
|
||||
Status: ${statusText}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
|
||||
html += '</div>';
|
||||
alarmList.innerHTML = html;
|
||||
|
||||
status.innerHTML = `✅ Found ${schedules.length} alarm(s)`;
|
||||
status.style.background = 'rgba(0, 255, 0, 0.3)'; // Green background
|
||||
})
|
||||
.catch(error => {
|
||||
alarmList.innerHTML = `❌ Error: ${error.message}`;
|
||||
status.innerHTML = `Failed to load alarms: ${error.message}`;
|
||||
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
|
||||
});
|
||||
} catch (error) {
|
||||
alarmList.innerHTML = `❌ Error: ${error.message}`;
|
||||
status.innerHTML = `Failed to load alarms: ${error.message}`;
|
||||
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
|
||||
}
|
||||
}
|
||||
|
||||
// Attach to window object
|
||||
window.configurePlugin = configurePlugin;
|
||||
window.testNotification = testNotification;
|
||||
window.requestPermissions = requestPermissions;
|
||||
window.checkComprehensiveStatus = checkComprehensiveStatus;
|
||||
window.loadAlarmList = loadAlarmList;
|
||||
|
||||
function loadPermissionStatus() {
|
||||
const notificationPermStatus = document.getElementById('notificationPermStatus');
|
||||
|
||||
Reference in New Issue
Block a user