Skip to content

Commit 4bacb59

Browse files
Improve table of contents implementation/readability and render logic with better mapping/configuration
1 parent b2265d7 commit 4bacb59

File tree

8 files changed

+348
-50
lines changed

8 files changed

+348
-50
lines changed

composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/detail/DetailScreenPreview.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,16 @@ import androidx.compose.runtime.Composable
44
import androidx.compose.ui.tooling.preview.PreviewLightDark
55
import com.developersbreach.kotlindictionarymultiplatform.previews.fakeTopicDetails
66
import com.developersbreach.kotlindictionarymultiplatform.ui.screens.detail.DetailScreenUI
7+
import com.developersbreach.kotlindictionarymultiplatform.ui.screens.detail.toDetailUi
78
import com.developersbreach.kotlindictionarymultiplatform.ui.theme.KotlinDictionaryTheme
89

910
@PreviewLightDark
1011
@Composable
1112
fun DetailScreenPreview() {
1213
KotlinDictionaryTheme {
13-
DetailScreenUI(topic = fakeTopicDetails())
14+
DetailScreenUI(
15+
detailUiState = fakeTopicDetails().toDetailUi(),
16+
navigateUp = {},
17+
)
1418
}
1519
}

composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/navigation/AppNavigation.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,10 @@ fun AppNavigation(
3434

3535
composable<AppDestinations.Detail> {
3636
val viewModel: DetailViewModel = koinViewModel()
37-
DetailScreen(viewModel = viewModel)
37+
DetailScreen(
38+
viewModel = viewModel,
39+
navigateUp = { navController.navigateUp() },
40+
)
3841
}
3942
}
4043
}

composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/DetailScreen.kt

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,16 @@ import androidx.compose.runtime.getValue
66
import com.developersbreach.kotlindictionarymultiplatform.ui.components.UiStateHandler
77

