An in-app notification center list you can use to notify your users. Allows you to build high quality, flexible notification feeds very quickly.
Requirement | Reason |
---|---|
Courier Inbox Provider
|
Needed to link your Courier Inbox to the SDK |
Authentication
|
Needed to view inbox messages that belong to a user. |
If you are using JWT authentication, be sure to enable JWT support on the Courier Inbox Provider here
.
Your app theme must use the Material Components parent. This is for Material buttons. Set your themes.xml
like this.
<resources>
<style name="Your.Theme" parent="Theme.MaterialComponents.DayNight.DarkActionBar" />
</resources>
CourierInbox
works with all native Android UI frameworks.
UI Framework | Support |
---|---|
XML |
✅ |
Programmatic |
✅ |
Jetpack Compose |
✅ |
The default CourierInbox
styles. Colors are using colorPrimary
located in your res/values/themes.xml
file.
CourierInbox(
modifier = Modifier.padding(innerPadding),
onClickMessageListener = { message, index ->
if (message.isRead) message.markAsUnread() else message.markAsRead()
},
onLongPressMessageListener = { message, index ->
message.markAsArchived()
},
onClickActionListener = { action, message, index ->
print(message.toString())
},
onScrollInboxListener = { offsetInDp ->
print(offsetInDp.toString())
}
)
<com.courier.android.ui.inbox.CourierInbox xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/courierInbox"
android:layout_width="match_parent"
android:layout_height="match_parent" />
val inbox: CourierInbox = view.findViewById(R.id.courierInbox)
inbox.setOnClickMessageListener { message, index ->
Courier.log(message.toString())
if (message.isRead) message.markAsUnread() else message.markAsRead()
}
inbox.setOnLongPressMessageListener { message, index ->
Courier.log(message.toString())
}
inbox.setOnClickActionListener { action, message, index ->
Courier.log(action.toString())
}
inbox.setOnScrollInboxListener { offsetInDp ->
Courier.log(offsetInDp.toString())
}
The styles you can use to quickly customize the CourierInbox
.
fun getTheme(context: Context): CourierInboxTheme {
val whiteColor = Color(0xFFFFFFFF).toArgb()
val blackColor = Color(0xFF000000).toArgb()
val blackLightColor = Color(0x80000000).toArgb()
val primaryColor = Color(0xFF6650a4).toArgb()
val primaryLightColor = Color(0xFF625b71).toArgb()
val font = ResourcesCompat.getFont(context, R.font.poppins)
return CourierInboxTheme(
loadingIndicatorColor = primaryColor,
tabIndicatorColor = primaryColor,
tabStyle = CourierStyles.Inbox.TabStyle(
selected = CourierStyles.Inbox.TabItemStyle(
font = CourierStyles.Font(
typeface = font,
sizeInSp = 18,
color = primaryColor
),
indicator = CourierStyles.Inbox.TabIndicatorStyle(
font = CourierStyles.Font(
typeface = font,
sizeInSp = 14,
color = whiteColor
),
color = primaryColor
)
),
unselected = CourierStyles.Inbox.TabItemStyle(
font = CourierStyles.Font(
typeface = font,
sizeInSp = 18,
color = blackLightColor,
),
indicator = CourierStyles.Inbox.TabIndicatorStyle(
font = CourierStyles.Font(
typeface = font,
sizeInSp = 14,
color = whiteColor
),
color = blackLightColor,
)
)
),
readingSwipeActionStyle = CourierStyles.Inbox.ReadingSwipeActionStyle(
read = CourierStyles.Inbox.SwipeActionStyle(
color = primaryColor
),
unread = CourierStyles.Inbox.SwipeActionStyle(
color = primaryLightColor
)
),
archivingSwipeActionStyle = CourierStyles.Inbox.ArchivingSwipeActionStyle(
CourierStyles.Inbox.SwipeActionStyle(
color = primaryColor
)
),
unreadIndicatorStyle = CourierStyles.Inbox.UnreadIndicatorStyle(
indicator = CourierStyles.Inbox.UnreadIndicator.DOT,
color = primaryColor
),
titleStyle = CourierStyles.Inbox.TextStyle(
unread = CourierStyles.Font(
typeface = font,
color = blackColor,
sizeInSp = 18
),
read = CourierStyles.Font(
typeface = font,
color = blackColor,
sizeInSp = 18
),
),
bodyStyle = CourierStyles.Inbox.TextStyle(
unread = CourierStyles.Font(
typeface = font,
color = blackLightColor,
sizeInSp = 16
),
read = CourierStyles.Font(
typeface = font,
color = blackLightColor,
sizeInSp = 16
)
),
timeStyle = CourierStyles.Inbox.TextStyle(
unread = CourierStyles.Font(
typeface = font,
color = blackColor,
sizeInSp = 14
),
read = CourierStyles.Font(
typeface = font,
color = blackColor,
sizeInSp = 14
)
),
infoViewStyle = CourierStyles.InfoViewStyle(
font = CourierStyles.Font(
typeface = font,
color = blackColor,
sizeInSp = 18
),
button = CourierStyles.Button(
font = CourierStyles.Font(
typeface = font,
color = whiteColor,
sizeInSp = 16
),
backgroundColor = primaryColor,
cornerRadiusInDp = 100
)
),
buttonStyle = CourierStyles.Inbox.ButtonStyle(
unread = CourierStyles.Button(
font = CourierStyles.Font(
typeface = font,
color = whiteColor,
sizeInSp = 16
),
backgroundColor = primaryColor,
cornerRadiusInDp = 100
),
read = CourierStyles.Button(
font = CourierStyles.Font(
typeface = font,
color = whiteColor,
sizeInSp = 16
),
backgroundColor = primaryColor,
cornerRadiusInDp = 100
)
),
dividerItemDecoration = DividerItemDecoration(context, DividerItemDecoration.VERTICAL)
)
}
CourierInbox(
modifier = Modifier.padding(innerPadding),
canSwipePages = true,
lightTheme = getTheme(context),
darkTheme = getTheme(context),
..
)
val inbox: CourierInbox = view.findViewById(R.id.courierInbox)
inbox.canSwipePages = true
inbox.lightTheme = getTheme(context)
inbox.darkTheme = getTheme(context)
inbox..
You can control your branding from the Courier Studio
.
Supported Brand Styles | Support |
---|---|
Primary Color |
✅ |
Show/Hide Courier Footer |
✅ |
👋 Branding APIs
can be found here
The raw data you can use to build any UI you'd like.
class CustomInboxFragment: Fragment(R.layout.fragment_custom_inbox) {
..
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
..
// Setup the listener
inboxListener = Courier.shared.addInboxListener(
onLoading = { isRefresh ->
// Called when listener is registered, refreshing or restarting
},
onError = { e ->
// Called on error or sign out
},
onUnreadCountChanged = { count ->
// Will return 0 when a user is signed out
},
onFeedChanged = { messageSet ->
// Called when the feed initially loads or is restarted from scratch
},
onArchiveChanged = { messageSet ->
// Called when the feed initially loads or is restarted from scratch
},
onPageAdded = { feed, messageSet ->
// Called when pagination happens
},
onMessageChanged = { feed, index, message ->
// Called when a message is change (i.e. read / unread)
},
onMessageAdded = { feed, index, message ->
// Called when a message is added (i.e. new message received in realtime)
},
onMessageRemoved = { feed, index, message ->
// Called when a message is removed (i.e. message is archived)
}
)
}
override fun onDestroyView() {
super.onDestroyView()
inboxListener.remove()
}
}
Link | Style |
---|---|
Default Example
|
Default
|
Styled Example
|
Styled
|
Custom Example
|
Custom
|
// Listen to all inbox events
// Only one "pipe" of data is created behind the scenes for network / performance reasons
val inboxListener = Courier.shared.addInboxListener(
onLoading = { isRefresh ->
// Called when listener is registered, refreshing or restarting
},
onError = { e ->
// Called on error or sign out
},
onUnreadCountChanged = { count ->
// Will return 0 when a user is signed out
},
onFeedChanged = { messageSet ->
// Called when the feed initially loads or is restarted from scratch
},
onArchiveChanged = { messageSet ->
// Called when the feed initially loads or is restarted from scratch
},
onPageAdded = { feed, messageSet ->
// Called when pagination happens
},
onMessageChanged = { feed, index, message ->
// Called when a message is change (i.e. read / unread)
},
onMessageAdded = { feed, index, message ->
// Called when a message is added (i.e. new message received in realtime)
},
onMessageRemoved = { feed, index, message ->
// Called when a message is removed (i.e. message is archived)
}
)
// Stop the current listener
inboxListener.remove()
// Remove all listeners
// This will also remove the listener of the prebuilt UI
Courier.shared.removeAllInboxListeners()
// The amount of inbox messages to fetch at a time
// Will affect prebuilt UI
Courier.shared.inboxPaginationLimit = 123
// The available messages the inbox has
val inboxMessages = Courier.shared.inboxMessages
lifecycle.coroutineScope.launch {
// Fetches the next page of messages
Courier.shared.fetchNextPageOfMessages()
// Reloads the inbox
// Commonly used with pull to refresh
Courier.shared.refreshInbox()
// Reads all the messages
// Writes the update instantly and performs request in background
try await Courier.shared.readAllInboxMessages()
}
// Inbox Message functions
lifecycle.coroutineScope.launch {
val messageId = "asdf"
Courier.shared.openMessage(messageId = messageId)
Courier.shared.clickMessage(messageId = messageId)
Courier.shared.readMessage(messageId = messageId)
Courier.shared.unreadMessage(messageId = messageId)
Courier.shared.archiveMessage(messageId = messageId)
}
// Extensions
let message = InboxMessage(..)
message.markAsOpened()
message.markAsRead()
message.markAsUnread()
message.markAsClicked()
message.markAsArchived()
// Clicking an action
message.actions?.first?.markAsClicked()
👋 Inbox APIs
can be found here