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:
Aryan 2026-05-15 22:36:51 +05:30 committed by GitHub
parent c0d0e57e79
commit b20ade9946
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
247 changed files with 43321 additions and 7087 deletions

View file

@ -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)
}