Skip to content

feat: convert Zayit to Kotlin Multiplatform (JVM + Android + iOS)#506

Open
kdroidFilter wants to merge 3 commits into
devfrom
feat/kmp-multiplatform
Open

feat: convert Zayit to Kotlin Multiplatform (JVM + Android + iOS)#506
kdroidFilter wants to merge 3 commits into
devfrom
feat/kmp-multiplatform

Conversation

@kdroidFilter

@kdroidFilter kdroidFilter commented Jun 22, 2026

Copy link
Copy Markdown
Owner

Summary

Converts the whole project to Kotlin Multiplatform. The JVM desktop app is
unchanged; Android and iOS now build, with stub UIs, and everything that is
platform-agnostic has moved into commonMain. JVM-only code (Jewel, Nucleus,
Lucene, AWT, JDBC, jsoup) stays in jvmMain.

Pairs with SeforimLibrary#83 (submodule). Merge that first; this PR bumps the
submodule pointer to it.

Build matrix (all verified)

Platform Result
JVM desktop compiles (main + tests) — full Jewel app intact
iOS compiles · SeforimApp.framework links (MainViewController entry)
Android compiles · :androidApp:assembleDebug produces an APK (~15 MB)

Highlights

  • Leaf libs (icons, texteffects, navigation, pagination, htmlparser,
    logger) → multiplatform. htmlparser swaps jsoup for ksoup so the parser
    runs on iOS; logger puts Sentry behind expect/actual; navigation uses
    kotlin.uuid.Uuid + kotlin.time.Clock.
  • SeforimApp gains Android (KMP library) + iOS targets. ~75 files of
    platform-agnostic code (onboarding / settings / search use-cases, state,
    AppSettings, core utils, theme enums) moved to commonMain. JVM-only deps
    relocated to jvmMain. AccentColor split into a common enum + a jvm color
    resolver. Search behind a common SearchEngine interface (JVM = Lucene,
    mobile = StubSearchEngine).
  • androidApp — new thin com.android.application module hosting the APK
    (AGP 9 forbids the application plugin inside the KMP module), depending on
    :SeforimApp.
  • Tooling: AGP 9.1.1 built-in Kotlin (no kotlin-android plugin), compileSdk 36,
    AGP/Kotlin aligned across the composite build.

Not in scope

The Android/iOS UI is a placeholder App() and the mobile search engine is a
no-op stub. Implementing the real mobile UI + a mobile search backend (and
abstracting the desktop split-panes out of bookcontent state to move even more
into common) are follow-ups. Opened as draft for that reason.

@kdroidFilter
kdroidFilter force-pushed the feat/kmp-multiplatform branch from 671f905 to a54c828 Compare June 22, 2026 15:55
Group search results by book into one deduplicated card per book: the top hit
shown prominently, locations in a leading reference column, matched terms in
gold, and the remaining hits in a fixed-height, scrollable list. Reuse the book
pane's ContentAwareScrollbarShell so the expanded list and the main results list
both get a themed, stable scrollbar thumb (sized from the facet book count, so it
no longer shrinks as more pages load).

- ViewModel: expose bookFacetCountsFlow and loadAllHitsForBook(bookId)
- TabsContent: wire book counts and the per-book hit loader into the shell
- strings: add search_more_in_book / search_collapse

Signed-off-by: Elie Gambache <elyahou.hadass@gmail.com>
…iOS)

The whole project is now KMP. JVM desktop is unchanged; Android and iOS build
with stub UIs, and everything platform-agnostic moved into commonMain.

leaf libraries (icons, texteffects, navigation, pagination, htmlparser, logger)
- add Android + iOS targets
- logger: Sentry + timestamp behind expect/actual (JVM=Sentry, mobile=stub),
  kotlin.concurrent.Volatile, drop @JvmField
- navigation: java.util.UUID -> kotlin.uuid.Uuid; nowEpochMillis via kotlin.time.Clock
- htmlparser: jsoup -> ksoup 0.2.6 (parser runs on all platforms)

SeforimApp
- add Android (KMP library) + iOS targets; iOS framework + MainViewController entry
- relocate JVM-only deps (Nucleus, network, releasefetcher, ktor-cio) commonMain -> jvmMain
- move ~75 files of platform-agnostic code (onboarding/settings/search use-cases,
  state, AppSettings, core utils, theme enums) into commonMain
