book-reader/desktopApp/build.gradle.kts
Aryan 9510293ac3
Update v1.0.49 (#330)
* Added PDF top tab strip visibility toggle and fixed WebView hit test NPE

* Refactored desktop reader screens and state management into specialized components

* Added image gallery to reader sidebar and refactored desktop PDF UI components

* Implemented EPUB image gallery

* Refactored reader and library models to use shared common types, centralizing file type resolution and texture management while removing redundant mapping logic

* Standardized UI styling and refactored app navigation layout

* Implemented auto-hiding reader chrome and activity tracking in desktop

* Refactored reader panels into distinct left and right modal layers with platform-specific sizing and keyboard navigation support.

* Added PPTX support for desktop and refactored parsing into a shared module

* Implement paid AI features and account management for the desktop application.

* Implement AI Hub and enhanced Cloud TTS integration for Desktop

* Implement streaming support for AI definition and summarization features

* Implement support for password-protected PDFs and file actions in the desktop reader.

* Implement cloud synchronization for desktop using Firestore and Google Drive

* Implement PDF reflow and "Text View" for the desktop reader

* Refactor OPDS logic to use SharedOpdsController

* Optimize PDF tile rendering performance

* Implement two-page spread support for PDF pagination

* Implement two-page spread support for the PDF viewer

* Improved shared spread zoom in PDF viewer

* Improve PDF spread navigation with fling support and configurable page gaps

* Add brightness control to PDF and EPUB readers

* Refactor folder synchronization to use shared logic engine

* Implement safe string formatting and validation for localized resources

* Implement TTS chunk skip navigation

* Implement deep-linking and playback controls for TTS media sessions

* Implement start index for TTS playback

* Improve TTS navigation, prefetching, and notification duration reporting

* Implement TTS mini playback bar for background reading

* Implement multi-window reader support for the desktop application

* Improve desktop modal window management and visibility syncing

* Implement localized string support for Desktop and shared UI

* Implement language selection and persistence for Desktop

* Implement plural string support for Desktop and migrate hardcoded counts to plurals.xml

* Implement localized banner messages and UI strings using resource-backed SharedText

* Implement compact badge styling for small book covers

* Refactor PDF native interaction and improve HTML import memory safety

* fix language persistence

* Refactor reader overflow menus to use section-based logic

* Refactor PDF layout remapping and improve text box interaction

* Improve CFI resolution and TTS resume accuracy using dynamic chunk offsets

* Centralize PDF annotation export mapping and improve metadata handling

* Add support for threaded comments in PDF highlight annotations

* Flatten highlight comments into a single thread for PDF export and allow author editing

* Integrate page slider into reader chrome and persist toggle state

* Handle fragments and queries in EPUB chapter paths

* Implement dynamic, theme-aware coloring for the reader slider

* Implement customizable app-wide font preference

* Implement one-hand zoom gestures in the PDF viewer

* Implement File Information dialog for PDF and EPUB readers

* Bump version to 1.0.49 (53)

* Refactor PDF reader logic into modular components

* Add ProGuard rules to prevent R8 optimization issues in EPUB reader screens

* Add option to use PDF filenames as display names

* Fix preservation of PDF filename display preference in library projection
2026-05-20 22:14:01 +05:30

655 lines
24 KiB
Kotlin

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
import java.util.Properties
plugins {
alias(libs.plugins.kotlin.multiplatform)
alias(libs.plugins.kotlin.compose)
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 generatedDesktopStringResourcesDir = layout.buildDirectory.dir("generated/desktopStringResources")
val rootLocalProperties = Properties()
val rootLocalPropertiesFile = rootProject.file("local.properties")
if (rootLocalPropertiesFile.exists()) {
rootLocalPropertiesFile.inputStream().use(rootLocalProperties::load)
}
fun desktopConfigValue(vararg keys: String): String {
return keys.firstNotNullOfOrNull { key ->
providers.gradleProperty(key).orNull
?: rootLocalProperties.getProperty(key)
?: System.getenv(key)
}?.trim().orEmpty()
}
val desktopCloudConfig = mapOf(
"AI_WORKER_URL" to desktopConfigValue("DESKTOP_AI_WORKER_URL", "AI_WORKER_URL"),
"TTS_WORKER_URL" to desktopConfigValue("DESKTOP_TTS_WORKER_URL", "TTS_WORKER_URL", "AI_WORKER_URL"),
"FIREBASE_WEB_API_KEY" to desktopConfigValue("DESKTOP_FIREBASE_WEB_API_KEY", "FIREBASE_WEB_API_KEY", "GOOGLE_API_KEY"),
"FIREBASE_PROJECT_ID" to desktopConfigValue("DESKTOP_FIREBASE_PROJECT_ID", "FIREBASE_PROJECT_ID").ifBlank { "reader-9fc469d7" },
"GOOGLE_OAUTH_CLIENT_ID" to desktopConfigValue("DESKTOP_GOOGLE_OAUTH_CLIENT_ID", "GOOGLE_OAUTH_CLIENT_ID", "GOOGLE_WEB_CLIENT_ID", "DEFAULT_WEB_CLIENT_ID"),
"GOOGLE_OAUTH_CLIENT_SECRET" to desktopConfigValue("DESKTOP_GOOGLE_OAUTH_CLIENT_SECRET", "GOOGLE_OAUTH_CLIENT_SECRET", "GOOGLE_WEB_CLIENT_SECRET", "DEFAULT_WEB_CLIENT_SECRET")
)
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("common") {
from(
providers.provider {
temporaryDir.resolve("desktop-cloud.properties").also { file ->
file.parentFile.mkdirs()
file.writeText(
desktopCloudConfig.entries.joinToString(separator = "\n", postfix = "\n") { (key, value) ->
"$key=${value.replace("\\", "\\\\").replace("\n", "")}"
}
)
}
}
)
}
into(generatedDesktopResourcesDir)
}
val prepareDesktopStringResources by tasks.registering(Sync::class) {
// Reuse Android string resources as the localization source for desktop.
from(rootProject.layout.projectDirectory.dir("app/src/main/res")) {
include("values*/strings.xml")
include("values*/plurals.xml")
into("desktop-android-res")
}
into(generatedDesktopStringResourcesDir)
}
kotlin {
jvm("desktop")
jvmToolchain(21)
sourceSets {
val desktopMain by getting {
resources.srcDir(prepareDesktopStringResources)
dependencies {
implementation(project(":shared"))
implementation(compose.desktop.currentOs)
implementation(compose.material3)
implementation(compose.materialIconsExtended)
implementation("io.github.kevinnzou:compose-webview-multiplatform:2.0.3")
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")
}
}
val desktopTest by getting {
dependencies {
implementation(kotlin("test"))
}
}
}
}
compose.desktop {
application {
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, 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"
}
}
}
}
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)
}