New Project Structure and Rewritten Architecture

This commit is contained in:
Bitmap
2025-11-12 23:08:29 +05:30
parent 0aa8d98778
commit 2459fa00e1
89 changed files with 2392 additions and 1575 deletions
Generated
+1
View File
@@ -0,0 +1 @@
AabToApk
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AndroidProjectSystem">
<option name="providerId" value="com.android.tools.idea.GradleProjectSystem" />
</component>
</project>
+1 -3
View File
@@ -1,8 +1,6 @@
<component name="ArtifactManager">
<artifact type="jar" name="AabToApk-jvm-1.0-SNAPSHOT">
<output-path>$PROJECT_DIR$/build/libs</output-path>
<root id="archive" name="AabToApk-jvm-1.0-SNAPSHOT.jar">
<element id="module-output" name="AabToApk.jvmMain" />
</root>
<root id="archive" name="AabToApk-jvm-1.0-SNAPSHOT.jar" />
</artifact>
</component>
+8
View File
@@ -0,0 +1,8 @@
<component name="ArtifactManager">
<artifact type="jar" name="composeApp-jvm">
<output-path>$PROJECT_DIR$/composeApp/build/libs</output-path>
<root id="archive" name="composeApp-jvm.jar">
<element id="module-output" name="AabToApk.composeApp.jvmMain" />
</root>
</artifact>
</component>
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AgentMigrationStateService">
<option name="migrationStatus" value="COMPLETED" />
</component>
</project>
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AskMigrationStateService">
<option name="migrationStatus" value="COMPLETED" />
</component>
</project>
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Ask2AgentMigrationStateService">
<option name="migrationStatus" value="COMPLETED" />
</component>
</project>
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="EditMigrationStateService">
<option name="migrationStatus" value="COMPLETED" />
</component>
</project>
+1
View File
@@ -9,6 +9,7 @@
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/composeApp" />
</set>
</option>
</GradleProjectSettings>
-1
View File
@@ -1,4 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="azul-18" project-jdk-type="JavaSDK">
+7 -57
View File
@@ -1,58 +1,8 @@
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
plugins {
kotlin("multiplatform")
id("org.jetbrains.compose")
}
group = "com.AabToApk"
version = "1.0-SNAPSHOT"
repositories {
google()
mavenCentral()
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
}
kotlin {
jvm {
jvmToolchain(11)
withJava()
}
sourceSets {
val jvmMain by getting {
dependencies {
implementation(compose.desktop.currentOs)
api("com.esotericsoftware:kryo:4.0.1")
}
}
val jvmTest by getting {
dependencies {
implementation(compose.desktop.uiTestJUnit4)
implementation(compose.desktop.currentOs)
}
}
val resourcesDir = "src/common/resources"
}
}
compose.desktop {
application {
mainClass = "MainKt"
nativeDistributions {
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
packageName = "AabToApk"
packageVersion = "1.0.4"
val iconsRoot = project.file("desktop-icons")
macOS{
iconFile.set(iconsRoot.resolve("launcher.icns"))
}
windows{
iconFile.set(iconsRoot.resolve("launcher.ico"))
}
linux{
iconFile.set(iconsRoot.resolve("launcher.png"))
}
}
}
}
// this is necessary to avoid the plugins to be loaded multiple times
// in each subproject's classloader
alias(libs.plugins.composeHotReload) apply false
alias(libs.plugins.composeMultiplatform) apply false
alias(libs.plugins.composeCompiler) apply false
alias(libs.plugins.kotlinMultiplatform) apply false
}
+75
View File
@@ -0,0 +1,75 @@
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
plugins {
alias(libs.plugins.kotlinMultiplatform)
alias(libs.plugins.composeMultiplatform)
alias(libs.plugins.composeCompiler)
alias(libs.plugins.composeHotReload)
alias(libs.plugins.kotlin.serialization)
}
kotlin {
jvm()
sourceSets {
commonMain.dependencies {
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material3)
implementation(compose.materialIconsExtended)
implementation(compose.ui)
implementation(compose.components.resources)
implementation(compose.components.uiToolingPreview)
implementation(libs.androidx.lifecycle.viewmodelCompose)
implementation(libs.androidx.lifecycle.runtimeCompose)
// Ktor Client
implementation(libs.ktor.client.core)
implementation(libs.ktor.client.content.negotiation)
implementation(libs.ktor.serialization.kotlinx.json)
implementation(libs.ktor.client.logging)
// Koin
implementation(libs.koin.core)
implementation(libs.koin.compose)
implementation(libs.koin.viewmodel)
implementation(libs.koin.navigation)
// Navigation
implementation(libs.androidx.compose.navigation)
// Datastore
implementation(libs.datastore)
implementation(libs.datastore.prefs)
}
commonTest.dependencies {
implementation(libs.kotlin.test)
}
jvmMain.dependencies {
implementation(compose.desktop.currentOs)
implementation(libs.kotlinx.coroutinesSwing)
implementation(libs.ktor.client.cio)
implementation(libs.kotlinx.coroutines.core)
implementation(libs.logback.logging)
}
val jvmMain by getting {
resources.srcDir("src/jvmMain/composeResources")
}
}
}
compose.desktop {
application {
mainClass = "MainKt"
nativeDistributions {
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
packageName = "AabToApk"
packageVersion = "1.0.4"
val iconsRoot = project.file("desktop-icons")
macOS{
iconFile.set(iconsRoot.resolve("launcher.icns"))
}
windows{
iconFile.set(iconsRoot.resolve("launcher.ico"))
}
linux{
iconFile.set(iconsRoot.resolve("launcher.png"))
}
}
}
}

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" ?>
<resources>
<string name="app_name">BundleTool Desktop</string>
<string name="title">AAB to APK Converter</string>
<string name="subtitle">Convert Android App Bundles to various APK formats with ease.</string>
<string name="step_one_title">1. Select Android App Bundle (.aab)</string>
<string name="no_aab_selected">No AAB file selected</string>
<string name="step_two_title">2. Choose BundleTool Executable</string>
<string name="bundletool_not_selected">Bundle Tool not selected</string>
<string name="download_bundletool">Download BundleTool</string>
<string name="step_three_title">3. Choose Output Mode</string>
<string name="universal_apk">Universal APK</string>
<string name="apk_set">APK Set (.apks)</string>
<string name="device_specific">Device-specific</string>
<string name="step_four_title">4. Output Directory (optional)</string>
<string name="step_four_subtitle">Leave empty for same directory as .aab</string>
</resources>
+25
View File
@@ -0,0 +1,25 @@
import aabtoapk.composeapp.generated.resources.Res
import aabtoapk.composeapp.generated.resources.app_name
import androidx.compose.ui.Alignment
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.WindowPosition
import androidx.compose.ui.window.application
import androidx.compose.ui.window.rememberWindowState
import di.initKoin
import org.jetbrains.compose.resources.stringResource
import ui.App
fun main() = application {
initKoin()
Window(
onCloseRequest = ::exitApplication,
state = rememberWindowState(
width = 800.dp, height = 1000.dp,
position = WindowPosition(Alignment.Center)
),
title = stringResource(Res.string.app_name)
) {
App {}
}
}
@@ -0,0 +1,86 @@
package command
import org.slf4j.Logger
import org.slf4j.LoggerFactory
class CommandBuilder(
private val config: Config
) : ICommandBuilder {
val logger = LoggerFactory.getLogger("CommandBuilder") as Logger
data class Config(
val bundleToolPath: String,
val aabPath: String,
val outputDir: String? = null,
val isUniversal: Boolean = true,
val keystore: KeystoreConfig? = null,
val deviceId: String? = null,
val overwrite: Boolean = false
)
data class KeystoreConfig(
val path: String,
val password: String,
val alias: String,
val keyPassword: String
)
override fun build(): Result<String> {
if (config.bundleToolPath.isBlank()) return Result.failure(IllegalArgumentException("BundleTool path missing"))
if (config.aabPath.isBlank()) return Result.failure(IllegalArgumentException("AAB file path missing"))
val cmd = buildString {
append("java -jar \"${config.bundleToolPath}\" build-apks ")
append("--bundle=\"${config.aabPath}\" ")
append("--output=\"${if(config.outputDir.isNullOrEmpty()) getDefaultOutput() else config.outputDir}\" ")
if (config.isUniversal) append("--mode=universal ")
if (config.overwrite) append("--overwrite ")
config.keystore?.let {
append("--ks=${it.path} ")
append("--ks-pass=pass:${it.password} ")
append("--ks-key-alias=${it.alias} ")
append("--key-pass=pass:${it.keyPassword} ")
}
config.deviceId?.let { append("--device-id=$it ") }
append("--overwrite ")
}
logger.debug(cmd.trim())
return Result.success(cmd.trim())
}
private fun getDefaultOutput(): String {
val base = config.aabPath.substringBeforeLast(".")
return "$base.apks"
}
companion object {
fun create(block: Builder.() -> Unit): CommandBuilder {
val builder = Builder()
builder.block()
return CommandBuilder(builder.build())
}
}
class Builder {
private var bundleToolPath: String = ""
private var aabPath: String = ""
private var outputDir: String? = null
private var isUniversal: Boolean = true
private var keystore: KeystoreConfig? = null
private var deviceId: String? = null
private var overwrite: Boolean = false
fun bundleTool(path: String) = apply { bundleToolPath = path }
fun aab(path: String) = apply { aabPath = path }
fun outputDir(dir: String?) = apply { outputDir = dir }
fun universal(enable: Boolean) = apply { isUniversal = enable }
fun overwrite(enable: Boolean) = apply { overwrite = enable }
fun keystore(block: KeystoreConfig.() -> Unit) = apply {
keystore = KeystoreConfig("", "", "", "").apply(block)
}
fun device(id: String?) = apply { deviceId = id }
fun build() = Config(bundleToolPath, aabPath, outputDir, isUniversal, keystore, deviceId, overwrite)
}
}

Some files were not shown because too many files have changed in this diff Show More