diff --git a/README.md b/README.md index 8a31fc3..f66677d 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ ## Download the APK Access the latest APK for Kotlin Dictionary from the link below. -[![Get APK](https://img.shields.io/badge/Get%20APK-maroon?style=for-the-badge&logo=android&logoColor=white)](https://github.com/DevelopersBreach/kotlin-dictionary-multiplatform/releases/download/v0.1.0/app-release-v0.1.0.apk) +[![Get APK](https://img.shields.io/badge/Get%20APK-%23B125EA?style=for-the-badge&logo=android&logoColor=white)](https://github.com/DevelopersBreach/kotlin-dictionary-multiplatform/releases/download/v0.1.0/app-release-v0.1.0.apk) --- @@ -29,13 +29,13 @@ Access the latest APK for Kotlin Dictionary from the link below. ### Roadmap v0.2.0 -- [ ] Assign unique IDs to objects and enforce consistent ordering logic +- [x] Assign unique IDs to objects and enforce consistent ordering logic - [ ] Correct usage of visibility modifiers across the codebase - [ ] Introduce common `@Preview` annotations for reusable Composable previews - [x] Add code block for syntax display on the `Detail Screen` - [ ] Implement caching on the `Detail Screen` to store previously viewed topic data -- [ ] Implement dynamic topic loading in `TopicRepository` to support scalability -- [ ] Integrate Room database to persist bookmark states +- [x] Implement dynamic topic loading in `TopicRepository` to support scalability +- [ ] Add bookmark feature for topic cards to allow users to save and revisit important topics - [ ] Add a `Home Page` for navigation - [ ] Add a `Quiz Page` to host topic-based quizzes - [ ] Add a button in `DetailScreen` to attempt a quiz for that topic diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts index c1798c3..f29f12f 100644 --- a/composeApp/build.gradle.kts +++ b/composeApp/build.gradle.kts @@ -87,6 +87,7 @@ kotlin { implementation(libs.koin.androidx.compose) implementation(libs.generativeai) implementation(compose.uiTooling) + implementation(libs.ktor.client.okhttp) } commonMain.dependencies { implementation(compose.runtime) diff --git a/composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/PreviewUtils.kt b/composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/PreviewUtils.kt index 11dac6b..75e2f26 100644 --- a/composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/PreviewUtils.kt +++ b/composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/PreviewUtils.kt @@ -53,20 +53,35 @@ internal fun fakeTopicDetails(): KotlinTopicDetails { private fun sampleTopicList(): List { return listOf( - Topic("Smart Casts"), - Topic("Null Safety"), - Topic("Coroutines"), - Topic("Lambdas"), - Topic("Sealed Classes"), + Topic( + name = "Smart Casts", + description = "Automatic casting by the compiler after type checks.", + ), + Topic( + name = "Null Safety", + description = "Kotlin's system to eliminate null pointer exceptions at compile time.", + ), + Topic( + name = "Coroutines", + description = "Lightweight threads for asynchronous and non-blocking programming.", + ), + Topic( + name = "Lambdas", + description = "Anonymous functions used to pass behavior as data.", + ), + Topic( + name = "Sealed Classes", + description = "Classes used to represent restricted class hierarchies for type safety.", + ), ) } internal fun sampleTopicUiList(): List { return sampleTopicList().map { topic -> ItemTopic( - name = topic.name, - initial = topic.name.firstOrNull()?.uppercase() ?: "", - isBookmarked = true, + name = topic.name ?: "", + initial = topic.name?.firstOrNull()?.uppercase() ?: "", + description = topic.description ?: "", ) } } \ No newline at end of file diff --git a/composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/topic/TopicScreenPreview.kt b/composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/topic/TopicScreenPreview.kt index 7d6fd86..c34fd62 100644 --- a/composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/topic/TopicScreenPreview.kt +++ b/composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/topic/TopicScreenPreview.kt @@ -12,10 +12,8 @@ private fun TopicScreenPreview() { KotlinDictionaryTheme { TopicScreenUI( topics = sampleTopicUiList(), - bookmarkedStates = listOf(), searchQuery = "Search", onQueryChange = { }, - onBookmarkClick = { }, onTopicClick = { }, ) } diff --git a/composeApp/src/commonMain/composeResources/values/string.xml b/composeApp/src/commonMain/composeResources/values/string.xml index 4afcf80..beb55cb 100644 --- a/composeApp/src/commonMain/composeResources/values/string.xml +++ b/composeApp/src/commonMain/composeResources/values/string.xml @@ -23,8 +23,6 @@ Topics Description need to be added Icon - Remove bookmark - Add bookmark Search Kotlin terms... Search \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/core/network/api/GeminiApiService.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/core/network/detailsGenerator/api/GeminiApiService.kt similarity index 92% rename from composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/core/network/api/GeminiApiService.kt rename to composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/core/network/detailsGenerator/api/GeminiApiService.kt index 3d7e2db..55ae629 100644 --- a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/core/network/api/GeminiApiService.kt +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/core/network/detailsGenerator/api/GeminiApiService.kt @@ -1,8 +1,8 @@ -package com.developersbreach.kotlindictionarymultiplatform.core.network.api +package com.developersbreach.kotlindictionarymultiplatform.core.network.detailsGenerator.api import com.developersbreach.kotlindictionarymultiplatform.Log -import com.developersbreach.kotlindictionarymultiplatform.core.network.parser.GeminiJsonParser -import com.developersbreach.kotlindictionarymultiplatform.core.network.request.GeminiPromptBuilder +import com.developersbreach.kotlindictionarymultiplatform.core.network.detailsGenerator.parser.GeminiJsonParser +import com.developersbreach.kotlindictionarymultiplatform.core.network.detailsGenerator.request.GeminiPromptBuilder import com.developersbreach.kotlindictionarymultiplatform.data.detail.model.KotlinTopicDetails import io.ktor.client.HttpClient import io.ktor.client.request.post diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/core/network/parser/GeminiJsonParser.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/core/network/detailsGenerator/parser/GeminiJsonParser.kt similarity index 96% rename from composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/core/network/parser/GeminiJsonParser.kt rename to composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/core/network/detailsGenerator/parser/GeminiJsonParser.kt index be4a28d..a386c9a 100644 --- a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/core/network/parser/GeminiJsonParser.kt +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/core/network/detailsGenerator/parser/GeminiJsonParser.kt @@ -1,4 +1,4 @@ -package com.developersbreach.kotlindictionarymultiplatform.core.network.parser +package com.developersbreach.kotlindictionarymultiplatform.core.network.detailsGenerator.parser import kotlinx.serialization.json.Json import kotlinx.serialization.json.jsonObject diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/core/network/request/GeminiPromptBuilder.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/core/network/detailsGenerator/request/GeminiPromptBuilder.kt similarity index 98% rename from composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/core/network/request/GeminiPromptBuilder.kt rename to composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/core/network/detailsGenerator/request/GeminiPromptBuilder.kt index ec755ea..06279ea 100644 --- a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/core/network/request/GeminiPromptBuilder.kt +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/core/network/detailsGenerator/request/GeminiPromptBuilder.kt @@ -1,4 +1,4 @@ -package com.developersbreach.kotlindictionarymultiplatform.core.network.request +package com.developersbreach.kotlindictionarymultiplatform.core.network.detailsGenerator.request import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.buildJsonObject diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/core/network/topicSource/FirestoreConstants.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/core/network/topicSource/FirestoreConstants.kt new file mode 100644 index 0000000..78f6401 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/core/network/topicSource/FirestoreConstants.kt @@ -0,0 +1,6 @@ +package com.developersbreach.kotlindictionarymultiplatform.core.network.topicSource + +object FirestoreConstants { + private const val ROOT_URL = "https://firestore.googleapis.com/v1/projects/kotlin-dictionary/databases/(default)/documents" + const val TOPICS_URL = "$ROOT_URL/topics" +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/data/detail/repository/DetailRepository.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/data/detail/repository/DetailRepository.kt index 4c4a0d1..c38a547 100644 --- a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/data/detail/repository/DetailRepository.kt +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/data/detail/repository/DetailRepository.kt @@ -1,7 +1,7 @@ package com.developersbreach.kotlindictionarymultiplatform.data.detail.repository import arrow.core.Either -import com.developersbreach.kotlindictionarymultiplatform.core.network.api.GeminiApiService +import com.developersbreach.kotlindictionarymultiplatform.core.network.detailsGenerator.api.GeminiApiService import com.developersbreach.kotlindictionarymultiplatform.data.detail.model.KotlinTopicDetails import com.developersbreach.kotlindictionarymultiplatform.getOpenApiKey diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/data/topic/model/Topic.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/data/topic/model/Topic.kt index 91f9539..00bdb0c 100644 --- a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/data/topic/model/Topic.kt +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/data/topic/model/Topic.kt @@ -1,5 +1,9 @@ package com.developersbreach.kotlindictionarymultiplatform.data.topic.model +import kotlinx.serialization.Serializable + +@Serializable data class Topic( - val name: String, + val name: String?, + val description: String?, ) \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/data/topic/model/TopicResponse.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/data/topic/model/TopicResponse.kt new file mode 100644 index 0000000..16e5002 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/data/topic/model/TopicResponse.kt @@ -0,0 +1,32 @@ +package com.developersbreach.kotlindictionarymultiplatform.data.topic.model + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class TopicResponse( + @SerialName("documents") val topics: List, +) + +@Serializable +data class RawTopic( + @SerialName("fields") val fields: TopicFields, +) + +@Serializable +data class TopicFields( + @SerialName("name") val name: RawField, + @SerialName("description") val description: RawField, +) + +@Serializable +data class RawField( + @SerialName("stringValue") val value: String, +) + +fun RawTopic.toTopic(): Topic { + return Topic( + name = fields.name.value, + description = fields.description.value, + ) +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/data/topic/repository/TopicRepository.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/data/topic/repository/TopicRepository.kt index 85462f4..16192dd 100644 --- a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/data/topic/repository/TopicRepository.kt +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/data/topic/repository/TopicRepository.kt @@ -1,28 +1,21 @@ package com.developersbreach.kotlindictionarymultiplatform.data.topic.repository import arrow.core.Either +import com.developersbreach.kotlindictionarymultiplatform.data.topic.model.TopicResponse import com.developersbreach.kotlindictionarymultiplatform.data.topic.model.Topic +import com.developersbreach.kotlindictionarymultiplatform.data.topic.model.toTopic +import com.developersbreach.kotlindictionarymultiplatform.core.network.topicSource.FirestoreConstants +import io.ktor.client.HttpClient +import io.ktor.client.call.body +import io.ktor.client.request.get -object TopicRepository { - fun getTopics(): Either> { +class TopicRepository( + private val httpClient: HttpClient, +) { + suspend fun getTopics(): Either> { return Either.catch { - listOf( - Topic("Variables"), - Topic("Strings"), - Topic("Functions"), - Topic("Coroutines"), - Topic("Classes"), - Topic("Interfaces"), - Topic("Objects"), - Topic("Collections"), - Topic("Null Safety"), - Topic("Lambdas"), - Topic("Higher-Order Functions"), - Topic("Delegation"), - Topic("Sealed Classes"), - Topic("Generics"), - Topic("Annotations"), - ) + val topicResponse: TopicResponse = httpClient.get(FirestoreConstants.TOPICS_URL).body() + topicResponse.topics.map { it.toTopic() } } } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/di/ApiModule.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/di/ApiModule.kt index 571ecb0..656e70a 100644 --- a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/di/ApiModule.kt +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/di/ApiModule.kt @@ -1,6 +1,6 @@ package com.developersbreach.kotlindictionarymultiplatform.di -import com.developersbreach.kotlindictionarymultiplatform.core.network.api.GeminiApiService +import com.developersbreach.kotlindictionarymultiplatform.core.network.detailsGenerator.api.GeminiApiService import org.koin.dsl.module internal val apiModule = module { diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/di/RepositoryModule.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/di/RepositoryModule.kt index 18a16fc..69838e5 100644 --- a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/di/RepositoryModule.kt +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/di/RepositoryModule.kt @@ -9,6 +9,6 @@ internal val repositoryModule = module { DetailRepository(get()) } single { - TopicRepository + TopicRepository(get()) } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/TopicCard.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/TopicCard.kt index 28de7c0..9998c81 100644 --- a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/TopicCard.kt +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/TopicCard.kt @@ -13,9 +13,6 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Bookmark -import androidx.compose.material.icons.outlined.BookmarkBorder import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -23,21 +20,14 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.shadow import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp -import com.developersbreach.designsystem.components.KdIconButton import com.developersbreach.designsystem.components.KdSurface import com.developersbreach.designsystem.components.KdText -import kotlindictionarymultiplatform.composeapp.generated.resources.Res -import kotlindictionarymultiplatform.composeapp.generated.resources.add_bookmark -import kotlindictionarymultiplatform.composeapp.generated.resources.remove_bookmark -import org.jetbrains.compose.resources.stringResource @Composable fun TopicCard( itemTopic: ItemTopic, topic: String, - subtitle: String, - isBookmarked: Boolean, - onBookmarkClick: () -> Unit, + description: String, onCardClick: () -> Unit, ) { KdSurface( @@ -91,7 +81,7 @@ fun TopicCard( Spacer(modifier = Modifier.height(6.dp)) KdText( modifier = Modifier, - text = subtitle, + text = description, style = MaterialTheme.typography.labelMedium.copy( color = MaterialTheme.colorScheme.onBackground, ), @@ -99,23 +89,6 @@ fun TopicCard( overflow = TextOverflow.Ellipsis, ) } - - KdIconButton( - modifier = Modifier, - iconModifier = Modifier, - onClick = onBookmarkClick, - imageVector = if (isBookmarked) { - Icons.Outlined.BookmarkBorder - } else { - Icons.Filled.Bookmark - }, - contentDescription = if (isBookmarked) { - stringResource(Res.string.remove_bookmark) - } else { - stringResource(Res.string.add_bookmark) - }, - tint = MaterialTheme.colorScheme.primary, - ) } } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/TopicList.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/TopicList.kt index 1e8e06f..c916049 100644 --- a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/TopicList.kt +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/TopicList.kt @@ -3,33 +3,25 @@ package com.developersbreach.kotlindictionarymultiplatform.ui.screens.topic import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.lazy.items import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp -import kotlindictionarymultiplatform.composeapp.generated.resources.Res -import kotlindictionarymultiplatform.composeapp.generated.resources.description_subtitle -import org.jetbrains.compose.resources.stringResource @Composable fun TopicList( topics: List, - bookmarkedStates: List, - onBookmarkClick: (Int) -> Unit, onTopicClick: (String) -> Unit, ) { LazyColumn( modifier = Modifier.fillMaxSize(), contentPadding = PaddingValues(bottom = 40.dp), ) { - itemsIndexed(topics) { index, topic -> - val isBookmarked = bookmarkedStates.getOrNull(index) ?: true + items(topics) { topic -> TopicCard( topic = topic.name, itemTopic = topic, - subtitle = stringResource(Res.string.description_subtitle), - isBookmarked = isBookmarked, - onBookmarkClick = { onBookmarkClick(index) }, + description = topic.description, onCardClick = { onTopicClick(topic.name) }, ) } diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/TopicScreen.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/TopicScreen.kt index 0647ad9..efebf55 100644 --- a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/TopicScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/TopicScreen.kt @@ -17,10 +17,8 @@ fun TopicScreen( ) { data -> TopicScreenUI( topics = data.filteredTopics, - bookmarkedStates = data.bookmarkedStates, searchQuery = data.searchQuery, onQueryChange = viewModel::updateSearchQuery, - onBookmarkClick = viewModel::toggleBookmark, onTopicClick = onTopicClick, ) } diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/TopicScreenUI.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/TopicScreenUI.kt index 105aa93..770320b 100644 --- a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/TopicScreenUI.kt +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/TopicScreenUI.kt @@ -12,10 +12,8 @@ import com.developersbreach.designsystem.components.KdScaffold @Composable fun TopicScreenUI( topics: List, - bookmarkedStates: List, searchQuery: String, onQueryChange: (String) -> Unit, - onBookmarkClick: (Int) -> Unit, onTopicClick: (String) -> Unit, ) { KdScaffold( @@ -34,8 +32,6 @@ fun TopicScreenUI( Spacer(modifier = Modifier.height(8.dp)) TopicList( topics = topics, - bookmarkedStates = bookmarkedStates, - onBookmarkClick = onBookmarkClick, onTopicClick = onTopicClick, ) } diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/TopicUiState.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/TopicUiState.kt index b11f3e1..d0bd8cd 100644 --- a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/TopicUiState.kt +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/TopicUiState.kt @@ -6,12 +6,11 @@ data class TopicUi( val isLoading: Boolean = false, val topics: List = emptyList(), val searchQuery: String = "", - val bookmarkedStates: List = emptyList(), val filteredTopics: List = emptyList(), ) data class ItemTopic( val name: String, val initial: String, - val isBookmarked: Boolean, + val description: String, ) \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/TopicViewModel.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/TopicViewModel.kt index 9a0b5c9..1476fcd 100644 --- a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/TopicViewModel.kt +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/TopicViewModel.kt @@ -24,14 +24,13 @@ class TopicViewModel( } } - private fun fetchTopicList() { + private suspend fun fetchTopicList() { _uiState.value = UiState.Success(TopicUi(isLoading = true)) repository.getTopics().fold( ifLeft = { UiState.Error(it) }, ifRight = { list -> - rawTopics = list.sortedBy { it.name.lowercase() } - val initialBookmarks = List(rawTopics.size) { true } - applyFilters(rawTopics, (_uiState.value as UiState.Success).data.searchQuery, initialBookmarks) + rawTopics = list.sortedBy { it.name?.lowercase() ?: "" } + applyFilters(rawTopics, (_uiState.value as UiState.Success).data.searchQuery) }, ) } @@ -39,34 +38,22 @@ class TopicViewModel( fun updateSearchQuery( newQuery: String, ) { - val bookmarks = (_uiState.value as UiState.Success).data.bookmarkedStates - applyFilters(rawTopics, newQuery, bookmarks) - } - - fun toggleBookmark( - index: Int, - ) { - val current = (_uiState.value as UiState.Success).data.bookmarkedStates - if (index !in current.indices) return - val updated = current.toMutableList().apply { this[index] = !this[index] } - applyFilters(rawTopics, (_uiState.value as UiState.Success).data.searchQuery, updated) + applyFilters(rawTopics, newQuery) } private fun applyFilters( topics: List, query: String, - bookmarks: List, ) { val filtered = topics - .withIndex() - .filter { (_, topic) -> - topic.name.contains(query, ignoreCase = true) + .filter { topic -> + topic.name?.contains(query, ignoreCase = true) == true } - .map { (index, topic) -> + .map { topic -> ItemTopic( - name = topic.name, - initial = topic.name.first().uppercase(), - isBookmarked = bookmarks.getOrNull(index) ?: false, + name = topic.name ?: "", + initial = topic.name?.firstOrNull()?.uppercase() ?: "", + description = topic.description ?: "", ) } @@ -75,7 +62,6 @@ class TopicViewModel( isLoading = false, searchQuery = query, topics = topics, - bookmarkedStates = bookmarks, filteredTopics = filtered, ), ) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f76afe7..5f49d58 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -29,6 +29,7 @@ jetbrainsKotlinJvm = "2.1.10" kotlinStdlib = "2.1.10" runner = "1.6.2" core = "1.6.1" +uiToolingPreviewAndroid = "1.8.2" [libraries] androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "navigation-compose" } @@ -56,6 +57,7 @@ ktor-client-android = { module = "io.ktor:ktor-client-android" } ktor-client-content-negotiation = { module = "io.ktor:ktor-client-content-negotiation" } ktor-client-logging = { module = "io.ktor:ktor-client-logging" } ktor-client-mock = { module = "io.ktor:ktor-client-mock" } +ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor-bom" } ktor-client-serialization = { module = "io.ktor:ktor-client-serialization" } ktor-serialization-kotlinx-json = { module = "io.ktor:ktor-serialization-kotlinx-json" } koin-android = { module = "io.insert-koin:koin-android" } @@ -67,6 +69,7 @@ koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin" } kotlin-stdlib = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib", version.ref = "kotlinStdlib" } androidx-runner = { group = "androidx.test", name = "runner", version.ref = "runner" } androidx-core = { group = "androidx.test", name = "core", version.ref = "core" } +androidx-ui-tooling-preview-android = { group = "androidx.compose.ui", name = "ui-tooling-preview-android", version.ref = "uiToolingPreviewAndroid" } [plugins] androidApplication = { id = "com.android.application", version.ref = "agp" }