Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,14 @@ Access the latest APK for Kotlin Dictionary from the link below.
- [ ] Implement caching on the `Detail Screen` to store previously viewed topic data
- [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
- [x] 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
- [ ] Add a `Contributors Page` to showcase project contributors
- [ ] Add a `Settings Page` with basic preferences
- [ ] Implement a `Splash Screen`
- [x] Integrate multiplatform paging for `Topic Screen`
- [ ] Add dark theme previews to the README

---

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.developersbreach.kotlindictionarymultiplatform.previews.home

import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.PreviewLightDark
import com.developersbreach.kotlindictionarymultiplatform.previews.sampleTopicUiList
import com.developersbreach.kotlindictionarymultiplatform.ui.screens.home.HomeScreenUI
import com.developersbreach.kotlindictionarymultiplatform.ui.theme.KotlinDictionaryTheme

@PreviewLightDark
@Composable
private fun HomeScreenPreview() {
KotlinDictionaryTheme {
HomeScreenUI(
topics = sampleTopicUiList(),
onViewAllClick = {},
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ private fun TopicScreenPreview() {
searchQuery = "Search",
onQueryChange = { },
onTopicClick = { },
onNavigateUp = { },
)
}
}
4 changes: 4 additions & 0 deletions composeApp/src/commonMain/composeResources/values/string.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,8 @@
<string name="icon">Icon</string>
<string name="search_kotlin_terms">Search Kotlin terms...</string>
<string name="search">Search</string>
<string name="menu">Menu</string>
<string name="welcome">Welcome,\nKotlin Enthusiast!</string>
<string name="quizzes">Quizzes</string>
<string name="view_all">View all</string>
</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.developersbreach.kotlindictionarymultiplatform.di

import androidx.lifecycle.SavedStateHandle
import com.developersbreach.kotlindictionarymultiplatform.ui.screens.detail.DetailViewModel
import com.developersbreach.kotlindictionarymultiplatform.ui.screens.home.HomeViewModel
import com.developersbreach.kotlindictionarymultiplatform.ui.screens.topic.TopicViewModel
import org.koin.core.module.dsl.viewModel
import org.koin.dsl.module
Expand All @@ -17,4 +18,10 @@ internal val viewModelModule = module {
viewModel {
TopicViewModel(get())
}

viewModel {
HomeViewModel(
topicRepository = get(),
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,7 @@ sealed interface AppDestinations {
data class Detail(
val topicId: String,
) : AppDestinations

@Serializable
data object Home : AppDestinations
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
package com.developersbreach.kotlindictionarymultiplatform.ui.navigation

import HomeScreen
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import com.developersbreach.kotlindictionarymultiplatform.ui.screens.detail.DetailScreen
import com.developersbreach.kotlindictionarymultiplatform.ui.screens.detail.DetailViewModel
import com.developersbreach.kotlindictionarymultiplatform.ui.screens.home.HomeViewModel
import com.developersbreach.kotlindictionarymultiplatform.ui.screens.topic.TopicScreen
import com.developersbreach.kotlindictionarymultiplatform.ui.screens.topic.TopicViewModel
import org.koin.compose.viewmodel.koinViewModel

@Composable
fun AppNavigation(
startDestination: AppDestinations = AppDestinations.TopicList,
startDestination: AppDestinations = AppDestinations.Home,
) {
val navController = rememberNavController()
val actions = remember(navController) { NavigationAction(navController) }
Expand All @@ -29,6 +31,7 @@ fun AppNavigation(
actions.navigateToDetail(selectedTopicId)
},
viewModel = viewModel,
onNavigateUp = { navController.navigateUp() },
)
}

Expand All @@ -39,5 +42,12 @@ fun AppNavigation(
navigateUp = { navController.navigateUp() },
)
}
composable<AppDestinations.Home> {
val viewModel: HomeViewModel = koinViewModel()
HomeScreen(
viewModel = viewModel,
navigateToTopicList = actions.navigateToTopic,
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,7 @@ class NavigationAction(
val navigateToDetail: (String) -> Unit = { topicId ->
navController.navigate(AppDestinations.Detail(topicId))
}
val navigateToTopic: () -> Unit = {
navController.navigate(AppDestinations.TopicList)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.developersbreach.kotlindictionarymultiplatform.ui.screens.home

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.unit.dp
import com.developersbreach.designsystem.components.KdCard
import com.developersbreach.designsystem.components.KdText

@Composable
fun HomeCard(
label: String,
) {
KdCard(
modifier = Modifier
.size(120.dp)
.clip(RoundedCornerShape(22.dp)),
colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.secondaryContainer,
),
elevation = CardDefaults.cardElevation(defaultElevation = 2.dp),
content = {
Box(
modifier = Modifier
.fillMaxSize()
.background(
Brush.verticalGradient(
colors = listOf(
MaterialTheme.colorScheme.primary.copy(alpha = 0.8f),
MaterialTheme.colorScheme.primaryContainer,
),
),
),
contentAlignment = Alignment.BottomStart,
) {
KdText(
text = label,
maxLines = 1,
modifier = Modifier
.padding(12.dp)
.align(Alignment.BottomStart),
color = MaterialTheme.colorScheme.onSecondaryContainer,
)
}
},
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import com.developersbreach.kotlindictionarymultiplatform.ui.screens.home.HomeScreenUI
import com.developersbreach.kotlindictionarymultiplatform.ui.screens.home.HomeViewModel

@Composable
fun HomeScreen(
viewModel: HomeViewModel,
navigateToTopicList: () -> Unit,
) {
val topicsState = viewModel.topics.collectAsState()

HomeScreenUI(
topics = topicsState.value,
onViewAllClick = navigateToTopicList,
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.developersbreach.kotlindictionarymultiplatform.ui.screens.home

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.developersbreach.designsystem.components.KdScaffold
import com.developersbreach.designsystem.components.KdText
import com.developersbreach.kotlindictionarymultiplatform.ui.screens.topic.Topic
import kotlindictionarymultiplatform.composeapp.generated.resources.Res
import kotlindictionarymultiplatform.composeapp.generated.resources.topics
import kotlindictionarymultiplatform.composeapp.generated.resources.welcome
import org.jetbrains.compose.resources.stringResource

@Composable
fun HomeScreenUI(
topics: List<Topic>,
onViewAllClick: () -> Unit,
) {
KdScaffold(
topBar = { HomeTopAppBar() },
modifier = Modifier,
) { innerPadding ->
Column(
modifier = Modifier
.padding(horizontal = 16.dp)
.padding(top = innerPadding.calculateTopPadding()),
) {
Spacer(modifier = Modifier.height(16.dp))
KdText(
text = stringResource(Res.string.welcome),
style = MaterialTheme.typography.displayLarge,
color = MaterialTheme.colorScheme.onBackground,
modifier = Modifier,
)
Spacer(modifier = Modifier.height(16.dp))
HorizontalScroll(
title = stringResource(Res.string.topics),
topics = topics,
onViewAllClick = onViewAllClick,
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.developersbreach.kotlindictionarymultiplatform.ui.screens.home

import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Menu
import kotlindictionarymultiplatform.composeapp.generated.resources.menu
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import com.developersbreach.designsystem.components.KdIconButton
import com.developersbreach.designsystem.components.KdText
import com.developersbreach.designsystem.components.KdTopAppBar
import kotlindictionarymultiplatform.composeapp.generated.resources.Res
import org.jetbrains.compose.resources.stringResource

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun HomeTopAppBar() {
KdTopAppBar(
title = {
KdText(
text = "Kotlin Dictionary",
style = MaterialTheme.typography.displayMedium,
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Start,
color = MaterialTheme.colorScheme.onPrimary,
)
},
colors = TopAppBarDefaults.topAppBarColors(
containerColor = MaterialTheme.colorScheme.onPrimaryContainer,
titleContentColor = MaterialTheme.colorScheme.onPrimary,
navigationIconContentColor = MaterialTheme.colorScheme.onPrimary,
),
navigationIcon = {
KdIconButton(
onClick = {},
modifier = Modifier,
contentDescription = stringResource(Res.string.menu),
iconModifier = Modifier,
imageVector = Icons.Default.Menu,
)
},
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.developersbreach.kotlindictionarymultiplatform.ui.screens.home

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.developersbreach.kotlindictionarymultiplatform.data.topic.repository.TopicRepository
import com.developersbreach.kotlindictionarymultiplatform.ui.screens.topic.Topic
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch

class HomeViewModel(
private val topicRepository: TopicRepository,
) : ViewModel() {

private val _topics = MutableStateFlow<List<Topic>>(emptyList())
val topics: StateFlow<List<Topic>> = _topics.asStateFlow()

init {
fetchTopics()
}

private fun fetchTopics() {
viewModelScope.launch {
val result = topicRepository.getTopicsPage(page = 1, pageSize = 5, query = "")
_topics.value = result
}
}
}
Loading
Loading