package com.tt.honeyDue.notifications /** * Structured representation of a Firebase Cloud Messaging data-payload for * iOS-parity notification types (task_reminder, task_overdue, residence_invite, * subscription). * * Mirrors the iOS `PushNotificationManager.swift` userInfo handling. The * backend sends a `data` map only (no `notification` field) so we can always * deliver actionable payloads regardless of app foreground state. */ data class NotificationPayload( val type: String, val taskId: Long?, val residenceId: Long?, val title: String, val body: String, val deepLink: String? ) { companion object { // Keys used by the backend. Kept in a single place so they can be updated // in lockstep with the Go API `internal/notification/` constants. private const val KEY_TYPE = "type" private const val KEY_TASK_ID = "task_id" private const val KEY_RESIDENCE_ID = "residence_id" private const val KEY_TITLE = "title" private const val KEY_BODY = "body" private const val KEY_DEEP_LINK = "deep_link" /** * Parse a raw FCM data map into a [NotificationPayload], or null if the * payload is missing the minimum required fields (type + at least one of * title/body). Numeric id fields that fail to parse are treated as null * (rather than failing the whole payload) so we still surface the text. */ fun parse(data: Map): NotificationPayload? { val type = data[KEY_TYPE]?.takeIf { it.isNotBlank() } ?: return null val title = data[KEY_TITLE]?.takeIf { it.isNotBlank() } val body = data[KEY_BODY]?.takeIf { it.isNotBlank() } // Require at least one of title/body, otherwise there's nothing to show. if (title == null && body == null) return null return NotificationPayload( type = type, taskId = data[KEY_TASK_ID]?.toLongOrNull(), residenceId = data[KEY_RESIDENCE_ID]?.toLongOrNull(), title = title ?: "", body = body ?: "", deepLink = data[KEY_DEEP_LINK]?.takeIf { it.isNotBlank() } ) } } }