Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ misc.xml
deploymentTargetDropDown.xml
render.experimental.xml

# Kotlin
.kotlin/

# Keystore files
*.jks
*.keystore
Expand All @@ -33,5 +36,7 @@ google-services.json
# Android Profiling
*.hprof

# Mac files
.DS_Store
# NPM modules
node_modules/
9 changes: 9 additions & 0 deletions .run/CLI GUI.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="CLI GUI" type="Application" factoryName="Application">
<option name="MAIN_CLASS_NAME" value="app.morphe.MorpheLauncherKt" />
<module name="morphe-cli.main" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>
118 changes: 104 additions & 14 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget

plugins {
alias(libs.plugins.kotlin)
alias(libs.plugins.kotlin.jvm)
alias(libs.plugins.kotlin.compose)
alias(libs.plugins.kotlin.serialization)
alias(libs.plugins.compose)
alias(libs.plugins.shadow)
application
`maven-publish`
Expand All @@ -11,10 +13,33 @@ plugins {

group = "app.morphe"

// ============================================================================
// JVM / Kotlin Configuration
// ============================================================================
kotlin {
jvmToolchain {
languageVersion.set(JavaLanguageVersion.of(17))
vendor.set(JvmVendorSpec.ADOPTIUM)
}
compilerOptions {
jvmTarget.set(JvmTarget.JVM_17)
}
}

// ============================================================================
// Application Entry Point
// ============================================================================
// Shadow JAR reads this for Main-Class manifest attribute.
//
// No args / double-click → GUI (Compose Desktop)
// With args (terminal) → CLI (PicoCLI)
application {
mainClass = "app.morphe.cli.command.MainCommandKt"
mainClass.set("app.morphe.MorpheLauncherKt")
}

// ============================================================================
// Repositories
// ============================================================================
repositories {
mavenLocal()
mavenCentral()
Expand All @@ -36,25 +61,67 @@ dependencies {
api(libs.morphe.patcher)
implementation(libs.arsclib)
implementation(libs.morphe.library)
implementation(libs.kotlinx.coroutines.core)
implementation(libs.kotlinx.serialization.json)
implementation(libs.picocli)

// -- Compose Desktop ---------------------------------------------------
// Platform-independent: single JAR runs on all supported OSes.
// Skiko auto-detects the OS at runtime and loads the correct native library.
implementation(compose.desktop.macos_arm64)
implementation(compose.desktop.macos_x64)
implementation(compose.desktop.linux_x64)
implementation(compose.desktop.linux_arm64)
implementation(compose.desktop.windows_x64)
implementation(compose.components.resources)
@Suppress("DEPRECATION")
implementation(compose.material3)
implementation(compose.materialIconsExtended)

// -- Async / Serialization ---------------------------------------------
implementation(libs.kotlinx.coroutines.core)
implementation(libs.kotlinx.coroutines.swing)
implementation(libs.kotlinx.serialization.json)
// testImplementation(libs.kotlin.test)
//}

// -- Networking (GUI) --------------------------------------------------
implementation(libs.ktor.client.core)
implementation(libs.ktor.client.cio)
implementation(libs.ktor.client.content.negotiation)
implementation(libs.ktor.serialization.kotlinx.json)
implementation(libs.ktor.client.logging)

// -- DI / Navigation (GUI) ---------------------------------------------
implementation(platform(libs.koin.bom))
implementation(libs.koin.core)
implementation(libs.koin.compose)

implementation(libs.voyager.navigator)
implementation(libs.voyager.screenmodel)
implementation(libs.voyager.koin)
implementation(libs.voyager.transitions)

// -- APK Parsing (GUI) -------------------------------------------------
implementation(libs.apk.parser)

// -- Testing -----------------------------------------------------------
testImplementation(libs.kotlin.test)
testImplementation(libs.junit.params)
testImplementation(libs.mockk)
}

kotlin {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_11)
// ============================================================================
// Tasks
// ============================================================================
tasks {
jar {
manifest {
attributes(
"Implementation-Title" to project.name,
"Implementation-Version" to project.version
)
}
}
}

java {
targetCompatibility = JavaVersion.VERSION_11
}

tasks {
test {
useJUnitPlatform()
testLogging {
Expand All @@ -63,9 +130,15 @@ tasks {
}

processResources {
expand("projectVersion" to project.version)
// Only expand properties files, not binary files like PNG/ICO
filesMatching("**/*.properties") {
expand("projectVersion" to project.version)
}
}

// -------------------------------------------------------------------------
// Shadow JAR — the only distribution artifact
// -------------------------------------------------------------------------
shadowJar {
exclude(
"/prebuilt/linux/aapt",
Expand All @@ -75,14 +148,31 @@ tasks {
minimize {
exclude(dependency("org.bouncycastle:.*"))
exclude(dependency("app.morphe:morphe-patcher"))
// Ktor uses ServiceLoader
exclude(dependency("io.ktor:.*"))
// Koin uses reflection
exclude(dependency("io.insert-koin:.*"))
}

mergeServiceFiles()
}

distTar {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}

distZip {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}

publish {
dependsOn(shadowJar)
}
}

// ============================================================================
// Publishing / Signing
// ============================================================================
// Needed by gradle-semantic-release-plugin.
// Tracking: https://github.com/KengoTODA/gradle-semantic-release-plugin/issues/435

Expand Down
68 changes: 62 additions & 6 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,24 +1,80 @@
[versions]
# Core
shadow = "9.3.2"
junit = "5.11.0"
kotlin = "2.3.0"
kotlinx = "1.9.0"

# CLI
picocli = "4.7.7"
arsclib = "9696ffecda"
morphe-patcher = "1.3.0-dev.2" # TODO: Update to 1.3.0 before merging to prod
morphe-library = "1.3.0"

# Compose Desktop
compose = "1.10.0"

# Networking
ktor = "3.4.0"

# DI
koin-bom = "4.1.1"

# Navigation
voyager = "1.1.0-beta03"

# Async / Serialization
coroutines = "1.10.2"
kotlinx-serialization = "1.9.0"

# APK
apk-parser = "2.6.10"

# Testing
mockk = "1.14.3"

[libraries]
# Morphe Core
arsclib = { module = "com.github.MorpheApp:ARSCLib", version.ref = "arsclib" }
junit-params = { module = "org.junit.jupiter:junit-jupiter-params", version.ref = "junit" }
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx" }
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx" }
picocli = { module = "info.picocli:picocli", version.ref = "picocli" }
morphe-patcher = { module = "app.morphe:morphe-patcher", version.ref = "morphe-patcher" }
morphe-library = { module = "app.morphe:morphe-library-jvm", version.ref = "morphe-library" }

# Ktor Client
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
ktor-client-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktor" }
ktor-client-content-negotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktor" }
ktor-serialization-kotlinx-json = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktor" }
ktor-client-logging = { module = "io.ktor:ktor-client-logging", version.ref = "ktor" }

# Koin
koin-bom = { module = "io.insert-koin:koin-bom", version.ref = "koin-bom" }
koin-core = { module = "io.insert-koin:koin-core" }
koin-compose = { module = "io.insert-koin:koin-compose" }

# Voyager Navigation
voyager-navigator = { module = "cafe.adriel.voyager:voyager-navigator", version.ref = "voyager" }
voyager-screenmodel = { module = "cafe.adriel.voyager:voyager-screenmodel", version.ref = "voyager" }
voyager-koin = { module = "cafe.adriel.voyager:voyager-koin", version.ref = "voyager" }
voyager-transitions = { module = "cafe.adriel.voyager:voyager-transitions", version.ref = "voyager" }

# Coroutines
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" }
kotlinx-coroutines-swing = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-swing", version.ref = "coroutines" }

# Serialization
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization" }

# APK
apk-parser = { module = "net.dongliu:apk-parser", version.ref = "apk-parser" }

# Testing
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
mockk = { module = "io.mockk:mockk", version.ref = "mockk" }

[plugins]
shadow = { id = "com.gradleup.shadow", version.ref = "shadow" }
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
compose = { id = "org.jetbrains.compose", version.ref = "compose" }
shadow = { id = "com.gradleup.shadow", version.ref = "shadow" }
13 changes: 13 additions & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
pluginManagement {
repositories {
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
google()
mavenCentral()
gradlePluginPortal()
}
}

plugins {
id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0"
}

rootProject.name = "morphe-cli"

// Include morphe-patcher and morphe-library as composite builds if they exist locally
Expand Down
40 changes: 40 additions & 0 deletions src/main/composeResources/drawable/morphe_dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading