From d1898472d5a33550847d789dff265524224dd0d3 Mon Sep 17 00:00:00 2001 From: Shreyas Deshmukh Date: Tue, 10 Jun 2025 21:53:20 +0530 Subject: [PATCH 1/9] - Added a `konsistTest` module to enforce coding conventions. --- build.gradle.kts | 1 + gradle/libs.versions.toml | 7 ++++ konsistTest/build.gradle.kts | 18 ++++++++++ .../java/com/example/konsisttest/MyClass.kt | 4 +++ .../src/test/kotlin/SampleKonsistTest.kt | 33 +++++++++++++++++++ settings.gradle.kts | 3 +- 6 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 konsistTest/build.gradle.kts create mode 100644 konsistTest/src/main/java/com/example/konsisttest/MyClass.kt create mode 100644 konsistTest/src/test/kotlin/SampleKonsistTest.kt diff --git a/build.gradle.kts b/build.gradle.kts index 5b452ac..200c5e9 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -9,4 +9,5 @@ plugins { alias(libs.plugins.serialization) apply false alias(libs.plugins.googleSecrets) apply false alias(libs.plugins.jetbrainsKotlinJvm) apply false + alias(libs.plugins.androidKotlinMultiplatformLibrary) apply false } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 80c5c24..afc614d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -25,6 +25,9 @@ navigation-compose = "2.9.0" ktlint = "12.2.0" secrets = "2.0.1" jetbrainsKotlinJvm = "2.1.10" +kotlinStdlib = "2.1.10" +runner = "1.6.2" +core = "1.6.1" [libraries] androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "navigation-compose" } @@ -59,6 +62,9 @@ koin-bom = { module = "io.insert-koin:koin-bom", version.ref = "koin" } koin-compose = { module = "io.insert-koin:koin-compose" } koin-compose-viewmodel = { module = "io.insert-koin:koin-compose-viewmodel", version.ref = "koin" } 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" } [plugins] androidApplication = { id = "com.android.application", version.ref = "agp" } @@ -70,3 +76,4 @@ serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint" } googleSecrets = { id = "com.google.android.libraries.mapsplatform.secrets-gradle-plugin", version.ref = "secrets" } jetbrainsKotlinJvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "jetbrainsKotlinJvm" } +androidKotlinMultiplatformLibrary = { id = "com.android.kotlin.multiplatform.library", version.ref = "agp" } diff --git a/konsistTest/build.gradle.kts b/konsistTest/build.gradle.kts new file mode 100644 index 0000000..b3af5fe --- /dev/null +++ b/konsistTest/build.gradle.kts @@ -0,0 +1,18 @@ +plugins { + kotlin("jvm") + id("java") +} + +kotlin { + jvmToolchain(21) +} + +dependencies { + testImplementation("com.lemonappdev:konsist:0.17.2") + testImplementation("org.junit.jupiter:junit-jupiter-engine:5.11.3") + testImplementation(kotlin("test")) +} + +tasks.test { + useJUnitPlatform() +} diff --git a/konsistTest/src/main/java/com/example/konsisttest/MyClass.kt b/konsistTest/src/main/java/com/example/konsisttest/MyClass.kt new file mode 100644 index 0000000..9d23051 --- /dev/null +++ b/konsistTest/src/main/java/com/example/konsisttest/MyClass.kt @@ -0,0 +1,4 @@ +package com.example.konsisttest + +class MyClass { +} \ No newline at end of file diff --git a/konsistTest/src/test/kotlin/SampleKonsistTest.kt b/konsistTest/src/test/kotlin/SampleKonsistTest.kt new file mode 100644 index 0000000..fc68119 --- /dev/null +++ b/konsistTest/src/test/kotlin/SampleKonsistTest.kt @@ -0,0 +1,33 @@ +import com.lemonappdev.konsist.api.Konsist +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Test + +class SampleKonsistTest { + @Test + fun `no direct usage of androidx compose text should be allowed except designSystem`() { + checkNoDirectUsageExceptAllowed( + componentName = "androidx.compose.material.Text", + excludePaths = arrayOf(), + ) + } +} + +fun checkNoDirectUsageExceptAllowed( + componentName: String, + excludePaths: Array, +) { + val offendingFiles = Konsist.scopeFromProject() + .files + .filter { file -> + val normalizedFilePath = file.path.replace("\\", "/").lowercase() + excludePaths.none { normalizedFilePath.contains(it.replace("\\", "/").lowercase()) } + } + .filter { file -> + file.imports.any { it.name == componentName } + } + + assertTrue(offendingFiles.isEmpty()) { + "Found forbidden imports of $componentName in files:\n" + + offendingFiles.joinToString("\n") { it.path } + } +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 622b012..34180fd 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -29,4 +29,5 @@ dependencyResolutionManagement { } include(":composeApp") -include(":custom-ktlint-rules") \ No newline at end of file +include(":custom-ktlint-rules") +include(":konsistTest") \ No newline at end of file From 789a8a237d8ba2fcb54a9234f3c9e317f3d3c907 Mon Sep 17 00:00:00 2001 From: Raj Date: Tue, 10 Jun 2025 23:02:31 +0530 Subject: [PATCH 2/9] Remove redundant konsist and shared modules --- konsistTest/build.gradle.kts | 18 ---------- .../java/com/example/konsisttest/MyClass.kt | 4 --- .../src/test/kotlin/SampleKonsistTest.kt | 33 ------------------- settings.gradle.kts | 1 - 4 files changed, 56 deletions(-) delete mode 100644 konsistTest/build.gradle.kts delete mode 100644 konsistTest/src/main/java/com/example/konsisttest/MyClass.kt delete mode 100644 konsistTest/src/test/kotlin/SampleKonsistTest.kt diff --git a/konsistTest/build.gradle.kts b/konsistTest/build.gradle.kts deleted file mode 100644 index b3af5fe..0000000 --- a/konsistTest/build.gradle.kts +++ /dev/null @@ -1,18 +0,0 @@ -plugins { - kotlin("jvm") - id("java") -} - -kotlin { - jvmToolchain(21) -} - -dependencies { - testImplementation("com.lemonappdev:konsist:0.17.2") - testImplementation("org.junit.jupiter:junit-jupiter-engine:5.11.3") - testImplementation(kotlin("test")) -} - -tasks.test { - useJUnitPlatform() -} diff --git a/konsistTest/src/main/java/com/example/konsisttest/MyClass.kt b/konsistTest/src/main/java/com/example/konsisttest/MyClass.kt deleted file mode 100644 index 9d23051..0000000 --- a/konsistTest/src/main/java/com/example/konsisttest/MyClass.kt +++ /dev/null @@ -1,4 +0,0 @@ -package com.example.konsisttest - -class MyClass { -} \ No newline at end of file diff --git a/konsistTest/src/test/kotlin/SampleKonsistTest.kt b/konsistTest/src/test/kotlin/SampleKonsistTest.kt deleted file mode 100644 index fc68119..0000000 --- a/konsistTest/src/test/kotlin/SampleKonsistTest.kt +++ /dev/null @@ -1,33 +0,0 @@ -import com.lemonappdev.konsist.api.Konsist -import org.junit.jupiter.api.Assertions.assertTrue -import org.junit.jupiter.api.Test - -class SampleKonsistTest { - @Test - fun `no direct usage of androidx compose text should be allowed except designSystem`() { - checkNoDirectUsageExceptAllowed( - componentName = "androidx.compose.material.Text", - excludePaths = arrayOf(), - ) - } -} - -fun checkNoDirectUsageExceptAllowed( - componentName: String, - excludePaths: Array, -) { - val offendingFiles = Konsist.scopeFromProject() - .files - .filter { file -> - val normalizedFilePath = file.path.replace("\\", "/").lowercase() - excludePaths.none { normalizedFilePath.contains(it.replace("\\", "/").lowercase()) } - } - .filter { file -> - file.imports.any { it.name == componentName } - } - - assertTrue(offendingFiles.isEmpty()) { - "Found forbidden imports of $componentName in files:\n" + - offendingFiles.joinToString("\n") { it.path } - } -} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 34180fd..1698ac0 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -30,4 +30,3 @@ dependencyResolutionManagement { include(":composeApp") include(":custom-ktlint-rules") -include(":konsistTest") \ No newline at end of file From 6fc0a70b4f5f111539f3a1a7d5aead8534379287 Mon Sep 17 00:00:00 2001 From: Raj Date: Tue, 10 Jun 2025 23:02:57 +0530 Subject: [PATCH 3/9] Move Konsist checks into desktopTest and add kotlin test dependency --- composeApp/build.gradle.kts | 9 +++++ .../SampleKonsistTest.kt | 34 +++++++++++++++++++ gradle/libs.versions.toml | 2 ++ 3 files changed, 45 insertions(+) create mode 100644 composeApp/src/desktopTest/kotlin/com/developersbreach/kotlindictionarymultiplatform/SampleKonsistTest.kt diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts index 0840d4d..ce91bd6 100644 --- a/composeApp/build.gradle.kts +++ b/composeApp/build.gradle.kts @@ -71,6 +71,15 @@ kotlin { sourceSets { val desktopMain by getting + val commonMain by getting + val commonTest by getting + + val desktopTest by getting { + dependencies { + implementation(kotlin("test")) + implementation(libs.konsist) + } + } androidMain.dependencies { implementation(libs.androidx.activity.compose) diff --git a/composeApp/src/desktopTest/kotlin/com/developersbreach/kotlindictionarymultiplatform/SampleKonsistTest.kt b/composeApp/src/desktopTest/kotlin/com/developersbreach/kotlindictionarymultiplatform/SampleKonsistTest.kt new file mode 100644 index 0000000..dc551ef --- /dev/null +++ b/composeApp/src/desktopTest/kotlin/com/developersbreach/kotlindictionarymultiplatform/SampleKonsistTest.kt @@ -0,0 +1,34 @@ +import kotlin.test.Test +import kotlin.test.assertTrue +import com.lemonappdev.konsist.api.Konsist + +class SampleKonsistTest { + + @Test + fun `no direct usage of androidx compose text should be allowed except designSystem`() { + checkNoDirectUsageExceptAllowed( + componentName = "androidx.compose.material3.Text", + excludePaths = arrayOf(), + ) + } +} + +fun checkNoDirectUsageExceptAllowed( + componentName: String, + excludePaths: Array, +) { + val offendingFiles = Konsist.scopeFromProject() + .files + .filter { file -> + val normalizedFilePath = file.path.replace("\\", "/").lowercase() + excludePaths.none { normalizedFilePath.contains(it.replace("\\", "/").lowercase()) } + } + .filter { file -> + file.imports.any { it.name == componentName } + } + + assertTrue( + actual = offendingFiles.isEmpty(), + message = "Found forbidden imports of $componentName in files:\n" + offendingFiles.joinToString("\n") { it.path }, + ) +} \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index afc614d..51243e7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -16,6 +16,7 @@ compose-multiplatform = "1.7.3" generativeai = "0.9.0" junit = "4.13.2" kermit = "2.0.4" +konsist = "0.17.3" kotlin = "2.1.10" kotlinx-coroutines = "1.10.2" kotlinx-serialization-json = "1.7.3" @@ -35,6 +36,7 @@ arrow-core = { module = "io.arrow-kt:arrow-core", version.ref = "arrowFxCoroutin arrow-fx-coroutines = { module = "io.arrow-kt:arrow-fx-coroutines", version.ref = "arrowFxCoroutines" } generativeai = { module = "com.google.ai.client.generativeai:generativeai", version.ref = "generativeai" } kermit = { module = "co.touchlab:kermit", version.ref = "kermit" } +konsist = { module = "com.lemonappdev:konsist", version.ref = "konsist" } kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" } kotlin-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" } junit = { group = "junit", name = "junit", version.ref = "junit" } From 7230ace1e7438a2ff0bc8fd155474097520bd748 Mon Sep 17 00:00:00 2001 From: Shreyas Deshmukh Date: Wed, 11 Jun 2025 17:13:20 +0530 Subject: [PATCH 4/9] Create a `design-system` module - Introduce `KonsistUtils.kt` with a `checkNoDirectUsageExceptAllowed` function to support these tests. --- composeApp/build.gradle.kts | 1 + .../{SampleKonsistTest.kt => KonsistUtils.kt} | 16 +-- design-system/build.gradle.kts | 106 ++++++++++++++++++ .../design_system/ExampleInstrumentedTest.kt | 24 ++++ .../example/design_system/ExampleUnitTest.kt | 16 +++ .../src/androidMain/AndroidManifest.xml | 4 + .../com/example/design_system/platform.kt | 3 + .../com/example/design_system/Platform.ios.kt | 3 + gradle/libs.versions.toml | 2 +- settings.gradle.kts | 1 + 10 files changed, 162 insertions(+), 14 deletions(-) rename composeApp/src/desktopTest/kotlin/com/developersbreach/kotlindictionarymultiplatform/{SampleKonsistTest.kt => KonsistUtils.kt} (70%) create mode 100644 design-system/build.gradle.kts create mode 100644 design-system/src/androidDeviceTest/kotlin/com/example/design_system/ExampleInstrumentedTest.kt create mode 100644 design-system/src/androidHostTest/kotlin/com/example/design_system/ExampleUnitTest.kt create mode 100644 design-system/src/androidMain/AndroidManifest.xml create mode 100644 design-system/src/appleMain/kotlin/com/example/design_system/platform.kt create mode 100644 design-system/src/iosMain/kotlin/com/example/design_system/Platform.ios.kt diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts index ce91bd6..4cd8b46 100644 --- a/composeApp/build.gradle.kts +++ b/composeApp/build.gradle.kts @@ -114,6 +114,7 @@ kotlin { implementation(libs.kermit) implementation(libs.arrow.core) implementation(libs.arrow.fx.coroutines) + implementation(project(":design-system")) } desktopMain.dependencies { implementation(compose.desktop.currentOs) diff --git a/composeApp/src/desktopTest/kotlin/com/developersbreach/kotlindictionarymultiplatform/SampleKonsistTest.kt b/composeApp/src/desktopTest/kotlin/com/developersbreach/kotlindictionarymultiplatform/KonsistUtils.kt similarity index 70% rename from composeApp/src/desktopTest/kotlin/com/developersbreach/kotlindictionarymultiplatform/SampleKonsistTest.kt rename to composeApp/src/desktopTest/kotlin/com/developersbreach/kotlindictionarymultiplatform/KonsistUtils.kt index dc551ef..4afe52d 100644 --- a/composeApp/src/desktopTest/kotlin/com/developersbreach/kotlindictionarymultiplatform/SampleKonsistTest.kt +++ b/composeApp/src/desktopTest/kotlin/com/developersbreach/kotlindictionarymultiplatform/KonsistUtils.kt @@ -1,17 +1,7 @@ -import kotlin.test.Test -import kotlin.test.assertTrue -import com.lemonappdev.konsist.api.Konsist - -class SampleKonsistTest { +package com.developersbreach.kotlindictionarymultiplatform - @Test - fun `no direct usage of androidx compose text should be allowed except designSystem`() { - checkNoDirectUsageExceptAllowed( - componentName = "androidx.compose.material3.Text", - excludePaths = arrayOf(), - ) - } -} +import com.lemonappdev.konsist.api.Konsist +import kotlin.test.assertTrue fun checkNoDirectUsageExceptAllowed( componentName: String, diff --git a/design-system/build.gradle.kts b/design-system/build.gradle.kts new file mode 100644 index 0000000..84e2094 --- /dev/null +++ b/design-system/build.gradle.kts @@ -0,0 +1,106 @@ +plugins { + alias(libs.plugins.kotlinMultiplatform) + alias(libs.plugins.androidKotlinMultiplatformLibrary) + alias(libs.plugins.composeMultiplatform) + alias(libs.plugins.composeCompiler) +} + +kotlin { + + // Target declarations - add or remove as needed below. These define + // which platforms this KMP module supports. + // See: https://kotlinlang.org/docs/multiplatform-discover-project.html#targets + androidLibrary { + namespace = "com.example.design_system" + compileSdk = 35 + minSdk = 24 + + withHostTestBuilder { + } + + withDeviceTestBuilder { + sourceSetTreeName = "test" + }.configure { + instrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + } + + // For iOS targets, this is also where you should + // configure native binary output. For more information, see: + // https://kotlinlang.org/docs/multiplatform-build-native-binaries.html#build-xcframeworks + + // A step-by-step guide on how to include this library in an XCode + // project can be found here: + // https://developer.android.com/kotlin/multiplatform/migrate + val xcfName = "design-systemKit" + + iosX64 { + binaries.framework { + baseName = xcfName + } + } + + iosArm64 { + binaries.framework { + baseName = xcfName + } + } + + iosSimulatorArm64 { + binaries.framework { + baseName = xcfName + } + } + + jvm("desktop") + + // Source set declarations. + // Declaring a target automatically creates a source set with the same name. By default, the + // Kotlin Gradle Plugin creates additional source sets that depend on each other, since it is + // common to share sources between related targets. + // See: https://kotlinlang.org/docs/multiplatform-hierarchy.html + sourceSets { + commonMain { + dependencies { + implementation(libs.kotlin.stdlib) + implementation(compose.runtime) + implementation(compose.foundation) + implementation(compose.material3) + } + } + + commonTest { + dependencies { + implementation(libs.kotlin.test) + implementation(compose.ui) + } + } + + androidMain { + dependencies { + // Add Android-specific dependencies here. Note that this source set depends on + // commonMain by default and will correctly pull the Android artifacts of any KMP + // dependencies declared in commonMain. + } + } + + getByName("androidDeviceTest") { + dependencies { + implementation(libs.androidx.runner) + implementation(libs.androidx.core) + implementation(libs.androidx.test.junit) + } + } + + iosMain { + dependencies { + // Add iOS-specific dependencies here. This a source set created by Kotlin Gradle + // Plugin (KGP) that each specific iOS target (e.g., iosX64) depends on as + // part of KMP’s default source set hierarchy. Note that this source set depends + // on common by default and will correctly pull the iOS artifacts of any + // KMP dependencies declared in commonMain. + } + } + } + +} \ No newline at end of file diff --git a/design-system/src/androidDeviceTest/kotlin/com/example/design_system/ExampleInstrumentedTest.kt b/design-system/src/androidDeviceTest/kotlin/com/example/design_system/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..4dca5d2 --- /dev/null +++ b/design-system/src/androidDeviceTest/kotlin/com/example/design_system/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.example.design_system + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.example.design_system.test", appContext.packageName) + } +} \ No newline at end of file diff --git a/design-system/src/androidHostTest/kotlin/com/example/design_system/ExampleUnitTest.kt b/design-system/src/androidHostTest/kotlin/com/example/design_system/ExampleUnitTest.kt new file mode 100644 index 0000000..ac78ab1 --- /dev/null +++ b/design-system/src/androidHostTest/kotlin/com/example/design_system/ExampleUnitTest.kt @@ -0,0 +1,16 @@ +package com.example.design_system + +import kotlin.test.Test +import kotlin.test.assertEquals + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} \ No newline at end of file diff --git a/design-system/src/androidMain/AndroidManifest.xml b/design-system/src/androidMain/AndroidManifest.xml new file mode 100644 index 0000000..a5918e6 --- /dev/null +++ b/design-system/src/androidMain/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/design-system/src/appleMain/kotlin/com/example/design_system/platform.kt b/design-system/src/appleMain/kotlin/com/example/design_system/platform.kt new file mode 100644 index 0000000..c2bd6dc --- /dev/null +++ b/design-system/src/appleMain/kotlin/com/example/design_system/platform.kt @@ -0,0 +1,3 @@ +package com.example.design_system + +expect fun platform(): String \ No newline at end of file diff --git a/design-system/src/iosMain/kotlin/com/example/design_system/Platform.ios.kt b/design-system/src/iosMain/kotlin/com/example/design_system/Platform.ios.kt new file mode 100644 index 0000000..69be02b --- /dev/null +++ b/design-system/src/iosMain/kotlin/com/example/design_system/Platform.ios.kt @@ -0,0 +1,3 @@ +package com.example.design_system + +actual fun platform() = "iOS" \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 51243e7..f76afe7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -78,4 +78,4 @@ serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint" } googleSecrets = { id = "com.google.android.libraries.mapsplatform.secrets-gradle-plugin", version.ref = "secrets" } jetbrainsKotlinJvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "jetbrainsKotlinJvm" } -androidKotlinMultiplatformLibrary = { id = "com.android.kotlin.multiplatform.library", version.ref = "agp" } +androidKotlinMultiplatformLibrary = { id = "com.android.kotlin.multiplatform.library", version.ref = "agp" } \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 1698ac0..45223d3 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -30,3 +30,4 @@ dependencyResolutionManagement { include(":composeApp") include(":custom-ktlint-rules") +include(":design-system") From b2218711af3826296f09021145285cb255b0c3ac Mon Sep 17 00:00:00 2001 From: Shreyas Deshmukh Date: Wed, 11 Jun 2025 17:16:36 +0530 Subject: [PATCH 5/9] - Introduce new design system components: `CaIcon`, `CaIconButton`, `CaScaffold`, `CaSurface`, and `CaTextField`. - Migrate existing UI elements in `composeApp` to use the new design system components. - Add tests to ensure that direct usage of `androidx.compose.material3` components is disallowed, promoting the use of the new design system components. - Mark the task "Create a separate module for reusable UI components" as complete in `README.md`. --- README.md | 2 +- .../ui/screens/detail/CodeExampleBox.kt | 4 +- .../ui/screens/detail/DetailScreenUI.kt | 18 +-- .../ui/screens/detail/DetailTopAppBar.kt | 14 +-- .../ui/screens/topic/SearchField.kt | 8 +- .../ui/screens/topic/TopicCard.kt | 105 ++++++++++-------- .../ui/screens/topic/TopicScreenUI.kt | 45 ++++---- .../ui/screens/topic/TopicTopAppBar.kt | 14 +-- .../DesignSystemTest.kt | 56 ++++++++++ .../designsystem/components/Icon.kt | 20 ++++ .../designsystem/components/IconButton.kt | 26 +++++ .../designsystem/components/Scaffold.kt | 20 ++++ .../designsystem/components/Surface.kt | 22 ++++ .../designsystem/components/TextField.kt | 40 +++++++ 14 files changed, 290 insertions(+), 104 deletions(-) create mode 100644 composeApp/src/desktopTest/kotlin/com/developersbreach/kotlindictionarymultiplatform/DesignSystemTest.kt create mode 100644 design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Icon.kt create mode 100644 design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/IconButton.kt create mode 100644 design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Scaffold.kt create mode 100644 design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Surface.kt create mode 100644 design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/TextField.kt diff --git a/README.md b/README.md index 9914c00..69f1c1d 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ - [x] Hide API key from code by using expect/actual for OpenAPI key - [x] Switch AI integration from OpenAI to Gemini - [x] Refactor network layer for cleaner architecture -- [ ] Create a separate module for reusable UI components +- [x] Create a separate module for reusable UI components --- 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 index 1c6643c..d6aa5af 100644 --- 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 @@ -16,7 +16,6 @@ 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 @@ -32,6 +31,7 @@ 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.designsystem.components.CaIcon import kotlindictionarymultiplatform.composeapp.generated.resources.Res import kotlindictionarymultiplatform.composeapp.generated.resources.copied import kotlindictionarymultiplatform.composeapp.generated.resources.copy @@ -99,7 +99,7 @@ fun CodeExampleBox( } .padding(4.dp), ) { - Icon( + CaIcon( imageVector = if (copied) Icons.Default.Check else Icons.Default.ContentCopy, contentDescription = stringResource(Res.string.copy), tint = MaterialTheme.colorScheme.onPrimary, 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 index 4a32901..c81cdd1 100644 --- 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 @@ -8,12 +8,12 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp +import com.developersbreach.designsystem.components.CaScaffold import kotlindictionarymultiplatform.composeapp.generated.resources.Res import kotlindictionarymultiplatform.composeapp.generated.resources.table_of_contents import kotlinx.coroutines.launch @@ -24,20 +24,20 @@ fun DetailScreenUI( detailUiState: DetailUiState, navigateUp: () -> Unit, ) { - Scaffold( + CaScaffold( topBar = { DetailTopBar( title = detailUiState.topicName, navigateUp = navigateUp, ) }, - containerColor = MaterialTheme.colorScheme.background, - ) { innerPadding -> - DetailContent( - detailUiState = detailUiState, - modifier = Modifier.padding(innerPadding), - ) - } + content = { innerPadding -> + DetailContent( + detailUiState = detailUiState, + modifier = Modifier.padding(innerPadding), + ) + }, + ) } @Composable 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 index ad1912f..40d94c4 100644 --- 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 @@ -4,14 +4,13 @@ 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 com.developersbreach.designsystem.components.CaIconButton import kotlindictionarymultiplatform.composeapp.generated.resources.Res import kotlindictionarymultiplatform.composeapp.generated.resources.back import org.jetbrains.compose.resources.stringResource @@ -32,12 +31,11 @@ fun DetailTopBar( ) }, navigationIcon = { - IconButton(onClick = navigateUp) { - Icon( - imageVector = Icons.AutoMirrored.Filled.ArrowBack, - contentDescription = stringResource(Res.string.back), - ) - } + CaIconButton( + onClick = navigateUp, + imageVector = Icons.AutoMirrored.Filled.ArrowBack, + contentDescription = stringResource(Res.string.back), + ) }, colors = TopAppBarDefaults.topAppBarColors( containerColor = MaterialTheme.colorScheme.background, diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/SearchField.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/SearchField.kt index c53f9e2..7c06094 100644 --- a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/SearchField.kt +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/SearchField.kt @@ -7,10 +7,8 @@ import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Search -import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text -import androidx.compose.material3.TextField import androidx.compose.material3.TextFieldDefaults import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -20,6 +18,8 @@ import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import com.developersbreach.designsystem.components.CaIcon +import com.developersbreach.designsystem.components.CaTextField import kotlindictionarymultiplatform.composeapp.generated.resources.Res import kotlindictionarymultiplatform.composeapp.generated.resources.search import kotlindictionarymultiplatform.composeapp.generated.resources.search_kotlin_terms @@ -30,7 +30,7 @@ fun SearchField( searchQuery: String, onQueryChange: (String) -> Unit, ) { - TextField( + CaTextField( value = searchQuery, onValueChange = onQueryChange, modifier = Modifier @@ -46,7 +46,7 @@ fun SearchField( ) }, leadingIcon = { - Icon( + CaIcon( imageVector = Icons.Filled.Search, contentDescription = stringResource(Res.string.search), tint = MaterialTheme.colorScheme.onBackground, 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 1a66905..90cd8ec 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 @@ -16,10 +16,7 @@ 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.Icon -import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -27,6 +24,8 @@ 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.CaIconButton +import com.developersbreach.designsystem.components.CaSurface import kotlindictionarymultiplatform.composeapp.generated.resources.Res import kotlindictionarymultiplatform.composeapp.generated.resources.add_bookmark import kotlindictionarymultiplatform.composeapp.generated.resources.remove_bookmark @@ -41,7 +40,7 @@ fun TopicCard( onBookmarkClick: () -> Unit, onCardClick: () -> Unit, ) { - Surface( + CaSurface( modifier = Modifier .fillMaxWidth() .padding(8.dp) @@ -51,58 +50,66 @@ fun TopicCard( clip = true, ) .clickable { onCardClick() }, - shape = RoundedCornerShape(16.dp), color = MaterialTheme.colorScheme.surface, - ) { - Row( - modifier = Modifier - .fillMaxWidth() - .padding(12.dp), - verticalAlignment = Alignment.CenterVertically, - ) { - Box( + shape = RoundedCornerShape(16.dp), + content = { + Row( modifier = Modifier - .size(36.dp) - .background( - color = MaterialTheme.colorScheme.primary, - shape = CircleShape, - ), - contentAlignment = Alignment.Center, + .fillMaxWidth() + .padding(12.dp), + verticalAlignment = Alignment.CenterVertically, ) { - Text(text = itemTopic.initial) - } + Box( + modifier = Modifier + .size(36.dp) + .background( + color = MaterialTheme.colorScheme.primary, + shape = CircleShape, + ), + contentAlignment = Alignment.Center, + ) { + Text(text = itemTopic.initial) + } - Spacer(modifier = Modifier.width(12.dp)) + Spacer(modifier = Modifier.width(12.dp)) - Column( - modifier = Modifier.weight(1f), - ) { - Text( - text = topic, - style = MaterialTheme.typography.headlineMedium.copy( - color = MaterialTheme.colorScheme.onPrimary, - ), - maxLines = 1, - overflow = TextOverflow.Ellipsis, - ) - Spacer(modifier = Modifier.height(6.dp)) - Text( - text = subtitle, - style = MaterialTheme.typography.labelMedium.copy( - color = MaterialTheme.colorScheme.onBackground, - ), - maxLines = 1, - overflow = TextOverflow.Ellipsis, - ) - } + Column( + modifier = Modifier.weight(1f), + ) { + Text( + text = topic, + style = MaterialTheme.typography.headlineMedium.copy( + color = MaterialTheme.colorScheme.onPrimary, + ), + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + Spacer(modifier = Modifier.height(6.dp)) + Text( + text = subtitle, + style = MaterialTheme.typography.labelMedium.copy( + color = MaterialTheme.colorScheme.onBackground, + ), + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + } - IconButton(onClick = onBookmarkClick) { - Icon( - imageVector = if (isBookmarked) Icons.Outlined.BookmarkBorder else Icons.Filled.Bookmark, - contentDescription = if (isBookmarked) stringResource(Res.string.remove_bookmark) else stringResource(Res.string.add_bookmark), + CaIconButton( + 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/TopicScreenUI.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/TopicScreenUI.kt index 8cbcd3e..b7f3847 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 @@ -4,11 +4,10 @@ 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.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp +import com.developersbreach.designsystem.components.CaScaffold @Composable fun TopicScreenUI( @@ -19,26 +18,26 @@ fun TopicScreenUI( onBookmarkClick: (Int) -> Unit, onTopicClick: (String) -> Unit, ) { - Scaffold( - containerColor = MaterialTheme.colorScheme.background, + CaScaffold( topBar = { TopicTopBar() }, - ) { paddingValues -> - Column( - modifier = Modifier - .padding(horizontal = 16.dp) - .padding(top = paddingValues.calculateTopPadding()), - ) { - SearchField( - searchQuery = searchQuery, - onQueryChange = onQueryChange, - ) - Spacer(modifier = Modifier.height(8.dp)) - TopicList( - topics = topics, - bookmarkedStates = bookmarkedStates, - onBookmarkClick = onBookmarkClick, - onTopicClick = onTopicClick, - ) - } - } + content = { paddingValues -> + Column( + modifier = Modifier + .padding(horizontal = 16.dp) + .padding(top = paddingValues.calculateTopPadding()), + ) { + SearchField( + searchQuery = searchQuery, + onQueryChange = onQueryChange, + ) + Spacer(modifier = Modifier.height(8.dp)) + TopicList( + topics = topics, + bookmarkedStates = bookmarkedStates, + onBookmarkClick = onBookmarkClick, + onTopicClick = onTopicClick, + ) + } + }, + ) } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/TopicTopAppBar.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/TopicTopAppBar.kt index b2c044a..3dddd99 100644 --- a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/TopicTopAppBar.kt +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/TopicTopAppBar.kt @@ -4,8 +4,6 @@ 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 @@ -13,6 +11,7 @@ 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.CaIconButton import kotlindictionarymultiplatform.composeapp.generated.resources.Res import kotlindictionarymultiplatform.composeapp.generated.resources.back import kotlindictionarymultiplatform.composeapp.generated.resources.topics @@ -31,12 +30,11 @@ fun TopicTopBar() { ) }, navigationIcon = { - IconButton(onClick = { /* Optional Back Logic */ }) { - Icon( - imageVector = Icons.AutoMirrored.Filled.ArrowBack, - contentDescription = stringResource(Res.string.back), - ) - } + CaIconButton( + onClick = {}, + imageVector = Icons.AutoMirrored.Filled.ArrowBack, + contentDescription = stringResource(Res.string.back), + ) }, colors = TopAppBarDefaults.topAppBarColors( containerColor = MaterialTheme.colorScheme.background, diff --git a/composeApp/src/desktopTest/kotlin/com/developersbreach/kotlindictionarymultiplatform/DesignSystemTest.kt b/composeApp/src/desktopTest/kotlin/com/developersbreach/kotlindictionarymultiplatform/DesignSystemTest.kt new file mode 100644 index 0000000..635b780 --- /dev/null +++ b/composeApp/src/desktopTest/kotlin/com/developersbreach/kotlindictionarymultiplatform/DesignSystemTest.kt @@ -0,0 +1,56 @@ +package com.developersbreach.kotlindictionarymultiplatform + +import kotlin.test.Test + +class DesignSystemTest { + + @Test + fun `no direct usage of androidx compose Surface should be allowed except designSystem`() { + checkNoDirectUsageExceptAllowed( + componentName = "androidx.compose.material3.Surface", + excludePaths = arrayOf( + "design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Surface.kt", + ), + ) + } + + @Test + fun `no direct usage of androidx compose scaffold should be allowed except designSystem`() { + checkNoDirectUsageExceptAllowed( + componentName = "androidx.compose.material3.Scaffold", + excludePaths = arrayOf( + "design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Scaffold.kt", + ), + ) + } + + @Test + fun `no direct usage of androidx compose icon should be allowed except designSystem`() { + checkNoDirectUsageExceptAllowed( + componentName = "androidx.compose.material3.Icon", + excludePaths = arrayOf( + "design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Icon.kt", + ), + ) + } + + @Test + fun `no direct usage of androidx compose iconButton should be allowed except designSystem`() { + checkNoDirectUsageExceptAllowed( + componentName = "androidx.compose.material3.IconButton", + excludePaths = arrayOf( + "design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/IconButton.kt", + ), + ) + } + + @Test + fun `no direct usage of androidx compose textField should be allowed except designSystem`() { + checkNoDirectUsageExceptAllowed( + componentName = "androidx.compose.material3.TextField", + excludePaths = arrayOf( + "design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/TextField.kt", + ), + ) + } +} \ No newline at end of file diff --git a/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Icon.kt b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Icon.kt new file mode 100644 index 0000000..e69a6f8 --- /dev/null +++ b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Icon.kt @@ -0,0 +1,20 @@ +package com.developersbreach.designsystem.components + +import androidx.compose.material3.Icon +import androidx.compose.material3.LocalContentColor +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector + +@Composable +fun CaIcon( + imageVector: ImageVector, + contentDescription: String?, + tint: Color= LocalContentColor.current +) { + Icon( + imageVector = imageVector, + contentDescription = contentDescription, + tint = tint + ) +} \ No newline at end of file diff --git a/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/IconButton.kt b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/IconButton.kt new file mode 100644 index 0000000..65ea62f --- /dev/null +++ b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/IconButton.kt @@ -0,0 +1,26 @@ +package com.developersbreach.designsystem.components + +import androidx.compose.material3.IconButton +import androidx.compose.material3.LocalContentColor +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector + +@Composable +fun CaIconButton( + onClick: () -> Unit, + imageVector: ImageVector, + contentDescription: String?, + tint: Color= LocalContentColor.current +) { + IconButton( + onClick = onClick, + content = { + CaIcon( + imageVector = imageVector, + contentDescription = contentDescription, + tint = tint + ) + } + ) +} diff --git a/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Scaffold.kt b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Scaffold.kt new file mode 100644 index 0000000..fcdccef --- /dev/null +++ b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Scaffold.kt @@ -0,0 +1,20 @@ +package com.developersbreach.designsystem.components + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color + +@Composable +fun CaScaffold( + topBar: @Composable () -> Unit, + containerColor: Color = MaterialTheme.colorScheme.background, + content: @Composable (PaddingValues) -> Unit +) { + Scaffold( + topBar = topBar, + containerColor = containerColor, + content = { content(it) } + ) +} \ No newline at end of file diff --git a/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Surface.kt b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Surface.kt new file mode 100644 index 0000000..d4e2246 --- /dev/null +++ b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Surface.kt @@ -0,0 +1,22 @@ +package com.developersbreach.designsystem.components + +import androidx.compose.material3.Surface +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.Shape + +@Composable +fun CaSurface( + modifier: Modifier, + content: @Composable () -> Unit, + color: Color, + shape: Shape, +) { + Surface( + modifier = modifier, + content = content, + shape = shape, + color = color, + ) +} \ No newline at end of file diff --git a/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/TextField.kt b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/TextField.kt new file mode 100644 index 0000000..a7bee41 --- /dev/null +++ b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/TextField.kt @@ -0,0 +1,40 @@ +package com.developersbreach.designsystem.components + +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material3.TextField +import androidx.compose.material3.TextFieldColors +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.text.TextStyle + +@Composable +fun CaTextField( + modifier: Modifier, + value: String, + onValueChange: (String) -> Unit, + placeholder: @Composable (() -> Unit)?, + leadingIcon: @Composable (() -> Unit)?, + colors: TextFieldColors, + shape: Shape, + singleLine: Boolean, + keyboardOptions: KeyboardOptions, + keyboardActions: KeyboardActions, + textStyle: TextStyle, +) { + TextField( + modifier = modifier, + value = value, + onValueChange = onValueChange, + leadingIcon = leadingIcon, + placeholder = placeholder, + shape = shape, + keyboardActions = keyboardActions, + textStyle = textStyle, + singleLine = singleLine, + keyboardOptions = keyboardOptions, + colors = colors, + + ) +} From f8443591456ee4d57651d7563f457adabc952df1 Mon Sep 17 00:00:00 2001 From: Shreyas Deshmukh Date: Wed, 11 Jun 2025 17:46:52 +0530 Subject: [PATCH 6/9] - Introduce `KdText` composable, a wrapper around `material3.Text`. - Replace direct usages of `material3.Text` with `KdText`. - Rename design system components from `Ca` prefix to `Kd` (e.g., `CaScaffold` to `KdScaffold`). - Add a test to prevent direct usage of `androidx.compose.material3.Text` outside the design system. --- .../ui/components/ShowAlertDialog.kt | 8 ++-- .../ui/screens/detail/CodeExampleBox.kt | 12 +++--- .../screens/detail/DetailScreenComponents.kt | 28 ++++++------- .../ui/screens/detail/DetailScreenUI.kt | 8 ++-- .../ui/screens/detail/DetailTopAppBar.kt | 8 ++-- .../ui/screens/topic/SearchField.kt | 12 +++--- .../ui/screens/topic/TopicCard.kt | 16 +++---- .../ui/screens/topic/TopicScreenUI.kt | 4 +- .../ui/screens/topic/TopicTopAppBar.kt | 8 ++-- .../DesignSystemTest.kt | 10 +++++ .../designsystem/components/Icon.kt | 2 +- .../designsystem/components/IconButton.kt | 4 +- .../designsystem/components/Scaffold.kt | 2 +- .../designsystem/components/Surface.kt | 2 +- .../designsystem/components/Text.kt | 42 +++++++++++++++++++ .../designsystem/components/TextField.kt | 2 +- 16 files changed, 110 insertions(+), 58 deletions(-) create mode 100644 design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Text.kt diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/components/ShowAlertDialog.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/components/ShowAlertDialog.kt index 678b3af..5423931 100644 --- a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/components/ShowAlertDialog.kt +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/components/ShowAlertDialog.kt @@ -1,10 +1,10 @@ package com.developersbreach.kotlindictionarymultiplatform.ui.components import androidx.compose.material3.AlertDialog -import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import com.developersbreach.designsystem.components.KdText import kotlindictionarymultiplatform.composeapp.generated.resources.Res import kotlindictionarymultiplatform.composeapp.generated.resources.ok import org.jetbrains.compose.resources.stringResource @@ -18,11 +18,11 @@ fun ShowAlertDialog( ) { AlertDialog( onDismissRequest = onButtonClick, - title = { Text(text = title) }, - text = { Text(text = description) }, + title = { KdText(text = title) }, + text = { KdText(text = description) }, confirmButton = { TextButton(onClick = onButtonClick) { - Text(text = stringResource(Res.string.ok)) + KdText(text = stringResource(Res.string.ok)) } }, modifier = modifier, 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 index d6aa5af..ad8301d 100644 --- 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 @@ -17,7 +17,6 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Check import androidx.compose.material.icons.filled.ContentCopy 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 @@ -31,7 +30,8 @@ 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.designsystem.components.CaIcon +import com.developersbreach.designsystem.components.KdIcon +import com.developersbreach.designsystem.components.KdText import kotlindictionarymultiplatform.composeapp.generated.resources.Res import kotlindictionarymultiplatform.composeapp.generated.resources.copied import kotlindictionarymultiplatform.composeapp.generated.resources.copy @@ -78,7 +78,7 @@ fun CodeExampleBox( horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, ) { - Text( + KdText( text = stringResource(Res.string.kotlin), color = MaterialTheme.colorScheme.onPrimary, fontWeight = FontWeight.Bold, @@ -99,13 +99,13 @@ fun CodeExampleBox( } .padding(4.dp), ) { - CaIcon( + KdIcon( 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( + KdText( text = if (copied) stringResource(Res.string.copied) else stringResource(Res.string.copy), fontSize = 12.sp, color = MaterialTheme.colorScheme.onPrimary, @@ -116,7 +116,7 @@ fun CodeExampleBox( Spacer(modifier = Modifier.height(8.dp)) - Text( + KdText( text = code, modifier = Modifier.padding( start = 12.dp, diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/DetailScreenComponents.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/DetailScreenComponents.kt index 7f38b24..e3efad3 100644 --- a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/DetailScreenComponents.kt +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/DetailScreenComponents.kt @@ -4,11 +4,11 @@ import androidx.compose.foundation.clickable 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.designsystem.components.KdText import com.developersbreach.kotlindictionarymultiplatform.data.detail.model.Section import com.developersbreach.kotlindictionarymultiplatform.data.detail.model.Syntax import kotlindictionarymultiplatform.composeapp.generated.resources.Res @@ -25,7 +25,7 @@ fun TableOfContents( item: String, onClick: () -> Unit, ) { - Text( + KdText( text = item, modifier = Modifier.clickable { onClick() }, color = MaterialTheme.colorScheme.onSurface, @@ -37,13 +37,13 @@ fun TableOfContents( fun IntroductionSection( intro: String, ) { - Text( + KdText( text = stringResource(resource = Res.string.introduction), style = MaterialTheme.typography.headlineLarge, color = MaterialTheme.colorScheme.onPrimary, ) Spacer(Modifier.height(4.dp)) - Text( + KdText( text = intro, style = MaterialTheme.typography.bodyMedium, ) @@ -54,19 +54,19 @@ fun IntroductionSection( fun SyntaxSection( syntax: Syntax, ) { - Text( + KdText( text = stringResource(resource = Res.string.syntax), style = MaterialTheme.typography.headlineLarge, color = MaterialTheme.colorScheme.onPrimary, ) Spacer(Modifier.height(4.dp)) - Text( + KdText( text = syntax.signature, style = MaterialTheme.typography.bodyMedium, ) syntax.notes?.let { Spacer(Modifier.height(4.dp)) - Text( + KdText( text = stringResource( Res.string.notes_with_value, it, @@ -82,7 +82,7 @@ fun SectionBlock( section: Section, ) { section.heading?.let { - Text( + KdText( text = it, style = MaterialTheme.typography.headlineLarge, color = MaterialTheme.colorScheme.onPrimary, @@ -91,7 +91,7 @@ fun SectionBlock( } section.content?.let { - Text( + KdText( text = it, style = MaterialTheme.typography.bodyMedium, ) @@ -100,7 +100,7 @@ fun SectionBlock( section.codeExamples.forEach { example -> example.description?.let { - Text( + KdText( text = it, fontWeight = FontWeight.Bold, style = MaterialTheme.typography.bodyMedium, @@ -116,14 +116,14 @@ fun SectionBlock( fun PitfallsSection( pitfalls: List, ) { - Text( + KdText( text = stringResource(resource = Res.string.pitfalls), style = MaterialTheme.typography.headlineLarge, color = MaterialTheme.colorScheme.onPrimary, ) Spacer(Modifier.height(4.dp)) pitfalls.forEach { - Text( + KdText( text = stringResource( Res.string.bullet_item, it, @@ -138,14 +138,14 @@ fun PitfallsSection( fun RelatedTopicsSection( relatedTopics: List, ) { - Text( + KdText( text = stringResource(resource = Res.string.related_topics), style = MaterialTheme.typography.headlineLarge, color = MaterialTheme.colorScheme.onPrimary, ) Spacer(Modifier.height(4.dp)) relatedTopics.forEach { - Text( + KdText( text = stringResource( Res.string.bullet_item, it, 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 index c81cdd1..471d537 100644 --- 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 @@ -8,12 +8,12 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp -import com.developersbreach.designsystem.components.CaScaffold +import com.developersbreach.designsystem.components.KdScaffold +import com.developersbreach.designsystem.components.KdText import kotlindictionarymultiplatform.composeapp.generated.resources.Res import kotlindictionarymultiplatform.composeapp.generated.resources.table_of_contents import kotlinx.coroutines.launch @@ -24,7 +24,7 @@ fun DetailScreenUI( detailUiState: DetailUiState, navigateUp: () -> Unit, ) { - CaScaffold( + KdScaffold( topBar = { DetailTopBar( title = detailUiState.topicName, @@ -55,7 +55,7 @@ private fun DetailContent( .padding(horizontal = 16.dp), ) { item { - Text( + KdText( text = stringResource(Res.string.table_of_contents), style = MaterialTheme.typography.titleLarge, color = MaterialTheme.colorScheme.onPrimary, 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 index 40d94c4..8460023 100644 --- 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 @@ -5,12 +5,12 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material3.ExperimentalMaterial3Api 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 com.developersbreach.designsystem.components.CaIconButton +import com.developersbreach.designsystem.components.KdIconButton +import com.developersbreach.designsystem.components.KdText import kotlindictionarymultiplatform.composeapp.generated.resources.Res import kotlindictionarymultiplatform.composeapp.generated.resources.back import org.jetbrains.compose.resources.stringResource @@ -23,7 +23,7 @@ fun DetailTopBar( ) { TopAppBar( title = { - Text( + KdText( text = title, style = MaterialTheme.typography.displayMedium, color = MaterialTheme.colorScheme.onPrimary, @@ -31,7 +31,7 @@ fun DetailTopBar( ) }, navigationIcon = { - CaIconButton( + KdIconButton( onClick = navigateUp, imageVector = Icons.AutoMirrored.Filled.ArrowBack, contentDescription = stringResource(Res.string.back), diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/SearchField.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/SearchField.kt index 7c06094..dd7ca8f 100644 --- a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/SearchField.kt +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/SearchField.kt @@ -8,7 +8,6 @@ import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Search import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text import androidx.compose.material3.TextFieldDefaults import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -18,8 +17,9 @@ import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.developersbreach.designsystem.components.CaIcon -import com.developersbreach.designsystem.components.CaTextField +import com.developersbreach.designsystem.components.KdIcon +import com.developersbreach.designsystem.components.KdText +import com.developersbreach.designsystem.components.KdTextField import kotlindictionarymultiplatform.composeapp.generated.resources.Res import kotlindictionarymultiplatform.composeapp.generated.resources.search import kotlindictionarymultiplatform.composeapp.generated.resources.search_kotlin_terms @@ -30,7 +30,7 @@ fun SearchField( searchQuery: String, onQueryChange: (String) -> Unit, ) { - CaTextField( + KdTextField( value = searchQuery, onValueChange = onQueryChange, modifier = Modifier @@ -38,7 +38,7 @@ fun SearchField( .clip(RoundedCornerShape(25.dp)) .padding(4.dp), placeholder = { - Text( + KdText( stringResource(Res.string.search_kotlin_terms), maxLines = 1, overflow = TextOverflow.Ellipsis, @@ -46,7 +46,7 @@ fun SearchField( ) }, leadingIcon = { - CaIcon( + KdIcon( imageVector = Icons.Filled.Search, contentDescription = stringResource(Res.string.search), tint = MaterialTheme.colorScheme.onBackground, 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 90cd8ec..402798f 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 @@ -17,15 +17,15 @@ 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.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment 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.CaIconButton -import com.developersbreach.designsystem.components.CaSurface +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 @@ -40,7 +40,7 @@ fun TopicCard( onBookmarkClick: () -> Unit, onCardClick: () -> Unit, ) { - CaSurface( + KdSurface( modifier = Modifier .fillMaxWidth() .padding(8.dp) @@ -68,7 +68,7 @@ fun TopicCard( ), contentAlignment = Alignment.Center, ) { - Text(text = itemTopic.initial) + KdText(text = itemTopic.initial) } Spacer(modifier = Modifier.width(12.dp)) @@ -76,7 +76,7 @@ fun TopicCard( Column( modifier = Modifier.weight(1f), ) { - Text( + KdText( text = topic, style = MaterialTheme.typography.headlineMedium.copy( color = MaterialTheme.colorScheme.onPrimary, @@ -85,7 +85,7 @@ fun TopicCard( overflow = TextOverflow.Ellipsis, ) Spacer(modifier = Modifier.height(6.dp)) - Text( + KdText( text = subtitle, style = MaterialTheme.typography.labelMedium.copy( color = MaterialTheme.colorScheme.onBackground, @@ -95,7 +95,7 @@ fun TopicCard( ) } - CaIconButton( + KdIconButton( onClick = onBookmarkClick, imageVector = if (isBookmarked) { Icons.Outlined.BookmarkBorder 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 b7f3847..998b16d 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 @@ -7,7 +7,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp -import com.developersbreach.designsystem.components.CaScaffold +import com.developersbreach.designsystem.components.KdScaffold @Composable fun TopicScreenUI( @@ -18,7 +18,7 @@ fun TopicScreenUI( onBookmarkClick: (Int) -> Unit, onTopicClick: (String) -> Unit, ) { - CaScaffold( + KdScaffold( topBar = { TopicTopBar() }, content = { paddingValues -> Column( diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/TopicTopAppBar.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/TopicTopAppBar.kt index 3dddd99..577ddbc 100644 --- a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/TopicTopAppBar.kt +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/TopicTopAppBar.kt @@ -5,13 +5,13 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material3.ExperimentalMaterial3Api 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 androidx.compose.ui.text.style.TextAlign -import com.developersbreach.designsystem.components.CaIconButton +import com.developersbreach.designsystem.components.KdIconButton +import com.developersbreach.designsystem.components.KdText import kotlindictionarymultiplatform.composeapp.generated.resources.Res import kotlindictionarymultiplatform.composeapp.generated.resources.back import kotlindictionarymultiplatform.composeapp.generated.resources.topics @@ -22,7 +22,7 @@ import org.jetbrains.compose.resources.stringResource fun TopicTopBar() { TopAppBar( title = { - Text( + KdText( text = stringResource(Res.string.topics), style = MaterialTheme.typography.displayMedium, modifier = Modifier.fillMaxWidth(), @@ -30,7 +30,7 @@ fun TopicTopBar() { ) }, navigationIcon = { - CaIconButton( + KdIconButton( onClick = {}, imageVector = Icons.AutoMirrored.Filled.ArrowBack, contentDescription = stringResource(Res.string.back), diff --git a/composeApp/src/desktopTest/kotlin/com/developersbreach/kotlindictionarymultiplatform/DesignSystemTest.kt b/composeApp/src/desktopTest/kotlin/com/developersbreach/kotlindictionarymultiplatform/DesignSystemTest.kt index 635b780..7e4216f 100644 --- a/composeApp/src/desktopTest/kotlin/com/developersbreach/kotlindictionarymultiplatform/DesignSystemTest.kt +++ b/composeApp/src/desktopTest/kotlin/com/developersbreach/kotlindictionarymultiplatform/DesignSystemTest.kt @@ -53,4 +53,14 @@ class DesignSystemTest { ), ) } + + @Test + fun `no direct usage of androidx compose text should be allowed except designSystem`() { + checkNoDirectUsageExceptAllowed( + componentName = "androidx.compose.material3.Text", + excludePaths = arrayOf( + "design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Text.kt", + ), + ) + } } \ No newline at end of file diff --git a/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Icon.kt b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Icon.kt index e69a6f8..15caf6b 100644 --- a/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Icon.kt +++ b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Icon.kt @@ -7,7 +7,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector @Composable -fun CaIcon( +fun KdIcon( imageVector: ImageVector, contentDescription: String?, tint: Color= LocalContentColor.current diff --git a/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/IconButton.kt b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/IconButton.kt index 65ea62f..67b1ba7 100644 --- a/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/IconButton.kt +++ b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/IconButton.kt @@ -7,7 +7,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector @Composable -fun CaIconButton( +fun KdIconButton( onClick: () -> Unit, imageVector: ImageVector, contentDescription: String?, @@ -16,7 +16,7 @@ fun CaIconButton( IconButton( onClick = onClick, content = { - CaIcon( + KdIcon( imageVector = imageVector, contentDescription = contentDescription, tint = tint diff --git a/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Scaffold.kt b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Scaffold.kt index fcdccef..49b548d 100644 --- a/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Scaffold.kt +++ b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Scaffold.kt @@ -7,7 +7,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.graphics.Color @Composable -fun CaScaffold( +fun KdScaffold( topBar: @Composable () -> Unit, containerColor: Color = MaterialTheme.colorScheme.background, content: @Composable (PaddingValues) -> Unit diff --git a/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Surface.kt b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Surface.kt index d4e2246..24044d8 100644 --- a/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Surface.kt +++ b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Surface.kt @@ -7,7 +7,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Shape @Composable -fun CaSurface( +fun KdSurface( modifier: Modifier, content: @Composable () -> Unit, color: Color, diff --git a/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Text.kt b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Text.kt new file mode 100644 index 0000000..bdd0b57 --- /dev/null +++ b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Text.kt @@ -0,0 +1,42 @@ +package com.developersbreach.designsystem.components + +import androidx.compose.material3.LocalTextStyle +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.TextUnit + +@Composable +fun KdText( + text: String, + modifier: Modifier = Modifier, + style: TextStyle = LocalTextStyle.current, + textAlign: TextAlign? = null, + maxLines: Int = Int.MAX_VALUE, + overflow: TextOverflow = TextOverflow.Clip, + color: Color = Color.Unspecified, + fontWeight: FontWeight? = null, + fontSize: TextUnit = TextUnit.Unspecified, + fontFamily: FontFamily? = null, + lineHeight: TextUnit = TextUnit.Unspecified, +){ + Text( + text = text, + modifier = modifier, + style = style, + textAlign = textAlign, + maxLines = maxLines, + overflow = overflow, + color=color, + fontWeight = fontWeight, + fontSize = fontSize, + fontFamily = fontFamily, + lineHeight = lineHeight + ) +} \ No newline at end of file diff --git a/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/TextField.kt b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/TextField.kt index a7bee41..2ee0a06 100644 --- a/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/TextField.kt +++ b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/TextField.kt @@ -10,7 +10,7 @@ import androidx.compose.ui.graphics.Shape import androidx.compose.ui.text.TextStyle @Composable -fun CaTextField( +fun KdTextField( modifier: Modifier, value: String, onValueChange: (String) -> Unit, From b769cb57408f18ba2ac856a0e54bf180e854a59d Mon Sep 17 00:00:00 2001 From: Shreyas Deshmukh Date: Wed, 11 Jun 2025 23:58:01 +0530 Subject: [PATCH 7/9] - Add new design system components: `KdAlertDialog`, `KdTextButton`, `KdCircularProgressIndicator`, and `KdTopAppBar`. - Add `modifier` parameter to existing design system components: `KdScaffold`, `KdText`, `KdIcon`, and `KdIconButton`. - Update Konsist tests to ensure all Material3 components are wrapped by the design system and exclude ktlint suppressed files. - Add ktlint plugin and dependency to `design-system` module. - Suppress ktlint for `platform.kt` files. --- .../ui/components/ShowAlertDialog.kt | 33 ++++++-- .../ui/components/UiStateHandler.kt | 6 +- .../ui/screens/detail/CodeExampleBox.kt | 2 + .../screens/detail/DetailScreenComponents.kt | 12 +++ .../ui/screens/detail/DetailScreenUI.kt | 2 + .../ui/screens/detail/DetailTopAppBar.kt | 6 +- .../ui/screens/topic/SearchField.kt | 2 + .../ui/screens/topic/TopicCard.kt | 9 ++- .../ui/screens/topic/TopicScreenUI.kt | 1 + .../ui/screens/topic/TopicTopAppBar.kt | 6 +- .../DesignSystemTest.kt | 75 ++++++++++++++----- .../KonsistUtils.kt | 29 ++++++- design-system/build.gradle.kts | 7 +- .../design_system/ExampleInstrumentedTest.kt | 1 + .../com/example/design_system/platform.kt | 1 + .../designsystem/components/AlertDialog.kt | 22 ++++++ .../components/CircularProgressIndicator.kt | 17 +++++ .../designsystem/components/Icon.kt | 7 +- .../designsystem/components/IconButton.kt | 13 +++- .../designsystem/components/Scaffold.kt | 7 +- .../designsystem/components/Text.kt | 8 +- .../designsystem/components/TextButton.kt | 19 +++++ .../designsystem/components/TextField.kt | 3 +- .../designsystem/components/TopAppBar.kt | 23 ++++++ .../com/example/design_system/Platform.ios.kt | 1 + 25 files changed, 258 insertions(+), 54 deletions(-) create mode 100644 design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/AlertDialog.kt create mode 100644 design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/CircularProgressIndicator.kt create mode 100644 design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/TextButton.kt create mode 100644 design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/TopAppBar.kt diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/components/ShowAlertDialog.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/components/ShowAlertDialog.kt index 5423931..d5c7acf 100644 --- a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/components/ShowAlertDialog.kt +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/components/ShowAlertDialog.kt @@ -1,10 +1,10 @@ package com.developersbreach.kotlindictionarymultiplatform.ui.components -import androidx.compose.material3.AlertDialog -import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import com.developersbreach.designsystem.components.KdAlertDialog import com.developersbreach.designsystem.components.KdText +import com.developersbreach.designsystem.components.KdTextButton import kotlindictionarymultiplatform.composeapp.generated.resources.Res import kotlindictionarymultiplatform.composeapp.generated.resources.ok import org.jetbrains.compose.resources.stringResource @@ -16,14 +16,31 @@ fun ShowAlertDialog( title: String, description: String, ) { - AlertDialog( + KdAlertDialog( onDismissRequest = onButtonClick, - title = { KdText(text = title) }, - text = { KdText(text = description) }, + title = { + KdText( + modifier = Modifier, + text = title, + ) + }, + text = { + KdText( + modifier = Modifier, + text = description, + ) + }, confirmButton = { - TextButton(onClick = onButtonClick) { - KdText(text = stringResource(Res.string.ok)) - } + KdTextButton( + modifier = Modifier, + onClick = onButtonClick, + content = { + KdText( + modifier = Modifier, + text = stringResource(Res.string.ok), + ) + }, + ) }, modifier = modifier, ) diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/components/UiStateHandler.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/components/UiStateHandler.kt index 9ef0afc..f574dfa 100644 --- a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/components/UiStateHandler.kt +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/components/UiStateHandler.kt @@ -2,7 +2,6 @@ package com.developersbreach.kotlindictionarymultiplatform.ui.components import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -10,6 +9,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import com.developersbreach.designsystem.components.KdCircularProgressIndicator import kotlindictionarymultiplatform.composeapp.generated.resources.Res import kotlindictionarymultiplatform.composeapp.generated.resources.error_info_unavailable import kotlindictionarymultiplatform.composeapp.generated.resources.error_occurred @@ -30,7 +30,7 @@ fun UiStateHandler( Box(modifier = Modifier.fillMaxSize()) { when (uiState) { is UiState.Loading -> { - CircularProgressIndicator( + KdCircularProgressIndicator( modifier = Modifier.align(Alignment.Center), color = MaterialTheme.colorScheme.onBackground, ) @@ -52,7 +52,7 @@ fun UiStateHandler( } if (isLoading) { - CircularProgressIndicator( + KdCircularProgressIndicator( modifier = Modifier.align(Alignment.Center), color = MaterialTheme.colorScheme.onBackground, ) 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 index ad8301d..f058e01 100644 --- 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 @@ -100,12 +100,14 @@ fun CodeExampleBox( .padding(4.dp), ) { KdIcon( + modifier = Modifier, 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)) KdText( + modifier = Modifier, text = if (copied) stringResource(Res.string.copied) else stringResource(Res.string.copy), fontSize = 12.sp, color = MaterialTheme.colorScheme.onPrimary, diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/DetailScreenComponents.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/DetailScreenComponents.kt index e3efad3..e85b89d 100644 --- a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/DetailScreenComponents.kt +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/detail/DetailScreenComponents.kt @@ -38,12 +38,14 @@ fun IntroductionSection( intro: String, ) { KdText( + modifier = Modifier, text = stringResource(resource = Res.string.introduction), style = MaterialTheme.typography.headlineLarge, color = MaterialTheme.colorScheme.onPrimary, ) Spacer(Modifier.height(4.dp)) KdText( + modifier = Modifier, text = intro, style = MaterialTheme.typography.bodyMedium, ) @@ -55,18 +57,21 @@ fun SyntaxSection( syntax: Syntax, ) { KdText( + modifier = Modifier, text = stringResource(resource = Res.string.syntax), style = MaterialTheme.typography.headlineLarge, color = MaterialTheme.colorScheme.onPrimary, ) Spacer(Modifier.height(4.dp)) KdText( + modifier = Modifier, text = syntax.signature, style = MaterialTheme.typography.bodyMedium, ) syntax.notes?.let { Spacer(Modifier.height(4.dp)) KdText( + modifier = Modifier, text = stringResource( Res.string.notes_with_value, it, @@ -83,6 +88,7 @@ fun SectionBlock( ) { section.heading?.let { KdText( + modifier = Modifier, text = it, style = MaterialTheme.typography.headlineLarge, color = MaterialTheme.colorScheme.onPrimary, @@ -92,6 +98,7 @@ fun SectionBlock( section.content?.let { KdText( + modifier = Modifier, text = it, style = MaterialTheme.typography.bodyMedium, ) @@ -101,6 +108,7 @@ fun SectionBlock( section.codeExamples.forEach { example -> example.description?.let { KdText( + modifier = Modifier, text = it, fontWeight = FontWeight.Bold, style = MaterialTheme.typography.bodyMedium, @@ -117,6 +125,7 @@ fun PitfallsSection( pitfalls: List, ) { KdText( + modifier = Modifier, text = stringResource(resource = Res.string.pitfalls), style = MaterialTheme.typography.headlineLarge, color = MaterialTheme.colorScheme.onPrimary, @@ -124,6 +133,7 @@ fun PitfallsSection( Spacer(Modifier.height(4.dp)) pitfalls.forEach { KdText( + modifier = Modifier, text = stringResource( Res.string.bullet_item, it, @@ -139,6 +149,7 @@ fun RelatedTopicsSection( relatedTopics: List, ) { KdText( + modifier = Modifier, text = stringResource(resource = Res.string.related_topics), style = MaterialTheme.typography.headlineLarge, color = MaterialTheme.colorScheme.onPrimary, @@ -146,6 +157,7 @@ fun RelatedTopicsSection( Spacer(Modifier.height(4.dp)) relatedTopics.forEach { KdText( + modifier = Modifier, text = stringResource( Res.string.bullet_item, it, 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 index 471d537..a20d9e8 100644 --- 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 @@ -25,6 +25,7 @@ fun DetailScreenUI( navigateUp: () -> Unit, ) { KdScaffold( + modifier = Modifier, topBar = { DetailTopBar( title = detailUiState.topicName, @@ -56,6 +57,7 @@ private fun DetailContent( ) { item { KdText( + modifier = Modifier, text = stringResource(Res.string.table_of_contents), style = MaterialTheme.typography.titleLarge, color = MaterialTheme.colorScheme.onPrimary, 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 index 8460023..8df468b 100644 --- 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 @@ -5,12 +5,12 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier 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 kotlindictionarymultiplatform.composeapp.generated.resources.back import org.jetbrains.compose.resources.stringResource @@ -21,7 +21,7 @@ fun DetailTopBar( title: String, navigateUp: () -> Unit, ) { - TopAppBar( + KdTopAppBar( title = { KdText( text = title, @@ -32,6 +32,8 @@ fun DetailTopBar( }, navigationIcon = { KdIconButton( + modifier = Modifier, + iconModifier = Modifier, onClick = navigateUp, imageVector = Icons.AutoMirrored.Filled.ArrowBack, contentDescription = stringResource(Res.string.back), diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/SearchField.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/SearchField.kt index dd7ca8f..50438c9 100644 --- a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/SearchField.kt +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/SearchField.kt @@ -43,10 +43,12 @@ fun SearchField( maxLines = 1, overflow = TextOverflow.Ellipsis, color = MaterialTheme.colorScheme.onBackground, + modifier = Modifier, ) }, leadingIcon = { KdIcon( + modifier = Modifier, imageVector = Icons.Filled.Search, contentDescription = stringResource(Res.string.search), tint = MaterialTheme.colorScheme.onBackground, 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 402798f..d503234 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 @@ -68,7 +68,10 @@ fun TopicCard( ), contentAlignment = Alignment.Center, ) { - KdText(text = itemTopic.initial) + KdText( + modifier = Modifier, + text = itemTopic.initial, + ) } Spacer(modifier = Modifier.width(12.dp)) @@ -77,6 +80,7 @@ fun TopicCard( modifier = Modifier.weight(1f), ) { KdText( + modifier = Modifier, text = topic, style = MaterialTheme.typography.headlineMedium.copy( color = MaterialTheme.colorScheme.onPrimary, @@ -86,6 +90,7 @@ fun TopicCard( ) Spacer(modifier = Modifier.height(6.dp)) KdText( + modifier = Modifier, text = subtitle, style = MaterialTheme.typography.labelMedium.copy( color = MaterialTheme.colorScheme.onBackground, @@ -96,6 +101,8 @@ fun TopicCard( } KdIconButton( + modifier = Modifier, + iconModifier = Modifier, onClick = onBookmarkClick, imageVector = if (isBookmarked) { Icons.Outlined.BookmarkBorder 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 998b16d..2288187 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 @@ -19,6 +19,7 @@ fun TopicScreenUI( onTopicClick: (String) -> Unit, ) { KdScaffold( + modifier = Modifier, topBar = { TopicTopBar() }, content = { paddingValues -> Column( diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/TopicTopAppBar.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/TopicTopAppBar.kt index 577ddbc..b1bb812 100644 --- a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/TopicTopAppBar.kt +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/TopicTopAppBar.kt @@ -5,13 +5,13 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.TopAppBar 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 kotlindictionarymultiplatform.composeapp.generated.resources.back import kotlindictionarymultiplatform.composeapp.generated.resources.topics @@ -20,7 +20,7 @@ import org.jetbrains.compose.resources.stringResource @OptIn(ExperimentalMaterial3Api::class) @Composable fun TopicTopBar() { - TopAppBar( + KdTopAppBar( title = { KdText( text = stringResource(Res.string.topics), @@ -31,6 +31,8 @@ fun TopicTopBar() { }, navigationIcon = { KdIconButton( + modifier = Modifier, + iconModifier = Modifier, onClick = {}, imageVector = Icons.AutoMirrored.Filled.ArrowBack, contentDescription = stringResource(Res.string.back), diff --git a/composeApp/src/desktopTest/kotlin/com/developersbreach/kotlindictionarymultiplatform/DesignSystemTest.kt b/composeApp/src/desktopTest/kotlin/com/developersbreach/kotlindictionarymultiplatform/DesignSystemTest.kt index 7e4216f..8ee6686 100644 --- a/composeApp/src/desktopTest/kotlin/com/developersbreach/kotlindictionarymultiplatform/DesignSystemTest.kt +++ b/composeApp/src/desktopTest/kotlin/com/developersbreach/kotlindictionarymultiplatform/DesignSystemTest.kt @@ -4,13 +4,29 @@ import kotlin.test.Test class DesignSystemTest { + @Test + fun `all material3 components have design-system wrappers`() { + val ignoreComponents = setOf( + "androidx.compose.material3.Typography", + "androidx.compose.material3.darkColorScheme", + "androidx.compose.material3.lightColorScheme", + "androidx.compose.material3.MaterialTheme", + "androidx.compose.material3.ExperimentalMaterial3Api", + "androidx.compose.material3.TopAppBarDefaults", + "androidx.compose.material3.TextFieldDefaults", + ) + + checkAllMaterial3ComponentsMoved( + allowedComponents = ignoreComponents, + excludePaths = arrayOf(DESIGN_SYSTEM_PATH), + ) + } + @Test fun `no direct usage of androidx compose Surface should be allowed except designSystem`() { checkNoDirectUsageExceptAllowed( componentName = "androidx.compose.material3.Surface", - excludePaths = arrayOf( - "design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Surface.kt", - ), + excludePaths = arrayOf("$DESIGN_SYSTEM_PATH/Surface.kt"), ) } @@ -18,9 +34,7 @@ class DesignSystemTest { fun `no direct usage of androidx compose scaffold should be allowed except designSystem`() { checkNoDirectUsageExceptAllowed( componentName = "androidx.compose.material3.Scaffold", - excludePaths = arrayOf( - "design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Scaffold.kt", - ), + excludePaths = arrayOf("$DESIGN_SYSTEM_PATH/Scaffold.kt"), ) } @@ -28,9 +42,7 @@ class DesignSystemTest { fun `no direct usage of androidx compose icon should be allowed except designSystem`() { checkNoDirectUsageExceptAllowed( componentName = "androidx.compose.material3.Icon", - excludePaths = arrayOf( - "design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Icon.kt", - ), + excludePaths = arrayOf("$DESIGN_SYSTEM_PATH/Icon.kt"), ) } @@ -38,9 +50,7 @@ class DesignSystemTest { fun `no direct usage of androidx compose iconButton should be allowed except designSystem`() { checkNoDirectUsageExceptAllowed( componentName = "androidx.compose.material3.IconButton", - excludePaths = arrayOf( - "design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/IconButton.kt", - ), + excludePaths = arrayOf("$DESIGN_SYSTEM_PATH/IconButton.kt"), ) } @@ -48,19 +58,44 @@ class DesignSystemTest { fun `no direct usage of androidx compose textField should be allowed except designSystem`() { checkNoDirectUsageExceptAllowed( componentName = "androidx.compose.material3.TextField", - excludePaths = arrayOf( - "design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/TextField.kt", - ), + excludePaths = arrayOf("$DESIGN_SYSTEM_PATH/TextField.kt"), ) } @Test - fun `no direct usage of androidx compose text should be allowed except designSystem`() { + fun `no direct usage of androidx compose alertDialog should be allowed except designSystem`() { checkNoDirectUsageExceptAllowed( - componentName = "androidx.compose.material3.Text", - excludePaths = arrayOf( - "design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Text.kt", - ), + componentName = "androidx.compose.material3.AlertDialog", + excludePaths = arrayOf("$DESIGN_SYSTEM_PATH/AlertDialog.kt"), ) } + + @Test + fun `no direct usage of androidx compose textButton should be allowed except designSystem`() { + checkNoDirectUsageExceptAllowed( + componentName = "androidx.compose.material3.TextButton", + excludePaths = arrayOf("$DESIGN_SYSTEM_PATH/TextButton.kt"), + ) + } + + @Test + fun `no direct usage of androidx compose circularProgressIndicator should be allowed except designSystem`() { + checkNoDirectUsageExceptAllowed( + componentName = "androidx.compose.material3.CircularProgressIndicator", + excludePaths = arrayOf("$DESIGN_SYSTEM_PATH/CircularProgressIndicator.kt"), + ) + } + + @Test + fun `no direct usage of androidx compose topAppBar should be allowed except designSystem`() { + checkNoDirectUsageExceptAllowed( + componentName = "androidx.compose.material3.TopAppBar", + excludePaths = arrayOf("$DESIGN_SYSTEM_PATH/TopAppBar.kt"), + ) + } + + companion object { + private const val DESIGN_SYSTEM_PATH = + "design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components" + } } \ No newline at end of file diff --git a/composeApp/src/desktopTest/kotlin/com/developersbreach/kotlindictionarymultiplatform/KonsistUtils.kt b/composeApp/src/desktopTest/kotlin/com/developersbreach/kotlindictionarymultiplatform/KonsistUtils.kt index 4afe52d..6d8d356 100644 --- a/composeApp/src/desktopTest/kotlin/com/developersbreach/kotlindictionarymultiplatform/KonsistUtils.kt +++ b/composeApp/src/desktopTest/kotlin/com/developersbreach/kotlindictionarymultiplatform/KonsistUtils.kt @@ -3,7 +3,7 @@ package com.developersbreach.kotlindictionarymultiplatform import com.lemonappdev.konsist.api.Konsist import kotlin.test.assertTrue -fun checkNoDirectUsageExceptAllowed( +internal fun checkNoDirectUsageExceptAllowed( componentName: String, excludePaths: Array, ) { @@ -21,4 +21,31 @@ fun checkNoDirectUsageExceptAllowed( actual = offendingFiles.isEmpty(), message = "Found forbidden imports of $componentName in files:\n" + offendingFiles.joinToString("\n") { it.path }, ) +} + +internal fun checkAllMaterial3ComponentsMoved( + allowedComponents: Set, + excludePaths: Array = emptyArray(), +) { + val files = Konsist + .scopeFromProject() + .files + .filter { file -> + val path = file.path.replace("\\", "/").lowercase() + excludePaths.none { path.contains(it.replace("\\", "/").lowercase()) } + } + + val allMaterial3Imports = files + .flatMap { it.imports } + .map { it.name } + .filter { it.startsWith("androidx.compose.material3.") } + .distinct() + + val pending = allMaterial3Imports - allowedComponents + + assertTrue( + actual = pending.isEmpty(), + message = "Found pending Material3 components not in design-system:\n" + + pending.joinToString("\n") { " • $it" }, + ) } \ No newline at end of file diff --git a/design-system/build.gradle.kts b/design-system/build.gradle.kts index 84e2094..c197325 100644 --- a/design-system/build.gradle.kts +++ b/design-system/build.gradle.kts @@ -3,6 +3,7 @@ plugins { alias(libs.plugins.androidKotlinMultiplatformLibrary) alias(libs.plugins.composeMultiplatform) alias(libs.plugins.composeCompiler) + alias(libs.plugins.ktlint) } kotlin { @@ -15,9 +16,6 @@ kotlin { compileSdk = 35 minSdk = 24 - withHostTestBuilder { - } - withDeviceTestBuilder { sourceSetTreeName = "test" }.configure { @@ -102,5 +100,8 @@ kotlin { } } } +} +dependencies { + ktlint(project(":custom-ktlint-rules")) } \ No newline at end of file diff --git a/design-system/src/androidDeviceTest/kotlin/com/example/design_system/ExampleInstrumentedTest.kt b/design-system/src/androidDeviceTest/kotlin/com/example/design_system/ExampleInstrumentedTest.kt index 4dca5d2..7b8a813 100644 --- a/design-system/src/androidDeviceTest/kotlin/com/example/design_system/ExampleInstrumentedTest.kt +++ b/design-system/src/androidDeviceTest/kotlin/com/example/design_system/ExampleInstrumentedTest.kt @@ -1,3 +1,4 @@ +@file:Suppress("ktlint") package com.example.design_system import androidx.test.platform.app.InstrumentationRegistry diff --git a/design-system/src/appleMain/kotlin/com/example/design_system/platform.kt b/design-system/src/appleMain/kotlin/com/example/design_system/platform.kt index c2bd6dc..6103572 100644 --- a/design-system/src/appleMain/kotlin/com/example/design_system/platform.kt +++ b/design-system/src/appleMain/kotlin/com/example/design_system/platform.kt @@ -1,3 +1,4 @@ +@file:Suppress("ktlint") package com.example.design_system expect fun platform(): String \ No newline at end of file diff --git a/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/AlertDialog.kt b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/AlertDialog.kt new file mode 100644 index 0000000..c34e3f5 --- /dev/null +++ b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/AlertDialog.kt @@ -0,0 +1,22 @@ +package com.developersbreach.designsystem.components + +import androidx.compose.material3.AlertDialog +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier + +@Composable +fun KdAlertDialog( + modifier: Modifier, + onDismissRequest: () -> Unit, + title: @Composable (() -> Unit)?, + text: @Composable (() -> Unit)?, + confirmButton: @Composable () -> Unit, +) { + AlertDialog( + modifier = modifier, + onDismissRequest = onDismissRequest, + title = title, + text = text, + confirmButton = confirmButton, + ) +} \ No newline at end of file diff --git a/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/CircularProgressIndicator.kt b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/CircularProgressIndicator.kt new file mode 100644 index 0000000..78b1fd3 --- /dev/null +++ b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/CircularProgressIndicator.kt @@ -0,0 +1,17 @@ +package com.developersbreach.designsystem.components + +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color + +@Composable +fun KdCircularProgressIndicator( + modifier: Modifier, + color: Color, +) { + CircularProgressIndicator( + modifier = modifier, + color = color, + ) +} \ No newline at end of file diff --git a/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Icon.kt b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Icon.kt index 15caf6b..3197853 100644 --- a/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Icon.kt +++ b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Icon.kt @@ -3,18 +3,21 @@ package com.developersbreach.designsystem.components import androidx.compose.material3.Icon import androidx.compose.material3.LocalContentColor import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector @Composable fun KdIcon( + modifier: Modifier, imageVector: ImageVector, contentDescription: String?, - tint: Color= LocalContentColor.current + tint: Color = LocalContentColor.current, ) { Icon( + modifier = modifier, imageVector = imageVector, contentDescription = contentDescription, - tint = tint + tint = tint, ) } \ No newline at end of file diff --git a/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/IconButton.kt b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/IconButton.kt index 67b1ba7..477d1bb 100644 --- a/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/IconButton.kt +++ b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/IconButton.kt @@ -3,24 +3,29 @@ package com.developersbreach.designsystem.components import androidx.compose.material3.IconButton import androidx.compose.material3.LocalContentColor import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector @Composable fun KdIconButton( + modifier: Modifier, + iconModifier: Modifier, onClick: () -> Unit, imageVector: ImageVector, contentDescription: String?, - tint: Color= LocalContentColor.current + tint: Color = LocalContentColor.current, ) { IconButton( + modifier = modifier, onClick = onClick, content = { KdIcon( imageVector = imageVector, contentDescription = contentDescription, - tint = tint + tint = tint, + modifier = iconModifier, ) - } + }, ) -} +} \ No newline at end of file diff --git a/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Scaffold.kt b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Scaffold.kt index 49b548d..8bfef3c 100644 --- a/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Scaffold.kt +++ b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Scaffold.kt @@ -4,17 +4,20 @@ import androidx.compose.foundation.layout.PaddingValues import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @Composable fun KdScaffold( + modifier: Modifier, topBar: @Composable () -> Unit, containerColor: Color = MaterialTheme.colorScheme.background, - content: @Composable (PaddingValues) -> Unit + content: @Composable (PaddingValues) -> Unit, ) { Scaffold( + modifier = modifier, topBar = topBar, containerColor = containerColor, - content = { content(it) } + content = { content(it) }, ) } \ No newline at end of file diff --git a/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Text.kt b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Text.kt index bdd0b57..07de47b 100644 --- a/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Text.kt +++ b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Text.kt @@ -15,7 +15,7 @@ import androidx.compose.ui.unit.TextUnit @Composable fun KdText( text: String, - modifier: Modifier = Modifier, + modifier: Modifier, style: TextStyle = LocalTextStyle.current, textAlign: TextAlign? = null, maxLines: Int = Int.MAX_VALUE, @@ -25,7 +25,7 @@ fun KdText( fontSize: TextUnit = TextUnit.Unspecified, fontFamily: FontFamily? = null, lineHeight: TextUnit = TextUnit.Unspecified, -){ +) { Text( text = text, modifier = modifier, @@ -33,10 +33,10 @@ fun KdText( textAlign = textAlign, maxLines = maxLines, overflow = overflow, - color=color, + color = color, fontWeight = fontWeight, fontSize = fontSize, fontFamily = fontFamily, - lineHeight = lineHeight + lineHeight = lineHeight, ) } \ No newline at end of file diff --git a/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/TextButton.kt b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/TextButton.kt new file mode 100644 index 0000000..82065a8 --- /dev/null +++ b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/TextButton.kt @@ -0,0 +1,19 @@ +package com.developersbreach.designsystem.components + +import androidx.compose.foundation.layout.RowScope +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier + +@Composable +fun KdTextButton( + onClick: () -> Unit, + modifier: Modifier, + content: @Composable RowScope.() -> Unit, +) { + TextButton( + onClick = onClick, + modifier = modifier, + content = content, + ) +} \ No newline at end of file diff --git a/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/TextField.kt b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/TextField.kt index 2ee0a06..dc4eb5a 100644 --- a/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/TextField.kt +++ b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/TextField.kt @@ -35,6 +35,5 @@ fun KdTextField( singleLine = singleLine, keyboardOptions = keyboardOptions, colors = colors, - ) -} +} \ No newline at end of file diff --git a/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/TopAppBar.kt b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/TopAppBar.kt new file mode 100644 index 0000000..f6872bf --- /dev/null +++ b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/TopAppBar.kt @@ -0,0 +1,23 @@ +package com.developersbreach.designsystem.components + +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarColors +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun KdTopAppBar( + title: @Composable () -> Unit, + modifier: Modifier = Modifier, + navigationIcon: @Composable () -> Unit, + colors: TopAppBarColors, +) { + TopAppBar( + title = title, + modifier = modifier, + navigationIcon = navigationIcon, + colors = colors, + ) +} \ No newline at end of file diff --git a/design-system/src/iosMain/kotlin/com/example/design_system/Platform.ios.kt b/design-system/src/iosMain/kotlin/com/example/design_system/Platform.ios.kt index 69be02b..1d900fb 100644 --- a/design-system/src/iosMain/kotlin/com/example/design_system/Platform.ios.kt +++ b/design-system/src/iosMain/kotlin/com/example/design_system/Platform.ios.kt @@ -1,3 +1,4 @@ +@file:Suppress("ktlint") package com.example.design_system actual fun platform() = "iOS" \ No newline at end of file From ca436e6564d3187d2626c3cd1c44ba6a0ae503d4 Mon Sep 17 00:00:00 2001 From: Shreyas Deshmukh Date: Thu, 12 Jun 2025 00:08:24 +0530 Subject: [PATCH 8/9] Removed trailing space manually --- .../kotlindictionarymultiplatform/ui/screens/topic/TopicCard.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 d503234..60f5b4e 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 @@ -69,7 +69,7 @@ fun TopicCard( contentAlignment = Alignment.Center, ) { KdText( - modifier = Modifier, + modifier = Modifier, text = itemTopic.initial, ) } From 5587c5cf15d2affac42395814a4f74323b2e4564 Mon Sep 17 00:00:00 2001 From: Raj Date: Thu, 12 Jun 2025 19:50:09 +0530 Subject: [PATCH 9/9] Improved component implementation for reusability, code clean up --- .../ui/components/ShowAlertDialog.kt | 47 ------- .../ui/components/UiStateHandler.kt | 13 +- .../ui/screens/topic/TopicCard.kt | 119 +++++++++--------- .../ui/screens/topic/TopicScreenUI.kt | 39 +++--- .../designsystem/components/AlertDialog.kt | 42 +++++++ .../components/CircularProgressIndicator.kt | 3 +- .../designsystem/components/Surface.kt | 2 +- 7 files changed, 131 insertions(+), 134 deletions(-) delete mode 100644 composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/components/ShowAlertDialog.kt diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/components/ShowAlertDialog.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/components/ShowAlertDialog.kt deleted file mode 100644 index d5c7acf..0000000 --- a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/components/ShowAlertDialog.kt +++ /dev/null @@ -1,47 +0,0 @@ -package com.developersbreach.kotlindictionarymultiplatform.ui.components - -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import com.developersbreach.designsystem.components.KdAlertDialog -import com.developersbreach.designsystem.components.KdText -import com.developersbreach.designsystem.components.KdTextButton -import kotlindictionarymultiplatform.composeapp.generated.resources.Res -import kotlindictionarymultiplatform.composeapp.generated.resources.ok -import org.jetbrains.compose.resources.stringResource - -@Composable -fun ShowAlertDialog( - onButtonClick: () -> Unit, - modifier: Modifier = Modifier, - title: String, - description: String, -) { - KdAlertDialog( - onDismissRequest = onButtonClick, - title = { - KdText( - modifier = Modifier, - text = title, - ) - }, - text = { - KdText( - modifier = Modifier, - text = description, - ) - }, - confirmButton = { - KdTextButton( - modifier = Modifier, - onClick = onButtonClick, - content = { - KdText( - modifier = Modifier, - text = stringResource(Res.string.ok), - ) - }, - ) - }, - modifier = modifier, - ) -} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/components/UiStateHandler.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/components/UiStateHandler.kt index f574dfa..2ce8840 100644 --- a/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/components/UiStateHandler.kt +++ b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/components/UiStateHandler.kt @@ -2,17 +2,18 @@ package com.developersbreach.kotlindictionarymultiplatform.ui.components import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import com.developersbreach.designsystem.components.KdAlertDialog import com.developersbreach.designsystem.components.KdCircularProgressIndicator import kotlindictionarymultiplatform.composeapp.generated.resources.Res import kotlindictionarymultiplatform.composeapp.generated.resources.error_info_unavailable import kotlindictionarymultiplatform.composeapp.generated.resources.error_occurred +import kotlindictionarymultiplatform.composeapp.generated.resources.ok import org.jetbrains.compose.resources.stringResource @Composable @@ -32,18 +33,21 @@ fun UiStateHandler( is UiState.Loading -> { KdCircularProgressIndicator( modifier = Modifier.align(Alignment.Center), - color = MaterialTheme.colorScheme.onBackground, ) } is UiState.Error -> { if (!shouldDismissErrorDialog.value) { val errorDetails = uiState.throwable - ShowAlertDialog( - onButtonClick = { shouldDismissErrorDialog.value = true }, + KdAlertDialog( + onDismissRequest = { shouldDismissErrorDialog.value = true }, modifier = Modifier, title = stringResource(Res.string.error_occurred), description = errorDetails.message ?: stringResource(Res.string.error_info_unavailable), + buttonTitle = stringResource(Res.string.ok), + onButtonClick = { + shouldDismissErrorDialog.value = true + }, ) } } @@ -54,7 +58,6 @@ fun UiStateHandler( if (isLoading) { KdCircularProgressIndicator( modifier = Modifier.align(Alignment.Center), - color = MaterialTheme.colorScheme.onBackground, ) } } 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 60f5b4e..28de7c0 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 @@ -52,71 +52,70 @@ fun TopicCard( .clickable { onCardClick() }, color = MaterialTheme.colorScheme.surface, shape = RoundedCornerShape(16.dp), - content = { - Row( + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(12.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Box( modifier = Modifier - .fillMaxWidth() - .padding(12.dp), - verticalAlignment = Alignment.CenterVertically, + .size(36.dp) + .background( + color = MaterialTheme.colorScheme.primary, + shape = CircleShape, + ), + contentAlignment = Alignment.Center, ) { - Box( - modifier = Modifier - .size(36.dp) - .background( - color = MaterialTheme.colorScheme.primary, - shape = CircleShape, - ), - contentAlignment = Alignment.Center, - ) { - KdText( - modifier = Modifier, - text = itemTopic.initial, - ) - } - - Spacer(modifier = Modifier.width(12.dp)) + KdText( + modifier = Modifier, + text = itemTopic.initial, + ) + } - Column( - modifier = Modifier.weight(1f), - ) { - KdText( - modifier = Modifier, - text = topic, - style = MaterialTheme.typography.headlineMedium.copy( - color = MaterialTheme.colorScheme.onPrimary, - ), - maxLines = 1, - overflow = TextOverflow.Ellipsis, - ) - Spacer(modifier = Modifier.height(6.dp)) - KdText( - modifier = Modifier, - text = subtitle, - style = MaterialTheme.typography.labelMedium.copy( - color = MaterialTheme.colorScheme.onBackground, - ), - maxLines = 1, - overflow = TextOverflow.Ellipsis, - ) - } + Spacer(modifier = Modifier.width(12.dp)) - KdIconButton( + Column( + modifier = Modifier.weight(1f), + ) { + KdText( 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, + text = topic, + style = MaterialTheme.typography.headlineMedium.copy( + color = MaterialTheme.colorScheme.onPrimary, + ), + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + Spacer(modifier = Modifier.height(6.dp)) + KdText( + modifier = Modifier, + text = subtitle, + style = MaterialTheme.typography.labelMedium.copy( + color = MaterialTheme.colorScheme.onBackground, + ), + maxLines = 1, + 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/TopicScreenUI.kt b/composeApp/src/commonMain/kotlin/com/developersbreach/kotlindictionarymultiplatform/ui/screens/topic/TopicScreenUI.kt index 2288187..105aa93 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 @@ -21,24 +21,23 @@ fun TopicScreenUI( KdScaffold( modifier = Modifier, topBar = { TopicTopBar() }, - content = { paddingValues -> - Column( - modifier = Modifier - .padding(horizontal = 16.dp) - .padding(top = paddingValues.calculateTopPadding()), - ) { - SearchField( - searchQuery = searchQuery, - onQueryChange = onQueryChange, - ) - Spacer(modifier = Modifier.height(8.dp)) - TopicList( - topics = topics, - bookmarkedStates = bookmarkedStates, - onBookmarkClick = onBookmarkClick, - onTopicClick = onTopicClick, - ) - } - }, - ) + ) { paddingValues -> + Column( + modifier = Modifier + .padding(horizontal = 16.dp) + .padding(top = paddingValues.calculateTopPadding()), + ) { + SearchField( + searchQuery = searchQuery, + onQueryChange = onQueryChange, + ) + Spacer(modifier = Modifier.height(8.dp)) + TopicList( + topics = topics, + bookmarkedStates = bookmarkedStates, + onBookmarkClick = onBookmarkClick, + onTopicClick = onTopicClick, + ) + } + } } \ No newline at end of file diff --git a/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/AlertDialog.kt b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/AlertDialog.kt index c34e3f5..29aadc2 100644 --- a/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/AlertDialog.kt +++ b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/AlertDialog.kt @@ -19,4 +19,46 @@ fun KdAlertDialog( text = text, confirmButton = confirmButton, ) +} + +@Composable +fun KdAlertDialog( + onDismissRequest: () -> Unit, + modifier: Modifier, + title: String, + description: String, + buttonTitle: String, + onButtonClick: () -> Unit, +) { + KdAlertDialog( + onDismissRequest = onDismissRequest, + title = { + KdText( + modifier = Modifier, + text = title, + ) + }, + text = { + KdText( + modifier = Modifier, + text = description, + ) + }, + confirmButton = { + KdTextButton( + modifier = Modifier, + onClick = { + onDismissRequest() + onButtonClick() + }, + content = { + KdText( + modifier = Modifier, + text = buttonTitle, + ) + }, + ) + }, + modifier = modifier, + ) } \ No newline at end of file diff --git a/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/CircularProgressIndicator.kt b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/CircularProgressIndicator.kt index 78b1fd3..560c2c7 100644 --- a/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/CircularProgressIndicator.kt +++ b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/CircularProgressIndicator.kt @@ -1,6 +1,7 @@ package com.developersbreach.designsystem.components import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -8,7 +9,7 @@ import androidx.compose.ui.graphics.Color @Composable fun KdCircularProgressIndicator( modifier: Modifier, - color: Color, + color: Color = MaterialTheme.colorScheme.onBackground, ) { CircularProgressIndicator( modifier = modifier, diff --git a/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Surface.kt b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Surface.kt index 24044d8..75782db 100644 --- a/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Surface.kt +++ b/design-system/src/commonMain/kotlin/com/developersbreach/designsystem/components/Surface.kt @@ -9,9 +9,9 @@ import androidx.compose.ui.graphics.Shape @Composable fun KdSurface( modifier: Modifier, - content: @Composable () -> Unit, color: Color, shape: Shape, + content: @Composable () -> Unit, ) { Surface( modifier = modifier,