Skip to content

Instantly share code, notes, and snippets.

@hlayan
Last active March 16, 2024 09:16
Show Gist options
  • Save hlayan/7025e63e71306d97f58343da68b77678 to your computer and use it in GitHub Desktop.
Save hlayan/7025e63e71306d97f58343da68b77678 to your computer and use it in GitHub Desktop.
Single Event Solution for Kotlin Flow and Compose
class Event<out T>(private val _value: T?) {
private val used = AtomicBoolean(false)
val value: T? get() = if (used.compareAndSet(false, true)) _value else null
}
val EmptyEvent get() = Event(null)
typealias FlowEvent<T> = StateFlow<Event<T>>
typealias MutableFlowEvent<T> = MutableStateFlow<Event<T>>
fun <T : Any> mutableFlowEvent(): MutableFlowEvent<T> = MutableStateFlow(EmptyEvent)
fun <T : Any> MutableFlowEvent<T>.asFlowEvent(): FlowEvent<T> = asStateFlow()
fun <T : Any> MutableFlowEvent<T>.sendEvent(value: T) {
this.value = Event(value)
}
suspend fun <T : Any> FlowEvent<T>.collectEvent(action: suspend (value: T) -> Unit) {
collectLatest { value.value?.let { action(it) } }
}
@Composable
fun <T> EventEffect(
event: Event<T>,
block: suspend CoroutineScope.(T) -> Unit
) {
LaunchedEffect(event) {
event.value?.let { block(it) }
}
}
@Composable
fun EventScreen(
modifier: Modifier = Modifier,
viewModel: EventViewModel = hiltViewModel()
) {
val snackbarHostState = remember { SnackbarHostState() }
val snackBarEvent by viewModel.snackBarEvent.collectAsStateWithLifecycle()
EventEffect(event = snackBarEvent) { message ->
snackbarHostState.showSnackbar(message)
}
}
@HiltViewModel
class EventViewModel @Inject constructor(
savedStateHandle: SavedStateHandle,
) : ViewModel() {
private val _snackBarEvent = mutableFlowEvent<String>()
val snackBarEvent = _snackBarEvent.asFlowEvent()
fun showMessage() {
_snackBarEvent.sendEvent("Cannot refresh data!")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment