From 1d6d10e8bdf31881448dd143a46e421ad00e76f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luka=CC=81s=CC=8C=20Krystek?= Date: Fri, 16 May 2025 10:43:53 +0200 Subject: [PATCH] feat: Add basic ViewModel with name generation This commit introduces a `MainViewModel` that handles the logic for generating random names. Key changes: - Added `MainViewModel` to manage UI state and business logic. - Implemented `onClick` function in `MainViewModel` to increment a counter and generate a new random name using a `Repository`. - The `MainActivity` now observes the state from `MainViewModel` and displays the generated names in a `LazyColumn`. - Added a `Button` to trigger the name generation. - Introduced a `Repository` class responsible for generating random strings. - The UI now displays a list of generated names, with a horizontal divider between them. - The button text dynamically updates to show the length of the next name to be generated. --- .../cz/eman/android/interview/MainActivity.kt | 51 ++++++++++++++++--- .../eman/android/interview/MainViewModel.kt | 25 +++++++++ .../interview/repository/Repository.kt | 13 +++++ 3 files changed, 83 insertions(+), 6 deletions(-) create mode 100644 app/src/main/java/cz/eman/android/interview/MainViewModel.kt create mode 100644 app/src/main/java/cz/eman/android/interview/repository/Repository.kt diff --git a/app/src/main/java/cz/eman/android/interview/MainActivity.kt b/app/src/main/java/cz/eman/android/interview/MainActivity.kt index 0306c4d..bde1ab5 100644 --- a/app/src/main/java/cz/eman/android/interview/MainActivity.kt +++ b/app/src/main/java/cz/eman/android/interview/MainActivity.kt @@ -3,19 +3,27 @@ package cz.eman.android.interview import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.windowInsetsPadding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material3.Button +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Surface import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.style.TextAlign import androidx.core.view.WindowCompat +import cz.eman.android.interview.repository.Repository class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { @@ -37,12 +45,7 @@ class MainActivity : ComponentActivity() { .fillMaxSize() .padding(paddingValues) ) { - Text( - modifier = Modifier.fillMaxSize(), - textAlign = TextAlign.Center, - color = Color.Blue, - text = "Hello eMan candidate", - ) + content(MainViewModel(Repository())) // DI will be done in next MR } } ) @@ -50,3 +53,39 @@ class MainActivity : ComponentActivity() { } } } + +@Composable +private fun content( + viewModel: MainViewModel, +) { + Column { + Text( + modifier = Modifier.fillMaxWidth(), + textAlign = TextAlign.Center, + color = Color.Blue, + text = "Hello eMan candidate", + ) + + val data = viewModel.state.collectAsState() + + Button( + onClick = { + viewModel.onClick() + } + ) { + Text(text = "Generate names with length ${data.value.number+1}") + } + + Column { + data.value.names.forEachIndexed { index, name -> + Text( + text = name + ) + + if (index < data.value.names.lastIndex) { + HorizontalDivider() + } + } + } + } +} diff --git a/app/src/main/java/cz/eman/android/interview/MainViewModel.kt b/app/src/main/java/cz/eman/android/interview/MainViewModel.kt new file mode 100644 index 0000000..fd41787 --- /dev/null +++ b/app/src/main/java/cz/eman/android/interview/MainViewModel.kt @@ -0,0 +1,25 @@ +package cz.eman.android.interview + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import cz.eman.android.interview.repository.Repository +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.launch + +data class MainState( + val number: Int = 0, + val names: MutableList = mutableListOf() +) + +class MainViewModel( + private val repository: Repository +): ViewModel() { + val state = MutableStateFlow(MainState()) + + fun onClick() { + viewModelScope.launch { + state.value = state.value.copy(number = state.value.number + 1) + state.value.names.apply { add("Name ${repository.getRandomName(state.value.number)}") } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/cz/eman/android/interview/repository/Repository.kt b/app/src/main/java/cz/eman/android/interview/repository/Repository.kt new file mode 100644 index 0000000..bb75063 --- /dev/null +++ b/app/src/main/java/cz/eman/android/interview/repository/Repository.kt @@ -0,0 +1,13 @@ +package cz.eman.android.interview.repository + +class Repository { + private fun getRandomString(length: Int) : String { + val allowedChars = ('A'..'Z') + ('a'..'z') + ('0'..'9') + return (1..length) + .map { allowedChars.random() } + .joinToString("") + } + + fun getRandomName(length: Int) = getRandomString( + length) +} \ No newline at end of file