Skip to content

Commit 1bbfda8

Browse files
authored
chore: rename to notification inbox (#659)
1 parent eb1c650 commit 1bbfda8

File tree

14 files changed

+289
-209
lines changed

14 files changed

+289
-209
lines changed

messaginginapp/api/messaginginapp.api

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public final class io/customer/messaginginapp/ModuleMessagingInApp : io/customer
2121
public fun getModuleConfig ()Lio/customer/messaginginapp/MessagingInAppModuleConfig;
2222
public synthetic fun getModuleConfig ()Lio/customer/sdk/core/module/CustomerIOModuleConfig;
2323
public fun getModuleName ()Ljava/lang/String;
24-
public final fun inbox ()Lio/customer/messaginginapp/inbox/MessageInbox;
24+
public final fun inbox ()Lio/customer/messaginginapp/inbox/NotificationInbox;
2525
public fun initialize ()V
2626
public static final fun instance ()Lio/customer/messaginginapp/ModuleMessagingInApp;
2727
public fun onAction (Lio/customer/messaginginapp/gist/data/model/Message;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
@@ -207,26 +207,26 @@ public final class io/customer/messaginginapp/gist/utilities/ElapsedTimer {
207207
public final fun start (Ljava/lang/String;)V
208208
}
209209

210-
public abstract interface class io/customer/messaginginapp/inbox/InboxChangeListener {
211-
public abstract fun onInboxChanged (Ljava/util/List;)V
212-
}
213-
214-
public final class io/customer/messaginginapp/inbox/MessageInbox {
215-
public final fun addChangeListener (Lio/customer/messaginginapp/inbox/InboxChangeListener;)V
216-
public final fun addChangeListener (Lio/customer/messaginginapp/inbox/InboxChangeListener;Ljava/lang/String;)V
217-
public static synthetic fun addChangeListener$default (Lio/customer/messaginginapp/inbox/MessageInbox;Lio/customer/messaginginapp/inbox/InboxChangeListener;Ljava/lang/String;ILjava/lang/Object;)V
210+
public final class io/customer/messaginginapp/inbox/NotificationInbox {
211+
public final fun addChangeListener (Lio/customer/messaginginapp/inbox/NotificationInboxChangeListener;)V
212+
public final fun addChangeListener (Lio/customer/messaginginapp/inbox/NotificationInboxChangeListener;Ljava/lang/String;)V
213+
public static synthetic fun addChangeListener$default (Lio/customer/messaginginapp/inbox/NotificationInbox;Lio/customer/messaginginapp/inbox/NotificationInboxChangeListener;Ljava/lang/String;ILjava/lang/Object;)V
218214
public final fun fetchMessages (Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V
219215
public final fun fetchMessages (Lkotlin/jvm/functions/Function1;)V
220216
public final fun getMessages (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
221217
public final fun getMessages (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
222-
public static synthetic fun getMessages$default (Lio/customer/messaginginapp/inbox/MessageInbox;Ljava/lang/String;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
218+
public static synthetic fun getMessages$default (Lio/customer/messaginginapp/inbox/NotificationInbox;Ljava/lang/String;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
223219
public final fun markMessageDeleted (Lio/customer/messaginginapp/gist/data/model/InboxMessage;)V
224220
public final fun markMessageOpened (Lio/customer/messaginginapp/gist/data/model/InboxMessage;)V
225221
public final fun markMessageUnopened (Lio/customer/messaginginapp/gist/data/model/InboxMessage;)V
226-
public final fun removeChangeListener (Lio/customer/messaginginapp/inbox/InboxChangeListener;)V
222+
public final fun removeChangeListener (Lio/customer/messaginginapp/inbox/NotificationInboxChangeListener;)V
227223
public final fun trackMessageClicked (Lio/customer/messaginginapp/gist/data/model/InboxMessage;)V
228224
public final fun trackMessageClicked (Lio/customer/messaginginapp/gist/data/model/InboxMessage;Ljava/lang/String;)V
229-
public static synthetic fun trackMessageClicked$default (Lio/customer/messaginginapp/inbox/MessageInbox;Lio/customer/messaginginapp/gist/data/model/InboxMessage;Ljava/lang/String;ILjava/lang/Object;)V
225+
public static synthetic fun trackMessageClicked$default (Lio/customer/messaginginapp/inbox/NotificationInbox;Lio/customer/messaginginapp/gist/data/model/InboxMessage;Ljava/lang/String;ILjava/lang/Object;)V
226+
}
227+
228+
public abstract interface class io/customer/messaginginapp/inbox/NotificationInboxChangeListener {
229+
public abstract fun onMessagesChanged (Ljava/util/List;)V
230230
}
231231

232232
public abstract interface class io/customer/messaginginapp/type/InAppEventListener {

messaginginapp/src/main/java/io/customer/messaginginapp/ModuleMessagingInApp.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ package io.customer.messaginginapp
22

33
import io.customer.messaginginapp.di.gistCustomAttributes
44
import io.customer.messaginginapp.di.gistProvider
5-
import io.customer.messaginginapp.di.messageInbox
5+
import io.customer.messaginginapp.di.notificationInbox
66
import io.customer.messaginginapp.gist.data.model.Message
77
import io.customer.messaginginapp.gist.presentation.GistListener
88
import io.customer.messaginginapp.gist.presentation.GistProvider
9-
import io.customer.messaginginapp.inbox.MessageInbox
9+
import io.customer.messaginginapp.inbox.NotificationInbox
1010
import io.customer.messaginginapp.type.InAppMessage
1111
import io.customer.sdk.communication.Event
1212
import io.customer.sdk.communication.subscribe
@@ -28,10 +28,10 @@ class ModuleMessagingInApp(
2828
/**
2929
* Access the inbox messages instance for managing user inbox messages.
3030
*
31-
* @return [MessageInbox] instance for inbox operations
31+
* @return [NotificationInbox] instance for inbox operations
3232
*/
33-
fun inbox(): MessageInbox {
34-
return SDKComponent.messageInbox
33+
fun inbox(): NotificationInbox {
34+
return SDKComponent.notificationInbox
3535
}
3636

3737
fun dismissMessage() {

messaginginapp/src/main/java/io/customer/messaginginapp/di/DIGraphMessagingInApp.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import io.customer.messaginginapp.gist.presentation.SseLifecycleManager
2020
import io.customer.messaginginapp.gist.utilities.ModalMessageGsonParser
2121
import io.customer.messaginginapp.gist.utilities.ModalMessageParser
2222
import io.customer.messaginginapp.gist.utilities.ModalMessageParserDefault
23-
import io.customer.messaginginapp.inbox.MessageInbox
23+
import io.customer.messaginginapp.inbox.NotificationInbox
2424
import io.customer.messaginginapp.state.InAppMessagingManager
2525
import io.customer.messaginginapp.store.InAppPreferenceStore
2626
import io.customer.messaginginapp.store.InAppPreferenceStoreImpl
@@ -137,11 +137,11 @@ internal val SDKComponent.inAppMessaging: ModuleMessagingInApp
137137
get() = ModuleMessagingInApp.instance()
138138

139139
/**
140-
* Provides singleton instance of [MessageInbox] for managing inbox messages.
140+
* Provides singleton instance of [NotificationInbox] for managing inbox messages.
141141
*/
142-
internal val SDKComponent.messageInbox: MessageInbox
142+
internal val SDKComponent.notificationInbox: NotificationInbox
143143
get() = singleton {
144-
MessageInbox(
144+
NotificationInbox(
145145
logger = logger,
146146
coroutineScope = scopeProvider.inAppLifecycleScope,
147147
dispatchersProvider = dispatchersProvider,

messaginginapp/src/main/java/io/customer/messaginginapp/gist/data/listeners/Queue.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ import io.customer.messaginginapp.gist.data.NetworkUtilities
1010
import io.customer.messaginginapp.gist.data.model.InboxMessage
1111
import io.customer.messaginginapp.gist.data.model.Message
1212
import io.customer.messaginginapp.gist.data.model.isMessageAnonymous
13+
import io.customer.messaginginapp.gist.data.model.response.InboxMessageFactory
1314
import io.customer.messaginginapp.gist.data.model.response.QueueMessagesResponse
14-
import io.customer.messaginginapp.gist.data.model.response.toDomain
1515
import io.customer.messaginginapp.gist.data.model.response.toLogString
1616
import io.customer.messaginginapp.state.InAppMessagingAction
1717
import io.customer.messaginginapp.state.InAppMessagingState
@@ -196,7 +196,7 @@ internal class Queue : GistQueue {
196196
val inboxMessages = response.inboxMessages
197197
logger.debug("Found ${inboxMessages.count()} inbox messages for user")
198198
val inboxMessagesMapped = inboxMessages.mapNotNull { item ->
199-
item.toDomain()?.let { message ->
199+
InboxMessageFactory.fromResponse(item)?.let { message ->
200200
if (fromCache) {
201201
// 304: apply cached opened status if available
202202
val cachedOpenedStatus = inAppPreferenceStore.getInboxMessageOpenedStatus(message.queueId)

messaginginapp/src/main/java/io/customer/messaginginapp/gist/data/model/response/InboxMessageExtensions.kt

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,5 @@ package io.customer.messaginginapp.gist.data.model.response
22

33
import io.customer.messaginginapp.gist.data.model.InboxMessage
44

5-
/**
6-
* Maps the API response model to domain model. This allows us to have safe defaults
7-
* for missing or nullable API fields so the domain model can remain predictable
8-
* and free of nullability checks elsewhere.
9-
*
10-
* Returns null if required fields (queueId, sentAt) are missing, indicating an invalid message
11-
* that should be filtered out.
12-
*/
13-
internal fun InboxMessageResponse.toDomain(): InboxMessage? {
14-
// Skip invalid messages missing required fields
15-
if (queueId == null || sentAt == null) {
16-
return null
17-
}
18-
19-
return InboxMessage(
20-
queueId = queueId,
21-
deliveryId = deliveryId,
22-
expiry = expiry,
23-
sentAt = sentAt,
24-
topics = topics ?: emptyList(),
25-
type = type ?: "",
26-
opened = opened ?: false,
27-
priority = priority,
28-
properties = properties ?: emptyMap()
29-
)
30-
}
31-
325
// Formats inbox message for logging.
336
internal fun InboxMessage.toLogString(): String = "$queueId (deliveryId: $deliveryId)"
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package io.customer.messaginginapp.gist.data.model.response
2+
3+
import io.customer.base.internal.InternalCustomerIOApi
4+
import io.customer.messaginginapp.gist.data.model.InboxMessage
5+
import java.util.Date
6+
7+
/**
8+
* Factory for creating InboxMessage domain models from various sources (API responses, Maps).
9+
*/
10+
@InternalCustomerIOApi
11+
object InboxMessageFactory {
12+
/**
13+
* Converts InboxMessageResponse to InboxMessage with safe defaults for nullable fields.
14+
* Returns null if required fields (queueId, sentAt) are missing.
15+
*/
16+
internal fun fromResponse(response: InboxMessageResponse): InboxMessage? {
17+
// Skip invalid messages missing required fields
18+
if (response.queueId == null || response.sentAt == null) {
19+
return null
20+
}
21+
22+
return InboxMessage(
23+
queueId = response.queueId,
24+
deliveryId = response.deliveryId,
25+
expiry = response.expiry,
26+
sentAt = response.sentAt,
27+
topics = response.topics ?: emptyList(),
28+
type = response.type ?: "",
29+
opened = response.opened ?: false,
30+
priority = response.priority,
31+
properties = response.properties ?: emptyMap()
32+
)
33+
}
34+
35+
/**
36+
* Converts Map to InboxMessage for SDK wrapper integrations.
37+
* Returns null if required fields (queueId, sentAt) are missing or invalid.
38+
*/
39+
fun fromMap(map: Map<String, Any?>): InboxMessage? {
40+
@Suppress("UNCHECKED_CAST")
41+
val properties = map["properties"] as? Map<String, Any?> ?: emptyMap()
42+
return fromResponse(
43+
InboxMessageResponse(
44+
queueId = map["queueId"] as? String,
45+
deliveryId = map["deliveryId"] as? String,
46+
expiry = (map["expiry"] as? Number)?.toLong()?.let { Date(it) },
47+
sentAt = (map["sentAt"] as? Number)?.toLong()?.let { Date(it) },
48+
topics = (map["topics"] as? List<*>)?.mapNotNull { it as? String },
49+
type = map["type"] as? String,
50+
opened = map["opened"] as? Boolean,
51+
priority = (map["priority"] as? Number)?.toInt(),
52+
properties = properties
53+
)
54+
)
55+
}
56+
}

messaginginapp/src/main/java/io/customer/messaginginapp/gist/data/sse/SseDataParser.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import com.google.gson.JsonSyntaxException
66
import io.customer.messaginginapp.gist.data.NetworkUtilities
77
import io.customer.messaginginapp.gist.data.model.InboxMessage
88
import io.customer.messaginginapp.gist.data.model.Message
9+
import io.customer.messaginginapp.gist.data.model.response.InboxMessageFactory
910
import io.customer.messaginginapp.gist.data.model.response.InboxMessageResponse
10-
import io.customer.messaginginapp.gist.data.model.response.toDomain
1111

1212
internal class SseDataParser(
1313
private val sseLogger: InAppSseLogger,
@@ -31,7 +31,7 @@ internal class SseDataParser(
3131
*/
3232
fun parseInboxMessages(data: String): List<InboxMessage> {
3333
val responses = parseMessageArray(data, Array<InboxMessageResponse>::class.java)
34-
val messages = responses.mapNotNull { it.toDomain() }
34+
val messages = responses.mapNotNull(InboxMessageFactory::fromResponse)
3535

3636
if (messages.size < responses.size) {
3737
sseLogger.logFilteredInvalidInboxMessages(responses.size - messages.size)

messaginginapp/src/main/java/io/customer/messaginginapp/inbox/MessageInbox.kt renamed to messaginginapp/src/main/java/io/customer/messaginginapp/inbox/NotificationInbox.kt

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import kotlinx.coroutines.launch
2525
* inbox.getMessages()
2626
* ```
2727
*/
28-
class MessageInbox internal constructor(
28+
class NotificationInbox internal constructor(
2929
private val logger: Logger,
3030
private val coroutineScope: CoroutineScope,
3131
private val dispatchersProvider: DispatchersProvider,
@@ -77,11 +77,12 @@ class MessageInbox internal constructor(
7777
/**
7878
* Fetches inbox messages for a specific topic asynchronously via callback.
7979
*
80-
* @param topic Topic filter. Only messages with this topic in their topics list are returned.
80+
* @param topic Optional topic filter. If provided, listener only receives messages
81+
* that have this topic in their topics list. If null, all messages are delivered.
8182
* @param callback Called with [Result] containing the list of messages or an error
8283
* if failed to retrieve
8384
*/
84-
fun fetchMessages(topic: String, callback: (Result<List<InboxMessage>>) -> Unit) {
85+
fun fetchMessages(topic: String?, callback: (Result<List<InboxMessage>>) -> Unit) {
8586
fetchMessagesWithCallback(topic, callback)
8687
}
8788

@@ -112,7 +113,7 @@ class MessageInbox internal constructor(
112113
*/
113114
@JvmOverloads
114115
@MainThread
115-
fun addChangeListener(listener: InboxChangeListener, topic: String? = null) {
116+
fun addChangeListener(listener: NotificationInboxChangeListener, topic: String? = null) {
116117
val registration = ListenerRegistration(listener, topic)
117118
listeners.add(registration)
118119

@@ -128,7 +129,7 @@ class MessageInbox internal constructor(
128129
* Unregisters a listener for inbox changes.
129130
* Removes all registrations of this listener, regardless of topic filters.
130131
*/
131-
fun removeChangeListener(listener: InboxChangeListener) {
132+
fun removeChangeListener(listener: NotificationInboxChangeListener) {
132133
listeners.forEach { registration ->
133134
if (registration.listener == listener) {
134135
listeners.remove(registration)
@@ -181,9 +182,9 @@ class MessageInbox internal constructor(
181182
* @param messages The messages to send to the listener
182183
*/
183184
@MainThread
184-
private fun notifyListener(listener: InboxChangeListener, messages: List<InboxMessage>) {
185+
private fun notifyListener(listener: NotificationInboxChangeListener, messages: List<InboxMessage>) {
185186
try {
186-
listener.onInboxChanged(messages)
187+
listener.onMessagesChanged(messages)
187188
} catch (ex: Exception) {
188189
// Log and continue to prevent one bad listener from breaking others
189190
logger.error("Error notifying inbox listener: ${ex.message}")
@@ -253,7 +254,7 @@ class MessageInbox internal constructor(
253254
* Wrapper class to store listener with optional topic filter.
254255
*/
255256
private data class ListenerRegistration(
256-
val listener: InboxChangeListener,
257+
val listener: NotificationInboxChangeListener,
257258
val topic: String? = null
258259
)
259260
}

messaginginapp/src/main/java/io/customer/messaginginapp/inbox/InboxChangeListener.kt renamed to messaginginapp/src/main/java/io/customer/messaginginapp/inbox/NotificationInboxChangeListener.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,22 @@ package io.customer.messaginginapp.inbox
33
import io.customer.messaginginapp.gist.data.model.InboxMessage
44

55
/**
6-
* Listener for inbox message changes.
6+
* Listener for notification inbox message changes.
77
*
88
* Receives real time notifications when inbox messages are added, updated, or removed.
99
* Callbacks are invoked on the main thread for safe UI updates.
1010
*
11-
* **Important:** Call [MessageInbox.removeChangeListener] when done (e.g., in `onDestroy()`)
11+
* **Important:** Call [NotificationInbox.removeChangeListener] when done (e.g., in `onDestroy()`)
1212
* to prevent memory leaks.
1313
*/
14-
interface InboxChangeListener {
14+
interface NotificationInboxChangeListener {
1515
/**
16-
* Called when inbox messages change.
16+
* Called when messages change.
1717
*
1818
* Invoked immediately with current messages when registered, then again whenever
1919
* messages are added, updated, or removed.
2020
*
2121
* @param messages Current inbox messages. Filtered by topic if specified during registration.
2222
*/
23-
fun onInboxChanged(messages: List<InboxMessage>)
23+
fun onMessagesChanged(messages: List<InboxMessage>)
2424
}

messaginginapp/src/test/java/io/customer/messaginginapp/InAppMessagingStoreTest.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -644,7 +644,7 @@ class InAppMessagingStoreTest : IntegrationTest() {
644644
}
645645

646646
@Test
647-
fun givenInboxMessages_whenProcessed_thenMessagesAreAvailableViaMessageInbox() = runTest {
647+
fun givenInboxMessages_whenProcessed_thenMessagesAreAvailableViaNotificationInbox() = runTest {
648648
initializeAndSetUser()
649649

650650
// Create test inbox messages
@@ -655,9 +655,9 @@ class InAppMessagingStoreTest : IntegrationTest() {
655655
// Process inbox messages via action
656656
manager.dispatch(InAppMessagingAction.ProcessInboxMessages(listOf(message1, message2, message3)))
657657

658-
// Verify MessageInbox.getMessages() returns correct messages
659-
val messageInbox = module.inbox()
660-
val retrievedMessages = messageInbox.getMessages()
658+
// Verify NotificationInbox.getMessages() returns correct messages
659+
val notificationInbox = module.inbox()
660+
val retrievedMessages = notificationInbox.getMessages()
661661
retrievedMessages.size shouldBeEqualTo 3
662662
retrievedMessages shouldContainAll listOf(message1, message2, message3)
663663
}

0 commit comments

Comments
 (0)