fix(android): improve notification scheduling and UX

- Fix cron parsing to correctly calculate next run time based on hour/minute
- Always schedule prefetch 5 minutes before notification (even without URL)
- Make notifications dismissable with setAutoCancel(true)
- Add click action to launch app when notification is tapped
- Conditionally require network only when URL is provided for prefetch
- Generate mock content when no URL is specified

These changes ensure notifications fire at the correct time, are
user-friendly (dismissable and clickable), and prefetch works reliably
even without a content URL.
This commit is contained in:
Matthew Raymer
2025-11-06 07:52:40 +00:00
parent 18106e5ba8
commit 9f8e295234
3 changed files with 130 additions and 22 deletions

View File

@@ -32,7 +32,9 @@ class NotifyReceiver : BroadcastReceiver() {
fun scheduleExactNotification(
context: Context,
triggerAtMillis: Long,
config: UserNotificationConfig
config: UserNotificationConfig,
isStaticReminder: Boolean = false,
reminderId: String? = null
) {
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(context, NotifyReceiver::class.java).apply {
@@ -41,6 +43,10 @@ class NotifyReceiver : BroadcastReceiver() {
putExtra("sound", config.sound ?: true)
putExtra("vibration", config.vibration ?: true)
putExtra("priority", config.priority ?: "normal")
putExtra("is_static_reminder", isStaticReminder)
if (reminderId != null) {
putExtra("reminder_id", reminderId)
}
}
val pendingIntent = PendingIntent.getBroadcast(
@@ -187,6 +193,25 @@ class NotifyReceiver : BroadcastReceiver() {
notificationManager.createNotificationChannel(channel)
}
// Create intent to launch app when notification is clicked
val intent = try {
Intent(context, Class.forName("com.timesafari.dailynotification.MainActivity")).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
} catch (e: ClassNotFoundException) {
Log.w(TAG, "MainActivity not found, using package launcher", e)
// Fallback: launch app by package name
context.packageManager.getLaunchIntentForPackage(context.packageName)?.apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
} ?: return
}
val pendingIntent = PendingIntent.getActivity(
context,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
val notification = NotificationCompat.Builder(context, CHANNEL_ID)
.setContentTitle(title)
.setContentText(body)
@@ -198,7 +223,8 @@ class NotifyReceiver : BroadcastReceiver() {
else -> NotificationCompat.PRIORITY_DEFAULT
}
)
.setAutoCancel(true)
.setAutoCancel(true) // Dismissible when user swipes it away
.setContentIntent(pendingIntent) // Launch app when clicked
.setVibrate(if (vibration) longArrayOf(0, 250, 250, 250) else null)
.build()
@@ -286,6 +312,25 @@ class NotifyReceiver : BroadcastReceiver() {
// Create notification channel for reminders
createReminderNotificationChannel(context, notificationManager)
// Create intent to launch app when notification is clicked
val intent = try {
Intent(context, Class.forName("com.timesafari.dailynotification.MainActivity")).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
} catch (e: ClassNotFoundException) {
Log.w(TAG, "MainActivity not found, using package launcher", e)
// Fallback: launch app by package name
context.packageManager.getLaunchIntentForPackage(context.packageName)?.apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
} ?: return
}
val pendingIntent = PendingIntent.getActivity(
context,
reminderId.hashCode(),
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
val notification = NotificationCompat.Builder(context, "daily_reminders")
.setSmallIcon(android.R.drawable.ic_dialog_info)
.setContentTitle(title)
@@ -298,7 +343,8 @@ class NotifyReceiver : BroadcastReceiver() {
}
)
.setSound(if (sound) null else null) // Use default sound if enabled
.setAutoCancel(true)
.setAutoCancel(true) // Dismissible when user swipes it away
.setContentIntent(pendingIntent) // Launch app when clicked
.setVibrate(if (vibration) longArrayOf(0, 250, 250, 250) else null)
.setCategory(NotificationCompat.CATEGORY_REMINDER)
.build()