diff --git a/app/src/androidTest/java/com/complycube/testandroidapp/ItemListScreenTest.kt b/app/src/androidTest/java/com/complycube/testandroidapp/ItemListScreenTest.kt new file mode 100644 index 0000000..264298a --- /dev/null +++ b/app/src/androidTest/java/com/complycube/testandroidapp/ItemListScreenTest.kt @@ -0,0 +1,73 @@ +package com.complycube.testandroidapp + +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.onNodeWithText +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.complycube.testandroidapp.ui.theme.TestAndroidAppTheme +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class ItemListScreenTest { + + @get:Rule + val composeTestRule = createComposeRule() + + private val testItems = List(5) { index -> + Item( + id = index + 1, + title = "Item ${index + 1}", + subtitle = "Description for item ${index + 1}" + ) + } + + @Test + fun itemList_isDisplayed() { + composeTestRule.setContent { + TestAndroidAppTheme { + ItemList(items = testItems) + } + } + + composeTestRule.onNodeWithTag("item_list").assertIsDisplayed() + } + + @Test + fun itemList_showsTitles() { + composeTestRule.setContent { + TestAndroidAppTheme { + ItemList(items = testItems) + } + } + + composeTestRule.onNodeWithText("Item 1").assertIsDisplayed() + composeTestRule.onNodeWithText("Item 3").assertIsDisplayed() + composeTestRule.onNodeWithText("Item 5").assertIsDisplayed() + } + + @Test + fun itemList_showsSubtitles() { + composeTestRule.setContent { + TestAndroidAppTheme { + ItemList(items = testItems) + } + } + + composeTestRule.onNodeWithText("Description for item 1").assertIsDisplayed() + composeTestRule.onNodeWithText("Description for item 5").assertIsDisplayed() + } + + @Test + fun itemList_withEmptyList_showsNoItems() { + composeTestRule.setContent { + TestAndroidAppTheme { + ItemList(items = emptyList()) + } + } + + composeTestRule.onNodeWithText("Item 1").assertDoesNotExist() + } +} diff --git a/app/src/main/java/com/complycube/testandroidapp/Item.kt b/app/src/main/java/com/complycube/testandroidapp/Item.kt new file mode 100644 index 0000000..44346c4 --- /dev/null +++ b/app/src/main/java/com/complycube/testandroidapp/Item.kt @@ -0,0 +1,3 @@ +package com.complycube.testandroidapp + +data class Item(val id: Int, val title: String, val subtitle: String) diff --git a/app/src/main/java/com/complycube/testandroidapp/ItemListScreen.kt b/app/src/main/java/com/complycube/testandroidapp/ItemListScreen.kt new file mode 100644 index 0000000..f8925a8 --- /dev/null +++ b/app/src/main/java/com/complycube/testandroidapp/ItemListScreen.kt @@ -0,0 +1,68 @@ +package com.complycube.testandroidapp + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material3.Card +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.complycube.testandroidapp.ui.theme.TestAndroidAppTheme + +@Composable +fun ItemListScreen( + viewModel: ItemListViewModel, + modifier: Modifier = Modifier +) { + val items by viewModel.items.collectAsState() + ItemList(items = items, modifier = modifier) +} + +@Composable +fun ItemList( + items: List, + modifier: Modifier = Modifier +) { + LazyColumn(modifier = modifier.testTag("item_list")) { + items(items = items, key = { it.id }) { item -> + ItemCard(item = item) + } + } +} + +@Composable +private fun ItemCard( + item: Item, + modifier: Modifier = Modifier +) { + Card( + modifier = modifier + .fillMaxWidth() + .padding(horizontal = 16.dp, vertical = 4.dp) + ) { + Column(modifier = Modifier.padding(16.dp)) { + Text(text = item.title, style = MaterialTheme.typography.titleMedium) + Text(text = item.subtitle, style = MaterialTheme.typography.bodyMedium) + } + } +} + +@Preview(showBackground = true) +@Composable +private fun ItemListPreview() { + TestAndroidAppTheme { + ItemList( + items = List(5) { index -> + Item(id = index + 1, title = "Item ${index + 1}", subtitle = "Description for item ${index + 1}") + } + ) + } +} diff --git a/app/src/main/java/com/complycube/testandroidapp/ItemListViewModel.kt b/app/src/main/java/com/complycube/testandroidapp/ItemListViewModel.kt new file mode 100644 index 0000000..fffc8bc --- /dev/null +++ b/app/src/main/java/com/complycube/testandroidapp/ItemListViewModel.kt @@ -0,0 +1,19 @@ +package com.complycube.testandroidapp + +import androidx.lifecycle.ViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow + +class ItemListViewModel : ViewModel() { + private val _items = MutableStateFlow( + List(30) { index -> + Item( + id = index + 1, + title = "Item ${index + 1}", + subtitle = "Description for item ${index + 1}" + ) + } + ) + val items: StateFlow> = _items.asStateFlow() +} diff --git a/app/src/main/java/com/complycube/testandroidapp/MainActivity.kt b/app/src/main/java/com/complycube/testandroidapp/MainActivity.kt index a5edc2d..187edb2 100644 --- a/app/src/main/java/com/complycube/testandroidapp/MainActivity.kt +++ b/app/src/main/java/com/complycube/testandroidapp/MainActivity.kt @@ -4,24 +4,24 @@ import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge +import androidx.activity.viewModels import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.tooling.preview.Preview import com.complycube.testandroidapp.ui.theme.TestAndroidAppTheme class MainActivity : ComponentActivity() { + private val viewModel: ItemListViewModel by viewModels() + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContent { TestAndroidAppTheme { Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -> - Greeting( - name = "Android", + ItemListScreen( + viewModel = viewModel, modifier = Modifier.padding(innerPadding) ) } @@ -29,19 +29,3 @@ class MainActivity : ComponentActivity() { } } } - -@Composable -fun Greeting(name: String, modifier: Modifier = Modifier) { - Text( - text = "Hello $name!", - modifier = modifier - ) -} - -@Preview(showBackground = true) -@Composable -fun GreetingPreview() { - TestAndroidAppTheme { - Greeting("Android") - } -} \ No newline at end of file