Skip to content

Instantly share code, notes, and snippets.

@okmanideep
Last active October 2, 2024 04:19

Revisions

  1. okmanideep revised this gist Jun 8, 2022. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion SampleUsage.kt
    Original file line number Diff line number Diff line change
    @@ -23,7 +23,7 @@ class WatchlistViewModel(): ViewModel() {

    updateState(response)
    if (shouldScrollToStart) {
    _eventQueue.push(LoginSuccess)
    _eventQueue.push(ScrollToStart)
    }
    }
    }
  2. okmanideep revised this gist Jun 8, 2022. 1 changed file with 16 additions and 19 deletions.
    35 changes: 16 additions & 19 deletions SampleUsage.kt
    Original file line number Diff line number Diff line change
    @@ -1,35 +1,32 @@
    // LoginScreen.kt
    // Watchlist.kt
    @Composable
    fun LoginScreen(viewModel: LoginViewModel) {
    fun Watchlist(viewModel: Watchlist) {
    // UI...

    EventHandler(viewModel.eventQueue) { event ->
    when (event) {
    is LoginSuccess -> {
    // navigate back
    }
    is LoginFailed -> snackbarHostState.showSnackbar(event.message)
    is ScrollToStart -> scrollState.animateScrollToIndex(0)
    }
    }
    }


    //LoginViewModel.kt
    class LoginViewModel(): ViewModel() {
    private val _eventQueue = mutableEventQueue<LoginEvent>()
    val eventQueue: EventQueue<LoginEvent> = _eventQueue
    //WatchlistViewModel.kt
    class WatchlistViewModel(): ViewModel() {
    private val _eventQueue = mutableEventQueue<WatchlistEvent>()
    val eventQueue: EventQueue<WatchlistEvent> = _eventQueue

    //...

    private fun onLoginFailed(message: String) {
    _eventQueue.push(LoginFailed(message))
    }

    private fun onLoginSuccess() {
    _eventQueue.push(LoginSuccess)
    private fun onWatchlistResponse(response) {
    val shouldScrollToStart = areNewItemsAdded(response)

    updateState(response)
    if (shouldScrollToStart) {
    _eventQueue.push(LoginSuccess)
    }
    }
    }

    sealed interface LoginEvent
    data class LoginFailed(val message: String): LoginEvent
    object LoginSuccess: LoginEvent
    sealed interface WatchlistEvent
    object ScrollToStart: WatchlistEvent
  3. okmanideep created this gist Apr 19, 2022.
    47 changes: 47 additions & 0 deletions EventQueue.kt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,47 @@
    import androidx.compose.runtime.*
    import kotlinx.coroutines.CoroutineScope

    @Stable
    internal class Event<T>(val value: T)

    class MutableEventQueue<T>
    internal constructor(): EventQueue<T>() {
    private val events = mutableListOf<Event<T>>()
    private val nextEventAsState = mutableStateOf<Event<T>?>(null)

    fun push(e: T) {
    events.add(Event(e))
    onEventsChanged()
    }

    override fun next(): State<Event<T>?> {
    return nextEventAsState
    }

    override fun onHandled(event: Event<T>) {
    events.remove(event)
    onEventsChanged()
    }

    private fun onEventsChanged() {
    nextEventAsState.value = events.firstOrNull()
    }
    }

    fun <T> mutableEventQueue() = MutableEventQueue<T>()

    abstract class EventQueue<T> {
    internal abstract fun next(): State<Event<T>?>
    internal abstract fun onHandled(event: Event<T>)
    }

    @Composable
    fun <T> EventHandler(eventQueue: EventQueue<T>, handler: suspend CoroutineScope.(T) -> Unit) {
    val e = eventQueue.next().value
    LaunchedEffect(e) {
    if (e != null) {
    handler(e.value)
    eventQueue.onHandled(e)
    }
    }
    }
    35 changes: 35 additions & 0 deletions SampleUsage.kt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,35 @@
    // LoginScreen.kt
    @Composable
    fun LoginScreen(viewModel: LoginViewModel) {
    // UI...

    EventHandler(viewModel.eventQueue) { event ->
    when (event) {
    is LoginSuccess -> {
    // navigate back
    }
    is LoginFailed -> snackbarHostState.showSnackbar(event.message)
    }
    }
    }


    //LoginViewModel.kt
    class LoginViewModel(): ViewModel() {
    private val _eventQueue = mutableEventQueue<LoginEvent>()
    val eventQueue: EventQueue<LoginEvent> = _eventQueue

    //...

    private fun onLoginFailed(message: String) {
    _eventQueue.push(LoginFailed(message))
    }

    private fun onLoginSuccess() {
    _eventQueue.push(LoginSuccess)
    }
    }

    sealed interface LoginEvent
    data class LoginFailed(val message: String): LoginEvent
    object LoginSuccess: LoginEvent