Repository navigation
feat(appkit): the app's logic in common code, for the mobile apps - #700
Draft
kdroidFilter wants to merge 9 commits into
Draft
kdroidFilter wants to merge 9 commits into
kdroidFilter wants to merge 9 commits into
Conversation
…le apps A new KMP module, appkit (JVM, Android 10+, iOS), takes from SeforimApp what doesn't need the desktop: the reader's state, use cases and paging, the user's data (highlights, notes, favorites, history, the UserSettingsDb schema), the settings (AppSettings and the settings view models), the onboarding's states and view models, the catalog and the cities. Packages are unchanged. - earthwidget and pagination get Android and iOS targets (Filament KMP renders there too); the solar position runs on kotlinx-datetime, the desktop views keep their java.util.Date overloads. - java.* replaced by common APIs: atomicfu locks, SeforimLibrary's :cache, LruCache, kotlin.time, FileKit paths. - Reader pane splits: PaneSplitState instead of compose-splitpane's desktop-only SplitPaneState. - AccentColor: the enum is common, its Jewel colors stay on the desktop (AccentColors.kt). - The quote links addon moves to appkit's jvmMain (null on mobile); its DB test stays in SeforimApp. - The tests of the moved code move with it: commonTest (run on the JVM and the iOS simulator) or jvmTest. Signed-off-by: Elie Gambache <elyahou.hadass@gmail.com>
- TabsViewModel drives a TabsHost port, the window's tabs as the platform holds them; the desktop's DesktopTabsHost maps it onto its TabWorkspace. A common test covers it on a fake host (JVM and iOS). - BookContentViewModel reaches the desktop through two ports: TabsResolver (DesktopManager) to open tabs next to its own, SessionRestoreState (SessionManager) to know whether the session is being restored. - pinnedTabLabel moves with it. Signed-off-by: Elie Gambache <elyahou.hadass@gmail.com>
SessionManager (saving, restoring and migrating the session, naming its tabs) moves to appkit, on kotlinx-io files under FileKit's databases directory as before. It reaches the shell through a SessionShell port: the desktops to save and the tabs' pictures to drop (the desktop's DesktopSessionShell, on DesktopManager and TabThumbnailStore), and the end-to-end harness that turns it off. DesktopManager stays on the desktop: it is the shell itself (windows, Nucleus tab workspaces, geometry, drag and drop between windows), behind the ports it implements (TabsResolver, SessionShell's desktops). Signed-off-by: Elie Gambache <elyahou.hadass@gmail.com>
…platform - AppKitBindings (appkit, contributed to AppScope): the settings, the app state, the catalog access, the user database and its stores, the books' repository and the search's settings and history, for every app's graph. - AppDatabases (expect/actual) opens the SQLite connections: on the desktop, PersistentSqliteDriver for the books and JDBC with a busy timeout for the user database; on Android and iOS, searchkit's drivers for the books and their own for the user database. The user tables are created on each open in common code, as before. - ShnayimMikraStore moves to appkit; the desktop's AppCoreBindings keeps its own (HTTP, Drive, search engine, delta updates, thumbnails, updater, DesktopManager and the shell's ports) and provides AppDatabases. Signed-off-by: Elie Gambache <elyahou.hadass@gmail.com>
…e search's session store in common code - CopyWithSource and BookErrorReport move to appkit, on htmlparser's new htmlToText (jsoup's Document.text() on the JVM and Android, Ksoup's on iOS) and a common percent-encoding of the mailto. - VisitEntry.destination() and openSiddurTab: kotlin.uuid. - DesktopSearchSessionStore, which only reads the common session, becomes appkit's TabSearchSessionStore. - Their tests move with them. Signed-off-by: Elie Gambache <elyahou.hadass@gmail.com>
…es in common code - The strings, fonts, pictures and files (composeResources) move to appkit, whose Res keeps its package (seforimapp.seforimapp.generated.resources), public for the apps' screens; Android packs them. The two OpenSans variable fonts lose the comma in their names, which Kotlin/Native refuses in an accessor (unused in code). - FontCatalog (on isMacOsDesktop), the window ViewModel store owner and the navigation helper move to appkit, with FontCatalog's tests. - CLAUDE.md describes appkit; the docs and font scripts point at the resources' new place. Signed-off-by: Elie Gambache <elyahou.hadass@gmail.com>
…d-kmp and our own tar reader - ExtractUseCase and BundleParts move to appkit on Okio: zstd-kmp decompresses (JNI on the desktop, native on Android and iOS), a common TarReader reads the archive (ustar, POSIX extended headers for long paths and big sizes as the packager writes them, GNU long names, base-256 sizes, header checksums) and Okio's HashingSource checks the bundle's sha256. An entry climbing out of the databases directory is refused. - zstd-jni leaves SeforimApp; its GraalVM metadata gains zstd-kmp's library and the fields its JNI code sets. - Tests: the tar reader and the extraction in common code (JVM and iOS simulator), BundleParts on a fake file system, and a bundle written as the packager does (zstd-jni, commons-compress) extracted on the JVM. Signed-off-by: Elie Gambache <elyahou.hadass@gmail.com>
…ive image included) ZAYIT_E2E_SCENARIO=extract with ZAYIT_E2E_BUNDLE naming a .tar.zst or its .part01 runs the onboarding's ExtractUseCase into the run's output, with throwaway settings, and notes the extracted database's size and sha256. On the GraalVM native image (macOS arm64), a 157 MB bundle in 3 parts written as the packager does (POSIX tar, zstd -T2 with checksum, manifest with its sha256) extracts to the expected database, and so does the single .tar.zst. Signed-off-by: Elie Gambache <elyahou.hadass@gmail.com>
… file system IosExtractBundleTest runs ExtractUseCase on FileSystem.SYSTEM in the simulator, with -PseforimTestBundle (a .tar.zst or its .part01) and -PseforimTestBundleSha256 (the extracted database's); skipped without them. The 157 MB bundle in 3 parts written as the packager does extracts to the expected database in 2.6 s, and so does the single .tar.zst. Signed-off-by: Elie Gambache <elyahou.hadass@gmail.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR is stacked on the search's port and must be merged after:
0.4.0)searchkit), this PR's base branch; once it's merged, this PR targetsmaster.NJA
0.4.0's Gradle plugin isn't on the Gradle Plugin Portal yet: here it was built from itsv0.4.0tag intomavenLocal, withmavenLocal()added to SeforimLibrary'spluginManagement(not committed).Summary
First step of the mobile UI: everything that doesn't need the desktop goes to common code, so the Android and iOS apps only have their screens to write.
appkit: a new KMP module (JVM, Android 10+, iOS), taken fromSeforimAppwith its packages unchanged.UserSettingsDbschema.AppSettingsand the general, fonts and display view models.CatalogPresets,CatalogAccess,CatalogCache),DatabasePathProviderand the cities.earthwidgetandpagination: Android and iOS targets (Filament KMP renders there too). The solar position now uses kotlinx-datetime; the desktop views keep theirjava.util.Dateoverloads.java.*:synchronized;:cachereplaces theConcurrentHashMapcaches;LruCachereplaces the access-orderLinkedHashMaps;kotlin.time/kotlin.uuidand FileKit paths replace the rest.PaneSplitStatereplaces compose-splitpane'sSplitPaneState, which is desktop only.AccentColor: the enum is common; its Jewel and system colors stay on the desktop (AccentColors.kt).appkit'sjvmMain(it's a JVM package);installedQuoteLinksis null on mobile.BookContentViewModelandTabsViewModel, behind ports likesearchkit's:TabsHost: the window's tabs as the platform holds them; the desktop'sDesktopTabsHostmaps it onto itsTabWorkspace.TabsResolver(DesktopManager): to open tabs next to the reader's own.SessionRestoreState(SessionManager): whether the session is being restored.SessionManager: saving, restoring and migrating the session, naming its tabs. It now uses kotlinx-io files, in FileKit's databases directory as before. It reaches the shell throughSessionShell: the desktops to save, the tab pictures to drop, and the end-to-end harness that turns it off. The desktop's implementation isDesktopSessionShell.AppKitBindings, a binding container contributed toAppScope, provides what every app's graph shares: settings, app state, catalog access, the user database and its stores, the books' repository, and the search's settings and history.AppDatabases(expect/actual) opens the SQLite connections:PersistentSqliteDriverfor the books, JDBC with a busy timeout for the user database;searchkit's drivers for the books, their own for the user database.CREATE TABLE IF NOT EXISTS), now in common code.AppCoreBindingskeeps only its own bindings: HTTP, Drive, search engine, delta updates, thumbnails, updater,DesktopManagerand the shell's ports.CopyWithSourceandBookErrorReport, onhtmlparser's newhtmlToText(jsoup/KsoupDocument.text()) and a common percent-encoding;VisitEntry.destination()andopenSiddurTab;TabSearchSessionStore, formerlyDesktopSearchSessionStore.appkit.Reskeeps its package, now public; Android packs the resources.FontCatalog, the window ViewModel store owner and the navigation helper move along.ExtractUseCaseandBundlePartsmove toappkit, on Okio.SeforimApp.TarReaderreads the archive: ustar, PAX headers for long paths and sizes over 8 GiB (as the packager writes them), GNU long names, base-256 sizes, header checksums.HashingSourcechecks the bundle's sha256.DesktopManagerstays on the desktop: it is the desktop shell (windows, Nucleus tab workspaces, geometry, drag & drop between windows). Mobile has neither windows nor virtual desktops, so it only implements the ports (TabsResolver, the desktops forSessionShell).commonTest(run on the JVM and the iOS simulator) orjvmTest.Still on the desktop (next steps)
HttpFileDownloader,GitHubReleaseFetcher).UserDataBackup,PendingUserDataRestore,DataSettingsViewModel): it needsbackup/backup-drivein KMP (zip, SHA, Drive's loopback OAuth).CatalogRow,TargumScrollbar,CategoryTreePanel…).AppGraphstays the desktop's root graph; a mobile graph only providesAppDatabasesand its shell's ports.Verification
:appkitfor the JVM, the iOS simulator and Android;:earthwidgetand:paginationlikewise.:appkit:jvmTest: 420 tests pass, including a bundle written as the packager does (zstd-jni, commons-compress) and extracted byExtractUseCase,, including a newTabsViewModelTeston a fake host.:appkit:iosSimulatorArm64Test: 374 tests pass (tar reader, extraction with zstd-kmp in native code).ZAYIT_E2E_SCENARIO=extractwithZAYIT_E2E_BUNDLE, runsExtractUseCasein the app as built.zstd -T2 --check, manifest with its sha256)..tar.zst. Same result on the JVM.IosExtractBundleTest(with-PseforimTestBundleand-PseforimTestBundleSha256) extracts the same bundle with zstd-kmp in native code..tar.zst: the expected sha256 too.:earthwidget:jvmTestpasses.:SeforimApp:jvmTest: the same 31 failures as onmaster(WidgetDragUiTest,*ScreenshotTest), no new ones.ktlintCheckpasses forappkit,earthwidget,paginationandSeforimApp.appkit, noMissingResourceException, and and renders the Home widgets with no exception. On quit, the commonSessionManagersaved the session it had restored at launch.