fix(android): improve channel status detection and UI refresh

- Fix isChannelEnabled() to create channel if missing and re-fetch from system
  to get actual state (handles previously blocked channels)
- Use correct channel ID 'timesafari.daily' instead of 'daily_notification_channel'
- Add detailed logging for channel status checks
- Fix UI to refresh channel status after notification permissions are granted
- Channel status now correctly reflects both app-level and channel-level settings
This commit is contained in:
Matthew Raymer
2025-11-18 09:50:23 +00:00
parent 8f20da7e8d
commit a8039d072d
2 changed files with 248 additions and 286 deletions

View File

@@ -95,7 +95,7 @@ open class DailyNotificationPlugin : Plugin() {
Log.e(TAG, "Context is null, cannot initialize database") Log.e(TAG, "Context is null, cannot initialize database")
return return
} }
db = DailyNotificationDatabase.getDatabase(context) db = DailyNotificationDatabase.getDatabase(context)
Log.i(TAG, "Daily Notification Plugin loaded successfully") Log.i(TAG, "Daily Notification Plugin loaded successfully")
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "Failed to initialize Daily Notification Plugin", e) Log.e(TAG, "Failed to initialize Daily Notification Plugin", e)
@@ -1048,21 +1048,73 @@ open class DailyNotificationPlugin : Plugin() {
@PluginMethod @PluginMethod
fun isChannelEnabled(call: PluginCall) { fun isChannelEnabled(call: PluginCall) {
try { try {
val channelId = call.getString("channelId") ?: "daily_notification_channel" if (context == null) {
val enabled = NotificationManagerCompat.from(context).areNotificationsEnabled() return call.reject("Context not available")
}
// Use the actual channel ID that matches what's used in notifications
val channelId = call.getString("channelId") ?: "timesafari.daily"
// Check app-level notifications first
val appNotificationsEnabled = NotificationManagerCompat.from(context).areNotificationsEnabled()
// Get notification channel importance if available // Get notification channel importance if available
var importance = 0 var importance = 0
var channelEnabled = false
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notificationManager = context?.getSystemService(Context.NOTIFICATION_SERVICE) as android.app.NotificationManager? val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as? android.app.NotificationManager
val channel = notificationManager?.getNotificationChannel(channelId) var channel = notificationManager?.getNotificationChannel(channelId)
importance = channel?.importance ?: android.app.NotificationManager.IMPORTANCE_DEFAULT
if (channel == null) {
// Channel doesn't exist - create it first (same as ChannelManager does)
Log.i(TAG, "Channel $channelId doesn't exist, creating it")
val newChannel = android.app.NotificationChannel(
channelId,
"Daily Notifications",
android.app.NotificationManager.IMPORTANCE_HIGH
).apply {
description = "Daily notifications from TimeSafari"
enableLights(true)
enableVibration(true)
setShowBadge(true)
}
notificationManager?.createNotificationChannel(newChannel)
Log.i(TAG, "Channel $channelId created with HIGH importance")
// Re-fetch the channel from the system to get actual state
// (in case it was previously blocked by user)
channel = notificationManager?.getNotificationChannel(channelId)
}
// Now check the channel (re-fetched from system to get actual state)
if (channel != null) {
importance = channel.importance
// Channel is enabled if importance is not IMPORTANCE_NONE
// IMPORTANCE_NONE = 0 means blocked/disabled
channelEnabled = importance != android.app.NotificationManager.IMPORTANCE_NONE
Log.d(TAG, "Channel $channelId status: importance=$importance, enabled=$channelEnabled")
} else {
// Channel still doesn't exist after creation attempt - should not happen
Log.w(TAG, "Channel $channelId still doesn't exist after creation attempt")
importance = android.app.NotificationManager.IMPORTANCE_NONE
channelEnabled = false
}
} else {
// Pre-Oreo: channels don't exist, use app-level check
channelEnabled = appNotificationsEnabled
importance = android.app.NotificationManager.IMPORTANCE_DEFAULT
} }
val finalEnabled = appNotificationsEnabled && channelEnabled
Log.i(TAG, "Channel status check complete: channelId=$channelId, appNotificationsEnabled=$appNotificationsEnabled, channelEnabled=$channelEnabled, importance=$importance, finalEnabled=$finalEnabled")
val result = JSObject().apply { val result = JSObject().apply {
put("enabled", enabled) // Channel is enabled if both app notifications are enabled AND channel importance is not NONE
put("enabled", finalEnabled)
put("channelId", channelId) put("channelId", channelId)
put("importance", importance) put("importance", importance)
put("appNotificationsEnabled", appNotificationsEnabled)
put("channelBlocked", importance == android.app.NotificationManager.IMPORTANCE_NONE)
} }
call.resolve(result) call.resolve(result)
} catch (e: Exception) { } catch (e: Exception) {
@@ -1074,28 +1126,80 @@ open class DailyNotificationPlugin : Plugin() {
@PluginMethod @PluginMethod
fun openChannelSettings(call: PluginCall) { fun openChannelSettings(call: PluginCall) {
try { try {
val channelId = call.getString("channelId") ?: "daily_notification_channel" if (context == null) {
val intent = Intent(android.provider.Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS).apply { return call.reject("Context not available")
putExtra(android.provider.Settings.EXTRA_APP_PACKAGE, context?.packageName)
putExtra(android.provider.Settings.EXTRA_CHANNEL_ID, channelId)
} }
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
// Use the actual channel ID that matches what's used in notifications
val channelId = call.getString("channelId") ?: "timesafari.daily"
// Ensure channel exists before trying to open settings
// This ensures the channel-specific settings page can be opened
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as? android.app.NotificationManager
val channel = notificationManager?.getNotificationChannel(channelId)
if (channel == null) {
// Channel doesn't exist - create it first
Log.i(TAG, "Channel $channelId doesn't exist, creating it")
val newChannel = android.app.NotificationChannel(
channelId,
"Daily Notifications",
android.app.NotificationManager.IMPORTANCE_HIGH
).apply {
description = "Daily notifications from TimeSafari"
enableLights(true)
enableVibration(true)
setShowBadge(true)
}
notificationManager?.createNotificationChannel(newChannel)
Log.i(TAG, "Channel $channelId created")
}
}
// Try to open channel-specific settings first
try { try {
activity?.startActivity(intent) val intent = Intent(android.provider.Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS).apply {
putExtra(android.provider.Settings.EXTRA_APP_PACKAGE, context.packageName)
putExtra(android.provider.Settings.EXTRA_CHANNEL_ID, channelId)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
activity?.startActivity(intent) ?: context.startActivity(intent)
Log.i(TAG, "Channel settings opened for channel: $channelId")
val result = JSObject().apply { val result = JSObject().apply {
put("opened", true) put("opened", true)
put("channelId", channelId) put("channelId", channelId)
} }
call.resolve(result) call.resolve(result)
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "Failed to start activity", e) // Fallback to general app notification settings if channel-specific fails
val result = JSObject().apply { Log.w(TAG, "Failed to open channel-specific settings, trying app notification settings", e)
put("opened", false) try {
put("channelId", channelId) val fallbackIntent = Intent(android.provider.Settings.ACTION_APP_NOTIFICATION_SETTINGS).apply {
put("error", e.message) putExtra(android.provider.Settings.EXTRA_APP_PACKAGE, context.packageName)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
activity?.startActivity(fallbackIntent) ?: context.startActivity(fallbackIntent)
Log.i(TAG, "App notification settings opened (fallback)")
val result = JSObject().apply {
put("opened", true)
put("channelId", channelId)
put("fallback", true)
put("message", "Opened app notification settings (channel-specific unavailable)")
}
call.resolve(result)
} catch (e2: Exception) {
Log.e(TAG, "Failed to open notification settings", e2)
val result = JSObject().apply {
put("opened", false)
put("channelId", channelId)
put("error", e2.message)
}
call.resolve(result)
} }
call.resolve(result)
} }
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "Failed to open channel settings", e) Log.e(TAG, "Failed to open channel settings", e)

View File

@@ -51,28 +51,24 @@
</head> </head>
<body> <body>
<div class="container"> <div class="container">
<h1>🔔 DailyNotification Plugin Test</h1> <div id="statusCard" class="status" style="margin-bottom: 20px; font-size: 14px;">
<p>Test the DailyNotification plugin functionality</p> <strong>Plugin Status</strong><br>
<p style="font-size: 12px; opacity: 0.8;">Build: 2025-10-14 05:00:00 UTC</p> <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>
</div>
<button class="button" onclick="testPlugin()">Test Plugin</button>
<button class="button" onclick="configurePlugin()">Configure Plugin</button> <button class="button" onclick="configurePlugin()">Configure Plugin</button>
<button class="button" onclick="checkStatus()">Check Status</button>
<h2>🔔 Notification Tests</h2>
<button class="button" onclick="testNotification()">Test Notification</button>
<button class="button" onclick="scheduleNotification()">Schedule Notification</button>
<button class="button" onclick="showReminder()">Show Reminder</button>
<h2>🔐 Permission Management</h2>
<button class="button" onclick="checkPermissions()">Check Permissions</button>
<button class="button" onclick="requestPermissions()">Request Permissions</button> <button class="button" onclick="requestPermissions()">Request Permissions</button>
<button class="button" onclick="openExactAlarmSettings()">Exact Alarm Settings</button> <button class="button" onclick="testNotification()">Test Notification</button>
<button class="button" onclick="checkComprehensiveStatus()">Full System Status</button>
<h2>📢 Channel Management</h2>
<button class="button" onclick="checkChannelStatus()">Check Channel Status</button>
<button class="button" onclick="openChannelSettings()">Open Channel Settings</button>
<button class="button" onclick="checkComprehensiveStatus()">Comprehensive Status</button>
<div id="status" class="status"> <div id="status" class="status">
Ready to test... Ready to test...
@@ -88,37 +84,26 @@
window.DailyNotification = window.Capacitor.Plugins.DailyNotification; window.DailyNotification = window.Capacitor.Plugins.DailyNotification;
// Define functions immediately and attach to window // Define functions immediately and attach to window
function testPlugin() {
console.log('testPlugin called');
const status = document.getElementById('status');
status.innerHTML = 'Testing plugin...';
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;
}
// Plugin is loaded and ready
status.innerHTML = 'Plugin is loaded and ready!';
status.style.background = 'rgba(0, 255, 0, 0.3)'; // Green background
} catch (error) {
status.innerHTML = `Plugin test failed: ${error.message}`;
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
}
}
function configurePlugin() { function configurePlugin() {
console.log('configurePlugin called'); console.log('configurePlugin called');
const status = document.getElementById('status'); const status = document.getElementById('status');
const configStatus = document.getElementById('configStatus');
const fetcherStatus = document.getElementById('fetcherStatus');
status.innerHTML = 'Configuring plugin...'; status.innerHTML = 'Configuring plugin...';
status.style.background = 'rgba(255, 255, 0, 0.3)'; // Yellow background status.style.background = 'rgba(255, 255, 0, 0.3)'; // Yellow background
// Update top status to show configuring
configStatus.innerHTML = '⏳ Configuring...';
fetcherStatus.innerHTML = '⏳ Waiting...';
try { try {
if (!window.DailyNotification) { if (!window.DailyNotification) {
status.innerHTML = 'DailyNotification plugin not available'; status.innerHTML = 'DailyNotification plugin not available';
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
configStatus.innerHTML = '❌ Plugin unavailable';
fetcherStatus.innerHTML = '❌ Plugin unavailable';
return; return;
} }
@@ -132,6 +117,9 @@
}) })
.then(() => { .then(() => {
console.log('Plugin settings configured, now configuring native fetcher...'); console.log('Plugin settings configured, now configuring native fetcher...');
// Update top status
configStatus.innerHTML = '✅ Configured';
// Configure native fetcher with demo credentials // Configure native fetcher with demo credentials
// Note: DemoNativeFetcher uses hardcoded mock data, so this is optional // Note: DemoNativeFetcher uses hardcoded mock data, so this is optional
// but demonstrates the API. In production, this would be real credentials. // but demonstrates the API. In production, this would be real credentials.
@@ -142,48 +130,62 @@
}); });
}) })
.then(() => { .then(() => {
status.innerHTML = 'Plugin configured successfully!<br>✅ Plugin settings<br>✅ Native fetcher (optional for demo)'; // 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 status.style.background = 'rgba(0, 255, 0, 0.3)'; // Green background
}) })
.catch(error => { .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.innerHTML = `Configuration failed: ${error.message}`;
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
}); });
} catch (error) { } catch (error) {
configStatus.innerHTML = '❌ Error';
fetcherStatus.innerHTML = '❌ Error';
status.innerHTML = `Configuration failed: ${error.message}`; status.innerHTML = `Configuration failed: ${error.message}`;
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
} }
} }
function checkStatus() { function loadPluginStatus() {
console.log('checkStatus called'); console.log('loadPluginStatus called');
const status = document.getElementById('status'); const pluginStatusContent = document.getElementById('pluginStatusContent');
status.innerHTML = 'Checking plugin status...'; const statusCard = document.getElementById('statusCard');
status.style.background = 'rgba(255, 255, 0, 0.3)'; // Yellow background
try { try {
if (!window.DailyNotification) { if (!window.DailyNotification) {
status.innerHTML = 'DailyNotification plugin not available'; pluginStatusContent.innerHTML = 'DailyNotification plugin not available';
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background statusCard.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
return; return;
} }
window.DailyNotification.getNotificationStatus() window.DailyNotification.getNotificationStatus()
.then(result => { .then(result => {
const nextTime = result.nextNotificationTime ? new Date(result.nextNotificationTime).toLocaleString() : 'None scheduled'; const nextTime = result.nextNotificationTime ? new Date(result.nextNotificationTime).toLocaleString() : 'None scheduled';
status.innerHTML = `Plugin Status:<br> const hasSchedules = result.isEnabled || (result.pending && result.pending > 0);
Enabled: ${result.isEnabled}<br> const statusIcon = hasSchedules ? '✅' : '⏸️';
Next Notification: ${nextTime}<br> pluginStatusContent.innerHTML = `${statusIcon} Active Schedules: ${hasSchedules ? 'Yes' : 'No'}<br>
Pending: ${result.pending}<br> 📅 Next Notification: ${nextTime}<br>
Settings: ${JSON.stringify(result.settings)}`; ⏳ Pending: ${result.pending || 0}`;
status.style.background = 'rgba(0, 255, 0, 0.3)'; // Green background statusCard.style.background = hasSchedules ?
'rgba(0, 255, 0, 0.15)' : 'rgba(255, 255, 255, 0.1)'; // Green if active, light gray if none
}) })
.catch(error => { .catch(error => {
status.innerHTML = `Status check failed: ${error.message}`; pluginStatusContent.innerHTML = `⚠️ Status check failed: ${error.message}`;
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background statusCard.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
}); });
} catch (error) { } catch (error) {
status.innerHTML = `Status check failed: ${error.message}`; pluginStatusContent.innerHTML = `⚠️ Status check failed: ${error.message}`;
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background statusCard.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
} }
} }
@@ -211,8 +213,8 @@
// Test the notification method directly // Test the notification method directly
console.log('Testing notification scheduling...'); console.log('Testing notification scheduling...');
const now = new Date(); const now = new Date();
const notificationTime = new Date(now.getTime() + 600000); // 10 minutes from now const notificationTime = new Date(now.getTime() + 240000); // 4 minutes from now
const prefetchTime = new Date(now.getTime() + 120000); // 2 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') + ':' + const notificationTimeString = notificationTime.getHours().toString().padStart(2, '0') + ':' +
notificationTime.getMinutes().toString().padStart(2, '0'); notificationTime.getMinutes().toString().padStart(2, '0');
const prefetchTimeString = prefetchTime.getHours().toString().padStart(2, '0') + ':' + const prefetchTimeString = prefetchTime.getHours().toString().padStart(2, '0') + ':' +
@@ -232,10 +234,22 @@
'📥 Prefetch: ' + prefetchTimeReadable + ' (' + prefetchTimeString + ')<br>' + '📥 Prefetch: ' + prefetchTimeReadable + ' (' + prefetchTimeString + ')<br>' +
'🔔 Notification: ' + notificationTimeReadable + ' (' + notificationTimeString + ')'; '🔔 Notification: ' + notificationTimeReadable + ' (' + notificationTimeString + ')';
status.style.background = 'rgba(0, 255, 0, 0.3)'; // Green background status.style.background = 'rgba(0, 255, 0, 0.3)'; // Green background
// Refresh plugin status display
setTimeout(() => loadPluginStatus(), 500);
}) })
.catch(error => { .catch(error => {
status.innerHTML = `Notification failed: ${error.message}`; // 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 status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
}
}); });
} catch (error) { } catch (error) {
status.innerHTML = `Notification test failed: ${error.message}`; status.innerHTML = `Notification test failed: ${error.message}`;
@@ -243,130 +257,8 @@
} }
} }
function scheduleNotification() {
console.log('scheduleNotification called');
const status = document.getElementById('status');
status.innerHTML = 'Scheduling notification...';
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;
}
// Schedule notification for 10 minutes from now (allows 2 min prefetch to fire)
const now = new Date();
const notificationTime = new Date(now.getTime() + 600000); // 10 minutes from now
const prefetchTime = new Date(now.getTime() + 120000); // 2 minutes from now
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: 'Scheduled Notification',
body: 'This notification was scheduled 10 minutes ago!',
sound: true,
priority: 'default'
})
.then(() => {
const prefetchTimeReadable = prefetchTime.toLocaleTimeString();
const notificationTimeReadable = notificationTime.toLocaleTimeString();
status.innerHTML = '✅ Notification scheduled!<br>' +
'📥 Prefetch: ' + prefetchTimeReadable + ' (' + prefetchTimeString + ')<br>' +
'🔔 Notification: ' + notificationTimeReadable + ' (' + notificationTimeString + ')';
status.style.background = 'rgba(0, 255, 0, 0.3)'; // Green background
})
.catch(error => {
status.innerHTML = `Scheduling failed: ${error.message}`;
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
});
} catch (error) {
status.innerHTML = `Scheduling test failed: ${error.message}`;
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
}
}
function showReminder() {
console.log('showReminder called');
const status = document.getElementById('status');
status.innerHTML = 'Showing reminder...';
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;
}
// Schedule daily reminder using scheduleDailyReminder
const now = new Date();
const reminderTime = new Date(now.getTime() + 10000); // 10 seconds from now
const timeString = reminderTime.getHours().toString().padStart(2, '0') + ':' +
reminderTime.getMinutes().toString().padStart(2, '0');
window.DailyNotification.scheduleDailyReminder({
id: 'daily-reminder-test',
title: 'Daily Reminder',
body: 'Don\'t forget to check your daily notifications!',
time: timeString,
sound: true,
vibration: true,
priority: 'default',
repeatDaily: false // Just for testing
})
.then(() => {
status.innerHTML = 'Daily reminder scheduled for ' + timeString + '!';
status.style.background = 'rgba(0, 255, 0, 0.3)'; // Green background
})
.catch(error => {
status.innerHTML = `Reminder failed: ${error.message}`;
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
});
} catch (error) {
status.innerHTML = `Reminder test failed: ${error.message}`;
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
}
}
// Permission management functions // Permission management functions
function checkPermissions() {
console.log('checkPermissions called');
const status = document.getElementById('status');
status.innerHTML = 'Checking 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.checkPermissionStatus()
.then(result => {
status.innerHTML = `Permission Status:<br>
Notifications: ${result.notificationsEnabled ? '✅' : '❌'}<br>
Exact Alarm: ${result.exactAlarmEnabled ? '✅' : '❌'}<br>
Wake Lock: ${result.wakeLockEnabled ? '✅' : '❌'}<br>
All Granted: ${result.allPermissionsGranted ? '✅' : '❌'}`;
status.style.background = result.allPermissionsGranted ?
'rgba(0, 255, 0, 0.3)' : 'rgba(255, 165, 0, 0.3)'; // Green or orange
})
.catch(error => {
status.innerHTML = `Permission check failed: ${error.message}`;
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
});
} catch (error) {
status.innerHTML = `Permission check failed: ${error.message}`;
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
}
}
function requestPermissions() { function requestPermissions() {
console.log('requestPermissions called'); console.log('requestPermissions called');
const status = document.getElementById('status'); const status = document.getElementById('status');
@@ -385,9 +277,10 @@
status.innerHTML = 'Permission request completed! Check your device settings if needed.'; status.innerHTML = 'Permission request completed! Check your device settings if needed.';
status.style.background = 'rgba(0, 255, 0, 0.3)'; // Green background status.style.background = 'rgba(0, 255, 0, 0.3)'; // Green background
// Check permissions again after request // Refresh permission and channel status display after request
setTimeout(() => { setTimeout(() => {
checkPermissions(); loadPermissionStatus();
loadChannelStatus();
}, 1000); }, 1000);
}) })
.catch(error => { .catch(error => {
@@ -400,91 +293,29 @@
} }
} }
function openExactAlarmSettings() { function loadChannelStatus() {
console.log('openExactAlarmSettings called'); const channelStatus = document.getElementById('channelStatus');
const status = document.getElementById('status');
status.innerHTML = 'Opening exact alarm settings...';
status.style.background = 'rgba(255, 255, 0, 0.3)'; // Yellow background
try { try {
if (!window.DailyNotification) { if (!window.DailyNotification) {
status.innerHTML = 'DailyNotification plugin not available'; channelStatus.innerHTML = '❌ Plugin unavailable';
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
return;
}
window.DailyNotification.openExactAlarmSettings()
.then(() => {
status.innerHTML = 'Exact alarm settings opened! Please enable "Allow exact alarms" and return to the app.';
status.style.background = 'rgba(0, 255, 0, 0.3)'; // Green background
})
.catch(error => {
status.innerHTML = `Failed to open exact alarm settings: ${error.message}`;
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
});
} catch (error) {
status.innerHTML = `Failed to open exact alarm settings: ${error.message}`;
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
}
}
function checkChannelStatus() {
const status = document.getElementById('status');
status.innerHTML = 'Checking channel 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; return;
} }
window.DailyNotification.isChannelEnabled() window.DailyNotification.isChannelEnabled()
.then(result => { .then(result => {
const importanceText = getImportanceText(result.importance); const importanceText = getImportanceText(result.importance);
status.innerHTML = `Channel Status: ${result.enabled ? 'Enabled' : 'Disabled'} (${importanceText})`; if (result.enabled) {
status.style.background = result.enabled ? 'rgba(0, 255, 0, 0.3)' : 'rgba(255, 0, 0, 0.3)'; channelStatus.innerHTML = `✅ Enabled (${importanceText})`;
})
.catch(error => {
status.innerHTML = `Channel check failed: ${error.message}`;
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
});
} catch (error) {
status.innerHTML = `Channel check failed: ${error.message}`;
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
}
}
function openChannelSettings() {
const status = document.getElementById('status');
status.innerHTML = 'Opening channel settings...';
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.openChannelSettings()
.then(result => {
if (result.opened) {
status.innerHTML = 'Channel settings opened! Please enable notifications and return to the app.';
status.style.background = 'rgba(0, 255, 0, 0.3)'; // Green background
} else { } else {
status.innerHTML = 'Could not open channel settings (may not be available on this device)'; channelStatus.innerHTML = `❌ Disabled (${importanceText})`;
status.style.background = 'rgba(255, 165, 0, 0.3)'; // Orange background
} }
}) })
.catch(error => { .catch(error => {
status.innerHTML = `Failed to open channel settings: ${error.message}`; channelStatus.innerHTML = '⚠️ Error';
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
}); });
} catch (error) { } catch (error) {
status.innerHTML = `Failed to open channel settings: ${error.message}`; channelStatus.innerHTML = '⚠️ Error';
status.style.background = 'rgba(255, 0, 0, 0.3)'; // Red background
} }
} }
@@ -549,26 +380,53 @@
} }
// Attach to window object // Attach to window object
window.testPlugin = testPlugin;
window.configurePlugin = configurePlugin; window.configurePlugin = configurePlugin;
window.checkStatus = checkStatus;
window.testNotification = testNotification; window.testNotification = testNotification;
window.scheduleNotification = scheduleNotification;
window.showReminder = showReminder;
window.checkPermissions = checkPermissions;
window.requestPermissions = requestPermissions; window.requestPermissions = requestPermissions;
window.openExactAlarmSettings = openExactAlarmSettings;
window.checkChannelStatus = checkChannelStatus;
window.openChannelSettings = openChannelSettings;
window.checkComprehensiveStatus = checkComprehensiveStatus; 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';
}
}
// 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();
}, 500);
});
console.log('Functions attached to window:', { console.log('Functions attached to window:', {
testPlugin: typeof window.testPlugin,
configurePlugin: typeof window.configurePlugin, configurePlugin: typeof window.configurePlugin,
checkStatus: typeof window.checkStatus, testNotification: typeof window.testNotification
testNotification: typeof window.testNotification,
scheduleNotification: typeof window.scheduleNotification,
showReminder: typeof window.showReminder
}); });
</script> </script>
</body> </body>