fix(ios): correct next notification time and improve rollover UI refresh

- Fix getNextNotificationTime() to find earliest scheduled notification
  instead of using first request (pendingNotificationRequests doesn't
  guarantee order)
- Add comprehensive logging for rollover tracking with DNP-ROLLOVER
  prefix for Xcode console filtering
- Reset all notifications and rollover state when scheduling new
  notification via scheduleDailyNotification() to ensure clean test
  state
- Fix userInfo scope error in handleNotificationDelivery error handler
- Update test app UI to refresh status every 5-10 seconds and
  immediately after notification delivery to reflect rollover changes
- Add console logging in UI to debug getNotificationStatus() results

This ensures the UI correctly displays the next notification time after
rollover completes, and test notifications start with a clean slate.
This commit is contained in:
Jose Olarte III
2025-12-15 21:42:48 +08:00
parent 527c075941
commit 0a2cbf24f7
12 changed files with 2281 additions and 12 deletions

View File

@@ -175,6 +175,15 @@
}
window.DailyNotification.getNotificationStatus()
.then(result => {
// Debug logging
console.log('getNotificationStatus result:', {
nextNotificationTime: result.nextNotificationTime,
pending: result.pending,
lastNotificationTime: result.lastNotificationTime,
rolloverEnabled: result.rolloverEnabled,
lastRolloverTime: result.lastRolloverTime
});
const nextTime = result.nextNotificationTime ? new Date(result.nextNotificationTime).toLocaleString() : 'None scheduled';
const hasSchedules = result.isEnabled || (result.pending && result.pending > 0);
const statusIcon = hasSchedules ? '✅' : '⏸️';
@@ -417,12 +426,14 @@
}
}
// Check for notification delivery periodically
// Check for notification delivery periodically and refresh status
function checkNotificationDelivery() {
if (!window.DailyNotification) return;
window.DailyNotification.getNotificationStatus()
.then(result => {
// Update notification received indicator
let notificationJustReceived = false;
if (result.lastNotificationTime) {
const lastTime = new Date(result.lastNotificationTime);
const now = new Date();
@@ -434,6 +445,10 @@
const timeSpan = document.getElementById('notificationReceivedTime');
if (indicator && timeSpan) {
// Check if this is a new notification (indicator was hidden)
const wasHidden = indicator.style.display === 'none' || !indicator.style.display;
notificationJustReceived = wasHidden;
indicator.style.display = 'block';
timeSpan.textContent = `Received at ${lastTime.toLocaleTimeString()}`;
@@ -444,6 +459,18 @@
}
}
}
// Always refresh the plugin status display to show updated next notification time
// This ensures rollover changes are reflected in the UI
loadPluginStatus();
// If notification just received, refresh again after a short delay to catch rollover
if (notificationJustReceived) {
console.log('Notification just received, refreshing status again in 2 seconds to catch rollover...');
setTimeout(() => {
loadPluginStatus();
}, 2000);
}
})
.catch(error => {
// Silently fail - this is just for visual feedback
@@ -459,8 +486,12 @@
loadPermissionStatus();
loadChannelStatus();
// Check for notification delivery every 5 seconds
// Check for notification delivery and refresh status every 5 seconds
setInterval(checkNotificationDelivery, 5000);
// Also refresh plugin status periodically to catch rollover updates
// This ensures the UI stays in sync even if checkNotificationDelivery misses an update
setInterval(loadPluginStatus, 10000); // Every 10 seconds
}, 500);
});

View File

@@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0920"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "504EC3031FED79650016851F"
BuildableName = "App.app"
BlueprintName = "App"
ReferencedContainer = "container:App.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "504EC3031FED79650016851F"
BuildableName = "App.app"
BlueprintName = "App"
ReferencedContainer = "container:App.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "504EC3031FED79650016851F"
BuildableName = "App.app"
BlueprintName = "App"
ReferencedContainer = "container:App.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -140,6 +140,34 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
NSLog("DNP-DEBUG: Notification body: %@", notification.request.content.body)
NSLog("DNP-DEBUG: Current delegate: %@", UNUserNotificationCenter.current().delegate != nil ? "SET" : "NOT SET")
// Extract notification info from userInfo for rollover
let userInfo = notification.request.content.userInfo
if let notificationId = userInfo["notification_id"] as? String,
let scheduledTime = userInfo["scheduled_time"] as? Int64 {
// Format scheduled time for logging
let scheduledDate = Date(timeIntervalSince1970: Double(scheduledTime) / 1000.0)
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .short
let scheduledTimeStr = formatter.string(from: scheduledDate)
NSLog("DNP-ROLLOVER: APPDELGATE_DETECTED id=%@ scheduled_time=%@", notificationId, scheduledTimeStr)
NSLog("DNP-DEBUG: Posted rollover notification for id=%@", notificationId)
// Post notification to trigger rollover (decoupled pattern)
NotificationCenter.default.post(
name: NSNotification.Name("DailyNotificationDelivered"),
object: nil,
userInfo: [
"notification_id": notificationId,
"scheduled_time": scheduledTime
]
)
} else {
NSLog("DNP-ROLLOVER: APPDELGATE_MISSING_DATA id=%@ userInfo=%@", notification.request.identifier, userInfo)
}
// Show notification with banner, sound, and badge
// Use .banner for iOS 14+, fallback to .alert for iOS 13
if #available(iOS 14.0, *) {