feat(kmp): Phases 0-2 — Compose Multiplatform desktop + shared preference/network foundations#1671
feat(kmp): Phases 0-2 — Compose Multiplatform desktop + shared preference/network foundations#1671cuong-tran wants to merge 4 commits into
Conversation
- Add Compose Multiplatform version/library/plugin entries to libs catalog - Add jvm(desktop) target to :i18n so shared MR resources compile for desktop - Add :desktopApp Compose for Desktop module sharing the :i18n KMP module Keeps the Android build untouched; desktop is the first verifiable KMP target on this Linux VM (iOS/Native targets require a macOS runner). Co-authored-by: Cuong-Tran <cuong-tran@users.noreply.github.com>
The org.jetbrains.compose plugin is not applied (its 'compose' extension clashes with the 'compose' version catalog), so select the host OS Compose Desktop artifact (desktop-jvm-<os>) explicitly to load the matching Skiko native lib. Co-authored-by: Cuong-Tran <cuong-tran@users.noreply.github.com>
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request establishes the foundational scaffolding for transitioning the project to Kotlin Multiplatform (KMP). It successfully integrates Compose Multiplatform for desktop without impacting the existing Android build, proving that shared modules can be consumed across platforms. This is a preliminary step intended to validate the toolchain and project structure before broader architectural changes are implemented. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. The code now runs on desktop screens, Beyond the reach of mobile scenes. With KMP the path is clear, To bring the app to all, my dear. Footnotes
|
Reviewer's GuideIntroduces initial Kotlin Multiplatform (KMP) scaffolding for a Compose Multiplatform desktop app by adding a JVM desktop target to the shared i18n module, wiring a new :desktopApp module that directly uses the Compose compiler and host-specific desktop artifact, and updating the version catalog to declare Compose Multiplatform versions and plugin aliasing, all without modifying the existing Android build. File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Code Review
This pull request introduces Phase 0 scaffolding for a Compose Multiplatform desktop application (:desktopApp), including the main entry point, build configuration, and adding the JVM desktop target to the shared :i18n module. The feedback suggests using type-safe version catalog accessors in build.gradle.kts to make the configuration cleaner and remove an unnecessary import. Additionally, it is recommended to handle potential null values from System.getProperty when determining the host OS and architecture to prevent potential NullPointerExceptions.
| @@ -0,0 +1,58 @@ | |||
| import org.gradle.api.artifacts.VersionCatalogsExtension | |||
| val composeMultiplatformVersion = the<VersionCatalogsExtension>() | ||
| .named("libs") | ||
| .findVersion("compose-multiplatform") | ||
| .get() | ||
| .requiredVersion |
| val hostComposeDesktopTarget: String = run { | ||
| val osName = System.getProperty("os.name").lowercase() | ||
| val osArch = System.getProperty("os.arch").lowercase() | ||
| val isArm = osArch.contains("aarch64") || osArch.contains("arm") |
There was a problem hiding this comment.
System.getProperty can theoretically return null if the property is not set or if a security manager restricts access. Using orEmpty() before calling lowercase() prevents potential NullPointerExceptions and ensures safer execution.
val hostComposeDesktopTarget: String = run {
val osName = System.getProperty("os.name").orEmpty().lowercase()
val osArch = System.getProperty("os.arch").orEmpty().lowercase()
val isArm = osArch.contains("aarch64") || osArch.contains("arm")- New KMP module :core:preference (android + desktop) holding the portable PreferenceStore/Preference/InMemoryPreferenceStore/TriState/CheckboxState abstractions, kept in the original tachiyomi.core.common.preference package so no imports change across the codebase. - Add DesktopPreferenceStore (java.util.prefs-backed) as the desktop actual of the shared PreferenceStore, mirroring AndroidPreferenceStore semantics. - core:common re-exports :core:preference via api(); AndroidPreference(Store) stay in core:common (they depend on logcat) to avoid a circular dependency. - desktopApp now persists a launch counter through the shared PreferenceStore. Co-authored-by: Cuong-Tran <cuong-tran@users.noreply.github.com>
- New KMP module :core:network (android + desktop) introducing the jvmShared intermediate source set pattern: OkHttp (a JVM library) lives in jvmShared and is shared by both JVM targets, while commonMain holds the platform-agnostic NetworkClient/NetworkResponse API + an expect httpClient() factory. - OkHttpNetworkClient provides the JVM actual; an iOS (Kotlin/Native) target would add an iosMain actual (e.g. Ktor Darwin) without touching this API. - desktopApp now performs a real HTTP GET through the shared NetworkClient. Additive and non-invasive: the existing core:common NetworkHelper and the source-api network ABI are untouched (migrating them onto this foundation is follow-on work, entangled with the source-api commonMain ABI). Co-authored-by: Cuong-Tran <cuong-tran@users.noreply.github.com>
Summary
Incremental, verifiable work toward making Komikku multiplatform (Android + desktop + iOS) with Kotlin Multiplatform, keeping the Android build green at every step.
Phase 0 — Compose Multiplatform desktop scaffolding
1.10.3(aligned with Kotlin 2.3.10) added to thelibscatalog.:i18ngains ajvm("desktop")target so the shared mokoMRcompiles for desktop.:desktopAppCompose for Desktop module consuming:i18n.composecatalog ↔org.jetbrains.composeplugin extension name clash by depending on the host-specificdesktop-jvm-<os>artifact directly (so the right Skiko native loads).Phase 1 — Shared multiplatform
PreferenceStore:core:preference(android + desktop) holding the portablePreferenceStore/Preference/InMemoryPreferenceStore/TriState/CheckboxState, kept in the originaltachiyomi.core.common.preferencepackage → zero import churn.DesktopPreferenceStore(java.util.prefs-backed) as the desktop implementation, mirroringAndroidPreferenceStore(including reactivechanges()).core:commonre-exports it viaapi();AndroidPreference(Store)stay incore:common(they needlogcat) to avoid a circular dependency.Phase 2 — Multiplatform networking foundation
:core:network(android + desktop) introducing thejvmSharedintermediate source set pattern: OkHttp (a JVM library) lives injvmSharedshared by both JVM targets, whilecommonMainholds the platform-agnosticNetworkClient/NetworkResponseAPI + anexpect httpClient()factory.OkHttpNetworkClientis the JVM actual; an iOS target would add aniosMainactual (e.g. Ktor Darwin) without changing the common API.core:commonNetworkHelperand thesource-apinetwork ABI are untouched.Scope / next steps
NetworkHelper/Requests/source-apiABI and givingdomain/datadesktop targets remain entangled (e.g.HttpSourceinsource-api/commonMainpulls in the Android network stack, andlogcatis Android-only). Each phase here delivered the cleanly-separable, non-cascading slice that's fully verifiable on desktop.Walkthrough
Phase 2 — the shared
NetworkClient(OkHttp) performs a liveGET example.comreturning HTTP 200 on desktop; the Phase 1 counter also persists (now 3):komikku_desktop_phase2_shared_networkclient.mp4
Desktop app: shared NetworkClient GET example.com HTTP 200
Phase 1 — shared
PreferenceStorepersists across runs (counter 1 → 2):komikku_desktop_phase1_preference_persistence.mp4
Persisted counter = 2 on second run
Testing
./gradlew :core:preference:compileKotlinDesktop/:core:network:compileKotlinDesktop/:core:network:compileDebugKotlinAndroid— new modules compile for both targets./gradlew :desktopApp:compileKotlin— desktop app compiles against the shared preference + network APIsSKIKO_RENDER_API=SOFTWARE ./gradlew :desktopApp:run— desktop app runs; preference persists across runs; sharedNetworkClientreturns HTTP 200 (see videos/screenshots)./gradlew spotlessCheck— passes./gradlew assembleDebug— Android build still green (BUILD SUCCESSFUL) after both extractionsAdd a 👍 reaction to pull requests you find important.
To show artifacts inline, enable in settings.
Summary by Sourcery
Introduce initial Kotlin Multiplatform desktop scaffolding to validate Compose Multiplatform integration and shared module reuse without impacting the existing Android app.
New Features: