From 57f021b8b5db14c1626b4cc04c2d0d42f10d6405 Mon Sep 17 00:00:00 2001 From: komodgn Date: Thu, 14 May 2026 00:05:40 +0900 Subject: [PATCH] feat(demo): Update sample app - Add CodeEditor sample. --- .../io/github/komodgn/example/Application.kt | 140 ++++++++---------- .../github/komodgn/example/DemoComponent.kt | 21 +++ .../komodgn/example/component/DemoTopBar.kt | 109 ++++++++++++++ .../example/section/CodeEditorSection.kt | 63 ++++++++ .../example/section/CodeViewSection.kt | 9 +- .../komodgn/example/section/EditorSection.kt | 1 - 6 files changed, 265 insertions(+), 78 deletions(-) create mode 100644 example/src/commonMain/kotlin/io/github/komodgn/example/DemoComponent.kt create mode 100644 example/src/commonMain/kotlin/io/github/komodgn/example/component/DemoTopBar.kt create mode 100644 example/src/commonMain/kotlin/io/github/komodgn/example/section/CodeEditorSection.kt diff --git a/example/src/commonMain/kotlin/io/github/komodgn/example/Application.kt b/example/src/commonMain/kotlin/io/github/komodgn/example/Application.kt index bbfc4de..8f0cbb5 100644 --- a/example/src/commonMain/kotlin/io/github/komodgn/example/Application.kt +++ b/example/src/commonMain/kotlin/io/github/komodgn/example/Application.kt @@ -24,33 +24,25 @@ import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.imePadding -import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.safeDrawing -import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.DarkMode -import androidx.compose.material.icons.filled.LightMode -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.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import io.github.komodgn.AppConfig import io.github.komodgn.codeview.core.CodeLanguage +import io.github.komodgn.example.component.DemoTopBar +import io.github.komodgn.example.section.CodeEditorSection import io.github.komodgn.example.section.CodeViewSection import io.github.komodgn.example.section.EditorSection import io.github.komodgn.example.theme.CodeViewTheme @@ -59,9 +51,9 @@ import io.github.komodgn.example.util.getInitialCode @Composable fun App() { var isDark by rememberSaveable { mutableStateOf(true) } + var selectedComponent by rememberSaveable { mutableStateOf(DemoComponent.CODE_VIEW) } var currentLang by remember { mutableStateOf(CodeLanguage.KOTLIN) } var userInput by remember { mutableStateOf(getInitialCode(currentLang, AppConfig.LIBRARY_VERSION)) } - val scrollState = rememberScrollState() CodeViewTheme(isDarkTheme = isDark) { Scaffold( @@ -69,29 +61,12 @@ fun App() { .fillMaxSize(), contentWindowInsets = WindowInsets(0, 0, 0, 0), topBar = { - Row( - modifier = Modifier - .fillMaxWidth() - .statusBarsPadding() - .navigationBarsPadding() - .background(MaterialTheme.colorScheme.primary) - .padding(horizontal = 16.dp, vertical = 8.dp), - verticalAlignment = Alignment.CenterVertically, - ) { - Text( - text = "Compose CodeView Demo", - fontWeight = FontWeight.Bold, - color = MaterialTheme.colorScheme.background, - modifier = Modifier.padding(8.dp), - ) - IconButton(onClick = { isDark = !isDark }) { - Icon( - imageVector = if (isDark) Icons.Default.LightMode else Icons.Default.DarkMode, - contentDescription = "Toggle Theme", - tint = MaterialTheme.colorScheme.background, - ) - } - } + DemoTopBar( + isDark = isDark, + onToggleTheme = { isDark = !isDark }, + selectedComponent = selectedComponent, + onComponentSelect = { selectedComponent = it }, + ) }, ) { innerPadding -> BoxWithConstraints( @@ -102,52 +77,65 @@ fun App() { .windowInsetsPadding(WindowInsets.safeDrawing) .imePadding(), ) { - val isCompact = maxWidth < 600.dp + MainContent( + isCompact = maxWidth < 600.dp, + selectedDemoComponent = selectedComponent, + code = userInput, + language = currentLang, + onCodeChange = { userInput = it }, + onLanguageChange = { newLang -> + currentLang = newLang + userInput = getInitialCode(newLang, AppConfig.LIBRARY_VERSION) + }, + ) + } + } + } +} + +@Composable +private fun MainContent( + isCompact: Boolean, + selectedDemoComponent: DemoComponent, + code: String, + language: CodeLanguage, + onCodeChange: (String) -> Unit, + onLanguageChange: (CodeLanguage) -> Unit, +) { + val scrollState = rememberScrollState() - Column( - modifier = Modifier - .fillMaxWidth() - .verticalScroll(scrollState) - .padding(horizontal = 16.dp, vertical = 8.dp), - verticalArrangement = Arrangement.Center, - ) { - if (isCompact) { - CodeViewSection( - code = userInput, - language = currentLang, - modifier = Modifier.fillMaxWidth(), - ) - EditorSection( - code = userInput, - selectedLanguage = currentLang, - onLanguageChange = { newLang -> - currentLang = newLang - userInput = getInitialCode(currentLang, AppConfig.LIBRARY_VERSION) - }, - onValueChange = { userInput = it }, - modifier = Modifier.fillMaxWidth(), - ) - } else { - Row(modifier = Modifier.fillMaxWidth().padding(16.dp, 0.dp, 16.dp, 0.dp)) { - EditorSection( - code = userInput, - selectedLanguage = currentLang, - onLanguageChange = { newLang -> - currentLang = newLang - userInput = getInitialCode(currentLang, AppConfig.LIBRARY_VERSION) - }, - onValueChange = { userInput = it }, - modifier = Modifier.weight(1f), - ) - CodeViewSection( - code = userInput, - language = currentLang, - modifier = Modifier.weight(1f), - ) - } + Column( + modifier = Modifier + .fillMaxWidth() + .verticalScroll(scrollState) + .padding(horizontal = 16.dp, vertical = 8.dp), + verticalArrangement = Arrangement.Center, + ) { + when (selectedDemoComponent) { + DemoComponent.CODE_VIEW -> { + if (isCompact) { + CodeViewSection(code, language, Modifier.fillMaxWidth()) + EditorSection(code, language, onLanguageChange, onCodeChange, Modifier.fillMaxWidth()) + } else { + Row( + modifier = Modifier.fillMaxWidth().padding(horizontal = 8.dp), + horizontalArrangement = Arrangement.spacedBy(8.dp), + ) { + EditorSection(code, language, onLanguageChange, onCodeChange, Modifier.weight(1f)) + CodeViewSection(code, language, Modifier.weight(1f)) } } } + + DemoComponent.CODE_EDITOR -> { + CodeEditorSection( + code, + language, + onCodeChange, + selectedLanguage = language, + onLanguageChange = onLanguageChange, + ) + } } } } diff --git a/example/src/commonMain/kotlin/io/github/komodgn/example/DemoComponent.kt b/example/src/commonMain/kotlin/io/github/komodgn/example/DemoComponent.kt new file mode 100644 index 0000000..caff562 --- /dev/null +++ b/example/src/commonMain/kotlin/io/github/komodgn/example/DemoComponent.kt @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2026 komodgn + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.github.komodgn.example + +enum class DemoComponent { + CODE_VIEW, + CODE_EDITOR, +} diff --git a/example/src/commonMain/kotlin/io/github/komodgn/example/component/DemoTopBar.kt b/example/src/commonMain/kotlin/io/github/komodgn/example/component/DemoTopBar.kt new file mode 100644 index 0000000..10f2ce0 --- /dev/null +++ b/example/src/commonMain/kotlin/io/github/komodgn/example/component/DemoTopBar.kt @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2026 komodgn + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.github.komodgn.example.component + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.statusBarsPadding +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.DarkMode +import androidx.compose.material.icons.filled.LightMode +import androidx.compose.material3.FilterChip +import androidx.compose.material3.FilterChipDefaults +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import io.github.komodgn.example.DemoComponent + +@Composable +fun DemoTopBar( + isDark: Boolean, + onToggleTheme: () -> Unit, + selectedComponent: DemoComponent, + onComponentSelect: (DemoComponent) -> Unit, +) { + Column( + modifier = Modifier + .fillMaxWidth() + .background(MaterialTheme.colorScheme.primary) + .statusBarsPadding(), + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(start = 16.dp, end = 16.dp, top = 4.dp, bottom = 0.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween, + ) { + Text( + text = "Compose CodeView Demo", + fontWeight = FontWeight.Bold, + color = MaterialTheme.colorScheme.onPrimary, + modifier = Modifier.padding(8.dp), + ) + IconButton(onClick = onToggleTheme) { + Icon( + imageVector = if (isDark) Icons.Default.LightMode else Icons.Default.DarkMode, + contentDescription = "Toggle Theme", + tint = MaterialTheme.colorScheme.onPrimary, + ) + } + } + + Row( + modifier = Modifier + .fillMaxWidth() + .padding(start = 16.dp, end = 16.dp, top = 0.dp, bottom = 8.dp), + horizontalArrangement = Arrangement.spacedBy(12.dp), + ) { + DemoComponent.entries.forEach { component -> + val isSelected = selectedComponent == component + FilterChip( + selected = isSelected, + onClick = { onComponentSelect(component) }, + label = { + Text( + text = when (component) { + DemoComponent.CODE_VIEW -> "CodeView" + DemoComponent.CODE_EDITOR -> "CodeEditor" + }, + ) + }, + colors = FilterChipDefaults.filterChipColors( + labelColor = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.7f), + selectedLabelColor = MaterialTheme.colorScheme.primary, + selectedContainerColor = MaterialTheme.colorScheme.onPrimary, + ), + border = FilterChipDefaults.filterChipBorder( + enabled = true, + selected = isSelected, + borderColor = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.5f), + ), + ) + } + } + } +} diff --git a/example/src/commonMain/kotlin/io/github/komodgn/example/section/CodeEditorSection.kt b/example/src/commonMain/kotlin/io/github/komodgn/example/section/CodeEditorSection.kt new file mode 100644 index 0000000..af57de5 --- /dev/null +++ b/example/src/commonMain/kotlin/io/github/komodgn/example/section/CodeEditorSection.kt @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2026 komodgn + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.github.komodgn.example.section + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +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.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import io.github.komodgn.codeview.compose.CodeEditor +import io.github.komodgn.codeview.core.CodeLanguage +import io.github.komodgn.example.component.LanguageDropDown + +@Composable +fun CodeEditorSection( + code: String, + language: CodeLanguage, + onValueChange: (String) -> Unit, + selectedLanguage: CodeLanguage, + onLanguageChange: (CodeLanguage) -> Unit, + modifier: Modifier = Modifier, +) { + Column(modifier = modifier.padding(16.dp, 8.dp, 16.dp, 16.dp)) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 8.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + text = "CodeEditor Preview", + style = MaterialTheme.typography.titleMedium, + ) + LanguageDropDown( + selectedLanguage = selectedLanguage, + onLanguageChange = onLanguageChange, + ) + } + CodeEditor( + value = code, + onValueChange = onValueChange, + language = language, + ) + } +} diff --git a/example/src/commonMain/kotlin/io/github/komodgn/example/section/CodeViewSection.kt b/example/src/commonMain/kotlin/io/github/komodgn/example/section/CodeViewSection.kt index d418cff..d8599ec 100644 --- a/example/src/commonMain/kotlin/io/github/komodgn/example/section/CodeViewSection.kt +++ b/example/src/commonMain/kotlin/io/github/komodgn/example/section/CodeViewSection.kt @@ -16,8 +16,11 @@ package io.github.komodgn.example.section import androidx.compose.foundation.layout.Column +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.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -33,7 +36,11 @@ fun CodeViewSection( modifier: Modifier, ) { Column(modifier = modifier.padding(8.dp)) { - Text("Preview", modifier = Modifier.padding(4.dp)) + Text( + text = "CodeView Preview", + style = MaterialTheme.typography.titleMedium, + ) + Spacer(modifier = Modifier.height(8.dp)) CodeView( code = code, language = language, diff --git a/example/src/commonMain/kotlin/io/github/komodgn/example/section/EditorSection.kt b/example/src/commonMain/kotlin/io/github/komodgn/example/section/EditorSection.kt index f66a6e9..6bee3ac 100644 --- a/example/src/commonMain/kotlin/io/github/komodgn/example/section/EditorSection.kt +++ b/example/src/commonMain/kotlin/io/github/komodgn/example/section/EditorSection.kt @@ -50,7 +50,6 @@ fun EditorSection( horizontalArrangement = Arrangement.SpaceBetween, ) { Text( - modifier = Modifier.padding(4.dp), text = "Edit Code", style = MaterialTheme.typography.titleMedium, )