Created
March 13, 2024 19:34
-
-
Save sajjadyousefnia/878f3c4dec0302650b7e4abd23e5a669 to your computer and use it in GitHub Desktop.
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 characters
class MainViewModel : BaseViewModel<MainContract.Event, MainContract.State, MainContract.Effect>() { | |
/** | |
* Create initial State of Views | |
*/ | |
override fun createInitialState(): MainContract.State { | |
val currentTime = Calendar.getInstance().getTime() | |
return MainContract.State("sajjad-agha-gole-bagha + $currentTime") | |
} | |
override fun handleEvent(event: MainContract.Event) { | |
viewModelScope.launch { | |
setState { | |
copy(variable = (Calendar.getInstance().getTime().toString())) | |
} | |
} | |
} | |
} | |
class MainContract { | |
// Events that user performed | |
sealed class Event : UiEvent { | |
data object OnButtonClicked : Event() | |
} | |
// Ui View States | |
data class State( | |
val variable: String | |
) : UiState | |
// View State that related to Random Number | |
sealed class GettingValue { | |
data class ReceiveValue(val value: String) : GettingValue() | |
} | |
// Side effects | |
sealed class Effect : UiEffect { | |
data object ShowSnack : Effect() | |
} | |
} | |
public abstract class BaseViewModel<Event : UiEvent, State : UiState, Effect : UiEffect> : | |
ViewModel() { | |
// Create Initial State of View | |
private val initialState: State by lazy { createInitialState() } | |
abstract fun createInitialState(): State | |
// Get Current State | |
val currentState: State | |
get() = uiState.value | |
private val _uiState: MutableStateFlow<State> = MutableStateFlow(initialState) | |
val uiState = _uiState.asStateFlow() | |
private val _event: MutableSharedFlow<Event> = MutableSharedFlow() | |
val event = _event.asSharedFlow() | |
private val _effect: Channel<Effect> = Channel() | |
val effect = _effect.receiveAsFlow() | |
/** | |
* Set new Event | |
*/ | |
protected fun setEvent(event: Event) { | |
val newEvent = event | |
viewModelScope.launch { _event.emit(newEvent) } | |
} | |
/** | |
* Set new Ui State | |
*/ | |
protected fun setState(reduce: State.() -> State) { | |
val newState = currentState.reduce() | |
_uiState.value = newState | |
} | |
/** | |
* Set new Effect | |
*/ | |
protected fun setEffect(builder: () -> Effect) { | |
val effectValue = builder() | |
viewModelScope.launch { _effect.send(effectValue) } | |
} | |
init { | |
subscribeEvents() | |
} | |
/** | |
* Start listening to Event | |
*/ | |
private fun subscribeEvents() { | |
viewModelScope.launch { | |
event.collect { | |
handleEvent(it) | |
} | |
} | |
} | |
/** | |
* Handle each event | |
*/ | |
abstract fun handleEvent(event: Event) | |
} | |
interface UiState | |
interface UiEvent | |
interface UiEffect | |
class MainActivity : ComponentActivity() { | |
override fun onCreate(savedInstanceState: Bundle?) { | |
super.onCreate(savedInstanceState) | |
setContent { | |
// A surface container using the 'background' color from the theme | |
MaterialTheme { | |
Surface( | |
modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background | |
) { | |
CallbackCatcher(this) | |
} | |
} | |
} | |
} | |
} | |
private val viewModel = MainViewModel() | |
@Composable | |
fun CallbackCatcher(context: Context) { | |
Column { | |
Button(modifier = Modifier.requiredSize(200.dp, 150.dp), onClick = { | |
viewModel.handleEvent(MainContract.Event.OnButtonClicked) | |
}) { | |
Text("sajjad agha gole bagha") | |
} | |
} | |
MyTextField() | |
} | |
@Composable | |
fun MyTextField() { | |
val textState = viewModel.uiState.collectAsState().value.variable | |
val viewModel = MainViewModel() | |
Text( | |
text = textState, | |
) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment