Events
the kindly sdk provides a unified event system that allows you to subscribe to all sdk events and state changes in real time this matches the web api pattern and provides a comprehensive way to monitor sdk behavior using kotlin flows event types the sdk emits the following event types kindly\ load settings and configuration loaded kindly\ message new messages (sent/received) kindly\ buttonclick button interactions kindly\ ui ui actions (open, close, end chat, etc ) kindly\ globalicon global icon events (defined but not currently implemented in mobile sdks) kindly\ state state changes (connection, display status) basic usage subscribe to all events import kotlinx coroutines coroutinescope import kotlinx coroutines dispatchers import kotlinx coroutines launch import no kindly chatsdk chat kindlysdk import no kindly chatsdk chat models kindlyeventdetail class myeventhandler { private val scope = coroutinescope(dispatchers main) fun setupeventlistening() { scope launch { kindlysdk events collect { event > println("event ${event type value}") println("timestamp ${event timestamp}") when (val detail = event detail) { is kindlyeventdetail load > { println("settings loaded ${detail settings name}") } is kindlyeventdetail message > { println("new message ${detail newmessage text ? "no text"}") } is kindlyeventdetail buttonclick > { println("button clicked ${detail button label}") } is kindlyeventdetail ui > { println("ui action ${detail action type value}") } is kindlyeventdetail state > { println("state changed connected ${detail state isconnected}") } is kindlyeventdetail globalicon > { // note globalicon events are not currently implemented in mobile sdks } } } } } } subscribe to state changes only scope launch { kindlysdk state collect { state > println("chat displayed ${state ischatdisplayed}") println("sdk started ${state isstarted}") println("socket connected ${state issocketconnected}") println("fully connected ${state isconnected}") println("connection state ${state connectionstate}") } } event details load event emitted when sdk settings are loaded from the server import kotlinx coroutines flow\ filter import no kindly chatsdk chat models kindlyeventtype scope launch { kindlysdk events filter { it type == kindlyeventtype load } collect { event > val detail = event detail as? kindlyeventdetail load detail? let { println("bot ${it settings name} (id ${it settings id})") println("languages ${it settings languages map { lang > lang code }}") val hascustombackground = it settings style background != null println("theme ${if (hascustombackground) "custom" else "default"}") } } } message event emitted for both incoming and outgoing messages scope launch { kindlysdk events filter { it type == kindlyeventtype message } collect { event > val detail = event detail as? kindlyeventdetail message detail? let { println("message from ${it newmessage from} ${it newmessage text ? ""}") println("chat has ${it chatlog size} total messages") } } } button click event emitted when users interact with chat buttons scope launch { kindlysdk events filter { it type == kindlyeventtype button click } collect { event > val detail = event detail as? kindlyeventdetail buttonclick detail? let { println("button ${it button label}") println("type ${it buttontype}") println("value ${it button value ? ""}") } } } ui events emitted for user interface actions like opening/closing chat, language changes, etc import no kindly chatsdk chat models kindlyuiactiontype scope launch { kindlysdk events filter { it type == kindlyeventtype ui } collect { event > val detail = event detail as? kindlyeventdetail ui detail? let { uidetail > when (uidetail action type) { kindlyuiactiontype open chat bubble > { println("chat opened") } kindlyuiactiontype close chat bubble > { println("chat closed") } kindlyuiactiontype end chat > { println("chat ended") } kindlyuiactiontype restart chat > { println("chat restarted") } kindlyuiactiontype change language > { println("language changed to ${uidetail action languagecode ? ""}") } kindlyuiactiontype download chat > { println("chat downloaded") } kindlyuiactiontype delete chat > { println("chat deleted") } kindlyuiactiontype show feedback > { println("feedback form shown") } kindlyuiactiontype submit feedback > { println("feedback submitted") } kindlyuiactiontype dismiss feedback > { println("feedback dismissed") } } } } } state events emitted when sdk connection or display state changes scope launch { kindlysdk state collect { state > when { state isconnected > { println("â
sdk is fully connected and ready!") } state isstarted && !state issocketconnected > { println("â ī¸ sdk started but socket disconnected") } !state isstarted > { println("âŗ sdk not started yet") } } } } advanced usage track chat display changes import kotlinx coroutines flow\ distinctuntilchanged import kotlinx coroutines flow\ map scope launch { kindlysdk state map { it ischatdisplayed } distinctuntilchanged() // only emit when value changes collect { isdisplayed > if (isdisplayed) { println("đą chat interface is now visible") } else { println("đ chat interface is now hidden") } } } monitor connection health scope launch { kindlysdk state map { state > triple(state isstarted, state issocketconnected, state isconnected) } distinctuntilchanged() collect { (isstarted, issocketconnected, isconnected) > when { isstarted && issocketconnected && isconnected > { println("đĸ fully connected") } isstarted && !issocketconnected > { println("đĄ started but disconnected") } !isstarted > { println("đ´ not started") } else > { println("đĄ partial connection") } } } } filter multiple event types scope launch { kindlysdk events filter { event > listof( kindlyeventtype message, kindlyeventtype button click, kindlyeventtype ui ) contains(event type) } collect { event > println("user interaction event ${event type value}") } } combine events with other flows import kotlinx coroutines flow\ combine scope launch { combine( kindlysdk state, kindlysdk events filter { it type == kindlyeventtype message } ) { state, messageevent > pair(state, messageevent) } collect { (state, messageevent) > if (state isconnected) { println("received message while connected $messageevent") } } } lifecycle management in activities/fragments class chatactivity appcompatactivity() { private val scope = coroutinescope(dispatchers main + supervisorjob()) override fun oncreate(savedinstancestate bundle?) { super oncreate(savedinstancestate) // setup event listening scope launch { kindlysdk events collect { event > // handle events } } } override fun ondestroy() { super ondestroy() scope cancel() // cancel all coroutines } } in viewmodels class chatviewmodel viewmodel() { init { // subscribe to events in viewmodel scope viewmodelscope launch { kindlysdk events collect { event > // handle events } } } } event data models kindlyevent data class kindlyevent( val type kindlyeventtype, val timestamp long, val detail kindlyeventdetail ) kindlyeventstate data class kindlyeventstate( val ischatdisplayed boolean, val isstarted boolean, val issocketconnected boolean, val isconnected boolean, val connectionstate string ) event types enum enum class kindlyeventtype(val value string) { load("kindly\ load"), message("kindly\ message"), button click("kindly\ buttonclick"), ui("kindly\ ui"), state("kindly\ state") // note global icon is defined but not implemented in mobile sdks } for more detailed information about event data structures, see the sdk source code documentation best practices use appropriate scope use viewmodelscope in viewmodels, activity/fragment lifecycle scope in ui components handle cancellation always cancel coroutines when they're no longer needed use flow operators leverage filter , map , distinctuntilchanged to process events efficiently error handling wrap event collection in try catch blocks for production apps performance use conflate() or sample() for high frequency events if needed error handling scope launch { try { kindlysdk events collect { event > // handle events } } catch (e exception) { log e("eventhandler", "error collecting events", e) } }