- AccentColor split: enum in commonMain, Jewel/Nucleus color resolution in jvmMain
- search engine via common SearchEngine interface (JVM=Lucene, mobile=StubSearchEngine)
- stub App() for Android/iOS; Jewel/Nucleus/Lucene/AWT desktop UI stays in jvmMain

androidApp
- new thin com.android.application module (AGP 9 forbids it in the KMP module) that
  hosts the launchable APK and depends on :SeforimApp

build
- AGP 9.1.1 built-in Kotlin (no kotlin-android plugin), compileSdk 36,
  android.library plugin available to subprojects, SeforimLibrary submodule bump

Signed-off-by: Elie Gambache <elyahou.hadass@gmail.com>
Signed-off-by: Elie Gambache <elyahou.hadass@gmail.com>
@kdroidFilter
kdroidFilter force-pushed the feat/kmp-multiplatform branch from 98351c1 to 1308e0b Compare June 22, 2026 16:13
@kdroidFilter
kdroidFilter marked this pull request as ready for review June 22, 2026 16:50
@kdroidFilter
kdroidFilter requested a review from Copilot June 22, 2026 16:50

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR migrates Zayit to Kotlin Multiplatform (JVM + Android + iOS), moving platform-agnostic logic into commonMain, keeping JVM-only dependencies in jvmMain, and adding thin Android/iOS entrypoints so mobile targets compile with placeholder UI.

Changes:

  • Introduces KMP targets (Android library + iOS frameworks) across the app and several leaf modules, and adds a new :androidApp launcher module.
  • Moves/introduces shared domain + UI-support code into commonMain (onboarding/settings/search/state/utils), while keeping desktop/JVM-only integrations in jvmMain.
  • Enhances desktop search results UI with grouped-per-book result cards and adds exact per-book facet counts + “expand all hits in book” behavior.

Reviewed changes

