diff --git a/android/src/main/java/app/tauri/notification/Notification.kt b/android/src/main/java/app/tauri/notification/Notification.kt index 1dbaa5d..42b4620 100644 --- a/android/src/main/java/app/tauri/notification/Notification.kt +++ b/android/src/main/java/app/tauri/notification/Notification.kt @@ -66,6 +66,7 @@ class Notification { var visibility: Int? = null var number: Int? = null var silent: Boolean? = null + var onlyAlertOnce: Boolean? = null fun getSound(context: Context, defaultSound: Int): String? { var soundPath: String? = null diff --git a/android/src/main/java/app/tauri/notification/TauriNotificationManager.kt b/android/src/main/java/app/tauri/notification/TauriNotificationManager.kt index bd4067e..a26714a 100644 --- a/android/src/main/java/app/tauri/notification/TauriNotificationManager.kt +++ b/android/src/main/java/app/tauri/notification/TauriNotificationManager.kt @@ -116,7 +116,6 @@ class TauriNotificationManager( } private fun trigger(notificationManager: NotificationManagerCompat, notification: Notification): Int { - dismissVisibleNotification(notification.id) cancelTimerForNotification(notification.id) buildNotification(notificationManager, notification) @@ -203,7 +202,7 @@ class TauriNotificationManager( } } mBuilder.setVisibility(notification.visibility ?: NotificationCompat.VISIBILITY_PRIVATE) - mBuilder.setOnlyAlertOnce(true) + mBuilder.setOnlyAlertOnce(notification.onlyAlertOnce ?: true) mBuilder.setSmallIcon(notification.getSmallIcon(context, getDefaultSmallIcon(context))) mBuilder.setLargeIcon(notification.getLargeIcon(context)) val iconColor = notification.getIconColor(config?.iconColor ?: "") diff --git a/android/src/main/java/app/tauri/notification/UnifiedPushNotifier.kt b/android/src/main/java/app/tauri/notification/UnifiedPushNotifier.kt index b08af94..e5bf4ed 100644 --- a/android/src/main/java/app/tauri/notification/UnifiedPushNotifier.kt +++ b/android/src/main/java/app/tauri/notification/UnifiedPushNotifier.kt @@ -125,7 +125,7 @@ object UnifiedPushNotifier { .setContentTitle(title) .setContentText(body) .setAutoCancel(true) - .setOnlyAlertOnce(true) + .setOnlyAlertOnce(silent) .setPriority(NotificationCompat.PRIORITY_HIGH) .setGroup(GROUP_KEY) .setContentIntent( diff --git a/src/lib.rs b/src/lib.rs index 31ee1d3..9c0f332 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -300,6 +300,13 @@ impl NotificationsBuilder { self.data.silent = true; self } + + /// Whether replacing a visible notification alerts again. Android only, `true` when unset. + #[must_use] + pub const fn only_alert_once(mut self, only_alert_once: bool) -> Self { + self.data.only_alert_once = Some(only_alert_once); + self + } } /// Extensions to [`tauri::App`], [`tauri::AppHandle`], [`tauri::WebviewWindow`], [`tauri::Webview`] and [`tauri::Window`] to access the notification APIs. diff --git a/src/models.rs b/src/models.rs index 3778361..3dc86d6 100644 --- a/src/models.rs +++ b/src/models.rs @@ -253,6 +253,7 @@ pub struct NotificationData { pub(crate) auto_cancel: bool, #[serde(default)] pub(crate) silent: bool, + pub(crate) only_alert_once: Option, } fn default_id() -> i32 { @@ -284,6 +285,7 @@ impl Default for NotificationData { ongoing: false, auto_cancel: false, silent: false, + only_alert_once: None, } } } @@ -806,6 +808,17 @@ mod tests { assert!(data.extra.is_empty()); } + #[test] + fn test_only_alert_once_uses_the_android_key() { + let data = NotificationData { + only_alert_once: Some(false), + ..Default::default() + }; + let json = serde_json::to_string(&data).expect("Failed to serialize notification data"); + assert!(json.contains("\"onlyAlertOnce\":false")); + assert!(NotificationData::default().only_alert_once.is_none()); + } + #[test] fn test_notification_data_serialization() { let data = NotificationData {