88
@Composable
9-
fun DetailScreen(viewModel: DetailViewModel) {
9+
fun DetailScreen(
10+
viewModel: DetailViewModel,
11+
navigateUp: () -> Unit,
12+
) {
1013
val topicState by viewModel.state.collectAsState()
1114

12-
UiStateHandler(uiState = topicState) { topic ->
13-
DetailScreenUI(topic)
15+
UiStateHandler(uiState = topicState) { detailUiState ->
16+
DetailScreenUI(
17+
detailUiState = detailUiState,
18+
navigateUp = navigateUp,
19+
)
1420
}
1521
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
package com.developersbreach.kotlindictionarymultiplatform.ui.screens.detail
2+
3+
import androidx.compose.foundation.clickable
4+
import androidx.compose.foundation.layout.Spacer
5+
import androidx.compose.foundation.layout.height
6+
import androidx.compose.material3.MaterialTheme
7+
import androidx.compose.material3.Text
8+
import androidx.compose.runtime.Composable
9+
import androidx.compose.ui.Modifier
10+
import androidx.compose.ui.text.font.FontWeight
11+
import androidx.compose.ui.unit.dp
12+
import com.developersbreach.kotlindictionarymultiplatform.data.detail.model.Section
13+
import com.developersbreach.kotlindictionarymultiplatform.data.detail.model.Syntax
14+
import kotlindictionarymultiplatform.composeapp.generated.resources.Res
15+
import kotlindictionarymultiplatform.composeapp.generated.resources.bullet_item
16+
import kotlindictionarymultiplatform.composeapp.generated.resources.introduction
17+
import kotlindictionarymultiplatform.composeapp.generated.resources.notes_with_value
18+
import kotlindictionarymultiplatform.composeapp.generated.resources.pitfalls
19+
import kotlindictionarymultiplatform.composeapp.generated.resources.related_topics
20+
import kotlindictionarymultiplatform.composeapp.generated.resources.syntax
21+
import org.jetbrains.compose.resources.stringResource
22+
23+
@Composable
24+
fun TableOfContents(
25+
item: String,
26+
onClick: () -> Unit,
27+
) {
28+
Text(
29+
text = item,
30+
modifier = Modifier.clickable { onClick() },
31+
color = MaterialTheme.colorScheme.onSurface,
32+
)
33+
Spacer(Modifier.height(4.dp))
34+
}
35+
36+
@Composable
37+
fun IntroductionSection(
38+
intro: String,
39+
) {
40+
Text(
41+
text = stringResource(resource = Res.string.introduction),
42+
style = MaterialTheme.typography.headlineLarge,
43+
color = MaterialTheme.colorScheme.onPrimary,
44+
)
45+
Spacer(Modifier.height(4.dp))
46+
Text(
47+
text = intro,
48+
style = MaterialTheme.typography.bodyMedium,
49+
)
50+
Spacer(Modifier.height(16.dp))
51+
}
52+
53+
@Composable
54+
fun SyntaxSection(
55+
syntax: Syntax,
56+
) {
57+
Text(
58+
text = stringResource(resource = Res.string.syntax),
59+
style = MaterialTheme.typography.headlineLarge,
60+
color = MaterialTheme.colorScheme.onPrimary,
61+
)
62+
Spacer(Modifier.height(4.dp))
63+
Text(
64+
text = syntax.signature,
65+
style = MaterialTheme.typography.bodyMedium,
66+
)
67+
syntax.notes?.let {
68+
Spacer(Modifier.height(4.dp))
69+
Text(
70+
text = stringResource(Res.string.notes_with_value, it),
71+
style = MaterialTheme.typography.bodyMedium,
72+
)
73+
}
74+
Spacer(Modifier.height(16.dp))
75+
}
76+
77+
@Composable
78+
fun SectionBlock(
79+
section: Section,
80+
) {
81+
section.heading?.let {
82+
Text(it, style = MaterialTheme.typography.headlineLarge, color = MaterialTheme.colorScheme.onPrimary)
83+
Spacer(Modifier.height(4.dp))
84+
}
85+
86+
section.content?.let {
87+
Text(it, style = MaterialTheme.typography.bodyMedium)
88+
Spacer(Modifier.height(8.dp))
89+
}
90+
91+
section.codeExamples.forEach { example ->
92+
example.description?.let {
93+
Text(it, fontWeight = FontWeight.Bold, style = MaterialTheme.typography.bodyMedium)
94+
}
95+
Spacer(Modifier.height(16.dp))
96+
CodeExampleBox(code = example.code)
97+
Spacer(Modifier.height(16.dp))
98+
}
99+
}
100+
101+
@Composable
102+
fun PitfallsSection(
103+
pitfalls: List<String>,
104+
) {
105+
Text(
106+
text = stringResource(resource = Res.string.pitfalls),
107+
style = MaterialTheme.typography.headlineLarge,
108+
color = MaterialTheme.colorScheme.onPrimary,
109+
)
110+
Spacer(Modifier.height(4.dp))
111+
pitfalls.forEach {
112+
Text(
113+
text = stringResource(Res.string.bullet_item, it),
114+
style = MaterialTheme.typography.bodyMedium,
115+
)
116+
}
117+
Spacer(Modifier.height(16.dp))
118+
}
119+
120+
@Composable
121+
fun RelatedTopicsSection(
122+
relatedTopics: List<String>,
123+
) {
124+
Text(
125+
text = stringResource(resource = Res.string.related_topics),
126+
style = MaterialTheme.typography.headlineLarge,
127+
color = MaterialTheme.colorScheme.onPrimary,
128+
)
129+
Spacer(Modifier.height(4.dp))
130+
relatedTopics.forEach {
131+
Text(
132+
text = stringResource(Res.string.bullet_item, it),
133+
style = MaterialTheme.typography.bodyMedium,
134+
)
135+
}
136+
}
Lines changed: 78 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,95 @@
11
package com.developersbreach.kotlindictionarymultiplatform.ui.screens.detail
22

3+
import androidx.compose.foundation.layout.Spacer
4+
import androidx.compose.foundation.layout.fillMaxSize
5+
import androidx.compose.foundation.layout.height
36
import androidx.compose.foundation.layout.padding
7+
import androidx.compose.foundation.lazy.LazyColumn
8+
import androidx.compose.foundation.lazy.items
9+
import androidx.compose.foundation.lazy.rememberLazyListState
410
import androidx.compose.material3.MaterialTheme
511
import androidx.compose.material3.Scaffold
12+
import androidx.compose.material3.Text
613
import androidx.compose.runtime.Composable
14+
import androidx.compose.runtime.rememberCoroutineScope
715
import androidx.compose.ui.Modifier
8-
import com.developersbreach.kotlindictionarymultiplatform.data.detail.model.KotlinTopicDetails
16+
import androidx.compose.ui.unit.dp
17+
import kotlindictionarymultiplatform.composeapp.generated.resources.Res
18+
import kotlindictionarymultiplatform.composeapp.generated.resources.table_of_contents
19+
import kotlinx.coroutines.launch
20+
import org.jetbrains.compose.resources.stringResource
921

1022
@Composable
11-
fun DetailScreenUI(topic: KotlinTopicDetails) {
23+
fun DetailScreenUI(
24+
detailUiState: DetailUiState,
25+
navigateUp: () -> Unit,
26+
) {
1227
Scaffold(
13-
topBar = { DetailTopBar(title = topic.topicName) },
28+
topBar = {
29+
DetailTopBar(
30+
title = detailUiState.topicName,
31+
navigateUp = navigateUp,
32+
)
33+
},
1434
containerColor = MaterialTheme.colorScheme.background,
1535
) { innerPadding ->
1636
DetailContent(
17-
topic = topic,
37+
detailUiState = detailUiState,
1838
modifier = Modifier.padding(innerPadding),
1939
)
2040
}
41+
}
42+
43+
@Composable
44+
private fun DetailContent(
45+
detailUiState: DetailUiState,
46+
modifier: Modifier = Modifier,
47+
) {
48+
val listState = rememberLazyListState()
49+
val coroutineScope = rememberCoroutineScope()
50+
51+
LazyColumn(
52+
state = listState,
53+
modifier = modifier
54+
.fillMaxSize()
55+
.padding(horizontal = 16.dp),
56+
) {
57+
item {
58+
Text(
59+
text = stringResource(Res.string.table_of_contents),
60+
style = MaterialTheme.typography.titleLarge,
61+
color = MaterialTheme.colorScheme.onPrimary,
62+
)
63+
Spacer(Modifier.height(4.dp))
64+
}
65+
66+
items(
67+
items = detailUiState.tocEntries,
68+
) {
69+
TableOfContents(
70+
item = stringResource(it.titleRes, *it.formatArgs.toTypedArray()),
71+
onClick = {
72+
coroutineScope.launch {
73+
listState.animateScrollToItem(it.destinationIndex)
74+
}
75+
},
76+
)
77+
}
78+
79+
item {
80+
Spacer(Modifier.height(16.dp))
81+
}
82+
83+
items(
84+
items = detailUiState.contentItems,
85+
) { toc: ItemTableOfContent ->
86+
when (toc) {
87+
is ItemTableOfContent.Introduction -> IntroductionSection(toc.intro)
88+
is ItemTableOfContent.Syntax -> SyntaxSection(toc.syntax)
89+
is ItemTableOfContent.Section -> SectionBlock(toc.sections)
90+
is ItemTableOfContent.Pitfall -> PitfallsSection(toc.pitfalls)
91+
is ItemTableOfContent.RelatedTopic -> RelatedTopicsSection(toc.relatedTopics)
92+
}
93+
}
94+
}
2195
}

composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/DetailTopAppBar.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@ import org.jetbrains.compose.resources.stringResource
1818

1919
@OptIn(ExperimentalMaterial3Api::class)
2020
@Composable
21-
fun DetailTopBar(title: String) {
21+
fun DetailTopBar(
22+
title: String,
23+
navigateUp: () -> Unit,
24+
) {
2225
TopAppBar(
2326
title = {
2427
Text(
@@ -29,7 +32,7 @@ fun DetailTopBar(title: String) {
2932
)
3033
},
3134
navigationIcon = {
32-
IconButton(onClick = { /* TODO: Navigate back */ }) {
35+
IconButton(onClick = navigateUp) {
3336
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = stringResource(Res.string.back))
3437
}
3538
},

0 commit comments

Comments
 (0)