Copilot reviewed 43 out of 114 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
texteffects/build.gradle.kts Adds Android + iOS targets and Android namespace/sdk config for texteffects.
settings.gradle.kts Registers new :androidApp module in the build.
SeforimApp/src/jvmTest/.../ResultsIndexingUseCaseTest.kt Updates assertion to match new index identity strategy.
SeforimApp/src/jvmTest/.../CopyWithSourceE2ETest.kt Adapts catalog loading to suspend API via runBlocking.
SeforimApp/src/jvmTest/.../CatalogAccessTest.kt Adapts catalog loading to suspend API via runBlocking.
SeforimApp/src/jvmMain/.../DatabaseUtils.kt Wraps suspend catalog load in runBlocking inside JVM cache loader.
SeforimApp/src/jvmMain/.../DisplaySettingsScreen.kt Updates theme-related import usage for JVM UI.
SeforimApp/src/jvmMain/.../SearchResultViewModel.kt Adds per-book facet counts flow and a method to load all hits for a book.
SeforimApp/src/jvmMain/.../SearchResultScreen.kt Reworks results UI into grouped per-book cards with expansion + custom scrollbar behavior.
SeforimApp/src/jvmMain/.../DownloadViewModel.kt Makes @Volatile annotation explicit for KMP compilation.
SeforimApp/src/jvmMain/.../HomeView.kt Updates theme import usage for JVM UI.
SeforimApp/src/jvmMain/.../HomeCelestialWidgets.kt Updates theme color resolution import usage for JVM UI.
SeforimApp/src/jvmMain/.../core/presentation/theme/AccentColorColors.kt Adds JVM-specific color resolution extensions for common AccentColor.
SeforimApp/src/jvmMain/.../core/presentation/theme/AccentColor.kt Removes JVM-only AccentColor enum (moved to common).
SeforimApp/src/jvmMain/.../core/presentation/tabs/TabsContent.kt Plumbs new book facet counts and book-hit loader into search tab UI.
SeforimApp/src/iosMain/.../MainViewController.kt Adds iOS entrypoint returning a ComposeUIViewController hosting App().
SeforimApp/src/commonMain/.../framework/di/AppScope.kt Adds app-wide DI scope marker for Metro.
SeforimApp/src/commonMain/.../framework/di/AppMetroViewModelFactory.kt Adds Metro ViewModel factory wiring for common ViewModels.
SeforimApp/src/commonMain/.../features/zmanim/data/Cities.kt Adds shared country/city coordinate dataset for region/zmanim features.
SeforimApp/src/commonMain/.../features/settings/SettingsWindowViewModel.kt Adds shared settings-window visibility ViewModel.
SeforimApp/src/commonMain/.../features/settings/SettingsWindowState.kt Adds settings window state model.
SeforimApp/src/commonMain/.../features/settings/SettingsWindowEvents.kt Adds settings window events model.
SeforimApp/src/commonMain/.../features/settings/navigation/SettingsDestination.kt Adds serializable settings destinations for navigation.
SeforimApp/src/commonMain/.../features/settings/general/GeneralSettingsViewModel.kt Adds shared General Settings ViewModel backed by AppSettings.
SeforimApp/src/commonMain/.../features/settings/general/GeneralSettingsState.kt Adds shared General Settings state model.
SeforimApp/src/commonMain/.../features/settings/general/GeneralSettingsEvents.kt Adds events model for General Settings.
SeforimApp/src/commonMain/.../features/settings/fonts/FontsSettingsViewModel.kt Adds shared Fonts Settings ViewModel backed by AppSettings.
SeforimApp/src/commonMain/.../features/settings/fonts/FontsSettingsState.kt Adds shared Fonts Settings state model.
SeforimApp/src/commonMain/.../features/settings/fonts/FontsSettingsEvents.kt Adds events model for Fonts Settings.
SeforimApp/src/commonMain/.../features/settings/display/DisplaySettingsViewModel.kt Adds shared Display Settings ViewModel backed by AppSettings.
SeforimApp/src/commonMain/.../features/settings/display/DisplaySettingsState.kt Adds shared Display Settings state model.
SeforimApp/src/commonMain/.../features/settings/display/DisplaySettingsEvents.kt Adds events model for Display Settings.
SeforimApp/src/commonMain/.../features/settings/dbupdate/DbDeltaUpdateState.kt Adds shared UI state surface for DB delta update panel.
SeforimApp/src/commonMain/.../features/settings/dbupdate/DbDeltaUpdateEvents.kt Adds events model for DB delta update panel.
SeforimApp/src/commonMain/.../features/settings/data/DataSettingsState.kt Adds shared Data settings state model (import/export/reset flags).
SeforimApp/src/commonMain/.../features/search/SearchFilter.kt Adds shared search mode enum for Home search.
SeforimApp/src/commonMain/.../features/search/domain/ResultsIndexingUseCase.kt Updates caching/identity and parallel filtering to be KMP-friendly.
SeforimApp/src/commonMain/.../features/search/domain/GetBreadcrumbPiecesUseCase.kt Adds shared use case for breadcrumb resolution with internal caching.
SeforimApp/src/commonMain/.../features/search/domain/CategoryNavigationUseCase.kt Adds shared category navigation use case with caching.
SeforimApp/src/commonMain/.../features/onboarding/userprofile/UserProfileViewModel.kt Adds shared onboarding user-profile ViewModel/state/events.
SeforimApp/src/commonMain/.../features/onboarding/userprofile/UserProfileUseCase.kt Adds shared user-profile helper use case.
SeforimApp/src/commonMain/.../features/onboarding/userprofile/UserProfileState.kt Adds shared user-profile state.
SeforimApp/src/commonMain/.../features/onboarding/userprofile/UserProfileEvents.kt Adds shared user-profile events.
SeforimApp/src/commonMain/.../features/onboarding/userprofile/Community.kt Adds shared community enum.
SeforimApp/src/commonMain/.../features/onboarding/typeofinstall/TypeOfInstallationViewModel.kt Adds shared onboarding step ViewModel for install type.
SeforimApp/src/commonMain/.../features/onboarding/typeofinstall/TypeOfInstallationState.kt Adds shared onboarding state model for install type.
SeforimApp/src/commonMain/.../features/onboarding/typeofinstall/TypeOfInstallationEvents.kt Adds events model for install type selection.
SeforimApp/src/commonMain/.../features/onboarding/region/RegionConfigViewModel.kt Adds shared region config ViewModel reading/writing AppSettings.
SeforimApp/src/commonMain/.../features/onboarding/region/RegionConfigUseCase.kt Adds shared region config use case backed by worldPlaces.
SeforimApp/src/commonMain/.../features/onboarding/region/RegionConfigState.kt Adds shared region config state + preview data.
SeforimApp/src/commonMain/.../features/onboarding/region/RegionConfigEvents.kt Adds events model for region selection.
SeforimApp/src/commonMain/.../features/onboarding/navigation/ProgressBarState.kt Adds shared progress controller singleton for onboarding UI.
SeforimApp/src/commonMain/.../features/onboarding/navigation/OnBoardingDestination.kt Adds serializable onboarding destinations.
SeforimApp/src/commonMain/.../features/onboarding/extract/ExtractState.kt Adds shared state model for extraction step.
SeforimApp/src/commonMain/.../features/onboarding/extract/ExtractEvents.kt Adds events model for extraction step.
SeforimApp/src/commonMain/.../features/onboarding/download/DownloadState.kt Adds shared download state + error categorization.
SeforimApp/src/commonMain/.../features/onboarding/download/DownloadEvents.kt Adds events model for download flow.
SeforimApp/src/commonMain/.../features/onboarding/diskspace/AvailableDiskSpaceState.kt Adds shared state for disk space checks.
SeforimApp/src/commonMain/.../features/onboarding/diskspace/AvailableDiskSpaceEvents.kt Adds events model for disk space screen.
SeforimApp/src/commonMain/.../features/onboarding/data/OnboardingProcessRepository.kt Adds shared transient onboarding process repository (e.g., pending .zst path).
SeforimApp/src/commonMain/.../features/database/update/navigation/DatabaseUpdateProgressBarState.kt Adds shared progress controller for DB update flow.
SeforimApp/src/commonMain/.../features/database/update/navigation/DatabaseUpdateDestination.kt Adds serializable destinations for DB update flow.
SeforimApp/src/commonMain/.../features/bookcontent/ui/panels/.../SelectionBarLogic.kt Extracts selection-bar decision logic into shared helper functions.
SeforimApp/src/commonMain/.../features/bookcontent/ui/panels/.../ScrollbarMetrics.kt Adds shared scrollbar measurement helpers and binary search utilities.
SeforimApp/src/commonMain/.../features/bookcontent/ui/panels/.../HomeCelestialWidgetsViewModel.kt Adds shared ViewModel for home zmanim widgets using region settings.
SeforimApp/src/commonMain/.../features/bookcontent/ui/panels/.../BookContentZoomInteraction.kt Adds composition local for zoom interaction state.
SeforimApp/src/commonMain/.../features/bookcontent/ui/components/SelectionWorkarounds.kt Adds shared safe selection container workaround for Compose crash.
SeforimApp/src/commonMain/.../features/bookcontent/state/StateKeys.kt Centralizes persisted state keys for book content.
SeforimApp/src/commonMain/.../features/bookcontent/state/SplitDefaults.kt Centralizes split-pane default constants.
SeforimApp/src/commonMain/.../features/bookcontent/state/LineConnectionsSnapshot.kt Adds shared snapshot model for line connection data.
SeforimApp/src/commonMain/.../features/bookcontent/state/CommentatorGroup.kt Adds shared models for commentaries grouping UI.
SeforimApp/src/commonMain/.../features/bookcontent/state/BookOpenSource.kt Adds shared enum to tag origins of “open book” actions.
SeforimApp/src/commonMain/.../features/bookcontent/BookContentEvent.kt Moves/introduces a shared sealed event model for book content interactions.
SeforimApp/src/commonMain/.../core/settings/AppSettings.kt Makes @Volatile explicit for KMP compatibility.
SeforimApp/src/commonMain/.../core/selection/SelectionContext.kt Introduces shared selection context interface + default implementation.
SeforimApp/src/commonMain/.../core/presentation/utils/WindowViewModelOwner.kt Adds a window-scoped ViewModelStoreOwner for Compose windows.
SeforimApp/src/commonMain/.../core/presentation/utils/TouchMode.kt Adds shared touch-mode detection composition local + modifier.
SeforimApp/src/commonMain/.../core/presentation/utils/FormatUtils.kt Replaces String.format with a multiplatform-friendly formatting helper.
SeforimApp/src/commonMain/.../core/presentation/theme/ThemeStyle.kt Adds shared theme-style enum.
SeforimApp/src/commonMain/.../core/presentation/theme/IntUiThemes.kt Adds shared light/dark/system enum.
SeforimApp/src/commonMain/.../core/presentation/theme/AccentColor.kt Moves the persisted AccentColor enum to commonMain.
SeforimApp/src/commonMain/.../core/presentation/text/HebrewSearch.kt Adds shared Hebrew-aware diacritic stripping + matching utilities.
SeforimApp/src/commonMain/.../core/presentation/navigation/NoAnimatedComposable.kt Adds shared navigation builder helper using disabled transitions on JVM.
SeforimApp/src/commonMain/.../core/presentation/components/ProgressBarController.kt Adds shared reactive progress controller base class.
SeforimApp/src/commonMain/.../core/presentation/components/HardDriveUpload.kt Adds shared vector asset definition for installer/update UI.
SeforimApp/src/commonMain/.../core/MainAppState.kt Adds shared app-level state holder (theme/onboarding) backed by AppSettings.
SeforimApp/src/commonMain/.../core/coroutines/CoroutineUtils.kt Adds coroutine-safe runSuspendCatching helper.
SeforimApp/src/commonMain/.../core/catalog/CatalogAccess.kt Makes @Volatile explicit for KMP compatibility.
SeforimApp/src/commonMain/.../core/annotations/HighlightSelectionResolver.kt Adds shared highlight range resolution for (multi-line) selections.
SeforimApp/src/commonMain/kotlin/.../App.kt Adds shared (stub) mobile app entry composable.
SeforimApp/src/commonMain/composeResources/values/strings.xml Adds new Hebrew strings for “more in book” and “collapse” in search.
SeforimApp/src/androidMain/.../Theme.android.kt Removes Android-only SystemAppearance implementation (moved/obsolete in KMP refactor).
SeforimApp/build.gradle.kts Converts SeforimApp to an Android library KMP module, adds iOS frameworks, relocates JVM-only deps.
pagination/src/commonMain/.../LinesPagingSource.kt Replaces Java reflection usage with KMP-safe ::class.
pagination/build.gradle.kts Adds Android + iOS targets and Android namespace/sdk config for pagination.
navigation/src/commonMain/.../TabsViewModel.kt Replaces java.util.UUID with kotlin.uuid.Uuid and uses shared epoch time helper.
navigation/src/commonMain/.../PlatformTime.kt Adds multiplatform epoch-millis helper using Clock.
navigation/build.gradle.kts Adds Android + iOS targets and includes kotlinx-datetime for time support.
logger/src/jvmMain/.../Logger.jvm.kt Adds JVM crash reporting implementation via Sentry for the new expect/actual logger API.
logger/src/iosMain/.../Logger.ios.kt Adds iOS timestamp implementation and stubs crash reporting.
logger/src/commonMain/.../Logger.kt Refactors logger into expect/actual timestamp + crash reporting; removes JVM-only code from common.
logger/src/androidMain/.../Logger.android.kt Adds Android crash-report stubs for expect/actual logger API.
logger/src/androidJvmMain/.../Logger.jvmAndroid.kt Adds shared JVM/Android timestamp formatting implementation.
logger/build.gradle.kts Makes logger multiplatform (Android + iOS) and defines an androidJvmMain shared source set.
icons/build.gradle.kts Adds Android + iOS targets and Android namespace/sdk config for icons.
htmlparser/src/commonMain/.../HtmlParser.kt Switches HTML parsing from jsoup to ksoup for iOS compatibility.
htmlparser/build.gradle.kts Adds Android + iOS targets and swaps dependency from jsoup to ksoup.
gradle/libs.versions.toml Adds ksoup dependency version and module coordinates.
build.gradle.kts Adds android-library plugin alias for subprojects.
androidApp/src/main/AndroidManifest.xml Adds new Android launcher manifest pointing at shared AppActivity.
androidApp/build.gradle.kts Adds thin Android application module that depends on :SeforimApp.
Comments suppressed due to low confidence (2)

SeforimApp/src/commonMain/kotlin/io/github/kdroidfilter/seforimapp/features/search/domain/ResultsIndexingUseCase.kt:66

  • ensureIndex can return a stale cachedIndex: cachedResults is updated to the new results list before the new index is assigned, so a concurrent caller can observe cachedResults === results while cachedIndex still points at the previous index and return it from this fast-path.
    androidApp/src/main/AndroidManifest.xml:7
  • The Android android:label is hardcoded. For localization (and consistency with the project guideline of not hardcoding user-visible text), it should reference an Android string resource (e.g. @string/app_name) defined in androidApp/src/main/res/values/strings.xml.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread androidApp/build.gradle.kts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants