Last active
October 11, 2024 04:39
-
-
Save sergejsha/ad70fdb3afcaa7a38fe29effb49d0bf6 to your computer and use it in GitHub Desktop.
Revisions
-
sergejsha revised this gist
Oct 10, 2024 . 1 changed file with 44 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,44 @@ // to be put under src/commonTest/kotlin import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.runComposeUiTest import de.halfbit.seventysix.DefaultAppViewModel import de.halfbit.seventysix.State import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlin.test.Test import kotlin.test.assertEquals @OptIn(ExperimentalCoroutinesApi::class) class AppViewModelTest { @OptIn(ExperimentalTestApi::class) @Test fun test_Fancy_VM() = runComposeUiTest { mainClock.autoAdvance = false val model = DefaultAppViewModel() lateinit var state: State setContent { state = model.state() } // initial state assertEquals(false, state.loading) assertEquals("", state.rssResult) // post event state.onLoadRss() waitForIdle() // before data is loaded assertEquals(true, state.loading) assertEquals("", state.rssResult) // let rss data to arrive mainClock.advanceTimeBy(3_000) // after data is loaded assertEquals(false, state.loading) assertEquals("RSS data is here", state.rssResult) } } -
sergejsha created this gist
Oct 9, 2024 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,112 @@ package de.halfbit.seventysix import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.material.Button import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.launch import org.jetbrains.compose.ui.tooling.preview.Preview import kotlin.time.Duration.Companion.seconds @Composable fun App(viewModel: AppViewModel) { MaterialTheme { Column( modifier = Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally ) { val state = viewModel.state() Button(onClick = state.onLoadRss) { Text("Load RSS") } if (state.loading) Text("Loading...") if (state.rssResult.isNotEmpty()) Text(state.rssResult) } } } @Preview @Composable fun PreviewApp() { App( viewModel = object : AppViewModel { @Composable override fun state(): State = State( loading = true, rssResult = "", onLoadRss = {}, ) } ) } data class State( val loading: Boolean, val rssResult: String, val onLoadRss: () -> Unit, ) sealed interface Event { data object LoadRss : Event } interface AppViewModel { @Composable fun state(): State } class DefaultAppViewModel( private val fetchRss: suspend () -> String = { delay(3.seconds); "RSS data is here" }, ) : AppViewModel { @Composable override fun state(): State { var loading by remember { mutableStateOf(false) } var rssResult by remember { mutableStateOf("") } val onLoadRes = { post(Event.LoadRss) } onEvent { event -> when (event) { Event.LoadRss -> { if (loading) return@onEvent loading = true rssResult = "" launch { rssResult = fetchRss() loading = false } } } } return State( loading = loading, rssResult = rssResult, onLoadRss = onLoadRes, ) } private val events = MutableSharedFlow<Event>(extraBufferCapacity = 20) @Composable private inline fun onEvent(crossinline block: CoroutineScope.(event: Event) -> Unit) { LaunchedEffect(Unit) { events.collect { event -> block(event) } } } private fun post(event: Event) { if (!events.tryEmit(event)) { error("Buffer overflow") } } } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,23 @@ package de.halfbit.seventysix import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.runtime.Composable import androidx.compose.ui.tooling.preview.Preview class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { App(DefaultAppViewModel()) } } } @Preview @Composable fun AppAndroidPreview() { App(DefaultAppViewModel()) }