diff --git a/composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/detail/DetailContentPreview.kt b/composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/detail/DetailContentPreview.kt new file mode 100644 index 0000000..1506c42 --- /dev/null +++ b/composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/detail/DetailContentPreview.kt @@ -0,0 +1,15 @@ +package com.developersbreach.kotlindictionarymultiplatform.previews.detail + +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.PreviewLightDark +import com.developersbreach.kotlindictionarymultiplatform.previews.fakeTopicDetails +import com.developersbreach.kotlindictionarymultiplatform.ui.screens.detail.DetailContent +import com.developersbreach.kotlindictionarymultiplatform.ui.theme.KotlinDictionaryTheme + +@PreviewLightDark +@Composable +fun DetailContentPreview() { + KotlinDictionaryTheme { + DetailContent(topic = fakeTopicDetails()) + } +} \ No newline at end of file diff --git a/composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/detail/PreviewDetailScreen.kt b/composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/detail/DetailScreenPreview.kt similarity index 85% rename from composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/detail/PreviewDetailScreen.kt rename to composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/detail/DetailScreenPreview.kt index f478f25..71b7ea4 100644 --- a/composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/detail/PreviewDetailScreen.kt +++ b/composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/detail/DetailScreenPreview.kt @@ -3,13 +3,13 @@ package com.developersbreach.kotlindictionarymultiplatform.previews.detail import androidx.compose.runtime.Composable import androidx.compose.ui.tooling.preview.PreviewLightDark import com.developersbreach.kotlindictionarymultiplatform.previews.fakeTopicDetails -import com.developersbreach.kotlindictionarymultiplatform.ui.screens.detail.DetailScreenContent +import com.developersbreach.kotlindictionarymultiplatform.ui.screens.detail.DetailScreenUI import com.developersbreach.kotlindictionarymultiplatform.ui.theme.KotlinDictionaryTheme @PreviewLightDark @Composable fun DetailScreenPreview() { KotlinDictionaryTheme { - DetailScreenContent(topic = fakeTopicDetails()) + DetailScreenUI(topic = fakeTopicDetails()) } } \ No newline at end of file diff --git a/composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/detail/DetailTopAppBarPreview.kt b/composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/detail/DetailTopAppBarPreview.kt new file mode 100644 index 0000000..809203a --- /dev/null +++ b/composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/detail/DetailTopAppBarPreview.kt @@ -0,0 +1,15 @@ +package com.developersbreach.kotlindictionarymultiplatform.previews.detail + +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.PreviewLightDark +import com.developersbreach.kotlindictionarymultiplatform.previews.fakeTopicDetails +import com.developersbreach.kotlindictionarymultiplatform.ui.screens.detail.DetailTopBar +import com.developersbreach.kotlindictionarymultiplatform.ui.theme.KotlinDictionaryTheme + +@PreviewLightDark +@Composable +fun DetailTopBarPreview() { + KotlinDictionaryTheme { + DetailTopBar(title = fakeTopicDetails().topicName) + } +} \ No newline at end of file diff --git a/composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/detail/IntroductionSectionPreview.kt b/composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/detail/IntroductionSectionPreview.kt new file mode 100644 index 0000000..0452750 --- /dev/null +++ b/composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/detail/IntroductionSectionPreview.kt @@ -0,0 +1,15 @@ +package com.developersbreach.kotlindictionarymultiplatform.previews.detail + +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.PreviewLightDark +import com.developersbreach.kotlindictionarymultiplatform.previews.fakeTopicDetails +import com.developersbreach.kotlindictionarymultiplatform.ui.screens.detail.components.IntroductionSection +import com.developersbreach.kotlindictionarymultiplatform.ui.theme.KotlinDictionaryTheme + +@PreviewLightDark +@Composable +fun IntroductionSectionPreview() { + KotlinDictionaryTheme { + IntroductionSection(topic = fakeTopicDetails()) + } +} \ No newline at end of file diff --git a/composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/detail/PitfallsSectionPreviews.kt b/composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/detail/PitfallsSectionPreviews.kt new file mode 100644 index 0000000..a37a2cb --- /dev/null +++ b/composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/detail/PitfallsSectionPreviews.kt @@ -0,0 +1,15 @@ +package com.developersbreach.kotlindictionarymultiplatform.previews.detail + +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.PreviewLightDark +import com.developersbreach.kotlindictionarymultiplatform.previews.fakeTopicDetails +import com.developersbreach.kotlindictionarymultiplatform.ui.screens.detail.components.PitfallsSection +import com.developersbreach.kotlindictionarymultiplatform.ui.theme.KotlinDictionaryTheme + +@PreviewLightDark +@Composable +fun PitfallsSectionPreview() { + KotlinDictionaryTheme { + PitfallsSection(topic = fakeTopicDetails()) + } +} \ No newline at end of file diff --git a/composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/detail/RelatedTopicsSectionPreview.kt b/composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/detail/RelatedTopicsSectionPreview.kt new file mode 100644 index 0000000..c9be028 --- /dev/null +++ b/composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/detail/RelatedTopicsSectionPreview.kt @@ -0,0 +1,15 @@ +package com.developersbreach.kotlindictionarymultiplatform.previews.detail + +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.PreviewLightDark +import com.developersbreach.kotlindictionarymultiplatform.previews.fakeTopicDetails +import com.developersbreach.kotlindictionarymultiplatform.ui.screens.detail.components.RelatedTopicsSection +import com.developersbreach.kotlindictionarymultiplatform.ui.theme.KotlinDictionaryTheme + +@PreviewLightDark +@Composable +fun RelatedTopicsSectionPreview() { + KotlinDictionaryTheme { + RelatedTopicsSection(topic = fakeTopicDetails()) + } +} \ No newline at end of file diff --git a/composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/detail/SectionsListPreview.kt b/composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/detail/SectionsListPreview.kt new file mode 100644 index 0000000..5fa52ca --- /dev/null +++ b/composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/detail/SectionsListPreview.kt @@ -0,0 +1,15 @@ +package com.developersbreach.kotlindictionarymultiplatform.previews.detail + +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.PreviewLightDark +import com.developersbreach.kotlindictionarymultiplatform.previews.fakeTopicDetails +import com.developersbreach.kotlindictionarymultiplatform.ui.screens.detail.components.SectionsList +import com.developersbreach.kotlindictionarymultiplatform.ui.theme.KotlinDictionaryTheme + +@PreviewLightDark +@Composable +fun SectionsListPreview() { + KotlinDictionaryTheme { + SectionsList(topic = fakeTopicDetails()) + } +} \ No newline at end of file diff --git a/composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/detail/SyntaxSectionPreview.kt b/composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/detail/SyntaxSectionPreview.kt new file mode 100644 index 0000000..df89e19 --- /dev/null +++ b/composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/detail/SyntaxSectionPreview.kt @@ -0,0 +1,15 @@ +package com.developersbreach.kotlindictionarymultiplatform.previews.detail + +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.PreviewLightDark +import com.developersbreach.kotlindictionarymultiplatform.previews.fakeTopicDetails +import com.developersbreach.kotlindictionarymultiplatform.ui.screens.detail.components.SyntaxSection +import com.developersbreach.kotlindictionarymultiplatform.ui.theme.KotlinDictionaryTheme + +@PreviewLightDark +@Composable +fun SyntaxSectionPreview() { + KotlinDictionaryTheme { + SyntaxSection(topic = fakeTopicDetails()) + } +} \ No newline at end of file diff --git a/composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/detail/TableOfContentsPreview.kt b/composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/detail/TableOfContentsPreview.kt new file mode 100644 index 0000000..b9e22c9 --- /dev/null +++ b/composeApp/src/androidMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/previews/detail/TableOfContentsPreview.kt @@ -0,0 +1,15 @@ +package com.developersbreach.kotlindictionarymultiplatform.previews.detail + +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.PreviewLightDark +import com.developersbreach.kotlindictionarymultiplatform.previews.fakeTopicDetails +import com.developersbreach.kotlindictionarymultiplatform.ui.screens.detail.components.TableOfContents +import com.developersbreach.kotlindictionarymultiplatform.ui.theme.KotlinDictionaryTheme + +@PreviewLightDark +@Composable +fun TableOfContentsPreview() { + KotlinDictionaryTheme { + TableOfContents(topic = fakeTopicDetails()) + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/CodeExampleBox.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/CodeExampleBox.kt new file mode 100644 index 0000000..ad15147 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/CodeExampleBox.kt @@ -0,0 +1,119 @@ +package com.developersbreach.kotlindictionarymultiplatform.ui.screens.detail + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Check +import androidx.compose.material.icons.filled.ContentCopy +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalClipboardManager +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import kotlindictionarymultiplatform.composeapp.generated.resources.Res +import kotlindictionarymultiplatform.composeapp.generated.resources.copied +import kotlindictionarymultiplatform.composeapp.generated.resources.copy +import kotlindictionarymultiplatform.composeapp.generated.resources.kotlin +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import org.jetbrains.compose.resources.stringResource + +@Composable +fun CodeExampleBox( + code: String, + modifier: Modifier = Modifier, +) { + val clipboardManager = LocalClipboardManager.current + var copied by remember { mutableStateOf(false) } + + Box( + modifier = modifier + .fillMaxWidth() + .border(1.dp, MaterialTheme.colorScheme.onPrimaryContainer, RoundedCornerShape(8.dp)) + .background(MaterialTheme.colorScheme.primaryContainer, RoundedCornerShape(8.dp)), + ) { + Column(modifier = Modifier.padding(0.dp)) { + Box( + modifier = Modifier + .fillMaxWidth() + .background(MaterialTheme.colorScheme.onPrimaryContainer, RoundedCornerShape(8.dp)) + .padding(6.dp), + ) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + text = stringResource(Res.string.kotlin), + color = MaterialTheme.colorScheme.onPrimary, + fontWeight = FontWeight.Bold, + fontSize = 14.sp, + modifier = Modifier.padding(start = 4.dp), + ) + + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .clickable { + clipboardManager.setText(AnnotatedString(code)) + copied = true + CoroutineScope(Dispatchers.Main).launch { + delay(2500) + copied = false + } + } + .padding(4.dp), + ) { + Icon( + imageVector = if (copied) Icons.Default.Check else Icons.Default.ContentCopy, + contentDescription = stringResource(Res.string.copy), + tint = MaterialTheme.colorScheme.onPrimary, + ) + Spacer(modifier = Modifier.width(4.dp)) + Text( + text = if (copied) stringResource(Res.string.copied) else stringResource(Res.string.copy), + fontSize = 12.sp, + color = MaterialTheme.colorScheme.onPrimary, + ) + } + } + } + + Spacer(modifier = Modifier.height(8.dp)) + + Text( + text = code, + modifier = Modifier.padding(start = 12.dp, end = 12.dp, bottom = 12.dp), + fontFamily = FontFamily.Monospace, + fontSize = 14.sp, + lineHeight = 20.sp, + color = MaterialTheme.colorScheme.onPrimary, + ) + } + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/DetailContent.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/DetailContent.kt new file mode 100644 index 0000000..501cb24 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/DetailContent.kt @@ -0,0 +1,28 @@ +package com.developersbreach.kotlindictionarymultiplatform.ui.screens.detail + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.developersbreach.kotlindictionarymultiplatform.data.detail.model.KotlinTopicDetails +import com.developersbreach.kotlindictionarymultiplatform.ui.screens.detail.components.IntroductionSection +import com.developersbreach.kotlindictionarymultiplatform.ui.screens.detail.components.PitfallsSection +import com.developersbreach.kotlindictionarymultiplatform.ui.screens.detail.components.RelatedTopicsSection +import com.developersbreach.kotlindictionarymultiplatform.ui.screens.detail.components.SectionsList +import com.developersbreach.kotlindictionarymultiplatform.ui.screens.detail.components.SyntaxSection +import com.developersbreach.kotlindictionarymultiplatform.ui.screens.detail.components.TableOfContents + +@Composable +fun DetailContent( + topic: KotlinTopicDetails, + modifier: Modifier = Modifier, +) { + Column(modifier = modifier.fillMaxSize()) { + TableOfContents(topic) + IntroductionSection(topic) + SyntaxSection(topic) + SectionsList(topic) + PitfallsSection(topic) + RelatedTopicsSection(topic) + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/DetailScreen.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/DetailScreen.kt index 3f5f88b..10acca5 100644 --- a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/DetailScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/DetailScreen.kt @@ -1,279 +1,15 @@ package com.developersbreach.kotlindictionarymultiplatform.ui.screens.detail -import androidx.compose.foundation.background -import androidx.compose.foundation.border -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.verticalScroll -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.filled.ArrowBack -import androidx.compose.material.icons.filled.Check -import androidx.compose.material.icons.filled.ContentCopy -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar -import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalClipboardManager -import androidx.compose.ui.text.AnnotatedString -import androidx.compose.ui.text.font.FontFamily -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import com.developersbreach.kotlindictionarymultiplatform.data.detail.model.KotlinTopicDetails import com.developersbreach.kotlindictionarymultiplatform.ui.components.UiStateHandler -import kotlindictionarymultiplatform.composeapp.generated.resources.Res -import kotlindictionarymultiplatform.composeapp.generated.resources.back -import kotlindictionarymultiplatform.composeapp.generated.resources.bullet_item -import kotlindictionarymultiplatform.composeapp.generated.resources.copied -import kotlindictionarymultiplatform.composeapp.generated.resources.copy -import kotlindictionarymultiplatform.composeapp.generated.resources.introduction -import kotlindictionarymultiplatform.composeapp.generated.resources.introduction_bullet -import kotlindictionarymultiplatform.composeapp.generated.resources.kotlin -import kotlindictionarymultiplatform.composeapp.generated.resources.notes_with_value -import kotlindictionarymultiplatform.composeapp.generated.resources.pitfalls -import kotlindictionarymultiplatform.composeapp.generated.resources.pitfalls_bullet -import kotlindictionarymultiplatform.composeapp.generated.resources.related_topics -import kotlindictionarymultiplatform.composeapp.generated.resources.related_topics_bullet -import kotlindictionarymultiplatform.composeapp.generated.resources.sections_bullet -import kotlindictionarymultiplatform.composeapp.generated.resources.syntax -import kotlindictionarymultiplatform.composeapp.generated.resources.syntax_bullet -import kotlindictionarymultiplatform.composeapp.generated.resources.table_of_contents -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch -import org.jetbrains.compose.resources.stringResource @Composable fun DetailScreen(viewModel: DetailViewModel) { val topicState by viewModel.state.collectAsState() UiStateHandler(uiState = topicState) { topic -> - DetailScreenContent(topic) - } -} - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun DetailScreenContent(topic: KotlinTopicDetails) { - val scrollState = rememberScrollState() - - Scaffold( - containerColor = MaterialTheme.colorScheme.background, - topBar = { - TopAppBar( - title = { - Text( - text = topic.topicName, - style = MaterialTheme.typography.displayMedium, - color = MaterialTheme.colorScheme.onPrimary, - modifier = Modifier.fillMaxWidth(), - ) - }, - navigationIcon = { - IconButton(onClick = { }) { - Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = stringResource(Res.string.back)) - } - }, - colors = TopAppBarDefaults.topAppBarColors( - containerColor = MaterialTheme.colorScheme.background, - titleContentColor = MaterialTheme.colorScheme.onPrimary, - navigationIconContentColor = MaterialTheme.colorScheme.onPrimary, - ), - ) - }, - ) { innerPadding -> - Column( - modifier = Modifier - .fillMaxSize() - .verticalScroll(scrollState) - .padding(16.dp) - .padding(innerPadding), - ) { - Text( - text = stringResource(Res.string.table_of_contents), - style = MaterialTheme.typography.titleLarge, - color = MaterialTheme.colorScheme.onPrimary, - ) - Spacer(modifier = Modifier.height(4.dp)) - - val tableOfContents = buildList { - add(stringResource(Res.string.introduction_bullet)) - if (topic.syntax.signature.isNotBlank()) add(stringResource(Res.string.syntax_bullet)) - if (topic.sections.isNotEmpty()) add(stringResource(Res.string.sections_bullet)) - if (topic.pitfalls.isNotEmpty()) add(stringResource(Res.string.pitfalls_bullet)) - if (topic.relatedTopics.isNotEmpty()) add(stringResource(Res.string.related_topics_bullet)) - } - - tableOfContents.forEach { - Text( - text = it, - modifier = Modifier - .clickable { } - .padding(vertical = 4.dp), - color = MaterialTheme.colorScheme.onSurface, - ) - } - - Spacer(modifier = Modifier.height(16.dp)) - - Text(stringResource(Res.string.introduction), style = MaterialTheme.typography.headlineLarge, color = MaterialTheme.colorScheme.onPrimary) - Spacer(modifier = Modifier.height(4.dp)) - Text(text = topic.intro, style = MaterialTheme.typography.bodyMedium) - - Spacer(modifier = Modifier.height(16.dp)) - - Text(stringResource(Res.string.syntax), style = MaterialTheme.typography.headlineLarge, color = MaterialTheme.colorScheme.onPrimary) - Spacer(modifier = Modifier.height(4.dp)) - Text(text = topic.syntax.signature, style = MaterialTheme.typography.bodyMedium) - topic.syntax.notes?.let { - Spacer(modifier = Modifier.height(4.dp)) - Text( - text = stringResource(Res.string.notes_with_value, it), - style = MaterialTheme.typography.bodyMedium, - ) - } - - Spacer(modifier = Modifier.height(16.dp)) - - topic.sections.forEach { section -> - section.heading?.let { - Text(it, style = MaterialTheme.typography.headlineLarge, color = MaterialTheme.colorScheme.onPrimary) - Spacer(modifier = Modifier.height(4.dp)) - } - section.content?.let { - Text(it, style = MaterialTheme.typography.bodyMedium) - Spacer(modifier = Modifier.height(8.dp)) - } - section.codeExamples.forEach { example -> - example.description?.let { - Text( - it, - fontWeight = FontWeight.Bold, - style = MaterialTheme.typography.bodyMedium, - ) - } - Spacer(modifier = Modifier.height(16.dp)) - CodeExampleBox(code = example.code) - Spacer(modifier = Modifier.height(16.dp)) - } - } - - if (topic.pitfalls.isNotEmpty()) { - Text(stringResource(Res.string.pitfalls), style = MaterialTheme.typography.headlineLarge, color = MaterialTheme.colorScheme.onPrimary) - Spacer(modifier = Modifier.height(4.dp)) - topic.pitfalls.forEach { - Text(stringResource(Res.string.bullet_item, it), style = MaterialTheme.typography.bodyMedium) - } - Spacer(modifier = Modifier.height(16.dp)) - } - - if (topic.relatedTopics.isNotEmpty()) { - Text(stringResource(Res.string.related_topics), style = MaterialTheme.typography.headlineLarge, color = MaterialTheme.colorScheme.onPrimary) - Spacer(modifier = Modifier.height(4.dp)) - topic.relatedTopics.forEach { - Text(stringResource(Res.string.bullet_item, it), style = MaterialTheme.typography.bodyMedium) - } - } - } - } -} - -@Composable -fun CodeExampleBox( - code: String, - modifier: Modifier = Modifier, -) { - val clipboardManager = LocalClipboardManager.current - var copied by remember { mutableStateOf(false) } - - Box( - modifier = modifier - .fillMaxWidth() - .border(1.dp, MaterialTheme.colorScheme.onPrimaryContainer, RoundedCornerShape(8.dp)) - .background(MaterialTheme.colorScheme.primaryContainer, RoundedCornerShape(8.dp)), - ) { - Column(modifier = Modifier.padding(0.dp)) { - Box( - modifier = Modifier - .fillMaxWidth() - .background(MaterialTheme.colorScheme.onPrimaryContainer, RoundedCornerShape(8.dp)) - .padding(6.dp), - ) { - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically, - ) { - Text( - text = stringResource(Res.string.kotlin), - color = MaterialTheme.colorScheme.onPrimary, - fontWeight = FontWeight.Bold, - fontSize = 14.sp, - modifier = Modifier.padding(start = 4.dp), - ) - - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier - .clickable { - clipboardManager.setText(AnnotatedString(code)) - copied = true - CoroutineScope(Dispatchers.Main).launch { - delay(2500) - copied = false - } - } - .padding(4.dp), - ) { - Icon( - imageVector = if (copied) Icons.Default.Check else Icons.Default.ContentCopy, - contentDescription = stringResource(Res.string.copy), - tint = MaterialTheme.colorScheme.onPrimary, - ) - Spacer(modifier = Modifier.width(4.dp)) - Text( - text = if (copied) stringResource(Res.string.copied) else stringResource(Res.string.copy), - fontSize = 12.sp, - color = MaterialTheme.colorScheme.onPrimary, - ) - } - } - } - - Spacer(modifier = Modifier.height(8.dp)) - - Text( - text = code, - modifier = Modifier.padding(start = 12.dp, end = 12.dp, bottom = 12.dp), - fontFamily = FontFamily.Monospace, - fontSize = 14.sp, - lineHeight = 20.sp, - color = MaterialTheme.colorScheme.onPrimary, - ) - } + DetailScreenUI(topic) } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/DetailScreenUI.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/DetailScreenUI.kt new file mode 100644 index 0000000..509559e --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/DetailScreenUI.kt @@ -0,0 +1,29 @@ +package com.developersbreach.kotlindictionarymultiplatform.ui.screens.detail + +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.developersbreach.kotlindictionarymultiplatform.data.detail.model.KotlinTopicDetails + +@Composable +fun DetailScreenUI(topic: KotlinTopicDetails) { + val scrollState = rememberScrollState() + + Scaffold( + containerColor = MaterialTheme.colorScheme.background, + topBar = { DetailTopBar(title = topic.topicName) }, + ) { innerPadding -> + DetailContent( + topic = topic, + modifier = Modifier + .padding(innerPadding) + .verticalScroll(scrollState) + .padding(16.dp), + ) + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/DetailTopAppBar.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/DetailTopAppBar.kt new file mode 100644 index 0000000..16736f5 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/DetailTopAppBar.kt @@ -0,0 +1,42 @@ +package com.developersbreach.kotlindictionarymultiplatform.ui.screens.detail + +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import kotlindictionarymultiplatform.composeapp.generated.resources.Res +import kotlindictionarymultiplatform.composeapp.generated.resources.back +import org.jetbrains.compose.resources.stringResource + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun DetailTopBar(title: String) { + TopAppBar( + title = { + Text( + text = title, + style = MaterialTheme.typography.displayMedium, + color = MaterialTheme.colorScheme.onPrimary, + modifier = Modifier.fillMaxWidth(), + ) + }, + navigationIcon = { + IconButton(onClick = { /* TODO: Navigate back */ }) { + Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = stringResource(Res.string.back)) + } + }, + colors = TopAppBarDefaults.topAppBarColors( + containerColor = MaterialTheme.colorScheme.background, + titleContentColor = MaterialTheme.colorScheme.onPrimary, + navigationIconContentColor = MaterialTheme.colorScheme.onPrimary, + ), + ) +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/components/IntroductionSection.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/components/IntroductionSection.kt new file mode 100644 index 0000000..0868acd --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/components/IntroductionSection.kt @@ -0,0 +1,20 @@ +package com.developersbreach.kotlindictionarymultiplatform.ui.screens.detail.components + +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.developersbreach.kotlindictionarymultiplatform.data.detail.model.KotlinTopicDetails +import kotlindictionarymultiplatform.composeapp.generated.resources.Res +import kotlindictionarymultiplatform.composeapp.generated.resources.introduction +import org.jetbrains.compose.resources.stringResource + +@Composable +fun IntroductionSection(topic: KotlinTopicDetails) { + Text(stringResource(Res.string.introduction), style = MaterialTheme.typography.headlineLarge, color = MaterialTheme.colorScheme.onPrimary) + Spacer(modifier = Modifier.height(4.dp)) + Text(text = topic.intro, style = MaterialTheme.typography.bodyMedium) +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/components/PitfallsSection.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/components/PitfallsSection.kt new file mode 100644 index 0000000..df446aa --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/components/PitfallsSection.kt @@ -0,0 +1,26 @@ +package com.developersbreach.kotlindictionarymultiplatform.ui.screens.detail.components + +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.developersbreach.kotlindictionarymultiplatform.data.detail.model.KotlinTopicDetails +import kotlindictionarymultiplatform.composeapp.generated.resources.Res +import kotlindictionarymultiplatform.composeapp.generated.resources.bullet_item +import kotlindictionarymultiplatform.composeapp.generated.resources.pitfalls +import org.jetbrains.compose.resources.stringResource + +@Composable +fun PitfallsSection(topic: KotlinTopicDetails) { + if (topic.pitfalls.isNotEmpty()) { + Text(stringResource(Res.string.pitfalls), style = MaterialTheme.typography.headlineLarge, color = MaterialTheme.colorScheme.onPrimary) + Spacer(Modifier.height(4.dp)) + topic.pitfalls.forEach { + Text(stringResource(Res.string.bullet_item, it), style = MaterialTheme.typography.bodyMedium) + } + Spacer(Modifier.height(16.dp)) + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/components/RelatedTopicsSection.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/components/RelatedTopicsSection.kt new file mode 100644 index 0000000..75137db --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/components/RelatedTopicsSection.kt @@ -0,0 +1,25 @@ +package com.developersbreach.kotlindictionarymultiplatform.ui.screens.detail.components + +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.developersbreach.kotlindictionarymultiplatform.data.detail.model.KotlinTopicDetails +import kotlindictionarymultiplatform.composeapp.generated.resources.Res +import kotlindictionarymultiplatform.composeapp.generated.resources.bullet_item +import kotlindictionarymultiplatform.composeapp.generated.resources.related_topics +import org.jetbrains.compose.resources.stringResource + +@Composable +fun RelatedTopicsSection(topic: KotlinTopicDetails) { + if (topic.relatedTopics.isNotEmpty()) { + Text(stringResource(Res.string.related_topics), style = MaterialTheme.typography.headlineLarge, color = MaterialTheme.colorScheme.onPrimary) + Spacer(Modifier.height(4.dp)) + topic.relatedTopics.forEach { + Text(stringResource(Res.string.bullet_item, it), style = MaterialTheme.typography.bodyMedium) + } + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/components/SectionsList.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/components/SectionsList.kt new file mode 100644 index 0000000..e9522fd --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/components/SectionsList.kt @@ -0,0 +1,34 @@ +package com.developersbreach.kotlindictionarymultiplatform.ui.screens.detail.components + +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import com.developersbreach.kotlindictionarymultiplatform.data.detail.model.KotlinTopicDetails +import com.developersbreach.kotlindictionarymultiplatform.ui.screens.detail.CodeExampleBox + +@Composable +fun SectionsList(topic: KotlinTopicDetails) { + topic.sections.forEach { section -> + section.heading?.let { + Text(it, style = MaterialTheme.typography.headlineLarge, color = MaterialTheme.colorScheme.onPrimary) + Spacer(Modifier.height(4.dp)) + } + section.content?.let { + Text(it, style = MaterialTheme.typography.bodyMedium) + Spacer(Modifier.height(8.dp)) + } + section.codeExamples.forEach { example -> + example.description?.let { + Text(it, fontWeight = FontWeight.Bold, style = MaterialTheme.typography.bodyMedium) + } + Spacer(Modifier.height(16.dp)) + CodeExampleBox(code = example.code) + Spacer(Modifier.height(16.dp)) + } + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/components/SyntaxSection.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/components/SyntaxSection.kt new file mode 100644 index 0000000..2ad56a3 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/components/SyntaxSection.kt @@ -0,0 +1,31 @@ +package com.developersbreach.kotlindictionarymultiplatform.ui.screens.detail.components + +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.developersbreach.kotlindictionarymultiplatform.data.detail.model.KotlinTopicDetails +import kotlindictionarymultiplatform.composeapp.generated.resources.Res +import kotlindictionarymultiplatform.composeapp.generated.resources.notes_with_value +import kotlindictionarymultiplatform.composeapp.generated.resources.syntax +import org.jetbrains.compose.resources.stringResource + +@Composable +fun SyntaxSection(topic: KotlinTopicDetails) { + if (topic.syntax.signature.isNotBlank()) { + Text(stringResource(Res.string.syntax), style = MaterialTheme.typography.headlineLarge, color = MaterialTheme.colorScheme.onPrimary) + Spacer(Modifier.height(4.dp)) + Text(text = topic.syntax.signature, style = MaterialTheme.typography.bodyMedium) + topic.syntax.notes?.let { + Spacer(Modifier.height(4.dp)) + Text( + text = stringResource(Res.string.notes_with_value, it), + style = MaterialTheme.typography.bodyMedium, + ) + } + Spacer(Modifier.height(16.dp)) + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/components/TableOfContents.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/components/TableOfContents.kt new file mode 100644 index 0000000..4413978 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/components/TableOfContents.kt @@ -0,0 +1,44 @@ +package com.developersbreach.kotlindictionarymultiplatform.ui.screens.detail.components + +import androidx.compose.foundation.clickable +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.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.developersbreach.kotlindictionarymultiplatform.data.detail.model.KotlinTopicDetails +import kotlindictionarymultiplatform.composeapp.generated.resources.Res +import kotlindictionarymultiplatform.composeapp.generated.resources.introduction_bullet +import kotlindictionarymultiplatform.composeapp.generated.resources.pitfalls_bullet +import kotlindictionarymultiplatform.composeapp.generated.resources.related_topics_bullet +import kotlindictionarymultiplatform.composeapp.generated.resources.sections_bullet +import kotlindictionarymultiplatform.composeapp.generated.resources.syntax_bullet +import kotlindictionarymultiplatform.composeapp.generated.resources.table_of_contents +import org.jetbrains.compose.resources.stringResource + +@Composable +fun TableOfContents(topic: KotlinTopicDetails) { + val items = buildList { + add(stringResource(Res.string.introduction_bullet)) + if (topic.syntax.signature.isNotBlank()) add(stringResource(Res.string.syntax_bullet)) + if (topic.sections.isNotEmpty()) add(stringResource(Res.string.sections_bullet)) + if (topic.pitfalls.isNotEmpty()) add(stringResource(Res.string.pitfalls_bullet)) + if (topic.relatedTopics.isNotEmpty()) add(stringResource(Res.string.related_topics_bullet)) + } + + Text(text = stringResource(Res.string.table_of_contents), style = MaterialTheme.typography.titleLarge, color = MaterialTheme.colorScheme.onPrimary) + Spacer(Modifier.height(4.dp)) + items.forEach { + Text( + text = it, + modifier = Modifier + .clickable { /* scroll-to support later */ } + .padding(vertical = 4.dp), + color = MaterialTheme.colorScheme.onSurface, + ) + } + Spacer(Modifier.height(16.dp)) +} \ No newline at end of file