@@ -489,8 +489,16 @@ open class EventNotificationManager : EventNotificationManagerInterface {
489489 }
490490 .toString()
491491
492+ // Compute if any NEW event is triggering this notification (Issue #162)
493+ // A "new triggering" event is: never shown before (Hidden), not snoozed, and not muted
494+ val hasNewTriggeringEvent = events.any { event ->
495+ event.displayStatus == EventDisplayStatus .Hidden &&
496+ event.snoozedUntil == 0L &&
497+ ! event.isMuted
498+ }
499+
492500 // Use appropriate channel using shared helper (testable)
493- val channelId = computeCollapsedChannelId(events, hasAlarms, playReminderSound)
501+ val channelId = computeCollapsedChannelId(events, hasAlarms, playReminderSound, hasNewTriggeringEvent )
494502
495503 val builder =
496504 NotificationCompat .Builder (context, channelId)
@@ -701,6 +709,11 @@ open class EventNotificationManager : EventNotificationManagerInterface {
701709
702710 shouldBeQuiet = shouldBeQuiet || event.isMuted
703711
712+ // Issue #162: Determine if this is a reminder (already tracked) or new event
713+ // New events (Hidden status) use calendar_events channel
714+ // Already tracked events (was collapsed, etc.) use calendar_reminders channel
715+ val isReminder = computeIsReminderForEvent(event)
716+
704717 postNotification(
705718 context,
706719 formatter,
@@ -709,7 +722,8 @@ open class EventNotificationManager : EventNotificationManagerInterface {
709722 force,
710723 wasCollapsed,
711724 snoozePresets,
712- isQuietPeriodActive)
725+ isQuietPeriodActive,
726+ isReminder = isReminder)
713727
714728 // Update db to indicate that this event is currently actively displayed
715729 db.updateEvent(event, displayStatus = EventDisplayStatus .DisplayedNormal )
@@ -730,6 +744,8 @@ open class EventNotificationManager : EventNotificationManagerInterface {
730744 // Update this time before posting notification as this is now used as a sort-key
731745 event.lastStatusChangeTime = currentTime
732746
747+ // Issue #162: Snoozed events returning are always "reminders" (already tracked)
748+ // They should use calendar_reminders channel, not calendar_events
733749 postNotification(
734750 context,
735751 formatter,
@@ -738,7 +754,8 @@ open class EventNotificationManager : EventNotificationManagerInterface {
738754 force,
739755 false ,
740756 snoozePresets,
741- isQuietPeriodActive)
757+ isQuietPeriodActive,
758+ isReminder = true ) // Always a reminder when returning from snooze
742759
743760 if (event.snoozedUntil + Consts .ALARM_THRESHOLD < currentTime) {
744761 DevLog .warn(LOG_TAG , " Warning: snooze alarm is very late: expected at ${event.snoozedUntil} , " +
@@ -1766,21 +1783,53 @@ open class EventNotificationManager : EventNotificationManagerInterface {
17661783 }
17671784 }
17681785
1786+ /* *
1787+ * Determines if an event should be treated as a "reminder" for channel selection purposes.
1788+ * THIS IS ACTUAL PRODUCTION CODE - called by postEventNotifications.
1789+ *
1790+ * Philosophy (Issue #162):
1791+ * - First notification from calendar → calendar_events channel
1792+ * - Every time after → calendar_reminders channel
1793+ *
1794+ * An event is NEW (not a reminder) when:
1795+ * - displayStatus == Hidden (never been shown) AND
1796+ * - snoozedUntil == 0 (not returning from snooze)
1797+ *
1798+ * An event is ALREADY TRACKED (is a reminder) when:
1799+ * - displayStatus != Hidden (was shown before - collapsed or normal), OR
1800+ * - snoozedUntil != 0 (returning from snooze)
1801+ *
1802+ * @param event The event to check
1803+ * @return true if event should use reminders channel, false for events channel
1804+ */
1805+ fun computeIsReminderForEvent (event : EventAlertRecord ): Boolean {
1806+ return event.displayStatus != EventDisplayStatus .Hidden || event.snoozedUntil != 0L
1807+ }
1808+
17691809 /* *
17701810 * Computes the notification channel ID for collapsed notifications (postEverythingCollapsed).
17711811 * THIS IS ACTUAL PRODUCTION CODE - called by postEverythingCollapsed.
17721812 *
1813+ * Channel selection (Issue #162):
1814+ * - If periodic reminder (playReminderSound=true) → reminders channel
1815+ * - If any NEW event is triggering → events channel (new thing on your plate)
1816+ * - If only OLD events triggering → reminders channel (already on your plate)
1817+ *
17731818 * @param events List of events to display
17741819 * @param hasAlarms Whether there are non-muted alarm events
1775- * @param isReminder Whether this is a reminder notification
1820+ * @param playReminderSound Whether this is a periodic reminder notification
1821+ * @param hasNewTriggeringEvent Whether any new (never shown) events are triggering this notification
17761822 * @return The appropriate channel ID
17771823 */
17781824 fun computeCollapsedChannelId (
17791825 events : List <EventAlertRecord >,
17801826 hasAlarms : Boolean ,
1781- isReminder : Boolean
1827+ playReminderSound : Boolean ,
1828+ hasNewTriggeringEvent : Boolean
17821829 ): String {
17831830 val allEventsMuted = events.all { it.isMuted }
1831+ // Use reminders channel if: periodic reminder OR no new events triggering
1832+ val isReminder = playReminderSound || ! hasNewTriggeringEvent
17841833 return NotificationChannels .getChannelId(
17851834 isAlarm = hasAlarms,
17861835 isMuted = allEventsMuted,
0 commit comments