UI
package com.yunho.feature.test.view
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.hilt.navigation.compose.hiltViewModel
import com.yunho.feature.navigation.LocalNavController
import com.yunho.feature.test.intent.TestEvent
import com.yunho.feature.test.intent.TestSideEffect
import com.yunho.feature.test.intent.TestState
import com.yunho.feature.test.view.component.TestDialog
import com.yunho.feature.test.view.component.TestDialogState.Companion.rememberTestDialogState
import com.yunho.feature.test.view.model.TestViewModel
import org.orbitmvi.orbit.compose.collectAsState
import org.orbitmvi.orbit.compose.collectSideEffect
@Composable
fun Test(
modifier: Modifier = Modifier,
viewModel: TestViewModel = hiltViewModel()
) {
val state by viewModel.collectAsState()
val dialogState = rememberTestDialogState()
val navController = LocalNavController.current
viewModel.collectSideEffect { effect ->
when (effect) {
TestSideEffect.Navigate.Back -> navController.popBackStack()
TestSideEffect.Hide.Dialog -> dialogState.hide()
is TestSideEffect.Show.Dialog -> dialogState.show(effect.content)
}
}
TestDialog(
dialogState = dialogState,
onDismissRequest = dialogState::hide,
onEvent = viewModel::onEvent
)
Test(
state = state,
onEvent = viewModel::onEvent,
modifier = modifier
)
}
@Composable
fun Test(
state: TestState,
onEvent: (TestEvent) -> Unit,
modifier: Modifier = Modifier
) {
Column(modifier = modifier) {
Button({
onEvent(TestEvent.Click.Back)
}) {
Text("Test ${state.data}")
}
}
}
viewModel
package com.yunho.feature.test.view.model
import com.yunho.feature.base.BaseViewModel
import com.yunho.feature.test.intent.TestEvent
import com.yunho.feature.test.intent.TestSideEffect
import com.yunho.feature.test.intent.TestState
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
@HiltViewModel
class TestViewModel @Inject constructor(
// TODO: 의존성 주입 파라미터
) : BaseViewModel<TestState, TestSideEffect>(initialState = TestState()) {
fun onEvent(event: TestEvent) {
when (event) {
is TestEvent.Click -> onClick(event)
}
}
private fun onClick(event: TestEvent.Click) {
intent {
when (event) {
TestEvent.Click.Back -> postSideEffect(TestSideEffect.Navigate.Back)
}
}
}
}
dialog
package com.yunho.feature.test.view.component
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import com.yunho.feature.test.intent.TestEvent
@Composable
fun TestDialog(
dialogState: TestDialogState,
onDismissRequest: () -> Unit,
onEvent: (TestEvent) -> Unit
) {
when {
dialogState.content != null -> Dialog(
onDismissRequest = onDismissRequest,
properties = DialogProperties()
) {
when (val content = dialogState.content) {
is TestDialogState.Content.Default -> Default(content = content, onEvent = onEvent)
null -> Unit
}
}
else -> Unit
}
}
@Composable
private fun Default(
content: TestDialogState.Content.Default,
onEvent: (TestEvent) -> Unit,
modifier: Modifier = Modifier
) {
Surface(
modifier = modifier,
shape = RoundedCornerShape(20.dp),
color = Color.White
) {
Column(
modifier = Modifier
.padding(horizontal = 20.dp)
.padding(top = 24.dp, bottom = 20.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
}
}
}
dialogState
package com.yunho.feature.test.view.component
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
class TestDialogState {
var content by mutableStateOf<Content?>(null)
fun hide() {
content = null
}
fun show(content: Content) {
this.content = content
}
sealed interface Content {
data object Default : Content
}
companion object {
@Composable
fun rememberTestDialogState() = remember { TestDialogState() }
}
}
State
package com.yunho.feature.test.intent
data class TestState(
val data: String
) {
constructor() : this(data = "")
}
SideEffect
package com.yunho.feature.test.intent
import com.yunho.feature.test.view.component.TestDialogState
sealed interface TestSideEffect {
sealed interface Navigate : TestSideEffect {
data object Back : Navigate
}
sealed interface Show : TestSideEffect {
data class Dialog(val content: TestDialogState.Content) : Show
}
sealed interface Hide : TestSideEffect {
data object Dialog : Hide
}
}
Event
package com.yunho.feature.test.intent
sealed interface TestEvent {
sealed interface Click : TestEvent {
data object Back : Click
}
}