Marker Interfaces
PulseDesktop uses marker interfaces to enforce type safety at the generic level. None of them has members; they exist solely to constrain type parameters.
PulseState
interface PulseStateMarks a class as the UI state managed by a PulseViewModel. Implement with a data class so copy() is available for immutable updates.
data class CounterState(
val count: Int = 0,
val isLoading: Boolean = false,
) : PulseStatePulseAction
interface PulseActionMarks a class as a user intent dispatched to a PulseViewModel. Implement with a sealed class so all possible actions can be enumerated exhaustively.
sealed class CounterAction : PulseAction {
data object Increment : CounterAction()
data object Decrement : CounterAction()
data class SetValue(val value: Int) : CounterAction()
}PulseEvent
interface PulseEventMarks a class as a one-time side effect emitted from a PulseViewModel to the UI. Implement with a sealed class.
sealed class CounterEvent : PulseEvent {
data class ShowMessage(val message: String) : CounterEvent()
data object NavigateBack : CounterEvent()
}PulseBroadcast
interface PulseBroadcastMarks a class as a broadcast message. PulseContainer delivers it to all registered PulseViewModel instances. Implement with a sealed class.
sealed class AppBroadcast : PulseBroadcast {
data object UserLoggedOut : AppBroadcast()
data class ThemeChanged(val isDark: Boolean) : AppBroadcast()
}PulseUnicast
interface PulseUnicastMarks a class as a unicast message. A child PulseViewModel emits it to its parent PulseContainer. Implement with a sealed class.
sealed class AppUnicast : PulseUnicast {
data object SaveRequested : AppUnicast()
data class ItemSelected(val id: String) : AppUnicast()
}