Desktop app (#308)
* Implement build profiles and feature policy for offline desktop builds * Introduce unified cross-platform Settings Hub * Refactor main settings into a hierarchical page-based navigation model * Refactor library projection to use shared multiplatform logic * Refactor UI state consumption by removing intermediate screen models * Introduce AndroidSharedStateBridge to centralize state mapping and reduction logic * Refactor state management for tabs, selection, and pinning to use shared bridge logic * Refactor file type management and validation into a centralized shared module * Centralize file type resolution and improve handling of unknown types * Centralize book import logic with SharedImportPlanner * Refactor magnifier geometry logic and coordinate mapping * Properly handle orientation changes in scroll-locked PDF reader * Add screen orientation controls to EPUB and PDF readers * Implement right-to-left (RTL) pagination support and refactor reader menus * Separate right-to-left pagination settings for PDF and EPUB * Ensure PDF page data is scoped by document key for multi tab support * Implement theme-aware link styling for the epub reader * Implement jump history for back and forward navigation in the epub reader * Improve locator handling and navigation logic in paginated reader mode * Implement stable pagination navigation and location tracking * Centralize banner message management and auto-dismiss logic in MainViewModel * Implement zoom and pan state preservation for PDF pan lock mode * Enhance reader navigation UI and workspace layout management in desktop app * Refactor reader navigation sidebar and relocate search controls in desktop app * Enhance reader UI with redesigned selection menus and bottom sheet overlays * Implement custom highlight palettes and reader theme customization in desktop app * Implement cross-platform modal layer and refine reader UI styling * Improve highlight accuracy and implement metadata enrichment on book open in desktop app * Implement two-page spread layout for paginated reader on desktop * Implement persistent caching for book loading and pagination in desktop app * Implement persistent caching for book loading and pagination in desktop app * Optimize reader settings updates by separating layout and appearance changes in desktop app * Improve desktop window branding and native Windows styling * Enhance reader selection interactions and UI across EPUB and PDF viewers in desktop app * Refine selection handle positioning and interaction logic * Implement EPUB selection debug logging and improve handle targeting * Optimize desktop book loading performance and UI responsiveness * Implement anchored zoom gestures and rendering optimizations for the Desktop PDF viewer. * Implement smooth zoom preview for the PDF reader in desktop app * Optimize PDF rendering performance and responsiveness in the desktop reader * Implement conditional diagnostic logging and update desktop build configuration * Implemented hierarchical TOC, custom scrollbars, and improved desktop modal handling * Added management options for annotations and highlights in the sidebar in desktop app * Implemented `SharedStableOutlinedTextField` and updated text input fields to use `TextFieldValue` for improved cursor and selection stability. * Refined library filters and enhanced OPDS functionality in desktop app * Improved EPUB pagination measurement and implemented layout diagnostic logging for desktop app * Added PPTX support including document parsing, rendering, and indexing * Improved PPTX rendering and layout accuracy * Implemented text autofit support for PPTX rendering * Enhanced PPTX rendering with support for custom geometry, automatic numbering, table styles, and image opacity * Improved EPUB pagination accuracy and added layout telemetry in desktop app * Improved folder synchronization with metadata-only mode and hashed sidecar management in desktop app * Implemented rich text font scaling and migrated desktop ink tools to custom pointer input handling * Implemented billing account obfuscation * Implemented hierarchical folder navigation and improved library selection functionality in desktop app * Implemented platform-aware directory resolution and multi-platform native library support for desktop * Added full-screen mode for the reader workspace * Added PDF zoom indicator and interactive vertical scrollbar with page tooltips * Refactored speech bubble prefetching to use a limited radius and improved ML detector initialization and lifecycle management * Updated PDF indexing to replace existing page text and removed search result item keys * Implemented "preparing" foreground notification for TTS service * Optimized PDF rendering performance by pre-calculating page-specific annotations * Refactored desktop packaging tasks and improved distribution configuration * Optimized EPUB parser memory usage and added path traversal protection * Refactored WorkManager monitoring logic and added work pruning * Implemented comprehensive resource cleanup and memory management for WebView-based components to prevent memory leaks * Implemented bitmap size limits and scaling to prevent canvas rendering errors * Split long text paragraphs into multiple semantic blocks during HTML parsing * Implemented local ActionMode for text selection to prevent platform crashes * Refactored PPTX text layout, optimized HtmlParser block detection, and improved banner dismissal logic * Added desktop startup splash screen and deferred WebView initialization * Reorganized settings hub and added separate PDF reader defaults * Implemented embedded cover extraction and metadata support for MOBI and FB2 formats * Implemented batching for MetadataExtractionWorker and optimized EPUB metadata extraction performance. * Implemented procedurally generated book covers and replaced static placeholders * Redesigned search UI with a top bar and results overlay in desktop app * Added PDF page gap and overlay visibility options and implemented DesktopBookImporter * Refactored PDF reader UI with tabbed inspector and improved theme background handling in desktop * Implemented PDF viewport persistence for zoom and scroll positions in desktop app * Improved desktop fullscreen implementation and state restoration * Implemented desktop window state persistence * Implemented flavor-based branding and ProGuard configuration for desktop builds * Implemented precise reader positioning and improved highlight rendering logic in desktop app * Added support for user-editable book metadata * Enhanced book metadata support and integrated info/edit dialogs * Implemented embedded EPUB metadata editing * Improved highlight mapping and added custom scrollbar styling for the reader. * Reduced desktop WebView bundle size by excluding unused locales and runtime files * Added neutral pan mode as the default PDF interaction state. * Refactored library empty states and updated primary navigation tabs in desktop app * Implemented native paginated reader and unified content rendering architecture in desktop epub reader * Implemented native EPUB image rendering for desktop and improved block layout spacing with margin collapsing. * Improved pagination overflow detection in desktop * Implemented multi-block text selection with interactive handles and CFI support in desktop epub pagination
This commit is contained in:
parent
c0d0e57e79
commit
b20ade9946
247 changed files with 43321 additions and 7087 deletions
|
|
@ -1,5 +1,16 @@
|
|||
import org.gradle.api.GradleException
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.provider.ListProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.JavaExec
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.PathSensitivity
|
||||
import org.gradle.api.tasks.Sync
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.jvm.tasks.Jar
|
||||
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
|
||||
import org.gradle.work.DisableCachingByDefault
|
||||
import java.io.File
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.kotlin.multiplatform)
|
||||
|
|
@ -7,6 +18,454 @@ plugins {
|
|||
alias(libs.plugins.compose.multiplatform)
|
||||
}
|
||||
|
||||
@DisableCachingByDefault(because = "Verification task has no outputs.")
|
||||
abstract class CheckBundledWebViewRuntimeTask : DefaultTask() {
|
||||
@get:Input
|
||||
abstract val bundleRootPath: Property<String>
|
||||
|
||||
@get:Input
|
||||
abstract val osName: Property<String>
|
||||
|
||||
@get:Input
|
||||
abstract val osArch: Property<String>
|
||||
|
||||
@get:Input
|
||||
abstract val requiredPaths: ListProperty<String>
|
||||
|
||||
@TaskAction
|
||||
fun checkRuntime() {
|
||||
val bundleRoot = File(bundleRootPath.get())
|
||||
val missingFiles = requiredPaths.get().filterNot { bundleRoot.resolve(it).exists() }
|
||||
if (missingFiles.isNotEmpty()) {
|
||||
throw GradleException(
|
||||
"Missing bundled KCEF runtime at ${bundleRoot.absolutePath}. " +
|
||||
"Expected ${missingFiles.joinToString()} for ${osName.get()} ${osArch.get()} desktop packages."
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@DisableCachingByDefault(because = "Verification task has no outputs.")
|
||||
abstract class CheckBundledPdfiumRuntimeTask : DefaultTask() {
|
||||
@get:Input
|
||||
abstract val bundleRootPath: Property<String>
|
||||
|
||||
@get:Input
|
||||
abstract val libraryPath: Property<String>
|
||||
|
||||
@TaskAction
|
||||
fun checkRuntime() {
|
||||
val bundleRoot = File(bundleRootPath.get())
|
||||
val library = bundleRoot.resolve(libraryPath.get())
|
||||
if (!library.isFile) {
|
||||
throw GradleException(
|
||||
"Missing bundled Pdfium runtime at ${library.absolutePath}. " +
|
||||
"Expected ${libraryPath.get()} inside ${bundleRoot.absolutePath}."
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun desktopOsId(osName: String = System.getProperty("os.name")): String {
|
||||
val normalized = osName.lowercase()
|
||||
return when {
|
||||
normalized.startsWith("windows") -> "windows"
|
||||
normalized == "linux" || normalized.contains("linux") -> "linux"
|
||||
normalized.startsWith("mac") || normalized.contains("darwin") -> "macos"
|
||||
else -> "other"
|
||||
}
|
||||
}
|
||||
|
||||
fun desktopArchId(osArch: String = System.getProperty("os.arch")): String {
|
||||
return when (osArch.lowercase()) {
|
||||
"amd64", "x86_64", "x64" -> "x64"
|
||||
"aarch64", "arm64" -> "arm64"
|
||||
"x86", "i386", "i686" -> "x86"
|
||||
else -> "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
fun desktopKcefBundleDirectoryName(
|
||||
osName: String = System.getProperty("os.name"),
|
||||
osArch: String = System.getProperty("os.arch")
|
||||
): String {
|
||||
return when (desktopOsId(osName)) {
|
||||
"windows" -> "kcef-bundle"
|
||||
"linux" -> "kcef-bundle-linux-${desktopArchId(osArch)}"
|
||||
"macos" -> "kcef-bundle-macos-${desktopArchId(osArch)}"
|
||||
else -> "kcef-bundle-${desktopArchId(osArch)}"
|
||||
}
|
||||
}
|
||||
|
||||
fun bundledWebViewRequiredPaths(osName: String, osArch: String): List<String> {
|
||||
return when (desktopOsId(osName)) {
|
||||
"windows" -> listOf("jcef.dll", "libcef.dll")
|
||||
"linux" -> listOf("libcef.so", "chrome-sandbox", "icudtl.dat", "locales")
|
||||
"macos" -> listOf("jcef Helper.app", "Chromium Embedded Framework.framework")
|
||||
else -> emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
fun desktopPdfiumDirectoryName(
|
||||
osName: String = System.getProperty("os.name"),
|
||||
osArch: String = System.getProperty("os.arch")
|
||||
): String {
|
||||
return when (desktopOsId(osName)) {
|
||||
"windows" -> "win-${desktopArchId(osArch)}-v8"
|
||||
"linux" -> "linux-${desktopArchId(osArch)}-v8"
|
||||
"macos" -> "mac-${desktopArchId(osArch)}-v8"
|
||||
else -> "${desktopArchId(osArch)}-v8"
|
||||
}
|
||||
}
|
||||
|
||||
fun desktopPdfiumLibraryPath(
|
||||
osName: String = System.getProperty("os.name"),
|
||||
osArch: String = System.getProperty("os.arch")
|
||||
): String {
|
||||
return when (desktopOsId(osName)) {
|
||||
"windows" -> "bin/pdfium.dll"
|
||||
"linux" -> "lib/libpdfium.so"
|
||||
"macos" -> "lib/libpdfium.dylib"
|
||||
else -> "lib/pdfium"
|
||||
}
|
||||
}
|
||||
|
||||
fun desktopJdkToolName(toolName: String, osName: String = System.getProperty("os.name")): String {
|
||||
return if (desktopOsId(osName) == "windows") "$toolName.exe" else toolName
|
||||
}
|
||||
|
||||
fun File.asDesktopJdkHome(): File {
|
||||
val absolute = absoluteFile
|
||||
return when {
|
||||
absolute.isFile && absolute.parentFile?.name?.equals("bin", ignoreCase = true) == true ->
|
||||
absolute.parentFile?.parentFile ?: absolute
|
||||
|
||||
absolute.isDirectory && absolute.name.equals("bin", ignoreCase = true) ->
|
||||
absolute.parentFile ?: absolute
|
||||
|
||||
absolute.resolve("Contents/Home/bin").isDirectory ->
|
||||
absolute.resolve("Contents/Home")
|
||||
|
||||
else -> absolute
|
||||
}
|
||||
}
|
||||
|
||||
fun File.desktopJdkTool(toolName: String, osName: String = System.getProperty("os.name")): File {
|
||||
return resolve("bin/${desktopJdkToolName(toolName, osName)}")
|
||||
}
|
||||
|
||||
fun File.isDesktopPackagingJdk(osName: String = System.getProperty("os.name")): Boolean {
|
||||
return desktopJdkTool("java", osName).isFile &&
|
||||
desktopJdkTool("jlink", osName).isFile &&
|
||||
desktopJdkTool("jpackage", osName).isFile
|
||||
}
|
||||
|
||||
fun File.desktopJdkMajorVersion(): Int? {
|
||||
val releaseFile = resolve("release")
|
||||
if (!releaseFile.isFile) return null
|
||||
|
||||
val version = runCatching {
|
||||
releaseFile.useLines { lines ->
|
||||
lines.firstOrNull { it.startsWith("JAVA_VERSION=") }
|
||||
?.substringAfter("=")
|
||||
?.trim()
|
||||
?.trim('"')
|
||||
}
|
||||
}.getOrNull() ?: return null
|
||||
|
||||
return version.removePrefix("1.").substringBefore(".").toIntOrNull()
|
||||
}
|
||||
|
||||
fun safeChildDirectories(root: File): List<File> {
|
||||
return runCatching {
|
||||
root.listFiles()?.filter { it.isDirectory }.orEmpty()
|
||||
}.getOrDefault(emptyList())
|
||||
}
|
||||
|
||||
fun stableDesktopJdkCandidates(candidates: List<File>, preferredMajorVersion: Int = 21): List<File> {
|
||||
return candidates
|
||||
.map { it.asDesktopJdkHome() }
|
||||
.distinctBy { runCatching { it.canonicalPath }.getOrElse { _ -> it.absolutePath }.lowercase() }
|
||||
.sortedWith(
|
||||
compareBy<File> { if (it.desktopJdkMajorVersion() == preferredMajorVersion) 0 else 1 }
|
||||
.thenBy { it.desktopJdkMajorVersion() ?: Int.MAX_VALUE }
|
||||
.thenBy { it.absolutePath.lowercase() }
|
||||
)
|
||||
}
|
||||
|
||||
fun desktopPathJdkCandidates(osName: String = System.getProperty("os.name")): List<File> {
|
||||
return System.getenv("PATH")
|
||||
?.split(File.pathSeparator)
|
||||
.orEmpty()
|
||||
.asSequence()
|
||||
.map { it.trim() }
|
||||
.filter { it.isNotEmpty() }
|
||||
.map { File(it).resolve(desktopJdkToolName("jpackage", osName)) }
|
||||
.filter { it.isFile }
|
||||
.mapNotNull { it.parentFile?.parentFile }
|
||||
.toList()
|
||||
}
|
||||
|
||||
fun desktopGradleJdkCandidates(): List<File> {
|
||||
val userHome = System.getProperty("user.home")?.let(::File) ?: return emptyList()
|
||||
return stableDesktopJdkCandidates(safeChildDirectories(userHome.resolve(".gradle/jdks")))
|
||||
}
|
||||
|
||||
fun desktopPlatformJdkCandidates(osName: String = System.getProperty("os.name")): List<File> {
|
||||
val roots = when (desktopOsId(osName)) {
|
||||
"windows" -> listOfNotNull(
|
||||
System.getenv("ProgramFiles")?.let { File(it, "Java") },
|
||||
System.getenv("ProgramFiles")?.let { File(it, "Eclipse Adoptium") },
|
||||
System.getenv("ProgramFiles")?.let { File(it, "Microsoft") },
|
||||
System.getenv("ProgramFiles(x86)")?.let { File(it, "Java") }
|
||||
)
|
||||
|
||||
"linux" -> listOf(
|
||||
File("/usr/lib/jvm"),
|
||||
File("/usr/java"),
|
||||
File("/opt/java"),
|
||||
File("/opt/jdk")
|
||||
)
|
||||
|
||||
"macos" -> listOfNotNull(
|
||||
File("/Library/Java/JavaVirtualMachines"),
|
||||
System.getProperty("user.home")?.let { File(it, "Library/Java/JavaVirtualMachines") }
|
||||
)
|
||||
|
||||
else -> emptyList()
|
||||
}
|
||||
|
||||
return stableDesktopJdkCandidates(roots + roots.flatMap(::safeChildDirectories))
|
||||
}
|
||||
|
||||
fun findDesktopPackagingJavaHome(
|
||||
explicitCandidates: List<String>,
|
||||
implicitCandidates: List<File>,
|
||||
osName: String = System.getProperty("os.name")
|
||||
): File? {
|
||||
val explicitJavaHome = explicitCandidates.firstOrNull { it.isNotBlank() }
|
||||
if (explicitJavaHome != null) {
|
||||
val candidate = File(explicitJavaHome).asDesktopJdkHome()
|
||||
if (!candidate.isDesktopPackagingJdk(osName)) {
|
||||
throw GradleException(
|
||||
"Desktop packaging JDK must include java, jlink, and jpackage under " +
|
||||
"${candidate.resolve("bin").absolutePath}. " +
|
||||
"Set -PdesktopPackagingJavaHome=<jdk-home> or DESKTOP_PACKAGING_JAVA_HOME to a full JDK."
|
||||
)
|
||||
}
|
||||
return candidate
|
||||
}
|
||||
|
||||
return implicitCandidates
|
||||
.map { it.asDesktopJdkHome() }
|
||||
.distinctBy { runCatching { it.canonicalPath }.getOrElse { _ -> it.absolutePath }.lowercase() }
|
||||
.firstOrNull { it.isDesktopPackagingJdk(osName) }
|
||||
}
|
||||
|
||||
fun normalizeDesktopPackageVersion(rawVersion: String): String {
|
||||
val coreVersion = rawVersion.trim()
|
||||
.substringBefore("-")
|
||||
.substringBefore("+")
|
||||
.takeIf { it.isNotBlank() }
|
||||
?: "1.0.0"
|
||||
val parts = coreVersion.split(".")
|
||||
val numericParts = parts.map { it.toIntOrNull() }
|
||||
val normalizedParts = when {
|
||||
parts.size in 1..3 && numericParts.all { it != null } ->
|
||||
numericParts.map { it ?: 0 } + List(3 - parts.size) { 0 }
|
||||
|
||||
else -> throw GradleException(
|
||||
"desktopPackageVersion must be numeric MAJOR[.MINOR[.BUILD]], but was '$rawVersion'."
|
||||
)
|
||||
}
|
||||
val (major, minor, build) = normalizedParts
|
||||
if (major !in 0..255 || minor !in 0..255 || build !in 0..65535) {
|
||||
throw GradleException(
|
||||
"desktopPackageVersion '$rawVersion' is outside the Windows package version range. " +
|
||||
"Expected MAJOR 0..255, MINOR 0..255, BUILD 0..65535."
|
||||
)
|
||||
}
|
||||
return "$major.$minor.$build"
|
||||
}
|
||||
|
||||
fun normalizeDesktopVersionName(rawVersion: String): String {
|
||||
return rawVersion.trim().takeIf { it.isNotBlank() } ?: "1.0.0"
|
||||
}
|
||||
|
||||
fun normalizeDesktopFlavor(rawFlavor: String): String {
|
||||
val flavor = rawFlavor.trim().lowercase()
|
||||
return when (flavor) {
|
||||
"oss", "oss-offline", "episteme-oss" -> "oss-offline"
|
||||
else -> "standard"
|
||||
}
|
||||
}
|
||||
|
||||
fun normalizeDesktopPackageArchitecture(osArch: String): String {
|
||||
val normalizedArch = desktopArchId(osArch)
|
||||
return if (normalizedArch != "unknown") {
|
||||
normalizedArch
|
||||
} else {
|
||||
osArch.lowercase()
|
||||
.replace(Regex("[^a-z0-9]+"), "-")
|
||||
.trim('-')
|
||||
.ifBlank { "unknown" }
|
||||
}
|
||||
}
|
||||
|
||||
fun renameDesktopMsiOutput(
|
||||
msiDirectory: File,
|
||||
packageName: String,
|
||||
packageVersion: String,
|
||||
architecture: String
|
||||
) {
|
||||
val source = msiDirectory.resolve("$packageName-$packageVersion.msi")
|
||||
if (!source.isFile) return
|
||||
|
||||
val target = msiDirectory.resolve("$packageName-$packageVersion-$architecture.msi")
|
||||
if (target.exists() && !target.delete()) {
|
||||
throw GradleException("Could not replace existing MSI at ${target.absolutePath}.")
|
||||
}
|
||||
if (!source.renameTo(target)) {
|
||||
throw GradleException("Could not rename MSI from ${source.absolutePath} to ${target.absolutePath}.")
|
||||
}
|
||||
}
|
||||
|
||||
val desktopVersionName = "1.0.0"
|
||||
val desktopFlavor = providers.gradleProperty("desktopFlavor")
|
||||
.orElse("standard")
|
||||
.map(::normalizeDesktopFlavor)
|
||||
.get()
|
||||
val isOssOfflineDesktop = desktopFlavor == "oss-offline"
|
||||
val desktopDiagnostics = providers.gradleProperty("desktopDiagnostics")
|
||||
.map { it.equals("true", ignoreCase = true) }
|
||||
.orElse(false)
|
||||
val desktopDiagnosticTags = providers.gradleProperty("desktopDiagnosticTags")
|
||||
.orElse("")
|
||||
val desktopResolvedVersionName = providers.gradleProperty("desktopVersionName")
|
||||
.orElse(providers.gradleProperty("desktopVersion"))
|
||||
.orElse(desktopVersionName)
|
||||
.map(::normalizeDesktopVersionName)
|
||||
val desktopPackageVersion = providers.gradleProperty("desktopPackageVersion")
|
||||
.orElse(desktopResolvedVersionName)
|
||||
.map(::normalizeDesktopPackageVersion)
|
||||
val desktopPackageName = if (isOssOfflineDesktop) "Episteme oss" else "Episteme"
|
||||
val desktopPackageDescription = if (isOssOfflineDesktop) {
|
||||
"Episteme oss offline desktop reader"
|
||||
} else {
|
||||
"Episteme desktop reader"
|
||||
}
|
||||
val desktopVendor = providers.gradleProperty("desktopVendor").orElse("Aryan")
|
||||
val desktopOsName = System.getProperty("os.name")
|
||||
val desktopOsArch = System.getProperty("os.arch")
|
||||
val desktopPackageArchitecture = normalizeDesktopPackageArchitecture(desktopOsArch)
|
||||
val generatedDesktopResourcesDir = layout.buildDirectory.dir("generated/desktopAppResources")
|
||||
val bundledWebViewDir = layout.projectDirectory.dir(desktopKcefBundleDirectoryName(desktopOsName, desktopOsArch))
|
||||
val bundledPdfiumDir = layout.projectDirectory.dir(
|
||||
"../third_party/pdfium/${desktopPdfiumDirectoryName(desktopOsName, desktopOsArch)}"
|
||||
)
|
||||
val bundledPdfiumLibraryPath = desktopPdfiumLibraryPath(desktopOsName, desktopOsArch)
|
||||
val bundledWebViewKeptLocales = setOf(
|
||||
"ar.pak",
|
||||
"de.pak",
|
||||
"en-GB.pak",
|
||||
"en-US.pak",
|
||||
"es-419.pak",
|
||||
"es.pak",
|
||||
"fr.pak",
|
||||
"hi.pak",
|
||||
"pt-BR.pak",
|
||||
"ru.pak",
|
||||
"tr.pak",
|
||||
"vi.pak"
|
||||
)
|
||||
val bundledWebViewTrimmedRuntimeFiles = listOf(
|
||||
"ct.sym",
|
||||
"jawt.lib",
|
||||
"jvm.lib",
|
||||
"jaccessinspector.exe",
|
||||
"jaccesswalker.exe",
|
||||
"jabswitch.exe",
|
||||
"javac.exe",
|
||||
"javadoc.exe",
|
||||
"jcmd.exe",
|
||||
"jdb.exe",
|
||||
"jfr.exe",
|
||||
"jhsdb.exe",
|
||||
"jinfo.exe",
|
||||
"jmap.exe",
|
||||
"jps.exe",
|
||||
"jrunscript.exe",
|
||||
"jstack.exe",
|
||||
"jstat.exe",
|
||||
"jwebserver.exe",
|
||||
"keytool.exe",
|
||||
"kinit.exe",
|
||||
"klist.exe",
|
||||
"ktab.exe",
|
||||
"rmiregistry.exe",
|
||||
"serialver.exe",
|
||||
"server/classes.jsa",
|
||||
"server/classes_nocoops.jsa"
|
||||
)
|
||||
val desktopWindowsIconFile = layout.projectDirectory.file("src/desktopMain/resources/episteme.ico")
|
||||
val desktopLinuxIconFile = layout.projectDirectory.file("src/desktopMain/resources/episteme_icon.png")
|
||||
val desktopWindowsUpgradeUuid = if (isOssOfflineDesktop) {
|
||||
"ca13b201-940a-420a-8a3f-16e7d83d12a8"
|
||||
} else {
|
||||
"c04c5823-b25a-4f38-a1cf-0da7b02ac397"
|
||||
}
|
||||
val desktopPackagingJavaHome = findDesktopPackagingJavaHome(
|
||||
explicitCandidates = listOfNotNull(
|
||||
providers.gradleProperty("desktopPackagingJavaHome").orNull,
|
||||
providers.environmentVariable("DESKTOP_PACKAGING_JAVA_HOME").orNull,
|
||||
providers.environmentVariable("JPACKAGE_HOME").orNull
|
||||
),
|
||||
implicitCandidates = buildList {
|
||||
addAll(desktopGradleJdkCandidates())
|
||||
providers.gradleProperty("org.gradle.java.home").orNull?.let { add(File(it)) }
|
||||
providers.environmentVariable("GRADLE_LOCAL_JAVA_HOME").orNull?.let { add(File(it)) }
|
||||
providers.environmentVariable("JAVA_HOME").orNull?.let { add(File(it)) }
|
||||
providers.environmentVariable("JDK_HOME").orNull?.let { add(File(it)) }
|
||||
add(File(System.getProperty("java.home")))
|
||||
addAll(desktopPathJdkCandidates(desktopOsName))
|
||||
addAll(desktopPlatformJdkCandidates(desktopOsName))
|
||||
},
|
||||
osName = desktopOsName
|
||||
)?.absolutePath
|
||||
|
||||
val checkBundledWebViewRuntime by tasks.registering(CheckBundledWebViewRuntimeTask::class) {
|
||||
val requiredPaths = bundledWebViewRequiredPaths(desktopOsName, desktopOsArch)
|
||||
bundleRootPath.set(bundledWebViewDir.asFile.absolutePath)
|
||||
osName.set(desktopOsName)
|
||||
osArch.set(desktopOsArch)
|
||||
this.requiredPaths.set(requiredPaths)
|
||||
}
|
||||
|
||||
val checkBundledPdfiumRuntime by tasks.registering(CheckBundledPdfiumRuntimeTask::class) {
|
||||
bundleRootPath.set(bundledPdfiumDir.asFile.absolutePath)
|
||||
libraryPath.set(bundledPdfiumLibraryPath)
|
||||
}
|
||||
|
||||
val prepareBundledDesktopResources by tasks.registering(Sync::class) {
|
||||
dependsOn(checkBundledWebViewRuntime, checkBundledPdfiumRuntime)
|
||||
from(bundledWebViewDir) {
|
||||
exclude(bundledWebViewTrimmedRuntimeFiles)
|
||||
val localeExcludes = bundledWebViewDir.asFile
|
||||
.resolve("locales")
|
||||
.listFiles { file -> file.isFile && file.extension.equals("pak", ignoreCase = true) }
|
||||
.orEmpty()
|
||||
.map { it.name }
|
||||
.filterNot { it in bundledWebViewKeptLocales }
|
||||
.map { "locales/$it" }
|
||||
exclude(localeExcludes)
|
||||
into("common/kcef-bundle")
|
||||
}
|
||||
from(bundledPdfiumDir) {
|
||||
into("common/third_party/pdfium/${desktopPdfiumDirectoryName(desktopOsName, desktopOsArch)}")
|
||||
}
|
||||
into(generatedDesktopResourcesDir)
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvm("desktop")
|
||||
jvmToolchain(21)
|
||||
|
|
@ -22,6 +481,7 @@ kotlin {
|
|||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")
|
||||
implementation("net.java.dev.jna:jna:5.17.0")
|
||||
implementation("org.apache.commons:commons-compress:1.28.0")
|
||||
implementation("org.apache.thrift:libthrift:0.22.0")
|
||||
implementation("org.tukaani:xz:1.10")
|
||||
implementation("com.twelvemonkeys.imageio:imageio-webp:3.13.1")
|
||||
}
|
||||
|
|
@ -36,28 +496,113 @@ kotlin {
|
|||
|
||||
compose.desktop {
|
||||
application {
|
||||
mainClass = "com.aryan.reader.desktop.MainKt"
|
||||
mainClass = "com.aryan.reader.desktop.LauncherKt"
|
||||
desktopPackagingJavaHome?.let { javaHome = it }
|
||||
|
||||
jvmArgs("--add-opens", "java.desktop/sun.awt=ALL-UNNAMED")
|
||||
jvmArgs("--add-opens", "java.desktop/java.awt.peer=ALL-UNNAMED")
|
||||
jvmArgs("-Depisteme.desktop.flavor=$desktopFlavor")
|
||||
jvmArgs("-Depisteme.desktop.diagnostics=${desktopDiagnostics.get()}")
|
||||
jvmArgs("-Depisteme.desktop.diagnostics.tags=${desktopDiagnosticTags.get()}")
|
||||
jvmArgs("-Depisteme.desktop.version=${desktopResolvedVersionName.get()}")
|
||||
|
||||
buildTypes.release.proguard {
|
||||
obfuscate.set(false)
|
||||
// Compose/Kotlin generated methods can produce very large stack-map frames.
|
||||
// ProGuard optimization has emitted invalid frames for SharedAppTheme in release builds.
|
||||
optimize.set(false)
|
||||
configurationFiles.from(project.file("compose-desktop.pro"))
|
||||
}
|
||||
|
||||
nativeDistributions {
|
||||
targetFormats(TargetFormat.Exe, TargetFormat.Msi)
|
||||
packageName = "Episteme"
|
||||
packageVersion = "1.0.0"
|
||||
description = "Episteme desktop shell"
|
||||
vendor = "Aryan Reader"
|
||||
targetFormats(TargetFormat.Exe, TargetFormat.Msi, TargetFormat.Deb, TargetFormat.Rpm)
|
||||
modules("java.net.http")
|
||||
packageName = desktopPackageName
|
||||
packageVersion = desktopPackageVersion.get()
|
||||
description = desktopPackageDescription
|
||||
vendor = desktopVendor.get()
|
||||
appResourcesRootDir.set(generatedDesktopResourcesDir)
|
||||
windows {
|
||||
iconFile.set(desktopWindowsIconFile)
|
||||
dirChooser = true
|
||||
shortcut = true
|
||||
menu = true
|
||||
menuGroup = "Episteme"
|
||||
perUserInstall = true
|
||||
upgradeUuid = desktopWindowsUpgradeUuid
|
||||
}
|
||||
linux {
|
||||
iconFile.set(desktopLinuxIconFile)
|
||||
packageName = if (isOssOfflineDesktop) "episteme-oss" else "episteme"
|
||||
debMaintainer = "epistemereader@gmail.com"
|
||||
menuGroup = "Office"
|
||||
appCategory = "Office"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
afterEvaluate {
|
||||
tasks.withType<JavaExec>().configureEach {
|
||||
jvmArgs("--add-opens", "java.desktop/sun.awt=ALL-UNNAMED")
|
||||
jvmArgs("--add-opens", "java.desktop/java.awt.peer=ALL-UNNAMED")
|
||||
if (System.getProperty("os.name").contains("Mac")) {
|
||||
jvmArgs("--add-opens", "java.desktop/sun.lwawt=ALL-UNNAMED")
|
||||
jvmArgs("--add-opens", "java.desktop/sun.lwawt.macosx=ALL-UNNAMED")
|
||||
tasks.withType<JavaExec>().configureEach {
|
||||
jvmArgs("--add-opens", "java.desktop/sun.awt=ALL-UNNAMED")
|
||||
jvmArgs("--add-opens", "java.desktop/java.awt.peer=ALL-UNNAMED")
|
||||
jvmArgs("-Depisteme.desktop.flavor=$desktopFlavor")
|
||||
jvmArgs("-Depisteme.desktop.diagnostics=${desktopDiagnostics.get()}")
|
||||
jvmArgs("-Depisteme.desktop.diagnostics.tags=${desktopDiagnosticTags.get()}")
|
||||
jvmArgs("-Depisteme.desktop.version=${desktopResolvedVersionName.get()}")
|
||||
if (System.getProperty("os.name").contains("Mac")) {
|
||||
jvmArgs("--add-opens", "java.desktop/sun.lwawt=ALL-UNNAMED")
|
||||
jvmArgs("--add-opens", "java.desktop/sun.lwawt.macosx=ALL-UNNAMED")
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType<Jar>().configureEach {
|
||||
manifest {
|
||||
attributes(
|
||||
"Implementation-Title" to desktopPackageName,
|
||||
"Implementation-Version" to desktopResolvedVersionName.get(),
|
||||
"Implementation-Vendor" to desktopVendor.get()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
mapOf(
|
||||
"packageMsi" to "main",
|
||||
"packageReleaseMsi" to "main-release"
|
||||
).forEach { (taskName, distributionName) ->
|
||||
tasks.matching { it.name == taskName }.configureEach {
|
||||
doLast {
|
||||
renameDesktopMsiOutput(
|
||||
msiDirectory = layout.buildDirectory.dir("compose/binaries/$distributionName/msi").get().asFile,
|
||||
packageName = desktopPackageName,
|
||||
packageVersion = desktopPackageVersion.get(),
|
||||
architecture = desktopPackageArchitecture
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.matching {
|
||||
it.name in setOf(
|
||||
"createDistributable",
|
||||
"createReleaseDistributable",
|
||||
"prepareAppResources",
|
||||
"prepareReleaseAppResources",
|
||||
"packageDistributionForCurrentOS",
|
||||
"packageReleaseDistributionForCurrentOS",
|
||||
"packageExe",
|
||||
"packageReleaseExe",
|
||||
"packageMsi",
|
||||
"packageReleaseMsi",
|
||||
"packageDeb",
|
||||
"packageReleaseDeb",
|
||||
"packageRpm",
|
||||
"packageReleaseRpm",
|
||||
"runDistributable",
|
||||
"runReleaseDistributable"
|
||||
)
|
||||
}.configureEach {
|
||||
dependsOn(prepareBundledDesktopResources)
|
||||
inputs.dir(generatedDesktopResourcesDir)
|
||||
.withPropertyName("bundledDesktopResources")
|
||||
.withPathSensitivity(PathSensitivity.RELATIVE)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue