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:
@@ -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,29 +1126,81 @@ 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
|
||||||
|
Log.w(TAG, "Failed to open channel-specific settings, trying app notification settings", e)
|
||||||
|
try {
|
||||||
|
val fallbackIntent = Intent(android.provider.Settings.ACTION_APP_NOTIFICATION_SETTINGS).apply {
|
||||||
|
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 {
|
val result = JSObject().apply {
|
||||||
put("opened", false)
|
put("opened", false)
|
||||||
put("channelId", channelId)
|
put("channelId", channelId)
|
||||||
put("error", e.message)
|
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)
|
||||||
call.reject("Failed to open channel settings: ${e.message}")
|
call.reject("Failed to open channel settings: ${e.message}")
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user