- Add loadConfigurationStatus() function to check if plugin/fetcher are configured
- Call loadConfigurationStatus() on page load and app resume (visibility change)
- Add logging to getConfig() to track configuration restoration from database
- UI now shows ✅ Configured status after force-stop recovery
Previously, after force-stop recovery:
- Configuration was stored in database but UI didn't check for it
- configStatus and fetcherStatus remained as 'Not configured' even though config existed
- No logging to track when configuration was restored
The fix:
- loadConfigurationStatus() queries database for native_fetcher_config
- Updates UI status indicators (configStatus, fetcherStatus) based on database state
- Called automatically on page load and when app becomes visible
- Android logs 'DNP-CONFIG: Configuration restored from database' when config is loaded
This ensures the 'Ready to test...' UI block shows correct configuration status
after force-stop recovery, matching the actual database state.
708 lines
37 KiB
HTML
708 lines
37 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
|
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
|
|
<meta http-equiv="Pragma" content="no-cache">
|
|
<meta http-equiv="Expires" content="0">
|
|
<title>DailyNotification Plugin Test</title>
|
|
<style>
|
|
body {
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
margin: 0;
|
|
padding: 20px;
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
min-height: 100vh;
|
|
color: white;
|
|
}
|
|
.container {
|
|
max-width: 600px;
|
|
margin: 0 auto;
|
|
text-align: center;
|
|
}
|
|
h1 {
|
|
margin-bottom: 30px;
|
|
font-size: 2.5em;
|
|
}
|
|
.button {
|
|
background: rgba(255, 255, 255, 0.2);
|
|
border: 2px solid rgba(255, 255, 255, 0.3);
|
|
color: white;
|
|
padding: 15px 30px;
|
|
margin: 10px;
|
|
border-radius: 25px;
|
|
cursor: pointer;
|
|
font-size: 16px;
|
|
transition: all 0.3s ease;
|
|
}
|
|
.button:hover {
|
|
background: rgba(255, 255, 255, 0.3);
|
|
transform: translateY(-2px);
|
|
}
|
|
.status {
|
|
margin-top: 30px;
|
|
padding: 20px;
|
|
background: rgba(255, 255, 255, 0.1);
|
|
border-radius: 10px;
|
|
font-family: monospace;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<div id="statusCard" class="status" style="margin-bottom: 20px; font-size: 14px;">
|
|
<strong>Plugin Status</strong><br>
|
|
<div style="margin-top: 10px;">
|
|
⚙️ Plugin Settings: <span id="configStatus">Not configured</span><br>
|
|
🔌 Native Fetcher: <span id="fetcherStatus">Not configured</span><br>
|
|
🔔 Notifications: <span id="notificationPermStatus">Checking...</span><br>
|
|
⏰ Exact Alarms: <span id="exactAlarmPermStatus">Checking...</span><br>
|
|
📢 Channel: <span id="channelStatus">Checking...</span><br>
|
|
<div id="pluginStatusContent" style="margin-top: 8px;">
|
|
Loading plugin status...
|
|
</div>
|
|
<div id="notificationReceivedIndicator" style="margin-top: 8px; padding: 8px; background: rgba(0, 255, 0, 0.2); border-radius: 5px; display: none;">
|
|
<strong>🔔 Notification Received!</strong><br>
|
|
<span id="notificationReceivedTime"></span><br>
|
|
<small>Check the top of your screen for the notification banner</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<button class="button" onclick="configurePlugin()">Configure Plugin</button>
|
|
<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>
|
|
|
|
<div id="status" class="status">
|
|
Ready to test...
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
console.log('Script loading...');
|
|
console.log('JavaScript is working!');
|
|
|
|
// Use real DailyNotification plugin
|
|
console.log('Using real DailyNotification plugin...');
|
|
window.DailyNotification = window.Capacitor.Plugins.DailyNotification;
|
|
|
|
// Define functions immediately and attach to window
|
|
|
|
function configurePlugin() {
|
|
console.log('configurePlugin called');
|
|
const status = document.getElementById('status');
|
|
const configStatus = document.getElementById('configStatus');
|
|
const fetcherStatus = document.getElementById('fetcherStatus');
|
|
|
|
status.innerHTML = 'Configuring plugin...';
|
|
status.style.background = 'rgba(255, 255, 0, 0.3)'; // Yellow background
|
|
|
|
// Update top status to show configuring
|
|
configStatus.innerHTML = '⏳ Configuring...';
|
|
fetcherStatus.innerHTML = '⏳ Waiting...';
|
|
|
|
try {
|
|
if (!window.DailyNotification) {
|
|
status.innerHTML = 'DailyNotification plugin not available';
|
|
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
|
|
configStatus.innerHTML = '❌ Plugin unavailable';
|
|
fetcherStatus.innerHTML = '❌ Plugin unavailable';
|
|
return;
|
|
}
|
|
|
|
// Configure plugin settings
|
|
window.DailyNotification.configure({
|
|
storage: 'tiered',
|
|
ttlSeconds: 86400,
|
|
prefetchLeadMinutes: 60,
|
|
maxNotificationsPerDay: 3,
|
|
retentionDays: 7
|
|
})
|
|
.then(() => {
|
|
console.log('Plugin settings configured, now configuring native fetcher...');
|
|
// Update top status
|
|
configStatus.innerHTML = '✅ Configured';
|
|
|
|
// Configure native fetcher with demo credentials
|
|
// Note: DemoNativeFetcher uses hardcoded mock data, so this is optional
|
|
// but demonstrates the API. In production, this would be real credentials.
|
|
return window.DailyNotification.configureNativeFetcher({
|
|
apiBaseUrl: 'http://10.0.2.2:3000', // Android emulator → host localhost
|
|
activeDid: 'did:ethr:0xDEMO1234567890', // Demo DID
|
|
jwtSecret: 'demo-jwt-secret-for-development-testing'
|
|
});
|
|
})
|
|
.then(() => {
|
|
// Update top status
|
|
fetcherStatus.innerHTML = '✅ Configured';
|
|
|
|
// Update bottom status for user feedback
|
|
status.innerHTML = 'Plugin configured successfully!';
|
|
status.style.background = 'rgba(0, 255, 0, 0.3)'; // Green background
|
|
})
|
|
.catch(error => {
|
|
// Update top status with error
|
|
if (configStatus.innerHTML.includes('Configuring')) {
|
|
configStatus.innerHTML = '❌ Failed';
|
|
}
|
|
if (fetcherStatus.innerHTML.includes('Waiting') || fetcherStatus.innerHTML.includes('Configuring')) {
|
|
fetcherStatus.innerHTML = '❌ Failed';
|
|
}
|
|
|
|
status.innerHTML = `Configuration failed: ${error.message}`;
|
|
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
|
|
});
|
|
} catch (error) {
|
|
configStatus.innerHTML = '❌ Error';
|
|
fetcherStatus.innerHTML = '❌ Error';
|
|
status.innerHTML = `Configuration failed: ${error.message}`;
|
|
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
|
|
}
|
|
}
|
|
|
|
// Format date/time with seconds normalized to :00
|
|
function formatDateTimeNormalized(timestamp) {
|
|
if (!timestamp || timestamp === 0) return 'None scheduled';
|
|
const date = new Date(timestamp);
|
|
// Normalize seconds to :00
|
|
date.setSeconds(0, 0);
|
|
// Format as: MM/DD/YYYY, HH:MM:00 AM/PM
|
|
const options = {
|
|
month: '2-digit',
|
|
day: '2-digit',
|
|
year: 'numeric',
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
second: '2-digit',
|
|
hour12: true
|
|
};
|
|
return date.toLocaleString('en-US', options);
|
|
}
|
|
|
|
function loadPluginStatus() {
|
|
console.log('[UI Refresh] loadPluginStatus called');
|
|
const pluginStatusContent = document.getElementById('pluginStatusContent');
|
|
const statusCard = document.getElementById('statusCard');
|
|
|
|
try {
|
|
if (!window.DailyNotification) {
|
|
console.warn('[UI Refresh] DailyNotification plugin not available');
|
|
pluginStatusContent.innerHTML = '❌ DailyNotification plugin not available';
|
|
statusCard.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
|
|
return;
|
|
}
|
|
console.log('[UI Refresh] Calling getNotificationStatus()...');
|
|
window.DailyNotification.getNotificationStatus()
|
|
.then(result => {
|
|
console.log('[UI Refresh] getNotificationStatus result:', JSON.stringify({
|
|
nextNotificationTime: result.nextNotificationTime,
|
|
nextNotificationTimeDate: result.nextNotificationTime ? new Date(result.nextNotificationTime).toISOString() : null,
|
|
isEnabled: result.isEnabled,
|
|
pending: result.pending,
|
|
lastNotificationTime: result.lastNotificationTime,
|
|
lastNotificationTimeDate: result.lastNotificationTime ? new Date(result.lastNotificationTime).toISOString() : null
|
|
}, null, 2));
|
|
|
|
const nextTime = formatDateTimeNormalized(result.nextNotificationTime);
|
|
const hasSchedules = result.isEnabled || (result.pending && result.pending > 0);
|
|
const statusIcon = hasSchedules ? '✅' : '⏸️';
|
|
|
|
console.log('[UI Refresh] Updating UI:', JSON.stringify({
|
|
nextTime: nextTime,
|
|
nextNotificationTimeRaw: result.nextNotificationTime,
|
|
nextNotificationTimeDate: result.nextNotificationTime ? new Date(result.nextNotificationTime).toISOString() : null,
|
|
hasSchedules: hasSchedules,
|
|
statusIcon: statusIcon,
|
|
pending: result.pending
|
|
}, null, 2));
|
|
|
|
pluginStatusContent.innerHTML = `${statusIcon} Active Schedules: ${hasSchedules ? 'Yes' : 'No'}<br>
|
|
📅 Next Notification: ${nextTime}<br>
|
|
⏳ Pending: ${result.pending || 0}`;
|
|
statusCard.style.background = hasSchedules ?
|
|
'rgba(0, 255, 0, 0.15)' : 'rgba(255, 255, 255, 0.1)'; // Green if active, light gray if none
|
|
|
|
console.log('[UI Refresh] UI updated successfully');
|
|
})
|
|
.catch(error => {
|
|
console.error('[UI Refresh] getNotificationStatus failed:', error);
|
|
pluginStatusContent.innerHTML = `⚠️ Status check failed: ${error.message}`;
|
|
statusCard.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
|
|
});
|
|
} catch (error) {
|
|
console.error('[UI Refresh] loadPluginStatus exception:', error);
|
|
pluginStatusContent.innerHTML = `⚠️ Status check failed: ${error.message}`;
|
|
statusCard.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
|
|
}
|
|
}
|
|
|
|
// Notification test functions
|
|
function testNotification() {
|
|
console.log('testNotification called');
|
|
|
|
// Quick sanity check - test plugin availability
|
|
if (window.Capacitor && window.Capacitor.isPluginAvailable) {
|
|
const isAvailable = window.Capacitor.isPluginAvailable('DailyNotification');
|
|
console.log('is plugin available?', isAvailable);
|
|
}
|
|
|
|
const status = document.getElementById('status');
|
|
status.innerHTML = 'Testing plugin connection...';
|
|
status.style.background = 'rgba(255, 255, 0, 0.3)'; // Yellow background
|
|
|
|
try {
|
|
if (!window.DailyNotification) {
|
|
status.innerHTML = 'DailyNotification plugin not available';
|
|
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
|
|
return;
|
|
}
|
|
|
|
// Test the notification method directly
|
|
console.log('Testing notification scheduling...');
|
|
const now = new Date();
|
|
const notificationTime = new Date(now.getTime() + 240000); // 4 minutes from now
|
|
const prefetchTime = new Date(now.getTime() + 120000); // 2 minutes from now (2 min before notification)
|
|
const notificationTimeString = notificationTime.getHours().toString().padStart(2, '0') + ':' +
|
|
notificationTime.getMinutes().toString().padStart(2, '0');
|
|
const prefetchTimeString = prefetchTime.getHours().toString().padStart(2, '0') + ':' +
|
|
prefetchTime.getMinutes().toString().padStart(2, '0');
|
|
|
|
window.DailyNotification.scheduleDailyNotification({
|
|
time: notificationTimeString,
|
|
title: 'Test Notification',
|
|
body: 'This is a test notification from the DailyNotification plugin!',
|
|
sound: true,
|
|
priority: 'high'
|
|
})
|
|
.then(() => {
|
|
// Normalize seconds to :00 for display
|
|
prefetchTime.setSeconds(0, 0);
|
|
notificationTime.setSeconds(0, 0);
|
|
const prefetchTimeReadable = prefetchTime.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: true });
|
|
const notificationTimeReadable = notificationTime.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: true });
|
|
status.innerHTML = '✅ Notification scheduled!<br>' +
|
|
'📥 Prefetch: ' + prefetchTimeReadable + ' (' + prefetchTimeString + ')<br>' +
|
|
'🔔 Notification: ' + notificationTimeReadable + ' (' + notificationTimeString + ')<br><br>' +
|
|
'<small>💡 When the notification fires, look for a banner at the <strong>top of your screen</strong>.</small>';
|
|
status.style.background = 'rgba(0, 255, 0, 0.3)'; // Green background
|
|
// Refresh plugin status display
|
|
setTimeout(() => loadPluginStatus(), 500);
|
|
})
|
|
.catch(error => {
|
|
// Check if this is an exact alarm permission error
|
|
if (error.code === 'EXACT_ALARM_PERMISSION_REQUIRED' ||
|
|
error.message.includes('Exact alarm permission') ||
|
|
error.message.includes('Alarms & reminders')) {
|
|
status.innerHTML = '⚠️ Exact Alarm Permission Required<br><br>' +
|
|
'Settings opened automatically.<br>' +
|
|
'Please enable "Allow exact alarms" and return to try again.';
|
|
status.style.background = 'rgba(255, 165, 0, 0.3)'; // Orange background
|
|
} else {
|
|
status.innerHTML = `❌ Notification failed: ${error.message}`;
|
|
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
|
|
}
|
|
});
|
|
} catch (error) {
|
|
status.innerHTML = `Notification test failed: ${error.message}`;
|
|
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
|
|
}
|
|
}
|
|
|
|
|
|
// Permission management functions
|
|
function requestPermissions() {
|
|
console.log('requestPermissions called');
|
|
const status = document.getElementById('status');
|
|
status.innerHTML = 'Requesting permissions...';
|
|
status.style.background = 'rgba(255, 255, 0, 0.3)'; // Yellow background
|
|
|
|
try {
|
|
if (!window.DailyNotification) {
|
|
status.innerHTML = 'DailyNotification plugin not available';
|
|
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
|
|
return;
|
|
}
|
|
|
|
window.DailyNotification.requestNotificationPermissions()
|
|
.then(() => {
|
|
status.innerHTML = 'Permission request completed! Check your device settings if needed.';
|
|
status.style.background = 'rgba(0, 255, 0, 0.3)'; // Green background
|
|
|
|
// Refresh permission and channel status display after request
|
|
setTimeout(() => {
|
|
loadPermissionStatus();
|
|
loadChannelStatus();
|
|
}, 1000);
|
|
})
|
|
.catch(error => {
|
|
status.innerHTML = `Permission request failed: ${error.message}`;
|
|
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
|
|
});
|
|
} catch (error) {
|
|
status.innerHTML = `Permission request failed: ${error.message}`;
|
|
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
|
|
}
|
|
}
|
|
|
|
// Load configuration status (plugin settings and native fetcher)
|
|
function loadConfigurationStatus() {
|
|
console.log('[Config Check] Checking configuration status...');
|
|
const configStatus = document.getElementById('configStatus');
|
|
const fetcherStatus = document.getElementById('fetcherStatus');
|
|
|
|
if (!window.DailyNotification) {
|
|
console.warn('[Config Check] DailyNotification plugin not available');
|
|
configStatus.innerHTML = '❌ Plugin unavailable';
|
|
fetcherStatus.innerHTML = '❌ Plugin unavailable';
|
|
return;
|
|
}
|
|
|
|
// Check if plugin settings are configured
|
|
// Plugin settings are stored internally, so we check by trying to get status
|
|
// For now, we'll check if native fetcher config exists as a proxy
|
|
// TODO: Add explicit plugin settings check method
|
|
window.DailyNotification.getConfig({ key: 'native_fetcher_config' })
|
|
.then(result => {
|
|
console.log('[Config Check] Native fetcher config result:', JSON.stringify(result));
|
|
if (result && result.config && result.config.configValue) {
|
|
try {
|
|
const configValue = JSON.parse(result.config.configValue);
|
|
if (configValue.apiBaseUrl && configValue.apiBaseUrl.length > 0) {
|
|
console.log('[Config Check] ✅ Native fetcher is configured');
|
|
fetcherStatus.innerHTML = '✅ Configured';
|
|
} else {
|
|
console.log('[Config Check] ⚠️ Native fetcher config exists but is empty');
|
|
fetcherStatus.innerHTML = '❌ Not configured';
|
|
}
|
|
} catch (e) {
|
|
console.warn('[Config Check] Failed to parse config value:', e);
|
|
fetcherStatus.innerHTML = '❌ Error';
|
|
}
|
|
} else {
|
|
console.log('[Config Check] ❌ Native fetcher config not found');
|
|
fetcherStatus.innerHTML = '❌ Not configured';
|
|
}
|
|
|
|
// For plugin settings, we assume configured if native fetcher is configured
|
|
// This is a heuristic - in production, add explicit check
|
|
if (fetcherStatus.innerHTML.includes('✅')) {
|
|
configStatus.innerHTML = '✅ Configured';
|
|
} else {
|
|
configStatus.innerHTML = '❌ Not configured';
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('[Config Check] Failed to check configuration:', error);
|
|
configStatus.innerHTML = '❌ Error';
|
|
fetcherStatus.innerHTML = '❌ Error';
|
|
});
|
|
}
|
|
|
|
function loadChannelStatus() {
|
|
const channelStatus = document.getElementById('channelStatus');
|
|
|
|
try {
|
|
if (!window.DailyNotification) {
|
|
channelStatus.innerHTML = '❌ Plugin unavailable';
|
|
return;
|
|
}
|
|
|
|
window.DailyNotification.isChannelEnabled()
|
|
.then(result => {
|
|
const importanceText = getImportanceText(result.importance);
|
|
if (result.enabled) {
|
|
channelStatus.innerHTML = `✅ Enabled (${importanceText})`;
|
|
} else {
|
|
channelStatus.innerHTML = `❌ Disabled (${importanceText})`;
|
|
}
|
|
})
|
|
.catch(error => {
|
|
channelStatus.innerHTML = '⚠️ Error';
|
|
});
|
|
} catch (error) {
|
|
channelStatus.innerHTML = '⚠️ Error';
|
|
}
|
|
}
|
|
|
|
function checkComprehensiveStatus() {
|
|
const status = document.getElementById('status');
|
|
status.innerHTML = 'Checking comprehensive status...';
|
|
status.style.background = 'rgba(255, 255, 0, 0.3)'; // Yellow background
|
|
|
|
try {
|
|
if (!window.DailyNotification) {
|
|
status.innerHTML = 'DailyNotification plugin not available';
|
|
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
|
|
return;
|
|
}
|
|
|
|
window.DailyNotification.checkStatus()
|
|
.then(result => {
|
|
const canSchedule = result.canScheduleNow;
|
|
const issues = [];
|
|
|
|
if (!result.postNotificationsGranted) {
|
|
issues.push('POST_NOTIFICATIONS permission');
|
|
}
|
|
if (!result.channelEnabled) {
|
|
issues.push('notification channel disabled');
|
|
}
|
|
if (!result.exactAlarmsGranted) {
|
|
issues.push('exact alarm permission');
|
|
}
|
|
|
|
let statusText = `Status: ${canSchedule ? 'Ready to schedule' : 'Issues found'}`;
|
|
if (issues.length > 0) {
|
|
statusText += `\nIssues: ${issues.join(', ')}`;
|
|
}
|
|
|
|
statusText += `\nChannel: ${getImportanceText(result.channelImportance)}`;
|
|
statusText += `\nChannel ID: ${result.channelId}`;
|
|
|
|
status.innerHTML = statusText;
|
|
status.style.background = canSchedule ? 'rgba(0, 255, 0, 0.3)' : 'rgba(255, 0, 0, 0.3)';
|
|
})
|
|
.catch(error => {
|
|
status.innerHTML = `Status check failed: ${error.message}`;
|
|
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
|
|
});
|
|
} catch (error) {
|
|
status.innerHTML = `Status check failed: ${error.message}`;
|
|
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
|
|
}
|
|
}
|
|
|
|
function getImportanceText(importance) {
|
|
switch (importance) {
|
|
case 0: return 'None (blocked)';
|
|
case 1: return 'Min';
|
|
case 2: return 'Low';
|
|
case 3: return 'Default';
|
|
case 4: return 'High';
|
|
case 5: return 'Max';
|
|
default: return `Unknown (${importance})`;
|
|
}
|
|
}
|
|
|
|
// Attach to window object
|
|
window.configurePlugin = configurePlugin;
|
|
window.testNotification = testNotification;
|
|
window.requestPermissions = requestPermissions;
|
|
window.checkComprehensiveStatus = checkComprehensiveStatus;
|
|
|
|
function loadPermissionStatus() {
|
|
const notificationPermStatus = document.getElementById('notificationPermStatus');
|
|
const exactAlarmPermStatus = document.getElementById('exactAlarmPermStatus');
|
|
|
|
try {
|
|
if (!window.DailyNotification) {
|
|
notificationPermStatus.innerHTML = '❌ Plugin unavailable';
|
|
exactAlarmPermStatus.innerHTML = '❌ Plugin unavailable';
|
|
return;
|
|
}
|
|
|
|
window.DailyNotification.checkPermissionStatus()
|
|
.then(result => {
|
|
notificationPermStatus.innerHTML = result.notificationsEnabled ? '✅ Granted' : '❌ Not granted';
|
|
exactAlarmPermStatus.innerHTML = result.exactAlarmEnabled ? '✅ Granted' : '❌ Not granted';
|
|
})
|
|
.catch(error => {
|
|
notificationPermStatus.innerHTML = '⚠️ Error';
|
|
exactAlarmPermStatus.innerHTML = '⚠️ Error';
|
|
});
|
|
} catch (error) {
|
|
notificationPermStatus.innerHTML = '⚠️ Error';
|
|
exactAlarmPermStatus.innerHTML = '⚠️ Error';
|
|
}
|
|
}
|
|
|
|
// Track last known nextNotificationTime to detect changes
|
|
let lastKnownNextNotificationTime = null;
|
|
|
|
// Check for notification delivery and status updates periodically
|
|
function checkNotificationDelivery() {
|
|
if (!window.DailyNotification) {
|
|
console.log('[Poll] DailyNotification not available, skipping check');
|
|
return;
|
|
}
|
|
|
|
console.log('[Poll] checkNotificationDelivery called');
|
|
window.DailyNotification.getNotificationStatus()
|
|
.then(result => {
|
|
console.log('[Poll] Status check result:', JSON.stringify({
|
|
nextNotificationTime: result.nextNotificationTime,
|
|
nextNotificationTimeDate: result.nextNotificationTime ? new Date(result.nextNotificationTime).toISOString() : null,
|
|
lastNotificationTime: result.lastNotificationTime,
|
|
lastNotificationTimeDate: result.lastNotificationTime ? new Date(result.lastNotificationTime).toISOString() : null,
|
|
lastKnownNextNotificationTime: lastKnownNextNotificationTime,
|
|
lastKnownNextNotificationTimeDate: lastKnownNextNotificationTime ? new Date(lastKnownNextNotificationTime).toISOString() : null
|
|
}, null, 2));
|
|
|
|
// Check for notification delivery
|
|
if (result.lastNotificationTime) {
|
|
const lastTime = new Date(result.lastNotificationTime);
|
|
const now = new Date();
|
|
const timeDiff = now - lastTime;
|
|
|
|
console.log('[Poll] Notification delivery check:', {
|
|
lastTime: lastTime.toISOString(),
|
|
now: now.toISOString(),
|
|
timeDiff: timeDiff,
|
|
withinWindow: timeDiff > 0 && timeDiff < 120000
|
|
});
|
|
|
|
// If notification was received in the last 2 minutes, show indicator
|
|
if (timeDiff > 0 && timeDiff < 120000) {
|
|
console.log('[Poll] Notification received recently, showing indicator');
|
|
const indicator = document.getElementById('notificationReceivedIndicator');
|
|
const timeSpan = document.getElementById('notificationReceivedTime');
|
|
|
|
if (indicator && timeSpan) {
|
|
indicator.style.display = 'block';
|
|
// Normalize seconds to :00
|
|
lastTime.setSeconds(0, 0);
|
|
timeSpan.textContent = `Received at ${lastTime.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: true })}`;
|
|
|
|
// Hide after 30 seconds
|
|
setTimeout(() => {
|
|
indicator.style.display = 'none';
|
|
}, 30000);
|
|
|
|
// Force immediate refresh when notification is received (rollover may have occurred)
|
|
console.log('[Poll] Scheduling UI refresh in 1 second (waiting for rollover)...');
|
|
setTimeout(() => {
|
|
console.log('[Poll] Triggering UI refresh after notification received');
|
|
loadPluginStatus();
|
|
}, 1000); // Wait 1 second for rollover to complete
|
|
}
|
|
}
|
|
}
|
|
|
|
// Detect if nextNotificationTime changed (rollover occurred)
|
|
const currentNextTime = result.nextNotificationTime;
|
|
console.log('[Poll] Comparing nextNotificationTime:', JSON.stringify({
|
|
current: currentNextTime,
|
|
currentDate: currentNextTime ? new Date(currentNextTime).toISOString() : null,
|
|
lastKnown: lastKnownNextNotificationTime,
|
|
lastKnownDate: lastKnownNextNotificationTime ? new Date(lastKnownNextNotificationTime).toISOString() : null,
|
|
changed: currentNextTime && currentNextTime !== lastKnownNextNotificationTime
|
|
}, null, 2));
|
|
|
|
if (currentNextTime && currentNextTime !== lastKnownNextNotificationTime) {
|
|
if (lastKnownNextNotificationTime !== null) {
|
|
console.log('[Poll] ⚠️ Next notification time changed - rollover detected!', {
|
|
old: lastKnownNextNotificationTime,
|
|
new: currentNextTime,
|
|
oldDate: new Date(lastKnownNextNotificationTime).toISOString(),
|
|
newDate: new Date(currentNextTime).toISOString()
|
|
});
|
|
// Force immediate refresh
|
|
loadPluginStatus();
|
|
} else {
|
|
console.log('[Poll] Initializing lastKnownNextNotificationTime:', currentNextTime);
|
|
}
|
|
lastKnownNextNotificationTime = currentNextTime;
|
|
} else {
|
|
console.log('[Poll] No change detected in nextNotificationTime');
|
|
}
|
|
|
|
// Auto-refresh plugin status periodically to show updated next notification time after rollover
|
|
// This ensures the UI updates when the plugin reschedules the notification
|
|
console.log('[Poll] Triggering periodic UI refresh');
|
|
loadPluginStatus();
|
|
})
|
|
.catch(error => {
|
|
console.error('[Poll] Status check failed:', error);
|
|
// Silently fail - this is just for visual feedback
|
|
});
|
|
}
|
|
|
|
// Load plugin status automatically on page load
|
|
window.addEventListener('load', () => {
|
|
console.log('Page loaded, loading plugin status...');
|
|
// Small delay to ensure Capacitor is ready
|
|
setTimeout(() => {
|
|
loadPluginStatus();
|
|
loadPermissionStatus();
|
|
loadChannelStatus();
|
|
loadConfigurationStatus();
|
|
|
|
// Initialize last known next notification time
|
|
if (window.DailyNotification) {
|
|
window.DailyNotification.getNotificationStatus()
|
|
.then(result => {
|
|
lastKnownNextNotificationTime = result.nextNotificationTime;
|
|
console.log('Initialized nextNotificationTime:', lastKnownNextNotificationTime);
|
|
})
|
|
.catch(() => {});
|
|
}
|
|
|
|
// Check for notification delivery and status updates every 3 seconds (more frequent)
|
|
// This ensures UI updates quickly when rollover occurs
|
|
setInterval(checkNotificationDelivery, 3000);
|
|
}, 500);
|
|
});
|
|
|
|
// Refresh UI when app comes back to foreground (after force-stop, app resume, etc.)
|
|
// This ensures the UI updates after recovery from force-stop
|
|
document.addEventListener('visibilitychange', () => {
|
|
if (!document.hidden) {
|
|
console.log('[Visibility] App became visible, refreshing UI status...');
|
|
// Small delay to allow recovery to complete
|
|
setTimeout(() => {
|
|
loadPluginStatus();
|
|
loadPermissionStatus();
|
|
loadChannelStatus();
|
|
loadConfigurationStatus();
|
|
|
|
// Also check for recent notifications that might have been missed
|
|
if (window.DailyNotification) {
|
|
window.DailyNotification.getNotificationStatus()
|
|
.then(result => {
|
|
// Check if a notification was received recently (within last 2 minutes)
|
|
if (result.lastNotificationTime) {
|
|
const lastTime = new Date(result.lastNotificationTime);
|
|
const now = new Date();
|
|
const timeDiff = now - lastTime;
|
|
|
|
if (timeDiff > 0 && timeDiff < 120000) {
|
|
console.log('[Visibility] Recent notification detected, showing indicator');
|
|
const indicator = document.getElementById('notificationReceivedIndicator');
|
|
const timeSpan = document.getElementById('notificationReceivedTime');
|
|
|
|
if (indicator && timeSpan) {
|
|
indicator.style.display = 'block';
|
|
lastTime.setSeconds(0, 0);
|
|
timeSpan.textContent = `Received at ${lastTime.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: true })}`;
|
|
|
|
// Hide after 30 seconds
|
|
setTimeout(() => {
|
|
indicator.style.display = 'none';
|
|
}, 30000);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Update last known next notification time
|
|
lastKnownNextNotificationTime = result.nextNotificationTime;
|
|
})
|
|
.catch(error => {
|
|
console.error('[Visibility] Failed to get notification status:', error);
|
|
});
|
|
}
|
|
}, 1000); // Wait 1 second for recovery to complete
|
|
}
|
|
});
|
|
|
|
|
|
|
|
console.log('Functions attached to window:', {
|
|
configurePlugin: typeof window.configurePlugin,
|
|
testNotification: typeof window.testNotification
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|