Skip to content

Commit cd627e6

Browse files
authored
feat: Add desktop GUI (#42)
1 parent 9f6ee1a commit cd627e6

55 files changed

Lines changed: 11742 additions & 23 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ misc.xml
2323
deploymentTargetDropDown.xml
2424
render.experimental.xml
2525

26+
# Kotlin
27+
.kotlin/
28+
2629
# Keystore files
2730
*.jks
2831
*.keystore
@@ -33,5 +36,7 @@ google-services.json
3336
# Android Profiling
3437
*.hprof
3538

39+
# Mac files
40+
.DS_Store
3641
# NPM modules
3742
node_modules/

.run/CLI GUI.run.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<component name="ProjectRunConfigurationManager">
2+
<configuration default="false" name="CLI GUI" type="Application" factoryName="Application">
3+
<option name="MAIN_CLASS_NAME" value="app.morphe.MorpheLauncherKt" />
4+
<module name="morphe-cli.main" />
5+
<method v="2">
6+
<option name="Make" enabled="true" />
7+
</method>
8+
</configuration>
9+
</component>

build.gradle.kts

Lines changed: 104 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
22

33
plugins {
4-
alias(libs.plugins.kotlin)
4+
alias(libs.plugins.kotlin.jvm)
5+
alias(libs.plugins.kotlin.compose)
56
alias(libs.plugins.kotlin.serialization)
7+
alias(libs.plugins.compose)
68
alias(libs.plugins.shadow)
79
application
810
`maven-publish`
@@ -11,10 +13,33 @@ plugins {
1113

1214
group = "app.morphe"
1315

16+
// ============================================================================
17+
// JVM / Kotlin Configuration
18+
// ============================================================================
19+
kotlin {
20+
jvmToolchain {
21+
languageVersion.set(JavaLanguageVersion.of(17))
22+
vendor.set(JvmVendorSpec.ADOPTIUM)
23+
}
24+
compilerOptions {
25+
jvmTarget.set(JvmTarget.JVM_17)
26+
}
27+
}
28+
29+
// ============================================================================
30+
// Application Entry Point
31+
// ============================================================================
32+
// Shadow JAR reads this for Main-Class manifest attribute.
33+
//
34+
// No args / double-click → GUI (Compose Desktop)
35+
// With args (terminal) → CLI (PicoCLI)
1436
application {
15-
mainClass = "app.morphe.cli.command.MainCommandKt"
37+
mainClass.set("app.morphe.MorpheLauncherKt")
1638
}
1739

40+
// ============================================================================
41+
// Repositories
42+
// ============================================================================
1843
repositories {
1944
mavenLocal()
2045
mavenCentral()
@@ -36,25 +61,67 @@ dependencies {
3661
api(libs.morphe.patcher)
3762
implementation(libs.arsclib)
3863
implementation(libs.morphe.library)
39-
implementation(libs.kotlinx.coroutines.core)
40-
implementation(libs.kotlinx.serialization.json)
4164
implementation(libs.picocli)
4265

66+
// -- Compose Desktop ---------------------------------------------------
67+
// Platform-independent: single JAR runs on all supported OSes.
68+
// Skiko auto-detects the OS at runtime and loads the correct native library.
69+
implementation(compose.desktop.macos_arm64)
70+
implementation(compose.desktop.macos_x64)
71+
implementation(compose.desktop.linux_x64)
72+
implementation(compose.desktop.linux_arm64)
73+
implementation(compose.desktop.windows_x64)
74+
implementation(compose.components.resources)
75+
@Suppress("DEPRECATION")
76+
implementation(compose.material3)
77+
implementation(compose.materialIconsExtended)
78+
79+
// -- Async / Serialization ---------------------------------------------
80+
implementation(libs.kotlinx.coroutines.core)
81+
implementation(libs.kotlinx.coroutines.swing)
82+
implementation(libs.kotlinx.serialization.json)
83+
// testImplementation(libs.kotlin.test)
84+
//}
85+
86+
// -- Networking (GUI) --------------------------------------------------
87+
implementation(libs.ktor.client.core)
88+
implementation(libs.ktor.client.cio)
89+
implementation(libs.ktor.client.content.negotiation)
90+
implementation(libs.ktor.serialization.kotlinx.json)
91+
implementation(libs.ktor.client.logging)
92+
93+
// -- DI / Navigation (GUI) ---------------------------------------------
94+
implementation(platform(libs.koin.bom))
95+
implementation(libs.koin.core)
96+
implementation(libs.koin.compose)
97+
98+
implementation(libs.voyager.navigator)
99+
implementation(libs.voyager.screenmodel)
100+
implementation(libs.voyager.koin)
101+
implementation(libs.voyager.transitions)
102+
103+
// -- APK Parsing (GUI) -------------------------------------------------
104+
implementation(libs.apk.parser)
105+
106+
// -- Testing -----------------------------------------------------------
43107
testImplementation(libs.kotlin.test)
44108
testImplementation(libs.junit.params)
109+
testImplementation(libs.mockk)
45110
}
46111

47-
kotlin {
48-
compilerOptions {
49-
jvmTarget.set(JvmTarget.JVM_11)
112+
// ============================================================================
113+
// Tasks
114+
// ============================================================================
115+
tasks {
116+
jar {
117+
manifest {
118+
attributes(
119+
"Implementation-Title" to project.name,
120+
"Implementation-Version" to project.version
121+
)
122+
}
50123
}
51-
}
52124

53-
java {
54-
targetCompatibility = JavaVersion.VERSION_11
55-
}
56-
57-
tasks {
58125
test {
59126
useJUnitPlatform()
60127
testLogging {
@@ -63,9 +130,15 @@ tasks {
63130
}
64131

65132
processResources {
66-
expand("projectVersion" to project.version)
133+
// Only expand properties files, not binary files like PNG/ICO
134+
filesMatching("**/*.properties") {
135+
expand("projectVersion" to project.version)
136+
}
67137
}
68138

139+
// -------------------------------------------------------------------------
140+
// Shadow JAR — the only distribution artifact
141+
// -------------------------------------------------------------------------
69142
shadowJar {
70143
exclude(
71144
"/prebuilt/linux/aapt",
@@ -75,14 +148,31 @@ tasks {
75148
minimize {
76149
exclude(dependency("org.bouncycastle:.*"))
77150
exclude(dependency("app.morphe:morphe-patcher"))
151+
// Ktor uses ServiceLoader
152+
exclude(dependency("io.ktor:.*"))
153+
// Koin uses reflection
154+
exclude(dependency("io.insert-koin:.*"))
78155
}
156+
157+
mergeServiceFiles()
158+
}
159+
160+
distTar {
161+
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
162+
}
163+
164+
distZip {
165+
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
79166
}
80167

81168
publish {
82169
dependsOn(shadowJar)
83170
}
84171
}
85172

173+
// ============================================================================
174+
// Publishing / Signing
175+
// ============================================================================
86176
// Needed by gradle-semantic-release-plugin.
87177
// Tracking: https://github.com/KengoTODA/gradle-semantic-release-plugin/issues/435
88178

gradle/libs.versions.toml

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,80 @@
11
[versions]
2+
# Core
23
shadow = "9.3.2"
34
junit = "5.11.0"
45
kotlin = "2.3.0"
5-
kotlinx = "1.9.0"
6+
7+
# CLI
68
picocli = "4.7.7"
79
arsclib = "9696ffecda"
810
morphe-patcher = "1.3.0-dev.2" # TODO: Update to 1.3.0 before merging to prod
911
morphe-library = "1.3.0"
1012

13+
# Compose Desktop
14+
compose = "1.10.0"
15+
16+
# Networking
17+
ktor = "3.4.0"
18+
19+
# DI
20+
koin-bom = "4.1.1"
21+
22+
# Navigation
23+
voyager = "1.1.0-beta03"
24+
25+
# Async / Serialization
26+
coroutines = "1.10.2"
27+
kotlinx-serialization = "1.9.0"
28+
29+
# APK
30+
apk-parser = "2.6.10"
31+
32+
# Testing
33+
mockk = "1.14.3"
34+
1135
[libraries]
36+
# Morphe Core
1237
arsclib = { module = "com.github.MorpheApp:ARSCLib", version.ref = "arsclib" }
1338
junit-params = { module = "org.junit.jupiter:junit-jupiter-params", version.ref = "junit" }
14-
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
15-
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx" }
16-
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx" }
1739
picocli = { module = "info.picocli:picocli", version.ref = "picocli" }
1840
morphe-patcher = { module = "app.morphe:morphe-patcher", version.ref = "morphe-patcher" }
1941
morphe-library = { module = "app.morphe:morphe-library-jvm", version.ref = "morphe-library" }
2042

43+
# Ktor Client
44+
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
45+
ktor-client-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktor" }
46+
ktor-client-content-negotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktor" }
47+
ktor-serialization-kotlinx-json = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktor" }
48+
ktor-client-logging = { module = "io.ktor:ktor-client-logging", version.ref = "ktor" }
49+
50+
# Koin
51+
koin-bom = { module = "io.insert-koin:koin-bom", version.ref = "koin-bom" }
52+
koin-core = { module = "io.insert-koin:koin-core" }
53+
koin-compose = { module = "io.insert-koin:koin-compose" }
54+
55+
# Voyager Navigation
56+
voyager-navigator = { module = "cafe.adriel.voyager:voyager-navigator", version.ref = "voyager" }
57+
voyager-screenmodel = { module = "cafe.adriel.voyager:voyager-screenmodel", version.ref = "voyager" }
58+
voyager-koin = { module = "cafe.adriel.voyager:voyager-koin", version.ref = "voyager" }
59+
voyager-transitions = { module = "cafe.adriel.voyager:voyager-transitions", version.ref = "voyager" }
60+
61+
# Coroutines
62+
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" }
63+
kotlinx-coroutines-swing = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-swing", version.ref = "coroutines" }
64+
65+
# Serialization
66+
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization" }
67+
68+
# APK
69+
apk-parser = { module = "net.dongliu:apk-parser", version.ref = "apk-parser" }
70+
71+
# Testing
72+
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
73+
mockk = { module = "io.mockk:mockk", version.ref = "mockk" }
74+
2175
[plugins]
22-
shadow = { id = "com.gradleup.shadow", version.ref = "shadow" }
23-
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
76+
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
77+
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
2478
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
79+
compose = { id = "org.jetbrains.compose", version.ref = "compose" }
80+
shadow = { id = "com.gradleup.shadow", version.ref = "shadow" }

settings.gradle.kts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
pluginManagement {
2+
repositories {
3+
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
4+
google()
5+
mavenCentral()
6+
gradlePluginPortal()
7+
}
8+
}
9+
10+
plugins {
11+
id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0"
12+
}
13+
114
rootProject.name = "morphe-cli"
215

316
// Include morphe-patcher and morphe-library as composite builds if they exist locally
Lines changed: 40 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)